Index: /tags/1.9/.travis.yml
===================================================================
--- /tags/1.9/.travis.yml	(revision 7684)
+++ /tags/1.9/.travis.yml	(revision 7684)
@@ -0,0 +1,54 @@
+language: php
+
+php:
+    - 5.2
+    - 5.3
+    - 5.4
+    - 5.5
+
+env:
+    - WP_VERSION=master WP_MULTISITE=0
+    - WP_VERSION=3.8 WP_MULTISITE=0
+    - WP_VERSION=3.7.1 WP_MULTISITE=0
+    - WP_VERSION=3.6.1 WP_MULTISITE=0
+    - WP_VERSION=3.5.2 WP_MULTISITE=0
+    - WP_VERSION=master WP_MULTISITE=1
+    - WP_VERSION=3.8 WP_MULTISITE=1
+    - WP_VERSION=3.7.1 WP_MULTISITE=1
+    - WP_VERSION=3.6.1 WP_MULTISITE=1
+    - WP_VERSION=3.5.2 WP_MULTISITE=1
+
+before_script:
+    # set up WP install
+    - WP_CORE_DIR=/tmp/wordpress/
+    - wget -nv -O /tmp/wordpress.tar.gz https://github.com/WordPress/WordPress/tarball/$WP_VERSION
+    - mkdir -p $WP_CORE_DIR
+    - tar --strip-components=1 -zxmf /tmp/wordpress.tar.gz -C $WP_CORE_DIR
+    - plugin_slug=$(basename $(pwd))
+    - plugin_dir=$WP_CORE_DIR/wp-content/plugins/$plugin_slug
+    - cd ..
+    - mv $plugin_slug $plugin_dir
+    # set up testing suite
+    - export WP_TESTS_DIR=/tmp/wordpress-tests/
+    - svn co --ignore-externals http://unit-tests.svn.wordpress.org/trunk/ $WP_TESTS_DIR
+    - cd $WP_TESTS_DIR
+    - cp wp-tests-config-sample.php wp-tests-config.php
+    - sed -i "s:dirname( __FILE__ ) . '/wordpress/':'$WP_CORE_DIR':" wp-tests-config.php
+    - sed -i "s/yourdbnamehere/wordpress_test/" wp-tests-config.php
+    - sed -i "s/yourusernamehere/root/" wp-tests-config.php
+    - sed -i "s/yourpasswordhere//" wp-tests-config.php
+    # set up database
+    - mysql -e 'CREATE DATABASE wordpress_test;' -uroot
+    # prepare for running the tests
+    - cd $plugin_dir/tests
+
+script: phpunit
+
+notifications:
+    email: false
+
+    irc:
+        channels:
+            - "irc.freenode.net#buddypress-dev"
+        template:
+            - "Build %{build_number} (%{branch} - %{commit}): %{message} %{build_url}"
Index: /tags/1.9/bp-activity/admin/css/admin.css
===================================================================
--- /tags/1.9/bp-activity/admin/css/admin.css	(revision 7684)
+++ /tags/1.9/bp-activity/admin/css/admin.css	(revision 7684)
@@ -0,0 +1,77 @@
+.akismet-status {
+	float: right;
+}
+.akismet-status a {
+	color: #AAA;
+	font-style: italic;
+}
+.akismet-history {
+	margin: 13px;
+}
+.akismet-history div {
+	margin-bottom: 13px;
+}
+.akismet-history span {
+	color: #999;
+}
+
+#wp-bp-activities-wrap {
+	padding: 5px 0;
+}
+#bp-activities {
+	height: 120px;
+}
+#bp-replyhead {
+	font-size: 1em;
+	line-height: 1.4em;
+	margin: 0;
+}
+#bp-replysubmit {
+	margin: 0;
+	padding: 0 0 3px;
+	text-align: center;
+}
+#bp-replysubmit .error {
+	color: red;
+	line-height: 21px;
+	text-align: center;
+	vertical-align: center;
+}
+#bp-replysubmit img.waiting {
+	float: right;
+	padding: 4px 10px 0;
+	vertical-align: top;
+}
+#bp-activities-form .column-response img {
+	float: left;
+	margin-right: 10px;
+	margin-top: 1px;
+}
+.activity-errors {
+	list-style-type: disc;
+	margin-left: 2em;
+}
+
+#bp_activity_action div.inside,
+#bp_activity_content div.inside {
+	line-height: 0;
+}
+#bp_activity_action h3,
+#bp_activity_content h3 {
+	cursor: auto;
+}
+#bp_activity_action td.mceIframeContainer,
+#bp_activity_content td.mceIframeContainer {
+	background-color: white;
+}
+#post-body #bp-activities-action_resize,
+#post-body #bp-activities-content_resize {
+	position: inherit;
+	margin-top: -2px;
+}
+#bp_activity_link input {
+	width: 99%;
+}
+#bp-activities-primaryid {
+	margin-bottom: 1em;
+}
Index: /tags/1.9/bp-activity/admin/css/admin.min.css
===================================================================
--- /tags/1.9/bp-activity/admin/css/admin.min.css	(revision 7684)
+++ /tags/1.9/bp-activity/admin/css/admin.min.css	(revision 7684)
@@ -0,0 +1,1 @@
+.akismet-status{float:right}.akismet-status a{color:#AAA;font-style:italic}.akismet-history{margin:13px}.akismet-history div{margin-bottom:13px}.akismet-history span{color:#999}#wp-bp-activities-wrap{padding:5px 0}#bp-activities{height:120px}#bp-replyhead{font-size:1em;line-height:1.4em;margin:0}#bp-replysubmit{margin:0;padding:0 0 3px;text-align:center}#bp-replysubmit .error{color:red;line-height:21px;text-align:center;vertical-align:center}#bp-replysubmit img.waiting{float:right;padding:4px 10px 0;vertical-align:top}#bp-activities-form .column-response img{float:left;margin-right:10px;margin-top:1px}.activity-errors{list-style-type:disc;margin-left:2em}#bp_activity_action div.inside,#bp_activity_content div.inside{line-height:0}#bp_activity_action h3,#bp_activity_content h3{cursor:auto}#bp_activity_action td.mceIframeContainer,#bp_activity_content td.mceIframeContainer{background-color:white}#post-body #bp-activities-action_resize,#post-body #bp-activities-content_resize{position:inherit;margin-top:-2px}#bp_activity_link input{width:99%}#bp-activities-primaryid{margin-bottom:1em}
Index: /tags/1.9/bp-activity/admin/js/admin.js
===================================================================
--- /tags/1.9/bp-activity/admin/js/admin.js	(revision 7684)
+++ /tags/1.9/bp-activity/admin/js/admin.js	(revision 7684)
@@ -0,0 +1,167 @@
+(function( $ ) {
+
+/**
+ * Activity reply object for the activity index screen
+ *
+ * @since BuddyPress (1.6)
+ */
+var activityReply = {
+
+	/**
+	 * Attach event handler functions to the relevant elements.
+	 *
+	 * @since BuddyPress (1.6)
+	 */
+	init : function() {
+		$(document).on( 'click', '.row-actions a.reply',              activityReply.open );
+		$(document).on( 'click', '#bp-activities-container a.cancel', activityReply.close );
+		$(document).on( 'click', '#bp-activities-container a.save',   activityReply.send );
+
+		// Close textarea on escape
+		$(document).on( 'keyup', '#bp-activities:visible', function( e ) {
+			if ( 27 == e.which ) {
+				activityReply.close();
+			}
+		});
+	},
+
+	/**
+	 * Reveals the entire row when "reply" is pressed.
+	 *
+	 * @since BuddyPress (1.6)
+	 */
+	open : function( e ) {
+		// Hide the container row, and move it to the new location
+		var box = $( '#bp-activities-container' ).hide();
+		$( this ).parents( 'tr' ).after( box );
+
+		// Fade the whole row in, and set focus on the text area.
+		box.fadeIn( '300' );
+		$( '#bp-activities' ).focus();
+
+		return false;
+	},
+
+	/**
+	 * Hide and reset the entire row when "cancel", or escape, are pressed.
+	 *
+	 * @since BuddyPress (1.6)
+	 */
+	close : function( e ) {
+		// Hide the container row
+		$('#bp-activities-container').fadeOut( '200', function () { 
+
+			// Empty and unfocus the text area
+			$( '#bp-activities' ).val( '' ).blur();
+
+			// Remove any error message and disable the spinner
+			$( '#bp-replysubmit .error' ).html( '' ).hide();
+			$( '#bp-replysubmit .waiting' ).hide();
+		});
+
+		return false;
+	},
+
+	/**
+	 * Submits "form" via AJAX back to WordPress.
+	 *
+	 * @since BuddyPress (1.6)
+	 */
+	send : function( e ) {
+		// Hide any existing error message, and show the loading spinner
+		$( '#bp-replysubmit .error' ).hide();
+		$( '#bp-replysubmit .waiting' ).show();
+
+		// Grab the nonce
+		var reply = {};
+		reply['_ajax_nonce-bp-activity-admin-reply'] = $( '#bp-activities-container input[name="_ajax_nonce-bp-activity-admin-reply"]' ).val();
+
+		// Get the rest of the data
+		reply.action    = 'bp-activity-admin-reply';
+		reply.content   = $( '#bp-activities' ).val();
+		reply.parent_id = $( '#bp-activities-container' ).prev().data( 'parent_id' );
+		reply.root_id   = $( '#bp-activities-container' ).prev().data( 'root_id' );
+
+		// Make the AJAX call
+		$.ajax({
+			data    : reply,
+			type    : 'POST',
+			url     : ajaxurl,
+
+			// Callbacks
+			error   : function( r ) { activityReply.error( r ); },
+			success : function( r ) { activityReply.show( r ); }
+		});
+
+		return false;
+	},
+
+	/**
+	 * send() error message handler
+	 *
+	 * @since BuddyPress (1.6)
+	 */
+	error : function( r ) {
+		var er = r.statusText;
+		$('#bp-replysubmit .waiting').hide();
+
+		if ( r.responseText ) {
+			er = r.responseText.replace( /<.[^<>]*?>/g, '' );
+		}
+
+		if ( er ) {
+			$('#bp-replysubmit .error').html( er ).show();
+		}
+	},
+
+	/**
+	 * send() success handler
+	 *
+	 * @since BuddyPress (1.6)
+	 */
+	show : function ( xml ) {
+		var bg, id, response;
+
+		// Handle any errors in the response
+		if ( typeof( xml ) == 'string' ) {
+			activityReply.error( { 'responseText': xml } );
+			return false;
+		}
+
+		response = wpAjax.parseAjaxResponse( xml );
+		if ( response.errors ) {
+			activityReply.error( { 'responseText': wpAjax.broken } );
+			return false;
+		}
+		response = response.responses[0];
+
+		// Close and reset the reply row, and add the new Activity item into the list.
+		$('#bp-activities-container').fadeOut( '200', function () { 
+
+			// Empty and unfocus the text area
+			$( '#bp-activities' ).val( '' ).blur();
+
+			// Remove any error message and disable the spinner
+			$( '#bp-replysubmit .error' ).html( '' ).hide();
+			$( '#bp-replysubmit .waiting' ).hide();
+
+			// Insert new activity item
+			$( '#bp-activities-container' ).before( response.data );
+
+			// Get background colour and animate the flash
+			id = $( '#activity-' + response.id );
+			bg = id.closest( '.widefat' ).css( 'backgroundColor' );
+			id.animate( { 'backgroundColor': '#CEB' }, 300 ).animate( { 'backgroundColor': bg }, 300 );
+		});
+	}
+};
+
+$(document).ready( function () {
+	// Create the Activity reply object after domready event
+	activityReply.init();
+
+	// On the edit screen, unload the close/open toggle js for the action & content metaboxes
+	$( '#bp_activity_action h3, #bp_activity_content h3' ).unbind( 'click' );
+});
+
+})(jQuery);
Index: /tags/1.9/bp-activity/admin/js/admin.min.js
===================================================================
--- /tags/1.9/bp-activity/admin/js/admin.min.js	(revision 7684)
+++ /tags/1.9/bp-activity/admin/js/admin.min.js	(revision 7684)
@@ -0,0 +1,1 @@
+(function(b){var a={init:function(){b(document).on("click",".row-actions a.reply",a.open);b(document).on("click","#bp-activities-container a.cancel",a.close);b(document).on("click","#bp-activities-container a.save",a.send);b(document).on("keyup","#bp-activities:visible",function(c){if(27==c.which){a.close()}})},open:function(d){var c=b("#bp-activities-container").hide();b(this).parents("tr").after(c);c.fadeIn("300");b("#bp-activities").focus();return false},close:function(c){b("#bp-activities-container").fadeOut("200",function(){b("#bp-activities").val("").blur();b("#bp-replysubmit .error").html("").hide();b("#bp-replysubmit .waiting").hide()});return false},send:function(d){b("#bp-replysubmit .error").hide();b("#bp-replysubmit .waiting").show();var c={};c["_ajax_nonce-bp-activity-admin-reply"]=b('#bp-activities-container input[name="_ajax_nonce-bp-activity-admin-reply"]').val();c.action="bp-activity-admin-reply";c.content=b("#bp-activities").val();c.parent_id=b("#bp-activities-container").prev().data("parent_id");c.root_id=b("#bp-activities-container").prev().data("root_id");b.ajax({data:c,type:"POST",url:ajaxurl,error:function(e){a.error(e)},success:function(e){a.show(e)}});return false},error:function(c){var d=c.statusText;b("#bp-replysubmit .waiting").hide();if(c.responseText){d=c.responseText.replace(/<.[^<>]*?>/g,"")}if(d){b("#bp-replysubmit .error").html(d).show()}},show:function(d){var e,f,c;if(typeof(d)=="string"){a.error({responseText:d});return false}c=wpAjax.parseAjaxResponse(d);if(c.errors){a.error({responseText:wpAjax.broken});return false}c=c.responses[0];b("#bp-activities-container").fadeOut("200",function(){b("#bp-activities").val("").blur();b("#bp-replysubmit .error").html("").hide();b("#bp-replysubmit .waiting").hide();b("#bp-activities-container").before(c.data);f=b("#activity-"+c.id);e=f.closest(".widefat").css("backgroundColor");f.animate({backgroundColor:"#CEB"},300).animate({backgroundColor:e},300)})}};b(document).ready(function(){a.init();b("#bp_activity_action h3, #bp_activity_content h3").unbind("click")})})(jQuery);
Index: /tags/1.9/bp-activity/bp-activity-actions.php
===================================================================
--- /tags/1.9/bp-activity/bp-activity-actions.php	(revision 7684)
+++ /tags/1.9/bp-activity/bp-activity-actions.php	(revision 7684)
@@ -0,0 +1,649 @@
+<?php
+
+/**
+ * Action functions are exactly the same as screen functions, however they do
+ * not have a template screen associated with them. Usually they will send the
+ * user back to the default screen after execution.
+ *
+ * @package BuddyPress
+ * @subpackage ActivityActions
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/**
+ * Allow core components and dependent plugins to register activity actions.
+ *
+ * @since BuddyPress (1.2)
+ *
+ * @uses do_action() To call 'bp_register_activity_actions' hook.
+ */
+function bp_register_activity_actions() {
+	do_action( 'bp_register_activity_actions' );
+}
+add_action( 'bp_init', 'bp_register_activity_actions', 8 );
+
+/**
+ * Catch and route requests for single activity item permalinks.
+ *
+ * @since BuddyPress (1.2)
+ *
+ * @global object $bp BuddyPress global settings
+ * @uses bp_is_activity_component()
+ * @uses bp_is_current_action()
+ * @uses bp_action_variable()
+ * @uses bp_activity_get_specific()
+ * @uses bp_is_active()
+ * @uses bp_core_get_user_domain()
+ * @uses groups_get_group()
+ * @uses bp_get_group_permalink()
+ * @uses apply_filters_ref_array() To call the 'bp_activity_permalink_redirect_url' hook.
+ * @uses bp_core_redirect()
+ * @uses bp_get_root_domain()
+ *
+ * @return bool False on failure.
+ */
+function bp_activity_action_permalink_router() {
+
+	// Not viewing activity
+	if ( ! bp_is_activity_component() || ! bp_is_current_action( 'p' ) )
+		return false;
+
+	// No activity to display
+	if ( ! bp_action_variable( 0 ) || ! is_numeric( bp_action_variable( 0 ) ) )
+		return false;
+
+	// Get the activity details
+	$activity = bp_activity_get_specific( array( 'activity_ids' => bp_action_variable( 0 ), 'show_hidden' => true ) );
+
+	// 404 if activity does not exist
+	if ( empty( $activity['activities'][0] ) ) {
+		bp_do_404();
+		return;
+	} else {
+		$activity = $activity['activities'][0];
+	}
+
+	// Do not redirect at default
+	$redirect = false;
+
+	// Redirect based on the type of activity
+	if ( bp_is_active( 'groups' ) && $activity->component == buddypress()->groups->id ) {
+
+		// Activity is a user update
+		if ( ! empty( $activity->user_id ) ) {
+			$redirect = bp_core_get_user_domain( $activity->user_id, $activity->user_nicename, $activity->user_login ) . bp_get_activity_slug() . '/' . $activity->id . '/';
+
+		// Activity is something else
+		} else {
+
+			// Set redirect to group activity stream
+			if ( $group = groups_get_group( array( 'group_id' => $activity->item_id ) ) ) {
+				$redirect = bp_get_group_permalink( $group ) . bp_get_activity_slug() . '/' . $activity->id . '/';
+			}
+		}
+
+	// Set redirect to users' activity stream
+	} else if ( ! empty( $activity->user_id ) ) {
+		$redirect = bp_core_get_user_domain( $activity->user_id, $activity->user_nicename, $activity->user_login ) . bp_get_activity_slug() . '/' . $activity->id . '/';
+	}
+
+	// If set, add the original query string back onto the redirect URL
+	if ( ! empty( $_SERVER['QUERY_STRING'] ) ) {
+		$query_frags = array();
+		wp_parse_str( $_SERVER['QUERY_STRING'], $query_frags );
+		$redirect = add_query_arg( urlencode_deep( $query_frags ), $redirect );
+	}
+
+	// Allow redirect to be filtered
+	if ( ! $redirect = apply_filters_ref_array( 'bp_activity_permalink_redirect_url', array( $redirect, &$activity ) ) ) {
+		bp_core_redirect( bp_get_root_domain() );
+	}
+
+	// Redirect to the actual activity permalink page
+	bp_core_redirect( $redirect );
+}
+add_action( 'bp_actions', 'bp_activity_action_permalink_router' );
+
+/**
+ * Delete specific activity item and redirect to previous page.
+ *
+ * @since BuddyPress (1.1)
+ *
+ * @param int $activity_id Activity id to be deleted. Defaults to 0.
+ *
+ * @uses bp_is_activity_component()
+ * @uses bp_is_current_action()
+ * @uses bp_action_variable()
+ * @uses check_admin_referer()
+ * @uses bp_activity_user_can_delete()
+ * @uses do_action() Calls 'bp_activity_before_action_delete_activity' hook to allow actions to be taken before the activity is deleted.
+ * @uses bp_activity_delete()
+ * @uses bp_core_add_message()
+ * @uses do_action() Calls 'bp_activity_action_delete_activity' hook to allow actions to be taken after the activity is deleted.
+ * @uses bp_core_redirect()
+ *
+ * @return bool False on failure.
+ */
+function bp_activity_action_delete_activity( $activity_id = 0 ) {
+
+	// Not viewing activity or action is not delete
+	if ( !bp_is_activity_component() || !bp_is_current_action( 'delete' ) )
+		return false;
+
+	if ( empty( $activity_id ) && bp_action_variable( 0 ) )
+		$activity_id = (int) bp_action_variable( 0 );
+
+	// Not viewing a specific activity item
+	if ( empty( $activity_id ) )
+		return false;
+
+	// Check the nonce
+	check_admin_referer( 'bp_activity_delete_link' );
+
+	// Load up the activity item
+	$activity = new BP_Activity_Activity( $activity_id );
+
+	// Check access
+	if ( ! bp_activity_user_can_delete( $activity ) )
+		return false;
+
+	// Call the action before the delete so plugins can still fetch information about it
+	do_action( 'bp_activity_before_action_delete_activity', $activity_id, $activity->user_id );
+
+	// Delete the activity item and provide user feedback
+	if ( bp_activity_delete( array( 'id' => $activity_id, 'user_id' => $activity->user_id ) ) )
+		bp_core_add_message( __( 'Activity deleted successfully', 'buddypress' ) );
+	else
+		bp_core_add_message( __( 'There was an error when deleting that activity', 'buddypress' ), 'error' );
+
+	do_action( 'bp_activity_action_delete_activity', $activity_id, $activity->user_id );
+
+	// Check for the redirect query arg, otherwise let WP handle things
+ 	if ( !empty( $_GET['redirect_to'] ) )
+		bp_core_redirect( esc_url( $_GET['redirect_to'] ) );
+	else
+		bp_core_redirect( wp_get_referer() );
+}
+add_action( 'bp_actions', 'bp_activity_action_delete_activity' );
+
+/**
+ * Mark specific activity item as spam and redirect to previous page.
+ *
+ * @since BuddyPress (1.6)
+ *
+ * @global object $bp BuddyPress global settings
+ * @param int $activity_id Activity id to be deleted. Defaults to 0.
+ * @return bool False on failure.
+ */
+function bp_activity_action_spam_activity( $activity_id = 0 ) {
+	global $bp;
+
+	// Not viewing activity, or action is not spam, or Akismet isn't present
+	if ( !bp_is_activity_component() || !bp_is_current_action( 'spam' ) || empty( $bp->activity->akismet ) )
+		return false;
+
+	if ( empty( $activity_id ) && bp_action_variable( 0 ) )
+		$activity_id = (int) bp_action_variable( 0 );
+
+	// Not viewing a specific activity item
+	if ( empty( $activity_id ) )
+		return false;
+
+	// Is the current user allowed to spam items?
+	if ( !bp_activity_user_can_mark_spam() )
+		return false;
+
+	// Load up the activity item
+	$activity = new BP_Activity_Activity( $activity_id );
+	if ( empty( $activity->id ) )
+		return false;
+
+	// Check nonce
+	check_admin_referer( 'bp_activity_akismet_spam_' . $activity->id );
+
+	// Call an action before the spamming so plugins can modify things if they want to
+	do_action( 'bp_activity_before_action_spam_activity', $activity->id, $activity );
+
+	// Mark as spam
+	bp_activity_mark_as_spam( $activity );
+	$activity->save();
+
+	// Tell the user the spamming has been succesful
+	bp_core_add_message( __( 'The activity item has been marked as spam and is no longer visible.', 'buddypress' ) );
+
+	do_action( 'bp_activity_action_spam_activity', $activity_id, $activity->user_id );
+
+	// Check for the redirect query arg, otherwise let WP handle things
+ 	if ( !empty( $_GET['redirect_to'] ) )
+		bp_core_redirect( esc_url( $_GET['redirect_to'] ) );
+	else
+		bp_core_redirect( wp_get_referer() );
+}
+add_action( 'bp_actions', 'bp_activity_action_spam_activity' );
+
+/**
+ * Post user/group activity update.
+ *
+ * @since BuddyPress (1.2)
+ *
+ * @uses is_user_logged_in()
+ * @uses bp_is_activity_component()
+ * @uses bp_is_current_action()
+ * @uses check_admin_referer()
+ * @uses apply_filters() To call 'bp_activity_post_update_content' hook.
+ * @uses apply_filters() To call 'bp_activity_post_update_object' hook.
+ * @uses apply_filters() To call 'bp_activity_post_update_item_id' hook.
+ * @uses bp_core_add_message()
+ * @uses bp_core_redirect()
+ * @uses bp_activity_post_update()
+ * @uses groups_post_update()
+ * @uses bp_core_redirect()
+ * @uses apply_filters() To call 'bp_activity_custom_update' hook.
+ *
+ * @return bool False on failure.
+ */
+function bp_activity_action_post_update() {
+
+	// Do not proceed if user is not logged in, not viewing activity, or not posting
+	if ( !is_user_logged_in() || !bp_is_activity_component() || !bp_is_current_action( 'post' ) )
+		return false;
+
+	// Check the nonce
+	check_admin_referer( 'post_update', '_wpnonce_post_update' );
+
+	// Get activity info
+	$content = apply_filters( 'bp_activity_post_update_content', $_POST['whats-new'] );
+
+	if ( ! empty( $_POST['whats-new-post-object'] ) ) {
+		$object = apply_filters( 'bp_activity_post_update_object', $_POST['whats-new-post-object'] );
+	}
+
+	if ( ! empty( $_POST['whats-new-post-in'] ) ) {
+		$item_id = apply_filters( 'bp_activity_post_update_item_id', $_POST['whats-new-post-in'] );
+	}
+
+	// No activity content so provide feedback and redirect
+	if ( empty( $content ) ) {
+		bp_core_add_message( __( 'Please enter some content to post.', 'buddypress' ), 'error' );
+		bp_core_redirect( wp_get_referer() );
+	}
+
+	// No existing item_id
+	if ( empty( $item_id ) ) {
+		$activity_id = bp_activity_post_update( array( 'content' => $content ) );
+
+	// Post to groups object
+	} else if ( 'groups' == $object && bp_is_active( 'groups' ) ) {
+		if ( (int) $item_id ) {
+			$activity_id = groups_post_update( array( 'content' => $content, 'group_id' => $item_id ) );
+		}
+
+	// Special circumstance so let filters handle it
+	} else {
+		$activity_id = apply_filters( 'bp_activity_custom_update', $object, $item_id, $content );
+	}
+
+	// Provide user feedback
+	if ( !empty( $activity_id ) )
+		bp_core_add_message( __( 'Update Posted!', 'buddypress' ) );
+	else
+		bp_core_add_message( __( 'There was an error when posting your update, please try again.', 'buddypress' ), 'error' );
+
+	// Redirect
+	bp_core_redirect( wp_get_referer() );
+}
+add_action( 'bp_actions', 'bp_activity_action_post_update' );
+
+/**
+ * Post new activity comment.
+ *
+ * @since BuddyPress (1.2)
+ *
+ * @uses is_user_logged_in()
+ * @uses bp_is_activity_component()
+ * @uses bp_is_current_action()
+ * @uses check_admin_referer()
+ * @uses apply_filters() To call 'bp_activity_post_comment_activity_id' hook.
+ * @uses apply_filters() To call 'bp_activity_post_comment_content' hook.
+ * @uses bp_core_add_message()
+ * @uses bp_core_redirect()
+ * @uses bp_activity_new_comment()
+ * @uses wp_get_referer()
+ *
+ * @return bool False on failure.
+ */
+function bp_activity_action_post_comment() {
+
+	if ( !is_user_logged_in() || !bp_is_activity_component() || !bp_is_current_action( 'reply' ) )
+		return false;
+
+	// Check the nonce
+	check_admin_referer( 'new_activity_comment', '_wpnonce_new_activity_comment' );
+
+	$activity_id = apply_filters( 'bp_activity_post_comment_activity_id', $_POST['comment_form_id'] );
+	$content = apply_filters( 'bp_activity_post_comment_content', $_POST['ac_input_' . $activity_id] );
+
+	if ( empty( $content ) ) {
+		bp_core_add_message( __( 'Please do not leave the comment area blank.', 'buddypress' ), 'error' );
+		bp_core_redirect( wp_get_referer() . '#ac-form-' . $activity_id );
+	}
+
+	$comment_id = bp_activity_new_comment( array(
+		'content'     => $content,
+		'activity_id' => $activity_id,
+		'parent_id'   => false
+	));
+
+	if ( !empty( $comment_id ) )
+		bp_core_add_message( __( 'Reply Posted!', 'buddypress' ) );
+	else
+		bp_core_add_message( __( 'There was an error posting that reply, please try again.', 'buddypress' ), 'error' );
+
+	bp_core_redirect( wp_get_referer() . '#ac-form-' . $activity_id );
+}
+add_action( 'bp_actions', 'bp_activity_action_post_comment' );
+
+/**
+ * Mark activity as favorite.
+ *
+ * @since BuddyPress (1.2)
+ *
+ * @uses is_user_logged_in()
+ * @uses bp_is_activity_component()
+ * @uses bp_is_current_action()
+ * @uses check_admin_referer()
+ * @uses bp_activity_add_user_favorite()
+ * @uses bp_action_variable()
+ * @uses bp_core_add_message()
+ * @uses bp_core_redirect()
+ * @uses wp_get_referer()
+ *
+ * @return bool False on failure.
+ */
+function bp_activity_action_mark_favorite() {
+
+	if ( !is_user_logged_in() || !bp_is_activity_component() || !bp_is_current_action( 'favorite' ) )
+		return false;
+
+	// Check the nonce
+	check_admin_referer( 'mark_favorite' );
+
+	if ( bp_activity_add_user_favorite( bp_action_variable( 0 ) ) )
+		bp_core_add_message( __( 'Activity marked as favorite.', 'buddypress' ) );
+	else
+		bp_core_add_message( __( 'There was an error marking that activity as a favorite, please try again.', 'buddypress' ), 'error' );
+
+	bp_core_redirect( wp_get_referer() . '#activity-' . bp_action_variable( 0 ) );
+}
+add_action( 'bp_actions', 'bp_activity_action_mark_favorite' );
+
+/**
+ * Remove activity from favorites.
+ *
+ * @since BuddyPress (1.2)
+ *
+ * @uses is_user_logged_in()
+ * @uses bp_is_activity_component()
+ * @uses bp_is_current_action()
+ * @uses check_admin_referer()
+ * @uses bp_activity_remove_user_favorite()
+ * @uses bp_action_variable()
+ * @uses bp_core_add_message()
+ * @uses bp_core_redirect()
+ * @uses wp_get_referer()
+ *
+ * @return bool False on failure.
+ */
+function bp_activity_action_remove_favorite() {
+
+	if ( ! is_user_logged_in() || ! bp_is_activity_component() || ! bp_is_current_action( 'unfavorite' ) )
+		return false;
+
+	// Check the nonce
+	check_admin_referer( 'unmark_favorite' );
+
+	if ( bp_activity_remove_user_favorite( bp_action_variable( 0 ) ) )
+		bp_core_add_message( __( 'Activity removed as favorite.', 'buddypress' ) );
+	else
+		bp_core_add_message( __( 'There was an error removing that activity as a favorite, please try again.', 'buddypress' ), 'error' );
+
+	bp_core_redirect( wp_get_referer() . '#activity-' . bp_action_variable( 0 ) );
+}
+add_action( 'bp_actions', 'bp_activity_action_remove_favorite' );
+
+/**
+ * Load the sitewide activity feed.
+ *
+ * @since BuddyPress (1.0)
+ *
+ * @global object $bp BuddyPress global settings
+ * @uses bp_is_activity_component()
+ * @uses bp_is_current_action()
+ * @uses bp_is_user()
+ * @uses status_header()
+ *
+ * @return bool False on failure.
+ */
+function bp_activity_action_sitewide_feed() {
+	global $bp;
+
+	if ( ! bp_is_activity_component() || ! bp_is_current_action( 'feed' ) || bp_is_user() || ! empty( $bp->groups->current_group ) )
+		return false;
+
+	// setup the feed
+	buddypress()->activity->feed = new BP_Activity_Feed( array(
+		'id'            => 'sitewide',
+
+		/* translators: Sitewide activity RSS title - "[Site Name] | Site Wide Activity" */
+		'title'         => sprintf( __( '%s | Site Wide Activity', 'buddypress' ), bp_get_site_name() ),
+
+		'link'          => bp_get_activity_directory_permalink(),
+		'description'   => __( 'Activity feed for the entire site.', 'buddypress' ),
+		'activity_args' => 'display_comments=threaded'
+	) );
+}
+add_action( 'bp_actions', 'bp_activity_action_sitewide_feed' );
+
+/**
+ * Load a user's personal activity feed.
+ *
+ * @since BuddyPress (1.0)
+ *
+ * @uses bp_is_user_activity()
+ * @uses bp_is_current_action()
+ * @uses status_header()
+ *
+ * @return bool False on failure.
+ */
+function bp_activity_action_personal_feed() {
+	if ( ! bp_is_user_activity() || ! bp_is_current_action( 'feed' ) ) {
+		return false;
+	}
+
+	// setup the feed
+	buddypress()->activity->feed = new BP_Activity_Feed( array(
+		'id'            => 'personal',
+
+		/* translators: Personal activity RSS title - "[Site Name] | [User Display Name] | Activity" */
+		'title'         => sprintf( __( '%1$s | %2$s | Activity', 'buddypress' ), bp_get_site_name(), bp_get_displayed_user_fullname() ),
+
+		'link'          => trailingslashit( bp_displayed_user_domain() . bp_get_activity_slug() ),
+		'description'   => sprintf( __( 'Activity feed for %s.', 'buddypress' ), bp_get_displayed_user_fullname() ),
+		'activity_args' => 'user_id=' . bp_displayed_user_id()
+	) );
+}
+add_action( 'bp_actions', 'bp_activity_action_personal_feed' );
+
+/**
+ * Load a user's friends' activity feed.
+ *
+ * @since BuddyPress (1.0)
+ *
+ * @uses bp_is_active()
+ * @uses bp_is_user_activity()
+ * @uses bp_is_current_action()
+ * @uses bp_get_friends_slug()
+ * @uses bp_is_action_variable()
+ * @uses status_header()
+ *
+ * @return bool False on failure.
+ */
+function bp_activity_action_friends_feed() {
+	if ( ! bp_is_active( 'friends' ) || ! bp_is_user_activity() || ! bp_is_current_action( bp_get_friends_slug() ) || ! bp_is_action_variable( 'feed', 0 ) ) {
+		return false;
+	}
+
+	// setup the feed
+	buddypress()->activity->feed = new BP_Activity_Feed( array(
+		'id'            => 'friends',
+
+		/* translators: Friends activity RSS title - "[Site Name] | [User Display Name] | Friends Activity" */
+		'title'         => sprintf( __( '%1$s | %2$s | Friends Activity', 'buddypress' ), bp_get_site_name(), bp_get_displayed_user_fullname() ),
+
+		'link'          => trailingslashit( bp_displayed_user_domain() . bp_get_activity_slug() . '/' . bp_get_friends_slug() ),
+		'description'   => sprintf( __( "Activity feed for %s's friends.", 'buddypress' ), bp_get_displayed_user_fullname() ),
+		'activity_args' => 'scope=friends'
+	) );
+}
+add_action( 'bp_actions', 'bp_activity_action_friends_feed' );
+
+/**
+ * Load the activity feed for a user's groups.
+ *
+ * @since BuddyPress (1.2)
+ *
+ * @uses bp_is_active()
+ * @uses bp_is_user_activity()
+ * @uses bp_is_current_action()
+ * @uses bp_get_groups_slug()
+ * @uses bp_is_action_variable()
+ * @uses status_header()
+ *
+ * @return bool False on failure.
+ */
+function bp_activity_action_my_groups_feed() {
+	if ( ! bp_is_active( 'groups' ) || ! bp_is_user_activity() || ! bp_is_current_action( bp_get_groups_slug() ) || ! bp_is_action_variable( 'feed', 0 ) ) {
+		return false;
+	}
+
+	// get displayed user's group IDs
+	$groups    = groups_get_user_groups();
+	$group_ids = implode( ',', $groups['groups'] );
+
+	// setup the feed
+	buddypress()->activity->feed = new BP_Activity_Feed( array(
+		'id'            => 'mygroups',
+
+		/* translators: Member groups activity RSS title - "[Site Name] | [User Display Name] | Groups Activity" */
+		'title'         => sprintf( __( '%1$s | %2$s | Group Activity', 'buddypress' ), bp_get_site_name(), bp_get_displayed_user_fullname() ),
+
+		'link'          => trailingslashit( bp_displayed_user_domain() . bp_get_activity_slug() . '/' . bp_get_groups_slug() ),
+		'description'   => sprintf( __( "Public group activity feed of which %s is a member of.", 'buddypress' ), bp_get_displayed_user_fullname() ),
+		'activity_args' => array(
+			'object'           => buddypress()->groups->id,
+			'primary_id'       => $group_ids,
+			'display_comments' => 'threaded'
+		)
+	) );
+}
+add_action( 'bp_actions', 'bp_activity_action_my_groups_feed' );
+
+/**
+ * Load a user's @mentions feed.
+ *
+ * @since BuddyPress (1.2)
+ *
+ * @uses bp_is_user_activity()
+ * @uses bp_is_current_action()
+ * @uses bp_is_action_variable()
+ * @uses status_header()
+ *
+ * @return bool False on failure.
+ */
+function bp_activity_action_mentions_feed() {
+	if ( ! bp_activity_do_mentions() ) {
+		return false;
+	}
+
+	if ( !bp_is_user_activity() || ! bp_is_current_action( 'mentions' ) || ! bp_is_action_variable( 'feed', 0 ) ) {
+		return false;
+	}
+
+	// setup the feed
+	buddypress()->activity->feed = new BP_Activity_Feed( array(
+		'id'            => 'mentions',
+
+		/* translators: User mentions activity RSS title - "[Site Name] | [User Display Name] | Mentions" */
+		'title'         => sprintf( __( '%1$s | %2$s | Mentions', 'buddypress' ), bp_get_site_name(), bp_get_displayed_user_fullname() ),
+
+		'link'          => bp_displayed_user_domain() . bp_get_activity_slug() . '/mentions/',
+		'description'   => sprintf( __( "Activity feed mentioning %s.", 'buddypress' ), bp_get_displayed_user_fullname() ),
+		'activity_args' => array(
+			'search_terms' => '@' . bp_core_get_username( bp_displayed_user_id() )
+		)
+	) );
+}
+add_action( 'bp_actions', 'bp_activity_action_mentions_feed' );
+
+/**
+ * Load a user's favorites feed.
+ *
+ * @since BuddyPress (1.2)
+ *
+ * @uses bp_is_user_activity()
+ * @uses bp_is_current_action()
+ * @uses bp_is_action_variable()
+ * @uses status_header()
+ *
+ * @return bool False on failure.
+ */
+function bp_activity_action_favorites_feed() {
+	if ( ! bp_is_user_activity() || ! bp_is_current_action( 'favorites' ) || ! bp_is_action_variable( 'feed', 0 ) ) {
+		return false;
+	}
+
+	// get displayed user's favorite activity IDs
+	$favs = bp_activity_get_user_favorites( bp_displayed_user_id() );
+	$fav_ids = implode( ',', (array) $favs );
+
+	// setup the feed
+	buddypress()->activity->feed = new BP_Activity_Feed( array(
+		'id'            => 'favorites',
+
+		/* translators: User activity favorites RSS title - "[Site Name] | [User Display Name] | Favorites" */
+		'title'         => sprintf( __( '%1$s | %2$s | Favorites', 'buddypress' ), bp_get_site_name(), bp_get_displayed_user_fullname() ),
+
+		'link'          => bp_displayed_user_domain() . bp_get_activity_slug() . '/favorites/',
+		'description'   => sprintf( __( "Activity feed of %s's favorites.", 'buddypress' ), bp_get_displayed_user_fullname() ),
+		'activity_args' => 'include=' . $fav_ids
+	) );
+}
+add_action( 'bp_actions', 'bp_activity_action_favorites_feed' );
+
+/**
+ * Loads Akismet filtering for activity.
+ *
+ * @since BuddyPress (1.6)
+ *
+ * @global object $bp BuddyPress global settings
+ */
+function bp_activity_setup_akismet() {
+	global $bp;
+
+	// Bail if Akismet is not active
+	if ( ! defined( 'AKISMET_VERSION' ) )
+		return;
+
+	// Bail if no Akismet key is set
+	if ( ! bp_get_option( 'wordpress_api_key' ) && ! defined( 'WPCOM_API_KEY' ) )
+		return;
+
+	// Bail if BuddyPress Activity Akismet support has been disabled by another plugin
+	if ( ! apply_filters( 'bp_activity_use_akismet', bp_is_akismet_active() ) )
+		return;
+
+	// Instantiate Akismet for BuddyPress
+	$bp->activity->akismet = new BP_Akismet();
+}
Index: /tags/1.9/bp-activity/bp-activity-admin.php
===================================================================
--- /tags/1.9/bp-activity/bp-activity-admin.php	(revision 7684)
+++ /tags/1.9/bp-activity/bp-activity-admin.php	(revision 7684)
@@ -0,0 +1,1457 @@
+<?php
+/**
+ * BuddyPress Activity component admin screen.
+ *
+ * Props to WordPress core for the Comments admin screen, and its contextual
+ * help text, on which this implementation is heavily based.
+ *
+ * @package BuddyPress
+ * @since BuddyPress (1.6.0)
+ * @subpackage Activity
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+// Include WP's list table class
+if ( !class_exists( 'WP_List_Table' ) ) require( ABSPATH . 'wp-admin/includes/class-wp-list-table.php' );
+
+// per_page screen option. Has to be hooked in extremely early.
+if ( is_admin() && ! empty( $_REQUEST['page'] ) && 'bp-activity' == $_REQUEST['page'] )
+	add_filter( 'set-screen-option', 'bp_activity_admin_screen_options', 10, 3 );
+
+/**
+ * Register the Activity component admin screen.
+ *
+ * @since BuddyPress (1.6)
+ */
+function bp_activity_add_admin_menu() {
+
+	// Add our screen
+	$hook = add_menu_page(
+		__( 'Activity', 'buddypress' ),
+		__( 'Activity', 'buddypress' ),
+		'bp_moderate',
+		'bp-activity',
+		'bp_activity_admin',
+		'div'
+	);
+
+	// Hook into early actions to load custom CSS and our init handler.
+	add_action( "load-$hook", 'bp_activity_admin_load' );
+}
+add_action( bp_core_admin_hook(), 'bp_activity_add_admin_menu' );
+
+/**
+ * Add activity component to custom menus array.
+ *
+ * Several BuddyPress components have top-level menu items in the Dashboard,
+ * which all appear together in the middle of the Dashboard menu. This function
+ * adds the Activity page to the array of these menu items.
+ *
+ * @since BuddyPress (1.7.0)
+ *
+ * @param array $custom_menus The list of top-level BP menu items.
+ * @return array $custom_menus List of top-level BP menu items, with Activity added
+ */
+function bp_activity_admin_menu_order( $custom_menus = array() ) {
+	array_push( $custom_menus, 'bp-activity' );
+	return $custom_menus;
+}
+add_filter( 'bp_admin_menu_order', 'bp_activity_admin_menu_order' );
+
+/**
+ * AJAX receiver for Activity replies via the admin screen.
+ *
+ * Processes requests to add new activity comments, and echoes HTML for a new
+ * table row.
+ *
+ * @since BuddyPress (1.6.0)
+ */
+function bp_activity_admin_reply() {
+	// Check nonce
+	check_ajax_referer( 'bp-activity-admin-reply', '_ajax_nonce-bp-activity-admin-reply' );
+
+	$parent_id = ! empty( $_REQUEST['parent_id'] ) ? (int) $_REQUEST['parent_id'] : 0;
+	$root_id   = ! empty( $_REQUEST['root_id'] )   ? (int) $_REQUEST['root_id']   : 0;
+
+	// $parent_id is required
+	if ( empty( $parent_id ) )
+		die( '-1' );
+
+	// If $root_id not set (e.g. for root items), use $parent_id
+	if ( empty( $root_id ) )
+		$root_id = $parent_id;
+
+	// Check that a reply has been entered
+	if ( empty( $_REQUEST['content'] ) )
+		die( __( 'ERROR: Please type a reply.', 'buddypress' ) );
+
+	// Check parent activity exists
+	$parent_activity = new BP_Activity_Activity( $parent_id );
+	if ( empty( $parent_activity->component ) )
+		die( __( 'ERROR: The item you are trying to reply to cannot be found, or it has been deleted.', 'buddypress' ) );
+
+	// @todo: Check if user is allowed to create new activity items
+	// if ( ! current_user_can( 'bp_new_activity' ) )
+	if ( ! current_user_can( 'bp_moderate' ) )
+		die( '-1' );
+
+	// Add new activity comment
+	$new_activity_id = bp_activity_new_comment( array(
+		'activity_id' => $root_id,              // ID of the root activity item
+		'content'     => $_REQUEST['content'],
+		'parent_id'   => $parent_id,            // ID of a parent comment
+	) );
+
+	// Fetch the new activity item, as we need it to create table markup to return
+	$new_activity = new BP_Activity_Activity( $new_activity_id );
+
+	// This needs to be set for the BP_Activity_List_Table constructor to work
+	set_current_screen( 'toplevel_page_bp-activity' );
+
+	// Set up an output buffer
+	ob_start();
+	$list_table = new BP_Activity_List_Table();
+	$list_table->single_row( (array) $new_activity );
+
+	// Get table markup
+	$response =  array(
+		'data'     => ob_get_contents(),
+		'id'       => $new_activity_id,
+		'position' => -1,
+		'what'     => 'bp_activity',
+	);
+	ob_end_clean();
+
+	// Send response
+	$r = new WP_Ajax_Response();
+	$r->add( $response );
+	$r->send();
+
+	exit();
+}
+add_action( 'wp_ajax_bp-activity-admin-reply', 'bp_activity_admin_reply' );
+
+/**
+ * Handle save/update of screen options for the Activity component admin screen.
+ *
+ * @since BuddyPress (1.6.0)
+ *
+ * @param string $value Will always be false unless another plugin filters it
+ *        first.
+ * @param string $option Screen option name.
+ * @param string $new_value Screen option form value.
+ * @return string Option value. False to abandon update.
+ */
+function bp_activity_admin_screen_options( $value, $option, $new_value ) {
+	if ( 'toplevel_page_bp_activity_per_page' != $option && 'toplevel_page_bp_activity_network_per_page' != $option )
+		return $value;
+
+	// Per page
+	$new_value = (int) $new_value;
+	if ( $new_value < 1 || $new_value > 999 )
+		return $value;
+
+	return $new_value;
+}
+
+/**
+ * Hide the advanced edit meta boxes by default, so we don't clutter the screen.
+ *
+ * @since BuddyPress (1.6.0)
+ *
+ * @param WP_Screen $screen Screen identifier.
+ * @return array Hidden Meta Boxes.
+ */
+function bp_activity_admin_edit_hidden_metaboxes( $hidden, $screen ) {
+	if ( empty( $screen->id ) || 'toplevel_page_bp-activity' != $screen->id && 'toplevel_page_bp-activity_network' != $screen->id )
+		return $hidden;
+
+	// Hide the primary link meta box by default
+	$hidden  = array_merge( (array) $hidden, array( 'bp_activity_itemids', 'bp_activity_link', 'bp_activity_type', 'bp_activity_userid', ) );
+
+	return apply_filters( 'bp_hide_meta_boxes', array_unique( $hidden ), $screen );
+}
+add_filter( 'default_hidden_meta_boxes', 'bp_activity_admin_edit_hidden_metaboxes', 10, 2 );
+
+/**
+ * Set up the Activity admin page.
+ *
+ * Does the following:
+ *   - Register contextual help and screen options for this admin page.
+ *   - Enqueues scripts and styles
+ *   - Catches POST and GET requests related to Activity
+ *
+ * @since BuddyPress (1.6.0)
+ *
+ * @global object $bp BuddyPress global settings.
+ * @global BP_Activity_List_Table $bp_activity_list_table Activity screen list table.
+ */
+function bp_activity_admin_load() {
+	global $bp, $bp_activity_list_table;
+
+	// Decide whether to load the dev version of the CSS and JavaScript
+	$min = ( defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ) ? '' : 'min.';
+
+	$doaction = bp_admin_list_table_current_bulk_action();
+
+	// Call an action for plugins to hook in early
+	do_action( 'bp_activity_admin_load', $doaction );
+
+	// Edit screen
+	if ( 'edit' == $doaction && ! empty( $_GET['aid'] ) ) {
+		// columns screen option
+		add_screen_option( 'layout_columns', array( 'default' => 2, 'max' => 2, ) );
+
+		get_current_screen()->add_help_tab( array(
+			'id'      => 'bp-activity-edit-overview',
+			'title'   => __( 'Overview', 'buddypress' ),
+			'content' =>
+				'<p>' . __( 'You edit activities made on your site similar to the way you edit a comment. This is useful if you need to change which page the activity links to, or when you notice that the author has made a typographical error.', 'buddypress' ) . '</p>' .
+				'<p>' . __( 'The two big editing areas for the activity title and content are fixed in place, but you can reposition all the other boxes using drag and drop, and can minimize or expand them by clicking the title bar of each box. Use the Screen Options tab to unhide more boxes (Primary Item/Secondary Item, Link, Type, Author ID) or to choose a 1- or 2-column layout for this screen.', 'buddypress' ) . '</p>' .
+				'<p>' . __( 'You can also moderate the activity from this screen using the Status box, where you can also change the timestamp of the activity.', 'buddypress' ) . '</p>'
+		) );
+
+		get_current_screen()->add_help_tab( array(
+			'id'      => 'bp-activity-edit-advanced',
+			'title'   => __( 'Item, Link, Type', 'buddypress' ),
+			'content' =>
+				'<p>' . __( '<strong>Primary Item/Secondary Item</strong> - These identify the object that created the activity. For example, the fields could reference a comment left on a specific site. Some types of activity may only use one, or none, of these fields.', 'buddypress' ) . '</p>' .
+				'<p>' . __( '<strong>Link</strong> - Activity generated by posts and comments, forum topics and replies, and some plugins, uses the link field for a permalink back to the content item. Some types of activity may not use this field, even if it has been set.', 'buddypress' ) . '</p>' .
+				'<p>' . __( '<strong>Type</strong> - Each distinct kind of activity has its own type. For example, <code>created_group</code> is used when a group is created and <code>joined_group</code> is used when a user joins a group.', 'buddypress' ) . '</p>' .
+				'<p>' . __( 'For information about when and how BuddyPress uses all of these settings, see the Managing Activity link in the panel to the side.', 'buddypress' ) . '</p>'
+		) );
+
+		// Help panel - sidebar links
+		get_current_screen()->set_help_sidebar(
+			'<p><strong>' . __( 'For more information:', 'buddypress' ) . '</strong></p>' .
+			'<p>' . __( '<a href="http://codex.buddypress.org/buddypress-site-administration/managing-activity/">Managing Activity</a>', 'buddypress' ) . '</p>' .
+			'<p>' . __( '<a href="http://buddypress.org/support/">Support Forums</a>', 'buddypress' ) . '</p>'
+		);
+
+		// Register metaboxes for the edit screen.
+		add_meta_box( 'submitdiv',           _x( 'Status', 'activity admin edit screen', 'buddypress' ), 'bp_activity_admin_edit_metabox_status', get_current_screen()->id, 'side', 'core' );
+		add_meta_box( 'bp_activity_itemids', _x( 'Primary Item/Secondary Item', 'activity admin edit screen', 'buddypress' ), 'bp_activity_admin_edit_metabox_itemids', get_current_screen()->id, 'normal', 'core' );
+		add_meta_box( 'bp_activity_link',    _x( 'Link', 'activity admin edit screen', 'buddypress' ), 'bp_activity_admin_edit_metabox_link', get_current_screen()->id, 'normal', 'core' );
+		add_meta_box( 'bp_activity_type',    _x( 'Type', 'activity admin edit screen', 'buddypress' ), 'bp_activity_admin_edit_metabox_type', get_current_screen()->id, 'normal', 'core' );
+		add_meta_box( 'bp_activity_userid',  _x( 'Author ID', 'activity admin edit screen', 'buddypress' ), 'bp_activity_admin_edit_metabox_userid', get_current_screen()->id, 'normal', 'core' );
+
+		// Enqueue javascripts
+		wp_enqueue_script( 'postbox' );
+		wp_enqueue_script( 'dashboard' );
+		wp_enqueue_script( 'comment' );
+
+	// Index screen
+	} else {
+		// Create the Activity screen list table
+		$bp_activity_list_table = new BP_Activity_List_Table();
+
+		// per_page screen option
+		add_screen_option( 'per_page', array( 'label' => _x( 'Activity', 'Activity items per page (screen options)', 'buddypress' )) );
+
+		// Help panel - overview text
+		get_current_screen()->add_help_tab( array(
+			'id'      => 'bp-activity-overview',
+			'title'   => __( 'Overview', 'buddypress' ),
+			'content' =>
+				'<p>' . __( 'You can manage activities made on your site similar to the way you manage comments and other content. This screen is customizable in the same ways as other management screens, and you can act on activities using the on-hover action links or the Bulk Actions.', 'buddypress' ) . '</p>' .
+				'<p>' . __( 'There are many different types of activities. Some are generated automatically by BuddyPress and other plugins, and some are entered directly by a user in the form of status update. To help manage the different activity types, use the filter dropdown box to switch between them.', 'buddypress' ) . '</p>'
+		) );
+
+		// Help panel - moderation text
+		get_current_screen()->add_help_tab( array(
+			'id'		=> 'bp-activity-moderating',
+			'title'		=> __( 'Moderating Activity', 'buddypress' ),
+			'content'	=>
+				'<p>' . __( 'In the <strong>Activity</strong> column, above each activity it says &#8220;Submitted on,&#8221; followed by the date and time the activity item was generated on your site. Clicking on the date/time link will take you to that activity on your live site. Hovering over any activity gives you options to reply, edit, spam mark, or delete that activity.', 'buddypress' ) . '</p>' .
+				'<p>' . __( "In the <strong>In Response To</strong> column, if the activity was in reply to another activity, it shows that activity's author's picture and name, and a link to that activity on your live site. If there is a small bubble, the number in it shows how many other activities are related to this one; these are usually comments. Clicking the bubble will filter the activity screen to show only related activity items.", 'buddypress' ) . '</p>'
+		) );
+
+		// Help panel - sidebar links
+		get_current_screen()->set_help_sidebar(
+			'<p><strong>' . __( 'For more information:', 'buddypress' ) . '</strong></p>' .
+			'<p>' . __( '<a href="http://buddypress.org/support/">Support Forums</a>', 'buddypress' ) . '</p>'
+		);
+	}
+
+	// Enqueue CSS and JavaScript
+	wp_enqueue_script( 'bp_activity_admin_js', BP_PLUGIN_URL . "bp-activity/admin/js/admin.{$min}js",   array( 'jquery', 'wp-ajax-response' ), bp_get_version(), true );
+	wp_enqueue_style( 'bp_activity_admin_css', BP_PLUGIN_URL . "bp-activity/admin/css/admin.{$min}css", array(),                               bp_get_version()       );
+
+	// Handle spam/un-spam/delete of activities
+	if ( !empty( $doaction ) && ! in_array( $doaction, array( '-1', 'edit', 'save', ) ) ) {
+
+		// Build redirection URL
+		$redirect_to = remove_query_arg( array( 'aid', 'deleted', 'error', 'spammed', 'unspammed', ), wp_get_referer() );
+		$redirect_to = add_query_arg( 'paged', $bp_activity_list_table->get_pagenum(), $redirect_to );
+
+		// Get activity IDs
+		$activity_ids = array_map( 'absint', (array) $_REQUEST['aid'] );
+
+		// Call a filter for plugins to modify the requested activities to load
+		$activity_ids = apply_filters( 'bp_activity_admin_action_activity_ids', $activity_ids );
+
+		// Is this a bulk request?
+		if ( 'bulk_' == substr( $doaction, 0, 5 ) && ! empty( $_REQUEST['aid'] ) ) {
+			// Check this is a valid form submission
+			check_admin_referer( 'bulk-activities' );
+
+			// Trim 'bulk_' off the action name to avoid duplicating a ton of code
+			$doaction = substr( $doaction, 5 );
+
+		// This is a request to delete, spam, or un-spam, a single item.
+		} elseif ( !empty( $_REQUEST['aid'] ) ) {
+
+			// Check this is a valid form submission
+			check_admin_referer( 'spam-activity_' . $activity_ids[0] );
+		}
+
+		// Initialise counters for how many of each type of item we perform an action on
+		$deleted = $spammed = $unspammed = 0;
+
+		// Store any errors that occurs when updating the database items
+		$errors = array();
+
+		// "We'd like to shoot the monster, could you move, please?"
+		foreach ( $activity_ids as $activity_id ) {
+			// @todo: Check the permissions on each
+			//if ( ! current_user_can( 'bp_edit_activity', $activity_id ) )
+			//	continue;
+
+			// Get the activity from the database
+			$activity = new BP_Activity_Activity( $activity_id );
+			if ( empty( $activity->component ) ) {
+				$errors[] = $activity_id;
+				continue;
+			}
+
+			switch ( $doaction ) {
+				case 'delete' :
+					if ( 'activity_comment' == $activity->type )
+						bp_activity_delete_comment( $activity->item_id, $activity->id );
+					else
+						bp_activity_delete( array( 'id' => $activity->id ) );
+
+					$deleted++;
+					break;
+
+				case 'ham' :
+					/**
+					 * Remove moderation and blacklist checks in case we want to ham an activity
+					 * which contains one of these listed keys.
+					 */
+					remove_action( 'bp_activity_before_save', 'bp_activity_check_moderation_keys', 2, 1 );
+					remove_action( 'bp_activity_before_save', 'bp_activity_check_blacklist_keys',  2, 1 );
+
+					bp_activity_mark_as_ham( $activity );
+					$result = $activity->save();
+
+					// Check for any error during activity save
+					if ( ! $result )
+						$errors[] = $activity->id;
+					else
+						$unspammed++;
+					break;
+
+				case 'spam' :
+					bp_activity_mark_as_spam( $activity );
+					$result = $activity->save();
+
+					// Check for any error during activity save
+					if ( ! $result )
+						$errors[] = $activity->id;
+					else
+						$spammed++;
+					break;
+
+				default:
+					break;
+			}
+
+			// Release memory
+			unset( $activity );
+		}
+
+		// Call actions for plugins to do something before we redirect
+		do_action( 'bp_activity_admin_action_after', array( $spammed, $unspammed, $deleted, $errors ), $redirect_to, $activity_ids );
+
+		// Add arguments to the redirect URL so that on page reload, we can easily display what we've just done.
+		if ( $spammed )
+			$redirect_to = add_query_arg( 'spammed', $spammed, $redirect_to );
+
+		if ( $unspammed )
+			$redirect_to = add_query_arg( 'unspammed', $unspammed, $redirect_to );
+
+		if ( $deleted )
+			$redirect_to = add_query_arg( 'deleted', $deleted, $redirect_to );
+
+		// If an error occurred, pass back the activity ID that failed
+		if ( ! empty( $errors ) )
+			$redirect_to = add_query_arg( 'error', implode ( ',', array_map( 'absint', $errors ) ), $redirect_to );
+
+		// Redirect
+		wp_redirect( apply_filters( 'bp_activity_admin_action_redirect', $redirect_to ) );
+		exit;
+
+
+	// Save the edit
+	} elseif ( $doaction && 'save' == $doaction ) {
+		// Build redirection URL
+		$redirect_to = remove_query_arg( array( 'action', 'aid', 'deleted', 'error', 'spammed', 'unspammed', ), $_SERVER['REQUEST_URI'] );
+
+		// Get activity ID
+		$activity_id = (int) $_REQUEST['aid'];
+
+		// Check this is a valid form submission
+		check_admin_referer( 'edit-activity_' . $activity_id );
+
+		// Get the activity from the database
+		$activity = new BP_Activity_Activity( $activity_id );
+
+		// If the activity doesn't exist, just redirect back to the index
+		if ( empty( $activity->component ) ) {
+			wp_redirect( $redirect_to );
+			exit;
+		}
+
+		// Check the form for the updated properties
+
+		// Store any error that occurs when updating the database item
+		$error = 0;
+
+		// Activity spam status
+		$prev_spam_status = $new_spam_status = false;
+		if ( ! empty( $_POST['activity_status'] ) ) {
+			$prev_spam_status = $activity->is_spam;
+			$new_spam_status  = ( 'spam' == $_POST['activity_status'] ) ? true : false;
+		}
+
+		// Activity action
+		if ( isset( $_POST['bp-activities-action'] ) )
+			$activity->action = $_POST['bp-activities-action'];
+
+		// Activity content
+		if ( isset( $_POST['bp-activities-content'] ) )
+			$activity->content = $_POST['bp-activities-content'];
+
+		// Activity primary link
+		if ( ! empty( $_POST['bp-activities-link'] ) )
+			$activity->primary_link = $_POST['bp-activities-link'];
+
+		// Activity user ID
+		if ( ! empty( $_POST['bp-activities-userid'] ) )
+			$activity->user_id = (int) $_POST['bp-activities-userid'];
+
+		// Activity item primary ID
+		if ( isset( $_POST['bp-activities-primaryid'] ) )
+			$activity->item_id = (int) $_POST['bp-activities-primaryid'];
+
+		// Activity item secondary ID
+		if ( isset( $_POST['bp-activities-secondaryid'] ) )
+			$activity->secondary_item_id = (int) $_POST['bp-activities-secondaryid'];
+
+		// Activity type
+		if ( ! empty( $_POST['bp-activities-type'] ) ) {
+			$actions  = array();
+
+			// Walk through the registered actions, and build an array of actions/values.
+			foreach ( $bp->activity->actions as $action ) {
+				$action = array_values( (array) $action );
+
+				for ( $i = 0, $i_count = count( $action ); $i < $i_count; $i++ )
+					$actions[] = $action[$i]['key'];
+			}
+
+			// This was a mis-named activity type from before BP 1.6
+			unset( $actions['friends_register_activity_action'] );
+
+			// Check that the new type is a registered activity type
+			if ( in_array( $_POST['bp-activities-type'], $actions ) )
+				$activity->type = $_POST['bp-activities-type'];
+		}
+
+		// Activity timestamp
+		if ( ! empty( $_POST['aa'] ) && ! empty( $_POST['mm'] ) && ! empty( $_POST['jj'] ) && ! empty( $_POST['hh'] ) && ! empty( $_POST['mn'] ) && ! empty( $_POST['ss'] ) ) {
+			$aa = $_POST['aa'];
+			$mm = $_POST['mm'];
+			$jj = $_POST['jj'];
+			$hh = $_POST['hh'];
+			$mn = $_POST['mn'];
+			$ss = $_POST['ss'];
+			$aa = ( $aa <= 0 ) ? date( 'Y' ) : $aa;
+			$mm = ( $mm <= 0 ) ? date( 'n' ) : $mm;
+			$jj = ( $jj > 31 ) ? 31 : $jj;
+			$jj = ( $jj <= 0 ) ? date( 'j' ) : $jj;
+			$hh = ( $hh > 23 ) ? $hh -24 : $hh;
+			$mn = ( $mn > 59 ) ? $mn -60 : $mn;
+			$ss = ( $ss > 59 ) ? $ss -60 : $ss;
+
+			// Reconstruct the date into a timestamp
+			$gmt_date = sprintf( "%04d-%02d-%02d %02d:%02d:%02d", $aa, $mm, $jj, $hh, $mn, $ss );
+
+			$activity->date_recorded = $gmt_date;
+		}
+
+		// Has the spam status has changed?
+		if ( $new_spam_status != $prev_spam_status ) {
+			if ( $new_spam_status )
+				bp_activity_mark_as_spam( $activity );
+			else
+				bp_activity_mark_as_ham( $activity );
+		}
+
+		// Save
+		$result = $activity->save();
+
+		// Clear the activity stream first page cache, in case this activity's timestamp was changed
+		wp_cache_delete( 'bp_activity_sitewide_front', 'bp' );
+
+		// Check for any error during activity save
+		if ( false === $result )
+			$error = $activity->id;
+
+		// Call actions for plugins to do something before we redirect
+		do_action_ref_array( 'bp_activity_admin_edit_after', array( &$activity, $error ) );
+
+		// If an error occurred, pass back the activity ID that failed
+		if ( $error )
+			$redirect_to = add_query_arg( 'error', (int) $error, $redirect_to );
+		else
+			$redirect_to = add_query_arg( 'updated', (int) $activity->id, $redirect_to );
+
+		// Redirect
+		wp_redirect( apply_filters( 'bp_activity_admin_edit_redirect', $redirect_to ) );
+		exit;
+
+
+	// If a referrer and a nonce is supplied, but no action, redirect back.
+	} elseif ( ! empty( $_GET['_wp_http_referer'] ) ) {
+		wp_redirect( remove_query_arg( array( '_wp_http_referer', '_wpnonce' ), stripslashes( $_SERVER['REQUEST_URI'] ) ) );
+		exit;
+	}
+}
+
+/**
+ * Output the Activity component admin screens.
+ *
+ * @since BuddyPress (1.6.0)
+ */
+function bp_activity_admin() {
+	// Decide whether to load the index or edit screen
+	$doaction = ! empty( $_REQUEST['action'] ) ? $_REQUEST['action'] : '';
+
+	// Display the single activity edit screen
+	if ( 'edit' == $doaction && ! empty( $_GET['aid'] ) )
+		bp_activity_admin_edit();
+
+	// Otherwise, display the Activity index screen
+	else
+		bp_activity_admin_index();
+}
+
+/**
+ * Display the single activity edit screen.
+ *
+ * @since BuddyPress (1.6.0)
+ */
+function bp_activity_admin_edit() {
+
+	// @todo: Check if user is allowed to edit activity items
+	// if ( ! current_user_can( 'bp_edit_activity' ) )
+	if ( ! is_super_admin() )
+		die( '-1' );
+
+	// Get the activity from the database
+	$activity = bp_activity_get( array(
+		'in'               => ! empty( $_REQUEST['aid'] ) ? (int) $_REQUEST['aid'] : 0,
+		'max'              => 1,
+		'show_hidden'      => true,
+		'spam'             => 'all',
+		'display_comments' => 0
+	) );
+
+	if ( ! empty( $activity['activities'][0] ) ) {
+		$activity = $activity['activities'][0];
+
+		// Workaround to use WP's touch_time() without duplicating that function
+		$GLOBALS['comment'] = new stdClass;
+		$GLOBALS['comment']->comment_date = $activity->date_recorded;
+	} else {
+		$activity = '';
+	}
+
+	// Construct URL for form
+	$form_url = remove_query_arg( array( 'action', 'deleted', 'error', 'spammed', 'unspammed', ), $_SERVER['REQUEST_URI'] );
+	$form_url = add_query_arg( 'action', 'save', $form_url );
+
+	// Call an action for plugins to modify the activity before we display the edit form
+	do_action_ref_array( 'bp_activity_admin_edit', array( &$activity ) ); ?>
+
+	<div class="wrap">
+		<?php screen_icon( 'buddypress-activity' ); ?>
+		<h2><?php printf( __( 'Editing Activity (ID #%s)', 'buddypress' ), number_format_i18n( (int) $_REQUEST['aid'] ) ); ?></h2>
+
+		<?php if ( ! empty( $activity ) ) : ?>
+
+			<form action="<?php echo esc_attr( $form_url ); ?>" id="bp-activities-edit-form" method="post">
+				<div id="poststuff">
+
+					<div id="post-body" class="metabox-holder columns-<?php echo 1 == get_current_screen()->get_columns() ? '1' : '2'; ?>">
+						<div id="post-body-content">
+							<div id="postdiv">
+								<div id="bp_activity_action" class="postbox">
+									<h3><?php _e( 'Action', 'buddypress' ); ?></h3>
+									<div class="inside">
+										<?php wp_editor( stripslashes( $activity->action ), 'bp-activities-action', array( 'media_buttons' => false, 'textarea_rows' => 7, 'teeny' => true, 'quicktags' => array( 'buttons' => 'strong,em,link,block,del,ins,img,code,spell,close' ) ) ); ?>
+									</div>
+								</div>
+
+								<div id="bp_activity_content" class="postbox">
+									<h3><?php _e( 'Content', 'buddypress' ); ?></h3>
+									<div class="inside">
+										<?php wp_editor( stripslashes( $activity->content ), 'bp-activities-content', array( 'media_buttons' => false, 'teeny' => true, 'quicktags' => array( 'buttons' => 'strong,em,link,block,del,ins,img,code,spell,close' ) ) ); ?>
+									</div>
+								</div>
+							</div>
+						</div><!-- #post-body-content -->
+
+						<div id="postbox-container-1" class="postbox-container">
+							<?php do_meta_boxes( get_current_screen()->id, 'side', $activity ); ?>
+						</div>
+
+						<div id="postbox-container-2" class="postbox-container">
+							<?php do_meta_boxes( get_current_screen()->id, 'normal', $activity ); ?>
+							<?php do_meta_boxes( get_current_screen()->id, 'advanced', $activity ); ?>
+						</div>
+					</div><!-- #post-body -->
+
+				</div><!-- #poststuff -->
+				<?php wp_nonce_field( 'closedpostboxes', 'closedpostboxesnonce', false ); ?>
+				<?php wp_nonce_field( 'meta-box-order', 'meta-box-order-nonce', false ); ?>
+				<?php wp_nonce_field( 'edit-activity_' . $activity->id ); ?>
+			</form>
+
+		<?php else : ?>
+			<p><?php printf( __( 'No activity found with this ID. <a href="%s">Go back and try again</a>.', 'buddypress' ), esc_url( bp_get_admin_url( 'admin.php?page=bp-activity' ) ) ); ?></p>
+		<?php endif; ?>
+
+	</div><!-- .wrap -->
+
+<?php
+}
+
+/**
+ * Status metabox for the Activity admin edit screen.
+ *
+ * @since BuddyPress (1.6.0)
+ *
+ * @param object $item Activity item.
+ */
+function bp_activity_admin_edit_metabox_status( $item ) {
+?>
+
+	<div class="submitbox" id="submitcomment">
+
+		<div id="minor-publishing">
+			<div id="minor-publishing-actions">
+				<div id="preview-action">
+					<a class="button preview" href="<?php echo esc_attr( bp_activity_get_permalink( $item->id, $item ) ); ?>" target="_blank"><?php _e( 'View Activity', 'buddypress' ); ?></a>
+				</div>
+
+				<div class="clear"></div>
+			</div><!-- #minor-publishing-actions -->
+
+			<div id="misc-publishing-actions">
+				<div class="misc-pub-section" id="comment-status-radio">
+					<label class="approved"><input type="radio" name="activity_status" value="ham" <?php checked( $item->is_spam, 0 ); ?>><?php _e( 'Approved', 'buddypress' ); ?></label><br />
+					<label class="spam"><input type="radio" name="activity_status" value="spam" <?php checked( $item->is_spam, 1 ); ?>><?php _e( 'Spam', 'buddypress' ); ?></label>
+				</div>
+
+				<div class="misc-pub-section curtime misc-pub-section-last">
+					<?php
+					// translators: Publish box date format, see http://php.net/date
+					$datef = __( 'M j, Y @ G:i', 'buddypress' );
+					$date  = date_i18n( $datef, strtotime( $item->date_recorded ) );
+					?>
+					<span id="timestamp"><?php printf( __( 'Submitted on: <strong>%1$s</strong>', 'buddypress' ), $date ); ?></span>&nbsp;<a href="#edit_timestamp" class="edit-timestamp hide-if-no-js" tabindex='4'><?php _e( 'Edit', 'buddypress' ); ?></a>
+
+					<div id='timestampdiv' class='hide-if-js'>
+						<?php touch_time( 1, 0, 5 ); ?>
+					</div><!-- #timestampdiv -->
+				</div>
+			</div> <!-- #misc-publishing-actions -->
+
+			<div class="clear"></div>
+		</div><!-- #minor-publishing -->
+
+		<div id="major-publishing-actions">
+			<div id="publishing-action">
+				<?php submit_button( __( 'Update', 'buddypress' ), 'primary', 'save', false, array( 'tabindex' => '4' ) ); ?>
+			</div>
+			<div class="clear"></div>
+		</div><!-- #major-publishing-actions -->
+
+	</div><!-- #submitcomment -->
+
+<?php
+}
+
+/**
+ * Primary link metabox for the Activity admin edit screen.
+ *
+ * @since BuddyPress (1.6.0)
+ *
+ * @param object $item Activity item.
+ */
+function bp_activity_admin_edit_metabox_link( $item ) {
+?>
+
+	<label class="screen-reader-text" for="bp-activities-link"><?php _e( 'Link', 'buddypress' ); ?></label>
+	<input type="url" name="bp-activities-link" value="<?php echo esc_url( $item->primary_link ); ?>" />
+	<p><?php _e( 'Activity generated by posts and comments, forum topics and replies, and some plugins, uses the link field for a permalink back to the content item.', 'buddypress' ); ?></p>
+
+<?php
+}
+
+/**
+ * User ID metabox for the Activity admin edit screen.
+ *
+ * @since BuddyPress (1.6.0)
+ *
+ * @param object $item Activity item.
+ */
+function bp_activity_admin_edit_metabox_userid( $item ) {
+?>
+
+	<label class="screen-reader-text" for="bp-activities-userid"><?php _e( 'Author ID', 'buddypress' ); ?></label>
+	<input type="number" name="bp-activities-userid" value="<?php echo esc_attr( $item->user_id ); ?>" min="1" />
+
+<?php
+}
+
+/**
+ * Activity type metabox for the Activity admin edit screen
+ *
+ * @since BuddyPress (1.6.0)
+ *
+ * @global object $bp BuddyPress global settings.
+ *
+ * @param object $item Activity item.
+ */
+function bp_activity_admin_edit_metabox_type( $item ) {
+	global $bp;
+
+	$actions  = array();
+	$selected = $item->type;
+
+	// Walk through the registered actions, and build an array of actions/values.
+	foreach ( $bp->activity->actions as $action ) {
+		$action = array_values( (array) $action );
+
+		for ( $i = 0, $i_count = count( $action ); $i < $i_count; $i++ )
+			$actions[ $action[$i]['key'] ] = $action[$i]['value'];
+	}
+
+	// This was a mis-named activity type from before BP 1.6
+	unset( $actions['friends_register_activity_action'] );
+
+	// Sort array by the human-readable value
+	natsort( $actions ); ?>
+
+	<select name="bp-activities-type">
+		<?php foreach ( $actions as $k => $v ) : ?>
+			<option value="<?php echo esc_attr( $k ); ?>" <?php selected( $k,  $selected ); ?>><?php echo esc_html( $v ); ?></option>
+		<?php endforeach; ?>
+	</select>
+
+<?php
+}
+
+/**
+ * Primary item ID/Secondary item ID metabox for the Activity admin edit screen.
+ *
+ * @since BuddyPress (1.6.0)
+ *
+ * @param object $item Activity item.
+ */
+function bp_activity_admin_edit_metabox_itemids( $item ) {
+?>
+
+	<label for="bp-activities-primaryid"><?php _e( 'Primary Item ID', 'buddypress' ); ?></label>
+	<input type="number" name="bp-activities-primaryid" id="bp-activities-primaryid" value="<?php echo esc_attr( $item->item_id ); ?>" min="0" />
+	<br />
+
+	<label for="bp-activities-secondaryid"><?php _e( 'Secondary Item ID', 'buddypress' ); ?></label>
+	<input type="number" name="bp-activities-secondaryid" id="bp-activities-secondaryid" value="<?php echo esc_attr( $item->secondary_item_id ); ?>" min="0" />
+
+	<p><?php _e( 'These identify the object that created this activity. For example, the fields could reference a pair of site and comment IDs.', 'buddypress' ); ?></p>
+
+<?php
+}
+
+/**
+ * Display the Activity admin index screen, which contains a list of all the activities.
+ *
+ * @since BuddyPress (1.6.0)
+ *
+ * @global BP_Activity_List_Table $bp_activity_list_table Activity screen list
+ *         table.
+ * @global string $plugin_page The current plugin page.
+ */
+function bp_activity_admin_index() {
+	global $bp_activity_list_table, $plugin_page;
+
+	$messages = array();
+
+	// If the user has just made a change to an activity item, build status messages
+	if ( ! empty( $_REQUEST['deleted'] ) || ! empty( $_REQUEST['spammed'] ) || ! empty( $_REQUEST['unspammed'] ) || ! empty( $_REQUEST['error'] ) || ! empty( $_REQUEST['updated'] ) ) {
+		$deleted   = ! empty( $_REQUEST['deleted']   ) ? (int) $_REQUEST['deleted']   : 0;
+		$errors    = ! empty( $_REQUEST['error']     ) ? $_REQUEST['error']           : '';
+		$spammed   = ! empty( $_REQUEST['spammed']   ) ? (int) $_REQUEST['spammed']   : 0;
+		$unspammed = ! empty( $_REQUEST['unspammed'] ) ? (int) $_REQUEST['unspammed'] : 0;
+		$updated   = ! empty( $_REQUEST['updated']   ) ? (int) $_REQUEST['updated']   : 0;
+
+		$errors = array_map( 'absint', explode( ',', $errors ) );
+
+		// Make sure we don't get any empty values in $errors
+		for ( $i = 0, $errors_count = count( $errors ); $i < $errors_count; $i++ ) {
+			if ( 0 === $errors[$i] ) {
+				unset( $errors[$i] );
+			}
+		}
+
+		// Reindex array
+		$errors = array_values( $errors );
+
+		if ( $deleted > 0 )
+			$messages[] = sprintf( _n( '%s activity item has been permanently deleted.', '%s activity items have been permanently deleted.', $deleted, 'buddypress' ), number_format_i18n( $deleted ) );
+
+		if ( ! empty( $errors ) ) {
+			if ( 1 == count( $errors ) ) {
+				$messages[] = sprintf( __( 'An error occurred when trying to update activity ID #%s.', 'buddypress' ), number_format_i18n( $errors[0] ) );
+
+			} else {
+				$error_msg  = __( 'Errors occurred when trying to update these activity items:', 'buddypress' );
+				$error_msg .= '<ul class="activity-errors">';
+
+				// Display each error as a list item
+				foreach ( $errors as $error ) {
+					// Translators: This is a bulleted list of item IDs
+					$error_msg .= '<li>' . sprintf( __( '#%s', 'buddypress' ), number_format_i18n( $error ) ) . '</li>';
+				}
+
+				$error_msg  .= '</ul>';
+				$messages[] = $error_msg;
+			}
+		}
+
+		if ( $spammed > 0 )
+			$messages[] = sprintf( _n( '%s activity item has been successfully spammed.', '%s activity items have been successfully spammed.', $spammed, 'buddypress' ), number_format_i18n( $spammed ) );
+
+		if ( $unspammed > 0 )
+			$messages[] = sprintf( _n( '%s activity item has been successfully unspammed.', '%s activity items have been successfully unspammed.', $unspammed, 'buddypress' ), number_format_i18n( $unspammed ) );
+
+		if ( $updated > 0 )
+			$messages[] = __( 'The activity item has been updated succesfully.', 'buddypress' );
+	}
+
+	// Prepare the activity items for display
+	$bp_activity_list_table->prepare_items();
+
+	// Call an action for plugins to modify the activity before we display the edit form
+	do_action( 'bp_activity_admin_index', $messages ); ?>
+
+	<div class="wrap">
+		<?php screen_icon( 'buddypress-activity' ); ?>
+		<h2>
+			<?php if ( !empty( $_REQUEST['aid'] ) ) : ?>
+				<?php printf( __( 'Activity related to ID #%s', 'buddypress' ), number_format_i18n( (int) $_REQUEST['aid'] ) ); ?>
+			<?php else : ?>
+				<?php _e( 'Activity', 'buddypress' ); ?>
+			<?php endif; ?>
+
+			<?php if ( !empty( $_REQUEST['s'] ) ) : ?>
+				<span class="subtitle"><?php printf( __( 'Search results for &#8220;%s&#8221;', 'buddypress' ), wp_html_excerpt( esc_html( stripslashes( $_REQUEST['s'] ) ), 50 ) ); ?></span>
+			<?php endif; ?>
+		</h2>
+
+		<?php // If the user has just made a change to an activity item, display the status messages ?>
+		<?php if ( !empty( $messages ) ) : ?>
+			<div id="moderated" class="<?php echo ( ! empty( $_REQUEST['error'] ) ) ? 'error' : 'updated'; ?>"><p><?php echo implode( "<br/>\n", $messages ); ?></p></div>
+		<?php endif; ?>
+
+		<?php // Display each activity on its own row ?>
+		<?php $bp_activity_list_table->views(); ?>
+
+		<form id="bp-activities-form" action="" method="get">
+			<?php $bp_activity_list_table->search_box( __( 'Search all Activity', 'buddypress' ), 'bp-activity' ); ?>
+			<input type="hidden" name="page" value="<?php echo esc_attr( $plugin_page ); ?>" />
+			<?php $bp_activity_list_table->display(); ?>
+		</form>
+
+		<?php // This markup is used for the reply form ?>
+		<table style="display: none;">
+			<tr id="bp-activities-container" style="display: none;">
+				<td colspan="4">
+					<form method="get" action="">
+
+						<h5 id="bp-replyhead"><?php _e( 'Reply to Activity', 'buddypress' ); ?></h5>
+						<?php wp_editor( '', 'bp-activities', array( 'dfw' => false, 'media_buttons' => false, 'quicktags' => array( 'buttons' => 'strong,em,link,block,del,ins,img,code,spell,close' ), 'tinymce' => false, ) ); ?>
+
+						<p id="bp-replysubmit" class="submit">
+							<a href="#" class="cancel button-secondary alignleft"><?php _e( 'Cancel', 'buddypress' ); ?></a>
+							<a href="#" class="save button-primary alignright"><?php _e( 'Reply', 'buddypress' ); ?></a>
+
+							<img class="waiting" style="display:none;" src="<?php echo esc_url( bp_get_admin_url( 'images/wpspin_light.gif' ) ); ?>" alt="" />
+							<span class="error" style="display:none;"></span>
+							<br class="clear" />
+						</p>
+
+						<?php wp_nonce_field( 'bp-activity-admin-reply', '_ajax_nonce-bp-activity-admin-reply', false ); ?>
+
+					</form>
+				</td>
+			</tr>
+		</table>
+	</div>
+
+<?php
+}
+
+/**
+ * List table class for the Activity component admin page.
+ *
+ * @since BuddyPress (1.6)
+ */
+class BP_Activity_List_Table extends WP_List_Table {
+
+	/**
+	 * What type of view is being displayed?
+	 *
+	 * e.g. "all", "pending", "approved", "spam"...
+	 *
+	 * @since BuddyPress (1.6.0)
+	 * @var string
+	 */
+	public $view = 'all';
+
+	/**
+	 * How many activity items have been marked as spam.
+	 *
+	 * @since BuddyPress (1.6.0)
+	 * @var int
+	 */
+	public $spam_count = 0;
+
+	/**
+	 * Store activity-to-user-ID mappings for use in the In Response To column.
+	 *
+	 * @since BuddyPress (1.6.0)
+	 * @var array
+	 */
+	protected $activity_user_id = array();
+
+	/**
+	 * Constructor.
+	 *
+	 * @since BuddyPress (1.6.0)
+	 */
+	public function __construct() {
+
+		// Define singular and plural labels, as well as whether we support AJAX.
+		parent::__construct( array(
+			'ajax'     => false,
+			'plural'   => 'activities',
+			'singular' => 'activity',
+			'screen'   => get_current_screen(),
+		) );
+	}
+
+	/**
+	 * Handle filtering of data, sorting, pagination, and any other data manipulation prior to rendering.
+	 *
+	 * @since BuddyPress (1.6.0)
+	 */
+	function prepare_items() {
+
+		// Option defaults
+		$filter           = array();
+		$include_id       = false;
+		$search_terms     = false;
+		$sort             = 'DESC';
+		$spam             = 'ham_only';
+
+		// Set current page
+		$page = $this->get_pagenum();
+
+		// Set per page from the screen options
+		$per_page = $this->get_items_per_page( str_replace( '-', '_', "{$this->screen->id}_per_page" ) );
+
+		// Check if we're on the "Spam" view
+		if ( !empty( $_REQUEST['activity_status'] ) && 'spam' == $_REQUEST['activity_status'] ) {
+			$spam       = 'spam_only';
+			$this->view = 'spam';
+		}
+
+		// Sort order
+		if ( !empty( $_REQUEST['order'] ) && 'desc' != $_REQUEST['order'] )
+			$sort = 'ASC';
+
+		// Order by
+		/*if ( !empty( $_REQUEST['orderby'] ) ) {
+		}*/
+
+		// Filter
+		if ( !empty( $_REQUEST['activity_type'] ) )
+			$filter = array( 'action' => $_REQUEST['activity_type'] );
+
+		// Are we doing a search?
+		if ( !empty( $_REQUEST['s'] ) )
+			$search_terms = $_REQUEST['s'];
+
+		// Check if user has clicked on a specific activity (if so, fetch only that, and any related, activity).
+		if ( !empty( $_REQUEST['aid'] ) )
+			$include_id = (int) $_REQUEST['aid'];
+
+		// Get the spam total (ignoring any search query or filter)
+		$spams = bp_activity_get( array(
+			'display_comments' => 'stream',
+			'show_hidden'      => true,
+			'spam'             => 'spam_only',
+		) );
+		$this->spam_count = $spams['total'];
+		unset( $spams );
+
+		// Get the activities from the database
+		$activities = bp_activity_get( array(
+			'display_comments' => 'stream',
+			'filter'           => $filter,
+			'in'               => $include_id,
+			'page'             => $page,
+			'per_page'         => $per_page,
+			'search_terms'     => $search_terms,
+			'show_hidden'      => true,
+			//'sort'             => $sort,
+			'spam'             => $spam,
+		) );
+
+		// If we're viewing a specific activity, flatten all activites into a single array.
+		if ( $include_id ) {
+			$activities['activities'] = BP_Activity_List_Table::flatten_activity_array( $activities['activities'] );
+			$activities['total']      = count( $activities['activities'] );
+
+			// Sort the array by the activity object's date_recorded value
+			usort( $activities['activities'], create_function( '$a, $b', 'return $a->date_recorded > $b->date_recorded;' ) );
+		}
+
+		// bp_activity_get returns an array of objects; cast these to arrays for WP_List_Table.
+		$new_activities = array();
+		foreach ( $activities['activities'] as $activity_item ) {
+			$new_activities[] = (array) $activity_item;
+
+			// Build an array of activity-to-user ID mappings for better efficency in the In Response To column
+			$this->activity_user_id[$activity_item->id] = $activity_item->user_id;
+		}
+
+		// Set raw data to display
+		$this->items       = $new_activities;
+
+		// Store information needed for handling table pagination
+		$this->set_pagination_args( array(
+			'per_page'    => $per_page,
+			'total_items' => $activities['total'],
+			'total_pages' => ceil( $activities['total'] / $per_page )
+		) );
+
+		// Don't truncate activity items; bp_activity_truncate_entry() needs to be used inside a BP_Activity_Template loop.
+		remove_filter( 'bp_get_activity_content_body', 'bp_activity_truncate_entry', 5 );
+	}
+
+	/**
+	 * Get an array of all the columns on the page.
+	 *
+	 * @since BuddyPress (1.6.0)
+	 *
+	 * @return array Column headers.
+	 */
+	function get_column_info() {
+		$this->_column_headers = array(
+			$this->get_columns(),
+			array(),
+			$this->get_sortable_columns(),
+		);
+
+		return $this->_column_headers;
+	}
+
+	/**
+	 * Display a message on screen when no items are found (e.g. no search matches).
+	 *
+	 * @since BuddyPress (1.6.0)
+	 */
+	function no_items() {
+		_e( 'No activities found.', 'buddypress' );
+	}
+
+	/**
+	 * Output the Activity data table.
+	 *
+	 * @since BuddyPress (1.6.0)
+	*/
+	function display() {
+		extract( $this->_args );
+
+		$this->display_tablenav( 'top' ); ?>
+
+		<table class="<?php echo implode( ' ', $this->get_table_classes() ); ?>" cellspacing="0">
+			<thead>
+				<tr>
+					<?php $this->print_column_headers(); ?>
+				</tr>
+			</thead>
+
+			<tfoot>
+				<tr>
+					<?php $this->print_column_headers( false ); ?>
+				</tr>
+			</tfoot>
+
+			<tbody id="the-comment-list">
+				<?php $this->display_rows_or_placeholder(); ?>
+			</tbody>
+		</table>
+		<?php
+
+		$this->display_tablenav( 'bottom' );
+	}
+
+	/**
+	 * Generate content for a single row of the table.
+	 *
+	 * @since BuddyPress (1.6.0)
+	 *
+	 * @param object $item The current item.
+	 */
+	function single_row( $item ) {
+		static $even = false;
+
+		if ( $even ) {
+			$row_class = ' class="even"';
+		} else {
+			$row_class = ' class="alternate odd"';
+		}
+
+		if ( 'activity_comment' === $item['type'] ) {
+			$root_id = $item['item_id'];
+		} else {
+			$root_id = $item['id'];
+		}
+
+		echo '<tr' . $row_class . ' id="activity-' . esc_attr( $item['id'] ) . '" data-parent_id="' . esc_attr( $item['id'] ) . '" data-root_id="' . esc_attr( $root_id ) . '">';
+		echo $this->single_row_columns( $item );
+		echo '</tr>';
+
+		$even = ! $even;
+	}
+
+	/**
+	 * Get the list of views available on this table (e.g. "all", "spam").
+	 *
+	 * @since BuddyPress (1.6.0)
+	 */
+	function get_views() {
+		$url_base = bp_get_admin_url( 'admin.php?page=bp-activity' ); ?>
+
+		<ul class="subsubsub">
+			<li class="all"><a href="<?php echo esc_attr( esc_url( $url_base ) ); ?>" class="<?php if ( 'spam' != $this->view ) echo 'current'; ?>"><?php _e( 'All', 'buddypress' ); ?></a> |</li>
+			<li class="spam"><a href="<?php echo esc_attr( esc_url( add_query_arg( 'activity_status', 'spam', $url_base ) ) ); ?>" class="<?php if ( 'spam' == $this->view ) echo 'current'; ?>"><?php printf( __( 'Spam <span class="count">(%s)</span>', 'buddypress' ), number_format_i18n( $this->spam_count ) ); ?></a></li>
+
+			<?php do_action( 'bp_activity_list_table_get_views', $url_base, $this->view ); ?>
+		</ul>
+	<?php
+	}
+
+	/**
+	 * Get bulk actions.
+	 *
+	 * @since BuddyPress (1.6.0)
+	 *
+	 * @return array Key/value pairs for the bulk actions dropdown.
+	 */
+	function get_bulk_actions() {
+		$actions = array();
+		$actions['bulk_spam']   = __( 'Mark as Spam', 'buddypress' );
+		$actions['bulk_ham']    = __( 'Not Spam', 'buddypress' );
+		$actions['bulk_delete'] = __( 'Delete Permanently', 'buddypress' );
+
+		return apply_filters( 'bp_activity_list_table_get_bulk_actions', $actions );
+	}
+
+	/**
+	 * Get the table column titles.
+	 *
+	 * @since BuddyPress (1.6.0)
+	 *
+	 * @see WP_List_Table::single_row_columns()
+	 *
+	 * @return array The columns to appear in the Activity list table.
+	 */
+	function get_columns() {
+		return array(
+			'cb'       => '<input name type="checkbox" />',
+			'author'   => __( 'Author', 'buddypress' ),
+			'comment'  => __( 'Activity', 'buddypress' ),
+			'response' => __( 'In Response To', 'buddypress' ),
+		);
+	}
+
+	/**
+	 * Get the column names for sortable columns.
+	 *
+	 * Currently, returns an empty array (no columns are sortable).
+	 *
+	 * @since BuddyPress (1.6.0)
+	 * @todo For this to work, BP_Activity_Activity::get() needs updating
+	 *       to support ordering by specific fields.
+	 *
+	 * @return array The columns that can be sorted on the Activity screen.
+	 */
+	function get_sortable_columns() {
+		return array();
+
+		/*return array(
+			'author' => array( 'activity_author', false ),  // Intentionally not using "=>"
+		);*/
+	}
+
+	/**
+	 * Markup for the "filter" part of the form (i.e. which activity type to display).
+	 *
+	 * @since BuddyPress (1.6.0)
+	 *
+	 * @param string $which 'top' or 'bottom'.
+	 */
+	function extra_tablenav( $which ) {
+		if ( 'bottom' == $which )
+			return;
+
+		$selected = !empty( $_REQUEST['activity_type'] ) ? $_REQUEST['activity_type'] : '';
+
+		// Get all types of activities, and sort alphabetically.
+		$actions  = bp_activity_get_types();
+		natsort( $actions );
+	?>
+
+		<div class="alignleft actions">
+			<select name="activity_type">
+				<option value="" <?php selected( !$selected ); ?>><?php _e( 'Show all activity types', 'buddypress' ); ?></option>
+
+				<?php foreach ( $actions as $k => $v ) : ?>
+					<option value="<?php echo esc_attr( $k ); ?>" <?php selected( $k,  $selected ); ?>><?php echo esc_html( $v ); ?></option>
+				<?php endforeach; ?>
+			</select>
+
+			<?php submit_button( __( 'Filter', 'buddypress' ), 'secondary', false, false, array( 'id' => 'post-query-submit' ) ); ?>
+		</div>
+
+	<?php
+	}
+
+	/**
+	 * Checkbox column markup.
+	 *
+	 * @since BuddyPress (1.6.0)
+	 *
+	 * @see WP_List_Table::single_row_columns()
+	 *
+	 * @param array $item A singular item (one full row).
+	 */
+	function column_cb( $item ) {
+		printf( '<label class="screen-reader-text" for="aid-%1$d">' . __( 'Select activity item %1$d', 'buddypress' ) . '</label><input type="checkbox" name="aid[]" value="%1$d" id="aid-%1$d" />', $item['id'] );
+	}
+
+	/**
+	 * Author column markup.
+	 *
+	 * @since BuddyPress (1.6.0)
+	 *
+	 * @see WP_List_Table::single_row_columns()
+	 *
+	 * @param array $item A singular item (one full row).
+	 */
+	function column_author( $item ) {
+		echo '<strong>' . get_avatar( $item['user_id'], '32' ) . ' ' . bp_core_get_userlink( $item['user_id'] ) . '</strong>';
+	}
+
+	/**
+	 * Content column, and "quick admin" rollover actions.
+	 *
+	 * Called "comment" in the CSS so we can re-use some WP core CSS.
+	 *
+	 * @since BuddyPress (1.6.0)
+	 *
+	 * @see WP_List_Table::single_row_columns()
+	 *
+	 * @param array $item A singular item (one full row).
+	 */
+	function column_comment( $item ) {
+		// Determine what type of item (row) we're dealing with
+		if ( $item['is_spam'] )
+			$item_status = 'spam';
+		else
+			$item_status = 'all';
+
+		// Preorder items: Reply | Edit | Spam | Delete Permanently
+		$actions = array(
+			'reply'  => '',
+			'edit'   => '',
+			'spam'   => '', 'unspam' => '',
+			'delete' => '',
+		);
+
+		// Build actions URLs
+		$base_url   = bp_get_admin_url( 'admin.php?page=bp-activity&amp;aid=' . $item['id'] );
+		$spam_nonce = esc_html( '_wpnonce=' . wp_create_nonce( 'spam-activity_' . $item['id'] ) );
+
+		$delete_url = $base_url . "&amp;action=delete&amp;$spam_nonce";
+		$edit_url   = $base_url . '&amp;action=edit';
+		$ham_url    = $base_url . "&amp;action=ham&amp;$spam_nonce";
+		$spam_url   = $base_url . "&amp;action=spam&amp;$spam_nonce";
+
+		// Rollover actions
+
+		// Reply - javascript only; implemented by AJAX.
+		if ( 'spam' != $item_status ) {
+			$actions['reply'] = sprintf( '<a href="#" class="reply hide-if-no-js">%s</a>', __( 'Reply', 'buddypress' ) );
+
+			// Edit
+			$actions['edit'] = sprintf( '<a href="%s">%s</a>', $edit_url, __( 'Edit', 'buddypress' ) );
+		}
+
+		// Spam/unspam
+		if ( 'spam' == $item_status )
+			$actions['unspam'] = sprintf( '<a href="%s">%s</a>', $ham_url, __( 'Not Spam', 'buddypress' ) );
+		else
+			$actions['spam'] = sprintf( '<a href="%s">%s</a>', $spam_url, __( 'Spam', 'buddypress' ) );
+
+		// Delete
+		$actions['delete'] = sprintf( '<a href="%s" onclick="%s">%s</a>', $delete_url, "javascript:return confirm('" . esc_js( __( 'Are you sure?', 'buddypress' ) ) . "'); ", __( 'Delete Permanently', 'buddypress' ) );
+
+		// Start timestamp
+		echo '<div class="submitted-on">';
+
+		// Other plugins can filter which actions are shown
+		$actions = apply_filters( 'bp_activity_admin_comment_row_actions', array_filter( $actions ), $item );
+
+		/* translators: 2: activity admin ui date/time */
+		printf( __( 'Submitted on <a href="%1$s">%2$s at %3$s</a>', 'buddypress' ), bp_activity_get_permalink( $item['id'] ), get_date_from_gmt( $item['date_recorded'], get_option( 'date_format' ) ), get_date_from_gmt( $item['date_recorded'], get_option( 'time_format' ) ) );
+
+		// End timestamp
+		echo '</div>';
+
+		// Get activity content - if not set, use the action
+		if ( ! empty( $item['content'] ) ) {
+			$content = apply_filters_ref_array( 'bp_get_activity_content_body', array( $item['content'] ) );
+		} else {
+			$content = apply_filters_ref_array( 'bp_get_activity_action', array( $item['action'] ) );
+		}
+
+		echo $content . ' ' . $this->row_actions( $actions );
+	}
+
+	/**
+	 * "In response to" column markup.
+	 *
+	 * @since BuddyPress (1.6.0)
+	 *
+	 * @see WP_List_Table::single_row_columns()
+	 *
+	 * @param array $item A singular item (one full row).
+	 */
+	function column_response( $item ) {
+		// Is $item is a root activity?
+		if ( empty( $item['item_id'] ) || ! in_array( $item['type'], apply_filters( 'bp_activity_admin_root_activity_types', array( 'activity_comment' ), $item ) ) ) {
+			$comment_count     = !empty( $item['children'] ) ? bp_activity_recurse_comment_count( (object) $item ) : 0;
+			$root_activity_url = bp_get_admin_url( 'admin.php?page=bp-activity&amp;aid=' . $item['id'] );
+
+			// If the activity has comments, display a link to the activity's permalink, with its comment count in a speech bubble
+			if ( $comment_count ) {
+				$title_attr = sprintf( _n( '%s related activity', '%s related activities', $comment_count, 'buddypress' ), number_format_i18n( $comment_count ) );
+				printf( '<a href="%1$s" title="%2$s" class="post-com-count"><span class="comment-count">%3$s</span></a>', esc_url( $root_activity_url ), esc_attr( $title_attr ), number_format_i18n( $comment_count ) );
+			}
+
+		// For non-root activities, display a link to the replied-to activity's author's profile
+		} else {
+			echo '<strong>' . get_avatar( $this->get_activity_user_id( $item['item_id'] ), '32' ) . ' ' . bp_core_get_userlink( $this->get_activity_user_id( $item['item_id'] ) ) . '</strong><br />';
+		}
+
+		// Activity permalink
+		if ( ! $item['is_spam'] )
+			printf( __( '<a href="%1$s">View Activity</a>', 'buddypress' ), bp_activity_get_permalink( $item['id'], (object) $item ) );
+	}
+
+	/**
+	 * Get the user id associated with a given activity item.
+	 *
+	 * Wraps bp_activity_get_specific(), with some additional logic for
+	 * avoiding duplicate queries.
+	 *
+	 * @since BuddyPress (1.6.0)
+	 *
+	 * @param int $activity_id Activity ID to retrieve User ID for.
+	 * @return int User ID of the activity item in question.
+	 */
+	protected function get_activity_user_id( $activity_id ) {
+		// If there is an existing activity/user ID mapping, just return the user ID.
+		if ( ! empty( $this->activity_user_id[$activity_id] ) ) {
+			return $this->activity_user_id[$activity_id];
+
+		/**
+		 * We don't have a mapping. This means the $activity_id is not on the current
+		 * page of results, so fetch its details from the database.
+		 */
+		} else {
+			$activity = bp_activity_get_specific( array( 'activity_ids' => $activity_id, 'show_hidden' => true, 'spam' => 'all', ) );
+
+			/**
+			 * If, somehow, the referenced activity has been deleted, leaving its associated
+			 * activites as orphans, use the logged in user's ID to avoid errors.
+			 */
+			if ( empty( $activity['activities'] ) )
+				return bp_loggedin_user_id();
+
+			// Store the new activity/user ID mapping for any later re-use
+			$this->activity_user_id[ $activity['activities'][0]->id ] = $activity['activities'][0]->user_id;
+
+			// Return the user ID
+			return $activity['activities'][0]->user_id;
+		}
+	}
+
+	/**
+	 * Flatten the activity array.
+	 *
+	 * In some cases, BuddyPress gives us a structured tree of activity
+	 * items plus their comments. This method converts it to a flat array.
+	 *
+	 * @since BuddyPress (1.6.0)
+	 *
+	 * @param array $tree Source array.
+	 * @return array Flattened array.
+	 */
+	public static function flatten_activity_array( $tree ){
+		foreach ( (array) $tree as $node ) {
+			if ( isset( $node->children ) ) {
+
+				foreach ( BP_Activity_List_Table::flatten_activity_array( $node->children ) as $child ) {
+					$tree[] = $child;
+				}
+
+				unset( $node->children );
+			}
+		}
+
+		return $tree;
+	}
+}
Index: /tags/1.9/bp-activity/bp-activity-akismet.php
===================================================================
--- /tags/1.9/bp-activity/bp-activity-akismet.php	(revision 7684)
+++ /tags/1.9/bp-activity/bp-activity-akismet.php	(revision 7684)
@@ -0,0 +1,631 @@
+<?php
+/**
+ * Akismet support for BuddyPress' Activity Stream.
+ *
+ * @package BuddyPress
+ * @since BuddyPress (1.6)
+ * @subpackage Activity
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/**
+ * Akismet support for the Activity component.
+ *
+ * @since BuddyPress (1.6)
+ */
+class BP_Akismet {
+	/**
+	 * The activity last marked as spam.
+	 *
+	 * @access protected
+	 * @var BP_Activity_Activity
+	 * @since BuddyPress (1.6)
+	 */
+	protected $last_activity = null;
+
+	/**
+	 * Constructor.
+	 *
+	 * @since BuddyPress (1.6)
+	 */
+	public function __construct() {
+		$this->setup_actions();
+	}
+
+	/**
+	 * Hook Akismet into the activity stream.
+	 *
+	 * @since BuddyPress (1.6)
+	 */
+	protected function setup_actions() {
+		// Add nonces to activity stream lists
+		add_action( 'bp_after_activity_post_form', array( $this, 'add_activity_stream_nonce' ) );
+		add_action( 'bp_activity_entry_comments',  array( $this, 'add_activity_stream_nonce' ) );
+
+		// Add a "mark as spam" button to individual activity items
+		add_action( 'bp_activity_entry_meta',      array( $this, 'add_activity_spam_button' ) );
+		add_action( 'bp_activity_comment_options', array( $this, 'add_activity_comment_spam_button' ) );
+
+		// Check activity for spam
+		add_action( 'bp_activity_before_save',     array( $this, 'check_activity' ), 4, 1 );
+
+		// Tidy up member's latest (activity) update
+		add_action( 'bp_activity_posted_update',   array( $this, 'check_member_activity_update' ), 1, 3 );
+
+		// Hooks to extend Activity core spam/ham functions for Akismet
+		add_action( 'bp_activity_mark_as_spam',    array( $this, 'mark_as_spam' ), 10, 2 );
+		add_action( 'bp_activity_mark_as_ham',     array( $this, 'mark_as_ham' ),  10, 2 );
+
+		// Hook into the Activity wp-admin screen
+		add_action( 'bp_activity_admin_comment_row_actions', array( $this, 'comment_row_action' ), 10, 2 );
+		add_action( 'bp_activity_admin_load',                array( $this, 'add_history_metabox' ) );
+	}
+
+	/**
+	 * Add a history item to the hover links in an activity's row.
+	 *
+	 * This function lifted with love from the Akismet WordPress plugin's
+	 * akismet_comment_row_action() function. Thanks!
+	 *
+	 * @since BuddyPress (1.6)
+	 *
+	 * @param array $actions The hover links.
+	 * @param array $activity The activity for the current row being processed.
+	 * @return array The hover links.
+	 */
+	function comment_row_action( $actions, $activity ) {
+		$akismet_result = bp_activity_get_meta( $activity['id'], '_bp_akismet_result' );
+		$user_result    = bp_activity_get_meta( $activity['id'], '_bp_akismet_user_result' );
+		$desc           = '';
+
+		if ( !$user_result || $user_result == $akismet_result ) {
+			// Show the original Akismet result if the user hasn't overridden it, or if their decision was the same
+			if ( 'true' == $akismet_result && $activity['is_spam'] )
+				$desc = __( 'Flagged as spam by Akismet', 'buddypress' );
+
+			elseif ( 'false' == $akismet_result && !$activity['is_spam'] )
+				$desc = __( 'Cleared by Akismet', 'buddypress' );
+
+		} else {
+			$who = bp_activity_get_meta( $activity['id'], '_bp_akismet_user' );
+
+			if ( 'true' == $user_result )
+				$desc = sprintf( __( 'Flagged as spam by %s', 'buddypress' ), $who );
+			else
+				$desc = sprintf( __( 'Un-spammed by %s', 'buddypress' ), $who );
+		}
+
+		// add a History item to the hover links, just after Edit
+		if ( $akismet_result ) {
+			$b = array();
+			foreach ( $actions as $k => $item ) {
+				$b[ $k ] = $item;
+				if ( $k == 'edit' )
+					$b['history'] = '<a href="' . esc_url( bp_get_admin_url( 'admin.php?page=bp-activity&amp;action=edit&aid=' . $activity['id'] ) ) . '#bp_activity_history"> '. __( 'History', 'buddypress' ) . '</a>';
+			}
+
+			$actions = $b;
+		}
+
+		if ( $desc )
+			echo '<span class="akismet-status"><a href="' . esc_url( bp_get_admin_url( 'admin.php?page=bp-activity&amp;action=edit&aid=' . $activity['id'] ) ) . '#bp_activity_history">' . htmlspecialchars( $desc ) . '</a></span>';
+
+		return apply_filters( 'bp_akismet_comment_row_action', $actions );
+	}
+
+	/**
+	 * Generate nonces for activity forms.
+	 *
+	 * These nonces appear in the member profile status form, as well as in
+	 * the reply form of each activity item. The nonces are, in turn, used
+	 * by Akismet to help detect spam activity.
+	 *
+	 * @since BuddyPress (1.6)
+	 *
+	 * @see http://plugins.trac.wordpress.org/ticket/1232
+	 */
+	public function add_activity_stream_nonce() {
+		$form_id = '_bp_as_nonce';
+		$value   = '_bp_as_nonce_' . bp_loggedin_user_id();
+
+		// If we're in the activity stream loop, we can use the current item's ID to make the nonce unique
+		if ( 'bp_activity_entry_comments' == current_filter() ) {
+			$form_id .= '_' . bp_get_activity_id();
+			$value   .= '_' . bp_get_activity_id();
+		}
+
+		wp_nonce_field( $value, $form_id, false );
+	}
+
+	/**
+	 * Clean up the bp_latest_update usermeta in case of spamming.
+	 *
+	 * Run just after an update is posted, this method check to see whether
+	 * the newly created update has been marked as spam by Akismet. If so,
+	 * the cached update is cleared from the user's 'bp_latest_update'
+	 * usermeta, ensuring that it won't appear in the member header and
+	 * elsewhere in the theme.
+	 *
+	 * This can't be done in BP_Akismet::check_activity() due to the
+	 * default AJAX implementation; see bp_dtheme_post_update().
+	 *
+	 * @since BuddyPress (1.6)
+	 *
+	 * @see bp_dtheme_post_update()
+	 *
+	 * @param string $content Activity update text.
+	 * @param int $user_id User ID.
+	 * @param int $activity_id Activity ID.
+	 */
+	public function check_member_activity_update( $content, $user_id, $activity_id ) {
+		// By default, only handle activity updates and activity comments.
+		if ( empty( $this->last_activity ) || !in_array( $this->last_activity->type, BP_Akismet::get_activity_types() ) )
+			return;
+
+		// Was this $activity_id just marked as spam? If not, bail out.
+		if ( !$this->last_activity->id || $activity_id != $this->last_activity->id || 'false' == $this->last_activity->akismet_submission['bp_as_result'] )
+			return;
+
+		// It was, so delete the member's latest activity update.
+		bp_delete_user_meta( $user_id, 'bp_latest_update' );
+	}
+
+	/**
+	 * Adds a "mark as spam" button to each activity item for site admins.
+	 *
+	 * This function is intended to be used inside the activity stream loop.
+	 *
+	 * @since BuddyPress (1.6)
+	 */
+	public function add_activity_spam_button() {
+		if ( !bp_activity_user_can_mark_spam() )
+			return;
+
+		// By default, only handle activity updates and activity comments.
+		if ( !in_array( bp_get_activity_type(), BP_Akismet::get_activity_types() ) )
+			return;
+
+		bp_button(
+			array(
+				'block_self' => false,
+				'component'  => 'activity',
+				'id'         => 'activity_make_spam_' . bp_get_activity_id(),
+				'link_class' => 'bp-secondary-action spam-activity confirm button item-button',
+				'link_href'  => wp_nonce_url( bp_get_root_domain() . '/' . bp_get_activity_slug() . '/spam/' . bp_get_activity_id() . '/', 'bp_activity_akismet_spam_' . bp_get_activity_id() ),
+				'link_text'  => __( 'Spam', 'buddypress' ),
+				'wrapper'    => false,
+			)
+		);
+	}
+
+	/**
+	 * Adds a "mark as spam" button to each activity COMMENT item for site admins.
+	 *
+	 * This function is intended to be used inside the activity stream loop.
+	 *
+	 * @since BuddyPress (1.6)
+	 */
+	public function add_activity_comment_spam_button() {
+		if ( !bp_activity_user_can_mark_spam() )
+			return;
+
+		// By default, only handle activity updates and activity comments.
+		$current_comment = bp_activity_current_comment();
+		if ( empty( $current_comment ) || !in_array( $current_comment->type, BP_Akismet::get_activity_types() ) )
+			return;
+
+		bp_button(
+			array(
+				'block_self' => false,
+				'component'  => 'activity',
+				'id'         => 'activity_make_spam_' . bp_get_activity_comment_id(),
+				'link_class' => 'bp-secondary-action spam-activity-comment confirm',
+				'link_href'  => wp_nonce_url( bp_get_root_domain() . '/' . bp_get_activity_slug() . '/spam/' . bp_get_activity_comment_id() . '/?cid=' . bp_get_activity_comment_id(), 'bp_activity_akismet_spam_' . bp_get_activity_comment_id() ),
+				'link_text'  => __( 'Spam', 'buddypress' ),
+				'wrapper'    => false,
+			)
+		);
+	}
+
+	/**
+	 * Get a filterable list of activity types that Akismet should automatically check for spam.
+	 *
+	 * @since BuddyPress (1.6)
+	 *
+	 * @static
+	 *
+	 * @return array List of activity types.
+	 */
+	public static function get_activity_types() {
+		return apply_filters( 'bp_akismet_get_activity_types', array( 'activity_comment', 'activity_update' ) );
+	}
+
+	/**
+	 * Mark activity item as spam.
+	 *
+	 * @since BuddyPress (1.6)
+	 *
+	 * @param BP_Activity_Activity $activity
+	 * @param string $source Either "by_a_person" (e.g. a person has manually marked the activity as spam) or "by_akismet" (automatically spammed).
+	 */
+	public function mark_as_spam( $activity, $source ) {
+		// Record this item so we can do some tidyup in BP_Akismet::check_member_activity_update()
+		$this->last_activity = $activity;
+
+		do_action( 'bp_activity_akismet_mark_as_spam', $activity, $source );
+	}
+
+	/**
+	 * Mark activity item as ham.
+	 *
+	 * @since BuddyPress (1.6)
+	 *
+	 * @param BP_Activity_Activity $activity
+	 * @param string $source Either "by_a_person" (e.g. a person has manually marked the activity as ham) or "by_akismet" (automatically hammed).
+	 */
+	public function mark_as_ham( $activity, $source ) {
+		// If the activity was, originally, automatically marked as spam by Akismet, run the @mentions filter as it would have been skipped.
+		if ( 'true' == bp_activity_get_meta( $activity->id, '_bp_akismet_result' ) && !bp_activity_get_meta( $activity->id, '_bp_akismet_user_result' ) )
+			$activity->content = bp_activity_at_name_filter( $activity->content, $activity->id );
+
+		do_action( 'bp_activity_akismet_mark_as_ham', $activity, $source );
+	}
+
+	/**
+	 * Build a data package for the Akismet service to inspect.
+	 *
+	 * @since BuddyPress (1.6)
+	 *
+	 * @see http://akismet.com/development/api/#comment-check
+	 * @static
+	 *
+	 * @param BP_Activity_Activity $activity Activity item data.
+	 */
+	public static function build_akismet_data_package( $activity ) {
+		$userdata = get_userdata( $activity->user_id );
+
+		$activity_data                          = array();
+		$activity_data['akismet_comment_nonce'] = 'inactive';
+		$activity_data['comment_author']        = $userdata->display_name;
+		$activity_data['comment_author_email']  = $userdata->user_email;
+		$activity_data['comment_author_url']    = bp_core_get_userlink( $userdata->ID, false, true);
+		$activity_data['comment_content']       = $activity->content;
+		$activity_data['comment_type']          = $activity->type;
+		$activity_data['permalink']             = bp_activity_get_permalink( $activity->id, $activity );
+		$activity_data['user_ID']               = $userdata->ID;
+		$activity_data['user_role']             = akismet_get_user_roles( $userdata->ID );
+
+		/**
+		 * Get the nonce if the new activity was submitted through the "what's up, Paul?" form.
+		 * This helps Akismet ensure that the update was a valid form submission.
+		 */
+		if ( !empty( $_POST['_bp_as_nonce'] ) )
+			$activity_data['akismet_comment_nonce'] = wp_verify_nonce( $_POST['_bp_as_nonce'], "_bp_as_nonce_{$userdata->ID}" ) ? 'passed' : 'failed';
+
+		/**
+		 * If the new activity was a reply to an existing item, check the nonce with the activity parent ID.
+		 * This helps Akismet ensure that the update was a valid form submission.
+		 */
+		elseif ( !empty( $activity->secondary_item_id ) && !empty( $_POST['_bp_as_nonce_' . $activity->secondary_item_id] ) )
+			$activity_data['akismet_comment_nonce'] = wp_verify_nonce( $_POST["_bp_as_nonce_{$activity->secondary_item_id}"], "_bp_as_nonce_{$userdata->ID}_{$activity->secondary_item_id}" ) ? 'passed' : 'failed';
+
+		return apply_filters( 'bp_akismet_build_akismet_data_package', $activity_data, $activity );
+	}
+
+	/**
+	 * Check if the activity item is spam or ham.
+	 *
+	 * @since BuddyPress (1.6)
+	 *
+	 * @see http://akismet.com/development/api/
+	 * @todo Spam counter?
+	 * @todo Auto-delete old spam?
+	 *
+	 * @param BP_Activity_Activity $activity The activity item to check.
+	 */
+	public function check_activity( $activity ) {
+		// By default, only handle activity updates and activity comments.
+		if ( !in_array( $activity->type, BP_Akismet::get_activity_types() ) )
+			return;
+
+		// Make sure last_activity is clear to avoid any confusion
+		$this->last_activity = null;
+
+		// Build data package for Akismet
+		$activity_data = BP_Akismet::build_akismet_data_package( $activity );
+
+		// Check with Akismet to see if this is spam
+		$activity_data = $this->send_akismet_request( $activity_data, 'check', 'spam' );
+
+		// Record this item
+		$this->last_activity = $activity;
+
+		// Store a copy of the data that was submitted to Akismet
+		$this->last_activity->akismet_submission = $activity_data;
+
+		// Spam
+		if ( 'true' == $activity_data['bp_as_result'] ) {
+			// Action for plugin authors
+			do_action_ref_array( 'bp_activity_akismet_spam_caught', array( &$activity, $activity_data ) );
+
+			// Mark as spam
+			bp_activity_mark_as_spam( $activity, 'by_akismet' );
+		}
+
+		// Update activity meta after a spam check
+		add_action( 'bp_activity_after_save', array( $this, 'update_activity_akismet_meta' ), 1, 1 );
+	}
+
+	/**
+	 * Update activity meta after a manual spam change (user-initiated).
+	 *
+	 * @since BuddyPress (1.6)
+	 *
+	 * @param BP_Activity_Activity $activity The activity to check.
+	 */
+	public function update_activity_spam_meta( $activity ) {
+		// By default, only handle activity updates and activity comments.
+		if ( !in_array( $activity->type, BP_Akismet::get_activity_types() ) )
+			return;
+
+		$this->update_activity_history( $activity->id, sprintf( __( '%s reported this activity as spam', 'buddypress' ), bp_get_loggedin_user_username() ), 'report-spam' );
+		bp_activity_update_meta( $activity->id, '_bp_akismet_user_result', 'true' );
+		bp_activity_update_meta( $activity->id, '_bp_akismet_user', bp_get_loggedin_user_username() );
+	}
+
+	/**
+	 * Update activity meta after a manual ham change (user-initiated).
+	 *
+	 * @since BuddyPress (1.6)
+	 *
+	 * @param BP_Activity_Activity $activity The activity to check.
+	 */
+	public function update_activity_ham_meta( $activity ) {
+		// By default, only handle activity updates and activity comments.
+		if ( !in_array( $activity->type, BP_Akismet::get_activity_types() ) )
+			return;
+
+		$this->update_activity_history( $activity->id, sprintf( __( '%s reported this activity as not spam', 'buddypress' ), bp_get_loggedin_user_username() ), 'report-ham' );
+		bp_activity_update_meta( $activity->id, '_bp_akismet_user_result', 'false' );
+		bp_activity_update_meta( $activity->id, '_bp_akismet_user', bp_get_loggedin_user_username() );
+	}
+
+	/**
+	 * Update activity meta after an automatic spam check (not user-initiated).
+	 *
+	 * @since BuddyPress (1.6)
+	 *
+	 * @param BP_Activity_Activity $activity The activity to check.
+	 */
+	public function update_activity_akismet_meta( $activity ) {
+		// Check we're dealing with what was last updated by Akismet
+		if ( empty( $this->last_activity ) || !empty( $this->last_activity ) && $activity->id != $this->last_activity->id )
+			return;
+
+		// By default, only handle activity updates and activity comments.
+		if ( !in_array( $this->last_activity->type, BP_Akismet::get_activity_types() ) )
+			return;
+
+		// Spam
+		if ( 'true' == $this->last_activity->akismet_submission['bp_as_result'] ) {
+			bp_activity_update_meta( $activity->id, '_bp_akismet_result', 'true' );
+			$this->update_activity_history( $activity->id, __( 'Akismet caught this item as spam', 'buddypress' ), 'check-spam' );
+
+		// Not spam
+		} elseif ( 'false' == $this->last_activity->akismet_submission['bp_as_result'] ) {
+			bp_activity_update_meta( $activity->id, '_bp_akismet_result', 'false' );
+			$this->update_activity_history( $activity->id, __( 'Akismet cleared this item', 'buddypress' ), 'check-ham' );
+
+		// Uh oh, something's gone horribly wrong. Unexpected result.
+		} else {
+			bp_activity_update_meta( $activity->id, '_bp_akismet_error', bp_core_current_time() );
+			$this->update_activity_history( $activity->id, sprintf( __( 'Akismet was unable to check this item (response: %s), will automatically retry again later.', 'buddypress' ), $this->last_activity->akismet_submission['bp_as_result'] ), 'check-error' );
+		}
+
+		// Record the original data which was submitted to Akismet for checking
+		bp_activity_update_meta( $activity->id, '_bp_akismet_submission', $this->last_activity->akismet_submission );
+	}
+
+	/**
+	 * Contact Akismet to check if this is spam or ham.
+	 *
+	 * Props to WordPress core Akismet plugin for alot of this.
+	 *
+	 * @since BuddyPress (1.6)
+	 *
+	 * @global string $akismet_api_host
+	 * @global string $akismet_api_port
+	 *
+	 * @param array $activity_data Packet of information to submit to Akismet.
+	 * @param string $check "check" or "submit".
+	 * @param string $spam "spam" or "ham".
+	 * @return array $activity_data Activity data, with Akismet data added.
+	 */
+	public function send_akismet_request( $activity_data, $check = 'check', $spam = 'spam' ) {
+		global $akismet_api_host, $akismet_api_port;
+
+		// Check that host and port are set, if not, set them
+		if ( function_exists( 'akismet_init' ) && ( empty( $akismet_api_host ) || empty( $akismet_api_port ) ) )
+			akismet_init();
+
+		$query_string = $path = $response = '';
+
+		$activity_data['blog']         = bp_get_option( 'home' );
+		$activity_data['blog_charset'] = bp_get_option( 'blog_charset' );
+		$activity_data['blog_lang']    = get_locale();
+		$activity_data['referrer']     = $_SERVER['HTTP_REFERER'];
+		$activity_data['user_agent']   = bp_core_current_user_ua();
+		$activity_data['user_ip']      = bp_core_current_user_ip();
+
+		if ( akismet_test_mode() )
+			$activity_data['is_test'] = 'true';
+
+		// Loop through _POST args and rekey strings
+		foreach ( $_POST as $key => $value )
+			if ( is_string( $value ) && 'cookie' != $key )
+				$activity_data['POST_' . $key] = $value;
+
+		// Keys to ignore
+		$ignore = array( 'HTTP_COOKIE', 'HTTP_COOKIE2', 'PHP_AUTH_PW' );
+
+		// Loop through _SERVER args and remove whitelisted keys
+		foreach ( $_SERVER as $key => $value ) {
+
+			// Key should not be ignored
+			if ( !in_array( $key, $ignore ) && is_string( $value ) ) {
+				$activity_data[$key] = $value;
+
+			// Key should be ignored
+			} else {
+				$activity_data[$key] = '';
+			}
+		}
+
+		foreach ( $activity_data as $key => $data )
+			$query_string .= $key . '=' . urlencode( stripslashes( $data ) ) . '&';
+
+		if ( 'check' == $check )
+			$path = '/1.1/comment-check';
+		elseif ( 'submit' == $check )
+			$path = '/1.1/submit-' . $spam;
+
+		// Send to Akismet
+		add_filter( 'akismet_ua', array( $this, 'buddypress_ua' ) );
+		$response = akismet_http_post( $query_string, $akismet_api_host, $path, $akismet_api_port );
+		remove_filter( 'akismet_ua', array( $this, 'buddypress_ua' ) );
+
+		// Get the response
+		if ( ! empty( $response[1] ) && ! is_wp_error( $response[1] ) )
+			$activity_data['bp_as_result'] = $response[1];
+		else
+			$activity_data['bp_as_result'] = false;
+
+		// Perform a daily tidy up
+		if ( ! wp_next_scheduled( 'bp_activity_akismet_delete_old_metadata' ) )
+			wp_schedule_event( time(), 'daily', 'bp_activity_akismet_delete_old_metadata' );
+
+		return $activity_data;
+	}
+
+	/**
+	 * Filters user agent when sending to Akismet to add BuddyPress info.
+	 *
+	 * @since BuddyPress (1.6)
+	 *
+	 * @param string $user_agent User agent string, as generated by Akismet.
+	 * @return string $user_agent Modified user agent string.
+	 */
+	public function buddypress_ua( $user_agent ) {
+		$user_agent = 'BuddyPress/' . bp_get_version() . ' | Akismet/'. constant( 'AKISMET_VERSION' );
+		return $user_agent;
+	}
+
+	/**
+	 * Adds a "History" meta box to the activity edit screen.
+	 *
+	 * @since BuddyPress (1.6)
+	 *
+	 * @param string $screen_action The type of screen that has been requested.
+	 */
+	function add_history_metabox( $screen_action ) {
+		// Only proceed if we're on the edit screen
+		if ( 'edit' != $screen_action )
+			return;
+
+		// Display meta box with a low priority (low position on screen by default)
+		add_meta_box( 'bp_activity_history',  __( 'Activity History', 'buddypress' ), array( $this, 'history_metabox' ), get_current_screen()->id, 'normal', 'low' );
+	}
+
+	/**
+	 * History meta box for the Activity admin edit screen.
+	 *
+	 * @since BuddyPress (1.6)
+	 *
+	 * @see http://buddypress.trac.wordpress.org/ticket/3907
+	 * @todo Update activity meta to allow >1 record with the same key (iterate through $history).
+	 *
+	 * @param object $item Activity item.
+	 */
+	function history_metabox( $item ) {
+		$history = BP_Akismet::get_activity_history( $item->id );
+
+		if ( empty( $history ) )
+			return;
+
+		echo '<div class="akismet-history"><div>';
+		printf( _x( '<span>%1$s</span> &mdash; %2$s', 'x hours ago - akismet cleared this item', 'buddypress' ), bp_core_time_since( $history[2] ), esc_html( $history[1] ) );
+		echo '</div></div>';
+	}
+
+	/**
+	 * Update an activity item's Akismet history.
+	 *
+	 * @since BuddyPress (1.6)
+	 *
+	 * @param int $activity_id Activity item ID.
+	 * @param string $message Human-readable description of what's changed.
+	 * @param string $event The type of check we were carrying out.
+	 */
+	public function update_activity_history( $activity_id = 0, $message = '', $event = '' ) {
+		$event = array(
+			'event'   => $event,
+			'message' => $message,
+			'time'    => akismet_microtime(),
+			'user'    => bp_loggedin_user_id(),
+		);
+
+		// Save the history data
+		bp_activity_update_meta( $activity_id, '_bp_akismet_history', $event );
+	}
+
+	/**
+	 * Get an activity item's Akismet history.
+	 *
+	 * @since BuddyPress (1.6)
+	 *
+	 * @param int $activity_id Activity item ID.
+	 * @return array The activity item's Akismet history.
+	 */
+	public function get_activity_history( $activity_id = 0 ) {
+		$history = bp_activity_get_meta( $activity_id, '_bp_akismet_history' );
+		if ( $history === false )
+			$history = array();
+
+		// Sort it by the time recorded
+		usort( $history, 'akismet_cmp_time' );
+
+		return $history;
+	}
+}
+
+/**
+ * Delete old spam activity meta data
+ *
+ * This is done as a clean-up mechanism, as _bp_akismet_submission meta can
+ * grow to be quite large.
+ *
+ * @since BuddyPress (1.6)
+ *
+ * @global object $bp BuddyPress global settings.
+ * @global wpdb $wpdb WordPress database object.
+ */
+function bp_activity_akismet_delete_old_metadata() {
+	global $bp, $wpdb;
+
+	$interval = apply_filters( 'bp_activity_akismet_delete_meta_interval', 15 );
+
+	// Enforce a minimum of 1 day
+	$interval = max( 1, absint( $interval ) );
+
+	// _bp_akismet_submission meta values are large, so expire them after $interval days regardless of the activity status
+	$sql          = $wpdb->prepare( "SELECT a.id FROM {$bp->activity->table_name} a LEFT JOIN {$bp->activity->table_name_meta} m ON a.id = m.activity_id WHERE m.meta_key = %s AND DATE_SUB(%s, INTERVAL {$interval} DAY) > a.date_recorded LIMIT 10000", '_bp_akismet_submission', current_time( 'mysql', 1 ) );
+	$activity_ids = $wpdb->get_col( $sql );
+
+	if ( ! empty( $activity_ids ) ) {
+		foreach ( $activity_ids as $activity_id )
+			bp_activity_delete_meta( $activity_id, '_bp_akismet_submission' );
+	}
+}
+add_action( 'bp_activity_akismet_delete_old_metadata', 'bp_activity_akismet_delete_old_metadata' );
Index: /tags/1.9/bp-activity/bp-activity-cache.php
===================================================================
--- /tags/1.9/bp-activity/bp-activity-cache.php	(revision 7684)
+++ /tags/1.9/bp-activity/bp-activity-cache.php	(revision 7684)
@@ -0,0 +1,55 @@
+<?php
+
+/**
+ * Functions related to the BuddyPress Activity component and the WP Cache.
+ *
+ * @since BuddyPress (1.6)
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/**
+ * Slurp up activitymeta for a specified set of activity items.
+ *
+ * This function is called in two places in the BP_Activity_Activity class:
+ *   - in the populate() method, when single activity objects are populated
+ *   - in the get() method, when multiple groups are queried
+ *
+ * It grabs all activitymeta associated with all of the activity items passed
+ * in $activity_ids and adds it to the WP cache. This improves efficiency when
+ * using querying activitymeta inline.
+ *
+ * @param int|str|array $activity_ids Accepts a single activity ID, or a comma-
+ *                                    separated list or array of activity ids
+ */
+function bp_activity_update_meta_cache( $activity_ids = false ) {
+	global $bp;
+
+	$cache_args = array(
+		'object_ids' 	   => $activity_ids,
+		'object_type' 	   => $bp->activity->id,
+		'object_column'    => 'activity_id',
+		'meta_table' 	   => $bp->activity->table_name_meta,
+		'cache_key_prefix' => 'bp_activity_meta'
+	);
+
+	bp_update_meta_cache( $cache_args );
+}
+
+/**
+ * Clear the cache for all metadata of a given activity.
+ *
+ * @param int $activity_id
+ */
+function bp_activity_clear_meta_cache_for_activity( $activity_id ) {
+	global $wp_object_cache;
+
+	if ( is_object( $wp_object_cache ) && ! empty( $wp_object_cache->cache['bp'] ) ) {
+		foreach ( $wp_object_cache->cache['bp'] as $ckey => $cvalue ) {
+			if ( 0 === strpos( $ckey, 'bp_activity_meta_' . $activity_id ) ) {
+				wp_cache_delete( $ckey, 'bp' );
+			}
+		}
+	}
+}
Index: /tags/1.9/bp-activity/bp-activity-classes.php
===================================================================
--- /tags/1.9/bp-activity/bp-activity-classes.php	(revision 7684)
+++ /tags/1.9/bp-activity/bp-activity-classes.php	(revision 7684)
@@ -0,0 +1,1411 @@
+<?php
+/**
+ * BuddyPress Activity Classes
+ *
+ * @package BuddyPress
+ * @subpackage Activity
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/**
+ * Database interaction class for the BuddyPress activity component.
+ *
+ * Instance methods are available for creating/editing an activity,
+ * static methods for querying activities.
+ *
+ * @since BuddyPress (1.0)
+ */
+class BP_Activity_Activity {
+
+	/** Properties ************************************************************/
+
+	/**
+	 * ID of the activity item.
+	 *
+	 * @var int
+	 */
+	var $id;
+
+	/**
+	 * ID of the associated item.
+	 *
+	 * @var int
+	 */
+	var $item_id;
+
+	/**
+	 * ID of the associated secondary item.
+	 *
+	 * @var int
+	 */
+	var $secondary_item_id;
+
+	/**
+	 * ID of user associated with the activity item.
+	 *
+	 * @var int
+	 */
+	var $user_id;
+
+	/**
+	 * The primary URL for the activity in RSS feeds.
+	 *
+	 * @var string
+	 */
+	var $primary_link;
+
+	/**
+	 * BuddyPress component the activity item relates to.
+	 *
+	 * @var string
+	 */
+	var $component;
+
+	/**
+	 * Activity type, eg 'new_blog_post'.
+	 *
+	 * @var string
+	 */
+	var $type;
+
+	/**
+	 * Description of the activity, eg 'Alex updated his profile.'
+	 *
+	 * @var string
+	 */
+	var $action;
+
+	/**
+	 * The content of the activity item.
+	 *
+	 * @var string
+	 */
+	var $content;
+
+	/**
+	 * The date the activity item was recorded, in 'Y-m-d h:i:s' format.
+	 *
+	 * @var string
+	 */
+	var $date_recorded;
+
+	/**
+	 * Whether the item should be hidden in sitewide streams.
+	 *
+	 * @var int
+	 */
+	var $hide_sitewide = false;
+
+	/**
+	 * Node boundary start for activity or activity comment.
+	 *
+	 * @var int
+	 */
+	var $mptt_left;
+
+	/**
+	 * Node boundary end for activity or activity comment.
+	 *
+	 * @var int
+	 */
+	var $mptt_right;
+
+	/**
+	 * Whether this item is marked as spam.
+	 *
+	 * @var int
+	 */
+	var $is_spam;
+
+	/**
+	 * Constructor method.
+	 *
+	 * @param int $id Optional. The ID of a specific activity item.
+	 */
+	public function __construct( $id = false ) {
+		if ( !empty( $id ) ) {
+			$this->id = $id;
+			$this->populate();
+		}
+	}
+
+	/**
+	 * Populate the object with data about the specific activity item.
+	 */
+	public function populate() {
+		global $wpdb, $bp;
+
+		if ( $row = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$bp->activity->table_name} WHERE id = %d", $this->id ) ) ) {
+			$this->id                = $row->id;
+			$this->item_id           = $row->item_id;
+			$this->secondary_item_id = $row->secondary_item_id;
+			$this->user_id           = $row->user_id;
+			$this->primary_link      = $row->primary_link;
+			$this->component         = $row->component;
+			$this->type              = $row->type;
+			$this->action            = $row->action;
+			$this->content           = $row->content;
+			$this->date_recorded     = $row->date_recorded;
+			$this->hide_sitewide     = $row->hide_sitewide;
+			$this->mptt_left         = $row->mptt_left;
+			$this->mptt_right        = $row->mptt_right;
+			$this->is_spam           = $row->is_spam;
+
+			bp_activity_update_meta_cache( $this->id );
+		}
+	}
+
+	/**
+	 * Save the activity item to the database.
+	 *
+	 * @return bool True on success.
+	 */
+	public function save() {
+		global $wpdb, $bp;
+
+		$this->id                = apply_filters_ref_array( 'bp_activity_id_before_save',                array( $this->id,                &$this ) );
+		$this->item_id           = apply_filters_ref_array( 'bp_activity_item_id_before_save',           array( $this->item_id,           &$this ) );
+		$this->secondary_item_id = apply_filters_ref_array( 'bp_activity_secondary_item_id_before_save', array( $this->secondary_item_id, &$this ) );
+		$this->user_id           = apply_filters_ref_array( 'bp_activity_user_id_before_save',           array( $this->user_id,           &$this ) );
+		$this->primary_link      = apply_filters_ref_array( 'bp_activity_primary_link_before_save',      array( $this->primary_link,      &$this ) );
+		$this->component         = apply_filters_ref_array( 'bp_activity_component_before_save',         array( $this->component,         &$this ) );
+		$this->type              = apply_filters_ref_array( 'bp_activity_type_before_save',              array( $this->type,              &$this ) );
+		$this->action            = apply_filters_ref_array( 'bp_activity_action_before_save',            array( $this->action,            &$this ) );
+		$this->content           = apply_filters_ref_array( 'bp_activity_content_before_save',           array( $this->content,           &$this ) );
+		$this->date_recorded     = apply_filters_ref_array( 'bp_activity_date_recorded_before_save',     array( $this->date_recorded,     &$this ) );
+		$this->hide_sitewide     = apply_filters_ref_array( 'bp_activity_hide_sitewide_before_save',     array( $this->hide_sitewide,     &$this ) );
+		$this->mptt_left         = apply_filters_ref_array( 'bp_activity_mptt_left_before_save',         array( $this->mptt_left,         &$this ) );
+		$this->mptt_right        = apply_filters_ref_array( 'bp_activity_mptt_right_before_save',        array( $this->mptt_right,        &$this ) );
+		$this->is_spam           = apply_filters_ref_array( 'bp_activity_is_spam_before_save',           array( $this->is_spam,           &$this ) );
+
+		// Use this, not the filters above
+		do_action_ref_array( 'bp_activity_before_save', array( &$this ) );
+
+		if ( !$this->component || !$this->type )
+			return false;
+
+		if ( !$this->primary_link )
+			$this->primary_link = bp_loggedin_user_domain();
+
+		// If we have an existing ID, update the activity item, otherwise insert it.
+		if ( $this->id )
+			$q = $wpdb->prepare( "UPDATE {$bp->activity->table_name} SET user_id = %d, component = %s, type = %s, action = %s, content = %s, primary_link = %s, date_recorded = %s, item_id = %d, secondary_item_id = %d, hide_sitewide = %d, is_spam = %d WHERE id = %d", $this->user_id, $this->component, $this->type, $this->action, $this->content, $this->primary_link, $this->date_recorded, $this->item_id, $this->secondary_item_id, $this->hide_sitewide, $this->is_spam, $this->id );
+		else
+			$q = $wpdb->prepare( "INSERT INTO {$bp->activity->table_name} ( user_id, component, type, action, content, primary_link, date_recorded, item_id, secondary_item_id, hide_sitewide, is_spam ) VALUES ( %d, %s, %s, %s, %s, %s, %s, %d, %d, %d, %d )", $this->user_id, $this->component, $this->type, $this->action, $this->content, $this->primary_link, $this->date_recorded, $this->item_id, $this->secondary_item_id, $this->hide_sitewide, $this->is_spam );
+
+		if ( false === $wpdb->query( $q ) )
+			return false;
+
+		// If this is a new activity item, set the $id property
+		if ( empty( $this->id ) )
+			$this->id = $wpdb->insert_id;
+
+		// If an existing activity item, prevent any changes to the content generating new @mention notifications.
+		else
+			add_filter( 'bp_activity_at_name_do_notifications', '__return_false' );
+
+		do_action_ref_array( 'bp_activity_after_save', array( &$this ) );
+
+		return true;
+	}
+
+	/** Static Methods ***************************************************/
+
+	/**
+	 * Get activity items, as specified by parameters
+	 *
+	 * @see BP_Activity_Activity::get_filter_sql() for a description of the
+	 *      'filter' parameter.
+	 * @see WP_Meta_Query::queries for a description of the 'meta_query'
+	 *      parameter format.
+	 *
+	 * @param array $args {
+	 *     An array of arguments. All items are optional.
+	 *     @type int $page Which page of results to fetch. Using page=1
+	 *                     without per_page will result in no pagination.
+	 *                     Default: 1.
+	 *     @type int|bool $per_page Number of results per page. Default: 25.
+	 *     @type int|bool $max Maximum number of results to return.
+	 *                         Default: false (unlimited).
+	 *     @type string $sort ASC or DESC. Default: 'DESC'.
+	 *     @type array $exclude Array of activity IDs to exclude.
+	 *                          Default: false.
+	 *     @type array $in Array of ids to limit query by (IN).
+	 *                     Default: false.
+	 *     @type array $meta_query An array of meta_query conditions.
+	 *                             See WP_Meta_Query::queries for description.
+	 *     @type array $filter See BP_Activity_Activity::get_filter_sql().
+	 *     @type string $search_terms Limit results by a search term.
+	 *                                Default: false.
+	 *     @type bool $display_comments Whether to include activity comments.
+	 *                                  Default: false.
+	 *     @type bool $show_hidden Whether to show items marked hide_sitewide.
+	 *                             Default: false.
+	 *     @type string $spam Spam status. Default: 'ham_only'.
+	 * }
+	 * @return array The array returned has two keys:
+	 *     - 'total' is the count of located activities
+	 *     - 'activities' is an array of the located activities
+	 */
+	public static function get( $args = array() ) {
+		global $wpdb, $bp;
+
+		// Backward compatibility with old method of passing arguments
+		if ( !is_array( $args ) || func_num_args() > 1 ) {
+			_deprecated_argument( __METHOD__, '1.6', sprintf( __( 'Arguments passed to %1$s should be in an associative array. See the inline documentation at %2$s for more details.', 'buddypress' ), __METHOD__, __FILE__ ) );
+
+			$old_args_keys = array(
+				0 => 'max',
+				1 => 'page',
+				2 => 'per_page',
+				3 => 'sort',
+				4 => 'search_terms',
+				5 => 'filter',
+				6 => 'display_comments',
+				7 => 'show_hidden',
+				8 => 'exclude',
+				9 => 'in',
+				10 => 'spam'
+			);
+
+			$func_args = func_get_args();
+			$args      = bp_core_parse_args_array( $old_args_keys, $func_args );
+		}
+
+		$defaults = array(
+			'page'             => 1,          // The current page
+			'per_page'         => 25,         // Activity items per page
+			'max'              => false,      // Max number of items to return
+			'sort'             => 'DESC',     // ASC or DESC
+			'exclude'          => false,      // Array of ids to exclude
+			'in'               => false,      // Array of ids to limit query by (IN)
+			'meta_query'       => false,      // Filter by activitymeta
+			'filter'           => false,      // See self::get_filter_sql()
+			'search_terms'     => false,      // Terms to search by
+			'display_comments' => false,      // Whether to include activity comments
+			'show_hidden'      => false,      // Show items marked hide_sitewide
+			'spam'             => 'ham_only', // Spam status
+		);
+		$r = wp_parse_args( $args, $defaults );
+		extract( $r );
+
+		// Select conditions
+		$select_sql = "SELECT DISTINCT a.*, u.user_email, u.user_nicename, u.user_login, u.display_name";
+
+		$from_sql = " FROM {$bp->activity->table_name} a LEFT JOIN {$wpdb->users} u ON a.user_id = u.ID";
+
+		$join_sql = '';
+
+		// Where conditions
+		$where_conditions = array();
+
+		// Spam
+		if ( 'ham_only' == $spam )
+			$where_conditions['spam_sql'] = 'a.is_spam = 0';
+		elseif ( 'spam_only' == $spam )
+			$where_conditions['spam_sql'] = 'a.is_spam = 1';
+
+		// Searching
+		if ( $search_terms ) {
+			$search_terms = esc_sql( $search_terms );
+			$where_conditions['search_sql'] = "a.content LIKE '%%" . esc_sql( like_escape( $search_terms ) ) . "%%'";
+		}
+
+		// Filtering
+		if ( $filter && $filter_sql = BP_Activity_Activity::get_filter_sql( $filter ) )
+			$where_conditions['filter_sql'] = $filter_sql;
+
+		// Sorting
+		if ( $sort != 'ASC' && $sort != 'DESC' )
+			$sort = 'DESC';
+
+		// Hide Hidden Items?
+		if ( !$show_hidden )
+			$where_conditions['hidden_sql'] = "a.hide_sitewide = 0";
+
+		// Exclude specified items
+		if ( !empty( $exclude ) ) {
+			$exclude = implode( ',', wp_parse_id_list( $exclude ) );
+			$where_conditions['exclude'] = "a.id NOT IN ({$exclude})";
+		}
+
+		// The specific ids to which you want to limit the query
+		if ( !empty( $in ) ) {
+			$in = implode( ',', wp_parse_id_list( $in ) );
+			$where_conditions['in'] = "a.id IN ({$in})";
+		}
+
+		// Process meta_query into SQL
+		$meta_query_sql = self::get_meta_query_sql( $meta_query );
+
+		if ( ! empty( $meta_query_sql['join'] ) ) {
+			$join_sql .= $meta_query_sql['join'];
+		}
+
+		if ( ! empty( $meta_query_sql['where'] ) ) {
+			$where_conditions[] = $meta_query_sql['where'];
+		}
+
+		// Alter the query based on whether we want to show activity item
+		// comments in the stream like normal comments or threaded below
+		// the activity.
+		if ( false === $display_comments || 'threaded' === $display_comments ) {
+			$where_conditions[] = "a.type != 'activity_comment'";
+		}
+
+		// Filter the where conditions
+		$where_conditions = apply_filters( 'bp_activity_get_where_conditions', $where_conditions, $r, $select_sql, $from_sql, $join_sql );
+
+		// Join the where conditions together
+		$where_sql = 'WHERE ' . join( ' AND ', $where_conditions );
+
+		// Define the preferred order for indexes
+		$indexes = apply_filters( 'bp_activity_preferred_index_order', array( 'user_id', 'item_id', 'secondary_item_id', 'date_recorded', 'component', 'type', 'hide_sitewide', 'is_spam' ) );
+
+		foreach( $indexes as $key => $index ) {
+			if ( false !== strpos( $where_sql, $index ) ) {
+				$the_index = $index;
+				break; // Take the first one we find
+			}
+		}
+
+		if ( !empty( $the_index ) ) {
+			$index_hint_sql = "USE INDEX ({$the_index})";
+		} else {
+			$index_hint_sql = '';
+		}
+
+		if ( !empty( $per_page ) && !empty( $page ) ) {
+
+			// Make sure page values are absolute integers
+			$page     = absint( $page     );
+			$per_page = absint( $per_page );
+
+			$pag_sql    = $wpdb->prepare( "LIMIT %d, %d", absint( ( $page - 1 ) * $per_page ), $per_page );
+			$activities = $wpdb->get_results( apply_filters( 'bp_activity_get_user_join_filter', "{$select_sql} {$from_sql} {$join_sql} {$where_sql} ORDER BY a.date_recorded {$sort} {$pag_sql}", $select_sql, $from_sql, $where_sql, $sort, $pag_sql ) );
+		} else {
+			$activities = $wpdb->get_results( apply_filters( 'bp_activity_get_user_join_filter', "{$select_sql} {$from_sql} {$join_sql} {$where_sql} ORDER BY a.date_recorded {$sort}", $select_sql, $from_sql, $where_sql, $sort ) );
+		}
+
+		$total_activities_sql = apply_filters( 'bp_activity_total_activities_sql', "SELECT count(DISTINCT a.id) FROM {$bp->activity->table_name} a {$index_hint_sql} {$join_sql} {$where_sql} ORDER BY a.date_recorded {$sort}", $where_sql, $sort );
+
+		$total_activities = $wpdb->get_var( $total_activities_sql );
+
+		// Get the fullnames of users so we don't have to query in the loop
+		if ( bp_is_active( 'xprofile' ) && !empty( $activities ) ) {
+			$activity_user_ids = wp_list_pluck( $activities, 'user_id' );
+			$activity_user_ids = implode( ',', wp_parse_id_list( $activity_user_ids ) );
+
+			if ( !empty( $activity_user_ids ) ) {
+				if ( $names = $wpdb->get_results( "SELECT user_id, value AS user_fullname FROM {$bp->profile->table_name_data} WHERE field_id = 1 AND user_id IN ({$activity_user_ids})" ) ) {
+					foreach ( (array) $names as $name )
+						$tmp_names[$name->user_id] = $name->user_fullname;
+
+					foreach ( (array) $activities as $i => $activity ) {
+						if ( !empty( $tmp_names[$activity->user_id] ) )
+							$activities[$i]->user_fullname = $tmp_names[$activity->user_id];
+					}
+
+					unset( $names );
+					unset( $tmp_names );
+				}
+			}
+		}
+
+		// Get activity meta
+		$activity_ids = array();
+		foreach ( (array) $activities as $activity ) {
+			$activity_ids[] = $activity->id;
+		}
+
+		if ( !empty( $activity_ids ) ) {
+			bp_activity_update_meta_cache( $activity_ids );
+		}
+
+		if ( $activities && $display_comments )
+			$activities = BP_Activity_Activity::append_comments( $activities, $spam );
+
+		// If $max is set, only return up to the max results
+		if ( !empty( $max ) ) {
+			if ( (int) $total_activities > (int) $max )
+				$total_activities = $max;
+		}
+
+		return array( 'activities' => $activities, 'total' => (int) $total_activities );
+	}
+
+	/**
+	 * Get the SQL for the 'meta_query' param in BP_Activity_Activity::get().
+	 *
+	 * We use WP_Meta_Query to do the heavy lifting of parsing the
+	 * meta_query array and creating the necessary SQL clauses. However,
+	 * since BP_Activity_Activity::get() builds its SQL differently than
+	 * WP_Query, we have to alter the return value (stripping the leading
+	 * AND keyword from the 'where' clause).
+	 *
+	 * @since BuddyPress (1.8)
+	 *
+	 * @param array $meta_query An array of meta_query filters. See the
+	 *   documentation for WP_Meta_Query for details.
+	 * @return array $sql_array 'join' and 'where' clauses.
+	 */
+	public static function get_meta_query_sql( $meta_query = array() ) {
+		global $wpdb;
+
+		$sql_array = array(
+			'join'  => '',
+			'where' => '',
+		);
+
+		if ( ! empty( $meta_query ) ) {
+			$activity_meta_query = new WP_Meta_Query( $meta_query );
+
+			// WP_Meta_Query expects the table name at
+			// $wpdb->activitymeta
+			$wpdb->activitymeta = buddypress()->activity->table_name_meta;
+
+			$meta_sql = $activity_meta_query->get_sql( 'activity', 'a', 'id' );
+
+			// Strip the leading AND - BP handles it in get()
+			$sql_array['where'] = preg_replace( '/^\sAND/', '', $meta_sql['where'] );
+			$sql_array['join']  = $meta_sql['join'];
+		}
+
+		return $sql_array;
+	}
+
+	/**
+	 * In BuddyPress 1.2.x, this was used to retrieve specific activity stream items (for example, on an activity's permalink page).
+	 *
+	 * As of 1.5.x, use BP_Activity_Activity::get() with an 'in' parameter instead.
+	 *
+	 * @since BuddyPress (1.2)
+	 *
+	 * @deprecated 1.5
+	 * @deprecated Use BP_Activity_Activity::get() with an 'in' parameter instead.
+	 *
+	 * @param mixed $activity_ids Array or comma-separated string of activity IDs to retrieve
+	 * @param int $max Maximum number of results to return. (Optional; default is no maximum)
+	 * @param int $page The set of results that the user is viewing. Used in pagination. (Optional; default is 1)
+	 * @param int $per_page Specifies how many results per page. Used in pagination. (Optional; default is 25)
+	 * @param string MySQL column sort; ASC or DESC. (Optional; default is DESC)
+	 * @param bool $display_comments Retrieve an activity item's associated comments or not. (Optional; default is false)
+	 * @return array
+	 */
+	public static function get_specific( $activity_ids, $max = false, $page = 1, $per_page = 25, $sort = 'DESC', $display_comments = false ) {
+		_deprecated_function( __FUNCTION__, '1.5', 'Use BP_Activity_Activity::get() with the "in" parameter instead.' );
+		return BP_Activity_Activity::get( $max, $page, $per_page, $sort, false, false, $display_comments, false, false, $activity_ids );
+	}
+
+	/**
+	 * Get the first activity ID that matches a set of criteria.
+	 *
+	 * @param int $user_id The user ID to filter by.
+	 * @param string $component The component to filter by.
+	 * @param string $type The activity type to filter by.
+	 * @param int $item_id The associated item to filter by.
+	 * @param int $secondary_item_id The secondary associated item to filter by.
+	 * @param string $action The action to filter by.
+	 * @param string $content The content to filter by.
+	 * @param string $date_recorded The date to filter by.
+	 * @return int|bool Activity ID on success, false if none is found.
+	 */
+	public static function get_id( $user_id, $component, $type, $item_id, $secondary_item_id, $action, $content, $date_recorded ) {
+		global $bp, $wpdb;
+
+		$where_args = false;
+
+		if ( !empty( $user_id ) )
+			$where_args[] = $wpdb->prepare( "user_id = %d", $user_id );
+
+		if ( !empty( $component ) )
+			$where_args[] = $wpdb->prepare( "component = %s", $component );
+
+		if ( !empty( $type ) )
+			$where_args[] = $wpdb->prepare( "type = %s", $type );
+
+		if ( !empty( $item_id ) )
+			$where_args[] = $wpdb->prepare( "item_id = %d", $item_id );
+
+		if ( !empty( $secondary_item_id ) )
+			$where_args[] = $wpdb->prepare( "secondary_item_id = %d", $secondary_item_id );
+
+		if ( !empty( $action ) )
+			$where_args[] = $wpdb->prepare( "action = %s", $action );
+
+		if ( !empty( $content ) )
+			$where_args[] = $wpdb->prepare( "content = %s", $content );
+
+		if ( !empty( $date_recorded ) )
+			$where_args[] = $wpdb->prepare( "date_recorded = %s", $date_recorded );
+
+		if ( !empty( $where_args ) )
+			$where_sql = 'WHERE ' . join( ' AND ', $where_args );
+		else
+			return false;
+
+		return $wpdb->get_var( "SELECT id FROM {$bp->activity->table_name} {$where_sql}" );
+	}
+
+	/**
+	 * Delete activity items from the database.
+	 *
+	 * To delete a specific activity item, pass an 'id' parameter.
+	 * Otherwise use the filters.
+	 *
+	 * @since BuddyPress (1.2)
+	 *
+	 * @param array $args {
+	 *     @int $id Optional. The ID of a specific item to delete.
+	 *     @string $action Optional. The action to filter by.
+	 *     @string $content Optional. The content to filter by.
+	 *     @string $component Optional. The component name to filter by.
+	 *     @string $type Optional. The activity type to filter by.
+	 *     @string $primary_link Optional. The primary URL to filter by.
+	 *     @int $user_id Optional. The user ID to filter by.
+	 *     @int $item_id Optional. The associated item ID to filter by.
+	 *     @int $secondary_item_id Optional. The secondary associated item ID to filter by.
+	 *     @string $date_recorded Optional. The date to filter by.
+	 *     @int $hide_sitewide Optional. Default: false.
+	 * }
+	 * @return array|bool An array of deleted activity IDs on success, false on failure.
+	 */
+	public static function delete( $args = array() ) {
+		global $wpdb, $bp;
+
+		$defaults = array(
+			'id'                => false,
+			'action'            => false,
+			'content'           => false,
+			'component'         => false,
+			'type'              => false,
+			'primary_link'      => false,
+			'user_id'           => false,
+			'item_id'           => false,
+			'secondary_item_id' => false,
+			'date_recorded'     => false,
+			'hide_sitewide'     => false
+		);
+		$params = wp_parse_args( $args, $defaults );
+		extract( $params );
+
+		$where_args = false;
+
+		if ( !empty( $id ) )
+			$where_args[] = $wpdb->prepare( "id = %d", $id );
+
+		if ( !empty( $user_id ) )
+			$where_args[] = $wpdb->prepare( "user_id = %d", $user_id );
+
+		if ( !empty( $action ) )
+			$where_args[] = $wpdb->prepare( "action = %s", $action );
+
+		if ( !empty( $content ) )
+			$where_args[] = $wpdb->prepare( "content = %s", $content );
+
+		if ( !empty( $component ) )
+			$where_args[] = $wpdb->prepare( "component = %s", $component );
+
+		if ( !empty( $type ) )
+			$where_args[] = $wpdb->prepare( "type = %s", $type );
+
+		if ( !empty( $primary_link ) )
+			$where_args[] = $wpdb->prepare( "primary_link = %s", $primary_link );
+
+		if ( !empty( $item_id ) )
+			$where_args[] = $wpdb->prepare( "item_id = %d", $item_id );
+
+		if ( !empty( $secondary_item_id ) )
+			$where_args[] = $wpdb->prepare( "secondary_item_id = %d", $secondary_item_id );
+
+		if ( !empty( $date_recorded ) )
+			$where_args[] = $wpdb->prepare( "date_recorded = %s", $date_recorded );
+
+		if ( !empty( $hide_sitewide ) )
+			$where_args[] = $wpdb->prepare( "hide_sitewide = %d", $hide_sitewide );
+
+		if ( !empty( $where_args ) )
+			$where_sql = 'WHERE ' . join( ' AND ', $where_args );
+		else
+			return false;
+
+		// Fetch the activity IDs so we can delete any comments for this activity item
+		$activity_ids = $wpdb->get_col( "SELECT id FROM {$bp->activity->table_name} {$where_sql}" );
+
+		if ( ! $wpdb->query( "DELETE FROM {$bp->activity->table_name} {$where_sql}" ) ) {
+			return false;
+		}
+
+		// Handle accompanying activity comments and meta deletion
+		if ( $activity_ids ) {
+			$activity_ids_comma          = implode( ',', wp_parse_id_list( $activity_ids ) );
+			$activity_comments_where_sql = "WHERE type = 'activity_comment' AND item_id IN ({$activity_ids_comma})";
+
+			// Fetch the activity comment IDs for our deleted activity items
+			$activity_comment_ids = $wpdb->get_col( "SELECT id FROM {$bp->activity->table_name} {$activity_comments_where_sql}" );
+
+			// We have activity comments!
+			if ( ! empty( $activity_comment_ids ) ) {
+				// Delete activity comments
+				$wpdb->query( "DELETE FROM {$bp->activity->table_name} {$activity_comments_where_sql}" );
+
+				// Merge activity IDs with activity comment IDs
+				$activity_ids = array_merge( $activity_ids, $activity_comment_ids );
+			}
+
+			// Delete all activity meta entries for activity items and activity comments
+			BP_Activity_Activity::delete_activity_meta_entries( $activity_ids );
+		}
+
+		return $activity_ids;
+	}
+
+	/**
+	 * Delete the comments associated with a set of activity items.
+	 *
+	 * @since BuddyPress (1.2)
+	 *
+	 * @todo Mark as deprecated?  Method is no longer used internally.
+	 *
+	 * @param array $activity_ids Activity IDs whose comments should be deleted.
+	 * @param bool $delete_meta Should we delete the activity meta items for these comments?
+	 * @return bool True on success.
+	 */
+	public static function delete_activity_item_comments( $activity_ids = array(), $delete_meta = true ) {
+		global $bp, $wpdb;
+
+		$delete_meta = (bool) $delete_meta;
+
+		$activity_ids = implode( ',', wp_parse_id_list( $activity_ids ) );
+
+		if ( $delete_meta ) {
+			// Fetch the activity comment IDs for our deleted activity items
+			$activity_comment_ids = $wpdb->get_col( "SELECT id FROM {$bp->activity->table_name} WHERE type = 'activity_comment' AND item_id IN ({$activity_ids})" );
+
+			if ( ! empty( $activity_comment_ids ) ) {
+				self::delete_activity_meta_entries( $activity_comment_ids );
+			}
+		}
+
+		return $wpdb->query( "DELETE FROM {$bp->activity->table_name} WHERE type = 'activity_comment' AND item_id IN ({$activity_ids})" );
+	}
+
+	/**
+	 * Delete the meta entries associated with a set of activity items.
+	 *
+	 * @since BuddyPress (1.2)
+	 *
+	 * @param array $activity_ids Activity IDs whose meta should be deleted.
+	 * @return bool True on success.
+	 */
+	public static function delete_activity_meta_entries( $activity_ids = array() ) {
+		global $bp, $wpdb;
+
+		$activity_ids = implode( ',', wp_parse_id_list( $activity_ids ) );
+
+		foreach ( (array) $activity_ids as $activity_id ) {
+			bp_activity_clear_meta_cache_for_activity( $activity_id );
+		}
+
+		return $wpdb->query( "DELETE FROM {$bp->activity->table_name_meta} WHERE activity_id IN ({$activity_ids})" );
+	}
+
+	/**
+	 * Append activity comments to their associated activity items.
+	 *
+	 * @since BuddyPress (1.2)
+	 *
+	 * @global wpdb $wpdb WordPress database object
+	 *
+	 * @param array $activities Activities to fetch comments for.
+	 * @param bool $spam Optional. 'ham_only' (default), 'spam_only' or 'all'.
+	 * @return array The updated activities with nested comments.
+	 */
+	public static function append_comments( $activities, $spam = 'ham_only' ) {
+		$activity_comments = array();
+
+		// Now fetch the activity comments and parse them into the correct position in the activities array.
+		foreach( (array) $activities as $activity ) {
+			$top_level_parent_id = 'activity_comment' == $activity->type ? $activity->item_id : 0;
+			$activity_comments[$activity->id] = BP_Activity_Activity::get_activity_comments( $activity->id, $activity->mptt_left, $activity->mptt_right, $spam, $top_level_parent_id );
+		}
+
+		// Merge the comments with the activity items
+		foreach( (array) $activities as $key => $activity )
+			if ( isset( $activity_comments[$activity->id] ) )
+				$activities[$key]->children = $activity_comments[$activity->id];
+
+		return $activities;
+	}
+
+	/**
+	 * Get activity comments that are associated with a specific activity ID.
+	 *
+	 * @since BuddyPress (1.2)
+	 *
+	 * @global BuddyPress $bp The one true BuddyPress instance.
+	 * @global wpdb $wpdb WordPress database object.
+	 *
+	 * @param int $activity_id Activity ID to fetch comments for.
+	 * @param int $left Left-most node boundary.
+	 * @param into $right Right-most node boundary.
+	 * @param bool $spam Optional. 'ham_only' (default), 'spam_only' or 'all'.
+	 * @param int $top_level_parent_id Optional. The id of the root-level parent activity item.
+	 * @return array The updated activities with nested comments.
+	 */
+	public static function get_activity_comments( $activity_id, $left, $right, $spam = 'ham_only', $top_level_parent_id = 0 ) {
+		global $wpdb, $bp;
+
+		if ( empty( $top_level_parent_id ) ) {
+			$top_level_parent_id = $activity_id;
+		}
+
+		if ( !$comments = wp_cache_get( 'bp_activity_comments_' . $activity_id ) ) {
+
+			// Select the user's fullname with the query
+			if ( bp_is_active( 'xprofile' ) ) {
+				$fullname_select = ", pd.value as user_fullname";
+				$fullname_from = ", {$bp->profile->table_name_data} pd ";
+				$fullname_where = "AND pd.user_id = a.user_id AND pd.field_id = 1";
+
+			// Prevent debug errors
+			} else {
+				$fullname_select = $fullname_from = $fullname_where = '';
+			}
+
+			// Don't retrieve activity comments marked as spam
+			if ( 'ham_only' == $spam ) {
+				$spam_sql = 'AND a.is_spam = 0';
+			} elseif ( 'spam_only' == $spam ) {
+				$spam_sql = 'AND a.is_spam = 1';
+			} else {
+				$spam_sql = '';
+			}
+
+			// The mptt BETWEEN clause allows us to limit returned descendants to the right part of the tree
+			$sql = apply_filters( 'bp_activity_comments_user_join_filter', $wpdb->prepare( "SELECT a.*, u.user_email, u.user_nicename, u.user_login, u.display_name{$fullname_select} FROM {$bp->activity->table_name} a, {$wpdb->users} u{$fullname_from} WHERE u.ID = a.user_id {$fullname_where} AND a.type = 'activity_comment' {$spam_sql} AND a.item_id = %d AND a.mptt_left > %d AND a.mptt_left < %d ORDER BY a.date_recorded ASC", $top_level_parent_id, $left, $right ), $activity_id, $left, $right, $spam_sql );
+
+			// Retrieve all descendants of the $root node
+			$descendants = $wpdb->get_results( $sql );
+			$ref         = array();
+
+			// Loop descendants and build an assoc array
+			foreach ( (array) $descendants as $d ) {
+				$d->children = array();
+
+				// If we have a reference on the parent
+				if ( isset( $ref[ $d->secondary_item_id ] ) ) {
+					$ref[ $d->secondary_item_id ]->children[ $d->id ] = $d;
+					$ref[ $d->id ] =& $ref[ $d->secondary_item_id ]->children[ $d->id ];
+
+				// If we don't have a reference on the parent, put in the root level
+				} else {
+					$comments[ $d->id ] = $d;
+					$ref[ $d->id ] =& $comments[ $d->id ];
+				}
+			}
+			wp_cache_set( 'bp_activity_comments_' . $activity_id, $comments, 'bp' );
+		}
+
+		return $comments;
+	}
+
+	/**
+	 * Rebuild nested comment tree under an activity or activity comment.
+	 *
+	 * @since BuddyPress (1.2)
+	 *
+	 * @global BuddyPress $bp The one true BuddyPress instance.
+	 * @global wpdb $wpdb WordPress database object.
+	 *
+	 * @param int $parent_id ID of an activty or activity comment.
+	 * @param int $left Node boundary start for activity or activity comment.
+	 * @return int Right node boundary of activity or activity comment.
+	 */
+	public static function rebuild_activity_comment_tree( $parent_id, $left = 1 ) {
+		global $wpdb, $bp;
+
+		// The right value of this node is the left value + 1
+		$right = $left + 1;
+
+		// Get all descendants of this node
+		$descendants = BP_Activity_Activity::get_child_comments( $parent_id );
+
+		// Loop the descendants and recalculate the left and right values
+		foreach ( (array) $descendants as $descendant )
+			$right = BP_Activity_Activity::rebuild_activity_comment_tree( $descendant->id, $right );
+
+		// We've got the left value, and now that we've processed the children
+		// of this node we also know the right value
+		if ( 1 == $left )
+			$wpdb->query( $wpdb->prepare( "UPDATE {$bp->activity->table_name} SET mptt_left = %d, mptt_right = %d WHERE id = %d", $left, $right, $parent_id ) );
+		else
+			$wpdb->query( $wpdb->prepare( "UPDATE {$bp->activity->table_name} SET mptt_left = %d, mptt_right = %d WHERE type = 'activity_comment' AND id = %d", $left, $right, $parent_id ) );
+
+		// Return the right value of this node + 1
+		return $right + 1;
+	}
+
+	/**
+	 * Get child comments of an activity or activity comment.
+	 *
+	 * @since BuddyPress (1.2)
+	 *
+	 * @global BuddyPress $bp The one true BuddyPress instance.
+	 * @global wpdb $wpdb WordPress database object.
+	 *
+	 * @param int $parent_id ID of an activty or activity comment.
+	 * @return object Numerically indexed array of child comments.
+	 */
+	public static function get_child_comments( $parent_id ) {
+		global $bp, $wpdb;
+
+		return $wpdb->get_results( $wpdb->prepare( "SELECT id FROM {$bp->activity->table_name} WHERE type = 'activity_comment' AND secondary_item_id = %d", $parent_id ) );
+	}
+
+	/**
+	 * Get a list of components that have recorded activity associated with them
+	 *
+	 * @return array List of component names.
+	 */
+	public static function get_recorded_components() {
+		global $wpdb, $bp;
+		return $wpdb->get_col( "SELECT DISTINCT component FROM {$bp->activity->table_name} ORDER BY component ASC" );
+	}
+
+	/**
+	 * Get sitewide activity items for use in an RSS feed.
+	 *
+	 * @param int $limit Optional. Number of items to fetch. Default: 35.
+	 * @return array $activity_feed List of activity items, with RSS data added.
+	 */
+	public static function get_sitewide_items_for_feed( $limit = 35 ) {
+		$activities    = bp_activity_get_sitewide( array( 'max' => $limit ) );
+		$activity_feed = array();
+
+		for ( $i = 0, $count = count( $activities ); $i < $count; ++$i ) {
+			$title                            = explode( '<span', $activities[$i]['content'] );
+			$activity_feed[$i]['title']       = trim( strip_tags( $title[0] ) );
+			$activity_feed[$i]['link']        = $activities[$i]['primary_link'];
+			$activity_feed[$i]['description'] = @sprintf( $activities[$i]['content'], '' );
+			$activity_feed[$i]['pubdate']     = $activities[$i]['date_recorded'];
+		}
+
+		return $activity_feed;
+	}
+
+	/**
+	 * Create SQL IN clause for filter queries.
+	 *
+	 * @since BuddyPress (1.5)
+	 *
+	 * @see BP_Activity_Activity::get_filter_sql()
+	 *
+	 * @param string $field The database field.
+	 * @param array|bool $items The values for the IN clause, or false when none are found.
+	 */
+	public static function get_in_operator_sql( $field, $items ) {
+		global $wpdb;
+
+		// split items at the comma
+		$items_dirty = explode( ',', $items );
+
+		// array of prepared integers or quoted strings
+		$items_prepared = array();
+
+		// clean up and format each item
+		foreach ( $items_dirty as $item ) {
+			// clean up the string
+			$item = trim( $item );
+			// pass everything through prepare for security and to safely quote strings
+			$items_prepared[] = ( is_numeric( $item ) ) ? $wpdb->prepare( '%d', $item ) : $wpdb->prepare( '%s', $item );
+		}
+
+		// build IN operator sql syntax
+		if ( count( $items_prepared ) )
+			return sprintf( '%s IN ( %s )', trim( $field ), implode( ',', $items_prepared ) );
+		else
+			return false;
+	}
+
+	/**
+	 * Create filter SQL clauses.
+	 *
+	 * @since BuddyPress (1.5)
+	 *
+	 * @param array $filter_array Fields and values to filter by. Should be
+	 *     in the format:
+	 *         $filter_array = array(
+	 *             'filter1' => $value,
+	 *             'filter2' => $value,
+	 *         )
+	 *     Possible filters are as follows. Each can be either a single
+	 *     string, a comma-separated list, or an array of values.
+	 *       - 'user_id' User ID(s)
+	 *       - 'object' Corresponds to the 'component' column in the database.
+	 *       - 'action' Corresponds to the 'type' column in the database.
+	 *       - 'primary_id' Corresponds to the 'item_id' column in the database.
+	 *       - 'secondary_id' Corresponds to the 'secondary_item_id' column in the database.
+	 * @return string The filter clause, for use in a SQL query.
+	 */
+	public static function get_filter_sql( $filter_array ) {
+
+		$filter_sql = array();
+
+		if ( !empty( $filter_array['user_id'] ) ) {
+			$user_sql = BP_Activity_Activity::get_in_operator_sql( 'a.user_id', $filter_array['user_id'] );
+			if ( !empty( $user_sql ) )
+				$filter_sql[] = $user_sql;
+		}
+
+		if ( !empty( $filter_array['object'] ) ) {
+			$object_sql = BP_Activity_Activity::get_in_operator_sql( 'a.component', $filter_array['object'] );
+			if ( !empty( $object_sql ) )
+				$filter_sql[] = $object_sql;
+		}
+
+		if ( !empty( $filter_array['action'] ) ) {
+			$action_sql = BP_Activity_Activity::get_in_operator_sql( 'a.type', $filter_array['action'] );
+			if ( !empty( $action_sql ) )
+				$filter_sql[] = $action_sql;
+		}
+
+		if ( !empty( $filter_array['primary_id'] ) ) {
+			$pid_sql = BP_Activity_Activity::get_in_operator_sql( 'a.item_id', $filter_array['primary_id'] );
+			if ( !empty( $pid_sql ) )
+				$filter_sql[] = $pid_sql;
+		}
+
+		if ( !empty( $filter_array['secondary_id'] ) ) {
+			$sid_sql = BP_Activity_Activity::get_in_operator_sql( 'a.secondary_item_id', $filter_array['secondary_id'] );
+			if ( !empty( $sid_sql ) )
+				$filter_sql[] = $sid_sql;
+		}
+
+		if ( empty( $filter_sql ) )
+			return false;
+
+		return join( ' AND ', $filter_sql );
+	}
+
+	/**
+	 * Get the date/time of last recorded activity.
+	 *
+	 * @since BuddyPress (1.2)
+	 *
+	 * @return string ISO timestamp.
+	 */
+	public static function get_last_updated() {
+		global $bp, $wpdb;
+
+		return $wpdb->get_var( "SELECT date_recorded FROM {$bp->activity->table_name} ORDER BY date_recorded DESC LIMIT 1" );
+	}
+
+	/**
+	 * Get favorite count for a given user.
+	 *
+	 * @since BuddyPress (1.2)
+	 *
+	 * @param int The ID of the user whose favorites you're counting.
+	 * @return int A count of the user's favorites.
+	 */
+	public static function total_favorite_count( $user_id ) {
+		if ( !$favorite_activity_entries = bp_get_user_meta( $user_id, 'bp_favorite_activities', true ) )
+			return 0;
+
+		return count( maybe_unserialize( $favorite_activity_entries ) );
+	}
+
+	/**
+	 * Check whether an activity item exists with a given string content.
+	 *
+	 * @param string $content The content to filter by.
+	 * @return int|bool The ID of the first matching item if found, otherwise false.
+	 */
+	public static function check_exists_by_content( $content ) {
+		global $wpdb, $bp;
+
+		return $wpdb->get_var( $wpdb->prepare( "SELECT id FROM {$bp->activity->table_name} WHERE content = %s", $content ) );
+	}
+
+	/**
+	 * Hide all activity for a given user.
+	 *
+	 * @param int $user_id The ID of the user whose activity you want to mark hidden.
+	 * @param int
+	 */
+	public static function hide_all_for_user( $user_id ) {
+		global $wpdb, $bp;
+
+		return $wpdb->get_var( $wpdb->prepare( "UPDATE {$bp->activity->table_name} SET hide_sitewide = 1 WHERE user_id = %d", $user_id ) );
+	}
+}
+
+/**
+ * Create a RSS feed using the activity component.
+ *
+ * You should only construct a new feed when you've validated that you're on
+ * the appropriate screen.
+ *
+ * See {@link bp_activity_action_sitewide_feed()} as an example.
+ *
+ * Accepted parameters:
+ *   id	              - internal id for the feed; should be alphanumeric only
+ *                      (required)
+ *   title            - RSS feed title
+ *   link             - Relevant link for the RSS feed
+ *   description      - RSS feed description
+ *   ttl              - Time-to-live (see inline doc in constructor)
+ *   update_period    - Part of the syndication module (see inline doc in
+ *                      constructor for more info)
+ *   update_frequency - Part of the syndication module (see inline doc in
+ *                      constructor for more info)
+ *   max              - Number of feed items to display
+ *   activity_args    - Arguments passed to {@link bp_has_activities()}
+ *
+ * @since BuddyPress (1.8)
+ */
+class BP_Activity_Feed {
+	/**
+	 * Holds our custom class properties.
+	 *
+	 * These variables are stored in a protected array that is magically
+	 * updated using PHP 5.2+ methods.
+	 *
+	 * @see BP_Feed::__construct() This is where $data is added
+	 * @var array
+	 */
+	protected $data;
+
+	/**
+	 * Magic method for checking the existence of a certain data variable.
+	 *
+	 * @param string $key
+	 */
+	public function __isset( $key ) { return isset( $this->data[$key] ); }
+
+	/**
+	 * Magic method for getting a certain data variable.
+	 *
+	 * @param string $key
+	 */
+	public function __get( $key ) { return isset( $this->data[$key] ) ? $this->data[$key] : null; }
+
+	/**
+	 * Constructor.
+	 *
+	 * @param array $args Optional
+	 */
+	public function __construct( $args = array() ) {
+		// If feeds are disabled, stop now!
+		if ( false === (bool) apply_filters( 'bp_activity_enable_feeds', true ) ) {
+			global $wp_query;
+
+			// set feed flag to false
+			$wp_query->is_feed = false;
+
+			return false;
+		}
+
+		// Setup data
+		$this->data = wp_parse_args( $args, array(
+			// Internal identifier for the RSS feed - should be alphanumeric only
+			'id'               => '',
+
+			// RSS title - should be plain-text
+			'title'            => '',
+
+			// relevant link for the RSS feed
+			'link'             => '',
+
+			// RSS description - should be plain-text
+			'description'      => '',
+
+			// Time-to-live - number of minutes to cache the data before an aggregator
+			// requests it again.  This is only acknowledged if the RSS client supports it
+			//
+			// See: http://www.rssboard.org/rss-profile#element-channel-ttl
+			//      http://www.kbcafe.com/rss/rssfeedstate.html#ttl
+			'ttl'              => '30',
+
+			// Syndication module - similar to ttl, but not really supported by RSS
+			// clients
+			//
+			// See: http://web.resource.org/rss/1.0/modules/syndication/#description
+			//      http://www.kbcafe.com/rss/rssfeedstate.html#syndicationmodule
+			'update_period'    => 'hourly',
+			'update_frequency' => 2,
+
+			// Number of items to display
+			'max'              => 50,
+
+			// Activity arguments passed to bp_has_activities()
+			'activity_args'    => array()
+		) );
+
+		// Plugins can use this filter to modify the feed before it is setup
+		do_action_ref_array( 'bp_activity_feed_prefetch', array( &$this ) );
+
+		// Setup class properties
+		$this->setup_properties();
+
+		// Check if id is valid
+		if ( empty( $this->id ) ) {
+			_doing_it_wrong( 'BP_Activity_Feed', __( "RSS feed 'id' must be defined", 'buddypress' ), 'BP 1.8' );
+			return false;
+		}
+
+		// Plugins can use this filter to modify the feed after it's setup
+		do_action_ref_array( 'bp_activity_feed_postfetch', array( &$this ) );
+
+		// Setup feed hooks
+		$this->setup_hooks();
+
+		// Output the feed
+		$this->output();
+
+		// Kill the rest of the output
+		die();
+	}
+
+	/** SETUP ****************************************************************/
+
+	/**
+	 * Setup and validate the class properties.
+	 *
+	 * @access protected
+	 */
+	protected function setup_properties() {
+		$this->id               = sanitize_title( $this->id );
+		$this->title            = strip_tags( $this->title );
+		$this->link             = esc_url_raw( $this->link );
+		$this->description      = strip_tags( $this->description );
+		$this->ttl              = (int) $this->ttl;
+		$this->update_period    = strip_tags( $this->update_period );
+		$this->update_frequency = (int) $this->update_frequency;
+
+		$this->activity_args    = wp_parse_args( $this->activity_args, array(
+			'max'              => $this->max,
+			'per_page'         => $this->max,
+			'display_comments' => 'stream'
+		) );
+
+	}
+
+	/**
+	 * Setup some hooks that are used in the feed.
+	 *
+	 * Currently, these hooks are used to maintain backwards compatibility with
+	 * the RSS feeds previous to BP 1.8.
+	 *
+	 * @access protected
+	 */
+	protected function setup_hooks() {
+		add_action( 'bp_activity_feed_rss_attributes',   array( $this, 'backpat_rss_attributes' ) );
+		add_action( 'bp_activity_feed_channel_elements', array( $this, 'backpat_channel_elements' ) );
+		add_action( 'bp_activity_feed_item_elements',    array( $this, 'backpat_item_elements' ) );
+	}
+
+	/** BACKPAT HOOKS ********************************************************/
+
+	/**
+	 * Fire a hook to ensure backward compatibility for RSS attributes.
+	 */
+	public function backpat_rss_attributes() {
+		do_action( 'bp_activity_' . $this->id . '_feed' );
+	}
+
+	/**
+	 * Fire a hook to ensure backward compatibility for channel elements.
+	 */
+	public function backpat_channel_elements() {
+		do_action( 'bp_activity_' . $this->id . '_feed_head' );
+	}
+
+	/**
+	 * Fire a hook to ensure backward compatibility for item elements.
+	 */
+	public function backpat_item_elements() {
+		switch ( $this->id ) {
+
+			// sitewide and friends feeds use the 'personal' hook
+			case 'sitewide' :
+			case 'friends' :
+				$id = 'personal';
+
+				break;
+
+			default :
+				$id = $this->id;
+
+				break;
+		}
+
+		do_action( 'bp_activity_' . $id . '_feed_item' );
+	}
+
+	/** HELPERS **************************************************************/
+
+	/**
+	 * Output the feed's item content.
+	 *
+	 * @access protected
+	 */
+	protected function feed_content() {
+		bp_activity_content_body();
+
+		switch ( $this->id ) {
+
+			// also output parent activity item if we're on a specific feed
+			case 'favorites' :
+			case 'friends' :
+			case 'mentions' :
+			case 'personal' :
+
+				if ( 'activity_comment' == bp_get_activity_action_name() ) :
+			?>
+				<strong><?php _e( 'In reply to', 'buddypress' ) ?></strong> -
+				<?php bp_activity_parent_content() ?>
+			<?php
+				endif;
+
+				break;
+		}
+	}
+
+	/**
+	 * Sets various HTTP headers related to Content-Type and browser caching.
+	 *
+	 * Most of this class method is derived from {@link WP::send_headers()}.
+	 *
+	 * @since BuddyPress (1.9.0)
+	 *
+	 * @access protected
+	 */
+	protected function http_headers() {
+		// set up some additional headers if not on a directory page
+		// this is done b/c BP uses pseudo-pages
+		if ( ! bp_is_directory() ) {
+			global $wp_query;
+
+			$wp_query->is_404 = false;
+			status_header( 200 );
+		}
+
+		// Set content-type
+		@header( 'Content-Type: text/xml; charset=' . get_option( 'blog_charset' ), true );
+
+		// Cache-related variables
+		$last_modified      = mysql2date( 'D, d M Y H:i:s O', bp_activity_get_last_updated(), false );
+		$modified_timestamp = strtotime( $last_modified );
+		$etag               = md5( $last_modified );
+
+		// Set cache-related headers
+		@header( 'Last-Modified: ' . $last_modified );
+		@header( 'Pragma: no-cache' );
+		@header( 'ETag: ' . '"' . $etag . '"' );
+
+		// First commit of BuddyPress! (Easter egg)
+		@header( 'Expires: Tue, 25 Mar 2008 17:13:55 GMT');
+
+		// Get ETag from supported user agents
+		if ( isset( $_SERVER['HTTP_IF_NONE_MATCH'] ) ) {
+			$client_etag = wp_unslash( $_SERVER['HTTP_IF_NONE_MATCH'] );
+
+			// Remove quotes from ETag
+			$client_etag = trim( $client_etag, '"' );
+
+			// Strip suffixes from ETag if they exist (eg. "-gzip")
+			if ( $etag_suffix_pos = strpos( $client_etag, '-' ) ) {
+				$client_etag = substr( $client_etag, 0, $etag_suffix_pos );
+			}
+
+		// No ETag found
+		} else {
+			$client_etag = false;
+		}
+
+		// Get client last modified timestamp from supported user agents
+		$client_last_modified      = empty( $_SERVER['HTTP_IF_MODIFIED_SINCE'] ) ? '' : trim( $_SERVER['HTTP_IF_MODIFIED_SINCE'] );
+		$client_modified_timestamp = $client_last_modified ? strtotime( $client_last_modified ) : 0;
+
+		// Set 304 status if feed hasn't been updated since last fetch
+		if ( ( $client_last_modified && $client_etag ) ?
+				 ( ( $client_modified_timestamp >= $modified_timestamp ) && ( $client_etag == $etag ) ) :
+				 ( ( $client_modified_timestamp >= $modified_timestamp ) || ( $client_etag == $etag ) ) ) {
+			$status = 304;
+		} else {
+			$status = false;
+		}
+
+		// If feed hasn't changed as reported by the user agent, set 304 status header
+		if ( ! empty( $status ) ) {
+			status_header( $status );
+
+			// cached response, so stop now!
+			if ( $status == 304 ) {
+				exit();
+			}
+		}
+	}
+
+	/** OUTPUT ***************************************************************/
+
+	/**
+	 * Output the RSS feed.
+	 *
+	 * @access protected
+	 */
+	protected function output() {
+		$this->http_headers();
+		echo '<?xml version="1.0" encoding="' . get_option( 'blog_charset' ) . '"?'.'>';
+	?>
+
+<rss version="2.0"
+	xmlns:content="http://purl.org/rss/1.0/modules/content/"
+	xmlns:atom="http://www.w3.org/2005/Atom"
+	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
+	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
+	<?php do_action( 'bp_activity_feed_rss_attributes' ); ?>
+>
+
+<channel>
+	<title><?php echo $this->title; ?></title>
+	<link><?php echo $this->link; ?></link>
+	<atom:link href="<?php self_link(); ?>" rel="self" type="application/rss+xml" />
+	<description><?php echo $this->description ?></description>
+	<lastBuildDate><?php echo mysql2date( 'D, d M Y H:i:s O', bp_activity_get_last_updated(), false ); ?></lastBuildDate>
+	<generator>http://buddypress.org/?v=<?php bp_version(); ?></generator>
+	<language><?php bloginfo_rss( 'language' ); ?></language>
+	<ttl><?php echo $this->ttl; ?></ttl>
+	<sy:updatePeriod><?php echo $this->update_period; ?></sy:updatePeriod>
+ 	<sy:updateFrequency><?php echo $this->update_frequency; ?></sy:updateFrequency>
+	<?php do_action( 'bp_activity_feed_channel_elements' ); ?>
+
+	<?php if ( bp_has_activities( $this->activity_args ) ) : ?>
+		<?php while ( bp_activities() ) : bp_the_activity(); ?>
+			<item>
+				<guid isPermaLink="false"><?php bp_activity_feed_item_guid(); ?></guid>
+				<title><?php echo stripslashes( bp_get_activity_feed_item_title() ); ?></title>
+				<link><?php bp_activity_thread_permalink() ?></link>
+				<pubDate><?php echo mysql2date( 'D, d M Y H:i:s O', bp_get_activity_feed_item_date(), false ); ?></pubDate>
+
+				<?php if ( bp_get_activity_feed_item_description() ) : ?>
+					<content:encoded><![CDATA[<?php $this->feed_content(); ?>]]></content:encoded>
+				<?php endif; ?>
+
+				<?php if ( bp_activity_can_comment() ) : ?>
+					<slash:comments><?php bp_activity_comment_count(); ?></slash:comments>
+				<?php endif; ?>
+
+				<?php do_action( 'bp_activity_feed_item_elements' ); ?>
+			</item>
+		<?php endwhile; ?>
+
+	<?php endif; ?>
+</channel>
+</rss><?php
+	}
+}
Index: /tags/1.9/bp-activity/bp-activity-filters.php
===================================================================
--- /tags/1.9/bp-activity/bp-activity-filters.php	(revision 7684)
+++ /tags/1.9/bp-activity/bp-activity-filters.php	(revision 7684)
@@ -0,0 +1,378 @@
+<?php
+
+/**
+ * Filters related to the Activity component.
+ *
+ * @package BuddyPress
+ * @subpackage ActivityFilters
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/** Filters *******************************************************************/
+
+// Apply WordPress defined filters
+add_filter( 'bp_get_activity_action',                'bp_activity_filter_kses', 1 );
+add_filter( 'bp_get_activity_content_body',          'bp_activity_filter_kses', 1 );
+add_filter( 'bp_get_activity_content',               'bp_activity_filter_kses', 1 );
+add_filter( 'bp_get_activity_parent_content',        'bp_activity_filter_kses', 1 );
+add_filter( 'bp_get_activity_latest_update',         'bp_activity_filter_kses', 1 );
+add_filter( 'bp_get_activity_latest_update_excerpt', 'bp_activity_filter_kses', 1 );
+add_filter( 'bp_get_activity_feed_item_description', 'bp_activity_filter_kses', 1 );
+add_filter( 'bp_activity_content_before_save',       'bp_activity_filter_kses', 1 );
+add_filter( 'bp_activity_action_before_save',        'bp_activity_filter_kses', 1 );
+add_filter( 'bp_activity_latest_update_content',     'wp_filter_kses', 1 );
+
+add_filter( 'bp_get_activity_action',                'force_balance_tags' );
+add_filter( 'bp_get_activity_content_body',          'force_balance_tags' );
+add_filter( 'bp_get_activity_content',               'force_balance_tags' );
+add_filter( 'bp_get_activity_latest_update',         'force_balance_tags' );
+add_filter( 'bp_get_activity_latest_update_excerpt', 'force_balance_tags' );
+add_filter( 'bp_get_activity_feed_item_description', 'force_balance_tags' );
+add_filter( 'bp_activity_content_before_save',       'force_balance_tags' );
+add_filter( 'bp_activity_action_before_save',        'force_balance_tags' );
+
+add_filter( 'bp_get_activity_action',                'wptexturize' );
+add_filter( 'bp_get_activity_content_body',          'wptexturize' );
+add_filter( 'bp_get_activity_content',               'wptexturize' );
+add_filter( 'bp_get_activity_parent_content',        'wptexturize' );
+add_filter( 'bp_get_activity_latest_update',         'wptexturize' );
+add_filter( 'bp_get_activity_latest_update_excerpt', 'wptexturize' );
+
+add_filter( 'bp_get_activity_action',                'convert_smilies' );
+add_filter( 'bp_get_activity_content_body',          'convert_smilies' );
+add_filter( 'bp_get_activity_content',               'convert_smilies' );
+add_filter( 'bp_get_activity_parent_content',        'convert_smilies' );
+add_filter( 'bp_get_activity_latest_update',         'convert_smilies' );
+add_filter( 'bp_get_activity_latest_update_excerpt', 'convert_smilies' );
+
+add_filter( 'bp_get_activity_action',                'convert_chars' );
+add_filter( 'bp_get_activity_content_body',          'convert_chars' );
+add_filter( 'bp_get_activity_content',               'convert_chars' );
+add_filter( 'bp_get_activity_parent_content',        'convert_chars' );
+add_filter( 'bp_get_activity_latest_update',         'convert_chars' );
+add_filter( 'bp_get_activity_latest_update_excerpt', 'convert_chars' );
+
+add_filter( 'bp_get_activity_action',                'wpautop' );
+add_filter( 'bp_get_activity_content_body',          'wpautop' );
+add_filter( 'bp_get_activity_content',               'wpautop' );
+add_filter( 'bp_get_activity_feed_item_description', 'wpautop' );
+
+add_filter( 'bp_get_activity_action',                'make_clickable', 9 );
+add_filter( 'bp_get_activity_content_body',          'make_clickable', 9 );
+add_filter( 'bp_get_activity_content',               'make_clickable', 9 );
+add_filter( 'bp_get_activity_parent_content',        'make_clickable', 9 );
+add_filter( 'bp_get_activity_latest_update',         'make_clickable', 9 );
+add_filter( 'bp_get_activity_latest_update_excerpt', 'make_clickable', 9 );
+add_filter( 'bp_get_activity_feed_item_description', 'make_clickable', 9 );
+
+add_filter( 'bp_acomment_name',                      'stripslashes_deep' );
+add_filter( 'bp_get_activity_action',                'stripslashes_deep' );
+add_filter( 'bp_get_activity_content',               'stripslashes_deep' );
+add_filter( 'bp_get_activity_content_body',          'stripslashes_deep' );
+add_filter( 'bp_get_activity_parent_content',        'stripslashes_deep' );
+add_filter( 'bp_get_activity_latest_update',         'stripslashes_deep' );
+add_filter( 'bp_get_activity_latest_update_excerpt', 'stripslashes_deep' );
+add_filter( 'bp_get_activity_feed_item_description', 'stripslashes_deep' );
+
+add_filter( 'bp_activity_primary_link_before_save',  'esc_url_raw' );
+
+// Apply BuddyPress-defined filters
+add_filter( 'bp_get_activity_content',               'bp_activity_make_nofollow_filter' );
+add_filter( 'bp_get_activity_content_body',          'bp_activity_make_nofollow_filter' );
+add_filter( 'bp_get_activity_parent_content',        'bp_activity_make_nofollow_filter' );
+add_filter( 'bp_get_activity_latest_update',         'bp_activity_make_nofollow_filter' );
+add_filter( 'bp_get_activity_latest_update_excerpt', 'bp_activity_make_nofollow_filter' );
+add_filter( 'bp_get_activity_feed_item_description', 'bp_activity_make_nofollow_filter' );
+
+add_filter( 'pre_comment_content',                   'bp_activity_at_name_filter' );
+add_filter( 'group_forum_topic_text_before_save',    'bp_activity_at_name_filter' );
+add_filter( 'group_forum_post_text_before_save',     'bp_activity_at_name_filter' );
+add_filter( 'the_content',                           'bp_activity_at_name_filter' );
+
+add_filter( 'bp_get_activity_parent_content',        'bp_create_excerpt' );
+
+add_filter( 'bp_get_activity_content_body', 'bp_activity_truncate_entry', 5 );
+add_filter( 'bp_get_activity_content',      'bp_activity_truncate_entry', 5 );
+
+/** Actions *******************************************************************/
+
+// At-name filter
+add_action( 'bp_activity_before_save', 'bp_activity_at_name_filter_updates' );
+
+// Activity stream moderation
+add_action( 'bp_activity_before_save', 'bp_activity_check_moderation_keys', 2, 1 );
+add_action( 'bp_activity_before_save', 'bp_activity_check_blacklist_keys',  2, 1 );
+
+/** Functions *****************************************************************/
+
+/**
+ * Types of activity stream items to moderate.
+ *
+ * @since BuddyPress (1.6)
+ *
+ * @return array $types List of the activity types to moderate.
+ */
+function bp_activity_get_moderated_activity_types() {
+	$types = array(
+		'activity_comment',
+		'activity_update'
+	);
+	return apply_filters( 'bp_activity_check_activity_types', $types );
+}
+
+/**
+ * Moderate the posted activity item, if it contains moderate keywords.
+ *
+ * @since BuddyPress (1.6)
+ *
+ * @param BP_Activity_Activity $activity The activity object to check.
+ */
+function bp_activity_check_moderation_keys( $activity ) {
+
+	// Only check specific types of activity updates
+	if ( !in_array( $activity->type, bp_activity_get_moderated_activity_types() ) )
+		return;
+
+	// Unset the activity component so activity stream update fails
+	// @todo This is temporary until some kind of moderation is built
+	if ( !bp_core_check_for_moderation( $activity->user_id, '', $activity->content ) )
+		$activity->component = false;
+}
+
+/**
+ * Mark the posted activity as spam, if it contains blacklist keywords.
+ *
+ * @since BuddyPress (1.6)
+ *
+ * @param BP_Activity_Activity $activity The activity object to check.
+ */
+function bp_activity_check_blacklist_keys( $activity ) {
+
+	// Only check specific types of activity updates
+	if ( ! in_array( $activity->type, bp_activity_get_moderated_activity_types() ) )
+		return;
+
+	// Mark as spam
+	if ( ! bp_core_check_for_blacklist( $activity->user_id, '', $activity->content ) )
+		bp_activity_mark_as_spam( $activity, 'by_blacklist' );
+}
+
+/**
+ * Custom kses filtering for activity content.
+ *
+ * @since BuddyPress (1.1)
+ *
+ * @uses apply_filters() To call the 'bp_activity_allowed_tags' hook.
+ * @uses wp_kses()
+ *
+ * @param string $content The activity content.
+ * @return string $content Filtered activity content.
+ */
+function bp_activity_filter_kses( $content ) {
+	global $allowedtags;
+
+	$activity_allowedtags = $allowedtags;
+	$activity_allowedtags['span']          = array();
+	$activity_allowedtags['span']['class'] = array();
+	$activity_allowedtags['a']['class']    = array();
+	$activity_allowedtags['a']['id']       = array();
+	$activity_allowedtags['a']['rel']      = array();
+	$activity_allowedtags['img']           = array();
+	$activity_allowedtags['img']['src']    = array();
+	$activity_allowedtags['img']['alt']    = array();
+	$activity_allowedtags['img']['class']  = array();
+	$activity_allowedtags['img']['width']  = array();
+	$activity_allowedtags['img']['height'] = array();
+	$activity_allowedtags['img']['class']  = array();
+	$activity_allowedtags['img']['id']     = array();
+	$activity_allowedtags['img']['title']  = array();
+	$activity_allowedtags['code']          = array();
+
+	$activity_allowedtags = apply_filters( 'bp_activity_allowed_tags', $activity_allowedtags );
+	return wp_kses( $content, $activity_allowedtags );
+}
+
+/**
+ * Finds and links @-mentioned users in the contents of a given item.
+ *
+ * @since BuddyPress (1.2)
+ *
+ * @uses bp_activity_find_mentions()
+ * @uses bp_core_get_user_domain()
+ *
+ * @param string $content The contents of a given item.
+ * @param int $activity_id The activity id. Deprecated.
+ * @return string $content Content filtered for mentions.
+ */
+function bp_activity_at_name_filter( $content, $activity_id = 0 ) {
+
+	// Are mentions disabled?
+	if ( ! bp_activity_do_mentions() ) {
+		return $content;
+	}
+
+	// Try to find mentions
+	$usernames = bp_activity_find_mentions( $content );
+
+	// No mentions? Stop now!
+	if ( empty( $usernames ) )
+		return $content;
+
+	// Linkify the mentions with the username
+	foreach( (array) $usernames as $user_id => $username ) {
+		$content = preg_replace( '/(@' . $username . '\b)/', "<a href='" . bp_core_get_user_domain( $user_id ) . "' rel='nofollow'>@$username</a>", $content );
+	}
+
+	// Return the content
+	return $content;
+}
+
+/**
+ * Catch mentions in an activity item before it is saved into the database.
+ *
+ * If mentions are found, replace @mention text with user links and add our
+ * hook to send mention notifications after the activity item is saved.
+ *
+ * @since BuddyPress (1.5)
+ *
+ * @uses bp_activity_find_mentions()
+ *
+ * @param BP_Activity_Activity $activity
+ */
+function bp_activity_at_name_filter_updates( $activity ) {
+	// Are mentions disabled?
+	if ( ! bp_activity_do_mentions() ) {
+		return;
+	}
+
+	// If activity was marked as spam, stop the rest of this function.
+	if ( ! empty( $activity->is_spam ) )
+		return;
+
+	// Try to find mentions
+	$usernames = bp_activity_find_mentions( $activity->content );
+
+	// We have mentions!
+	if ( ! empty( $usernames ) ) {
+		// Replace @mention text with userlinks
+		foreach( (array) $usernames as $user_id => $username ) {
+			$activity->content = preg_replace( '/(@' . $username . '\b)/', "<a href='" . bp_core_get_user_domain( $user_id ) . "' rel='nofollow'>@$username</a>", $activity->content );
+		}
+
+		// Add our hook to send @mention emails after the activity item is saved
+		add_action( 'bp_activity_after_save', 'bp_activity_at_name_send_emails' );
+
+		// temporary variable to avoid having to run bp_activity_find_mentions() again
+		buddypress()->activity->mentioned_users = $usernames;
+	}
+}
+
+/**
+ * Sends emails and BP notifications for users @-mentioned in an activity item.
+ *
+ * @since BuddyPress (1.7)
+ *
+ * @uses bp_activity_at_message_notification()
+ * @uses bp_activity_update_mention_count_for_user()
+ *
+ * @param BP_Activity_Activity $activity The BP_Activity_Activity object
+ */
+function bp_activity_at_name_send_emails( $activity ) {
+	// Are mentions disabled?
+	if ( ! bp_activity_do_mentions() ) {
+		return;
+	}
+
+	// If our temporary variable doesn't exist, stop now.
+	if ( empty( buddypress()->activity->mentioned_users ) )
+		return;
+
+	// Grab our temporary variable from bp_activity_at_name_filter_updates()
+	$usernames = buddypress()->activity->mentioned_users;
+
+	// Get rid of temporary variable
+	unset( buddypress()->activity->mentioned_users );
+
+	// Send @mentions and setup BP notifications
+	foreach( (array) $usernames as $user_id => $username ) {
+		// If you want to disable notifications, you can use this filter to stop email sending
+		if ( apply_filters( 'bp_activity_at_name_do_notifications', true, $usernames ) ) {
+			bp_activity_at_message_notification( $activity->id, $user_id );
+		}
+
+		// Updates mention count for the user
+		bp_activity_update_mention_count_for_user( $user_id, $activity->id );
+	}
+}
+
+/**
+ * Catch links in activity text so rel=nofollow can be added.
+ *
+ * @since BuddyPress (1.2)
+ *
+ * @param string $text Activity text.
+ * @return string $text Text with rel=nofollow added to any links.
+ */
+function bp_activity_make_nofollow_filter( $text ) {
+	return preg_replace_callback( '|<a (.+?)>|i', 'bp_activity_make_nofollow_filter_callback', $text );
+}
+
+	/**
+	 * Add rel=nofollow to a link.
+	 *
+	 * @since BuddyPress (1.2)
+	 *
+	 * @param array $matches
+	 *
+	 * @param array $matches Items matched by preg_replace_callback() in bp_activity_make_nofollow_filter().
+	 * @return string $text Link with rel=nofollow added
+	 */
+	function bp_activity_make_nofollow_filter_callback( $matches ) {
+		$text = $matches[1];
+		$text = str_replace( array( ' rel="nofollow"', " rel='nofollow'"), '', $text );
+		return "<a $text rel=\"nofollow\">";
+	}
+
+/**
+ * Truncate long activity entries when viewed in activity streams.
+ *
+ * @since BuddyPress (1.5)
+ *
+ * @uses bp_is_single_activity()
+ * @uses apply_filters() To call the 'bp_activity_excerpt_append_text' hook.
+ * @uses apply_filters() To call the 'bp_activity_excerpt_length' hook.
+ * @uses bp_create_excerpt()
+ * @uses bp_get_activity_id()
+ * @uses bp_get_activity_thread_permalink()
+ * @uses apply_filters() To call the 'bp_activity_truncate_entry' hook.
+ *
+ * @param string $text The original activity entry text.
+ * @return string $excerpt The truncated text.
+ */
+function bp_activity_truncate_entry( $text ) {
+	global $activities_template;
+
+	// The full text of the activity update should always show on the single activity screen
+	if ( bp_is_single_activity() )
+		return $text;
+
+	$append_text    = apply_filters( 'bp_activity_excerpt_append_text', __( '[Read more]', 'buddypress' ) );
+	$excerpt_length = apply_filters( 'bp_activity_excerpt_length', 358 );
+
+	// Run the text through the excerpt function. If it's too short, the original text will be
+	// returned.
+	$excerpt        = bp_create_excerpt( $text, $excerpt_length, array( 'ending' => __( '&hellip;', 'buddypress' ) ) );
+
+	// If the text returned by bp_create_excerpt() is different from the original text (ie it's
+	// been truncated), add the "Read More" link. Note that bp_create_excerpt() is stripping
+	// shortcodes, so we have strip them from the $text before the comparison
+	if ( $excerpt != strip_shortcodes( $text ) ) {
+		$id = !empty( $activities_template->activity->current_comment->id ) ? 'acomment-read-more-' . $activities_template->activity->current_comment->id : 'activity-read-more-' . bp_get_activity_id();
+
+		$excerpt = sprintf( '%1$s<span class="activity-read-more" id="%2$s"><a href="%3$s" rel="nofollow">%4$s</a></span>', $excerpt, $id, bp_get_activity_thread_permalink(), $append_text );
+	}
+
+	return apply_filters( 'bp_activity_truncate_entry', $excerpt, $text, $append_text );
+}
Index: /tags/1.9/bp-activity/bp-activity-functions.php
===================================================================
--- /tags/1.9/bp-activity/bp-activity-functions.php	(revision 7684)
+++ /tags/1.9/bp-activity/bp-activity-functions.php	(revision 7684)
@@ -0,0 +1,1862 @@
+<?php
+
+/**
+ * BuddyPress Activity Functions.
+ *
+ * Functions for the Activity Streams component.
+ *
+ * @package BuddyPress
+ * @subpackage ActivityFunctions
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/**
+ * Check whether the $bp global lists an activity directory page.
+ *
+ * @since BuddyPress (1.5)
+ *
+ * @global object $bp BuddyPress global settings
+ *
+ * @return bool True if activity directory page is found, otherwise false.
+ */
+function bp_activity_has_directory() {
+	global $bp;
+
+	return (bool) !empty( $bp->pages->activity->id );
+}
+
+/**
+ * Are mentions enabled or disabled?
+ *
+ * The Mentions feature does a number of things, all of which will be turned
+ * off if you disable mentions:
+ *   - Detecting and auto-linking @username in all BP/WP content
+ *   - Sending BP notifications and emails to users when they are mentioned
+ *     using the @username syntax
+ *   - The Public Message button on user profiles
+ *
+ * Mentions are enabled by default. To disable, put the following line in
+ * bp-custom.php or your theme's functions.php file:
+ *
+ *   add_filter( 'bp_activity_do_mentions', '__return_false' );
+ *
+ * @since BuddyPress (1.8)
+ *
+ * @uses apply_filters() To call 'bp_activity_do_mentions' hook.
+ *
+ * @return bool $retval True to enable mentions, false to disable.
+ */
+function bp_activity_do_mentions() {
+	return (bool) apply_filters( 'bp_activity_do_mentions', true );
+}
+
+/**
+ * Locate usernames in an activity content string, as designated by an @ sign.
+ *
+ * @since BuddyPress (1.5)
+ *
+ * @param string $content The content of the activity, usually found in $activity->content.
+ * @return array|bool Associative array with user ID as key and username as value. Boolean false if no mentions found.
+ */
+function bp_activity_find_mentions( $content ) {
+	$pattern = '/[@]+([A-Za-z0-9-_\.@]+)\b/';
+	preg_match_all( $pattern, $content, $usernames );
+
+	// Make sure there's only one instance of each username
+	if ( !$usernames = array_unique( $usernames[1] ) )
+		return false;
+
+	$mentioned_users = array();
+
+	// We've found some mentions! Check to see if users exist
+	foreach( (array) $usernames as $key => $username ) {
+		$user_id = bp_activity_get_userid_from_mentionname( $username );
+
+		// user ID exists, so let's add it to our array
+		if ( ! empty( $user_id ) ) {
+			$mentioned_users[$user_id] = $username;
+		}
+	}
+
+	if ( empty( $mentioned_users ) )
+		return false;
+
+	return $mentioned_users;
+}
+
+/**
+ * Reset a user's unread mentions list and count.
+ *
+ * @since BuddyPress (1.5)
+ *
+ * @uses bp_delete_user_meta()
+ *
+ * @param int $user_id The id of the user whose unread mentions are being reset.
+ */
+function bp_activity_clear_new_mentions( $user_id ) {
+	bp_delete_user_meta( $user_id, 'bp_new_mention_count' );
+	bp_delete_user_meta( $user_id, 'bp_new_mentions' );
+}
+
+/**
+ * Adjusts mention count for mentioned users in activity items.
+ *
+ * This function is useful if you only have the activity ID handy and you
+ * haven't parsed an activity item for @mentions yet.
+ *
+ * Currently, only used in {@link bp_activity_delete()}.
+ *
+ * @since BuddyPress (1.5)
+ *
+ * @uses bp_activity_find_mentions()
+ * @uses bp_activity_update_mention_count_for_user()
+ *
+ * @param int $activity_id The unique id for the activity item.
+ * @param string $action Can be 'delete' or 'add'. Defaults to 'add'.
+ */
+function bp_activity_adjust_mention_count( $activity_id = 0, $action = 'add' ) {
+	if ( empty( $activity_id ) )
+		return false;
+
+	// Get activity object
+	$activity = new BP_Activity_Activity( (int) $activity_id );
+
+	// Try to find mentions
+	$usernames = bp_activity_find_mentions( strip_tags( $activity->content ) );
+
+	// Still empty? Stop now
+	if ( empty( $usernames ) )
+		return false;
+
+	// Increment mention count foreach mentioned user
+	foreach( (array) $usernames as $user_id => $username ) {
+		bp_activity_update_mention_count_for_user( $user_id, $activity_id, $action );
+	}
+}
+
+/**
+ * Update the mention count for a given user.
+ *
+ * This function should be used when you've already parsed your activity item
+ * for @mentions.
+ *
+ * @since BuddyPress (1.7)
+ *
+ * @uses bp_get_user_meta()
+ * @uses bp_update_user_meta()
+ *
+ * @param int $user_id The user ID.
+ * @param int $activity_id The unique ID for the activity item.
+ * @param string $action 'delete' or 'add'. Default: 'add'.
+ * @return bool
+ */
+function bp_activity_update_mention_count_for_user( $user_id, $activity_id, $action = 'add' ) {
+	if ( empty( $user_id ) || empty( $activity_id ) )
+		return false;
+
+	// Adjust the mention list and count for the member
+	$new_mention_count = (int) bp_get_user_meta( $user_id, 'bp_new_mention_count', true );
+	if ( !$new_mentions = bp_get_user_meta( $user_id, 'bp_new_mentions', true ) )
+		$new_mentions = array();
+
+	switch ( $action ) {
+		case 'delete' :
+			$key = array_search( $activity_id, $new_mentions );
+
+			if ( $key !== false ) {
+				unset( $new_mentions[$key] );
+			}
+
+			break;
+
+		case 'add' :
+		default :
+			if ( !in_array( $activity_id, $new_mentions ) ) {
+				$new_mentions[] = (int) $activity_id;
+			}
+
+			break;
+	}
+
+	// Get an updated mention count
+	$new_mention_count = count( $new_mentions );
+
+	// Resave the user_meta
+	bp_update_user_meta( $user_id, 'bp_new_mention_count', $new_mention_count );
+	bp_update_user_meta( $user_id, 'bp_new_mentions',      $new_mentions );
+
+	return true;
+}
+
+/**
+ * Determine a user's "mentionname", the name used for that user in @-mentions.
+ *
+ * @since BuddyPress (1.9.0)
+ *
+ * @return string User name appropriate for @-mentions.
+ */
+function bp_activity_get_user_mentionname( $user_id ) {
+	$mentionname = '';
+
+	$userdata = bp_core_get_core_userdata( $user_id );
+
+	if ( $userdata ) {
+		if ( bp_is_username_compatibility_mode() ) {
+			$mentionname = str_replace( ' ', '-', $userdata->user_login );
+		} else {
+			$mentionname = $userdata->user_nicename;
+		}
+	}
+
+	return $mentionname;
+}
+
+/**
+ * Get a user ID from a "mentionname", the name used for a user in @-mentions.
+ *
+ * @since BuddyPress (1.9.0)
+ *
+ * @return int|bool ID of the user, if one is found. Otherwise false.
+ */
+function bp_activity_get_userid_from_mentionname( $mentionname ) {
+	$user_id = false;
+
+	// In username compatibility mode, hyphens are ambiguous between
+	// actual hyphens and converted spaces.
+	//
+	// @todo There is the potential for username clashes between 'foo bar'
+	// and 'foo-bar' in compatibility mode. Come up with a system for
+	// unique mentionnames.
+	if ( bp_is_username_compatibility_mode() ) {
+		// First, try the raw username
+		$userdata = get_user_by( 'login', $mentionname );
+
+		// Doing a direct query to use proper regex. Necessary to
+		// account for hyphens + spaces in the same user_login.
+		if ( empty( $userdata ) || ! is_a( $userdata, 'WP_User' ) ) {
+			global $wpdb;
+			$regex   = esc_sql( str_replace( '-', '[ \-]', $mentionname ) );
+			$user_id = $wpdb->get_var( "SELECT ID FROM {$wpdb->users} WHERE user_login REGEXP '{$regex}'" );
+		} else {
+			$user_id = $userdata->ID;
+		}
+
+	// When username compatibility mode is disabled, the mentionname is
+	// the same as the nicename
+	} else {
+		$user_id = bp_core_get_userid_from_nicename( $mentionname );
+	}
+
+
+	return $user_id;
+}
+
+/** Actions ******************************************************************/
+
+/**
+ * Set the current action for a given activity stream location.
+ *
+ * @since BuddyPress (1.1)
+ *
+ * @global object $bp BuddyPress global settings
+ * @uses apply_filters() To call the 'bp_activity_set_action' hook
+ *
+ * @param string $component_id The unique string ID of the component.
+ * @param string $key The action key.
+ * @param string $value The action value.
+ * @return bool False if any param is empty, otherwise true.
+ */
+function bp_activity_set_action( $component_id, $key, $value ) {
+	global $bp;
+
+	// Return false if any of the above values are not set
+	if ( empty( $component_id ) || empty( $key ) || empty( $value ) )
+		return false;
+
+	// Set activity action
+	if ( !isset( $bp->activity->actions ) || !is_object( $bp->activity->actions ) ) {
+		$bp->activity->actions = new stdClass;
+	}
+
+	if ( !isset( $bp->activity->actions->{$component_id} ) || !is_object( $bp->activity->actions->{$component_id} ) ) {
+		$bp->activity->actions->{$component_id} = new stdClass;
+	}
+
+	$bp->activity->actions->{$component_id}->{$key} = apply_filters( 'bp_activity_set_action', array(
+		'key'   => $key,
+		'value' => $value
+	), $component_id, $key, $value );
+
+	return true;
+}
+
+/**
+ * Retreive the current action from a component and key.
+ *
+ * @since BuddyPress (1.1)
+ *
+ * @global object $bp BuddyPress global settings.
+ * @uses apply_filters() To call the 'bp_activity_get_action' hook.
+ *
+ * @param string $component_id The unique string ID of the component.
+ * @param string $key The action key.
+ * @return string|bool Action value if found, otherwise false.
+ */
+function bp_activity_get_action( $component_id, $key ) {
+	global $bp;
+
+	// Return false if any of the above values are not set
+	if ( empty( $component_id ) || empty( $key ) )
+		return false;
+
+	return apply_filters( 'bp_activity_get_action', $bp->activity->actions->{$component_id}->{$key}, $component_id, $key );
+}
+
+/**
+ * Fetch details of all registered activity types.
+ *
+ * @since BuddyPress (1.7)
+ *
+ * @return array array( type => description ), ...
+ */
+function bp_activity_get_types() {
+	$actions  = array();
+
+	// Walk through the registered actions, and build an array of actions/values.
+	foreach ( buddypress()->activity->actions as $action ) {
+		$action = array_values( (array) $action );
+
+		for ( $i = 0, $i_count = count( $action ); $i < $i_count; $i++ )
+			$actions[ $action[$i]['key'] ] = $action[$i]['value'];
+	}
+
+	// This was a mis-named activity type from before BP 1.6
+	unset( $actions['friends_register_activity_action'] );
+
+	// This type has not been used since BP 1.0.3. It will be re-instated in a future version.
+	unset( $actions['updated_profile'] );
+
+	return apply_filters( 'bp_activity_get_types', $actions );
+}
+
+/** Favorites ****************************************************************/
+
+/**
+ * Get a users favorite activity stream items.
+ *
+ * @since BuddyPress (1.2)
+ *
+ * @uses bp_get_user_meta()
+ * @uses apply_filters() To call the 'bp_activity_get_user_favorites' hook.
+ *
+ * @param int $user_id ID of the user whose favorites are being queried.
+ * @return array IDs of the user's favorite activity items.
+ */
+function bp_activity_get_user_favorites( $user_id = 0 ) {
+
+	// Fallback to logged in user if no user_id is passed
+	if ( empty( $user_id ) )
+		$user_id = bp_displayed_user_id();
+
+	// Get favorites for user
+	$favs = bp_get_user_meta( $user_id, 'bp_favorite_activities', true );
+
+	return apply_filters( 'bp_activity_get_user_favorites', $favs );
+}
+
+/**
+ * Add an activity stream item as a favorite for a user.
+ *
+ * @since BuddyPress (1.2)
+ *
+ * @uses is_user_logged_in()
+ * @uses bp_get_user_meta()
+ * @uses bp_activity_get_meta()
+ * @uses bp_update_user_meta()
+ * @uses bp_activity_update_meta()
+ * @uses do_action() To call the 'bp_activity_add_user_favorite' hook.
+ * @uses do_action() To call the 'bp_activity_add_user_favorite_fail' hook.
+ *
+ * @param int $activity_id ID of the activity item being favorited.
+ * @param int $user_id ID of the user favoriting the activity item.
+ * @return bool True on success, false on failure.
+ */
+function bp_activity_add_user_favorite( $activity_id, $user_id = 0 ) {
+
+	// Favorite activity stream items are for logged in users only
+	if ( !is_user_logged_in() )
+		return false;
+
+	// Fallback to logged in user if no user_id is passed
+	if ( empty( $user_id ) )
+		$user_id = bp_loggedin_user_id();
+
+	// Update the user's personal favorites
+	$my_favs   = bp_get_user_meta( $user_id, 'bp_favorite_activities', true );
+	$my_favs[] = $activity_id;
+
+	// Update the total number of users who have favorited this activity
+	$fav_count = bp_activity_get_meta( $activity_id, 'favorite_count' );
+	$fav_count = !empty( $fav_count ) ? (int) $fav_count + 1 : 1;
+
+	// Update user meta
+	bp_update_user_meta( $user_id, 'bp_favorite_activities', $my_favs );
+
+	// Update activity meta counts
+	if ( true === bp_activity_update_meta( $activity_id, 'favorite_count', $fav_count ) ) {
+
+		// Execute additional code
+		do_action( 'bp_activity_add_user_favorite', $activity_id, $user_id );
+
+		// Success
+		return true;
+
+	// Saving meta was unsuccessful for an unknown reason
+	} else {
+		// Execute additional code
+		do_action( 'bp_activity_add_user_favorite_fail', $activity_id, $user_id );
+
+		return false;
+	}
+}
+
+/**
+ * Remove an activity stream item as a favorite for a user.
+ *
+ * @since BuddyPress (1.2)
+ *
+ * @uses is_user_logged_in()
+ * @uses bp_get_user_meta()
+ * @uses bp_activity_get_meta()
+ * @uses bp_activity_update_meta()
+ * @uses bp_update_user_meta()
+ * @uses do_action() To call the 'bp_activity_remove_user_favorite' hook.
+ *
+ * @param int $activity_id ID of the activity item being unfavorited.
+ * @param int $user_id ID of the user unfavoriting the activity item.
+ * @return bool True on success, false on failure.
+ */
+function bp_activity_remove_user_favorite( $activity_id, $user_id = 0 ) {
+
+	// Favorite activity stream items are for logged in users only
+	if ( !is_user_logged_in() )
+		return false;
+
+	// Fallback to logged in user if no user_id is passed
+	if ( empty( $user_id ) )
+		$user_id = bp_loggedin_user_id();
+
+	// Remove the fav from the user's favs
+	$my_favs = bp_get_user_meta( $user_id, 'bp_favorite_activities', true );
+	$my_favs = array_flip( (array) $my_favs );
+	unset( $my_favs[$activity_id] );
+	$my_favs = array_unique( array_flip( $my_favs ) );
+
+	// Update the total number of users who have favorited this activity
+	if ( $fav_count = bp_activity_get_meta( $activity_id, 'favorite_count' ) ) {
+
+		// Deduct from total favorites
+		if ( bp_activity_update_meta( $activity_id, 'favorite_count', (int) $fav_count - 1 ) ) {
+
+			// Update users favorites
+			if ( bp_update_user_meta( $user_id, 'bp_favorite_activities', $my_favs ) ) {
+
+				// Execute additional code
+				do_action( 'bp_activity_remove_user_favorite', $activity_id, $user_id );
+
+				// Success
+				return true;
+
+			// Error updating
+			} else {
+				return false;
+			}
+
+		// Error updating favorite count
+		} else {
+			return false;
+		}
+
+	// Error getting favorite count
+	} else {
+		return false;
+	}
+}
+
+/**
+ * Check whether an activity item exists with a given content string.
+ *
+ * @since BuddyPress (1.1)
+ *
+ * @uses BP_Activity_Activity::check_exists_by_content() {@link BP_Activity_Activity}
+ * @uses apply_filters() To call the 'bp_activity_check_exists_by_content' hook.
+ *
+ * @param string $content The content to filter by.
+ * @return int|null The ID of the located activity item. Null if none is found.
+ */
+function bp_activity_check_exists_by_content( $content ) {
+	return apply_filters( 'bp_activity_check_exists_by_content', BP_Activity_Activity::check_exists_by_content( $content ) );
+}
+
+/**
+ * Retrieve the last time activity was updated.
+ *
+ * @since BuddyPress (1.0)
+ *
+ * @uses BP_Activity_Activity::get_last_updated() {@link BP_Activity_Activity}
+ * @uses apply_filters() To call the 'bp_activity_get_last_updated' hook.
+ *
+ * @return string Date last updated.
+ */
+function bp_activity_get_last_updated() {
+	return apply_filters( 'bp_activity_get_last_updated', BP_Activity_Activity::get_last_updated() );
+}
+
+/**
+ * Retrieve the number of favorite activity stream items a user has.
+ *
+ * @since BuddyPress (1.2)
+ *
+ * @uses BP_Activity_Activity::total_favorite_count() {@link BP_Activity_Activity}
+ *
+ * @param int $user_id ID of the user whose favorite count is being requested.
+ * @return int Total favorite count for the user.
+ */
+function bp_activity_total_favorites_for_user( $user_id = 0 ) {
+
+	// Fallback on displayed user, and then logged in user
+	if ( empty( $user_id ) )
+		$user_id = ( bp_displayed_user_id() ) ? bp_displayed_user_id() : bp_loggedin_user_id();
+
+	return BP_Activity_Activity::total_favorite_count( $user_id );
+}
+
+/** Meta *********************************************************************/
+
+/**
+ * Delete a meta entry from the DB for an activity stream item.
+ *
+ * @since BuddyPress (1.2)
+ *
+ * @global object $wpdb WordPress database access object.
+ * @global object $bp BuddyPress global settings.
+ * @uses wp_cache_delete()
+ * @uses is_wp_error()
+ *
+ * @param int $activity_id ID of the activity item whose metadata is being deleted.
+ * @param string $meta_key Optional. The key of the metadata being deleted. If
+ *                         omitted, all metadata associated with the activity
+ *                         item will be deleted.
+ * @param string $meta_value Optional. If present, the metadata will only be
+ *                           deleted if the meta_value matches this parameter.
+ * @return bool True on success, false on failure.
+ */
+function bp_activity_delete_meta( $activity_id, $meta_key = '', $meta_value = '' ) {
+	global $wpdb, $bp;
+
+	// Return false if any of the above values are not set
+	if ( !is_numeric( $activity_id ) )
+		return false;
+
+	// Sanitize key
+	$meta_key = preg_replace( '|[^a-z0-9_]|i', '', $meta_key );
+
+	if ( is_array( $meta_value ) || is_object( $meta_value ) )
+		$meta_value = serialize( $meta_value );
+
+	// Trim off whitespace
+	$meta_value = trim( $meta_value );
+
+	// Delete all for activity_id
+	if ( empty( $meta_key ) )
+		$retval = $wpdb->query( $wpdb->prepare( "DELETE FROM {$bp->activity->table_name_meta} WHERE activity_id = %d", $activity_id ) );
+
+	// Delete only when all match
+	else if ( $meta_value )
+		$retval = $wpdb->query( $wpdb->prepare( "DELETE FROM {$bp->activity->table_name_meta} WHERE activity_id = %d AND meta_key = %s AND meta_value = %s", $activity_id, $meta_key, $meta_value ) );
+
+	// Delete only when activity_id and meta_key match
+	else
+		$retval = $wpdb->query( $wpdb->prepare( "DELETE FROM {$bp->activity->table_name_meta} WHERE activity_id = %d AND meta_key = %s", $activity_id, $meta_key ) );
+
+	// Delete cache entry
+	wp_cache_delete( 'bp_activity_meta_' . $activity_id . '_' . $meta_key, 'bp' );
+
+	// Success
+	if ( !is_wp_error( $retval ) )
+		return true;
+
+	// Fail
+	else
+		return false;
+}
+
+/**
+ * Get metadata for a given activity item.
+ *
+ * @since BuddyPress (1.2)
+ *
+ * @global object $wpdb WordPress database access object.
+ * @global object $bp BuddyPress global settings.
+ * @uses wp_cache_get()
+ * @uses wp_cache_set()
+ * @uses apply_filters() To call the 'bp_activity_get_meta' hook.
+ *
+ * @param int $activity_id ID of the activity item whose metadata is being requseted.
+ * @param string $meta_key Optional. If present, only the metadata matching
+ *                         that meta key will be returned. Otherwise, all
+ *                         metadata for the activity item will be fetched.
+ * @return mixed The meta value(s) being requested.
+ */
+function bp_activity_get_meta( $activity_id = 0, $meta_key = '' ) {
+	global $wpdb, $bp;
+
+	// Make sure activity_id is valid
+	if ( empty( $activity_id ) || !is_numeric( $activity_id ) )
+		return false;
+
+	// We have a key to look for
+	if ( !empty( $meta_key ) ) {
+
+		// Sanitize key
+		$meta_key = preg_replace( '|[^a-z0-9_]|i', '', $meta_key );
+
+		// Check cache
+		if ( !$metas = wp_cache_get( 'bp_activity_meta_' . $activity_id . '_' . $meta_key, 'bp' ) ) {
+			// No cache so hit the DB
+			$metas = $wpdb->get_col( $wpdb->prepare("SELECT meta_value FROM {$bp->activity->table_name_meta} WHERE activity_id = %d AND meta_key = %s", $activity_id, $meta_key ) );
+
+			// Set cache
+			wp_cache_set( 'bp_activity_meta_' . $activity_id . '_' . $meta_key, $metas, 'bp' );
+		}
+
+	// No key so get all for activity_id
+	} else {
+		$metas = $wpdb->get_results( $wpdb->prepare( "SELECT meta_key, meta_value FROM {$bp->activity->table_name_meta} WHERE activity_id = %d", $activity_id ) );
+
+		if ( !empty( $metas ) ) {
+			$metas = array_map( 'maybe_unserialize', (array) $metas );
+
+			foreach( $metas as $mkey => $mvalue ) {
+				wp_cache_set( 'bp_activity_meta_' . $activity_id . '_' . $mkey, $mvalue, 'bp' );
+			}
+		}
+	}
+
+	// No result so return false
+	if ( empty( $metas ) )
+		return false;
+
+	// Maybe, just maybe... unserialize
+	$metas = array_map( 'maybe_unserialize', (array) $metas );
+
+	// Return first item in array if only 1, else return all metas found
+	$retval = ( 1 == count( $metas ) ? $metas[0] : $metas );
+
+	// Filter result before returning
+	return apply_filters( 'bp_activity_get_meta', $retval, $activity_id, $meta_key );
+}
+
+/**
+ * Update a piece of activity meta.
+ *
+ * @since BuddyPress (1.2)
+ *
+ * @global object $wpdb WordPress database access object.
+ * @global object $bp BuddyPress global settings.
+ * @uses maybe_serialize()
+ * @uses bp_activity_delete_meta()
+ * @uses wp_cache_set()
+ *
+ * @param int $activity_id ID of the activity item whose metadata is being updated.
+ * @param string $meta_key Key of the metadata being updated.
+ * @param mixed $meta_value Value to be set.
+ * @return bool True on success, false on failure.
+ */
+function bp_activity_update_meta( $activity_id, $meta_key, $meta_value ) {
+	global $wpdb, $bp;
+
+	// Make sure activity_id is valid
+	if ( !is_numeric( $activity_id ) )
+		return false;
+
+	// Sanitize key
+	$meta_key = preg_replace( '|[^a-z0-9_]|i', '', $meta_key );
+
+	// Sanitize value
+	if ( is_string( $meta_value ) ) {
+		$meta_value = stripslashes( $meta_value );
+	}
+
+	// Maybe, just maybe... serialize
+	$meta_value = maybe_serialize( $meta_value );
+
+	// If value is false, delete the meta key
+	if ( false === $meta_value )
+		return bp_activity_delete_meta( $activity_id, $meta_key );
+
+	// See if meta key exists for activity_id
+	$cur = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$bp->activity->table_name_meta} WHERE activity_id = %d AND meta_key = %s", $activity_id, $meta_key ) );
+
+	// Meta key does not exist so INSERT
+	if ( empty( $cur ) )
+		$wpdb->query( $wpdb->prepare( "INSERT INTO {$bp->activity->table_name_meta} ( activity_id, meta_key, meta_value ) VALUES ( %d, %s, %s )", $activity_id, $meta_key, $meta_value ) );
+
+	// Meta key exists, so UPDATE
+	else if ( $cur->meta_value != $meta_value )
+		$wpdb->query( $wpdb->prepare( "UPDATE {$bp->activity->table_name_meta} SET meta_value = %s WHERE activity_id = %d AND meta_key = %s", $meta_value, $activity_id, $meta_key ) );
+
+	// Weirdness, so return false
+	else
+		return false;
+
+	// Set cache
+	wp_cache_set( 'bp_activity_meta_' . $activity_id . '_' . $meta_key, $meta_value, 'bp' );
+
+	// Victory is ours!
+	return true;
+}
+
+/** Clean up *****************************************************************/
+
+/**
+ * Completely remove a user's activity data.
+ *
+ * @since BuddyPress (1.5)
+ *
+ * @uses is_user_logged_in()
+ * @uses bp_activity_delete()
+ * @uses bp_delete_user_meta()
+ * @uses do_action() To call the 'bp_activity_remove_data' hook.
+ * @uses do_action() To call the 'bp_activity_remove_all_user_data' hook.
+ *
+ * @param int $user_id ID of the user whose activity is being deleted.
+ */
+function bp_activity_remove_all_user_data( $user_id = 0 ) {
+
+	// Do not delete user data unless a logged in user says so
+	if ( empty( $user_id ) || !is_user_logged_in() )
+		return false;
+
+	// Clear the user's activity from the sitewide stream and clear their activity tables
+	bp_activity_delete( array( 'user_id' => $user_id ) );
+
+	// Remove any usermeta
+	bp_delete_user_meta( $user_id, 'bp_latest_update' );
+	bp_delete_user_meta( $user_id, 'bp_favorite_activities' );
+
+	// Execute additional code
+	do_action( 'bp_activity_remove_data', $user_id ); // Deprecated! Do not use!
+
+	// Use this going forward
+	do_action( 'bp_activity_remove_all_user_data', $user_id );
+}
+add_action( 'wpmu_delete_user',  'bp_activity_remove_all_user_data' );
+add_action( 'delete_user',       'bp_activity_remove_all_user_data' );
+
+/**
+ * Mark all of the user's activity as spam.
+ *
+ * @since BuddyPress (1.6)
+ *
+ * @global object $wpdb WordPress database access object.
+ * @global object $bp BuddyPress global settings.
+ *
+ * @param int $user_id ID of the user whose activity is being spammed.
+ */
+function bp_activity_spam_all_user_data( $user_id = 0 ) {
+	global $bp, $wpdb;
+
+	// Do not delete user data unless a logged in user says so
+	if ( empty( $user_id ) || ! is_user_logged_in() )
+		return false;
+
+	// Get all the user's activities.
+	$activities = bp_activity_get( array( 'display_comments' => 'stream', 'filter' => array( 'user_id' => $user_id ), 'show_hidden' => true, ) );
+
+	// Mark each as spam
+	foreach ( (array) $activities['activities'] as $activity ) {
+
+		// Create an activity object
+		$activity_obj = new BP_Activity_Activity;
+		foreach ( $activity as $k => $v )
+			$activity_obj->$k = $v;
+
+		// Mark as spam
+		bp_activity_mark_as_spam( $activity_obj );
+
+		/*
+		 * If Akismet is present, update the activity history meta.
+		 *
+		 * This is usually taken care of when BP_Activity_Activity::save() happens, but
+		 * as we're going to be updating all the activity statuses directly, for efficency,
+		 * we need to update manually.
+		 */
+		if ( ! empty( $bp->activity->akismet ) )
+			$bp->activity->akismet->update_activity_spam_meta( $activity_obj );
+
+		// Tidy up
+		unset( $activity_obj );
+	}
+
+	// Mark all of this user's activities as spam
+	$wpdb->query( $wpdb->prepare( "UPDATE {$bp->activity->table_name} SET is_spam = 1 WHERE user_id = %d", $user_id ) );
+
+	// Call an action for plugins to use
+	do_action( 'bp_activity_spam_all_user_data', $user_id, $activities['activities'] );
+}
+add_action( 'bp_make_spam_user', 'bp_activity_spam_all_user_data' );
+
+/**
+ * Mark all of the user's activity as ham (not spam).
+ *
+ * @since BuddyPress (1.6)
+ *
+ * @global object $wpdb WordPress database access object.
+ * @global object $bp BuddyPress global settings.
+ *
+ * @param int $user_id ID of the user whose activity is being hammed.
+ */
+function bp_activity_ham_all_user_data( $user_id = 0 ) {
+	global $bp, $wpdb;
+
+	// Do not delete user data unless a logged in user says so
+	if ( empty( $user_id ) || ! is_user_logged_in() )
+		return false;
+
+	// Get all the user's activities.
+	$activities = bp_activity_get( array( 'display_comments' => 'stream', 'filter' => array( 'user_id' => $user_id ), 'show_hidden' => true, 'spam' => 'all', ) );
+
+	// Mark each as not spam
+	foreach ( (array) $activities['activities'] as $activity ) {
+
+		// Create an activity object
+		$activity_obj = new BP_Activity_Activity;
+		foreach ( $activity as $k => $v )
+			$activity_obj->$k = $v;
+
+		// Mark as not spam
+		bp_activity_mark_as_ham( $activity_obj );
+
+		/*
+		 * If Akismet is present, update the activity history meta.
+		 *
+		 * This is usually taken care of when BP_Activity_Activity::save() happens, but
+		 * as we're going to be updating all the activity statuses directly, for efficency,
+		 * we need to update manually.
+		 */
+		if ( ! empty( $bp->activity->akismet ) )
+			$bp->activity->akismet->update_activity_ham_meta( $activity_obj );
+
+		// Tidy up
+		unset( $activity_obj );
+	}
+
+	// Mark all of this user's activities as spam
+	$wpdb->query( $wpdb->prepare( "UPDATE {$bp->activity->table_name} SET is_spam = 0 WHERE user_id = %d", $user_id ) );
+
+	// Call an action for plugins to use
+	do_action( 'bp_activity_ham_all_user_data', $user_id, $activities['activities'] );
+}
+add_action( 'bp_make_ham_user', 'bp_activity_ham_all_user_data' );
+
+/**
+ * Register the activity stream actions for updates
+ *
+ * @since BuddyPress (1.6)
+ *
+ * @global object $bp BuddyPress global settings.
+ */
+function bp_activity_register_activity_actions() {
+	global $bp;
+
+	bp_activity_set_action( $bp->activity->id, 'activity_update', __( 'Posted a status update', 'buddypress' ) );
+	bp_activity_set_action( $bp->activity->id, 'activity_comment', __( 'Replied to a status update', 'buddypress' ) );
+
+	do_action( 'bp_activity_register_activity_actions' );
+
+	// Backpat. Don't use this.
+	do_action( 'updates_register_activity_actions' );
+}
+add_action( 'bp_register_activity_actions', 'bp_activity_register_activity_actions' );
+
+/******************************************************************************
+ * Business functions are where all the magic happens in BuddyPress. They will
+ * handle the actual saving or manipulation of information. Usually they will
+ * hand off to a database class for data access, then return
+ * true or false on success or failure.
+ */
+
+/**
+ * Retrieve an activity or activities.
+ *
+ * bp_activity_get() shares all arguments with BP_Activity_Activity::get(). The
+ * following is a list of bp_activity_get() parameters that have different
+ * default values from BP_Activity_Activity::get() (value in parentheses is
+ * the default for the bp_activity_get()).
+ *   - 'per_page' (false)
+ *
+ * @since BuddyPress (1.2)
+ *
+ * @see BP_Activity_Activity::get() For more information on accepted arguments
+ *      and the format of the returned value.
+ * @uses wp_parse_args()
+ * @uses wp_cache_get()
+ * @uses wp_cache_set()
+ * @uses BP_Activity_Activity::get() {@link BP_Activity_Activity}
+ * @uses apply_filters_ref_array() To call the 'bp_activity_get' hook.
+ *
+ * @param array $args See BP_Activity_Activity::get() for description.
+ * @return array $activity See BP_Activity_Activity::get() for description.
+ */
+function bp_activity_get( $args = '' ) {
+	$defaults = array(
+		'max'              => false,        // Maximum number of results to return
+		'page'             => 1,            // page 1 without a per_page will result in no pagination.
+		'per_page'         => false,        // results per page
+		'sort'             => 'DESC',       // sort ASC or DESC
+		'display_comments' => false,        // false for no comments. 'stream' for within stream display, 'threaded' for below each activity item
+
+		'search_terms'     => false,        // Pass search terms as a string
+		'meta_query'       => false,        // Filter by activity meta. See WP_Meta_Query for format
+		'show_hidden'      => false,        // Show activity items that are hidden site-wide?
+		'exclude'          => false,        // Comma-separated list of activity IDs to exclude
+		'in'               => false,        // Comma-separated list or array of activity IDs to which you want to limit the query
+		'spam'             => 'ham_only',   // 'ham_only' (default), 'spam_only' or 'all'.
+
+		/**
+		 * Pass filters as an array -- all filter items can be multiple values comma separated:
+		 * array(
+		 * 	'user_id'      => false, // user_id to filter on
+		 *	'object'       => false, // object to filter on e.g. groups, profile, status, friends
+		 *	'action'       => false, // action to filter on e.g. activity_update, profile_updated
+		 *	'primary_id'   => false, // object ID to filter on e.g. a group_id or forum_id or blog_id etc.
+		 *	'secondary_id' => false, // secondary object ID to filter on e.g. a post_id
+		 * );
+		 */
+		'filter' => array()
+	);
+	$r = wp_parse_args( $args, $defaults );
+	extract( $r, EXTR_SKIP );
+
+	// Attempt to return a cached copy of the first page of sitewide activity.
+	if ( 1 == (int) $page && empty( $max ) && empty( $search_terms ) && empty( $meta_query ) && empty( $filter ) && empty( $exclude ) && empty( $in ) && 'DESC' == $sort && empty( $exclude ) && 'ham_only' == $spam ) {
+		if ( !$activity = wp_cache_get( 'bp_activity_sitewide_front', 'bp' ) ) {
+			$args = array(
+				'page'             => $page,
+				'per_page'         => $per_page,
+				'max'              => $max,
+				'sort'             => $sort,
+				'search_terms'     => $search_terms,
+				'meta_query'       => $meta_query,
+				'filter'           => $filter,
+				'display_comments' => $display_comments,
+				'show_hidden'      => $show_hidden,
+				'spam'             => $spam
+			);
+			$activity = BP_Activity_Activity::get( $args );
+			wp_cache_set( 'bp_activity_sitewide_front', $activity, 'bp' );
+		}
+
+	} else {
+		$args = array(
+			'page'             => $page,
+			'per_page'         => $per_page,
+			'max'              => $max,
+			'sort'             => $sort,
+			'search_terms'     => $search_terms,
+			'meta_query'       => $meta_query,
+			'filter'           => $filter,
+			'display_comments' => $display_comments,
+			'show_hidden'      => $show_hidden,
+			'exclude'          => $exclude,
+			'in'               => $in,
+			'spam'             => $spam
+		);
+		$activity = BP_Activity_Activity::get( $args );
+	}
+
+	return apply_filters_ref_array( 'bp_activity_get', array( &$activity, &$r ) );
+}
+
+/**
+ * Fetch specific activity items.
+ *
+ * @since BuddyPress (1.2)
+ *
+ * @see BP_Activity_Activity::get() For more information on accepted arguments
+ * @uses wp_parse_args()
+ * @uses apply_filters() To call the 'bp_activity_get_specific' hook
+ * @uses BP_Activity_Activity::get() {@link BP_Activity_Activity}
+ *
+ * @param array $args {
+ *     All arguments and defaults are shared with BP_Activity_Activity::get(),
+ *     except for the following:
+ *     @type string|int|array Single activity ID, comma-separated list of IDs,
+ *                            or array of IDs.
+ * }
+ * @return array $activity See BP_Activity_Activity::get() for description.
+ */
+function bp_activity_get_specific( $args = '' ) {
+	$defaults = array(
+		'activity_ids'     => false,       // A single activity_id or array of IDs.
+		'display_comments' => false,       // true or false to display threaded comments for these specific activity items
+		'max'              => false,       // Maximum number of results to return
+		'page'             => 1,           // page 1 without a per_page will result in no pagination.
+		'per_page'         => false,       // results per page
+		'show_hidden'      => true,        // When fetching specific items, show all
+		'sort'             => 'DESC',      // sort ASC or DESC
+		'spam'             => 'ham_only',  // Retrieve items marked as spam
+	);
+	$r = wp_parse_args( $args, $defaults );
+	extract( $r, EXTR_SKIP );
+
+	$get_args = array(
+		'page'             => $page,
+		'per_page'         => $per_page,
+		'max'              => $max,
+		'sort'             => $sort,
+		'display_comments' => $display_comments,
+		'show_hidden'      => $show_hidden,
+		'in'               => $activity_ids,
+		'spam'             => $spam
+	);
+	return apply_filters( 'bp_activity_get_specific', BP_Activity_Activity::get( $get_args ), $args, $get_args );
+}
+
+/**
+ * Add an activity item.
+ *
+ * @since BuddyPress (1.1)
+ *
+ * @uses wp_parse_args()
+ * @uses BP_Activity_Activity::save() {@link BP_Activity_Activity}
+ * @uses BP_Activity_Activity::rebuild_activity_comment_tree() {@link BP_Activity_Activity}
+ * @uses wp_cache_delete()
+ * @uses do_action() To call the 'bp_activity_add' hook
+ *
+ * @param array $args {
+ *     An array of arguments.
+ *     @type int|bool $id Pass an activity ID to update an existing item, or
+ *           false to create a new item. Default: false.
+ *     @type string $action Optional. The activity action/description, typically
+ *           something like "Joe posted an update".
+ *     @type string $content Optional. The content of the activity item.
+ *     @type string $component The unique name of the component associated with
+ *           the activity item - 'groups', 'profile', etc.
+ *     @type string $type The specific activity type, used for directory
+ *           filtering. 'new_blog_post', 'activity_update', etc.
+ *     @type string $primary_link Optional. The URL for this item, as used in
+ *           RSS feeds. Defaults to the URL for this activity item's permalink page.
+ *     @type int|bool $user_id Optional. The ID of the user associated with the
+ *           activity item. May be set to false or 0 if the item is not related
+ *           to any user. Default: the ID of the currently logged-in user.
+ *     @type int $item_id Optional. The ID of the associated item.
+ *     @type int $secondary_item_id Optional. The ID of a secondary associated
+ *           item.
+ *     @type string $date_recorded Optional. The GMT time, in Y-m-d h:i:s format,
+ *           when the item was recorded. Defaults to the current time.
+ *     @type bool $hide_sitewide Should the item be hidden on sitewide streams?
+ *           Default: false.
+ *     @type bool $is_spam Should the item be marked as spam? Default: false.
+ * }
+ * @return int|bool The ID of the activity on success. False on error.
+ */
+function bp_activity_add( $args = '' ) {
+
+	$defaults = array(
+		'id'                => false, // Pass an existing activity ID to update an existing entry.
+
+		'action'            => '',    // The activity action - e.g. "Jon Doe posted an update"
+		'content'           => '',    // Optional: The content of the activity item e.g. "BuddyPress is awesome guys!"
+
+		'component'         => false, // The name/ID of the component e.g. groups, profile, mycomponent
+		'type'              => false, // The activity type e.g. activity_update, profile_updated
+		'primary_link'      => '',    // Optional: The primary URL for this item in RSS feeds (defaults to activity permalink)
+
+		'user_id'           => bp_loggedin_user_id(), // Optional: The user to record the activity for, can be false if this activity is not for a user.
+		'item_id'           => false, // Optional: The ID of the specific item being recorded, e.g. a blog_id
+		'secondary_item_id' => false, // Optional: A second ID used to further filter e.g. a comment_id
+		'recorded_time'     => bp_core_current_time(), // The GMT time that this activity was recorded
+		'hide_sitewide'     => false, // Should this be hidden on the sitewide activity stream?
+		'is_spam'           => false, // Is this activity item to be marked as spam?
+	);
+	$params = wp_parse_args( $args, $defaults );
+	extract( $params, EXTR_SKIP );
+
+	// Make sure we are backwards compatible
+	if ( empty( $component ) && !empty( $component_name ) )
+		$component = $component_name;
+
+	if ( empty( $type ) && !empty( $component_action ) )
+		$type = $component_action;
+
+	// Setup activity to be added
+	$activity                    = new BP_Activity_Activity( $id );
+	$activity->user_id           = $user_id;
+	$activity->component         = $component;
+	$activity->type              = $type;
+	$activity->action            = $action;
+	$activity->content           = $content;
+	$activity->primary_link      = $primary_link;
+	$activity->item_id           = $item_id;
+	$activity->secondary_item_id = $secondary_item_id;
+	$activity->date_recorded     = $recorded_time;
+	$activity->hide_sitewide     = $hide_sitewide;
+	$activity->is_spam           = $is_spam;
+
+	if ( !$activity->save() )
+		return false;
+
+	// If this is an activity comment, rebuild the tree
+	if ( 'activity_comment' == $activity->type )
+		BP_Activity_Activity::rebuild_activity_comment_tree( $activity->item_id );
+
+	wp_cache_delete( 'bp_activity_sitewide_front', 'bp' );
+	do_action( 'bp_activity_add', $params );
+
+	return $activity->id;
+}
+
+/**
+ * Post an activity update.
+ *
+ * @since BuddyPress (1.2)
+ *
+ * @global object $bp BuddyPress global settings.
+ * @uses wp_parse_args()
+ * @uses bp_is_user_inactive()
+ * @uses bp_core_get_userlink()
+ * @uses bp_activity_add()
+ * @uses apply_filters() To call the 'bp_activity_new_update_action' hook.
+ * @uses apply_filters() To call the 'bp_activity_new_update_content' hook.
+ * @uses apply_filters() To call the 'bp_activity_new_update_primary_link' hook.
+ * @uses bp_update_user_meta()
+ * @uses wp_filter_kses()
+ * @uses do_action() To call the 'bp_activity_posted_update' hook.
+ *
+ * @param array $args {
+ *     @type string $content The content of the activity update.
+ *     @type int $user_id Optional. Defaults to the logged-in user.
+ * }
+ * @return int $activity_id The activity id
+ */
+function bp_activity_post_update( $args = '' ) {
+	global $bp;
+
+	$defaults = array(
+		'content' => false,
+		'user_id' => bp_loggedin_user_id()
+	);
+	$r = wp_parse_args( $args, $defaults );
+	extract( $r, EXTR_SKIP );
+
+	if ( empty( $content ) || !strlen( trim( $content ) ) )
+		return false;
+
+	if ( bp_is_user_inactive( $user_id ) )
+		return false;
+
+	// Record this on the user's profile
+	$from_user_link   = bp_core_get_userlink( $user_id );
+	$activity_action  = sprintf( __( '%s posted an update', 'buddypress' ), $from_user_link );
+	$activity_content = $content;
+	$primary_link     = bp_core_get_userlink( $user_id, false, true );
+
+	// Now write the values
+	$activity_id = bp_activity_add( array(
+		'user_id'      => $user_id,
+		'action'       => apply_filters( 'bp_activity_new_update_action', $activity_action ),
+		'content'      => apply_filters( 'bp_activity_new_update_content', $activity_content ),
+		'primary_link' => apply_filters( 'bp_activity_new_update_primary_link', $primary_link ),
+		'component'    => $bp->activity->id,
+		'type'         => 'activity_update'
+	) );
+
+	$activity_content = apply_filters( 'bp_activity_latest_update_content', $content, $activity_content );
+
+	// Add this update to the "latest update" usermeta so it can be fetched anywhere.
+	bp_update_user_meta( bp_loggedin_user_id(), 'bp_latest_update', array( 'id' => $activity_id, 'content' => $activity_content ) );
+
+	do_action( 'bp_activity_posted_update', $content, $user_id, $activity_id );
+
+	return $activity_id;
+}
+
+/**
+ * Add an activity comment.
+ *
+ * @since BuddyPress (1.2)
+ *
+ * @global object $bp BuddyPress global settings.
+ * @uses wp_parse_args()
+ * @uses bp_activity_add()
+ * @uses apply_filters() To call the 'bp_activity_comment_action' hook.
+ * @uses apply_filters() To call the 'bp_activity_comment_content' hook.
+ * @uses bp_activity_new_comment_notification()
+ * @uses wp_cache_delete()
+ * @uses do_action() To call the 'bp_activity_comment_posted' hook.
+ *
+ * @param array $args {
+ *     @type int $id Optional. Pass an ID to update an existing comment.
+ *     @type string $content The content of the comment.
+ *     @type int $user_id Optional. The ID of the user making the comment.
+ *                        Defaults to the ID of the logged-in user.
+ *     @type int $activity_id The ID of the "root" activity item, ie the oldest
+ *                            ancestor of the comment.
+ *     @type int $parent_id Optional. The ID of the parent activity item, ie the
+ *                          item to which the comment is an immediate reply. If
+ *                          not provided, this value defaults to the $activity_id.
+ * }
+ * @return int|bool The ID of the comment on success, otherwise false.
+ */
+function bp_activity_new_comment( $args = '' ) {
+
+	$params = wp_parse_args( $args, array(
+		'id'          => false,
+		'content'     => false,
+		'user_id'     => bp_loggedin_user_id(),
+		'activity_id' => false, // ID of the root activity item
+		'parent_id'   => false  // ID of a parent comment (optional)
+	) );
+
+	extract( $params, EXTR_SKIP );
+
+	// Bail if missing necessary data
+	if ( empty( $content ) || empty( $user_id ) || empty( $activity_id ) ) {
+		return false;
+	}
+
+	// Maybe set current activity ID as the parent
+	if ( empty( $parent_id ) ) {
+		$parent_id = $activity_id;
+	}
+
+	// Check to see if the parent activity is hidden, and if so, hide this comment publically.
+	$activity  = new BP_Activity_Activity( $activity_id );
+	$is_hidden = ( (int) $activity->hide_sitewide ) ? 1 : 0;
+
+	// Insert the activity comment
+	$comment_id = bp_activity_add( array(
+		'id'                => $id,
+		'action'            => apply_filters( 'bp_activity_comment_action', sprintf( __( '%s posted a new activity comment', 'buddypress' ), bp_core_get_userlink( $user_id ) ) ),
+		'content'           => apply_filters( 'bp_activity_comment_content', $content ),
+		'component'         => buddypress()->activity->id,
+		'type'              => 'activity_comment',
+		'user_id'           => $user_id,
+		'item_id'           => $activity_id,
+		'secondary_item_id' => $parent_id,
+		'hide_sitewide'     => $is_hidden
+	) );
+
+	// Clear the comment cache for this activity
+	wp_cache_delete( 'bp_activity_comments_' . $parent_id );
+
+	do_action( 'bp_activity_comment_posted', $comment_id, $params, $activity );
+
+	return $comment_id;
+}
+
+/**
+ * Fetch the activity_id for an existing activity entry in the DB.
+ *
+ * @since BuddyPress (1.2)
+ *
+ * @see BP_Activity_Activity::get() For more information on accepted arguments.
+ * @uses wp_parse_args()
+ * @uses apply_filters() To call the 'bp_activity_get_activity_id' hook.
+ * @uses BP_Activity_Activity::save() {@link BP_Activity_Activity}
+ *
+ * @param array $args See BP_Activity_Activity::get() for description.
+ * @return int $activity_id The ID of the activity item found.
+ */
+function bp_activity_get_activity_id( $args = '' ) {
+	$defaults = array(
+		'user_id'           => false,
+		'component'         => false,
+		'type'              => false,
+		'item_id'           => false,
+		'secondary_item_id' => false,
+		'action'            => false,
+		'content'           => false,
+		'date_recorded'     => false,
+	);
+
+	$r = wp_parse_args( $args, $defaults );
+	extract( $r, EXTR_SKIP );
+
+ 	return apply_filters( 'bp_activity_get_activity_id', BP_Activity_Activity::get_id( $user_id, $component, $type, $item_id, $secondary_item_id, $action, $content, $date_recorded ) );
+}
+
+/**
+ * Delete activity item(s).
+ *
+ * If you're looking to hook into one action that provides the ID(s) of
+ * the activity/activities deleted, then use:
+ *
+ * add_action( 'bp_activity_deleted_activities', 'my_function' );
+ *
+ * The action passes one parameter that is a single activity ID or an
+ * array of activity IDs depending on the number deleted.
+ *
+ * If you are deleting an activity comment please use bp_activity_delete_comment();
+ *
+ * @since BuddyPress (1.0)
+ *
+ * @see BP_Activity_Activity::get() For more information on accepted arguments.
+ * @uses wp_parse_args()
+ * @uses bp_activity_adjust_mention_count()
+ * @uses BP_Activity_Activity::delete() {@link BP_Activity_Activity}
+ * @uses do_action() To call the 'bp_before_activity_delete' hook.
+ * @uses bp_get_user_meta()
+ * @uses bp_delete_user_meta()
+ * @uses do_action() To call the 'bp_activity_delete' hook.
+ * @uses do_action() To call the 'bp_activity_deleted_activities' hook.
+ * @uses wp_cache_delete()
+ *
+ * @param array $args To delete specific activity items, use
+ *            $args = array( 'id' => $ids );
+ *        Otherwise, to use filters for item deletion, the argument format is
+ *        the same as BP_Activity_Activity::get(). See that method for a description.
+ * @return bool True on success, false on failure.
+ */
+function bp_activity_delete( $args = '' ) {
+
+	// Pass one or more the of following variables to delete by those variables
+	$defaults = array(
+		'id'                => false,
+		'action'            => false,
+		'content'           => false,
+		'component'         => false,
+		'type'              => false,
+		'primary_link'      => false,
+		'user_id'           => false,
+		'item_id'           => false,
+		'secondary_item_id' => false,
+		'date_recorded'     => false,
+		'hide_sitewide'     => false
+	);
+
+	$args = wp_parse_args( $args, $defaults );
+
+	do_action( 'bp_before_activity_delete', $args );
+
+	// Adjust the new mention count of any mentioned member
+	bp_activity_adjust_mention_count( $args['id'], 'delete' );
+
+	if ( !$activity_ids_deleted = BP_Activity_Activity::delete( $args ) )
+		return false;
+
+	// Check if the user's latest update has been deleted
+	if ( empty( $args['user_id'] ) )
+		$user_id = bp_loggedin_user_id();
+	else
+		$user_id = $args['user_id'];
+
+	$latest_update = bp_get_user_meta( $user_id, 'bp_latest_update', true );
+	if ( !empty( $latest_update ) ) {
+		if ( in_array( (int) $latest_update['id'], (array) $activity_ids_deleted ) ) {
+			bp_delete_user_meta( $user_id, 'bp_latest_update' );
+		}
+	}
+
+	do_action( 'bp_activity_delete', $args );
+	do_action( 'bp_activity_deleted_activities', $activity_ids_deleted );
+
+	wp_cache_delete( 'bp_activity_sitewide_front', 'bp' );
+
+	return true;
+}
+
+	/**
+	 * Delete an activity item by activity id.
+	 *
+	 * You should use bp_activity_delete() instead.
+	 *
+	 * @since BuddyPress (1.1)
+	 * @deprecated BuddyPress (1.2)
+	 *
+	 * @uses wp_parse_args()
+	 * @uses bp_activity_delete()
+	 *
+	 * @param array $args See BP_Activity_Activity::get for a description
+	 *                    of accepted arguments.
+	 *
+	 * @return bool True on success, false on failure.
+	 */
+	function bp_activity_delete_by_item_id( $args = '' ) {
+
+		$defaults = array(
+			'item_id'           => false,
+			'component'         => false,
+			'type'              => false,
+			'user_id'           => false,
+			'secondary_item_id' => false
+		);
+		$r = wp_parse_args( $args, $defaults );
+		extract( $r, EXTR_SKIP );
+
+		return bp_activity_delete( array( 'item_id' => $item_id, 'component' => $component, 'type' => $type, 'user_id' => $user_id, 'secondary_item_id' => $secondary_item_id ) );
+	}
+
+	/**
+	 * Delete an activity item by activity id.
+	 *
+	 * @since BuddyPress (1.1)
+	 *
+	 * @uses bp_activity_delete()
+	 *
+	 * @param int ID of the activity item to be deleted.
+	 * @return bool True on success, false on failure.
+	 */
+	function bp_activity_delete_by_activity_id( $activity_id ) {
+		return bp_activity_delete( array( 'id' => $activity_id ) );
+	}
+
+	/**
+	 * Delete an activity item by its content.
+	 *
+	 * You should use bp_activity_delete() instead.
+	 *
+	 * @since BuddyPress (1.1)
+	 * @deprecated BuddyPress (1.2)
+	 *
+	 * @uses bp_activity_delete()
+	 *
+	 * @param int $user_id The user id.
+	 * @param string $content The activity id.
+	 * @param string $component The activity component.
+	 * @param string $type The activity type.
+	 * @return bool True on success, false on failure.
+	 */
+	function bp_activity_delete_by_content( $user_id, $content, $component, $type ) {
+		return bp_activity_delete( array( 'user_id' => $user_id, 'content' => $content, 'component' => $component, 'type' => $type ) );
+	}
+
+	/**
+	 * Delete a user's activity for a component.
+	 *
+	 * You should use bp_activity_delete() instead.
+	 *
+	 * @since BuddyPress (1.1)
+	 * @deprecated BuddyPress (1.2)
+	 *
+	 * @uses bp_activity_delete()
+	 *
+	 * @param int $user_id The user id.
+	 * @param string $component The activity component.
+	 * @return bool True on success, false on failure.
+	 */
+	function bp_activity_delete_for_user_by_component( $user_id, $component ) {
+		return bp_activity_delete( array( 'user_id' => $user_id, 'component' => $component ) );
+	}
+
+/**
+ * Delete an activity comment.
+ *
+ * @since BuddyPress (1.2)
+ *
+ * @uses apply_filters() To call the 'bp_activity_delete_comment_pre' hook.
+ * @uses bp_activity_delete_children()
+ * @uses bp_activity_delete()
+ * @uses BP_Activity_Activity::rebuild_activity_comment_tree() {@link BP_Activity_Activity}
+ * @uses do_action() To call the 'bp_activity_delete_comment' hook.
+ * @todo Why is an activity id required? We could look this up.
+ * @todo Why do we encourage users to call this function directly? We could just
+ *       as easily examine the activity type in bp_activity_delete() and then
+ *       call this function with the proper arguments if necessary.
+ *
+ * @param int $activity_id The ID of the "root" activity, ie the comment's
+ *                         oldest ancestor.
+ * @param int $comment_id The ID of the comment to be deleted.
+ * @return bool True on success, false on failure
+ */
+function bp_activity_delete_comment( $activity_id, $comment_id ) {
+	/***
+	 * You may want to hook into this filter if you want to override this function and
+	 * handle the deletion of child comments differently. Make sure you return false.
+	 */
+	if ( !apply_filters( 'bp_activity_delete_comment_pre', true, $activity_id, $comment_id ) )
+		return false;
+
+	// Delete any children of this comment.
+	bp_activity_delete_children( $activity_id, $comment_id );
+
+	// Delete the actual comment
+	if ( !bp_activity_delete( array( 'id' => $comment_id, 'type' => 'activity_comment' ) ) )
+		return false;
+
+	// Recalculate the comment tree
+	BP_Activity_Activity::rebuild_activity_comment_tree( $activity_id );
+
+	do_action( 'bp_activity_delete_comment', $activity_id, $comment_id );
+
+	return true;
+}
+
+	/**
+	 * Delete an activity comment's children.
+	 *
+	 * @since BuddyPress (1.2)
+	 *
+	 * @uses BP_Activity_Activity::get_child_comments() {@link BP_Activity_Activity}
+	 * @uses bp_activity_delete_children()
+	 * @uses bp_activity_delete()
+	 *
+	 * @param int $activity_id The ID of the "root" activity, ie the
+	 *                         comment's oldest ancestor.
+	 * @param int $comment_id The ID of the comment to be deleted.
+	 */
+	function bp_activity_delete_children( $activity_id, $comment_id) {
+		// Recursively delete all children of this comment.
+		if ( $children = BP_Activity_Activity::get_child_comments( $comment_id ) ) {
+			foreach( (array) $children as $child ) {
+				bp_activity_delete_children( $activity_id, $child->id );
+			}
+		}
+		bp_activity_delete( array( 'secondary_item_id' => $comment_id, 'type' => 'activity_comment', 'item_id' => $activity_id ) );
+	}
+
+/**
+ * Get the permalink for a single activity item.
+ *
+ * When only the $activity_id param is passed, BP has to instantiate a new
+ * BP_Activity_Activity object. To save yourself some processing overhead,
+ * be sure to pass the full $activity_obj parameter as well, if you already
+ * have it available.
+ *
+ * @since BuddyPress (1.2)
+ *
+ * @uses bp_get_root_domain()
+ * @uses bp_get_activity_root_slug()
+ * @uses apply_filters_ref_array() To call the 'bp_activity_get_permalink' hook.
+ *
+ * @param int $activity_id The unique id of the activity object.
+ * @param object $activity_obj Optional. The activity object.
+ * @return string $link Permalink for the activity item.
+ */
+function bp_activity_get_permalink( $activity_id, $activity_obj = false ) {
+
+	if ( empty( $activity_obj ) )
+		$activity_obj = new BP_Activity_Activity( $activity_id );
+
+	if ( isset( $activity_obj->current_comment ) ) {
+		$activity_obj = $activity_obj->current_comment;
+	}
+
+	if ( 'new_blog_post' == $activity_obj->type || 'new_blog_comment' == $activity_obj->type || 'new_forum_topic' == $activity_obj->type || 'new_forum_post' == $activity_obj->type ) {
+		$link = $activity_obj->primary_link;
+	} else {
+		if ( 'activity_comment' == $activity_obj->type ) {
+			$link = bp_get_root_domain() . '/' . bp_get_activity_root_slug() . '/p/' . $activity_obj->item_id . '/';
+		} else {
+			$link = bp_get_root_domain() . '/' . bp_get_activity_root_slug() . '/p/' . $activity_obj->id . '/';
+		}
+	}
+
+	return apply_filters_ref_array( 'bp_activity_get_permalink', array( $link, &$activity_obj ) );
+}
+
+/**
+ * Hide a user's activity.
+ *
+ * @since BuddyPress (1.2)
+ *
+ * @uses BP_Activity_Activity::hide_all_for_user() {@link BP_Activity_Activity}
+ *
+ * @param int $user_id The ID of the user whose activity is being hidden.
+ * @return bool True on success, false on failure.
+ */
+function bp_activity_hide_user_activity( $user_id ) {
+	return BP_Activity_Activity::hide_all_for_user( $user_id );
+}
+
+/**
+ * Take content, remove images, and replace them with a single thumbnail image.
+ *
+ * The format of items in the activity stream is such that we do not want to
+ * allow an arbitrary number of arbitrarily large images to be rendered.
+ * However, the activity stream is built to elegantly display a single
+ * thumbnail corresponding to the activity comment. This function looks
+ * through the content, grabs the first image and converts it to a thumbnail,
+ * and removes the rest of the images from the string.
+ *
+ * @since BuddyPress (1.2)
+ *
+ * @uses esc_attr()
+ * @uses apply_filters() To call the 'bp_activity_thumbnail_content_images' hook
+ *
+ * @param string $content The content of the activity item.
+ * @param string $link Optional. The unescaped URL that the image should link
+ *                               to. If absent, the image will not be a link.
+ * @param array $activity_args Optional. The args passed to the activity
+ *                             creation function (eg bp_blogs_record_activity()).
+ * @return string $content The content with images stripped and replaced with a
+ *                         single thumb.
+ */
+function bp_activity_thumbnail_content_images( $content, $link = false, $args = false ) {
+
+	preg_match_all( '/<img[^>]*>/Ui', $content, $matches );
+
+	// Remove <img> tags. Also remove caption shortcodes and caption text if present
+	$content = preg_replace('|(\[caption(.*?)\])?<img[^>]*>([^\[\[]*\[\/caption\])?|', '', $content );
+
+	if ( !empty( $matches ) && !empty( $matches[0] ) ) {
+		// Get the SRC value
+		preg_match( '/<img.*?(src\=[\'|"]{0,1}.*?[\'|"]{0,1})[\s|>]{1}/i', $matches[0][0], $src );
+
+		// Get the width and height
+		preg_match( '/<img.*?(height\=[\'|"]{0,1}.*?[\'|"]{0,1})[\s|>]{1}/i', $matches[0][0], $height );
+		preg_match( '/<img.*?(width\=[\'|"]{0,1}.*?[\'|"]{0,1})[\s|>]{1}/i',  $matches[0][0], $width  );
+
+		if ( !empty( $src ) ) {
+			$src    = substr( substr( str_replace( 'src=', '', $src[1] ), 0, -1 ), 1 );
+			$height = substr( substr( str_replace( 'height=', '', $height[1] ), 0, -1 ), 1 );
+			$width  = substr( substr( str_replace( 'width=', '', $width[1] ), 0, -1 ), 1 );
+
+			if ( empty( $width ) || empty( $height ) ) {
+				$width  = 100;
+				$height = 100;
+			}
+
+			$ratio      = (int) $width / (int) $height;
+			$new_height = (int) $height >= 100 ? 100 : $height;
+			$new_width  = $new_height * $ratio;
+			$image      = '<img src="' . esc_url( $src ) . '" width="' . absint( $new_width ) . '" height="' . absint( $new_height ) . '" alt="' . __( 'Thumbnail', 'buddypress' ) . '" class="align-left thumbnail" />';
+
+			if ( !empty( $link ) ) {
+				$image = '<a href="' . esc_url( $link ) . '">' . $image . '</a>';
+			}
+
+			$content = $image . $content;
+		}
+	}
+
+	return apply_filters( 'bp_activity_thumbnail_content_images', $content, $matches, $args );
+}
+
+/**
+ * Fetch whether the current user is allowed to mark items as spam.
+ *
+ * @since BuddyPress (1.6)
+ *
+ * @return bool True if user is allowed to mark activity items as spam.
+ */
+function bp_activity_user_can_mark_spam() {
+	return apply_filters( 'bp_activity_user_can_mark_spam', bp_current_user_can( 'bp_moderate' ) );
+}
+
+/**
+ * Mark an activity item as spam.
+ *
+ * @since BuddyPress (1.6)
+ *
+ * @global object $bp BuddyPress global settings.
+ *
+ * @param BP_Activity_Activity $activity The activity item to be spammed.
+ * @param string $source Optional. Default is "by_a_person" (ie, a person has
+ *                       manually marked the activity as spam). BP core also
+ *                       accepts 'by_akismet'.
+ */
+function bp_activity_mark_as_spam( &$activity, $source = 'by_a_person' ) {
+	global $bp;
+
+	$activity->is_spam = 1;
+
+	// Clear the activity stream first page cache
+	wp_cache_delete( 'bp_activity_sitewide_front', 'bp' );
+
+	// Clear the activity comment cache for this activity item
+	wp_cache_delete( 'bp_activity_comments_' . $activity->id, 'bp' );
+
+	// If Akismet is active, and this was a manual spam/ham request, stop Akismet checking the activity
+	if ( 'by_a_person' == $source && !empty( $bp->activity->akismet ) ) {
+		remove_action( 'bp_activity_before_save', array( $bp->activity->akismet, 'check_activity' ), 4, 1 );
+
+		// Build data package for Akismet
+		$activity_data = BP_Akismet::build_akismet_data_package( $activity );
+
+		// Tell Akismet this is spam
+		$activity_data = $bp->activity->akismet->send_akismet_request( $activity_data, 'submit', 'spam' );
+
+		// Update meta
+		add_action( 'bp_activity_after_save', array( $bp->activity->akismet, 'update_activity_spam_meta' ), 1, 1 );
+	}
+
+	do_action( 'bp_activity_mark_as_spam', $activity, $source );
+}
+
+/**
+ * Mark an activity item as ham.
+ *
+ * @since BuddyPress (1.6)
+ *
+ * @global object $bp BuddyPress global settings.
+ *
+ * @param BP_Activity_Activity $activity The activity item to be hammed.
+ * @param string $source Optional. Default is "by_a_person" (ie, a person has
+ *                       manually marked the activity as spam). BP core also
+ *                       accepts 'by_akismet'.
+ */
+function bp_activity_mark_as_ham( &$activity, $source = 'by_a_person' ) {
+	global $bp;
+
+	$activity->is_spam = 0;
+
+	// Clear the activity stream first page cache
+	wp_cache_delete( 'bp_activity_sitewide_front', 'bp' );
+
+	// Clear the activity comment cache for this activity item
+	wp_cache_delete( 'bp_activity_comments_' . $activity->id, 'bp' );
+
+	// If Akismet is active, and this was a manual spam/ham request, stop Akismet checking the activity
+	if ( 'by_a_person' == $source && !empty( $bp->activity->akismet ) ) {
+		remove_action( 'bp_activity_before_save', array( $bp->activity->akismet, 'check_activity' ), 4, 1 );
+
+		// Build data package for Akismet
+		$activity_data = BP_Akismet::build_akismet_data_package( $activity );
+
+		// Tell Akismet this is spam
+		$activity_data = $bp->activity->akismet->send_akismet_request( $activity_data, 'submit', 'ham' );
+
+		// Update meta
+		add_action( 'bp_activity_after_save', array( $bp->activity->akismet, 'update_activity_ham_meta' ), 1, 1 );
+	}
+
+	do_action( 'bp_activity_mark_as_ham', $activity, $source );
+}
+
+
+/** Embeds *******************************************************************/
+
+/**
+ * Set up activity oEmbed cache during the activity loop.
+ *
+ * During an activity loop, this function sets up the hooks necessary to grab
+ * each item's embeds from the cache, or put them in the cache if they are
+ * not there yet.
+ *
+ * This does not cover recursive activity comments, as they do not use a real loop.
+ * For that, see {@link bp_activity_comment_embed()}.
+ *
+ * @since BuddyPress (1.5)
+ *
+ * @see BP_Embed
+ * @see bp_embed_activity_cache()
+ * @see bp_embed_activity_save_cache()
+ * @uses add_filter() To attach 'bp_get_activity_id' to 'embed_post_id'.
+ * @uses add_filter() To attach 'bp_embed_activity_cache' to 'bp_embed_get_cache'.
+ * @uses add_action() To attach 'bp_embed_activity_save_cache' to 'bp_embed_update_cache'.
+ */
+function bp_activity_embed() {
+	add_filter( 'embed_post_id',         'bp_get_activity_id'                  );
+	add_filter( 'bp_embed_get_cache',    'bp_embed_activity_cache',      10, 3 );
+	add_action( 'bp_embed_update_cache', 'bp_embed_activity_save_cache', 10, 3 );
+}
+add_action( 'activity_loop_start', 'bp_activity_embed' );
+
+/**
+ * Set up activity oEmbed cache while recursing through activity comments.
+ *
+ * While crawling through an activity comment tree
+ * ({@link bp_activity_recurse_comments}), this function sets up the hooks
+ * necessary to grab each comment's embeds from the cache, or put them in
+ * the cache if they are not there yet.
+ *
+ * @since BuddyPress (1.5)
+ *
+ * @see BP_Embed
+ * @see bp_embed_activity_cache()
+ * @see bp_embed_activity_save_cache()
+ * @uses add_filter() To attach 'bp_get_activity_comment_id' to 'embed_post_id'.
+ * @uses add_filter() To attach 'bp_embed_activity_cache' to 'bp_embed_get_cache'.
+ * @uses add_action() To attach 'bp_embed_activity_save_cache' to 'bp_embed_update_cache'.
+ */
+function bp_activity_comment_embed() {
+	add_filter( 'embed_post_id',         'bp_get_activity_comment_id'          );
+	add_filter( 'bp_embed_get_cache',    'bp_embed_activity_cache',      10, 3 );
+	add_action( 'bp_embed_update_cache', 'bp_embed_activity_save_cache', 10, 3 );
+}
+add_action( 'bp_before_activity_comment', 'bp_activity_comment_embed' );
+
+/**
+ * When a user clicks on a "Read More" item, make sure embeds are correctly parsed and shown for the expanded content.
+ *
+ * @since BuddyPress (1.5)
+ *
+ * @see BP_Embed
+ * @global object $bp BuddyPress global settings
+ * @uses add_filter() To attach create_function() to 'embed_post_id'.
+ * @uses add_filter() To attach 'bp_embed_activity_cache' to 'bp_embed_get_cache'.
+ * @uses add_action() To attach 'bp_embed_activity_save_cache' to 'bp_embed_update_cache'.
+ *
+ * @param object $activity The activity that is being expanded.
+ */
+function bp_dtheme_embed_read_more( $activity ) {
+	global $bp;
+
+	$bp->activity->read_more_id = $activity->id;
+
+	add_filter( 'embed_post_id',            create_function( '', 'global $bp; return $bp->activity->read_more_id;' ) );
+	add_filter( 'bp_embed_get_cache',       'bp_embed_activity_cache',      10, 3 );
+	add_action( 'bp_embed_update_cache',    'bp_embed_activity_save_cache', 10, 3 );
+}
+add_action( 'bp_dtheme_get_single_activity_content', 'bp_dtheme_embed_read_more' );
+
+/**
+ * Clean up 'embed_post_id' filter after comment recursion.
+ *
+ * This filter must be removed so that the non-comment filters take over again
+ * once the comments are done being processed.
+ *
+ * @since BuddyPress (1.5)
+ *
+ * @see bp_activity_comment_embed()
+ * @uses remove_filter() To remove 'bp_get_activity_comment_id' from 'embed_post_id'.
+ */
+function bp_activity_comment_embed_after_recurse() {
+	remove_filter( 'embed_post_id', 'bp_get_activity_comment_id' );
+}
+add_action( 'bp_after_activity_comment', 'bp_activity_comment_embed_after_recurse' );
+
+/**
+ * Fetch an activity item's cached embeds.
+ *
+ * Used during {@link BP_Embed::parse_oembed()} via {@link bp_activity_embed()}.
+ *
+ * @since BuddyPress (1.5)
+ *
+ * @see BP_Embed::parse_oembed()
+ * @uses bp_activity_get_meta()
+ *
+ * @param string $cache An empty string passed by BP_Embed::parse_oembed() for
+ *                      functions like this one to filter.
+ * @param int $id The ID of the activity item.
+ * @param string $cachekey The cache key generated in BP_Embed::parse_oembed().
+ * @return mixed The cached embeds for this activity item.
+ */
+function bp_embed_activity_cache( $cache, $id, $cachekey ) {
+	return bp_activity_get_meta( $id, $cachekey );
+}
+
+/**
+ * Set an activity item's embed cache.
+ *
+ * Used during {@link BP_Embed::parse_oembed()} via {@link bp_activity_embed()}.
+ *
+ * @since BuddyPress (1.5)
+ *
+ * @see BP_Embed::parse_oembed()
+ * @uses bp_activity_update_meta()
+ *
+ * @param string $cache An empty string passed by BP_Embed::parse_oembed() for
+ *                      functions like this one to filter.
+ * @param int $id The ID of the activity item.
+ * @param string $cachekey The cache key generated in BP_Embed::parse_oembed().
+ * @return bool True on success, false on failure.
+ */
+function bp_embed_activity_save_cache( $cache, $cachekey, $id ) {
+	bp_activity_update_meta( $id, $cachekey, $cache );
+}
Index: /tags/1.9/bp-activity/bp-activity-loader.php
===================================================================
--- /tags/1.9/bp-activity/bp-activity-loader.php	(revision 7684)
+++ /tags/1.9/bp-activity/bp-activity-loader.php	(revision 7684)
@@ -0,0 +1,363 @@
+<?php
+
+/**
+ * BuddyPress Activity Streams Loader.
+ *
+ * An activity stream component, for users, groups, and site tracking.
+ *
+ * @package BuddyPress
+ * @subpackage ActivityCore
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/**
+ * Main Activity Class.
+ *
+ * @since BuddyPress (1.5)
+ */
+class BP_Activity_Component extends BP_Component {
+
+	/**
+	 * Start the activity component setup process.
+	 *
+	 * @since BuddyPress (1.5)
+	 */
+	function __construct() {
+		parent::start(
+			'activity',
+			__( 'Activity Streams', 'buddypress' ),
+			BP_PLUGIN_DIR,
+			array(
+				'adminbar_myaccount_order' => 10
+			)
+		);
+	}
+
+	/**
+	 * Include component files.
+	 *
+	 * @since BuddyPress (1.5)
+	 *
+	 * @see BP_Component::includes() for a description of arguments.
+	 *
+	 * @param array $includes See BP_Component::includes() for a description.
+	 */
+	public function includes( $includes = array() ) {
+		// Files to include
+		$includes = array(
+			'actions',
+			'screens',
+			'filters',
+			'classes',
+			'template',
+			'functions',
+			'notifications',
+			'cache'
+		);
+
+		// Load Akismet support if Akismet is configured
+		$akismet_key = bp_get_option( 'wordpress_api_key' );
+		if ( defined( 'AKISMET_VERSION' ) && ( !empty( $akismet_key ) || defined( 'WPCOM_API_KEY' ) ) && apply_filters( 'bp_activity_use_akismet', bp_is_akismet_active() ) ) {
+			$includes[] = 'akismet';
+		}
+
+		if ( is_admin() ) {
+			$includes[] = 'admin';
+		}
+
+		parent::includes( $includes );
+	}
+
+	/**
+	 * Set up component global variables.
+	 *
+	 * The BP_ACTIVITY_SLUG constant is deprecated, and only used here for
+	 * backwards compatibility.
+	 *
+	 * @since BuddyPress (1.5)
+	 *
+	 * @see BP_Component::setup_globals() for a description of arguments.
+	 *
+	 * @param array $args See BP_Component::setup_globals() for a description.
+	 */
+	public function setup_globals( $args = array() ) {
+		$bp = buddypress();
+
+		// Define a slug, if necessary
+		if ( !defined( 'BP_ACTIVITY_SLUG' ) )
+			define( 'BP_ACTIVITY_SLUG', $this->id );
+
+		// Global tables for activity component
+		$global_tables = array(
+			'table_name'      => $bp->table_prefix . 'bp_activity',
+			'table_name_meta' => $bp->table_prefix . 'bp_activity_meta',
+		);
+
+		// All globals for activity component.
+		// Note that global_tables is included in this array.
+		$args = array(
+			'slug'                  => BP_ACTIVITY_SLUG,
+			'root_slug'             => isset( $bp->pages->activity->slug ) ? $bp->pages->activity->slug : BP_ACTIVITY_SLUG,
+			'has_directory'         => true,
+			'search_string'         => __( 'Search Activity...', 'buddypress' ),
+			'global_tables'         => $global_tables,
+			'notification_callback' => 'bp_activity_format_notifications',
+		);
+
+		parent::setup_globals( $args );
+	}
+
+	/**
+	 * Set up component navigation.
+	 *
+	 * @since BuddyPress (1.5)
+	 *
+	 * @see BP_Component::setup_nav() for a description of arguments.
+	 * @uses bp_is_active()
+	 * @uses is_user_logged_in()
+	 * @uses bp_get_friends_slug()
+	 * @uses bp_get_groups_slug()
+	 *
+	 * @param array $main_nav Optional. See BP_Component::setup_nav() for
+	 *                        description.
+	 * @param array $sub_nav Optional. See BP_Component::setup_nav() for
+	 *                       description.
+	 */
+	public function setup_nav( $main_nav = array(), $sub_nav = array() ) {
+
+		// Add 'Activity' to the main navigation
+		$main_nav = array(
+			'name'                => __( 'Activity', 'buddypress' ),
+			'slug'                => $this->slug,
+			'position'            => 10,
+			'screen_function'     => 'bp_activity_screen_my_activity',
+			'default_subnav_slug' => 'just-me',
+			'item_css_id'         => $this->id
+		);
+
+		// Stop if there is no user displayed or logged in
+		if ( !is_user_logged_in() && !bp_displayed_user_id() )
+			return;
+
+		// Determine user to use
+		if ( bp_displayed_user_domain() ) {
+			$user_domain = bp_displayed_user_domain();
+		} elseif ( bp_loggedin_user_domain() ) {
+			$user_domain = bp_loggedin_user_domain();
+		} else {
+			return;
+		}
+
+		// User link
+		$activity_link = trailingslashit( $user_domain . $this->slug );
+
+		// Add the subnav items to the activity nav item if we are using a theme that supports this
+		$sub_nav[] = array(
+			'name'            => __( 'Personal', 'buddypress' ),
+			'slug'            => 'just-me',
+			'parent_url'      => $activity_link,
+			'parent_slug'     => $this->slug,
+			'screen_function' => 'bp_activity_screen_my_activity',
+			'position'        => 10
+		);
+
+		// @ mentions
+		if ( bp_activity_do_mentions() ) {
+			$sub_nav[] = array(
+				'name'            => __( 'Mentions', 'buddypress' ),
+				'slug'            => 'mentions',
+				'parent_url'      => $activity_link,
+				'parent_slug'     => $this->slug,
+				'screen_function' => 'bp_activity_screen_mentions',
+				'position'        => 20,
+				'item_css_id'     => 'activity-mentions'
+			);
+		}
+
+		// Favorite activity items
+		$sub_nav[] = array(
+			'name'            => __( 'Favorites', 'buddypress' ),
+			'slug'            => 'favorites',
+			'parent_url'      => $activity_link,
+			'parent_slug'     => $this->slug,
+			'screen_function' => 'bp_activity_screen_favorites',
+			'position'        => 30,
+			'item_css_id'     => 'activity-favs'
+		);
+
+		// Additional menu if friends is active
+		if ( bp_is_active( 'friends' ) ) {
+			$sub_nav[] = array(
+				'name'            => __( 'Friends', 'buddypress' ),
+				'slug'            => bp_get_friends_slug(),
+				'parent_url'      => $activity_link,
+				'parent_slug'     => $this->slug,
+				'screen_function' => 'bp_activity_screen_friends',
+				'position'        => 40,
+				'item_css_id'     => 'activity-friends'
+			) ;
+		}
+
+		// Additional menu if groups is active
+		if ( bp_is_active( 'groups' ) ) {
+			$sub_nav[] = array(
+				'name'            => __( 'Groups', 'buddypress' ),
+				'slug'            => bp_get_groups_slug(),
+				'parent_url'      => $activity_link,
+				'parent_slug'     => $this->slug,
+				'screen_function' => 'bp_activity_screen_groups',
+				'position'        => 50,
+				'item_css_id'     => 'activity-groups'
+			);
+		}
+
+		parent::setup_nav( $main_nav, $sub_nav );
+	}
+
+	/**
+	 * Set up the component entries in the WordPress Admin Bar.
+	 *
+	 * @since BuddyPress (1.5)
+	 *
+	 * @see BP_Component::setup_nav() for a description of the $wp_admin_nav
+	 *      parameter array.
+	 * @uses is_user_logged_in()
+	 * @uses trailingslashit()
+	 * @uses bp_get_total_mention_count_for_user()
+	 * @uses bp_loggedin_user_id()
+	 * @uses bp_is_active()
+	 * @uses bp_get_friends_slug()
+	 * @uses bp_get_groups_slug()
+	 *
+	 * @param array $wp_admin_nav See BP_Component::setup_admin_bar() for a
+	 *                            description.
+	 */
+	public function setup_admin_bar( $wp_admin_nav = array() ) {
+		$bp = buddypress();
+
+		// Menus for logged in user
+		if ( is_user_logged_in() ) {
+
+			// Setup the logged in user variables
+			$user_domain   = bp_loggedin_user_domain();
+			$activity_link = trailingslashit( $user_domain . $this->slug );
+
+			// Unread message count
+			if ( bp_activity_do_mentions() ) {
+				$count = bp_get_total_mention_count_for_user( bp_loggedin_user_id() );
+				if ( !empty( $count ) ) {
+					$title = sprintf( __( 'Mentions <span class="count">%s</span>', 'buddypress' ), number_format_i18n( $count ) );
+				} else {
+					$title = __( 'Mentions', 'buddypress' );
+				}
+			}
+
+			// Add the "Activity" sub menu
+			$wp_admin_nav[] = array(
+				'parent' => $bp->my_account_menu_id,
+				'id'     => 'my-account-' . $this->id,
+				'title'  => __( 'Activity', 'buddypress' ),
+				'href'   => trailingslashit( $activity_link )
+			);
+
+			// Mentions
+			if ( bp_activity_do_mentions() ) {
+				$wp_admin_nav[] = array(
+					'parent' => 'my-account-' . $this->id,
+					'id'     => 'my-account-' . $this->id . '-mentions',
+					'title'  => $title,
+					'href'   => trailingslashit( $activity_link . 'mentions' )
+				);
+			}
+
+			// Personal
+			$wp_admin_nav[] = array(
+				'parent' => 'my-account-' . $this->id,
+				'id'     => 'my-account-' . $this->id . '-personal',
+				'title'  => __( 'Personal', 'buddypress' ),
+				'href'   => trailingslashit( $activity_link )
+			);
+
+			// Favorites
+			$wp_admin_nav[] = array(
+				'parent' => 'my-account-' . $this->id,
+				'id'     => 'my-account-' . $this->id . '-favorites',
+				'title'  => __( 'Favorites', 'buddypress' ),
+				'href'   => trailingslashit( $activity_link . 'favorites' )
+			);
+
+			// Friends?
+			if ( bp_is_active( 'friends' ) ) {
+				$wp_admin_nav[] = array(
+					'parent' => 'my-account-' . $this->id,
+					'id'     => 'my-account-' . $this->id . '-friends',
+					'title'  => __( 'Friends', 'buddypress' ),
+					'href'   => trailingslashit( $activity_link . bp_get_friends_slug() )
+				);
+			}
+
+			// Groups?
+			if ( bp_is_active( 'groups' ) ) {
+				$wp_admin_nav[] = array(
+					'parent' => 'my-account-' . $this->id,
+					'id'     => 'my-account-' . $this->id . '-groups',
+					'title'  => __( 'Groups', 'buddypress' ),
+					'href'   => trailingslashit( $activity_link . bp_get_groups_slug() )
+				);
+			}
+		}
+
+		parent::setup_admin_bar( $wp_admin_nav );
+	}
+
+	/**
+	 * Set up the title for pages and <title>.
+	 *
+	 * @since BuddyPress (1.5)
+	 *
+	 * @uses bp_is_activity_component()
+	 * @uses bp_is_my_profile()
+	 * @uses bp_core_fetch_avatar()
+	 */
+	function setup_title() {
+		$bp = buddypress();
+
+		// Adjust title based on view
+		if ( bp_is_activity_component() ) {
+			if ( bp_is_my_profile() ) {
+				$bp->bp_options_title = __( 'My Activity', 'buddypress' );
+			} else {
+				$bp->bp_options_avatar = bp_core_fetch_avatar( array(
+					'item_id' => bp_displayed_user_id(),
+					'type'    => 'thumb',
+					'alt'	  => sprintf( __( 'Profile picture of %s', 'buddypress' ), bp_get_displayed_user_fullname() )
+				) );
+				$bp->bp_options_title  = bp_get_displayed_user_fullname();
+			}
+		}
+
+		parent::setup_title();
+	}
+
+	/**
+	 * Set up actions necessary for the component.
+	 *
+	 * @since BuddyPress (1.6)
+	 */
+	 function setup_actions() {
+		// Spam prevention
+		add_action( 'bp_include', 'bp_activity_setup_akismet' );
+
+		parent::setup_actions();
+	}
+}
+
+/**
+ * Bootstrap the Activity component.
+ */
+function bp_setup_activity() {
+	buddypress()->activity = new BP_Activity_Component();
+}
+add_action( 'bp_setup_components', 'bp_setup_activity', 6 );
Index: /tags/1.9/bp-activity/bp-activity-notifications.php
===================================================================
--- /tags/1.9/bp-activity/bp-activity-notifications.php	(revision 7684)
+++ /tags/1.9/bp-activity/bp-activity-notifications.php	(revision 7684)
@@ -0,0 +1,353 @@
+<?php
+
+/**
+ * BuddyPress Activity Notifications.
+ *
+ * @package BuddyPress
+ * @subpackage ActivityNotifications
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/* Emails *********************************************************************/
+
+/**
+ * Send email and BP notifications when a user is mentioned in an update.
+ *
+ * @since BuddyPress (1.2)
+ *
+ * @uses bp_notifications_add_notification()
+ * @uses bp_get_user_meta()
+ * @uses bp_core_get_user_displayname()
+ * @uses bp_activity_get_permalink()
+ * @uses bp_core_get_user_domain()
+ * @uses bp_get_settings_slug()
+ * @uses bp_activity_filter_kses()
+ * @uses bp_core_get_core_userdata()
+ * @uses wp_specialchars_decode()
+ * @uses get_blog_option()
+ * @uses bp_is_active()
+ * @uses bp_is_group()
+ * @uses bp_get_current_group_name()
+ * @uses apply_filters() To call the 'bp_activity_at_message_notification_to' hook.
+ * @uses apply_filters() To call the 'bp_activity_at_message_notification_subject' hook.
+ * @uses apply_filters() To call the 'bp_activity_at_message_notification_message' hook.
+ * @uses wp_mail()
+ * @uses do_action() To call the 'bp_activity_sent_mention_email' hook
+ *
+ * @param int $activity_id The ID of the activity update.
+ * @param int $receiver_user_id The ID of the user who is receiving the update.
+ */
+function bp_activity_at_message_notification( $activity_id, $receiver_user_id ) {
+
+	// Don't leave multiple notifications for the same activity item
+	$notifications = BP_Core_Notification::get_all_for_user( $receiver_user_id, 'all' );
+
+	foreach( $notifications as $notification ) {
+		if ( $activity_id == $notification->item_id ) {
+			return;
+		}
+	}
+
+	$activity = new BP_Activity_Activity( $activity_id );
+
+	$subject = '';
+	$message = '';
+	$content = '';
+
+	// Now email the user with the contents of the message (if they have enabled email notifications)
+	if ( 'no' != bp_get_user_meta( $receiver_user_id, 'notification_activity_new_mention', true ) ) {
+		$poster_name = bp_core_get_user_displayname( $activity->user_id );
+
+		$message_link  = bp_activity_get_permalink( $activity_id );
+		$settings_slug = function_exists( 'bp_get_settings_slug' ) ? bp_get_settings_slug() : 'settings';
+		$settings_link = bp_core_get_user_domain( $receiver_user_id ) . $settings_slug . '/notifications/';
+
+		$poster_name = stripslashes( $poster_name );
+		$content = bp_activity_filter_kses( strip_tags( stripslashes( $activity->content ) ) );
+
+		// Set up and send the message
+		$ud       = bp_core_get_core_userdata( $receiver_user_id );
+		$to       = $ud->user_email;
+		$subject  = bp_get_email_subject( array( 'text' => sprintf( __( '%s mentioned you in an update', 'buddypress' ), $poster_name ) ) );
+
+		if ( bp_is_active( 'groups' ) && bp_is_group() ) {
+			$message = sprintf( __(
+'%1$s mentioned you in the group "%2$s":
+
+"%3$s"
+
+To view and respond to the message, log in and visit: %4$s
+
+---------------------
+', 'buddypress' ), $poster_name, bp_get_current_group_name(), $content, $message_link );
+		} else {
+			$message = sprintf( __(
+'%1$s mentioned you in an update:
+
+"%2$s"
+
+To view and respond to the message, log in and visit: %3$s
+
+---------------------
+', 'buddypress' ), $poster_name, $content, $message_link );
+		}
+
+		// Only show the disable notifications line if the settings component is enabled
+		if ( bp_is_active( 'settings' ) ) {
+			$message .= sprintf( __( 'To disable these notifications please log in and go to: %s', 'buddypress' ), $settings_link );
+		}
+
+		// Send the message
+		$to 	 = apply_filters( 'bp_activity_at_message_notification_to', $to );
+		$subject = apply_filters( 'bp_activity_at_message_notification_subject', $subject, $poster_name );
+		$message = apply_filters( 'bp_activity_at_message_notification_message', $message, $poster_name, $content, $message_link, $settings_link );
+
+		wp_mail( $to, $subject, $message );
+	}
+
+	do_action( 'bp_activity_sent_mention_email', $activity, $subject, $message, $content, $receiver_user_id );
+}
+
+/**
+ * Send email and BP notifications when an activity item receives a comment.
+ *
+ * @since BuddyPress (1.2)
+ *
+ * @uses bp_get_user_meta()
+ * @uses bp_core_get_user_displayname()
+ * @uses bp_activity_get_permalink()
+ * @uses bp_core_get_user_domain()
+ * @uses bp_get_settings_slug()
+ * @uses bp_activity_filter_kses()
+ * @uses bp_core_get_core_userdata()
+ * @uses wp_specialchars_decode()
+ * @uses get_blog_option()
+ * @uses bp_get_root_blog_id()
+ * @uses apply_filters() To call the 'bp_activity_new_comment_notification_to' hook
+ * @uses apply_filters() To call the 'bp_activity_new_comment_notification_subject' hook
+ * @uses apply_filters() To call the 'bp_activity_new_comment_notification_message' hook
+ * @uses wp_mail()
+ * @uses do_action() To call the 'bp_activity_sent_reply_to_update_email' hook
+ * @uses apply_filters() To call the 'bp_activity_new_comment_notification_comment_author_to' hook
+ * @uses apply_filters() To call the 'bp_activity_new_comment_notification_comment_author_subject' hook
+ * @uses apply_filters() To call the 'bp_activity_new_comment_notification_comment_author_message' hook
+ * @uses do_action() To call the 'bp_activity_sent_reply_to_reply_email' hook
+ *
+ * @param int $comment_id The comment id.
+ * @param int $commenter_id The ID of the user who posted the comment.
+ * @param array $params {@link bp_activity_new_comment()}
+ */
+function bp_activity_new_comment_notification( $comment_id = 0, $commenter_id = 0, $params = array() ) {
+
+	// Set some default parameters
+	$activity_id = 0;
+	$parent_id   = 0;
+
+	extract( $params );
+
+	$original_activity = new BP_Activity_Activity( $activity_id );
+
+	if ( $original_activity->user_id != $commenter_id && 'no' != bp_get_user_meta( $original_activity->user_id, 'notification_activity_new_reply', true ) ) {
+		$poster_name   = bp_core_get_user_displayname( $commenter_id );
+		$thread_link   = bp_activity_get_permalink( $activity_id );
+		$settings_slug = function_exists( 'bp_get_settings_slug' ) ? bp_get_settings_slug() : 'settings';
+		$settings_link = bp_core_get_user_domain( $original_activity->user_id ) . $settings_slug . '/notifications/';
+
+		$poster_name = stripslashes( $poster_name );
+		$content = bp_activity_filter_kses( stripslashes($content) );
+
+		// Set up and send the message
+		$ud      = bp_core_get_core_userdata( $original_activity->user_id );
+		$to      = $ud->user_email;
+		$subject = bp_get_email_subject( array( 'text' => sprintf( __( '%s replied to one of your updates', 'buddypress' ), $poster_name ) ) );
+		$message = sprintf( __(
+'%1$s replied to one of your updates:
+
+"%2$s"
+
+To view your original update and all comments, log in and visit: %3$s
+
+---------------------
+', 'buddypress' ), $poster_name, $content, $thread_link );
+
+		// Only show the disable notifications line if the settings component is enabled
+		if ( bp_is_active( 'settings' ) ) {
+			$message .= sprintf( __( 'To disable these notifications please log in and go to: %s', 'buddypress' ), $settings_link );
+		}
+
+		/* Send the message */
+		$to = apply_filters( 'bp_activity_new_comment_notification_to', $to );
+		$subject = apply_filters( 'bp_activity_new_comment_notification_subject', $subject, $poster_name );
+		$message = apply_filters( 'bp_activity_new_comment_notification_message', $message, $poster_name, $content, $thread_link, $settings_link );
+
+		wp_mail( $to, $subject, $message );
+
+		do_action( 'bp_activity_sent_reply_to_update_email', $original_activity->user_id, $subject, $message, $comment_id, $commenter_id, $params );
+	}
+
+	/***
+	 * If this is a reply to another comment, send an email notification to the
+	 * author of the immediate parent comment.
+	 */
+	if ( empty( $parent_id ) || ( $activity_id == $parent_id ) ) {
+		return false;
+	}
+
+	$parent_comment = new BP_Activity_Activity( $parent_id );
+
+	if ( $parent_comment->user_id != $commenter_id && $original_activity->user_id != $parent_comment->user_id && 'no' != bp_get_user_meta( $parent_comment->user_id, 'notification_activity_new_reply', true ) ) {
+		$poster_name   = bp_core_get_user_displayname( $commenter_id );
+		$thread_link   = bp_activity_get_permalink( $activity_id );
+		$settings_slug = function_exists( 'bp_get_settings_slug' ) ? bp_get_settings_slug() : 'settings';
+		$settings_link = bp_core_get_user_domain( $parent_comment->user_id ) . $settings_slug . '/notifications/';
+
+		// Set up and send the message
+		$ud       = bp_core_get_core_userdata( $parent_comment->user_id );
+		$to       = $ud->user_email;
+		$subject = bp_get_email_subject( array( 'text' => sprintf( __( '%s replied to one of your comments', 'buddypress' ), $poster_name ) ) );
+
+		$poster_name = stripslashes( $poster_name );
+		$content = bp_activity_filter_kses( stripslashes( $content ) );
+
+$message = sprintf( __(
+'%1$s replied to one of your comments:
+
+"%2$s"
+
+To view the original activity, your comment and all replies, log in and visit: %3$s
+
+---------------------
+', 'buddypress' ), $poster_name, $content, $thread_link );
+
+		// Only show the disable notifications line if the settings component is enabled
+		if ( bp_is_active( 'settings' ) ) {
+			$message .= sprintf( __( 'To disable these notifications please log in and go to: %s', 'buddypress' ), $settings_link );
+		}
+
+		/* Send the message */
+		$to = apply_filters( 'bp_activity_new_comment_notification_comment_author_to', $to );
+		$subject = apply_filters( 'bp_activity_new_comment_notification_comment_author_subject', $subject, $poster_name );
+		$message = apply_filters( 'bp_activity_new_comment_notification_comment_author_message', $message, $poster_name, $content, $settings_link, $thread_link );
+
+		wp_mail( $to, $subject, $message );
+
+		do_action( 'bp_activity_sent_reply_to_reply_email', $original_activity->user_id, $subject, $message, $comment_id, $commenter_id, $params );
+	}
+}
+
+/**
+ * Helper method to map action arguments to function parameters
+ *
+ * @since BuddyPress (1.9.0)
+ * @param int $comment_id
+ * @param array $params
+ */
+function bp_activity_new_comment_notification_helper( $comment_id, $params ) {
+	bp_activity_new_comment_notification( $comment_id, $params['user_id'], $params );
+}
+add_action( 'bp_activity_comment_posted', 'bp_activity_new_comment_notification_helper', 10, 2 );
+
+/** Notifications *************************************************************/
+
+/**
+ * Format notifications related to activity.
+ *
+ * @since BuddyPress (1.5)
+ *
+ * @uses bp_loggedin_user_domain()
+ * @uses bp_get_activity_slug()
+ * @uses bp_core_get_user_displayname()
+ * @uses apply_filters() To call the 'bp_activity_multiple_at_mentions_notification' hook.
+ * @uses apply_filters() To call the 'bp_activity_single_at_mentions_notification' hook.
+ * @uses do_action() To call 'activity_format_notifications' hook.
+ *
+ * @param string $action The type of activity item. Just 'new_at_mention' for now.
+ * @param int $item_id The activity ID.
+ * @param int $secondary_item_id In the case of at-mentions, this is the mentioner's ID.
+ * @param int $total_items The total number of notifications to format.
+ * @param string $format 'string' to get a BuddyBar-compatible notification, 'array' otherwise.
+ * @return string $return Formatted @mention notification.
+ */
+function bp_activity_format_notifications( $action, $item_id, $secondary_item_id, $total_items, $format = 'string' ) {
+
+	switch ( $action ) {
+		case 'new_at_mention':
+			$activity_id      = $item_id;
+			$poster_user_id   = $secondary_item_id;
+			$at_mention_link  = bp_loggedin_user_domain() . bp_get_activity_slug() . '/mentions/';
+			$at_mention_title = sprintf( __( '@%s Mentions', 'buddypress' ), bp_get_loggedin_user_username() );
+
+			if ( (int) $total_items > 1 ) {
+				$text = sprintf( __( 'You have %1$d new mentions', 'buddypress' ), (int) $total_items );
+				$filter = 'bp_activity_multiple_at_mentions_notification';
+			} else {
+				$user_fullname = bp_core_get_user_displayname( $poster_user_id );
+				$text =  sprintf( __( '%1$s mentioned you', 'buddypress' ), $user_fullname );
+				$filter = 'bp_activity_single_at_mentions_notification';
+			}
+		break;
+	}
+
+	if ( 'string' == $format ) {
+		$return = apply_filters( $filter, '<a href="' . esc_url( $at_mention_link ) . '" title="' . esc_attr( $at_mention_title ) . '">' . esc_html( $text ) . '</a>', $at_mention_link, (int) $total_items, $activity_id, $poster_user_id );
+	} else {
+		$return = apply_filters( $filter, array(
+			'text' => $text,
+			'link' => $at_mention_link
+		), $at_mention_link, (int) $total_items, $activity_id, $poster_user_id );
+	}
+
+	do_action( 'activity_format_notifications', $action, $item_id, $secondary_item_id, $total_items );
+
+	return $return;
+}
+
+/**
+ * Notify a member when their nicename is mentioned in an activity stream item.
+ *
+ * Hooked to the 'bp_activity_sent_mention_email' action, we piggy back off the
+ * existing email code for now, since it does the heavy lifting for us. In the
+ * future when we separate emails from Notifications, this will need its own
+ * 'bp_activity_at_name_send_emails' equivalent helper function.
+ *
+ * @since BuddyPress (1.9.0)
+ *
+ * @param obj $activity
+ * @param string $subject (not used)
+ * @param string $message (not used)
+ * @param string $content (not used)
+ * @param int $receiver_user_id
+ */
+function bp_activity_at_mention_add_notification( $activity, $subject, $message, $content, $receiver_user_id ) {
+	if ( bp_is_active( 'notifications' ) ) {
+		bp_notifications_add_notification( array(
+			'user_id'           => $receiver_user_id,
+			'item_id'           => $activity->id,
+			'secondary_item_id' => $activity->user_id,
+			'component_name'    => buddypress()->activity->id,
+			'component_action'  => 'new_at_mention',
+			'date_notified'     => bp_core_current_time(),
+			'is_new'            => 1,
+		) );
+	}
+}
+add_action( 'bp_activity_sent_mention_email', 'bp_activity_at_mention_add_notification', 10, 5 );
+
+/**
+ * Remove activity notifications when a user clicks on them.
+ *
+ * @since BuddyPress (1.5)
+ *
+ * @uses bp_notifications_mark_all_notifications_by_type()
+ */
+function bp_activity_remove_screen_notifications() {
+	if ( bp_is_active( 'notifications' ) ) {
+		bp_notifications_mark_notifications_by_type( bp_loggedin_user_id(), buddypress()->activity->id, 'new_at_mention' );
+	}
+}
+add_action( 'bp_activity_screen_my_activity',               'bp_activity_remove_screen_notifications' );
+add_action( 'bp_activity_screen_single_activity_permalink', 'bp_activity_remove_screen_notifications' );
+add_action( 'bp_activity_screen_mentions',                  'bp_activity_remove_screen_notifications' );
+
Index: /tags/1.9/bp-activity/bp-activity-screens.php
===================================================================
--- /tags/1.9/bp-activity/bp-activity-screens.php	(revision 7684)
+++ /tags/1.9/bp-activity/bp-activity-screens.php	(revision 7684)
@@ -0,0 +1,457 @@
+<?php
+
+/**
+ * BuddyPress Activity Screens.
+ *
+ * The functions in this file detect, with each page load, whether an Activity
+ * component page is being requested. If so, it parses any necessary data from
+ * the URL, and tells BuddyPress to load the appropriate template.
+ *
+ * @package BuddyPress
+ * @subpackage ActivityScreens
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/**
+ * Load the Activity directory.
+ *
+ * @since BuddyPress (1.5)
+ *
+ * @uses bp_displayed_user_id()
+ * @uses bp_is_activity_component()
+ * @uses bp_current_action()
+ * @uses bp_update_is_directory()
+ * @uses do_action() To call the 'bp_activity_screen_index' hook.
+ * @uses bp_core_load_template()
+ * @uses apply_filters() To call the 'bp_activity_screen_index' hook.
+ */
+function bp_activity_screen_index() {
+	if ( !bp_displayed_user_id() && bp_is_activity_component() && !bp_current_action() ) {
+		bp_update_is_directory( true, 'activity' );
+
+		do_action( 'bp_activity_screen_index' );
+
+		bp_core_load_template( apply_filters( 'bp_activity_screen_index', 'activity/index' ) );
+	}
+}
+add_action( 'bp_screens', 'bp_activity_screen_index' );
+
+/**
+ * Load the 'My Activity' page.
+ *
+ * @since BuddyPress (1.0)
+ *
+ * @uses do_action() To call the 'bp_activity_screen_my_activity' hook.
+ * @uses bp_core_load_template()
+ * @uses apply_filters() To call the 'bp_activity_template_my_activity' hook.
+ */
+function bp_activity_screen_my_activity() {
+	do_action( 'bp_activity_screen_my_activity' );
+	bp_core_load_template( apply_filters( 'bp_activity_template_my_activity', 'members/single/home' ) );
+}
+
+/**
+ * Load the 'My Friends' activity page.
+ *
+ * @since BuddyPress (1.0)
+ *
+ * @uses bp_is_active()
+ * @uses bp_update_is_item_admin()
+ * @uses bp_current_user_can()
+ * @uses do_action() To call the 'bp_activity_screen_friends' hook.
+ * @uses bp_core_load_template()
+ * @uses apply_filters() To call the 'bp_activity_template_friends_activity' hook.
+ */
+function bp_activity_screen_friends() {
+	if ( !bp_is_active( 'friends' ) )
+		return false;
+
+	bp_update_is_item_admin( bp_current_user_can( 'bp_moderate' ), 'activity' );
+	do_action( 'bp_activity_screen_friends' );
+	bp_core_load_template( apply_filters( 'bp_activity_template_friends_activity', 'members/single/home' ) );
+}
+
+/**
+ * Load the 'My Groups' activity page.
+ *
+ * @since BuddyPress (1.2)
+ *
+ * @uses bp_is_active()
+ * @uses bp_update_is_item_admin()
+ * @uses bp_current_user_can()
+ * @uses do_action() To call the 'bp_activity_screen_groups' hook
+ * @uses bp_core_load_template()
+ * @uses apply_filters() To call the 'bp_activity_template_groups_activity' hook
+ */
+function bp_activity_screen_groups() {
+	if ( !bp_is_active( 'groups' ) )
+		return false;
+
+	bp_update_is_item_admin( bp_current_user_can( 'bp_moderate' ), 'activity' );
+	do_action( 'bp_activity_screen_groups' );
+	bp_core_load_template( apply_filters( 'bp_activity_template_groups_activity', 'members/single/home' ) );
+}
+
+/**
+ * Load the 'Favorites' activity page.
+ *
+ * @since BuddyPress (1.2)
+ *
+ * @uses bp_update_is_item_admin()
+ * @uses bp_current_user_can()
+ * @uses do_action() To call the 'bp_activity_screen_favorites' hook
+ * @uses bp_core_load_template()
+ * @uses apply_filters() To call the 'bp_activity_template_favorite_activity' hook
+ */
+function bp_activity_screen_favorites() {
+	bp_update_is_item_admin( bp_current_user_can( 'bp_moderate' ), 'activity' );
+	do_action( 'bp_activity_screen_favorites' );
+	bp_core_load_template( apply_filters( 'bp_activity_template_favorite_activity', 'members/single/home' ) );
+}
+
+/**
+ * Load the 'Mentions' activity page.
+ *
+ * @since BuddyPress (1.2)
+ *
+ * @uses bp_update_is_item_admin()
+ * @uses bp_current_user_can()
+ * @uses do_action() To call the 'bp_activity_screen_mentions' hook
+ * @uses bp_core_load_template()
+ * @uses apply_filters() To call the 'bp_activity_template_mention_activity' hook
+ */
+function bp_activity_screen_mentions() {
+	bp_update_is_item_admin( bp_current_user_can( 'bp_moderate' ), 'activity' );
+	do_action( 'bp_activity_screen_mentions' );
+	bp_core_load_template( apply_filters( 'bp_activity_template_mention_activity', 'members/single/home' ) );
+}
+
+/**
+ * Reset the logged-in user's new mentions data when he visits his mentions screen.
+ *
+ * @since BuddyPress (1.5)
+ *
+ * @uses bp_is_my_profile()
+ * @uses bp_activity_clear_new_mentions()
+ * @uses bp_loggedin_user_id()
+ */
+function bp_activity_reset_my_new_mentions() {
+	if ( bp_is_my_profile() )
+		bp_activity_clear_new_mentions( bp_loggedin_user_id() );
+}
+add_action( 'bp_activity_screen_mentions', 'bp_activity_reset_my_new_mentions' );
+
+/**
+ * Load the page for a single activity item.
+ *
+ * @since BuddyPress (1.2)
+ *
+ * @global object $bp BuddyPress global settings
+ * @uses bp_is_activity_component()
+ * @uses bp_activity_get_specific()
+ * @uses bp_current_action()
+ * @uses bp_action_variables()
+ * @uses bp_do_404()
+ * @uses bp_is_active()
+ * @uses groups_get_group()
+ * @uses groups_is_user_member()
+ * @uses apply_filters_ref_array() To call the 'bp_activity_permalink_access' hook
+ * @uses do_action() To call the 'bp_activity_screen_single_activity_permalink' hook
+ * @uses bp_core_add_message()
+ * @uses is_user_logged_in()
+ * @uses bp_core_redirect()
+ * @uses site_url()
+ * @uses esc_url()
+ * @uses bp_get_root_domain()
+ * @uses bp_get_activity_root_slug()
+ * @uses bp_core_load_template()
+ * @uses apply_filters() To call the 'bp_activity_template_profile_activity_permalink' hook
+ */
+function bp_activity_screen_single_activity_permalink() {
+	global $bp;
+
+	// No displayed user or not viewing activity component
+	if ( !bp_is_activity_component() )
+		return false;
+
+	if ( ! bp_current_action() || !is_numeric( bp_current_action() ) )
+		return false;
+
+	// Get the activity details
+	$activity = bp_activity_get_specific( array( 'activity_ids' => bp_current_action(), 'show_hidden' => true, 'spam' => 'ham_only', ) );
+
+	// 404 if activity does not exist
+	if ( empty( $activity['activities'][0] ) || bp_action_variables() ) {
+		bp_do_404();
+		return;
+
+	} else {
+		$activity = $activity['activities'][0];
+	}
+
+	// Default access is true
+	$has_access = true;
+
+	// If activity is from a group, do an extra cap check
+	if ( isset( $bp->groups->id ) && $activity->component == $bp->groups->id ) {
+
+		// Activity is from a group, but groups is currently disabled
+		if ( !bp_is_active( 'groups') ) {
+			bp_do_404();
+			return;
+		}
+
+		// Check to see if the group is not public, if so, check the
+		// user has access to see this activity
+		if ( $group = groups_get_group( array( 'group_id' => $activity->item_id ) ) ) {
+
+			// Group is not public
+			if ( 'public' != $group->status ) {
+
+				// User is not a member of group
+				if ( !groups_is_user_member( bp_loggedin_user_id(), $group->id ) ) {
+					$has_access = false;
+				}
+			}
+		}
+	}
+
+	// Allow access to be filtered
+	$has_access = apply_filters_ref_array( 'bp_activity_permalink_access', array( $has_access, &$activity ) );
+
+	// Allow additional code execution
+	do_action( 'bp_activity_screen_single_activity_permalink', $activity, $has_access );
+
+	// Access is specifically disallowed
+	if ( false === $has_access ) {
+
+		// User feedback
+		bp_core_add_message( __( 'You do not have access to this activity.', 'buddypress' ), 'error' );
+
+		// Redirect based on logged in status
+		is_user_logged_in() ?
+			bp_core_redirect( bp_loggedin_user_domain() ) :
+			bp_core_redirect( site_url( 'wp-login.php?redirect_to=' . esc_url( bp_get_root_domain() . '/' . bp_get_activity_root_slug() . '/p/' . bp_current_action() . '/' ) ) );
+	}
+
+	bp_core_load_template( apply_filters( 'bp_activity_template_profile_activity_permalink', 'members/single/activity/permalink' ) );
+}
+add_action( 'bp_screens', 'bp_activity_screen_single_activity_permalink' );
+
+/**
+ * Add activity notifications settings to the notifications settings page.
+ *
+ * @since BuddyPress (1.2)
+ *
+ * @uses bp_get_user_meta()
+ * @uses bp_core_get_username()
+ * @uses do_action() To call the 'bp_activity_screen_notification_settings' hook.
+ */
+function bp_activity_screen_notification_settings() {
+
+	if ( bp_activity_do_mentions() ) {
+		if ( ! $mention = bp_get_user_meta( bp_displayed_user_id(), 'notification_activity_new_mention', true ) ) {
+			$mention = 'yes';
+		}
+	}
+
+	if ( ! $reply = bp_get_user_meta( bp_displayed_user_id(), 'notification_activity_new_reply', true ) ) {
+		$reply = 'yes';
+	}
+
+	?>
+
+	<table class="notification-settings" id="activity-notification-settings">
+		<thead>
+			<tr>
+				<th class="icon">&nbsp;</th>
+				<th class="title"><?php _e( 'Activity', 'buddypress' ) ?></th>
+				<th class="yes"><?php _e( 'Yes', 'buddypress' ) ?></th>
+				<th class="no"><?php _e( 'No', 'buddypress' )?></th>
+			</tr>
+		</thead>
+
+		<tbody>
+			<?php if ( bp_activity_do_mentions() ) : ?>
+				<tr id="activity-notification-settings-mentions">
+					<td>&nbsp;</td>
+					<td><?php printf( __( 'A member mentions you in an update using "@%s"', 'buddypress' ), bp_core_get_username( bp_displayed_user_id() ) ) ?></td>
+					<td class="yes"><input type="radio" name="notifications[notification_activity_new_mention]" value="yes" <?php checked( $mention, 'yes', true ) ?>/></td>
+					<td class="no"><input type="radio" name="notifications[notification_activity_new_mention]" value="no" <?php checked( $mention, 'no', true ) ?>/></td>
+				</tr>
+			<?php endif; ?>
+
+			<tr id="activity-notification-settings-replies">
+				<td>&nbsp;</td>
+				<td><?php _e( "A member replies to an update or comment you've posted", 'buddypress' ) ?></td>
+				<td class="yes"><input type="radio" name="notifications[notification_activity_new_reply]" value="yes" <?php checked( $reply, 'yes', true ) ?>/></td>
+				<td class="no"><input type="radio" name="notifications[notification_activity_new_reply]" value="no" <?php checked( $reply, 'no', true ) ?>/></td>
+			</tr>
+
+			<?php do_action( 'bp_activity_screen_notification_settings' ) ?>
+		</tbody>
+	</table>
+
+<?php
+}
+add_action( 'bp_notification_settings', 'bp_activity_screen_notification_settings', 1 );
+
+/** Theme Compatability *******************************************************/
+
+/**
+ * The main theme compat class for BuddyPress Activity.
+ *
+ * This class sets up the necessary theme compatability actions to safely output
+ * activity template parts to the_title and the_content areas of a theme.
+ *
+ * @since BuddyPress (1.7)
+ */
+class BP_Activity_Theme_Compat {
+
+	/**
+	 * Set up the activity component theme compatibility.
+	 *
+	 * @since BuddyPress (1.7)
+	 */
+	public function __construct() {
+		add_action( 'bp_setup_theme_compat', array( $this, 'is_activity' ) );
+	}
+
+	/**
+	 * Set up the theme compatibility hooks, if we're looking at an activity page.
+	 *
+	 * @since BuddyPress (1.7)
+	 */
+	public function is_activity() {
+
+		// Bail if not looking at a group
+		if ( ! bp_is_activity_component() )
+			return;
+
+		// Activity Directory
+		if ( ! bp_displayed_user_id() && ! bp_current_action() ) {
+			bp_update_is_directory( true, 'activity' );
+
+			do_action( 'bp_activity_screen_index' );
+
+			add_filter( 'bp_get_buddypress_template',                array( $this, 'directory_template_hierarchy' ) );
+			add_action( 'bp_template_include_reset_dummy_post_data', array( $this, 'directory_dummy_post' ) );
+			add_filter( 'bp_replace_the_content',                    array( $this, 'directory_content'    ) );
+
+		// Single activity
+		} elseif ( bp_is_single_activity() ) {
+			add_filter( 'bp_get_buddypress_template',                array( $this, 'single_template_hierarchy' ) );
+			add_action( 'bp_template_include_reset_dummy_post_data', array( $this, 'single_dummy_post' ) );
+			add_filter( 'bp_replace_the_content',                    array( $this, 'single_dummy_content'    ) );
+		}
+	}
+
+	/** Directory *************************************************************/
+
+	/**
+	 * Add template hierarchy to theme compat for the activity directory page.
+	 *
+	 * This is to mirror how WordPress has {@link https://codex.wordpress.org/Template_Hierarchy template hierarchy}.
+	 *
+	 * @since BuddyPress (1.8)
+	 *
+	 * @param string $templates The templates from bp_get_theme_compat_templates().
+	 * @return array $templates Array of custom templates to look for.
+	 */
+	public function directory_template_hierarchy( $templates ) {
+		// Setup our templates based on priority
+		$new_templates = apply_filters( 'bp_template_hierarchy_activity_directory', array(
+			'activity/index-directory.php'
+		) );
+
+		// Merge new templates with existing stack
+		// @see bp_get_theme_compat_templates()
+		$templates = array_merge( (array) $new_templates, $templates );
+
+		return $templates;
+	}
+
+	/**
+	 * Update the global $post with directory data.
+	 *
+	 * @since BuddyPress (1.7)
+	 */
+	public function directory_dummy_post() {
+		bp_theme_compat_reset_post( array(
+			'ID'             => 0,
+			'post_title'     => __( 'Sitewide Activity', 'buddypress' ),
+			'post_author'    => 0,
+			'post_date'      => 0,
+			'post_content'   => '',
+			'post_type'      => 'bp_activity',
+			'post_status'    => 'publish',
+			'is_archive'     => true,
+			'comment_status' => 'closed'
+		) );
+	}
+
+	/**
+	 * Filter the_content with the groups index template part.
+	 *
+	 * @since BuddyPress (1.7)
+	 */
+	public function directory_content() {
+		return bp_buffer_template_part( 'activity/index', null, false );
+	}
+
+	/** Single ****************************************************************/
+
+	/**
+	 * Add custom template hierarchy to theme compat for activity permalink pages.
+	 *
+	 * This is to mirror how WordPress has {@link https://codex.wordpress.org/Template_Hierarchy template hierarchy}.
+	 *
+	 * @since BuddyPress (1.8)
+	 *
+	 * @param string $templates The templates from bp_get_theme_compat_templates().
+	 * @return array $templates Array of custom templates to look for.
+	 */
+	public function single_template_hierarchy( $templates ) {
+		// Setup our templates based on priority
+		$new_templates = apply_filters( 'bp_template_hierarchy_activity_single_item', array(
+			'activity/single/index.php'
+		) );
+
+		// Merge new templates with existing stack
+		// @see bp_get_theme_compat_templates()
+		$templates = array_merge( (array) $new_templates, $templates );
+
+		return $templates;
+	}
+
+	/**
+	 * Update the global $post with the displayed user's data.
+	 *
+	 * @since BuddyPress (1.7)
+	 */
+	public function single_dummy_post() {
+		bp_theme_compat_reset_post( array(
+			'ID'             => 0,
+			'post_title'     => __( 'Activity', 'buddypress' ),
+			'post_author'    => 0,
+			'post_date'      => 0,
+			'post_content'   => '',
+			'post_type'      => 'bp_activity',
+			'post_status'    => 'publish',
+			'is_archive'     => true,
+			'comment_status' => 'closed'
+		) );
+	}
+
+	/**
+	 * Filter the_content with the members' activity permalink template part.
+	 *
+	 * @since BuddyPress (1.7)
+	 */
+	public function single_dummy_content() {
+		return bp_buffer_template_part( 'activity/single/home', null, false );
+	}
+}
+new BP_Activity_Theme_Compat();
Index: /tags/1.9/bp-activity/bp-activity-template.php
===================================================================
--- /tags/1.9/bp-activity/bp-activity-template.php	(revision 7684)
+++ /tags/1.9/bp-activity/bp-activity-template.php	(revision 7684)
@@ -0,0 +1,3271 @@
+<?php
+
+/**
+ * BuddyPress Activity Template Functions.
+ *
+ * @package BuddyPress
+ * @subpackage ActivityTemplate
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/**
+ * Output the activity component slug.
+ *
+ * @since BuddyPress (1.5)
+ *
+ * @uses bp_get_activity_slug()
+ */
+function bp_activity_slug() {
+	echo bp_get_activity_slug();
+}
+	/**
+	 * Return the activity component slug.
+	 *
+	 * @since BuddyPress (1.5)
+	 *
+	 * @global object $bp BuddyPress global settings.
+	 * @uses apply_filters() To call the 'bp_get_activity_slug' hook.
+	 *
+	 * @return string The activity component slug.
+	 */
+	function bp_get_activity_slug() {
+		global $bp;
+		return apply_filters( 'bp_get_activity_slug', $bp->activity->slug );
+	}
+
+/**
+ * Output the activity component root slug.
+ *
+ * @since BuddyPress (1.5)
+ *
+ * @uses bp_get_activity_root_slug()
+ */
+function bp_activity_root_slug() {
+	echo bp_get_activity_root_slug();
+}
+	/**
+	 * Return the activity component root slug.
+	 *
+	 * @since BuddyPress (1.5)
+	 *
+	 * @global object $bp BuddyPress global settings.
+	 * @uses apply_filters() To call the 'bp_get_activity_root_slug' hook.
+	 *
+	 * @return string The activity component root slug.
+	 */
+	function bp_get_activity_root_slug() {
+		global $bp;
+		return apply_filters( 'bp_get_activity_root_slug', $bp->activity->root_slug );
+	}
+
+/**
+ * Output activity directory permalink.
+ *
+ * @since BuddyPress (1.5)
+ *
+ * @uses bp_get_activity_directory_permalink()
+ */
+function bp_activity_directory_permalink() {
+	echo bp_get_activity_directory_permalink();
+}
+	/**
+	 * Return activity directory permalink
+	 *
+	 * @since BuddyPress (1.5)
+	 *
+	 * @uses traisingslashit()
+	 * @uses bp_get_root_domain()
+	 * @uses bp_get_activity_root_slug()
+	 * @uses apply_filters() To call the 'bp_get_activity_directory_permalink' hook.
+	 *
+	 * @return string Activity directory permalink.
+	 */
+	function bp_get_activity_directory_permalink() {
+		return apply_filters( 'bp_get_activity_directory_permalink', trailingslashit( bp_get_root_domain() . '/' . bp_get_activity_root_slug() ) );
+	}
+
+/**
+ * The main activity template loop class.
+ *
+ * This is responsible for loading a group of activity items and displaying them.
+ *
+ * @since BuddyPress (1.0)
+ */
+class BP_Activity_Template {
+	var $current_activity = -1;
+	var $activity_count;
+	var $total_activity_count;
+	var $activities;
+	var $activity;
+
+	var $in_the_loop;
+
+	var $pag_page;
+	var $pag_num;
+	var $pag_links;
+
+	var $full_name;
+
+	/**
+	 * Constructor method.
+	 *
+	 * The arguments passed to this class constructor are of the same
+	 * format as {@link BP_Activity_Activity::get()}.
+	 *
+	 * @see BP_Activity_Activity::get() for a description of the argument
+	 *      structure, as well as default values.
+	 *
+	 * @param array $args {
+	 *     Array of arguments. Supports all arguments from
+	 *     BP_Activity_Activity::get(), as well as 'page_arg' and
+	 *     'include'. Default values for 'per_page' and 'display_comments'
+	 *     differ from the originating function, and are described below.
+	 *     @type string $page_arg The string used as a query parameter in
+	 *           pagination links. Default: 'acpage'.
+	 *     @type array|bool $include Pass an array of activity IDs to
+	 *           retrieve only those items, or false to noop the 'include'
+	 *           parameter. 'include' differs from 'in' in that 'in' forms
+	 *           an IN clause that works in conjunction with other filters
+	 *           passed to the function, while 'include' is interpreted as
+	 *           an exact list of items to retrieve, which skips all other
+	 *           filter-related parameters. Default: false.
+	 *     @type int|bool $per_page Default: 20.
+	 *     @type string|bool $display_comments Default: 'threaded'.
+	 * }
+	 */
+	function __construct( $args ) {
+		global $bp;
+
+		// Backward compatibility with old method of passing arguments
+		if ( !is_array( $args ) || func_num_args() > 1 ) {
+			_deprecated_argument( __METHOD__, '1.6', sprintf( __( 'Arguments passed to %1$s should be in an associative array. See the inline documentation at %2$s for more details.', 'buddypress' ), __METHOD__, __FILE__ ) );
+
+			$old_args_keys = array(
+				0 => 'page',
+				1 => 'per_page',
+				2 => 'max',
+				3 => 'include',
+				4 => 'sort',
+				5 => 'filter',
+				6 => 'search_terms',
+				7 => 'display_comments',
+				8 => 'show_hidden',
+				9 => 'exclude',
+				10 => 'in',
+				11 => 'spam',
+				12 => 'page_arg'
+			);
+
+			$func_args = func_get_args();
+			$args = bp_core_parse_args_array( $old_args_keys, $func_args );
+		}
+
+		$defaults = array(
+			'page'             => 1,
+			'per_page'         => 20,
+			'page_arg'         => 'acpage',
+			'max'              => false,
+			'sort'             => false,
+			'include'          => false,
+			'exclude'          => false,
+			'in'               => false,
+			'filter'           => false,
+			'search_terms'     => false,
+			'meta_query'       => false,
+			'display_comments' => 'threaded',
+			'show_hidden'      => false,
+			'spam'             => 'ham_only',
+		);
+		$r = wp_parse_args( $args, $defaults );
+		extract( $r );
+
+		$this->pag_page = isset( $_REQUEST[$page_arg] ) ? intval( $_REQUEST[$page_arg] ) : $page;
+		$this->pag_num  = isset( $_REQUEST['num'] ) ? intval( $_REQUEST['num'] ) : $per_page;
+
+		// Check if blog/forum replies are disabled
+		$this->disable_blogforum_replies = isset( $bp->site_options['bp-disable-blogforum-comments'] ) ? $bp->site_options['bp-disable-blogforum-comments'] : false;
+
+		// Get an array of the logged in user's favorite activities
+		$this->my_favs = maybe_unserialize( bp_get_user_meta( bp_loggedin_user_id(), 'bp_favorite_activities', true ) );
+
+		// Fetch specific activity items based on ID's
+		if ( !empty( $include ) )
+			$this->activities = bp_activity_get_specific( array( 'activity_ids' => explode( ',', $include ), 'max' => $max, 'page' => $this->pag_page, 'per_page' => $this->pag_num, 'sort' => $sort, 'display_comments' => $display_comments, 'show_hidden' => $show_hidden, 'spam' => $spam ) );
+
+		// Fetch all activity items
+		else
+			$this->activities = bp_activity_get( array( 'display_comments' => $display_comments, 'max' => $max, 'per_page' => $this->pag_num, 'page' => $this->pag_page, 'sort' => $sort, 'search_terms' => $search_terms, 'meta_query' => $meta_query, 'filter' => $filter, 'show_hidden' => $show_hidden, 'exclude' => $exclude, 'in' => $in, 'spam' => $spam ) );
+
+		if ( !$max || $max >= (int) $this->activities['total'] )
+			$this->total_activity_count = (int) $this->activities['total'];
+		else
+			$this->total_activity_count = (int) $max;
+
+		$this->activities = $this->activities['activities'];
+
+		if ( $max ) {
+			if ( $max >= count($this->activities) ) {
+				$this->activity_count = count( $this->activities );
+			} else {
+				$this->activity_count = (int) $max;
+			}
+		} else {
+			$this->activity_count = count( $this->activities );
+		}
+
+		$this->full_name = bp_get_displayed_user_fullname();
+
+		// Fetch parent content for activity comments so we do not have to query in the loop
+		foreach ( (array) $this->activities as $activity ) {
+			if ( 'activity_comment' != $activity->type )
+				continue;
+
+			$parent_ids[] = $activity->item_id;
+		}
+
+		if ( !empty( $parent_ids ) )
+			$activity_parents = bp_activity_get_specific( array( 'activity_ids' => $parent_ids ) );
+
+		if ( !empty( $activity_parents['activities'] ) ) {
+			foreach( $activity_parents['activities'] as $parent )
+				$this->activity_parents[$parent->id] = $parent;
+
+			unset( $activity_parents );
+		}
+
+		if ( (int) $this->total_activity_count && (int) $this->pag_num ) {
+			$this->pag_links = paginate_links( array(
+				'base'      => add_query_arg( $page_arg, '%#%' ),
+				'format'    => '',
+				'total'     => ceil( (int) $this->total_activity_count / (int) $this->pag_num ),
+				'current'   => (int) $this->pag_page,
+				'prev_text' => _x( '&larr;', 'Activity pagination previous text', 'buddypress' ),
+				'next_text' => _x( '&rarr;', 'Activity pagination next text', 'buddypress' ),
+				'mid_size'  => 1
+			) );
+		}
+	}
+
+	/**
+	 * Whether there are activity items available in the loop.
+	 *
+	 * @see bp_has_activities()
+	 *
+	 * @return bool True if there are items in the loop, otherwise false.
+	 */
+	function has_activities() {
+		if ( $this->activity_count )
+			return true;
+
+		return false;
+	}
+
+	/**
+	 * Set up the next activity item and iterate index.
+	 *
+	 * @return object The next activity item to iterate over.
+	 */
+	function next_activity() {
+		$this->current_activity++;
+		$this->activity = $this->activities[$this->current_activity];
+
+		return $this->activity;
+	}
+
+	/**
+	 * Rewind the posts and reset post index.
+	 */
+	function rewind_activities() {
+		$this->current_activity = -1;
+		if ( $this->activity_count > 0 ) {
+			$this->activity = $this->activities[0];
+		}
+	}
+
+	/**
+	 * Whether there are activity items left in the loop to iterate over.
+	 *
+	 * This method is used by {@link bp_activities()} as part of the while loop
+	 * that controls iteration inside the activities loop, eg:
+	 *     while ( bp_activities() ) { ...
+	 *
+	 * @see bp_activities()
+	 *
+	 * @return bool True if there are more activity items to show,
+	 *              otherwise false.
+	 */
+	function user_activities() {
+		if ( $this->current_activity + 1 < $this->activity_count ) {
+			return true;
+		} elseif ( $this->current_activity + 1 == $this->activity_count ) {
+			do_action('activity_loop_end');
+			// Do some cleaning up after the loop
+			$this->rewind_activities();
+		}
+
+		$this->in_the_loop = false;
+		return false;
+	}
+
+	/**
+	 * Set up the current activity item inside the loop.
+	 *
+	 * Used by {@link bp_the_activity()} to set up the current activity item
+	 * data while looping, so that template tags used during that iteration
+	 * make reference to the current activity item.
+	 *
+	 * @see bp_the_activity()
+	 */
+	function the_activity() {
+
+		$this->in_the_loop = true;
+		$this->activity    = $this->next_activity();
+
+		if ( is_array( $this->activity ) )
+			$this->activity = (object) $this->activity;
+
+		if ( $this->current_activity == 0 ) // loop has just started
+			do_action('activity_loop_start');
+	}
+}
+
+/**
+ * Initialize the activity loop.
+ *
+ * Based on the $args passed, bp_has_activities() populates the
+ * $activities_template global, enabling the use of BuddyPress templates and
+ * template functions to display a list of activity items.
+ *
+ * @since BuddyPress (1.0)
+ *
+ * @global object $activities_template {@link BP_Activity_Template}
+ * @global object $bp BuddyPress global settings.
+ * @uses groups_is_user_member()
+ * @uses bp_current_action()
+ * @uses bp_is_current_action()
+ * @uses bp_get_activity_slug()
+ * @uses bp_action_variable()
+ * @uses wp_parse_args()
+ * @uses bp_is_active()
+ * @uses friends_get_friend_user_ids()
+ * @uses groups_get_user_groups()
+ * @uses bp_activity_get_user_favorites()
+ * @uses apply_filters() To call the 'bp_has_activities' hook.
+ *
+ * @param array $args {
+ *     Arguments for limiting the contents of the activity loop. Most
+ *     arguments are in the same format as {@link BP_Activity_Activity::get()}.
+ *     However, because the format of the arguments accepted here differs in
+ *     a number of ways, and because bp_has_activities() determines some
+ *     default arguments in a dynamic fashion, we list all accepted arguments
+ *     here as well.
+ *
+ *     Arguments can be passed as an associative array, or as a URL query
+ *     string (eg, 'user_id=4&display_comments=threaded').
+ *
+ *     @type int $page Which page of results to fetch. Using page=1 without
+ *           per_page will result in no pagination. Default: 1.
+ *     @type int|bool $per_page Number of results per page. Default: 20.
+ *     @type string $page_arg The string used as a query parameter in
+ *           pagination links. Default: 'acpage'.
+ *     @type int|bool $max Maximum number of results to return.
+ *           Default: false (unlimited).
+ *     @type string $sort 'ASC' or 'DESC'. Default: 'DESC'.
+ *     @type array|bool $exclude Array of activity IDs to exclude. Default: false.
+ *     @type array|bool $in Array of IDs to limit query by (IN). 'in' is
+ *           intended to be used in conjunction with other filter parameters.
+ *           Default: false.
+ *     @type array|bool $include Array of exact activity IDs to query.
+ *           Providing an 'include' array will override all other filters
+ *           passed in the argument array. When viewing a the permalink page
+ *           for a single activity item, this value defaults to the ID of that
+ *           item. Otherwise the default is false.
+ *     @type array $meta_query Limit by activitymeta by passing an array of
+ *           meta_query conditions. See {@link WP_Meta_Query::queries} for a
+ *           description of the syntax.
+ *     @type string $search_terms Limit results by a search term. Default: false.
+ *     @type string|bool $scope Use one of BuddyPress's pre-built filters. In
+ *           each case, the term 'current user' refers to the displayed user
+ *           when looking at a user profile, and otherwise to the logged-in user.
+ *             - 'just-me' retrieves items belonging only to the logged-in user;
+ *               this is equivalent to passing a 'user_id' argument
+ *             - 'friends' retrieves items belonging to the friends of the
+ *               current user
+ *             - 'groups' retrieves items associated with the groups to which
+ *               the current user belongs
+ *             - 'favorites' retrieves the current user's favorited activity
+ *               items
+ *             - 'mentions' retrieves activity items where the current user has
+ *               received an @-mention
+ *           The default value of 'scope' is set to one of the above if that
+ *           value appears in the appropriate place in the URL; eg, 'scope' will
+ *           be 'groups' when visiting http://example.com/members/joe/activity/groups/.
+ *           Otherwise defaults to false.
+ *     @type int|array|bool $user_id The ID(s) of user(s) whose activity should
+ *           be fetched. Pass a single ID or an array of IDs. When viewing a
+ *           user profile page (but not that user's activity subpages, ie My
+ *           Friends, My Groups, etc), 'user_id' defaults to the ID of the
+ *           displayed user. Otherwise the default is false.
+ *     @type string|array|bool $object Filters by the `component` column in the
+ *           database, which is generally the component ID in the case of
+ *           BuddyPress components, or the plugin slug in the case of plugins.
+ *           For example, 'groups' will limit results to those that are
+ *           associated with the BP Groups component. Accepts a single
+ *           component string, or an array of multiple components. Defaults to
+ *           'groups' when viewing the page of a single group, the My Groups
+ *           activity filter, or the Activity > Groups filter of a user profile.
+ *           Otherwise defaults to false.
+ *     @type string|array|bool $action Filters by the `type` column in the
+ *           database, which is a string categorizing the activity item (eg,
+ *           'new_blog_post', 'created_group'). Accepts a single type string,
+ *           or an array of multiple types. Defaults to false.
+ *     @type int|array|bool $primary_id Filters by the `item_id` column in the
+ *           database. The meaning of 'primary_id' differs between components/
+ *           types; for example, in the case of 'created_group', 'primary_id'
+ *           is the ID of the group. Accepts a single ID, or an array of
+ *           multiple IDs. When viewing a single group, defaults to the current
+ *           group ID. When viewing a user's Groups stream page, defaults to
+ *           the IDs of the user's groups. Otherwise defaults to false.
+ *     @type int|array|bool $secondary_id Filters by the `secondary_item_id`
+ *           column in the database. The meaning of 'secondary_id' differs
+ *           between components/types. Accepts a single ID, or an array of
+ *           multiple IDs. Defaults to false.
+ *     @type string|bool $display_comments How to handle activity comments.
+ *           Possible values:
+ *             - 'threaded' - comments appear in a threaded tree, under their
+ *               parent items
+ *             - 'stream' - the activity stream is presented in a flat manner,
+ *               with comments sorted in chronological order alongside other
+ *               activity items
+ *             - false - don't fetch activity comments at all
+ *           Default: 'threaded'.
+ *     @type bool $show_hidden Whether to show items marked hide_sitewide.
+ *           Defaults to false, except in the following cases:
+ *             - User is viewing his own activity stream
+ *             - User is viewing the activity stream of a non-public group of
+ *               which he is a member
+ *     @type bool $show_hidden Normally defaults to false, except when:
+ *             - a user is viewing his own activity stream
+ *             - a user is viewing the activity stream of a non-public group of
+ *               which he is a member
+ *     @type string|bool $spam Spam status. 'ham_only', 'spam_only', or false
+ *           to show all activity regardless of spam status. Default: 'ham_only'.
+ * }
+ * @return bool Returns true when activities are found, otherwise false.
+ */
+function bp_has_activities( $args = '' ) {
+	global $activities_template, $bp;
+
+	/***
+	 * Set the defaults based on the current page. Any of these will be overridden
+	 * if arguments are directly passed into the loop. Custom plugins should always
+	 * pass their parameters directly to the loop.
+	 */
+	$user_id     = false;
+	$include     = false;
+	$exclude     = false;
+	$in          = false;
+	$show_hidden = false;
+	$object      = false;
+	$primary_id  = false;
+
+	// User filtering
+	if ( bp_displayed_user_id() )
+		$user_id = bp_displayed_user_id();
+
+	// Group filtering
+	if ( !empty( $bp->groups->current_group ) ) {
+		$object = $bp->groups->id;
+		$primary_id = $bp->groups->current_group->id;
+
+		if ( ( 'public' != $bp->groups->current_group->status ) && ( groups_is_user_member( bp_loggedin_user_id(), $bp->groups->current_group->id ) || bp_current_user_can( 'bp_moderate' ) ) )
+			$show_hidden = true;
+	}
+
+	// The default scope should recognize custom slugs
+	if ( array_key_exists( bp_current_action(), (array) $bp->loaded_components ) ) {
+		$scope = $bp->loaded_components[bp_current_action()];
+	}
+	else
+		$scope = bp_current_action();
+
+	// Support for permalinks on single item pages: /groups/my-group/activity/124/
+	if ( bp_is_current_action( bp_get_activity_slug() ) )
+		$include = bp_action_variable( 0 );
+
+	// Note: any params used for filtering can be a single value, or multiple values comma separated.
+	$defaults = array(
+		'display_comments' => 'threaded',   // false for none, stream/threaded - show comments in the stream or threaded under items
+		'include'          => $include,     // pass an activity_id or string of IDs comma-separated
+		'exclude'          => $exclude,     // pass an activity_id or string of IDs comma-separated
+		'in'               => $in,          // comma-separated list or array of activity IDs among which to search
+		'sort'             => 'DESC',       // sort DESC or ASC
+		'page'             => 1,            // which page to load
+		'per_page'         => 20,           // number of items per page
+		'max'              => false,        // max number to return
+		'show_hidden'      => $show_hidden, // Show activity items that are hidden site-wide?
+		'spam'             => 'ham_only',   // Hide spammed items
+
+		'page_arg'         => 'acpage',     // See https://buddypress.trac.wordpress.org/ticket/3679
+
+		// Scope - pre-built activity filters for a user (friends/groups/favorites/mentions)
+		'scope'            => $scope,
+
+		// Filtering
+		'user_id'          => $user_id,     // user_id to filter on
+		'object'           => $object,      // object to filter on e.g. groups, profile, status, friends
+		'action'           => false,        // action to filter on e.g. activity_update, new_forum_post, profile_updated
+		'primary_id'       => $primary_id,  // object ID to filter on e.g. a group_id or forum_id or blog_id etc.
+		'secondary_id'     => false,        // secondary object ID to filter on e.g. a post_id
+
+		'meta_query'       => false,        // filter on activity meta. See WP_Meta_Query for format
+
+		// Searching
+		'search_terms'     => false         // specify terms to search on
+	);
+
+	$r = wp_parse_args( $args, $defaults );
+	extract( $r );
+
+	// Translate various values for 'display_comments'
+	// This allows disabling comments via ?display_comments=0
+	// or =none or =false. Final true is a strict type check. See #5029
+	if ( in_array( $display_comments, array( 0, '0', 'none', 'false' ), true ) ) {
+		$display_comments = false;
+	}
+
+	if ( empty( $search_terms ) && ! empty( $_REQUEST['s'] ) )
+		$search_terms = $_REQUEST['s'];
+
+	// If you have passed a "scope" then this will override any filters you have passed.
+	if ( 'just-me' == $scope || 'friends' == $scope || 'groups' == $scope || 'favorites' == $scope || 'mentions' == $scope ) {
+		if ( 'just-me' == $scope )
+			$display_comments = 'stream';
+
+		// determine which user_id applies
+		if ( empty( $user_id ) )
+			$user_id = bp_displayed_user_id() ? bp_displayed_user_id() : bp_loggedin_user_id();
+
+		// are we displaying user specific activity?
+		if ( is_numeric( $user_id ) ) {
+			$show_hidden = ( $user_id == bp_loggedin_user_id() && $scope != 'friends' ) ? 1 : 0;
+
+			switch ( $scope ) {
+				case 'friends':
+					if ( bp_is_active( 'friends' ) )
+						$friends = friends_get_friend_user_ids( $user_id );
+						if ( empty( $friends ) )
+							return false;
+
+						$user_id = implode( ',', (array) $friends );
+					break;
+				case 'groups':
+					if ( bp_is_active( 'groups' ) ) {
+						$groups = groups_get_user_groups( $user_id );
+						if ( empty( $groups['groups'] ) )
+							return false;
+
+						$object = $bp->groups->id;
+						$primary_id = implode( ',', (array) $groups['groups'] );
+
+						$user_id = 0;
+					}
+					break;
+				case 'favorites':
+					$favs = bp_activity_get_user_favorites( $user_id );
+					if ( empty( $favs ) )
+						return false;
+
+					$in = implode( ',', (array) $favs );
+					$display_comments = true;
+					$user_id = 0;
+					break;
+				case 'mentions':
+
+					// Are mentions disabled?
+					if ( ! bp_activity_do_mentions() ) {
+						return false;
+					}
+
+					// Start search at @ symbol and stop search at closing tag delimiter.
+					$search_terms     = '@' . bp_activity_get_user_mentionname( $user_id ) . '<';
+					$display_comments = 'stream';
+					$user_id = 0;
+					break;
+			}
+		}
+	}
+
+	// Do not exceed the maximum per page
+	if ( !empty( $max ) && ( (int) $per_page > (int) $max ) )
+		$per_page = $max;
+
+	// Support for basic filters in earlier BP versions is disabled by default. To enable, put
+	//   add_filter( 'bp_activity_enable_afilter_support', '__return_true' );
+	// into bp-custom.php or your theme's functions.php
+	if ( isset( $_GET['afilter'] ) && apply_filters( 'bp_activity_enable_afilter_support', false ) )
+		$filter = array( 'object' => $_GET['afilter'] );
+	else if ( !empty( $user_id ) || !empty( $object ) || !empty( $action ) || !empty( $primary_id ) || !empty( $secondary_id ) )
+		$filter = array( 'user_id' => $user_id, 'object' => $object, 'action' => $action, 'primary_id' => $primary_id, 'secondary_id' => $secondary_id );
+	else
+		$filter = false;
+
+	// If specific activity items have been requested, override the $hide_spam argument. This prevents backpat errors with AJAX.
+	if ( !empty( $include ) && ( 'ham_only' == $spam ) )
+		$spam = 'all';
+
+	$template_args = array(
+		'page'             => $page,
+		'per_page'         => $per_page,
+		'page_arg'         => $page_arg,
+		'max'              => $max,
+		'sort'             => $sort,
+		'include'          => $include,
+		'exclude'          => $exclude,
+		'in'               => $in,
+		'filter'           => $filter,
+		'search_terms'     => $search_terms,
+		'meta_query'       => $meta_query,
+		'display_comments' => $display_comments,
+		'show_hidden'      => $show_hidden,
+		'spam'             => $spam
+	);
+
+	$activities_template = new BP_Activity_Template( $template_args );
+
+	return apply_filters( 'bp_has_activities', $activities_template->has_activities(), $activities_template, $template_args );
+}
+
+/**
+ * Determine if there are still activities left in the loop.
+ *
+ * @since BuddyPress (1.0)
+ *
+ * @global object $activities_template {@link BP_Activity_Template}
+ * @uses BP_Activity_Template::user_activities() {@link BP_Activity_Template::user_activities()}
+ *
+ * @return bool Returns true when activities are found.
+ */
+function bp_activities() {
+	global $activities_template;
+	return $activities_template->user_activities();
+}
+
+/**
+ * Get the current activity object in the loop.
+ *
+ * @since BuddyPress (1.0)
+ *
+ * @global object $activities_template {@link BP_Activity_Template}
+ * @uses BP_Activity_Template::the_activity() {@link BP_Activity_Template::the_activity()}
+ *
+ * @return object The current activity within the loop.
+ */
+function bp_the_activity() {
+	global $activities_template;
+	return $activities_template->the_activity();
+}
+
+/**
+ * Output the activity pagination count.
+ *
+ * @since BuddyPress (1.0)
+ *
+ * @global object $activities_template {@link BP_Activity_Template}
+ * @uses BP_Activity_Template::the_activity() {@link BP_Activity_Template::the_activity()}
+ */
+function bp_activity_pagination_count() {
+	echo bp_get_activity_pagination_count();
+}
+
+	/**
+	 * Return the activity pagination count.
+	 *
+	 * @since BuddyPress (1.2)
+	 *
+	 * @global object $activities_template {@link BP_Activity_Template}
+	 * @uses bp_core_number_format()
+	 *
+	 * @return string The pagination text.
+	 */
+	function bp_get_activity_pagination_count() {
+		global $activities_template;
+
+		$start_num = intval( ( $activities_template->pag_page - 1 ) * $activities_template->pag_num ) + 1;
+		$from_num  = bp_core_number_format( $start_num );
+		$to_num    = bp_core_number_format( ( $start_num + ( $activities_template->pag_num - 1 ) > $activities_template->total_activity_count ) ? $activities_template->total_activity_count : $start_num + ( $activities_template->pag_num - 1 ) );
+		$total     = bp_core_number_format( $activities_template->total_activity_count );
+
+		return sprintf( _n( 'Viewing item %1$s to %2$s (of %3$s item)', 'Viewing item %1$s to %2$s (of %3$s items)', $total, 'buddypress' ), $from_num, $to_num, $total );
+	}
+
+/**
+ * Output the activity pagination links.
+ *
+ * @since BuddyPress (1.0)
+ *
+ * @uses bp_get_activity_pagination_links()
+ */
+function bp_activity_pagination_links() {
+	echo bp_get_activity_pagination_links();
+}
+
+	/**
+	 * Return the activity pagination links.
+	 *
+	 * @since BuddyPress (1.0)
+	 *
+	 * @global object $activities_template {@link BP_Activity_Template}
+	 * @uses apply_filters() To call the 'bp_get_activity_pagination_links' hook.
+	 *
+	 * @return string The pagination links.
+	 */
+	function bp_get_activity_pagination_links() {
+		global $activities_template;
+
+		return apply_filters( 'bp_get_activity_pagination_links', $activities_template->pag_links );
+	}
+
+/**
+ * Return true when there are more activity items to be shown than currently appear.
+ *
+ * @since BuddyPress (1.5)
+ *
+ * @global object $activities_template {@link BP_Activity_Template}
+ * @uses apply_filters() To call the 'bp_activity_has_more_items' hook.
+ *
+ * @return bool $has_more_items True if more items, false if not.
+ */
+function bp_activity_has_more_items() {
+	global $activities_template;
+
+	$remaining_pages = floor( ( $activities_template->total_activity_count - 1 ) / ( $activities_template->pag_num * $activities_template->pag_page ) );
+	$has_more_items  = (int) $remaining_pages ? true : false;
+
+	return apply_filters( 'bp_activity_has_more_items', $has_more_items );
+}
+
+/**
+ * Output the activity count.
+ *
+ * @since BuddyPress (1.2)
+ *
+ * @uses bp_get_activity_count()
+ */
+function bp_activity_count() {
+	echo bp_get_activity_count();
+}
+
+	/**
+	 * Return the activity count.
+	 *
+	 * @since BuddyPress (1.2)
+	 *
+	 * @global object $activities_template {@link BP_Activity_Template}
+	 * @uses apply_filters() To call the 'bp_get_activity_count' hook.
+	 *
+	 * @return int The activity count.
+	 */
+	function bp_get_activity_count() {
+		global $activities_template;
+
+		return apply_filters( 'bp_get_activity_count', (int) $activities_template->activity_count );
+	}
+
+/**
+ * Output the number of activities per page.
+ *
+ * @since BuddyPress (1.2)
+ *
+ * @uses bp_get_activity_per_page()
+ */
+function bp_activity_per_page() {
+	echo bp_get_activity_per_page();
+}
+
+	/**
+	 * Return the number of activities per page.
+	 *
+	 * @since BuddyPress (1.2)
+	 *
+	 * @global object $activities_template {@link BP_Activity_Template}
+	 * @uses apply_filters() To call the 'bp_get_activity_per_page' hook.
+	 *
+	 * @return int The activities per page.
+	 */
+	function bp_get_activity_per_page() {
+		global $activities_template;
+
+		return apply_filters( 'bp_get_activity_per_page', (int) $activities_template->pag_num );
+	}
+
+/**
+ * Output the activities title.
+ *
+ * @since BuddyPress (1.0)
+ *
+ * @uses bp_get_activities_title()
+ * @todo Deprecate.
+ */
+function bp_activities_title() {
+	echo bp_get_activities_title();
+}
+
+	/**
+	 * Return the activities title.
+	 *
+	 * @since BuddyPress (1.0)
+	 *
+	 * @global string $bp_activity_title
+	 * @uses apply_filters() To call the 'bp_get_activities_title' hook.
+	 * @todo Deprecate.
+	 *
+	 * @return int The activities title.
+	 */
+	function bp_get_activities_title() {
+		global $bp_activity_title;
+
+		return apply_filters( 'bp_get_activities_title', $bp_activity_title );
+	}
+
+/**
+ * {@internal Missing Description}
+ *
+ * @since BuddyPress (1.0)
+ *
+ * @uses bp_get_activities_no_activity()
+ * @todo Deprecate.
+ */
+function bp_activities_no_activity() {
+	echo bp_get_activities_no_activity();
+}
+
+	/**
+	 * {@internal Missing Description}
+	 *
+	 * @since BuddyPress (1.0)
+	 *
+	 * @global string $bp_activity_no_activity
+	 * @uses apply_filters() To call the 'bp_get_activities_no_activity' hook
+	 * @todo Deprecate.
+	 *
+	 * @return string
+	 */
+	function bp_get_activities_no_activity() {
+		global $bp_activity_no_activity;
+
+		return apply_filters( 'bp_get_activities_no_activity', $bp_activity_no_activity );
+	}
+
+/**
+ * Output the activity ID.
+ *
+ * @since BuddyPress (1.2)
+ *
+ * @uses bp_get_activity_id()
+ */
+function bp_activity_id() {
+	echo bp_get_activity_id();
+}
+
+	/**
+	 * Return the activity ID.
+	 *
+	 * @since BuddyPress (1.2)
+	 *
+	 * @global object $activities_template {@link BP_Activity_Template}
+	 * @uses apply_filters() To call the 'bp_get_activity_id' hook.
+	 *
+	 * @return int The activity ID.
+	 */
+	function bp_get_activity_id() {
+		global $activities_template;
+		return apply_filters( 'bp_get_activity_id', $activities_template->activity->id );
+	}
+
+/**
+ * Output the activity item ID.
+ *
+ * @since BuddyPress (1.2)
+ *
+ * @uses bp_get_activity_item_id()
+ */
+function bp_activity_item_id() {
+	echo bp_get_activity_item_id();
+}
+
+	/**
+	 * Return the activity item ID.
+	 *
+	 * @since BuddyPress (1.2)
+	 *
+	 * @global object $activities_template {@link BP_Activity_Template}
+	 * @uses apply_filters() To call the 'bp_get_activity_item_id' hook.
+	 *
+	 * @return int The activity item ID.
+	 */
+	function bp_get_activity_item_id() {
+		global $activities_template;
+		return apply_filters( 'bp_get_activity_item_id', $activities_template->activity->item_id );
+	}
+
+/**
+ * Output the activity secondary item ID.
+ *
+ * @since BuddyPress (1.2)
+ *
+ * @uses bp_get_activity_secondary_item_id()
+ */
+function bp_activity_secondary_item_id() {
+	echo bp_get_activity_secondary_item_id();
+}
+
+	/**
+	 * Return the activity secondary item ID.
+	 *
+	 * @since BuddyPress (1.2)
+	 *
+	 * @global object $activities_template {@link BP_Activity_Template}
+	 * @uses apply_filters() To call the 'bp_get_activity_secondary_item_id' hook.
+	 *
+	 * @return int The activity secondary item ID.
+	 */
+	function bp_get_activity_secondary_item_id() {
+		global $activities_template;
+		return apply_filters( 'bp_get_activity_secondary_item_id', $activities_template->activity->secondary_item_id );
+	}
+
+/**
+ * Output the date the activity was recorded.
+ *
+ * @since BuddyPress (1.2)
+ *
+ * @uses bp_get_activity_date_recorded()
+ */
+function bp_activity_date_recorded() {
+	echo bp_get_activity_date_recorded();
+}
+
+	/**
+	 * Return the date the activity was recorded.
+	 *
+	 * @since BuddyPress (1.2)
+	 *
+	 * @global object $activities_template {@link BP_Activity_Template}
+	 * @uses apply_filters() To call the 'bp_get_activity_date_recorded' hook.
+	 *
+	 * @return string The date the activity was recorded.
+	 */
+	function bp_get_activity_date_recorded() {
+		global $activities_template;
+		return apply_filters( 'bp_get_activity_date_recorded', $activities_template->activity->date_recorded );
+	}
+
+/**
+ * Output the activity object name.
+ *
+ * @since BuddyPress (1.2)
+ *
+ * @uses bp_get_activity_object_name()
+ */
+function bp_activity_object_name() {
+	echo bp_get_activity_object_name();
+}
+
+	/**
+	 * Return the activity object name.
+	 *
+	 * @since BuddyPress (1.2)
+	 *
+	 * @global object $activities_template {@link BP_Activity_Template}
+	 * @uses apply_filters() To call the 'bp_get_activity_object_name' hook.
+	 *
+	 * @return string The activity object name.
+	 */
+	function bp_get_activity_object_name() {
+		global $activities_template;
+		return apply_filters( 'bp_get_activity_object_name', $activities_template->activity->component );
+	}
+
+/**
+ * Output the activity type.
+ *
+ * @since BuddyPress (1.2)
+ *
+ * @uses bp_get_activity_type()
+ */
+function bp_activity_type() {
+	echo bp_get_activity_type();
+}
+
+	/**
+	 * Return the activity type.
+	 *
+	 * @since BuddyPress (1.2)
+	 *
+	 * @global object $activities_template {@link BP_Activity_Template}
+	 * @uses apply_filters() To call the 'bp_get_activity_type' hook.
+	 *
+	 * @return string The activity type.
+	 */
+	function bp_get_activity_type() {
+		global $activities_template;
+		return apply_filters( 'bp_get_activity_type', $activities_template->activity->type );
+	}
+
+	/**
+	 * Output the activity action name.
+	 *
+	 * Just a wrapper for bp_activity_type().
+	 *
+	 * @since BuddyPress (1.2)
+	 * @deprecated BuddyPress (1.5)
+	 *
+	 * @todo Properly deprecate in favor of bp_activity_type() and
+	 *		 remove redundant echo
+	 *
+	 * @uses bp_activity_type()
+	 */
+	function bp_activity_action_name() { echo bp_activity_type(); }
+
+	/**
+	 * Return the activity type.
+	 *
+	 * Just a wrapper for bp_get_activity_type().
+	 *
+	 * @since BuddyPress (1.2)
+	 * @deprecated BuddyPress (1.5)
+	 *
+	 * @todo Properly deprecate in favor of bp_get_activity_type().
+	 *
+	 * @uses bp_get_activity_type()
+	 *
+	 * @return string The activity type.
+	 */
+	function bp_get_activity_action_name() { return bp_get_activity_type(); }
+
+/**
+ * Output the activity user ID.
+ *
+ * @since BuddyPress (1.1)
+ *
+ * @uses bp_get_activity_user_id()
+ */
+function bp_activity_user_id() {
+	echo bp_get_activity_user_id();
+}
+
+	/**
+	 * Return the activity user ID.
+	 *
+	 * @since BuddyPress (1.1)
+	 *
+	 * @global object $activities_template {@link BP_Activity_Template}
+	 * @uses apply_filters() To call the 'bp_get_activity_user_id' hook.
+	 *
+	 * @return int The activity user ID.
+	 */
+	function bp_get_activity_user_id() {
+		global $activities_template;
+		return apply_filters( 'bp_get_activity_user_id', $activities_template->activity->user_id );
+	}
+
+/**
+ * Output the activity user link.
+ *
+ * @since BuddyPress (1.2)
+ *
+ * @uses bp_get_activity_user_link()
+ */
+function bp_activity_user_link() {
+	echo bp_get_activity_user_link();
+}
+
+	/**
+	 * Return the activity user link.
+	 *
+	 * @since BuddyPress (1.2)
+	 *
+	 * @global object $activities_template {@link BP_Activity_Template}
+	 * @uses bp_core_get_user_domain()
+	 * @uses apply_filters() To call the 'bp_get_activity_user_link' hook.
+	 *
+	 * @return string $link The activity user link.
+	 */
+	function bp_get_activity_user_link() {
+		global $activities_template;
+
+		if ( empty( $activities_template->activity->user_id ) )
+			$link = $activities_template->activity->primary_link;
+		else
+			$link = bp_core_get_user_domain( $activities_template->activity->user_id, $activities_template->activity->user_nicename, $activities_template->activity->user_login );
+
+		return apply_filters( 'bp_get_activity_user_link', $link );
+	}
+
+/**
+ * Output the avatar of the user that performed the action.
+ *
+ * @since BuddyPress (1.1)
+ *
+ * @see bp_get_activity_avatar() for description of arguments.
+ * @uses bp_get_activity_avatar()
+ *
+ * @param array $args See {@link bp_get_activity_avatar()} for description.
+ */
+function bp_activity_avatar( $args = '' ) {
+	echo bp_get_activity_avatar( $args );
+}
+	/**
+	 * Return the avatar of the user that performed the action.
+	 *
+	 * @since BuddyPress (1.1)
+	 *
+	 * @see bp_core_fetch_avatar() For a description of the arguments.
+	 * @global object $activities_template {@link BP_Activity_Template}
+	 * @global object $bp BuddyPress global settings
+	 * @uses bp_is_single_activity()
+	 * @uses wp_parse_args()
+	 * @uses apply_filters() To call the 'bp_get_activity_avatar_object_' . $current_activity_item->component hook
+	 * @uses apply_filters() To call the 'bp_get_activity_avatar_item_id' hook
+	 * @uses bp_core_fetch_avatar()
+	 * @uses apply_filters() To call the 'bp_get_activity_avatar' hook
+	 *
+	 * @param array $args  {
+	 *     Arguments are listed here with an explanation of their defaults.
+	 *     For more information about the arguments, see
+	 *     {@link bp_core_fetch_avatar()}.
+	 *     @type string $alt Default: 'Profile picture of [user name]' if
+	 *           activity user name is available, otherwise 'Profile picture'.
+	 *     @type string $class Default: 'avatar'.
+	 *     @type string|bool $email Default: Email of the activity's
+	 *           associated user, if available. Otherwise false.
+	 *     @type string $type Default: 'full' when viewing a single activity
+	 *           permalink page, otherwise 'thumb'.
+	 *     @type int|bool $user_id Default: ID of the activity's user.
+	 * }
+	 * @return string User avatar string.
+	 */
+	function bp_get_activity_avatar( $args = '' ) {
+		global $activities_template;
+
+		$bp = buddypress();
+
+		// On activity permalink pages, default to the full-size avatar
+		$type_default = bp_is_single_activity() ? 'full' : 'thumb';
+
+		// Within the activity comment loop, the current activity should be set
+		// to current_comment. Otherwise, just use activity.
+		$current_activity_item = isset( $activities_template->activity->current_comment ) ? $activities_template->activity->current_comment : $activities_template->activity;
+
+		// Activity user display name
+		$dn_default  = isset( $current_activity_item->display_name ) ? $current_activity_item->display_name : '';
+
+		// Prepend some descriptive text to alt
+		$alt_default = !empty( $dn_default ) ? sprintf( __( 'Profile picture of %s', 'buddypress' ), $dn_default ) : __( 'Profile picture', 'buddypress' );
+
+		$defaults = array(
+			'alt'     => $alt_default,
+			'class'   => 'avatar',
+			'email'   => false,
+			'type'    => $type_default,
+			'user_id' => false
+		);
+
+		$r = wp_parse_args( $args, $defaults );
+		extract( $r, EXTR_SKIP );
+
+		if ( !isset( $height ) && !isset( $width ) ) {
+
+			// Backpat
+			if ( isset( $bp->avatar->full->height ) || isset( $bp->avatar->thumb->height ) ) {
+				$height = ( 'full' == $type ) ? $bp->avatar->full->height : $bp->avatar->thumb->height;
+			} else {
+				$height = 20;
+			}
+
+			// Backpat
+			if ( isset( $bp->avatar->full->width ) || isset( $bp->avatar->thumb->width ) ) {
+				$width = ( 'full' == $type ) ? $bp->avatar->full->width : $bp->avatar->thumb->width;
+			} else {
+				$width = 20;
+			}
+		}
+
+		// Primary activity avatar is always a user, but can be modified via a filter
+		$object  = apply_filters( 'bp_get_activity_avatar_object_' . $current_activity_item->component, 'user' );
+		$item_id = !empty( $user_id ) ? $user_id : $current_activity_item->user_id;
+		$item_id = apply_filters( 'bp_get_activity_avatar_item_id', $item_id );
+
+		// If this is a user object pass the users' email address for Gravatar so we don't have to refetch it.
+		if ( 'user' == $object && empty( $user_id ) && empty( $email ) && isset( $current_activity_item->user_email ) )
+			$email = $current_activity_item->user_email;
+
+		return apply_filters( 'bp_get_activity_avatar', bp_core_fetch_avatar( array(
+			'item_id' => $item_id,
+			'object'  => $object,
+			'type'    => $type,
+			'alt'     => $alt,
+			'class'   => $class,
+			'width'   => $width,
+			'height'  => $height,
+			'email'   => $email
+		) ) );
+	}
+
+/**
+ * Output the avatar of the object that action was performed on.
+ *
+ * @since BuddyPress (1.2)
+ *
+ * @see bp_get_activity_secondary_avatar() for description of arguments.
+ * @uses bp_get_activity_secondary_avatar()
+ *
+ * @param array $args See {@link bp_get_activity_secondary_avatar} for description.
+ */
+function bp_activity_secondary_avatar( $args = '' ) {
+	echo bp_get_activity_secondary_avatar( $args );
+}
+
+	/**
+	 * Return the avatar of the object that action was performed on
+	 *
+	 * @since BuddyPress (1.2)
+	 *
+	 * @see bp_core_fetch_avatar() for description of arguments.
+	 * @global object $activities_template {@link BP_Activity_Template}
+	 * @uses wp_parse_args()
+	 * @uses get_blog_option()
+	 * @uses apply_filters() To call the 'bp_get_activity_secondary_avatar_object_' . $activities_template->activity->component hook.
+	 * @uses apply_filters() To call the 'bp_get_activity_secondary_avatar_item_id' hook.
+	 * @uses bp_core_fetch_avatar()
+	 * @uses apply_filters() To call the 'bp_get_activity_secondary_avatar' hook.
+	 *
+	 * @param array $args  {
+	 *     For a complete description of arguments, see {@link bp_core_fetch_avatar()}.
+	 *     @type string $alt Default value varies based on current activity
+	 *           item component.
+	 *     @type string $type Default: 'full' when viewing a single activity
+	 *           permalink page, otherwise 'thumb'.
+	 *     @type string $class Default: 'avatar'.
+	 *     @type string|bool $email Default: email of the activity's user.
+	 *     @type int|bool $user_id Default: ID of the activity's user.
+	 * }
+	 * @return string The secondary avatar
+	 */
+	function bp_get_activity_secondary_avatar( $args = '' ) {
+		global $activities_template;
+
+		$r = wp_parse_args( $args, array(
+			'alt'        => '',
+			'type'       => 'thumb',
+			'width'      => 20,
+			'height'     => 20,
+			'class'      => 'avatar',
+			'link_class' => '',
+			'linked'     => true,
+			'email'      => false
+		) );
+		extract( $r, EXTR_SKIP );
+
+		// Set item_id and object (default to user)
+		switch ( $activities_template->activity->component ) {
+			case 'groups' :
+				$object  = 'group';
+				$item_id = $activities_template->activity->item_id;
+				$link    = '';
+				$name    = '';
+
+				// Only if groups is active
+				if ( bp_is_active( 'groups' ) ) {
+					$group = groups_get_group( array( 'group_id' => $item_id ) );
+					$link  = bp_get_group_permalink( $group );
+					$name  = $group->name;
+				}
+
+				if ( empty( $alt ) ) {
+					$alt = __( 'Group logo', 'buddypress' );
+
+					if ( ! empty( $name ) ) {
+						$alt = sprintf( __( 'Group logo of %s', 'buddypress' ), $name );
+					}
+				}
+
+				break;
+			case 'blogs' :
+				$object  = 'blog';
+				$item_id = $activities_template->activity->item_id;
+				$link    = home_url();
+
+				if ( empty( $alt ) ) {
+					$alt = sprintf( __( 'Profile picture of the author of the site %s', 'buddypress' ), get_blog_option( $item_id, 'blogname' ) );
+				}
+
+				break;
+			case 'friends' :
+				$object  = 'user';
+				$item_id = $activities_template->activity->secondary_item_id;
+				$link    = bp_core_get_userlink( $item_id, false, true );
+
+				if ( empty( $alt ) ) {
+					$alt = sprintf( __( 'Profile picture of %s', 'buddypress' ), bp_core_get_user_displayname( $activities_template->activity->secondary_item_id ) );
+				}
+
+				break;
+			default :
+				$object  = 'user';
+				$item_id = $activities_template->activity->user_id;
+				$email   = $activities_template->activity->user_email;
+				$link    = bp_core_get_userlink( $item_id, false, true );
+
+				if ( empty( $alt ) ) {
+					$alt = sprintf( __( 'Profile picture of %s', 'buddypress' ), $activities_template->activity->display_name );
+				}
+
+				break;
+		}
+
+		// Allow object, item_id, and link to be filtered
+		$object  = apply_filters( 'bp_get_activity_secondary_avatar_object_' . $activities_template->activity->component, $object );
+		$item_id = apply_filters( 'bp_get_activity_secondary_avatar_item_id', $item_id );
+
+		// If we have no item_id or object, there is no avatar to display
+		if ( empty( $item_id ) || empty( $object ) ) {
+			return false;
+		}
+
+		// Get the avatar
+		$avatar = bp_core_fetch_avatar( array(
+			'item_id' => $item_id,
+			'object'  => $object,
+			'type'    => $type,
+			'alt'     => $alt,
+			'class'   => $class,
+			'width'   => $width,
+			'height'  => $height,
+			'email'   => $email
+		) );
+
+		if ( !empty( $linked ) ) {
+			$link = apply_filters( 'bp_get_activity_secondary_avatar_link', $link, $activities_template->activity->component );
+
+			return sprintf( '<a href="%s" class="%s">%s</a>',
+				$link,
+				$link_class,
+				apply_filters( 'bp_get_activity_secondary_avatar', $avatar )
+			);
+		}
+
+		// else
+		return apply_filters( 'bp_get_activity_secondary_avatar', $avatar );
+	}
+
+/**
+ * Output the activity action
+ *
+ * @since BuddyPress (1.2)
+ *
+ * @param array $args See bp_get_activity_action()
+ * @uses bp_get_activity_action()
+ */
+function bp_activity_action( $args = array() ) {
+	echo bp_get_activity_action( $args );
+}
+
+	/**
+	 * Return the activity action
+	 *
+	 * @since BuddyPress (1.2)
+	 *
+	 * @global object $activities_template {@link BP_Activity_Template}
+	 * @param array $args Only parameter is "no_timestamp". If true, timestamp is shown in output.
+	 * @uses apply_filters_ref_array() To call the 'bp_get_activity_action_pre_meta' hook
+	 * @uses bp_insert_activity_meta()
+	 * @uses apply_filters_ref_array() To call the 'bp_get_activity_action' hook.
+	 *
+	 * @param array $args {
+	 *     @type bool $no_timestamp Whether to exclude the timestamp.
+	 * }
+	 * @return string The activity action.
+	 */
+	function bp_get_activity_action( $args = array() ) {
+		global $activities_template;
+
+		$defaults = array(
+			'no_timestamp' => false,
+		);
+
+		$args = wp_parse_args( $args, $defaults );
+		extract( $args, EXTR_SKIP );
+
+		$action = $activities_template->activity->action;
+		$action = apply_filters_ref_array( 'bp_get_activity_action_pre_meta', array( $action, &$activities_template->activity, $args ) );
+
+		if ( ! empty( $action ) && ! $no_timestamp )
+			$action = bp_insert_activity_meta( $action );
+
+		return apply_filters_ref_array( 'bp_get_activity_action', array( $action, &$activities_template->activity, $args ) );
+	}
+
+/**
+ * Output the activity content body
+ *
+ * @since BuddyPress (1.2)
+ *
+ * @uses bp_get_activity_content_body()
+ */
+function bp_activity_content_body() {
+	echo bp_get_activity_content_body();
+}
+
+	/**
+	 * Return the activity content body
+	 *
+	 * @since BuddyPress (1.2)
+	 *
+	 * @global object $activities_template {@link BP_Activity_Template}
+	 * @uses bp_insert_activity_meta()
+	 * @uses apply_filters_ref_array() To call the 'bp_get_activity_content_body' hook.
+	 *
+	 * @return string The activity content body.
+	 */
+	function bp_get_activity_content_body() {
+		global $activities_template;
+
+		// Backwards compatibility if action is not being used
+		if ( empty( $activities_template->activity->action ) && !empty( $activities_template->activity->content ) )
+			$activities_template->activity->content = bp_insert_activity_meta( $activities_template->activity->content );
+
+		return apply_filters_ref_array( 'bp_get_activity_content_body', array( $activities_template->activity->content, &$activities_template->activity ) );
+	}
+
+/**
+ * Does the activity have content?
+ *
+ * @since BuddyPress (1.2)
+ *
+ * @global object $activities_template {@link BP_Activity_Template}
+ *
+ * @return bool True if activity has content, false otherwise.
+ */
+function bp_activity_has_content() {
+	global $activities_template;
+
+	if ( !empty( $activities_template->activity->content ) )
+		return true;
+
+	return false;
+}
+
+/**
+ * Output the activity content.
+ *
+ * @since BuddyPress (1.0)
+ * @deprecated BuddyPress (1.5)
+ *
+ * @todo properly deprecate this function.
+ *
+ * @uses bp_get_activity_content()
+ */
+function bp_activity_content() {
+	echo bp_get_activity_content();
+}
+
+	/**
+	 * Return the activity content.
+	 *
+	 * @since BuddyPress (1.0)
+	 * @deprecated BuddyPress (1.5)
+	 *
+	 * @todo properly deprecate this function.
+	 *
+	 * @uses bp_get_activity_action()
+	 * @uses bp_get_activity_content_body()
+	 * @uses apply_filters() To call the 'bp_get_activity_content' hook.
+	 *
+	 * @return string The activity content.
+	 */
+	function bp_get_activity_content() {
+		/**
+		 * If you want to filter activity update content, please use
+		 * the filter 'bp_get_activity_content_body'
+		 *
+		 * This function is mainly for backwards comptibility.
+		 */
+
+		$content = bp_get_activity_action() . ' ' . bp_get_activity_content_body();
+		return apply_filters( 'bp_get_activity_content', $content );
+	}
+
+/**
+ * Attach metadata about an activity item to the activity content.
+ *
+ * This metadata includes the time since the item was posted (which will appear
+ * as a link to the item's permalink).
+ *
+ * @since BuddyPress (1.2)
+ *
+ * @global object $activities_template {@link BP_Activity_Template}
+ * @uses bp_core_time_since()
+ * @uses apply_filters_ref_array() To call the 'bp_activity_time_since' hook.
+ * @uses bp_is_single_activity()
+ * @uses bp_activity_get_permalink()
+ * @uses esc_attr__()
+ * @uses apply_filters_ref_array() To call the 'bp_activity_permalink' hook.
+ * @uses apply_filters() To call the 'bp_insert_activity_meta' hook.
+ *
+ * @param string $content The activity content.
+ * @return string The activity content with the metadata string attached.
+ */
+function bp_insert_activity_meta( $content ) {
+	global $activities_template;
+
+	// Strip any legacy time since placeholders from BP 1.0-1.1
+	$content = str_replace( '<span class="time-since">%s</span>', '', $content );
+
+	// Insert the time since.
+	$time_since = apply_filters_ref_array( 'bp_activity_time_since', array( '<span class="time-since">' . bp_core_time_since( $activities_template->activity->date_recorded ) . '</span>', &$activities_template->activity ) );
+
+	// Insert the permalink
+	if ( !bp_is_single_activity() )
+		$content = apply_filters_ref_array( 'bp_activity_permalink', array( sprintf( '%1$s <a href="%2$s" class="view activity-time-since" title="%3$s">%4$s</a>', $content, bp_activity_get_permalink( $activities_template->activity->id, $activities_template->activity ), esc_attr__( 'View Discussion', 'buddypress' ), $time_since ), &$activities_template->activity ) );
+	else
+		$content .= str_pad( $time_since, strlen( $time_since ) + 2, ' ', STR_PAD_BOTH );
+
+	return apply_filters( 'bp_insert_activity_meta', $content );
+}
+
+/**
+ * Determine if the current user can delete an activity item.
+ *
+ * @since BuddyPress (1.2)
+ *
+ * @global object $activities_template {@link BP_Activity_Template}
+ * @uses apply_filters() To call the 'bp_activity_user_can_delete' hook
+ *
+ * @param object $activity Optional. Falls back on the current item in the loop.
+ * @return bool True if can delete, false otherwise.
+ */
+function bp_activity_user_can_delete( $activity = false ) {
+	global $activities_template;
+
+	if ( !$activity )
+		$activity = $activities_template->activity;
+
+	if ( isset( $activity->current_comment ) )
+		$activity = $activity->current_comment;
+
+	$can_delete = false;
+
+	if ( bp_current_user_can( 'bp_moderate' ) )
+		$can_delete = true;
+
+	if ( is_user_logged_in() && $activity->user_id == bp_loggedin_user_id() )
+		$can_delete = true;
+
+	if ( bp_is_item_admin() && bp_is_single_item() )
+		$can_delete = true;
+
+	return apply_filters( 'bp_activity_user_can_delete', $can_delete, $activity );
+}
+
+/**
+ * Output the activity parent content.
+ *
+ * @since BuddyPress (1.2)
+ *
+ * @see bp_get_activity_parent_content() for a description of arguments.
+ * @uses bp_get_activity_parent_content()
+ *
+ * @param array $args See {@link bp_get_activity_parent_content} for description.
+ */
+function bp_activity_parent_content( $args = '' ) {
+	echo bp_get_activity_parent_content($args);
+}
+
+	/**
+	 * Return the activity content.
+	 *
+	 * @since BuddyPress (1.2)
+	 *
+	 * @global object $activities_template {@link BP_Activity_Template}
+	 * @uses wp_parse_args()
+	 * @uses apply_filters() To call the 'bp_get_activity_parent_content' hook.
+	 *
+	 * @param array $args {
+	 *     Array of optional arguments.
+	 *     @deprecated bool $hide_user No longer used.
+	 * }
+	 * @return mixed False on failure, otherwise the activity parent content
+	 */
+	function bp_get_activity_parent_content( $args = '' ) {
+		global $activities_template;
+
+		$defaults = array(
+			'hide_user' => false
+		);
+
+		$r = wp_parse_args( $args, $defaults );
+		extract( $r, EXTR_SKIP );
+
+		// Get the ID of the parent activity content
+		if ( !$parent_id = $activities_template->activity->item_id )
+			return false;
+
+		// Bail if no parent content
+		if ( empty( $activities_template->activity_parents[$parent_id] ) )
+			return false;
+
+		// Bail if no action
+		if ( empty( $activities_template->activity_parents[$parent_id]->action ) )
+			return false;
+
+		// Content always includes action
+		$content = $activities_template->activity_parents[$parent_id]->action;
+
+		// Maybe append activity content, if it exists
+		if ( ! empty( $activities_template->activity_parents[$parent_id]->content ) )
+			$content .= ' ' . $activities_template->activity_parents[$parent_id]->content;
+
+		// Remove the time since content for backwards compatibility
+		$content = str_replace( '<span class="time-since">%s</span>', '', $content );
+
+		// Remove images
+		$content = preg_replace( '/<img[^>]*>/Ui', '', $content );
+
+		return apply_filters( 'bp_get_activity_parent_content', $content );
+	}
+
+/**
+ * Output the parent activity's user ID.
+ *
+ * @since BuddyPress (1.7)
+ */
+function bp_activity_parent_user_id() {
+	echo bp_get_activity_parent_user_id();
+}
+
+	/**
+	 * Return the parent activity's user ID.
+	 *
+	 * @since BuddyPress (1.7)
+	 *
+	 * @global BP_Activity_Template $activities_template
+	 *
+	 * @return bool|int False if parent activity can't be found, otherwise
+	 *         the parent activity's user ID.
+	 */
+	function bp_get_activity_parent_user_id() {
+		global $activities_template;
+
+		// Bail if no activity on no item ID
+		if ( empty( $activities_template->activity ) || empty( $activities_template->activity->item_id ) )
+			return false;
+
+		// Get the ID of the parent activity content
+		if ( !$parent_id = $activities_template->activity->item_id )
+			return false;
+
+		// Bail if no parent item
+		if ( empty( $activities_template->activity_parents[$parent_id] ) )
+			return false;
+
+		// Bail if no parent user ID
+		if ( empty( $activities_template->activity_parents[$parent_id]->user_id ) )
+			return false;
+
+		$retval = $activities_template->activity_parents[$parent_id]->user_id;
+
+		return (int) apply_filters( 'bp_get_activity_parent_user_id', $retval );
+	}
+
+/**
+ * Output whether or not the current activity is in a current user's favorites.
+ *
+ * @since BuddyPress (1.2)
+ *
+ * @uses bp_get_activity_is_favorite()
+ */
+function bp_activity_is_favorite() {
+	echo bp_get_activity_is_favorite();
+}
+
+	/**
+	 * Return whether the current activity is in a current user's favorites.
+	 *
+	 * @since BuddyPress (1.2)
+	 *
+	 * @global object $activities_template {@link BP_Activity_Template}
+	 * @uses apply_filters() To call the 'bp_get_activity_is_favorite' hook.
+	 *
+	 * @return bool True if user favorite, false otherwise.
+	 */
+	function bp_get_activity_is_favorite() {
+		global $activities_template;
+
+ 		return apply_filters( 'bp_get_activity_is_favorite', in_array( $activities_template->activity->id, (array) $activities_template->my_favs ) );
+	}
+
+/**
+ * Output the comment markup for an activity item.
+ *
+ * @since BuddyPress (1.2)
+ *
+ * @todo deprecate $args param
+ *
+ * @param string $args Unused. Appears to be left over from an earlier implementation.
+ */
+function bp_activity_comments( $args = '' ) {
+	echo bp_activity_get_comments( $args );
+}
+
+	/**
+	 * Get the comment markup for an activity item.
+	 *
+	 * @since BuddyPress (1.2)
+	 *
+	 * @todo deprecate $args param
+	 *
+	 * @todo Given that checks for children already happen in bp_activity_recurse_comments(),
+	 *    this function can probably be streamlined or removed.
+	 *
+	 * @param string $args Unused. Appears to be left over from an earlier implementation.
+	 *
+	 * @global object $activities_template {@link BP_Activity_Template}
+	 * @uses bp_activity_recurse_comments()
+	 */
+	function bp_activity_get_comments( $args = '' ) {
+		global $activities_template;
+
+		if ( !isset( $activities_template->activity->children ) || !$activities_template->activity->children )
+			return false;
+
+		bp_activity_recurse_comments( $activities_template->activity );
+	}
+
+		/**
+		 * Loops through a level of activity comments and loads the template for each
+		 *
+		 * Note: The recursion itself used to happen entirely in this function. Now it is
+		 * split between here and the comment.php template.
+		 *
+		 * @since BuddyPress (1.2)
+		 *
+		 * @todo remove $counter global
+		 *
+		 * @param object $comment The activity object currently being recursed
+		 *
+		 * @global object $activities_template {@link BP_Activity_Template}
+		 * @uses locate_template()
+		 */
+		function bp_activity_recurse_comments( $comment ) {
+			global $activities_template;
+
+			if ( empty( $comment ) )
+				return false;
+
+			if ( empty( $comment->children ) )
+				return false;
+
+			echo apply_filters( 'bp_activity_recurse_comments_start_ul', '<ul>');
+			foreach ( (array) $comment->children as $comment_child ) {
+				// Put the comment into the global so it's available to filters
+				$activities_template->activity->current_comment = $comment_child;
+
+				$template = bp_locate_template( 'activity/comment.php', false, false );
+
+				// Backward compatibility. In older versions of BP, the markup was
+				// generated in the PHP instead of a template. This ensures that
+				// older themes (which are not children of bp-default and won't
+				// have the new template) will still work.
+				if ( !$template ) {
+					$template = BP_PLUGIN_DIR . '/bp-themes/bp-default/activity/comment.php';
+				}
+
+				load_template( $template, false );
+
+				unset( $activities_template->activity->current_comment );
+			}
+			echo apply_filters( 'bp_activity_recurse_comments_end_ul', '</ul>');
+		}
+
+/**
+ * Utility function that returns the comment currently being recursed.
+ *
+ * @since BuddyPress (1.5)
+ *
+ * @global object $activities_template {@link BP_Activity_Template}
+ * @uses apply_filters() To call the 'bp_activity_current_comment' hook.
+ *
+ * @return object|bool $current_comment The activity comment currently being
+ *         displayed. False on failure.
+ */
+function bp_activity_current_comment() {
+	global $activities_template;
+
+	$current_comment = !empty( $activities_template->activity->current_comment ) ? $activities_template->activity->current_comment : false;
+
+	return apply_filters( 'bp_activity_current_comment', $current_comment );
+}
+
+
+/**
+ * Output the ID of the activity comment currently being displayed.
+ *
+ * @since BuddyPress (1.5)
+ *
+ * @uses bp_get_activity_comment_id()
+ */
+function bp_activity_comment_id() {
+	echo bp_get_activity_comment_id();
+}
+
+	/**
+	 * Return the ID of the activity comment currently being displayed.
+	 *
+	 * @since BuddyPress (1.5)
+	 *
+	 * @global object $activities_template {@link BP_Activity_Template}
+	 * @uses apply_filters() To call the 'bp_activity_comment_id' hook.
+	 *
+	 * @return int|bool $comment_id The ID of the activity comment
+	 *         currently being displayed, false if none is found.
+	 */
+	function bp_get_activity_comment_id() {
+		global $activities_template;
+
+		$comment_id = isset( $activities_template->activity->current_comment->id ) ? $activities_template->activity->current_comment->id : false;
+
+		return apply_filters( 'bp_activity_comment_id', $comment_id );
+	}
+
+/**
+ * Output the ID of the author of the activity comment currently being displayed.
+ *
+ * @since BuddyPress (1.5)
+ *
+ * @uses bp_get_activity_comment_user_id()
+ */
+function bp_activity_comment_user_id() {
+	echo bp_get_activity_comment_user_id();
+}
+
+	/**
+	 * Return the ID of the author of the activity comment currently being displayed.
+	 *
+	 * @since BuddyPress (1.5)
+	 *
+	 * @global object $activities_template {@link BP_Activity_Template}
+	 * @uses apply_filters() To call the 'bp_activity_comment_user_id' hook.
+	 *
+	 * @return int|bool $user_id The user_id of the author of the displayed
+	 *         activity comment. False on failure.
+	 */
+	function bp_get_activity_comment_user_id() {
+		global $activities_template;
+
+		$user_id = isset( $activities_template->activity->current_comment->user_id ) ? $activities_template->activity->current_comment->user_id : false;
+
+		return apply_filters( 'bp_activity_comment_user_id', $user_id );
+	}
+
+/**
+ * Output the author link for the activity comment currently being displayed.
+ *
+ * @since BuddyPress (1.5)
+ *
+ * @uses bp_get_activity_comment_user_link()
+ */
+function bp_activity_comment_user_link() {
+	echo bp_get_activity_comment_user_link();
+}
+
+	/**
+	 * Return the author link for the activity comment currently being displayed.
+	 *
+	 * @since BuddyPress (1.5)
+	 *
+	 * @uses bp_core_get_user_domain()
+	 * @uses bp_get_activity_comment_user_id()
+	 * @uses apply_filters() To call the 'bp_activity_comment_user_link' hook
+	 *
+	 * @return string $user_link The URL of the activity comment author's profile.
+	 */
+	function bp_get_activity_comment_user_link() {
+		$user_link = bp_core_get_user_domain( bp_get_activity_comment_user_id() );
+
+		return apply_filters( 'bp_activity_comment_user_link', $user_link );
+	}
+
+/**
+ * Output the author name for the activity comment currently being displayed.
+ *
+ * @since BuddyPress (1.5)
+ *
+ * @uses bp_get_activity_comment_name()
+ */
+function bp_activity_comment_name() {
+	echo bp_get_activity_comment_name();
+}
+
+	/**
+	 * Return the author name for the activity comment currently being displayed.
+	 *
+	 * The use of the 'bp_acomment_name' filter is deprecated. Please use
+	 * 'bp_activity_comment_name'.
+	 *
+	 * @since BuddyPress (1.5)
+	 *
+	 * @global object $activities_template {@link BP_Activity_Template}
+	 * @uses apply_filters() To call the 'bp_acomment_name' hook.
+	 * @uses apply_filters() To call the 'bp_activity_comment_name' hook.
+	 *
+	 * @return string $name The full name of the activity comment author.
+	 */
+	function bp_get_activity_comment_name() {
+		global $activities_template;
+
+		if ( isset( $activities_template->activity->current_comment->user_fullname ) )
+			$name = apply_filters( 'bp_acomment_name', $activities_template->activity->current_comment->user_fullname, $activities_template->activity->current_comment );  // backward compatibility
+		else
+			$name = $activities_template->activity->current_comment->display_name;
+
+		return apply_filters( 'bp_activity_comment_name', $name );
+	}
+
+/**
+ * Output the date_recorded of the activity comment currently being displayed.
+ *
+ * @since BuddyPress (1.5)
+ *
+ * @uses bp_get_activity_comment_date_recorded()
+ */
+function bp_activity_comment_date_recorded() {
+	echo bp_get_activity_comment_date_recorded();
+}
+
+	/**
+	 * Return the date_recorded for the activity comment currently being displayed.
+	 *
+	 * @since BuddyPress (1.5)
+	 *
+	 * @global object $activities_template {@link BP_Activity_Template}
+	 * @uses bp_core_time_since()
+	 * @uses apply_filters() To call the 'bp_activity_comment_date_recorded' hook
+	 *
+	 * @return string|bool $date_recorded Time since the activity was recorded,
+	 *         in the form "%s ago". False on failure.
+	 */
+	function bp_get_activity_comment_date_recorded() {
+		global $activities_template;
+
+		if ( empty( $activities_template->activity->current_comment->date_recorded ) )
+			return false;
+
+		$date_recorded = bp_core_time_since( $activities_template->activity->current_comment->date_recorded );
+
+		return apply_filters( 'bp_activity_comment_date_recorded', $date_recorded );
+	}
+
+/**
+ * Output the 'delete' URL for the activity comment currently being displayed.
+ *
+ * @since BuddyPress (1.5)
+ *
+ * @uses bp_get_activity_comment_delete_link()
+ */
+function bp_activity_comment_delete_link() {
+	echo bp_get_activity_comment_delete_link();
+}
+
+	/**
+	 * Gets the 'delete' URL for the activity comment currently being displayed
+	 *
+	 * @since BuddyPress (1.5)
+	 *
+	 * @uses wp_nonce_url()
+	 * @uses bp_get_root_domain()
+	 * @uses bp_get_activity_slug()
+	 * @uses bp_get_activity_comment_id()
+	 * @uses apply_filters() To call the 'bp_activity_comment_delete_link' hook.
+	 *
+	 * @return string $link The nonced URL for deleting the current
+	 *         activity comment.
+	 */
+	function bp_get_activity_comment_delete_link() {
+		$link = wp_nonce_url( bp_get_root_domain() . '/' . bp_get_activity_slug() . '/delete/' . bp_get_activity_comment_id() . '?cid=' . bp_get_activity_comment_id(), 'bp_activity_delete_link' );
+
+		return apply_filters( 'bp_activity_comment_delete_link', $link );
+	}
+
+/**
+ * Output the content of the activity comment currently being displayed.
+ *
+ * @since BuddyPress (1.5)
+ *
+ * @uses bp_get_activity_comment_content()
+ */
+function bp_activity_comment_content() {
+	echo bp_get_activity_comment_content();
+}
+
+	/**
+	 * Return the content of the activity comment currently being displayed.
+	 *
+	 * The content is run through two filters. 'bp_get_activity_content'
+	 * will apply all filters applied to activity items in general. Use
+	 * 'bp_activity_comment_content' to modify the content of activity
+	 * comments only.
+	 *
+	 * @since BuddyPress (1.5)
+	 *
+	 * @global object $activities_template {@link BP_Activity_Template}
+	 * @uses apply_filters() To call the 'bp_get_activity_content' hook.
+	 * @uses apply_filters() To call the 'bp_activity_comment_content' hook.
+	 *
+	 * @return string $content The content of the current activity comment.
+	 */
+	function bp_get_activity_comment_content() {
+		global $activities_template;
+
+		$content = apply_filters( 'bp_get_activity_content', $activities_template->activity->current_comment->content );
+
+		return apply_filters( 'bp_activity_comment_content', $content );
+	}
+
+/**
+ * Output the activity comment count.
+ *
+ * @since BuddyPress (1.2)
+ *
+ * @uses bp_activity_get_comment_count()
+ */
+function bp_activity_comment_count() {
+	echo bp_activity_get_comment_count();
+}
+
+	/**
+	 * Return the content of the activity comment currently being displayed.
+	 *
+	 * The content is run through two filters. 'bp_get_activity_content'
+	 * will apply all filters applied to activity items in general. Use
+	 * 'bp_activity_comment_content' to modify the content of activity
+	 * comments only.
+	 *
+	 * @since BuddyPress (1.2)
+	 *
+	 * @global object $activities_template {@link BP_Activity_Template}
+	 * @uses bp_activity_recurse_comment_count()
+	 * @uses apply_filters() To call the 'bp_activity_get_comment_count' hook.
+	 * @todo deprecate $args
+	 *
+	 * @param array $args Deprecated.
+	 * @return int $count The activity comment count.
+	 */
+	function bp_activity_get_comment_count( $args = '' ) {
+		global $activities_template;
+
+		if ( !isset( $activities_template->activity->children ) || !$activities_template->activity->children )
+			return 0;
+
+		$count = bp_activity_recurse_comment_count( $activities_template->activity );
+
+		return apply_filters( 'bp_activity_get_comment_count', (int) $count );
+	}
+
+		/**
+		 * Return the content of the activity comment currently being displayed.
+		 *
+		 * The content is run through two filters. 'bp_get_activity_content'
+		 * will apply all filters applied to activity items in general.
+		 * Use bp_activity_comment_content to modify the content of
+		 * activity comments only.
+		 *
+		 * @since BuddyPress (1.2)
+		 *
+		 * @uses bp_activity_recurse_comment_count()
+		 * @uses apply_filters() To call the 'bp_activity_get_comment_count' hook
+		 * @todo investigate why bp_activity_recurse_comment_count() is used while being declared
+		 *
+		 * @param object $comment Activity comment object.
+		 * @param int $count The current iteration count.
+		 * @return int $count The activity comment count.
+		 */
+		function bp_activity_recurse_comment_count( $comment, $count = 0 ) {
+
+			if ( empty( $comment->children ) )
+				return $count;
+
+			foreach ( (array) $comment->children as $comment ) {
+				$count++;
+				$count = bp_activity_recurse_comment_count( $comment, $count );
+			}
+
+			return $count;
+		}
+
+/**
+ * Output the activity comment link.
+ *
+ * @since BuddyPress (1.2)
+ *
+ * @uses bp_get_activity_comment_link()
+ */
+function bp_activity_comment_link() {
+	echo bp_get_activity_comment_link();
+}
+
+	/**
+	 * Return the activity comment link.
+	 *
+	 * @since BuddyPress (1.2)
+	 *
+	 * @global object $activities_template {@link BP_Activity_Template}
+	 * @uses apply_filters() To call the 'bp_get_activity_comment_link' hook.
+	 *
+	 * @return string The activity comment link.
+	 */
+	function bp_get_activity_comment_link() {
+		global $activities_template;
+		return apply_filters( 'bp_get_activity_comment_link', '?ac=' . $activities_template->activity->id . '/#ac-form-' . $activities_template->activity->id );
+	}
+
+/**
+ * Output the activity comment form no javascript display CSS.
+ *
+ * @since BuddyPress (1.2)
+ *
+ * @uses bp_get_activity_comment_form_nojs_display()
+ */
+function bp_activity_comment_form_nojs_display() {
+	echo bp_get_activity_comment_form_nojs_display();
+}
+
+	/**
+	 * Return the activity comment form no javascript display CSS.
+	 *
+	 * @since BuddyPress (1.2)
+	 *
+	 * @global object $activities_template {@link BP_Activity_Template}
+	 *
+	 * @return string|bool The activity comment form no javascript
+	 *         display CSS. False on failure
+	 */
+	function bp_get_activity_comment_form_nojs_display() {
+		global $activities_template;
+		if ( isset( $_GET['ac'] ) && $_GET['ac'] == $activities_template->activity->id . '/' )
+			return 'style="display: block"';
+
+		return false;
+	}
+
+/**
+ * Output the activity comment form action.
+ *
+ * @since BuddyPress (1.2)
+ *
+ * @uses bp_get_activity_comment_form_action()
+ */
+function bp_activity_comment_form_action() {
+	echo bp_get_activity_comment_form_action();
+}
+
+	/**
+	 * Return the activity comment form action.
+	 *
+	 * @since BuddyPress (1.2)
+	 *
+	 * @uses home_url()
+	 * @uses bp_get_activity_root_slug()
+	 * @uses apply_filters() To call the 'bp_get_activity_comment_form_action' hook.
+	 *
+	 * @return string The activity comment form action.
+	 */
+	function bp_get_activity_comment_form_action() {
+		return apply_filters( 'bp_get_activity_comment_form_action', home_url( bp_get_activity_root_slug() . '/reply/' ) );
+	}
+
+/**
+ * Output the activity permalink ID.
+ *
+ * @since BuddyPress (1.2)
+ *
+ * @uses bp_get_activity_permalink_id()
+ */
+function bp_activity_permalink_id() {
+	echo bp_get_activity_permalink_id();
+}
+
+	/**
+	 * Return the activity permalink ID.
+	 *
+	 * @since BuddyPress (1.2)
+	 *
+	 * @uses apply_filters() To call the 'bp_get_activity_permalink_id' hook.
+	 *
+	 * @return string The activity permalink ID.
+	 */
+	function bp_get_activity_permalink_id() {
+		return apply_filters( 'bp_get_activity_permalink_id', bp_current_action() );
+	}
+
+/**
+ * Output the activity thread permalink.
+ *
+ * @since BuddyPress (1.2)
+ *
+ * @uses bp_get_activity_permalink_id()
+ */
+function bp_activity_thread_permalink() {
+	echo bp_get_activity_thread_permalink();
+}
+
+	/**
+	 * Return the activity thread permalink.
+	 *
+	 * @since BuddyPress (1.2)
+	 *
+	 * @uses bp_activity_get_permalink()
+	 * @uses apply_filters() To call the 'bp_get_activity_thread_permalink' hook.
+	 *
+	 * @return string $link The activity thread permalink.
+	 */
+	function bp_get_activity_thread_permalink() {
+		global $activities_template;
+
+		$link = bp_activity_get_permalink( $activities_template->activity->id, $activities_template->activity );
+
+	 	return apply_filters( 'bp_get_activity_thread_permalink', $link );
+	}
+
+/**
+ * Output the activity comment permalink.
+ *
+ * @since BuddyPress (1.8)
+ *
+ * @uses bp_get_activity_permalink_id()
+ */
+function bp_activity_comment_permalink() {
+	echo bp_get_activity_comment_permalink();
+}
+	/**
+	 * Return the activity comment permalink.
+	 *
+	 * @since BuddyPress (1.8)
+	 *
+	 * @uses bp_activity_get_permalink()
+	 * @uses apply_filters() To call the 'bp_get_activity_comment_permalink' hook.
+	 *
+	 * @return string $link The activity comment permalink.
+	 */
+	function bp_get_activity_comment_permalink() {
+		global $activities_template;
+
+		$link = bp_activity_get_permalink( $activities_template->activity->id, $activities_template->activity ) . '#acomment-' . $activities_template->activity->current_comment->id;
+
+		return apply_filters( 'bp_get_activity_comment_permalink', $link );
+	}
+
+/**
+ * Output the activity favorite link.
+ *
+ * @since BuddyPress (1.2)
+ *
+ * @uses bp_get_activity_favorite_link()
+ */
+function bp_activity_favorite_link() {
+	echo bp_get_activity_favorite_link();
+}
+
+	/**
+	 * Return the activity favorite link.
+	 *
+	 * @since BuddyPress (1.2)
+	 *
+	 * @global object $activities_template {@link BP_Activity_Template}
+	 * @uses wp_nonce_url()
+	 * @uses home_url()
+	 * @uses bp_get_activity_root_slug()
+	 * @uses apply_filters() To call the 'bp_get_activity_favorite_link' hook
+	 *
+	 * @return string The activity favorite link.
+	 */
+	function bp_get_activity_favorite_link() {
+		global $activities_template;
+		return apply_filters( 'bp_get_activity_favorite_link', wp_nonce_url( home_url( bp_get_activity_root_slug() . '/favorite/' . $activities_template->activity->id . '/' ), 'mark_favorite' ) );
+	}
+
+/**
+ * Output the activity unfavorite link.
+ *
+ * @since BuddyPress (1.2)
+ *
+ * @uses bp_get_activity_unfavorite_link()
+ */
+function bp_activity_unfavorite_link() {
+	echo bp_get_activity_unfavorite_link();
+}
+
+	/**
+	 * Return the activity unfavorite link.
+	 *
+	 * @since BuddyPress (1.2)
+	 *
+	 * @global object $activities_template {@link BP_Activity_Template}
+	 * @uses wp_nonce_url()
+	 * @uses home_url()
+	 * @uses bp_get_activity_root_slug()
+	 * @uses apply_filters() To call the 'bp_get_activity_unfavorite_link' hook.
+	 *
+	 * @return string The activity unfavorite link.
+	 */
+	function bp_get_activity_unfavorite_link() {
+		global $activities_template;
+		return apply_filters( 'bp_get_activity_unfavorite_link', wp_nonce_url( home_url( bp_get_activity_root_slug() . '/unfavorite/' . $activities_template->activity->id . '/' ), 'unmark_favorite' ) );
+	}
+
+/**
+ * Output the activity CSS class.
+ *
+ * @since BuddyPress (1.0)
+ *
+ * @uses bp_get_activity_css_class()
+ */
+function bp_activity_css_class() {
+	echo bp_get_activity_css_class();
+}
+
+	/**
+	 * Return the current activity item's CSS class.
+	 *
+	 * @since BuddyPress (1.0)
+	 *
+	 * @global object $activities_template {@link BP_Activity_Template}
+	 * @uses apply_filters() To call the 'bp_activity_mini_activity_types' hook.
+	 * @uses bp_activity_get_comment_count()
+	 * @uses bp_activity_can_comment()
+	 * @uses apply_filters() To call the 'bp_get_activity_css_class' hook.
+	 *
+	 * @return string The activity item's CSS class.
+	 */
+	function bp_get_activity_css_class() {
+		global $activities_template;
+
+		$mini_activity_actions = apply_filters( 'bp_activity_mini_activity_types', array(
+			'friendship_accepted',
+			'friendship_created',
+			'new_blog',
+			'joined_group',
+			'created_group',
+			'new_member'
+		) );
+
+		$class = ' activity-item';
+
+		if ( in_array( $activities_template->activity->type, (array) $mini_activity_actions ) || empty( $activities_template->activity->content ) )
+			$class .= ' mini';
+
+		if ( bp_activity_get_comment_count() && bp_activity_can_comment() )
+			$class .= ' has-comments';
+
+		return apply_filters( 'bp_get_activity_css_class', $activities_template->activity->component . ' ' . $activities_template->activity->type . $class );
+	}
+
+/**
+ * Output the activity delete link.
+ *
+ * @since BuddyPress (1.1)
+ *
+ * @uses bp_get_activity_delete_link()
+ */
+function bp_activity_delete_link() {
+	echo bp_get_activity_delete_link();
+}
+
+	/**
+	 * Return the activity delete link.
+	 *
+	 * @since BuddyPress (1.1)
+	 *
+	 * @global object $activities_template {@link BP_Activity_Template}
+	 * @uses bp_get_root_domain()
+	 * @uses bp_get_activity_root_slug()
+	 * @uses bp_is_activity_component()
+	 * @uses bp_current_action()
+	 * @uses add_query_arg()
+	 * @uses wp_get_referer()
+	 * @uses wp_nonce_url()
+	 * @uses apply_filters() To call the 'bp_get_activity_delete_link' hook.
+	 *
+	 * @return string $link Activity delete link. Contains $redirect_to arg
+	 *         if on single activity page.
+	 */
+	function bp_get_activity_delete_link() {
+		global $activities_template;
+
+		$url   = bp_get_root_domain() . '/' . bp_get_activity_root_slug() . '/delete/' . $activities_template->activity->id;
+		$class = 'delete-activity';
+
+		// Determine if we're on a single activity page, and customize accordingly
+		if ( bp_is_activity_component() && is_numeric( bp_current_action() ) ) {
+			$url   = add_query_arg( array( 'redirect_to' => wp_get_referer() ), $url );
+			$class = 'delete-activity-single';
+		}
+
+		$link = '<a href="' . wp_nonce_url( $url, 'bp_activity_delete_link' ) . '" class="button item-button bp-secondary-action ' . $class . ' confirm" rel="nofollow">' . __( 'Delete', 'buddypress' ) . '</a>';
+		return apply_filters( 'bp_get_activity_delete_link', $link );
+	}
+
+/**
+ * Output the activity latest update link.
+ *
+ * @since BuddyPress (1.2)
+ *
+ * @see bp_get_activity_latest_update() for description of parameters.
+ * @uses bp_get_activity_latest_update()
+ *
+ * @param int $user_id See {@link bp_get_activity_latest_update()} for description.
+ */
+function bp_activity_latest_update( $user_id = 0 ) {
+	echo bp_get_activity_latest_update( $user_id );
+}
+
+	/**
+	 * Return the activity latest update link.
+	 *
+	 * @since BuddyPress (1.2)
+	 *
+	 * @uses bp_is_user_inactive()
+	 * @uses bp_core_is_user_deleted()
+	 * @uses bp_get_user_meta()
+	 * @uses apply_filters() To call the 'bp_get_activity_latest_update_excerpt' hook
+	 * @uses bp_create_excerpt()
+	 * @uses bp_get_root_domain()
+	 * @uses bp_get_activity_root_slug()
+	 * @uses apply_filters() To call the 'bp_get_activity_latest_update' hook
+	 *
+	 * @param int $user_id If empty, will fall back on displayed user.
+	 * @return string|bool $latest_update The activity latest update link.
+	 *         False on failure
+	 */
+	function bp_get_activity_latest_update( $user_id = 0 ) {
+
+		if ( empty( $user_id ) )
+			$user_id = bp_displayed_user_id();
+
+		if ( bp_is_user_inactive( $user_id ) )
+			return false;
+
+		if ( !$update = bp_get_user_meta( $user_id, 'bp_latest_update', true ) )
+			return false;
+
+		$latest_update = apply_filters( 'bp_get_activity_latest_update_excerpt', trim( strip_tags( bp_create_excerpt( $update['content'], 358 ) ) ) );
+		$latest_update .= ' <a href="' . bp_get_root_domain() . '/' . bp_get_activity_root_slug() . '/p/' . $update['id'] . '/"> ' . __( 'View', 'buddypress' ) . '</a>';
+
+		return apply_filters( 'bp_get_activity_latest_update', $latest_update  );
+	}
+
+/**
+ * Output the activity filter links.
+ *
+ * @since BuddyPress (1.1)
+ *
+ * @see bp_get_activity_filter_links() for description of parameters.
+ * @uses bp_get_activity_filter_links()
+ *
+ * @param array $args See {@link bp_get_activity_filter_links()} for description.
+ */
+function bp_activity_filter_links( $args = false ) {
+	echo bp_get_activity_filter_links( $args );
+}
+
+	/**
+	 * Return the activity filter links.
+	 *
+	 * @since BuddyPress (1.1)
+	 *
+	 * @uses wp_parse_args()
+	 * @uses BP_Activity_Activity::get_recorded_components() {@link BP_Activity_Activity}
+	 * @uses esc_attr()
+	 * @uses add_query_arg()
+	 * @uses remove_query_arg()
+	 * @uses apply_filters() To call the 'bp_get_activity_filter_link_href' hook.
+	 * @uses apply_filters() To call the 'bp_get_activity_filter_links' hook.
+	 *
+	 * @param array $args {
+	 *     @type string $style The type of markup to use for the links.
+	 *           'list', 'paragraph', or 'span'. Default: 'list'.
+	 * }
+	 * @return string|bool $component_links The activity filter links.
+	 *         False on failure.
+	 */
+	function bp_get_activity_filter_links( $args = false ) {
+
+		$defaults = array(
+			'style' => 'list'
+		);
+
+		$r = wp_parse_args( $args, $defaults );
+		extract( $r, EXTR_SKIP );
+
+		// Define local variable
+		$component_links = array();
+
+		// Fetch the names of components that have activity recorded in the DB
+		$components = BP_Activity_Activity::get_recorded_components();
+
+		if ( empty( $components ) )
+			return false;
+
+		foreach ( (array) $components as $component ) {
+
+			// Skip the activity comment filter
+			if ( 'activity' == $component )
+				continue;
+
+			if ( isset( $_GET['afilter'] ) && $component == $_GET['afilter'] )
+				$selected = ' class="selected"';
+			else
+				unset($selected);
+
+			$component = esc_attr( $component );
+
+			switch ( $style ) {
+				case 'list':
+					$tag = 'li';
+					$before = '<li id="afilter-' . $component . '"' . $selected . '>';
+					$after = '</li>';
+				break;
+				case 'paragraph':
+					$tag = 'p';
+					$before = '<p id="afilter-' . $component . '"' . $selected . '>';
+					$after = '</p>';
+				break;
+				case 'span':
+					$tag = 'span';
+					$before = '<span id="afilter-' . $component . '"' . $selected . '>';
+					$after = '</span>';
+				break;
+			}
+
+			$link = add_query_arg( 'afilter', $component );
+			$link = remove_query_arg( 'acpage' , $link );
+			$link = apply_filters( 'bp_get_activity_filter_link_href', $link, $component );
+
+			$component_links[] = $before . '<a href="' . esc_attr( $link ) . '">' . ucwords( $component ) . '</a>' . $after;
+		}
+
+		$link = remove_query_arg( 'afilter' , $link );
+
+		if ( isset( $_GET['afilter'] ) )
+			$component_links[] = '<' . $tag . ' id="afilter-clear"><a href="' . esc_attr( $link ) . '">' . __( 'Clear Filter', 'buddypress' ) . '</a></' . $tag . '>';
+
+ 		return apply_filters( 'bp_get_activity_filter_links', implode( "\n", $component_links ) );
+	}
+
+/**
+ * Determine if a comment can be made on an activity item.
+ *
+ * @since BuddyPress (1.2)
+ *
+ * @global object $activities_template {@link BP_Activity_Template}
+ * @uses bp_get_activity_action_name()
+ * @uses apply_filters() To call the 'bp_activity_can_comment' hook.
+ *
+ * @return bool $can_comment True if item can receive comments.
+ */
+function bp_activity_can_comment() {
+	global $activities_template;
+
+	$can_comment = true;
+
+	if ( false === $activities_template->disable_blogforum_replies || (int) $activities_template->disable_blogforum_replies ) {
+		if ( 'new_blog_post' == bp_get_activity_action_name() || 'new_blog_comment' == bp_get_activity_action_name() || 'new_forum_topic' == bp_get_activity_action_name() || 'new_forum_post' == bp_get_activity_action_name() )
+			$can_comment = false;
+	}
+
+	if ( 'activity_comment' == bp_get_activity_action_name() )
+		$can_comment = false;
+
+	return apply_filters( 'bp_activity_can_comment', $can_comment );
+}
+
+/**
+ * Determine if a comment can be made on an activity reply item.
+ *
+ * Defaults to true, but can be modified by plugins.
+ *
+ * @since BuddyPress (1.5)
+ *
+ * @uses apply_filters() To call the 'bp_activity_can_comment_reply' hook
+ *
+ * @param object $comment Activity comment.
+ * @return bool $can_comment True if comment can receive comments.
+ */
+function bp_activity_can_comment_reply( $comment ) {
+	$can_comment = true;
+
+	return apply_filters( 'bp_activity_can_comment_reply', $can_comment, $comment );
+}
+
+/**
+ * Determine if an favorites are allowed.
+ *
+ * Defaults to true, but can be modified by plugins.
+ *
+ * @since BuddyPress (1.5)
+ *
+ * @uses apply_filters() To call the 'bp_activity_can_favorite' hook.
+ *
+ * @return bool $can_favorite True if comment can receive comments.
+ */
+function bp_activity_can_favorite() {
+	$can_favorite = true;
+
+	return apply_filters( 'bp_activity_can_favorite', $can_favorite );
+}
+
+/**
+ * Output the total favorite count for a specified user.
+ *
+ * @since BuddyPress (1.2)
+ *
+ * @see bp_get_total_favorite_count_for_user() for description of parameters.
+ * @uses bp_get_total_favorite_count_for_user()
+ *
+ * @param int $user_id See {@link bp_get_total_favorite_count_for_user()}.
+ */
+function bp_total_favorite_count_for_user( $user_id = 0 ) {
+	echo bp_get_total_favorite_count_for_user( $user_id );
+}
+
+	/**
+	 * Return the total favorite count for a specified user.
+	 *
+	 * @since BuddyPress (1.2)
+	 *
+	 * @uses bp_activity_total_favorites_for_user()
+	 * @uses apply_filters() To call the 'bp_get_total_favorite_count_for_user' hook
+	 *
+	 * @param int $user_id ID of user being queried. Default: displayed user ID.
+	 * @return int The total favorite count for the specified user.
+	 */
+	function bp_get_total_favorite_count_for_user( $user_id = 0 ) {
+		if ( ! $user_id ) {
+			$user_id = bp_displayed_user_id();
+		}
+
+		return apply_filters( 'bp_get_total_favorite_count_for_user', bp_activity_total_favorites_for_user( $user_id ) );
+	}
+	add_filter( 'bp_get_total_favorite_count_for_user', 'bp_core_number_format' );
+
+/**
+ * Output the total mention count for a specified user.
+ *
+ * @since BuddyPress (1.2)
+ *
+ * @see bp_get_total_mention_count_for_user() for description of parameters.
+ * @uses bp_get_total_favorite_count_for_user()
+ *
+ * @param int $user_id See {@link bp_get_total_mention_count_for_user()}.
+ */
+function bp_total_mention_count_for_user( $user_id = 0 ) {
+	echo bp_get_total_mention_count_for_user( $user_id );
+}
+
+	/**
+	 * Return the total mention count for a specified user.
+	 *
+	 * @since BuddyPress (1.2)
+	 *
+	 * @uses bp_get_user_meta()
+	 * @uses apply_filters() To call the 'bp_get_total_mention_count_for_user' hook.
+	 *
+	 * @param int $user_id ID of user being queried. Default: displayed user ID.
+	 * @return int The total mention count for the specified user.
+	 */
+	function bp_get_total_mention_count_for_user( $user_id = 0 ) {
+		if ( ! $user_id ) {
+			$user_id = bp_displayed_user_id();
+		}
+
+		return apply_filters( 'bp_get_total_mention_count_for_user', bp_get_user_meta( $user_id, 'bp_new_mention_count', true ) );
+	}
+	add_filter( 'bp_get_total_mention_count_for_user', 'bp_core_number_format' );
+
+/**
+ * Output the public message link for displayed user.
+ *
+ * @since BuddyPress (1.2)
+ *
+ * @uses bp_get_send_public_message_link()
+ */
+function bp_send_public_message_link() {
+	echo bp_get_send_public_message_link();
+}
+
+	/**
+	 * Return the public message link for the displayed user.
+	 *
+	 * @since BuddyPress (1.2)
+	 *
+	 * @uses is_user_logged_in()
+	 * @uses bp_is_my_profile()
+	 * @uses bp_is_user()
+	 * @uses wp_nonce_url()
+	 * @uses bp_get_activity_directory_permalink()
+	 * @uses apply_filters() To call the 'bp_get_send_public_message_link' hook
+	 *
+	 * @return string The public message link for the displayed user.
+	 */
+	function bp_get_send_public_message_link() {
+
+		if ( ! is_user_logged_in() || ! bp_is_user() || bp_is_my_profile() )
+			return false;
+
+		return apply_filters( 'bp_get_send_public_message_link', wp_nonce_url( bp_get_activity_directory_permalink() . '?r=' . bp_get_displayed_user_mentionname() ) );
+	}
+
+
+/**
+ * Output the mentioned user display name.
+ *
+ * @since BuddyPress (1.2)
+ *
+ * @see bp_get_mentioned_user_display_name() for description of parameters.
+ * @uses bp_get_mentioned_user_display_name()
+ *
+ * @param int|string $user_id_or_username See {@link bp_get_mentioned_user_display_name()}.
+ */
+function bp_mentioned_user_display_name( $user_id_or_username ) {
+	echo bp_get_mentioned_user_display_name( $user_id_or_username );
+}
+
+	/**
+	 * Returns the mentioned user display name
+	 *
+	 * @since BuddyPress (1.2)
+	 *
+	 * @uses bp_core_get_user_displayname()
+	 * @uses apply_filters() To call the 'bp_get_mentioned_user_display_name' hook.
+	 *
+	 * @param int|string User ID or username.
+	 * @return string The mentioned user's display name.
+	 */
+	function bp_get_mentioned_user_display_name( $user_id_or_username ) {
+		if ( !$name = bp_core_get_user_displayname( $user_id_or_username ) )
+			$name = __( 'a user', 'buddypress' );
+
+		return apply_filters( 'bp_get_mentioned_user_display_name', $name, $user_id_or_username );
+	}
+
+/**
+ * Output button for sending a public message (an @-mention).
+ *
+ * @since BuddyPress (1.2)
+ *
+ * @see bp_get_send_public_message_button() for description of parameters.
+ * @uses bp_get_send_public_message_button()
+ *
+ * @param array $args See {@link bp_get_send_public_message_button()}.
+ */
+function bp_send_public_message_button( $args = '' ) {
+	echo bp_get_send_public_message_button( $args );
+}
+
+	/**
+	 * Return button for sending a public message (an @-mention).
+	 *
+	 * @since BuddyPress (1.2)
+	 *
+	 * @uses bp_get_send_public_message_link()
+	 * @uses wp_parse_args()
+	 * @uses bp_get_button()
+	 * @uses apply_filters() To call the 'bp_get_send_public_message_button' hook.
+	 *
+	 * @param array $args {
+	 *     All arguments are optional. See {@link BP_Button} for complete
+	 *     descriptions.
+	 *     @type string $id Default: 'public_message'.
+	 *     @type string $component Default: 'activity'.
+	 *     @type bool $must_be_logged_in Default: true.
+	 *     @type bool $block_self Default: true.
+	 *     @type string $wrapper_id Default: 'post-mention'.
+	 *     @type string $link_href Default: the public message link for
+	 *           the current member in the loop.
+	 *     @type string $link_title Default: 'Send a public message on your
+	 *           activity stream.'.
+	 *     @type string $link_text Default: 'Public Message'.
+	 *     @type string $link_class Default: 'activity-button mention'.
+	 * }
+	 * @return string The button for sending a public message.
+	 */
+	function bp_get_send_public_message_button( $args = '' ) {
+		$defaults = array(
+			'id'                => 'public_message',
+			'component'         => 'activity',
+			'must_be_logged_in' => true,
+			'block_self'        => true,
+			'wrapper_id'        => 'post-mention',
+			'link_href'         => bp_get_send_public_message_link(),
+			'link_title'        => __( 'Send a public message on your activity stream.', 'buddypress' ),
+			'link_text'         => __( 'Public Message', 'buddypress' ),
+			'link_class'        => 'activity-button mention'
+		);
+
+		$button = wp_parse_args( $args, $defaults );
+
+		// Filter and return the HTML button
+		return bp_get_button( apply_filters( 'bp_get_send_public_message_button', $button ) );
+	}
+
+/**
+ * Output the activity post form action.
+ *
+ * @since BuddyPress (1.2)
+ *
+ * @uses bp_get_activity_post_form_action()
+ */
+function bp_activity_post_form_action() {
+	echo bp_get_activity_post_form_action();
+}
+
+	/**
+	 * Return the activity post form action.
+	 *
+	 * @since BuddyPress (1.2)
+	 *
+	 * @uses home_url()
+	 * @uses bp_get_activity_root_slug()
+	 * @uses apply_filters() To call the 'bp_get_activity_post_form_action' hook.
+	 *
+	 * @return string The activity post form action.
+	 */
+	function bp_get_activity_post_form_action() {
+		return apply_filters( 'bp_get_activity_post_form_action', home_url( bp_get_activity_root_slug() . '/post/' ) );
+	}
+
+/**
+ * Echo a list of linked avatars of users who have commented on the current activity item.
+ *
+ * Use this function to easily output activity comment authors' avatars.
+ *
+ * Avatars are wrapped in <li> elements, but you've got to provide your own
+ * <ul> or <ol> wrapper markup.
+ *
+ * @since BuddyPress (1.7)
+ *
+ * @see bp_core_fetch_avatar() for a description of arguments.
+ *
+ * @param array $args See {@link bp_core_fetch_avatar()}.
+ */
+function bp_activity_comments_user_avatars( $args = array() ) {
+	$defaults = array(
+		'height' => false,
+		'html'   => true,
+		'type'   => 'thumb',
+		'width'  => false,
+	);
+
+	$args = wp_parse_args( $args, $defaults );
+	extract( $args, EXTR_SKIP );
+
+	// Get the user IDs of everyone who has left a comment to the current activity item
+	$user_ids = bp_activity_get_comments_user_ids();
+
+	$output = array();
+	foreach ( (array) $user_ids as $user_id ) {
+		$profile_link = bp_core_get_user_domain( $user_id );
+		$image_html   = bp_core_fetch_avatar( array( 'item_id' => $user_id, 'height' => $height, 'html' => $html, 'type' => $type, 'width' => $width, ) );
+
+		$output[] = sprintf( '<a href="%1$s">%2$s</a>', esc_url( $profile_link ), $image_html );
+	}
+
+	echo apply_filters( 'bp_activity_comments_user_avatars', '<li>' . implode( '</li><li>', $output ) . '</li>', $args, $output );
+}
+
+/**
+ * Return the IDs of every user who's left a comment on the current activity item.
+ *
+ * @since BuddyPress (1.7)
+ *
+ * @return bool|array An array of IDs, or false if none are found.
+ */
+function bp_activity_get_comments_user_ids() {
+	if ( empty( $GLOBALS['activities_template']->activity ) || empty( $GLOBALS['activities_template']->activity->children ) )
+		return false;
+
+	$user_ids = (array) bp_activity_recurse_comments_user_ids( $GLOBALS['activities_template']->activity->children );
+	return apply_filters( 'bp_activity_get_comments_user_ids', array_unique( $user_ids ) );
+}
+
+	/**
+	 * Recurse through all activity comments and collect the IDs of the users who wrote them.
+	 *
+	 * @since BuddyPress (1.7)
+	 *
+	 * @param array $comments Array of {@link BP_Activity_Activity} items.
+	 * @return array Array of user IDs.
+	 */
+	function bp_activity_recurse_comments_user_ids( array $comments ) {
+		$user_ids = array();
+
+		foreach ( $comments as $comment ) {
+			// If a user is a spammer, their activity items will have been automatically marked as spam. Skip these.
+			if ( $comment->is_spam )
+				continue;
+
+			$user_ids[] = $comment->user_id;
+
+			// Check for commentception
+			if ( ! empty( $comment->children ) )
+				$user_ids = array_merge( $user_ids, bp_activity_recurse_comments_user_ids( $comment->children ) );
+		}
+
+		return $user_ids;
+	}
+
+/**
+ * Output the mentionname for the displayed user.
+ *
+ * @since BuddyPress (1.9.0)
+ */
+function bp_displayed_user_mentionname() {
+	echo bp_get_displayed_user_mentionname();
+}
+	/**
+	 * Get the mentionname for the displayed user.
+	 *
+	 * @since BuddyPress (1.9.0)
+	 *
+	 * @return string Mentionname for the displayed user, if available.
+	 */
+	function bp_get_displayed_user_mentionname() {
+		return apply_filters( 'bp_get_displayed_user_mentionname', bp_activity_get_user_mentionname( bp_displayed_user_id() ) );
+	}
+
+/**
+ * Echo a list of all registered activity types for use in dropdowns or checkbox lists.
+ *
+ * @since BuddyPress (1.7)
+ *
+ * @param string $output Optional. Either 'select' or 'checkbox'. Default: 'select'.
+ * @param array $args {
+ *     Optional extra arguments.
+ *     @type string $checkbox_name When returning checkboxes, sets the 'name'
+ *           attribute.
+ *     @type array|string $selected A list of types that should be checked/
+ *           selected.
+ * }
+ */
+function bp_activity_types_list( $output = 'select', $args = '' ) {
+	$defaults = array(
+		'checkbox_name' => 'bp_activity_types',
+		'selected'      => array(),
+	);
+	$args = wp_parse_args( $args, $defaults );
+
+	$activities = bp_activity_get_types();
+	natsort( $activities );
+
+	// Loop through the activity types and output markup
+	foreach ( $activities as $type => $description ) {
+
+		// See if we need to preselect the current type
+		$checked  = checked(  true, in_array( $type, (array) $args['selected'] ), false );
+		$selected = selected( true, in_array( $type, (array) $args['selected'] ), false );
+
+		if ( 'select' == $output )
+			printf( '<option value="%1$s" %2$s>%3$s</option>', esc_attr( $type ), $selected, esc_html( $description ) );
+
+		elseif ( 'checkbox' == $output )
+			printf( '<label style="">%1$s<input type="checkbox" name="%2$s[]" value="%3$s" %4$s/></label>', esc_html( $description ), esc_attr( $args['checkbox_name'] ), esc_attr( $type ), $checked );
+
+		// Allow custom markup
+		do_action( 'bp_activity_types_list_' . $output, $args, $type, $description );
+	}
+
+	// Backpat with BP-Default for dropdown boxes only
+	if ( 'select' == $output )
+		do_action( 'bp_activity_filter_options' );
+}
+
+
+/* RSS Feed Template Tags ****************************************************/
+
+/**
+ * Output the sitewide activity feed link.
+ *
+ * @since BuddyPress (1.0)
+ *
+ * @uses bp_get_sitewide_activity_feed_link()
+ */
+function bp_sitewide_activity_feed_link() {
+	echo bp_get_sitewide_activity_feed_link();
+}
+
+	/**
+	 * Returns the sitewide activity feed link.
+	 *
+	 * @since BuddyPress (1.0)
+	 *
+	 * @uses home_url()
+	 * @uses bp_get_activity_root_slug()
+	 * @uses apply_filters() To call the 'bp_get_sitewide_activity_feed_link' hook.
+	 *
+	 * @return string The sitewide activity feed link.
+	 */
+	function bp_get_sitewide_activity_feed_link() {
+		return apply_filters( 'bp_get_sitewide_activity_feed_link', bp_get_root_domain() . '/' . bp_get_activity_root_slug() . '/feed/' );
+	}
+
+/**
+ * Output the member activity feed link.
+ *
+ * @since BuddyPress (1.2)
+ *
+ * @uses bp_get_member_activity_feed_link()
+ */
+function bp_member_activity_feed_link() {
+	echo bp_get_member_activity_feed_link();
+}
+
+/**
+ * Output the member activity feed link.
+ *
+ * @since BuddyPress (1.0)
+ * @deprecated BuddyPress (1.2)
+ *
+ * @todo properly deprecate in favor of bp_member_activity_feed_link().
+ *
+ * @uses bp_get_member_activity_feed_link()
+ */
+function bp_activities_member_rss_link() { echo bp_get_member_activity_feed_link(); }
+
+	/**
+	 * Return the member activity feed link.
+	 *
+	 * @since BuddyPress (1.2)
+	 *
+	 * @uses bp_is_profile_component()
+	 * @uses bp_is_current_action()
+	 * @uses bp_displayed_user_domain()
+	 * @uses bp_get_activity_slug()
+	 * @uses bp_is_active()
+	 * @uses bp_get_friends_slug()
+	 * @uses bp_get_groups_slug()
+	 * @uses apply_filters() To call the 'bp_get_activities_member_rss_link' hook.
+	 *
+	 * @return string $link The member activity feed link.
+	 */
+	function bp_get_member_activity_feed_link() {
+
+		if ( bp_is_profile_component() || bp_is_current_action( 'just-me' ) )
+			$link = bp_displayed_user_domain() . bp_get_activity_slug() . '/feed/';
+		elseif ( bp_is_active( 'friends' ) && bp_is_current_action( bp_get_friends_slug() ) )
+			$link = bp_displayed_user_domain() . bp_get_activity_slug() . '/' . bp_get_friends_slug() . '/feed/';
+		elseif ( bp_is_active( 'groups'  ) && bp_is_current_action( bp_get_groups_slug()  ) )
+			$link = bp_displayed_user_domain() . bp_get_activity_slug() . '/' . bp_get_groups_slug() . '/feed/';
+		elseif ( 'favorites' == bp_current_action() )
+			$link = bp_displayed_user_domain() . bp_get_activity_slug() . '/favorites/feed/';
+		elseif ( 'mentions' == bp_current_action() && bp_activity_do_mentions() )
+			$link = bp_displayed_user_domain() . bp_get_activity_slug() . '/mentions/feed/';
+		else
+			$link = '';
+
+		return apply_filters( 'bp_get_activities_member_rss_link', $link );
+	}
+
+	/**
+	 * Return the member activity feed link.
+	 *
+	 * @since BuddyPress (1.0)
+	 * @deprecated BuddyPress (1.2)
+	 *
+	 * @todo properly deprecate in favor of bp_get_member_activity_feed_link().
+	 *
+	 * @uses bp_get_member_activity_feed_link()
+	 *
+	 * @return string The member activity feed link.
+	 */
+	function bp_get_activities_member_rss_link() { return bp_get_member_activity_feed_link(); }
+
+
+/** Template tags for RSS feed output ****************************************/
+
+/**
+ * Outputs the activity feed item guid.
+ *
+ * @since BuddyPress (1.0)
+ *
+ * @uses bp_activity_feed_item_guid()
+ */
+function bp_activity_feed_item_guid() {
+	echo bp_get_activity_feed_item_guid();
+}
+
+	/**
+	 * Returns the activity feed item guid.
+	 *
+	 * @since BuddyPress (1.2)
+	 *
+	 * @global object $activities_template {@link BP_Activity_Template}
+	 * @uses apply_filters() To call the 'bp_get_activity_feed_item_guid' hook.
+	 *
+	 * @return string The activity feed item guid.
+	 */
+	function bp_get_activity_feed_item_guid() {
+		global $activities_template;
+
+		return apply_filters( 'bp_get_activity_feed_item_guid', md5( $activities_template->activity->date_recorded . '-' . $activities_template->activity->content ) );
+	}
+
+/**
+ * Output the activity feed item title.
+ *
+ * @since BuddyPress (1.0)
+ *
+ * @uses bp_get_activity_feed_item_title()
+ */
+function bp_activity_feed_item_title() {
+	echo bp_get_activity_feed_item_title();
+}
+
+	/**
+	 * Return the activity feed item title.
+	 *
+	 * @since BuddyPress (1.0)
+	 *
+	 * @global object $activities_template {@link BP_Activity_Template}
+	 * @uses ent2ncr()
+	 * @uses convert_chars()
+	 * @uses bp_create_excerpt()
+	 * @uses apply_filters() To call the 'bp_get_activity_feed_item_title' hook.
+	 *
+	 * @return string $title The activity feed item title.
+	 */
+	function bp_get_activity_feed_item_title() {
+		global $activities_template;
+
+		if ( !empty( $activities_template->activity->action ) )
+			$content = $activities_template->activity->action;
+		else
+			$content = $activities_template->activity->content;
+
+		$content = explode( '<span', $content );
+		$title = strip_tags( ent2ncr( trim( convert_chars( $content[0] ) ) ) );
+
+		if ( ':' == substr( $title, -1 ) )
+			$title = substr( $title, 0, -1 );
+
+		if ( 'activity_update' == $activities_template->activity->type )
+			$title .= ': ' . strip_tags( ent2ncr( trim( convert_chars( bp_create_excerpt( $activities_template->activity->content, 70, array( 'ending' => " [&#133;]" ) ) ) ) ) );
+
+		return apply_filters( 'bp_get_activity_feed_item_title', $title );
+	}
+
+/**
+ * Output the activity feed item link
+ *
+ * @since BuddyPress (1.0)
+ *
+ * @uses bp_get_activity_feed_item_link()
+ */
+function bp_activity_feed_item_link() {
+	echo bp_get_activity_feed_item_link();
+}
+
+	/**
+	 * Return the activity feed item link
+	 *
+	 * @since BuddyPress (1.0)
+	 *
+	 * @global object $activities_template {@link BP_Activity_Template}
+	 * @uses apply_filters() To call the 'bp_get_activity_feed_item_link' hook.
+	 *
+	 * @return string The activity feed item link.
+	 */
+	function bp_get_activity_feed_item_link() {
+		global $activities_template;
+
+		return apply_filters( 'bp_get_activity_feed_item_link', $activities_template->activity->primary_link );
+	}
+
+/**
+ * Output the activity feed item date.
+ *
+ * @since BuddyPress (1.0)
+ *
+ * @uses bp_get_activity_feed_item_date()
+ */
+function bp_activity_feed_item_date() {
+	echo bp_get_activity_feed_item_date();
+}
+
+	/**
+	 * Return the activity feed item date.
+	 *
+	 * @since BuddyPress (1.0)
+	 *
+	 * @global object $activities_template {@link BP_Activity_Template}
+	 * @uses apply_filters() To call the 'bp_get_activity_feed_item_date' hook.
+	 *
+	 * @return string The activity feed item date.
+	 */
+	function bp_get_activity_feed_item_date() {
+		global $activities_template;
+
+		return apply_filters( 'bp_get_activity_feed_item_date', $activities_template->activity->date_recorded );
+	}
+
+/**
+ * Output the activity feed item description.
+ *
+ * @since BuddyPress (1.0)
+ *
+ * @uses bp_get_activity_feed_item_description()
+ */
+function bp_activity_feed_item_description() {
+	echo bp_get_activity_feed_item_description();
+}
+
+	/**
+	 * Return the activity feed item description.
+	 *
+	 * @since BuddyPress (1.0)
+	 *
+	 * @global object $activities_template {@link BP_Activity_Template}
+	 * @uses ent2ncr()
+	 * @uses convert_chars()
+	 * @uses apply_filters() To call the 'bp_get_activity_feed_item_description' hook.
+	 *
+	 * @return string The activity feed item description.
+	 */
+	function bp_get_activity_feed_item_description() {
+		global $activities_template;
+
+		$content = '';
+		if ( ! empty( $activities_template->activity->content ) )
+			$content = $activities_template->activity->content;
+
+		return apply_filters( 'bp_get_activity_feed_item_description', ent2ncr( convert_chars( str_replace( '%s', '', $content ) ) ) );
+	}
+
+/**
+ * Template tag so we can hook activity feed to <head>.
+ *
+ * @since BuddyPress (1.5)
+ *
+ * @uses bloginfo()
+ * @uses bp_sitewide_activity_feed_link()
+ */
+function bp_activity_sitewide_feed() {
+?>
+
+	<link rel="alternate" type="application/rss+xml" title="<?php bloginfo( 'name' ) ?> | <?php _e( 'Site Wide Activity RSS Feed', 'buddypress' ) ?>" href="<?php bp_sitewide_activity_feed_link() ?>" />
+
+<?php
+}
+add_action( 'bp_head', 'bp_activity_sitewide_feed' );
Index: /tags/1.9/bp-blogs/bp-blogs-actions.php
===================================================================
--- /tags/1.9/bp-blogs/bp-blogs-actions.php	(revision 7684)
+++ /tags/1.9/bp-blogs/bp-blogs-actions.php	(revision 7684)
@@ -0,0 +1,34 @@
+<?php
+
+/**
+ * BuddyPress Blogs Actions.
+ *
+ * @package BuddyPress
+ * @subpackage BlogsActions
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/**
+ * Redirect to a random blog in the multisite network.
+ *
+ * @since BuddyPress (1.0.0)
+ */
+function bp_blogs_redirect_to_random_blog() {
+
+	// Bail if not looking for a random blog
+	if ( ! bp_is_blogs_component() || ! isset( $_GET['random-blog'] ) )
+		return;
+
+	// Multisite is active so find a random blog
+	if ( is_multisite() ) {
+		$blog = bp_blogs_get_random_blogs( 1, 1 );
+		bp_core_redirect( get_home_url( $blog['blogs'][0]->blog_id ) );
+
+	// No multisite and still called, always redirect to root
+	} else {
+		bp_core_redirect( bp_core_get_root_domain() );
+	}
+}
+add_action( 'bp_actions', 'bp_blogs_redirect_to_random_blog' );
Index: /tags/1.9/bp-blogs/bp-blogs-activity.php
===================================================================
--- /tags/1.9/bp-blogs/bp-blogs-activity.php	(revision 7684)
+++ /tags/1.9/bp-blogs/bp-blogs-activity.php	(revision 7684)
@@ -0,0 +1,143 @@
+<?php
+
+/**
+ * BuddyPress Blogs Activity.
+ *
+ * @package BuddyPress
+ * @subpackage BlogsActivity
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/**
+ * Register activity actions for the blogs component.
+ *
+ * @since BuddyPress (1.0.0)
+ *
+ * @global object $bp The BuddyPress global settings object.
+ *
+ * @return bool|null Returns false if activity component is not active.
+ */
+function bp_blogs_register_activity_actions() {
+	global $bp;
+
+	// Bail if activity is not active
+	if ( ! bp_is_active( 'activity' ) ) {
+		return false;
+	}
+
+	if ( is_multisite() ) {
+		bp_activity_set_action( $bp->blogs->id, 'new_blog', __( 'New site created',        'buddypress' ) );
+	}
+
+	bp_activity_set_action( $bp->blogs->id, 'new_blog_post',    __( 'New post published',      'buddypress' ) );
+	bp_activity_set_action( $bp->blogs->id, 'new_blog_comment', __( 'New post comment posted', 'buddypress' ) );
+
+	do_action( 'bp_blogs_register_activity_actions' );
+}
+add_action( 'bp_register_activity_actions', 'bp_blogs_register_activity_actions' );
+
+/**
+ * Record blog-related activity to the activity stream.
+ *
+ * @since BuddyPress (1.0.0)
+ *
+ * @see bp_activity_add() for description of parameters.
+ * @global object $bp The BuddyPress global settings object.
+ *
+ * @param array $args {
+ *     See {@link bp_activity_add()} for complete description of arguments.
+ *     The arguments listed here have different default values from
+ *     bp_activity_add().
+ *     @type string $component Default: 'blogs'.
+ * }
+ * @return int|bool On success, returns the activity ID. False on failure.
+ */
+function bp_blogs_record_activity( $args = '' ) {
+	global $bp;
+
+	// Bail if activity is not active
+	if ( ! bp_is_active( 'activity' ) )
+		return false;
+
+	$defaults = array(
+		'user_id'           => bp_loggedin_user_id(),
+		'action'            => '',
+		'content'           => '',
+		'primary_link'      => '',
+		'component'         => $bp->blogs->id,
+		'type'              => false,
+		'item_id'           => false,
+		'secondary_item_id' => false,
+		'recorded_time'     => bp_core_current_time(),
+		'hide_sitewide'     => false
+	);
+
+	$r = wp_parse_args( $args, $defaults );
+	extract( $r, EXTR_SKIP );
+
+	// Remove large images and replace them with just one image thumbnail
+ 	if ( !empty( $content ) )
+		$content = bp_activity_thumbnail_content_images( $content, $primary_link, $r );
+
+	if ( !empty( $action ) )
+		$action = apply_filters( 'bp_blogs_record_activity_action', $action );
+
+	if ( !empty( $content ) )
+		$content = apply_filters( 'bp_blogs_record_activity_content', bp_create_excerpt( $content ), $content );
+
+	// Check for an existing entry and update if one exists.
+	$id = bp_activity_get_activity_id( array(
+		'user_id'           => $user_id,
+		'component'         => $component,
+		'type'              => $type,
+		'item_id'           => $item_id,
+		'secondary_item_id' => $secondary_item_id
+	) );
+
+	return bp_activity_add( array( 'id' => $id, 'user_id' => $user_id, 'action' => $action, 'content' => $content, 'primary_link' => $primary_link, 'component' => $component, 'type' => $type, 'item_id' => $item_id, 'secondary_item_id' => $secondary_item_id, 'recorded_time' => $recorded_time, 'hide_sitewide' => $hide_sitewide ) );
+}
+
+/**
+ * Delete a blog-related activity stream item.
+ *
+ * @since BuddyPress (1.0.0)
+ *
+ * @see bp_activity_delete() for description of parameters.
+ * @global object $bp The BuddyPress global settings object.
+ *
+ * @param array $args {
+ *     See {@link bp_activity_delete()} for complete description of arguments.
+ *     The arguments listed here have different default values from
+ *     bp_activity_add().
+ *     @type string $component Default: 'blogs'.
+ * }
+ * @return bool True on success, false on failure.
+ */
+function bp_blogs_delete_activity( $args = true ) {
+	global $bp;
+
+	// Bail if activity is not active
+	if ( ! bp_is_active( 'activity' ) )
+		return false;
+
+	$defaults = array(
+		'item_id'           => false,
+		'component'         => $bp->blogs->id,
+		'type'              => false,
+		'user_id'           => false,
+		'secondary_item_id' => false
+	);
+
+	$params = wp_parse_args( $args, $defaults );
+	extract( $params, EXTR_SKIP );
+
+	bp_activity_delete_by_item_id( array(
+		'item_id'           => $item_id,
+		'component'         => $component,
+		'type'              => $type,
+		'user_id'           => $user_id,
+		'secondary_item_id' => $secondary_item_id
+	) );
+}
Index: /tags/1.9/bp-blogs/bp-blogs-buddybar.php
===================================================================
--- /tags/1.9/bp-blogs/bp-blogs-buddybar.php	(revision 7684)
+++ /tags/1.9/bp-blogs/bp-blogs-buddybar.php	(revision 7684)
@@ -0,0 +1,78 @@
+<?php
+
+/**
+ * BuddyPress Blogs BuddyBar functions.
+ *
+ * @package BuddyPress
+ * @subpackage BlogsBuddyBar
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/**
+ * Add a Sites menu to the BuddyBar.
+ *
+ * @since BuddyPress (1.0.0)
+ *
+ * @global object $bp The BuddyPress global settings object.
+ *
+ * @return bool|null Returns false on failure. Otherwise echoes the menu item.
+ */
+function bp_adminbar_blogs_menu() {
+	global $bp;
+
+	if ( !is_user_logged_in() || !bp_is_active( 'blogs' ) )
+		return false;
+
+	if ( !is_multisite() )
+		return false;
+
+	$blogs = wp_cache_get( 'bp_blogs_of_user_' . bp_loggedin_user_id() . '_inc_hidden', 'bp' );
+	if ( empty( $blogs ) ) {
+		$blogs = bp_blogs_get_blogs_for_user( bp_loggedin_user_id(), true );
+		wp_cache_set( 'bp_blogs_of_user_' . bp_loggedin_user_id() . '_inc_hidden', $blogs, 'bp' );
+	}
+
+	$counter = 0;
+	if ( is_array( $blogs['blogs'] ) && (int) $blogs['count'] ) {
+
+		echo '<li id="bp-adminbar-blogs-menu"><a href="' . trailingslashit( bp_loggedin_user_domain() . bp_get_blogs_slug() ) . '">';
+
+		_e( 'My Sites', 'buddypress' );
+
+		echo '</a>';
+		echo '<ul>';
+
+		foreach ( (array) $blogs['blogs'] as $blog ) {
+			$alt      = ( 0 == $counter % 2 ) ? ' class="alt"' : '';
+			$site_url = esc_attr( $blog->siteurl );
+
+			echo '<li' . $alt . '>';
+			echo '<a href="' . $site_url . '">' . esc_html( $blog->name ) . '</a>';
+			echo '<ul>';
+			echo '<li class="alt"><a href="' . $site_url . 'wp-admin/">' . __( 'Dashboard', 'buddypress' ) . '</a></li>';
+			echo '<li><a href="' . $site_url . 'wp-admin/post-new.php">' . __( 'New Post', 'buddypress' ) . '</a></li>';
+			echo '<li class="alt"><a href="' . $site_url . 'wp-admin/edit.php">' . __( 'Manage Posts', 'buddypress' ) . '</a></li>';
+			echo '<li><a href="' . $site_url . 'wp-admin/edit-comments.php">' . __( 'Manage Comments', 'buddypress' ) . '</a></li>';
+			echo '</ul>';
+
+			do_action( 'bp_adminbar_blog_items', $blog );
+
+			echo '</li>';
+			$counter++;
+		}
+
+		$alt = ( 0 == $counter % 2 ) ? ' class="alt"' : '';
+
+		if ( bp_blog_signup_enabled() ) {
+			echo '<li' . $alt . '>';
+			echo '<a href="' . bp_get_root_domain() . '/' . bp_get_blogs_root_slug() . '/create/">' . __( 'Create a Site!', 'buddypress' ) . '</a>';
+			echo '</li>';
+		}
+
+		echo '</ul>';
+		echo '</li>';
+	}
+}
+add_action( 'bp_adminbar_menus', 'bp_adminbar_blogs_menu', 6 );
Index: /tags/1.9/bp-blogs/bp-blogs-cache.php
===================================================================
--- /tags/1.9/bp-blogs/bp-blogs-cache.php	(revision 7684)
+++ /tags/1.9/bp-blogs/bp-blogs-cache.php	(revision 7684)
@@ -0,0 +1,55 @@
+<?php
+
+/**
+ * BuddyPress Blogs Caching.
+ *
+ * Caching functions handle the clearing of cached objects and pages on specific
+ * actions throughout BuddyPress.
+ *
+ * @package BuddyPress
+ * @subpackage BlogsCache
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/**
+ * Clear the blog object cache.
+ *
+ * @since BuddyPress (1.0.0)
+ *
+ * @param int $blog_id ID of the current blog.
+ * @param int $user_id ID of the user whose blog cache should be cleared.
+ */
+function bp_blogs_clear_blog_object_cache( $blog_id, $user_id ) {
+	wp_cache_delete( 'bp_blogs_of_user_'        . $user_id, 'bp' );
+	wp_cache_delete( 'bp_total_blogs_for_user_' . $user_id, 'bp' );
+}
+
+/**
+ * Clear cache when a new blog is created.
+ *
+ * @since BuddyPress (1.0.0)
+ *
+ * @param BP_Blogs_Blog $recorded_blog_obj The recorded blog, passed by
+ *        'bp_blogs_new_blog'.
+ */
+function bp_blogs_format_clear_blog_cache( $recorded_blog_obj ) {
+	bp_blogs_clear_blog_object_cache( false, $recorded_blog_obj->user_id );
+	wp_cache_delete( 'bp_total_blogs', 'bp' );
+}
+
+// List actions to clear object caches on
+add_action( 'bp_blogs_remove_blog_for_user', 'bp_blogs_clear_blog_object_cache', 10, 2 );
+add_action( 'bp_blogs_new_blog',             'bp_blogs_format_clear_blog_cache', 10, 2 );
+
+// List actions to clear super cached pages on, if super cache is installed
+add_action( 'bp_blogs_remove_data_for_blog', 'bp_core_clear_cache' );
+add_action( 'bp_blogs_remove_comment',       'bp_core_clear_cache' );
+add_action( 'bp_blogs_remove_post',          'bp_core_clear_cache' );
+add_action( 'bp_blogs_remove_blog_for_user', 'bp_core_clear_cache' );
+add_action( 'bp_blogs_remove_blog',          'bp_core_clear_cache' );
+add_action( 'bp_blogs_new_blog_comment',     'bp_core_clear_cache' );
+add_action( 'bp_blogs_new_blog_post',        'bp_core_clear_cache' );
+add_action( 'bp_blogs_new_blog',             'bp_core_clear_cache' );
+add_action( 'bp_blogs_remove_data',          'bp_core_clear_cache' );
Index: /tags/1.9/bp-blogs/bp-blogs-classes.php
===================================================================
--- /tags/1.9/bp-blogs/bp-blogs-classes.php	(revision 7684)
+++ /tags/1.9/bp-blogs/bp-blogs-classes.php	(revision 7684)
@@ -0,0 +1,490 @@
+<?php
+
+/**
+ * BuddyPress Blogs Classes.
+ *
+ * @package BuddyPress
+ * @subpackage BlogsClasses
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/**
+ * The main BuddyPress blog class.
+ *
+ * A BP_Blogs_Object represents a link between a specific WordPress blog on a
+ * network and a specific user on that blog.
+ *
+ * @since BuddyPress (1.0.0)
+ */
+class BP_Blogs_Blog {
+	public $id;
+	public $user_id;
+	public $blog_id;
+
+	/**
+	 * Constructor method.
+	 *
+	 * @param int $id Optional. The ID of the blog.
+	 */
+	public function __construct( $id = null ) {
+		if ( !empty( $id ) ) {
+			$this->id = $id;
+			$this->populate();
+		}
+	}
+
+	/**
+	 * Populate the object with data about the specific activity item.
+	 */
+	public function populate() {
+		global $wpdb, $bp;
+
+		$blog = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$bp->blogs->table_name} WHERE id = %d", $this->id ) );
+
+		$this->user_id = $blog->user_id;
+		$this->blog_id = $blog->blog_id;
+	}
+
+	/**
+	 * Save the BP blog data to the database.
+	 *
+	 * @return bool True on success, false on failure.
+	 */
+	public function save() {
+		global $wpdb, $bp;
+
+		$this->user_id = apply_filters( 'bp_blogs_blog_user_id_before_save', $this->user_id, $this->id );
+		$this->blog_id = apply_filters( 'bp_blogs_blog_id_before_save', $this->blog_id, $this->id );
+
+		do_action_ref_array( 'bp_blogs_blog_before_save', array( &$this ) );
+
+		// Don't try and save if there is no user ID or blog ID set.
+		if ( !$this->user_id || !$this->blog_id )
+			return false;
+
+		// Don't save if this blog has already been recorded for the user.
+		if ( !$this->id && $this->exists() )
+			return false;
+
+		if ( $this->id ) {
+			// Update
+			$sql = $wpdb->prepare( "UPDATE {$bp->blogs->table_name} SET user_id = %d, blog_id = %d WHERE id = %d", $this->user_id, $this->blog_id, $this->id );
+		} else {
+			// Save
+			$sql = $wpdb->prepare( "INSERT INTO {$bp->blogs->table_name} ( user_id, blog_id ) VALUES ( %d, %d )", $this->user_id, $this->blog_id );
+		}
+
+		if ( !$wpdb->query($sql) )
+			return false;
+
+		do_action_ref_array( 'bp_blogs_blog_after_save', array( &$this ) );
+
+		if ( $this->id )
+			return $this->id;
+		else
+			return $wpdb->insert_id;
+	}
+
+	/**
+	 * Check whether an association between this user and this blog exists.
+	 *
+	 * @return int The number of associations between the user and blog
+	 *         saved in the blog component tables.
+	 */
+	public function exists() {
+		global $bp, $wpdb;
+
+		return $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(id) FROM {$bp->blogs->table_name} WHERE user_id = %d AND blog_id = %d", $this->user_id, $this->blog_id ) );
+	}
+
+	/** Static Methods ***************************************************/
+
+	/**
+	 * Retrieve a set of blog-user associations.
+	 *
+	 * @param string $type The order in which results should be returned.
+	 *        'active', 'alphabetical', 'newest', or 'random'.
+	 * @param int|bool $limit Optional. The maximum records to return.
+	 *        Default: false.
+	 * @param int|bool $page Optional. The page of records to return.
+	 *        Default: false (unlimited results).
+	 * @param int $user_id Optional. ID of the user whose blogs are being
+	 *        retrieved. Default: 0.
+	 * @param string|bool $search_terms Optional. Search by text stored in
+	 *        blogmeta (such as the blog name). Default: false.
+	 * @return array Multidimensional results array, structured as follows:
+	 *           'blogs' - Array of located blog objects
+	 *           'total' - A count of the total blogs matching the filter params
+	 */
+	public static function get( $type, $limit = false, $page = false, $user_id = 0, $search_terms = false ) {
+		global $bp, $wpdb;
+
+		if ( !is_user_logged_in() || ( !bp_current_user_can( 'bp_moderate' ) && ( $user_id != bp_loggedin_user_id() ) ) )
+			$hidden_sql = "AND wb.public = 1";
+		else
+			$hidden_sql = '';
+
+		$pag_sql = ( $limit && $page ) ? $wpdb->prepare( " LIMIT %d, %d", intval( ( $page - 1 ) * $limit), intval( $limit ) ) : '';
+
+		$user_sql = !empty( $user_id ) ? $wpdb->prepare( " AND b.user_id = %d", $user_id ) : '';
+
+		switch ( $type ) {
+			case 'active': default:
+				$order_sql = "ORDER BY bm.meta_value DESC";
+				break;
+			case 'alphabetical':
+				$order_sql = "ORDER BY bm2.meta_value ASC";
+				break;
+			case 'newest':
+				$order_sql = "ORDER BY wb.registered DESC";
+				break;
+			case 'random':
+				$order_sql = "ORDER BY RAND()";
+				break;
+		}
+
+		if ( !empty( $search_terms ) ) {
+			$filter = esc_sql( like_escape( $search_terms ) );
+			$paged_blogs = $wpdb->get_results( "SELECT b.blog_id, b.user_id as admin_user_id, u.user_email as admin_user_email, wb.domain, wb.path, bm.meta_value as last_activity, bm2.meta_value as name FROM {$bp->blogs->table_name} b, {$bp->blogs->table_name_blogmeta} bm, {$bp->blogs->table_name_blogmeta} bm2, {$wpdb->base_prefix}blogs wb, {$wpdb->users} u WHERE b.blog_id = wb.blog_id AND b.user_id = u.ID AND b.blog_id = bm.blog_id AND b.blog_id = bm2.blog_id AND wb.archived = '0' AND wb.spam = 0 AND wb.mature = 0 AND wb.deleted = 0 {$hidden_sql} AND bm.meta_key = 'last_activity' AND bm2.meta_key = 'name' AND bm2.meta_value LIKE '%%$filter%%' {$user_sql} GROUP BY b.blog_id {$order_sql} {$pag_sql}" );
+			$total_blogs = $wpdb->get_var( "SELECT COUNT(DISTINCT b.blog_id) FROM {$bp->blogs->table_name} b, {$wpdb->base_prefix}blogs wb, {$bp->blogs->table_name_blogmeta} bm, {$bp->blogs->table_name_blogmeta} bm2 WHERE b.blog_id = wb.blog_id AND bm.blog_id = b.blog_id AND bm2.blog_id = b.blog_id AND wb.archived = '0' AND wb.spam = 0 AND wb.mature = 0 AND wb.deleted = 0 {$hidden_sql} AND bm.meta_key = 'name' AND bm2.meta_key = 'description' AND ( bm.meta_value LIKE '%%$filter%%' || bm2.meta_value LIKE '%%$filter%%' ) {$user_sql}" );
+		} else {
+			$paged_blogs = $wpdb->get_results( "SELECT b.blog_id, b.user_id as admin_user_id, u.user_email as admin_user_email, wb.domain, wb.path, bm.meta_value as last_activity, bm2.meta_value as name FROM {$bp->blogs->table_name} b, {$bp->blogs->table_name_blogmeta} bm, {$bp->blogs->table_name_blogmeta} bm2, {$wpdb->base_prefix}blogs wb, {$wpdb->users} u WHERE b.blog_id = wb.blog_id AND b.user_id = u.ID AND b.blog_id = bm.blog_id AND b.blog_id = bm2.blog_id {$user_sql} AND wb.archived = '0' AND wb.spam = 0 AND wb.mature = 0 AND wb.deleted = 0 {$hidden_sql} AND bm.meta_key = 'last_activity' AND bm2.meta_key = 'name' GROUP BY b.blog_id {$order_sql} {$pag_sql}" );
+			$total_blogs = $wpdb->get_var( "SELECT COUNT(DISTINCT b.blog_id) FROM {$bp->blogs->table_name} b, {$wpdb->base_prefix}blogs wb WHERE b.blog_id = wb.blog_id {$user_sql} AND wb.archived = '0' AND wb.spam = 0 AND wb.mature = 0 AND wb.deleted = 0 {$hidden_sql}" );
+		}
+
+		$blog_ids = array();
+		foreach ( (array) $paged_blogs as $blog ) {
+			$blog_ids[] = (int) $blog->blog_id;
+		}
+
+		$paged_blogs = BP_Blogs_Blog::get_blog_extras( $paged_blogs, $blog_ids, $type );
+
+		return array( 'blogs' => $paged_blogs, 'total' => $total_blogs );
+	}
+
+	/**
+	 * Delete the record of a given blog for all users.
+	 *
+	 * @param int $blog_id The blog being removed from all users.
+	 * @return int|bool Number of rows deleted on success, false on failure.
+	 */
+	public static function delete_blog_for_all( $blog_id ) {
+		global $wpdb, $bp;
+
+		bp_blogs_delete_blogmeta( $blog_id );
+		return $wpdb->query( $wpdb->prepare( "DELETE FROM {$bp->blogs->table_name} WHERE blog_id = %d", $blog_id ) );
+	}
+
+	/**
+	 * Delete the record of a given blog for a specific user.
+	 *
+	 * @param int $blog_id The blog being removed.
+	 * @param int $user_id Optional. The ID of the user from whom the blog
+	 *        is being removed. If absent, defaults to the logged-in user ID.
+	 * @return int|bool Number of rows deleted on success, false on failure.
+	 */
+	public static function delete_blog_for_user( $blog_id, $user_id = null ) {
+		global $wpdb, $bp;
+
+		if ( !$user_id )
+			$user_id = bp_loggedin_user_id();
+
+		return $wpdb->query( $wpdb->prepare( "DELETE FROM {$bp->blogs->table_name} WHERE user_id = %d AND blog_id = %d", $user_id, $blog_id ) );
+	}
+
+	/**
+	 * Delete all of a user's blog associations in the BP tables.
+	 *
+	 * @param int $user_id Optional. The ID of the user whose blog
+	 *        associations are being deleted. If absent, defaults to
+	 *        logged-in user ID.
+	 * @return int|bool Number of rows deleted on success, false on failure.
+	 */
+	public static function delete_blogs_for_user( $user_id = null ) {
+		global $wpdb, $bp;
+
+		if ( !$user_id )
+			$user_id = bp_loggedin_user_id();
+
+		return $wpdb->query( $wpdb->prepare( "DELETE FROM {$bp->blogs->table_name} WHERE user_id = %d", $user_id ) );
+	}
+
+	/**
+	 * Get all of a user's blogs, as tracked by BuddyPress.
+	 *
+	 * Note that this is different from the WordPress function
+	 * {@link get_blogs_of_user()}; the current method returns only those
+	 * blogs that have been recorded by BuddyPress, while the WP function
+	 * does a true query of a user's blog capabilities.
+	 *
+	 * @param int $user_id Optional. ID of the user whose blogs are being
+	 *        queried. Defaults to logged-in user.
+	 * @param bool $show_hidden Optional. Whether to include blogs that are
+	 *        not marked public. Defaults to true when viewing one's own
+	 *        profile.
+	 * @return array Multidimensional results array, structured as follows:
+	 *           'blogs' - Array of located blog objects
+	 *           'total' - A count of the total blogs for the user.
+	 */
+	public static function get_blogs_for_user( $user_id = 0, $show_hidden = false ) {
+		global $bp, $wpdb;
+
+		if ( !$user_id )
+			$user_id = bp_displayed_user_id();
+
+		// Show logged in users their hidden blogs.
+		if ( !bp_is_my_profile() && !$show_hidden )
+			$blogs = $wpdb->get_results( $wpdb->prepare( "SELECT DISTINCT b.blog_id, b.id, bm1.meta_value as name, wb.domain, wb.path FROM {$bp->blogs->table_name} b, {$wpdb->base_prefix}blogs wb, {$bp->blogs->table_name_blogmeta} bm1 WHERE b.blog_id = wb.blog_id AND b.blog_id = bm1.blog_id AND bm1.meta_key = 'name' AND wb.public = 1 AND wb.deleted = 0 AND wb.spam = 0 AND wb.mature = 0 AND wb.archived = '0' AND b.user_id = %d ORDER BY b.blog_id", $user_id ) );
+		else
+			$blogs = $wpdb->get_results( $wpdb->prepare( "SELECT DISTINCT b.blog_id, b.id, bm1.meta_value as name, wb.domain, wb.path FROM {$bp->blogs->table_name} b, {$wpdb->base_prefix}blogs wb, {$bp->blogs->table_name_blogmeta} bm1 WHERE b.blog_id = wb.blog_id AND b.blog_id = bm1.blog_id AND bm1.meta_key = 'name' AND wb.deleted = 0 AND wb.spam = 0 AND wb.mature = 0 AND wb.archived = '0' AND b.user_id = %d ORDER BY b.blog_id", $user_id ) );
+
+		$total_blog_count = BP_Blogs_Blog::total_blog_count_for_user( $user_id );
+
+		$user_blogs = array();
+		foreach ( (array) $blogs as $blog ) {
+			$user_blogs[$blog->blog_id] = new stdClass;
+			$user_blogs[$blog->blog_id]->id = $blog->id;
+			$user_blogs[$blog->blog_id]->blog_id = $blog->blog_id;
+			$user_blogs[$blog->blog_id]->siteurl = ( is_ssl() ) ? 'https://' . $blog->domain . $blog->path : 'http://' . $blog->domain . $blog->path;
+			$user_blogs[$blog->blog_id]->name = $blog->name;
+		}
+
+		return array( 'blogs' => $user_blogs, 'count' => $total_blog_count );
+	}
+
+	/**
+	 * Get IDs of all of a user's blogs, as tracked by BuddyPress.
+	 *
+	 * This method always includes hidden blogs.
+	 *
+	 * @param int $user_id Optional. ID of the user whose blogs are being
+	 *        queried. Defaults to logged-in user.
+	 * @return int The number of blogs associated with the user.
+	 */
+	public static function get_blog_ids_for_user( $user_id = 0 ) {
+		global $bp, $wpdb;
+
+		if ( !$user_id )
+			$user_id = bp_displayed_user_id();
+
+		return $wpdb->get_col( $wpdb->prepare( "SELECT blog_id FROM {$bp->blogs->table_name} WHERE user_id = %d", $user_id ) );
+	}
+
+	/**
+	 * Check whether a blog has been recorded by BuddyPress.
+	 *
+	 * @param int $blog_id ID of the blog being queried.
+	 * @return int|null The ID of the first located entry in the BP table
+	 *         on success, otherwise null.
+	 */
+	public static function is_recorded( $blog_id ) {
+		global $bp, $wpdb;
+
+		return $wpdb->get_var( $wpdb->prepare( "SELECT id FROM {$bp->blogs->table_name} WHERE blog_id = %d", $blog_id ) );
+	}
+
+	/**
+	 * Return a count of associated blogs for a given user.
+	 *
+	 * Includes hidden blogs when the logged-in user is the same as the
+	 * $user_id parameter, or when the logged-in user has the bp_moderate
+	 * cap.
+	 *
+	 * @param int $user_id Optional. ID of the user whose blogs are being
+	 *        queried. Defaults to logged-in user.
+	 * @return int Blog count for the user.
+	 */
+	public static function total_blog_count_for_user( $user_id = null ) {
+		global $bp, $wpdb;
+
+		if ( !$user_id )
+			$user_id = bp_displayed_user_id();
+
+		// If the user is logged in return the blog count including their hidden blogs.
+		if ( ( is_user_logged_in() && $user_id == bp_loggedin_user_id() ) || bp_current_user_can( 'bp_moderate' ) ) {
+			return $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(DISTINCT b.blog_id) FROM {$bp->blogs->table_name} b LEFT JOIN {$wpdb->base_prefix}blogs wb ON b.blog_id = wb.blog_id WHERE wb.deleted = 0 AND wb.spam = 0 AND wb.mature = 0 AND wb.archived = '0' AND user_id = %d", $user_id ) );
+		} else {
+			return $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(DISTINCT b.blog_id) FROM {$bp->blogs->table_name} b LEFT JOIN {$wpdb->base_prefix}blogs wb ON b.blog_id = wb.blog_id WHERE wb.public = 1 AND wb.deleted = 0 AND wb.spam = 0 AND wb.mature = 0 AND wb.archived = '0' AND user_id = %d", $user_id ) );
+		}
+	}
+
+	/**
+	 * Return a list of blogs matching a search term.
+	 *
+	 * Matches against blog names and descriptions, as stored in the BP
+	 * blogmeta table.
+	 *
+	 * @param string $filter The search term.
+	 * @param int $limit Optional. The maximum number of items to return.
+	 *        Default: null (no limit).
+	 * @param int $page Optional. The page of results to return. Default:
+	 *        null (no limit).
+	 * @return array Multidimensional results array, structured as follows:
+	 *           'blogs' - Array of located blog objects
+	 *           'total' - A count of the total blogs matching the query.
+	 */
+	public static function search_blogs( $filter, $limit = null, $page = null ) {
+		global $wpdb, $bp;
+
+		$filter = esc_sql( like_escape( $filter ) );
+
+		$hidden_sql = '';
+		if ( !bp_current_user_can( 'bp_moderate' ) )
+			$hidden_sql = "AND wb.public = 1";
+
+		if ( $limit && $page ) {
+			$pag_sql = $wpdb->prepare( " LIMIT %d, %d", intval( ( $page - 1 ) * $limit), intval( $limit ) );
+		}
+
+		$paged_blogs = $wpdb->get_results( "SELECT DISTINCT bm.blog_id FROM {$bp->blogs->table_name_blogmeta} bm LEFT JOIN {$wpdb->base_prefix}blogs wb ON bm.blog_id = wb.blog_id WHERE ( ( bm.meta_key = 'name' OR bm.meta_key = 'description' ) AND bm.meta_value LIKE '%%$filter%%' ) {$hidden_sql} AND wb.mature = 0 AND wb.spam = 0 AND wb.archived = '0' AND wb.deleted = 0 ORDER BY meta_value ASC{$pag_sql}" );
+		$total_blogs = $wpdb->get_var( "SELECT COUNT(DISTINCT bm.blog_id) FROM {$bp->blogs->table_name_blogmeta} bm LEFT JOIN {$wpdb->base_prefix}blogs wb ON bm.blog_id = wb.blog_id WHERE ( ( bm.meta_key = 'name' OR bm.meta_key = 'description' ) AND bm.meta_value LIKE '%%$filter%%' ) {$hidden_sql} AND wb.mature = 0 AND wb.spam = 0 AND wb.archived = '0' AND wb.deleted = 0 ORDER BY meta_value ASC" );
+
+		return array( 'blogs' => $paged_blogs, 'total' => $total_blogs );
+	}
+
+	/**
+	 * Retrieve a list of all blogs.
+	 *
+	 * Query will include hidden blogs if the logged-in user has the
+	 * 'bp_moderate' cap.
+	 *
+	 * @param int $limit Optional. The maximum number of items to return.
+	 *        Default: null (no limit).
+	 * @param int $page Optional. The page of results to return. Default:
+	 *        null (no limit).
+	 * @return array Multidimensional results array, structured as follows:
+	 *           'blogs' - Array of located blog objects
+	 *           'total' - A count of the total blogs.
+	 */
+	public static function get_all( $limit = null, $page = null ) {
+		global $bp, $wpdb;
+
+		$hidden_sql = !bp_current_user_can( 'bp_moderate' ) ? "AND wb.public = 1" : '';
+		$pag_sql = ( $limit && $page ) ? $wpdb->prepare( " LIMIT %d, %d", intval( ( $page - 1 ) * $limit), intval( $limit ) ) : '';
+
+		$paged_blogs = $wpdb->get_results( "SELECT DISTINCT b.blog_id FROM {$bp->blogs->table_name} b LEFT JOIN {$wpdb->base_prefix}blogs wb ON b.blog_id = wb.blog_id WHERE wb.mature = 0 AND wb.spam = 0 AND wb.archived = '0' AND wb.deleted = 0 {$hidden_sql} {$pag_sql}" );
+		$total_blogs = $wpdb->get_var( "SELECT COUNT(DISTINCT b.blog_id) FROM {$bp->blogs->table_name} b LEFT JOIN {$wpdb->base_prefix}blogs wb ON b.blog_id = wb.blog_id WHERE wb.mature = 0 AND wb.spam = 0 AND wb.archived = '0' AND wb.deleted = 0 {$hidden_sql}" );
+
+		return array( 'blogs' => $paged_blogs, 'total' => $total_blogs );
+	}
+
+	/**
+	 * Retrieve a list of blogs whose names start with a given letter.
+	 *
+	 * Query will include hidden blogs if the logged-in user has the
+	 * 'bp_moderate' cap.
+	 *
+	 * @param string $letter. The letter you're looking for.
+	 * @param int $limit Optional. The maximum number of items to return.
+	 *        Default: null (no limit).
+	 * @param int $page Optional. The page of results to return. Default:
+	 *        null (no limit).
+	 * @return array Multidimensional results array, structured as follows:
+	 *           'blogs' - Array of located blog objects.
+	 *           'total' - A count of the total blogs matching the query.
+	 */
+	public static function get_by_letter( $letter, $limit = null, $page = null ) {
+		global $bp, $wpdb;
+
+		$letter = esc_sql( like_escape( $letter ) );
+
+		$hidden_sql = '';
+		if ( !bp_current_user_can( 'bp_moderate' ) )
+			$hidden_sql = "AND wb.public = 1";
+
+		if ( $limit && $page )
+			$pag_sql = $wpdb->prepare( " LIMIT %d, %d", intval( ( $page - 1 ) * $limit), intval( $limit ) );
+
+		$paged_blogs = $wpdb->get_results( "SELECT DISTINCT bm.blog_id FROM {$bp->blogs->table_name_blogmeta} bm LEFT JOIN {$wpdb->base_prefix}blogs wb ON bm.blog_id = wb.blog_id WHERE bm.meta_key = 'name' AND bm.meta_value LIKE '$letter%%' {$hidden_sql} AND wb.mature = 0 AND wb.spam = 0 AND wb.archived = '0' AND wb.deleted = 0 ORDER BY bm.meta_value ASC{$pag_sql}" );
+		$total_blogs = $wpdb->get_var( "SELECT COUNT(DISTINCT bm.blog_id) FROM {$bp->blogs->table_name_blogmeta} bm LEFT JOIN {$wpdb->base_prefix}blogs wb ON bm.blog_id = wb.blog_id WHERE bm.meta_key = 'name' AND bm.meta_value LIKE '$letter%%' {$hidden_sql} AND wb.mature = 0 AND wb.spam = 0 AND wb.archived = '0' AND wb.deleted = 0 ORDER BY bm.meta_value ASC" );
+
+		return array( 'blogs' => $paged_blogs, 'total' => $total_blogs );
+	}
+
+	/**
+	 * Fetch blog data not caught in the main query and append it to results array.
+	 *
+	 * Gets the following information, which is either unavailable at the
+	 * time of the original query, or is more efficient to look up in one
+	 * fell swoop:
+	 *   - The latest post for each blog, include Featured Image data
+	 *   - The blog description
+	 *
+	 * @param array $paged_blogs Array of results from the original query.
+	 * @param array $blog_ids Array of IDs returned from the original query.
+	 * @param string|bool $type Not currently used. Default: false.
+	 * @return array $paged_blogs The located blogs array, with the extras added.
+	 */
+	public static function get_blog_extras( &$paged_blogs, &$blog_ids, $type = false ) {
+		global $bp, $wpdb;
+
+		if ( empty( $blog_ids ) )
+			return $paged_blogs;
+
+		$blog_ids = implode( ',', wp_parse_id_list( $blog_ids ) );
+
+		for ( $i = 0, $count = count( $paged_blogs ); $i < $count; ++$i ) {
+			$blog_prefix = $wpdb->get_blog_prefix( $paged_blogs[$i]->blog_id );
+			$paged_blogs[$i]->latest_post = $wpdb->get_row( "SELECT ID, post_content, post_title, post_excerpt, guid FROM {$blog_prefix}posts WHERE post_status = 'publish' AND post_type = 'post' AND id != 1 ORDER BY id DESC LIMIT 1" );
+			$images = array();
+
+			// Add URLs to any Featured Image this post might have
+			if ( ! empty( $paged_blogs[$i]->latest_post ) && has_post_thumbnail( $paged_blogs[$i]->latest_post->ID ) ) {
+
+				// Grab 4 sizes of the image. Thumbnail.
+				$image = wp_get_attachment_image_src( get_post_thumbnail_id( $paged_blogs[$i]->latest_post->ID ), 'thumbnail', false );
+				if ( ! empty( $image ) )
+					$images['thumbnail'] = $image[0];
+
+				// Medium
+				$image = wp_get_attachment_image_src( get_post_thumbnail_id( $paged_blogs[$i]->latest_post->ID ), 'medium', false );
+				if ( ! empty( $image ) )
+					$images['medium'] = $image[0];
+
+				// Large
+				$image = wp_get_attachment_image_src( get_post_thumbnail_id( $paged_blogs[$i]->latest_post->ID ), 'large', false );
+				if ( ! empty( $image ) )
+					$images['large'] = $image[0];
+
+				// Post thumbnail
+				$image = wp_get_attachment_image_src( get_post_thumbnail_id( $paged_blogs[$i]->latest_post->ID ), 'post-thumbnail', false );
+				if ( ! empty( $image ) )
+					$images['post-thumbnail'] = $image[0];
+
+				// Add the images to the latest_post object
+				$paged_blogs[$i]->latest_post->images = $images;
+			}
+		}
+
+		/* Fetch the blog description for each blog (as it may be empty we can't fetch it in the main query). */
+		$blog_descs = $wpdb->get_results( "SELECT blog_id, meta_value as description FROM {$bp->blogs->table_name_blogmeta} WHERE meta_key = 'description' AND blog_id IN ( {$blog_ids} )" );
+
+		for ( $i = 0, $count = count( $paged_blogs ); $i < $count; ++$i ) {
+			foreach ( (array) $blog_descs as $desc ) {
+				if ( $desc->blog_id == $paged_blogs[$i]->blog_id )
+					$paged_blogs[$i]->description = $desc->description;
+			}
+		}
+
+		return $paged_blogs;
+	}
+
+	/**
+	 * Check whether a given blog is hidden.
+	 *
+	 * Checks the 'public' column in the wp_blogs table.
+	 *
+	 * @param int $blog_id The ID of the blog being checked.
+	 * @return bool True if hidden (public = 0), false otherwise.
+	 */
+	public static function is_hidden( $blog_id ) {
+		global $wpdb;
+
+		if ( !(int) $wpdb->get_var( $wpdb->prepare( "SELECT DISTINCT public FROM {$wpdb->base_prefix}blogs WHERE blog_id = %d", $blog_id ) ) )
+			return true;
+
+		return false;
+	}
+}
Index: /tags/1.9/bp-blogs/bp-blogs-filters.php
===================================================================
--- /tags/1.9/bp-blogs/bp-blogs-filters.php	(revision 7684)
+++ /tags/1.9/bp-blogs/bp-blogs-filters.php	(revision 7684)
@@ -0,0 +1,38 @@
+<?php
+
+/**
+ * Filters related to the Blogs component.
+ *
+ * @package BuddyPress
+ * @subpackage Blogs
+ * @since BuddyPress (1.6.0)
+ */
+
+/** Display Filters **********************************************************/
+
+add_filter( 'bp_get_blog_latest_post_title', 'wptexturize'   );
+add_filter( 'bp_get_blog_latest_post_title', 'convert_chars' );
+add_filter( 'bp_get_blog_latest_post_title', 'trim'          );
+
+add_filter( 'bp_blog_latest_post_content', 'wptexturize'        );
+add_filter( 'bp_blog_latest_post_content', 'convert_smilies'    );
+add_filter( 'bp_blog_latest_post_content', 'convert_chars'      );
+add_filter( 'bp_blog_latest_post_content', 'wpautop'            );
+add_filter( 'bp_blog_latest_post_content', 'shortcode_unautop'  );
+add_filter( 'bp_blog_latest_post_content', 'prepend_attachment' );
+
+/**
+ * Ensure that the 'Create a new site' link at wp-admin/my-sites.php points to the BP blog signup.
+ *
+ * @since BuddyPress (1.6.0)
+ *
+ * @uses apply_filters() Filter 'bp_blogs_creation_location' to alter the
+ *       returned value.
+ *
+ * @param string $url The original URL (points to wp-signup.php by default).
+ * @return string The new URL.
+ */
+function bp_blogs_creation_location( $url ) {
+	return apply_filters( 'bp_blogs_creation_location', trailingslashit( bp_get_root_domain() . '/' . bp_get_blogs_root_slug() . '/create', $url ) );
+}
+add_filter( 'wp_signup_location', 'bp_blogs_creation_location' );
Index: /tags/1.9/bp-blogs/bp-blogs-functions.php
===================================================================
--- /tags/1.9/bp-blogs/bp-blogs-functions.php	(revision 7684)
+++ /tags/1.9/bp-blogs/bp-blogs-functions.php	(revision 7684)
@@ -0,0 +1,972 @@
+<?php
+/**
+ * Blogs component functions.
+ *
+ * @package BuddyPress
+ * @subpackage BlogsFunctions
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/**
+ * Check whether the $bp global lists an activity directory page.
+ *
+ * @since BuddyPress (1.5.0)
+ *
+ * @global BuddyPress $bp The one true BuddyPress instance.
+ *
+ * @return bool True if set, false if empty.
+ */
+function bp_blogs_has_directory() {
+	global $bp;
+
+	return (bool) !empty( $bp->pages->blogs->id );
+}
+
+/**
+ * Retrieve a set of blogs
+ *
+ * @see BP_Blogs_Blog::get() for a description of arguments and return value.
+ *
+ * @param array $args {
+ *     Arguments are listed here with their default values. For more
+ *     information about the arguments, see {@link BP_Blogs_Blog::get()}.
+ *     @type string $type Default: 'active'.
+ *     @type int|bool $user_id Default: false.
+ *     @type string|bool $search_terms Default: false.
+ *     @type int $per_page Default: 20.
+ *     @type int $page Default: 1.
+ * }
+ * @return array See {@link BP_Blogs_Blog::get()}.
+ */
+function bp_blogs_get_blogs( $args = '' ) {
+
+	$defaults = array(
+		'type'         => 'active', // active, alphabetical, newest, or random
+		'user_id'      => false,    // Pass a user_id to limit to only blogs that this user has privilages higher than subscriber on
+		'search_terms' => false,    // Limit to blogs that match these search terms
+		'per_page'     => 20,       // The number of results to return per page
+		'page'         => 1,        // The page to return if limiting per page
+	);
+
+	$params = wp_parse_args( $args, $defaults );
+	extract( $params, EXTR_SKIP );
+
+	return apply_filters( 'bp_blogs_get_blogs', BP_Blogs_Blog::get( $type, $per_page, $page, $user_id, $search_terms ), $params );
+}
+
+/**
+ * Populate the BP blogs table with existing blogs.
+ *
+ * @global object $bp BuddyPress global settings
+ * @global object $wpdb WordPress database object
+ * @uses get_users()
+ * @uses bp_blogs_record_blog()
+ */
+function bp_blogs_record_existing_blogs() {
+	global $bp, $wpdb;
+
+	// Truncate user blogs table and re-record.
+	$wpdb->query( "TRUNCATE TABLE {$bp->blogs->table_name}" );
+
+	if ( is_multisite() ) {
+		$blog_ids = $wpdb->get_col( $wpdb->prepare( "SELECT blog_id FROM {$wpdb->base_prefix}blogs WHERE mature = 0 AND spam = 0 AND deleted = 0 AND site_id = %d", $wpdb->siteid ) );
+	} else {
+		$blog_ids = 1;
+	}
+
+	if ( !empty( $blog_ids ) ) {
+		foreach( (array) $blog_ids as $blog_id ) {
+			$users       = get_users( array( 'blog_id' => $blog_id, 'fields' => 'ID' ) );
+			$subscribers = get_users( array( 'blog_id' => $blog_id, 'fields' => 'ID', 'role' => 'subscriber' ) );
+
+			if ( !empty( $users ) ) {
+				foreach ( (array) $users as $user ) {
+					// Don't record blogs for subscribers
+					if ( !in_array( $user, $subscribers ) ) {
+						bp_blogs_record_blog( $blog_id, $user, true );
+					}
+				}
+			}
+		}
+	}
+}
+
+/**
+ * Check whether a given blog should be recorded in activity streams.
+ *
+ * If $user_id is provided, you can restrict site from being recordable
+ * only to particular users.
+ *
+ * @since BuddyPress (1.7.0)
+ *
+ * @uses apply_filters()
+ *
+ * @param int $blog_id ID of the blog being checked.
+ * @param int $user_id Optional. ID of the user for whom access is being checked.
+ * @return bool True if blog is recordable, otherwise false.
+ */
+function bp_blogs_is_blog_recordable( $blog_id, $user_id = 0 ) {
+
+	$recordable_globally = apply_filters( 'bp_blogs_is_blog_recordable', true, $blog_id );
+
+	if ( !empty( $user_id ) ) {
+		$recordable_for_user = apply_filters( 'bp_blogs_is_blog_recordable_for_user', $recordable_globally, $blog_id, $user_id );
+	} else {
+		$recordable_for_user = $recordable_globally;
+	}
+
+	if ( !empty( $recordable_for_user ) ) {
+		return true;
+	}
+
+	return $recordable_globally;
+}
+
+/**
+ * Check whether a given blog should be tracked by the Blogs component.
+ *
+ * If $user_id is provided, the developer can restrict site from
+ * being trackable only to particular users.
+ *
+ * @since BuddyPress (1.7.0)
+ *
+ * @uses bp_blogs_is_blog_recordable
+ * @uses apply_filters()
+ *
+ * @param int $blog_id ID of the blog being checked.
+ * @param int $user_id Optional. ID of the user for whom access is being checked.
+ * @return bool True if blog is trackable, otherwise false.
+ */
+function bp_blogs_is_blog_trackable( $blog_id, $user_id = 0 ) {
+
+	$trackable_globally = apply_filters( 'bp_blogs_is_blog_trackable', bp_blogs_is_blog_recordable( $blog_id, $user_id ), $blog_id );
+
+	if ( !empty( $user_id ) ) {
+		$trackable_for_user = apply_filters( 'bp_blogs_is_blog_trackable_for_user', $trackable_globally, $blog_id, $user_id );
+	} else {
+		$trackable_for_user = $trackable_globally;
+	}
+
+	if ( !empty( $trackable_for_user ) ) {
+		return $trackable_for_user;
+	}
+
+	return $trackable_globally;
+}
+
+/**
+ * Make BuddyPress aware of a new site so that it can track its activity.
+ *
+ * @since BuddyPress (1.0.0)
+ *
+ * @uses BP_Blogs_Blog
+ *
+ * @param int $blog_id ID of the blog being recorded.
+ * @param int $user_id ID of the user for whom the blog is being recorded.
+ * @param bool $no_activity Optional. Whether to skip recording an activity
+ *        item about this blog creation. Default: false.
+ * @return bool|null Returns false on failure.
+ */
+function bp_blogs_record_blog( $blog_id, $user_id, $no_activity = false ) {
+
+	if ( empty( $user_id ) )
+		$user_id = bp_loggedin_user_id();
+
+	// If blog is not recordable, do not record the activity.
+	if ( !bp_blogs_is_blog_recordable( $blog_id, $user_id ) )
+		return false;
+
+	$name        = get_blog_option( $blog_id, 'blogname' );
+	$description = get_blog_option( $blog_id, 'blogdescription' );
+
+	if ( empty( $name ) )
+		return false;
+
+	$recorded_blog          = new BP_Blogs_Blog;
+	$recorded_blog->user_id = $user_id;
+	$recorded_blog->blog_id = $blog_id;
+	$recorded_blog_id       = $recorded_blog->save();
+	$is_recorded            = !empty( $recorded_blog_id ) ? true : false;
+
+	bp_blogs_update_blogmeta( $recorded_blog->blog_id, 'name', $name );
+	bp_blogs_update_blogmeta( $recorded_blog->blog_id, 'description', $description );
+	bp_blogs_update_blogmeta( $recorded_blog->blog_id, 'last_activity', bp_core_current_time() );
+
+	$is_private = !empty( $_POST['blog_public'] ) && (int) $_POST['blog_public'] ? false : true;
+	$is_private = !apply_filters( 'bp_is_new_blog_public', !$is_private );
+
+	// Only record this activity if the blog is public
+	if ( !$is_private && !$no_activity && bp_blogs_is_blog_trackable( $blog_id, $user_id ) ) {
+
+		// Record this in activity streams
+		bp_blogs_record_activity( array(
+			'user_id'      => $recorded_blog->user_id,
+			'action'       => apply_filters( 'bp_blogs_activity_created_blog_action', sprintf( __( '%s created the site %s', 'buddypress'), bp_core_get_userlink( $recorded_blog->user_id ), '<a href="' . get_home_url( $recorded_blog->blog_id ) . '">' . esc_attr( $name ) . '</a>' ), $recorded_blog, $name, $description ),
+			'primary_link' => apply_filters( 'bp_blogs_activity_created_blog_primary_link', get_home_url( $recorded_blog->blog_id ), $recorded_blog->blog_id ),
+			'type'         => 'new_blog',
+			'item_id'      => $recorded_blog->blog_id
+		) );
+	}
+
+	do_action_ref_array( 'bp_blogs_new_blog', array( &$recorded_blog, $is_private, $is_recorded ) );
+}
+add_action( 'wpmu_new_blog', 'bp_blogs_record_blog', 10, 2 );
+
+/**
+ * Update blog name in BuddyPress blogmeta table.
+ *
+ * @global object $wpdb DB Layer.
+ *
+ * @param string $oldvalue Value before save. Passed by do_action() but
+ *        unused here.
+ * @param string $newvalue Value to change meta to.
+ */
+function bp_blogs_update_option_blogname( $oldvalue, $newvalue ) {
+	global $wpdb;
+
+	bp_blogs_update_blogmeta( $wpdb->blogid, 'name', $newvalue );
+}
+add_action( 'update_option_blogname', 'bp_blogs_update_option_blogname', 10, 2 );
+
+/**
+ * Update blog description in BuddyPress blogmeta table
+ *
+ * @global object $wpdb DB Layer.
+ *
+ * @param string $oldvalue Value before save. Passed by do_action() but
+ *        unused here.
+ * @param string $newvalue Value to change meta to.
+ */
+function bp_blogs_update_option_blogdescription( $oldvalue, $newvalue ) {
+	global $wpdb;
+
+	bp_blogs_update_blogmeta( $wpdb->blogid, 'description', $newvalue );
+}
+add_action( 'update_option_blogdescription', 'bp_blogs_update_option_blogdescription', 10, 2 );
+
+/**
+ * Detect a change in post status, and initiate an activity update if necessary.
+ *
+ * Posts get new activity updates when (a) they are being published, and (b)
+ * they have not already been published. This enables proper posting for
+ * regular posts as well as scheduled posts, while preventing post bumping.
+ *
+ * See #4090, #3746, #2546 for background.
+ *
+ * @since BuddyPress (1.9.0)
+ *
+ * @param string $new_status New status for the post.
+ * @param string $old_status Old status for the post.
+ * @param object $post Post data.
+ */
+function bp_blogs_catch_published_post( $new_status, $old_status, $post ) {
+
+	// Only record published posts
+	if ( 'publish' !== $new_status ) {
+		return;
+	}
+
+	// Don't record edits (publish -> publish)
+	if ( 'publish' === $old_status ) {
+		return;
+	}
+
+	return bp_blogs_record_post( $post->ID, $post );
+}
+add_action( 'transition_post_status', 'bp_blogs_catch_published_post', 10, 3 );
+
+/**
+ * Record a new blog post in the BuddyPress activity stream.
+ *
+ * @param int $post_id ID of the post being recorded.
+ * @param object $post The WP post object passed to the 'save_post' action.
+ * @param int $user_id Optional. The user to whom the activity item will be
+ *        associated. Defaults to the post_author.
+ * @return bool|null Returns false on failure.
+ */
+function bp_blogs_record_post( $post_id, $post, $user_id = 0 ) {
+	global $bp, $wpdb;
+
+	$post_id = (int) $post_id;
+	$blog_id = (int) $wpdb->blogid;
+
+	// If blog is not trackable, do not record the activity.
+	if ( ! bp_blogs_is_blog_trackable( $blog_id, $user_id ) )
+		return false;
+
+	if ( !$user_id )
+		$user_id = (int) $post->post_author;
+
+	// Stop infinite loops with WordPress MU Sitewide Tags.
+	// That plugin changed the way its settings were stored at some point. Thus the dual check.
+	if ( !empty( $bp->site_options['sitewide_tags_blog'] ) ) {
+		$st_options = maybe_unserialize( $bp->site_options['sitewide_tags_blog'] );
+		$tags_blog_id = isset( $st_options['tags_blog_id'] ) ? $st_options['tags_blog_id'] : 0;
+	} else {
+		$tags_blog_id = isset( $bp->site_options['tags_blog_id'] ) ? $bp->site_options['tags_blog_id'] : 0;
+	}
+
+	if ( (int) $blog_id == $tags_blog_id && apply_filters( 'bp_blogs_block_sitewide_tags_activity', true ) )
+		return false;
+
+	// Don't record this if it's not a post
+	if ( !in_array( $post->post_type, apply_filters( 'bp_blogs_record_post_post_types', array( 'post' ) ) ) )
+		return false;
+
+	$is_blog_public = apply_filters( 'bp_is_blog_public', (int)get_blog_option( $blog_id, 'blog_public' ) );
+
+	if ( 'publish' == $post->post_status && empty( $post->post_password ) ) {
+		if ( $is_blog_public || !is_multisite() ) {
+
+			// Record this in activity streams
+			$post_permalink = add_query_arg(
+				'p',
+				$post_id,
+				trailingslashit( get_home_url( $blog_id ) )
+			);
+
+			if ( is_multisite() )
+				$activity_action  = sprintf( __( '%1$s wrote a new post, %2$s, on the site %3$s', 'buddypress' ), bp_core_get_userlink( (int) $post->post_author ), '<a href="' . $post_permalink . '">' . $post->post_title . '</a>', '<a href="' . get_blog_option( $blog_id, 'home' ) . '">' . get_blog_option( $blog_id, 'blogname' ) . '</a>' );
+			else
+				$activity_action  = sprintf( __( '%1$s wrote a new post, %2$s', 'buddypress' ), bp_core_get_userlink( (int) $post->post_author ), '<a href="' . $post_permalink . '">' . $post->post_title . '</a>' );
+
+			// Make sure there's not an existing entry for this post (prevent bumping)
+			if ( bp_is_active( 'activity' ) ) {
+				$existing = bp_activity_get( array(
+					'filter' => array(
+						'action'       => 'new_blog_post',
+						'primary_id'   => $blog_id,
+						'secondary_id' => $post_id,
+					)
+				) );
+
+				if ( !empty( $existing['activities'] ) ) {
+					return;
+				}
+			}
+
+			$activity_content = $post->post_content;
+
+			bp_blogs_record_activity( array(
+				'user_id'           => (int) $post->post_author,
+				'action'            => apply_filters( 'bp_blogs_activity_new_post_action',       $activity_action,  $post, $post_permalink ),
+				'content'           => apply_filters( 'bp_blogs_activity_new_post_content',      $activity_content, $post, $post_permalink ),
+				'primary_link'      => apply_filters( 'bp_blogs_activity_new_post_primary_link', $post_permalink,   $post_id               ),
+				'type'              => 'new_blog_post',
+				'item_id'           => $blog_id,
+				'secondary_item_id' => $post_id,
+				'recorded_time'     => $post->post_date_gmt,
+			));
+		}
+
+		// Update the blogs last activity
+		bp_blogs_update_blogmeta( $blog_id, 'last_activity', bp_core_current_time() );
+	} else {
+		bp_blogs_remove_post( $post_id, $blog_id, $user_id );
+	}
+
+	do_action( 'bp_blogs_new_blog_post', $post_id, $post, $user_id );
+}
+
+/**
+ * Record a new blog comment in the BuddyPress activity stream.
+ *
+ * Only posts the item if blog is public and post is not password-protected.
+ *
+ * @param int $comment_id ID of the comment being recorded.
+ * @param bool|string $is_approved Optional. The $is_approved value passed to
+ *        the 'comment_post' action. Default: true.
+ * @return bool|object Returns false on failure, the comment object on success.
+ */
+function bp_blogs_record_comment( $comment_id, $is_approved = true ) {
+	// Get the users comment
+	$recorded_comment = get_comment( $comment_id );
+
+	// Don't record activity if the comment hasn't been approved
+	if ( empty( $is_approved ) )
+		return false;
+
+	// Don't record activity if no email address has been included
+	if ( empty( $recorded_comment->comment_author_email ) )
+		return false;
+
+	// Don't record activity if the comment has already been marked as spam
+	if ( 'spam' === $is_approved )
+		return false;
+
+	// Get the user by the comment author email.
+	$user = get_user_by( 'email', $recorded_comment->comment_author_email );
+
+	// If user isn't registered, don't record activity
+	if ( empty( $user ) )
+		return false;
+
+	// Get the user_id
+	$user_id = (int) $user->ID;
+
+	// Get blog and post data
+	$blog_id = get_current_blog_id();
+
+	// If blog is not trackable, do not record the activity.
+	if ( ! bp_blogs_is_blog_trackable( $blog_id, $user_id ) )
+		return false;
+
+	$recorded_comment->post = get_post( $recorded_comment->comment_post_ID );
+
+	if ( empty( $recorded_comment->post ) || is_wp_error( $recorded_comment->post ) )
+		return false;
+
+	// If this is a password protected post, don't record the comment
+	if ( !empty( $recorded_comment->post->post_password ) )
+		return false;
+
+	// Don't record activity if the comment's associated post isn't a WordPress Post
+	if ( !in_array( $recorded_comment->post->post_type, apply_filters( 'bp_blogs_record_comment_post_types', array( 'post' ) ) ) )
+		return false;
+
+	$is_blog_public = apply_filters( 'bp_is_blog_public', (int)get_blog_option( $blog_id, 'blog_public' ) );
+
+	// If blog is public allow activity to be posted
+	if ( $is_blog_public ) {
+
+		// Get activity related links
+		$post_permalink = get_permalink( $recorded_comment->comment_post_ID );
+		$comment_link   = get_comment_link( $recorded_comment->comment_ID );
+
+		// Prepare to record in activity streams
+		if ( is_multisite() )
+			$activity_action = sprintf( __( '%1$s commented on the post, %2$s, on the site %3$s', 'buddypress' ), bp_core_get_userlink( $user_id ), '<a href="' . $post_permalink . '">' . apply_filters( 'the_title', $recorded_comment->post->post_title ) . '</a>', '<a href="' . get_blog_option( $blog_id, 'home' ) . '">' . get_blog_option( $blog_id, 'blogname' ) . '</a>' );
+		else
+			$activity_action = sprintf( __( '%1$s commented on the post, %2$s', 'buddypress' ), bp_core_get_userlink( $user_id ), '<a href="' . $post_permalink . '">' . apply_filters( 'the_title', $recorded_comment->post->post_title ) . '</a>' );
+
+		$activity_content	= $recorded_comment->comment_content;
+
+		// Record in activity streams
+		bp_blogs_record_activity( array(
+			'user_id'           => $user_id,
+			'action'            => apply_filters_ref_array( 'bp_blogs_activity_new_comment_action',       array( $activity_action,  &$recorded_comment, $comment_link ) ),
+			'content'           => apply_filters_ref_array( 'bp_blogs_activity_new_comment_content',      array( $activity_content, &$recorded_comment, $comment_link ) ),
+			'primary_link'      => apply_filters_ref_array( 'bp_blogs_activity_new_comment_primary_link', array( $comment_link,     &$recorded_comment                ) ),
+			'type'              => 'new_blog_comment',
+			'item_id'           => $blog_id,
+			'secondary_item_id' => $comment_id,
+			'recorded_time'     => $recorded_comment->comment_date_gmt
+		) );
+
+		// Update the blogs last active date
+		bp_blogs_update_blogmeta( $blog_id, 'last_activity', bp_core_current_time() );
+	}
+
+	return $recorded_comment;
+}
+add_action( 'comment_post', 'bp_blogs_record_comment', 10, 2 );
+add_action( 'edit_comment', 'bp_blogs_record_comment', 10    );
+
+/**
+ * Record a user's association with a blog.
+ *
+ * This function is hooked to several WordPress actions where blog roles are
+ * set/changed ('add_user_to_blog', 'profile_update', 'user_register'). It
+ * parses the changes, and records them as necessary in the BP blog tracker.
+ *
+ * BuddyPress does not track blogs for Subscribers.
+ *
+ * @param int $user_id The ID of the user.
+ * @param string|bool $role The WP role being assigned to the user
+ *        ('subscriber', 'contributor', 'author', 'editor', 'administrator', or
+ *        a custom role). Defaults to false.
+ * @param int $blog_id Default: the current blog ID.
+ * @return bool|null False on failure.
+ */
+function bp_blogs_add_user_to_blog( $user_id, $role = false, $blog_id = 0 ) {
+	global $wpdb;
+
+	if ( empty( $blog_id ) ) {
+		$blog_id = isset( $wpdb->blogid ) ? $wpdb->blogid : bp_get_root_blog_id();
+	}
+
+	if ( empty( $role ) ) {
+		$key = $wpdb->get_blog_prefix( $blog_id ). 'capabilities';
+
+		$roles = bp_get_user_meta( $user_id, $key, true );
+
+		if ( is_array( $roles ) )
+			$role = array_search( 1, $roles );
+		else
+			return false;
+	}
+
+	if ( $role != 'subscriber' )
+		bp_blogs_record_blog( $blog_id, $user_id, true );
+}
+add_action( 'add_user_to_blog', 'bp_blogs_add_user_to_blog', 10, 3 );
+add_action( 'profile_update',   'bp_blogs_add_user_to_blog'        );
+add_action( 'user_register',    'bp_blogs_add_user_to_blog'        );
+
+/**
+ * Remove a blog-user pair from BP's blog tracker.
+ *
+ * @param int $user_id ID of the user whose blog is being removed.
+ * @param int $blog_id Optional. ID of the blog being removed. Default: current blog ID.
+ */
+function bp_blogs_remove_user_from_blog( $user_id, $blog_id = 0 ) {
+	global $wpdb;
+
+	if ( empty( $blog_id ) )
+		$blog_id = $wpdb->blogid;
+
+	bp_blogs_remove_blog_for_user( $user_id, $blog_id );
+}
+add_action( 'remove_user_from_blog', 'bp_blogs_remove_user_from_blog', 10, 2 );
+
+/**
+ * Rehook WP's maybe_add_existing_user_to_blog with a later priority
+ *
+ * WordPress catches add-user-to-blog requests at init:10. In some cases, this
+ * can precede BP's Blogs component. This function bumps the priority of the
+ * core function, so that we can be sure that the Blogs component is loaded
+ * first. See http://buddypress.trac.wordpress.org/ticket/3916.
+ *
+ * @since BuddyPress (1.6)
+ * @access private
+ */
+function bp_blogs_maybe_add_user_to_blog() {
+	if ( ! is_multisite() )
+		return;
+
+	remove_action( 'init', 'maybe_add_existing_user_to_blog' );
+	add_action( 'init', 'maybe_add_existing_user_to_blog', 20 );
+}
+add_action( 'init', 'bp_blogs_maybe_add_user_to_blog', 1 );
+
+/**
+ * Remove the "blog created" item from the BP blogs tracker and activity stream.
+ *
+ * @param int $blog_id ID of the blog being removed.
+ */
+function bp_blogs_remove_blog( $blog_id ) {
+	global $bp;
+
+	$blog_id = (int) $blog_id;
+	do_action( 'bp_blogs_before_remove_blog', $blog_id );
+
+	BP_Blogs_Blog::delete_blog_for_all( $blog_id );
+
+	// Delete activity stream item
+	bp_blogs_delete_activity( array( 'item_id' => $blog_id, 'component' => $bp->blogs->id, 'type' => 'new_blog' ) );
+
+	do_action( 'bp_blogs_remove_blog', $blog_id );
+}
+add_action( 'delete_blog', 'bp_blogs_remove_blog' );
+
+/**
+ * Remove a blog from the tracker for a specific user.
+ *
+ * @param int $user_id ID of the user for whom the blog is being removed.
+ * @param int $blog_id ID of the blog being removed.
+ */
+function bp_blogs_remove_blog_for_user( $user_id, $blog_id ) {
+	global $bp;
+
+	$blog_id = (int) $blog_id;
+	$user_id = (int) $user_id;
+
+	do_action( 'bp_blogs_before_remove_blog_for_user', $blog_id, $user_id );
+
+	BP_Blogs_Blog::delete_blog_for_user( $blog_id, $user_id );
+
+	// Delete activity stream item
+	bp_blogs_delete_activity( array(
+		'item_id'   => $blog_id,
+		'component' => $bp->blogs->id,
+		'type'      => 'new_blog'
+	) );
+
+	do_action( 'bp_blogs_remove_blog_for_user', $blog_id, $user_id );
+}
+add_action( 'remove_user_from_blog', 'bp_blogs_remove_blog_for_user', 10, 2 );
+
+/**
+ * Remove a blog post activity item from the activity stream.
+ *
+ * @param int $post_id ID of the post to be removed.
+ * @param int $blog_id Optional. Defaults to current blog ID.
+ * @param int $user_id Optional. Defaults to the logged-in user ID. This param
+ *        is currently unused in the function (but is passed to hooks).
+ */
+function bp_blogs_remove_post( $post_id, $blog_id = 0, $user_id = 0 ) {
+	global $wpdb, $bp;
+
+	if ( empty( $wpdb->blogid ) )
+		return false;
+
+	$post_id = (int) $post_id;
+
+	if ( !$blog_id )
+		$blog_id = (int) $wpdb->blogid;
+
+	if ( !$user_id )
+		$user_id = bp_loggedin_user_id();
+
+	do_action( 'bp_blogs_before_remove_post', $blog_id, $post_id, $user_id );
+
+	// Delete activity stream item
+	bp_blogs_delete_activity( array( 'item_id' => $blog_id, 'secondary_item_id' => $post_id, 'component' => $bp->blogs->id, 'type' => 'new_blog_post' ) );
+
+	do_action( 'bp_blogs_remove_post', $blog_id, $post_id, $user_id );
+}
+add_action( 'delete_post', 'bp_blogs_remove_post' );
+
+/**
+ * Remove a blog comment activity item from the activity stream.
+ *
+ * @param int $comment_id ID of the comment to be removed.
+ */
+function bp_blogs_remove_comment( $comment_id ) {
+	global $wpdb;
+
+	// Delete activity stream item
+	bp_blogs_delete_activity( array( 'item_id' => $wpdb->blogid, 'secondary_item_id' => $comment_id, 'type' => 'new_blog_comment' ) );
+
+	do_action( 'bp_blogs_remove_comment', $wpdb->blogid, $comment_id, bp_loggedin_user_id() );
+}
+add_action( 'delete_comment', 'bp_blogs_remove_comment' );
+
+/**
+ * When a blog comment status transition occurs, update the relevant activity's status.
+ *
+ * @since BuddyPress (1.6.0)
+ *
+ * @global object $bp BuddyPress global settings.
+ *
+ * @param string $new_status New comment status.
+ * @param string $old_status Previous comment status.
+ * @param object $comment Comment data.
+ */
+function bp_blogs_transition_activity_status( $new_status, $old_status, $comment ) {
+	global $bp;
+
+	// Check the Activity component is active
+	if ( ! bp_is_active( 'activity' ) )
+		return;
+
+	/**
+	 * Activity currently doesn't have any concept of a trash, or an unapproved/approved state.
+	 *
+	 * If a blog comment transitions to a "delete" or "hold" status, delete the activity item.
+	 * If a blog comment transitions to trashed, or spammed, mark the activity as spam.
+	 * If a blog comment transitions to approved (and the activity exists), mark the activity as ham.
+	 * Otherwise, record the comment into the activity stream.
+	 */
+
+	// This clause was moved in from bp_blogs_remove_comment() in BuddyPress 1.6. It handles delete/hold.
+	if ( in_array( $new_status, array( 'delete', 'hold' ) ) )
+		return bp_blogs_remove_comment( $comment->comment_ID );
+
+	// These clauses handle trash, spam, and un-spams.
+	elseif ( in_array( $new_status, array( 'trash', 'spam' ) ) )
+		$action = 'spam_activity';
+	elseif ( 'approved' == $new_status )
+		$action = 'ham_activity';
+
+	// Get the activity
+	$activity_id = bp_activity_get_activity_id( array( 'component' => $bp->blogs->id, 'item_id' => get_current_blog_id(), 'secondary_item_id' => $comment->comment_ID, 'type' => 'new_blog_comment', ) );
+
+	// Check activity item exists
+	if ( ! $activity_id ) {
+
+		// If no activity exists, but the comment has been approved, record it into the activity table.
+		if ( 'approved' == $new_status )
+			return bp_blogs_record_comment( $comment->comment_ID, true );
+
+		return;
+	}
+
+	// Create an activity object
+	$activity = new BP_Activity_Activity( $activity_id );
+	if ( empty( $activity->component ) )
+		return;
+
+	// Spam/ham the activity if it's not already in that state
+	if ( 'spam_activity' == $action && ! $activity->is_spam ) {
+		bp_activity_mark_as_spam( $activity );
+	} elseif ( 'ham_activity' == $action) {
+		bp_activity_mark_as_ham( $activity );
+	}
+
+	// Add "new_blog_comment" to the whitelisted activity types, so that the activity's Akismet history is generated
+	$comment_akismet_history = create_function( '$t', '$t[] = "new_blog_comment"; return $t;' );
+	add_filter( 'bp_akismet_get_activity_types', $comment_akismet_history );
+
+	// Save the updated activity
+	$activity->save();
+
+	// Remove the "new_blog_comment" activity type whitelist so we don't break anything
+	remove_filter( 'bp_akismet_get_activity_types', $comment_akismet_history );
+}
+add_action( 'transition_comment_status', 'bp_blogs_transition_activity_status', 10, 3 );
+
+/**
+ * Get the total number of blogs being tracked by BuddyPress.
+ *
+ * @return int $count Total blog count.
+ */
+function bp_blogs_total_blogs() {
+	if ( !$count = wp_cache_get( 'bp_total_blogs', 'bp' ) ) {
+		$blogs = BP_Blogs_Blog::get_all();
+		$count = $blogs['total'];
+		wp_cache_set( 'bp_total_blogs', $count, 'bp' );
+	}
+	return $count;
+}
+
+/**
+ * Get the total number of blogs being tracked by BP for a specific user.
+ *
+ * @param int $user_id ID of the user being queried. Default: on a user page,
+ *        the displayed user. Otherwise, the logged-in user.
+ * @return int $count Total blog count for the user.
+ */
+function bp_blogs_total_blogs_for_user( $user_id = 0 ) {
+
+	if ( empty( $user_id ) )
+		$user_id = ( bp_displayed_user_id() ) ? bp_displayed_user_id() : bp_loggedin_user_id();
+
+	if ( !$count = wp_cache_get( 'bp_total_blogs_for_user_' . $user_id, 'bp' ) ) {
+		$count = BP_Blogs_Blog::total_blog_count_for_user( $user_id );
+		wp_cache_set( 'bp_total_blogs_for_user_' . $user_id, $count, 'bp' );
+	}
+
+	return $count;
+}
+
+/**
+ * Remove the all data related to a given blog from the BP blogs tracker and activity stream.
+ *
+ * @param int $blog_id The ID of the blog to expunge.
+ */
+function bp_blogs_remove_data_for_blog( $blog_id ) {
+	global $bp;
+
+	do_action( 'bp_blogs_before_remove_data_for_blog', $blog_id );
+
+	// If this is regular blog, delete all data for that blog.
+	BP_Blogs_Blog::delete_blog_for_all( $blog_id );
+
+	// Delete activity stream item
+	bp_blogs_delete_activity( array( 'item_id' => $blog_id, 'component' => $bp->blogs->id, 'type' => false ) );
+
+	do_action( 'bp_blogs_remove_data_for_blog', $blog_id );
+}
+add_action( 'delete_blog', 'bp_blogs_remove_data_for_blog', 1 );
+
+/**
+ * Get all of a user's blogs, as tracked by BuddyPress.
+ *
+ * @see BP_Blogs_Blog::get_blogs_for_user() for a description of parameters
+ *      and return values.
+ *
+ * @param int $user_id See {@BP_Blogs_Blog::get_blogs_for_user()}.
+ * @param bool $show_hidden See {@BP_Blogs_Blog::get_blogs_for_user()}.
+ * @return array See {@BP_Blogs_Blog::get_blogs_for_user()}.
+ */
+function bp_blogs_get_blogs_for_user( $user_id, $show_hidden = false ) {
+	return BP_Blogs_Blog::get_blogs_for_user( $user_id, $show_hidden );
+}
+
+/**
+ * Retrieve a list of all blogs.
+ *
+ * @see BP_Blogs_Blog::get_all() for a description of parameters and return values.
+ *
+ * @param int $limit See {@BP_Blogs_Blog::get_all()}.
+ * @param int $page See {@BP_Blogs_Blog::get_all()}.
+ * @return array See {@BP_Blogs_Blog::get_all()}.
+ */
+function bp_blogs_get_all_blogs( $limit = null, $page = null ) {
+	return BP_Blogs_Blog::get_all( $limit, $page );
+}
+
+/**
+ * Retrieve a random list of blogs.
+ *
+ * @see BP_Blogs_Blog::get() for a description of parameters and return values.
+ *
+ * @param int $limit See {@BP_Blogs_Blog::get()}.
+ * @param int $page See {@BP_Blogs_Blog::get()}.
+ * @return array See {@BP_Blogs_Blog::get()}.
+ */
+function bp_blogs_get_random_blogs( $limit = null, $page = null ) {
+	return BP_Blogs_Blog::get( 'random', $limit, $page );
+}
+
+/**
+ * Check whether a given blog is hidden.
+ *
+ * @see BP_Blogs_Blog::is_hidden() for a description of parameters and return values.
+ *
+ * @param int $blog_id See {@BP_Blogs_Blog::is_hidden()}.
+ * @return bool See {@BP_Blogs_Blog::is_hidden()}.
+ */
+function bp_blogs_is_blog_hidden( $blog_id ) {
+	return BP_Blogs_Blog::is_hidden( $blog_id );
+}
+
+/*******************************************************************************
+ * Blog meta functions
+ *
+ * These functions are used to store specific blogmeta in one global table,
+ * rather than in each blog's options table. Significantly speeds up global blog
+ * queries. By default each blog's name, description and last updated time are
+ * stored and synced here.
+ */
+
+/**
+ * Delete a metadta from the DB for a blog.
+ *
+ * @global object $wpdb WordPress database access object.
+ * @global object $bp BuddyPress global settings.
+ *
+ * @param int $blog_id ID of the blog whose metadata is being deleted.
+ * @param string $meta_key Optional. The key of the metadata being deleted. If
+ *        omitted, all BP metadata associated with the blog will be deleted.
+ * @param string $meta_value Optional. If present, the metadata will only be
+ *        deleted if the meta_value matches this parameter.
+ * @return bool True on success, false on failure.
+ */
+function bp_blogs_delete_blogmeta( $blog_id, $meta_key = false, $meta_value = false ) {
+	global $wpdb, $bp;
+
+	if ( !is_numeric( $blog_id ) )
+		return false;
+
+	$meta_key = preg_replace('|[^a-z0-9_]|i', '', $meta_key);
+
+	if ( is_array($meta_value) || is_object($meta_value) )
+		$meta_value = serialize($meta_value);
+
+	$meta_value = trim( $meta_value );
+
+	if ( !$meta_key )
+		$wpdb->query( $wpdb->prepare( "DELETE FROM {$bp->blogs->table_name_blogmeta} WHERE blog_id = %d", $blog_id ) );
+	else if ( $meta_value )
+		$wpdb->query( $wpdb->prepare( "DELETE FROM {$bp->blogs->table_name_blogmeta} WHERE blog_id = %d AND meta_key = %s AND meta_value = %s", $blog_id, $meta_key, $meta_value ) );
+	else
+		$wpdb->query( $wpdb->prepare( "DELETE FROM {$bp->blogs->table_name_blogmeta} WHERE blog_id = %d AND meta_key = %s", $blog_id, $meta_key ) );
+
+	wp_cache_delete( 'bp_blogs_blogmeta_' . $blog_id . '_' . $meta_key, 'bp' );
+
+	return true;
+}
+
+/**
+ * Get metadata for a given blog.
+ *
+ * @since BuddyPress (1.2.0)
+ *
+ * @global object $wpdb WordPress database access object.
+ * @global object $bp BuddyPress global settings.
+ *
+ * @param int $blog_id ID of the blog whose metadata is being requested.
+ * @param string $meta_key Optional. If present, only the metadata matching
+ *        that meta key will be returned. Otherwise, all metadata for the
+ *        blog will be fetched.
+ * @return mixed The meta value(s) being requested.
+ */
+function bp_blogs_get_blogmeta( $blog_id, $meta_key = '') {
+	global $wpdb, $bp;
+
+	$blog_id = (int) $blog_id;
+
+	if ( !$blog_id )
+		return false;
+
+	if ( !empty($meta_key) ) {
+		$meta_key = preg_replace('|[^a-z0-9_]|i', '', $meta_key);
+
+		if ( !$metas = wp_cache_get( 'bp_blogs_blogmeta_' . $blog_id . '_' . $meta_key, 'bp' ) ) {
+			$metas = $wpdb->get_col( $wpdb->prepare( "SELECT meta_value FROM {$bp->blogs->table_name_blogmeta} WHERE blog_id = %d AND meta_key = %s", $blog_id, $meta_key ) );
+			wp_cache_set( 'bp_blogs_blogmeta_' . $blog_id . '_' . $meta_key, $metas, 'bp' );
+		}
+	} else {
+		$metas = $wpdb->get_col( $wpdb->prepare("SELECT meta_value FROM {$bp->blogs->table_name_blogmeta} WHERE blog_id = %d", $blog_id ) );
+	}
+
+	if ( empty($metas) ) {
+		if ( empty($meta_key) )
+			return array();
+		else
+			return '';
+	}
+
+	$metas = array_map('maybe_unserialize', (array) $metas);
+
+	if ( 1 == count($metas) )
+		return $metas[0];
+	else
+		return $metas;
+}
+
+/**
+ * Update a piece of blog meta.
+ *
+ * @global object $wpdb WordPress database access object.
+ * @global object $bp BuddyPress global settings.
+ *
+ * @param int $blog_id ID of the blog whose metadata is being updated.
+ * @param string $meta_key Key of the metadata being updated.
+ * @param mixed $meta_value Value to be set.
+ * @return bool True on success, false on failure.
+ */
+function bp_blogs_update_blogmeta( $blog_id, $meta_key, $meta_value ) {
+	global $wpdb, $bp;
+
+	if ( !is_numeric( $blog_id ) )
+		return false;
+
+	$meta_key = preg_replace( '|[^a-z0-9_]|i', '', $meta_key );
+
+	if ( is_string($meta_value) )
+		$meta_value = stripslashes( esc_sql( $meta_value ) );
+
+	$meta_value = maybe_serialize($meta_value);
+
+	if (empty( $meta_value ) )
+		return bp_blogs_delete_blogmeta( $blog_id, $meta_key );
+
+	$cur = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$bp->blogs->table_name_blogmeta} WHERE blog_id = %d AND meta_key = %s", $blog_id, $meta_key ) );
+
+	if ( !$cur )
+		$wpdb->query( $wpdb->prepare( "INSERT INTO {$bp->blogs->table_name_blogmeta} ( blog_id, meta_key, meta_value ) VALUES ( %d, %s, %s )", $blog_id, $meta_key, $meta_value ) );
+	else if ( $cur->meta_value != $meta_value )
+		$wpdb->query( $wpdb->prepare( "UPDATE {$bp->blogs->table_name_blogmeta} SET meta_value = %s WHERE blog_id = %d AND meta_key = %s", $meta_value, $blog_id, $meta_key ) );
+	else
+		return false;
+
+	wp_cache_set( 'bp_blogs_blogmeta_' . $blog_id . '_' . $meta_key, $meta_value, 'bp' );
+
+	return true;
+}
+
+/**
+ * Remove all blog associations for a given user.
+ *
+ * @param int $user_id ID whose blog data should be removed.
+ * @return bool|null Returns false on failure.
+ */
+function bp_blogs_remove_data( $user_id ) {
+	if ( !is_multisite() )
+		return false;
+
+	do_action( 'bp_blogs_before_remove_data', $user_id );
+
+	// If this is regular blog, delete all data for that blog.
+	BP_Blogs_Blog::delete_blogs_for_user( $user_id );
+
+	do_action( 'bp_blogs_remove_data', $user_id );
+}
+add_action( 'wpmu_delete_user',  'bp_blogs_remove_data' );
+add_action( 'delete_user',       'bp_blogs_remove_data' );
+add_action( 'bp_make_spam_user', 'bp_blogs_remove_data' );
Index: /tags/1.9/bp-blogs/bp-blogs-loader.php
===================================================================
--- /tags/1.9/bp-blogs/bp-blogs-loader.php	(revision 7684)
+++ /tags/1.9/bp-blogs/bp-blogs-loader.php	(revision 7684)
@@ -0,0 +1,247 @@
+<?php
+
+/**
+ * BuddyPress Blogs Streams Loader
+ *
+ * An blogs stream component, for users, groups, and blog tracking.
+ *
+ * @package BuddyPress
+ * @subpackage Blogs Core
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+class BP_Blogs_Component extends BP_Component {
+
+	/**
+	 * Start the blogs component creation process.
+	 *
+	 * @since BuddyPress (1.5.0)
+	 */
+	function __construct() {
+		parent::start(
+			'blogs',
+			__( 'Site Tracking', 'buddypress' ),
+			BP_PLUGIN_DIR,
+			array(
+				'adminbar_myaccount_order' => 30
+			)
+		);
+	}
+
+	/**
+	 * Set up global settings for the blogs component.
+	 *
+	 * The BP_BLOGS_SLUG constant is deprecated, and only used here for
+	 * backwards compatibility.
+	 *
+	 * @since BuddyPress (1.5.0)
+	 *
+	 * @see BP_Component::setup_globals() for description of parameters.
+	 *
+	 * @param array $args See {@link BP_Component::setup_globals()}.
+	 */
+	public function setup_globals( $args = array() ) {
+		$bp = buddypress();
+
+		if ( !defined( 'BP_BLOGS_SLUG' ) )
+			define ( 'BP_BLOGS_SLUG', $this->id );
+
+		// Global tables for messaging component
+		$global_tables = array(
+			'table_name'          => $bp->table_prefix . 'bp_user_blogs',
+			'table_name_blogmeta' => $bp->table_prefix . 'bp_user_blogs_blogmeta',
+		);
+
+		// All globals for messaging component.
+		// Note that global_tables is included in this array.
+		$args = array(
+			'slug'                  => BP_BLOGS_SLUG,
+			'root_slug'             => isset( $bp->pages->blogs->slug ) ? $bp->pages->blogs->slug : BP_BLOGS_SLUG,
+			'has_directory'         => is_multisite(), // Non-multisite installs don't need a top-level Sites directory, since there's only one site
+			'notification_callback' => 'bp_blogs_format_notifications',
+			'search_string'         => __( 'Search sites...', 'buddypress' ),
+			'autocomplete_all'      => defined( 'BP_MESSAGES_AUTOCOMPLETE_ALL' ),
+			'global_tables'         => $global_tables,
+		);
+
+		// Setup the globals
+		parent::setup_globals( $args );
+	}
+
+	/**
+	 * Include bp-blogs files.
+	 *
+	 * @see BP_Component::includes() for description of parameters.
+	 *
+	 * @param array $includes See {@link BP_Component::includes()}.
+	 */
+	public function includes( $includes = array() ) {
+		// Files to include
+		$includes = array(
+			'cache',
+			'actions',
+			'screens',
+			'classes',
+			'template',
+			'filters',
+			'activity',
+			'functions',
+			'buddybar'
+		);
+
+		if ( is_multisite() )
+			$includes[] = 'widgets';
+
+		// Include the files
+		parent::includes( $includes );
+	}
+
+	/**
+	 * Set up component navigation for bp-blogs.
+	 *
+	 * @see BP_Component::setup_nav() for a description of arguments.
+	 *
+	 * @param array $main_nav Optional. See BP_Component::setup_nav() for
+	 *        description.
+	 * @param array $sub_nav Optional. See BP_Component::setup_nav() for
+	 *        description.
+	 */
+	public function setup_nav( $main_nav = array(), $sub_nav = array() ) {
+		$bp = buddypress();
+
+		/**
+		 * Blog/post/comment menus should not appear on single WordPress setups.
+		 * Although comments and posts made by users will still show on their
+		 * activity stream.
+		 */
+		if ( !is_multisite() )
+			return false;
+
+		// Add 'Sites' to the main navigation
+		$main_nav =  array(
+			'name'                => sprintf( __( 'Sites <span>%d</span>', 'buddypress' ), bp_blogs_total_blogs_for_user() ),
+			'slug'                => $this->slug,
+			'position'            => 30,
+			'screen_function'     => 'bp_blogs_screen_my_blogs',
+			'default_subnav_slug' => 'my-sites',
+			'item_css_id'         => $this->id
+		);
+
+		// Determine user to use
+		if ( bp_displayed_user_domain() ) {
+			$user_domain = bp_displayed_user_domain();
+		} elseif ( bp_loggedin_user_domain() ) {
+			$user_domain = bp_loggedin_user_domain();
+		} else {
+			return;
+		}
+
+		$parent_url = trailingslashit( $user_domain . bp_get_blogs_slug() );
+
+		$sub_nav[] = array(
+			'name'            => __( 'My Sites', 'buddypress' ),
+			'slug'            => 'my-sites',
+			'parent_url'      => $parent_url,
+			'parent_slug'     => $bp->blogs->slug,
+			'screen_function' => 'bp_blogs_screen_my_blogs',
+			'position'        => 10
+		);
+
+		// Setup navigation
+		parent::setup_nav( $main_nav, $sub_nav );
+	}
+
+	/**
+	 * Set up bp-blogs integration with the WordPress admin bar.
+	 *
+	 * @since BuddyPress (1.5.0)
+	 *
+	 * @see BP_Component::setup_admin_bar() for a description of arguments.
+	 *
+	 * @param array $wp_admin_nav See BP_Component::setup_admin_bar()
+	 *        for description.
+	 */
+	public function setup_admin_bar( $wp_admin_nav = array() ) {
+		$bp = buddypress();
+
+		/**
+		 * Site/post/comment menus should not appear on single WordPress setups.
+		 * Although comments and posts made by users will still show on their
+		 * activity stream.
+		 */
+		if ( !is_multisite() )
+			return false;
+
+		// Menus for logged in user
+		if ( is_user_logged_in() ) {
+
+			$blogs_link = trailingslashit( bp_loggedin_user_domain() . $this->slug );
+
+			// Add the "Sites" sub menu
+			$wp_admin_nav[] = array(
+				'parent' => $bp->my_account_menu_id,
+				'id'     => 'my-account-' . $this->id,
+				'title'  => __( 'Sites', 'buddypress' ),
+				'href'   => trailingslashit( $blogs_link )
+			);
+
+			// My Sites
+			$wp_admin_nav[] = array(
+				'parent' => 'my-account-' . $this->id,
+				'id'     => 'my-account-' . $this->id . '-my-sites',
+				'title'  => __( 'My Sites', 'buddypress' ),
+				'href'   => trailingslashit( $blogs_link )
+			);
+
+			// Create a Site
+			if ( bp_blog_signup_enabled() ) {
+				$wp_admin_nav[] = array(
+					'parent' => 'my-account-' . $this->id,
+					'id'     => 'my-account-' . $this->id . '-create',
+					'title'  => __( 'Create a Site', 'buddypress' ),
+					'href'   => trailingslashit( bp_get_blogs_directory_permalink() . 'create' )
+				);
+			}
+		}
+
+		parent::setup_admin_bar( $wp_admin_nav );
+	}
+
+	/**
+	 * Set up the title for pages and <title>
+	 */
+	function setup_title() {
+		$bp = buddypress();
+
+		// Set up the component options navigation for Site
+		if ( bp_is_blogs_component() ) {
+			if ( bp_is_my_profile() ) {
+				if ( bp_is_active( 'xprofile' ) ) {
+					$bp->bp_options_title = __( 'My Sites', 'buddypress' );
+				}
+
+			// If we are not viewing the logged in user, set up the current
+			// users avatar and name
+			} else {
+				$bp->bp_options_avatar = bp_core_fetch_avatar( array(
+					'item_id' => bp_displayed_user_id(),
+					'type'    => 'thumb',
+					'alt'     => sprintf( __( 'Profile picture of %s', 'buddypress' ), bp_get_displayed_user_fullname() )
+				) );
+				$bp->bp_options_title = bp_get_displayed_user_fullname();
+			}
+		}
+
+		parent::setup_title();
+	}
+}
+
+/**
+ * Set up the bp-blogs component.
+ */
+function bp_setup_blogs() {
+	buddypress()->blogs = new BP_Blogs_Component();
+}
+add_action( 'bp_setup_components', 'bp_setup_blogs', 6 );
Index: /tags/1.9/bp-blogs/bp-blogs-screens.php
===================================================================
--- /tags/1.9/bp-blogs/bp-blogs-screens.php	(revision 7684)
+++ /tags/1.9/bp-blogs/bp-blogs-screens.php	(revision 7684)
@@ -0,0 +1,236 @@
+<?php
+
+/**
+ * BuddyPress Blogs Screens
+ *
+ * @package BuddyPress
+ * @subpackage BlogsScreens
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/**
+ * Load the "My Blogs" screen.
+ */
+function bp_blogs_screen_my_blogs() {
+	if ( !is_multisite() )
+		return false;
+
+	do_action( 'bp_blogs_screen_my_blogs' );
+
+	bp_core_load_template( apply_filters( 'bp_blogs_template_my_blogs', 'members/single/home' ) );
+}
+
+/**
+ * Load the "Create a Blog" screen.
+ */
+function bp_blogs_screen_create_a_blog() {
+
+	if ( !is_multisite() ||  !bp_is_blogs_component() || !bp_is_current_action( 'create' ) )
+		return false;
+
+	if ( !is_user_logged_in() || !bp_blog_signup_enabled() )
+		return false;
+
+	do_action( 'bp_blogs_screen_create_a_blog' );
+
+	bp_core_load_template( apply_filters( 'bp_blogs_template_create_a_blog', 'blogs/create' ) );
+}
+add_action( 'bp_screens', 'bp_blogs_screen_create_a_blog', 3 );
+
+/**
+ * Load the top-level Blogs directory.
+ */
+function bp_blogs_screen_index() {
+	if ( is_multisite() && bp_is_blogs_component() && !bp_current_action() ) {
+		bp_update_is_directory( true, 'blogs' );
+
+		do_action( 'bp_blogs_screen_index' );
+
+		bp_core_load_template( apply_filters( 'bp_blogs_screen_index', 'blogs/index' ) );
+	}
+}
+add_action( 'bp_screens', 'bp_blogs_screen_index', 2 );
+
+/** Theme Compatability *******************************************************/
+
+/**
+ * The main theme compat class for BuddyPress Blogs
+ *
+ * This class sets up the necessary theme compatability actions to safely output
+ * group template parts to the_title and the_content areas of a theme.
+ *
+ * @since BuddyPress (1.7.0)
+ */
+class BP_Blogs_Theme_Compat {
+
+	/**
+	 * Set up theme compatibility for the Blogs component.
+	 *
+	 * @since BuddyPress (1.7.0)
+	 */
+	public function __construct() {
+		add_action( 'bp_setup_theme_compat', array( $this, 'is_blogs' ) );
+	}
+
+	/**
+	 * Are we looking at something that needs Blogs theme compatability?
+	 *
+	 * @since BuddyPress (1.7.0)
+	 */
+	public function is_blogs() {
+
+		// Bail if not looking at a group
+		if ( ! bp_is_blogs_component() )
+			return;
+
+		// Bail if looking at a users sites
+		if ( bp_is_user() )
+			return;
+
+		// Blog Directory
+		if ( is_multisite() && ! bp_current_action() ) {
+			bp_update_is_directory( true, 'blogs' );
+
+			do_action( 'bp_blogs_screen_index' );
+
+			add_filter( 'bp_get_buddypress_template',                array( $this, 'directory_template_hierarchy' ) );
+			add_action( 'bp_template_include_reset_dummy_post_data', array( $this, 'directory_dummy_post' ) );
+			add_filter( 'bp_replace_the_content',                    array( $this, 'directory_content'    ) );
+
+		// Create blog
+		} elseif ( is_user_logged_in() && bp_blog_signup_enabled() ) {
+			add_filter( 'bp_get_buddypress_template',                array( $this, 'create_template_hierarchy' ) );
+			add_action( 'bp_template_include_reset_dummy_post_data', array( $this, 'create_dummy_post' ) );
+			add_filter( 'bp_replace_the_content',                    array( $this, 'create_content'    ) );
+		}
+	}
+
+	/** Directory *************************************************************/
+
+	/**
+	 * Add template hierarchy to theme compat for the blog directory page.
+	 *
+	 * This is to mirror how WordPress has
+	 * {@link https://codex.wordpress.org/Template_Hierarchy template hierarchy}.
+	 *
+	 * @since BuddyPress (1.8.0)
+	 *
+	 * @param string $templates The templates from
+	 *        bp_get_theme_compat_templates().
+	 * @return array $templates Array of custom templates to look for.
+	 */
+	public function directory_template_hierarchy( $templates ) {
+		// Setup our templates based on priority
+		$new_templates = apply_filters( 'bp_template_hierarchy_blogs_create', array(
+			'blogs/index-directory.php'
+		) );
+
+		// Merge new templates with existing stack
+		// @see bp_get_theme_compat_templates()
+		$templates = array_merge( (array) $new_templates, $templates );
+
+		return $templates;
+	}
+
+	/**
+	 * Update the global $post with directory data.
+	 *
+	 * @since BuddyPress (1.7.0)
+	 */
+	public function directory_dummy_post() {
+
+		// Title based on ability to create blogs
+		if ( is_user_logged_in() && bp_blog_signup_enabled() ) {
+			$title = __( 'Sites', 'buddypress' ) . '&nbsp;<a class="button" href="' . trailingslashit( bp_get_root_domain() . '/' . bp_get_blogs_root_slug() . '/create' ) . '">' . __( 'Create a Sites', 'buddypress' ) . '</a>';
+		} else {
+			$title = __( 'Sites', 'buddypress' );
+		}
+
+		bp_theme_compat_reset_post( array(
+			'ID'             => 0,
+			'post_title'     => $title,
+			'post_author'    => 0,
+			'post_date'      => 0,
+			'post_content'   => '',
+			'post_type'      => 'bp_blogs',
+			'post_status'    => 'publish',
+			'is_archive'     => true,
+			'comment_status' => 'closed'
+		) );
+	}
+
+	/**
+	 * Filter the_content with the groups index template part.
+	 *
+	 * @since BuddyPress (1.7.0)
+	 */
+	public function directory_content() {
+		return bp_buffer_template_part( 'blogs/index', null, false );
+	}
+
+	/** Create ****************************************************************/
+
+	/**
+	 * Add custom template hierarchy to theme compat for the blog create page.
+	 *
+	 * This is to mirror how WordPress has
+	 * {@link https://codex.wordpress.org/Template_Hierarchy template hierarchy}.
+	 *
+	 * @since BuddyPress (1.8.0)
+	 *
+	 * @param string $templates The templates from
+	 *        bp_get_theme_compat_templates().
+	 * @return array $templates Array of custom templates to look for.
+	 */
+	public function create_template_hierarchy( $templates ) {
+		// Setup our templates based on priority
+		$new_templates = apply_filters( 'bp_template_hierarchy_blogs_create', array(
+			'blogs/index-create.php'
+		) );
+
+		// Merge new templates with existing stack
+		// @see bp_get_theme_compat_templates()
+		$templates = array_merge( (array) $new_templates, $templates );
+
+		return $templates;
+	}
+
+	/**
+	 * Update the global $post with create screen data.
+	 *
+	 * @since BuddyPress (1.7.0)
+	 */
+	public function create_dummy_post() {
+
+		// Title based on ability to create blogs
+		if ( is_user_logged_in() && bp_blog_signup_enabled() ) {
+			$title = '<a class="button bp-title-button" href="' . trailingslashit( bp_get_root_domain() . '/' . bp_get_blogs_root_slug() ) . '">' . __( 'Sites', 'buddypress' ) . '</a>&nbsp;' . __( 'Create a Site', 'buddypress' );
+		} else {
+			$title = __( 'Sites', 'buddypress' );
+		}
+
+		bp_theme_compat_reset_post( array(
+			'ID'             => 0,
+			'post_title'     => $title,
+			'post_author'    => 0,
+			'post_date'      => 0,
+			'post_content'   => '',
+			'post_type'      => 'bp_group',
+			'post_status'    => 'publish',
+			'is_archive'     => true,
+			'comment_status' => 'closed'
+		) );
+	}
+
+	/**
+	 * Filter the_content with the create screen template part.
+	 *
+	 * @since BuddyPress (1.7.0)
+	 */
+	public function create_content() {
+		return bp_buffer_template_part( 'blogs/create', null, false );
+	}
+}
+new BP_Blogs_Theme_Compat();
Index: /tags/1.9/bp-blogs/bp-blogs-template.php
===================================================================
--- /tags/1.9/bp-blogs/bp-blogs-template.php	(revision 7684)
+++ /tags/1.9/bp-blogs/bp-blogs-template.php	(revision 7684)
@@ -0,0 +1,1188 @@
+<?php
+
+/**
+ * BuddyPress Blogs Template Tags.
+ *
+ * @package BuddyPress
+ * @subpackage BlogsTemplate
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/**
+ * Output the blogs component slug.
+ *
+ * @since BuddyPress (1.5.0)
+ *
+ * @uses bp_get_blogs_slug()
+ */
+function bp_blogs_slug() {
+	echo bp_get_blogs_slug();
+}
+	/**
+	 * Return the blogs component slug.
+	 *
+	 * @since BuddyPress (1.5.0)
+	 *
+	 * @return string The 'blogs' slug.
+	 */
+	function bp_get_blogs_slug() {
+		return apply_filters( 'bp_get_blogs_slug', buddypress()->blogs->slug );
+	}
+
+/**
+ * Output the blogs component root slug.
+ *
+ * @since BuddyPress (1.5.0)
+ *
+ * @uses bp_get_blogs_root_slug()
+ */
+function bp_blogs_root_slug() {
+	echo bp_get_blogs_root_slug();
+}
+	/**
+	 * Return the blogs component root slug.
+	 *
+	 * @since BuddyPress (1.5.0)
+	 *
+	 * @return string The 'blogs' root slug.
+	 */
+	function bp_get_blogs_root_slug() {
+		return apply_filters( 'bp_get_blogs_root_slug', buddypress()->blogs->root_slug );
+	}
+
+/**
+ * Output blog directory permalink.
+ *
+ * @since BuddyPress (1.5.0)
+ *
+ * @uses bp_get_blogs_directory_permalink()
+ */
+function bp_blogs_directory_permalink() {
+	echo bp_get_blogs_directory_permalink();
+}
+	/**
+	 * Return blog directory permalink.
+	 *
+	 * @since BuddyPress (1.5.0)
+	 *
+	 * @uses apply_filters()
+	 * @uses trailingslashit()
+	 * @uses bp_get_root_domain()
+	 * @uses bp_get_blogs_root_slug()
+	 * @return string The URL of the Blogs directory.
+	 */
+	function bp_get_blogs_directory_permalink() {
+		return apply_filters( 'bp_get_blogs_directory_permalink', trailingslashit( bp_get_root_domain() . '/' . bp_get_blogs_root_slug() ) );
+	}
+
+/**
+ * The main blog template loop class.
+ *
+ * Responsible for loading a group of blogs into a loop for display.
+ */
+class BP_Blogs_Template {
+
+	/**
+	 * The loop iterator.
+	 *
+	 * @access public
+	 * @var int
+	 */
+	var $current_blog = -1;
+
+	/**
+	 * The number of blogs returned by the paged query.
+	 *
+	 * @access public
+	 * @var int
+	 */
+	var $blog_count;
+
+	/**
+	 * Array of blogs located by the query..
+	 *
+	 * @access public
+	 * @var array
+	 */
+	var $blogs;
+
+	/**
+	 * The blog object currently being iterated on.
+	 *
+	 * @access public
+	 * @var object
+	 */
+	var $blog;
+
+	/**
+	 * A flag for whether the loop is currently being iterated.
+	 *
+	 * @access public
+	 * @var bool
+	 */
+	var $in_the_loop;
+
+	/**
+	 * The page number being requested.
+	 *
+	 * @access public
+	 * @var public
+	 */
+	var $pag_page;
+
+	/**
+	 * The number of items being requested per page.
+	 *
+	 * @access public
+	 * @var public
+	 */
+	var $pag_num;
+
+	/**
+	 * An HTML string containing pagination links.
+	 *
+	 * @access public
+	 * @var string
+	 */
+	var $pag_links;
+
+	/**
+	 * The total number of blogs matching the query parameters.
+	 *
+	 * @access public
+	 * @var int
+	 */
+	var $total_blog_count;
+
+	/**
+	 * Constructor method.
+	 *
+	 * @see BP_Blogs_Blog::get() for a description of parameters.
+	 *
+	 * @param string $type See {@link BP_Blogs_Blog::get()}.
+	 * @param string $page See {@link BP_Blogs_Blog::get()}.
+	 * @param string $per_page See {@link BP_Blogs_Blog::get()}.
+	 * @param string $max See {@link BP_Blogs_Blog::get()}.
+	 * @param string $user_id See {@link BP_Blogs_Blog::get()}.
+	 * @param string $search_terms See {@link BP_Blogs_Blog::get()}.
+	 * @param string $page_arg The string used as a query parameter in
+	 *        pagination links. Default: 'bpage'.
+	 */
+	function __construct( $type, $page, $per_page, $max, $user_id, $search_terms, $page_arg = 'bpage' ) {
+
+		$this->pag_page = isset( $_REQUEST[$page_arg] ) ? intval( $_REQUEST[$page_arg] ) : $page;
+		$this->pag_num = isset( $_REQUEST['num'] ) ? intval( $_REQUEST['num'] ) : $per_page;
+
+		if ( isset( $_REQUEST['letter'] ) && '' != $_REQUEST['letter'] )
+			$this->blogs = BP_Blogs_Blog::get_by_letter( $_REQUEST['letter'], $this->pag_num, $this->pag_page );
+		else
+			$this->blogs = bp_blogs_get_blogs( array( 'type' => $type, 'per_page' => $this->pag_num, 'page' => $this->pag_page, 'user_id' => $user_id, 'search_terms' => $search_terms ) );
+
+		if ( !$max || $max >= (int) $this->blogs['total'] )
+			$this->total_blog_count = (int) $this->blogs['total'];
+		else
+			$this->total_blog_count = (int) $max;
+
+		$this->blogs = $this->blogs['blogs'];
+
+		if ( $max ) {
+			if ( $max >= count($this->blogs) ) {
+				$this->blog_count = count( $this->blogs );
+			} else {
+				$this->blog_count = (int) $max;
+			}
+		} else {
+			$this->blog_count = count( $this->blogs );
+		}
+
+		if ( (int) $this->total_blog_count && (int) $this->pag_num ) {
+			$this->pag_links = paginate_links( array(
+				'base'      => add_query_arg( $page_arg, '%#%' ),
+				'format'    => '',
+				'total'     => ceil( (int) $this->total_blog_count / (int) $this->pag_num ),
+				'current'   => (int) $this->pag_page,
+				'prev_text' => _x( '&larr;', 'Blog pagination previous text', 'buddypress' ),
+				'next_text' => _x( '&rarr;', 'Blog pagination next text', 'buddypress' ),
+				'mid_size'  => 1
+			) );
+		}
+	}
+
+	/**
+	 * Whether there are blogs available in the loop.
+	 *
+	 * @see bp_has_blogs()
+	 *
+	 * @return bool True if there are items in the loop, otherwise false.
+	 */
+	function has_blogs() {
+		if ( $this->blog_count )
+			return true;
+
+		return false;
+	}
+
+	/**
+	 * Set up the next blog and iterate index.
+	 *
+	 * @return object The next blog to iterate over.
+	 */
+	function next_blog() {
+		$this->current_blog++;
+		$this->blog = $this->blogs[$this->current_blog];
+
+		return $this->blog;
+	}
+
+	/**
+	 * Rewind the blogs and reset blog index.
+	 */
+	function rewind_blogs() {
+		$this->current_blog = -1;
+		if ( $this->blog_count > 0 ) {
+			$this->blog = $this->blogs[0];
+		}
+	}
+
+	/**
+	 * Whether there are blogs left in the loop to iterate over.
+	 *
+	 * This method is used by {@link bp_blogs()} as part of the while loop
+	 * that controls iteration inside the blogs loop, eg:
+	 *     while ( bp_blogs() ) { ...
+	 *
+	 * @see bp_blogs()
+	 *
+	 * @return bool True if there are more blogs to show, otherwise false.
+	 */
+	function blogs() {
+		if ( $this->current_blog + 1 < $this->blog_count ) {
+			return true;
+		} elseif ( $this->current_blog + 1 == $this->blog_count ) {
+			do_action('blog_loop_end');
+			// Do some cleaning up after the loop
+			$this->rewind_blogs();
+		}
+
+		$this->in_the_loop = false;
+		return false;
+	}
+
+	/**
+	 * Set up the current blog inside the loop.
+	 *
+	 * Used by {@link bp_the_blog()} to set up the current blog data while
+	 * looping, so that template tags used during that iteration make
+	 * reference to the current blog.
+	 *
+	 * @see bp_the_blog()
+	 */
+	function the_blog() {
+
+		$this->in_the_loop = true;
+		$this->blog        = $this->next_blog();
+
+		if ( 0 == $this->current_blog ) // loop has just started
+			do_action('blog_loop_start');
+	}
+}
+
+/**
+ * Rewind the blogs and reset blog index.
+ */
+function bp_rewind_blogs() {
+	global $blogs_template;
+
+	$blogs_template->rewind_blogs();
+}
+
+/**
+ * Initialize the blogs loop.
+ *
+ * Based on the $args passed, bp_has_blogs() populates the $blogs_template
+ * global, enabling the use of BuddyPress templates and template functions to
+ * display a list of activity items.
+ *
+ * @global object $blogs_template {@link BP_Blogs_Template}
+ *
+ * @param array $args {
+ *     Arguments for limiting the contents of the blogs loop. Most arguments
+ *     are in the same format as {@link BP_Blogs_Blog::get()}. However, because
+ *     the format of the arguments accepted here differs in a number of ways,
+ *     and because bp_has_blogs() determines some default arguments in a
+ *     dynamic fashion, we list all accepted arguments here as well.
+ *
+ *     Arguments can be passed as an associative array, or as a URL query
+ *     string (eg, 'user_id=4&per_page=3').
+ *
+ *     @type int $page Which page of results to fetch. Using page=1 without
+ *           per_page will result in no pagination. Default: 1.
+ *     @type int|bool $per_page Number of results per page. Default: 20.
+ *     @type string $page_arg The string used as a query parameter in
+ *           pagination links. Default: 'bpage'.
+ *     @type int|bool $max Maximum number of results to return.
+ *           Default: false (unlimited).
+ *     @type string $type The order in which results should be fetched.
+	     'active', 'alphabetical', 'newest', or 'random'.
+ *     @type string $sort 'ASC' or 'DESC'. Default: 'DESC'.
+ *     @type string $search_terms Limit results by a search term. Default: null.
+ *     @type int $user_id The ID of the user whose blogs should be retrieved.
+ *           When viewing a user profile page, 'user_id' defaults to the ID of
+ *           the displayed user. Otherwise the default is false.
+ * }
+ * @return bool Returns true when blogs are found, otherwise false.
+ */
+function bp_has_blogs( $args = '' ) {
+	global $blogs_template;
+
+	/***
+	 * Set the defaults based on the current page. Any of these will be overridden
+	 * if arguments are directly passed into the loop. Custom plugins should always
+	 * pass their parameters directly to the loop.
+	 */
+	$type         = 'active';
+	$user_id      = 0;
+	$search_terms = null;
+
+	// User filtering
+	if ( bp_displayed_user_id() )
+		$user_id = bp_displayed_user_id();
+
+	$defaults = array(
+		'type'         => $type,
+		'page'         => 1,
+		'per_page'     => 20,
+		'max'          => false,
+
+		'page_arg'     => 'bpage',        // See https://buddypress.trac.wordpress.org/ticket/3679
+
+		'user_id'      => $user_id,       // Pass a user_id to limit to only blogs this user has higher than subscriber access to
+		'search_terms' => $search_terms   // Pass search terms to filter on the blog title or description.
+	);
+
+	$r = wp_parse_args( $args, $defaults );
+	extract( $r );
+
+	if ( is_null( $search_terms ) ) {
+		if ( isset( $_REQUEST['s'] ) && !empty( $_REQUEST['s'] ) )
+			$search_terms = $_REQUEST['s'];
+		else
+			$search_terms = false;
+	}
+
+	if ( $max ) {
+		if ( $per_page > $max ) {
+			$per_page = $max;
+		}
+	}
+
+	$blogs_template = new BP_Blogs_Template( $type, $page, $per_page, $max, $user_id, $search_terms, $page_arg );
+	return apply_filters( 'bp_has_blogs', $blogs_template->has_blogs(), $blogs_template );
+}
+
+/**
+ * Determine if there are still blogs left in the loop.
+ *
+ * @global object $blogs_template {@link BP_Blogs_Template}
+ *
+ * @return bool Returns true when blogs are found.
+ */
+function bp_blogs() {
+	global $blogs_template;
+
+	return $blogs_template->blogs();
+}
+
+/**
+ * Get the current blog object in the loop.
+ *
+ * @global object $blogs_template {@link BP_Blogs_Template}
+ *
+ * @return object The current blog within the loop.
+ */
+function bp_the_blog() {
+	global $blogs_template;
+
+	return $blogs_template->the_blog();
+}
+
+/**
+ * Output the blogs pagination count.
+ *
+ * @global object $blogs_template {@link BP_Blogs_Template}
+ */
+function bp_blogs_pagination_count() {
+	global $blogs_template;
+
+	$start_num = intval( ( $blogs_template->pag_page - 1 ) * $blogs_template->pag_num ) + 1;
+	$from_num  = bp_core_number_format( $start_num );
+	$to_num    = bp_core_number_format( ( $start_num + ( $blogs_template->pag_num - 1 ) > $blogs_template->total_blog_count ) ? $blogs_template->total_blog_count : $start_num + ( $blogs_template->pag_num - 1 ) );
+	$total     = bp_core_number_format( $blogs_template->total_blog_count );
+
+	echo sprintf( _n( 'Viewing site %1$s to %2$s (of %3$s site)', 'Viewing site %1$s to %2$s (of %3$s sites)', $total, 'buddypress' ), $from_num, $to_num, $total );
+}
+
+/**
+ * Output the blogs pagination links.
+ */
+function bp_blogs_pagination_links() {
+	echo bp_get_blogs_pagination_links();
+}
+	/**
+	 * Return the blogs pagination links.
+	 *
+	 * @global object $blogs_template {@link BP_Blogs_Template}
+	 *
+	 * @return string HTML pagination links.
+	 */
+	function bp_get_blogs_pagination_links() {
+		global $blogs_template;
+
+		return apply_filters( 'bp_get_blogs_pagination_links', $blogs_template->pag_links );
+	}
+
+/**
+ * Output a blog's avatar.
+ *
+ * @see bp_get_blog_avatar() for description of arguments.
+ *
+ * @param array $args See {@link bp_get_blog_avatar()}.
+ */
+function bp_blog_avatar( $args = '' ) {
+	echo bp_get_blog_avatar( $args );
+}
+	/**
+	 * Get a blog's avatar.
+	 *
+	 * At the moment, blog avatars are simply the user avatars of the blog
+	 * admin. Filter 'bp_get_blog_avatar_' . $blog_id to customize.
+	 *
+	 * @see bp_core_fetch_avatar() For a description of arguments and
+	 *      return values.
+	 *
+	 * @param array $args  {
+	 *     Arguments are listed here with an explanation of their defaults.
+	 *     For more information about the arguments, see
+	 *     {@link bp_core_fetch_avatar()}.
+	 *     @type string $alt Default: 'Profile picture of site author
+	 *           [user name]'.
+	 *     @type string $class Default: 'avatar'.
+	 *     @type string $type Default: 'full'.
+	 *     @type int|bool $width Default: false.
+	 *     @type int|bool $height Default: false.
+	 *     @type bool $id Currently unused.
+	 *     @type bool $no_grav Default: false.
+	 * }
+	 * @return string User avatar string.
+	 */
+	function bp_get_blog_avatar( $args = '' ) {
+		global $blogs_template;
+
+		$defaults = array(
+			'type'    => 'full',
+			'width'   => false,
+			'height'  => false,
+			'class'   => 'avatar',
+			'id'      => false,
+			'alt'     => sprintf( __( 'Profile picture of site author %s', 'buddypress' ), bp_core_get_user_displayname( $blogs_template->blog->admin_user_id ) ),
+			'no_grav' => true
+		);
+
+		$r = wp_parse_args( $args, $defaults );
+		extract( $r, EXTR_SKIP );
+
+		/***
+		 * In future BuddyPress versions you will be able to set the avatar for a blog.
+		 * Right now you can use a filter with the ID of the blog to change it if you wish.
+		 * By default it will return the avatar for the primary blog admin.
+		 *
+		 * This filter is deprecated as of BuddyPress 1.5 and may be removed in a future version.
+		 * Use the 'bp_get_blog_avatar' filter instead.
+		 */
+		$avatar = apply_filters( 'bp_get_blog_avatar_' . $blogs_template->blog->blog_id, bp_core_fetch_avatar( array( 'item_id' => $blogs_template->blog->admin_user_id, 'type' => $type, 'alt' => $alt, 'width' => $width, 'height' => $height, 'class' => $class, 'email' => $blogs_template->blog->admin_user_email ) ) );
+
+		return apply_filters( 'bp_get_blog_avatar', $avatar, $blogs_template->blog->blog_id, array( 'item_id' => $blogs_template->blog->admin_user_id, 'type' => $type, 'alt' => $alt, 'width' => $width, 'height' => $height, 'class' => $class, 'email' => $blogs_template->blog->admin_user_email ) );
+	}
+
+function bp_blog_permalink() {
+	echo bp_get_blog_permalink();
+}
+	function bp_get_blog_permalink() {
+		global $blogs_template;
+
+		if ( empty( $blogs_template->blog->domain ) )
+			$permalink = bp_get_root_domain() . $blogs_template->blog->path;
+		else {
+			$protocol = 'http://';
+			if ( is_ssl() )
+				$protocol = 'https://';
+
+			$permalink = $protocol . $blogs_template->blog->domain . $blogs_template->blog->path;
+		}
+
+		return apply_filters( 'bp_get_blog_permalink', $permalink );
+	}
+
+/**
+ * Output the name of the current blog in the loop.
+ */
+function bp_blog_name() {
+	echo bp_get_blog_name();
+}
+	/**
+	 * Return the name of the current blog in the loop.
+	 *
+	 * @return string The name of the current blog in the loop.
+	 */
+	function bp_get_blog_name() {
+		global $blogs_template;
+
+		return apply_filters( 'bp_get_blog_name', $blogs_template->blog->name );
+	}
+
+/**
+ * Output the ID of the current blog in the loop.
+ *
+ * @since BuddyPress (1.7.0)
+ */
+function bp_blog_id() {
+	echo bp_get_blog_id();
+}
+	/**
+	 * Return the ID of the current blog in the loop.
+	 *
+	 * @since BuddyPress (1.7.0)
+	 *
+	 * @return int ID of the current blog in the loop.
+	 */
+	function bp_get_blog_id() {
+		global $blogs_template;
+
+		return apply_filters( 'bp_get_blog_id', $blogs_template->blog->blog_id );
+	}
+
+/**
+ * Output the description of the current blog in the loop.
+ */
+function bp_blog_description() {
+	echo apply_filters( 'bp_blog_description', bp_get_blog_description() );
+}
+	/**
+	 * Return the description of the current blog in the loop.
+	 *
+	 * @return string Description of the current blog in the loop.
+	 */
+	function bp_get_blog_description() {
+		global $blogs_template;
+
+		return apply_filters( 'bp_get_blog_description', $blogs_template->blog->description );
+	}
+
+/**
+ * Output the row class of the current blog in the loop.
+ *
+ * @since BuddyPress (1.7.0)
+ */
+function bp_blog_class() {
+	echo bp_get_blog_class();
+}
+	/**
+	 * Return the row class of the current blog in the loop.
+	 *
+	 * @since BuddyPress (1.7.0)
+	 *
+	 * @global BP_Blogs_Template $blogs_template
+	 *
+	 * @return string Row class of the site.
+	 */
+	function bp_get_blog_class() {
+		global $blogs_template;
+
+		$classes     = array();
+		$pos_in_loop = (int) $blogs_template->current_blog;
+
+		// If we've only one site in the loop, don't bother with odd and even.
+		if ( $blogs_template->blog_count > 1 )
+			$classes[] = ( $pos_in_loop % 2 ) ? 'even' : 'odd';
+		else
+			$classes[] = 'bp-single-blog';
+
+		$classes = apply_filters( 'bp_get_blog_class', $classes );
+		$classes = array_merge( $classes, array() );
+
+		$retval = 'class="' . join( ' ', $classes ) . '"';
+		return $retval;
+	}
+
+/**
+ * Output the last active date of the current blog in the loop.
+ */
+function bp_blog_last_active() {
+	echo bp_get_blog_last_active();
+}
+	/**
+	 * Return the last active date of the current blog in the loop.
+	 *
+	 * @return string Last active date.
+	 */
+	function bp_get_blog_last_active() {
+		global $blogs_template;
+
+		return apply_filters( 'bp_blog_last_active', bp_core_get_last_activity( $blogs_template->blog->last_activity, __( 'active %s', 'buddypress' ) ) );
+	}
+
+/**
+ * Output the latest post from the current blog in the loop.
+ */
+function bp_blog_latest_post() {
+	echo bp_get_blog_latest_post();
+}
+	/**
+	 * Return the latest post from the current blog in the loop.
+	 *
+	 * @return string $retval String of the form 'Latest Post: [link to post]'.
+	 */
+	function bp_get_blog_latest_post() {
+		global $blogs_template;
+
+		$retval = bp_get_blog_latest_post_title();
+
+		if ( ! empty( $retval ) )
+			$retval = sprintf( __( 'Latest Post: %s', 'buddypress' ), '<a href="' . $blogs_template->blog->latest_post->guid . '">' . apply_filters( 'the_title', $retval ) . '</a>' );
+
+		return apply_filters( 'bp_get_blog_latest_post', $retval );
+	}
+
+/**
+ * Output the title of the latest post on the current blog in the loop.
+ *
+ * @since BuddyPress (1.7.0)
+ *
+ * @see bp_get_blog_latest_post_title()
+ */
+function bp_blog_latest_post_title() {
+	echo bp_get_blog_latest_post_title();
+}
+	/**
+	 * Return the title of the latest post on the current blog in the loop.
+	 *
+	 * @since BuddyPress (1.7.0)
+	 *
+	 * @global BP_Blogs_Template
+	 *
+	 * @return string Post title.
+	 */
+	function bp_get_blog_latest_post_title() {
+		global $blogs_template;
+
+		$retval = '';
+
+		if ( ! empty( $blogs_template->blog->latest_post ) && ! empty( $blogs_template->blog->latest_post->post_title ) )
+			$retval = $blogs_template->blog->latest_post->post_title;
+
+		return apply_filters( 'bp_get_blog_latest_post_title', $retval );
+	}
+
+/**
+ * Output the permalink of the latest post on the current blog in the loop.
+ *
+ * @since BuddyPress (1.7.0)
+ *
+ * @see bp_get_blog_latest_post_title()
+ */
+function bp_blog_latest_post_permalink() {
+	echo bp_get_blog_latest_post_permalink();
+}
+	/**
+	 * Return the permalink of the latest post on the current blog in the loop.
+	 *
+	 * @since BuddyPress (1.7.0)
+	 *
+	 * @global BP_Blogs_Template
+	 *
+	 * @return string URL of the blog's latest post.
+	 */
+	function bp_get_blog_latest_post_permalink() {
+		global $blogs_template;
+
+		$retval = '';
+
+		if ( ! empty( $blogs_template->blog->latest_post ) && ! empty( $blogs_template->blog->latest_post->ID ) )
+			$retval = add_query_arg( 'p', $blogs_template->blog->latest_post->ID, bp_get_blog_permalink() );
+
+		return apply_filters( 'bp_get_blog_latest_post_permalink', $retval );
+	}
+
+/**
+ * Output the content of the latest post on the current blog in the loop.
+ *
+ * @since BuddyPress (1.7.0)
+ *
+ * @uses bp_get_blog_latest_post_content()
+ */
+function bp_blog_latest_post_content() {
+	echo bp_get_blog_latest_post_content();
+}
+	/**
+	 * Return the content of the latest post on the current blog in the loop.
+	 *
+	 * @since BuddyPress (1.7.0)
+	 *
+	 * @global BP_Blogs_Template
+	 *
+	 * @return string Content of the blog's latest post.
+	 */
+	function bp_get_blog_latest_post_content() {
+		global $blogs_template;
+
+		$retval = '';
+
+		if ( ! empty( $blogs_template->blog->latest_post ) && ! empty( $blogs_template->blog->latest_post->post_content ) )
+			$retval = $blogs_template->blog->latest_post->post_content;
+
+		return apply_filters( 'bp_get_blog_latest_post_content', $retval );
+	}
+
+/**
+ * Output the featured image of the latest post on the current blog in the loop.
+ *
+ * @since BuddyPress (1.7.0)
+ *
+ * @see bp_get_blog_latest_post_content() For description of parameters.
+ *
+ * @param string $size See {@link bp_get_blog_latest_post_featured_image()}.
+ */
+function bp_blog_latest_post_featured_image( $size = 'thumbnail' ) {
+	echo bp_get_blog_latest_post_featured_image( $size );
+}
+	/**
+	 * Return the featured image of the latest post on the current blog in the loop.
+	 *
+	 * @since BuddyPress (1.7.0)
+	 *
+	 * @global BP_Blogs_Template
+	 *
+	 * @param string $size Image version to return. 'thumbnail', 'medium',
+	 *        'large', or 'post-thumbnail'. Default: 'thumbnail'.
+	 * @return string URL of the image.
+	 */
+	function bp_get_blog_latest_post_featured_image( $size = 'thumbnail' ) {
+		global $blogs_template;
+
+		$retval = '';
+
+		if ( ! empty( $blogs_template->blog->latest_post ) && ! empty( $blogs_template->blog->latest_post->images[$size] ) )
+			$retval = $blogs_template->blog->latest_post->images[$size];
+
+		return apply_filters( 'bp_get_blog_latest_post_featured_image', $retval );
+	}
+
+/**
+ * Does the latest blog post have a featured image?
+ *
+ * @since BuddyPress (1.7.0)
+ *
+ * @param string $size Image version to return. 'thumbnail', 'medium', 'large',
+ *        or 'post-thumbnail'. Default: 'thumbnail'.
+ * @return bool True if the latest blog post from the current blog has a
+ *         featured image of the given size.
+ */
+function bp_blog_latest_post_has_featured_image( $thumbnail = 'thumbnail' ) {
+	$image  = bp_get_blog_latest_post_featured_image( $thumbnail );
+
+	return apply_filters( 'bp_blog_latest_post_has_featured_image', ! empty( $image ), $thumbnail, $image );
+}
+
+/**
+ * Output hidden fields to help with form submissions in Sites directory.
+ *
+ * This function detects whether 's', 'letter', or 'blogs_search' requests are
+ * currently being made (as in a URL parameter), and creates corresponding
+ * hidden fields.
+ */
+function bp_blog_hidden_fields() {
+	if ( isset( $_REQUEST['s'] ) )
+		echo '<input type="hidden" id="search_terms" value="' . esc_attr( $_REQUEST['s'] ). '" name="search_terms" />';
+
+	if ( isset( $_REQUEST['letter'] ) )
+		echo '<input type="hidden" id="selected_letter" value="' . esc_attr( $_REQUEST['letter'] ) . '" name="selected_letter" />';
+
+	if ( isset( $_REQUEST['blogs_search'] ) )
+		echo '<input type="hidden" id="search_terms" value="' . esc_attr( $_REQUEST['blogs_search'] ) . '" name="search_terms" />';
+}
+
+/**
+ * Output the total number of blogs on the site.
+ */
+function bp_total_blog_count() {
+	echo bp_get_total_blog_count();
+}
+	/**
+	 * Return the total number of blogs on the site.
+	 *
+	 * @return int Total number of blogs.
+	 */
+	function bp_get_total_blog_count() {
+		return apply_filters( 'bp_get_total_blog_count', bp_blogs_total_blogs() );
+	}
+	add_filter( 'bp_get_total_blog_count', 'bp_core_number_format' );
+
+/**
+ * Output the total number of blogs for a given user.
+ *
+ * @param int $user_id ID of the user.
+ */
+function bp_total_blog_count_for_user( $user_id = 0 ) {
+	echo bp_get_total_blog_count_for_user( $user_id );
+}
+	/**
+	 * Return the total number of blogs for a given user.
+	 *
+	 * @param int $user_id ID of the user.
+	 * @return int Total number of blogs for the user.
+	 */
+	function bp_get_total_blog_count_for_user( $user_id = 0 ) {
+		return apply_filters( 'bp_get_total_blog_count_for_user', bp_blogs_total_blogs_for_user( $user_id ) );
+	}
+	add_filter( 'bp_get_total_blog_count_for_user', 'bp_core_number_format' );
+
+
+/** Blog Registration ********************************************************/
+
+/**
+ * Checks whether blog creation is enabled.
+ *
+ * Returns true when blog creation is enabled for logged-in users only, or
+ * when it's enabled for new registrations.
+ *
+ * @return bool True if blog registration is enabled.
+ */
+function bp_blog_signup_enabled() {
+	global $bp;
+
+	$active_signup = isset( $bp->site_options['registration'] ) ? $bp->site_options['registration'] : 'all';
+
+	$active_signup = apply_filters( 'wpmu_active_signup', $active_signup ); // return "all", "none", "blog" or "user"
+
+	if ( 'none' == $active_signup || 'user' == $active_signup )
+		return false;
+
+	return true;
+}
+
+/**
+ * Output the wrapper markup for the blog signup form.
+ *
+ * @param string $blogname Optional. The default blog name (path or domain).
+ * @param string $blog_title Optional. The default blog title.
+ * @param string|WP_Error Optional. The WP_Error object returned by a previous
+ *        submission attempt.
+ */
+function bp_show_blog_signup_form($blogname = '', $blog_title = '', $errors = '') {
+	global $current_user;
+
+	if ( isset($_POST['submit']) ) {
+		bp_blogs_validate_blog_signup();
+	} else {
+		if ( ! is_wp_error($errors) ) {
+			$errors = new WP_Error();
+		}
+
+		// allow definition of default variables
+		$filtered_results = apply_filters('signup_another_blog_init', array('blogname' => $blogname, 'blog_title' => $blog_title, 'errors' => $errors ));
+		$blogname = $filtered_results['blogname'];
+		$blog_title = $filtered_results['blog_title'];
+		$errors = $filtered_results['errors'];
+
+		if ( $errors->get_error_code() ) {
+			echo "<p>" . __('There was a problem, please correct the form below and try again.', 'buddypress') . "</p>";
+		}
+		?>
+		<p><?php printf(__("By filling out the form below, you can <strong>add a site to your account</strong>. There is no limit to the number of sites that you can have, so create to your heart's content, but blog responsibly!", 'buddypress'), $current_user->display_name) ?></p>
+
+		<p><?php _e("If you&#8217;re not going to use a great domain, leave it for a new user. Now have at it!", 'buddypress') ?></p>
+
+		<form class="standard-form" id="setupform" method="post" action="">
+
+			<input type="hidden" name="stage" value="gimmeanotherblog" />
+			<?php do_action( 'signup_hidden_fields' ); ?>
+
+			<?php bp_blogs_signup_blog($blogname, $blog_title, $errors); ?>
+			<p>
+				<input id="submit" type="submit" name="submit" class="submit" value="<?php _e('Create Site', 'buddypress') ?>" />
+			</p>
+
+			<?php wp_nonce_field( 'bp_blog_signup_form' ) ?>
+		</form>
+		<?php
+	}
+}
+
+/**
+ * Output the input fields for the blog creation form.
+ *
+ * @param string $blogname Optional. The default blog name (path or domain).
+ * @param string $blog_title Optional. The default blog title.
+ * @param string|WP_Error Optional. The WP_Error object returned by a previous
+ *        submission attempt.
+ */
+function bp_blogs_signup_blog( $blogname = '', $blog_title = '', $errors = '' ) {
+	global $current_site;
+
+	// Blog name
+	if( !is_subdomain_install() )
+		echo '<label for="blogname">' . __('Site Name:', 'buddypress') . '</label>';
+	else
+		echo '<label for="blogname">' . __('Site Domain:', 'buddypress') . '</label>';
+
+	if ( $errmsg = $errors->get_error_message('blogname') ) { ?>
+
+		<p class="error"><?php echo $errmsg ?></p>
+
+	<?php }
+
+	if ( !is_subdomain_install() )
+		echo '<span class="prefix_address">' . $current_site->domain . $current_site->path . '</span> <input name="blogname" type="text" id="blogname" value="'.$blogname.'" maxlength="63" /><br />';
+	else
+		echo '<input name="blogname" type="text" id="blogname" value="'.$blogname.'" maxlength="63" /> <span class="suffix_address">.' . bp_blogs_get_subdomain_base() . '</span><br />';
+
+	if ( !is_user_logged_in() ) {
+		print '(<strong>' . __( 'Your address will be ' , 'buddypress');
+
+		if ( !is_subdomain_install() ) {
+			print $current_site->domain . $current_site->path . __( 'blogname' , 'buddypress');
+		} else {
+			print __( 'domain.' , 'buddypress') . $current_site->domain . $current_site->path;
+		}
+
+		echo '.</strong> ' . __( 'Must be at least 4 characters, letters and numbers only. It cannot be changed so choose carefully!)' , 'buddypress') . '</p>';
+	}
+
+	// Blog Title
+	?>
+
+	<label for="blog_title"><?php _e('Site Title:', 'buddypress') ?></label>
+
+	<?php if ( $errmsg = $errors->get_error_message('blog_title') ) { ?>
+
+		<p class="error"><?php echo $errmsg ?></p>
+
+	<?php }
+	echo '<input name="blog_title" type="text" id="blog_title" value="'.esc_html($blog_title, 1).'" /></p>';
+	?>
+
+	<p>
+		<label for="blog_public_on"><?php _e('Privacy:', 'buddypress') ?></label>
+		<?php _e( 'I would like my site to appear in search engines, and in public listings around this network.', 'buddypress' ); ?>
+
+		<label class="checkbox" for="blog_public_on">
+			<input type="radio" id="blog_public_on" name="blog_public" value="1" <?php if( !isset( $_POST['blog_public'] ) || '1' == $_POST['blog_public'] ) { ?>checked="checked"<?php } ?> />
+			<strong><?php _e( 'Yes' , 'buddypress'); ?></strong>
+		</label>
+		<label class="checkbox" for="blog_public_off">
+			<input type="radio" id="blog_public_off" name="blog_public" value="0" <?php if( isset( $_POST['blog_public'] ) && '0' == $_POST['blog_public'] ) { ?>checked="checked"<?php } ?> />
+			<strong><?php _e( 'No' , 'buddypress'); ?></strong>
+		</label>
+	</p>
+
+	<?php
+	do_action('signup_blogform', $errors);
+}
+
+/**
+ * Output the base URL for subdomain installations of WordPress Multisite.
+ *
+ * @since BuddyPress (1.6.0)
+ */
+function bp_blogs_subdomain_base() {
+	echo bp_blogs_get_subdomain_base();
+}
+	/**
+	 * Return the base URL for subdomain installations of WordPress Multisite.
+	 *
+	 * @since BuddyPress (1.6.0)
+	 *
+	 * @return string The base URL - eg, 'example.com' for site_url() example.com or www.example.com.
+	 */
+	function bp_blogs_get_subdomain_base() {
+		global $current_site;
+
+		return apply_filters( 'bp_blogs_subdomain_base', preg_replace( '|^www\.|', '', $current_site->domain ) . $current_site->path );
+	}
+
+/**
+ * Process a blog registration submission.
+ *
+ * Passes submitted values to {@link wpmu_create_blog()}.
+ *
+ * @return bool True on success, false on failure.
+ */
+function bp_blogs_validate_blog_signup() {
+	global $wpdb, $current_user, $blogname, $blog_title, $errors, $domain, $path, $current_site;
+
+	if ( !check_admin_referer( 'bp_blog_signup_form' ) )
+		return false;
+
+	$current_user = wp_get_current_user();
+
+	if( !is_user_logged_in() )
+		die();
+
+	$result = bp_blogs_validate_blog_form();
+	extract($result);
+
+	if ( $errors->get_error_code() ) {
+		unset($_POST['submit']);
+		bp_show_blog_signup_form( $blogname, $blog_title, $errors );
+		return false;
+	}
+
+	$public = (int) $_POST['blog_public'];
+
+	$meta = apply_filters( 'signup_create_blog_meta', array( 'lang_id' => 1, 'public' => $public ) ); // depreciated
+	$meta = apply_filters( 'add_signup_meta', $meta );
+
+	// If this is a subdomain install, set up the site inside the root domain.
+	if ( is_subdomain_install() )
+		$domain = $blogname . '.' . preg_replace( '|^www\.|', '', $current_site->domain );
+
+	wpmu_create_blog( $domain, $path, $blog_title, $current_user->ID, $meta, $wpdb->siteid );
+	bp_blogs_confirm_blog_signup($domain, $path, $blog_title, $current_user->user_login, $current_user->user_email, $meta);
+	return true;
+}
+
+/**
+ * Validate a blog creation submission.
+ *
+ * Essentially, a wrapper for {@link wpmu_validate_blog_signup()}.
+ *
+ * @return array Contains the new site data and error messages.
+ */
+function bp_blogs_validate_blog_form() {
+	$user = '';
+	if ( is_user_logged_in() )
+		$user = wp_get_current_user();
+
+	return wpmu_validate_blog_signup($_POST['blogname'], $_POST['blog_title'], $user);
+}
+
+/**
+ * Display a message after successful blog registration.
+ *
+ * @param string $domain The new blog's domain.
+ * @param string $path The new blog's path.
+ * @param string $blog_title The new blog's title.
+ * @param string $user_name The user name of the user who created the blog. Unused.
+ * @param string $user_email The email of the user who created the blog. Unused.
+ * @param string|array $meta Meta values associated with the new blog. Unused.
+ */
+function bp_blogs_confirm_blog_signup( $domain, $path, $blog_title, $user_name, $user_email = '', $meta = '' ) {
+	$protocol = is_ssl() ? 'https://' : 'http://';
+	$blog_url = $protocol . $domain . $path; ?>
+
+	<p><?php _e( 'Congratulations! You have successfully registered a new site.', 'buddypress' ) ?></p>
+	<p>
+		<?php printf(__( '<a href="%1$s">%2$s</a> is your new site.  <a href="%3$s">Login</a> as "%4$s" using your existing password.', 'buddypress' ), $blog_url, $blog_url, $blog_url . "wp-login.php", $user_name ); ?>
+	</p>
+
+<?php
+	do_action('signup_finished');
+}
+
+/**
+ * Output a "Create a Site" link for users viewing their own profiles.
+ */
+function bp_create_blog_link() {
+	if ( bp_is_my_profile() )
+		echo apply_filters( 'bp_create_blog_link', '<a href="' . bp_get_root_domain() . '/' . bp_get_blogs_root_slug() . '/create/">' . __( 'Create a Site', 'buddypress' ) . '</a>' );
+}
+
+/**
+ * Output navigation tabs for a user Blogs page.
+ *
+ * Currently unused by BuddyPress.
+ */
+function bp_blogs_blog_tabs() {
+
+	// Don't show these tabs on a user's own profile
+	if ( bp_is_my_profile() )
+		return false;
+
+	?>
+
+	<ul class="content-header-nav">
+		<li<?php if ( bp_is_current_action( 'my-blogs'        ) || !bp_current_action() ) : ?> class="current"<?php endif; ?>><a href="<?php echo trailingslashit( bp_displayed_user_domain() . bp_get_blogs_slug() . '/my-blogs'        ); ?>"><?php printf( __( "%s's Sites", 'buddypress' ),           bp_get_displayed_user_fullname() ); ?></a></li>
+		<li<?php if ( bp_is_current_action( 'recent-posts'    )                         ) : ?> class="current"<?php endif; ?>><a href="<?php echo trailingslashit( bp_displayed_user_domain() . bp_get_blogs_slug() . '/recent-posts'    ); ?>"><?php printf( __( "%s's Recent Posts", 'buddypress' ),    bp_get_displayed_user_fullname() ); ?></a></li>
+		<li<?php if ( bp_is_current_action( 'recent-comments' )                         ) : ?> class="current"<?php endif; ?>><a href="<?php echo trailingslashit( bp_displayed_user_domain() . bp_get_blogs_slug() . '/recent-comments' ); ?>"><?php printf( __( "%s's Recent Comments", 'buddypress' ), bp_get_displayed_user_fullname() ); ?></a></li>
+	</ul>
+
+<?php
+	do_action( 'bp_blogs_blog_tabs' );
+}
+
+/**
+ * Output the blog directory search form.
+ */
+function bp_directory_blogs_search_form() {
+	$default_search_value = bp_get_search_default_text();
+	$search_value         = !empty( $_REQUEST['s'] ) ? stripslashes( $_REQUEST['s'] ) : $default_search_value;
+
+	$search_form_html = '<form action="" method="get" id="search-blogs-form">
+		<label><input type="text" name="s" id="blogs_search" placeholder="'. esc_attr( $search_value ) .'" /></label>
+		<input type="submit" id="blogs_search_submit" name="blogs_search_submit" value="' . __( 'Search', 'buddypress' ) . '" />
+	</form>';
+
+	echo apply_filters( 'bp_directory_blogs_search_form', $search_form_html );
+}
+
+/**
+ * Output button for visiting a blog in a loop.
+ *
+ * @see bp_get_blogs_visit_blog_button() for description of arguments.
+ *
+ * @param array $args See {@link bp_get_blogs_visit_blog_button()}.
+ */
+function bp_blogs_visit_blog_button( $args = '' ) {
+	echo bp_get_blogs_visit_blog_button( $args );
+}
+	/**
+	 * Return button for visiting a blog in a loop.
+	 *
+	 * @see BP_Button for a complete description of arguments and return
+	 *      value.
+	 *
+	 * @param array $args {
+	 *     Arguments are listed below, with their default values. For a
+	 *     complete description of arguments, see {@link BP_Button}.
+	 *     @type string $id Default: 'visit_blog'.
+	 *     @type string $component Default: 'blogs'.
+	 *     @type bool $must_be_logged_in Default: false.
+	 *     @type bool $block_self Default: false.
+	 *     @type string $wrapper_class Default: 'blog-button visit'.
+	 *     @type string $link_href Permalink of the current blog in the loop.
+	 *     @type string $link_class Default: 'blog-button visit'.
+	 *     @type string $link_text Default: 'Visit Site'.
+	 *     @type string $link_title Default: 'Visit Site'.
+	 * }
+	 * @return string The HTML for the Visit button.
+	 */
+	function bp_get_blogs_visit_blog_button( $args = '' ) {
+		$defaults = array(
+			'id'                => 'visit_blog',
+			'component'         => 'blogs',
+			'must_be_logged_in' => false,
+			'block_self'        => false,
+			'wrapper_class'     => 'blog-button visit',
+			'link_href'         => bp_get_blog_permalink(),
+			'link_class'        => 'blog-button visit',
+			'link_text'         => __( 'Visit Site', 'buddypress' ),
+			'link_title'        => __( 'Visit Site', 'buddypress' ),
+		);
+
+		$button = wp_parse_args( $args, $defaults );
+
+		// Filter and return the HTML button
+		return bp_get_button( apply_filters( 'bp_get_blogs_visit_blog_button', $button ) );
+	}
Index: /tags/1.9/bp-blogs/bp-blogs-widgets.php
===================================================================
--- /tags/1.9/bp-blogs/bp-blogs-widgets.php	(revision 7684)
+++ /tags/1.9/bp-blogs/bp-blogs-widgets.php	(revision 7684)
@@ -0,0 +1,138 @@
+<?php
+
+/**
+ * BuddyPress Blogs Widgets
+ *
+ * @package BuddyPress
+ * @subpackage BlogsWidgets
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/**
+ * Register the widgets for the Blogs component.
+ */
+function bp_blogs_register_widgets() {
+	global $wpdb;
+
+	if ( bp_is_active( 'activity' ) && (int) $wpdb->blogid == bp_get_root_blog_id() )
+		add_action( 'widgets_init', create_function( '', 'return register_widget("BP_Blogs_Recent_Posts_Widget");' ) );
+}
+add_action( 'bp_register_widgets', 'bp_blogs_register_widgets' );
+
+/**
+ * The Recent Networkwide Posts widget
+ */
+class BP_Blogs_Recent_Posts_Widget extends WP_Widget {
+
+	/**
+	 * Constructor method.
+	 */
+	function __construct() {
+		$widget_ops = array(
+			'description' => __( 'A list of recently published posts from across your network.', 'buddypress' ),
+			'classname'   => 'widget_bp_blogs_widget buddypress widget',
+		);
+		parent::__construct( false, $name = _x( '(BuddyPress) Recent Networkwide Posts', 'widget name', 'buddypress' ), $widget_ops );
+	}
+
+	/**
+	 * Display the networkwide posts widget.
+	 *
+	 * @see WP_Widget::widget() for description of parameters.
+	 *
+	 * @param array $args Widget arguments.
+	 * @param array $instance Widget settings, as saved by the user.
+	 */
+	function widget( $args, $instance ) {
+
+		$title = ! empty( $instance['title'] ) ? esc_html( $instance['title'] ) : __( 'Recent Networkwide Posts', 'buddypress' );
+
+		if ( ! empty( $instance['link_title'] ) ) {
+			$title = '<a href="' . trailingslashit( bp_get_root_domain() ) . trailingslashit( bp_get_blogs_root_slug() ) . '">' . esc_html( $title ) . '</a>';
+		}
+
+		echo $args['before_widget'];
+		echo $args['before_title'] . $title . $args['after_title'];
+
+		if ( empty( $instance['max_posts'] ) || !$instance['max_posts'] )
+			$instance['max_posts'] = 10; ?>
+
+		<?php // Override some of the contextually set parameters for bp_has_activities() ?>
+		<?php if ( bp_has_activities( array( 'action' => 'new_blog_post', 'max' => $instance['max_posts'], 'per_page' => $instance['max_posts'], 'user_id' => 0, 'scope' => false, 'object' => false, 'primary_id' => false ) ) ) : ?>
+
+			<ul id="blog-post-list" class="activity-list item-list">
+
+				<?php while ( bp_activities() ) : bp_the_activity(); ?>
+
+					<li>
+						<div class="activity-content" style="margin: 0">
+
+							<div class="activity-header">
+								<?php bp_activity_action() ?>
+							</div>
+
+							<?php if ( bp_get_activity_content_body() ) : ?>
+								<div class="activity-inner">
+									<?php bp_activity_content_body() ?>
+								</div>
+							<?php endif; ?>
+
+						</div>
+					</li>
+
+				<?php endwhile; ?>
+
+			</ul>
+
+		<?php else : ?>
+			<div id="message" class="info">
+				<p><?php _e( 'Sorry, there were no posts found. Why not write one?', 'buddypress' ) ?></p>
+			</div>
+		<?php endif; ?>
+
+		<?php echo $args['after_widget']; ?>
+	<?php
+	}
+
+	/**
+	 * Update the networkwide posts widget options.
+	 *
+	 * @param array $new_instance The new instance options.
+	 * @param array $old_instance The old instance options.
+	 * @return array $instance The parsed options to be saved.
+	 */
+	function update( $new_instance, $old_instance ) {
+		$instance = $old_instance;
+		$instance['title'] = strip_tags( $new_instance['title'] );
+		$instance['max_posts'] = strip_tags( $new_instance['max_posts'] );
+		$instance['link_title'] = (bool) $new_instance['link_title'];
+
+		return $instance;
+	}
+
+	/**
+	 * Output the networkwide posts widget options form.
+	 *
+	 * @param $instance Settings for this widget.
+	 */
+	function form( $instance ) {
+		$instance = wp_parse_args( (array) $instance, array(
+			'title'      => __( 'Recent Networkwide Posts', 'buddypress' ),
+			'max_posts'  => 10,
+			'link_title' => false,
+		) );
+
+		$title = strip_tags( $instance['title'] );
+		$max_posts = strip_tags( $instance['max_posts'] );
+		$link_title = (bool) $instance['link_title'];
+
+		?>
+
+		<p><label for="<?php echo $this->get_field_id( 'title' ) ?>"><?php _ex( 'Title:', 'Label for the Title field of the Recent Networkwide Posts widget', 'buddypress' ) ?> <input class="widefat" id="<?php echo $this->get_field_id( 'title' ) ?>" name="<?php echo $this->get_field_name( 'title' ) ?>" type="text" value="<?php echo esc_attr( $title ) ?>" style="width: 100%;" /></label></p>
+		<p><label for="<?php echo $this->get_field_id( 'link_title' ) ?>"><input type="checkbox" name="<?php echo $this->get_field_name( 'link_title' ) ?>" value="1" <?php checked( $link_title ) ?> /> <?php _e( 'Link widget title to Blogs directory', 'buddypress' ) ?></label></p>
+		<p><label for="<?php echo $this->get_field_id( 'max_posts' ) ?>"><?php _e( 'Max posts to show:', 'buddypress' ); ?> <input class="widefat" id="<?php echo $this->get_field_id( 'max_posts' ); ?>" name="<?php echo $this->get_field_name( 'max_posts' ); ?>" type="text" value="<?php echo esc_attr( $max_posts ); ?>" style="width: 30%" /></label></p>
+		<?php
+	}
+}
Index: /tags/1.9/bp-core/admin/bp-core-actions.php
===================================================================
--- /tags/1.9/bp-core/admin/bp-core-actions.php	(revision 7684)
+++ /tags/1.9/bp-core/admin/bp-core-actions.php	(revision 7684)
@@ -0,0 +1,174 @@
+<?php
+
+/**
+ * BuddyPress Admin Actions
+ *
+ * This file contains the actions that are used through-out BuddyPress Admin. They
+ * are consolidated here to make searching for them easier, and to help developers
+ * understand at a glance the order in which things occur.
+ *
+ * There are a few common places that additional actions can currently be found
+ *
+ *  - BuddyPress: In {@link BuddyPress::setup_actions()} in BuddyPress.php
+ *  - Admin: More in {@link bp_Admin::setup_actions()} in admin.php
+ *
+ * @package BuddyPress
+ * @subpackage Admin
+ * @see bp-core-actions.php
+ * @see bp-core-filters.php
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/**
+ * Attach BuddyPress to WordPress
+ *
+ * BuddyPress uses its own internal actions to help aid in third-party plugin
+ * development, and to limit the amount of potential future code changes when
+ * updates to WordPress core occur.
+ *
+ * These actions exist to create the concept of 'plugin dependencies'. They
+ * provide a safe way for plugins to execute code *only* when BuddyPress is
+ * installed and activated, without needing to do complicated guesswork.
+ *
+ * For more information on how this works, see the 'Plugin Dependency' section
+ * near the bottom of this file.
+ *
+ *           v--WordPress Actions       v--BuddyPress Sub-actions
+ */
+add_action( 'admin_menu',              'bp_admin_menu'                    );
+add_action( 'admin_init',              'bp_admin_init'                    );
+add_action( 'admin_head',              'bp_admin_head'                    );
+add_action( 'admin_notices',           'bp_admin_notices'                 );
+add_action( 'admin_enqueue_scripts',   'bp_admin_enqueue_scripts'         );
+add_action( 'network_admin_menu',      'bp_admin_menu'                    );
+add_action( 'custom_menu_order',       'bp_admin_custom_menu_order'       );
+add_action( 'menu_order',              'bp_admin_menu_order'              );
+add_action( 'wpmu_new_blog',           'bp_new_site',               10, 6 );
+
+// Hook on to admin_init
+add_action( 'bp_admin_init', 'bp_setup_updater',          1000 );
+add_action( 'bp_admin_init', 'bp_core_activation_notice', 1010 );
+add_action( 'bp_admin_init', 'bp_register_importers'           );
+add_action( 'bp_admin_init', 'bp_register_admin_style'         );
+add_action( 'bp_admin_init', 'bp_register_admin_settings'      );
+add_action( 'bp_admin_init', 'bp_do_activation_redirect', 1    );
+
+// Add a new separator
+add_action( 'bp_admin_menu', 'bp_admin_separator' );
+
+/**
+ * When a new site is created in a multisite installation, run the activation
+ * routine on that site
+ *
+ * @since BuddyPress (1.7)
+ *
+ * @param int $blog_id
+ * @param int $user_id
+ * @param string $domain
+ * @param string $path
+ * @param int $site_id
+ * @param array() $meta
+ */
+function bp_new_site( $blog_id, $user_id, $domain, $path, $site_id, $meta ) {
+
+	// Bail if plugin is not network activated
+	if ( ! is_plugin_active_for_network( buddypress()->basename ) )
+		return;
+
+	// Switch to the new blog
+	switch_to_blog( $blog_id );
+
+	// Do the BuddyPress activation routine
+	do_action( 'bp_new_site', $blog_id, $user_id, $domain, $path, $site_id, $meta );
+
+	// restore original blog
+	restore_current_blog();
+}
+
+/** Sub-Actions ***************************************************************/
+
+/**
+ * Piggy back admin_init action
+ *
+ * @since BuddyPress (1.7)
+ * @uses do_action() Calls 'bp_admin_init'
+ */
+function bp_admin_init() {
+	do_action( 'bp_admin_init' );
+}
+
+/**
+ * Piggy back admin_menu action
+ *
+ * @since BuddyPress (1.7)
+ * @uses do_action() Calls 'bp_admin_menu'
+ */
+function bp_admin_menu() {
+	do_action( 'bp_admin_menu' );
+}
+
+/**
+ * Piggy back admin_head action
+ *
+ * @since BuddyPress (1.7)
+ * @uses do_action() Calls 'bp_admin_head'
+ */
+function bp_admin_head() {
+	do_action( 'bp_admin_head' );
+}
+
+/**
+ * Piggy back admin_notices action
+ *
+ * @since BuddyPress (1.7)
+ * @uses do_action() Calls 'bp_admin_notices'
+ */
+function bp_admin_notices() {
+	do_action( 'bp_admin_notices' );
+}
+
+/**
+ * Piggy back admin_enqueue_scripts action.
+ *
+ * @since BuddyPress (1.7.0)
+ *
+ * @uses do_action() Calls 'bp_admin_enqueue_scripts''.
+ *
+ * @param string $hook_suffix The current admin page, passed to
+ *        'admin_enqueue_scripts'.
+ */
+function bp_admin_enqueue_scripts( $hook_suffix = '' ) {
+	do_action( 'bp_admin_enqueue_scripts', $hook_suffix );
+}
+
+/**
+ * Dedicated action to register BuddyPress importers
+ *
+ * @since BuddyPress (1.7)
+ * @uses do_action() Calls 'bp_admin_notices'
+ */
+function bp_register_importers() {
+	do_action( 'bp_register_importers' );
+}
+
+/**
+ * Dedicated action to register admin styles
+ *
+ * @since BuddyPress (1.7)
+ * @uses do_action() Calls 'bp_admin_notices'
+ */
+function bp_register_admin_style() {
+	do_action( 'bp_register_admin_style' );
+}
+
+/**
+ * Dedicated action to register admin settings
+ *
+ * @since BuddyPress (1.7)
+ * @uses do_action() Calls 'bp_register_admin_settings'
+ */
+function bp_register_admin_settings() {
+	do_action( 'bp_register_admin_settings' );
+}
Index: /tags/1.9/bp-core/admin/bp-core-components.php
===================================================================
--- /tags/1.9/bp-core/admin/bp-core-components.php	(revision 7684)
+++ /tags/1.9/bp-core/admin/bp-core-components.php	(revision 7684)
@@ -0,0 +1,424 @@
+<?php
+
+/**
+ * BuddyPress Admin Component Functions
+ *
+ * @package BuddyPress
+ * @subpackage CoreAdministration
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/**
+ * Renders the Component Setup admin panel.
+ *
+ * @package BuddyPress
+ * @since BuddyPress (1.6)
+ * @uses bp_core_admin_component_options()
+ */
+function bp_core_admin_components_settings() {
+?>
+
+	<div class="wrap">
+		<?php screen_icon( 'buddypress'); ?>
+
+		<h2 class="nav-tab-wrapper"><?php bp_core_admin_tabs( __( 'Components', 'buddypress' ) ); ?></h2>
+		<form action="" method="post" id="bp-admin-component-form">
+
+			<?php bp_core_admin_components_options(); ?>
+
+			<p class="submit clear">
+				<input class="button-primary" type="submit" name="bp-admin-component-submit" id="bp-admin-component-submit" value="<?php _e( 'Save Settings', 'buddypress' ) ?>"/>
+			</p>
+
+			<?php wp_nonce_field( 'bp-admin-component-setup' ); ?>
+
+		</form>
+	</div>
+
+<?php
+}
+
+/**
+ * Creates reusable markup for component setup on the Components and Pages dashboard panel.
+ *
+ * @package BuddyPress
+ * @since BuddyPress (1.6)
+ * @todo Use settings API
+ */
+function bp_core_admin_components_options() {
+
+	// Declare local variables
+	$deactivated_components = array();
+	$active_components      = apply_filters( 'bp_active_components', bp_get_option( 'bp-active-components' ) );
+
+	// The default components (if none are previously selected)
+	$default_components = array(
+		'xprofile' => array(
+			'title'       => __( 'Extended Profiles', 'buddypress' ),
+			'description' => __( 'Customize your community with fully editable profile fields that allow your users to describe themselves.', 'buddypress' )
+		),
+		'settings' => array(
+			'title'       => __( 'Account Settings', 'buddypress' ),
+			'description' => __( 'Allow your users to modify their account and notification settings directly from within their profiles.', 'buddypress' )
+		),
+		'notifications' => array(
+			'title'       => __( 'Notifications', 'buddypress' ),
+			'description' => __( 'Notify members of relevant activity with a toolbar bubble and/or via email, and allow them to customize their notification settings.', 'buddypress' )
+		),
+	);
+
+	$optional_components = bp_core_admin_get_components( 'optional' );
+	$required_components = bp_core_admin_get_components( 'required' );
+	$retired_components  = bp_core_admin_get_components( 'retired'  );
+
+	// Don't show Forums component in optional components if it's disabled
+	if ( ! bp_is_active( 'forums' ) ) {
+		unset( $optional_components['forums'] );
+	}
+
+	// Merge optional and required together
+	$all_components = $optional_components + $required_components;
+
+	// If this is an upgrade from before BuddyPress 1.5, we'll have to convert
+	// deactivated components into activated ones.
+	if ( empty( $active_components ) ) {
+		$deactivated_components = bp_get_option( 'bp-deactivated-components' );
+		if ( !empty( $deactivated_components ) ) {
+
+			// Trim off namespace and filename
+			$trimmed = array();
+			foreach ( array_keys( (array) $deactivated_components ) as $component ) {
+				$trimmed[] = str_replace( '.php', '', str_replace( 'bp-', '', $component ) );
+			}
+
+			// Loop through the optional components to create an active component array
+			foreach ( array_keys( (array) $optional_components ) as $ocomponent ) {
+				if ( !in_array( $ocomponent, $trimmed ) ) {
+					$active_components[$ocomponent] = 1;
+				}
+			}
+		}
+	}
+
+	// On new install, set active components to default
+	if ( empty( $active_components ) ) {
+		$active_components = $default_components;
+	}
+
+	// Core component is always active
+	$active_components['core'] = $all_components['core'];
+	$inactive_components       = array_diff( array_keys( $all_components ) , array_keys( $active_components ) );
+
+	/** Display ***************************************************************/
+
+	// Get the total count of all plugins
+	$all_count = count( $all_components );
+	$page      = bp_core_do_network_admin()  ? 'settings.php' : 'options-general.php';
+	$action    = !empty( $_GET['action'] ) ? $_GET['action'] : 'all';
+
+	switch( $action ) {
+		case 'all' :
+			$current_components = $all_components;
+			break;
+		case 'active' :
+			foreach ( array_keys( $active_components ) as $component ) {
+				$current_components[$component] = $all_components[$component];
+			}
+			break;
+		case 'inactive' :
+			foreach ( $inactive_components as $component ) {
+				$current_components[$component] = $all_components[$component];
+			}
+			break;
+		case 'mustuse' :
+			$current_components = $required_components;
+			break;
+		case 'retired' :
+			$current_components = $retired_components;
+			break;
+	} ?>
+
+	<ul class="subsubsub">
+		<li><a href="<?php echo add_query_arg( array( 'page' => 'bp-components', 'action' => 'all'      ), bp_get_admin_url( $page ) ); ?>" <?php if ( $action === 'all'      ) : ?>class="current"<?php endif; ?>><?php printf( _nx( 'All <span class="count">(%s)</span>',      'All <span class="count">(%s)</span>',      $all_count,         'plugins', 'buddypress' ), number_format_i18n( $all_count                    ) ); ?></a> | </li>
+		<li><a href="<?php echo add_query_arg( array( 'page' => 'bp-components', 'action' => 'active'   ), bp_get_admin_url( $page ) ); ?>" <?php if ( $action === 'active'   ) : ?>class="current"<?php endif; ?>><?php printf( _n(  'Active <span class="count">(%s)</span>',   'Active <span class="count">(%s)</span>',   count( $active_components   ), 'buddypress' ), number_format_i18n( count( $active_components   ) ) ); ?></a> | </li>
+		<li><a href="<?php echo add_query_arg( array( 'page' => 'bp-components', 'action' => 'inactive' ), bp_get_admin_url( $page ) ); ?>" <?php if ( $action === 'inactive' ) : ?>class="current"<?php endif; ?>><?php printf( _n(  'Inactive <span class="count">(%s)</span>', 'Inactive <span class="count">(%s)</span>', count( $inactive_components ), 'buddypress' ), number_format_i18n( count( $inactive_components ) ) ); ?></a> | </li>
+		<li><a href="<?php echo add_query_arg( array( 'page' => 'bp-components', 'action' => 'mustuse'  ), bp_get_admin_url( $page ) ); ?>" <?php if ( $action === 'mustuse'  ) : ?>class="current"<?php endif; ?>><?php printf( _n(  'Must-Use <span class="count">(%s)</span>', 'Must-Use <span class="count">(%s)</span>', count( $required_components ), 'buddypress' ), number_format_i18n( count( $required_components ) ) ); ?></a> | </li>
+		<li><a href="<?php echo add_query_arg( array( 'page' => 'bp-components', 'action' => 'retired'  ), bp_get_admin_url( $page ) ); ?>" <?php if ( $action === 'retired'  ) : ?>class="current"<?php endif; ?>><?php printf( _n(  'Retired <span class="count">(%s)</span>',  'Retired <span class="count">(%s)</span>',  count( $retired_components ),  'buddypress' ), number_format_i18n( count( $retired_components  ) ) ); ?></a></li>
+	</ul>
+
+	<table class="widefat fixed plugins" cellspacing="0">
+		<thead>
+			<tr>
+				<th scope="col" id="cb" class="manage-column column-cb check-column">&nbsp;</th>
+				<th scope="col" id="name" class="manage-column column-name" style="width: 190px;"><?php _e( 'Component', 'buddypress' ); ?></th>
+				<th scope="col" id="description" class="manage-column column-description"><?php _e( 'Description', 'buddypress' ); ?></th>
+			</tr>
+		</thead>
+
+		<tfoot>
+			<tr>
+				<th scope="col" class="manage-column column-cb check-column">&nbsp;</th>
+				<th scope="col" class="manage-column column-name" style="width: 190px;"><?php _e( 'Component', 'buddypress' ); ?></th>
+				<th scope="col" class="manage-column column-description"><?php _e( 'Description', 'buddypress' ); ?></th>
+			</tr>
+		</tfoot>
+
+		<tbody id="the-list">
+
+			<?php if ( !empty( $current_components ) ) : ?>
+
+				<?php foreach ( $current_components as $name => $labels ) : ?>
+
+					<?php if ( !in_array( $name, array( 'core', 'members' ) ) ) :
+						$class = isset( $active_components[esc_attr( $name )] ) ? 'active' : 'inactive';
+					else :
+						$class = 'active';
+					endif; ?>
+
+					<tr id="<?php echo esc_attr( $name ); ?>" class="<?php echo esc_attr( $name ) . ' ' . esc_attr( $class ); ?>">
+						<th scope="row">
+
+							<?php if ( !in_array( $name, array( 'core', 'members' ) ) ) : ?>
+
+								<input type="checkbox" id="bp_components[<?php echo esc_attr( $name ); ?>]" name="bp_components[<?php echo esc_attr( $name ); ?>]" value="1"<?php checked( isset( $active_components[esc_attr( $name )] ) ); ?> />
+
+							<?php endif; ?>
+
+							<label class="screen-reader-text" for="bp_components[<?php echo esc_attr( $name ); ?>]"><?php sprintf( __( 'Select %s', 'buddypress' ), esc_html( $labels['title'] ) );  ?></label>
+						</th>
+						<td class="plugin-title" style="width: 190px;">
+							<span></span>
+							<strong><?php echo esc_html( $labels['title'] ); ?></strong>
+							<div class="row-actions-visible">
+
+							</div>
+						</td>
+
+						<td class="column-description desc">
+							<div class="plugin-description">
+								<p><?php echo $labels['description']; ?></p>
+							</div>
+							<div class="active second plugin-version-author-uri">
+
+							</div>
+						</td>
+					</tr>
+
+				<?php endforeach ?>
+
+			<?php else : ?>
+
+				<tr class="no-items">
+					<td class="colspanchange" colspan="3"><?php _e( 'No components found.', 'buddypress' ); ?></td>
+				</tr>
+
+			<?php endif; ?>
+
+		</tbody>
+	</table>
+
+	<input type="hidden" name="bp_components[members]" value="1" />
+
+	<?php
+}
+
+/**
+ * Handle saving the Component settings
+ *
+ * @since BuddyPress (1.6)
+ * @todo Use settings API when it supports saving network settings
+ */
+function bp_core_admin_components_settings_handler() {
+
+	// Bail if not saving settings
+	if ( ! isset( $_POST['bp-admin-component-submit'] ) )
+		return;
+
+	// Bail if nonce fails
+	if ( ! check_admin_referer( 'bp-admin-component-setup' ) )
+		return;
+
+	// Settings form submitted, now save the settings. First, set active components
+	if ( isset( $_POST['bp_components'] ) ) {
+
+		// Load up BuddyPress
+		$bp = buddypress();
+
+		// Save settings and upgrade schema
+		require_once( BP_PLUGIN_DIR . '/bp-core/admin/bp-core-schema.php' );
+
+		$submitted = stripslashes_deep( $_POST['bp_components'] );
+		$bp->active_components = bp_core_admin_get_active_components_from_submitted_settings( $submitted );
+
+		bp_core_install( $bp->active_components );
+		bp_core_add_page_mappings( $bp->active_components );
+		bp_update_option( 'bp-active-components', $bp->active_components );
+	}
+
+	// Where are we redirecting to?
+	$base_url = bp_get_admin_url( add_query_arg( array( 'page' => 'bp-components', 'updated' => 'true' ), 'admin.php' ) );
+
+	// Redirect
+	wp_redirect( $base_url );
+}
+add_action( 'bp_admin_init', 'bp_core_admin_components_settings_handler' );
+
+/**
+ * Calculates the components that should be active after save, based on submitted settings
+ *
+ * The way that active components must be set after saving your settings must
+ * be calculated differently depending on which of the Components subtabs you
+ * are coming from:
+ * - When coming from All or Active, the submitted checkboxes accurately
+ *   reflect the desired active components, so we simply pass them through
+ * - When coming from Inactive, components can only be activated - already
+ *   active components will not be passed in the $_POST global. Thus, we must
+ *   parse the newly activated components with the already active components
+ *   saved in the $bp global
+ * - When activating a Retired component, the situation is similar to Inactive.
+ * - When deactivating a Retired component, no value is passed in the $_POST
+ *   global (because the component settings are checkboxes). So, in order to
+ *   determine whether a retired component is being deactivated, we retrieve a
+ *   list of retired components, and check each one to ensure that its checkbox
+ *   is not present, before merging the submitted components with the active
+ *   ones.
+ *
+ * @since (BuddyPress) 1.7
+ *
+ * @param array This is the array of component settings coming from the POST
+ *   global. You should stripslashes_deep() before passing to this function
+ * @return array The calculated list of component settings
+ */
+function bp_core_admin_get_active_components_from_submitted_settings( $submitted ) {
+	$current_action = 'all';
+
+	if ( isset( $_GET['action'] ) && in_array( $_GET['action'], array( 'active', 'inactive', 'retired' ) ) ) {
+		$current_action = $_GET['action'];
+	}
+
+	$current_components = buddypress()->active_components;
+
+	switch ( $current_action ) {
+		case 'retired' :
+			$retired_components = bp_core_admin_get_components( 'retired' );
+			foreach ( array_keys( $retired_components ) as $retired_component ) {
+				if ( ! isset( $submitted[ $retired_component ] ) ) {
+					unset( $current_components[ $retired_component ] );
+				}
+			}
+			// fall through
+
+		case 'inactive' :
+			$components = array_merge( $submitted, $current_components );
+			break;
+
+		case 'all' :
+		case 'active' :
+		default :
+			$components = $submitted;
+			break;
+	}
+
+	return $components;
+}
+
+/**
+ * Return a list of component information, optionally filtered by type
+ *
+ * We use this information both to build the markup for the admin screens, as
+ * well as to do some processing on settings data submitted from those screens.
+ *
+ * @since (BuddyPress) 1.7
+ *
+ * @param string $type 'all', 'optional', 'retired', 'required'
+ * @return array An array of requested component data
+ */
+function bp_core_admin_get_components( $type = 'all' ) {
+
+	// Required components
+	$required_components = array(
+		'core' => array(
+			'title'       => __( 'BuddyPress Core', 'buddypress' ),
+			'description' => __( 'It&#8216;s what makes <del>time travel</del> BuddyPress possible!', 'buddypress' )
+		),
+		'members' => array(
+			'title'       => __( 'Community Members', 'buddypress' ),
+			'description' => __( 'Everything in a BuddyPress community revolves around its members.', 'buddypress' )
+		),
+	);
+
+	// Retired components
+	$retired_components = array(
+		'forums' => array(
+			'title'       => __( 'Group Forums', 'buddypress' ),
+			'description' => sprintf( __( 'BuddyPress Forums are retired. Use %s.', 'buddypress' ), '<a href="http://bbpress.org">bbPress</a>' )
+		),
+	);
+
+	// Optional core components
+	$optional_components = array(
+		'xprofile' => array(
+			'title'       => __( 'Extended Profiles', 'buddypress' ),
+			'description' => __( 'Customize your community with fully editable profile fields that allow your users to describe themselves.', 'buddypress' )
+		),
+		'settings' => array(
+			'title'       => __( 'Account Settings', 'buddypress' ),
+			'description' => __( 'Allow your users to modify their account and notification settings directly from within their profiles.', 'buddypress' )
+		),
+		'friends'  => array(
+			'title'       => __( 'Friend Connections', 'buddypress' ),
+			'description' => __( 'Let your users make connections so they can track the activity of others and focus on the people they care about the most.', 'buddypress' )
+		),
+		'messages' => array(
+			'title'       => __( 'Private Messaging', 'buddypress' ),
+			'description' => __( 'Allow your users to talk to each other directly and in private. Not just limited to one-on-one discussions, messages can be sent between any number of members.', 'buddypress' )
+		),
+		'activity' => array(
+			'title'       => __( 'Activity Streams', 'buddypress' ),
+			'description' => __( 'Global, personal, and group activity streams with threaded commenting, direct posting, favoriting, and @mentions, all with full RSS feed and email notification support.', 'buddypress' )
+		),
+		'notifications' => array(
+			'title'       => __( 'Notifications', 'buddypress' ),
+			'description' => __( 'Notify members of relevant activity with a toolbar bubble and/or via email, and allow them to customize their notification settings.', 'buddypress' )
+		),
+		'groups'   => array(
+			'title'       => __( 'User Groups', 'buddypress' ),
+			'description' => __( 'Groups allow your users to organize themselves into specific public, private or hidden sections with separate activity streams and member listings.', 'buddypress' )
+		),
+		'forums'   => array(
+			'title'       => __( 'Group Forums (Legacy)', 'buddypress' ),
+			'description' => __( 'Group forums allow for focused, bulletin-board style conversations.', 'buddypress' )
+		),
+		'blogs'    => array(
+			'title'       => __( 'Site Tracking', 'buddypress' ),
+			'description' => __( 'Record activity for new posts and comments from your site.', 'buddypress' )
+		)
+	);
+
+
+	// Add blogs tracking if multisite
+	if ( is_multisite() ) {
+		$optional_components['blogs']['description'] = __( 'Record activity for new sites, posts, and comments across your network.', 'buddypress' );
+	}
+
+	switch ( $type ) {
+		case 'required' :
+			$components = $required_components;
+			break;
+		case 'optional' :
+			$components = $optional_components;
+			break;
+		case 'retired' :
+			$components = $retired_components;
+			break;
+		case 'all' :
+		default :
+			$components = array_merge( $required_components, $optional_components, $retired_components );
+			break;
+
+	}
+
+	return $components;
+}
Index: /tags/1.9/bp-core/admin/bp-core-functions.php
===================================================================
--- /tags/1.9/bp-core/admin/bp-core-functions.php	(revision 7684)
+++ /tags/1.9/bp-core/admin/bp-core-functions.php	(revision 7684)
@@ -0,0 +1,787 @@
+<?php
+
+/**
+ * BuddyPress Common Admin Functions
+ *
+ * @package BuddyPress
+ * @subpackage CoreAdministration
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/** Menu **********************************************************************/
+
+/**
+ * Initializes the wp-admin area "BuddyPress" menus and sub menus.
+ *
+ * @package BuddyPress Core
+ * @uses bp_current_user_can() returns true if the current user is a site admin, false if not
+ */
+function bp_core_admin_menu_init() {
+	add_action( bp_core_admin_hook(), 'bp_core_add_admin_menu', 9 );
+}
+
+/**
+ * In BP 1.6, the top-level admin menu was removed. For backpat, this function
+ * keeps the top-level menu if a plugin has registered a menu into the old
+ * 'bp-general-settings' menu.
+ *
+ * The old "bp-general-settings" page was renamed "bp-components".
+ *
+ * @global array $_parent_pages
+ * @global array $_registered_pages
+ * @global array $submenu
+ * @since BuddyPress (1.6)
+ */
+function bp_core_admin_backpat_menu() {
+	global $_parent_pages, $_registered_pages, $submenu;
+
+	// If there's no bp-general-settings menu (perhaps because the current
+	// user is not an Administrator), there's nothing to do here
+	if ( ! isset( $submenu['bp-general-settings'] ) ) {
+		return;
+	}
+
+	/**
+	 * By default, only the core "Help" submenu is added under the top-level BuddyPress menu.
+	 * This means that if no third-party plugins have registered their admin pages into the
+	 * 'bp-general-settings' menu, it will only contain one item. Kill it.
+	 */
+	if ( 1 != count( $submenu['bp-general-settings'] ) ) {
+		return;
+	}
+
+	// This removes the top-level menu
+	remove_submenu_page( 'bp-general-settings', 'bp-general-settings' );
+	remove_menu_page( 'bp-general-settings' );
+
+	// These stop people accessing the URL directly
+	unset( $_parent_pages['bp-general-settings'] );
+	unset( $_registered_pages['toplevel_page_bp-general-settings'] );
+}
+add_action( bp_core_admin_hook(), 'bp_core_admin_backpat_menu', 999 );
+
+/**
+ * This tells WP to highlight the Settings > BuddyPress menu item,
+ * regardless of which actual BuddyPress admin screen we are on.
+ *
+ * The conditional prevents the behaviour when the user is viewing the
+ * backpat "Help" page, the Activity page, or any third-party plugins.
+ *
+ * @global string $plugin_page
+ * @global array $submenu
+ * @since BuddyPress (1.6)
+ */
+function bp_core_modify_admin_menu_highlight() {
+	global $plugin_page, $submenu_file;
+
+	// This tweaks the Settings subnav menu to show only one BuddyPress menu item
+	if ( ! in_array( $plugin_page, array( 'bp-activity', 'bp-general-settings', ) ) )
+		$submenu_file = 'bp-components';
+}
+
+/**
+ * Generates markup for a fallback top-level BuddyPress menu page, if the site is running
+ * a legacy plugin which hasn't been updated. If the site is up to date, this page
+ * will never appear.
+ *
+ * @see bp_core_admin_backpat_menu()
+ * @since BuddyPress (1.6)
+ * @todo Add convenience links into the markup once new positions are finalised.
+ */
+function bp_core_admin_backpat_page() {
+	$url          = bp_core_do_network_admin() ? network_admin_url( 'settings.php' ) : admin_url( 'options-general.php' );
+	$settings_url = add_query_arg( 'page', 'bp-components', $url ); ?>
+
+	<div class="wrap">
+		<?php screen_icon( 'buddypress' ); ?>
+		<h2><?php _e( 'Why have all my BuddyPress menus disappeared?', 'buddypress' ); ?></h2>
+
+		<p><?php _e( "Don't worry! We've moved the BuddyPress options into more convenient and easier to find locations. You're seeing this page because you are running a legacy BuddyPress plugin which has not been updated.", 'buddypress' ); ?></p>
+		<p><?php printf( __( 'Components, Pages, Settings, and Forums, have been moved to <a href="%s">Settings &gt; BuddyPress</a>. Profile Fields has been moved into the <a href="%s">Users</a> menu.', 'buddypress' ), esc_url( $settings_url ), bp_get_admin_url( 'users.php?page=bp-profile-setup' ) ); ?></p>
+	</div>
+
+	<?php
+}
+
+/** Notices *******************************************************************/
+
+/**
+ * Print admin messages to admin_notices or network_admin_notices
+ *
+ * BuddyPress combines all its messages into a single notice, to avoid a preponderance of yellow
+ * boxes.
+ *
+ * @package BuddyPress Core
+ * @since BuddyPress (1.5)
+ *
+ * @uses bp_current_user_can() to check current user permissions before showing the notices
+ * @uses bp_is_root_blog()
+ */
+function bp_core_print_admin_notices() {
+
+	// Only the super admin should see messages
+	if ( ! bp_current_user_can( 'bp_moderate' ) ) {
+		return;
+	}
+
+	// On multisite installs, don't show on a non-root blog, unless
+	// 'do_network_admin' is overridden.
+	if ( is_multisite() && bp_core_do_network_admin() && ! bp_is_root_blog() ) {
+		return;
+	}
+
+	// Get the admin notices
+	$admin_notices = buddypress()->admin->notices;
+
+	// Show the messages
+	if ( !empty( $admin_notices ) ) : ?>
+
+		<div id="message" class="updated fade">
+
+			<?php foreach ( $admin_notices as $notice ) : ?>
+
+				<p><?php echo $notice; ?></p>
+
+			<?php endforeach; ?>
+
+		</div>
+
+	<?php endif;
+}
+add_action( 'admin_notices',         'bp_core_print_admin_notices' );
+add_action( 'network_admin_notices', 'bp_core_print_admin_notices' );
+
+/**
+ * Add an admin notice to the BP queue
+ *
+ * Messages added with this function are displayed in BuddyPress's general purpose admin notices
+ * box. It is recommended that you hook this function to admin_init, so that your messages are
+ * loaded in time.
+ *
+ * @package BuddyPress Core
+ * @since BuddyPress (1.5)
+ *
+ * @param string $notice The notice you are adding to the queue
+ */
+function bp_core_add_admin_notice( $notice = '' ) {
+
+	// Do not add if the notice is empty
+	if ( empty( $notice ) ) {
+		return;
+	}
+
+	// Double check the object before referencing it
+	if ( ! isset( buddypress()->admin->notices ) ) {
+		buddypress()->admin->notices = array();
+	}
+
+	// Add the notice
+	buddypress()->admin->notices[] = $notice;
+}
+
+/**
+ * Verify that some BP prerequisites are set up properly, and notify the admin if not
+ *
+ * On every Dashboard page, this function checks the following:
+ *   - that pretty permalinks are enabled
+ *   - that every BP component that needs a WP page for a directory has one
+ *   - that no WP page has multiple BP components associated with it
+ * The administrator will be shown a notice for each check that fails.
+ *
+ * @global WPDB $wpdb WordPress DB object
+ * @global WP_Rewrite $wp_rewrite
+ * @since BuddyPress (1.2)
+ */
+function bp_core_activation_notice() {
+	global $wpdb, $wp_rewrite;
+
+	$bp = buddypress();
+
+	// Only the super admin gets warnings
+	if ( ! bp_current_user_can( 'bp_moderate' ) ) {
+		return;
+	}
+
+	// On multisite installs, don't load on a non-root blog, unless do_network_admin is overridden
+	if ( is_multisite() && bp_core_do_network_admin() && !bp_is_root_blog() ) {
+		return;
+	}
+
+	// Bail if in network admin, and BuddyPress is not network activated
+	if ( is_network_admin() && ! bp_is_network_activated() ) {
+		return;
+	}
+
+	// Bail in network admin
+	if ( is_user_admin() ) {
+		return;
+	}
+
+	/**
+	 * Check to make sure that the blog setup routine has run. This can't happen during the
+	 * wizard because of the order which the components are loaded. We check for multisite here
+	 * on the off chance that someone has activated the blogs component and then disabled MS
+	 */
+	if ( bp_is_active( 'blogs' ) ) {
+		$count = $wpdb->get_var( "SELECT COUNT(*) FROM {$bp->blogs->table_name}" );
+
+		if ( empty( $count ) ) {
+			bp_blogs_record_existing_blogs();
+		}
+	}
+
+	/**
+	 * Are pretty permalinks enabled?
+	 */
+	if ( isset( $_POST['permalink_structure'] ) ) {
+		return;
+	}
+
+	if ( empty( $wp_rewrite->permalink_structure ) ) {
+		bp_core_add_admin_notice( sprintf( __( '<strong>BuddyPress is almost ready</strong>. You must <a href="%s">update your permalink structure</a> to something other than the default for it to work.', 'buddypress' ), admin_url( 'options-permalink.php' ) ) );
+	}
+
+	/**
+	 * Check for orphaned BP components (BP component is enabled, no WP page exists)
+	 */
+	$orphaned_components = array();
+	$wp_page_components  = array();
+
+	// Only components with 'has_directory' require a WP page to function
+	foreach( array_keys( $bp->loaded_components ) as $component_id ) {
+		if ( !empty( $bp->{$component_id}->has_directory ) ) {
+			$wp_page_components[] = array(
+				'id'   => $component_id,
+				'name' => isset( $bp->{$component_id}->name ) ? $bp->{$component_id}->name : ucwords( $bp->{$component_id}->id )
+			);
+		}
+	}
+
+	// Activate and Register are special cases. They are not components but they need WP pages.
+	// If user registration is disabled, we can skip this step.
+	if ( bp_get_signup_allowed() ) {
+		$wp_page_components[] = array(
+			'id'   => 'activate',
+			'name' => __( 'Activate', 'buddypress' )
+		);
+
+		$wp_page_components[] = array(
+			'id'   => 'register',
+			'name' => __( 'Register', 'buddypress' )
+		);
+	}
+
+	// On the first admin screen after a new installation, this isn't set, so grab it to supress a misleading error message.
+	if ( empty( $bp->pages->members ) ) {
+		$bp->pages = bp_core_get_directory_pages();
+	}
+
+	foreach( $wp_page_components as $component ) {
+		if ( !isset( $bp->pages->{$component['id']} ) ) {
+			$orphaned_components[] = $component['name'];
+		}
+	}
+
+	// Special case: If the Forums component is orphaned, but the bbPress 1.x installation is
+	// not correctly set up, don't show a nag. (In these cases, it's probably the case that the
+	// user is using bbPress 2.x; see https://buddypress.trac.wordpress.org/ticket/4292
+	if ( isset( $bp->forums->name ) && in_array( $bp->forums->name, $orphaned_components ) && !bp_forums_is_installed_correctly() ) {
+		$forum_key = array_search( $bp->forums->name, $orphaned_components );
+		unset( $orphaned_components[$forum_key] );
+		$orphaned_components = array_values( $orphaned_components );
+	}
+
+	if ( !empty( $orphaned_components ) ) {
+		$admin_url = bp_get_admin_url( add_query_arg( array( 'page' => 'bp-page-settings' ), 'admin.php' ) );
+		$notice    = sprintf( __( 'The following active BuddyPress Components do not have associated WordPress Pages: %2$s. <a href="%1$s">Repair</a>', 'buddypress' ), $admin_url, '<strong>' . implode( '</strong>, <strong>', $orphaned_components ) . '</strong>' );
+
+		bp_core_add_admin_notice( $notice );
+	}
+
+	// BP components cannot share a single WP page. Check for duplicate assignments, and post a message if found.
+	$dupe_names = array();
+	$page_ids   = (array)bp_core_get_directory_page_ids();
+	$dupes      = array_diff_assoc( $page_ids, array_unique( $page_ids ) );
+
+	if ( !empty( $dupes ) ) {
+		foreach( array_keys( $dupes ) as $dupe_component ) {
+			$dupe_names[] = $bp->pages->{$dupe_component}->title;
+		}
+
+		// Make sure that there are no duplicate duplicates :)
+		$dupe_names = array_unique( $dupe_names );
+	}
+
+	// If there are duplicates, post a message about them
+	if ( !empty( $dupe_names ) ) {
+		$admin_url = bp_get_admin_url( add_query_arg( array( 'page' => 'bp-page-settings' ), 'admin.php' ) );
+		$notice    = sprintf( __( 'Each BuddyPress Component needs its own WordPress page. The following WordPress Pages have more than one component associated with them: %2$s. <a href="%1$s">Repair</a>', 'buddypress' ), $admin_url, '<strong>' . implode( '</strong>, <strong>', $dupe_names ) . '</strong>' );
+
+		bp_core_add_admin_notice( $notice );
+	}
+}
+
+/**
+ * Redirect user to BuddyPress's What's New page on activation
+ *
+ * @since BuddyPress (1.7)
+ *
+ * @internal Used internally to redirect BuddyPress to the about page on activation
+ *
+ * @uses get_transient() To see if transient to redirect exists
+ * @uses delete_transient() To delete the transient if it exists
+ * @uses is_network_admin() To bail if being network activated
+ * @uses wp_safe_redirect() To redirect
+ * @uses add_query_arg() To help build the URL to redirect to
+ * @uses admin_url() To get the admin URL to index.php
+ */
+function bp_do_activation_redirect() {
+
+	// Bail if no activation redirect
+	if ( ! get_transient( '_bp_activation_redirect' ) )
+		return;
+
+	// Delete the redirect transient
+	delete_transient( '_bp_activation_redirect' );
+
+	// Bail if activating from network, or bulk
+	if ( isset( $_GET['activate-multi'] ) )
+		return;
+
+	$query_args = array( 'page' => 'bp-about' );
+	if ( get_transient( '_bp_is_new_install' ) ) {
+		$query_args['is_new_install'] = '1';
+		delete_transient( '_bp_is_new_install' );
+	}
+
+	// Redirect to BuddyPress about page
+	wp_safe_redirect( add_query_arg( $query_args, bp_get_admin_url( 'index.php' ) ) );
+}
+
+/** UI/Styling ****************************************************************/
+
+/**
+ * Output the tabs in the admin area
+ *
+ * @since BuddyPress (1.5)
+ * @param string $active_tab Name of the tab that is active
+ */
+function bp_core_admin_tabs( $active_tab = '' ) {
+
+	// Declare local variables
+	$tabs_html    = '';
+	$idle_class   = 'nav-tab';
+	$active_class = 'nav-tab nav-tab-active';
+
+	// Setup core admin tabs
+	$tabs = array(
+		'0' => array(
+			'href' => bp_get_admin_url( add_query_arg( array( 'page' => 'bp-components' ), 'admin.php' ) ),
+			'name' => __( 'Components', 'buddypress' )
+		),
+		'1' => array(
+			'href' => bp_get_admin_url( add_query_arg( array( 'page' => 'bp-page-settings' ), 'admin.php' ) ),
+			'name' => __( 'Pages', 'buddypress' )
+		),
+		'2' => array(
+			'href' => bp_get_admin_url( add_query_arg( array( 'page' => 'bp-settings' ), 'admin.php' ) ),
+			'name' => __( 'Settings', 'buddypress' )
+		)
+	);
+
+	// If forums component is active, add additional tab
+	if ( bp_is_active( 'forums' ) && class_exists( 'BP_Forums_Component' ) ) {
+
+		// enqueue thickbox
+		wp_enqueue_script( 'thickbox' );
+		wp_enqueue_style( 'thickbox' );
+
+		$tabs['3'] = array(
+			'href' => bp_get_admin_url( add_query_arg( array( 'page' => 'bb-forums-setup'  ), 'admin.php' ) ),
+			'name' => __( 'Forums', 'buddypress' )
+		);
+	}
+
+	// Allow the tabs to be filtered
+	$tabs = apply_filters( 'bp_core_admin_tabs', $tabs );
+
+	// Loop through tabs and build navigation
+	foreach ( array_values( $tabs ) as $tab_data ) {
+		$is_current = (bool) ( $tab_data['name'] == $active_tab );
+		$tab_class  = $is_current ? $active_class : $idle_class;
+		$tabs_html .= '<a href="' . esc_url( $tab_data['href'] ) . '" class="' . esc_attr( $tab_class ) . '">' . esc_html( $tab_data['name'] ) . '</a>';
+	}
+
+	// Output the tabs
+	echo $tabs_html;
+
+	// Do other fun things
+	do_action( 'bp_admin_tabs' );
+}
+
+/** Help **********************************************************************/
+
+/**
+ * adds contextual help to BuddyPress admin pages
+ *
+ * @since BuddyPress (1.7)
+ * @todo Make this part of the BP_Component class and split into each component
+ */
+function bp_core_add_contextual_help( $screen = '' ) {
+
+	$screen = get_current_screen();
+
+	switch ( $screen->id ) {
+
+		// Compontent page
+		case 'settings_page_bp-components' :
+
+			// help tabs
+			$screen->add_help_tab( array(
+				'id'      => 'bp-comp-overview',
+				'title'   => __( 'Overview' ),
+				'content' => bp_core_add_contextual_help_content( 'bp-comp-overview' ),
+			) );
+
+			// help panel - sidebar links
+			$screen->set_help_sidebar(
+				'<p><strong>' . __( 'For more information:', 'buddypress' ) . '</strong></p>' .
+				'<p>' . __( '<a href="http://codex.buddypress.org/getting-started/configure-buddypress-components/#settings-buddypress-components">Managing Components</a>', 'buddypress' ) . '</p>' .
+				'<p>' . __( '<a href="http://buddypress.org/support/">Support Forums</a>', 'buddypress' ) . '</p>'
+			);
+			break;
+
+		// Pages page
+		case 'settings_page_bp-page-settings' :
+
+			// Help tabs
+			$screen->add_help_tab( array(
+				'id' => 'bp-page-overview',
+				'title' => __( 'Overview' ),
+				'content' => bp_core_add_contextual_help_content( 'bp-page-overview' ),
+			) );
+
+			// Help panel - sidebar links
+			$screen->set_help_sidebar(
+				'<p><strong>' . __( 'For more information:', 'buddypress' ) . '</strong></p>' .
+				'<p>' . __( '<a href="http://codex.buddypress.org/getting-started/configure-buddypress-components/#settings-buddypress-pages">Managing Pages</a>', 'buddypress' ) . '</p>' .
+				'<p>' . __( '<a href="http://buddypress.org/support/">Support Forums</a>', 'buddypress' ) . '</p>'
+			);
+
+			break;
+
+		// Settings page
+		case 'settings_page_bp-settings' :
+
+			// Help tabs
+			$screen->add_help_tab( array(
+				'id'      => 'bp-settings-overview',
+				'title'   => __( 'Overview' ),
+				'content' => bp_core_add_contextual_help_content( 'bp-settings-overview' ),
+			) );
+
+			// Help panel - sidebar links
+			$screen->set_help_sidebar(
+				'<p><strong>' . __( 'For more information:', 'buddypress' ) . '</strong></p>' .
+				'<p>' . __( '<a href="http://codex.buddypress.org/getting-started/configure-buddypress-components/#settings-buddypress-settings">Managing Settings</a>', 'buddypress' ) . '</p>' .
+				'<p>' . __( '<a href="http://buddypress.org/support/">Support Forums</a>', 'buddypress' ) . '</p>'
+			);
+
+			break;
+
+		// Profile fields page
+		case 'users_page_bp-profile-overview' :
+
+			// Help tabs
+			$screen->add_help_tab( array(
+				'id'      => 'bp-profile-overview',
+				'title'   => __( 'Overview' ),
+				'content' => bp_core_add_contextual_help_content( 'bp-profile-overview' ),
+			) );
+
+			// Help panel - sidebar links
+			$screen->set_help_sidebar(
+				'<p><strong>' . __( 'For more information:', 'buddypress' ) . '</strong></p>' .
+				'<p>' . __( '<a href="http://codex.buddypress.org/getting-started/configure-buddypress-components/#users-profile-fields">Managing Profile Fields</a>', 'buddypress' ) . '</p>' .
+				'<p>' . __( '<a href="http://buddypress.org/support/">Support Forums</a>', 'buddypress' ) . '</p>'
+			);
+
+			break;
+	}
+}
+add_action( 'contextual_help', 'bp_core_add_contextual_help' );
+
+/**
+ * renders contextual help content to contextual help tabs
+ *
+ * @since BuddyPress (1.7)
+ */
+function bp_core_add_contextual_help_content( $tab = '' ) {
+
+	switch ( $tab ) {
+		case 'bp-comp-overview' :
+			$retval = __( 'By default, all BuddyPress components are enabled. You can selectively disable any of the components by using the form. Your BuddyPress installation will continue to function. However, the features of the disabled components will no longer be accessible to anyone using the site.', 'buddypress' );
+			break;
+
+		case 'bp-page-overview' :
+			$retval = __( 'BuddyPress Components use WordPress Pages for their root directory/archive pages. Here you can change the page associations for each active component.', 'buddypress' );
+			break;
+
+		case 'bp-settings-overview' :
+			$retval = __( 'Extra configuration settings.', 'buddypress' );
+			break;
+
+		case 'bp-profile-overview' :
+			$retval = __( 'Your users will distinguish themselves through their profile page. Create relevant profile fields that will show on each users profile.</br></br>Note: Any fields in the first group will appear on the signup page.', 'buddypress' );
+			break;
+
+		default:
+			$retval = false;
+			break;
+	}
+
+	// Wrap text in a paragraph tag
+	if ( !empty( $retval ) ) {
+		$retval = '<p>' . $retval . '</p>';
+	}
+
+	return $retval;
+}
+
+/** Separator *****************************************************************/
+
+/**
+ * Add a separator to the WordPress admin menus
+ *
+ * @since BuddyPress (1.7)
+ *
+ * @uses bp_current_user_can() To check users capability on root blog
+ */
+function bp_admin_separator() {
+
+	// Bail if BuddyPress is not network activated and viewing network admin
+	if ( is_network_admin() && ! bp_is_network_activated() )
+		return;
+
+	// Bail if BuddyPress is network activated and viewing site admin
+	if ( ! is_network_admin() && bp_is_network_activated() )
+		return;
+
+	// Prevent duplicate separators when no core menu items exist
+	if ( ! bp_current_user_can( 'bp_moderate' ) )
+		return;
+
+	// Bail if there are no components with admin UI's. Hardcoded for now, until
+	// there's a real API for determining this later.
+	if ( ! bp_is_active( 'activity' ) && ! bp_is_active( 'groups' ) )
+		return;
+
+	global $menu;
+
+	$menu[] = array( '', 'read', 'separator-buddypress', '', 'wp-menu-separator buddypress' );
+}
+
+/**
+ * Tell WordPress we have a custom menu order
+ *
+ * @since BuddyPress (1.7)
+ *
+ * @param bool $menu_order Menu order
+ * @uses bp_current_user_can() To check users capability on root blog
+ * @return bool Always true
+ */
+function bp_admin_custom_menu_order( $menu_order = false ) {
+
+	// Bail if user cannot see admin pages
+	if ( ! bp_current_user_can( 'bp_moderate' ) )
+		return $menu_order;
+
+	return true;
+}
+
+/**
+ * Move our custom separator above our custom post types
+ *
+ * @since BuddyPress (1.7)
+ *
+ * @param array $menu_order Menu Order
+ * @uses bp_current_user_can() To check users capability on root blog
+ * @return array Modified menu order
+ */
+function bp_admin_menu_order( $menu_order = array() ) {
+
+	// Bail if user cannot see admin pages
+	if ( empty( $menu_order ) || ! bp_current_user_can( 'bp_moderate' ) )
+		return $menu_order;
+
+	// Initialize our custom order array
+	$bp_menu_order = array();
+
+	// Menu values
+	$last_sep     = is_network_admin() ? 'separator1' : 'separator2';
+
+	// Filter the custom admin menus
+	$custom_menus = (array) apply_filters( 'bp_admin_menu_order', array() );
+
+	// Bail if no components have top level admin pages
+	if ( empty( $custom_menus ) )
+		return $menu_order;
+
+	// Add our separator to beginning of array
+	array_unshift( $custom_menus, 'separator-buddypress' );
+
+	// Loop through menu order and do some rearranging
+	foreach ( (array) $menu_order as $item ) {
+
+		// Position BuddyPress menus above appearance
+		if ( $last_sep == $item ) {
+
+			// Add our custom menus
+			foreach( (array) $custom_menus as $custom_menu ) {
+				if ( array_search( $custom_menu, $menu_order ) ) {
+					$bp_menu_order[] = $custom_menu;
+				}
+			}
+
+			// Add the appearance separator
+			$bp_menu_order[] = $last_sep;
+
+		// Skip our menu items
+		} elseif ( ! in_array( $item, $custom_menus ) ) {
+			$bp_menu_order[] = $item;
+		}
+	}
+
+	// Return our custom order
+	return $bp_menu_order;
+}
+
+/** Utility  *****************************************************************/
+
+/**
+ * When using a WP_List_Table, get the currently selected bulk action
+ *
+ * WP_List_Tables have bulk actions at the top and at the bottom of the tables,
+ * and the inputs have different keys in the $_REQUEST array. This function
+ * reconciles the two values and returns a single action being performed.
+ *
+ * @since BuddyPress (1.7)
+ * @return string
+ */
+function bp_admin_list_table_current_bulk_action() {
+
+	$action = ! empty( $_REQUEST['action'] ) ? $_REQUEST['action'] : '';
+
+	// If the bottom is set, let it override the action
+	if ( ! empty( $_REQUEST['action2'] ) && $_REQUEST['action2'] != "-1" ) {
+		$action = $_REQUEST['action2'];
+	}
+
+	return $action;
+}
+
+/** Menus *********************************************************************/
+
+/**
+ * Register meta box and associated JS for BuddyPress WP Nav Menu .
+ *
+ * @since BuddyPress (1.9.0)
+ */
+function bp_admin_wp_nav_menu_meta_box() {
+	if ( ! bp_is_root_blog() ) {
+		return;
+	}
+
+	add_meta_box( 'add-buddypress-nav-menu', __( 'BuddyPress', 'buddypress' ), 'bp_admin_do_wp_nav_menu_meta_box', 'nav-menus', 'side', 'default' );
+
+	add_action( 'admin_print_footer_scripts', 'bp_admin_wp_nav_menu_restrict_items' );
+}
+
+/**
+ * Build and populate the BuddyPress accordion on Appearance > Menus.
+ *
+ * @since BuddyPress (1.9.0)
+ *
+ * @global $nav_menu_selected_id
+ */
+function bp_admin_do_wp_nav_menu_meta_box() {
+	global $nav_menu_selected_id;
+
+	$walker = new BP_Walker_Nav_Menu_Checklist( false );
+	$args   = array( 'walker' => $walker );
+
+	$post_type_name = 'buddypress';
+
+	$tabs = array();
+
+	$tabs['loggedin']['label']  = __( 'Logged-In', 'buddypress' );
+	$tabs['loggedin']['pages']  = bp_nav_menu_get_loggedin_pages();
+
+	$tabs['loggedout']['label'] = __( 'Logged-Out', 'buddypress' );
+	$tabs['loggedout']['pages'] = bp_nav_menu_get_loggedout_pages();
+
+	?>
+
+	<div id="buddypress-menu" class="posttypediv">
+		<h4><?php _e( 'Logged-In', 'buddypress' ) ?></h4>
+		<p><?php _e( '<em>Logged-In</em> links are relative to the current user, and are not visible to visitors who are not logged in.', 'buddypress' ) ?></p>
+
+		<div id="tabs-panel-posttype-<?php echo $post_type_name; ?>-loggedin" class="tabs-panel tabs-panel-active">
+			<ul id="buddypress-menu-checklist-loggedin" class="categorychecklist form-no-clear">
+				<?php echo walk_nav_menu_tree( array_map( 'wp_setup_nav_menu_item', $tabs['loggedin']['pages'] ), 0, (object) $args );?>
+			</ul>
+		</div>
+
+		<h4><?php _e( 'Logged-Out', 'buddypress' ) ?></h4>
+		<p><?php _e( '<em>Logged-Out</em> links are not visible to users who are logged in.', 'buddypress' ) ?></p>
+
+		<div id="tabs-panel-posttype-<?php echo $post_type_name; ?>-loggedout" class="tabs-panel tabs-panel-active">
+			<ul id="buddypress-menu-checklist-loggedout" class="categorychecklist form-no-clear">
+				<?php echo walk_nav_menu_tree( array_map( 'wp_setup_nav_menu_item', $tabs['loggedout']['pages'] ), 0, (object) $args );?>
+			</ul>
+		</div>
+
+		<p class="button-controls">
+			<span class="add-to-menu">
+				<input type="submit"<?php wp_nav_menu_disabled_check( $nav_menu_selected_id ); ?> class="button-secondary submit-add-to-menu right" value="<?php esc_attr_e( 'Add to Menu' ); ?>" name="add-custom-menu-item" id="submit-buddypress-menu" />
+				<span class="spinner"></span>
+			</span>
+		</p>
+	</div><!-- /#buddypress-menu -->
+
+	<?php
+}
+
+/**
+ * Restrict various items from view if editing a BuddyPress menu.
+ *
+ * If a person is editing a BP menu item, that person should not be able to
+ * see or edit the following fields:
+ *
+ * - CSS Classes - We use the 'bp-menu' CSS class to determine if the
+ *   menu item belongs to BP, so we cannot allow manipulation of this field to
+ *   occur.
+ * - URL - This field is automatically generated by BP on output, so this
+ *   field is useless and can cause confusion.
+ *
+ * Note: These restrictions are only enforced if javascript is enabled.
+ *
+ * @since BuddyPress (1.9.0)
+ */
+function bp_admin_wp_nav_menu_restrict_items() {
+?>
+	<script type="text/javascript">
+	jQuery( '#menu-to-edit').on( 'click', 'a.item-edit', function() {
+		var settings  = jQuery(this).closest( '.menu-item-bar' ).next( '.menu-item-settings' );
+		var css_class = settings.find( '.edit-menu-item-classes' );
+
+		if( css_class.val().indexOf( 'bp-menu' ) === 0 ) {
+			css_class.attr( 'readonly', 'readonly' );
+			settings.find( '.field-url' ).css( 'display', 'none' );
+		}
+	});
+	</script>
+<?php
+}
Index: /tags/1.9/bp-core/admin/bp-core-schema.php
===================================================================
--- /tags/1.9/bp-core/admin/bp-core-schema.php	(revision 7684)
+++ /tags/1.9/bp-core/admin/bp-core-schema.php	(revision 7684)
@@ -0,0 +1,345 @@
+<?php
+/**
+ * BuddyPress DB schema
+ *
+ * @package BuddyPress
+ * @subpackage CoreAdministration
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+function bp_core_set_charset() {
+	global $wpdb;
+
+	require_once( ABSPATH . 'wp-admin/includes/upgrade.php' );
+
+	// BuddyPress component DB schema
+	return !empty( $wpdb->charset ) ? "DEFAULT CHARACTER SET {$wpdb->charset}" : '';
+}
+
+function bp_core_install( $active_components = false ) {
+
+	if ( empty( $active_components ) )
+		$active_components = apply_filters( 'bp_active_components', bp_get_option( 'bp-active-components' ) );
+
+	// Notifications
+	if ( !empty( $active_components['notifications'] ) )
+		bp_core_install_notifications();
+
+	// Activity Streams
+	if ( !empty( $active_components['activity'] ) )
+		bp_core_install_activity_streams();
+
+	// Friend Connections
+	if ( !empty( $active_components['friends'] ) )
+		bp_core_install_friends();
+
+	// Extensible Groups
+	if ( !empty( $active_components['groups'] ) )
+		bp_core_install_groups();
+
+	// Private Messaging
+	if ( !empty( $active_components['messages'] ) )
+		bp_core_install_private_messaging();
+
+	// Extended Profiles
+	if ( !empty( $active_components['xprofile'] ) )
+		bp_core_install_extended_profiles();
+
+	// Blog tracking
+	if ( !empty( $active_components['blogs'] ) )
+		bp_core_install_blog_tracking();
+}
+
+function bp_core_install_notifications() {
+
+	$sql             = array();
+	$charset_collate = bp_core_set_charset();
+	$bp_prefix       = bp_core_get_table_prefix();
+
+	$sql[] = "CREATE TABLE {$bp_prefix}bp_notifications (
+	  		    id bigint(20) NOT NULL AUTO_INCREMENT PRIMARY KEY,
+			    user_id bigint(20) NOT NULL,
+			    item_id bigint(20) NOT NULL,
+			    secondary_item_id bigint(20),
+	  		    component_name varchar(75) NOT NULL,
+			    component_action varchar(75) NOT NULL,
+	  		    date_notified datetime NOT NULL,
+			    is_new bool NOT NULL DEFAULT 0,
+		        KEY item_id (item_id),
+			    KEY secondary_item_id (secondary_item_id),
+			    KEY user_id (user_id),
+			    KEY is_new (is_new),
+			    KEY component_name (component_name),
+	 	   	    KEY component_action (component_action),
+			    KEY useritem (user_id,is_new)
+		       ) {$charset_collate};";
+
+	dbDelta( $sql );
+}
+
+function bp_core_install_activity_streams() {
+
+	$sql             = array();
+	$charset_collate = bp_core_set_charset();
+	$bp_prefix       = bp_core_get_table_prefix();
+
+	$sql[] = "CREATE TABLE {$bp_prefix}bp_activity (
+				id bigint(20) NOT NULL AUTO_INCREMENT PRIMARY KEY,
+				user_id bigint(20) NOT NULL,
+				component varchar(75) NOT NULL,
+				type varchar(75) NOT NULL,
+				action text NOT NULL,
+				content longtext NOT NULL,
+				primary_link varchar(255) NOT NULL,
+				item_id bigint(20) NOT NULL,
+				secondary_item_id bigint(20) DEFAULT NULL,
+				date_recorded datetime NOT NULL,
+				hide_sitewide bool DEFAULT 0,
+				mptt_left int(11) NOT NULL DEFAULT 0,
+				mptt_right int(11) NOT NULL DEFAULT 0,
+				is_spam tinyint(1) NOT NULL DEFAULT 0,
+				KEY date_recorded (date_recorded),
+				KEY user_id (user_id),
+				KEY item_id (item_id),
+				KEY secondary_item_id (secondary_item_id),
+				KEY component (component),
+				KEY type (type),
+				KEY mptt_left (mptt_left),
+				KEY mptt_right (mptt_right),
+				KEY hide_sitewide (hide_sitewide),
+				KEY is_spam (is_spam)
+			) {$charset_collate};";
+
+	$sql[] = "CREATE TABLE {$bp_prefix}bp_activity_meta (
+				id bigint(20) NOT NULL AUTO_INCREMENT PRIMARY KEY,
+				activity_id bigint(20) NOT NULL,
+				meta_key varchar(255) DEFAULT NULL,
+				meta_value longtext DEFAULT NULL,
+				KEY activity_id (activity_id),
+				KEY meta_key (meta_key)
+		   	   ) {$charset_collate};";
+
+	dbDelta( $sql );
+}
+
+function bp_core_install_friends() {
+
+	$sql             = array();
+	$charset_collate = bp_core_set_charset();
+	$bp_prefix       = bp_core_get_table_prefix();
+
+	$sql[] = "CREATE TABLE {$bp_prefix}bp_friends (
+	  		    id bigint(20) NOT NULL AUTO_INCREMENT PRIMARY KEY,
+	  		    initiator_user_id bigint(20) NOT NULL,
+	  		    friend_user_id bigint(20) NOT NULL,
+	  		    is_confirmed bool DEFAULT 0,
+			    is_limited bool DEFAULT 0,
+	  		    date_created datetime NOT NULL,
+		        KEY initiator_user_id (initiator_user_id),
+		        KEY friend_user_id (friend_user_id)
+	 	       ) {$charset_collate};";
+
+	dbDelta( $sql );
+}
+
+function bp_core_install_groups() {
+
+	$sql             = array();
+	$charset_collate = bp_core_set_charset();
+	$bp_prefix       = bp_core_get_table_prefix();
+
+	$sql[] = "CREATE TABLE {$bp_prefix}bp_groups (
+		  		id bigint(20) NOT NULL AUTO_INCREMENT PRIMARY KEY,
+				creator_id bigint(20) NOT NULL,
+		  		name varchar(100) NOT NULL,
+		  		slug varchar(200) NOT NULL,
+		  		description longtext NOT NULL,
+				status varchar(10) NOT NULL DEFAULT 'public',
+				enable_forum tinyint(1) NOT NULL DEFAULT '1',
+				date_created datetime NOT NULL,
+			    KEY creator_id (creator_id),
+			    KEY status (status)
+		 	   ) {$charset_collate};";
+
+	$sql[] = "CREATE TABLE {$bp_prefix}bp_groups_members (
+		  		id bigint(20) NOT NULL AUTO_INCREMENT PRIMARY KEY,
+				group_id bigint(20) NOT NULL,
+				user_id bigint(20) NOT NULL,
+				inviter_id bigint(20) NOT NULL,
+				is_admin tinyint(1) NOT NULL DEFAULT '0',
+				is_mod tinyint(1) NOT NULL DEFAULT '0',
+				user_title varchar(100) NOT NULL,
+				date_modified datetime NOT NULL,
+				comments longtext NOT NULL,
+				is_confirmed tinyint(1) NOT NULL DEFAULT '0',
+				is_banned tinyint(1) NOT NULL DEFAULT '0',
+				invite_sent tinyint(1) NOT NULL DEFAULT '0',
+				KEY group_id (group_id),
+				KEY is_admin (is_admin),
+				KEY is_mod (is_mod),
+			 	KEY user_id (user_id),
+				KEY inviter_id (inviter_id),
+				KEY is_confirmed (is_confirmed)
+		 	   ) {$charset_collate};";
+
+	$sql[] = "CREATE TABLE {$bp_prefix}bp_groups_groupmeta (
+				id bigint(20) NOT NULL AUTO_INCREMENT PRIMARY KEY,
+				group_id bigint(20) NOT NULL,
+				meta_key varchar(255) DEFAULT NULL,
+				meta_value longtext DEFAULT NULL,
+				KEY group_id (group_id),
+				KEY meta_key (meta_key)
+			   ) {$charset_collate};";
+
+	dbDelta( $sql );
+}
+
+function bp_core_install_private_messaging() {
+
+	$sql             = array();
+	$charset_collate = bp_core_set_charset();
+	$bp_prefix       = bp_core_get_table_prefix();
+
+	$sql[] = "CREATE TABLE {$bp_prefix}bp_messages_messages (
+		  		id bigint(20) NOT NULL AUTO_INCREMENT PRIMARY KEY,
+		  		thread_id bigint(20) NOT NULL,
+		  		sender_id bigint(20) NOT NULL,
+		  		subject varchar(200) NOT NULL,
+		  		message longtext NOT NULL,
+		  		date_sent datetime NOT NULL,
+			    KEY sender_id (sender_id),
+			    KEY thread_id (thread_id)
+		 	   ) {$charset_collate};";
+
+	$sql[] = "CREATE TABLE {$bp_prefix}bp_messages_recipients (
+		  		id bigint(20) NOT NULL AUTO_INCREMENT PRIMARY KEY,
+		  		user_id bigint(20) NOT NULL,
+		  		thread_id bigint(20) NOT NULL,
+		  		unread_count int(10) NOT NULL DEFAULT '0',
+				sender_only tinyint(1) NOT NULL DEFAULT '0',
+				is_deleted tinyint(1) NOT NULL DEFAULT '0',
+			    KEY user_id (user_id),
+			    KEY thread_id (thread_id),
+				KEY is_deleted (is_deleted),
+				KEY sender_only (sender_only),
+			    KEY unread_count (unread_count)
+		 	   ) {$charset_collate};";
+
+	$sql[] = "CREATE TABLE {$bp_prefix}bp_messages_notices (
+		  		id bigint(20) NOT NULL AUTO_INCREMENT PRIMARY KEY,
+		  		subject varchar(200) NOT NULL,
+		  		message longtext NOT NULL,
+		  		date_sent datetime NOT NULL,
+				is_active tinyint(1) NOT NULL DEFAULT '0',
+			    KEY is_active (is_active)
+		 	   ) {$charset_collate};";
+
+	dbDelta( $sql );
+}
+
+function bp_core_install_extended_profiles() {
+	global $wpdb;
+
+	$sql             = array();
+	$charset_collate = bp_core_set_charset();
+	$bp_prefix       = bp_core_get_table_prefix();
+
+	// These values should only be updated if they are not already present
+	if ( ! bp_get_option( 'bp-xprofile-base-group-name' ) ) {
+		bp_update_option( 'bp-xprofile-base-group-name', _x( 'General', 'First field-group name', 'buddypress' ) );
+	}
+
+	if ( ! bp_get_option( 'bp-xprofile-fullname-field-name' ) ) {
+		bp_update_option( 'bp-xprofile-fullname-field-name', _x( 'Display Name', 'Display name field', 'buddypress' ) );
+	}
+
+	$sql[] = "CREATE TABLE {$bp_prefix}bp_xprofile_groups (
+			    id bigint(20) unsigned NOT NULL AUTO_INCREMENT PRIMARY KEY,
+			    name varchar(150) NOT NULL,
+			    description mediumtext NOT NULL,
+			    group_order bigint(20) NOT NULL DEFAULT '0',
+			    can_delete tinyint(1) NOT NULL,
+			    KEY can_delete (can_delete)
+			   ) {$charset_collate};";
+
+	$sql[] = "CREATE TABLE {$bp_prefix}bp_xprofile_fields (
+			    id bigint(20) unsigned NOT NULL AUTO_INCREMENT PRIMARY KEY,
+			    group_id bigint(20) unsigned NOT NULL,
+			    parent_id bigint(20) unsigned NOT NULL,
+			    type varchar(150) NOT NULL,
+			    name varchar(150) NOT NULL,
+			    description longtext NOT NULL,
+			    is_required tinyint(1) NOT NULL DEFAULT '0',
+			    is_default_option tinyint(1) NOT NULL DEFAULT '0',
+			    field_order bigint(20) NOT NULL DEFAULT '0',
+			    option_order bigint(20) NOT NULL DEFAULT '0',
+			    order_by varchar(15) NOT NULL DEFAULT '',
+			    can_delete tinyint(1) NOT NULL DEFAULT '1',
+			    KEY group_id (group_id),
+			    KEY parent_id (parent_id),
+			    KEY field_order (field_order),
+			    KEY can_delete (can_delete),
+			    KEY is_required (is_required)
+			   ) {$charset_collate};";
+
+	$sql[] = "CREATE TABLE {$bp_prefix}bp_xprofile_data (
+			    id bigint(20) unsigned NOT NULL AUTO_INCREMENT PRIMARY KEY,
+			    field_id bigint(20) unsigned NOT NULL,
+			    user_id bigint(20) unsigned NOT NULL,
+			    value longtext NOT NULL,
+			    last_updated datetime NOT NULL,
+			    KEY field_id (field_id),
+			    KEY user_id (user_id)
+			   ) {$charset_collate};";
+
+	$sql[] = "CREATE TABLE {$bp_prefix}bp_xprofile_meta (
+				id bigint(20) NOT NULL AUTO_INCREMENT PRIMARY KEY,
+				object_id bigint(20) NOT NULL,
+				object_type varchar(150) NOT NULL,
+				meta_key varchar(255) DEFAULT NULL,
+				meta_value longtext DEFAULT NULL,
+				KEY object_id (object_id),
+				KEY meta_key (meta_key)
+		   	   ) {$charset_collate};";
+
+	dbDelta( $sql );
+
+	// Insert the default group and fields
+	$insert_sql = array();
+
+	if ( !$wpdb->get_var( "SELECT id FROM {$bp_prefix}bp_xprofile_groups WHERE id = 1" ) )
+		$insert_sql[] = "INSERT INTO {$bp_prefix}bp_xprofile_groups ( name, description, can_delete ) VALUES ( " . $wpdb->prepare( '%s', stripslashes( bp_get_option( 'bp-xprofile-base-group-name' ) ) ) . ", '', 0 );";
+
+	if ( !$wpdb->get_var( "SELECT id FROM {$bp_prefix}bp_xprofile_fields WHERE id = 1" ) )
+		$insert_sql[] = "INSERT INTO {$bp_prefix}bp_xprofile_fields ( group_id, parent_id, type, name, description, is_required, can_delete ) VALUES ( 1, 0, 'textbox', " . $wpdb->prepare( '%s', stripslashes( bp_get_option( 'bp-xprofile-fullname-field-name' ) ) ) . ", '', 1, 0 );";
+
+	dbDelta( $insert_sql );
+}
+
+function bp_core_install_blog_tracking() {
+
+	$sql             = array();
+	$charset_collate = bp_core_set_charset();
+	$bp_prefix       = bp_core_get_table_prefix();
+
+	$sql[] = "CREATE TABLE {$bp_prefix}bp_user_blogs (
+	  		    id bigint(20) NOT NULL AUTO_INCREMENT PRIMARY KEY,
+			    user_id bigint(20) NOT NULL,
+			    blog_id bigint(20) NOT NULL,
+			    KEY user_id (user_id),
+			    KEY blog_id (blog_id)
+		       ) {$charset_collate};";
+
+	$sql[] = "CREATE TABLE {$bp_prefix}bp_user_blogs_blogmeta (
+				id bigint(20) NOT NULL AUTO_INCREMENT PRIMARY KEY,
+				blog_id bigint(20) NOT NULL,
+				meta_key varchar(255) DEFAULT NULL,
+				meta_value longtext DEFAULT NULL,
+				KEY blog_id (blog_id),
+				KEY meta_key (meta_key)
+		       ) {$charset_collate};";
+
+	dbDelta( $sql );
+}
Index: /tags/1.9/bp-core/admin/bp-core-settings.php
===================================================================
--- /tags/1.9/bp-core/admin/bp-core-settings.php	(revision 7684)
+++ /tags/1.9/bp-core/admin/bp-core-settings.php	(revision 7684)
@@ -0,0 +1,367 @@
+<?php
+
+/**
+ * BuddyPress Admin Settings
+ *
+ * @package BuddyPress
+ * @subpackage CoreAdministration
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/**
+ * Main settings section description for the settings page
+ *
+ * @since BuddyPress (1.6)
+ */
+function bp_admin_setting_callback_main_section() { }
+
+/**
+ * Admin bar for logged out users setting field
+ *
+ * @since BuddyPress (1.6)
+ *
+ * @uses bp_form_option() To output the option value
+ */
+function bp_admin_setting_callback_admin_bar() {
+?>
+
+	<input id="hide-loggedout-adminbar" name="hide-loggedout-adminbar" type="checkbox" value="1" <?php checked( !bp_hide_loggedout_adminbar( false ) ); ?> />
+	<label for="hide-loggedout-adminbar"><?php _e( 'Show the Toolbar for logged out users', 'buddypress' ); ?></label>
+
+<?php
+}
+
+/**
+ * Allow members to delete their accounts setting field
+ *
+ * @since BuddyPress (1.6)
+ *
+ * @uses checked() To display the checked attribute
+ */
+function bp_admin_setting_callback_account_deletion() {
+?>
+
+	<input id="bp-disable-account-deletion" name="bp-disable-account-deletion" type="checkbox" value="1" <?php checked( !bp_disable_account_deletion( false ) ); ?> />
+	<label for="bp-disable-account-deletion"><?php _e( 'Allow registered members to delete their own accounts', 'buddypress' ); ?></label>
+
+<?php
+}
+
+/**
+ * If user has upgraded to 1.6 and chose to retain their BuddyBar, offer then a switch to change over
+ * to the WP Toolbar.
+ *
+ * @since BuddyPress (1.6)
+ */
+function bp_admin_setting_callback_force_buddybar() {
+?>
+
+	<input id="_bp_force_buddybar" name="_bp_force_buddybar" type="checkbox" value="1" <?php checked( ! bp_force_buddybar( true ) ); ?> />
+	<label for="_bp_force_buddybar"><?php _e( 'Switch to WordPress Toolbar', 'buddypress' ); ?></label>
+
+<?php
+}
+
+/** Activity *******************************************************************/
+
+/**
+ * Groups settings section description for the settings page
+ *
+ * @since BuddyPress (1.6)
+ */
+function bp_admin_setting_callback_activity_section() { }
+
+/**
+ * Allow Akismet setting field
+ *
+ * @since BuddyPress (1.6)
+ *
+ * @uses checked() To display the checked attribute
+ */
+function bp_admin_setting_callback_activity_akismet() {
+?>
+
+	<input id="_bp_enable_akismet" name="_bp_enable_akismet" type="checkbox" value="1" <?php checked( bp_is_akismet_active( true ) ); ?> />
+	<label for="_bp_enable_akismet"><?php _e( 'Allow Akismet to scan for activity stream spam', 'buddypress' ); ?></label>
+
+<?php
+}
+
+/**
+ * Allow activity comments on blog posts and forum posts
+ *
+ * @since BuddyPress (1.6)
+ */
+function bp_admin_setting_callback_blogforum_comments() {
+?>
+
+	<input id="bp-disable-blogforum-comments" name="bp-disable-blogforum-comments" type="checkbox" value="1" <?php checked( !bp_disable_blogforum_comments( false ) ); ?> />
+	<label for="bp-disable-blogforum-comments"><?php _e( 'Allow activity stream commenting on blog and forum posts', 'buddypress' ); ?></label>
+
+<?php
+}
+
+/**
+ * Sanitization for _bp_force_buddyvar
+ *
+ * If upgraded to 1.6 and you chose to keep the BuddyBar, a checkbox asks if you want to switch to
+ * the WP Toolbar. The option we store is 1 if the BuddyBar is forced on, so we use this function
+ * to flip the boolean before saving the intval.
+ *
+ * @since BuddyPress (1.6)
+ * @access Private
+ */
+function bp_admin_sanitize_callback_force_buddybar( $value = false ) {
+	return $value ? 0 : 1;
+}
+
+/**
+ * Sanitization for bp-disable-blogforum-comments setting
+ *
+ * In the UI, a checkbox asks whether you'd like to *enable* blog/forum activity comments. For
+ * legacy reasons, the option that we store is 1 if these comments are *disabled*. So we use this
+ * function to flip the boolean before saving the intval.
+ *
+ * @since BuddyPress (1.6)
+ */
+function bp_admin_sanitize_callback_blogforum_comments( $value = false ) {
+	return $value ? 0 : 1;
+}
+
+/** XProfile ******************************************************************/
+
+/**
+ * Profile settings section description for the settings page
+ *
+ * @since BuddyPress (1.6)
+ */
+function bp_admin_setting_callback_xprofile_section() { }
+
+/**
+ * Enable BP->WP profile syncing field
+ *
+ * @since BuddyPress (1.6)
+ *
+ * @uses bp_form_option() To output the option value
+ */
+function bp_admin_setting_callback_profile_sync() {
+?>
+
+	<input id="bp-disable-profile-sync" name="bp-disable-profile-sync" type="checkbox" value="1" <?php checked( !bp_disable_profile_sync( false ) ); ?> />
+	<label for="bp-disable-profile-sync"><?php _e( 'Enable BuddyPress to WordPress profile syncing', 'buddypress' ); ?></label>
+
+<?php
+}
+
+/**
+ * Allow members to upload avatars field
+ *
+ * @since BuddyPress (1.6)
+ *
+ * @uses checked() To display the checked attribute
+ */
+function bp_admin_setting_callback_avatar_uploads() {
+?>
+
+	<input id="bp-disable-avatar-uploads" name="bp-disable-avatar-uploads" type="checkbox" value="1" <?php checked( !bp_disable_avatar_uploads( false ) ); ?> />
+	<label for="bp-disable-avatar-uploads"><?php _e( 'Allow registered members to upload avatars', 'buddypress' ); ?></label>
+
+<?php
+}
+
+/** Groups Section ************************************************************/
+
+/**
+ * Groups settings section description for the settings page
+ *
+ * @since BuddyPress (1.6)
+ */
+function bp_admin_setting_callback_groups_section() { }
+
+/**
+ * Allow all users to create groups field
+ *
+ * @since BuddyPress (1.6)
+ *
+ * @uses checked() To display the checked attribute
+ */
+function bp_admin_setting_callback_group_creation() {
+?>
+
+	<input id="bp_restrict_group_creation" name="bp_restrict_group_creation" type="checkbox"value="1" <?php checked( !bp_restrict_group_creation( false ) ); ?> />
+	<label for="bp_restrict_group_creation"><?php _e( 'Enable group creation for all users', 'buddypress' ); ?></label>
+	<p class="description"><?php _e( 'Administrators can always create groups, regardless of this setting.', 'buddypress' ); ?></p>
+
+<?php
+}
+
+/** Forums Section ************************************************************/
+
+/**
+ * Forums settings section description for the settings page
+ *
+ * @since BuddyPress (1.6)
+ */
+function bp_admin_setting_callback_bbpress_section() { }
+
+/**
+ * bb-config.php location field
+ *
+ * @since BuddyPress (1.6)
+ * @uses checked() To display the checked attribute
+ * @uses bp_get_option() To get the config location
+ * @uses bp_form_option() To get the sanitized form option
+ */
+function bp_admin_setting_callback_bbpress_configuration() {
+
+	$config_location = bp_get_option( 'bb-config-location' );
+	$file_exists     = (bool) ( file_exists( $config_location ) || is_file( $config_location ) ); ?>
+
+	<input name="bb-config-location" type="text" id="bb-config-location" value="<?php bp_form_option( 'bb-config-location', '' ); ?>" class="medium-text" style="width: 300px;" />
+
+	<?php if ( false === $file_exists ) : ?>
+
+		<a class="button" href="<?php bp_admin_url( 'admin.php?page=bb-forums-setup&repair=1' ); ?>" title="<?php _e( 'Attempt to save a new config file.', 'buddypress' ); ?>"><?php _e( 'Repair', 'buddypress' ) ?></a>
+		<span class="attention"><?php _e( 'File does not exist', 'buddypress' ); ?></span>
+
+	<?php endif; ?>
+
+	<p class="description"><?php _e( 'Absolute path to your bbPress configuration file.', 'buddypress' ); ?></p>
+
+<?php
+}
+
+/** Settings Page *************************************************************/
+
+/**
+ * The main settings page
+ *
+ * @since BuddyPress (1.6)
+ *
+ * @uses screen_icon() To display the screen icon
+ * @uses settings_fields() To output the hidden fields for the form
+ * @uses do_settings_sections() To output the settings sections
+ */
+function bp_core_admin_settings() {
+
+	// We're saving our own options, until the WP Settings API is updated to work with Multisite
+	$form_action = add_query_arg( 'page', 'bp-settings', bp_get_admin_url( 'admin.php' ) );
+
+	?>
+
+	<div class="wrap">
+
+		<?php screen_icon( 'buddypress' ); ?>
+
+		<h2 class="nav-tab-wrapper"><?php bp_core_admin_tabs( __( 'Settings', 'buddypress' ) ); ?></h2>
+
+		<form action="<?php echo $form_action ?>" method="post">
+
+			<?php settings_fields( 'buddypress' ); ?>
+
+			<?php do_settings_sections( 'buddypress' ); ?>
+
+			<p class="submit">
+				<input type="submit" name="submit" class="button-primary" value="<?php _e( 'Save Settings', 'buddypress' ); ?>" />
+			</p>
+		</form>
+	</div>
+
+<?php
+}
+
+/**
+ * Save our settings
+ *
+ * @since BuddyPress (1.6)
+ */
+function bp_core_admin_settings_save() {
+	global $wp_settings_fields;
+
+	if ( isset( $_GET['page'] ) && 'bp-settings' == $_GET['page'] && !empty( $_POST['submit'] ) ) {
+		check_admin_referer( 'buddypress-options' );
+
+		// Because many settings are saved with checkboxes, and thus will have no values
+		// in the $_POST array when unchecked, we loop through the registered settings
+		if ( isset( $wp_settings_fields['buddypress'] ) ) {
+			foreach( (array) $wp_settings_fields['buddypress'] as $section => $settings ) {
+				foreach( $settings as $setting_name => $setting ) {
+					$value = isset( $_POST[$setting_name] ) ? $_POST[$setting_name] : '';
+
+					bp_update_option( $setting_name, $value );
+				}
+			}
+		}
+
+		// Some legacy options are not registered with the Settings API
+		$legacy_options = array(
+			'bp-disable-account-deletion',
+			'bp-disable-avatar-uploads',
+			'bp_disable_blogforum_comments',
+			'bp-disable-profile-sync',
+			'bp_restrict_group_creation',
+			'hide-loggedout-adminbar',
+		);
+
+		foreach( $legacy_options as $legacy_option ) {
+			// Note: Each of these options is represented by its opposite in the UI
+			// Ie, the Profile Syncing option reads "Enable Sync", so when it's checked,
+			// the corresponding option should be unset
+			$value = isset( $_POST[$legacy_option] ) ? '' : 1;
+			bp_update_option( $legacy_option, $value );
+		}
+
+		bp_core_redirect( add_query_arg( array( 'page' => 'bp-settings', 'updated' => 'true' ), bp_get_admin_url( 'admin.php' ) ) );
+	}
+}
+add_action( 'bp_admin_init', 'bp_core_admin_settings_save', 100 );
+
+/**
+ * Output settings API option
+ *
+ * @since BuddyPress (1.6)
+ *
+ * @uses bp_get_bp_form_option()
+ *
+ * @param string $option
+ * @param string $default
+ * @param bool $slug
+ */
+function bp_form_option( $option, $default = '' , $slug = false ) {
+	echo bp_get_form_option( $option, $default, $slug );
+}
+	/**
+	 * Return settings API option
+	 *
+	 * @since BuddyPress (1.6)
+	 *
+	 * @uses bp_get_option()
+	 * @uses esc_attr()
+	 * @uses apply_filters()
+	 *
+	 * @param string $option
+	 * @param string $default
+	 * @param bool $slug
+	 */
+	function bp_get_form_option( $option, $default = '', $slug = false ) {
+
+		// Get the option and sanitize it
+		$value = bp_get_option( $option, $default );
+
+		// Slug?
+		if ( true === $slug )
+			$value = esc_attr( apply_filters( 'editable_slug', $value ) );
+
+		// Not a slug
+		else
+			$value = esc_attr( $value );
+
+		// Fallback to default
+		if ( empty( $value ) )
+			$value = $default;
+
+		// Allow plugins to further filter the output
+		return apply_filters( 'bp_get_form_option', $value, $option );
+	}
Index: /tags/1.9/bp-core/admin/bp-core-slugs.php
===================================================================
--- /tags/1.9/bp-core/admin/bp-core-slugs.php	(revision 7684)
+++ /tags/1.9/bp-core/admin/bp-core-slugs.php	(revision 7684)
@@ -0,0 +1,222 @@
+<?php
+
+/**
+ * BuddyPress Admin Slug Functions
+ *
+ * @package BuddyPress
+ * @subpackage CoreAdministration
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/**
+ * Renders the page mapping admin panel.
+ *
+ * @since BuddyPress (1.6)
+ * @todo Use settings API
+ * @uses bp_core_admin_component_options()
+ */
+function bp_core_admin_slugs_settings() {
+?>
+
+	<div class="wrap">
+		<?php screen_icon( 'buddypress'); ?>
+
+		<h2 class="nav-tab-wrapper"><?php bp_core_admin_tabs( __( 'Pages', 'buddypress' ) ); ?></h2>
+		<form action="" method="post" id="bp-admin-page-form">
+
+			<?php bp_core_admin_slugs_options(); ?>
+
+			<p class="submit clear">
+				<input class="button-primary" type="submit" name="bp-admin-pages-submit" id="bp-admin-pages-submit" value="<?php _e( 'Save Settings', 'buddypress' ) ?>"/>
+			</p>
+
+			<?php wp_nonce_field( 'bp-admin-pages-setup' ); ?>
+
+		</form>
+	</div>
+
+<?php
+}
+
+/**
+ * Creates reusable markup for page setup on the Components and Pages dashboard panel.
+ *
+ * @package BuddyPress
+ * @since BuddyPress (1.6)
+ * @todo Use settings API
+ */
+function bp_core_admin_slugs_options() {
+	global $bp;
+
+	// Get the existing WP pages
+	$existing_pages = bp_core_get_directory_page_ids();
+
+	// Set up an array of components (along with component names) that have
+	// directory pages.
+	$directory_pages = array();
+
+	// Loop through loaded components and collect directories
+	if ( is_array( $bp->loaded_components ) ) {
+		foreach( $bp->loaded_components as $component_slug => $component_id ) {
+
+			// Only components that need directories should be listed here
+			if ( isset( $bp->{$component_id} ) && !empty( $bp->{$component_id}->has_directory ) ) {
+
+				// component->name was introduced in BP 1.5, so we must provide a fallback
+				$directory_pages[$component_id] = !empty( $bp->{$component_id}->name ) ? $bp->{$component_id}->name : ucwords( $component_id );
+			}
+		}
+	}
+
+	/** Directory Display *****************************************************/
+
+	$directory_pages = apply_filters( 'bp_directory_pages', $directory_pages );
+
+	if ( !empty( $directory_pages ) ) : ?>
+
+		<h3><?php _e( 'Directories', 'buddypress' ); ?></h3>
+
+		<p><?php _e( 'Associate a WordPress Page with each BuddyPress component directory.', 'buddypress' ); ?></p>
+
+		<table class="form-table">
+			<tbody>
+
+				<?php foreach ( $directory_pages as $name => $label ) : ?>
+
+					<tr valign="top">
+						<th scope="row">
+							<label for="bp_pages[<?php echo esc_attr( $name ) ?>]"><?php echo esc_html( $label ) ?></label>
+						</th>
+
+						<td>
+
+							<?php if ( ! bp_is_root_blog() ) switch_to_blog( bp_get_root_blog_id() ); ?>
+
+							<?php echo wp_dropdown_pages( array(
+								'name'             => 'bp_pages[' . esc_attr( $name ) . ']',
+								'echo'             => false,
+								'show_option_none' => __( '- None -', 'buddypress' ),
+								'selected'         => !empty( $existing_pages[$name] ) ? $existing_pages[$name] : false
+							) ); ?>
+
+							<a href="<?php echo admin_url( add_query_arg( array( 'post_type' => 'page' ), 'post-new.php' ) ); ?>" class="button-secondary"><?php _e( 'New Page', 'buddypress' ); ?></a>
+							<input class="button-primary" type="submit" name="bp-admin-pages-single" value="<?php _e( 'Save', 'buddypress' ) ?>" />
+
+							<?php if ( !empty( $existing_pages[$name] ) ) : ?>
+
+								<a href="<?php echo get_permalink( $existing_pages[$name] ); ?>" class="button-secondary" target="_bp"><?php _e( 'View', 'buddypress' ); ?></a>
+
+							<?php endif; ?>
+
+							<?php if ( ! bp_is_root_blog() ) restore_current_blog(); ?>
+
+						</td>
+					</tr>
+
+
+				<?php endforeach ?>
+
+				<?php do_action( 'bp_active_external_directories' ); ?>
+
+			</tbody>
+		</table>
+
+	<?php
+
+	endif;
+
+	/** Static Display ********************************************************/
+
+	// Static pages
+	$static_pages = array(
+		'register' => __( 'Register', 'buddypress' ),
+		'activate' => __( 'Activate', 'buddypress' ),
+	);
+
+	$static_pages = apply_filters( 'bp_static_pages', $static_pages );
+
+	if ( !empty( $static_pages ) ) : ?>
+
+		<h3><?php _e( 'Registration', 'buddypress' ); ?></h3>
+
+		<p><?php _e( 'Associate WordPress Pages with the following BuddyPress Registration pages.', 'buddypress' ); ?></p>
+
+		<table class="form-table">
+			<tbody>
+
+				<?php foreach ( $static_pages as $name => $label ) : ?>
+
+					<tr valign="top">
+						<th scope="row">
+							<label for="bp_pages[<?php echo esc_attr( $name ) ?>]"><?php echo esc_html( $label ) ?></label>
+						</th>
+
+						<td>
+
+							<?php if ( ! bp_is_root_blog() ) switch_to_blog( bp_get_root_blog_id() ); ?>
+
+							<?php echo wp_dropdown_pages( array(
+								'name'             => 'bp_pages[' . esc_attr( $name ) . ']',
+								'echo'             => false,
+								'show_option_none' => __( '- None -', 'buddypress' ),
+								'selected'         => !empty( $existing_pages[$name] ) ? $existing_pages[$name] : false
+							) ) ?>
+
+							<a href="<?php echo admin_url( add_query_arg( array( 'post_type' => 'page' ), 'post-new.php' ) ); ?>" class="button-secondary"><?php _e( 'New Page', 'buddypress' ); ?></a>
+							<input class="button-primary" type="submit" name="bp-admin-pages-single" value="<?php _e( 'Save', 'buddypress' ) ?>" />
+
+							<?php if ( !empty( $existing_pages[$name] ) ) : ?>
+
+								<a href="<?php echo get_permalink( $existing_pages[$name] ); ?>" class="button-secondary" target="_bp"><?php _e( 'View', 'buddypress' ); ?></a>
+
+							<?php endif; ?>
+
+							<?php if ( ! bp_is_root_blog() ) restore_current_blog(); ?>
+
+						</td>
+					</tr>
+
+				<?php endforeach ?>
+
+				<?php do_action( 'bp_active_external_pages' ); ?>
+
+			</tbody>
+		</table>
+
+		<?php
+	endif;
+}
+
+/**
+ * Handle saving of the BuddyPress slugs
+ *
+ * @since BuddyPress (1.6)
+ * @todo Use settings API
+ */
+function bp_core_admin_slugs_setup_handler() {
+
+	if ( isset( $_POST['bp-admin-pages-submit'] ) || isset( $_POST['bp-admin-pages-single'] ) ) {
+		if ( !check_admin_referer( 'bp-admin-pages-setup' ) )
+			return false;
+
+		// Then, update the directory pages
+		if ( isset( $_POST['bp_pages'] ) ) {
+
+			$directory_pages = array();
+
+			foreach ( (array) $_POST['bp_pages'] as $key => $value ) {
+				if ( !empty( $value ) ) {
+					$directory_pages[$key] = (int) $value;
+				}
+			}
+			bp_core_update_directory_page_ids( $directory_pages );
+		}
+
+		$base_url = bp_get_admin_url( add_query_arg( array( 'page' => 'bp-page-settings', 'updated' => 'true' ), 'admin.php' ) );
+
+		wp_redirect( $base_url );
+	}
+}
+add_action( 'bp_admin_init', 'bp_core_admin_slugs_setup_handler' );
Index: /tags/1.9/bp-core/admin/css/common.css
===================================================================
--- /tags/1.9/bp-core/admin/css/common.css	(revision 7684)
+++ /tags/1.9/bp-core/admin/css/common.css	(revision 7684)
@@ -0,0 +1,429 @@
+/**
+ * CSS that is always loaded when in wp-admin
+ *
+ * @since BuddyPress (1.6)
+ */
+
+/* Icon 32's
+------------------------------------------------------------------------------*/
+
+body.branch-3-6 div#icon-buddypress,
+body.branch-3-7 div#icon-buddypress {
+	background: url('../images/icons32.png') no-repeat -370px -6px;
+}
+
+body.branch-3-6 div#icon-buddypress-activity,
+body.branch-3-7 div#icon-buddypress-activity {
+	background: url('../images/icons32.png') no-repeat -10px -6px;
+}
+
+body.branch-3-6 div#icon-buddypress-groups,
+body.branch-3-7 div#icon-buddypress-groups {
+	background: url('../images/icons32.png') no-repeat -250px -6px;
+}
+
+/* Menu Icons
+------------------------------------------------------------------------------*/
+
+/* Backpat */
+body.branch-3-6 ul#adminmenu li.toplevel_page_bp-components .wp-menu-image,
+body.branch-3-6 ul#adminmenu li.toplevel_page_bp-general-settings .wp-menu-image,
+body.branch-3-7 ul#adminmenu li.toplevel_page_bp-components .wp-menu-image,
+body.branch-3-7 ul#adminmenu li.toplevel_page_bp-general-settings .wp-menu-image {
+	background-image: url('../images/menu.png') !important;
+	background-position: -178px -34px;
+}
+
+body.branch-3-6 ul#adminmenu li.toplevel_page_bp-components:hover .wp-menu-image,
+body.branch-3-6 ul#adminmenu li.toplevel_page_bp-general-settings:hover .wp-menu-image,
+body.branch-3-6 ul#adminmenu li.toplevel_page_bp-components.wp-has-current-submenu .wp-menu-image,
+body.branch-3-6 ul#adminmenu li.toplevel_page_bp-general-settings.wp-has-current-submenu .wp-menu-image,
+body.branch-3-7 ul#adminmenu li.toplevel_page_bp-components:hover .wp-menu-image,
+body.branch-3-7 ul#adminmenu li.toplevel_page_bp-general-settings:hover .wp-menu-image,
+body.branch-3-7 ul#adminmenu li.toplevel_page_bp-components.wp-has-current-submenu .wp-menu-image,
+body.branch-3-7 ul#adminmenu li.toplevel_page_bp-general-settings.wp-has-current-submenu .wp-menu-image {
+	background-position: -178px -2px;
+}
+
+/* Activity */
+body.branch-3-6 ul#adminmenu li.toplevel_page_bp-activity .wp-menu-image,
+body.branch-3-6 ul#adminmenu li.toplevel_page_bp-activity_network .wp-menu-image,
+body.branch-3-7 ul#adminmenu li.toplevel_page_bp-activity .wp-menu-image,
+body.branch-3-7 ul#adminmenu li.toplevel_page_bp-activity_network .wp-menu-image {
+	background-image: url('../images/menu.png');
+	background-position: 0 -34px;
+}
+body.branch-3-6 ul#adminmenu li.toplevel_page_bp-activity:hover .wp-menu-image,
+body.branch-3-6 ul#adminmenu li.toplevel_page_bp-activity.current .wp-menu-image,
+body.branch-3-6 ul#adminmenu li.toplevel_page_bp-activity.wp-has-current-submenu .wp-menu-image,
+body.branch-3-6 ul#adminmenu li.toplevel_page_bp-activity_network:hover .wp-menu-image,
+body.branch-3-6 ul#adminmenu li.toplevel_page_bp-activity_network.current .wp-menu-image,
+body.branch-3-6 ul#adminmenu li.toplevel_page_bp-activity_network.wp-has-current-submenu .wp-menu-image,
+body.branch-3-7 ul#adminmenu li.toplevel_page_bp-activity:hover .wp-menu-image,
+body.branch-3-7 ul#adminmenu li.toplevel_page_bp-activity.current .wp-menu-image,
+body.branch-3-7 ul#adminmenu li.toplevel_page_bp-activity.wp-has-current-submenu .wp-menu-image,
+body.branch-3-7 ul#adminmenu li.toplevel_page_bp-activity_network:hover .wp-menu-image,
+body.branch-3-7 ul#adminmenu li.toplevel_page_bp-activity_network.current .wp-menu-image,
+body.branch-3-7 ul#adminmenu li.toplevel_page_bp-activity_network.wp-has-current-submenu .wp-menu-image {
+	background-position: 0 -2px;
+}
+
+/* Groups */
+body.branch-3-6 ul#adminmenu li.toplevel_page_bp-groups .wp-menu-image,
+body.branch-3-6 ul#adminmenu li.toplevel_page_bp-groups_network .wp-menu-image,
+body.branch-3-7 ul#adminmenu li.toplevel_page_bp-groups .wp-menu-image,
+body.branch-3-7 ul#adminmenu li.toplevel_page_bp-groups_network .wp-menu-image {
+	background-image: url('../images/menu.png');
+	background-position: -61px -34px;
+}
+body.branch-3-6 ul#adminmenu li.toplevel_page_bp-groups:hover .wp-menu-image,
+body.branch-3-6 ul#adminmenu li.toplevel_page_bp-groups.current .wp-menu-image,
+body.branch-3-6 ul#adminmenu li.toplevel_page_bp-groups.wp-has-current-submenu .wp-menu-image,
+body.branch-3-6 ul#adminmenu li.toplevel_page_bp-groups_network:hover .wp-menu-image,
+body.branch-3-6 ul#adminmenu li.toplevel_page_bp-groups_network.current .wp-menu-image,
+body.branch-3-6 ul#adminmenu li.toplevel_page_bp-groups_network.wp-has-current-submenu .wp-menu-image,
+body.branch-3-7 ul#adminmenu li.toplevel_page_bp-groups:hover .wp-menu-image,
+body.branch-3-7 ul#adminmenu li.toplevel_page_bp-groups.current .wp-menu-image,
+body.branch-3-7 ul#adminmenu li.toplevel_page_bp-groups.wp-has-current-submenu .wp-menu-image,
+body.branch-3-7 ul#adminmenu li.toplevel_page_bp-groups_network:hover .wp-menu-image,
+body.branch-3-7 ul#adminmenu li.toplevel_page_bp-groups_network.current .wp-menu-image,
+body.branch-3-7 ul#adminmenu li.toplevel_page_bp-groups_network.wp-has-current-submenu .wp-menu-image {
+	background-position: -61px -2px;
+}
+th.column-gid {
+	width: 60px;
+}
+td.column-gid {
+	vertical-align: middle;
+}
+table.bp-group-members th,
+table.bp-group-members td {
+	padding: 5px 0;
+}
+table.bp-group-members .uid-column {
+	padding-left: 20px;
+	padding-right: 20px;
+}
+table.bp-group-members .uname-column {
+	width: 70%;
+}
+table.bp-group-members .urole-column {
+	padding-left: 20px;
+	padding-right: 20px;
+}
+
+/* Components
+------------------------------------------------------------------------------*/
+
+/* Dashicons */
+#adminmenu #toplevel_page_bp-activity .wp-menu-image:before,
+#adminmenu #toplevel_page_bp-activity_user .wp-menu-image:before,
+#adminmenu #toplevel_page_bp-activity_network .wp-menu-image:before {
+	content: "\f452";
+}
+
+#adminmenu #toplevel_page_bp-groups .wp-menu-image:before,
+#adminmenu #toplevel_page_bp-groups_user .wp-menu-image:before,
+#adminmenu #toplevel_page_bp-groups_network .wp-menu-image:before {
+	content: "\f456";
+}
+
+#adminmenu #toplevel_page_bp-notifications .wp-menu-image:before,
+#adminmenu #toplevel_page_bp-notifications_user .wp-menu-image:before,
+#adminmenu #toplevel_page_bp-notifications_network .wp-menu-image:before {
+	content: "\f439";
+}
+
+#adminmenu #toplevel_page_bp-messages .wp-menu-image:before,
+#adminmenu #toplevel_page_bp-messages_user .wp-menu-image:before,
+#adminmenu #toplevel_page_bp-messages_network .wp-menu-image:before {
+	content: "\f457";
+}
+
+#adminmenu #toplevel_page_bp-friends .wp-menu-image:before,
+#adminmenu #toplevel_page_bp-friends_user .wp-menu-image:before,
+#adminmenu #toplevel_page_bp-friends_network .wp-menu-image:before{
+	content: "\f454";
+}
+
+#adminmenu #toplevel_page_bp-settings .wp-menu-image:before,
+#adminmenu #toplevel_page_bp-settings_user .wp-menu-image:before,
+#adminmenu #toplevel_page_bp-settings_network .wp-menu-image:before {
+	content: "\f108";
+}
+
+#adminmenu li.toplevel_page_bp-components .wp-menu-image,
+#adminmenu li.toplevel_page_bp-general-settings .wp-menu-image {
+	content: "\f448";
+}
+
+/* Dashicons overrides for backward compatibility */
+body.branch-3-6 #adminmenu #toplevel_page_bp-activity .wp-menu-image:before,
+body.branch-3-6 #adminmenu #toplevel_page_bp-activity_network .wp-menu-image:before,
+body.branch-3-6 #adminmenu #toplevel_page_bp-groups .wp-menu-image:before,
+body.branch-3-6 #adminmenu #toplevel_page_bp-groups_network .wp-menu-image:before,
+body.branch-3-6 #adminmenu li.toplevel_page_bp-components .wp-menu-image,
+body.branch-3-6 #adminmenu li.toplevel_page_bp-general-settings .wp-menu-image,
+body.branch-3-7 #adminmenu #toplevel_page_bp-activity .wp-menu-image:before,
+body.branch-3-7 #adminmenu #toplevel_page_bp-activity_network .wp-menu-image:before,
+body.branch-3-7 #adminmenu #toplevel_page_bp-groups .wp-menu-image:before,
+body.branch-3-7 #adminmenu #toplevel_page_bp-groups_network .wp-menu-image:before,
+body.branch-3-7 #adminmenu li.toplevel_page_bp-components .wp-menu-image,
+body.branch-3-7 #adminmenu li.toplevel_page_bp-general-settings .wp-menu-image {
+	content: "";
+}
+
+/* Settings - Dashicons (WP 3.8+) */
+.settings_page_bp-components td.plugin-title span {
+	float: left;
+	width: 18px;
+	height: 18px;
+	margin-right: 5px;
+}
+
+.settings_page_bp-components td.plugin-title span:before {
+	font-family: 'dashicons';
+	font-size: 18px;
+}
+
+.settings_page_bp-components tr.activity td.plugin-title span:before {
+	content: "\f452";
+}
+
+.settings_page_bp-components tr.notifications td.plugin-title span:before {
+	content: "\f339";
+}
+
+.settings_page_bp-components tr.xprofile td.plugin-title span:before {
+	content: "\f336";
+}
+
+.settings_page_bp-components tr.settings td.plugin-title span:before {
+	content: "\f108";
+}
+
+.settings_page_bp-components tr.groups td.plugin-title span:before {
+	content: "\f456";
+}
+
+.settings_page_bp-components tr.messages td.plugin-title span:before {
+	content: "\f457";
+}
+
+.settings_page_bp-components tr.forums td.plugin-title span:before {
+	content: "\f452";
+}
+
+.settings_page_bp-components tr.blogs td.plugin-title span:before {
+	content: "\f120";
+}
+
+.settings_page_bp-components tr.friends td.plugin-title span:before {
+	content: "\f454";
+}
+
+/* Settings - Legacy (< WP 3.8) */
+body.branch-3-6.settings_page_bp-components tr.activity td.plugin-title span:before,
+body.branch-3-6.settings_page_bp-components tr.notifications td.plugin-title span:before,
+body.branch-3-6.settings_page_bp-components tr.xprofile td.plugin-title span:before,
+body.branch-3-6.settings_page_bp-components tr.settings td.plugin-title span:before,
+body.branch-3-6.settings_page_bp-components tr.groups td.plugin-title span:before,
+body.branch-3-6.settings_page_bp-components tr.messages td.plugin-title span:before,
+body.branch-3-6.settings_page_bp-components tr.forums td.plugin-title span:before,
+body.branch-3-6.settings_page_bp-components tr.blogs td.plugin-title span:before,
+body.branch-3-6.settings_page_bp-components tr.friends td.plugin-title span:before,
+body.branch-3-7.settings_page_bp-components tr.activity td.plugin-title span:before,
+body.branch-3-7.settings_page_bp-components tr.notifications td.plugin-title span:before,
+body.branch-3-7.settings_page_bp-components tr.xprofile td.plugin-title span:before,
+body.branch-3-7.settings_page_bp-components tr.settings td.plugin-title span:before,
+body.branch-3-7.settings_page_bp-components tr.groups td.plugin-title span:before,
+body.branch-3-7.settings_page_bp-components tr.messages td.plugin-title span:before,
+body.branch-3-7.settings_page_bp-components tr.forums td.plugin-title span:before,
+body.branch-3-7.settings_page_bp-components tr.blogs td.plugin-title span:before,
+body.branch-3-7.settings_page_bp-components tr.friends td.plugin-title span:before {
+	content: "";
+}
+
+body.branch-3-6.settings_page_bp-components td.plugin-title span,
+body.branch-3-7.settings_page_bp-components td.plugin-title span {
+	background-image: url('../images/menu.png');
+	background-position: -4px -40px;
+	background-repeat: no-repeat;
+}
+
+body.branch-3-6.settings_page_bp-components tr.active td.plugin-title span,
+body.branch-3-7.settings_page_bp-components tr.active td.plugin-title span {
+	background-position-y: -7px;
+}
+
+body.branch-3-6.settings_page_bp-components tr.activity td.plugin-title span,
+body.branch-3-7.settings_page_bp-components tr.activity td.plugin-title span {
+	background-position: -4px -40px;
+}
+
+body.branch-3-6.settings_page_bp-components tr.activity.active td.plugin-title span,
+body.branch-3-7.settings_page_bp-components tr.activity.active td.plugin-title span {
+	background-position: -4px -7px;
+}
+
+body.branch-3-6.settings_page_bp-components tr.xprofile td.plugin-title span,
+body.branch-3-7.settings_page_bp-components tr.xprofile td.plugin-title span {
+	background-image: url('../images/menu-wp.png');
+	background-position: -305px -40px;
+}
+
+body.branch-3-6.settings_page_bp-components tr.xprofile.active td.plugin-title span,
+body.branch-3-7.settings_page_bp-components tr.xprofile.active td.plugin-title span {
+	background-position: -305px -7px;
+}
+
+body.branch-3-6.settings_page_bp-components tr.settings td.plugin-title span,
+body.branch-3-7.settings_page_bp-components tr.settings td.plugin-title span {
+	background-image: url('../images/menu-wp.png');
+	background-position: -334px -40px;
+}
+
+body.branch-3-6.settings_page_bp-components tr.settings.active td.plugin-title span,
+body.branch-3-7.settings_page_bp-components tr.settings.active td.plugin-title span {
+	background-position: -334px -7px;
+}
+
+body.branch-3-6.settings_page_bp-components tr.groups td.plugin-title span,
+body.branch-3-7.settings_page_bp-components tr.groups td.plugin-title span {
+	background-position: -66px -40px;
+}
+
+body.branch-3-6.settings_page_bp-components tr.groups.active td.plugin-title span,
+body.branch-3-7.settings_page_bp-components tr.groups.active td.plugin-title span {
+	background-position: -66px -7px;
+}
+
+body.branch-3-6.settings_page_bp-components tr.messages td.plugin-title span,
+body.branch-3-7.settings_page_bp-components tr.messages td.plugin-title span {
+	background-position: -154px -40px;
+}
+
+body.branch-3-6.settings_page_bp-components tr.messages.active td.plugin-title span,
+body.branch-3-7.settings_page_bp-components tr.messages.active td.plugin-title span {
+	background-position: -154px -7px;
+}
+
+body.branch-3-6.settings_page_bp-components tr.forums td.plugin-title span,
+body.branch-3-7.settings_page_bp-components tr.forums td.plugin-title span {
+	background-image: url('../images/menu-wp.png');
+	background-position: -36px -40px;
+}
+
+body.branch-3-6.settings_page_bp-components tr.forums.active td.plugin-title span,
+body.branch-3-7.settings_page_bp-components tr.forums.active td.plugin-title span {
+	background-position: -36px -7px;
+}
+
+body.branch-3-6.settings_page_bp-components tr.blogs td.plugin-title span,
+body.branch-3-7.settings_page_bp-components tr.blogs td.plugin-title span {
+	background-position: -125px -40px;
+}
+
+body.branch-3-6.settings_page_bp-components tr.blogs.active td.plugin-title span,
+body.branch-3-7.settings_page_bp-components tr.blogs.active td.plugin-title span {
+	background-position: -125px -7px;
+}
+
+body.branch-3-6.settings_page_bp-components tr.friends td.plugin-title span,
+body.branch-3-7.settings_page_bp-components tr.friends td.plugin-title span {
+	background-position: -95px -40px;
+}
+
+body.branch-3-6.settings_page_bp-components tr.friends.active td.plugin-title span,
+body.branch-3-7.settings_page_bp-components tr.friends.active td.plugin-title span {
+	background-position: -95px -7px;
+}
+
+body.branch-3-6.settings_page_bp-components tr.core td.plugin-title span,
+body.branch-3-7.settings_page_bp-components tr.core td.plugin-title span {
+	background-position: -184px -40px;
+}
+
+body.branch-3-6.settings_page_bp-components tr.core.active td.plugin-title span,
+body.branch-3-7.settings_page_bp-components tr.core.active td.plugin-title span {
+	background-position: -184px -7px;
+}
+
+body.branch-3-6.settings_page_bp-components tr.members td.plugin-title span,
+body.branch-3-7.settings_page_bp-components tr.members td.plugin-title span {
+	background-position: -36px -40px;
+}
+
+body.branch-3-6.settings_page_bp-components tr.members.active td.plugin-title span,
+body.branch-3-7.settings_page_bp-components tr.members.active td.plugin-title span {
+	background-position: -36px -7px;
+}
+
+#bp-admin-component-form .widefat th {
+    display: table-cell;
+    vertical-align: top;
+}
+
+/* Version Badge */
+
+.bp-badge {
+	padding-top: 142px;
+	height: 50px;
+	width: 173px;
+	color: #fafafa;
+	font-weight: bold;
+	font-size: 14px;
+	text-align: center;
+	margin: 0 -5px;
+	background: url('../images/badge.png') no-repeat;
+}
+
+.about-wrap .bp-badge {
+	position: absolute;
+	top: 0;
+	right: 0;
+}
+	body.rtl .about-wrap .bp-badge {
+		right: auto;
+		left: 0;
+	}
+
+/* HiDPI
+------------------------------------------------------------------------------*/
+
+@media only screen and (-webkit-min-device-pixel-ratio: 1.5) {
+
+	/* Icon 32 */
+	body.branch-3-6 div#icon-buddypress,
+	body.branch-3-6 div#icon-buddypress-activity,
+	body.branch-3-6 div#icon-buddypress-groups,
+	body.branch-3-7 div#icon-buddypress,
+	body.branch-3-7 div#icon-buddypress-activity,
+	body.branch-3-7 div#icon-buddypress-groups {
+		background-image: url('../images/icons64.png');
+		background-size: 419px 45px;
+	}
+
+	/* Backpat */
+	body.branch-3-6 ul#adminmenu li.toplevel_page_bp-components .wp-menu-image,
+	body.branch-3-6 ul#adminmenu li.toplevel_page_bp-general-settings .wp-menu-image,
+	body.branch-3-6 ul#adminmenu li.toplevel_page_bp-activity .wp-menu-image,
+	body.branch-3-6 ul#adminmenu li.toplevel_page_bp-activity_network .wp-menu-image,
+	body.branch-3-6 ul#adminmenu li.toplevel_page_bp-groups .wp-menu-image,
+	body.branch-3-6 ul#adminmenu li.toplevel_page_bp-groups_network .wp-menu-image,
+	body.branch-3-7 ul#adminmenu li.toplevel_page_bp-components .wp-menu-image,
+	body.branch-3-7 ul#adminmenu li.toplevel_page_bp-general-settings .wp-menu-image,
+	body.branch-3-7 ul#adminmenu li.toplevel_page_bp-activity .wp-menu-image,
+	body.branch-3-7 ul#adminmenu li.toplevel_page_bp-activity_network .wp-menu-image,
+	body.branch-3-7 ul#adminmenu li.toplevel_page_bp-groups .wp-menu-image,
+	body.branch-3-7 ul#adminmenu li.toplevel_page_bp-groups_network .wp-menu-image {
+		background-image: url('../images/menu-2x.png') !important;
+		background-size: 209px 64px;
+	}
+
+	/* Badge */
+	.bp-badge {
+		background-image: url('../images/badge-2x.png');
+		background-size: 173px 194px;
+	}
+}
Index: /tags/1.9/bp-core/admin/css/common.min.css
===================================================================
--- /tags/1.9/bp-core/admin/css/common.min.css	(revision 7684)
+++ /tags/1.9/bp-core/admin/css/common.min.css	(revision 7684)
@@ -0,0 +1,1 @@
+body.branch-3-6 div#icon-buddypress,body.branch-3-7 div#icon-buddypress{background:url('../images/icons32.png') no-repeat -370px -6px}body.branch-3-6 div#icon-buddypress-activity,body.branch-3-7 div#icon-buddypress-activity{background:url('../images/icons32.png') no-repeat -10px -6px}body.branch-3-6 div#icon-buddypress-groups,body.branch-3-7 div#icon-buddypress-groups{background:url('../images/icons32.png') no-repeat -250px -6px}body.branch-3-6 ul#adminmenu li.toplevel_page_bp-components .wp-menu-image,body.branch-3-6 ul#adminmenu li.toplevel_page_bp-general-settings .wp-menu-image,body.branch-3-7 ul#adminmenu li.toplevel_page_bp-components .wp-menu-image,body.branch-3-7 ul#adminmenu li.toplevel_page_bp-general-settings .wp-menu-image{background-image:url('../images/menu.png') !important;background-position:-178px -34px}body.branch-3-6 ul#adminmenu li.toplevel_page_bp-components:hover .wp-menu-image,body.branch-3-6 ul#adminmenu li.toplevel_page_bp-general-settings:hover .wp-menu-image,body.branch-3-6 ul#adminmenu li.toplevel_page_bp-components.wp-has-current-submenu .wp-menu-image,body.branch-3-6 ul#adminmenu li.toplevel_page_bp-general-settings.wp-has-current-submenu .wp-menu-image,body.branch-3-7 ul#adminmenu li.toplevel_page_bp-components:hover .wp-menu-image,body.branch-3-7 ul#adminmenu li.toplevel_page_bp-general-settings:hover .wp-menu-image,body.branch-3-7 ul#adminmenu li.toplevel_page_bp-components.wp-has-current-submenu .wp-menu-image,body.branch-3-7 ul#adminmenu li.toplevel_page_bp-general-settings.wp-has-current-submenu .wp-menu-image{background-position:-178px -2px}body.branch-3-6 ul#adminmenu li.toplevel_page_bp-activity .wp-menu-image,body.branch-3-6 ul#adminmenu li.toplevel_page_bp-activity_network .wp-menu-image,body.branch-3-7 ul#adminmenu li.toplevel_page_bp-activity .wp-menu-image,body.branch-3-7 ul#adminmenu li.toplevel_page_bp-activity_network .wp-menu-image{background-image:url('../images/menu.png');background-position:0 -34px}body.branch-3-6 ul#adminmenu li.toplevel_page_bp-activity:hover .wp-menu-image,body.branch-3-6 ul#adminmenu li.toplevel_page_bp-activity.current .wp-menu-image,body.branch-3-6 ul#adminmenu li.toplevel_page_bp-activity.wp-has-current-submenu .wp-menu-image,body.branch-3-6 ul#adminmenu li.toplevel_page_bp-activity_network:hover .wp-menu-image,body.branch-3-6 ul#adminmenu li.toplevel_page_bp-activity_network.current .wp-menu-image,body.branch-3-6 ul#adminmenu li.toplevel_page_bp-activity_network.wp-has-current-submenu .wp-menu-image,body.branch-3-7 ul#adminmenu li.toplevel_page_bp-activity:hover .wp-menu-image,body.branch-3-7 ul#adminmenu li.toplevel_page_bp-activity.current .wp-menu-image,body.branch-3-7 ul#adminmenu li.toplevel_page_bp-activity.wp-has-current-submenu .wp-menu-image,body.branch-3-7 ul#adminmenu li.toplevel_page_bp-activity_network:hover .wp-menu-image,body.branch-3-7 ul#adminmenu li.toplevel_page_bp-activity_network.current .wp-menu-image,body.branch-3-7 ul#adminmenu li.toplevel_page_bp-activity_network.wp-has-current-submenu .wp-menu-image{background-position:0 -2px}body.branch-3-6 ul#adminmenu li.toplevel_page_bp-groups .wp-menu-image,body.branch-3-6 ul#adminmenu li.toplevel_page_bp-groups_network .wp-menu-image,body.branch-3-7 ul#adminmenu li.toplevel_page_bp-groups .wp-menu-image,body.branch-3-7 ul#adminmenu li.toplevel_page_bp-groups_network .wp-menu-image{background-image:url('../images/menu.png');background-position:-61px -34px}body.branch-3-6 ul#adminmenu li.toplevel_page_bp-groups:hover .wp-menu-image,body.branch-3-6 ul#adminmenu li.toplevel_page_bp-groups.current .wp-menu-image,body.branch-3-6 ul#adminmenu li.toplevel_page_bp-groups.wp-has-current-submenu .wp-menu-image,body.branch-3-6 ul#adminmenu li.toplevel_page_bp-groups_network:hover .wp-menu-image,body.branch-3-6 ul#adminmenu li.toplevel_page_bp-groups_network.current .wp-menu-image,body.branch-3-6 ul#adminmenu li.toplevel_page_bp-groups_network.wp-has-current-submenu .wp-menu-image,body.branch-3-7 ul#adminmenu li.toplevel_page_bp-groups:hover .wp-menu-image,body.branch-3-7 ul#adminmenu li.toplevel_page_bp-groups.current .wp-menu-image,body.branch-3-7 ul#adminmenu li.toplevel_page_bp-groups.wp-has-current-submenu .wp-menu-image,body.branch-3-7 ul#adminmenu li.toplevel_page_bp-groups_network:hover .wp-menu-image,body.branch-3-7 ul#adminmenu li.toplevel_page_bp-groups_network.current .wp-menu-image,body.branch-3-7 ul#adminmenu li.toplevel_page_bp-groups_network.wp-has-current-submenu .wp-menu-image{background-position:-61px -2px}th.column-gid{width:60px}td.column-gid{vertical-align:middle}table.bp-group-members th,table.bp-group-members td{padding:5px 0}table.bp-group-members .uid-column{padding-left:20px;padding-right:20px}table.bp-group-members .uname-column{width:70%}table.bp-group-members .urole-column{padding-left:20px;padding-right:20px}#adminmenu #toplevel_page_bp-activity .wp-menu-image:before,#adminmenu #toplevel_page_bp-activity_user .wp-menu-image:before,#adminmenu #toplevel_page_bp-activity_network .wp-menu-image:before{content:"\f452"}#adminmenu #toplevel_page_bp-groups .wp-menu-image:before,#adminmenu #toplevel_page_bp-groups_user .wp-menu-image:before,#adminmenu #toplevel_page_bp-groups_network .wp-menu-image:before{content:"\f456"}#adminmenu #toplevel_page_bp-notifications .wp-menu-image:before,#adminmenu #toplevel_page_bp-notifications_user .wp-menu-image:before,#adminmenu #toplevel_page_bp-notifications_network .wp-menu-image:before{content:"\f439"}#adminmenu #toplevel_page_bp-messages .wp-menu-image:before,#adminmenu #toplevel_page_bp-messages_user .wp-menu-image:before,#adminmenu #toplevel_page_bp-messages_network .wp-menu-image:before{content:"\f457"}#adminmenu #toplevel_page_bp-friends .wp-menu-image:before,#adminmenu #toplevel_page_bp-friends_user .wp-menu-image:before,#adminmenu #toplevel_page_bp-friends_network .wp-menu-image:before{content:"\f454"}#adminmenu #toplevel_page_bp-settings .wp-menu-image:before,#adminmenu #toplevel_page_bp-settings_user .wp-menu-image:before,#adminmenu #toplevel_page_bp-settings_network .wp-menu-image:before{content:"\f108"}#adminmenu li.toplevel_page_bp-components .wp-menu-image,#adminmenu li.toplevel_page_bp-general-settings .wp-menu-image{content:"\f448"}body.branch-3-6 #adminmenu #toplevel_page_bp-activity .wp-menu-image:before,body.branch-3-6 #adminmenu #toplevel_page_bp-activity_network .wp-menu-image:before,body.branch-3-6 #adminmenu #toplevel_page_bp-groups .wp-menu-image:before,body.branch-3-6 #adminmenu #toplevel_page_bp-groups_network .wp-menu-image:before,body.branch-3-6 #adminmenu li.toplevel_page_bp-components .wp-menu-image,body.branch-3-6 #adminmenu li.toplevel_page_bp-general-settings .wp-menu-image,body.branch-3-7 #adminmenu #toplevel_page_bp-activity .wp-menu-image:before,body.branch-3-7 #adminmenu #toplevel_page_bp-activity_network .wp-menu-image:before,body.branch-3-7 #adminmenu #toplevel_page_bp-groups .wp-menu-image:before,body.branch-3-7 #adminmenu #toplevel_page_bp-groups_network .wp-menu-image:before,body.branch-3-7 #adminmenu li.toplevel_page_bp-components .wp-menu-image,body.branch-3-7 #adminmenu li.toplevel_page_bp-general-settings .wp-menu-image{content:""}.settings_page_bp-components td.plugin-title span{float:left;width:18px;height:18px;margin-right:5px}.settings_page_bp-components td.plugin-title span:before{font-family:'dashicons';font-size:18px}.settings_page_bp-components tr.activity td.plugin-title span:before{content:"\f452"}.settings_page_bp-components tr.notifications td.plugin-title span:before{content:"\f339"}.settings_page_bp-components tr.xprofile td.plugin-title span:before{content:"\f336"}.settings_page_bp-components tr.settings td.plugin-title span:before{content:"\f108"}.settings_page_bp-components tr.groups td.plugin-title span:before{content:"\f456"}.settings_page_bp-components tr.messages td.plugin-title span:before{content:"\f457"}.settings_page_bp-components tr.forums td.plugin-title span:before{content:"\f452"}.settings_page_bp-components tr.blogs td.plugin-title span:before{content:"\f120"}.settings_page_bp-components tr.friends td.plugin-title span:before{content:"\f454"}body.branch-3-6.settings_page_bp-components tr.activity td.plugin-title span:before,body.branch-3-6.settings_page_bp-components tr.notifications td.plugin-title span:before,body.branch-3-6.settings_page_bp-components tr.xprofile td.plugin-title span:before,body.branch-3-6.settings_page_bp-components tr.settings td.plugin-title span:before,body.branch-3-6.settings_page_bp-components tr.groups td.plugin-title span:before,body.branch-3-6.settings_page_bp-components tr.messages td.plugin-title span:before,body.branch-3-6.settings_page_bp-components tr.forums td.plugin-title span:before,body.branch-3-6.settings_page_bp-components tr.blogs td.plugin-title span:before,body.branch-3-6.settings_page_bp-components tr.friends td.plugin-title span:before,body.branch-3-7.settings_page_bp-components tr.activity td.plugin-title span:before,body.branch-3-7.settings_page_bp-components tr.notifications td.plugin-title span:before,body.branch-3-7.settings_page_bp-components tr.xprofile td.plugin-title span:before,body.branch-3-7.settings_page_bp-components tr.settings td.plugin-title span:before,body.branch-3-7.settings_page_bp-components tr.groups td.plugin-title span:before,body.branch-3-7.settings_page_bp-components tr.messages td.plugin-title span:before,body.branch-3-7.settings_page_bp-components tr.forums td.plugin-title span:before,body.branch-3-7.settings_page_bp-components tr.blogs td.plugin-title span:before,body.branch-3-7.settings_page_bp-components tr.friends td.plugin-title span:before{content:""}body.branch-3-6.settings_page_bp-components td.plugin-title span,body.branch-3-7.settings_page_bp-components td.plugin-title span{background-image:url('../images/menu.png');background-position:-4px -40px;background-repeat:no-repeat}body.branch-3-6.settings_page_bp-components tr.active td.plugin-title span,body.branch-3-7.settings_page_bp-components tr.active td.plugin-title span{background-position-y:-7px}body.branch-3-6.settings_page_bp-components tr.activity td.plugin-title span,body.branch-3-7.settings_page_bp-components tr.activity td.plugin-title span{background-position:-4px -40px}body.branch-3-6.settings_page_bp-components tr.activity.active td.plugin-title span,body.branch-3-7.settings_page_bp-components tr.activity.active td.plugin-title span{background-position:-4px -7px}body.branch-3-6.settings_page_bp-components tr.xprofile td.plugin-title span,body.branch-3-7.settings_page_bp-components tr.xprofile td.plugin-title span{background-image:url('../images/menu-wp.png');background-position:-305px -40px}body.branch-3-6.settings_page_bp-components tr.xprofile.active td.plugin-title span,body.branch-3-7.settings_page_bp-components tr.xprofile.active td.plugin-title span{background-position:-305px -7px}body.branch-3-6.settings_page_bp-components tr.settings td.plugin-title span,body.branch-3-7.settings_page_bp-components tr.settings td.plugin-title span{background-image:url('../images/menu-wp.png');background-position:-334px -40px}body.branch-3-6.settings_page_bp-components tr.settings.active td.plugin-title span,body.branch-3-7.settings_page_bp-components tr.settings.active td.plugin-title span{background-position:-334px -7px}body.branch-3-6.settings_page_bp-components tr.groups td.plugin-title span,body.branch-3-7.settings_page_bp-components tr.groups td.plugin-title span{background-position:-66px -40px}body.branch-3-6.settings_page_bp-components tr.groups.active td.plugin-title span,body.branch-3-7.settings_page_bp-components tr.groups.active td.plugin-title span{background-position:-66px -7px}body.branch-3-6.settings_page_bp-components tr.messages td.plugin-title span,body.branch-3-7.settings_page_bp-components tr.messages td.plugin-title span{background-position:-154px -40px}body.branch-3-6.settings_page_bp-components tr.messages.active td.plugin-title span,body.branch-3-7.settings_page_bp-components tr.messages.active td.plugin-title span{background-position:-154px -7px}body.branch-3-6.settings_page_bp-components tr.forums td.plugin-title span,body.branch-3-7.settings_page_bp-components tr.forums td.plugin-title span{background-image:url('../images/menu-wp.png');background-position:-36px -40px}body.branch-3-6.settings_page_bp-components tr.forums.active td.plugin-title span,body.branch-3-7.settings_page_bp-components tr.forums.active td.plugin-title span{background-position:-36px -7px}body.branch-3-6.settings_page_bp-components tr.blogs td.plugin-title span,body.branch-3-7.settings_page_bp-components tr.blogs td.plugin-title span{background-position:-125px -40px}body.branch-3-6.settings_page_bp-components tr.blogs.active td.plugin-title span,body.branch-3-7.settings_page_bp-components tr.blogs.active td.plugin-title span{background-position:-125px -7px}body.branch-3-6.settings_page_bp-components tr.friends td.plugin-title span,body.branch-3-7.settings_page_bp-components tr.friends td.plugin-title span{background-position:-95px -40px}body.branch-3-6.settings_page_bp-components tr.friends.active td.plugin-title span,body.branch-3-7.settings_page_bp-components tr.friends.active td.plugin-title span{background-position:-95px -7px}body.branch-3-6.settings_page_bp-components tr.core td.plugin-title span,body.branch-3-7.settings_page_bp-components tr.core td.plugin-title span{background-position:-184px -40px}body.branch-3-6.settings_page_bp-components tr.core.active td.plugin-title span,body.branch-3-7.settings_page_bp-components tr.core.active td.plugin-title span{background-position:-184px -7px}body.branch-3-6.settings_page_bp-components tr.members td.plugin-title span,body.branch-3-7.settings_page_bp-components tr.members td.plugin-title span{background-position:-36px -40px}body.branch-3-6.settings_page_bp-components tr.members.active td.plugin-title span,body.branch-3-7.settings_page_bp-components tr.members.active td.plugin-title span{background-position:-36px -7px}#bp-admin-component-form .widefat th{display:table-cell;vertical-align:top}.bp-badge{padding-top:142px;height:50px;width:173px;color:#fafafa;font-weight:bold;font-size:14px;text-align:center;margin:0 -5px;background:url('../images/badge.png') no-repeat}.about-wrap .bp-badge{position:absolute;top:0;right:0}body.rtl .about-wrap .bp-badge{right:auto;left:0}@media only screen and (-webkit-min-device-pixel-ratio:1.5){body.branch-3-6 div#icon-buddypress,body.branch-3-6 div#icon-buddypress-activity,body.branch-3-6 div#icon-buddypress-groups,body.branch-3-7 div#icon-buddypress,body.branch-3-7 div#icon-buddypress-activity,body.branch-3-7 div#icon-buddypress-groups{background-image:url('../images/icons64.png');background-size:419px 45px}body.branch-3-6 ul#adminmenu li.toplevel_page_bp-components .wp-menu-image,body.branch-3-6 ul#adminmenu li.toplevel_page_bp-general-settings .wp-menu-image,body.branch-3-6 ul#adminmenu li.toplevel_page_bp-activity .wp-menu-image,body.branch-3-6 ul#adminmenu li.toplevel_page_bp-activity_network .wp-menu-image,body.branch-3-6 ul#adminmenu li.toplevel_page_bp-groups .wp-menu-image,body.branch-3-6 ul#adminmenu li.toplevel_page_bp-groups_network .wp-menu-image,body.branch-3-7 ul#adminmenu li.toplevel_page_bp-components .wp-menu-image,body.branch-3-7 ul#adminmenu li.toplevel_page_bp-general-settings .wp-menu-image,body.branch-3-7 ul#adminmenu li.toplevel_page_bp-activity .wp-menu-image,body.branch-3-7 ul#adminmenu li.toplevel_page_bp-activity_network .wp-menu-image,body.branch-3-7 ul#adminmenu li.toplevel_page_bp-groups .wp-menu-image,body.branch-3-7 ul#adminmenu li.toplevel_page_bp-groups_network .wp-menu-image{background-image:url('../images/menu-2x.png') !important;background-size:209px 64px}.bp-badge{background-image:url('../images/badge-2x.png');background-size:173px 194px}}
Index: /tags/1.9/bp-core/bp-core-actions.php
===================================================================
--- /tags/1.9/bp-core/bp-core-actions.php	(revision 7684)
+++ /tags/1.9/bp-core/bp-core-actions.php	(revision 7684)
@@ -0,0 +1,104 @@
+<?php
+
+/**
+ * BuddyPress Filters & Actions.
+ *
+ * @package BuddyPress
+ * @subpackage Hooks
+ *
+ * This file contains the actions and filters that are used through-out BuddyPress.
+ * They are consolidated here to make searching for them easier, and to help
+ * developers understand at a glance the order in which things occur.
+ *
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/**
+ * Attach BuddyPress to WordPress.
+ *
+ * BuddyPress uses its own internal actions to help aid in third-party plugin
+ * development, and to limit the amount of potential future code changes when
+ * updates to WordPress core occur.
+ *
+ * These actions exist to create the concept of 'plugin dependencies'. They
+ * provide a safe way for plugins to execute code *only* when BuddyPress is
+ * installed and activated, without needing to do complicated guesswork.
+ *
+ * For more information on how this works, see the 'Plugin Dependency' section
+ * near the bottom of this file.
+ *
+ *           v--WordPress Actions       v--BuddyPress Sub-actions
+  */
+add_action( 'plugins_loaded',          'bp_loaded',                 10    );
+add_action( 'init',                    'bp_init',                   10    );
+add_action( 'parse_query',             'bp_parse_query',            2     ); // Early for overrides
+add_action( 'wp',                      'bp_ready',                  10    );
+add_action( 'set_current_user',        'bp_setup_current_user',     10    );
+add_action( 'setup_theme',             'bp_setup_theme',            10    );
+add_action( 'after_setup_theme',       'bp_after_setup_theme',      100   ); // After WP themes
+add_action( 'wp_enqueue_scripts',      'bp_enqueue_scripts',        10    );
+add_action( 'admin_bar_menu',          'bp_setup_admin_bar',        20    ); // After WP core
+add_action( 'template_redirect',       'bp_template_redirect',      10    );
+add_action( 'widgets_init',            'bp_widgets_init',           10    );
+add_action( 'generate_rewrite_rules',  'bp_generate_rewrite_rules', 10    );
+
+/**
+ * bp_loaded - Attached to 'plugins_loaded' above
+ *
+ * Attach various loader actions to the bp_loaded action.
+ * The load order helps to execute code at the correct time.
+ *                                                      v---Load order
+ */
+add_action( 'bp_loaded', 'bp_setup_components',         2  );
+add_action( 'bp_loaded', 'bp_include',                  4  );
+add_action( 'bp_loaded', 'bp_setup_widgets',            6  );
+add_action( 'bp_loaded', 'bp_register_theme_packages',  12 );
+add_action( 'bp_loaded', 'bp_register_theme_directory', 14 );
+
+/**
+ * bp_init - Attached to 'init' above
+ *
+ * Attach various initialization actions to the bp_init action.
+ * The load order helps to execute code at the correct time.
+ *                                                   v---Load order
+ */
+add_action( 'bp_init', 'bp_core_set_uri_globals',    2  );
+add_action( 'bp_init', 'bp_setup_globals',           4  );
+add_action( 'bp_init', 'bp_setup_nav',               6  );
+add_action( 'bp_init', 'bp_setup_title',             8  );
+add_action( 'bp_init', 'bp_core_load_admin_bar_css', 12 );
+add_action( 'bp_init', 'bp_add_rewrite_tags',        20 );
+add_action( 'bp_init', 'bp_add_rewrite_rules',       30 );
+add_action( 'bp_init', 'bp_add_permastructs',        40 );
+
+/**
+ * bp_template_redirect - Attached to 'template_redirect' above
+ *
+ * Attach various template actions to the bp_template_redirect action.
+ * The load order helps to execute code at the correct time.
+ *
+ * Note that we currently use template_redirect versus template include because
+ * BuddyPress is a bully and overrides the existing themes output in many
+ * places. This won't always be this way, we promise.
+ *                                                           v---Load order
+ */
+add_action( 'bp_template_redirect', 'bp_redirect_canonical', 2  );
+add_action( 'bp_template_redirect', 'bp_actions',            4  );
+add_action( 'bp_template_redirect', 'bp_screens',            6  );
+add_action( 'bp_template_redirect', 'bp_post_request',       10 );
+add_action( 'bp_template_redirect', 'bp_get_request',        10 );
+
+/**
+ * Add the BuddyPress functions file
+ */
+add_action( 'bp_after_setup_theme', 'bp_load_theme_functions', 1 );
+
+// Load the admin
+if ( is_admin() ) {
+	add_action( 'bp_loaded', 'bp_admin' );
+}
+
+// Activation redirect
+add_action( 'bp_activation', 'bp_add_activation_redirect' );
Index: /tags/1.9/bp-core/bp-core-admin.php
===================================================================
--- /tags/1.9/bp-core/bp-core-admin.php	(revision 7684)
+++ /tags/1.9/bp-core/bp-core-admin.php	(revision 7684)
@@ -0,0 +1,681 @@
+<?php
+
+/**
+ * Main BuddyPress Admin Class.
+ *
+ * @package BuddyPress
+ * @subpackage CoreAdministration
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+if ( !class_exists( 'BP_Admin' ) ) :
+/**
+ * Load BuddyPress plugin admin area.
+ *
+ * @package BuddyPress
+ * @subpackage CoreAdministration
+ *
+ * @since BuddyPress (1.6.0)
+ */
+class BP_Admin {
+
+	/** Directory *************************************************************/
+
+	/**
+	 * Path to the BuddyPress admin directory.
+	 *
+	 * @var string $admin_dir
+	 */
+	public $admin_dir = '';
+
+	/** URLs ******************************************************************/
+
+	/**
+	 * URL to the BuddyPress admin directory.
+	 *
+	 * @var string $admin_url
+	 */
+	public $admin_url = '';
+
+	/**
+	 * URL to the BuddyPress images directory.
+	 *
+	 * @var string $images_url
+	 */
+	public $images_url = '';
+
+	/**
+	 * URL to the BuddyPress admin CSS directory.
+	 *
+	 * @var string $css_url
+	 */
+	public $css_url = '';
+
+	/**
+	 * URL to the BuddyPress admin JS directory.
+	 *
+	 * @var string
+	 */
+	public $js_url = '';
+
+	/** Other *****************************************************************/
+
+	/**
+	 * Notices used for user feedback, like saving settings.
+	 *
+	 * @var array()
+	 */
+	public $notices = array();
+
+	/** Methods ***************************************************************/
+
+	/**
+	 * The main BuddyPress admin loader.
+	 *
+	 * @since BuddyPress (1.6.0)
+	 *
+	 * @uses BP_Admin::setup_globals() Setup the globals needed.
+	 * @uses BP_Admin::includes() Include the required files.
+	 * @uses BP_Admin::setup_actions() Setup the hooks and actions.
+	 */
+	public function __construct() {
+		$this->setup_globals();
+		$this->includes();
+		$this->setup_actions();
+	}
+
+	/**
+	 * Set admin-related globals.
+	 *
+	 * @access private
+	 * @since BuddyPress (1.6.0)
+	 */
+	private function setup_globals() {
+		$bp = buddypress();
+
+		// Paths and URLs
+		$this->admin_dir  = trailingslashit( $bp->plugin_dir  . 'bp-core/admin' ); // Admin path
+		$this->admin_url  = trailingslashit( $bp->plugin_url  . 'bp-core/admin' ); // Admin url
+		$this->images_url = trailingslashit( $this->admin_url . 'images'        ); // Admin images URL
+		$this->css_url    = trailingslashit( $this->admin_url . 'css'           ); // Admin css URL
+		$this->js_url     = trailingslashit( $this->admin_url . 'js'            ); // Admin css URL
+
+		// Main settings page
+		$this->settings_page = bp_core_do_network_admin() ? 'settings.php' : 'options-general.php';
+	}
+
+	/**
+	 * Include required files.
+	 *
+	 * @since BuddyPress (1.6.0)
+	 * @access private
+	 */
+	private function includes() {
+		require( $this->admin_dir . 'bp-core-actions.php'    );
+		require( $this->admin_dir . 'bp-core-settings.php'   );
+		require( $this->admin_dir . 'bp-core-functions.php'  );
+		require( $this->admin_dir . 'bp-core-components.php' );
+		require( $this->admin_dir . 'bp-core-slugs.php'      );
+	}
+
+	/**
+	 * Set up the admin hooks, actions, and filters.
+	 *
+	 * @access private
+	 * @since BuddyPress (1.6.0)
+	 *
+	 * @uses add_action() To add various actions.
+	 * @uses add_filter() To add various filters.
+	 */
+	private function setup_actions() {
+
+		/** General Actions ***************************************************/
+
+		// Add some page specific output to the <head>
+		add_action( 'bp_admin_head',            array( $this, 'admin_head'  ), 999 );
+
+		// Add menu item to settings menu
+		add_action( bp_core_admin_hook(),       array( $this, 'admin_menus' ), 5 );
+
+		// Enqueue all admin JS and CSS
+		add_action( 'bp_admin_enqueue_scripts', array( $this, 'enqueue_scripts' ) );
+
+		/** BuddyPress Actions ************************************************/
+
+		// Load the BuddyPress metabox in the WP Nav Menu Admin UI
+		add_action( 'load-nav-menus.php', 'bp_admin_wp_nav_menu_meta_box' );
+
+		// Add settings
+		add_action( 'bp_register_admin_settings', array( $this, 'register_admin_settings' ) );
+
+		// Add a link to BuddyPress About page to the admin bar
+		add_action( 'admin_bar_menu', array( $this, 'admin_bar_about_link' ), 15 );
+
+		/** Filters ***********************************************************/
+
+		// Add link to settings page
+		add_filter( 'plugin_action_links',               array( $this, 'modify_plugin_action_links' ), 10, 2 );
+		add_filter( 'network_admin_plugin_action_links', array( $this, 'modify_plugin_action_links' ), 10, 2 );
+	}
+
+	/**
+	 * Add the navigational menu elements.
+	 *
+	 * @since BuddyPress (1.6)
+	 *
+	 * @uses add_management_page() To add the Recount page in Tools section.
+	 * @uses add_options_page() To add the Forums settings page in Settings
+	 *       section.
+	 */
+	public function admin_menus() {
+
+		// Bail if user cannot moderate
+		if ( ! bp_current_user_can( 'manage_options' ) )
+			return;
+
+		// About
+		add_dashboard_page(
+			__( 'Welcome to BuddyPress',  'buddypress' ),
+			__( 'Welcome to BuddyPress',  'buddypress' ),
+			'manage_options',
+			'bp-about',
+			array( $this, 'about_screen' )
+		);
+
+		// Credits
+		add_dashboard_page(
+			__( 'Welcome to BuddyPress',  'buddypress' ),
+			__( 'Welcome to BuddyPress',  'buddypress' ),
+			'manage_options',
+			'bp-credits',
+			array( $this, 'credits_screen' )
+		);
+
+		$hooks = array();
+
+		// Changed in BP 1.6 . See bp_core_admin_backpat_menu()
+		$hooks[] = add_menu_page(
+			__( 'BuddyPress', 'buddypress' ),
+			__( 'BuddyPress', 'buddypress' ),
+			'manage_options',
+			'bp-general-settings',
+			'bp_core_admin_backpat_menu',
+			'div'
+		);
+
+		$hooks[] = add_submenu_page(
+			'bp-general-settings',
+			__( 'BuddyPress Help', 'buddypress' ),
+			__( 'Help', 'buddypress' ),
+			'manage_options',
+			'bp-general-settings',
+			'bp_core_admin_backpat_page'
+		);
+
+		// Add the option pages
+		$hooks[] = add_submenu_page(
+			$this->settings_page,
+			__( 'BuddyPress Components', 'buddypress' ),
+			__( 'BuddyPress', 'buddypress' ),
+			'manage_options',
+			'bp-components',
+			'bp_core_admin_components_settings'
+		);
+
+		$hooks[] = add_submenu_page(
+			$this->settings_page,
+			__( 'BuddyPress Pages', 'buddypress' ),
+			__( 'BuddyPress Pages', 'buddypress' ),
+			'manage_options',
+			'bp-page-settings',
+			'bp_core_admin_slugs_settings'
+		);
+
+		$hooks[] = add_submenu_page(
+			$this->settings_page,
+			__( 'BuddyPress Settings', 'buddypress' ),
+			__( 'BuddyPress Settings', 'buddypress' ),
+			'manage_options',
+			'bp-settings',
+			'bp_core_admin_settings'
+		);
+
+		// Fudge the highlighted subnav item when on a BuddyPress admin page
+		foreach( $hooks as $hook ) {
+			add_action( "admin_head-$hook", 'bp_core_modify_admin_menu_highlight' );
+		}
+	}
+
+	/**
+	 * Register the settings.
+	 *
+	 * @since BuddyPress (1.6.0)
+	 *
+	 * @uses add_settings_section() To add our own settings section.
+	 * @uses add_settings_field() To add various settings fields.
+	 * @uses register_setting() To register various settings.
+	 */
+	public function register_admin_settings() {
+
+		/** Main Section ******************************************************/
+
+		// Add the main section
+		add_settings_section( 'bp_main',            __( 'Main Settings',    'buddypress' ), 'bp_admin_setting_callback_main_section',     'buddypress'            );
+
+		// Hide toolbar for logged out users setting
+		add_settings_field( 'hide-loggedout-adminbar',        __( 'Toolbar',        'buddypress' ), 'bp_admin_setting_callback_admin_bar',        'buddypress', 'bp_main' );
+	 	register_setting  ( 'buddypress',           'hide-loggedout-adminbar',        'intval'                                                                              );
+
+		// Only show 'switch to Toolbar' option if the user chose to retain the BuddyBar during the 1.6 upgrade
+		if ( (bool) bp_get_option( '_bp_force_buddybar', false ) ) {
+			add_settings_field( '_bp_force_buddybar', __( 'Toolbar', 'buddypress' ), 'bp_admin_setting_callback_force_buddybar', 'buddypress', 'bp_main' );
+		 	register_setting( 'buddypress', '_bp_force_buddybar', 'bp_admin_sanitize_callback_force_buddybar' );
+		}
+
+		// Allow account deletion
+		add_settings_field( 'bp-disable-account-deletion', __( 'Account Deletion', 'buddypress' ), 'bp_admin_setting_callback_account_deletion', 'buddypress', 'bp_main' );
+	 	register_setting  ( 'buddypress',           'bp-disable-account-deletion', 'intval'                                                                              );
+
+		/** XProfile Section **************************************************/
+
+		if ( bp_is_active( 'xprofile' ) ) {
+
+			// Add the main section
+			add_settings_section( 'bp_xprofile',      __( 'Profile Settings', 'buddypress' ), 'bp_admin_setting_callback_xprofile_section', 'buddypress'                );
+
+			// Allow avatar uploads
+			add_settings_field( 'bp-disable-avatar-uploads', __( 'Avatar Uploads',   'buddypress' ), 'bp_admin_setting_callback_avatar_uploads',   'buddypress', 'bp_xprofile' );
+			register_setting  ( 'buddypress',         'bp-disable-avatar-uploads',   'intval'                                                                                  );
+
+			// Profile sync setting
+			add_settings_field( 'bp-disable-profile-sync',   __( 'Profile Syncing',  'buddypress' ), 'bp_admin_setting_callback_profile_sync',     'buddypress', 'bp_xprofile' );
+			register_setting  ( 'buddypress',         'bp-disable-profile-sync',     'intval'                                                                                  );
+		}
+
+		/** Groups Section ****************************************************/
+
+		if ( bp_is_active( 'groups' ) ) {
+
+			// Add the main section
+			add_settings_section( 'bp_groups',        __( 'Groups Settings',  'buddypress' ), 'bp_admin_setting_callback_groups_section',   'buddypress'              );
+
+			// Allow subscriptions setting
+			add_settings_field( 'bp_restrict_group_creation', __( 'Group Creation',   'buddypress' ), 'bp_admin_setting_callback_group_creation',   'buddypress', 'bp_groups' );
+			register_setting  ( 'buddypress',         'bp_restrict_group_creation',   'intval'                                                                                );
+		}
+
+		/** Forums ************************************************************/
+
+		if ( bp_is_active( 'forums' ) ) {
+
+			// Add the main section
+			add_settings_section( 'bp_forums',        __( 'Legacy Group Forums',       'buddypress' ), 'bp_admin_setting_callback_bbpress_section',       'buddypress'              );
+
+			// Allow subscriptions setting
+			add_settings_field( 'bb-config-location', __( 'bbPress Configuration', 'buddypress' ), 'bp_admin_setting_callback_bbpress_configuration', 'buddypress', 'bp_forums' );
+			register_setting  ( 'buddypress',         'bb-config-location',        ''                                                                                           );
+		}
+
+		/** Activity Section **************************************************/
+
+		if ( bp_is_active( 'activity' ) ) {
+
+			// Add the main section
+			add_settings_section( 'bp_activity',      __( 'Activity Settings', 'buddypress' ), 'bp_admin_setting_callback_activity_section', 'buddypress'                );
+
+			// Activity commenting on blog and forum posts
+			add_settings_field( 'bp-disable-blogforum-comments', __( 'Blog &amp; Forum Comments', 'buddypress' ), 'bp_admin_setting_callback_blogforum_comments', 'buddypress', 'bp_activity' );
+			register_setting( 'buddypress', 'bp-disable-blogforum-comments', 'bp_admin_sanitize_callback_blogforum_comments' );
+
+			// Allow activity akismet
+			if ( is_plugin_active( 'akismet/akismet.php' ) && defined( 'AKISMET_VERSION' ) ) {
+				add_settings_field( '_bp_enable_akismet', __( 'Akismet',          'buddypress' ), 'bp_admin_setting_callback_activity_akismet', 'buddypress', 'bp_activity' );
+				register_setting  ( 'buddypress',         '_bp_enable_akismet',   'intval'                                                                                  );
+			}
+		}
+	}
+
+	/**
+	 * Add a link to BuddyPress About page to the admin bar.
+	 *
+	 * @since BuddyPress (1.9.0)
+	 *
+	 * @param WP_Admin_Bar $wp_admin_bar As passed to 'admin_bar_menu'.
+	 */
+	public function admin_bar_about_link( $wp_admin_bar ) {
+		if ( is_user_logged_in() ) {
+			$wp_admin_bar->add_menu( array(
+				'parent' => 'wp-logo',
+				'id'     => 'bp-about',
+				'title'  => esc_html__( 'About BuddyPress', 'buddypress' ),
+				'href'   => add_query_arg( array( 'page' => 'bp-about' ), bp_get_admin_url( 'index.php' ) ),
+			) );
+		}
+	}
+
+	/**
+	 * Add Settings link to plugins area.
+	 *
+	 * @since BuddyPress (1.6.0)
+	 *
+	 * @param array $links Links array in which we would prepend our link.
+	 * @param string $file Current plugin basename.
+	 * @return array Processed links.
+	 */
+	public function modify_plugin_action_links( $links, $file ) {
+
+		// Return normal links if not BuddyPress
+		if ( plugin_basename( buddypress()->file ) != $file )
+			return $links;
+
+		// Add a few links to the existing links array
+		return array_merge( $links, array(
+			'settings' => '<a href="' . add_query_arg( array( 'page' => 'bp-components' ), bp_get_admin_url( $this->settings_page ) ) . '">' . esc_html__( 'Settings', 'buddypress' ) . '</a>',
+			'about'    => '<a href="' . add_query_arg( array( 'page' => 'bp-about'      ), bp_get_admin_url( 'index.php'          ) ) . '">' . esc_html__( 'About',    'buddypress' ) . '</a>'
+		) );
+	}
+
+	/**
+	 * Add some general styling to the admin area.
+	 *
+	 * @since BuddyPress (1.6.0)
+	 */
+	public function admin_head() {
+
+		// Settings pages
+		remove_submenu_page( $this->settings_page, 'bp-page-settings' );
+		remove_submenu_page( $this->settings_page, 'bp-settings'      );
+
+		// About and Credits pages
+		remove_submenu_page( 'index.php', 'bp-about'   );
+		remove_submenu_page( 'index.php', 'bp-credits' );
+	}
+
+	/**
+	 * Add some general styling to the admin area.
+	 *
+	 * @since BuddyPress (1.6.0)
+	 */
+	public function enqueue_scripts() {
+
+		$min = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min';
+
+		$file = $this->css_url . "common{$min}.css";
+		$file = apply_filters( 'bp_core_admin_common_css', $file );
+		wp_enqueue_style( 'bp-admin-common-css', $file, array(), bp_get_version() );
+	}
+
+	/** About *****************************************************************/
+
+	/**
+	 * Output the about screen.
+	 *
+	 * @since BuddyPress (1.7.0)
+	 */
+	public function about_screen() {
+		global $wp_rewrite;
+
+		$is_new_install = ! empty( $_GET['is_new_install'] );
+
+		$pretty_permalinks_enabled = ! empty( $wp_rewrite->permalink_structure );
+
+		list( $display_version ) = explode( '-', bp_get_version() ); ?>
+
+		<div class="wrap about-wrap">
+			<h1><?php printf( __( 'Welcome to BuddyPress %s', 'buddypress' ), $display_version ); ?></h1>
+			<div class="about-text">
+				<?php if ( $is_new_install ) : ?>
+				<?php printf( __( 'It&#8217;s a great time to use BuddyPress! %s is our first version with a new component in over two years. Not only that, there are plenty of new features, enhancements, and bug fixes.', 'buddypress' ), $display_version ); ?>
+				<?php else : ?>
+					<?php printf( __( 'Thanks for updating! BuddyPress %s is our first version with a new component in over two years. Not only that, there are plenty of new features, enhancements, and bug fixes.', 'buddypress' ), $display_version ); ?>
+				<?php endif; ?>
+			</div>
+
+			<div class="changelog">
+				<h3><?php _e( 'Check out the highlights:', 'buddypress' ); ?></h3>
+
+				<ul>
+					<li><strong><?php _e( 'You can now add dynamic BuddyPress links to custom navigation menus.', 'buddypress' ); ?></strong></li>
+					<li><strong><?php _e( 'Notifications have been moved into their own component.', 'buddypress' ); ?></strong></li>
+					<li><strong><?php _e( 'Three new widgets, allowing easier site customization.', 'buddypress' ); ?></strong></li>
+				<ul>
+			</div>
+
+			<div class="bp-badge"><?php printf( __( 'Version %s', 'buddypress' ), $display_version ); ?></div>
+
+			<h2 class="nav-tab-wrapper">
+				<a class="nav-tab nav-tab-active" href="<?php echo esc_url( bp_get_admin_url( add_query_arg( array( 'page' => 'bp-about' ), 'index.php' ) ) ); ?>">
+					<?php _e( 'What&#8217;s New', 'buddypress' ); ?>
+				</a><a class="nav-tab" href="<?php echo esc_url( bp_get_admin_url( add_query_arg( array( 'page' => 'bp-credits' ), 'index.php' ) ) ); ?>">
+					<?php _e( 'Credits', 'buddypress' ); ?>
+				</a>
+			</h2>
+
+			<?php if ( $is_new_install ) : ?>
+			<h3><?php _e( 'Getting Started', 'buddypress' ); ?></h3>
+
+				<div class="feature-section">
+					<h4><?php _e( 'Your Default Setup', 'buddypress' ); ?></h4>
+
+					<?php if ( bp_is_active( 'members' ) && bp_is_active( 'activity' ) ) : ?>
+						<p><?php printf(
+						__( 'BuddyPress&#8217;s powerful features help your users connect and collaborate. To help get your community started, we&#8217;ve activated two of the most commonly used tools in BP: <strong>Extended Profiles</strong> and <strong>Activity Streams</strong>. See these components in action at the %1$s and %2$s directories, and be sure to spend a few minutes <a href="%3$s">configuring user profiles</a>. Want to explore more of BP&#8217;s features? Visit the <a href="%4$s">Components panel</a>.', 'buddypress' ),
+						$pretty_permalinks_enabled ? '<a href="' . trailingslashit( bp_get_root_domain() . '/' . bp_get_members_root_slug() ) . '">' . __( 'Members', 'buddypress' ) . '</a>' : __( 'Members', 'buddypress' ),
+						$pretty_permalinks_enabled ? '<a href="' . trailingslashit( bp_get_root_domain() . '/' . bp_get_activity_root_slug() ) . '">' . __( 'Activity', 'buddypress' ) . '</a>' : __( 'Activity', 'buddypress' ),
+						bp_get_admin_url( add_query_arg( array( 'page' => 'bp-profile-setup' ), 'users.php' ) ),
+						bp_get_admin_url( add_query_arg( array( 'page' => 'bp-components' ), $this->settings_page ) )
+					); ?></p>
+
+					<?php else : ?>
+						<p><?php printf(
+						__( 'BuddyPress&#8217;s powerful features help your users connect and collaborate. Want to explore BP&#8217;s features? Visit the <a href="%s">Components panel</a>.', 'buddypress' ),
+						bp_get_admin_url( add_query_arg( array( 'page' => 'bp-components' ), $this->settings_page ) )
+					); ?></p>
+
+					<?php endif; ?>
+
+					<h4><?php _e( 'Community and Support', 'buddypress' ); ?></h4>
+					<p><?php _e( 'Looking for help? The <a href="http://codex.buddypress.org/">BuddyPress Codex</a> has you covered, with dozens of user-contributed guides on how to configure and use your BP site. Can&#8217;t find what you need? Stop by <a href="http://buddypress.org/support/">our support forums</a>, where a vibrant community of BuddyPress users and developers is waiting to share tips, show off their sites, talk about the future of BuddyPress, and much more.', 'buddypress' ) ?></p>
+				</div>
+
+			<?php endif; ?>
+
+			<hr />
+			<div class="changelog">
+				<h3><?php _e( 'Dynamic links for custom navigation menus', 'buddypress' ); ?></h3>
+
+				<div class="feature-section">
+					<p><?php printf( __( 'It&#8217;s now easy to add BuddyPress-specific links to your menus through <a href="%s">Appearance &gt; Menus</a>. For example, you can now add a link to a specific user profile screen, and each person will end up at that screen inside their own user profile.', 'buddypress' ), admin_url( 'nav-menus.php' ) ); ?></p>
+				</div>
+			</div>
+
+			<hr />
+			<div class="changelog">
+				<h3><?php _e( 'Notifications component', 'buddypress' ); ?></h3>
+
+				<div class="feature-section">
+					<p><?php _e( 'The notification features have been promoted into a new component. Use it to keep your site&#8217;s members abreast of the latest connections and @mentions within the site, via email notifications and Toolbar alerts.', 'buddypress' ); ?></p>
+
+				</div>
+			</div>
+
+			<hr />
+			<div class="changelog">
+				<h3><?php _e( 'Widgets', 'buddypress' ); ?></h3>
+
+				<div class="feature-section">
+					<ul>
+						<li><?php _e( '<strong>Friends Widget</strong>: a list of recently active, popular, and newest friends of the displayed member.', 'buddypress' ); ?></li>
+						<li><?php _e( '<strong>Log In Widget</strong>: adds a simple &ldquo;Log In&rdquo; form to your site.', 'buddypress' ); ?></li>
+						<li><?php _e( '<strong>Sitewide Notices Widget</strong>: display Sitewide Notices from the Private Messaging component.', 'buddypress' ); ?></li>
+					</ul>
+				</div>
+			</div>
+
+			<hr />
+			<div class="changelog">
+				<h3><?php _e( 'Developer changes', 'buddypress' ); ?></h3>
+
+				<div class="feature-section">
+					<ul>
+						<li><?php _e( '<code>bp_redirect_canonical()</code> functionality has been reinstated', 'buddypress' ); ?></li>
+						<li><?php _e( 'Improved phpDoc inline documentation', 'buddypress' ); ?></li>
+						<li><?php printf( __( 'Improved compatibility with <a href="%s">develop.svn.wordpress.org</a> unit-test suite', 'buddypress' ), 'https://develop.svn.wordpress.org/' ); ?></li>
+						<li><?php printf( __( '<a href="%s">&hellip;and lots more!</a>' ), 'http://codex.buddypress.org/releases/version-1-9' ); ?></li>
+					</ul>
+				</div>
+
+				<div class="return-to-dashboard">
+					<a href="<?php echo esc_url( bp_get_admin_url( add_query_arg( array( 'page' => 'bp-components' ), $this->settings_page ) ) ); ?>"><?php _e( 'Go to the BuddyPress Settings page', 'buddypress' ); ?></a>
+				</div>
+
+			</div>
+
+		<?php
+	}
+
+	/**
+	 * Output the credits screen.
+	 *
+	 * Hardcoding this in here is pretty janky. It's fine for now, but we'll
+	 * want to leverage api.wordpress.org eventually.
+	 *
+	 * @since BuddyPress (1.7.0)
+	 */
+	public function credits_screen() {
+
+		list( $display_version ) = explode( '-', bp_get_version() ); ?>
+
+		<div class="wrap about-wrap">
+			<h1><?php printf( __( 'Welcome to BuddyPress %s', 'buddypress' ), $display_version ); ?></h1>
+			<div class="about-text"><?php printf( __( 'BuddyPress %s is our first version with a new component in over two years. Not only that, there are plenty of new features, enhancements, and bug fixes.', 'buddypress' ), $display_version ); ?></div>
+			<div class="bp-badge"><?php printf( __( 'Version %s', 'buddypress' ), $display_version ); ?></div>
+
+			<h2 class="nav-tab-wrapper">
+				<a href="<?php echo esc_url( bp_get_admin_url( add_query_arg( array( 'page' => 'bp-about' ), 'index.php' ) ) ); ?>" class="nav-tab">
+					<?php _e( 'What&#8217;s New', 'buddypress' ); ?>
+				</a><a href="<?php echo esc_url( bp_get_admin_url( add_query_arg( array( 'page' => 'bp-credits' ), 'index.php' ) ) ); ?>" class="nav-tab nav-tab-active">
+					<?php _e( 'Credits', 'buddypress' ); ?>
+				</a>
+			</h2>
+
+			<p class="about-description"><?php _e( 'BuddyPress is created by a worldwide network of friendly folks.', 'buddypress' ); ?></p>
+
+			<h4 class="wp-people-group"><?php _e( 'Project Leaders', 'buddypress' ); ?></h4>
+			<ul class="wp-people-group " id="wp-people-group-project-leaders">
+				<li class="wp-person" id="wp-person-apeatling">
+					<a href="http://profiles.wordpress.org/apeatling"><img src="http://0.gravatar.com/avatar/bb29d699b5cba218c313b61aa82249da?s=60" class="gravatar" alt="Andy Peatling" /></a>
+					<a class="web" href="http://profiles.wordpress.org/apeatling">Andy Peatling</a>
+					<span class="title"><?php _e( 'Founding Developer', 'buddypress' ); ?></span>
+				</li>
+				<li class="wp-person" id="wp-person-johnjamesjacoby">
+					<a href="http://profiles.wordpress.org/johnjamesjacoby"><img src="http://0.gravatar.com/avatar/81ec16063d89b162d55efe72165c105f?s=60" class="gravatar" alt="John James Jacoby" /></a>
+					<a class="web" href="http://profiles.wordpress.org/johnjamesjacoby">John James Jacoby</a>
+					<span class="title"><?php _e( 'Project Lead', 'buddypress' ); ?></span>
+				</li>
+				<li class="wp-person" id="wp-person-boonebgorges">
+					<a href="http://profiles.wordpress.org/boonebgorges"><img src="http://0.gravatar.com/avatar/9cf7c4541a582729a5fc7ae484786c0c?s=60" class="gravatar" alt="Boone B. Gorges" /></a>
+					<a class="web" href="http://profiles.wordpress.org/boonebgorges">Boone B. Gorges</a>
+					<span class="title"><?php _e( 'Lead Developer', 'buddypress' ); ?></span>
+				</li>
+				<li class="wp-person" id="wp-person-djpaul">
+					<a href="http://profiles.wordpress.org/djpaul"><img src="http://0.gravatar.com/avatar/3bc9ab796299d67ce83dceb9554f75df?s=60" class="gravatar" alt="Paul Gibbs" /></a>
+					<a class="web" href="http://profiles.wordpress.org/djpaul">Paul Gibbs</a>
+					<span class="title"><?php _e( 'Lead Developer', 'buddypress' ); ?></span>
+				</li>
+			</ul>
+
+			<h4 class="wp-people-group"><?php _e( 'Core Developers', 'buddypress' ); ?></h4>
+			<ul class="wp-people-group " id="wp-people-group-core-developers">
+				<li class="wp-person" id="wp-person-r-a-y">
+					<a href="http://profiles.wordpress.org/r-a-y"><img src="http://0.gravatar.com/avatar/3bfa556a62b5bfac1012b6ba5f42ebfa?s=60" class="gravatar" alt="Ray" /></a>
+					<a class="web" href="http://profiles.wordpress.org/r-a-y">Ray</a>
+				</li>
+			</ul>
+
+			<h4 class="wp-people-group"><?php _e( 'Recent Rockstars', 'buddypress' ); ?></h4>
+			<ul class="wp-people-group " id="wp-people-group-rockstars">
+				<li class="wp-person" id="wp-person-imath">
+					<a href="http://profiles.wordpress.org/imath"><img src="http://0.gravatar.com/avatar/8b208ca408dad63888253ee1800d6a03?s=60" class="gravatar" alt="Mathieu Viet" /></a>
+					<a class="web" href="http://profiles.wordpress.org/imath">Mathieu Viet</a>
+				</li>
+				<li class="wp-person" id="wp-person-hnla">
+					<a href="http://profiles.wordpress.org/hnla"><img src="http://0.gravatar.com/avatar/3860c955aa3f79f13b92826ae47d07fe?s=60" class="gravatar" alt="Hugo Ashmore" /></a>
+					<a class="web" href="http://profiles.wordpress.org/hnla">Hugo Ashmore</a>
+				</li>
+				<li class="wp-person" id="wp-person-mercime">
+					<a href="http://profiles.wordpress.org/mercime"><img src="http://0.gravatar.com/avatar/fae451be6708241627983570a1a1817a?s=60" class="gravatar" alt="Mercime" /></a>
+					<a class="web" href="http://profiles.wordpress.org/mercime">Mercime</a>
+				</li>
+				<li class="wp-person" id="wp-person-karmatosed">
+					<a href="http://profiles.wordpress.org/karmatosed"><img src="http://0.gravatar.com/avatar/d36d2c1821af9249b69ff7f5ed60529b?s=60" class="gravatar" alt="Tammie Lister" /></a>
+					<a class="web" href="http://profiles.wordpress.org/karmatosed">Tammie Lister</a>
+				</li>
+			</ul>
+
+			<h4 class="wp-people-group"><?php _e( 'Contributors to BuddyPress 1.9', 'buddypress' ); ?></h4>
+			<p class="wp-credits-list">
+				<a href="http://profiles.wordpress.org/AliMH/">AliMH</a>,
+				<a href="http://profiles.wordpress.org/asakurayoh/">asakurayoh</a>,
+				<a href="http://profiles.wordpress.org/boonebgorges/">boonebgorges</a>,
+				<a href="http://profiles.wordpress.org/burakali/">burakali</a>,
+				<a href="http://profiles.wordpress.org/dcavins/">dcavins</a>,
+				<a href="http://profiles.wordpress.org/ddean/">ddean</a>,
+				<a href="http://profiles.wordpress.org/DennisSmolek/">DennisSmolek</a>,
+				<a href="http://profiles.wordpress.org/dimensionmedia/">dimensionmedia</a>,
+				<a href="http://profiles.wordpress.org/djpaul/">DJPaul</a>,
+				<a href="http://profiles.wordpress.org/dtc7240/">dtc7240</a>,
+				<a href="http://profiles.wordpress.org/ericlewis/">ericlewis</a>,
+				<a href="http://profiles.wordpress.org/gametako/">gametako</a>,
+				<a href="http://profiles.wordpress.org/geoffroycochard/">geoffroycochard</a>,
+				<a href="http://profiles.wordpress.org/graham-washbrook/">graham-washbrook</a>,
+				<a href="http://profiles.wordpress.org/hanni/">hanni</a>,
+				<a href="http://profiles.wordpress.org/haykayltduk/">haykayltduk</a>,
+				<a href="http://profiles.wordpress.org/henrywright/">henrywright</a>,
+				<a href="http://profiles.wordpress.org/hnla/">hnla</a>,
+				<a href="http://profiles.wordpress.org/imath/">imath</a>,
+				<a href="http://profiles.wordpress.org/johnjamesjacoby/">johnjamesjacoby</a>,
+				<a href="http://profiles.wordpress.org/lenasterg/">lenasterg</a>,
+				<a href="http://profiles.wordpress.org/mboynes/">mboynes</a>,
+				<a href="http://profiles.wordpress.org/megainfo/">megainfo</a>,
+				<a href="http://profiles.wordpress.org/Mike_Cowobo/">Mike_Cowobo</a>,
+				<a href="http://profiles.wordpress.org/modemlooper/">modemlooper</a>,
+				<a href="http://profiles.wordpress.org/olivM/">olivM</a>,
+				<a href="http://profiles.wordpress.org/needle/">needle</a>,
+				<a href="http://profiles.wordpress.org/netweblogic/">netweblogic</a>,
+				<a href="http://profiles.wordpress.org/r-a-y/">r-a-y</a>,
+				<a href="http://profiles.wordpress.org/ryderlewis/">ryderlewis</a>,
+				<a href="http://profiles.wordpress.org/sbrajesh/">sbrajesh</a>,
+				<a href="http://profiles.wordpress.org/sgr33n/">sgr33n</a>,
+				<a href="http://profiles.wordpress.org/sooskriszta/">sooskriszta</a>,
+				<a href="http://profiles.wordpress.org/terraling/">terraling</a>,
+				<a href="http://profiles.wordpress.org/tomdxw/">tomdxw</a>,
+				<a href="http://profiles.wordpress.org/trishasalas/">trishasalas</a>,
+				<a href="http://profiles.wordpress.org/vhauri/">vhauri</a>,
+				<a href="http://profiles.wordpress.org/williamsba1/">williamsba1</a>,
+				<a href="http://profiles.wordpress.org/wpdennis/">wpdennis</a>
+			</p>
+
+			<div class="return-to-dashboard">
+				<a href="<?php echo esc_url( bp_get_admin_url( add_query_arg( array( 'page' => 'bp-components' ), $this->settings_page ) ) ); ?>"><?php _e( 'Go to the BuddyPress Settings page', 'buddypress' ); ?></a>
+			</div>
+
+		</div>
+
+		<?php
+	}
+}
+endif; // class_exists check
+
+/**
+ * Setup BuddyPress Admin.
+ *
+ * @since BuddyPress (1.6.0)
+ *
+ * @uses BP_Admin
+ */
+function bp_admin() {
+       buddypress()->admin = new BP_Admin();
+}
Index: /tags/1.9/bp-core/bp-core-adminbar.php
===================================================================
--- /tags/1.9/bp-core/bp-core-adminbar.php	(revision 7684)
+++ /tags/1.9/bp-core/bp-core-adminbar.php	(revision 7684)
@@ -0,0 +1,111 @@
+<?php
+
+/**
+ * BuddyPress Core Toolbar.
+ *
+ * Handles the core functions related to the WordPress Toolbar.
+ *
+ * @package BuddyPress
+ * @subpackage Core
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/**
+ * Add the secondary BuddyPress area to the my-account menu.
+ *
+ * @since BuddyPress (1.6.0)
+ *
+ * @global WP_Admin_Bar $wp_admin_bar
+ */
+function bp_admin_bar_my_account_root() {
+	global $wp_admin_bar;
+
+	// Bail if this is an ajax request
+	if ( !bp_use_wp_admin_bar() || defined( 'DOING_AJAX' ) )
+		return;
+
+	// Only add menu for logged in user
+	if ( is_user_logged_in() ) {
+
+		// Add secondary parent item for all BuddyPress components
+		$wp_admin_bar->add_menu( array(
+			'parent'    => 'my-account',
+			'id'        => 'my-account-buddypress',
+			'title'     => __( 'My Account' ),
+			'group'     => true,
+			'meta'      => array(
+				'class' => 'ab-sub-secondary'
+			)
+		) );
+	}
+}
+add_action( 'admin_bar_menu', 'bp_admin_bar_my_account_root', 100 );
+
+/**
+ * Handle the Toolbar/BuddyBar business.
+ *
+ * @since BuddyPress (1.2.0)
+ *
+ * @global string $wp_version
+ * @uses bp_get_option()
+ * @uses is_user_logged_in()
+ * @uses bp_use_wp_admin_bar()
+ * @uses show_admin_bar()
+ * @uses add_action() To hook 'bp_adminbar_logo' to 'bp_adminbar_logo'.
+ * @uses add_action() To hook 'bp_adminbar_login_menu' to 'bp_adminbar_menus'.
+ * @uses add_action() To hook 'bp_adminbar_account_menu' to 'bp_adminbar_menus'.
+ * @uses add_action() To hook 'bp_adminbar_thisblog_menu' to 'bp_adminbar_menus'.
+ * @uses add_action() To hook 'bp_adminbar_random_menu' to 'bp_adminbar_menus'.
+ * @uses add_action() To hook 'bp_core_admin_bar' to 'wp_footer'.
+ * @uses add_action() To hook 'bp_core_admin_bar' to 'admin_footer'.
+ */
+function bp_core_load_admin_bar() {
+
+	// Show the Toolbar for logged out users
+	if ( ! is_user_logged_in() && (int) bp_get_option( 'hide-loggedout-adminbar' ) != 1 ) {
+		show_admin_bar( true );
+	}
+
+	// Hide the WordPress Toolbar and show the BuddyBar
+	if ( ! bp_use_wp_admin_bar() ) {
+
+		// Keep the WP Toolbar from loading
+		show_admin_bar( false );
+
+		// Actions used to build the BP Toolbar
+		add_action( 'bp_adminbar_logo',  'bp_adminbar_logo'               );
+		add_action( 'bp_adminbar_menus', 'bp_adminbar_login_menu',    2   );
+		add_action( 'bp_adminbar_menus', 'bp_adminbar_account_menu',  4   );
+		add_action( 'bp_adminbar_menus', 'bp_adminbar_thisblog_menu', 6   );
+		add_action( 'bp_adminbar_menus', 'bp_adminbar_random_menu',   100 );
+
+		// Actions used to append BP Toolbar to footer
+		add_action( 'wp_footer',    'bp_core_admin_bar', 8 );
+		add_action( 'admin_footer', 'bp_core_admin_bar'    );
+	}
+}
+add_action( 'init', 'bp_core_load_admin_bar', 9 );
+
+/**
+ * Handle the Toolbar CSS.
+ *
+ * @since BuddyPress (1.5.0)
+ */
+function bp_core_load_admin_bar_css() {
+	global $wp_styles;
+
+	if ( ! bp_use_wp_admin_bar() || ! is_admin_bar_showing() )
+		return;
+
+	$min = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min';
+
+	// Toolbar styles
+	$stylesheet = BP_PLUGIN_URL . "bp-core/css/admin-bar{$min}.css";
+
+	wp_enqueue_style( 'bp-admin-bar', apply_filters( 'bp_core_admin_bar_css', $stylesheet ), array( 'admin-bar' ), bp_get_version() );
+	$wp_styles->add_data( 'bp-admin-bar', 'rtl', true );
+	if ( $min )
+		$wp_styles->add_data( 'bp-admin-bar', 'suffix', $min );
+}
Index: /tags/1.9/bp-core/bp-core-avatars.php
===================================================================
--- /tags/1.9/bp-core/bp-core-avatars.php	(revision 7684)
+++ /tags/1.9/bp-core/bp-core-avatars.php	(revision 7684)
@@ -0,0 +1,1134 @@
+<?php
+
+/**
+ * BuddyPress Avatars.
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/***
+ * Set up the constants we need for avatar support.
+ */
+function bp_core_set_avatar_constants() {
+
+	if ( !defined( 'BP_AVATAR_THUMB_WIDTH' ) )
+		define( 'BP_AVATAR_THUMB_WIDTH', 50 );
+
+	if ( !defined( 'BP_AVATAR_THUMB_HEIGHT' ) )
+		define( 'BP_AVATAR_THUMB_HEIGHT', 50 );
+
+	if ( !defined( 'BP_AVATAR_FULL_WIDTH' ) )
+		define( 'BP_AVATAR_FULL_WIDTH', 150 );
+
+	if ( !defined( 'BP_AVATAR_FULL_HEIGHT' ) )
+		define( 'BP_AVATAR_FULL_HEIGHT', 150 );
+
+	if ( !defined( 'BP_AVATAR_ORIGINAL_MAX_WIDTH' ) )
+		define( 'BP_AVATAR_ORIGINAL_MAX_WIDTH', 450 );
+
+	if ( !defined( 'BP_AVATAR_ORIGINAL_MAX_FILESIZE' ) ) {
+
+		$bp = buddypress();
+
+		if ( !isset( $bp->site_options['fileupload_maxk'] ) ) {
+			define( 'BP_AVATAR_ORIGINAL_MAX_FILESIZE', 5120000 ); // 5mb
+		} else {
+			define( 'BP_AVATAR_ORIGINAL_MAX_FILESIZE', $bp->site_options['fileupload_maxk'] * 1024 );
+		}
+	}
+
+	if ( !defined( 'BP_AVATAR_DEFAULT' ) )
+		define( 'BP_AVATAR_DEFAULT', BP_PLUGIN_URL . 'bp-core/images/mystery-man.jpg' );
+
+	if ( !defined( 'BP_AVATAR_DEFAULT_THUMB' ) )
+		define( 'BP_AVATAR_DEFAULT_THUMB', BP_PLUGIN_URL . 'bp-core/images/mystery-man-50.jpg' );
+
+	if ( ! defined( 'BP_SHOW_AVATARS' ) ) {
+		define( 'BP_SHOW_AVATARS', bp_get_option( 'show_avatars' ) );
+	}
+}
+add_action( 'bp_init', 'bp_core_set_avatar_constants', 3 );
+
+/**
+ * Set up global variables related to avatars.
+ *
+ * @since BuddyPress (1.5.0)
+ */
+function bp_core_set_avatar_globals() {
+	$bp = buddypress();
+
+	$bp->avatar        = new stdClass;
+	$bp->avatar->thumb = new stdClass;
+	$bp->avatar->full  = new stdClass;
+
+	// Dimensions
+	$bp->avatar->thumb->width  = BP_AVATAR_THUMB_WIDTH;
+	$bp->avatar->thumb->height = BP_AVATAR_THUMB_HEIGHT;
+	$bp->avatar->full->width   = BP_AVATAR_FULL_WIDTH;
+	$bp->avatar->full->height  = BP_AVATAR_FULL_HEIGHT;
+
+	// Upload maximums
+	$bp->avatar->original_max_width    = BP_AVATAR_ORIGINAL_MAX_WIDTH;
+	$bp->avatar->original_max_filesize = BP_AVATAR_ORIGINAL_MAX_FILESIZE;
+
+	// Defaults
+	$bp->avatar->thumb->default = BP_AVATAR_DEFAULT_THUMB;
+	$bp->avatar->full->default  = BP_AVATAR_DEFAULT;
+
+	// These have to be set on page load in order to avoid infinite filter loops at runtime
+	$bp->avatar->upload_path = bp_core_avatar_upload_path();
+	$bp->avatar->url = bp_core_avatar_url();
+
+	// Cache the root blog's show_avatars setting, to avoid unnecessary
+	// calls to switch_to_blog()
+	$bp->avatar->show_avatars = (bool) BP_SHOW_AVATARS;
+
+	// Backpat for pre-1.5
+	if ( ! defined( 'BP_AVATAR_UPLOAD_PATH' ) )
+		define( 'BP_AVATAR_UPLOAD_PATH', $bp->avatar->upload_path );
+
+	// Backpat for pre-1.5
+	if ( ! defined( 'BP_AVATAR_URL' ) )
+		define( 'BP_AVATAR_URL', $bp->avatar->url );
+
+	do_action( 'bp_core_set_avatar_globals' );
+}
+add_action( 'bp_setup_globals', 'bp_core_set_avatar_globals' );
+
+/**
+ * Get an avatar for a BuddyPress object.
+ *
+ * Supports avatars for users, groups, and blogs by default, but can be
+ * extended to support custom components as well.
+ *
+ * This function gives precedence to locally-uploaded avatars. When a local
+ * avatar is not found, Gravatar is queried. To disable Gravatar fallbacks
+ * locally:
+ *    add_filter( 'bp_core_fetch_avatar_no_grav', '__return_true' );
+ *
+ * @param array $args {
+ *     An array of arguments. All arguments are technically optional; some
+ *     will, if not provided, be auto-detected by bp_core_fetch_avatar(). This
+ *     auto-detection is described more below, when discussing specific
+ *     arguments.
+ *
+ *     @type int|bool $item_id The numeric ID of the item for which you're
+ *           requesting an avatar (eg, a user ID). If no 'item_id' is present,
+ *           the function attempts to infer an ID from the 'object' + the
+ *           current context: if 'object' is 'user' and the current page is a
+ *           user page, 'item_id' will default to the displayed user ID; if
+ *           'group' and on a group page, to the current group ID; if 'blog',
+ *           to the current blog's ID. If no 'item_id' can be determined in
+ *           this way, the function returns false. Default: false.
+ *     @type string $object The kind of object for which you're getting an
+ *           avatar. BuddyPress natively supports three options: 'user',
+ *           'group', 'blog'; a plugin may register more.  Default: 'user'.
+ *     @type string $type When a new avatar is uploaded to BP, 'thumb' and
+ *           'full' versions are saved. This parameter specifies whether you'd
+ *           like the 'full' or smaller 'thumb' avatar. Default: 'thumb'.
+ *     @type string|bool $avatar_dir The name of the subdirectory where the
+ *           requested avatar should be found. If no value is passed,
+ *           'avatar_dir' is inferred from 'object': 'user' becomes 'avatars',
+ *           'group' becomes 'group-avatars', 'blog' becomes 'blog-avatars'.
+ *           Remember that this string denotes a subdirectory of BP's main
+ *           avatar directory (usually based on {@link wp_upload_dir()}); it's a
+ *           string like 'group-avatars' rather than the full directory path.
+ *           Generally, it'll only be necessary to override the default value if
+ *           storing avatars in a non-default location. Defaults to false
+ *           (auto-detected).
+ *     @type int|bool $width Requested avatar width. The unit is px. This value
+ *           is used to build the 'width' attribute for the <img> element. If
+ *           no value is passed, BP uses the global avatar width for this
+ *           avatar type. Default: false (auto-detected).
+ *     @type int|bool $height Requested avatar height. The unit is px. This
+ *           value is used to build the 'height' attribute for the <img>
+ *           element. If no value is passed, BP uses the global avatar height
+ *           for this avatar type. Default: false (auto-detected).
+ *     @type string $class The CSS class for the <img> element. Note that BP
+ *           uses the 'avatar' class fairly extensively in its default styling,
+ *           so if you plan to pass a custom value, consider appending it to
+ *           'avatar' (eg 'avatar foo') rather than replacing it altogether.
+ *           Default: 'avatar'.
+ *     @type string|bool $css_id The CSS id for the <img> element.
+ *           Default: false.
+ *     @type string $title The title attribute for the <img> element.
+ *           Default: false.
+ *     @type string $alt The alt attribute for the <img> element. In BP, this
+ *           value is generally passed by the wrapper functions, where the data
+ *           necessary for concatenating the string is at hand; see
+ *           {@link bp_get_activity_avatar()} for an example. Default: ''.
+ *     @type string|bool $email An email to use in Gravatar queries. Unless
+ *           otherwise configured, BP uses Gravatar as a fallback for avatars
+ *           that are not provided locally. Gravatar's API requires using a hash
+ *           of the user's email address; this argument provides it. If not
+ *           provided, the function will infer it: for users, by getting the
+ *           user's email from the database, for groups/blogs, by concatenating
+ *           "{$item_id}-{$object}@{bp_get_root_domain()}". The user query adds
+ *           overhead, so it's recommended that wrapper functions provide a
+ *           value for 'email' when querying user IDs. Default: false.
+ *     @type bool $no_grav Whether to disable the default Gravatar fallback.
+ *           By default, BP will fall back on Gravatar when it cannot find a
+ *           local avatar. In some cases, this may be undesirable, in which
+ *           case 'no_grav' should be set to true. To disable Gravatar
+ *           fallbacks globally, see the 'bp_core_fetch_avatar_no_grav' filter.
+ *           Default: false.
+ *     @type bool $html Whether to return an <img> HTML element, vs a raw URL
+ *           to an avatar. If false, <img>-specific arguments (like 'css_id')
+ *           will be ignored. Default: true.
+ * }
+ * @return string Formatted HTML <img> element, or raw avatar URL based on $html arg.
+ */
+function bp_core_fetch_avatar( $args = '' ) {
+
+	// If avatars are disabled for the root site, obey that request and bail
+	if ( ! buddypress()->avatar->show_avatars )
+		return;
+
+	global $current_blog;
+
+	$bp = buddypress();
+
+	// Set a few default variables
+	$def_object = 'user';
+	$def_type   = 'thumb';
+	$def_class  = 'avatar';
+
+	// Set the default variables array
+	$params = wp_parse_args( $args, array(
+		'item_id'    => false,
+		'object'     => $def_object, // user/group/blog/custom type (if you use filters)
+		'type'       => $def_type,   // thumb or full
+		'avatar_dir' => false,       // Specify a custom avatar directory for your object
+		'width'      => false,       // Custom width (int)
+		'height'     => false,       // Custom height (int)
+		'class'      => $def_class,  // Custom <img> class (string)
+		'css_id'     => false,       // Custom <img> ID (string)
+		'alt'        => '',    	     // Custom <img> alt (string)
+		'email'      => false,       // Pass the user email (for gravatar) to prevent querying the DB for it
+		'no_grav'    => false,       // If there is no avatar found, return false instead of a grav?
+		'html'       => true,        // Wrap the return img URL in <img />
+		'title'      => ''           // Custom <img> title (string)
+	) );
+	extract( $params, EXTR_SKIP );
+
+	/** Set item_id ***********************************************************/
+
+	if ( empty( $item_id ) ) {
+
+		switch ( $object ) {
+
+			case 'blog'  :
+				$item_id = $current_blog->id;
+				break;
+
+			case 'group' :
+				if ( bp_is_active( 'groups' ) ) {
+					$item_id = $bp->groups->current_group->id;
+				} else {
+					$item_id = false;
+				}
+
+				break;
+
+			case 'user'  :
+			default      :
+				$item_id = bp_displayed_user_id();
+				break;
+		}
+
+		$item_id = apply_filters( 'bp_core_avatar_item_id', $item_id, $object, $params );
+
+		if ( empty( $item_id ) ) {
+			return false;
+		}
+	}
+
+	$class = apply_filters( 'bp_core_avatar_class', $class, $item_id, $object, $params );
+
+	/** Set avatar_dir ********************************************************/
+
+	if ( empty( $avatar_dir ) ) {
+
+		switch ( $object ) {
+
+			case 'blog'  :
+				$avatar_dir = 'blog-avatars';
+				break;
+
+			case 'group' :
+				if ( bp_is_active( 'groups' ) ) {
+					$avatar_dir = 'group-avatars';
+				} else {
+					$avatar_dir = false;
+				}
+
+				break;
+
+			case 'user'  :
+			default      :
+				$avatar_dir = 'avatars';
+				break;
+		}
+
+		$avatar_dir = apply_filters( 'bp_core_avatar_dir', $avatar_dir, $object, $params );
+
+		if ( empty( $avatar_dir ) ) {
+			return false;
+		}
+	}
+
+	/** <img> alt *************************************************************/
+
+	if ( false !== strpos( $alt, '%s' ) || false !== strpos( $alt, '%1$s' ) ) {
+
+		switch ( $object ) {
+
+			case 'blog'  :
+				$item_name = get_blog_option( $item_id, 'blogname' );
+				break;
+
+			case 'group' :
+				$item_name = bp_get_group_name( groups_get_group( array( 'group_id' => $item_id ) ) );
+				break;
+
+			case 'user'  :
+			default :
+				$item_name = bp_core_get_user_displayname( $item_id );
+				break;
+		}
+
+		$item_name = apply_filters( 'bp_core_avatar_alt', $item_name, $item_id, $object, $params );
+		$alt       = sprintf( $alt, $item_name );
+	}
+
+	/** Sanity Checks *********************************************************/
+
+	// Get a fallback for the 'alt' parameter
+	if ( empty( $alt ) )
+		$alt = __( 'Avatar Image', 'buddypress' );
+
+	$html_alt = ' alt="' . esc_attr( $alt ) . '"';
+
+	// Set title tag, if it's been provided
+	if ( !empty( $title ) ) {
+		$title = " title='" . esc_attr( apply_filters( 'bp_core_avatar_title', $title, $item_id, $object, $params ) ) . "'";
+	}
+
+	// Set CSS ID if passed
+	if ( !empty( $css_id ) ) {
+		$css_id = ' id="' . esc_attr( $css_id ) . '"';
+	}
+
+	// Set image width
+	if ( false !== $width ) {
+		$html_width = ' width="' . $width . '"';
+	} elseif ( 'thumb' == $type ) {
+		$html_width = ' width="' . bp_core_avatar_thumb_width() . '"';
+	} else {
+		$html_width = ' width="' . bp_core_avatar_full_width() . '"';
+	}
+
+	// Set image height
+	if ( false !== $height ) {
+		$html_height = ' height="' . $height . '"';
+	} elseif ( 'thumb' == $type ) {
+		$html_height = ' height="' . bp_core_avatar_thumb_height() . '"';
+	} else {
+		$html_height = ' height="' . bp_core_avatar_full_height() . '"';
+	}
+
+	// Set img URL and DIR based on prepopulated constants
+	$avatar_loc        = new stdClass();
+	$avatar_loc->path  = trailingslashit( bp_core_avatar_upload_path() );
+	$avatar_loc->url   = trailingslashit( bp_core_avatar_url() );
+
+	$avatar_loc->dir   = trailingslashit( $avatar_dir );
+	$avatar_folder_url = apply_filters( 'bp_core_avatar_folder_url', ( $avatar_loc->url  . $avatar_loc->dir . $item_id ), $item_id, $object, $avatar_dir );
+	$avatar_folder_dir = apply_filters( 'bp_core_avatar_folder_dir', ( $avatar_loc->path . $avatar_loc->dir . $item_id ), $item_id, $object, $avatar_dir );
+
+	// Add an identifying class
+	$class .= ' ' . $object . '-' . $item_id . '-avatar ' . sanitize_html_class( "avatar-$width" ) . ' photo';
+
+	/**
+	 * Look for uploaded avatar first. Use it if it exists.
+	 * Set the file names to search for, to select the full size
+	 * or thumbnail image.
+	 */
+	$avatar_size              = ( 'full' == $type ) ? '-bpfull' : '-bpthumb';
+	$legacy_user_avatar_name  = ( 'full' == $type ) ? '-avatar2' : '-avatar1';
+	$legacy_group_avatar_name = ( 'full' == $type ) ? '-groupavatar-full' : '-groupavatar-thumb';
+
+	// Check for directory
+	if ( file_exists( $avatar_folder_dir ) ) {
+
+		// Open directory
+		if ( $av_dir = opendir( $avatar_folder_dir ) ) {
+
+			// Stash files in an array once to check for one that matches
+			$avatar_files = array();
+			while ( false !== ( $avatar_file = readdir( $av_dir ) ) ) {
+				// Only add files to the array (skip directories)
+				if ( 2 < strlen( $avatar_file ) ) {
+					$avatar_files[] = $avatar_file;
+				}
+			}
+
+			// Check for array
+			if ( 0 < count( $avatar_files ) ) {
+
+				// Check for current avatar
+				foreach( $avatar_files as $key => $value ) {
+					if ( strpos ( $value, $avatar_size )!== false ) {
+						$avatar_url = $avatar_folder_url . '/' . $avatar_files[$key];
+					}
+				}
+
+				// Legacy avatar check
+				if ( !isset( $avatar_url ) ) {
+					foreach( $avatar_files as $key => $value ) {
+						if ( strpos ( $value, $legacy_user_avatar_name )!== false ) {
+							$avatar_url = $avatar_folder_url . '/' . $avatar_files[$key];
+						}
+					}
+
+					// Legacy group avatar check
+					if ( !isset( $avatar_url ) ) {
+						foreach( $avatar_files as $key => $value ) {
+							if ( strpos ( $value, $legacy_group_avatar_name )!== false ) {
+								$avatar_url = $avatar_folder_url . '/' . $avatar_files[$key];
+							}
+						}
+					}
+				}
+			}
+		}
+
+		// Close the avatar directory
+		closedir( $av_dir );
+
+		// If we found a locally uploaded avatar
+		if ( isset( $avatar_url ) ) {
+
+			// Return it wrapped in an <img> element
+			if ( true === $html ) {
+				return apply_filters( 'bp_core_fetch_avatar', '<img src="' . $avatar_url . '" class="' . esc_attr( $class ) . '"' . $css_id . $html_width . $html_height . $html_alt . $title . ' />', $params, $item_id, $avatar_dir, $css_id, $html_width, $html_height, $avatar_folder_url, $avatar_folder_dir );
+
+			// ...or only the URL
+			} else {
+				return apply_filters( 'bp_core_fetch_avatar_url', $avatar_url, $params );
+			}
+		}
+	}
+
+	// If no avatars could be found, try to display a gravatar
+
+	// Skips gravatar check if $no_grav is passed
+	if ( ! apply_filters( 'bp_core_fetch_avatar_no_grav', $no_grav ) ) {
+
+		// Set gravatar size
+		if ( false !== $width ) {
+			$grav_size = $width;
+		} else if ( 'full' == $type ) {
+			$grav_size = bp_core_avatar_full_width();
+		} else if ( 'thumb' == $type ) {
+			$grav_size = bp_core_avatar_thumb_width();
+		}
+
+		// Set gravatar type
+		if ( empty( $bp->grav_default->{$object} ) ) {
+			$default_grav = 'wavatar';
+		} else if ( 'mystery' == $bp->grav_default->{$object} ) {
+			$default_grav = apply_filters( 'bp_core_mysteryman_src', bp_core_avatar_default(), $grav_size );
+		} else {
+			$default_grav = $bp->grav_default->{$object};
+		}
+
+		// Set gravatar object
+		if ( empty( $email ) ) {
+			if ( 'user' == $object ) {
+				$email = bp_core_get_user_email( $item_id );
+			} else if ( 'group' == $object || 'blog' == $object ) {
+				$email = "{$item_id}-{$object}@{bp_get_root_domain()}";
+			}
+		}
+
+		// Set host based on if using ssl
+		$host = 'http://gravatar.com/avatar/';
+		if ( is_ssl() ) {
+			$host = 'https://secure.gravatar.com/avatar/';
+		}
+
+		// Filter gravatar vars
+		$email    = apply_filters( 'bp_core_gravatar_email', $email, $item_id, $object );
+		$gravatar = apply_filters( 'bp_gravatar_url', $host ) . md5( strtolower( $email ) ) . '?d=' . $default_grav . '&amp;s=' . $grav_size;
+
+		// Gravatar rating; http://bit.ly/89QxZA
+		$rating = get_option( 'avatar_rating' );
+		if ( ! empty( $rating ) ) {
+			$gravatar .= "&amp;r={$rating}";
+		}
+
+	// No avatar was found, and we've been told not to use a gravatar.
+	} else {
+		$gravatar = apply_filters( "bp_core_default_avatar_$object", BP_PLUGIN_URL . 'bp-core/images/mystery-man.jpg', $params );
+	}
+
+	if ( true === $html ) {
+		return apply_filters( 'bp_core_fetch_avatar', '<img src="' . $gravatar . '" class="' . esc_attr( $class ) . '"' . $css_id . $html_width . $html_height . $html_alt . $title . ' />', $params, $item_id, $avatar_dir, $css_id, $html_width, $html_height, $avatar_folder_url, $avatar_folder_dir );
+	} else {
+		return apply_filters( 'bp_core_fetch_avatar_url', $gravatar, $params );
+	}
+}
+
+/**
+ * Delete an existing avatar.
+ *
+ * @param array $args {
+ *     Array of function parameters.
+ *     @type bool|int $item_id ID of the item whose avatar you're deleting.
+ *           Defaults to the current item of type $object.
+ *     @type string $object Object type of the item whose avatar you're
+ *           deleting. 'user', 'group', 'blog', or custom. Default: 'user'.
+ *     @type bool|string $avatar_dir Subdirectory where avatar is located.
+ *           Default: false, which falls back on the default location
+ *           corresponding to the $object.
+ * }
+ * @return bool True on success, false on failure.
+ */
+function bp_core_delete_existing_avatar( $args = '' ) {
+
+	$defaults = array(
+		'item_id'    => false,
+		'object'     => 'user', // user OR group OR blog OR custom type (if you use filters)
+		'avatar_dir' => false
+	);
+
+	$args = wp_parse_args( $args, $defaults );
+	extract( $args, EXTR_SKIP );
+
+	if ( empty( $item_id ) ) {
+		if ( 'user' == $object )
+			$item_id = bp_displayed_user_id();
+		else if ( 'group' == $object )
+			$item_id = buddypress()->groups->current_group->id;
+		else if ( 'blog' == $object )
+			$item_id = $current_blog->id;
+
+		$item_id = apply_filters( 'bp_core_avatar_item_id', $item_id, $object );
+
+		if ( !$item_id ) return false;
+	}
+
+	if ( empty( $avatar_dir ) ) {
+		if ( 'user' == $object )
+			$avatar_dir = 'avatars';
+		else if ( 'group' == $object )
+			$avatar_dir = 'group-avatars';
+		else if ( 'blog' == $object )
+			$avatar_dir = 'blog-avatars';
+
+		$avatar_dir = apply_filters( 'bp_core_avatar_dir', $avatar_dir, $object );
+
+		if ( !$avatar_dir ) return false;
+	}
+
+	$avatar_folder_dir = apply_filters( 'bp_core_avatar_folder_dir', bp_core_avatar_upload_path() . '/' . $avatar_dir . '/' . $item_id, $item_id, $object, $avatar_dir );
+
+	if ( !file_exists( $avatar_folder_dir ) )
+		return false;
+
+	if ( $av_dir = opendir( $avatar_folder_dir ) ) {
+		while ( false !== ( $avatar_file = readdir($av_dir) ) ) {
+			if ( ( preg_match( "/-bpfull/", $avatar_file ) || preg_match( "/-bpthumb/", $avatar_file ) ) && '.' != $avatar_file && '..' != $avatar_file )
+				@unlink( $avatar_folder_dir . '/' . $avatar_file );
+		}
+	}
+	closedir($av_dir);
+
+	@rmdir( $avatar_folder_dir );
+
+	do_action( 'bp_core_delete_existing_avatar', $args );
+
+	return true;
+}
+
+/**
+ * Handle avatar uploading.
+ *
+ * The functions starts off by checking that the file has been uploaded
+ * properly using bp_core_check_avatar_upload(). It then checks that the file
+ * size is within limits, and that it has an accepted file extension (jpg, gif,
+ * png). If everything checks out, crop the image and move it to its real
+ * location.
+ *
+ * @see bp_core_check_avatar_upload()
+ * @see bp_core_check_avatar_type()
+ *
+ * @param array $file The appropriate entry the from $_FILES superglobal.
+ * @param string $upload_dir_filter A filter to be applied to 'upload_dir'.
+ * @return bool True on success, false on failure.
+ */
+function bp_core_avatar_handle_upload( $file, $upload_dir_filter ) {
+
+	/***
+	 * You may want to hook into this filter if you want to override this function.
+	 * Make sure you return false.
+	 */
+	if ( !apply_filters( 'bp_core_pre_avatar_handle_upload', true, $file, $upload_dir_filter ) )
+		return true;
+
+	require_once( ABSPATH . '/wp-admin/includes/file.php' );
+
+	$uploadErrors = array(
+		0 => __( 'The image was uploaded successfully', 'buddypress' ),
+		1 => __( 'The image exceeds the maximum allowed file size of: ', 'buddypress' ) . size_format( bp_core_avatar_original_max_filesize() ),
+		2 => __( 'The image exceeds the maximum allowed file size of: ', 'buddypress' ) . size_format( bp_core_avatar_original_max_filesize() ),
+		3 => __( 'The uploaded file was only partially uploaded.', 'buddypress' ),
+		4 => __( 'The image was not uploaded.', 'buddypress' ),
+		6 => __( 'Missing a temporary folder.', 'buddypress' )
+	);
+
+	if ( ! bp_core_check_avatar_upload( $file ) ) {
+		bp_core_add_message( sprintf( __( 'Your upload failed, please try again. Error was: %s', 'buddypress' ), $uploadErrors[$file['file']['error']] ), 'error' );
+		return false;
+	}
+
+	if ( ! bp_core_check_avatar_size( $file ) ) {
+		bp_core_add_message( sprintf( __( 'The file you uploaded is too big. Please upload a file under %s', 'buddypress' ), size_format( bp_core_avatar_original_max_filesize() ) ), 'error' );
+		return false;
+	}
+
+	if ( ! bp_core_check_avatar_type( $file ) ) {
+		bp_core_add_message( __( 'Please upload only JPG, GIF or PNG photos.', 'buddypress' ), 'error' );
+		return false;
+	}
+
+	// Filter the upload location
+	add_filter( 'upload_dir', $upload_dir_filter, 10, 0 );
+
+	$bp = buddypress();
+
+	$bp->avatar_admin->original = wp_handle_upload( $file['file'], array( 'action'=> 'bp_avatar_upload' ) );
+
+	// Remove the upload_dir filter, so that other upload URLs on the page
+	// don't break
+	remove_filter( 'upload_dir', $upload_dir_filter, 10, 0 );
+
+	// Move the file to the correct upload location.
+	if ( !empty( $bp->avatar_admin->original['error'] ) ) {
+		bp_core_add_message( sprintf( __( 'Upload Failed! Error was: %s', 'buddypress' ), $bp->avatar_admin->original['error'] ), 'error' );
+		return false;
+	}
+
+	// Get image size
+	$size  = @getimagesize( $bp->avatar_admin->original['file'] );
+	$error = false;
+
+	// Check image size and shrink if too large
+	if ( $size[0] > bp_core_avatar_original_max_width() ) {
+		$editor = wp_get_image_editor( $bp->avatar_admin->original['file'] );
+
+		if ( ! is_wp_error( $editor ) ) {
+			$editor->set_quality( 100 );
+
+			$resized = $editor->resize( bp_core_avatar_original_max_width(), bp_core_avatar_original_max_width(), false );
+			if ( ! is_wp_error( $resized ) ) {
+				$thumb = $editor->save( $editor->generate_filename() );
+			} else {
+				$error = $resized;
+			}
+
+			// Check for thumbnail creation errors
+			if ( false === $error && is_wp_error( $thumb ) ) {
+				$error = $thumb;
+			}
+
+			// Thumbnail is good so proceed
+			if ( false === $error ) {
+				$bp->avatar_admin->resized = $thumb;
+			}
+
+		} else {
+			$error = $editor;
+		}
+
+		if ( false !== $error ) {
+			bp_core_add_message( sprintf( __( 'Upload Failed! Error was: %s', 'buddypress' ), $error->get_error_message() ), 'error' );
+			return false;
+		}
+	}
+
+	if ( ! isset( $bp->avatar_admin->image ) )
+		$bp->avatar_admin->image = new stdClass();
+
+	// We only want to handle one image after resize.
+	if ( empty( $bp->avatar_admin->resized ) ) {
+		$bp->avatar_admin->image->dir = str_replace( bp_core_avatar_upload_path(), '', $bp->avatar_admin->original['file'] );
+	} else {
+		$bp->avatar_admin->image->dir = str_replace( bp_core_avatar_upload_path(), '', $bp->avatar_admin->resized['path'] );
+		@unlink( $bp->avatar_admin->original['file'] );
+	}
+
+	// Check for WP_Error on what should be an image
+	if ( is_wp_error( $bp->avatar_admin->image->dir ) ) {
+		bp_core_add_message( sprintf( __( 'Upload failed! Error was: %s', 'buddypress' ), $bp->avatar_admin->image->dir->get_error_message() ), 'error' );
+		return false;
+	}
+
+	// Set the url value for the image
+	$bp->avatar_admin->image->url = bp_core_avatar_url() . $bp->avatar_admin->image->dir;
+
+	return true;
+}
+
+/**
+ * Crop an uploaded avatar.
+ *
+ * $args has the following parameters:
+ *  object - What component the avatar is for, e.g. "user"
+ *  avatar_dir  The absolute path to the avatar
+ *  item_id - Item ID
+ *  original_file - The absolute path to the original avatar file
+ *  crop_w - Crop width
+ *  crop_h - Crop height
+ *  crop_x - The horizontal starting point of the crop
+ *  crop_y - The vertical starting point of the crop
+ *
+ * @param array $args {
+ *     Array of function parameters.
+ *     @type string $object Object type of the item whose avatar you're
+ *           handling. 'user', 'group', 'blog', or custom. Default: 'user'.
+ *     @type string $avatar_dir Subdirectory where avatar should be stored.
+ *           Default: 'avatars'.
+ *     @type bool|int $item_id ID of the item that the avatar belongs to.
+ *     @type bool|string $original_file Absolute papth to the original avatar
+ *           file.
+ *     @type int $crop_w Crop width. Default: the global 'full' avatar width,
+ *           as retrieved by bp_core_avatar_full_width().
+ *     @type int $crop_h Crop height. Default: the global 'full' avatar height,
+ *           as retrieved by bp_core_avatar_full_height().
+ *     @type int $crop_x The horizontal starting point of the crop. Default: 0.
+ *     @type int $crop_y The vertical starting point of the crop. Default: 0.
+ * }
+ * @return bool True on success, false on failure.
+ */
+function bp_core_avatar_handle_crop( $args = '' ) {
+
+	$r = wp_parse_args( $args, array(
+		'object'        => 'user',
+		'avatar_dir'    => 'avatars',
+		'item_id'       => false,
+		'original_file' => false,
+		'crop_w'        => bp_core_avatar_full_width(),
+		'crop_h'        => bp_core_avatar_full_height(),
+		'crop_x'        => 0,
+		'crop_y'        => 0
+	) );
+
+	/***
+	 * You may want to hook into this filter if you want to override this function.
+	 * Make sure you return false.
+	 */
+	if ( !apply_filters( 'bp_core_pre_avatar_handle_crop', true, $r ) )
+		return true;
+
+	extract( $r, EXTR_SKIP );
+
+	if ( empty( $original_file ) )
+		return false;
+
+	$original_file = bp_core_avatar_upload_path() . $original_file;
+
+	if ( !file_exists( $original_file ) )
+		return false;
+
+	if ( empty( $item_id ) ) {
+		$avatar_folder_dir = apply_filters( 'bp_core_avatar_folder_dir', dirname( $original_file ), $item_id, $object, $avatar_dir );
+	} else {
+		$avatar_folder_dir = apply_filters( 'bp_core_avatar_folder_dir', bp_core_avatar_upload_path() . '/' . $avatar_dir . '/' . $item_id, $item_id, $object, $avatar_dir );
+	}
+
+	if ( !file_exists( $avatar_folder_dir ) )
+		return false;
+
+	require_once( ABSPATH . '/wp-admin/includes/image.php' );
+	require_once( ABSPATH . '/wp-admin/includes/file.php' );
+
+	// Delete the existing avatar files for the object
+	bp_core_delete_existing_avatar( array( 'object' => $object, 'avatar_path' => $avatar_folder_dir ) );
+
+	// Make sure we at least have a width and height for cropping
+	if ( empty( $crop_w ) ) {
+		$crop_w = bp_core_avatar_full_width();
+	}
+
+	if ( empty( $crop_h ) ) {
+		$crop_h = bp_core_avatar_full_height();
+	}
+
+	// Get the file extension
+	$data = @getimagesize( $original_file );
+	$ext  = $data['mime'] == 'image/png' ? 'png' : 'jpg';
+
+	// Set the full and thumb filenames
+	$full_filename  = wp_hash( $original_file . time() ) . '-bpfull.'  . $ext;
+	$thumb_filename = wp_hash( $original_file . time() ) . '-bpthumb.' . $ext;
+
+	// Crop the image
+	$full_cropped  = wp_crop_image( $original_file, (int) $crop_x, (int) $crop_y, (int) $crop_w, (int) $crop_h, bp_core_avatar_full_width(),  bp_core_avatar_full_height(),  false, $avatar_folder_dir . '/' . $full_filename  );
+	$thumb_cropped = wp_crop_image( $original_file, (int) $crop_x, (int) $crop_y, (int) $crop_w, (int) $crop_h, bp_core_avatar_thumb_width(), bp_core_avatar_thumb_height(), false, $avatar_folder_dir . '/' . $thumb_filename );
+
+	// Check for errors
+	if ( empty( $full_cropped ) || empty( $thumb_cropped ) || is_wp_error( $full_cropped ) || is_wp_error( $thumb_cropped ) )
+		return false;
+
+	// Remove the original
+	@unlink( $original_file );
+
+	return true;
+}
+
+/**
+ * Replace default WordPress avatars with BP avatars, if available.
+ *
+ * Filters 'get_avatar'.
+ *
+ * @param string $avatar The avatar path passed to 'get_avatar'.
+ * @param int|string|object $user A user ID, email address, or comment object.
+ * @param int $size Size of the avatar image ('thumb' or 'full').
+ * @param string $default URL to a default image to use if no avatar is available.
+ * @param string $alt Alternate text to use in image tag. Default: ''.
+ * @return string BP avatar path, if found; else the original avatar path.
+ */
+function bp_core_fetch_avatar_filter( $avatar, $user, $size, $default, $alt = '' ) {
+	global $pagenow;
+
+	// Do not filter if inside WordPress options page
+	if ( 'options-discussion.php' == $pagenow )
+		return $avatar;
+
+	// If passed an object, assume $user->user_id
+	if ( is_object( $user ) ) {
+		$id = $user->user_id;
+
+	// If passed a number, assume it was a $user_id
+	} else if ( is_numeric( $user ) ) {
+		$id = $user;
+
+	// If passed a string and that string returns a user, get the $id
+	} elseif ( is_string( $user ) && ( $user_by_email = get_user_by( 'email', $user ) ) ) {
+		$id = $user_by_email->ID;
+	}
+
+	// If somehow $id hasn't been assigned, return the result of get_avatar
+	if ( empty( $id ) ) {
+		return !empty( $avatar ) ? $avatar : $default;
+	}
+
+	// Image alt tag
+	if ( empty( $alt ) ) {
+		$alt = sprintf( __( 'Avatar of %s', 'buddypress' ), bp_core_get_user_displayname( $id ) );
+	}
+
+	// Use the 'thumb' type, unless the requested width is bigger than
+	// BP's thumb width.
+	$type = 'thumb';
+	if ( (int) $size > bp_core_avatar_thumb_width() ) {
+		$type = 'full';
+	}
+
+	// Let BuddyPress handle the fetching of the avatar
+	$bp_avatar = bp_core_fetch_avatar( array(
+		'item_id' => $id,
+		'type'    => $type,
+		'width'   => $size,
+		'height'  => $size,
+		'alt'     => $alt,
+	) );
+
+	// If BuddyPress found an avatar, use it. If not, use the result of get_avatar
+	return ( !$bp_avatar ) ? $avatar : $bp_avatar;
+}
+add_filter( 'get_avatar', 'bp_core_fetch_avatar_filter', 10, 5 );
+
+/**
+ * Is the current avatar upload error-free?
+ *
+ * @param array $file The $_FILES array.
+ * @return bool True if no errors are found. False if there are errors.
+ */
+function bp_core_check_avatar_upload( $file ) {
+	if ( isset( $file['error'] ) && $file['error'] )
+		return false;
+
+	return true;
+}
+
+/**
+ * Is the file size of the current avatar upload permitted?
+ *
+ * @param array $file The $_FILES array.
+ * @return bool True if the avatar is under the size limit, otherwise false.
+ */
+function bp_core_check_avatar_size( $file ) {
+	if ( $file['file']['size'] > bp_core_avatar_original_max_filesize() )
+		return false;
+
+	return true;
+}
+
+/**
+ * Does the current avatar upload have an allowed file type?
+ *
+ * Permitted file types are JPG, GIF and PNG.
+ *
+ * @param array $file The $_FILES array.
+ * @return bool True if the file extension is permitted, otherwise false.
+ */
+function bp_core_check_avatar_type($file) {
+	if ( ( !empty( $file['file']['type'] ) && !preg_match('/(jpe?g|gif|png)$/i', $file['file']['type'] ) ) || !preg_match( '/(jpe?g|gif|png)$/i', $file['file']['name'] ) )
+		return false;
+
+	return true;
+}
+
+/**
+ * Fetch data from the BP root blog's upload directory.
+ *
+ * Handy for multisite instances because all uploads are made on the BP root
+ * blog and we need to query the BP root blog for the upload directory data.
+ *
+ * This function ensures that we only need to use {@link switch_to_blog()}
+ * once to get what we need.
+ *
+ * @since BuddyPress (1.8.0)
+ *
+ * @uses wp_upload_dir()
+ *
+ * @param string $type The variable we want to return from the $bp->avatars
+ *        object. Only 'upload_path' and 'url' are supported. Default: 'upload_path'.
+ * @return string The avatar upload directory path.
+ */
+function bp_core_get_upload_dir( $type = 'upload_path' ) {
+	$bp = buddypress();
+
+	switch ( $type ) {
+		case 'upload_path' :
+			$constant = 'BP_AVATAR_UPLOAD_PATH';
+			$key      = 'basedir';
+
+			break;
+
+		case 'url' :
+			$constant = 'BP_AVATAR_URL';
+			$key      = 'baseurl';
+
+			break;
+
+		default :
+			return false;
+
+			break;
+	}
+
+	// See if the value has already been calculated and stashed in the $bp global
+	if ( isset( $bp->avatar->$type ) ) {
+		$retval = $bp->avatar->$type;
+	} else {
+		// If this value has been set in a constant, just use that
+		if ( defined( $constant ) ) {
+			$retval = constant( $constant );
+		} else {
+
+			// Use cached upload dir data if available
+			if ( ! empty( $bp->avatar->upload_dir ) ) {
+				$upload_dir = $bp->avatar->upload_dir;
+
+			// No cache, so query for it
+			} else {
+				// We need to switch to the root blog on multisite installs
+				if ( is_multisite() ) {
+					switch_to_blog( bp_get_root_blog_id() );
+				}
+
+				// Get upload directory information from current site
+				$upload_dir = wp_upload_dir();
+
+				// Will bail if not switched
+				restore_current_blog();
+
+				// Stash upload directory data for later use
+				$bp->avatar->upload_dir = $upload_dir;
+			}
+
+			// Directory does not exist and cannot be created
+			if ( ! empty( $upload_dir['error'] ) ) {
+				$retval = '';
+
+			} else {
+				$retval = $upload_dir[$key];
+
+				// If $key is 'baseurl', check to see if we're on SSL
+				// Workaround for WP13941, WP15928, WP19037.
+				if ( $key == 'baseurl' && is_ssl() ) {
+					$retval = str_replace( 'http://', 'https://', $retval );
+				}
+			}
+
+		}
+
+		// Stash in $bp for later use
+		$bp->avatar->$type = $retval;
+	}
+
+	return $retval;
+}
+
+/**
+ * Get the absolute upload path for the WP installation.
+ *
+ * @uses wp_upload_dir To get upload directory info
+ *
+ * @return string Absolute path to WP upload directory.
+ */
+function bp_core_avatar_upload_path() {
+	return apply_filters( 'bp_core_avatar_upload_path', bp_core_get_upload_dir() );
+}
+
+/**
+ * Get the raw base URL for root site upload location.
+ *
+ * @uses wp_upload_dir To get upload directory info.
+ *
+ * @return string Full URL to current upload location.
+ */
+function bp_core_avatar_url() {
+	return apply_filters( 'bp_core_avatar_url', bp_core_get_upload_dir( 'url' ) );
+}
+
+/**
+ * Check if a given user ID has an uploaded avatar.
+ *
+ * @since BuddyPress (1.0.0)
+ *
+ * @param int $user_id ID of the user whose avatar is being checked.
+ * @return bool True if the user has uploaded a local avatar. Otherwise false.
+ */
+function bp_get_user_has_avatar( $user_id = 0 ) {
+
+	if ( empty( $user_id ) )
+		$user_id = bp_displayed_user_id();
+
+	$retval = false;
+	if ( bp_core_fetch_avatar( array( 'item_id' => $user_id, 'no_grav' => true, 'html' => false ) ) != bp_core_avatar_default() )
+		$retval = true;
+
+	return (bool) apply_filters( 'bp_get_user_has_avatar', $retval, $user_id );
+}
+
+/**
+ * Utility function for fetching an avatar dimension setting.
+ *
+ * @since BuddyPress (1.5.0)
+ *
+ * @param string $type Dimension type you're fetching dimensions for. 'thumb'
+ *        or 'full'. Default: 'thumb'.
+ * @param string $h_or_w Which dimension is being fetched. 'height' or 'width'.
+ *        Default: 'height'.
+ * @return int $dim The dimension.
+ */
+function bp_core_avatar_dimension( $type = 'thumb', $h_or_w = 'height' ) {
+	$bp  = buddypress();
+	$dim = isset( $bp->avatar->{$type}->{$h_or_w} ) ? (int) $bp->avatar->{$type}->{$h_or_w} : false;
+
+	return apply_filters( 'bp_core_avatar_dimension', $dim, $type, $h_or_w );
+}
+
+/**
+ * Get the 'thumb' avatar width setting.
+ *
+ * @since BuddyPress (1.5.0)
+ *
+ * @return int The 'thumb' width.
+ */
+function bp_core_avatar_thumb_width() {
+	return apply_filters( 'bp_core_avatar_thumb_width', bp_core_avatar_dimension( 'thumb', 'width' ) );
+}
+
+/**
+ * Get the 'thumb' avatar height setting.
+ *
+ * @since BuddyPress (1.5.0)
+ *
+ * @return int The 'thumb' height.
+ */
+function bp_core_avatar_thumb_height() {
+	return apply_filters( 'bp_core_avatar_thumb_height', bp_core_avatar_dimension( 'thumb', 'height' ) );
+}
+
+/**
+ * Get the 'full' avatar width setting
+ *
+ * @since BuddyPress (1.5.0)
+ *
+ * @return int The 'full' width.
+ */
+function bp_core_avatar_full_width() {
+	return apply_filters( 'bp_core_avatar_full_width', bp_core_avatar_dimension( 'full', 'width' ) );
+}
+
+/**
+ * Get the 'full' avatar height setting.
+ *
+ * @since BuddyPress (1.5.0)
+ *
+ * @return int The 'full' height.
+ */
+function bp_core_avatar_full_height() {
+	return apply_filters( 'bp_core_avatar_full_height', bp_core_avatar_dimension( 'full', 'height' ) );
+}
+
+/**
+ * Get the max width for original avatar uploads.
+ *
+ * @since BuddyPress (1.5.0)
+ *
+ * @return int The max width for original avatar uploads.
+ */
+function bp_core_avatar_original_max_width() {
+	return apply_filters( 'bp_core_avatar_original_max_width', (int) buddypress()->avatar->original_max_width );
+}
+
+/**
+ * Get the max filesize for original avatar uploads.
+ *
+ * @since BuddyPress (1.5.0)
+ *
+ * @return int The max filesize for original avatar uploads.
+ */
+function bp_core_avatar_original_max_filesize() {
+	return apply_filters( 'bp_core_avatar_original_max_filesize', (int) buddypress()->avatar->original_max_filesize );
+}
+
+/**
+ * Get the URL of the 'full' default avatar.
+ *
+ * @since BuddyPress (1.5.0)
+ *
+ * @return string The URL of the default avatar.
+ */
+function bp_core_avatar_default() {
+	return apply_filters( 'bp_core_avatar_default', buddypress()->avatar->full->default );
+}
+
+/**
+ * Get the URL of the 'thumb' default avatar.
+ *
+ * @since BuddyPress (1.5.0)
+ *
+ * @return string The URL of the default avatar thumb.
+ */
+function bp_core_avatar_default_thumb() {
+	return apply_filters( 'bp_core_avatar_thumb', buddypress()->avatar->thumb->default );
+}
Index: /tags/1.9/bp-core/bp-core-buddybar.php
===================================================================
--- /tags/1.9/bp-core/bp-core-buddybar.php	(revision 7684)
+++ /tags/1.9/bp-core/bp-core-buddybar.php	(revision 7684)
@@ -0,0 +1,712 @@
+<?php
+
+/**
+ * Core BuddyPress Navigational Functions.
+ *
+ * @package BuddyPress
+ * @subpackage Core
+ * @todo Deprecate BuddyBar functions.
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/**
+ * Add an item to the main BuddyPress navigation array.
+ *
+ * @global BuddyPress $bp The one true BuddyPress instance.
+ *
+ * @param array $args {
+ *     Array describing the new nav item.
+ *     @type string $name Display name for the nav item.
+ *     @type string $slug Unique URL slug for the nav item.
+ *     @type bool|string $item_css_id Optional. 'id' attribute for the nav
+ *           item. Default: the value of $slug.
+ *     @type bool $show_for_displayed_user Optional. Whether the nav item
+ *           should be visible when viewing a member profile other than your
+ *           own. Default: true.
+ *     @type bool $site_admin_only Optional. Whether the nav item should be
+ *           visible only to site admins (those with the 'bp_moderate' cap).
+ *           Default: false.
+ *     @type int $position Optional. Numerical index specifying where the item
+ *           should appear in the nav array. Default: 99.
+ *     @type callable $screen_function The callback function that will run
+ *           when the nav item is clicked.
+ *     @type bool|string $default_subnav_slug Optional. The slug of the default
+ *           subnav item to select when the nav item is clicked.
+ * }
+ * @return bool|null Returns false on failure.
+ */
+function bp_core_new_nav_item( $args = '' ) {
+	global $bp;
+
+	$defaults = array(
+		'name'                    => false, // Display name for the nav item
+		'slug'                    => false, // URL slug for the nav item
+		'item_css_id'             => false, // The CSS ID to apply to the HTML of the nav item
+		'show_for_displayed_user' => true,  // When viewing another user does this nav item show up?
+		'site_admin_only'         => false, // Can only site admins see this nav item?
+		'position'                => 99,    // Index of where this nav item should be positioned
+		'screen_function'         => false, // The name of the function to run when clicked
+		'default_subnav_slug'     => false  // The slug of the default subnav item to select when clicked
+	);
+
+	$r = wp_parse_args( $args, $defaults );
+	extract( $r, EXTR_SKIP );
+
+	// If we don't have the required info we need, don't create this subnav item
+	if ( empty( $name ) || empty( $slug ) )
+		return false;
+
+	// If this is for site admins only and the user is not one, don't create the subnav item
+	if ( !empty( $site_admin_only ) && !bp_current_user_can( 'bp_moderate' ) )
+		return false;
+
+	if ( empty( $item_css_id ) )
+		$item_css_id = $slug;
+
+	$bp->bp_nav[$slug] = array(
+		'name'                    => $name,
+		'slug'                    => $slug,
+		'link'                    => trailingslashit( bp_loggedin_user_domain() . $slug ),
+		'css_id'                  => $item_css_id,
+		'show_for_displayed_user' => $show_for_displayed_user,
+		'position'                => $position,
+		'screen_function'         => &$screen_function,
+		'default_subnav_slug'	  => $default_subnav_slug
+	);
+
+ 	/**
+	 * If this nav item is hidden for the displayed user, and
+	 * the logged in user is not the displayed user
+	 * looking at their own profile, don't create the nav item.
+	 */
+	if ( empty( $show_for_displayed_user ) && !bp_user_has_access() )
+		return false;
+
+	/**
+ 	 * If the nav item is visible, we are not viewing a user, and this is a root
+	 * component, don't attach the default subnav function so we can display a
+	 * directory or something else.
+ 	 */
+	if ( ( -1 != $position ) && bp_is_root_component( $slug ) && !bp_displayed_user_id() )
+		return;
+
+	// Look for current component
+	if ( bp_is_current_component( $slug ) || bp_is_current_item( $slug ) ) {
+
+		// The requested URL has explicitly included the default subnav
+		// (eg: http://example.com/members/membername/activity/just-me/)
+		// The canonical version will not contain this subnav slug.
+		if ( !empty( $default_subnav_slug ) && bp_is_current_action( $default_subnav_slug ) && !bp_action_variable( 0 ) ) {
+			unset( $bp->canonical_stack['action'] );
+		} elseif ( ! bp_current_action() ) {
+
+			// Add our screen hook if screen function is callable
+			if ( is_callable( $screen_function ) ) {
+				add_action( 'bp_screens', $screen_function, 3 );
+			}
+
+			if ( !empty( $default_subnav_slug ) ) {
+				$bp->current_action = apply_filters( 'bp_default_component_subnav', $default_subnav_slug, $r );
+			}
+		}
+	}
+
+	do_action( 'bp_core_new_nav_item', $r, $args, $defaults );
+}
+
+/**
+ * Modify the default subnav item that loads when a top level nav item is clicked.
+ *
+ * @global BuddyPress $bp The one true BuddyPress instance.
+ *
+ * @param array $args {
+ *     @type string $parent_slug The slug of the nav item whose default is
+ *           being changed.
+ *     @type callable $screen_function The new default callback function that
+ *           will run when the nav item is clicked.
+ *     @type string $subnav_slug The slug of the new default subnav item.
+ * }
+ */
+function bp_core_new_nav_default( $args = '' ) {
+	global $bp;
+
+	$defaults = array(
+		'parent_slug'     => false, // Slug of the parent
+		'screen_function' => false, // The name of the function to run when clicked
+		'subnav_slug'     => false  // The slug of the subnav item to select when clicked
+	);
+
+	$r = wp_parse_args( $args, $defaults );
+	extract( $r, EXTR_SKIP );
+
+	if ( $function = $bp->bp_nav[$parent_slug]['screen_function'] ) {
+		// Remove our screen hook if screen function is callable
+		if ( is_callable( $function ) ) {
+			remove_action( 'bp_screens', $function, 3 );
+		}
+	}
+
+	$bp->bp_nav[$parent_slug]['screen_function'] = &$screen_function;
+
+	if ( bp_is_current_component( $parent_slug ) ) {
+
+		// The only way to tell whether to set the subnav is to peek at the unfiltered_uri
+		// Find the component
+		$component_uri_key = array_search( $parent_slug, $bp->unfiltered_uri );
+
+		if ( false !== $component_uri_key ) {
+			if ( !empty( $bp->unfiltered_uri[$component_uri_key + 1] ) ) {
+				$unfiltered_action = $bp->unfiltered_uri[$component_uri_key + 1];
+			}
+		}
+
+		// No subnav item has been requested in the URL, so set a new nav default
+		if ( empty( $unfiltered_action ) ) {
+			if ( !bp_is_current_action( $subnav_slug ) ) {
+				if ( is_callable( $screen_function ) ) {
+					add_action( 'bp_screens', $screen_function, 3 );
+				}
+
+				$bp->current_action = $subnav_slug;
+				unset( $bp->canonical_stack['action'] );
+			}
+
+		// The URL is explicitly requesting the new subnav item, but should be
+		// directed to the canonical URL
+		} elseif ( $unfiltered_action == $subnav_slug ) {
+			unset( $bp->canonical_stack['action'] );
+
+		// In all other cases (including the case where the original subnav item
+		// is explicitly called in the URL), the canonical URL will contain the
+		// subnav slug
+		} else {
+			$bp->canonical_stack['action'] = bp_current_action();
+		}
+	}
+
+	return;
+}
+
+/**
+ * Sort the navigation menu items.
+ *
+ * The sorting is split into a separate function because it can only happen
+ * after all plugins have had a chance to register their navigation items.
+ *
+ * @global BuddyPress $bp The one true BuddyPress instance
+ *
+ * @return bool|null Returns false on failure.
+ */
+function bp_core_sort_nav_items() {
+	global $bp;
+
+	if ( empty( $bp->bp_nav ) || !is_array( $bp->bp_nav ) )
+		return false;
+
+	$temp = array();
+
+	foreach ( (array) $bp->bp_nav as $slug => $nav_item ) {
+		if ( empty( $temp[$nav_item['position']]) ) {
+			$temp[$nav_item['position']] = $nav_item;
+		} else {
+			// increase numbers here to fit new items in.
+			do {
+				$nav_item['position']++;
+			} while ( !empty( $temp[$nav_item['position']] ) );
+
+			$temp[$nav_item['position']] = $nav_item;
+		}
+	}
+
+	ksort( $temp );
+	$bp->bp_nav = &$temp;
+}
+add_action( 'wp_head',    'bp_core_sort_nav_items' );
+add_action( 'admin_head', 'bp_core_sort_nav_items' );
+
+/**
+ * Add a subnav item to the BuddyPress navigation.
+ *
+ * @global BuddyPress $bp The one true BuddyPress instance.
+ *
+ * @param array $args {
+ *     Array describing the new subnav item.
+ *     @type string $name Display name for the subnav item.
+ *     @type string $slug Unique URL slug for the subnav item.
+ *     @type string $parent_slug Slug of the top-level nav item under which the
+ *           new subnav item should be added.
+ *     @type string $parent_url URL of the parent nav item.
+ *     @type bool|string $item_css_id Optional. 'id' attribute for the nav
+ *           item. Default: the value of $slug.
+ *     @type bool $user_has_access Optional. True if the logged-in user has
+ *           access to the subnav item, otherwise false. Can be set dynamically
+ *           when registering the subnav; eg, use bp_is_my_profile() to restrict
+ *           access to profile owners only. Default: true.
+ *     @type bool $site_admin_only Optional. Whether the nav item should be
+ *           visible only to site admins (those with the 'bp_moderate' cap).
+ *           Default: false.
+ *     @type int $position Optional. Numerical index specifying where the item
+ *           should appear in the subnav array. Default: 90.
+ *     @type callable $screen_function The callback function that will run
+ *           when the nav item is clicked.
+ *     @type string $link Optional. The URL that the subnav item should point
+ *           to. Defaults to a value generated from the $parent_url + $slug.
+ * }
+ * @return bool|null Returns false on failure.
+ */
+function bp_core_new_subnav_item( $args = '' ) {
+	global $bp;
+
+	$defaults = array(
+		'name'            => false, // Display name for the nav item
+		'slug'            => false, // URL slug for the nav item
+		'parent_slug'     => false, // URL slug of the parent nav item
+		'parent_url'      => false, // URL of the parent item
+		'item_css_id'     => false, // The CSS ID to apply to the HTML of the nav item
+		'user_has_access' => true,  // Can the logged in user see this nav item?
+		'site_admin_only' => false, // Can only site admins see this nav item?
+		'position'        => 90,    // Index of where this nav item should be positioned
+		'screen_function' => false, // The name of the function to run when clicked
+		'link'            => ''     // The link for the subnav item; optional, not usually required.
+	);
+
+	$r = wp_parse_args( $args, $defaults );
+	extract( $r, EXTR_SKIP );
+
+	// If we don't have the required info we need, don't create this subnav item
+	if ( empty( $name ) || empty( $slug ) || empty( $parent_slug ) || empty( $parent_url ) || empty( $screen_function ) )
+		return false;
+
+	// Link was not forced, so create one
+	if ( empty( $link ) ) {
+		$link = $parent_url . $slug;
+
+		// If this sub item is the default for its parent, skip the slug
+		if ( ! empty( $bp->bp_nav[$parent_slug]['default_subnav_slug'] ) && $slug == $bp->bp_nav[$parent_slug]['default_subnav_slug'] ) {
+			$link = $parent_url;
+		}
+	}
+
+	// If this is for site admins only and the user is not one, don't create the subnav item
+	if ( !empty( $site_admin_only ) && !bp_current_user_can( 'bp_moderate' ) )
+		return false;
+
+	if ( empty( $item_css_id ) )
+		$item_css_id = $slug;
+
+	$bp->bp_options_nav[$parent_slug][$slug] = array(
+		'name'            => $name,
+		'link'            => trailingslashit( $link ),
+		'slug'            => $slug,
+		'css_id'          => $item_css_id,
+		'position'        => $position,
+		'user_has_access' => $user_has_access,
+		'screen_function' => &$screen_function
+	);
+
+	/**
+	 * The last step is to hook the screen function for the added subnav item. But this only
+	 * needs to be done if this subnav item is the current view, and the user has access to the
+	 * subnav item. We figure out whether we're currently viewing this subnav by checking the
+	 * following two conditions:
+	 *   (1) Either:
+	 *	     (a) the parent slug matches the current_component, or
+	 *	     (b) the parent slug matches the current_item
+	 *   (2) And either:
+	 *	     (a) the current_action matches $slug, or
+	 *       (b) there is no current_action (ie, this is the default subnav for the parent nav)
+	 *	     and this subnav item is the default for the parent item (which we check by
+	 *	     comparing this subnav item's screen function with the screen function of the
+	 *	     parent nav item in $bp->bp_nav). This condition only arises when viewing a
+	 *	     user, since groups should always have an action set.
+	 */
+
+	// If we *don't* meet condition (1), return
+	if ( ! bp_is_current_component( $parent_slug ) && ! bp_is_current_item( $parent_slug ) )
+		return;
+
+	// If we *do* meet condition (2), then the added subnav item is currently being requested
+	if ( ( bp_current_action() && bp_is_current_action( $slug ) ) || ( bp_is_user() && ! bp_current_action() && ( $screen_function == $bp->bp_nav[$parent_slug]['screen_function'] ) ) ) {
+
+		// Before hooking the screen function, check user access
+		if ( !empty( $user_has_access ) ) {
+			// Add our screen hook if screen function is callable
+			if ( is_callable( $screen_function ) ) {
+				add_action( 'bp_screens', $screen_function, 3 );
+			}
+		} else {
+
+			// When the content is off-limits, we handle the situation
+			// differently depending on whether the current user is logged in
+			if ( is_user_logged_in() ) {
+				if ( !bp_is_my_profile() && empty( $bp->bp_nav[$bp->default_component]['show_for_displayed_user'] ) ) {
+
+					// This covers the edge case where the default component is
+					// a non-public tab, like 'messages'
+					if ( bp_is_active( 'activity' ) && isset( $bp->pages->activity ) ) {
+						$redirect_to = trailingslashit( bp_displayed_user_domain() . bp_get_activity_slug() );
+					} else {
+						$redirect_to = trailingslashit( bp_displayed_user_domain() . ( 'xprofile' == $bp->profile->id ? 'profile' : $bp->profile->id ) );
+					}
+
+					$message     = '';
+				} else {
+					$message     = __( 'You do not have access to this page.', 'buddypress' );
+					$redirect_to = bp_displayed_user_domain();
+				}
+
+				// Off-limits to this user. Throw an error and redirect to the displayed user's domain
+				bp_core_no_access( array(
+					'message'  => $message,
+					'root'     => $redirect_to,
+					'redirect' => false
+				) );
+
+			// Not logged in. Allow the user to log in, and attempt to redirect
+			} else {
+				bp_core_no_access();
+			}
+		}
+	}
+}
+
+/**
+ * Sort all subnavigation arrays.
+ *
+ * @global BuddyPress $bp The one true BuddyPress instance
+ *
+ * @return bool|null Returns false on failure.
+ */
+function bp_core_sort_subnav_items() {
+	global $bp;
+
+	if ( empty( $bp->bp_options_nav ) || !is_array( $bp->bp_options_nav ) )
+		return false;
+
+	foreach ( (array) $bp->bp_options_nav as $parent_slug => $subnav_items ) {
+		if ( !is_array( $subnav_items ) )
+			continue;
+
+		foreach ( (array) $subnav_items as $subnav_item ) {
+			if ( empty( $temp[$subnav_item['position']]) )
+				$temp[$subnav_item['position']] = $subnav_item;
+			else {
+				// increase numbers here to fit new items in.
+				do {
+					$subnav_item['position']++;
+				} while ( !empty( $temp[$subnav_item['position']] ) );
+
+				$temp[$subnav_item['position']] = $subnav_item;
+			}
+		}
+		ksort( $temp );
+		$bp->bp_options_nav[$parent_slug] = &$temp;
+		unset( $temp );
+	}
+}
+add_action( 'wp_head',    'bp_core_sort_subnav_items' );
+add_action( 'admin_head', 'bp_core_sort_subnav_items' );
+
+/**
+ * Check whether a given nav item has subnav items.
+ *
+ * @since BuddyPress (1.5.0)
+ *
+ * @param string $nav_item The slug of the top-level nav item whose subnav
+ *        items you're checking. Default: the current component slug.
+ * @return bool $has_subnav True if the nav item is found and has subnav
+ *        items; false otherwise.
+ */
+function bp_nav_item_has_subnav( $nav_item = '' ) {
+	global $bp;
+
+	if ( !$nav_item )
+		$nav_item = bp_current_component();
+
+	$has_subnav = isset( $bp->bp_options_nav[$nav_item] ) && count( $bp->bp_options_nav[$nav_item] ) > 0;
+
+	return apply_filters( 'bp_nav_item_has_subnav', $has_subnav, $nav_item );
+}
+
+/**
+ * Remove a nav item from the navigation array.
+ *
+ * @param int $parent_id The slug of the parent navigation item.
+ * @param bool Returns false on failure, ie if the nav item can't be found.
+ */
+function bp_core_remove_nav_item( $parent_id ) {
+	global $bp;
+
+	// Unset subnav items for this nav item
+	if ( isset( $bp->bp_options_nav[$parent_id] ) && is_array( $bp->bp_options_nav[$parent_id] ) ) {
+		foreach( (array) $bp->bp_options_nav[$parent_id] as $subnav_item ) {
+			bp_core_remove_subnav_item( $parent_id, $subnav_item['slug'] );
+		}
+	}
+
+	if ( empty( $bp->bp_nav[ $parent_id ] ) )
+		return false;
+
+	if ( $function = $bp->bp_nav[$parent_id]['screen_function'] ) {
+		// Remove our screen hook if screen function is callable
+		if ( is_callable( $function ) ) {
+			remove_action( 'bp_screens', $function, 3 );
+		}
+	}
+
+	unset( $bp->bp_nav[$parent_id] );
+}
+
+/**
+ * Remove a subnav item from the navigation array.
+ *
+ * @param string $parent_id The slug of the parent navigation item.
+ * @param string $slug The slug of the subnav item to be removed.
+ */
+function bp_core_remove_subnav_item( $parent_id, $slug ) {
+	global $bp;
+
+	$screen_function = isset( $bp->bp_options_nav[$parent_id][$slug]['screen_function'] ) ? $bp->bp_options_nav[$parent_id][$slug]['screen_function'] : false;
+
+	if ( ! empty( $screen_function ) ) {
+		// Remove our screen hook if screen function is callable
+		if ( is_callable( $screen_function ) ) {
+			remove_action( 'bp_screens', $screen_function, 3 );
+		}
+	}
+
+	unset( $bp->bp_options_nav[$parent_id][$slug] );
+
+	if ( isset( $bp->bp_options_nav[$parent_id] ) && !count( $bp->bp_options_nav[$parent_id] ) )
+		unset($bp->bp_options_nav[$parent_id]);
+}
+
+/**
+ * Clear all subnav items from a specific nav item.
+ *
+ * @global BuddyPress $bp The one true BuddyPress instance.
+ *
+ * @param string $parent_slug The slug of the parent navigation item.
+ */
+function bp_core_reset_subnav_items( $parent_slug ) {
+	global $bp;
+
+	unset( $bp->bp_options_nav[$parent_slug] );
+}
+
+/** BuddyBar Template functions ***********************************************/
+
+/**
+ * Wrapper function for rendering the BuddyBar.
+ *
+ * @return bool|null Returns false if the BuddyBar is disabled.
+ */
+function bp_core_admin_bar() {
+	global $bp;
+
+	if ( defined( 'BP_DISABLE_ADMIN_BAR' ) && BP_DISABLE_ADMIN_BAR )
+		return false;
+
+	if ( (int) bp_get_option( 'hide-loggedout-adminbar' ) && !is_user_logged_in() )
+		return false;
+
+	$bp->doing_admin_bar = true;
+
+	echo '<div id="wp-admin-bar"><div class="padder">';
+
+	// **** Do bp-adminbar-logo Actions ********
+	do_action( 'bp_adminbar_logo' );
+
+	echo '<ul class="main-nav">';
+
+	// **** Do bp-adminbar-menus Actions ********
+	do_action( 'bp_adminbar_menus' );
+
+	echo '</ul>';
+	echo "</div></div><!-- #wp-admin-bar -->\n\n";
+
+	$bp->doing_admin_bar = false;
+}
+
+/**
+ * Output the BuddyBar logo.
+ */
+function bp_adminbar_logo() {
+	echo '<a href="' . bp_get_root_domain() . '" id="admin-bar-logo">' . get_blog_option( bp_get_root_blog_id(), 'blogname' ) . '</a>';
+}
+
+/**
+ * Output the "Log In" and "Sign Up" names to the BuddyBar.
+ *
+ * Visible only to visitors who are not logged in.
+ *
+ * @return bool|null Returns false if the current user is logged in.
+ */
+function bp_adminbar_login_menu() {
+
+	if ( is_user_logged_in() )
+		return false;
+
+	echo '<li class="bp-login no-arrow"><a href="' . wp_login_url() . '">' . __( 'Log In', 'buddypress' ) . '</a></li>';
+
+	// Show "Sign Up" link if user registrations are allowed
+	if ( bp_get_signup_allowed() )
+		echo '<li class="bp-signup no-arrow"><a href="' . bp_get_signup_page() . '">' . __( 'Sign Up', 'buddypress' ) . '</a></li>';
+}
+
+/**
+ * Output the My Account BuddyBar menu.
+ *
+ * @return bool|null Returns false on failure.
+ */
+function bp_adminbar_account_menu() {
+	global $bp;
+
+	if ( !$bp->bp_nav || !is_user_logged_in() )
+		return false;
+
+	echo '<li id="bp-adminbar-account-menu"><a href="' . bp_loggedin_user_domain() . '">';
+	echo __( 'My Account', 'buddypress' ) . '</a>';
+	echo '<ul>';
+
+	// Loop through each navigation item
+	$counter = 0;
+	foreach( (array) $bp->bp_nav as $nav_item ) {
+		$alt = ( 0 == $counter % 2 ) ? ' class="alt"' : '';
+
+		if ( -1 == $nav_item['position'] )
+			continue;
+
+		echo '<li' . $alt . '>';
+		echo '<a id="bp-admin-' . $nav_item['css_id'] . '" href="' . $nav_item['link'] . '">' . $nav_item['name'] . '</a>';
+
+		if ( isset( $bp->bp_options_nav[$nav_item['slug']] ) && is_array( $bp->bp_options_nav[$nav_item['slug']] ) ) {
+			echo '<ul>';
+			$sub_counter = 0;
+
+			foreach( (array) $bp->bp_options_nav[$nav_item['slug']] as $subnav_item ) {
+				$link = $subnav_item['link'];
+				$name = $subnav_item['name'];
+
+				if ( bp_displayed_user_domain() )
+					$link = str_replace( bp_displayed_user_domain(), bp_loggedin_user_domain(), $subnav_item['link'] );
+
+				if ( isset( $bp->displayed_user->userdata->user_login ) )
+					$name = str_replace( $bp->displayed_user->userdata->user_login, $bp->loggedin_user->userdata->user_login, $subnav_item['name'] );
+
+				$alt = ( 0 == $sub_counter % 2 ) ? ' class="alt"' : '';
+				echo '<li' . $alt . '><a id="bp-admin-' . $subnav_item['css_id'] . '" href="' . $link . '">' . $name . '</a></li>';
+				$sub_counter++;
+			}
+			echo '</ul>';
+		}
+
+		echo '</li>';
+
+		$counter++;
+	}
+
+	$alt = ( 0 == $counter % 2 ) ? ' class="alt"' : '';
+
+	echo '<li' . $alt . '><a id="bp-admin-logout" class="logout" href="' . wp_logout_url( home_url() ) . '">' . __( 'Log Out', 'buddypress' ) . '</a></li>';
+	echo '</ul>';
+	echo '</li>';
+}
+
+function bp_adminbar_thisblog_menu() {
+	if ( current_user_can( 'edit_posts' ) ) {
+		echo '<li id="bp-adminbar-thisblog-menu"><a href="' . admin_url() . '">';
+		_e( 'Dashboard', 'buddypress' );
+		echo '</a>';
+		echo '<ul>';
+
+		echo '<li class="alt"><a href="' . admin_url() . 'post-new.php">' . __( 'New Post', 'buddypress' ) . '</a></li>';
+		echo '<li><a href="' . admin_url() . 'edit.php">' . __( 'Manage Posts', 'buddypress' ) . '</a></li>';
+		echo '<li class="alt"><a href="' . admin_url() . 'edit-comments.php">' . __( 'Manage Comments', 'buddypress' ) . '</a></li>';
+
+		do_action( 'bp_adminbar_thisblog_items' );
+
+		echo '</ul>';
+		echo '</li>';
+	}
+}
+
+/**
+ * Output the Random BuddyBar menu.
+ *
+ * Not visible for logged-in users.
+ */
+function bp_adminbar_random_menu() {
+?>
+
+	<li class="align-right" id="bp-adminbar-visitrandom-menu">
+		<a href="#"><?php _e( 'Visit', 'buddypress' ) ?></a>
+		<ul class="random-list">
+			<li><a href="<?php echo trailingslashit( bp_get_root_domain() . '/' . bp_get_members_root_slug() ) . '?random-member' ?>" rel="nofollow"><?php _e( 'Random Member', 'buddypress' ) ?></a></li>
+
+			<?php if ( bp_is_active( 'groups' ) ) : ?>
+
+				<li class="alt"><a href="<?php echo trailingslashit( bp_get_root_domain() . '/' . bp_get_groups_root_slug() ) . '?random-group' ?>"  rel="nofollow"><?php _e( 'Random Group', 'buddypress' ) ?></a></li>
+
+			<?php endif; ?>
+
+			<?php if ( is_multisite() && bp_is_active( 'blogs' ) ) : ?>
+
+				<li><a href="<?php echo trailingslashit( bp_get_root_domain() . '/' . bp_get_blogs_root_slug() ) . '?random-blog' ?>"  rel="nofollow"><?php _e( 'Random Site', 'buddypress' ) ?></a></li>
+
+			<?php endif; ?>
+
+			<?php do_action( 'bp_adminbar_random_menu' ) ?>
+
+		</ul>
+	</li>
+
+	<?php
+}
+
+/**
+ * Retrieve the Toolbar display preference of a user based on context.
+ *
+ * This is a direct copy of WP's private _get_admin_bar_pref()
+ *
+ * @since BuddyPress (1.5.0)
+ *
+ * @uses get_user_option()
+ *
+ * @param string $context Context of this preference check. 'admin' or 'front'.
+ * @param int $user Optional. ID of the user to check. Default: 0 (which falls
+ *        back to the logged-in user's ID).
+ * @return bool True if the toolbar should be showing for this user.
+ */
+function bp_get_admin_bar_pref( $context, $user = 0 ) {
+	$pref = get_user_option( "show_admin_bar_{$context}", $user );
+	if ( false === $pref )
+		return true;
+
+	return 'true' === $pref;
+}
+
+/**
+ * Enqueue the BuddyBar CSS.
+ */
+function bp_core_load_buddybar_css() {
+	global $wp_styles;
+
+	if ( bp_use_wp_admin_bar() || ( (int) bp_get_option( 'hide-loggedout-adminbar' ) && !is_user_logged_in() ) || ( defined( 'BP_DISABLE_ADMIN_BAR' ) && BP_DISABLE_ADMIN_BAR ) )
+		return;
+
+	$min = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min';
+
+	if ( file_exists( get_stylesheet_directory() . '/_inc/css/adminbar.css' ) ) // Backwards compatibility
+		$stylesheet = get_stylesheet_directory_uri() . '/_inc/css/adminbar.css';
+	else
+		$stylesheet = BP_PLUGIN_URL . "bp-core/css/buddybar{$min}.css";
+
+	wp_enqueue_style( 'bp-admin-bar', apply_filters( 'bp_core_buddybar_rtl_css', $stylesheet ), array(), bp_get_version() );
+	$wp_styles->add_data( 'bp-admin-bar', 'rtl', true );
+	if ( $min )
+		$wp_styles->add_data( 'bp-admin-bar', 'suffix', $min );
+}
+add_action( 'bp_init', 'bp_core_load_buddybar_css' );
Index: /tags/1.9/bp-core/bp-core-cache.php
===================================================================
--- /tags/1.9/bp-core/bp-core-cache.php	(revision 7684)
+++ /tags/1.9/bp-core/bp-core-cache.php	(revision 7684)
@@ -0,0 +1,147 @@
+<?php
+/**
+ * BuddyPress Core Caching Functions.
+ *
+ * Caching functions handle the clearing of cached objects and pages on specific
+ * actions throughout BuddyPress.
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/**
+ * Prune the WP Super Cache.
+ *
+ * @see prune_super_cache()
+ *
+ * When wp-super-cache is installed this function will clear cached pages
+ * so that success/error messages are not cached, or time sensitive content.
+ */
+function bp_core_clear_cache() {
+	global $cache_path;
+
+	if ( function_exists( 'prune_super_cache' ) ) {
+		do_action( 'bp_core_clear_cache' );
+		return prune_super_cache( $cache_path, true );
+	}
+}
+
+/**
+ * Add 'bp' to global group of network wide cachable objects.
+ */
+function bp_core_add_global_group() {
+	if ( function_exists( 'wp_cache_add_global_groups' ) ) {
+		wp_cache_add_global_groups( array( 'bp' ) );
+	}
+}
+add_action( 'bp_loaded', 'bp_core_add_global_group' );
+
+/**
+ * Clear all cached objects for a user, or those that a user is part of.
+ */
+function bp_core_clear_user_object_cache( $user_id ) {
+	wp_cache_delete( 'bp_user_' . $user_id, 'bp' );
+}
+
+/**
+ * Clear member count caches and transients.
+ */
+function bp_core_clear_member_count_caches() {
+	wp_cache_delete( 'bp_total_member_count', 'bp' );
+	delete_transient( 'bp_active_member_count' );
+}
+add_action( 'bp_core_activated_user',         'bp_core_clear_member_count_caches' );
+add_action( 'bp_core_process_spammer_status', 'bp_core_clear_member_count_caches' );
+add_action( 'bp_core_deleted_account',        'bp_core_clear_member_count_caches' );
+add_action( 'bp_first_activity_for_member',   'bp_core_clear_member_count_caches' );
+add_action( 'deleted_user',                   'bp_core_clear_member_count_caches' );
+
+/**
+ * Update the metadata cache for the specified objects.
+ *
+ * Based on WordPress's {@link update_meta_cache()}, this function primes the
+ * cache with metadata related to a set of objects. This is typically done when
+ * querying for a loop of objects; pre-fetching metadata for each queried
+ * object can lead to dramatic performance improvements when using metadata
+ * in the context of template loops.
+ *
+ * @since BuddyPress (1.6.0)
+ *
+ * @global $wpdb WordPress database object for queries..
+ *
+ * @param array $args {
+ *     Array of arguments.
+ *     @type array|string $object_ids List of object IDs to fetch metadata for.
+ *           Accepts an array or a comma-separated list of numeric IDs.
+ *     @type string $object_type The type of object, eg 'groups' or 'activity'.
+ *     @type string $meta_table The name of the metadata table being queried.
+ *     @type string $object_column Optional. The name of the database column
+ *           where IDs (those provided by $object_ids) are found. Eg, 'group_id'
+ *           for the groups metadata tables. Default: $object_type . '_id'.
+ *     @type string $cache_key_prefix Optional. The prefix to use when creating
+ *           cache key names. Default: the value of $meta_table.
+ * }
+ * @return array|bool Metadata cache for the specified objects, or false on failure.
+ */
+function bp_update_meta_cache( $args = array() ) {
+	global $wpdb;
+
+	$defaults = array(
+		'object_ids' 	   => array(), // Comma-separated list or array of item ids
+		'object_type' 	   => '',      // Canonical component id: groups, members, etc
+		'meta_table' 	   => '',      // Name of the table containing the metadata
+		'object_column'    => '',      // DB column for the object ids (group_id, etc)
+		'cache_key_prefix' => ''       // Prefix to use when creating cache key names. Eg
+					       //    'bp_groups_groupmeta'
+	);
+	$r = wp_parse_args( $args, $defaults );
+	extract( $r );
+
+	if ( empty( $object_ids ) || empty( $object_type ) || empty( $meta_table ) ) {
+		return false;
+	}
+
+	if ( empty( $cache_key_prefix ) ) {
+		$cache_key_prefix = $meta_table;
+	}
+
+	if ( empty( $object_column ) ) {
+		$object_column = $object_type . '_id';
+	}
+
+	$object_ids = wp_parse_id_list( $object_ids );
+
+	$cache = array();
+
+	// Get meta info
+	$id_list   = join( ',', $object_ids );
+	$meta_list = $wpdb->get_results( $wpdb->prepare( "SELECT {$object_column}, meta_key, meta_value FROM {$meta_table} WHERE {$object_column} IN ($id_list)", $object_type ), ARRAY_A );
+
+	if ( !empty( $meta_list ) ) {
+		foreach ( $meta_list as $metarow ) {
+			$mpid = intval( $metarow[$object_column] );
+			$mkey = $metarow['meta_key'];
+			$mval = $metarow['meta_value'];
+
+			// Force subkeys to be array type:
+			if ( !isset( $cache[$mpid] ) || !is_array( $cache[$mpid] ) )
+				$cache[$mpid] = array();
+			if ( !isset( $cache[$mpid][$mkey] ) || !is_array( $cache[$mpid][$mkey] ) )
+				$cache[$mpid][$mkey] = array();
+
+			// Add a value to the current pid/key:
+			$cache[$mpid][$mkey][] = $mval;
+		}
+	}
+
+	foreach ( $object_ids as $id ) {
+		if ( ! isset($cache[$id]) )
+			$cache[$id] = array();
+
+		foreach( $cache[$id] as $meta_key => $meta_value ) {
+			wp_cache_set( $cache_key_prefix . '_' . $id . '_' . $meta_key, $meta_value, 'bp' );
+		}
+	}
+
+	return $cache;
+}
Index: /tags/1.9/bp-core/bp-core-caps.php
===================================================================
--- /tags/1.9/bp-core/bp-core-caps.php	(revision 7684)
+++ /tags/1.9/bp-core/bp-core-caps.php	(revision 7684)
@@ -0,0 +1,295 @@
+<?php
+
+/**
+ * BuddyPress Capabilites.
+ *
+ * @package BuddyPress
+ * @subpackage Capabilities
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/**
+ * Add capabilities to WordPress user roles.
+ *
+ * This is called on plugin activation.
+ *
+ * @since BuddyPress (1.6.0)
+ *
+ * @uses get_role() To get the administrator, default and moderator roles.
+ * @uses WP_Role::add_cap() To add various capabilities.
+ * @uses do_action() Calls 'bp_add_caps'.
+ */
+function bp_add_caps() {
+	global $wp_roles;
+
+	// Load roles if not set
+	if ( ! isset( $wp_roles ) )
+		$wp_roles = new WP_Roles();
+
+	// Loop through available roles and add them
+	foreach( $wp_roles->role_objects as $role ) {
+		foreach ( bp_get_caps_for_role( $role->name ) as $cap ) {
+			$role->add_cap( $cap );
+		}
+	}
+
+	do_action( 'bp_add_caps' );
+}
+
+/**
+ * Remove capabilities from WordPress user roles.
+ *
+ * This is called on plugin deactivation.
+ *
+ * @since BuddyPress (1.6.0)
+ *
+ * @uses get_role() To get the administrator and default roles.
+ * @uses WP_Role::remove_cap() To remove various capabilities.
+ * @uses do_action() Calls 'bp_remove_caps'.
+ */
+function bp_remove_caps() {
+	global $wp_roles;
+
+	// Load roles if not set
+	if ( ! isset( $wp_roles ) )
+		$wp_roles = new WP_Roles();
+
+	// Loop through available roles and remove them
+	foreach( $wp_roles->role_objects as $role ) {
+		foreach ( bp_get_caps_for_role( $role->name ) as $cap ) {
+			$role->remove_cap( $cap );
+		}
+	}
+
+	do_action( 'bp_remove_caps' );
+}
+
+/**
+ * Map community caps to built in WordPress caps.
+ *
+ * @since BuddyPress (1.6.0)
+ *
+ * @see WP_User::has_cap() for description of the arguments passed to the
+ *      'map_meta_cap' filter.
+ * @uses get_post() To get the post.
+ * @uses get_post_type_object() To get the post type object.
+ * @uses apply_filters() Calls 'bp_map_meta_caps' with caps, cap, user ID and
+ *       args.
+ *
+ * @param array $caps See {@link WP_User::has_cap()}.
+ * @param string $cap See {@link WP_User::has_cap()}.
+ * @param int $user_id See {@link WP_User::has_cap()}.
+ * @param mixed $args See {@link WP_User::has_cap()}.
+ * @return array Actual capabilities for meta capability. See {@link WP_User::has_cap()}.
+ */
+function bp_map_meta_caps( $caps, $cap, $user_id, $args ) {
+	return apply_filters( 'bp_map_meta_caps', $caps, $cap, $user_id, $args );
+}
+
+/**
+ * Return community capabilities.
+ *
+ * @since BuddyPress (1.6.0)
+ *
+ * @uses apply_filters() Calls 'bp_get_community_caps' with the capabilities.
+ *
+ * @return array Community capabilities.
+ */
+function bp_get_community_caps() {
+
+	// Forum meta caps
+	$caps = array();
+
+	return apply_filters( 'bp_get_community_caps', $caps );
+}
+
+/**
+ * Return an array of capabilities based on the role that is being requested.
+ *
+ * @since BuddyPress (1.6.0)
+ *
+ * @uses apply_filters() Allow return value to be filtered.
+ *
+ * @param string $role The role for which you're loading caps.
+ * @return array Capabilities for $role.
+ */
+function bp_get_caps_for_role( $role = '' ) {
+
+	// Which role are we looking for?
+	switch ( $role ) {
+
+		// Administrator
+		case 'administrator' :
+			$caps = array(
+				// Misc
+				'bp_moderate',
+			);
+
+			break;
+
+		case 'editor'          :
+		case 'author'          :
+		case 'contributor'     :
+		case 'subscriber'      :
+		default                :
+			$caps = array();
+			break;
+	}
+
+	return apply_filters( 'bp_get_caps_for_role', $caps, $role );
+}
+
+/**
+ * Set a default role for the current user.
+ *
+ * Give a user the default role when creating content on a site they do not
+ * already have a role or capability on.
+ *
+ * @since BuddyPress (1.6.0)
+ *
+ * @global BuddyPress $bp Global BuddyPress settings object.
+ *
+ * @uses is_multisite()
+ * @uses bp_allow_global_access()
+ * @uses bp_is_user_inactive()
+ * @uses is_user_logged_in()
+ * @uses current_user_can()
+ * @uses WP_User::set_role()
+ */
+function bp_set_current_user_default_role() {
+
+	// Bail if not multisite or not root blog
+	if ( ! is_multisite() || ! bp_is_root_blog() )
+		return;
+
+	// Bail if user is not logged in or already a member
+	if ( ! is_user_logged_in() || is_user_member_of_blog() )
+		return;
+
+	// Bail if user is not active
+	if ( bp_is_user_inactive() )
+		return;
+
+	// Set the current users default role
+	buddypress()->current_user->set_role( bp_get_option( 'default_role', 'subscriber' ) );
+}
+
+/**
+ * Check whether the current user has a given capability.
+ *
+ * Can be passed blog ID, or will use the root blog by default.
+ *
+ * @since BuddyPress (1.6.0)
+ *
+ * @param string $capability Capability or role name.
+ * @param int $blog_id Optional. Blog ID. Defaults to the BP root blog.
+ * @return bool True if the user has the cap for the given blog.
+ */
+function bp_current_user_can( $capability, $blog_id = 0 ) {
+
+	// Use root blog if no ID passed
+	if ( empty( $blog_id ) )
+		$blog_id = bp_get_root_blog_id();
+
+	$retval = current_user_can_for_blog( $blog_id, $capability );
+
+	return (bool) apply_filters( 'bp_current_user_can', $retval, $capability, $blog_id );
+}
+
+/**
+ * Temporary implementation of 'bp_moderate' cap.
+ *
+ * In BuddyPress 1.6, the 'bp_moderate' cap was introduced. In order to
+ * enforce that bp_current_user_can( 'bp_moderate' ) always returns true for
+ * Administrators, we must manually add the 'bp_moderate' cap to the list of
+ * user caps for Admins.
+ *
+ * Note that this level of enforcement is only necessary in the case of
+ * non-Multisite. This is because WordPress automatically assigns every
+ * capability - and thus 'bp_moderate' - to Super Admins on a Multisite
+ * installation. See {@link WP_User::has_cap()}.
+ *
+ * This implementation of 'bp_moderate' is temporary, until BuddyPress properly
+ * matches caps to roles and stores them in the database. Plugin authors: Do
+ * not use this function.
+ *
+ * @access private
+ * @since BuddyPress (1.6.0)
+ *
+ * @see WP_User::has_cap()
+ *
+ * @param array $allcaps The caps that WP associates with the given role.
+ * @param array $caps The caps being tested for in WP_User::has_cap().
+ * @param array $args Miscellaneous arguments passed to the user_has_cap filter.
+ * @return array $allcaps The user's cap list, with 'bp_moderate' appended, if relevant.
+ */
+function _bp_enforce_bp_moderate_cap_for_admins( $caps = array(), $cap = '', $user_id = 0, $args = array() ) {
+
+	// Bail if not checking the 'bp_moderate' cap
+	if ( 'bp_moderate' !== $cap )
+		return $caps;
+
+	// Bail if BuddyPress is not network activated
+	if ( bp_is_network_activated() )
+		return $caps;
+
+	// Never trust inactive users
+	if ( bp_is_user_inactive( $user_id ) )
+		return $caps;
+
+	// Only users that can 'manage_options' on this site can 'bp_moderate'
+	return array( 'manage_options' );
+}
+add_filter( 'map_meta_cap', '_bp_enforce_bp_moderate_cap_for_admins', 10, 4 );
+
+/** Deprecated ****************************************************************/
+
+/**
+ * Adds BuddyPress-specific user roles.
+ *
+ * This is called on plugin activation.
+ *
+ * @since BuddyPress (1.6.0)
+ * @deprecated 1.7.0
+ */
+function bp_add_roles() {
+	_doing_it_wrong( 'bp_add_roles', __( 'Special community roles no longer exist. Use mapped capabilities instead', 'buddypress' ), '1.7' );
+}
+
+/**
+ * Removes BuddyPress-specific user roles.
+ *
+ * This is called on plugin deactivation.
+ *
+ * @since BuddyPress (1.6.0)
+ * @deprecated 1.7.0
+ */
+function bp_remove_roles() {
+	_doing_it_wrong( 'bp_remove_roles', __( 'Special community roles no longer exist. Use mapped capabilities instead', 'buddypress' ), '1.7' );
+}
+
+
+/**
+ * The participant role for registered users without roles.
+ *
+ * This is primarily for multisite compatibility when users without roles on
+ * sites that have global communities enabled.
+ *
+ * @since BuddyPress (1.6)
+ * @deprecated 1.7.0
+ */
+function bp_get_participant_role() {
+	_doing_it_wrong( 'bp_get_participant_role', __( 'Special community roles no longer exist. Use mapped capabilities instead', 'buddypress' ), '1.7' );
+}
+
+/**
+ * The moderator role for BuddyPress users.
+ *
+ * @since BuddyPress (1.6.0)
+ * @deprecated 1.7.0
+ */
+function bp_get_moderator_role() {
+	_doing_it_wrong( 'bp_get_moderator_role', __( 'Special community roles no longer exist. Use mapped capabilities instead', 'buddypress' ), '1.7' );
+}
Index: /tags/1.9/bp-core/bp-core-catchuri.php
===================================================================
--- /tags/1.9/bp-core/bp-core-catchuri.php	(revision 7684)
+++ /tags/1.9/bp-core/bp-core-catchuri.php	(revision 7684)
@@ -0,0 +1,785 @@
+<?php
+
+/**
+ * BuddyPress URI catcher.
+ *
+ * Functions for parsing the URI and determining which BuddyPress template file
+ * to use on-screen.
+ *
+ * @package BuddyPress
+ * @subpackage Core
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/**
+ * Analyze the URI and break it down into BuddyPress-usable chunks.
+ *
+ * BuddyPress can use complete custom friendly URIs without the user having to
+ * add new rewrite rules. Custom components are able to use their own custom
+ * URI structures with very little work.
+ *
+ * The URIs are broken down as follows:
+ *   - http:// domain.com / members / andy / [current_component] / [current_action] / [action_variables] / [action_variables] / ...
+ *   - OUTSIDE ROOT: http:// domain.com / sites / buddypress / members / andy / [current_component] / [current_action] / [action_variables] / [action_variables] / ...
+ *
+ *	Example:
+ *    - http://domain.com/members/andy/profile/edit/group/5/
+ *    - $bp->current_component: string 'xprofile'
+ *    - $bp->current_action: string 'edit'
+ *    - $bp->action_variables: array ['group', 5]
+ *
+ * @since BuddyPress (1.0.0)
+ */
+function bp_core_set_uri_globals() {
+	global $bp, $current_blog, $wp_rewrite;
+
+	// Don't catch URIs on non-root blogs unless multiblog mode is on
+	if ( !bp_is_root_blog() && !bp_is_multiblog_mode() )
+		return false;
+
+	// Define local variables
+	$root_profile = $match   = false;
+	$key_slugs    = $matches = $uri_chunks = array();
+
+	// Fetch all the WP page names for each component
+	if ( empty( $bp->pages ) )
+		$bp->pages = bp_core_get_directory_pages();
+
+	// Ajax or not?
+	if ( defined( 'DOING_AJAX' ) && DOING_AJAX || strpos( $_SERVER['REQUEST_URI'], 'wp-load.php' ) )
+		$path = bp_core_referrer();
+	else
+		$path = esc_url( $_SERVER['REQUEST_URI'] );
+
+	// Filter the path
+	$path = apply_filters( 'bp_uri', $path );
+
+	// Take GET variables off the URL to avoid problems
+	$path = strtok( $path, '?' );
+
+	// Fetch current URI and explode each part separated by '/' into an array
+	$bp_uri = explode( '/', $path );
+
+	// Loop and remove empties
+	foreach ( (array) $bp_uri as $key => $uri_chunk ) {
+		if ( empty( $bp_uri[$key] ) ) {
+			unset( $bp_uri[$key] );
+		}
+	}
+
+	// If running off blog other than root, any subdirectory names must be
+	// removed from $bp_uri. This includes two cases:
+	//
+	//    1. when WP is installed in a subdirectory,
+	//    2. when BP is running on secondary blog of a subdirectory
+	//       multisite installation. Phew!
+	if ( is_multisite() && !is_subdomain_install() && ( bp_is_multiblog_mode() || 1 != bp_get_root_blog_id() ) ) {
+
+		// Blow chunks
+		$chunks = explode( '/', $current_blog->path );
+
+		// If chunks exist...
+		if ( !empty( $chunks ) ) {
+
+			// ...loop through them...
+			foreach( $chunks as $key => $chunk ) {
+				$bkey = array_search( $chunk, $bp_uri );
+
+				// ...and unset offending keys
+				if ( false !== $bkey ) {
+					unset( $bp_uri[$bkey] );
+				}
+
+				$bp_uri = array_values( $bp_uri );
+			}
+		}
+	}
+
+	// Get site path items
+	$paths = explode( '/', bp_core_get_site_path() );
+
+	// Take empties off the end of path
+	if ( empty( $paths[count( $paths ) - 1] ) )
+		array_pop( $paths );
+
+	// Take empties off the start of path
+	if ( empty( $paths[0] ) )
+		array_shift( $paths );
+
+	// Reset indexes
+	$bp_uri = array_values( $bp_uri );
+	$paths  = array_values( $paths );
+
+	// Unset URI indices if they intersect with the paths
+	foreach ( (array) $bp_uri as $key => $uri_chunk ) {
+		if ( isset( $paths[$key] ) && $uri_chunk == $paths[$key] ) {
+			unset( $bp_uri[$key] );
+		}
+	}
+
+	// Reset the keys by merging with an empty array
+	$bp_uri = array_merge( array(), $bp_uri );
+
+	// If a component is set to the front page, force its name into $bp_uri
+	// so that $current_component is populated (unless a specific WP post is being requested
+	// via a URL parameter, usually signifying Preview mode)
+	if ( 'page' == get_option( 'show_on_front' ) && get_option( 'page_on_front' ) && empty( $bp_uri ) && empty( $_GET['p'] ) && empty( $_GET['page_id'] ) ) {
+		$post = get_post( get_option( 'page_on_front' ) );
+		if ( !empty( $post ) ) {
+			$bp_uri[0] = $post->post_name;
+		}
+	}
+
+	// Keep the unfiltered URI safe
+	$bp->unfiltered_uri = $bp_uri;
+
+	// Don't use $bp_unfiltered_uri, this is only for backpat with old plugins. Use $bp->unfiltered_uri.
+	$GLOBALS['bp_unfiltered_uri'] = &$bp->unfiltered_uri;
+
+	// Get slugs of pages into array
+	foreach ( (array) $bp->pages as $page_key => $bp_page )
+		$key_slugs[$page_key] = trailingslashit( '/' . $bp_page->slug );
+
+	// Bail if keyslugs are empty, as BP is not setup correct
+	if ( empty( $key_slugs ) )
+		return;
+
+	// Loop through page slugs and look for exact match to path
+	foreach ( $key_slugs as $key => $slug ) {
+		if ( $slug == $path ) {
+			$match      = $bp->pages->{$key};
+			$match->key = $key;
+			$matches[]  = 1;
+			break;
+		}
+	}
+
+	// No exact match, so look for partials
+	if ( empty( $match ) ) {
+
+		// Loop through each page in the $bp->pages global
+		foreach ( (array) $bp->pages as $page_key => $bp_page ) {
+
+			// Look for a match (check members first)
+			if ( in_array( $bp_page->name, (array) $bp_uri ) ) {
+
+				// Match found, now match the slug to make sure.
+				$uri_chunks = explode( '/', $bp_page->slug );
+
+				// Loop through uri_chunks
+				foreach ( (array) $uri_chunks as $key => $uri_chunk ) {
+
+					// Make sure chunk is in the correct position
+					if ( !empty( $bp_uri[$key] ) && ( $bp_uri[$key] == $uri_chunk ) ) {
+						$matches[] = 1;
+
+					// No match
+					} else {
+						$matches[] = 0;
+					}
+				}
+
+				// Have a match
+				if ( !in_array( 0, (array) $matches ) ) {
+					$match      = $bp_page;
+					$match->key = $page_key;
+					break;
+				};
+
+				// Unset matches
+				unset( $matches );
+			}
+
+			// Unset uri chunks
+			unset( $uri_chunks );
+		}
+	}
+
+	// URLs with BP_ENABLE_ROOT_PROFILES enabled won't be caught above
+	if ( empty( $matches ) && bp_core_enable_root_profiles() ) {
+
+		// Switch field based on compat
+		$field = bp_is_username_compatibility_mode() ? 'login' : 'slug';
+
+		// Make sure there's a user corresponding to $bp_uri[0]
+		if ( !empty( $bp->pages->members ) && !empty( $bp_uri[0] ) && $root_profile = get_user_by( $field, $bp_uri[0] ) ) {
+
+			// Force BP to recognize that this is a members page
+			$matches[]  = 1;
+			$match      = $bp->pages->members;
+			$match->key = 'members';
+		}
+	}
+
+	// Search doesn't have an associated page, so we check for it separately
+	if ( !empty( $bp_uri[0] ) && ( bp_get_search_slug() == $bp_uri[0] ) ) {
+		$matches[]   = 1;
+		$match       = new stdClass;
+		$match->key  = 'search';
+		$match->slug = bp_get_search_slug();
+	}
+
+	// This is not a BuddyPress page, so just return.
+	if ( empty( $matches ) )
+		return false;
+
+	$wp_rewrite->use_verbose_page_rules = false;
+
+	// Find the offset. With $root_profile set, we fudge the offset down so later parsing works
+	$slug       = !empty ( $match ) ? explode( '/', $match->slug ) : '';
+	$uri_offset = empty( $root_profile ) ? 0 : -1;
+
+	// Rejig the offset
+	if ( !empty( $slug ) && ( 1 < count( $slug ) ) ) {
+		array_pop( $slug );
+		$uri_offset = count( $slug );
+	}
+
+	// Global the unfiltered offset to use in bp_core_load_template().
+	// To avoid PHP warnings in bp_core_load_template(), it must always be >= 0
+	$bp->unfiltered_uri_offset = $uri_offset >= 0 ? $uri_offset : 0;
+
+	// We have an exact match
+	if ( isset( $match->key ) ) {
+
+		// Set current component to matched key
+		$bp->current_component = $match->key;
+
+		// If members component, do more work to find the actual component
+		if ( 'members' == $match->key ) {
+
+			// Viewing a specific user
+			if ( !empty( $bp_uri[$uri_offset + 1] ) ) {
+
+				// Switch the displayed_user based on compatbility mode
+				if ( bp_is_username_compatibility_mode() ) {
+					$bp->displayed_user->id = (int) bp_core_get_userid( urldecode( $bp_uri[$uri_offset + 1] ) );
+				} else {
+					$bp->displayed_user->id = (int) bp_core_get_userid_from_nicename( urldecode( $bp_uri[$uri_offset + 1] ) );
+				}
+
+				if ( !bp_displayed_user_id() ) {
+
+					// Prevent components from loading their templates
+					$bp->current_component = '';
+
+					bp_do_404();
+					return;
+				}
+
+				// If the displayed user is marked as a spammer, 404 (unless logged-
+				// in user is a super admin)
+				if ( bp_displayed_user_id() && bp_is_user_spammer( bp_displayed_user_id() ) ) {
+					if ( bp_current_user_can( 'bp_moderate' ) ) {
+						bp_core_add_message( __( 'This user has been marked as a spammer. Only site admins can view this profile.', 'buddypress' ), 'warning' );
+					} else {
+						bp_do_404();
+						return;
+					}
+				}
+
+				// Bump the offset
+				if ( isset( $bp_uri[$uri_offset + 2] ) ) {
+					$bp_uri                = array_merge( array(), array_slice( $bp_uri, $uri_offset + 2 ) );
+					$bp->current_component = $bp_uri[0];
+
+				// No component, so default will be picked later
+				} else {
+					$bp_uri                = array_merge( array(), array_slice( $bp_uri, $uri_offset + 2 ) );
+					$bp->current_component = '';
+				}
+
+				// Reset the offset
+				$uri_offset = 0;
+			}
+		}
+	}
+
+	// Set the current action
+	$bp->current_action = isset( $bp_uri[$uri_offset + 1] ) ? $bp_uri[$uri_offset + 1] : '';
+
+	// Slice the rest of the $bp_uri array and reset offset
+	$bp_uri      = array_slice( $bp_uri, $uri_offset + 2 );
+	$uri_offset  = 0;
+
+	// Set the entire URI as the action variables, we will unset the current_component and action in a second
+	$bp->action_variables = $bp_uri;
+
+	// Reset the keys by merging with an empty array
+	$bp->action_variables = array_merge( array(), $bp->action_variables );
+}
+
+/**
+ * Are root profiles enabled and allowed?
+ *
+ * @since BuddyPress (1.6.0)
+ *
+ * @return bool True if yes, false if no.
+ */
+function bp_core_enable_root_profiles() {
+
+	$retval = false;
+
+	if ( defined( 'BP_ENABLE_ROOT_PROFILES' ) && ( true == BP_ENABLE_ROOT_PROFILES ) )
+		$retval = true;
+
+	return apply_filters( 'bp_core_enable_root_profiles', $retval );
+}
+
+/**
+ * Load a specific template file with fallback support.
+ *
+ * Example:
+ *   bp_core_load_template( 'members/index' );
+ * Loads:
+ *   wp-content/themes/[activated_theme]/members/index.php
+ *
+ * @param array $templates Array of templates to attempt to load.
+ * @return bool|null Returns false on failure.
+ */
+function bp_core_load_template( $templates ) {
+	global $post, $bp, $wp_query, $wpdb;
+
+	// Determine if the root object WP page exists for this request
+	// note: get_page_by_path() breaks non-root pages
+	if ( !empty( $bp->unfiltered_uri_offset ) ) {
+		if ( !$page_exists = $wpdb->get_var( $wpdb->prepare( "SELECT ID FROM {$wpdb->posts} WHERE post_name = %s", $bp->unfiltered_uri[$bp->unfiltered_uri_offset] ) ) ) {
+			return false;
+		}
+	}
+
+	// Set the root object as the current wp_query-ied item
+	$object_id = 0;
+	foreach ( (array) $bp->pages as $page ) {
+		if ( $page->name == $bp->unfiltered_uri[$bp->unfiltered_uri_offset] ) {
+			$object_id = $page->id;
+		}
+	}
+
+	// Make the queried/post object an actual valid page
+	if ( !empty( $object_id ) ) {
+		$wp_query->queried_object    = get_post( $object_id );
+		$wp_query->queried_object_id = $object_id;
+		$post                        = $wp_query->queried_object;
+	}
+
+	// Fetch each template and add the php suffix
+	$filtered_templates = array();
+	foreach ( (array) $templates as $template ) {
+		$filtered_templates[] = $template . '.php';
+	}
+
+	// Filter the template locations so that plugins can alter where they are located
+	$located_template = apply_filters( 'bp_located_template', locate_template( (array) $filtered_templates, false ), $filtered_templates );
+	if ( !empty( $located_template ) ) {
+
+		// Template was located, lets set this as a valid page and not a 404.
+		status_header( 200 );
+		$wp_query->is_page     = true;
+		$wp_query->is_singular = true;
+		$wp_query->is_404      = false;
+
+		do_action( 'bp_core_pre_load_template', $located_template );
+
+		load_template( apply_filters( 'bp_load_template', $located_template ) );
+
+		do_action( 'bp_core_post_load_template', $located_template );
+
+		// Kill any other output after this.
+		exit();
+
+	// No template found, so setup theme compatability
+	// @todo Some other 404 handling if theme compat doesn't kick in
+	} else {
+
+		// We know where we are, so reset important $wp_query bits here early.
+		// The rest will be done by bp_theme_compat_reset_post() later.
+		if ( is_buddypress() ) {
+			status_header( 200 );
+			$wp_query->is_page     = true;
+			$wp_query->is_singular = true;
+			$wp_query->is_404      = false;
+		}
+
+		do_action( 'bp_setup_theme_compat' );
+	}
+}
+
+/**
+ * Redirect away from /profile URIs if XProfile is not enabled.
+ */
+function bp_core_catch_profile_uri() {
+	if ( !bp_is_active( 'xprofile' ) ) {
+		bp_core_load_template( apply_filters( 'bp_core_template_display_profile', 'members/single/home' ) );
+	}
+}
+
+/**
+ * Catch unauthorized access to certain BuddyPress pages and redirect accordingly.
+ *
+ * @since BuddyPress (1.5.0)
+ */
+function bp_core_catch_no_access() {
+	global $bp, $wp_query;
+
+	// If coming from bp_core_redirect() and $bp_no_status_set is true,
+	// we are redirecting to an accessible page so skip this check.
+	if ( !empty( $bp->no_status_set ) )
+		return false;
+
+	if ( !isset( $wp_query->queried_object ) && !bp_is_blog_page() ) {
+		bp_do_404();
+	}
+}
+add_action( 'bp_template_redirect', 'bp_core_catch_no_access', 1 );
+
+/**
+ * Redirect a user to log in for BP pages that require access control.
+ *
+ * Add an error message (if one is provided).
+ *
+ * If authenticated, redirects user back to requested content by default.
+ *
+ * @since BuddyPress (1.5.0)
+ *
+ * @param array $args {
+ *     @type int $mode Specifies the destintation of the redirect. 1 will
+ *           direct to the root domain (home page), which assumes you have a
+ *           log-in form there; 2 directs to wp-login.php. Default: 2.
+ *     @type string $redirect The URL the user will be redirected to after
+ *           successfully logging in. Default: the URL originally requested.
+ *     @type string $root The root URL of the site, used in case of error or
+ *           mode 1 redirects. Default: the value of {@link bp_get_root_domain()}.
+ *     @type string $message An error message to display to the user on the
+ *           log-in page. Default: "You must log in to access the page you
+ *           requested."
+ * }
+ */
+function bp_core_no_access( $args = '' ) {
+
+ 	// Build the redirect URL
+ 	$redirect_url  = is_ssl() ? 'https://' : 'http://';
+ 	$redirect_url .= $_SERVER['HTTP_HOST'];
+ 	$redirect_url .= $_SERVER['REQUEST_URI'];
+
+	$defaults = array(
+		'mode'     => 2,                    // 1 = $root, 2 = wp-login.php
+		'redirect' => $redirect_url,        // the URL you get redirected to when a user successfully logs in
+		'root'     => bp_get_root_domain(),	// the landing page you get redirected to when a user doesn't have access
+		'message'  => __( 'You must log in to access the page you requested.', 'buddypress' )
+	);
+
+	$r = wp_parse_args( $args, $defaults );
+	$r = apply_filters( 'bp_core_no_access', $r );
+	extract( $r, EXTR_SKIP );
+
+	/**
+	 * @ignore Ignore these filters and use 'bp_core_no_access' above
+	 */
+	$mode     = apply_filters( 'bp_no_access_mode',     $mode,     $root,     $redirect, $message );
+	$redirect = apply_filters( 'bp_no_access_redirect', $redirect, $root,     $message,  $mode    );
+	$root     = apply_filters( 'bp_no_access_root',     $root,     $redirect, $message,  $mode    );
+	$message  = apply_filters( 'bp_no_access_message',  $message,  $root,     $redirect, $mode    );
+	$root     = trailingslashit( $root );
+
+	switch ( $mode ) {
+
+		// Option to redirect to wp-login.php
+		// Error message is displayed with bp_core_no_access_wp_login_error()
+		case 2 :
+			if ( !empty( $redirect ) ) {
+				bp_core_redirect( add_query_arg( array( 'action' => 'bpnoaccess' ), wp_login_url( $redirect ) ) );
+			} else {
+				bp_core_redirect( $root );
+			}
+
+			break;
+
+		// Redirect to root with "redirect_to" parameter
+		// Error message is displayed with bp_core_add_message()
+		case 1 :
+		default :
+
+			$url = $root;
+			if ( !empty( $redirect ) )
+				$url = add_query_arg( 'redirect_to', urlencode( $redirect ), $root );
+
+			if ( !empty( $message ) ) {
+				bp_core_add_message( $message, 'error' );
+			}
+
+			bp_core_redirect( $url );
+
+			break;
+	}
+}
+
+/**
+ * Add an error message to wp-login.php.
+ *
+ * Hooks into the "bpnoaccess" action defined in bp_core_no_access().
+ *
+ * @since BuddyPress (1.5.0)
+ *
+ * @global $error Error message to pass to wp-login.php
+ */
+function bp_core_no_access_wp_login_error() {
+	global $error;
+
+	$error = apply_filters( 'bp_wp_login_error', __( 'You must log in to access the page you requested.', 'buddypress' ), $_REQUEST['redirect_to'] );
+
+	// shake shake shake!
+	add_action( 'login_head', 'wp_shake_js', 12 );
+}
+add_action( 'login_form_bpnoaccess', 'bp_core_no_access_wp_login_error' );
+
+/**
+ * Canonicalize BuddyPress URLs.
+ *
+ * This function ensures that requests for BuddyPress content are always
+ * redirected to their canonical versions. Canonical versions are always
+ * trailingslashed, and are typically the most general possible versions of the
+ * URL - eg, example.com/groups/mygroup/ instead of
+ * example.com/groups/mygroup/home/.
+ *
+ * @since BuddyPress (1.6.0)
+ *
+ * @see BP_Members_Component::setup_globals() where
+ *      $bp->canonical_stack['base_url'] and ['component'] may be set.
+ * @see bp_core_new_nav_item() where $bp->canonical_stack['action'] may be set.
+ * @uses bp_get_canonical_url()
+ * @uses bp_get_requested_url()
+ */
+function bp_redirect_canonical() {
+	global $bp;
+
+	if ( !bp_is_blog_page() && apply_filters( 'bp_do_redirect_canonical', true ) ) {
+		// If this is a POST request, don't do a canonical redirect.
+		// This is for backward compatibility with plugins that submit form requests to
+		// non-canonical URLs. Plugin authors should do their best to use canonical URLs in
+		// their form actions.
+		if ( !empty( $_POST ) ) {
+			return;
+		}
+
+		// build the URL in the address bar
+		$requested_url  = bp_get_requested_url();
+
+		// Stash query args
+		$url_stack      = explode( '?', $requested_url );
+		$req_url_clean  = $url_stack[0];
+		$query_args     = isset( $url_stack[1] ) ? $url_stack[1] : '';
+
+		$canonical_url  = bp_get_canonical_url();
+
+		// Only redirect if we've assembled a URL different from the request
+		if ( $canonical_url !== $req_url_clean ) {
+
+			// Template messages have been deleted from the cookie by this point, so
+			// they must be readded before redirecting
+			if ( isset( $bp->template_message ) ) {
+				$message      = stripslashes( $bp->template_message );
+				$message_type = isset( $bp->template_message_type ) ? $bp->template_message_type : 'success';
+
+				bp_core_add_message( $message, $message_type );
+			}
+
+			if ( !empty( $query_args ) ) {
+				$canonical_url .= '?' . $query_args;
+			}
+
+			bp_core_redirect( $canonical_url, 301 );
+		}
+	}
+}
+
+/**
+ * Output rel=canonical header tag for BuddyPress content.
+ *
+ * @since BuddyPress (1.6.0)
+ */
+function bp_rel_canonical() {
+	$canonical_url = bp_get_canonical_url();
+
+	// Output rel=canonical tag
+	echo "<link rel='canonical' href='" . esc_attr( $canonical_url ) . "' />\n";
+}
+
+/**
+ * Get the canonical URL of the current page.
+ *
+ * @since BuddyPress (1.6.0)
+ *
+ * @uses apply_filters() Filter bp_get_canonical_url to modify return value.
+ *
+ * @param array $args {
+ *     Optional array of arguments.
+ *     @type bool $include_query_args Whether to include current URL arguments
+ *           in the canonical URL returned from the function.
+ * }
+ * @return string Canonical URL for the current page.
+ */
+function bp_get_canonical_url( $args = array() ) {
+	global $bp;
+
+	// For non-BP content, return the requested url, and let WP do the work
+	if ( bp_is_blog_page() ) {
+		return bp_get_requested_url();
+	}
+
+	$defaults = array(
+		'include_query_args' => false // Include URL arguments, eg ?foo=bar&foo2=bar2
+	);
+	$r = wp_parse_args( $args, $defaults );
+	extract( $r );
+
+	// Special case: when a BuddyPress directory (eg example.com/members)
+	// is set to be the front page, ensure that the current canonical URL
+	// is the home page URL.
+	if ( 'page' == get_option( 'show_on_front' ) && $page_on_front = (int) get_option( 'page_on_front' ) ) {
+		$front_page_component = array_search( $page_on_front, bp_core_get_directory_page_ids() );
+
+		// If requesting the front page component directory, canonical
+		// URL is the front page. We detect whether we're detecting a
+		// component *directory* by checking that bp_current_action()
+		// is empty - ie, this not a single item or a feed
+		if ( false !== $front_page_component && bp_is_current_component( $front_page_component ) && ! bp_current_action() ) {
+			$bp->canonical_stack['canonical_url'] = trailingslashit( bp_get_root_domain() );
+
+		// Except when the front page is set to the registration page
+		// and the current user is logged in. In this case we send to
+		// the members directory to avoid redirect loops
+		} else if ( bp_is_register_page() && 'register' == $front_page_component && is_user_logged_in() ) {
+			$bp->canonical_stack['canonical_url'] = apply_filters( 'bp_loggedin_register_page_redirect_to', trailingslashit( bp_get_root_domain() . '/' . bp_get_members_root_slug() ) );
+		}
+	}
+
+	if ( empty( $bp->canonical_stack['canonical_url'] ) ) {
+		// Build the URL in the address bar
+		$requested_url  = bp_get_requested_url();
+
+		// Stash query args
+		$url_stack      = explode( '?', $requested_url );
+
+		// Build the canonical URL out of the redirect stack
+		if ( isset( $bp->canonical_stack['base_url'] ) )
+			$url_stack[0] = $bp->canonical_stack['base_url'];
+
+		if ( isset( $bp->canonical_stack['component'] ) )
+			$url_stack[0] = trailingslashit( $url_stack[0] . $bp->canonical_stack['component'] );
+
+		if ( isset( $bp->canonical_stack['action'] ) )
+			$url_stack[0] = trailingslashit( $url_stack[0] . $bp->canonical_stack['action'] );
+
+		if ( !empty( $bp->canonical_stack['action_variables'] ) ) {
+			foreach( (array) $bp->canonical_stack['action_variables'] as $av ) {
+				$url_stack[0] = trailingslashit( $url_stack[0] . $av );
+			}
+		}
+
+		// Add trailing slash
+		$url_stack[0] = trailingslashit( $url_stack[0] );
+
+		// Stash in the $bp global
+		$bp->canonical_stack['canonical_url'] = implode( '?', $url_stack );
+	}
+
+	$canonical_url = $bp->canonical_stack['canonical_url'];
+
+	if ( !$include_query_args ) {
+		$canonical_url = array_reverse( explode( '?', $canonical_url ) );
+		$canonical_url = array_pop( $canonical_url );
+	}
+
+	return apply_filters( 'bp_get_canonical_url', $canonical_url, $args );
+}
+
+/**
+ * Return the URL as requested on the current page load by the user agent.
+ *
+ * @since BuddyPress (1.6.0)
+ *
+ * @return string Requested URL string.
+ */
+function bp_get_requested_url() {
+	global $bp;
+
+	if ( empty( $bp->canonical_stack['requested_url'] ) ) {
+		$bp->canonical_stack['requested_url']  = is_ssl() ? 'https://' : 'http://';
+		$bp->canonical_stack['requested_url'] .= $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
+	}
+
+	return apply_filters( 'bp_get_requested_url', $bp->canonical_stack['requested_url'] );
+}
+
+/**
+ * Remove WP's canonical redirect when we are trying to load BP-specific content.
+ *
+ * Avoids issues with WordPress thinking that a BuddyPress URL might actually
+ * be a blog post or page.
+ *
+ * This function should be considered temporary, and may be removed without
+ * notice in future versions of BuddyPress.
+ *
+ * @since BuddyPress (1.6.0)
+ *
+ * @uses bp_is_blog_page()
+ */
+function _bp_maybe_remove_redirect_canonical() {
+	if ( ! bp_is_blog_page() )
+		remove_action( 'template_redirect', 'redirect_canonical' );
+}
+add_action( 'bp_init', '_bp_maybe_remove_redirect_canonical' );
+
+/**
+ * Rehook maybe_redirect_404() to run later than the default.
+ *
+ * WordPress's maybe_redirect_404() allows admins on a multisite installation
+ * to define 'NOBLOGREDIRECT', a URL to which 404 requests will be redirected.
+ * maybe_redirect_404() is hooked to template_redirect at priority 10, which
+ * creates a race condition with bp_template_redirect(), our piggyback hook.
+ * Due to a legacy bug in BuddyPress, internal BP content (such as members and
+ * groups) is marked 404 in $wp_query until bp_core_load_template(), when BP
+ * manually overrides the automatic 404. However, the race condition with
+ * maybe_redirect_404() means that this manual un-404-ing doesn't happen in
+ * time, with the results that maybe_redirect_404() thinks that the page is
+ * a legitimate 404, and redirects incorrectly to NOBLOGREDIRECT.
+ *
+ * By switching maybe_redirect_404() to catch at a higher priority, we avoid
+ * the race condition. If bp_core_load_template() runs, it dies before reaching
+ * maybe_redirect_404(). If bp_core_load_template() does not run, it means that
+ * the 404 is legitimate, and maybe_redirect_404() can proceed as expected.
+ *
+ * This function will be removed in a later version of BuddyPress. Plugins
+ * (and plugin authors!) should ignore it.
+ *
+ * @since BuddyPress (1.6.1)
+ *
+ * @link http://buddypress.trac.wordpress.org/ticket/4329
+ * @link http://buddypress.trac.wordpress.org/ticket/4415
+ */
+function _bp_rehook_maybe_redirect_404() {
+	if ( defined( 'NOBLOGREDIRECT' ) ) {
+		remove_action( 'template_redirect', 'maybe_redirect_404' );
+		add_action( 'template_redirect', 'maybe_redirect_404', 100 );
+	}
+}
+add_action( 'template_redirect', '_bp_rehook_maybe_redirect_404', 1 );
+
+/**
+ * Remove WP's rel=canonical HTML tag if we are trying to load BP-specific content.
+ *
+ * This function should be considered temporary, and may be removed without
+ * notice in future versions of BuddyPress.
+ *
+ * @since BuddyPress (1.6.0)
+ */
+function _bp_maybe_remove_rel_canonical() {
+	if ( ! bp_is_blog_page() && ! is_404() ) {
+		remove_action( 'wp_head', 'rel_canonical' );
+		add_action( 'bp_head', 'bp_rel_canonical' );
+	}
+}
+add_action( 'wp_head', '_bp_maybe_remove_rel_canonical', 8 );
Index: /tags/1.9/bp-core/bp-core-classes.php
===================================================================
--- /tags/1.9/bp-core/bp-core-classes.php	(revision 7684)
+++ /tags/1.9/bp-core/bp-core-classes.php	(revision 7684)
@@ -0,0 +1,2223 @@
+<?php
+/**
+ * Core component classes.
+ *
+ * @package BuddyPress
+ * @subpackage Core
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/**
+ * BuddyPress User Query class.
+ *
+ * Used for querying users in a BuddyPress context, in situations where
+ * WP_User_Query won't do the trick: Member directories, the Friends component,
+ * etc.
+ *
+ * @since BuddyPress (1.7.0)
+ *
+ * @param array $query {
+ *     Query arguments. All items are optional.
+ *     @type string $type Determines sort order. Select from 'newest', 'active',
+ *           'online', 'random', 'popular', 'alphabetical'. Default: 'newest'.
+ *     @type int $per_page Number of results to return. Default: 0 (no limit).
+ *     @type int $page Page offset (together with $per_page). Default: 1.
+ *     @type int $user_id ID of a user. If present, and if the friends
+ *           component is activated, results will be limited to the friends of
+ *           that user. Default: 0.
+ *     @type string|bool $search_terms Terms to search by. Search happens
+ *           across xprofile fields. Requires XProfile component.
+ *           Default: false.
+ *     @type array|string|bool $include An array or comma-separated list of
+ *           user IDs to which query should be limited.
+ *           Default: false.
+ *     @type array|string|bool $exclude An array or comma-separated list of
+ *           user IDs that will be excluded from query results. Default: false.
+ *     @type array|string|bool $user_ids An array or comma-separated list of
+ *           IDs corresponding to the users that should be returned. When this
+ *           parameter is passed, it will override all others; BP User objects
+ *           will be constructed using these IDs only. Default: false.
+ *     @type string|bool $meta_key Limit results to users that have usermeta
+ *           associated with this meta_key. Usually used with $meta_value.
+ *           Default: false.
+ *     @type string|bool $meta_value When used with $meta_key, limits results
+ *           to users whose usermeta value associated with $meta_key matches
+ *           $meta_value. Default: false.
+ *     @type bool $populate_extras True if you want to fetch extra metadata
+ *           about returned users, such as total group and friend counts.
+ *     @type string $count_total Determines how BP_User_Query will do a count
+ *           of total users matching the other filter criteria. Default value
+ *           is 'count_query', which does a separate SELECT COUNT query to
+ *           determine the total. 'sql_count_found_rows' uses
+ *           SQL_COUNT_FOUND_ROWS and SELECT FOUND_ROWS(). Pass an empty string
+ *           to skip the total user count query.
+ * }
+ */
+class BP_User_Query {
+
+	/** Variables *************************************************************/
+
+	/**
+	 * Unaltered params as passed to the constructor.
+	 *
+	 * @since BuddyPress (1.8.0)
+	 * @var array
+	 */
+	public $query_vars_raw = array();
+
+	/**
+	 * Array of variables to query with.
+	 *
+	 * @since BuddyPress (1.7.0)
+	 * @var array
+	 */
+	public $query_vars = array();
+
+	/**
+	 * List of found users and their respective data.
+	 *
+	 * @access public To allow components to manipulate them.
+	 * @since BuddyPress (1.7.0)
+	 * @var array
+	 */
+	public $results = array();
+
+	/**
+	 * Total number of found users for the current query.
+	 *
+	 * @access public To allow components to manipulate it.
+	 * @since BuddyPress (1.7.0)
+	 * @var int
+	 */
+	public $total_users = 0;
+
+	/**
+	 * List of found user IDs.
+	 *
+	 * @access public To allow components to manipulate it.
+	 * @since BuddyPress (1.7.0)
+	 * @var array
+	 */
+	public $user_ids = array();
+
+	/**
+	 * SQL clauses for the user ID query.
+	 *
+	 * @access public To allow components to manipulate it.
+	 * @since BuddyPress (1.7.0)
+	 * @var array
+	 */
+	public $uid_clauses = array();
+
+	/**
+	 * SQL database column name to order by.
+	 *
+	 * @since BuddyPress (1.7.0)
+	 * @var string
+	 */
+	public $uid_name = '';
+
+	/**
+	 * Standard response when the query should not return any rows.
+	 *
+	 * @access protected
+	 * @since BuddyPress (1.7.0)
+	 * @var string
+	 */
+	protected $no_results = array( 'join' => '', 'where' => '0 = 1' );
+
+
+	/** Methods ***************************************************************/
+
+	/**
+	 * Constructor.
+	 *
+	 * @since BuddyPress (1.7.0)
+	 *
+	 * @param string|array $query See {@link BP_User_Query}.
+	 */
+	public function __construct( $query = null ) {
+
+		// Store the raw query vars for later access
+		$this->query_vars_raw = $query;
+
+		// Allow extending classes to register action/filter hooks
+		$this->setup_hooks();
+
+		if ( ! empty( $this->query_vars_raw ) ) {
+			$this->query_vars = wp_parse_args( $this->query_vars_raw, array(
+				'type'            => 'newest',
+				'per_page'        => 0,
+				'page'            => 1,
+				'user_id'         => 0,
+				'search_terms'    => false,
+				'include'         => false,
+				'exclude'         => false,
+				'user_ids'        => false,
+				'meta_key'        => false,
+				'meta_value'      => false,
+				'populate_extras' => true,
+				'count_total'     => 'count_query'
+			) );
+
+			// Plugins can use this filter to modify query args
+			// before the query is constructed
+			do_action_ref_array( 'bp_pre_user_query_construct', array( &$this ) );
+
+			// Get user ids
+			// If the user_ids param is present, we skip the query
+			if ( false !== $this->query_vars['user_ids'] ) {
+				$this->user_ids = wp_parse_id_list( $this->query_vars['user_ids'] );
+			} else {
+				$this->prepare_user_ids_query();
+				$this->do_user_ids_query();
+			}
+		}
+
+		// Bail if no user IDs were found
+		if ( empty( $this->user_ids ) ) {
+			return;
+		}
+
+		// Fetch additional data. First, using WP_User_Query
+		$this->do_wp_user_query();
+
+		// Get BuddyPress specific user data
+		$this->populate_extras();
+	}
+
+	/**
+	 * Allow extending classes to set up action/filter hooks.
+	 *
+	 * When extending BP_User_Query, you may need to use some of its
+	 * internal hooks to modify the output. It's not convenient to call
+	 * add_action() or add_filter() in your class constructor, because
+	 * BP_User_Query::__construct() contains a fair amount of logic that
+	 * you may not want to override in your class. Define this method in
+	 * your own class if you need a place where your extending class can
+	 * add its hooks early in the query-building process. See
+	 * {@link BP_Group_Member_Query::setup_hooks()} for an example.
+	 *
+	 * @since BuddyPress (1.8.0)
+	 */
+	public function setup_hooks() {}
+
+	/**
+	 * Prepare the query for user_ids.
+	 *
+	 * @since BuddyPress (1.7.0)
+	 */
+	public function prepare_user_ids_query() {
+		global $wpdb, $bp;
+
+		// Default query variables used here
+		$type         = '';
+		$per_page     = 0;
+		$page         = 1;
+		$user_id      = 0;
+		$include      = false;
+		$search_terms = false;
+		$exclude      = false;
+		$meta_key     = false;
+		$meta_value   = false;
+
+		extract( $this->query_vars );
+
+		// Setup the main SQL query container
+		$sql = array(
+			'select'  => '',
+			'where'   => array(),
+			'orderby' => '',
+			'order'   => '',
+			'limit'   => ''
+		);
+
+		/** TYPE **************************************************************/
+
+		// Determines the sort order, which means it also determines where the
+		// user IDs are drawn from (the SELECT and WHERE statements)
+		switch ( $type ) {
+
+			// 'online' query happens against the last_activity usermeta key
+			// Filter 'bp_user_query_online_interval' to modify the
+			// number of minutes used as an interval
+			case 'online' :
+				$this->uid_name = 'user_id';
+				$sql['select']  = "SELECT DISTINCT u.{$this->uid_name} as id FROM {$wpdb->usermeta} u";
+				$sql['where'][] = $wpdb->prepare( "u.meta_key = %s", bp_get_user_meta_key( 'last_activity' ) );
+				$sql['where'][] = $wpdb->prepare( "u.meta_value >= DATE_SUB( UTC_TIMESTAMP(), INTERVAL %d MINUTE )", apply_filters( 'bp_user_query_online_interval', 15 ) );
+				$sql['orderby'] = "ORDER BY u.meta_value";
+				$sql['order']   = "DESC";
+
+				break;
+
+			// 'active', 'newest', and 'random' queries
+			// all happen against the last_activity usermeta key
+			case 'active' :
+			case 'newest' :
+			case 'random' :
+				$this->uid_name = 'user_id';
+				$sql['select']  = "SELECT DISTINCT u.{$this->uid_name} as id FROM {$wpdb->usermeta} u";
+				$sql['where'][] = $wpdb->prepare( "u.meta_key = %s", bp_get_user_meta_key( 'last_activity' ) );
+
+				if ( 'newest' == $type ) {
+					$sql['orderby'] = "ORDER BY u.user_id";
+					$sql['order'] = "DESC";
+				} else if ( 'random' == $type ) {
+					$sql['orderby'] = "ORDER BY rand()";
+				} else {
+					$sql['orderby'] = "ORDER BY u.meta_value";
+					$sql['order'] = "DESC";
+				}
+
+				break;
+
+			// 'popular' sorts by the 'total_friend_count' usermeta
+			case 'popular' :
+				$this->uid_name = 'user_id';
+				$sql['select']  = "SELECT DISTINCT u.{$this->uid_name} as id FROM {$wpdb->usermeta} u";
+				$sql['where'][] = $wpdb->prepare( "u.meta_key = %s", bp_get_user_meta_key( 'total_friend_count' ) );
+				$sql['orderby'] = "ORDER BY CONVERT(u.meta_value, SIGNED)";
+				$sql['order']   = "DESC";
+
+				break;
+
+			// 'alphabetical' sorts depend on the xprofile setup
+			case 'alphabetical' :
+
+				// We prefer to do alphabetical sorts against the display_name field
+				// of wp_users, because the table is smaller and better indexed. We
+				// can do so if xprofile sync is enabled, or if xprofile is inactive.
+				//
+				// @todo remove need for bp_is_active() check
+				if ( ! bp_disable_profile_sync() || ! bp_is_active( 'xprofile' ) ) {
+					$this->uid_name = 'ID';
+					$sql['select']  = "SELECT DISTINCT u.{$this->uid_name} as id FROM {$wpdb->users} u";
+					$sql['orderby'] = "ORDER BY u.display_name";
+					$sql['order']   = "ASC";
+
+				// When profile sync is disabled, alphabetical sorts must happen against
+				// the xprofile table
+				} else {
+					$fullname_field_id = $wpdb->get_var( $wpdb->prepare( "SELECT id FROM {$bp->profile->table_name_fields} WHERE name = %s", bp_xprofile_fullname_field_name() ) );
+
+					$this->uid_name = 'user_id';
+					$sql['select']  = "SELECT DISTINCT u.{$this->uid_name} as id FROM {$bp->profile->table_name_data} u";
+					$sql['where'][] = "u.field_id = {$fullname_field_id}";
+					$sql['orderby'] = "ORDER BY u.value";
+					$sql['order']   = "ASC";
+				}
+
+				// Alphabetical queries ignore last_activity, while BP uses last_activity
+				// to infer spam/deleted/non-activated users. To ensure that these users
+				// are filtered out, we add an appropriate sub-query.
+				$sql['where'][] = "u.{$this->uid_name} IN ( SELECT ID FROM {$wpdb->users} WHERE " . bp_core_get_status_sql( '' ) . " )";
+
+				break;
+
+			// Any other 'type' falls through
+			default :
+				$this->uid_name = 'ID';
+				$sql['select']  = "SELECT DISTINCT u.{$this->uid_name} as id FROM {$wpdb->users} u";
+
+				// In this case, we assume that a plugin is
+				// handling order, so we leave those clauses
+				// blank
+
+				break;
+		}
+
+		/** WHERE *************************************************************/
+
+		// 'include' - User ids to include in the results
+		$include     = false !== $include ? wp_parse_id_list( $include ) : array();
+		$include_ids = $this->get_include_ids( $include );
+		if ( ! empty( $include_ids ) ) {
+			$include_ids    = implode( ',', wp_parse_id_list( $include_ids ) );
+			$sql['where'][] = "u.{$this->uid_name} IN ({$include_ids})";
+		}
+
+		// 'exclude' - User ids to exclude from the results
+		if ( false !== $exclude ) {
+			$exclude_ids    = implode( ',', wp_parse_id_list( $exclude ) );
+			$sql['where'][] = "u.{$this->uid_name} NOT IN ({$exclude_ids})";
+		}
+
+		// 'user_id' - When a user id is passed, limit to the friends of the user
+		// @todo remove need for bp_is_active() check
+		if ( ! empty( $user_id ) && bp_is_active( 'friends' ) ) {
+			$friend_ids = friends_get_friend_user_ids( $user_id );
+			$friend_ids = implode( ',', wp_parse_id_list( $friend_ids ) );
+
+			if ( ! empty( $friend_ids ) ) {
+				$sql['where'][] = "u.{$this->uid_name} IN ({$friend_ids})";
+
+			// If the user has no friends, the query should always
+			// return no users
+			} else {
+				$sql['where'][] = $this->no_results['where'];
+			}
+		}
+
+		/** Search Terms ******************************************************/
+
+		// 'search_terms' searches the xprofile fields
+		// To avoid global joins, do a separate query
+		// @todo remove need for bp_is_active() check
+		if ( false !== $search_terms && bp_is_active( 'xprofile' ) ) {
+			$search_terms_clean = mysql_real_escape_string( mysql_real_escape_string( $search_terms ) );
+			$search_terms_clean = like_escape( $search_terms_clean );
+			$found_user_ids_query = "SELECT user_id FROM {$bp->profile->table_name_data} WHERE value LIKE '%" . $search_terms_clean . "%'";
+			$found_user_ids = $wpdb->get_col( $found_user_ids_query );
+
+			if ( ! empty( $found_user_ids ) ) {
+				$sql['where'][] = "u.{$this->uid_name} IN (" . implode( ',', wp_parse_id_list( $found_user_ids ) ) . ")";
+			} else {
+				$sql['where'][] = $this->no_results['where'];
+			}
+		}
+
+		// 'meta_key', 'meta_value' allow usermeta search
+		// To avoid global joins, do a separate query
+		if ( false !== $meta_key ) {
+			$meta_sql = $wpdb->prepare( "SELECT user_id FROM {$wpdb->usermeta} WHERE meta_key = %s", $meta_key );
+
+			if ( false !== $meta_value ) {
+				$meta_sql .= $wpdb->prepare( " AND meta_value = %s", $meta_value );
+			}
+
+			$found_user_ids = $wpdb->get_col( $meta_sql );
+
+			if ( ! empty( $found_user_ids ) ) {
+				$sql['where'][] = "u.{$this->uid_name} IN (" . implode( ',', wp_parse_id_list( $found_user_ids ) ) . ")";
+			}
+		}
+
+		// 'per_page', 'page' - handles LIMIT
+		if ( !empty( $per_page ) && !empty( $page ) ) {
+			$sql['limit'] = $wpdb->prepare( "LIMIT %d, %d", intval( ( $page - 1 ) * $per_page ), intval( $per_page ) );
+		} else {
+			$sql['limit'] = '';
+		}
+
+		// Assemble the query chunks
+		$this->uid_clauses['select']  = $sql['select'];
+		$this->uid_clauses['where']   = ! empty( $sql['where'] ) ? 'WHERE ' . implode( ' AND ', $sql['where'] ) : '';
+		$this->uid_clauses['orderby'] = $sql['orderby'];
+		$this->uid_clauses['order']   = $sql['order'];
+		$this->uid_clauses['limit']   = $sql['limit'];
+
+		do_action_ref_array( 'bp_pre_user_query', array( &$this ) );
+	}
+
+	/**
+	 * Query for IDs of users that match the query parameters.
+	 *
+	 * Perform a database query to specifically get only user IDs, using
+	 * existing query variables set previously in the constructor.
+	 *
+	 * Also used to quickly perform user total counts.
+	 *
+	 * @since BuddyPress (1.7.0)
+	 */
+	public function do_user_ids_query() {
+		global $wpdb;
+
+		// If counting using SQL_CALC_FOUND_ROWS, set it up here
+		if ( 'sql_calc_found_rows' == $this->query_vars['count_total'] ) {
+			$this->uid_clauses['select'] = str_replace( 'SELECT', 'SELECT SQL_CALC_FOUND_ROWS', $this->uid_clauses['select'] );
+		}
+
+		// Get the specific user ids
+		$this->user_ids = $wpdb->get_col( "{$this->uid_clauses['select']} {$this->uid_clauses['where']} {$this->uid_clauses['orderby']} {$this->uid_clauses['order']} {$this->uid_clauses['limit']}" );
+
+		// Get the total user count
+		if ( 'sql_calc_found_rows' == $this->query_vars['count_total'] ) {
+			$this->total_users = $wpdb->get_var( apply_filters( 'bp_found_user_query', "SELECT FOUND_ROWS()", $this ) );
+		} elseif ( 'count_query' == $this->query_vars['count_total'] ) {
+			$count_select      = preg_replace( '/^SELECT.*?FROM (\S+) u/', "SELECT COUNT(DISTINCT u.{$this->uid_name}) FROM $1 u", $this->uid_clauses['select'] );
+			$this->total_users = $wpdb->get_var( apply_filters( 'bp_found_user_query', "{$count_select} {$this->uid_clauses['where']}", $this ) );
+		}
+	}
+
+	/**
+	 * Use WP_User_Query() to pull data for the user IDs retrieved in the main query.
+	 *
+	 * @since BuddyPress (1.7.0)
+	 */
+	public function do_wp_user_query() {
+		$wp_user_query = new WP_User_Query( apply_filters( 'bp_wp_user_query_args', array(
+
+			// Relevant
+			'fields'      => array( 'ID', 'user_registered', 'user_login', 'user_nicename', 'display_name', 'user_email' ),
+			'include'     => $this->user_ids,
+
+			// Overrides
+			'blog_id'     => 0,    // BP does not require blog roles
+			'count_total' => false // We already have a count
+
+		), $this ) );
+
+		// We calculate total_users using a standalone query, except
+		// when a whitelist of user_ids is passed to the constructor.
+		// This clause covers the latter situation, and ensures that
+		// pagination works when querying by $user_ids.
+		if ( empty( $this->total_users ) ) {
+			$this->total_users = count( $wp_user_query->results );
+		}
+
+		// Reindex for easier matching
+		$r = array();
+		foreach ( $wp_user_query->results as $u ) {
+			$r[ $u->ID ] = $u;
+		}
+
+		// Match up to the user ids from the main query
+		foreach ( $this->user_ids as $uid ) {
+			if ( isset( $r[ $uid ] ) ) {
+				$this->results[ $uid ] = $r[ $uid ];
+
+				// The BP template functions expect an 'id'
+				// (as opposed to 'ID') property
+				$this->results[ $uid ]->id = $uid;
+			}
+		}
+	}
+
+	/**
+	 * Fetch the IDs of users to put in the IN clause of the main query.
+	 *
+	 * By default, returns the value passed to it
+	 * ($this->query_vars['include']). Having this abstracted into a
+	 * standalone method means that extending classes can override the
+	 * logic, parsing together their own user_id limits with the 'include'
+	 * ids passed to the class constructor. See {@link BP_Group_Member_Query}
+	 * for an example.
+	 *
+	 * @since BuddyPress (1.8.0)
+	 *
+	 * @param array Sanitized array of user IDs, as passed to the 'include'
+	 *        parameter of the class constructor.
+	 * @return array The list of users to which the main query should be
+	 *         limited.
+	 */
+	public function get_include_ids( $include = array() ) {
+		return $include;
+	}
+
+	/**
+	 * Perform a database query to populate any extra metadata we might need.
+	 *
+	 * Different components will hook into the 'bp_user_query_populate_extras'
+	 * action to loop in the things they want.
+	 *
+	 * @since BuddyPress (1.7.0)
+	 *
+	 * @global BuddyPress $bp Global BuddyPress settings object.
+	 * @global WPDB $wpdb Global WordPress database access object.
+	 */
+	public function populate_extras() {
+		global $wpdb;
+
+		// Bail if no users
+		if ( empty( $this->user_ids ) || empty( $this->results ) ) {
+			return;
+		}
+
+		// Bail if the populate_extras flag is set to false
+		// In the case of the 'popular' sort type, we force
+		// populate_extras to true, because we need the friend counts
+		if ( 'popular' == $this->query_vars['type'] ) {
+			$this->query_vars['populate_extras'] = 1;
+		}
+
+		if ( ! (bool) $this->query_vars['populate_extras'] ) {
+			return;
+		}
+
+		// Turn user ID's into a query-usable, comma separated value
+		$user_ids_sql = implode( ',', wp_parse_id_list( $this->user_ids ) );
+
+		/**
+		 * Use this action to independently populate your own custom extras.
+		 *
+		 * Note that anything you add here should query using $user_ids_sql, to
+		 * avoid running multiple queries per user in the loop.
+		 *
+		 * Two BuddyPress components currently do this:
+		 * - XProfile: To override display names
+		 * - Friends:  To set whether or not a user is the current users friend
+		 *
+		 * @see bp_xprofile_filter_user_query_populate_extras()
+		 * @see bp_friends_filter_user_query_populate_extras()
+		 */
+		do_action_ref_array( 'bp_user_query_populate_extras', array( $this, $user_ids_sql ) );
+
+		// Fetch usermeta data
+		// We want the three following pieces of info from usermeta:
+		// - friend count
+		// - last activity
+		// - latest update
+		$total_friend_count_key = bp_get_user_meta_key( 'total_friend_count' );
+		$last_activity_key      = bp_get_user_meta_key( 'last_activity'      );
+		$bp_latest_update_key   = bp_get_user_meta_key( 'bp_latest_update'   );
+
+		// total_friend_count must be set for each user, even if its
+		// value is 0
+		foreach ( $this->results as $uindex => $user ) {
+			$this->results[$uindex]->total_friend_count = 0;
+		}
+
+		// Create, prepare, and run the seperate usermeta query
+		$user_metas = $wpdb->get_results( $wpdb->prepare( "SELECT user_id, meta_key, meta_value FROM {$wpdb->usermeta} WHERE meta_key IN (%s,%s,%s) AND user_id IN ({$user_ids_sql})", $total_friend_count_key, $last_activity_key, $bp_latest_update_key ) );
+
+		// The $members_template global expects the index key to be different
+		// from the meta_key in some cases, so we rejig things here.
+		foreach ( $user_metas as $user_meta ) {
+			switch ( $user_meta->meta_key ) {
+				case $total_friend_count_key :
+					$key = 'total_friend_count';
+					break;
+
+				case $last_activity_key :
+					$key = 'last_activity';
+					break;
+
+				case $bp_latest_update_key :
+					$key = 'latest_update';
+					break;
+			}
+
+			if ( isset( $this->results[ $user_meta->user_id ] ) ) {
+				$this->results[ $user_meta->user_id ]->{$key} = $user_meta->meta_value;
+			}
+		}
+
+		// When meta_key or meta_value have been passed to the query,
+		// fetch the resulting values for use in the template functions
+		if ( ! empty( $this->query_vars['meta_key'] ) ) {
+			$meta_sql = array(
+				'select' => "SELECT user_id, meta_key, meta_value",
+				'from'   => "FROM $wpdb->usermeta",
+				'where'  => $wpdb->prepare( "WHERE meta_key = %s", $this->query_vars['meta_key'] )
+			);
+
+			if ( false !== $this->query_vars['meta_value'] ) {
+				$meta_sql['where'] .= $wpdb->prepare( " AND meta_value = %s", $this->query_vars['meta_value'] );
+			}
+
+			$metas = $wpdb->get_results( "{$meta_sql['select']} {$meta_sql['from']} {$meta_sql['where']}" );
+
+			if ( ! empty( $metas ) ) {
+				foreach ( $metas as $meta ) {
+					if ( isset( $this->results[ $meta->user_id ] ) ) {
+						$this->results[ $meta->user_id ]->meta_key = $meta->meta_key;
+
+						if ( ! empty( $meta->meta_value ) ) {
+							$this->results[ $meta->user_id ]->meta_value = $meta->meta_value;
+						}
+					}
+				}
+			}
+		}
+	}
+}
+
+/**
+ * Fetch data about a BuddyPress user.
+ *
+ * BP_Core_User class can be used by any component. It will fetch useful
+ * details for any user when provided with a user_id.
+ *
+ * Example:
+ *    $user = new BP_Core_User( $user_id );
+ *    $user_avatar = $user->avatar;
+ *	  $user_email = $user->email;
+ *    $user_status = $user->status;
+ *    etc.
+ */
+class BP_Core_User {
+
+	/**
+	 * ID of the user which the object relates to.
+	 *
+	 * @var integer
+	 */
+	public $id;
+
+	/**
+	 * The URL to the full size of the avatar for the user.
+	 *
+	 * @var string
+	 */
+	public $avatar;
+
+	/**
+	 * The URL to the thumb size of the avatar for the user.
+	 *
+	 * @var string
+	 */
+	public $avatar_thumb;
+
+	/**
+	 * The URL to the mini size of the avatar for the user.
+	 *
+	 * @var string
+	 */
+	public $avatar_mini;
+
+	/**
+	 * The full name of the user
+	 *
+	 * @var string
+	 */
+	public $fullname;
+
+	/**
+	 * The email for the user.
+	 *
+	 * @var string
+	 */
+	public $email;
+
+	/**
+	 * The absolute url for the user's profile.
+	 *
+	 * @var string
+	 */
+	public $user_url;
+
+	/**
+	 * The HTML for the user link, with the link text being the user's full name.
+	 *
+	 * @var string
+	 */
+	public $user_link;
+
+	/**
+	 * Contains a formatted string when the last time the user was active.
+	 *
+	 * Example: "active 2 hours and 50 minutes ago"
+	 *
+	 * @var string
+	 */
+	public $last_active;
+
+	/* Extras */
+
+	/**
+	 * The total number of "Friends" the user has on site.
+	 *
+	 * @var integer
+	 */
+	public $total_friends;
+
+	/**
+	 * The total number of blog posts posted by the user
+	 *
+	 * @var integer
+	 * @deprecated No longer used
+	 */
+	public $total_blogs;
+
+	/**
+	 * The total number of groups the user is a part of.
+	 *
+	 * Example: "1 group", "2 groups"
+	 *
+	 * @var string
+	 */
+	public $total_groups;
+
+	/**
+	 * Profile information for the specific user.
+	 *
+	 * @since BuddyPress (1.2.0)
+	 * @var array
+	 */
+	public $profile_data;
+
+	/** Public Methods *******************************************************/
+
+	/**
+	 * Class constructor.
+	 *
+	 * @param integer $user_id The ID for the user being queried.
+	 * @param bool $populate_extras Whether to fetch extra information
+	 *        such as group/friendship counts or not. Default: false.
+	 */
+	public function __construct( $user_id, $populate_extras = false ) {
+		if ( !empty( $user_id ) ) {
+			$this->id = $user_id;
+			$this->populate();
+
+			if ( !empty( $populate_extras ) ) {
+				$this->populate_extras();
+			}
+		}
+	}
+
+	/**
+	 * Populate the instantiated class with data based on the User ID provided.
+	 *
+	 * @uses bp_core_get_userurl() Returns the URL with no HTML markup for
+	 *       a user based on their user id.
+	 * @uses bp_core_get_userlink() Returns a HTML formatted link for a
+	 *       user with the user's full name as the link text.
+	 * @uses bp_core_get_user_email() Returns the email address for the
+	 *       user based on user ID.
+	 * @uses bp_get_user_meta() BP function returns the value of passed
+	 *       usermeta name from usermeta table.
+	 * @uses bp_core_fetch_avatar() Returns HTML formatted avatar for a user
+	 * @uses bp_profile_last_updated_date() Returns the last updated date
+	 *       for a user.
+	 */
+	public function populate() {
+
+		if ( bp_is_active( 'xprofile' ) )
+			$this->profile_data = $this->get_profile_data();
+
+		if ( !empty( $this->profile_data ) ) {
+			$full_name_field_name = bp_xprofile_fullname_field_name();
+
+			$this->user_url  = bp_core_get_user_domain( $this->id, $this->profile_data['user_nicename'], $this->profile_data['user_login'] );
+			$this->fullname  = esc_attr( $this->profile_data[$full_name_field_name]['field_data'] );
+			$this->user_link = "<a href='{$this->user_url}' title='{$this->fullname}'>{$this->fullname}</a>";
+			$this->email     = esc_attr( $this->profile_data['user_email'] );
+		} else {
+			$this->user_url  = bp_core_get_user_domain( $this->id );
+			$this->user_link = bp_core_get_userlink( $this->id );
+			$this->fullname  = esc_attr( bp_core_get_user_displayname( $this->id ) );
+			$this->email     = esc_attr( bp_core_get_user_email( $this->id ) );
+		}
+
+		// Cache a few things that are fetched often
+		wp_cache_set( 'bp_user_fullname_' . $this->id, $this->fullname, 'bp' );
+		wp_cache_set( 'bp_user_email_' . $this->id, $this->email, 'bp' );
+		wp_cache_set( 'bp_user_url_' . $this->id, $this->user_url, 'bp' );
+
+		$this->avatar       = bp_core_fetch_avatar( array( 'item_id' => $this->id, 'type' => 'full', 'alt' => sprintf( __( 'Avatar of %s', 'buddypress' ), $this->fullname ) ) );
+		$this->avatar_thumb = bp_core_fetch_avatar( array( 'item_id' => $this->id, 'type' => 'thumb', 'alt' => sprintf( __( 'Avatar of %s', 'buddypress' ), $this->fullname ) ) );
+		$this->avatar_mini  = bp_core_fetch_avatar( array( 'item_id' => $this->id, 'type' => 'thumb', 'alt' => sprintf( __( 'Avatar of %s', 'buddypress' ), $this->fullname ), 'width' => 30, 'height' => 30 ) );
+		$this->last_active  = bp_core_get_last_activity( bp_get_user_last_activity( $this->id ), __( 'active %s', 'buddypress' ) );
+	}
+
+	/**
+	 * Populates extra fields such as group and friendship counts.
+	 */
+	public function populate_extras() {
+
+		if ( bp_is_active( 'friends' ) ) {
+			$this->total_friends = BP_Friends_Friendship::total_friend_count( $this->id );
+		}
+
+		if ( bp_is_active( 'groups' ) ) {
+			$this->total_groups = BP_Groups_Member::total_group_count( $this->id );
+			$this->total_groups = sprintf( _n( '%d group', '%d groups', $this->total_groups, 'buddypress' ), $this->total_groups );
+		}
+	}
+
+	/**
+	 * Fetch xprofile data for the current user.
+	 *
+	 * @see BP_XProfile_ProfileData::get_all_for_user() for description of
+	 *      return value.
+	 *
+	 * @return array See {@link BP_XProfile_Profile_Data::get_all_for_user()}.
+	 */
+	public function get_profile_data() {
+		return BP_XProfile_ProfileData::get_all_for_user( $this->id );
+	}
+
+	/** Static Methods ********************************************************/
+
+	/**
+	 * Get a list of users that match the query parameters.
+	 *
+	 * Since BuddyPress 1.7, use {@link BP_User_Query} instead.
+	 *
+	 * @deprecated 1.7.0 Use {@link BP_User_Query}.
+	 *
+	 * @see BP_User_Query for a description of parameters, most of which
+	 *      are used there in the same way.
+	 *
+	 * @param string $type See {@link BP_User_Query}.
+	 * @param int $limit See {@link BP_User_Query}. Default: 0.
+	 * @param int $page See {@link BP_User_Query}. Default: 1.
+	 * @param int $user_id See {@link BP_User_Query}. Default: 0.
+	 * @param mixed $include See {@link BP_User_Query}. Default: false.
+	 * @param string|bool $search_terms See {@link BP_User_Query}.
+	 *        Default: false.
+	 * @param bool $populate_extras See {@link BP_User_Query}.
+	 *        Default: true.
+	 * @param mixed $exclude See {@link BP_User_Query}. Default: false.
+	 * @param string|bool $meta_key See {@link BP_User_Query}.
+	 *        Default: false.
+	 * @param string|bool $meta_value See {@link BP_User_Query}.
+	 *        Default: false.
+	 * @return array {
+	 *     @type int $total_users Total number of users matched by query
+	 *           params.
+	 *     @type array $paged_users The current page of users matched by
+	 *           query params.
+	 * }
+	 */
+	public static function get_users( $type, $limit = 0, $page = 1, $user_id = 0, $include = false, $search_terms = false, $populate_extras = true, $exclude = false, $meta_key = false, $meta_value = false ) {
+		global $wpdb, $bp;
+
+		_deprecated_function( __METHOD__, '1.7', 'BP_User_Query' );
+
+		$sql = array();
+
+		$sql['select_main'] = "SELECT DISTINCT u.ID as id, u.user_registered, u.user_nicename, u.user_login, u.display_name, u.user_email";
+
+		if ( 'active' == $type || 'online' == $type || 'newest' == $type  ) {
+			$sql['select_active'] = ", um.meta_value as last_activity";
+		}
+
+		if ( 'popular' == $type ) {
+			$sql['select_popular'] = ", um.meta_value as total_friend_count";
+		}
+
+		if ( 'alphabetical' == $type ) {
+			$sql['select_alpha'] = ", pd.value as fullname";
+		}
+
+		if ( $meta_key ) {
+			$sql['select_meta'] = ", umm.meta_key";
+
+			if ( $meta_value ) {
+				$sql['select_meta'] .= ", umm.meta_value";
+			}
+		}
+
+		$sql['from'] = "FROM {$wpdb->users} u LEFT JOIN {$wpdb->usermeta} um ON um.user_id = u.ID";
+
+		// We search against xprofile fields, so we must join the table
+		if ( $search_terms && bp_is_active( 'xprofile' ) ) {
+			$sql['join_profiledata_search'] = "LEFT JOIN {$bp->profile->table_name_data} spd ON u.ID = spd.user_id";
+		}
+
+		// Alphabetical sorting is done by the xprofile Full Name field
+		if ( 'alphabetical' == $type ) {
+			$sql['join_profiledata_alpha'] = "LEFT JOIN {$bp->profile->table_name_data} pd ON u.ID = pd.user_id";
+		}
+
+		if ( $meta_key ) {
+			$sql['join_meta'] = "LEFT JOIN {$wpdb->usermeta} umm ON umm.user_id = u.ID";
+		}
+
+		$sql['where'] = 'WHERE ' . bp_core_get_status_sql( 'u.' );
+
+		if ( 'active' == $type || 'online' == $type || 'newest' == $type ) {
+			$sql['where_active'] = $wpdb->prepare( "AND um.meta_key = %s", bp_get_user_meta_key( 'last_activity' ) );
+		}
+
+		if ( 'popular' == $type ) {
+			$sql['where_popular'] = $wpdb->prepare( "AND um.meta_key = %s", bp_get_user_meta_key( 'total_friend_count' ) );
+		}
+
+		if ( 'online' == $type ) {
+			$sql['where_online'] = "AND DATE_ADD( um.meta_value, INTERVAL 5 MINUTE ) >= UTC_TIMESTAMP()";
+		}
+
+		if ( 'alphabetical' == $type ) {
+			$sql['where_alpha'] = "AND pd.field_id = 1";
+		}
+
+		if ( !empty( $exclude ) ) {
+			$exclude              = implode( ',', wp_parse_id_list( $exclude ) );
+			$sql['where_exclude'] = "AND u.ID NOT IN ({$exclude})";
+		}
+
+		// Passing an $include value of 0 or '0' will necessarily result in an empty set
+		// returned. The default value of false will hit the 'else' clause.
+		if ( 0 === $include || '0' === $include ) {
+			$sql['where_users'] = "AND 0 = 1";
+		} else {
+			if ( !empty( $include ) ) {
+				$include = implode( ',',  wp_parse_id_list( $include ) );
+				$sql['where_users'] = "AND u.ID IN ({$include})";
+			} elseif ( !empty( $user_id ) && bp_is_active( 'friends' ) ) {
+				$friend_ids = friends_get_friend_user_ids( $user_id );
+
+				if ( !empty( $friend_ids ) ) {
+					$friend_ids = implode( ',', wp_parse_id_list( $friend_ids ) );
+					$sql['where_friends'] = "AND u.ID IN ({$friend_ids})";
+
+				// User has no friends, return false since there will be no users to fetch.
+				} else {
+					return false;
+				}
+			}
+		}
+
+		if ( !empty( $search_terms ) && bp_is_active( 'xprofile' ) ) {
+			$search_terms             = esc_sql( like_escape( $search_terms ) );
+			$sql['where_searchterms'] = "AND spd.value LIKE '%%$search_terms%%'";
+		}
+
+		if ( !empty( $meta_key ) ) {
+			$sql['where_meta'] = $wpdb->prepare( " AND umm.meta_key = %s", $meta_key );
+
+			// If a meta value is provided, match it
+			if ( $meta_value ) {
+				$sql['where_meta'] .= $wpdb->prepare( " AND umm.meta_value = %s", $meta_value );
+			}
+		}
+
+		switch ( $type ) {
+			case 'active': case 'online': default:
+				$sql[] = "ORDER BY um.meta_value DESC";
+				break;
+			case 'newest':
+				$sql[] = "ORDER BY u.ID DESC";
+				break;
+			case 'alphabetical':
+				$sql[] = "ORDER BY pd.value ASC";
+				break;
+			case 'random':
+				$sql[] = "ORDER BY rand()";
+				break;
+			case 'popular':
+				$sql[] = "ORDER BY CONVERT(um.meta_value, SIGNED) DESC";
+				break;
+		}
+
+		if ( !empty( $limit ) && !empty( $page ) ) {
+			$sql['pagination'] = $wpdb->prepare( "LIMIT %d, %d", intval( ( $page - 1 ) * $limit), intval( $limit ) );
+		}
+
+		// Get paginated results
+		$paged_users_sql = apply_filters( 'bp_core_get_paged_users_sql', join( ' ', (array) $sql ), $sql );
+		$paged_users     = $wpdb->get_results( $paged_users_sql );
+
+		// Re-jig the SQL so we can get the total user count
+		unset( $sql['select_main'] );
+
+		if ( !empty( $sql['select_active'] ) ) {
+			unset( $sql['select_active'] );
+		}
+
+		if ( !empty( $sql['select_popular'] ) ) {
+			unset( $sql['select_popular'] );
+		}
+
+		if ( !empty( $sql['select_alpha'] ) ) {
+			unset( $sql['select_alpha'] );
+		}
+
+		if ( !empty( $sql['pagination'] ) ) {
+			unset( $sql['pagination'] );
+		}
+
+		array_unshift( $sql, "SELECT COUNT(DISTINCT u.ID)" );
+
+		// Get total user results
+		$total_users_sql = apply_filters( 'bp_core_get_total_users_sql', join( ' ', (array) $sql ), $sql );
+		$total_users     = $wpdb->get_var( $total_users_sql );
+
+		/***
+		 * Lets fetch some other useful data in a separate queries, this will be faster than querying the data for every user in a list.
+		 * We can't add these to the main query above since only users who have this information will be returned (since the much of the data is in usermeta and won't support any type of directional join)
+		 */
+		if ( !empty( $populate_extras ) ) {
+			$user_ids = array();
+
+			foreach ( (array) $paged_users as $user ) {
+				$user_ids[] = $user->id;
+			}
+
+			// Add additional data to the returned results
+			$paged_users = BP_Core_User::get_user_extras( $paged_users, $user_ids, $type );
+		}
+
+		return array( 'users' => $paged_users, 'total' => $total_users );
+	}
+
+
+	/**
+	 * Fetch the details for all users whose usernames start with the given letter.
+	 *
+	 * @global BuddyPress $bp The one true BuddyPress instance.
+	 * @global wpdb $wpdb WordPress database object.
+	 *
+	 * @param string $letter The letter the users names are to start with.
+	 * @param int $limit The number of users we wish to retrive.
+	 * @param int $page The page number we are currently on, used in
+	 *        conjunction with $limit to get the start position for the
+	 *        limit.
+	 * @param bool $populate_extras Populate extra user fields?
+	 * @param string $exclude Comma-separated IDs of users whose results
+	 *        aren't to be fetched.
+	 * @return mixed False on error, otherwise associative array of results.
+	 */
+	public static function get_users_by_letter( $letter, $limit = null, $page = 1, $populate_extras = true, $exclude = '' ) {
+		global $bp, $wpdb;
+
+		$pag_sql = '';
+		if ( $limit && $page ) {
+			$pag_sql = $wpdb->prepare( " LIMIT %d, %d", intval( ( $page - 1 ) * $limit), intval( $limit ) );
+		}
+
+		// Multibyte compliance
+		if ( function_exists( 'mb_strlen' ) ) {
+			if ( mb_strlen( $letter, 'UTF-8' ) > 1 || is_numeric( $letter ) || !$letter ) {
+				return false;
+			}
+		} else {
+			if ( strlen( $letter ) > 1 || is_numeric( $letter ) || !$letter ) {
+				return false;
+			}
+		}
+
+		$letter     = esc_sql( like_escape( $letter ) );
+		$status_sql = bp_core_get_status_sql( 'u.' );
+
+		if ( !empty( $exclude ) ) {
+			$exclude     = implode( ',', wp_parse_id_list( $r['exclude'] ) );
+			$exclude_sql = " AND u.id NOT IN ({$exclude})";
+		} else {
+			$exclude_sql = '';
+		}
+
+		$total_users_sql = apply_filters( 'bp_core_users_by_letter_count_sql', $wpdb->prepare( "SELECT COUNT(DISTINCT u.ID) FROM {$wpdb->users} u LEFT JOIN {$bp->profile->table_name_data} pd ON u.ID = pd.user_id LEFT JOIN {$bp->profile->table_name_fields} pf ON pd.field_id = pf.id WHERE {$status_sql} AND pf.name = %s {$exclude_sql} AND pd.value LIKE '{$letter}%%'  ORDER BY pd.value ASC", bp_xprofile_fullname_field_name() ) );
+		$paged_users_sql = apply_filters( 'bp_core_users_by_letter_sql',       $wpdb->prepare( "SELECT DISTINCT u.ID as id, u.user_registered, u.user_nicename, u.user_login, u.user_email FROM {$wpdb->users} u LEFT JOIN {$bp->profile->table_name_data} pd ON u.ID = pd.user_id LEFT JOIN {$bp->profile->table_name_fields} pf ON pd.field_id = pf.id WHERE {$status_sql} AND pf.name = %s {$exclude_sql} AND pd.value LIKE '{$letter}%%' ORDER BY pd.value ASC{$pag_sql}", bp_xprofile_fullname_field_name() ) );
+
+		$total_users = $wpdb->get_var( $total_users_sql );
+		$paged_users = $wpdb->get_results( $paged_users_sql );
+
+		/***
+		 * Lets fetch some other useful data in a separate queries, this will be
+		 * faster than querying the data for every user in a list. We can't add
+		 * these to the main query above since only users who have this
+		 * information will be returned (since the much of the data is in
+		 * usermeta and won't support any type of directional join)
+		 */
+		$user_ids = array();
+		foreach ( (array) $paged_users as $user )
+			$user_ids[] = (int) $user->id;
+
+		// Add additional data to the returned results
+		if ( $populate_extras ) {
+			$paged_users = BP_Core_User::get_user_extras( $paged_users, $user_ids );
+		}
+
+		return array( 'users' => $paged_users, 'total' => $total_users );
+	}
+
+	/**
+	 * Get details of specific users from the database.
+	 *
+	 * Use {@link BP_User_Query} with the 'user_ids' param instead.
+	 *
+	 * @global wpdb $wpdb WordPress database object.
+	 * @param array $user_ids The user IDs of the users who we wish to
+	 *        fetch information on.
+	 * @param int $limit The limit of results we want.
+	 * @param int $page The page we are on for pagination.
+	 * @param bool $populate_extras Populate extra user fields?
+	 * @return array Associative array.
+	 */
+	public static function get_specific_users( $user_ids, $limit = null, $page = 1, $populate_extras = true ) {
+		global $wpdb;
+
+		$pag_sql = '';
+		if ( $limit && $page )
+			$pag_sql = $wpdb->prepare( " LIMIT %d, %d", intval( ( $page - 1 ) * $limit), intval( $limit ) );
+
+		$user_ids   = implode( ',', wp_parse_id_list( $user_ids ) );
+		$status_sql = bp_core_get_status_sql();
+
+		$total_users_sql = apply_filters( 'bp_core_get_specific_users_count_sql', "SELECT COUNT(DISTINCT ID) FROM {$wpdb->users} WHERE {$status_sql} AND ID IN ({$user_ids})" );
+		$paged_users_sql = apply_filters( 'bp_core_get_specific_users_count_sql', "SELECT DISTINCT ID as id, user_registered, user_nicename, user_login, user_email FROM {$wpdb->users} WHERE {$status_sql} AND ID IN ({$user_ids}) {$pag_sql}" );
+
+		$total_users = $wpdb->get_var( $total_users_sql );
+		$paged_users = $wpdb->get_results( $paged_users_sql );
+
+		/***
+		 * Lets fetch some other useful data in a separate queries, this will be
+		 * faster than querying the data for every user in a list. We can't add
+		 * these to the main query above since only users who have this
+		 * information will be returned (since the much of the data is in
+		 * usermeta and won't support any type of directional join)
+		 */
+
+		// Add additional data to the returned results
+		if ( !empty( $populate_extras ) ) {
+			$paged_users = BP_Core_User::get_user_extras( $paged_users, $user_ids );
+		}
+
+		return array( 'users' => $paged_users, 'total' => $total_users );
+	}
+
+	/**
+	 * Find users who match on the value of an xprofile data.
+	 *
+	 * @global BuddyPress $bp The one true BuddyPress instance.
+	 * @global wpdb $wpdb WordPress database object.
+	 *
+	 * @param string $search_terms The terms to search the profile table
+	 *        value column for.
+	 * @param integer $limit The limit of results we want.
+	 * @param integer $page The page we are on for pagination.
+	 * @param boolean $populate_extras Populate extra user fields?
+	 * @return array Associative array.
+	 */
+	public static function search_users( $search_terms, $limit = null, $page = 1, $populate_extras = true ) {
+		global $bp, $wpdb;
+
+		$user_ids = array();
+		$pag_sql  = $limit && $page ? $wpdb->prepare( " LIMIT %d, %d", intval( ( $page - 1 ) * intval( $limit ) ), intval( $limit ) ) : '';
+
+		$search_terms = esc_sql( like_escape( $search_terms ) );
+		$status_sql   = bp_core_get_status_sql( 'u.' );
+
+		$total_users_sql = apply_filters( 'bp_core_search_users_count_sql', "SELECT COUNT(DISTINCT u.ID) as id FROM {$wpdb->users} u LEFT JOIN {$bp->profile->table_name_data} pd ON u.ID = pd.user_id WHERE {$status_sql} AND pd.value LIKE '%%{$search_terms}%%' ORDER BY pd.value ASC", $search_terms );
+		$paged_users_sql = apply_filters( 'bp_core_search_users_sql',       "SELECT DISTINCT u.ID as id, u.user_registered, u.user_nicename, u.user_login, u.user_email FROM {$wpdb->users} u LEFT JOIN {$bp->profile->table_name_data} pd ON u.ID = pd.user_id WHERE {$status_sql} AND pd.value LIKE '%%{$search_terms}%%' ORDER BY pd.value ASC{$pag_sql}", $search_terms, $pag_sql );
+
+		$total_users = $wpdb->get_var( $total_users_sql );
+		$paged_users = $wpdb->get_results( $paged_users_sql );
+
+		/***
+		 * Lets fetch some other useful data in a separate queries, this will be faster than querying the data for every user in a list.
+		 * We can't add these to the main query above since only users who have this information will be returned (since the much of the data is in usermeta and won't support any type of directional join)
+		 */
+		foreach ( (array) $paged_users as $user )
+			$user_ids[] = $user->id;
+
+		// Add additional data to the returned results
+		if ( $populate_extras )
+			$paged_users = BP_Core_User::get_user_extras( $paged_users, $user_ids );
+
+		return array( 'users' => $paged_users, 'total' => $total_users );
+	}
+
+	/**
+	 * Fetch extra user information, such as friend count and last profile update message.
+	 *
+	 * Accepts multiple user IDs to fetch data for.
+	 *
+	 * @global BuddyPress $bp The one true BuddyPress instance.
+	 * @global wpdb $wpdb WordPress database object.
+	 *
+	 * @param array $paged_users An array of stdClass containing the users.
+	 * @param string $user_ids The user ids to select information about.
+	 * @param string $type The type of fields we wish to get.
+	 * @return mixed False on error, otherwise associative array of results.
+	 */
+	public static function get_user_extras( &$paged_users, &$user_ids, $type = false ) {
+		global $bp, $wpdb;
+
+		if ( empty( $user_ids ) )
+			return $paged_users;
+
+		// Sanitize user IDs
+		$user_ids = implode( ',', wp_parse_id_list( $user_ids ) );
+
+		// Fetch the user's full name
+		if ( bp_is_active( 'xprofile' ) && 'alphabetical' != $type ) {
+			$names = $wpdb->get_results( $wpdb->prepare( "SELECT pd.user_id as id, pd.value as fullname FROM {$bp->profile->table_name_fields} pf, {$bp->profile->table_name_data} pd WHERE pf.id = pd.field_id AND pf.name = %s AND pd.user_id IN ( {$user_ids} )", bp_xprofile_fullname_field_name() ) );
+			for ( $i = 0, $count = count( $paged_users ); $i < $count; ++$i ) {
+				foreach ( (array) $names as $name ) {
+					if ( $name->id == $paged_users[$i]->id )
+						$paged_users[$i]->fullname = $name->fullname;
+				}
+			}
+		}
+
+		// Fetch the user's total friend count
+		if ( 'popular' != $type ) {
+			$friend_count = $wpdb->get_results( $wpdb->prepare( "SELECT user_id as id, meta_value as total_friend_count FROM {$wpdb->usermeta} WHERE meta_key = %s AND user_id IN ( {$user_ids} )", bp_get_user_meta_key( 'total_friend_count' ) ) );
+			for ( $i = 0, $count = count( $paged_users ); $i < $count; ++$i ) {
+				foreach ( (array) $friend_count as $fcount ) {
+					if ( $fcount->id == $paged_users[$i]->id )
+						$paged_users[$i]->total_friend_count = (int) $fcount->total_friend_count;
+				}
+			}
+		}
+
+		// Fetch whether or not the user is a friend
+		if ( bp_is_active( 'friends' ) ) {
+			$friend_status = $wpdb->get_results( $wpdb->prepare( "SELECT initiator_user_id, friend_user_id, is_confirmed FROM {$bp->friends->table_name} WHERE (initiator_user_id = %d AND friend_user_id IN ( {$user_ids} ) ) OR (initiator_user_id IN ( {$user_ids} ) AND friend_user_id = %d )", bp_loggedin_user_id(), bp_loggedin_user_id() ) );
+			for ( $i = 0, $count = count( $paged_users ); $i < $count; ++$i ) {
+				foreach ( (array) $friend_status as $status ) {
+					if ( $status->initiator_user_id == $paged_users[$i]->id || $status->friend_user_id == $paged_users[$i]->id )
+						$paged_users[$i]->is_friend = $status->is_confirmed;
+				}
+			}
+		}
+
+		if ( 'active' != $type ) {
+			$user_activity = $wpdb->get_results( $wpdb->prepare( "SELECT user_id as id, meta_value as last_activity FROM {$wpdb->usermeta} WHERE meta_key = %s AND user_id IN ( {$user_ids} )", bp_get_user_meta_key( 'last_activity' ) ) );
+			for ( $i = 0, $count = count( $paged_users ); $i < $count; ++$i ) {
+				foreach ( (array) $user_activity as $activity ) {
+					if ( $activity->id == $paged_users[$i]->id )
+						$paged_users[$i]->last_activity = $activity->last_activity;
+				}
+			}
+		}
+
+		// Fetch the user's last_activity
+		if ( 'active' != $type ) {
+			$user_activity = $wpdb->get_results( $wpdb->prepare( "SELECT user_id as id, meta_value as last_activity FROM {$wpdb->usermeta} WHERE meta_key = %s AND user_id IN ( {$user_ids} )", bp_get_user_meta_key( 'last_activity' ) ) );
+			for ( $i = 0, $count = count( $paged_users ); $i < $count; ++$i ) {
+				foreach ( (array) $user_activity as $activity ) {
+					if ( $activity->id == $paged_users[$i]->id )
+						$paged_users[$i]->last_activity = $activity->last_activity;
+				}
+			}
+		}
+
+		// Fetch the user's latest update
+		$user_update = $wpdb->get_results( $wpdb->prepare( "SELECT user_id as id, meta_value as latest_update FROM {$wpdb->usermeta} WHERE meta_key = %s AND user_id IN ( {$user_ids} )", bp_get_user_meta_key( 'bp_latest_update' ) ) );
+		for ( $i = 0, $count = count( $paged_users ); $i < $count; ++$i ) {
+			foreach ( (array) $user_update as $update ) {
+				if ( $update->id == $paged_users[$i]->id )
+					$paged_users[$i]->latest_update = $update->latest_update;
+			}
+		}
+
+		return $paged_users;
+	}
+
+	/**
+	 * Get WordPress user details for a specified user.
+	 *
+	 * @global wpdb $wpdb WordPress database object.
+	 *
+	 * @param integer $user_id User ID.
+	 * @return array Associative array.
+	 */
+	public static function get_core_userdata( $user_id ) {
+		global $wpdb;
+
+		if ( !$user = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$wpdb->users} WHERE ID = %d LIMIT 1", $user_id ) ) )
+			return false;
+
+		return $user;
+	}
+}
+
+
+/**
+ * BP_Core_Notification is deprecated.
+ *
+ * Use BP_Notifications_Notification instead.
+ *
+ * @package BuddyPress Core
+ * @deprecated since BuddyPress (1.9)
+ */
+class BP_Core_Notification {
+
+	/**
+	 * The notification id
+	 *
+	 * @var integer
+	 */
+	public $id;
+
+	/**
+	 * The ID to which the notification relates to within the component.
+	 *
+	 * @var integer
+	 */
+	public $item_id;
+
+	/**
+	 * The secondary ID to which the notification relates to within the component.
+	 *
+	 * @var integer
+	 */
+	public $secondary_item_id = null;
+
+	/**
+	 * The user ID for who the notification is for.
+	 *
+	 * @var integer
+	 */
+	public $user_id;
+
+	/**
+	 * The name of the component that the notification is for.
+	 *
+	 * @var string
+	 */
+	public $component_name;
+
+	/**
+	 * The action within the component which the notification is related to.
+	 *
+	 * @var string
+	 */
+	public $component_action;
+
+	/**
+	 * The date the notification was created.
+	 *
+	 * @var string
+	 */
+	public $date_notified;
+
+	/**
+	 * Is the notification new or has it already been read.
+	 *
+	 * @var boolean
+	 */
+	public $is_new;
+
+	/** Public Methods ********************************************************/
+
+	/**
+	 * Constructor
+	 *
+	 * @param integer $id
+	 */
+	public function __construct( $id = 0 ) {
+		if ( !empty( $id ) ) {
+			$this->id = $id;
+			$this->populate();
+		}
+	}
+
+	/**
+	 * Update or insert notification details into the database.
+	 *
+	 * @global BuddyPress $bp The one true BuddyPress instance
+	 * @global wpdb $wpdb WordPress database object
+	 * @return bool Success or failure
+	 */
+	public function save() {
+		global $bp, $wpdb;
+
+		// Update
+		if ( !empty( $this->id ) ) {
+			$sql = $wpdb->prepare( "UPDATE {$bp->core->table_name_notifications} SET item_id = %d, secondary_item_id = %d, user_id = %d, component_name = %s, component_action = %d, date_notified = %s, is_new = %d ) WHERE id = %d", $this->item_id, $this->secondary_item_id, $this->user_id, $this->component_name, $this->component_action, $this->date_notified, $this->is_new, $this->id );
+
+		// Save
+		} else {
+			$sql = $wpdb->prepare( "INSERT INTO {$bp->core->table_name_notifications} ( item_id, secondary_item_id, user_id, component_name, component_action, date_notified, is_new ) VALUES ( %d, %d, %d, %s, %s, %s, %d )", $this->item_id, $this->secondary_item_id, $this->user_id, $this->component_name, $this->component_action, $this->date_notified, $this->is_new );
+		}
+
+		if ( !$result = $wpdb->query( $sql ) )
+			return false;
+
+		$this->id = $wpdb->insert_id;
+
+		return true;
+	}
+
+	/** Private Methods *******************************************************/
+
+	/**
+	 * Fetches the notification data from the database.
+	 *
+	 * @global BuddyPress $bp The one true BuddyPress instance
+	 * @global wpdb $wpdb WordPress database object
+	 */
+	public function populate() {
+		global $bp, $wpdb;
+
+		if ( $notification = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$bp->core->table_name_notifications} WHERE id = %d", $this->id ) ) ) {
+			$this->item_id = $notification->item_id;
+			$this->secondary_item_id = $notification->secondary_item_id;
+			$this->user_id           = $notification->user_id;
+			$this->component_name    = $notification->component_name;
+			$this->component_action  = $notification->component_action;
+			$this->date_notified     = $notification->date_notified;
+			$this->is_new            = $notification->is_new;
+		}
+	}
+
+	/** Static Methods ********************************************************/
+
+	public static function check_access( $user_id, $notification_id ) {
+		global $wpdb, $bp;
+
+		return $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(id) FROM {$bp->core->table_name_notifications} WHERE id = %d AND user_id = %d", $notification_id, $user_id ) );
+	}
+
+	/**
+	 * Fetches all the notifications in the database for a specific user.
+	 *
+	 * @global BuddyPress $bp The one true BuddyPress instance
+	 * @global wpdb $wpdb WordPress database object
+	 * @param integer $user_id User ID
+	 * @param string $status 'is_new' or 'all'
+	 * @return array Associative array
+	 * @static
+	 */
+	public static function get_all_for_user( $user_id, $status = 'is_new' ) {
+		global $bp, $wpdb;
+
+		$is_new = ( 'is_new' == $status ) ? ' AND is_new = 1 ' : '';
+
+ 		return $wpdb->get_results( $wpdb->prepare( "SELECT * FROM {$bp->core->table_name_notifications} WHERE user_id = %d {$is_new}", $user_id ) );
+	}
+
+	/**
+	 * Delete all the notifications for a user based on the component name and action.
+	 *
+	 * @global BuddyPress $bp The one true BuddyPress instance
+	 * @global wpdb $wpdb WordPress database object
+	 * @param integer $user_id
+	 * @param string $component_name
+	 * @param string $component_action
+	 * @static
+	 */
+	public static function delete_for_user_by_type( $user_id, $component_name, $component_action ) {
+		global $bp, $wpdb;
+
+		return $wpdb->query( $wpdb->prepare( "DELETE FROM {$bp->core->table_name_notifications} WHERE user_id = %d AND component_name = %s AND component_action = %s", $user_id, $component_name, $component_action ) );
+	}
+
+	/**
+	 * Delete all the notifications that have a specific item id, component name and action.
+	 *
+	 * @global BuddyPress $bp The one true BuddyPress instance
+	 * @global wpdb $wpdb WordPress database object
+	 * @param integer $user_id The ID of the user who the notifications are for.
+	 * @param integer $item_id The item ID of the notifications we wish to delete.
+	 * @param string $component_name The name of the component that the notifications we wish to delete.
+	 * @param string $component_action The action of the component that the notifications we wish to delete.
+	 * @param integer $secondary_item_id (optional) The secondary item id of the notifications that we wish to use to delete.
+	 * @static
+	 */
+	public static function delete_for_user_by_item_id( $user_id, $item_id, $component_name, $component_action, $secondary_item_id = false ) {
+		global $bp, $wpdb;
+
+		$secondary_item_sql = !empty( $secondary_item_id ) ? $wpdb->prepare( " AND secondary_item_id = %d", $secondary_item_id ) : '';
+
+		return $wpdb->query( $wpdb->prepare( "DELETE FROM {$bp->core->table_name_notifications} WHERE user_id = %d AND item_id = %d AND component_name = %s AND component_action = %s{$secondary_item_sql}", $user_id, $item_id, $component_name, $component_action ) );
+	}
+
+	/**
+	 * Deletes all the notifications sent by a specific user, by component and action.
+	 *
+	 * @global BuddyPress $bp The one true BuddyPress instance
+	 * @global wpdb $wpdb WordPress database object
+	 * @param integer $user_id The ID of the user whose sent notifications we wish to delete.
+	 * @param string $component_name The name of the component the notification was sent from.
+	 * @param string $component_action The action of the component the notification was sent from.
+	 * @static
+	 */
+	public static function delete_from_user_by_type( $user_id, $component_name, $component_action ) {
+		global $bp, $wpdb;
+
+		return $wpdb->query( $wpdb->prepare( "DELETE FROM {$bp->core->table_name_notifications} WHERE item_id = %d AND component_name = %s AND component_action = %s", $user_id, $component_name, $component_action ) );
+	}
+
+	/**
+	 * Deletes all the notifications for all users by item id, and optional secondary item id, and component name and action.
+	 *
+	 * @global BuddyPress $bp The one true BuddyPress instance
+	 * @global wpdb $wpdb WordPress database object
+	 * @param string $item_id The item id that they notifications are to be for.
+	 * @param string $component_name The component that the notifications are to be from.
+	 * @param string $component_action The action that the notificationsa are to be from.
+	 * @param string $secondary_item_id Optional secondary item id that the notifications are to have.
+	 * @static
+	 */
+	public static function delete_all_by_type( $item_id, $component_name, $component_action, $secondary_item_id ) {
+		global $bp, $wpdb;
+
+		if ( $component_action )
+			$component_action_sql = $wpdb->prepare( "AND component_action = %s", $component_action );
+		else
+			$component_action_sql = '';
+
+		if ( $secondary_item_id )
+			$secondary_item_sql = $wpdb->prepare( "AND secondary_item_id = %d", $secondary_item_id );
+		else
+			$secondary_item_sql = '';
+
+		return $wpdb->query( $wpdb->prepare( "DELETE FROM {$bp->core->table_name_notifications} WHERE item_id = %d AND component_name = %s {$component_action_sql} {$secondary_item_sql}", $item_id, $component_name ) );
+	}
+}
+
+/**
+ * API to create BuddyPress buttons.
+ *
+ * @since BuddyPress (1.2.6)
+ *
+ * @param array $args {
+ *     Array of arguments.
+ *     @type string $id String describing the button type.
+ *     @type string $component The name of the component the button belongs to.
+ *           Default: 'core'.
+ *     @type bool $must_be_logged_in Optional. Does the user need to be logged
+ *           in to see this button? Default: true.
+ *     @type bool $block_self Optional. True if the button should be hidden
+ *           when a user is viewing his own profile. Default: true.
+ *     @type string|bool $wrapper Optional. HTML element type that should wrap
+ *           the button: 'div', 'span', 'p', or 'li'. False for no wrapper at
+ *           all. Default: 'div'.
+ *     @type string $wrapper_id Optional. DOM ID of the button wrapper element.
+ *           Default: ''.
+ *     @type string $wrapper_class Optional. DOM class of the button wrapper
+ *           element. Default: ''.
+ *     @type string $link_href Optional. Destination link of the button.
+ *           Default: ''.
+ *     @type string $link_class Optional. DOM class of the button. Default: ''.
+ *     @type string $link_id Optional. DOM ID of the button. Default: ''.
+ *     @type string $link_rel Optional. DOM 'rel' attribute of the button.
+ *           Default: ''.
+ *     @type string $link_title Optional. Title attribute of the button.
+ *           Default: ''.
+ *     @type string $link_text Optional. Text to appear on the button.
+ *           Default: ''.
+ * }
+ */
+class BP_Button {
+
+	/** Button properties *****************************************************/
+
+	/**
+	 * The button ID.
+	 *
+	 * @var string
+	 */
+	public $id = '';
+
+	/**
+	 * The name of the component that the button belongs to.
+	 *
+	 * @var string
+	 */
+	public $component = 'core';
+
+	/**
+	 * Does the user need to be logged in to see this button?
+	 *
+	 * @var bool
+	 */
+	public $must_be_logged_in = true;
+
+	/**
+	 * Whether the button should be hidden when viewing your own profile.
+	 *
+	 * @var bool
+	 */
+	public $block_self = true;
+
+	/** Wrapper ***************************************************************/
+
+	/**
+	 * The type of DOM element to use for a wrapper.
+	 *
+	 * @var string|bool 'div', 'span', 'p', 'li', or false for no wrapper.
+	 */
+	public $wrapper = 'div';
+
+	/**
+	 * The DOM class of the button wrapper.
+	 *
+	 * @var string
+	 */
+	public $wrapper_class = '';
+
+	/**
+	 * The DOM ID of the button wrapper.
+	 *
+	 * @var string
+	 */
+	public $wrapper_id = '';
+
+	/** Button ****************************************************************/
+
+	/**
+	 * The destination link of the button.
+	 *
+	 * @var string
+	 */
+	public $link_href = '';
+
+	/**
+	 * The DOM class of the button link.
+	 *
+	 * @var string
+	 */
+	public $link_class = '';
+
+	/**
+	 * The DOM ID of the button link.
+	 *
+	 * @var string
+	 */
+	public $link_id = '';
+
+	/**
+	 * The DOM rel value of the button link.
+	 *
+	 * @var string
+	 */
+	public $link_rel = '';
+
+	/**
+	 * Title of the button link.
+	 *
+	 * @var string
+	 */
+	public $link_title = '';
+
+	/**
+	 * The contents of the button link.
+	 *
+	 * @var string
+	 */
+	public $link_text = '';
+
+	/** HTML result ***********************************************************/
+
+	public $contents = '';
+
+	/** Methods ***************************************************************/
+
+	/**
+	 * Builds the button based on class parameters.
+	 *
+	 * @since BuddyPress (1.2.6)
+	 *
+	 * @param array $args See {@BP_Button}.
+	 * @return bool|null Returns false when the button is not allowed for
+	 *         the current context.
+	 */
+	public function __construct( $args = '' ) {
+
+		$r = wp_parse_args( $args, get_class_vars( __CLASS__ ) );
+
+		// Required button properties
+		$this->id                = $r['id'];
+		$this->component         = $r['component'];
+		$this->must_be_logged_in = (bool) $r['must_be_logged_in'];
+		$this->block_self        = (bool) $r['block_self'];
+		$this->wrapper           = $r['wrapper'];
+
+		// $id and $component are required
+		if ( empty( $r['id'] ) || empty( $r['component'] ) )
+			return false;
+
+		// No button if component is not active
+		if ( ! bp_is_active( $this->component ) )
+			return false;
+
+		// No button for guests if must be logged in
+		if ( true == $this->must_be_logged_in && ! is_user_logged_in() )
+			return false;
+
+		// No button if viewing your own profile
+		if ( true == $this->block_self && bp_is_my_profile() )
+			return false;
+
+		// No button if you are the current user in a loop
+		if ( true === $this->block_self && is_user_logged_in() && bp_loggedin_user_id() === bp_get_member_user_id() )
+			return false;
+
+		// Wrapper properties
+		if ( false !== $this->wrapper ) {
+
+			// Wrapper ID
+			if ( !empty( $r['wrapper_id'] ) ) {
+				$this->wrapper_id    = ' id="' . $r['wrapper_id'] . '"';
+			}
+
+			// Wrapper class
+			if ( !empty( $r['wrapper_class'] ) ) {
+				$this->wrapper_class = ' class="generic-button ' . $r['wrapper_class'] . '"';
+			} else {
+				$this->wrapper_class = ' class="generic-button"';
+			}
+
+			// Set before and after
+			$before = '<' . $r['wrapper'] . $this->wrapper_class . $this->wrapper_id . '>';
+			$after  = '</' . $r['wrapper'] . '>';
+
+		// No wrapper
+		} else {
+			$before = $after = '';
+		}
+
+		// Link properties
+		if ( !empty( $r['link_id']    ) ) $this->link_id    = ' id="' .    $r['link_id']    . '"';
+		if ( !empty( $r['link_href']  ) ) $this->link_href  = ' href="' .  $r['link_href']  . '"';
+		if ( !empty( $r['link_title'] ) ) $this->link_title = ' title="' . $r['link_title'] . '"';
+		if ( !empty( $r['link_rel']   ) ) $this->link_rel   = ' rel="' .   $r['link_rel']   . '"';
+		if ( !empty( $r['link_class'] ) ) $this->link_class = ' class="' . $r['link_class'] . '"';
+		if ( !empty( $r['link_text']  ) ) $this->link_text  =              $r['link_text'];
+
+		// Build the button
+		$this->contents = $before . '<a'. $this->link_href . $this->link_title . $this->link_id . $this->link_rel . $this->link_class . '>' . $this->link_text . '</a>' . $after;
+
+		// Allow button to be manipulated externally
+		$this->contents = apply_filters( 'bp_button_' . $this->component . '_' . $this->id, $this->contents, $this, $before, $after );
+	}
+
+	/**
+	 * Return the markup for the generated button.
+	 *
+	 * @since BuddyPress (1.2.6)
+	 *
+	 * @return string Button markup.
+	 */
+	public function contents() {
+		return $this->contents;
+	}
+
+	/**
+	 * Output the markup of button.
+	 *
+	 * @since BuddyPress (1.2.6)
+	 */
+	public function display() {
+		if ( !empty( $this->contents ) )
+			echo $this->contents;
+	}
+}
+
+/**
+ * Enable oEmbeds in BuddyPress contexts.
+ *
+ * Extends WP_Embed class for use with BuddyPress.
+ *
+ * @since BuddyPress (1.5.0)
+ *
+ * @see WP_Embed
+ */
+class BP_Embed extends WP_Embed {
+
+	/**
+	 * Constructor
+	 *
+	 * @global WP_Embed $wp_embed
+	 */
+	public function __construct() {
+		global $wp_embed;
+
+		// Make sure we populate the WP_Embed handlers array.
+		// These are providers that use a regex callback on the URL in question.
+		// Do not confuse with oEmbed providers, which require an external ping.
+		// Used in WP_Embed::shortcode()
+		$this->handlers = $wp_embed->handlers;
+
+		if ( bp_use_embed_in_activity() ) {
+			add_filter( 'bp_get_activity_content_body', array( &$this, 'autoembed' ), 8 );
+			add_filter( 'bp_get_activity_content_body', array( &$this, 'run_shortcode' ), 7 );
+		}
+
+		if ( bp_use_embed_in_activity_replies() ) {
+			add_filter( 'bp_get_activity_content', array( &$this, 'autoembed' ), 8 );
+			add_filter( 'bp_get_activity_content', array( &$this, 'run_shortcode' ), 7 );
+		}
+
+		if ( bp_use_embed_in_forum_posts() ) {
+			add_filter( 'bp_get_the_topic_post_content', array( &$this, 'autoembed' ), 8 );
+			add_filter( 'bp_get_the_topic_post_content', array( &$this, 'run_shortcode' ), 7 );
+		}
+
+		if ( bp_use_embed_in_private_messages() ) {
+			add_filter( 'bp_get_the_thread_message_content', array( &$this, 'autoembed' ), 8 );
+			add_filter( 'bp_get_the_thread_message_content', array( &$this, 'run_shortcode' ), 7 );
+		}
+
+		do_action_ref_array( 'bp_core_setup_oembed', array( &$this ) );
+	}
+
+	/**
+	 * The {@link do_shortcode()} callback function.
+	 *
+	 * Attempts to convert a URL into embed HTML. Starts by checking the
+	 * URL against the regex of the registered embed handlers. Next, checks
+	 * the URL against the regex of registered {@link WP_oEmbed} providers
+	 * if oEmbed discovery is false. If none of the regex matches and it's
+	 * enabled, then the URL will be passed to {@link BP_Embed::parse_oembed()}
+	 * for oEmbed parsing.
+	 *
+	 * @uses wp_parse_args()
+	 * @uses wp_embed_defaults()
+	 * @uses current_user_can()
+	 * @uses _wp_oembed_get_object()
+	 * @uses WP_Embed::maybe_make_link()
+	 *
+	 * @param array $attr Shortcode attributes.
+	 * @param string $url The URL attempting to be embeded.
+	 * @return string The embed HTML on success, otherwise the original URL.
+	 */
+	public function shortcode( $attr, $url = '' ) {
+		if ( empty( $url ) )
+			return '';
+
+		$rawattr = $attr;
+		$attr = wp_parse_args( $attr, wp_embed_defaults() );
+
+		// kses converts & into &amp; and we need to undo this
+		// See http://core.trac.wordpress.org/ticket/11311
+		$url = str_replace( '&amp;', '&', $url );
+
+		// Look for known internal handlers
+		ksort( $this->handlers );
+		foreach ( $this->handlers as $priority => $handlers ) {
+			foreach ( $handlers as $hid => $handler ) {
+				if ( preg_match( $handler['regex'], $url, $matches ) && is_callable( $handler['callback'] ) ) {
+					if ( false !== $return = call_user_func( $handler['callback'], $matches, $attr, $url, $rawattr ) ) {
+						return apply_filters( 'embed_handler_html', $return, $url, $attr );
+					}
+				}
+			}
+		}
+
+		// Get object ID
+		$id = apply_filters( 'embed_post_id', 0 );
+
+		// Is oEmbed discovery on?
+		$attr['discover'] = ( apply_filters( 'bp_embed_oembed_discover', false ) && current_user_can( 'unfiltered_html' ) );
+
+		// Set up a new WP oEmbed object to check URL with registered oEmbed providers
+		require_once( ABSPATH . WPINC . '/class-oembed.php' );
+		$oembed_obj = _wp_oembed_get_object();
+
+		// If oEmbed discovery is true, skip oEmbed provider check
+		$is_oembed_link = false;
+		if ( !$attr['discover'] ) {
+			foreach ( (array) $oembed_obj->providers as $provider_matchmask => $provider ) {
+				$regex = ( $is_regex = $provider[1] ) ? $provider_matchmask : '#' . str_replace( '___wildcard___', '(.+)', preg_quote( str_replace( '*', '___wildcard___', $provider_matchmask ), '#' ) ) . '#i';
+
+				if ( preg_match( $regex, $url ) )
+					$is_oembed_link = true;
+			}
+
+			// If url doesn't match a WP oEmbed provider, stop parsing
+			if ( !$is_oembed_link )
+				return $this->maybe_make_link( $url );
+		}
+
+		return $this->parse_oembed( $id, $url, $attr, $rawattr );
+	}
+
+	/**
+	 * Base function so BP components/plugins can parse links to be embedded.
+	 *
+	 * View an example to add support in {@link bp_activity_embed()}.
+	 *
+	 * @uses apply_filters() Filters cache.
+	 * @uses do_action() To save cache.
+	 * @uses wp_oembed_get() Connects to oEmbed provider and returns HTML
+	 *       on success.
+	 * @uses WP_Embed::maybe_make_link() Process URL for hyperlinking on
+	 *       oEmbed failure.
+	 *
+	 * @param int $id ID to do the caching for.
+	 * @param string $url The URL attempting to be embedded.
+	 * @param array $attr Shortcode attributes from {@link WP_Embed::shortcode()}.
+	 * @param array $rawattr Untouched shortcode attributes from
+	 *        {@link WP_Embed::shortcode()}.
+	 * @return string The embed HTML on success, otherwise the original URL.
+	 */
+	public function parse_oembed( $id, $url, $attr, $rawattr ) {
+		$id = intval( $id );
+
+		if ( $id ) {
+			// Setup the cachekey
+			$cachekey = '_oembed_' . md5( $url . serialize( $attr ) );
+
+			// Let components / plugins grab their cache
+			$cache = '';
+			$cache = apply_filters( 'bp_embed_get_cache', $cache, $id, $cachekey, $url, $attr, $rawattr );
+
+			// Grab cache and return it if available
+			if ( !empty( $cache ) ) {
+				return apply_filters( 'bp_embed_oembed_html', $cache, $url, $attr, $rawattr );
+
+			// If no cache, ping the oEmbed provider and cache the result
+			} else {
+				$html = wp_oembed_get( $url, $attr );
+				$cache = ( $html ) ? $html : $url;
+
+				// Let components / plugins save their cache
+				do_action( 'bp_embed_update_cache', $cache, $cachekey, $id );
+
+				// If there was a result, return it
+				if ( $html )
+					return apply_filters( 'bp_embed_oembed_html', $html, $url, $attr, $rawattr );
+			}
+		}
+
+		// Still unknown
+		return $this->maybe_make_link( $url );
+	}
+}
+
+/**
+ * Create HTML list of BP nav items.
+ *
+ * @since BuddyPress (1.7.0)
+ */
+class BP_Walker_Nav_Menu extends Walker_Nav_Menu {
+
+	/**
+	 * Description of fields indexes for building markup.
+	 *
+	 * @since BuddyPress (1.7.0)
+	 * @var array
+	 */
+	var $db_fields = array( 'id' => 'css_id', 'parent' => 'parent' );
+
+	/**
+	 * Tree type.
+	 *
+	 * @since BuddyPress (1.7.0)
+	 * @var string
+	 */
+	var $tree_type = array();
+
+	/**
+	 * Display array of elements hierarchically.
+	 *
+	 * This method is almost identical to the version in {@link Walker::walk()}.
+	 * The only change is on one line which has been commented. An IF was
+	 * comparing 0 to a non-empty string which was preventing child elements
+	 * being grouped under their parent menu element.
+	 *
+	 * This caused a problem for BuddyPress because our primary/secondary
+	 * navigations don't have a unique numerical ID that describes a
+	 * hierarchy (we use a slug). Obviously, WordPress Menus use Posts, and
+	 * those have ID/post_parent.
+	 *
+	 * @since BuddyPress (1.7.0)
+	 *
+	 * @see Walker::walk()
+	 *
+	 * @param array $elements See {@link Walker::walk()}.
+	 * @param int $max_depth See {@link Walker::walk()}.
+	 * @return string See {@link Walker::walk()}.
+	 */
+	public function walk( $elements, $max_depth ) {
+		$args   = array_slice( func_get_args(), 2 );
+		$output = '';
+
+		if ( $max_depth < -1 ) // invalid parameter
+			return $output;
+
+		if ( empty( $elements ) ) // nothing to walk
+			return $output;
+
+		$id_field     = $this->db_fields['id'];
+		$parent_field = $this->db_fields['parent'];
+
+		// flat display
+		if ( -1 == $max_depth ) {
+
+			$empty_array = array();
+			foreach ( $elements as $e )
+				$this->display_element( $e, $empty_array, 1, 0, $args, $output );
+
+			return $output;
+		}
+
+		/*
+		 * need to display in hierarchical order
+		 * separate elements into two buckets: top level and children elements
+		 * children_elements is two dimensional array, eg.
+		 * children_elements[10][] contains all sub-elements whose parent is 10.
+		 */
+		$top_level_elements = array();
+		$children_elements  = array();
+
+		foreach ( $elements as $e ) {
+			// BuddyPress: changed '==' to '==='. This is the only change from version in Walker::walk().
+			if ( 0 === $e->$parent_field )
+				$top_level_elements[] = $e;
+			else
+				$children_elements[$e->$parent_field][] = $e;
+		}
+
+		/*
+		 * when none of the elements is top level
+		 * assume the first one must be root of the sub elements
+		 */
+		if ( empty( $top_level_elements ) ) {
+
+			$first              = array_slice( $elements, 0, 1 );
+			$root               = $first[0];
+			$top_level_elements = array();
+			$children_elements  = array();
+
+			foreach ( $elements as $e ) {
+				if ( $root->$parent_field == $e->$parent_field )
+					$top_level_elements[] = $e;
+				else
+					$children_elements[$e->$parent_field][] = $e;
+			}
+		}
+
+		foreach ( $top_level_elements as $e )
+			$this->display_element( $e, $children_elements, $max_depth, 0, $args, $output );
+
+		/*
+		 * if we are displaying all levels, and remaining children_elements is not empty,
+		 * then we got orphans, which should be displayed regardless
+		 */
+		if ( ( $max_depth == 0 ) && count( $children_elements ) > 0 ) {
+			$empty_array = array();
+
+			foreach ( $children_elements as $orphans )
+				foreach ( $orphans as $op )
+					$this->display_element( $op, $empty_array, 1, 0, $args, $output );
+		 }
+
+		 return $output;
+	}
+
+	/**
+	 * Display the current <li> that we are on.
+	 *
+	 * @see Walker::start_el() for complete description of parameters .
+	 *
+	 * @since BuddyPress (1.7.0)
+	 *
+	 * @param string $output Passed by reference. Used to append
+	 *        additional content.
+	 * @param object $item Menu item data object.
+	 * @param int $depth Depth of menu item. Used for padding. Optional,
+	 *        defaults to 0.
+	 * @param array $args Optional. See {@link Walker::start_el()}.
+	 * @param int $current_page Menu item ID. Optional.
+	 */
+	public function start_el( &$output, $item, $depth = 0, $args = array(), $id = 0 ) {
+		// If we're someway down the tree, indent the HTML with the appropriate number of tabs
+		$indent = $depth ? str_repeat( "\t", $depth ) : '';
+
+		// Add HTML classes
+		$class_names = join( ' ', apply_filters( 'bp_nav_menu_css_class', array_filter( $item->class ), $item, $args ) );
+		$class_names = ! empty( $class_names ) ? ' class="' . esc_attr( $class_names ) . '"' : '';
+
+		// Add HTML ID
+		$id = sanitize_html_class( $item->css_id . '-personal-li' );  // Backpat with BP pre-1.7
+		$id = apply_filters( 'bp_nav_menu_item_id', $id, $item, $args );
+		$id = ! empty( $id ) ? ' id="' . esc_attr( $id ) . '"' : '';
+
+		// Opening tag; closing tag is handled in Walker_Nav_Menu::end_el().
+		$output .= $indent . '<li' . $id . $class_names . '>';
+
+		// Add href attribute
+		$attributes = ! empty( $item->link ) ? ' href="' . esc_attr( esc_url( $item->link ) ) . '"' : '';
+
+		// Construct the link
+		$item_output = $args->before;
+		$item_output .= '<a' . $attributes . '>';
+		$item_output .= $args->link_before . apply_filters( 'the_title', $item->name, 0 ) . $args->link_after;
+		$item_output .= '</a>';
+		$item_output .= $args->after;
+
+		// $output is byref
+		$output .= apply_filters( 'bp_walker_nav_menu_start_el', $item_output, $item, $depth, $args );
+	}
+}
+
+/**
+ * Create a set of BuddyPress-specific links for use in the Menus admin UI.
+ *
+ * Borrowed heavily from {@link Walker_Nav_Menu_Checklist}, but modified so as not
+ * to require an actual post type or taxonomy, and to force certain CSS classes
+ *
+ * @since BuddyPress (1.9.0)
+ */
+class BP_Walker_Nav_Menu_Checklist extends Walker_Nav_Menu {
+
+	/**
+	 * Constructor.
+	 *
+	 * @see Walker_Nav_Menu::__construct() for a description of parameters.
+	 *
+	 * @param array $fields See {@link Walker_Nav_Menu::__construct()}.
+	 */
+	public function __construct( $fields = false ) {
+		if ( $fields ) {
+			$this->db_fields = $fields;
+		}
+	}
+
+	/**
+	 * Create the markup to start a tree level.
+	 *
+	 * @see Walker_Nav_Menu::start_lvl() for description of parameters.
+	 *
+	 * @param string $output See {@Walker_Nav_Menu::start_lvl()}.
+	 * @param int $depth See {@Walker_Nav_Menu::start_lvl()}.
+	 * @param array $args See {@Walker_Nav_Menu::start_lvl()}.
+	 */
+	public function start_lvl( &$output, $depth = 0, $args = array() ) {
+		$indent = str_repeat( "\t", $depth );
+		$output .= "\n$indent<ul class='children'>\n";
+	}
+
+	/**
+	 * Create the markup to end a tree level.
+	 *
+	 * @see Walker_Nav_Menu::end_lvl() for description of parameters.
+	 *
+	 * @param string $output See {@Walker_Nav_Menu::end_lvl()}.
+	 * @param int $depth See {@Walker_Nav_Menu::end_lvl()}.
+	 * @param array $args See {@Walker_Nav_Menu::end_lvl()}.
+	 */
+	public function end_lvl( &$output, $depth = 0, $args = array() ) {
+		$indent = str_repeat( "\t", $depth );
+		$output .= "\n$indent</ul>";
+	}
+
+	/**
+	 * Create the markup to start an element.
+	 *
+	 * @see Walker::start_el() for description of parameters.
+	 *
+	 * @param string $output Passed by reference. Used to append additional
+	 *        content.
+	 * @param object $item Menu item data object.
+	 * @param int $depth Depth of menu item. Used for padding.
+	 * @param object $args See {@Walker::start_el()}.
+	 * @param int $id See {@Walker::start_el()}.
+	 */
+	function start_el( &$output, $item, $depth = 0, $args = array(), $id = 0 ) {
+		global $_nav_menu_placeholder;
+
+		$_nav_menu_placeholder = ( 0 > $_nav_menu_placeholder ) ? intval($_nav_menu_placeholder) - 1 : -1;
+		$possible_object_id = isset( $item->post_type ) && 'nav_menu_item' == $item->post_type ? $item->object_id : $_nav_menu_placeholder;
+		$possible_db_id = ( ! empty( $item->ID ) ) && ( 0 < $possible_object_id ) ? (int) $item->ID : 0;
+
+		$indent = ( $depth ) ? str_repeat( "\t", $depth ) : '';
+
+		$output .= $indent . '<li>';
+		$output .= '<label class="menu-item-title">';
+		$output .= '<input type="checkbox" class="menu-item-checkbox';
+
+		if ( property_exists( $item, 'label' ) ) {
+			$title = $item->label;
+		}
+
+		$output .= '" name="menu-item[' . $possible_object_id . '][menu-item-object-id]" value="'. esc_attr( $item->object_id ) .'" /> ';
+		$output .= isset( $title ) ? esc_html( $title ) : esc_html( $item->title );
+		$output .= '</label>';
+
+		if ( empty( $item->url ) ) {
+			$item->url = $item->guid;
+		}
+
+		if ( ! in_array( array( 'bp-menu', 'bp-'. $item->post_excerpt .'-nav' ), $item->classes ) ) {
+			$item->classes[] = 'bp-menu';
+			$item->classes[] = 'bp-'. $item->post_excerpt .'-nav';
+		}
+
+		// Menu item hidden fields
+		$output .= '<input type="hidden" class="menu-item-db-id" name="menu-item[' . $possible_object_id . '][menu-item-db-id]" value="' . $possible_db_id . '" />';
+		$output .= '<input type="hidden" class="menu-item-object" name="menu-item[' . $possible_object_id . '][menu-item-object]" value="'. esc_attr( $item->object ) .'" />';
+		$output .= '<input type="hidden" class="menu-item-parent-id" name="menu-item[' . $possible_object_id . '][menu-item-parent-id]" value="'. esc_attr( $item->menu_item_parent ) .'" />';
+		$output .= '<input type="hidden" class="menu-item-type" name="menu-item[' . $possible_object_id . '][menu-item-type]" value="custom" />';
+		$output .= '<input type="hidden" class="menu-item-title" name="menu-item[' . $possible_object_id . '][menu-item-title]" value="'. esc_attr( $item->title ) .'" />';
+		$output .= '<input type="hidden" class="menu-item-url" name="menu-item[' . $possible_object_id . '][menu-item-url]" value="'. esc_attr( $item->url ) .'" />';
+		$output .= '<input type="hidden" class="menu-item-target" name="menu-item[' . $possible_object_id . '][menu-item-target]" value="'. esc_attr( $item->target ) .'" />';
+		$output .= '<input type="hidden" class="menu-item-attr_title" name="menu-item[' . $possible_object_id . '][menu-item-attr_title]" value="'. esc_attr( $item->attr_title ) .'" />';
+		$output .= '<input type="hidden" class="menu-item-classes" name="menu-item[' . $possible_object_id . '][menu-item-classes]" value="'. esc_attr( implode( ' ', $item->classes ) ) .'" />';
+		$output .= '<input type="hidden" class="menu-item-xfn" name="menu-item[' . $possible_object_id . '][menu-item-xfn]" value="'. esc_attr( $item->xfn ) .'" />';
+	}
+}
Index: /tags/1.9/bp-core/bp-core-component.php
===================================================================
--- /tags/1.9/bp-core/bp-core-component.php	(revision 7684)
+++ /tags/1.9/bp-core/bp-core-component.php	(revision 7684)
@@ -0,0 +1,524 @@
+<?php
+/**
+ * Component classes.
+ *
+ * @package BuddyPress
+ * @subpackage Core
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+if ( !class_exists( 'BP_Component' ) ) :
+/**
+ * BuddyPress Component Class.
+ *
+ * The BuddyPress component class is responsible for simplifying the creation
+ * of components that share similar behaviors and routines. It is used
+ * internally by BuddyPress to create the bundled components, but can be
+ * extended to create other really neat things.
+ *
+ * @package BuddyPress
+ * @subpackage Component
+ *
+ * @since BuddyPress (1.5.0)
+ */
+class BP_Component {
+
+	/** Variables *************************************************************/
+
+	/**
+	 * Translatable name for the component.
+	 *
+	 * @internal
+	 * @var string $name
+	 */
+	public $name = '';
+
+	/**
+	 * Unique ID for the component.
+	 *
+	 * @var string $id
+	 */
+	public $id = '';
+
+	/**
+	 * Unique slug for the component, for use in query strings and URLs.
+	 *
+	 * @var string $slug
+	 */
+	public $slug = '';
+
+	/**
+	 * Does the component need a top-level directory?
+	 *
+	 * @var bool $has_directory
+	 */
+	public $has_directory = false;
+
+	/**
+	 * The path to the component's files.
+	 *
+	 * @var string $path
+	 */
+	public $path = '';
+
+	/**
+	 * The WP_Query loop for this component.
+	 *
+	 * @var WP_Query $query
+	 */
+	public $query = false;
+
+	/**
+	 * The current ID of the queried object.
+	 *
+	 * @var string $current_id
+	 */
+	public $current_id = '';
+
+	/**
+	 * Callback for formatting notifications.
+	 *
+	 * @var callable $notification_callback
+	 */
+	public $notification_callback = '';
+
+	/**
+	 * WordPress Toolbar links.
+	 *
+	 * @var array $admin_menu
+	 */
+	public $admin_menu = '';
+
+	/**
+	 * Placeholder text for component directory search box.
+	 *
+	 * @since BuddyPress (1.5.0)
+	 * @var string $search_string
+	 */
+	public $search_string = '';
+
+	/**
+	 * Root slug for the component.
+	 *
+	 * @since BuddyPress (1.5.0)
+	 * @var string $root_slug
+	 */
+	public $root_slug = '';
+
+	/** Methods ***************************************************************/
+
+	/**
+	 * Component loader.
+	 *
+	 * @since BuddyPress (1.5.0)
+	 *
+	 * @uses BP_Component::setup_actions() Set up the hooks and actions.
+	 *
+	 * @param string $id Unique ID (for internal identification). Letters,
+	 *        numbers, and underscores only.
+	 * @param string $name Unique name. This should be a translatable name,
+	 *        eg __( 'Groups', 'buddypress' ).
+	 * @param string $path The file path for the component's files. Used by
+	 *        {@link BP_Component::includes()}.
+	 * @param array $params Additional parameters used by the component.
+	 *        The config array supports the following values:
+	 *        - 'adminbar_myaccount_order' Sets the position for our
+	 *          component menu under the WP Toolbar's "My Account" menu.
+	 */
+	public function start( $id = '', $name = '', $path = '', $params = array() ) {
+
+		// Internal identifier of component
+		$this->id   = $id;
+
+		// Internal component name
+		$this->name = $name;
+
+		// Path for includes
+		$this->path = $path;
+
+		// Miscellaneous component parameters that need to be set early on
+		if ( ! empty( $params ) ) {
+			// Sets the position for our menu under the WP Toolbar's "My Account" menu
+			if ( ! empty( $params['adminbar_myaccount_order'] ) ) {
+				$this->adminbar_myaccount_order = (int) $params['adminbar_myaccount_order'];
+			}
+
+		// Set defaults if not passed
+		} else {
+			// new component menus are added before the settings menu if not set
+			$this->adminbar_myaccount_order = 90;
+		}
+
+		// Move on to the next step
+		$this->setup_actions();
+	}
+
+	/**
+	 * Set up component global variables.
+	 *
+	 * @since BuddyPress (1.5)
+	 *
+	 * @uses apply_filters() Calls 'bp_{@link bp_Component::name}_id'.
+	 * @uses apply_filters() Calls 'bp_{@link bp_Component::name}_slug'.
+	 *
+	 * @param array $args {
+	 *     All values are optional.
+	 *     @type string $slug The component slug. Used to construct certain
+	 *           URLs, such as 'friends' in http://example.com/members/joe/friends/
+	 *           Default: the value of $this->id.
+	 *     @type string $root_slug The component root slug. Note that this
+	 *           value is generally unused if the component has a root
+	 *           directory (the slug will be overridden by the post_name of
+	 *           the directory page). Default: the slug of the directory
+	 *           page if one is found, otherwise an empty string.
+	 *     @type bool $has_directory Set to true if the component requires
+	 *           an associated WordPress page.
+	 *     @type callable $notification_callback Optional. The callable
+	 *           function that formats the component's notifications.
+	 *     @type string $search_term Optional. The placeholder text in the
+	 *           component directory search box. Eg, 'Search Groups...'.
+	 *     @type array $global_tables Optional. An array of database table
+	 *           names.
+	 * }
+	 */
+	public function setup_globals( $args = array() ) {
+
+		/** Slugs *************************************************************/
+
+		// If a WP directory page exists for the component, it should
+		// be the default value of 'root_slug'.
+		$default_root_slug = isset( buddypress()->pages->{$this->id}->slug ) ? buddypress()->pages->{$this->id}->slug : '';
+
+		$r = wp_parse_args( $args, array(
+			'slug'                  => $this->id,
+			'root_slug'             => $default_root_slug,
+			'has_directory'         => false,
+			'notification_callback' => '',
+			'search_string'         => '',
+			'global_tables'         => ''
+		) );
+
+		// Slug used for permalink URI chunk after root
+		$this->slug                  = apply_filters( 'bp_' . $this->id . '_slug',                  $r['slug']                  );
+
+		// Slug used for root directory
+		$this->root_slug             = apply_filters( 'bp_' . $this->id . '_root_slug',             $r['root_slug']             );
+
+		// Does this component have a top-level directory?
+		$this->has_directory         = apply_filters( 'bp_' . $this->id . '_has_directory',         $r['has_directory']         );
+
+		// Search string
+		$this->search_string         = apply_filters( 'bp_' . $this->id . '_search_string',         $r['search_string']         );
+
+		// Notifications callback
+		$this->notification_callback = apply_filters( 'bp_' . $this->id . '_notification_callback', $r['notification_callback'] );
+
+		// Set up global table names
+		if ( !empty( $r['global_tables'] ) ) {
+
+			// This filter allows for component-specific filtering of table names
+			// To filter *all* tables, use the 'bp_core_get_table_prefix' filter instead
+			$r['global_tables'] = apply_filters( 'bp_' . $this->id . '_global_tables', $r['global_tables'] );
+
+			foreach ( $r['global_tables'] as $global_name => $table_name ) {
+				$this->$global_name = $table_name;
+			}
+		}
+
+		/** BuddyPress ********************************************************/
+
+		// Register this component in the loaded components array
+		buddypress()->loaded_components[$this->slug] = $this->id;
+
+		// Call action
+		do_action( 'bp_' . $this->id . '_setup_globals' );
+	}
+
+	/**
+	 * Include required files.
+	 *
+	 * Please note that, by default, this method is fired on the bp_include
+	 * hook, with priority 8. This is necessary so that core components are
+	 * loaded in time to be available to third-party plugins. However, this
+	 * load order means that third-party plugins whose main files are
+	 * loaded at bp_include with priority 10 (as recommended), will not be
+	 * loaded in time for their includes() method to fire automatically.
+	 *
+	 * For this reason, it is recommended that your plugin has its own
+	 * method or function for requiring necessary files. If you must use
+	 * this method, you will have to call it manually in your constructor
+	 * class, ie
+	 *   $this->includes();
+	 *
+	 * Note that when you pass an array value like 'actions' to includes,
+	 * it looks for the following three files (assuming your component is
+	 * called 'my_component'):
+	 *   - ./actions
+	 *   - ./bp-my_component/actions
+	 *   - ./bp-my_component/bp-my_component-actions.php
+	 *
+	 * @since BuddyPress (1.5.0)
+	 *
+	 * @uses do_action() Calls 'bp_{@link bp_Component::name}includes'.
+	 *
+	 * @param array $includes An array of file names, or file name chunks,
+	 *        to be parsed and then included.
+	 */
+	public function includes( $includes = array() ) {
+
+		// Bail if no files to include
+		if ( empty( $includes ) )
+			return;
+
+		$slashed_path = trailingslashit( $this->path );
+
+		// Loop through files to be included
+		foreach ( (array) $includes as $file ) {
+
+			$paths = array(
+
+				// Passed with no extension
+				'bp-' . $this->id . '/bp-' . $this->id . '-' . $file  . '.php',
+				'bp-' . $this->id . '-' . $file . '.php',
+				'bp-' . $this->id . '/' . $file . '.php',
+
+				// Passed with extension
+				$file,
+				'bp-' . $this->id . '-' . $file,
+				'bp-' . $this->id . '/' . $file,
+			);
+
+			foreach ( $paths as $path ) {
+				if ( @is_file( $slashed_path . $path ) ) {
+					require( $slashed_path . $path );
+					break;
+				}
+			}
+		}
+
+		// Call action
+		do_action( 'bp_' . $this->id . '_includes' );
+	}
+
+	/**
+	 * Set up the actions.
+	 *
+	 * @since BuddyPress (1.5.0)
+	 *
+	 * @uses add_action() To add various actions.
+	 * @uses do_action() Calls 'bp_{@link BP_Component::name}setup_actions'.
+	 */
+	public function setup_actions() {
+
+		// Setup globals
+		add_action( 'bp_setup_globals',          array( $this, 'setup_globals'          ), 10 );
+
+		// Include required files. Called early to ensure that BP core
+		// components are loaded before plugins that hook their loader functions
+		// to bp_include with the default priority of 10. This is for backwards
+		// compatibility; henceforth, plugins should register themselves by
+		// extending this base class.
+		add_action( 'bp_include',                array( $this, 'includes'               ), 8 );
+
+		// Setup navigation
+		add_action( 'bp_setup_nav',              array( $this, 'setup_nav'              ), 10 );
+
+		// Setup WP Toolbar menus
+		add_action( 'bp_setup_admin_bar',        array( $this, 'setup_admin_bar'        ), $this->adminbar_myaccount_order );
+
+		// Setup component title
+		add_action( 'bp_setup_title',            array( $this, 'setup_title'            ), 10 );
+
+		// Register post types
+		add_action( 'bp_register_post_types',    array( $this, 'register_post_types'    ), 10 );
+
+		// Register taxonomies
+		add_action( 'bp_register_taxonomies',    array( $this, 'register_taxonomies'    ), 10 );
+
+		// Add the rewrite tags
+		add_action( 'bp_add_rewrite_tags',       array( $this, 'add_rewrite_tags'       ), 10 );
+
+		// Add the rewrite rules
+		add_action( 'bp_add_rewrite_rules',      array( $this, 'add_rewrite_rules'      ), 10 );
+
+		// Add the permalink structure
+		add_action( 'bp_add_permastructs',       array( $this, 'add_permastructs'       ), 10 );
+
+		// Allow components to parse the main query
+		add_action( 'bp_parse_query',            array( $this, 'parse_query'            ), 10 );
+
+		// Generate rewrite rules
+		add_action( 'bp_generate_rewrite_rules', array( $this, 'generate_rewrite_rules' ), 10 );
+
+		// Additional actions can be attached here
+		do_action( 'bp_' . $this->id . '_setup_actions' );
+	}
+
+	/**
+	 * Set up component navigation.
+	 *
+	 * @see bp_core_new_nav_item() For a description of the $main_nav
+	 *      parameter formatting.
+	 * @see bp_core_new_subnav_item() For a description of how each item
+	 *      in the $sub_nav parameter array should be formatted.
+	 *
+	 * @param array $main_nav Optional. Passed directly to
+	 *        bp_core_new_nav_item(). See that function for a description.
+	 * @param array $sub_nav Optional. Multidimensional array, each item in
+	 *        which is passed to bp_core_new_subnav_item(). See that
+	 *        function for a description.
+	 */
+	public function setup_nav( $main_nav = array(), $sub_nav = array() ) {
+
+		// No sub nav items without a main nav item
+		if ( !empty( $main_nav ) ) {
+			bp_core_new_nav_item( $main_nav );
+
+			// Sub nav items are not required
+			if ( !empty( $sub_nav ) ) {
+				foreach( (array) $sub_nav as $nav ) {
+					bp_core_new_subnav_item( $nav );
+				}
+			}
+		}
+
+		// Call action
+		do_action( 'bp_' . $this->id . '_setup_nav' );
+	}
+
+	/**
+	 * Set up the component entries in the WordPress Admin Bar.
+	 *
+	 * @see WP_Admin_Bar::add_menu() for a description of the syntax
+	 *      required by each item in the $wp_admin_nav parameter array.
+	 * @global obj $wp_admin_bar
+	 *
+	 * @param array $wp_admin_nav An array of nav item arguments. Each item
+	 *        in this parameter array is passed to {@link WP_Admin_Bar::add_menu()}.
+	 *        See that method for a description of the required syntax for
+	 *        each item.
+	 */
+	public function setup_admin_bar( $wp_admin_nav = array() ) {
+
+		// Bail if this is an ajax request
+		if ( defined( 'DOING_AJAX' ) )
+			return;
+
+		// Do not proceed if BP_USE_WP_ADMIN_BAR constant is not set or is false
+		if ( !bp_use_wp_admin_bar() )
+			return;
+
+		// Filter the passed admin nav
+		$wp_admin_nav = apply_filters( 'bp_' . $this->id . '_admin_nav', $wp_admin_nav );
+
+		// Do we have Toolbar menus to add?
+		if ( !empty( $wp_admin_nav ) ) {
+
+			// Set this objects menus
+			$this->admin_menu = $wp_admin_nav;
+
+			// Define the WordPress global
+			global $wp_admin_bar;
+
+			// Add each admin menu
+			foreach( $this->admin_menu as $admin_menu ) {
+				$wp_admin_bar->add_menu( $admin_menu );
+			}
+		}
+
+		// Call action
+		do_action( 'bp_' . $this->id . '_setup_admin_bar' );
+	}
+
+	/**
+	 * Set up the component title.
+	 *
+	 * @since BuddyPress (1.5.0)
+	 *
+	 * @uses do_action() Calls 'bp_{@link bp_Component::name}setup_title'.
+	 */
+	public function setup_title() {
+		do_action(  'bp_' . $this->id . '_setup_title' );
+	}
+
+	/**
+	 * Set up the component post types.
+	 *
+	 * @since BuddyPress (1.5.0)
+	 *
+	 * @uses do_action() Calls 'bp_{@link bp_Component::name}_register_post_types'.
+	 */
+	public function register_post_types() {
+		do_action( 'bp_' . $this->id . '_register_post_types' );
+	}
+
+	/**
+	 * Register component-specific taxonomies.
+	 *
+	 * @since BuddyPress (1.5.0)
+	 *
+	 * @uses do_action() Calls 'bp_{@link bp_Component::name}_register_taxonomies'.
+	 */
+	public function register_taxonomies() {
+		do_action( 'bp_' . $this->id . '_register_taxonomies' );
+	}
+
+	/**
+	 * Add any additional rewrite tags.
+	 *
+	 * @since BuddyPress (1.5.0)
+	 *
+	 * @uses do_action() Calls 'bp_{@link bp_Component::name}_add_rewrite_tags'.
+	 */
+	public function add_rewrite_tags() {
+		do_action( 'bp_' . $this->id . '_add_rewrite_tags' );
+	}
+
+	/**
+	 * Add any additional rewrite rules.
+	 *
+	 * @since BuddyPress (1.9.0)
+	 *
+	 * @uses do_action() Calls 'bp_{@link bp_Component::name}_add_rewrite_rules'.
+	 */
+	public function add_rewrite_rules() {
+		do_action( 'bp_' . $this->id . '_add_rewrite_rules' );
+	}
+
+	/**
+	 * Add any permalink structures
+	 *
+	 * @since BuddyPress (1.9)
+	 *
+	 * @uses do_action() Calls 'bp_{@link bp_Component::name}_add_permastruct'
+	 */
+	public function add_permastructs() {
+		do_action( 'bp_' . $this->id . '_add_permastructs' );
+	}
+
+	/**
+	 * Allow components to parse the main query
+	 *
+	 * @since BuddyPress (1.9)
+	 *
+	 * @uses do_action() Calls 'bp_{@link bp_Component::name}_parse_query'
+	 * @param object The main WP_Query
+	 */
+	public function parse_query( $query ) {
+		do_action_ref_array( 'bp_' . $this->id . '_parse_query', array( &$query ) );
+	}
+
+	/**
+	 * Generate any additional rewrite rules
+	 *
+	 * @since BuddyPress (1.5)
+	 *
+	 * @uses do_action() Calls 'bp_{@link bp_Component::name}_generate_rewrite_rules'
+	 */
+	public function generate_rewrite_rules() {
+		do_action( 'bp_' . $this->id . '_generate_rewrite_rules' );
+	}
+}
+endif; // BP_Component
Index: /tags/1.9/bp-core/bp-core-cssjs.php
===================================================================
--- /tags/1.9/bp-core/bp-core-cssjs.php	(revision 7684)
+++ /tags/1.9/bp-core/bp-core-cssjs.php	(revision 7684)
@@ -0,0 +1,164 @@
+<?php
+/**
+ * Core component CSS & JS.
+ *
+ * @package BuddyPress
+ * @subpackage Core
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/**
+ * Load the JS for "Are you sure?" .confirm links.
+ */
+function bp_core_confirmation_js() {
+
+	if ( is_multisite() && ! bp_is_root_blog() )
+		return false;
+
+	if ( !wp_script_is( 'jquery' ) )
+		wp_enqueue_script( 'jquery' );
+
+	if ( !wp_script_is( 'jquery', 'done' ) )
+		wp_print_scripts( 'jquery' ); ?>
+
+	<script type="text/javascript">
+		jQuery( document ).ready( function() {
+			jQuery( 'a.confirm').click( function() {
+				if ( confirm( '<?php _e( 'Are you sure?', 'buddypress' ) ?>' ) )
+					return true; else return false;
+			});
+		});
+	</script>
+
+<?php
+}
+add_action( 'wp_head',    'bp_core_confirmation_js', 100 );
+add_action( 'admin_head', 'bp_core_confirmation_js', 100 );
+
+/**
+ * Enqueues jCrop library and hooks BP's custom cropper JS.
+ */
+function bp_core_add_jquery_cropper() {
+	wp_enqueue_style( 'jcrop' );
+	wp_enqueue_script( 'jcrop', array( 'jquery' ) );
+	add_action( 'wp_head', 'bp_core_add_cropper_inline_js' );
+	add_action( 'wp_head', 'bp_core_add_cropper_inline_css' );
+}
+
+/**
+ * Output the inline JS needed for the cropper to work on a per-page basis.
+ */
+function bp_core_add_cropper_inline_js() {
+
+	// Bail if no image was uploaded
+	$image = apply_filters( 'bp_inline_cropper_image', getimagesize( bp_core_avatar_upload_path() . buddypress()->avatar_admin->image->dir ) );
+	if ( empty( $image ) )
+		return;
+
+	//
+	$full_height = bp_core_avatar_full_height();
+	$full_width  = bp_core_avatar_full_width();
+
+	// Calculate Aspect Ratio
+	if ( !empty( $full_height ) && ( $full_width != $full_height ) ) {
+		$aspect_ratio = $full_width / $full_height;
+	} else {
+		$aspect_ratio = 1;
+	}
+
+	// Default cropper coordinates
+	$crop_left   = round( $image[0] / 4 );
+	$crop_top    = round( $image[1] / 4 );
+	$crop_right  = $image[0] - $crop_left;
+	$crop_bottom = $image[1] - $crop_top; ?>
+
+	<script type="text/javascript">
+		jQuery(window).load( function(){
+			jQuery('#avatar-to-crop').Jcrop({
+				onChange: showPreview,
+				onSelect: showPreview,
+				onSelect: updateCoords,
+				aspectRatio: <?php echo $aspect_ratio; ?>,
+				setSelect: [ <?php echo $crop_left; ?>, <?php echo $crop_top; ?>, <?php echo $crop_right; ?>, <?php echo $crop_bottom; ?> ]
+			});
+			updateCoords({x: <?php echo $crop_left; ?>, y: <?php echo $crop_top; ?>, w: <?php echo $crop_right; ?>, h: <?php echo $crop_bottom; ?>});
+		});
+
+		function updateCoords(c) {
+			jQuery('#x').val(c.x);
+			jQuery('#y').val(c.y);
+			jQuery('#w').val(c.w);
+			jQuery('#h').val(c.h);
+		}
+
+		function showPreview(coords) {
+			if ( parseInt(coords.w) > 0 ) {
+				var fw = <?php echo $full_width; ?>;
+				var fh = <?php echo $full_height; ?>;
+				var rx = fw / coords.w;
+				var ry = fh / coords.h;
+
+				jQuery( '#avatar-crop-preview' ).css({
+					width: Math.round(rx * <?php echo $image[0]; ?>) + 'px',
+					height: Math.round(ry * <?php echo $image[1]; ?>) + 'px',
+					marginLeft: '-' + Math.round(rx * coords.x) + 'px',
+					marginTop: '-' + Math.round(ry * coords.y) + 'px'
+				});
+			}
+		}
+	</script>
+
+<?php
+}
+
+/**
+ * Output the inline CSS for the BP image cropper.
+ *
+ * @package BuddyPress Core
+ */
+function bp_core_add_cropper_inline_css() {
+?>
+
+	<style type="text/css">
+		.jcrop-holder { float: left; margin: 0 20px 20px 0; text-align: left; }
+		#avatar-crop-pane { width: <?php echo bp_core_avatar_full_width() ?>px; height: <?php echo bp_core_avatar_full_height() ?>px; overflow: hidden; }
+		#avatar-crop-submit { margin: 20px 0; }
+		.jcrop-holder img,
+		#avatar-crop-pane img,
+		#avatar-upload-form img,
+		#create-group-form img,
+		#group-settings-form img { border: none !important; max-width: none !important; }
+	</style>
+
+<?php
+}
+
+/**
+ * Define the 'ajaxurl' JS variable, used by themes as an AJAX endpoint.
+ *
+ * @since BuddyPress (1.1.0)
+ */
+function bp_core_add_ajax_url_js() {
+?>
+
+	<script type="text/javascript">var ajaxurl = '<?php echo bp_core_ajax_url(); ?>';</script>
+
+<?php
+}
+add_action( 'wp_head', 'bp_core_add_ajax_url_js' );
+
+/**
+ * Get the proper value for BP's ajaxurl.
+ *
+ * Designed to be sensitive to FORCE_SSL_ADMIN and non-standard multisite
+ * configurations.
+ *
+ * @since BuddyPress (1.7.0)
+ *
+ * @return string AJAX endpoint URL.
+ */
+function bp_core_ajax_url() {
+	return apply_filters( 'bp_core_ajax_url', admin_url( 'admin-ajax.php', is_ssl() ? 'admin' : 'http' ) );
+}
Index: /tags/1.9/bp-core/bp-core-dependency.php
===================================================================
--- /tags/1.9/bp-core/bp-core-dependency.php	(revision 7684)
+++ /tags/1.9/bp-core/bp-core-dependency.php	(revision 7684)
@@ -0,0 +1,390 @@
+<?php
+
+/**
+ * Plugin Dependency Action Hooks.
+ *
+ * The purpose of the following hooks is to mimic the behavior of something
+ * called 'plugin dependency' which enables a plugin to have plugins of their
+ * own in a safe and reliable way.
+ *
+ * We do this in BuddyPress by mirroring existing WordPress hooks in many places
+ * allowing dependant plugins to hook into the BuddyPress specific ones, thus
+ * guaranteeing proper code execution only when BuddyPress is active.
+ *
+ * The following functions are wrappers for hooks, allowing them to be
+ * manually called and/or piggy-backed on top of other hooks if needed.
+ *
+ * @todo use anonymous functions when PHP minimun requirement allows (5.3)
+ */
+
+/**
+ * Fire the 'bp_include' action, where plugins should include files.
+ */
+function bp_include() {
+	do_action( 'bp_include' );
+}
+
+/**
+ * Fire the 'bp_setup_components' action, where plugins should initialize components.
+ */
+function bp_setup_components() {
+	do_action( 'bp_setup_components' );
+}
+
+/**
+ * Fire the 'bp_setup_globals' action, where plugins should initialize global settings.
+ */
+function bp_setup_globals() {
+	do_action( 'bp_setup_globals' );
+}
+
+/**
+ * Fire the 'bp_setup_nav' action, where plugins should register their navigation items.
+ */
+function bp_setup_nav() {
+	do_action( 'bp_setup_nav' );
+}
+
+/**
+ * Fire the 'bp_setup_admin_bar' action, where plugins should add items to the WP admin bar.
+ */
+function bp_setup_admin_bar() {
+	if ( bp_use_wp_admin_bar() )
+		do_action( 'bp_setup_admin_bar' );
+}
+
+/**
+ * Fire the 'bp_setup_title' action, where plugins should modify the page title.
+ */
+function bp_setup_title() {
+	do_action( 'bp_setup_title' );
+}
+
+/**
+ * Fire the 'bp_register_widgets' action, where plugins should register widgets.
+ */
+function bp_setup_widgets() {
+	do_action( 'bp_register_widgets' );
+}
+
+/**
+ * Set up the currently logged-in user.
+ *
+ * @uses did_action() To make sure the user isn't loaded out of order.
+ * @uses do_action() Calls 'bp_setup_current_user'.
+ */
+function bp_setup_current_user() {
+
+	// If the current user is being setup before the "init" action has fired,
+	// strange (and difficult to debug) role/capability issues will occur.
+	if ( ! did_action( 'after_setup_theme' ) ) {
+		_doing_it_wrong( __FUNCTION__, __( 'The current user is being initialized without using $wp->init().', 'buddypress' ), '1.7' );
+	}
+
+	do_action( 'bp_setup_current_user' );
+}
+
+/**
+ * Fire the 'bp_init' action, BuddyPress's main initialization hook.
+ */
+function bp_init() {
+	do_action( 'bp_init' );
+}
+
+/**
+ * Fire the 'bp_loaded' action, which fires after BP's core plugin files have been loaded.
+ *
+ * Attached to 'plugins_loaded'.
+ */
+function bp_loaded() {
+	do_action( 'bp_loaded' );
+}
+
+/**
+ * Fire the 'bp_ready' action, which runs after BP is set up and the page is about to render.
+ *
+ * Attached to 'wp'.
+ */
+function bp_ready() {
+	do_action( 'bp_ready' );
+}
+
+/**
+ * Fire the 'bp_actions' action, which runs just before rendering.
+ *
+ * Attach potential template actions, such as catching form requests or routing
+ * custom URLs.
+ */
+function bp_actions() {
+	do_action( 'bp_actions' );
+}
+
+/**
+ * Fire the 'bp_screens' action, which runs just before rendering.
+ *
+ * Runs just after 'bp_actions'. Use this hook to attach your template
+ * loaders.
+ */
+function bp_screens() {
+	do_action( 'bp_screens' );
+}
+
+/**
+ * Fire 'bp_widgets_init', which runs after widgets have been set up.
+ *
+ * Hooked to 'widgets_init'.
+ */
+function bp_widgets_init() {
+	do_action ( 'bp_widgets_init' );
+}
+
+/**
+ * Fire 'bp_head', which is used to hook scripts and styles in the <head>.
+ *
+ * Hooked to 'wp_head'.
+ */
+function bp_head() {
+	do_action ( 'bp_head' );
+}
+
+/** Theme Permissions *********************************************************/
+
+/**
+ * Fire the 'bp_template_redirect' action.
+ *
+ * Run at 'template_redirect', just before WordPress selects and loads a theme
+ * template. The main purpose of this hook in BuddyPress is to redirect users
+ * who do not have the proper permission to access certain content.
+ *
+ * @since BuddyPress (1.6.0)
+ *
+ * @uses do_action()
+ */
+function bp_template_redirect() {
+	do_action( 'bp_template_redirect' );
+}
+
+/** Theme Helpers *************************************************************/
+
+/**
+ * Fire the 'bp_register_theme_directory' action.
+ *
+ * The main action used registering theme directories.
+ *
+ * @since BuddyPress (1.5.0)
+ *
+ * @uses do_action()
+ */
+function bp_register_theme_directory() {
+	do_action( 'bp_register_theme_directory' );
+}
+
+/**
+ * Fire the 'bp_register_theme_packages' action.
+ *
+ * The main action used registering theme packages.
+ *
+ * @since BuddyPress (1.7.0)
+ *
+ * @uses do_action()
+ */
+function bp_register_theme_packages() {
+	do_action( 'bp_register_theme_packages' );
+}
+
+/**
+ * Fire the 'bp_enqueue_scripts' action, where BP enqueues its CSS and JS.
+ *
+ * @since BuddyPress (1.6.0)
+ *
+ * @uses do_action() Calls 'bp_enqueue_scripts'.
+ */
+function bp_enqueue_scripts() {
+	do_action ( 'bp_enqueue_scripts' );
+}
+
+/**
+ * Fire the 'bp_add_rewrite_tag' action, where BP adds its custom rewrite tags.
+ *
+ * @since BuddyPress (1.8.0)
+ *
+ * @uses do_action() Calls 'bp_add_rewrite_tags'.
+ */
+function bp_add_rewrite_tags() {
+	do_action( 'bp_add_rewrite_tags' );
+}
+
+/**
+ * Fire the 'bp_add_rewrite_rules' action, where BP adds its custom rewrite rules.
+ *
+ * @since BuddyPress (1.9.0)
+ *
+ * @uses do_action() Calls 'bp_add_rewrite_rules'.
+ */
+function bp_add_rewrite_rules() {
+	do_action( 'bp_add_rewrite_rules' );
+}
+
+/**
+ * Fire the 'bp_add_permastructs' action, where BP adds its BP-specific permalink structure.
+ *
+ * @since BuddyPress (1.9.0)
+ *
+ * @uses do_action() Calls 'bp_add_permastructs'.
+ */
+function bp_add_permastructs() {
+	do_action( 'bp_add_permastructs' );
+}
+
+/**
+ * Fire the 'bp_setup_theme' action.
+ *
+ * The main purpose of 'bp_setup_theme' is give themes a place to load their
+ * BuddyPress-specific functionality.
+ *
+ * @since BuddyPress (1.6.0)
+ *
+ * @uses do_action() Calls 'bp_setup_theme'.
+ */
+function bp_setup_theme() {
+	do_action ( 'bp_setup_theme' );
+}
+
+/**
+ * Fire the 'bp_after_setup_theme' action.
+ *
+ * Piggy-back action for BuddyPress-specific theme actions once the theme has
+ * been set up and the theme's functions.php has loaded.
+ *
+ * Hooked to 'after_setup_theme' with a priority of 100. This allows plenty of
+ * time for other themes to load their features, such as BuddyPress support,
+ * before our theme compatibility layer kicks in.
+ *
+ * @since BuddyPress (1.6.0)
+ *
+ * @uses do_action() Calls 'bp_after_setup_theme'.
+ */
+function bp_after_setup_theme() {
+	do_action ( 'bp_after_setup_theme' );
+}
+
+/** Theme Compatibility Filter ************************************************/
+
+/**
+ * Fire the 'bp_request' filter, a piggy-back of WP's 'request'.
+ *
+ * @since BuddyPress (1.7.0)
+ *
+ * @see WP::parse_request() for a description of parameters.
+ *
+ * @param array $query_vars See {@link WP::parse_request()}.
+ * @return array $query_vars See {@link WP::parse_request()}.
+ */
+function bp_request( $query_vars = array() ) {
+	return apply_filters( 'bp_request', $query_vars );
+}
+
+/**
+ * Fire the 'bp_login_redirect' filter, a piggy-back of WP's 'login_redirect'.
+ *
+ * @since BuddyPress (1.7.0)
+ *
+ * @param string $redirect_to See 'login_redirect'.
+ * @param string $redirect_to_raw See 'login_redirect'.
+ * @param string $user See 'login_redirect'.
+ */
+function bp_login_redirect( $redirect_to = '', $redirect_to_raw = '', $user = false ) {
+	return apply_filters( 'bp_login_redirect', $redirect_to, $redirect_to_raw, $user );
+}
+
+/**
+ * Fire 'bp_template_include', main filter used for theme compatibility and displaying custom BP theme files.
+ *
+ * Hooked to 'template_include'.
+ *
+ * @since BuddyPress (1.6.0)
+ *
+ * @uses apply_filters()
+ *
+ * @param string $template See 'template_include'.
+ * @return string Template file to use.
+ */
+function bp_template_include( $template = '' ) {
+	return apply_filters( 'bp_template_include', $template );
+}
+
+/**
+ * Fire the 'bp_generate_rewrite_rules' filter, where BP generates its rewrite rules.
+ *
+ * @since BuddyPress (1.7.0)
+ *
+ * @uses do_action() Calls 'bp_generate_rewrite_rules' with {@link WP_Rewrite}.
+ *
+ * @param WP_Rewrite $wp_rewrite See 'generate_rewrite_rules'.
+ */
+function bp_generate_rewrite_rules( $wp_rewrite ) {
+	do_action_ref_array( 'bp_generate_rewrite_rules', array( &$wp_rewrite ) );
+}
+
+/**
+ * Fire the 'bp_allowed_themes' filter.
+ *
+ * Filter the allowed themes list for BuddyPress-specific themes.
+ *
+ * @since BuddyPress (1.7.0)
+ *
+ * @uses apply_filters() Calls 'bp_allowed_themes' with the allowed themes list.
+ */
+function bp_allowed_themes( $themes ) {
+	return apply_filters( 'bp_allowed_themes', $themes );
+}
+
+/** Requests ******************************************************************/
+
+/**
+ * The main action used for handling theme-side POST requests
+ *
+ * @since BuddyPress (1.9.0)
+ * @uses do_action()
+ */
+function bp_post_request() {
+
+	// Bail if not a POST action
+	if ( ! bp_is_post_request() )
+		return;
+
+	// Bail if no action
+	if ( empty( $_POST['action'] ) )
+		return;
+
+	// This dynamic action is probably the one you want to use. It narrows down
+	// the scope of the 'action' without needing to check it in your function.
+	do_action( 'bp_post_request_' . $_POST['action'] );
+
+	// Use this static action if you don't mind checking the 'action' yourself.
+	do_action( 'bp_post_request',   $_POST['action'] );
+}
+
+/**
+ * The main action used for handling theme-side GET requests
+ *
+ * @since BuddyPress (1.9.0)
+ * @uses do_action()
+ */
+function bp_get_request() {
+
+	// Bail if not a POST action
+	if ( ! bp_is_get_request() )
+		return;
+
+	// Bail if no action
+	if ( empty( $_GET['action'] ) )
+		return;
+
+	// This dynamic action is probably the one you want to use. It narrows down
+	// the scope of the 'action' without needing to check it in your function.
+	do_action( 'bp_get_request_' . $_GET['action'] );
+
+	// Use this static action if you don't mind checking the 'action' yourself.
+	do_action( 'bp_get_request',   $_GET['action'] );
+}
Index: /tags/1.9/bp-core/bp-core-filters.php
===================================================================
--- /tags/1.9/bp-core/bp-core-filters.php	(revision 7684)
+++ /tags/1.9/bp-core/bp-core-filters.php	(revision 7684)
@@ -0,0 +1,495 @@
+<?php
+
+/**
+ * BuddyPress Filters.
+ *
+ * This file contains the filters that are used throughout BuddyPress. They are
+ * consolidated here to make searching for them easier, and to help developers
+ * understand at a glance the order in which things occur.
+ *
+ * There are a few common places that additional filters can currently be found.
+ *
+ *  - BuddyPress: In {@link BuddyPress::setup_actions()} in buddypress.php
+ *  - Component: In {@link BP_Component::setup_actions()} in
+ *                bp-core/bp-core-component.php
+ *  - Admin: More in {@link BP_Admin::setup_actions()} in
+ *            bp-core/bp-core-admin.php
+ *
+ * @package BuddyPress
+ * @subpackage Core
+ * @see bp-core-actions.php
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/**
+ * Attach BuddyPress to WordPress.
+ *
+ * BuddyPress uses its own internal actions to help aid in third-party plugin
+ * development, and to limit the amount of potential future code changes when
+ * updates to WordPress core occur.
+ *
+ * These actions exist to create the concept of 'plugin dependencies'. They
+ * provide a safe way for plugins to execute code *only* when BuddyPress is
+ * installed and activated, without needing to do complicated guesswork.
+ *
+ * For more information on how this works, see the 'Plugin Dependency' section
+ * near the bottom of this file.
+ *
+ *           v--WordPress Actions       v--BuddyPress Sub-actions
+ */
+add_filter( 'request',                 'bp_request',             10    );
+add_filter( 'template_include',        'bp_template_include',    10    );
+add_filter( 'login_redirect',          'bp_login_redirect',      10, 3 );
+add_filter( 'map_meta_cap',            'bp_map_meta_caps',       10, 4 );
+
+// Add some filters to feedback messages
+add_filter( 'bp_core_render_message_content', 'wptexturize'       );
+add_filter( 'bp_core_render_message_content', 'convert_smilies'   );
+add_filter( 'bp_core_render_message_content', 'convert_chars'     );
+add_filter( 'bp_core_render_message_content', 'wpautop'           );
+add_filter( 'bp_core_render_message_content', 'shortcode_unautop' );
+add_filter( 'bp_core_render_message_content', 'wp_kses_data', 5   );
+
+/**
+ * Template Compatibility.
+ *
+ * If you want to completely bypass this and manage your own custom BuddyPress
+ * template hierarchy, start here by removing this filter, then look at how
+ * bp_template_include() works and do something similar. :)
+ */
+add_filter( 'bp_template_include',   'bp_template_include_theme_supports', 2, 1 );
+add_filter( 'bp_template_include',   'bp_template_include_theme_compat',   4, 2 );
+
+// Filter BuddyPress template locations
+add_filter( 'bp_get_template_stack', 'bp_add_template_stack_locations'          );
+
+// Turn comments off for BuddyPress pages
+add_filter( 'comments_open', 'bp_comments_open', 10, 2 );
+
+/**
+ * Prevent specific pages (eg 'Activate') from showing on page listings.
+ *
+ * @uses bp_is_active() checks if a BuddyPress component is active.
+ *
+ * @param array $pages List of excluded page IDs, as passed to the
+ *        'wp_list_pages_excludes' filter.
+ * @return array The exclude list, with BP's pages added.
+ */
+function bp_core_exclude_pages( $pages = array() ) {
+
+	// Bail if not the root blog
+	if ( ! bp_is_root_blog() )
+		return $pages;
+
+	$bp = buddypress();
+
+	if ( !empty( $bp->pages->activate ) )
+		$pages[] = $bp->pages->activate->id;
+
+	if ( !empty( $bp->pages->register ) )
+		$pages[] = $bp->pages->register->id;
+
+	if ( !empty( $bp->pages->forums ) && ( !bp_is_active( 'forums' ) || ( bp_is_active( 'forums' ) && bp_forums_has_directory() && !bp_forums_is_installed_correctly() ) ) )
+		$pages[] = $bp->pages->forums->id;
+
+	return apply_filters( 'bp_core_exclude_pages', $pages );
+}
+add_filter( 'wp_list_pages_excludes', 'bp_core_exclude_pages' );
+
+/**
+ * Set "From" name in outgoing email to the site name.
+ *
+ * @uses bp_get_option() fetches the value for a meta_key in the wp_X_options table.
+ *
+ * @return string The blog name for the root blog.
+ */
+function bp_core_email_from_name_filter() {
+ 	return apply_filters( 'bp_core_email_from_name_filter', bp_get_option( 'blogname', 'WordPress' ) );
+}
+add_filter( 'wp_mail_from_name', 'bp_core_email_from_name_filter' );
+
+/**
+ * Filter the blog post comments array and insert BuddyPress URLs for users.
+ *
+ * @param array $comments The array of comments supplied to the comments template.
+ * @param int $post->ID The post ID.
+ * @return array $comments The modified comment array.
+ */
+function bp_core_filter_comments( $comments, $post_id ) {
+	global $wpdb;
+
+	foreach( (array) $comments as $comment ) {
+		if ( $comment->user_id )
+			$user_ids[] = $comment->user_id;
+	}
+
+	if ( empty( $user_ids ) )
+		return $comments;
+
+	$user_ids = implode( ',', wp_parse_id_list( $user_ids ) );
+
+	if ( !$userdata = $wpdb->get_results( "SELECT ID as user_id, user_login, user_nicename FROM {$wpdb->users} WHERE ID IN ({$user_ids})" ) )
+		return $comments;
+
+	foreach( (array) $userdata as $user )
+		$users[$user->user_id] = bp_core_get_user_domain( $user->user_id, $user->user_nicename, $user->user_login );
+
+	foreach( (array) $comments as $i => $comment ) {
+		if ( !empty( $comment->user_id ) ) {
+			if ( !empty( $users[$comment->user_id] ) )
+				$comments[$i]->comment_author_url = $users[$comment->user_id];
+		}
+	}
+
+	return $comments;
+}
+add_filter( 'comments_array', 'bp_core_filter_comments', 10, 2 );
+
+/**
+ * When a user logs in, redirect him in a logical way.
+ *
+ * @uses apply_filters() Filter 'bp_core_login_redirect' to modify where users
+ *       are redirected to on login.
+ *
+ * @param string $redirect_to The URL to be redirected to, sanitized
+ *        in wp-login.php.
+ * @param string $redirect_to_raw The unsanitized redirect_to URL ($_REQUEST['redirect_to'])
+ * @param WP_User $user The WP_User object corresponding to a successfully
+ *        logged-in user. Otherwise a WP_Error object.
+ * @return string The redirect URL.
+ */
+function bp_core_login_redirect( $redirect_to, $redirect_to_raw, $user ) {
+
+	// Only modify the redirect if we're on the main BP blog
+	if ( !bp_is_root_blog() ) {
+		return $redirect_to;
+	}
+
+	// Only modify the redirect once the user is logged in
+	if ( !is_a( $user, 'WP_User' ) ) {
+		return $redirect_to;
+	}
+
+	// Allow plugins to allow or disallow redirects, as desired
+	$maybe_redirect = apply_filters( 'bp_core_login_redirect', false, $redirect_to, $redirect_to_raw, $user );
+	if ( false !== $maybe_redirect ) {
+		return $maybe_redirect;
+	}
+
+	// If a 'redirect_to' parameter has been passed that contains 'wp-admin', verify that the
+	// logged-in user has any business to conduct in the Dashboard before allowing the
+	// redirect to go through
+	if ( !empty( $redirect_to ) && ( false === strpos( $redirect_to, 'wp-admin' ) || user_can( $user, 'edit_posts' ) ) ) {
+		return $redirect_to;
+	}
+
+	if ( false === strpos( wp_get_referer(), 'wp-login.php' ) && false === strpos( wp_get_referer(), 'activate' ) && empty( $_REQUEST['nr'] ) ) {
+		return wp_get_referer();
+	}
+
+	return apply_filters( 'bp_core_login_redirect_to', bp_get_root_domain() );
+}
+add_filter( 'bp_login_redirect', 'bp_core_login_redirect', 10, 3 );
+
+/**
+ * Replace the generated password in the welcome email with '[User Set]'.
+ *
+ * On a standard BP installation, users who register themselves also set their
+ * own passwords. Therefore there is no need for the insecure practice of
+ * emailing the plaintext password to the user in the welcome email.
+ *
+ * This filter will not fire when a user is registered by the site admin.
+ *
+ * @param string $welcome_email Complete email passed through WordPress.
+ * @return string Filtered $welcome_email with the password replaced
+ *         by '[User Set]'.
+ */
+function bp_core_filter_user_welcome_email( $welcome_email ) {
+
+	// Don't touch the email if we don't have a custom registration template
+	if ( ! bp_has_custom_signup_page() )
+		return $welcome_email;
+
+	// [User Set] Replaces 'PASSWORD' in welcome email; Represents value set by user
+	return str_replace( 'PASSWORD', __( '[User Set]', 'buddypress' ), $welcome_email );
+}
+add_filter( 'update_welcome_user_email', 'bp_core_filter_user_welcome_email' );
+
+/**
+ * Replace the generated password in the welcome email with '[User Set]'.
+ *
+ * On a standard BP installation, users who register themselves also set their
+ * own passwords. Therefore there is no need for the insecure practice of
+ * emailing the plaintext password to the user in the welcome email.
+ *
+ * This filter will not fire when a user is registered by the site admin.
+ *
+ * @param string $welcome_email Complete email passed through WordPress.
+ * @param int $blog_id ID of the blog user is joining.
+ * @param int $user_id ID of the user joining.
+ * @param string $password Password of user.
+ * @return string Filtered $welcome_email with $password replaced by '[User Set]'.
+ */
+function bp_core_filter_blog_welcome_email( $welcome_email, $blog_id, $user_id, $password ) {
+
+	// Don't touch the email if we don't have a custom registration template
+	if ( ! bp_has_custom_signup_page() )
+		return $welcome_email;
+
+	// [User Set] Replaces $password in welcome email; Represents value set by user
+	return str_replace( $password, __( '[User Set]', 'buddypress' ), $welcome_email );
+}
+add_filter( 'update_welcome_email', 'bp_core_filter_blog_welcome_email', 10, 4 );
+
+/**
+ * Notify new users of a successful registration (with blog).
+ *
+ * This function filter's WP's 'wpmu_signup_blog_notification', and replaces
+ * WP's default welcome email with a BuddyPress-specific message.
+ *
+ * @see wpmu_signup_blog_notification() for a description of parameters.
+ *
+ * @param string $domain The new blog domain.
+ * @param string $path The new blog path.
+ * @param string $title The site title.
+ * @param string $user The user's login name.
+ * @param string $user_email The user's email address.
+ * @param string $key The activation key created in wpmu_signup_blog()
+ * @param array $meta By default, contains the requested privacy setting and
+ *        lang_id.
+ * @return bool True on success, false on failure.
+ */
+function bp_core_activation_signup_blog_notification( $domain, $path, $title, $user, $user_email, $key, $meta ) {
+
+	// Set up activation link
+	$activate_url = bp_get_activation_page() ."?key=$key";
+	$activate_url = esc_url( $activate_url );
+
+	// Email contents
+	$message = sprintf( __( "Thanks for registering! To complete the activation of your account and blog, please click the following link:\n\n%1\$s\n\n\n\nAfter you activate, you can visit your blog here:\n\n%2\$s", 'buddypress' ), $activate_url, esc_url( "http://{$domain}{$path}" ) );
+	$subject = bp_get_email_subject( array( 'text' => sprintf( __( 'Activate %s', 'buddypress' ), 'http://' . $domain . $path ) ) );
+
+	// Email filters
+	$to      = apply_filters( 'bp_core_activation_signup_blog_notification_to',   $user_email, $domain, $path, $title, $user, $user_email, $key, $meta );
+	$subject = apply_filters( 'bp_core_activation_signup_blog_notification_subject', $subject, $domain, $path, $title, $user, $user_email, $key, $meta );
+	$message = apply_filters( 'bp_core_activation_signup_blog_notification_message', $message, $domain, $path, $title, $user, $user_email, $key, $meta );
+
+	// Send the email
+	wp_mail( $to, $subject, $message );
+
+	// Set up the $admin_email to pass to the filter
+	$admin_email = bp_get_option( 'admin_email' );
+
+	do_action( 'bp_core_sent_blog_signup_email', $admin_email, $subject, $message, $domain, $path, $title, $user, $user_email, $key, $meta );
+
+	// Return false to stop the original WPMU function from continuing
+	return false;
+}
+add_filter( 'wpmu_signup_blog_notification', 'bp_core_activation_signup_blog_notification', 1, 7 );
+
+/**
+ * Notify new users of a successful registration (without blog).
+ *
+ * @see wpmu_signup_user_notification() for a full description of params.
+ *
+ * @param string $user The user's login name.
+ * @param string $user_email The user's email address.
+ * @param string $key The activation key created in wpmu_signup_user()
+ * @param array $meta By default, an empty array.
+ * @return bool True on success, false on failure.
+ */
+function bp_core_activation_signup_user_notification( $user, $user_email, $key, $meta ) {
+
+	// Set up activation link
+	$activate_url = bp_get_activation_page() . "?key=$key";
+	$activate_url = esc_url( $activate_url );
+
+	// Email contents
+	$message = sprintf( __( "Thanks for registering! To complete the activation of your account please click the following link:\n\n%1\$s\n\n", 'buddypress' ), $activate_url );
+	$subject = bp_get_email_subject( array( 'text' => __( 'Activate Your Account', 'buddypress' ) ) );
+
+	// Email filters
+	$to      = apply_filters( 'bp_core_activation_signup_user_notification_to',   $user_email, $user, $user_email, $key, $meta );
+	$subject = apply_filters( 'bp_core_activation_signup_user_notification_subject', $subject, $user, $user_email, $key, $meta );
+	$message = apply_filters( 'bp_core_activation_signup_user_notification_message', $message, $user, $user_email, $key, $meta );
+
+	// Send the email
+	wp_mail( $to, $subject, $message );
+
+	// Set up the $admin_email to pass to the filter
+	$admin_email = bp_get_option( 'admin_email' );
+
+	do_action( 'bp_core_sent_user_signup_email', $admin_email, $subject, $message, $user, $user_email, $key, $meta );
+
+	// Return false to stop the original WPMU function from continuing
+	return false;
+}
+add_filter( 'wpmu_signup_user_notification', 'bp_core_activation_signup_user_notification', 1, 4 );
+
+/**
+ * Filter the page title for BuddyPress pages.
+ *
+ * @since BuddyPress (1.5.0)
+ *
+ * @see wp_title()
+ * @global object $bp BuddyPress global settings.
+ *
+ * @param string $title Original page title.
+ * @param string $sep How to separate the various items within the page title.
+ * @param string $seplocation Direction to display title.
+ * @return string New page title.
+ */
+function bp_modify_page_title( $title, $sep, $seplocation ) {
+	global $bp;
+
+	// If this is not a BP page, just return the title produced by WP
+	if ( bp_is_blog_page() )
+		return $title;
+
+	// If this is a 404, let WordPress handle it
+	if ( is_404() ) {
+		return $title;
+	}
+
+	// If this is the front page of the site, return WP's title
+	if ( is_front_page() || is_home() )
+		return $title;
+
+	$title = '';
+
+	// Displayed user
+	if ( bp_get_displayed_user_fullname() && !is_404() ) {
+
+		// Get the component's ID to try and get it's name
+		$component_id = $component_name = bp_current_component();
+
+		// Use the actual component name
+		if ( !empty( $bp->{$component_id}->name ) ) {
+			$component_name = $bp->{$component_id}->name;
+
+		// Fall back on the component ID (probably same as current_component)
+		} elseif ( !empty( $bp->{$component_id}->id ) ) {
+			$component_name = $bp->{$component_id}->id;
+		}
+
+		// Construct the page title. 1 = user name, 2 = seperator, 3 = component name
+		$title = strip_tags( sprintf( _x( '%1$s %3$s %2$s', 'Construct the page title. 1 = user name, 2 = component name, 3 = seperator', 'buddypress' ), bp_get_displayed_user_fullname(), ucwords( $component_name ), $sep ) );
+
+	// A single group
+	} elseif ( bp_is_active( 'groups' ) && !empty( $bp->groups->current_group ) && !empty( $bp->bp_options_nav[$bp->groups->current_group->slug] ) ) {
+		$subnav = isset( $bp->bp_options_nav[$bp->groups->current_group->slug][bp_current_action()]['name'] ) ? $bp->bp_options_nav[$bp->groups->current_group->slug][bp_current_action()]['name'] : '';
+		// translators: "group name | group nav section name"
+		$title = sprintf( __( '%1$s | %2$s', 'buddypress' ), $bp->bp_options_title, $subnav );
+
+	// A single item from a component other than groups
+	} elseif ( bp_is_single_item() ) {
+		// translators: "component item name | component nav section name | root component name"
+		$title = sprintf( __( '%1$s | %2$s | %3$s', 'buddypress' ), $bp->bp_options_title, $bp->bp_options_nav[bp_current_item()][bp_current_action()]['name'], bp_get_name_from_root_slug( bp_get_root_slug() ) );
+
+	// An index or directory
+	} elseif ( bp_is_directory() ) {
+		if ( !bp_current_component() ) {
+			$title = sprintf( __( '%s Directory', 'buddypress' ), bp_get_name_from_root_slug() );
+		} else {
+			$title = sprintf( __( '%s Directory', 'buddypress' ), bp_get_name_from_root_slug() );
+		}
+
+	// Sign up page
+	} elseif ( bp_is_register_page() ) {
+		$title = __( 'Create an Account', 'buddypress' );
+
+	// Activation page
+	} elseif ( bp_is_activation_page() ) {
+		$title = __( 'Activate your Account', 'buddypress' );
+
+	// Group creation page
+	} elseif ( bp_is_group_create() ) {
+		$title = __( 'Create a Group', 'buddypress' );
+
+	// Blog creation page
+	} elseif ( bp_is_create_blog() ) {
+		$title = __( 'Create a Site', 'buddypress' );
+	}
+
+	// Some BP nav items contain item counts. Remove them
+	$title = preg_replace( '|<span>[0-9]+</span>|', '', $title );
+
+	return apply_filters( 'bp_modify_page_title', $title . ' ' . $sep . ' ', $title, $sep, $seplocation );
+}
+add_filter( 'wp_title', 'bp_modify_page_title', 10, 3 );
+add_filter( 'bp_modify_page_title', 'wptexturize'     );
+add_filter( 'bp_modify_page_title', 'convert_chars'   );
+add_filter( 'bp_modify_page_title', 'esc_html'        );
+
+/**
+ * Add BuddyPress-specific items to the wp_nav_menu.
+ *
+ * @since BuddyPress (1.9.0)
+ *
+ * @param WP_Post $menu_item The menu item.
+ * @return obj The modified WP_Post object.
+ */
+function bp_setup_nav_menu_item( $menu_item ) {
+	if ( is_admin() ) {
+		return $menu_item;
+	}
+
+	// We use information stored in the CSS class to determine what kind of
+	// menu item this is, and how it should be treated
+	$css_target = preg_match( '/\sbp-(.*)-nav/', implode( ' ', $menu_item->classes), $matches );
+
+	// If this isn't a BP menu item, we can stop here
+	if ( empty( $matches[1] ) ) {
+		return $menu_item;
+	}
+
+	switch ( $matches[1] ) {
+		case 'login' :
+			if ( is_user_logged_in() ) {
+				$menu_item->_invalid = true;
+			} else {
+				$menu_item->url = wp_login_url( wp_guess_url() );
+			}
+
+			break;
+
+		case 'logout' :
+			if ( ! is_user_logged_in() ) {
+				$menu_item->_invalid = true;
+			} else {
+				$menu_item->url = wp_logout_url( wp_guess_url() );
+			}
+
+			break;
+
+		// Don't show the Register link to logged-in users
+		case 'register' :
+			if ( is_user_logged_in() ) {
+				$menu_item->_invalid = true;
+			}
+
+			break;
+
+		// All other BP nav items are specific to the logged-in user,
+		// and so are not relevant to logged-out users
+		default:
+			if ( is_user_logged_in() ) {
+				$menu_item->url = bp_nav_menu_get_item_url( $matches[1] );
+			} else {
+				$menu_item->_invalid = true;
+			}
+
+			break;
+	}
+
+	// Highlight the current page
+	$current = bp_get_requested_url();
+	if ( strpos( $current, $menu_item->url ) !== false ) {
+		$menu_item->classes[] = 'current_page_item';
+	}
+
+	return $menu_item;
+}
+add_filter( 'wp_setup_nav_menu_item', 'bp_setup_nav_menu_item', 10, 1 );
Index: /tags/1.9/bp-core/bp-core-functions.php
===================================================================
--- /tags/1.9/bp-core/bp-core-functions.php	(revision 7684)
+++ /tags/1.9/bp-core/bp-core-functions.php	(revision 7684)
@@ -0,0 +1,1788 @@
+<?php
+
+/**
+ * BuddyPress Common Functions.
+ *
+ * @package BuddyPress
+ * @subpackage Functions
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/** Versions ******************************************************************/
+
+/**
+ * Output the BuddyPress version.
+ *
+ * @since BuddyPress (1.6.0)
+ *
+ * @uses bp_get_version() To get the BuddyPress version.
+ */
+function bp_version() {
+	echo bp_get_version();
+}
+	/**
+	 * Return the BuddyPress version.
+	 *
+	 * @since BuddyPress (1.6.0)
+	 *
+	 * @return string The BuddyPress version.
+	 */
+	function bp_get_version() {
+		return buddypress()->version;
+	}
+
+/**
+ * Output the BuddyPress database version.
+ *
+ * @since BuddyPress (1.6.0)
+ *
+ * @uses bp_get_db_version() To get the BuddyPress database version.
+ */
+function bp_db_version() {
+	echo bp_get_db_version();
+}
+	/**
+	 * Return the BuddyPress database version.
+	 *
+	 * @since BuddyPress (1.6.0)
+	 * @return string The BuddyPress database version.
+	 */
+	function bp_get_db_version() {
+		return buddypress()->db_version;
+	}
+
+/**
+ * Output the BuddyPress database version.
+ *
+ * @since BuddyPress (1.6.0)
+ *
+ * @uses bp_get_db_version_raw() To get the current database BuddyPress version.
+ */
+function bp_db_version_raw() {
+	echo bp_get_db_version_raw();
+}
+	/**
+	 * Return the BuddyPress database version
+	 *
+	 * @since BuddyPress (1.6)
+	 *
+	 * @return string The BuddyPress version direct from the database.
+	 */
+	function bp_get_db_version_raw() {
+		$bp     = buddypress();
+		return !empty( $bp->db_version_raw ) ? $bp->db_version_raw : 0;
+	}
+
+/** Functions *****************************************************************/
+
+/**
+ * Get the $wpdb base prefix, run through the 'bp_core_get_table_prefix' filter.
+ *
+ * The filter is intended primarily for use in multinetwork installations.
+ *
+ * @global object $wpdb WordPress database object.
+ *
+ * @return string Filtered database prefix.
+ */
+function bp_core_get_table_prefix() {
+	global $wpdb;
+
+	return apply_filters( 'bp_core_get_table_prefix', $wpdb->base_prefix );
+}
+
+/**
+ * Sort an array of objects or arrays by alphabetically sorting by a specific key/property.
+ *
+ * For instance, if you have an array of WordPress post objects, you can sort
+ * them by post_name as follows:
+ *     $sorted_posts = bp_alpha_sort_by_key( $posts, 'post_name' );
+ *
+ * The main purpose for this function is so that you can avoid having to create
+ * your own awkward callback function for usort().
+ *
+ * @since BuddyPress (1.9.0)
+ *
+ * @param array $items The array to be sorted. Its constituent items can be
+ *        either associative arrays or objects.
+ * @param string|int $key The array index or property name to sort by.
+ * @return array $items The sorted array.
+ */
+function bp_alpha_sort_by_key( $items, $key ) {
+	usort( $items, create_function( '$a, $b', '
+		$values = array( 0 => false, 1 => false, );
+		foreach ( func_get_args() as $indexi => $index ) {
+			if ( isset( $index->' . $key . ' ) ) {
+				$values[ $indexi ] = $index->' . $key . ';
+			} else if ( isset( $index["' . $key . '"] ) ) {
+				$values[ $indexi ] = $index["' . $key . '"];
+			}
+		}
+
+		if ( $values[0] && $values[1] ) {
+			$cmp = strcmp( $values[0], $values[1] );
+			if ( 0 > $cmp ) {
+				$retval = -1;
+			} else if ( 0 < $cmp ) {
+				$retval = 1;
+			} else {
+				$retval = 0;
+			}
+			return $retval;
+		} else {
+			return 0;
+		}
+	') );
+
+	return $items;
+}
+
+/**
+ * Format numbers the BuddyPress way.
+ *
+ * @param int $number The number to be formatted.
+ * @param bool $decimals Whether to use decimals. See {@link number_format_i18n()}.
+ * @return string The formatted number.
+ */
+function bp_core_number_format( $number, $decimals = false ) {
+
+	// Force number to 0 if needed
+	if ( empty( $number ) )
+		$number = 0;
+
+	return apply_filters( 'bp_core_number_format', number_format_i18n( $number, $decimals ), $number, $decimals );
+}
+
+/**
+ * A utility for parsing individual function arguments into an array.
+ *
+ * The purpose of this function is to help with backward compatibility in cases where
+ *
+ *   function foo( $bar = 1, $baz = false, $barry = array(), $blip = false ) { // ...
+ *
+ * is deprecated in favor of
+ *
+ *   function foo( $args = array() ) {
+ *       $defaults = array(
+ *           'bar'  => 1,
+ *           'arg2' => false,
+ *           'arg3' => array(),
+ *           'arg4' => false,
+ *       );
+ *       $r = wp_parse_args( $args, $defaults ); // ...
+ *
+ * The first argument, $old_args_keys, is an array that matches the parameter positions (keys) to
+ * the new $args keys (values):
+ *
+ *   $old_args_keys = array(
+ *       0 => 'bar', // because $bar was the 0th parameter for foo()
+ *       1 => 'baz', // because $baz was the 1st parameter for foo()
+ *       2 => 'barry', // etc
+ *       3 => 'blip'
+ *   );
+ *
+ * For the second argument, $func_args, you should just pass the value of func_get_args().
+ *
+ * @since BuddyPress (1.6)
+ * @param array $old_args_keys Old argument indexs, keyed to their positions.
+ * @param array $func_args The parameters passed to the originating function.
+ * @return array $new_args The parsed arguments.
+ */
+function bp_core_parse_args_array( $old_args_keys, $func_args ) {
+	$new_args = array();
+
+	foreach( $old_args_keys as $arg_num => $arg_key ) {
+		if ( isset( $func_args[$arg_num] ) ) {
+			$new_args[$arg_key] = $func_args[$arg_num];
+		}
+	}
+
+	return $new_args;
+}
+
+/**
+ * Sanitize an 'order' parameter for use in building SQL queries.
+ *
+ * Strings like 'DESC', 'desc', ' desc' will be interpreted into 'DESC'.
+ * Everything else becomes 'ASC'.
+ *
+ * @since BuddyPress (1.8.0)
+ *
+ * @param string $order The 'order' string, as passed to the SQL constructor.
+ * @return string The sanitized value 'DESC' or 'ASC'.
+ */
+function bp_esc_sql_order( $order = '' ) {
+	$order = strtoupper( trim( $order ) );
+	return 'DESC' === $order ? 'DESC' : 'ASC';
+}
+
+/**
+ * Are we running username compatibility mode?
+ *
+ * @since BuddyPress (1.5.0)
+ *
+ * @uses apply_filters() Filter 'bp_is_username_compatibility_mode' to alter.
+ * @todo Move to members component?
+ *
+ * @return bool False when compatibility mode is disabled, true when enabled.
+ *         Default: false.
+ */
+function bp_is_username_compatibility_mode() {
+	return apply_filters( 'bp_is_username_compatibility_mode', defined( 'BP_ENABLE_USERNAME_COMPATIBILITY_MODE' ) && BP_ENABLE_USERNAME_COMPATIBILITY_MODE );
+}
+
+/**
+ * Should we use the WP Toolbar?
+ *
+ * The WP Toolbar, introduced in WP 3.1, is fully supported in BuddyPress as
+ * of BP 1.5. For BP 1.6, the WP Toolbar is the default.
+ *
+ * @since BuddyPress (1.5.0)
+ *
+ * @uses apply_filters() Filter 'bp_use_wp_admin_bar' to alter.
+ *
+ * @return bool False when WP Toolbar support is disabled, true when enabled.
+ *        Default: true.
+ */
+function bp_use_wp_admin_bar() {
+	$use_admin_bar = true;
+
+	// Has the WP Toolbar constant been explicity set?
+	if ( defined( 'BP_USE_WP_ADMIN_BAR' ) && ! BP_USE_WP_ADMIN_BAR )
+		$use_admin_bar = false;
+
+	// Has the admin chosen to use the BuddyBar during an upgrade?
+	elseif ( (bool) bp_get_option( '_bp_force_buddybar', false ) )
+		$use_admin_bar = false;
+
+	return apply_filters( 'bp_use_wp_admin_bar', $use_admin_bar );
+}
+
+/** Directory *****************************************************************/
+
+/**
+ * Fetch a list of BP directory pages from the appropriate meta table.
+ *
+ * @since BuddyPress (1.5.0)
+ *
+ * @return array|string An array of page IDs, keyed by component names, or an
+ *         empty string if the list is not found.
+ */
+function bp_core_get_directory_page_ids() {
+	$page_ids = bp_get_option( 'bp-pages' );
+
+	// Ensure that empty indexes are unset. Should only matter in edge cases
+	if ( !empty( $page_ids ) && is_array( $page_ids ) ) {
+		foreach( (array) $page_ids as $component_name => $page_id ) {
+			if ( empty( $component_name ) || empty( $page_id ) ) {
+				unset( $page_ids[$component_name] );
+			}
+		}
+	}
+
+	return apply_filters( 'bp_core_get_directory_page_ids', $page_ids );
+}
+
+/**
+ * Store the list of BP directory pages in the appropriate meta table.
+ *
+ * bp-pages data is stored in site_options (falls back to options on non-MS),
+ * in an array keyed by blog_id. This allows you to change your
+ * bp_get_root_blog_id() and go through the setup process again.
+ *
+ * @since BuddyPress (1.5.0)
+ *
+ * @param array $blog_page_ids The IDs of the WP pages corresponding to BP
+ *        component directories.
+ */
+function bp_core_update_directory_page_ids( $blog_page_ids ) {
+	bp_update_option( 'bp-pages', $blog_page_ids );
+}
+
+/**
+ * Get names and slugs for BuddyPress component directory pages.
+ *
+ * @since BuddyPress (1.5.0).
+ *
+ * @return object Page names, IDs, and slugs.
+ */
+function bp_core_get_directory_pages() {
+	global $wpdb;
+
+	// Set pages as standard class
+	$pages = new stdClass;
+
+	// Get pages and IDs
+	$page_ids = bp_core_get_directory_page_ids();
+	if ( !empty( $page_ids ) ) {
+
+		// Always get page data from the root blog, except on multiblog mode, when it comes
+		// from the current blog
+		$posts_table_name = bp_is_multiblog_mode() ? $wpdb->posts : $wpdb->get_blog_prefix( bp_get_root_blog_id() ) . 'posts';
+		$page_ids_sql     = implode( ',', wp_parse_id_list( $page_ids ) );
+		$page_names       = $wpdb->get_results( "SELECT ID, post_name, post_parent, post_title FROM {$posts_table_name} WHERE ID IN ({$page_ids_sql}) AND post_status = 'publish' " );
+
+		foreach ( (array) $page_ids as $component_id => $page_id ) {
+			foreach ( (array) $page_names as $page_name ) {
+				if ( $page_name->ID == $page_id ) {
+					if ( !isset( $pages->{$component_id} ) || !is_object( $pages->{$component_id} ) ) {
+						$pages->{$component_id} = new stdClass;
+					}
+
+					$pages->{$component_id}->name  = $page_name->post_name;
+					$pages->{$component_id}->id    = $page_name->ID;
+					$pages->{$component_id}->title = $page_name->post_title;
+					$slug[]                        = $page_name->post_name;
+
+					// Get the slug
+					while ( $page_name->post_parent != 0 ) {
+						$parent                 = $wpdb->get_results( $wpdb->prepare( "SELECT post_name, post_parent FROM {$posts_table_name} WHERE ID = %d", $page_name->post_parent ) );
+						$slug[]                 = $parent[0]->post_name;
+						$page_name->post_parent = $parent[0]->post_parent;
+					}
+
+					$pages->{$component_id}->slug = implode( '/', array_reverse( (array) $slug ) );
+				}
+
+				unset( $slug );
+			}
+		}
+	}
+
+	return apply_filters( 'bp_core_get_directory_pages', $pages );
+}
+
+/**
+ * Creates necessary directory pages.
+ *
+ * Directory pages are those WordPress pages used by BP components to display
+ * content (eg, the 'groups' page created by BP).
+ *
+ * @since BuddyPress (1.7.0)
+ *
+ * @param array $default_components Components to create pages for.
+ * @param string $existing 'delete' if you want to delete existing page
+ *        mappings and replace with new ones. Otherwise existing page mappings
+ *        are kept, and the gaps filled in with new pages. Default: 'keep'.
+ */
+function bp_core_add_page_mappings( $components, $existing = 'keep' ) {
+
+	// Make sure that the pages are created on the root blog no matter which Dashboard the setup is being run on
+	if ( ! bp_is_root_blog() )
+		switch_to_blog( bp_get_root_blog_id() );
+
+	$pages = bp_core_get_directory_page_ids();
+
+	// Delete any existing pages
+	if ( 'delete' == $existing ) {
+		foreach ( (array) $pages as $page_id ) {
+			wp_delete_post( $page_id, true );
+		}
+
+		$pages = array();
+	}
+
+	$page_titles = array(
+		'activity' => _x( 'Activity', 'Page title for the Activity directory.', 'buddypress' ),
+		'groups'   => _x( 'Groups', 'Page title for the Groups directory.', 'buddypress' ),
+		'sites'    => _x( 'Sites', 'Page title for the Sites directory.', 'buddypress' ),
+		'activate' => _x( 'Activate', 'Page title for the user account activation screen.', 'buddypress' ),
+		'members'  => _x( 'Members', 'Page title for the Members directory.', 'buddypress' ),
+		'register' => _x( 'Register', 'Page title for the user registration screen.', 'buddypress' ),
+	);
+
+	$pages_to_create = array();
+	foreach ( array_keys( $components ) as $component_name ) {
+		if ( ! isset( $pages[ $component_name ] ) && isset( $page_titles[ $component_name ] ) ) {
+			$pages_to_create[ $component_name ] = $page_titles[ $component_name ];
+		}
+	}
+
+	// Register and Activate are not components, but need pages when
+	// registration is enabled
+	if ( bp_get_signup_allowed() ) {
+		foreach ( array( 'register', 'activate' ) as $slug ) {
+			if ( ! isset( $pages[ $slug ] ) ) {
+				$pages_to_create[ $slug ] = $page_titles[ $slug ];
+			}
+		}
+	}
+
+	// No need for a Sites directory unless we're on multisite
+	if ( ! is_multisite() && isset( $pages_to_create['sites'] ) ) {
+		unset( $pages_to_create['sites'] );
+	}
+
+	// Members must always have a page, no matter what
+	if ( ! isset( $pages['members'] ) && ! isset( $pages_to_create['members'] ) ) {
+		$pages_to_create['members'] = $page_titles['members'];
+	}
+
+	// Create the pages
+	foreach ( $pages_to_create as $component_name => $page_name ) {
+		$pages[ $component_name ] = wp_insert_post( array(
+			'comment_status' => 'closed',
+			'ping_status'    => 'closed',
+			'post_status'    => 'publish',
+			'post_title'     => $page_name,
+			'post_type'      => 'page',
+		) );
+	}
+
+	// Save the page mapping
+	bp_update_option( 'bp-pages', $pages );
+
+	// If we had to switch_to_blog, go back to the original site.
+	if ( ! bp_is_root_blog() )
+		restore_current_blog();
+}
+
+/**
+ * Create a default component slug from a WP page root_slug.
+ *
+ * Since 1.5, BP components get their root_slug (the slug used immediately
+ * following the root domain) from the slug of a corresponding WP page.
+ *
+ * E.g. if your BP installation at example.com has its members page at
+ * example.com/community/people, $bp->members->root_slug will be
+ * 'community/people'.
+ *
+ * By default, this function creates a shorter version of the root_slug for
+ * use elsewhere in the URL, by returning the content after the final '/'
+ * in the root_slug ('people' in the example above).
+ *
+ * Filter on 'bp_core_component_slug_from_root_slug' to override this method
+ * in general, or define a specific component slug constant (e.g.
+ * BP_MEMBERS_SLUG) to override specific component slugs.
+ *
+ * @since BuddyPress (1.5.0)
+ *
+ * @param string $root_slug The root slug, which comes from $bp->pages->[component]->slug.
+ * @return string The short slug for use in the middle of URLs.
+ */
+function bp_core_component_slug_from_root_slug( $root_slug ) {
+	$slug_chunks = explode( '/', $root_slug );
+ 	$slug        = array_pop( $slug_chunks );
+
+ 	return apply_filters( 'bp_core_component_slug_from_root_slug', $slug, $root_slug );
+}
+
+/**
+ * Add support for a top-level ("root") component.
+ *
+ * This function originally (pre-1.5) let plugins add support for pages in the
+ * root of the install. These root level pages are now handled by actual
+ * WordPress pages and this function is now a convenience for compatibility
+ * with the new method.
+ *
+ * @param string $slug The slug of the component being added to the root list.
+ */
+function bp_core_add_root_component( $slug ) {
+	$bp = buddypress();
+
+	if ( empty( $bp->pages ) ) {
+		$bp->pages = bp_core_get_directory_pages();
+	}
+
+	$match = false;
+
+	// Check if the slug is registered in the $bp->pages global
+	foreach ( (array) $bp->pages as $key => $page ) {
+		if ( $key == $slug || $page->slug == $slug ) {
+			$match = true;
+		}
+	}
+
+	// Maybe create the add_root array
+	if ( empty( $bp->add_root ) ) {
+		$bp->add_root = array();
+	}
+
+	// If there was no match, add a page for this root component
+	if ( empty( $match ) ) {
+		$bp->add_root[] = $slug;
+	}
+
+	// Make sure that this component is registered as requiring a top-level directory
+	if ( isset( $bp->{$slug} ) ) {
+		$bp->loaded_components[$bp->{$slug}->slug] = $bp->{$slug}->id;
+		$bp->{$slug}->has_directory = true;
+	}
+}
+
+/**
+ * Create WordPress pages to be used as BP component directories.
+ */
+function bp_core_create_root_component_page() {
+	global $bp;
+
+	$new_page_ids = array();
+
+	foreach ( (array) $bp->add_root as $slug )
+		$new_page_ids[$slug] = wp_insert_post( array( 'comment_status' => 'closed', 'ping_status' => 'closed', 'post_title' => ucwords( $slug ), 'post_status' => 'publish', 'post_type' => 'page' ) );
+
+	$page_ids = array_merge( (array) $new_page_ids, (array) bp_core_get_directory_page_ids() );
+	bp_core_update_directory_page_ids( $page_ids );
+}
+
+/**
+ * Add illegal blog names to WP so that root components will not conflict with blog names on a subdirectory installation.
+ *
+ * For example, it would stop someone creating a blog with the slug "groups".
+ *
+ * @todo Deprecate?
+ */
+function bp_core_add_illegal_names() {
+	update_site_option( 'illegal_names', get_site_option( 'illegal_names' ), array() );
+}
+
+/**
+ * Determine whether BuddyPress should register the bp-themes directory.
+ *
+ * @since BuddyPress (1.9.0)
+ *
+ * @return bool True if bp-themes should be registered, false otherwise.
+ */
+function bp_do_register_theme_directory() {
+	$register = 'bp-default' === get_stylesheet() || 'bp-default' === get_template();
+	return apply_filters( 'bp_do_register_theme_directory', $register );
+}
+
+/** URI ***********************************************************************/
+
+/**
+ * Return the domain for the root blog.
+ *
+ * eg: http://domain.com OR https://domain.com
+ *
+ * @uses get_blog_option() WordPress function to fetch blog meta.
+ *
+ * @return string The domain URL for the blog.
+ */
+function bp_core_get_root_domain() {
+
+	$domain = get_home_url( bp_get_root_blog_id() );
+
+	return apply_filters( 'bp_core_get_root_domain', $domain );
+}
+
+/**
+ * Perform a status-safe wp_redirect() that is compatible with BP's URI parser.
+ *
+ * @uses wp_safe_redirect()
+ *
+ * @param string $location The redirect URL.
+ * @param int $status Optional. The numeric code to give in the redirect
+ *        headers. Default: 302.
+ */
+function bp_core_redirect( $location, $status = 302 ) {
+
+	// On some setups, passing the value of wp_get_referer() may result in an
+	// empty value for $location, which results in an error. Ensure that we
+	// have a valid URL.
+	if ( empty( $location ) )
+		$location = bp_get_root_domain();
+
+	// Make sure we don't call status_header() in bp_core_do_catch_uri() as this
+	// conflicts with wp_redirect() and wp_safe_redirect().
+	buddypress()->no_status_set = true;
+
+	wp_safe_redirect( $location, $status );
+	die;
+}
+
+/**
+ * Return the referrer URL without the http(s)://
+ *
+ * @return string The referrer URL.
+ */
+function bp_core_referrer() {
+	$referer = explode( '/', wp_get_referer() );
+	unset( $referer[0], $referer[1], $referer[2] );
+	return implode( '/', $referer );
+}
+
+/**
+ * Get the path of of the current site.
+ *
+ * @global object $current_site
+ *
+ * @return string URL to the current site.
+ */
+function bp_core_get_site_path() {
+	global $current_site;
+
+	if ( is_multisite() )
+		$site_path = $current_site->path;
+	else {
+		$site_path = (array) explode( '/', home_url() );
+
+		if ( count( $site_path ) < 2 )
+			$site_path = '/';
+		else {
+			// Unset the first three segments (http(s)://domain.com part)
+			unset( $site_path[0] );
+			unset( $site_path[1] );
+			unset( $site_path[2] );
+
+			if ( !count( $site_path ) )
+				$site_path = '/';
+			else
+				$site_path = '/' . implode( '/', $site_path ) . '/';
+		}
+	}
+
+	return apply_filters( 'bp_core_get_site_path', $site_path );
+}
+
+/** Time **********************************************************************/
+
+/**
+ * Get the current GMT time to save into the DB.
+ *
+ * @since BuddyPress (1.2.6)
+ *
+ * @param bool $gmt True to use GMT (rather than local) time. Default: true.
+ * @return string Current time in 'Y-m-d h:i:s' format.
+ */
+function bp_core_current_time( $gmt = true ) {
+	// Get current time in MYSQL format
+	$current_time = current_time( 'mysql', $gmt );
+
+	return apply_filters( 'bp_core_current_time', $current_time );
+}
+
+/**
+ * Get an English-language representation of the time elapsed since a given date.
+ *
+ * Based on function created by Dunstan Orchard - http://1976design.com
+ *
+ * This function will return an English representation of the time elapsed
+ * since a given date.
+ * eg: 2 hours and 50 minutes
+ * eg: 4 days
+ * eg: 4 weeks and 6 days
+ *
+ * Note that fractions of minutes are not represented in the return string. So
+ * an interval of 3 minutes will be represented by "3 minutes ago", as will an
+ * interval of 3 minutes 59 seconds.
+ *
+ * @uses apply_filters() Filter 'bp_core_time_since_pre' to bypass BP's calculations.
+ * @uses apply_filters() Filter 'bp_core_time_since' to modify BP's calculations.
+ *
+ * @param int|string $older_date The earlier time from which you're calculating
+ *        the time elapsed. Enter either as an integer Unix timestamp, or as a
+ *        date string of the format 'Y-m-d h:i:s'.
+ * @param int $newer_date Optional. Unix timestamp of date to compare older
+ *        date to. Default: false (current time).
+ * @return string String representing the time since the older date, eg
+ *         "2 hours and 50 minutes".
+ */
+function bp_core_time_since( $older_date, $newer_date = false ) {
+
+	// Use this filter to bypass BuddyPress's time_since calculations
+	if ( $pre_value = apply_filters( 'bp_core_time_since_pre', false, $older_date, $newer_date ) ) {
+		return $pre_value;
+	}
+
+	// Setup the strings
+	$unknown_text   = apply_filters( 'bp_core_time_since_unknown_text',   __( 'sometime',  'buddypress' ) );
+	$right_now_text = apply_filters( 'bp_core_time_since_right_now_text', __( 'right now', 'buddypress' ) );
+	$ago_text       = apply_filters( 'bp_core_time_since_ago_text',       __( '%s ago',    'buddypress' ) );
+
+	// array of time period chunks
+	$chunks = array(
+		YEAR_IN_SECONDS,
+		30 * DAY_IN_SECONDS,
+		WEEK_IN_SECONDS,
+		DAY_IN_SECONDS,
+		HOUR_IN_SECONDS,
+		MINUTE_IN_SECONDS,
+		1
+	);
+
+	if ( !empty( $older_date ) && !is_numeric( $older_date ) ) {
+		$time_chunks = explode( ':', str_replace( ' ', ':', $older_date ) );
+		$date_chunks = explode( '-', str_replace( ' ', '-', $older_date ) );
+		$older_date  = gmmktime( (int) $time_chunks[1], (int) $time_chunks[2], (int) $time_chunks[3], (int) $date_chunks[1], (int) $date_chunks[2], (int) $date_chunks[0] );
+	}
+
+	/**
+	 * $newer_date will equal false if we want to know the time elapsed between
+	 * a date and the current time. $newer_date will have a value if we want to
+	 * work out time elapsed between two known dates.
+	 */
+	$newer_date = ( !$newer_date ) ? strtotime( bp_core_current_time() ) : $newer_date;
+
+	// Difference in seconds
+	$since = $newer_date - $older_date;
+
+	// Something went wrong with date calculation and we ended up with a negative date.
+	if ( 0 > $since ) {
+		$output = $unknown_text;
+
+	/**
+	 * We only want to output two chunks of time here, eg:
+	 * x years, xx months
+	 * x days, xx hours
+	 * so there's only two bits of calculation below:
+	 */
+	} else {
+
+		// Step one: the first chunk
+		for ( $i = 0, $j = count( $chunks ); $i < $j; ++$i ) {
+			$seconds = $chunks[$i];
+
+			// Finding the biggest chunk (if the chunk fits, break)
+			$count = floor( $since / $seconds );
+			if ( 0 != $count ) {
+				break;
+			}
+		}
+
+		// If $i iterates all the way to $j, then the event happened 0 seconds ago
+		if ( !isset( $chunks[$i] ) ) {
+			$output = $right_now_text;
+
+		} else {
+
+			// Set output var
+			switch ( $seconds ) {
+				case YEAR_IN_SECONDS :
+					$output = sprintf( _n( '%s year',   '%s years',   $count, 'buddypress' ), $count );
+					break;
+				case 30 * DAY_IN_SECONDS :
+					$output = sprintf( _n( '%s month',  '%s months',  $count, 'buddypress' ), $count );
+					break;
+				case WEEK_IN_SECONDS :
+					$output = sprintf( _n( '%s week',   '%s weeks',   $count, 'buddypress' ), $count );
+					break;
+				case DAY_IN_SECONDS :
+					$output = sprintf( _n( '%s day',    '%s days',    $count, 'buddypress' ), $count );
+					break;
+				case HOUR_IN_SECONDS :
+					$output = sprintf( _n( '%s hour',   '%s hours',   $count, 'buddypress' ), $count );
+					break;
+				case MINUTE_IN_SECONDS :
+					$output = sprintf( _n( '%s minute', '%s minutes', $count, 'buddypress' ), $count );
+					break;
+				default:
+					$output = sprintf( _n( '%s second', '%s seconds', $count, 'buddypress' ), $count );
+			}
+
+			// Step two: the second chunk
+			// A quirk in the implementation means that this
+			// condition fails in the case of minutes and seconds.
+			// We've left the quirk in place, since fractions of a
+			// minute are not a useful piece of information for our
+			// purposes
+			if ( $i + 2 < $j ) {
+				$seconds2 = $chunks[$i + 1];
+				$count2   = floor( ( $since - ( $seconds * $count ) ) / $seconds2 );
+
+				// Add to output var
+				if ( 0 != $count2 ) {
+					$output .= _x( ',', 'Separator in time since', 'buddypress' ) . ' ';
+
+					switch ( $seconds2 ) {
+						case 30 * DAY_IN_SECONDS :
+							$output .= sprintf( _n( '%s month',  '%s months',  $count2, 'buddypress' ), $count2 );
+							break;
+						case WEEK_IN_SECONDS :
+							$output .= sprintf( _n( '%s week',   '%s weeks',   $count2, 'buddypress' ), $count2 );
+							break;
+						case DAY_IN_SECONDS :
+							$output .= sprintf( _n( '%s day',    '%s days',    $count2, 'buddypress' ), $count2 );
+							break;
+						case HOUR_IN_SECONDS :
+							$output .= sprintf( _n( '%s hour',   '%s hours',   $count2, 'buddypress' ), $count2 );
+							break;
+						case MINUTE_IN_SECONDS :
+							$output .= sprintf( _n( '%s minute', '%s minutes', $count2, 'buddypress' ), $count2 );
+							break;
+						default:
+							$output .= sprintf( _n( '%s second', '%s seconds', $count2, 'buddypress' ), $count2 );
+					}
+				}
+			}
+
+			// No output, so happened right now
+			if ( ! (int) trim( $output ) ) {
+				$output = $right_now_text;
+			}
+		}
+	}
+
+	// Append 'ago' to the end of time-since if not 'right now'
+	if ( $output != $right_now_text ) {
+		$output = sprintf( $ago_text, $output );
+	}
+
+	return apply_filters( 'bp_core_time_since', $output, $older_date, $newer_date );
+}
+
+/** Messages ******************************************************************/
+
+/**
+ * Add a feedback (error/success) message to the WP cookie so it can be displayed after the page reloads.
+ *
+ * @global BuddyPress $bp The one true BuddyPress instance.
+ *
+ * @param string $message Feedback message to be displayed.
+ * @param string $type Message type. 'updated', 'success', 'error', 'warning'.
+ *        Default: 'success'.
+ */
+function bp_core_add_message( $message, $type = '' ) {
+	global $bp;
+
+	// Success is the default
+	if ( empty( $type ) )
+		$type = 'success';
+
+	// Send the values to the cookie for page reload display
+	@setcookie( 'bp-message',      $message, time() + 60 * 60 * 24, COOKIEPATH );
+	@setcookie( 'bp-message-type', $type,    time() + 60 * 60 * 24, COOKIEPATH );
+
+	/***
+	 * Send the values to the $bp global so we can still output messages
+	 * without a page reload
+	 */
+	$bp->template_message      = $message;
+	$bp->template_message_type = $type;
+}
+
+/**
+ * Set up the display of the 'template_notices' feedback message.
+ *
+ * Checks whether there is a feedback message in the WP cookie and, if so, adds
+ * a "template_notices" action so that the message can be parsed into the
+ * template and displayed to the user.
+ *
+ * After the message is displayed, it removes the message vars from the cookie
+ * so that the message is not shown to the user multiple times.
+ *
+ * @global BuddyPress $bp BuddyPress global settings object.
+ * @uses setcookie() Sets a cookie value for the user.
+ */
+function bp_core_setup_message() {
+	global $bp;
+
+	if ( empty( $bp->template_message ) && isset( $_COOKIE['bp-message'] ) )
+		$bp->template_message = stripslashes( $_COOKIE['bp-message'] );
+
+	if ( empty( $bp->template_message_type ) && isset( $_COOKIE['bp-message-type'] ) )
+		$bp->template_message_type = stripslashes( $_COOKIE['bp-message-type'] );
+
+	add_action( 'template_notices', 'bp_core_render_message' );
+
+	if ( isset( $_COOKIE['bp-message'] ) )
+		@setcookie( 'bp-message', false, time() - 1000, COOKIEPATH );
+	if ( isset( $_COOKIE['bp-message-type'] ) )
+		@setcookie( 'bp-message-type', false, time() - 1000, COOKIEPATH );
+}
+add_action( 'bp_actions', 'bp_core_setup_message', 5 );
+
+/**
+ * Render the 'template_notices' feedback message.
+ *
+ * The hook action 'template_notices' is used to call this function, it is not
+ * called directly.
+ *
+ * @global BuddyPress $bp The one true BuddyPress instance.
+ */
+function bp_core_render_message() {
+	global $bp;
+
+	if ( !empty( $bp->template_message ) ) :
+		$type    = ( 'success' == $bp->template_message_type ) ? 'updated' : 'error';
+		$content = apply_filters( 'bp_core_render_message_content', $bp->template_message, $type ); ?>
+
+		<div id="message" class="bp-template-notice <?php echo $type; ?>">
+
+			<?php echo $content; ?>
+
+		</div>
+
+	<?php
+
+		do_action( 'bp_core_render_message' );
+
+	endif;
+}
+
+/** Last active ***************************************************************/
+
+/**
+ * Listener function for the logged-in user's 'last_activity' metadata.
+ *
+ * Many functions use a "last active" feature to show the length of time since
+ * the user was last active. This function will update that time as a usermeta
+ * setting for the user every 5 minutes while the user is actively browsing the
+ * site.
+ *
+ * @uses bp_update_user_meta() BP function to update user metadata in the
+ *       usermeta table.
+ *
+ * @return bool|null Returns false if there is nothing to do.
+ */
+function bp_core_record_activity() {
+
+	if ( !is_user_logged_in() )
+		return false;
+
+	$user_id = bp_loggedin_user_id();
+
+	if ( bp_is_user_inactive( $user_id ) )
+		return false;
+
+	$activity = bp_get_user_last_activity( $user_id );
+
+	if ( !is_numeric( $activity ) )
+		$activity = strtotime( $activity );
+
+	// Get current time
+	$current_time = bp_core_current_time();
+
+	// Use this action to detect the very first activity for a given member
+	if ( empty( $activity ) ) {
+		do_action( 'bp_first_activity_for_member', $user_id );
+	}
+
+	if ( empty( $activity ) || strtotime( $current_time ) >= strtotime( '+5 minutes', $activity ) ) {
+		bp_update_user_last_activity( $user_id, $current_time );
+	}
+}
+add_action( 'wp_head', 'bp_core_record_activity' );
+
+/**
+ * Format last activity string based on time since date given.
+ *
+ * @uses bp_core_time_since() This function will return an English
+ *       representation of the time elapsed.
+ *
+ * @param int|string $last_activity_date The date of last activity.
+ * @param string $string A sprintf()-able statement of the form '% ago'.
+ * @return string $last_active A string of the form '3 years ago'.
+ */
+function bp_core_get_last_activity( $last_activity_date, $string ) {
+
+	if ( empty( $last_activity_date ) )
+		$last_active = __( 'Not recently active', 'buddypress' );
+	else
+		$last_active = sprintf( $string, bp_core_time_since( $last_activity_date ) );
+
+	return apply_filters( 'bp_core_get_last_activity', $last_active, $last_activity_date, $string );
+}
+
+/** Meta **********************************************************************/
+
+/**
+ * Get the meta_key for a given piece of user metadata
+ *
+ * BuddyPress stores a number of pieces of userdata in the WordPress central
+ * usermeta table. In order to allow plugins to enable multiple instances of
+ * BuddyPress on a single WP installation, BP's usermeta keys are filtered
+ * through this function, so that they can be altered on the fly.
+ *
+ * Plugin authors should use BP's _user_meta() functions, which bakes in
+ * bp_get_user_meta_key():
+ *    $last_active = bp_get_user_meta( $user_id, 'last_activity', true );
+ * If you must use WP's _user_meta() functions directly for some reason, you
+ * should use this function to determine the $key parameter, eg
+ *    $last_active = get_user_meta( $user_id, bp_get_user_meta_key( 'last_activity' ), true );
+ * If using the WP functions, do not not hardcode your meta keys.
+ *
+ * @since BuddyPress (1.5.0)
+ *
+ * @uses apply_filters() Filter 'bp_get_user_meta_key' to modify keys individually.
+ *
+ * @param string $key The usermeta meta_key.
+ * @return string $key The usermeta meta_key.
+ */
+function bp_get_user_meta_key( $key = false ) {
+	return apply_filters( 'bp_get_user_meta_key', $key );
+}
+
+/**
+ * Get a piece of usermeta.
+ *
+ * This is a wrapper for get_user_meta() that allows for easy use of
+ * bp_get_user_meta_key(), thereby increasing compatibility with non-standard
+ * BP setups.
+ *
+ * @since BuddyPress (1.5.0)
+ *
+ * @see get_user_meta() For complete details about parameters and return values.
+ * @uses bp_get_user_meta_key() For a filterable version of the meta key.
+ *
+ * @param int $user_id The ID of the user whose meta you're fetching.
+ * @param string $key The meta key to retrieve.
+ * @param bool $single Whether to return a single value.
+ * @return mixed Will be an array if $single is false. Will be value of meta data field if $single
+ *         is true.
+ */
+function bp_get_user_meta( $user_id, $key, $single = false ) {
+	return get_user_meta( $user_id, bp_get_user_meta_key( $key ), $single );
+}
+
+/**
+ * Update a piece of usermeta.
+ *
+ * This is a wrapper for update_user_meta() that allows for easy use of
+ * bp_get_user_meta_key(), thereby increasing compatibility with non-standard
+ * BP setups.
+ *
+ * @since BuddyPress (1.5.0)
+ *
+ * @see update_user_meta() For complete details about parameters and return values.
+ * @uses bp_get_user_meta_key() For a filterable version of the meta key.
+ *
+ * @param int $user_id The ID of the user whose meta you're setting.
+ * @param string $key The meta key to set.
+ * @param mixed $value Metadata value.
+ * @param mixed $prev_value Optional. Previous value to check before removing.
+ * @return bool False on failure, true on success.
+ */
+function bp_update_user_meta( $user_id, $key, $value, $prev_value = '' ) {
+	return update_user_meta( $user_id, bp_get_user_meta_key( $key ), $value, $prev_value );
+}
+
+/**
+ * Delete a piece of usermeta.
+ *
+ * This is a wrapper for delete_user_meta() that allows for easy use of
+ * bp_get_user_meta_key(), thereby increasing compatibility with non-standard
+ * BP setups.
+ *
+ * @since BuddyPress (1.5.0)
+ *
+ * @see delete_user_meta() For complete details about parameters and return values.
+ * @uses bp_get_user_meta_key() For a filterable version of the meta key.
+ *
+ * @param int $user_id The ID of the user whose meta you're deleting.
+ * @param string $key The meta key to delete.
+ * @param mixed $value Optional. Metadata value.
+ * @return bool False for failure. True for success.
+ */
+function bp_delete_user_meta( $user_id, $key, $value = '' ) {
+	return delete_user_meta( $user_id, bp_get_user_meta_key( $key ), $value );
+}
+
+/** Embeds ********************************************************************/
+
+/**
+ * Initializes {@link BP_Embed} after everything is loaded.
+ *
+ * @since BuddyPress (1.5.0)
+ *
+ * @global BuddyPress $bp BuddyPress global settings.
+ */
+function bp_embed_init() {
+	global $bp;
+
+	if ( empty( $bp->embed ) )
+		$bp->embed = new BP_Embed();
+}
+add_action( 'bp_init', 'bp_embed_init', 9 );
+
+/**
+ * Are oembeds allowed in activity items?
+ *
+ * @since BuddyPress (1.5.0)
+ *
+ * @return bool False when activity embed support is disabled; true when
+ *         enabled. Default: true.
+ */
+function bp_use_embed_in_activity() {
+	return apply_filters( 'bp_use_oembed_in_activity', !defined( 'BP_EMBED_DISABLE_ACTIVITY' ) || !BP_EMBED_DISABLE_ACTIVITY );
+}
+
+/**
+ * Are oembeds allwoed in activity replies?
+ *
+ * @since BuddyPress (1.5.0)
+ *
+ * @return bool False when activity replies embed support is disabled; true
+ *         when enabled. Default: true.
+ */
+function bp_use_embed_in_activity_replies() {
+	return apply_filters( 'bp_use_embed_in_activity_replies', !defined( 'BP_EMBED_DISABLE_ACTIVITY_REPLIES' ) || !BP_EMBED_DISABLE_ACTIVITY_REPLIES );
+}
+
+/**
+ * Are oembeds allowed in forum posts?
+ *
+ * @since BuddyPress (1.5.0)
+ *
+ * @return bool False when forum post embed support is disabled; true when
+ *         enabled. Default: true.
+ */
+function bp_use_embed_in_forum_posts() {
+	return apply_filters( 'bp_use_embed_in_forum_posts', !defined( 'BP_EMBED_DISABLE_FORUM_POSTS' ) || !BP_EMBED_DISABLE_FORUM_POSTS );
+}
+
+/**
+ * Are oembeds allowed in private messages?
+ *
+ * @since BuddyPress (1.5.0)
+ *
+ * @return bool False when private message embed support is disabled; true when
+ *         enabled. Default: true.
+ */
+function bp_use_embed_in_private_messages() {
+	return apply_filters( 'bp_use_embed_in_private_messages', !defined( 'BP_EMBED_DISABLE_PRIVATE_MESSAGES' ) || !BP_EMBED_DISABLE_PRIVATE_MESSAGES );
+}
+
+/** Admin *********************************************************************/
+
+/**
+ * Output the correct admin URL based on BuddyPress and WordPress configuration.
+ *
+ * @since BuddyPress (1.5.0)
+ *
+ * @see bp_get_admin_url() For description of parameters.
+ *
+ * @param string $path See {@link bp_get_admin_url()}.
+ * @param string $scheme See {@link bp_get_admin_url()}.
+ */
+function bp_admin_url( $path = '', $scheme = 'admin' ) {
+	echo bp_get_admin_url( $path, $scheme );
+}
+	/**
+	 * Return the correct admin URL based on BuddyPress and WordPress configuration.
+	 *
+	 * @since BuddyPress (1.5.0)
+	 *
+	 * @uses bp_core_do_network_admin()
+	 * @uses network_admin_url()
+	 * @uses admin_url()
+	 *
+	 * @param string $path Optional. The sub-path under /wp-admin to be
+	 *        appended to the admin URL.
+	 * @param string $scheme The scheme to use. Default is 'admin', which
+	 *        obeys {@link force_ssl_admin()} and {@link is_ssl()}. 'http'
+	 *        or 'https' can be passed to force those schemes.
+	 * @return string Admin url link with optional path appended.
+	 */
+	function bp_get_admin_url( $path = '', $scheme = 'admin' ) {
+
+		// Links belong in network admin
+		if ( bp_core_do_network_admin() ) {
+			$url = network_admin_url( $path, $scheme );
+
+		// Links belong in site admin
+		} else {
+			$url = admin_url( $path, $scheme );
+		}
+
+		return $url;
+	}
+
+/**
+ * Should BuddyPress appear in network admin (vs a single site Dashboard)?
+ *
+ * Because BuddyPress can be installed in multiple ways and with multiple
+ * configurations, we need to check a few things to be confident about where
+ * to hook into certain areas of WordPress's admin.
+ *
+ * @since BuddyPress (1.5.0)
+ *
+ * @uses bp_is_network_activated()
+ * @uses bp_is_multiblog_mode()
+ *
+ * @return bool True if the BP admin screen should appear in the Network Admin,
+ *         otherwise false.
+ */
+function bp_core_do_network_admin() {
+
+	// Default
+	$retval = bp_is_network_activated();
+
+	if ( bp_is_multiblog_mode() )
+		$retval = false;
+
+	return (bool) apply_filters( 'bp_core_do_network_admin', $retval );
+}
+
+/**
+ * Return the action name that BuddyPress nav setup callbacks should be hooked to.
+ *
+ * Functions used to set up BP Dashboard pages (wrapping such admin-panel
+ * functions as add_submenu_page()) should use bp_core_admin_hook() for the
+ * first parameter in add_action(). BuddyPress will then determine
+ * automatically whether to load the panels in the Network Admin. Ie:
+ *
+ *     add_action( bp_core_admin_hook(), 'myplugin_dashboard_panel_setup' );
+ *
+ * @return string $hook The proper hook ('network_admin_menu' or 'admin_menu').
+ */
+function bp_core_admin_hook() {
+	$hook = bp_core_do_network_admin() ? 'network_admin_menu' : 'admin_menu';
+
+	return apply_filters( 'bp_core_admin_hook', $hook );
+}
+
+/** Multisite *****************************************************************/
+
+/**
+ * Is this the root blog?
+ *
+ * @since BuddyPress (1.5.0)
+ *
+ * @param int $blog_id Optional. Default: the ID of the current blog.
+ * @return bool $is_root_blog Returns true if this is bp_get_root_blog_id().
+ */
+function bp_is_root_blog( $blog_id = 0 ) {
+
+	// Assume false
+	$is_root_blog = false;
+
+	// Use current blog if no ID is passed
+	if ( empty( $blog_id ) )
+		$blog_id = get_current_blog_id();
+
+	// Compare to root blog ID
+	if ( $blog_id == bp_get_root_blog_id() )
+		$is_root_blog = true;
+
+	return (bool) apply_filters( 'bp_is_root_blog', (bool) $is_root_blog );
+}
+
+/**
+ * Get the ID of the root blog.
+ *
+ * The "root blog" is the blog on a WordPress network where BuddyPress content
+ * appears (where member profile URLs resolve, where a given theme is loaded,
+ * etc.).
+ *
+ * @since BuddyPress (1.5.0)
+ *
+ * @return int The root site ID.
+ */
+function bp_get_root_blog_id() {
+	global $bp;
+
+	return (int) apply_filters( 'bp_get_root_blog_id', (int) $bp->root_blog_id );
+}
+
+/**
+ * Are we running multiblog mode?
+ *
+ * Note that BP_ENABLE_MULTIBLOG is different from (but dependent on) WordPress
+ * Multisite. "Multiblog" is BuddyPress setup that allows BuddyPress components
+ * to be viewed on every blog on the network, each with their own settings.
+ *
+ * Thus, instead of having all 'boonebgorges' links go to
+ *   http://example.com/members/boonebgorges
+ * on the root blog, each blog will have its own version of the same content, eg
+ *   http://site2.example.com/members/boonebgorges (for subdomains)
+ *   http://example.com/site2/members/boonebgorges (for subdirectories)
+ *
+ * Multiblog mode is disabled by default, meaning that all BuddyPress content
+ * must be viewed on the root blog. It's also recommended not to use the
+ * BP_ENABLE_MULTIBLOG constant beyond 1.7, as BuddyPress can now be activated
+ * on individual sites.
+ *
+ * Why would you want to use this? Originally it was intended to allow
+ * BuddyPress to live in mu-plugins and be visible on mapped domains. This is
+ * a very small use-case with large architectural shortcomings, so do not go
+ * down this road unless you specifically need to.
+ *
+ * @since BuddyPress (1.5.0)
+ *
+ * @uses apply_filters() Filter 'bp_is_multiblog_mode' to alter.
+ *
+ * @return bool False when multiblog mode is disabled; true when enabled.
+ *         Default: false.
+ */
+function bp_is_multiblog_mode() {
+
+	// Setup some default values
+	$retval         = false;
+	$is_multisite   = is_multisite();
+	$network_active = bp_is_network_activated();
+	$is_multiblog   = defined( 'BP_ENABLE_MULTIBLOG' ) && BP_ENABLE_MULTIBLOG;
+
+	// Multisite, Network Activated, and Specifically Multiblog
+	if ( $is_multisite && $network_active && $is_multiblog ) {
+		$retval = true;
+
+	// Multisite, but not network activated
+	} elseif ( $is_multisite && ! $network_active ) {
+		$retval = true;
+	}
+
+	return apply_filters( 'bp_is_multiblog_mode', $retval );
+}
+
+/**
+ * Is BuddyPress active at the network level for this network?
+ *
+ * Used to determine admin menu placement, and where settings and options are
+ * stored. If you're being *really* clever and manually pulling BuddyPress in
+ * with an mu-plugin or some other method, you'll want to filter
+ * 'bp_is_network_activated' and override the auto-determined value.
+ *
+ * @since BuddyPress (1.7.0)
+ *
+ * @return bool True if BuddyPress is network activated.
+ */
+function bp_is_network_activated() {
+
+	// Default to is_multisite()
+	$retval  = is_multisite();
+
+	// Check the sitewide plugins array
+	$base    = buddypress()->basename;
+	$plugins = get_site_option( 'active_sitewide_plugins' );
+
+	// Override is_multisite() if not network activated
+	if ( ! is_array( $plugins ) || ! isset( $plugins[$base] ) )
+		$retval = false;
+
+	return (bool) apply_filters( 'bp_is_network_activated', $retval );
+}
+
+/** Global Manipulators *******************************************************/
+
+/**
+ * Set the $bp->is_directory global.
+ *
+ * @global BuddyPress $bp The one true BuddyPress instance.
+ *
+ * @param bool $is_directory Optional. Default: false.
+ * @param string $component Optional. Component name. Default: the current
+ *        component.
+ */
+function bp_update_is_directory( $is_directory = false, $component = '' ) {
+	global $bp;
+
+	if ( empty( $component ) )
+		$component = bp_current_component();
+
+	$bp->is_directory = apply_filters( 'bp_update_is_directory', $is_directory, $component );
+}
+
+/**
+ * Set the $bp->is_item_admin global.
+ *
+ * @global BuddyPress $bp The one true BuddyPress instance.
+ *
+ * @param bool $is_item_admin Optional. Default: false.
+ * @param string $component. Optional. Component name. Default: the current
+ *        component.
+ */
+function bp_update_is_item_admin( $is_item_admin = false, $component = '' ) {
+	global $bp;
+
+	if ( empty( $component ) )
+		$component = bp_current_component();
+
+	$bp->is_item_admin = apply_filters( 'bp_update_is_item_admin', $is_item_admin, $component );
+}
+
+/**
+ * Set the $bp->is_item_mod global.
+ *
+ * @global BuddyPress $bp The one true BuddyPress instance.
+ *
+ * @param bool $is_item_mod Optional. Default: false.
+ * @param string $component. Optional. Component name. Default: the current
+ *        component.
+ */
+function bp_update_is_item_mod( $is_item_mod = false, $component = '' ) {
+	global $bp;
+
+	if ( empty( $component ) )
+		$component = bp_current_component();
+
+	$bp->is_item_mod = apply_filters( 'bp_update_is_item_mod', $is_item_mod, $component );
+}
+
+/**
+ * Trigger a 404.
+ *
+ * @since BuddyPress (1.5.0)
+ *
+ * @global WP_Query $wp_query WordPress query object.
+ *
+ * @param string $redirect If 'remove_canonical_direct', remove WordPress'
+ *        "helpful" redirect_canonical action. Default: 'remove_canonical_redirect'.
+ */
+function bp_do_404( $redirect = 'remove_canonical_direct' ) {
+	global $wp_query;
+
+	do_action( 'bp_do_404', $redirect );
+
+	$wp_query->set_404();
+	status_header( 404 );
+	nocache_headers();
+
+	if ( 'remove_canonical_direct' == $redirect )
+		remove_action( 'template_redirect', 'redirect_canonical' );
+}
+
+/** Nonces ********************************************************************/
+
+/**
+ * Makes sure the user requested an action from another page on this site.
+ *
+ * To avoid security exploits within the theme.
+ *
+ * @since BuddyPress (1.6.0)
+ *
+ * @uses do_action() Calls 'bp_verify_nonce_request' on $action.
+ *
+ * @param string $action Action nonce.
+ * @param string $query_arg where to look for nonce in $_REQUEST.
+ * @return bool True if the nonce is verified, otherwise false.
+ */
+function bp_verify_nonce_request( $action = '', $query_arg = '_wpnonce' ) {
+
+	/** Home URL **************************************************************/
+
+	// Parse home_url() into pieces to remove query-strings, strange characters,
+	// and other funny things that plugins might to do to it.
+	$parsed_home = parse_url( home_url( '/', ( is_ssl() ? 'https://' : 'http://' ) ) );
+
+	// Maybe include the port, if it's included
+	if ( isset( $parsed_home['port'] ) ) {
+		$parsed_host = $parsed_home['host'] . ':' . $parsed_home['port'];
+	} else {
+		$parsed_host = $parsed_home['host'];
+	}
+
+	// Set the home URL for use in comparisons
+	$home_url = trim( strtolower( $parsed_home['scheme'] . '://' . $parsed_host . $parsed_home['path'] ), '/' );
+
+	/** Requested URL *********************************************************/
+
+	// Maybe include the port, if it's included in home_url()
+	if ( isset( $parsed_home['port'] ) ) {
+		$request_host = $_SERVER['HTTP_HOST'] . ':' . $_SERVER['SERVER_PORT'];
+	} else {
+		$request_host = $_SERVER['HTTP_HOST'];
+	}
+
+	// Build the currently requested URL
+	$scheme        = is_ssl() ? 'https://' : 'http://';
+	$requested_url = strtolower( $scheme . $request_host . $_SERVER['REQUEST_URI'] );
+
+	/** Look for match ********************************************************/
+
+	// Filter the requested URL, for configurations like reverse proxying
+	$matched_url = apply_filters( 'bp_verify_nonce_request_url', $requested_url );
+
+	// Check the nonce
+	$result = isset( $_REQUEST[$query_arg] ) ? wp_verify_nonce( $_REQUEST[$query_arg], $action ) : false;
+
+	// Nonce check failed
+	if ( empty( $result ) || empty( $action ) || ( strpos( $matched_url, $home_url ) !== 0 ) ) {
+		$result = false;
+	}
+
+	// Do extra things
+	do_action( 'bp_verify_nonce_request', $action, $result );
+
+	return $result;
+}
+
+/** Requests ******************************************************************/
+
+/**
+ * Return true|false if this is a POST request
+ *
+ * @since BuddyPress (1.9.0)
+ * @return bool
+ */
+function bp_is_post_request() {
+	return (bool) ( 'POST' === strtoupper( $_SERVER['REQUEST_METHOD'] ) );
+}
+
+/**
+ * Return true|false if this is a GET request
+ *
+ * @since BuddyPress (1.9.0)
+ * @return bool
+ */
+function bp_is_get_request() {
+	return (bool) ( 'GET' === strtoupper( $_SERVER['REQUEST_METHOD'] ) );
+}
+
+
+/** Miscellaneous hooks *******************************************************/
+
+/**
+ * Load the buddypress translation file for current language.
+ *
+ * @see load_textdomain() for a description of return values.
+ *
+ * @return bool True on success, false on failure.
+ */
+function bp_core_load_buddypress_textdomain() {
+	// Try to load via load_plugin_textdomain() first, for future
+	// wordpress.org translation downloads
+	if ( load_plugin_textdomain( 'buddypress', false, 'buddypress/bp-languages' ) ) {
+		return true;
+	}
+
+	// Nothing found in bp-languages, so try to load from WP_LANG_DIR
+	$locale = apply_filters( 'buddypress_locale', get_locale() );
+	$mofile = WP_LANG_DIR . '/buddypress-' . $locale . '.mo';
+
+	return load_textdomain( 'buddypress', $mofile );
+}
+add_action ( 'bp_core_loaded', 'bp_core_load_buddypress_textdomain' );
+
+/**
+ * A javascript-free implementation of the search functions in BuddyPress.
+ *
+ * @param string $slug The slug to redirect to for searching.
+ */
+function bp_core_action_search_site( $slug = '' ) {
+
+	if ( !bp_is_current_component( bp_get_search_slug() ) )
+		return;
+
+	if ( empty( $_POST['search-terms'] ) ) {
+		bp_core_redirect( bp_get_root_domain() );
+		return;
+	}
+
+	$search_terms = stripslashes( $_POST['search-terms'] );
+	$search_which = !empty( $_POST['search-which'] ) ? $_POST['search-which'] : '';
+	$query_string = '/?s=';
+
+	if ( empty( $slug ) ) {
+		switch ( $search_which ) {
+			case 'posts':
+				$slug = '';
+				$var  = '/?s=';
+
+				// If posts aren't displayed on the front page, find the post page's slug.
+				if ( 'page' == get_option( 'show_on_front' ) ) {
+					$page = get_post( get_option( 'page_for_posts' ) );
+
+					if ( !is_wp_error( $page ) && !empty( $page->post_name ) ) {
+						$slug = $page->post_name;
+						$var  = '?s=';
+					}
+				}
+				break;
+
+			case 'blogs':
+				$slug = bp_is_active( 'blogs' )  ? bp_get_blogs_root_slug()  : '';
+				break;
+
+			case 'forums':
+				$slug = bp_is_active( 'forums' ) ? bp_get_forums_root_slug() : '';
+				$query_string = '/?fs=';
+				break;
+
+			case 'groups':
+				$slug = bp_is_active( 'groups' ) ? bp_get_groups_root_slug() : '';
+				break;
+
+			case 'members':
+			default:
+				$slug = bp_get_members_root_slug();
+				break;
+		}
+
+		if ( empty( $slug ) && 'posts' != $search_which ) {
+			bp_core_redirect( bp_get_root_domain() );
+			return;
+		}
+	}
+
+	bp_core_redirect( apply_filters( 'bp_core_search_site', home_url( $slug . $query_string . urlencode( $search_terms ) ), $search_terms ) );
+}
+add_action( 'bp_init', 'bp_core_action_search_site', 7 );
+
+/**
+ * Print the generation time in the footer of the site.
+ */
+function bp_core_print_generation_time() {
+?>
+
+<!-- Generated in <?php timer_stop(1); ?> seconds. (<?php echo get_num_queries(); ?> q) -->
+
+	<?php
+}
+add_action( 'wp_footer', 'bp_core_print_generation_time' );
+
+/** Nav Menu ******************************************************************/
+
+/**
+ * Create fake "post" objects for BP's logged-in nav menu for use in the WordPress "Menus" settings page.
+ *
+ * WordPress nav menus work by representing post or tax term data as a custom
+ * post type, which is then used to populate the checkboxes that appear on
+ * Dashboard > Appearance > Menu as well as the menu as rendered on the front
+ * end. Most of the items in the BuddyPress set of nav items are neither posts
+ * nor tax terms, so we fake a post-like object so as to be compatible with the
+ * menu.
+ *
+ * This technique also allows us to generate links dynamically, so that, for
+ * example, "My Profile" will always point to the URL of the profile of the
+ * logged-in user.
+ *
+ * @since BuddyPress (1.9.0)
+ *
+ * @return mixed A URL or an array of dummy pages.
+ */
+function bp_nav_menu_get_loggedin_pages() {
+
+	// Try to catch the cached version first
+	if ( ! empty( buddypress()->wp_nav_menu_items->loggedin ) ) {
+		return buddypress()->wp_nav_menu_items->loggedin;
+	}
+
+	// Pull up a list of items registered in BP's top-level nav array
+	$bp_menu_items = buddypress()->bp_nav;
+
+	// Alphabetize
+	$bp_menu_items = bp_alpha_sort_by_key( $bp_menu_items, 'name' );
+
+	// Some BP nav menu items will not be represented in bp_nav, because
+	// they are not real BP components. We add them manually here.
+	$bp_menu_items[] = array(
+		'name' => __( 'Log Out', 'buddypress' ),
+		'slug' => 'logout',
+		'link' => wp_logout_url(),
+	);
+
+	// If there's nothing to show, we're done
+	if ( count( $bp_menu_items ) < 1 ) {
+		return false;
+	}
+
+	$page_args = array();
+
+	foreach ( $bp_menu_items as $bp_item ) {
+		$item_name = '';
+
+		// Remove <span>number</span>
+		$item_name = preg_replace( '/([.0-9]+)/', '', $bp_item['name'] );
+		$item_name = trim( strip_tags( $item_name ) );
+
+		$page_args[ $bp_item['slug'] ] = (object) array(
+			'ID'             => -1,
+			'post_title'     => $item_name,
+			'post_author'    => 0,
+			'post_date'      => 0,
+			'post_excerpt'   => $bp_item['slug'],
+			'post_type'      => 'page',
+			'post_status'    => 'publish',
+			'comment_status' => 'closed',
+			'guid'           => $bp_item['link']
+		);
+	}
+
+	if ( empty( buddypress()->wp_nav_menu_items ) ) {
+		buddypress()->wp_nav_menu_items = new stdClass;
+	}
+
+	buddypress()->wp_nav_menu_items->loggedin = $page_args;
+
+	return $page_args;
+}
+
+/**
+ * Create fake "post" objects for BP's logged-out nav menu for use in the WordPress "Menus" settings page.
+ *
+ * WordPress nav menus work by representing post or tax term data as a custom
+ * post type, which is then used to populate the checkboxes that appear on
+ * Dashboard > Appearance > Menu as well as the menu as rendered on the front
+ * end. Most of the items in the BuddyPress set of nav items are neither posts
+ * nor tax terms, so we fake a post-like object so as to be compatible with the
+ * menu.
+ *
+ * @since BuddyPress (1.9.0)
+ *
+ * @return mixed A URL or an array of dummy pages.
+ */
+function bp_nav_menu_get_loggedout_pages() {
+
+	// Try to catch the cached version first
+	if ( ! empty( buddypress()->wp_nav_menu_items->loggedout ) ) {
+		return buddypress()->wp_nav_menu_items->loggedout;
+	}
+
+	$bp_menu_items = array();
+
+	// Some BP nav menu items will not be represented in bp_nav, because
+	// they are not real BP components. We add them manually here.
+	$bp_menu_items[] = array(
+		'name' => __( 'Log In', 'buddypress' ),
+		'slug' => 'login',
+		'link' => wp_login_url(),
+	);
+
+	// The Register page will not always be available (ie, when
+	// registration is disabled)
+	$bp_directory_page_ids = bp_core_get_directory_page_ids();
+
+	if( ! empty( $bp_directory_page_ids['register'] ) ) {
+		$register_page = get_post( $bp_directory_page_ids['register'] );
+		$bp_menu_items[] = array(
+			'name' => $register_page->post_title,
+			'slug' => $register_page->post_name,
+			'link' => get_permalink( $register_page->ID ),
+		);
+	}
+
+	// If there's nothing to show, we're done
+	if ( count( $bp_menu_items ) < 1 ) {
+		return false;
+	}
+
+	$page_args = array();
+
+	foreach ( $bp_menu_items as $bp_item ) {
+		$page_args[ $bp_item['slug'] ] = (object) array(
+			'ID'             => -1,
+			'post_title'     => $bp_item['name'],
+			'post_author'    => 0,
+			'post_date'      => 0,
+			'post_excerpt'   => $bp_item['slug'],
+			'post_type'      => 'page',
+			'post_status'    => 'publish',
+			'comment_status' => 'closed',
+			'guid'           => $bp_item['link']
+		);
+	}
+
+	if ( empty( buddypress()->wp_nav_menu_items ) ) {
+		buddypress()->wp_nav_menu_items = new stdClass;
+	}
+
+	buddypress()->wp_nav_menu_items->loggedout = $page_args;
+
+	return $page_args;
+}
+
+/**
+ * Get the URL for a BuddyPress WP nav menu item, based on slug.
+ *
+ * BuddyPress-specific WP nav menu items have dynamically generated URLs,
+ * based on the identity of the current user. This function lets you fetch the
+ * proper URL for a given nav item slug (such as 'login' or 'messages').
+ *
+ * @since BuddyPress (1.9.0)
+ *
+ * @param string $slug The slug of the nav item: login, register, or one of the
+ *        slugs from buddypress()->bp_nav.
+ * @return string $nav_item_url The URL generated for the current user.
+ */
+function bp_nav_menu_get_item_url( $slug ) {
+	$nav_item_url   = '';
+	$nav_menu_items = bp_nav_menu_get_loggedin_pages();
+
+	if ( isset( $nav_menu_items[ $slug ] ) ) {
+		$nav_item_url = $nav_menu_items[ $slug ]->guid;
+	}
+
+	return $nav_item_url;
+}
Index: /tags/1.9/bp-core/bp-core-loader.php
===================================================================
--- /tags/1.9/bp-core/bp-core-loader.php	(revision 7684)
+++ /tags/1.9/bp-core/bp-core-loader.php	(revision 7684)
@@ -0,0 +1,260 @@
+<?php
+
+/**
+ * BuddyPress Core Loader.
+ *
+ * Core contains the commonly used functions, classes, and APIs.
+ *
+ * @package BuddyPress
+ * @subpackage Core
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+class BP_Core extends BP_Component {
+
+	/**
+	 * Start the members component creation process.
+	 *
+	 * @since BuddyPress (1.5.0)
+	 *
+	 * @uses BP_Core::bootstrap()
+	 */
+	function __construct() {
+		parent::start(
+			'core',
+			__( 'BuddyPress Core', 'buddypress' )
+			, BP_PLUGIN_DIR
+		);
+
+		$this->bootstrap();
+	}
+
+	/**
+	 * Populate the global data needed before BuddyPress can continue.
+	 *
+	 * This involves figuring out the currently required, active, deactive,
+	 * and optional components.
+	 *
+	 * @since BuddyPress (1.5.0)
+	 */
+	private function bootstrap() {
+		$bp = buddypress();
+
+		/**
+		 * At this point in the stack, BuddyPress core has been loaded but
+		 * individual components (friends/activity/groups/etc...) have not.
+		 *
+		 * The 'bp_core_loaded' action lets you execute code ahead of the
+		 * other components.
+		 */
+		do_action( 'bp_core_loaded' );
+
+		/** Components ********************************************************/
+
+		// Set the included and optional components.
+		$bp->optional_components = apply_filters( 'bp_optional_components', array( 'activity', 'blogs', 'forums', 'friends', 'groups', 'messages', 'notifications', 'settings', 'xprofile' ) );
+
+		// Set the required components
+		$bp->required_components = apply_filters( 'bp_required_components', array( 'members' ) );
+
+		// Get a list of activated components
+		if ( $active_components = bp_get_option( 'bp-active-components' ) ) {
+			$bp->active_components      = apply_filters( 'bp_active_components', $active_components );
+			$bp->deactivated_components = apply_filters( 'bp_deactivated_components', array_values( array_diff( array_values( array_merge( $bp->optional_components, $bp->required_components ) ), array_keys( $bp->active_components ) ) ) );
+
+		// Pre 1.5 Backwards compatibility
+		} elseif ( $deactivated_components = bp_get_option( 'bp-deactivated-components' ) ) {
+
+			// Trim off namespace and filename
+			foreach ( array_keys( (array) $deactivated_components ) as $component ) {
+				$trimmed[] = str_replace( '.php', '', str_replace( 'bp-', '', $component ) );
+			}
+
+			// Set globals
+			$bp->deactivated_components = apply_filters( 'bp_deactivated_components', $trimmed );
+
+			// Setup the active components
+			$active_components     = array_fill_keys( array_diff( array_values( array_merge( $bp->optional_components, $bp->required_components ) ), array_values( $bp->deactivated_components ) ), '1' );
+
+			// Set the active component global
+			$bp->active_components = apply_filters( 'bp_active_components', $bp->active_components );
+
+		// Default to all components active
+		} else {
+
+			// Set globals
+			$bp->deactivated_components = array();
+
+			// Setup the active components
+			$active_components     = array_fill_keys( array_values( array_merge( $bp->optional_components, $bp->required_components ) ), '1' );
+
+			// Set the active component global
+			$bp->active_components = apply_filters( 'bp_active_components', $bp->active_components );
+		}
+
+		// Loop through optional components
+		foreach( $bp->optional_components as $component )
+			if ( bp_is_active( $component ) && file_exists( BP_PLUGIN_DIR . '/bp-' . $component . '/bp-' . $component . '-loader.php' ) )
+				include( BP_PLUGIN_DIR . '/bp-' . $component . '/bp-' . $component . '-loader.php' );
+
+		// Loop through required components
+		foreach( $bp->required_components as $component )
+			if ( file_exists( BP_PLUGIN_DIR . '/bp-' . $component . '/bp-' . $component . '-loader.php' ) )
+				include( BP_PLUGIN_DIR . '/bp-' . $component . '/bp-' . $component . '-loader.php' );
+
+		// Add Core to required components
+		$bp->required_components[] = 'core';
+	}
+
+	/**
+	 * Include bp-core files.
+	 *
+	 * @see BP_Component::includes() for description of parameters.
+	 *
+	 * @param array $includes See {@link BP_Component::includes()}.
+	 */
+	public function includes( $includes = array() ) {
+
+		if ( !is_admin() )
+			return;
+
+		$includes = array(
+			'admin'
+		);
+
+		parent::includes( $includes );
+	}
+
+	/**
+	 * Set up bp-core global settings.
+	 *
+	 * Sets up a majority of the BuddyPress globals that require a minimal
+	 * amount of processing, meaning they cannot be set in the BuddyPress class.
+	 *
+	 * @since BuddyPress (1.5.0)
+	 *
+	 * @see BP_Component::setup_globals() for description of parameters.
+	 *
+	 * @param array $args See {@link BP_Component::setup_globals()}.
+	 */
+	public function setup_globals( $args = array() ) {
+		$bp = buddypress();
+
+		/** Database **********************************************************/
+
+		// Get the base database prefix
+		if ( empty( $bp->table_prefix ) )
+			$bp->table_prefix = bp_core_get_table_prefix();
+
+		// The domain for the root of the site where the main blog resides
+		if ( empty( $bp->root_domain ) )
+			$bp->root_domain = bp_core_get_root_domain();
+
+		// Fetches all of the core BuddyPress settings in one fell swoop
+		if ( empty( $bp->site_options ) )
+			$bp->site_options = bp_core_get_root_options();
+
+		// The names of the core WordPress pages used to display BuddyPress content
+		if ( empty( $bp->pages ) )
+			$bp->pages = bp_core_get_directory_pages();
+
+		/** Basic current user data *******************************************/
+
+		// Logged in user is the 'current_user'
+		$current_user            = wp_get_current_user();
+
+		// The user ID of the user who is currently logged in.
+		$bp->loggedin_user       = new stdClass;
+		$bp->loggedin_user->id   = isset( $current_user->ID ) ? $current_user->ID : 0;
+
+		/** Avatars ***********************************************************/
+
+		// Fetches the default Gravatar image to use if the user/group/blog has no avatar or gravatar
+		$bp->grav_default        = new stdClass;
+		$bp->grav_default->user  = apply_filters( 'bp_user_gravatar_default',  $bp->site_options['avatar_default'] );
+		$bp->grav_default->group = apply_filters( 'bp_group_gravatar_default', $bp->grav_default->user );
+		$bp->grav_default->blog  = apply_filters( 'bp_blog_gravatar_default',  $bp->grav_default->user );
+
+		// Notifications table. Included here for legacy purposes. Use
+		// bp-notifications instead.
+		$bp->core->table_name_notifications = $bp->table_prefix . 'bp_notifications';
+
+		/**
+		 * Used to determine if user has admin rights on current content. If the
+		 * logged in user is viewing their own profile and wants to delete
+		 * something, is_item_admin is used. This is a generic variable so it
+		 * can be used by other components. It can also be modified, so when
+		 * viewing a group 'is_item_admin' would be 'true' if they are a group
+		 * admin, and 'false' if they are not.
+		 */
+		bp_update_is_item_admin( bp_user_has_access(), 'core' );
+
+		// Is the logged in user is a mod for the current item?
+		bp_update_is_item_mod( false,                  'core' );
+
+		do_action( 'bp_core_setup_globals' );
+	}
+
+	/**
+	 * Set up component navigation.
+	 *
+	 * @since BuddyPress (1.5.0)
+	 *
+	 * @see BP_Component::setup_nav() for a description of arguments.
+	 *
+	 * @param array $main_nav Optional. See BP_Component::setup_nav() for
+	 *        description.
+	 * @param array $sub_nav Optional. See BP_Component::setup_nav() for
+	 *        description.
+	 */
+         public function setup_nav( $main_nav = array(), $sub_nav = array() ) {
+		$bp = buddypress();
+
+		 // If xprofile component is disabled, revert to WordPress profile
+		if ( !bp_is_active( 'xprofile' ) ) {
+
+			// Fallback values if xprofile is disabled
+			if ( ! isset( $bp->core->profile ) ) {
+				$bp->core->profile = new stdClass;
+			}
+			$bp->core->profile->slug = 'profile';
+			$bp->active_components[$bp->core->profile->slug] = $bp->core->profile->slug;
+
+			// Add 'Profile' to the main navigation
+			$main_nav = array(
+				'name'                => __( 'Profile', 'buddypress' ),
+				'slug'                => $bp->core->profile->slug,
+				'position'            => 20,
+				'screen_function'     => 'bp_core_catch_profile_uri',
+				'default_subnav_slug' => 'public'
+			);
+
+			$profile_link = trailingslashit( bp_loggedin_user_domain() . '/' . $bp->core->profile->slug );
+
+			// Add the subnav items to the profile
+			$sub_nav[] = array(
+				'name'            => __( 'View', 'buddypress' ),
+				'slug'            => 'public',
+				'parent_url'      => $profile_link,
+				'parent_slug'     => $bp->core->profile->slug,
+				'screen_function' => 'bp_core_catch_profile_uri'
+			);
+
+			parent::setup_nav( $main_nav, $sub_nav );
+		}
+	}
+}
+
+/**
+ * Set up the BuddyPress Core component.
+ *
+ * @since BuddyPress (1.6.0)
+ *
+ * @global BuddyPress $bp BuddyPress global settings object.
+ */
+function bp_setup_core() {
+	buddypress()->core = new BP_Core();
+}
+add_action( 'bp_setup_components', 'bp_setup_core', 2 );
Index: /tags/1.9/bp-core/bp-core-moderation.php
===================================================================
--- /tags/1.9/bp-core/bp-core-moderation.php	(revision 7684)
+++ /tags/1.9/bp-core/bp-core-moderation.php	(revision 7684)
@@ -0,0 +1,275 @@
+<?php
+/**
+ * BuddyPress Moderation Functions.
+ *
+ * @package BuddyPress
+ * @subpackage Core
+ * @since BuddyPress (1.6.0)
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/** Moderation ****************************************************************/
+
+/**
+ * Check for flooding.
+ *
+ * Check to make sure that a user is not making too many posts in a short amount
+ * of time.
+ *
+ * @since BuddyPress (1.6.0)
+ *
+ * @uses current_user_can() To check if the current user can throttle.
+ * @uses bp_get_option() To get the throttle time.
+ * @uses get_transient() To get the last posted transient of the ip.
+ * @uses get_user_meta() To get the last posted meta of the user.
+ *
+ * @param int $user_id User id to check for flood.
+ * @return bool True if there is no flooding, false if there is.
+ */
+function bp_core_check_for_flood( $user_id = 0 ) {
+
+	// Option disabled. No flood checks.
+	if ( !$throttle_time = bp_get_option( '_bp_throttle_time' ) )
+		return true;
+
+	// Bail if no user ID passed
+	if ( empty( $user_id ) )
+		return false;
+
+	$last_posted = get_user_meta( $user_id, '_bp_last_posted', true );
+	if ( isset( $last_posted ) && ( time() < ( $last_posted + $throttle_time ) ) && !current_user_can( 'throttle' ) )
+		return false;
+
+	return true;
+}
+
+/**
+ * Check for moderation keys and too many links.
+ *
+ * @since BuddyPress (1.6.0)
+ *
+ * @uses bp_current_author_ip() To get current user IP address.
+ * @uses bp_current_author_ua() To get current user agent.
+ * @uses bp_current_user_can() Allow super admins to bypass blacklist.
+ *
+ * @param int $user_id Topic or reply author ID.
+ * @param string $title The title of the content.
+ * @param string $content The content being posted.
+ * @return bool True if test is passed, false if fail.
+ */
+function bp_core_check_for_moderation( $user_id = 0, $title = '', $content = '' ) {
+
+	// Bail if super admin is author
+	if ( is_super_admin( $user_id ) )
+		return true;
+
+	// Define local variable(s)
+	$post      = array();
+	$match_out = '';
+
+	/** Blacklist *************************************************************/
+
+	// Get the moderation keys
+	$blacklist = trim( get_option( 'moderation_keys' ) );
+
+	// Bail if blacklist is empty
+	if ( empty( $blacklist ) )
+		return true;
+
+	/** User Data *************************************************************/
+
+	if ( !empty( $user_id ) ) {
+
+		// Get author data
+		$user = get_userdata( $user_id );
+
+		// If data exists, map it
+		if ( !empty( $user ) ) {
+			$post['author'] = $user->display_name;
+			$post['email']  = $user->user_email;
+			$post['url']    = $user->user_url;
+		}
+	}
+
+	// Current user IP and user agent
+	$post['user_ip'] = bp_core_current_user_ip();
+	$post['user_ua'] = bp_core_current_user_ua();
+
+	// Post title and content
+	$post['title']   = $title;
+	$post['content'] = $content;
+
+	/** Max Links *************************************************************/
+
+	$max_links = get_option( 'comment_max_links' );
+	if ( !empty( $max_links ) ) {
+
+		// How many links?
+		$num_links = preg_match_all( '/<a [^>]*href/i', $content, $match_out );
+
+		// Allow for bumping the max to include the user's URL
+		$num_links = apply_filters( 'comment_max_links_url', $num_links, $post['url'] );
+
+		// Das ist zu viele links!
+		if ( $num_links >= $max_links ) {
+			return false;
+		}
+	}
+
+	/** Words *****************************************************************/
+
+	// Get words separated by new lines
+	$words = explode( "\n", $blacklist );
+
+	// Loop through words
+	foreach ( (array) $words as $word ) {
+
+		// Trim the whitespace from the word
+		$word = trim( $word );
+
+		// Skip empty lines
+		if ( empty( $word ) ) { continue; }
+
+		// Do some escaping magic so that '#' chars in the
+		// spam words don't break things:
+		$word    = preg_quote( $word, '#' );
+		$pattern = "#$word#i";
+
+		// Loop through post data
+		foreach( $post as $post_data ) {
+
+			// Check each user data for current word
+			if ( preg_match( $pattern, $post_data ) ) {
+
+				// Post does not pass
+				return false;
+			}
+		}
+	}
+
+	// Check passed successfully
+	return true;
+}
+
+/**
+ * Check for blocked keys.
+ *
+ * @since BuddyPress (1.6.0)
+ *
+ * @uses bp_current_author_ip() To get current user IP address.
+ * @uses bp_current_author_ua() To get current user agent.
+ * @uses bp_current_user_can() Allow super admins to bypass blacklist.
+ *
+ * @param int $user_id Topic or reply author ID.
+ * @param string $title The title of the content.
+ * @param string $content The content being posted.
+ * @return bool True if test is passed, false if fail.
+ */
+function bp_core_check_for_blacklist( $user_id = 0, $title = '', $content = '' ) {
+
+	// Bail if super admin is author
+	if ( is_super_admin( $user_id ) )
+		return true;
+
+	// Define local variable
+	$post = array();
+
+	/** Blacklist *************************************************************/
+
+	// Get the moderation keys
+	$blacklist = trim( get_option( 'blacklist_keys' ) );
+
+	// Bail if blacklist is empty
+	if ( empty( $blacklist ) )
+		return true;
+
+	/** User Data *************************************************************/
+
+	// Map current user data
+	if ( !empty( $user_id ) ) {
+
+		// Get author data
+		$user = get_userdata( $user_id );
+
+		// If data exists, map it
+		if ( !empty( $user ) ) {
+			$post['author'] = $user->display_name;
+			$post['email']  = $user->user_email;
+			$post['url']    = $user->user_url;
+		}
+	}
+
+	// Current user IP and user agent
+	$post['user_ip'] = bp_core_current_user_ip();
+	$post['user_ua'] = bp_core_current_user_ua();
+
+	// Post title and content
+	$post['title']   = $title;
+	$post['content'] = $content;
+
+	/** Words *****************************************************************/
+
+	// Get words separated by new lines
+	$words = explode( "\n", $blacklist );
+
+	// Loop through words
+	foreach ( (array) $words as $word ) {
+
+		// Trim the whitespace from the word
+		$word = trim( $word );
+
+		// Skip empty lines
+		if ( empty( $word ) ) { continue; }
+
+		// Do some escaping magic so that '#' chars in the spam words don't break things:
+		$word    = preg_quote( $word, '#' );
+		$pattern = "#$word#i";
+
+		// Loop through post data
+		foreach( $post as $post_data ) {
+
+			// Check each user data for current word
+			if ( preg_match( $pattern, $post_data ) ) {
+
+				// Post does not pass
+				return false;
+			}
+		}
+	}
+
+	// Check passed successfully
+	return true;
+}
+
+/**
+ * Get the current user's IP address.
+ *
+ * @since BuddyPress (1.6.0)
+ *
+ * @return string IP address.
+ */
+function bp_core_current_user_ip() {
+	$retval = preg_replace( '/[^0-9a-fA-F:., ]/', '', $_SERVER['REMOTE_ADDR'] );
+
+	return apply_filters( 'bp_core_current_user_ip', $retval );
+}
+
+/**
+ * Get the current user's user-agent.
+ *
+ * @since BuddyPress (1.6.0)
+ *
+ * @return string User agent string.
+ */
+function bp_core_current_user_ua() {
+
+	// Sanity check the user agent
+	if ( !empty( $_SERVER['HTTP_USER_AGENT'] ) )
+		$retval = substr( $_SERVER['HTTP_USER_AGENT'], 0, 254 );
+	else
+		$retval = '';
+
+	return apply_filters( 'bp_core_current_user_ua', $retval );
+}
Index: /tags/1.9/bp-core/bp-core-options.php
===================================================================
--- /tags/1.9/bp-core/bp-core-options.php	(revision 7684)
+++ /tags/1.9/bp-core/bp-core-options.php	(revision 7684)
@@ -0,0 +1,565 @@
+<?php
+
+/**
+ * BuddyPress Options.
+ *
+ * @package BuddyPress
+ * @subpackage Options
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/**
+ * Get the default site options and their values.
+ *
+ * @since BuddyPress (1.6.0)
+ *
+ * @return array Filtered option names and values.
+ */
+function bp_get_default_options() {
+
+	// Default options
+	$options = array (
+
+		/** Components ********************************************************/
+
+		'bp-deactivated-components'       => array(),
+
+		/** bbPress ***********************************************************/
+
+		// Legacy bbPress config location
+		'bb-config-location'              => ABSPATH . 'bb-config.php',
+
+		/** XProfile **********************************************************/
+
+		// Base profile groups name
+		'bp-xprofile-base-group-name'     => 'Base',
+
+		// Base fullname field name
+		'bp-xprofile-fullname-field-name' => 'Name',
+
+		/** Blogs *************************************************************/
+
+		// Used to decide if blogs need indexing
+		'bp-blogs-first-install'          => false,
+
+		/** Settings **********************************************************/
+
+		// Disable the WP to BP profile sync
+		'bp-disable-profile-sync'         => false,
+
+		// Hide the Toolbar for logged out users
+		'hide-loggedout-adminbar'         => false,
+
+		// Avatar uploads
+		'bp-disable-avatar-uploads'       => false,
+
+		// Allow users to delete their own accounts
+		'bp-disable-account-deletion'     => false,
+
+		// Allow comments on blog and forum activity items
+		'bp-disable-blogforum-comments'   => true,
+
+		// The ID for the current theme package.
+		'_bp_theme_package_id'            => 'legacy',
+
+		/** Groups ************************************************************/
+
+		// @todo Move this into the groups component
+
+		// Restrict group creation to super admins
+		'bp_restrict_group_creation'      => false,
+
+		/** Akismet ***********************************************************/
+
+		// Users from all sites can post
+		'_bp_enable_akismet'              => true,
+
+		/** BuddyBar **********************************************************/
+
+		// Force the BuddyBar
+		'_bp_force_buddybar'              => false
+	);
+
+	return apply_filters( 'bp_get_default_options', $options );
+}
+
+/**
+ * Add default options when BuddyPress is first activated.
+ *
+ * Hooked to bp_activate, it is only called once when BuddyPress is activated.
+ * This is non-destructive, so existing settings will not be overridden.
+ *
+ * Currently unused.
+ *
+ * @since BuddyPress (1.6.0)
+ *
+ * @uses bp_get_default_options() To get default options.
+ * @uses add_option() Adds default options.
+ * @uses do_action() Calls 'bp_add_options'.
+ */
+function bp_add_options() {
+
+	// Get the default options and values
+	$options = bp_get_default_options();
+
+	// Add default options
+	foreach ( $options as $key => $value )
+		add_option( $key, $value );
+
+	// Allow previously activated plugins to append their own options.
+	do_action( 'bp_add_options' );
+}
+
+/**
+ * Delete default options.
+ *
+ * Hooked to bp_uninstall, it is only called once when BuddyPress is uninstalled.
+ * This is destructive, so existing settings will be destroyed.
+ *
+ * Currently unused.
+ *
+ * @since BuddyPress (1.6.0)
+ *
+ * @uses bp_get_default_options() To get default options.
+ * @uses delete_option() Removes default options.
+ * @uses do_action() Calls 'bp_delete_options'.
+ */
+function bp_delete_options() {
+
+	// Get the default options and values
+	$options = bp_get_default_options();
+
+	// Add default options
+	foreach ( $options as $key => $value )
+		delete_option( $key );
+
+	// Allow previously activated plugins to append their own options.
+	do_action( 'bp_delete_options' );
+}
+
+/**
+ * Add filters to each BP option, allowing them to be overloaded from inside the $bp->options array.
+ *
+ * Currently unused.
+ *
+ * @since BuddyPress (1.6.0)
+ *
+ * @uses bp_get_default_options() To get default options.
+ * @uses add_filter() To add filters to 'pre_option_{$key}'.
+ * @uses do_action() Calls 'bp_add_option_filters'.
+ */
+function bp_setup_option_filters() {
+
+	// Get the default options and values
+	$options = bp_get_default_options();
+
+	// Add filters to each BuddyPress option
+	foreach ( $options as $key => $value )
+		add_filter( 'pre_option_' . $key, 'bp_pre_get_option' );
+
+	// Allow previously activated plugins to append their own options.
+	do_action( 'bp_setup_option_filters' );
+}
+
+/**
+ * Filter default options and allow them to be overloaded from inside the $bp->options array.
+ *
+ * Currently unused.
+ *
+ * @since BuddyPress (1.6)
+ *
+ * @global BuddyPress $bp
+ * @param bool $value Optional. Default value false
+ * @return mixed false if not overloaded, mixed if set
+ */
+function bp_pre_get_option( $value = false ) {
+	global $bp;
+
+	// Get the name of the current filter so we can manipulate it
+	$filter = current_filter();
+
+	// Remove the filter prefix
+	$option = str_replace( 'pre_option_', '', $filter );
+
+	// Check the options global for preset value
+	if ( !empty( $bp->options[$option] ) )
+		$value = $bp->options[$option];
+
+	// Always return a value, even if false
+	return $value;
+}
+
+/**
+ * Retrieve an option.
+ *
+ * This is a wrapper for {@link get_blog_option()}, which in turn stores settings data
+ * (such as bp-pages) on the appropriate blog, given your current setup.
+ *
+ * The 'bp_get_option' filter is primarily for backward-compatibility.
+ *
+ * @since BuddyPress (1.5.0)
+ *
+ * @uses bp_get_root_blog_id()
+ *
+ * @param string $option_name The option to be retrieved.
+ * @param string $default Optional. Default value to be returned if the option
+ *        isn't set. See {@link get_blog_option()}.
+ * @return mixed The value for the option.
+ */
+function bp_get_option( $option_name, $default = '' ) {
+	$value = get_blog_option( bp_get_root_blog_id(), $option_name, $default );
+
+	return apply_filters( 'bp_get_option', $value );
+}
+
+/**
+ * Save an option.
+ *
+ * This is a wrapper for {@link update_blog_option()}, which in turn stores
+ * settings data (such as bp-pages) on the appropriate blog, given your current
+ * setup.
+ *
+ * @since BuddyPress (1.5.0)
+ *
+ * @uses bp_get_root_blog_id()
+ *
+ * @param string $option_name The option key to be set.
+ * @param string $value The value to be set.
+ */
+function bp_update_option( $option_name, $value ) {
+	update_blog_option( bp_get_root_blog_id(), $option_name, $value );
+}
+
+/**
+ * Delete an option.
+ *
+ * This is a wrapper for {@link delete_blog_option()}, which in turn deletes
+ * settings data (such as bp-pages) on the appropriate blog, given your current
+ * setup.
+ *
+ * @since BuddyPress (1.5.0)
+ *
+ * @uses bp_get_root_blog_id()
+ *
+ * @param string $option_name The option key to be deleted.
+ */
+function bp_delete_option( $option_name ) {
+	delete_blog_option( bp_get_root_blog_id(), $option_name );
+}
+
+/**
+ * Copy BP options from a single site to multisite config.
+ *
+ * Run when switching from single to multisite and we need to copy blog options
+ * to site options.
+ *
+ * This function is no longer used.
+ *
+ * @deprecated 1.6.0
+ */
+function bp_core_activate_site_options( $keys = array() ) {
+	global $bp;
+
+	if ( !empty( $keys ) && is_array( $keys ) ) {
+		$errors = false;
+
+		foreach ( $keys as $key => $default ) {
+			if ( empty( $bp->site_options[ $key ] ) ) {
+				$bp->site_options[ $key ] = bp_get_option( $key, $default );
+
+				if ( !bp_update_option( $key, $bp->site_options[ $key ] ) ) {
+					$errors = true;
+				}
+			}
+		}
+
+		if ( empty( $errors ) ) {
+			return true;
+		}
+	}
+
+	return false;
+}
+
+/**
+ * Fetch global BP options.
+ *
+ * BuddyPress uses common options to store configuration settings. Many of these
+ * settings are needed at run time. Instead of fetching them all and adding many
+ * initial queries to each page load, let's fetch them all in one go.
+ *
+ * @todo Use settings API and audit these methods.
+ *
+ * @return array $root_blog_options_meta List of options.
+ */
+function bp_core_get_root_options() {
+	global $wpdb;
+
+	// Get all the BuddyPress settings, and a few useful WP ones too
+	$root_blog_options                   = bp_get_default_options();
+	$root_blog_options['registration']   = '0';
+	$root_blog_options['avatar_default'] = 'mysteryman';
+	$root_blog_option_keys               = array_keys( $root_blog_options );
+
+	// Do some magic to get all the root blog options in 1 swoop
+	$blog_options_keys      = "'" . join( "', '", (array) $root_blog_option_keys ) . "'";
+	$blog_options_table	    = bp_is_multiblog_mode() ? $wpdb->options : $wpdb->get_blog_prefix( bp_get_root_blog_id() ) . 'options';
+	$blog_options_query     = "SELECT option_name AS name, option_value AS value FROM {$blog_options_table} WHERE option_name IN ( {$blog_options_keys} )";
+	$root_blog_options_meta = $wpdb->get_results( $blog_options_query );
+
+	// On Multisite installations, some options must always be fetched from sitemeta
+	if ( is_multisite() ) {
+		$network_options = apply_filters( 'bp_core_network_options', array(
+			'tags_blog_id'       => '0',
+			'sitewide_tags_blog' => '',
+			'registration'       => '0',
+			'fileupload_maxk'    => '1500'
+		) );
+
+		$current_site           = get_current_site();
+		$network_option_keys    = array_keys( $network_options );
+		$sitemeta_options_keys  = "'" . join( "', '", (array) $network_option_keys ) . "'";
+		$sitemeta_options_query = $wpdb->prepare( "SELECT meta_key AS name, meta_value AS value FROM {$wpdb->sitemeta} WHERE meta_key IN ( {$sitemeta_options_keys} ) AND site_id = %d", $current_site->id );
+		$network_options_meta   = $wpdb->get_results( $sitemeta_options_query );
+
+		// Sitemeta comes second in the merge, so that network 'registration' value wins
+		$root_blog_options_meta = array_merge( $root_blog_options_meta, $network_options_meta );
+	}
+
+	// Missing some options, so do some one-time fixing
+	if ( empty( $root_blog_options_meta ) || ( count( $root_blog_options_meta ) < count( $root_blog_option_keys ) ) ) {
+
+		// Get a list of the keys that are already populated
+		$existing_options = array();
+		foreach( $root_blog_options_meta as $already_option ) {
+			$existing_options[$already_option->name] = $already_option->value;
+		}
+
+		// Unset the query - We'll be resetting it soon
+		unset( $root_blog_options_meta );
+
+		// Loop through options
+		foreach ( $root_blog_options as $old_meta_key => $old_meta_default ) {
+			// Clear out the value from the last time around
+			unset( $old_meta_value );
+
+			if ( isset( $existing_options[$old_meta_key] ) ) {
+				continue;
+			}
+
+			// Get old site option
+			if ( is_multisite() )
+				$old_meta_value = get_site_option( $old_meta_key );
+
+			// No site option so look in root blog
+			if ( empty( $old_meta_value ) )
+				$old_meta_value = bp_get_option( $old_meta_key, $old_meta_default );
+
+			// Update the root blog option
+			bp_update_option( $old_meta_key, $old_meta_value );
+
+			// Update the global array
+			$root_blog_options_meta[$old_meta_key] = $old_meta_value;
+		}
+
+		$root_blog_options_meta = array_merge( $root_blog_options_meta, $existing_options );
+		unset( $existing_options );
+
+	// We're all matched up
+	} else {
+		// Loop through our results and make them usable
+		foreach ( $root_blog_options_meta as $root_blog_option )
+			$root_blog_options[$root_blog_option->name] = $root_blog_option->value;
+
+		// Copy the options no the return val
+		$root_blog_options_meta = $root_blog_options;
+
+		// Clean up our temporary copy
+		unset( $root_blog_options );
+	}
+
+	return apply_filters( 'bp_core_get_root_options', $root_blog_options_meta );
+}
+
+/** Active? *******************************************************************/
+
+/**
+ * Is profile sycing disabled?
+ *
+ * @since BuddyPress (1.6.0)
+ *
+ * @uses bp_get_option() To get the profile sync option.
+ *
+ * @param bool $default Optional. Fallback value if not found in the database.
+ *        Default: true.
+ * @return bool True if profile sync is enabled, otherwise false.
+ */
+function bp_disable_profile_sync( $default = true ) {
+	return (bool) apply_filters( 'bp_disable_profile_sync', (bool) bp_get_option( 'bp-disable-profile-sync', $default ) );
+}
+
+/**
+ * Is the Toolbar hidden for logged out users?
+ *
+ * @since BuddyPress (1.6.0)
+ *
+ * @uses bp_get_option() To get the logged out Toolbar option.
+ *
+ * @param bool $default Optional. Fallback value if not found in the database.
+ *        Default: true.
+ * @return bool True if the admin bar should be hidden for logged-out users,
+ *         otherwise false.
+ */
+function bp_hide_loggedout_adminbar( $default = true ) {
+	return (bool) apply_filters( 'bp_hide_loggedout_adminbar', (bool) bp_get_option( 'hide-loggedout-adminbar', $default ) );
+}
+
+/**
+ * Are members able to upload their own avatars?
+ *
+ * @since BuddyPress (1.6.0)
+ *
+ * @uses bp_get_option() To get the avatar uploads option.
+ *
+ * @param bool $default Optional. Fallback value if not found in the database.
+ *        Default: true.
+ * @return bool True if avatar uploads are disabled, otherwise false.
+ */
+function bp_disable_avatar_uploads( $default = true ) {
+	return (bool) apply_filters( 'bp_disable_avatar_uploads', (bool) bp_get_option( 'bp-disable-avatar-uploads', $default ) );
+}
+
+/**
+ * Are members able to delete their own accounts?
+ *
+ * @since BuddyPress (1.6.0)
+ *
+ * @uses bp_get_option() To get the account deletion option.
+ *
+ * @param bool $default Optional. Fallback value if not found in the database.
+ *        Default: true.
+ * @return bool True if users are able to delete their own accounts, otherwise
+ *         false.
+ */
+function bp_disable_account_deletion( $default = false ) {
+	return apply_filters( 'bp_disable_account_deletion', (bool) bp_get_option( 'bp-disable-account-deletion', $default ) );
+}
+
+/**
+ * Are blog and forum activity stream comments disabled?
+ *
+ * @since BuddyPress (1.6.0)
+ *
+ * @todo split and move into blog and forum components.
+ * @uses bp_get_option() To get the blog/forum comments option.
+ *
+ * @param bool $default Optional. Fallback value if not found in the database.
+ *        Default: false.
+ * @return bool True if activity comments are disabled for blog and forum
+ *         items, otherwise false.
+ */
+function bp_disable_blogforum_comments( $default = false ) {
+	return (bool) apply_filters( 'bp_disable_blogforum_comments', (bool) bp_get_option( 'bp-disable-blogforum-comments', $default ) );
+}
+
+/**
+ * Is group creation turned off?
+ *
+ * @since BuddyPress (1.6.0)
+ *
+ * @todo Move into groups component.
+ * @uses bp_get_option() To get the group creation.
+ *
+ * @param bool $default Optional. Fallback value if not found in the database.
+ *        Default: true.
+ * @return bool True if group creation is restricted, otherwise false.
+ */
+function bp_restrict_group_creation( $default = true ) {
+	return (bool) apply_filters( 'bp_restrict_group_creation', (bool) bp_get_option( 'bp_restrict_group_creation', $default ) );
+}
+
+/**
+ * Should the old BuddyBar be forced in place of the WP admin bar?
+ *
+ * @since BuddyPress (1.6.0)
+ *
+ * @uses bp_get_option() To get the BuddyBar option.
+ *
+ * @param bool $default Optional. Fallback value if not found in the database.
+ *        Default: true.
+ * @return bool True if the BuddyBar should be forced on, otherwise false.
+ */
+function bp_force_buddybar( $default = true ) {
+	return (bool) apply_filters( 'bp_force_buddybar', (bool) bp_get_option( '_bp_force_buddybar', $default ) );
+}
+
+/**
+ * Output the group forums root parent forum id.
+ *
+ * @since BuddyPress (1.6.0)
+ *
+ * @param bool $default Optional. Default: '0'.
+ */
+function bp_group_forums_root_id( $default = '0' ) {
+	echo bp_get_group_forums_root_id( $default );
+}
+	/**
+	 * Return the group forums root parent forum id.
+	 *
+	 * @since BuddyPress (1.6.0)
+	 *
+	 * @uses bp_get_option() To get the root forum ID from the database.
+	 *
+	 * @param bool $default Optional. Default: '0'.
+	 * @return int The ID of the group forums root forum.
+	 */
+	function bp_get_group_forums_root_id( $default = '0' ) {
+		return (int) apply_filters( 'bp_get_group_forums_root_id', (int) bp_get_option( '_bp_group_forums_root_id', $default ) );
+	}
+
+/**
+ * Check whether BuddyPress Group Forums are enabled.
+ *
+ * @since BuddyPress (1.6.0)
+ *
+ * @uses bp_get_option() To get the group forums option.
+ *
+ * @param bool $default Optional. Fallback value if not found in the database.
+ *        Default: true.
+ * @return bool True if group forums are active, otherwise false.
+ */
+function bp_is_group_forums_active( $default = true ) {
+	return (bool) apply_filters( 'bp_is_group_forums_active', (bool) bp_get_option( '_bp_enable_group_forums', $default ) );
+}
+
+/**
+ * Check whether Akismet is enabled.
+ *
+ * @since BuddyPress (1.6.0)
+ *
+ * @uses bp_get_option() To get the Akismet option.
+ *
+ * @param bool $default Optional. Fallback value if not found in the database.
+ *        Default: true.
+ * @return bool True if Akismet is enabled, otherwise false.
+ */
+function bp_is_akismet_active( $default = true ) {
+	return (bool) apply_filters( 'bp_is_akismet_active', (bool) bp_get_option( '_bp_enable_akismet', $default ) );
+}
+
+/**
+ * Get the current theme package ID.
+ *
+ * @since BuddyPress (1.7.0)
+ *
+ * @uses get_option() To get the theme package option.
+ *
+ * @param bool $default Optional. Fallback value if not found in the database.
+ *        Default: 'legacy'.
+ * @return string ID of the theme package.
+ */
+function bp_get_theme_package_id( $default = 'legacy' ) {
+	return apply_filters( 'bp_get_theme_package_id', bp_get_option( '_bp_theme_package_id', $default ) );
+}
Index: /tags/1.9/bp-core/bp-core-template-loader.php
===================================================================
--- /tags/1.9/bp-core/bp-core-template-loader.php	(revision 7684)
+++ /tags/1.9/bp-core/bp-core-template-loader.php	(revision 7684)
@@ -0,0 +1,443 @@
+<?php
+
+/**
+ * BuddyPress Template Functions.
+ *
+ * This file contains functions necessary to mirror the WordPress core template
+ * loading process. Many of those functions are not filterable, and even then
+ * would not be robust enough to predict where BuddyPress templates might exist.
+ *
+ * @package BuddyPress
+ * @subpackage TemplateFunctions
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/**
+ * Get a BuddyPress template part for display in a theme.
+ *
+ * @since BuddyPress (1.7.0)
+ *
+ * @uses bp_locate_template()
+ * @uses load_template()
+ * @uses get_template_part()
+ *
+ * @param string $slug Template part slug. Used to generate filenames, eg
+ *        'friends' for 'friends.php'.
+ * @param string $name Optional. Template part name. Used to generate
+ *        secondary filenames, eg 'personal' for 'activity-personal.php'.
+ * @return string Path to located template. See {@link bp_locate_template()}.
+ */
+function bp_get_template_part( $slug, $name = null ) {
+
+	// Execute code for this part
+	do_action( 'get_template_part_' . $slug, $slug, $name );
+
+	// Setup possible parts
+	$templates = array();
+	if ( isset( $name ) )
+		$templates[] = $slug . '-' . $name . '.php';
+	$templates[] = $slug . '.php';
+
+	// Allow template parts to be filtered
+	$templates = apply_filters( 'bp_get_template_part', $templates, $slug, $name );
+
+	// Return the part that is found
+	return bp_locate_template( $templates, true, false );
+}
+
+/**
+ * Retrieve the name of the highest priority template file that exists.
+ *
+ * Searches in the STYLESHEETPATH before TEMPLATEPATH so that themes which
+ * inherit from a parent theme can just overload one file. If the template is
+ * not found in either of those, it looks in the theme-compat folder last.
+ *
+ * @since BuddyPress (1.7.0)
+ *
+ * @param string|array $template_names Template file(s) to search for, in order.
+ * @param bool $load Optional. If true, the template file will be loaded when
+ *        found. If false, the path will be returned. Default: false.
+ * @param bool $require_once Optional. Whether to require_once or require. Has
+ *        no effect if $load is false. Default: true.
+ * @return string The template filename if one is located.
+ */
+function bp_locate_template( $template_names, $load = false, $require_once = true ) {
+
+	// No file found yet
+	$located            = false;
+	$template_locations = bp_get_template_stack();
+
+	// Try to find a template file
+	foreach ( (array) $template_names as $template_name ) {
+
+		// Continue if template is empty
+		if ( empty( $template_name ) )
+			continue;
+
+		// Trim off any slashes from the template name
+		$template_name  = ltrim( $template_name, '/' );
+
+		// Loop through template stack
+		foreach ( (array) $template_locations as $template_location ) {
+
+			// Continue if $template_location is empty
+			if ( empty( $template_location ) )
+				continue;
+
+			// Check child theme first
+			if ( file_exists( trailingslashit( $template_location ) . $template_name ) ) {
+				$located = trailingslashit( $template_location ) . $template_name;
+				break 2;
+			}
+		}
+	}
+
+	// Maybe load the template if one was located
+	if ( ( true == $load ) && !empty( $located ) )
+		load_template( $located, $require_once );
+
+	return $located;
+}
+
+/**
+ * Register a new template stack location.
+ *
+ * This allows for templates to live in places beyond just the parent/child
+ * relationship, to allow for custom template locations. Used in conjunction
+ * with bp_locate_template(), this allows for easy template overrides.
+ *
+ * @since BuddyPress (1.7.0)
+ *
+ * @todo Make 'callable' instead of 'function'.
+ *
+ * @param string $location Callback function that returns the stack location.
+ * @param int $priority Optional. The priority parameter as passed to
+ *        add_filter(). Default: 10.
+ * @return bool See {@link add_filter()}.
+ */
+function bp_register_template_stack( $location_callback = '', $priority = 10 ) {
+
+	// Bail if no location, or function does not exist
+	if ( empty( $location_callback ) || ! function_exists( $location_callback ) )
+		return false;
+
+	// Add location callback to template stack
+	return add_filter( 'bp_template_stack', $location_callback, (int) $priority );
+}
+
+/**
+ * Deregister a previously registered template stack location.
+ *
+ * @since BuddyPress (1.7.0)
+ *
+ * @see bp_register_template_stack()
+ *
+ * @param string $location Callback function that returns the stack location.
+ * @param int $priority Optional. The priority parameter passed to
+ *        {@link bp_register_template_stack()}. Default: 10.
+ * @return bool See {@link remove_filter()}.
+ */
+function bp_deregister_template_stack( $location_callback = '', $priority = 10 ) {
+
+	// Bail if no location, or function does not exist
+	if ( empty( $location_callback ) || ! function_exists( $location_callback ) )
+		return false;
+
+	// Add location callback to template stack
+	return remove_filter( 'bp_template_stack', $location_callback, (int) $priority );
+}
+
+/**
+ * Get the "template stack", a list of registered directories where templates can be found.
+ *
+ * Calls the functions added to the 'bp_template_stack' filter hook, and return
+ * an array of the template locations.
+ *
+ * @see bp_register_template_stack()
+ *
+ * @since BuddyPress (1.7.0)
+ *
+ * @global array $wp_filter Stores all of the filters.
+ * @global array $merged_filters Merges the filter hooks using this function..
+ * @global array $wp_current_filter stores the list of current filters with
+ *         the current one last.
+ * @return array The filtered value after all hooked functions are applied to it.
+ */
+function bp_get_template_stack() {
+	global $wp_filter, $merged_filters, $wp_current_filter;
+
+	// Setup some default variables
+	$tag  = 'bp_template_stack';
+	$args = $stack = array();
+
+	// Add 'bp_template_stack' to the current filter array
+	$wp_current_filter[] = $tag;
+
+	// Sort
+	if ( ! isset( $merged_filters[ $tag ] ) ) {
+		ksort( $wp_filter[$tag] );
+		$merged_filters[ $tag ] = true;
+	}
+
+	// Ensure we're always at the beginning of the filter array
+	reset( $wp_filter[ $tag ] );
+
+	// Loop through 'bp_template_stack' filters, and call callback functions
+	do {
+		foreach( (array) current( $wp_filter[$tag] ) as $the_ ) {
+			if ( ! is_null( $the_['function'] ) ) {
+				$args[1] = $stack;
+				$stack[] = call_user_func_array( $the_['function'], array_slice( $args, 1, (int) $the_['accepted_args'] ) );
+			}
+		}
+	} while ( next( $wp_filter[$tag] ) !== false );
+
+	// Remove 'bp_template_stack' from the current filter array
+	array_pop( $wp_current_filter );
+
+	// Remove empties and duplicates
+	$stack = array_unique( array_filter( $stack ) );
+
+	return (array) apply_filters( 'bp_get_template_stack', $stack ) ;
+}
+
+/**
+ * Put a template part into an output buffer, and return it.
+ *
+ * @since BuddyPress (1.7.0)
+ *
+ * @see bp_get_template_part() for a description of $slug and $name params.
+ *
+ * @param string $slug See {@link bp_get_template_part()}.
+ * @param string $name See {@link bp_get_template_part()}.
+ * @param bool $echo If true, template content will be echoed. If false,
+ *        returned. Default: true.
+ * @return string|null If $echo, returns the template content.
+ */
+function bp_buffer_template_part( $slug, $name = null, $echo = true ) {
+	ob_start();
+
+	// Remove 'bp_replace_the_content' filter to prevent infinite loops
+	remove_filter( 'the_content', 'bp_replace_the_content' );
+
+	bp_get_template_part( $slug, $name );
+
+	// Remove 'bp_replace_the_content' filter to prevent infinite loops
+	add_filter( 'the_content', 'bp_replace_the_content' );
+
+	// Get the output buffer contents
+	$output = ob_get_clean();
+
+	// Echo or return the output buffer contents
+	if ( true === $echo ) {
+		echo $output;
+	} else {
+		return $output;
+	}
+}
+
+/**
+ * Retrieve the path to a template.
+ *
+ * Used to quickly retrieve the path of a template without including the file
+ * extension. It will also check the parent theme and theme-compat theme with
+ * the use of {@link bp_locate_template()}. Allows for more generic template
+ * locations without the use of the other get_*_template() functions.
+ *
+ * @since BuddyPress (1.7.0)
+ *
+ * @uses bp_set_theme_compat_templates()
+ * @uses bp_locate_template()
+ * @uses bp_set_theme_compat_template()
+ *
+ * @param string $type Filename without extension.
+ * @param array $templates An optional list of template candidates.
+ * @return string Full path to file.
+ */
+function bp_get_query_template( $type, $templates = array() ) {
+	$type = preg_replace( '|[^a-z0-9-]+|', '', $type );
+
+	if ( empty( $templates ) )
+		$templates = array( "{$type}.php" );
+
+	// Filter possible templates, try to match one, and set any BuddyPress theme
+	// compat properties so they can be cross-checked later.
+	$templates = apply_filters( "bp_get_{$type}_template", $templates );
+	$templates = bp_set_theme_compat_templates( $templates );
+	$template  = bp_locate_template( $templates );
+	$template  = bp_set_theme_compat_template( $template );
+
+	return apply_filters( "bp_{$type}_template", $template );
+}
+
+/**
+ * Get the possible subdirectories to check for templates in
+ *
+ * @since BuddyPress (1.7)
+ * @param array $templates Templates we are looking for
+ * @return array Possible subfolders to look in
+ */
+function bp_get_template_locations( $templates = array() ) {
+	$locations = array(
+		'buddypress',
+		'community',
+		''
+	);
+	return apply_filters( 'bp_get_template_locations', $locations, $templates );
+}
+
+/**
+ * Add template locations to template files being searched for.
+ *
+ * @since BuddyPress (1.7.0)
+ *
+ * @param array $stacks Array of template locations.
+ * @return array() Array of all template locations registered so far.
+ */
+function bp_add_template_stack_locations( $stacks = array() ) {
+	$retval = array();
+
+	// Get alternate locations
+	$locations = bp_get_template_locations();
+
+	// Loop through locations and stacks and combine
+	foreach ( (array) $stacks as $stack )
+		foreach ( (array) $locations as $custom_location )
+			$retval[] = untrailingslashit( trailingslashit( $stack ) . $custom_location );
+
+	return apply_filters( 'bp_add_template_stack_locations', array_unique( $retval ), $stacks );
+}
+
+/**
+ * Add checks for BuddyPress conditions to 'parse_query' action.
+ *
+ * @since BuddyPress (1.7.0)
+ *
+ * @param WP_Query $posts_query
+ */
+function bp_parse_query( $posts_query ) {
+
+	// Bail if $posts_query is not the main loop
+	if ( ! $posts_query->is_main_query() )
+		return;
+
+	// Bail if filters are suppressed on this query
+	if ( true == $posts_query->get( 'suppress_filters' ) )
+		return;
+
+	// Bail if in admin
+	if ( is_admin() )
+		return;
+
+	// Allow BuddyPress components to parse the main query
+	do_action_ref_array( 'bp_parse_query', array( &$posts_query ) );
+}
+
+/**
+ * Possibly intercept the template being loaded.
+ *
+ * Listens to the 'template_include' filter and waits for any BuddyPress specific
+ * template condition to be met. If one is met and the template file exists,
+ * it will be used; otherwise
+ *
+ * Note that the _edit() checks are ahead of their counterparts, to prevent them
+ * from being stomped on accident.
+ *
+ * @since BuddyPress (1.7.0)
+ *
+ * @param string $template
+ * @return string The path to the template file that is being used.
+ */
+function bp_template_include_theme_supports( $template = '' ) {
+
+	// Look for root BuddyPress template files in parent/child themes
+	$new_template = apply_filters( 'bp_get_root_template', false, $template );
+
+	// A BuddyPress template file was located, so override the WordPress
+	// template and use it to switch off BuddyPress's theme compatibility.
+	if ( !empty( $new_template ) ) {
+		$template = bp_set_template_included( $new_template );
+	}
+
+	return apply_filters( 'bp_template_include_theme_supports', $template );
+}
+
+/**
+ * Set the included template.
+ *
+ * @since BuddyPress (1.8.0)
+ *
+ * @param mixed $template Default: false.
+ * @return mixed False if empty. Template name if template included.
+ */
+function bp_set_template_included( $template = false ) {
+	buddypress()->theme_compat->found_template = $template;
+
+	return buddypress()->theme_compat->found_template;
+}
+
+/**
+ * Is a BuddyPress template being included?
+ *
+ * @since BuddyPress (1.8.0)
+ * @return bool True if yes, false if no.
+ */
+function bp_is_template_included() {
+	return ! empty( buddypress()->theme_compat->found_template );
+}
+
+/**
+ * Attempt to load a custom BP functions file, similar to each themes functions.php file.
+ *
+ * @since BuddyPress (1.7.0)
+ *
+ * @global string $pagenow
+ * @uses bp_locate_template()
+ */
+function bp_load_theme_functions() {
+	global $pagenow, $wp_query;
+
+	// do not load our custom BP functions file if theme compat is disabled
+	if ( ! bp_use_theme_compat_with_current_theme() ) {
+		return;
+	}
+
+	// Do not include on BuddyPress deactivation
+	if ( bp_is_deactivation() )
+		return;
+
+	// If the $wp_query global is empty (the main query has not been run,
+	// or has been reset), load_template() will fail at setting certain
+	// global values. This does not happen on a normal page load, but can
+	// cause problems when running automated tests
+	if ( ! is_a( $wp_query, 'WP_Query' ) ) {
+		return;
+	}
+
+	// Only include if not installing or if activating via wp-activate.php
+	if ( ! defined( 'WP_INSTALLING' ) || 'wp-activate.php' === $pagenow ) {
+		bp_locate_template( 'buddypress-functions.php', true );
+	}
+}
+
+/**
+ * Get the templates to use as the endpoint for BuddyPress template parts.
+ *
+ * @since BuddyPress (1.7.0)
+ *
+ * @return array Array of possible root level wrapper template files.
+ */
+function bp_get_theme_compat_templates() {
+	$templates = array(
+		'plugin-buddypress.php',
+		'buddypress.php',
+		'community.php',
+		'generic.php',
+		'page.php',
+		'single.php',
+		'index.php'
+	);
+	return bp_get_query_template( 'buddypress', $templates );
+}
Index: /tags/1.9/bp-core/bp-core-template.php
===================================================================
--- /tags/1.9/bp-core/bp-core-template.php	(revision 7684)
+++ /tags/1.9/bp-core/bp-core-template.php	(revision 7684)
@@ -0,0 +1,2616 @@
+<?php
+/**
+ * Core component template tag functions
+ *
+ * @package BuddyPress
+ * @subpackage TemplateFunctions
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/**
+ * Output the "options nav", the secondary-level single item navigation menu.
+ *
+ * Uses the $bp->bp_options_nav global to render out the sub navigation for the
+ * current component. Each component adds to its sub navigation array within
+ * its own setup_nav() function.
+ *
+ * This sub navigation array is the secondary level navigation, so for profile
+ * it contains:
+ *      [Public, Edit Profile, Change Avatar]
+ *
+ * The function will also analyze the current action for the current component
+ * to determine whether or not to highlight a particular sub nav item.
+ *
+ * @global BuddyPress $bp The one true BuddyPress instance.
+ * @uses bp_get_user_nav() Renders the navigation for a profile of a currently
+ *       viewed user.
+ */
+function bp_get_options_nav() {
+	global $bp;
+
+	// If we are looking at a member profile, then the we can use the current component as an
+	// index. Otherwise we need to use the component's root_slug
+	$component_index = !empty( $bp->displayed_user ) ? bp_current_component() : bp_get_root_slug( bp_current_component() );
+
+	if ( !bp_is_single_item() ) {
+		if ( !isset( $bp->bp_options_nav[$component_index] ) || count( $bp->bp_options_nav[$component_index] ) < 1 ) {
+			return false;
+		} else {
+			$the_index = $component_index;
+		}
+	} else {
+		if ( !isset( $bp->bp_options_nav[bp_current_item()] ) || count( $bp->bp_options_nav[bp_current_item()] ) < 1 ) {
+			return false;
+		} else {
+			$the_index = bp_current_item();
+		}
+	}
+
+	// Loop through each navigation item
+	foreach ( (array) $bp->bp_options_nav[$the_index] as $subnav_item ) {
+		if ( !$subnav_item['user_has_access'] )
+			continue;
+
+		// If the current action or an action variable matches the nav item id, then add a highlight CSS class.
+		if ( $subnav_item['slug'] == bp_current_action() ) {
+			$selected = ' class="current selected"';
+		} else {
+			$selected = '';
+		}
+
+		// List type depends on our current component
+		$list_type = bp_is_group() ? 'groups' : 'personal';
+
+		// echo out the final list item
+		echo apply_filters( 'bp_get_options_nav_' . $subnav_item['css_id'], '<li id="' . $subnav_item['css_id'] . '-' . $list_type . '-li" ' . $selected . '><a id="' . $subnav_item['css_id'] . '" href="' . $subnav_item['link'] . '">' . $subnav_item['name'] . '</a></li>', $subnav_item );
+	}
+}
+
+/**
+ * Get the 'bp_options_title' property from the BP global.
+ *
+ * Not currently used in BuddyPress.
+ * @todo Deprecate.
+ */
+function bp_get_options_title() {
+	global $bp;
+
+	if ( empty( $bp->bp_options_title ) )
+		$bp->bp_options_title = __( 'Options', 'buddypress' );
+
+	echo apply_filters( 'bp_get_options_title', esc_attr( $bp->bp_options_title ) );
+}
+
+/** Avatars *******************************************************************/
+
+/**
+ * Check to see if there is an options avatar.
+ *
+ * An options avatar is an avatar for something like a group, or a friend.
+ * Basically an avatar that appears in the sub nav options bar.
+ *
+ * Not currently used in BuddyPress.
+ *
+ * @global BuddyPress $bp The one true BuddyPress instance.
+ * @todo Deprecate.
+ *
+ * @return bool Returns true if an options avatar has been set, otherwise
+ *         false.
+ */
+function bp_has_options_avatar() {
+	global $bp;
+
+	if ( empty( $bp->bp_options_avatar ) )
+		return false;
+
+	return true;
+}
+
+/**
+ * Output the options avatar.
+ *
+ * Not currently used in BuddyPress.
+ *
+ * @todo Deprecate.
+ */
+function bp_get_options_avatar() {
+	global $bp;
+
+	echo apply_filters( 'bp_get_options_avatar', $bp->bp_options_avatar );
+}
+
+/**
+ * Output a comment author's avatar.
+ *
+ * Not currently used in BuddyPress.
+ *
+ * @todo Deprecate.
+ */
+function bp_comment_author_avatar() {
+	global $comment;
+
+	if ( function_exists( 'bp_core_fetch_avatar' ) )
+		echo apply_filters( 'bp_comment_author_avatar', bp_core_fetch_avatar( array( 'item_id' => $comment->user_id, 'type' => 'thumb', 'alt' => sprintf( __( 'Avatar of %s', 'buddypress' ), bp_core_get_user_displayname( $comment->user_id ) ) ) ) );
+	else if ( function_exists('get_avatar') )
+		get_avatar();
+}
+
+/**
+ * Output a post author's avatar.
+ *
+ * Not currently used in BuddyPress.
+ *
+ * @todo Deprecate.
+ */
+function bp_post_author_avatar() {
+	global $post;
+
+	if ( function_exists( 'bp_core_fetch_avatar' ) )
+		echo apply_filters( 'bp_post_author_avatar', bp_core_fetch_avatar( array( 'item_id' => $post->post_author, 'type' => 'thumb', 'alt' => sprintf( __( 'Avatar of %s', 'buddypress' ), bp_core_get_user_displayname( $post->post_author ) ) ) ) );
+	else if ( function_exists('get_avatar') )
+		get_avatar();
+}
+
+/**
+ * Output the current avatar upload step.
+ */
+function bp_avatar_admin_step() {
+	echo bp_get_avatar_admin_step();
+}
+	/**
+	 * Return the current avatar upload step.
+	 *
+	 * @return string The current avatar upload step. Returns 'upload-image'
+	 *         if none is found.
+	 */
+	function bp_get_avatar_admin_step() {
+		global $bp;
+
+		if ( isset( $bp->avatar_admin->step ) )
+			$step = $bp->avatar_admin->step;
+		else
+			$step = 'upload-image';
+
+		return apply_filters( 'bp_get_avatar_admin_step', $step );
+	}
+
+/**
+ * Output the URL of the avatar to crop.
+ */
+function bp_avatar_to_crop() {
+	echo bp_get_avatar_to_crop();
+}
+	/**
+	 * Return the URL of the avatar to crop.
+	 *
+	 * @return string URL of the avatar awaiting cropping.
+	 */
+	function bp_get_avatar_to_crop() {
+		global $bp;
+
+		if ( isset( $bp->avatar_admin->image->url ) )
+			$url = $bp->avatar_admin->image->url;
+		else
+			$url = '';
+
+		return apply_filters( 'bp_get_avatar_to_crop', $url );
+	}
+
+/**
+ * Output the relative file path to the avatar to crop.
+ */
+function bp_avatar_to_crop_src() {
+	echo bp_get_avatar_to_crop_src();
+}
+	/**
+	 * Return the relative file path to the avatar to crop.
+	 *
+	 * @return string Relative file path to the avatar.
+	 */
+	function bp_get_avatar_to_crop_src() {
+		global $bp;
+
+		return apply_filters( 'bp_get_avatar_to_crop_src', str_replace( WP_CONTENT_DIR, '', $bp->avatar_admin->image->dir ) );
+	}
+
+/**
+ * Output the avatar cropper <img> markup.
+ *
+ * No longer used in BuddyPress.
+ *
+ * @todo Deprecate.
+ */
+function bp_avatar_cropper() {
+	global $bp;
+
+	echo '<img id="avatar-to-crop" class="avatar" src="' . $bp->avatar_admin->image . '" />';
+}
+
+/**
+ * Output the name of the BP site. Used in RSS headers.
+ */
+function bp_site_name() {
+	echo bp_get_site_name();
+}
+	/**
+	 * Returns the name of the BP site. Used in RSS headers.
+	 *
+	 * @since BuddyPress (1.6.0)
+	 */
+	function bp_get_site_name() {
+		return apply_filters( 'bp_site_name', get_bloginfo( 'name', 'display' ) );
+	}
+
+/**
+ * Format a date.
+ *
+ * @param int $time The UNIX timestamp to be formatted.
+ * @param bool $just_date Optional. True to return only the month + day, false
+ *        to return month, day, and time. Default: false.
+ * @param bool $localize_time Optional. True to display in local time, false to
+ *        leave in GMT. Default: true.
+ * @return string|bool $localize_time Optional. A string representation of
+ *         $time, in the format "January 1, 2010 at 9:50pm" (or whatever your
+ *         'date_format' and 'time_format' settings are). False on failure.
+ */
+function bp_format_time( $time, $just_date = false, $localize_time = true ) {
+	if ( !isset( $time ) || !is_numeric( $time ) )
+		return false;
+
+	// Get GMT offset from root blog
+	$root_blog_offset = false;
+	if ( $localize_time )
+		$root_blog_offset = get_blog_option( bp_get_root_blog_id(), 'gmt_offset' );
+
+	// Calculate offset time
+	$time_offset = $time + ( $root_blog_offset * 3600 );
+
+	// Current date (January 1, 2010)
+	$date = date_i18n( get_option( 'date_format' ), $time_offset );
+
+	// Should we show the time also?
+	if ( !$just_date ) {
+		// Current time (9:50pm)
+		$time = date_i18n( get_option( 'time_format' ), $time_offset );
+
+		// Return string formatted with date and time
+		$date = sprintf( __( '%1$s at %2$s', 'buddypress' ), $date, $time );
+	}
+
+	return apply_filters( 'bp_format_time', $date );
+}
+
+/**
+ * Select between two dynamic strings, according to context.
+ *
+ * This function can be used in cases where a phrase used in a template will
+ * differ for a user looking at his own profile and a user looking at another
+ * user's profile (eg, "My Friends" and "Joe's Friends"). Pass both versions
+ * of the phrase, and bp_word_or_name() will detect which is appropriate, and
+ * do the necessary argument swapping for dynamic phrases.
+ *
+ * @param string $youtext The "you" version of the phrase (eg "Your Friends").
+ * @param string $nametext The other-user version of the phrase. Should be in
+ *        a format appropriate for sprintf() - use %s in place of the displayed
+ *        user's name (eg "%'s Friends").
+ * @param bool $capitalize Optional. Force into title case. Default: true.
+ * @param bool $echo Optional. True to echo the results, false to return them.
+ *        Default: true.
+ * @return string|null If ! $echo, returns the appropriate string.
+ */
+function bp_word_or_name( $youtext, $nametext, $capitalize = true, $echo = true ) {
+
+	if ( !empty( $capitalize ) )
+		$youtext = bp_core_ucfirst( $youtext );
+
+	if ( bp_displayed_user_id() == bp_loggedin_user_id() ) {
+		if ( true == $echo ) {
+			echo apply_filters( 'bp_word_or_name', $youtext );
+		} else {
+			return apply_filters( 'bp_word_or_name', $youtext );
+		}
+	} else {
+		$fullname = bp_get_displayed_user_fullname();
+		$fullname = (array) explode( ' ', $fullname );
+		$nametext = sprintf( $nametext, $fullname[0] );
+		if ( true == $echo ) {
+			echo apply_filters( 'bp_word_or_name', $nametext );
+		} else {
+			return apply_filters( 'bp_word_or_name', $nametext );
+		}
+	}
+}
+
+/**
+ * Do the 'bp_styles' action, and call wp_print_styles().
+ *
+ * No longer used in BuddyPress.
+ *
+ * @todo Deprecate.
+ */
+function bp_styles() {
+	do_action( 'bp_styles' );
+	wp_print_styles();
+}
+
+/** Search Form ***************************************************************/
+
+/**
+ * Return the "action" attribute for search forms.
+ *
+ * @return string URL action attribute for search forms, eg example.com/search/.
+ */
+function bp_search_form_action() {
+	return apply_filters( 'bp_search_form_action', trailingslashit( bp_get_root_domain() . '/' . bp_get_search_slug() ) );
+}
+
+/**
+ * Generate the basic search form as used in BP-Default's header.
+ *
+ * @since BuddyPress (1.0.0)
+ *
+ * @return string HTML <select> element.
+ */
+function bp_search_form_type_select() {
+
+	$options = array();
+
+	if ( bp_is_active( 'xprofile' ) )
+		$options['members'] = __( 'Members', 'buddypress' );
+
+	if ( bp_is_active( 'groups' ) )
+		$options['groups']  = __( 'Groups',  'buddypress' );
+
+	if ( bp_is_active( 'blogs' ) && is_multisite() )
+		$options['blogs']   = __( 'Blogs',   'buddypress' );
+
+	if ( bp_is_active( 'forums' ) && bp_forums_is_installed_correctly() && bp_forums_has_directory() )
+		$options['forums']  = __( 'Forums',  'buddypress' );
+
+	$options['posts'] = __( 'Posts', 'buddypress' );
+
+	// Eventually this won't be needed and a page will be built to integrate all search results.
+	$selection_box  = '<label for="search-which" class="accessibly-hidden">' . __( 'Search these:', 'buddypress' ) . '</label>';
+	$selection_box .= '<select name="search-which" id="search-which" style="width: auto">';
+
+	$options = apply_filters( 'bp_search_form_type_select_options', $options );
+	foreach( (array) $options as $option_value => $option_title )
+		$selection_box .= sprintf( '<option value="%s">%s</option>', $option_value, $option_title );
+
+	$selection_box .= '</select>';
+
+	return apply_filters( 'bp_search_form_type_select', $selection_box );
+}
+
+/**
+ * Output the default text for the search box for a given component.
+ *
+ * @since BuddyPress (1.5.0)
+ *
+ * @see bp_get_search_default_text()
+ *
+ * @param string $component See {@link bp_get_search_default_text()}.
+ */
+function bp_search_default_text( $component = '' ) {
+	echo bp_get_search_default_text( $component );
+}
+	/**
+	 * Return the default text for the search box for a given component.
+	 *
+	 * @since BuddyPress (1.5.0)
+	 *
+	 * @param string $component Component name. Default: current component.
+	 * @return string Placeholder text for search field.
+	 */
+	function bp_get_search_default_text( $component = '' ) {
+		global $bp;
+
+		if ( empty( $component ) )
+			$component = bp_current_component();
+
+		$default_text = __( 'Search anything...', 'buddypress' );
+
+		// Most of the time, $component will be the actual component ID
+		if ( !empty( $component ) ) {
+			if ( !empty( $bp->{$component}->search_string ) ) {
+				$default_text = $bp->{$component}->search_string;
+			} else {
+				// When the request comes through AJAX, we need to get the component
+				// name out of $bp->pages
+				if ( !empty( $bp->pages->{$component}->slug ) ) {
+					$key = $bp->pages->{$component}->slug;
+					if ( !empty( $bp->{$key}->search_string ) )
+						$default_text = $bp->{$key}->search_string;
+				}
+			}
+		}
+
+		return apply_filters( 'bp_get_search_default_text', $default_text, $component );
+	}
+
+/**
+ * Fire the 'bp_custom_profile_boxes' action.
+ *
+ * No longer used in BuddyPress.
+ *
+ * @todo Deprecate.
+ */
+function bp_custom_profile_boxes() {
+	do_action( 'bp_custom_profile_boxes' );
+}
+
+/**
+ * Fire the 'bp_custom_profile_sidebar_boxes' action.
+ *
+ * No longer used in BuddyPress.
+ *
+ * @todo Deprecate.
+ */
+function bp_custom_profile_sidebar_boxes() {
+	do_action( 'bp_custom_profile_sidebar_boxes' );
+}
+
+/**
+ * Create and output a button.
+ *
+ * @see bp_get_button()
+ *
+ * @param array $args See {@link BP_Button}.
+ */
+function bp_button( $args = '' ) {
+	echo bp_get_button( $args );
+}
+	/**
+	 * Create and return a button.
+	 *
+	 * @see BP_Button for a description of arguments and return value.
+	 *
+	 * @param array $args See {@link BP_Button}.
+	 * @return string HTML markup for the button.
+	 */
+	function bp_get_button( $args = '' ) {
+		$button = new BP_Button( $args );
+		return apply_filters( 'bp_get_button', $button->contents, $args, $button );
+	}
+
+/**
+ * Truncate text.
+ *
+ * Cuts a string to the length of $length and replaces the last characters
+ * with the ending if the text is longer than length.
+ *
+ * This function is borrowed from CakePHP v2.0, under the MIT license. See
+ * http://book.cakephp.org/view/1469/Text#truncate-1625
+ *
+ * ### Options:
+ *
+ * - `ending` Will be used as Ending and appended to the trimmed string
+ * - `exact` If false, $text will not be cut mid-word
+ * - `html` If true, HTML tags would be handled correctly
+ * - `filter_shortcodes` If true, shortcodes will be stripped before truncating
+ *
+ * @param string $text String to truncate.
+ * @param int $length Optional. Length of returned string, including ellipsis.
+ *        Default: 225.
+ * @param array $options {
+ *     An array of HTML attributes and options. Each item is optional.
+ *     @type string $ending The string used after truncation.
+ *           Default: ' [&hellip;]'.
+ *     @type bool $exact If true, $text will be trimmed to exactly $length.
+ *           If false, $text will not be cut mid-word. Default: false.
+ *     @type bool $html If true, don't include HTML tags when calculating
+ *           excerpt length. Default: true.
+ *     @type bool $filter_shortcodes If true, shortcodes will be stripped.
+ *           Default: true.
+ * }
+ * @return string Trimmed string.
+ */
+function bp_create_excerpt( $text, $length = 225, $options = array() ) {
+	// Backward compatibility. The third argument used to be a boolean $filter_shortcodes
+	$filter_shortcodes_default = is_bool( $options ) ? $options : true;
+
+	$defaults = array(
+		'ending'            => __( ' [&hellip;]', 'buddypress' ),
+		'exact'             => false,
+		'html'              => true,
+		'filter_shortcodes' => $filter_shortcodes_default
+	);
+	$r = wp_parse_args( $options, $defaults );
+	extract( $r );
+
+	// Save the original text, to be passed along to the filter
+	$original_text = $text;
+
+	// Allow plugins to modify these values globally
+	$length = apply_filters( 'bp_excerpt_length', $length );
+	$ending = apply_filters( 'bp_excerpt_append_text', $ending );
+
+	// Remove shortcodes if necessary
+	if ( !empty( $filter_shortcodes ) )
+		$text = strip_shortcodes( $text );
+
+	// When $html is true, the excerpt should be created without including HTML tags in the
+	// excerpt length
+	if ( !empty( $html ) ) {
+		// The text is short enough. No need to truncate
+		if ( mb_strlen( preg_replace( '/<.*?>/', '', $text ) ) <= $length ) {
+			return $text;
+		}
+
+		$totalLength = mb_strlen( strip_tags( $ending ) );
+		$openTags    = array();
+		$truncate    = '';
+
+		// Find all the tags and put them in a stack for later use
+		preg_match_all( '/(<\/?([\w+]+)[^>]*>)?([^<>]*)/', $text, $tags, PREG_SET_ORDER );
+		foreach ( $tags as $tag ) {
+			// Process tags that need to be closed
+			if ( !preg_match( '/img|br|input|hr|area|base|basefont|col|frame|isindex|link|meta|param/s',  $tag[2] ) ) {
+				if ( preg_match( '/<[\w]+[^>]*>/s', $tag[0] ) ) {
+					array_unshift( $openTags, $tag[2] );
+				} else if ( preg_match('/<\/([\w]+)[^>]*>/s', $tag[0], $closeTag ) ) {
+					$pos = array_search( $closeTag[1], $openTags );
+					if ( $pos !== false ) {
+						array_splice( $openTags, $pos, 1 );
+					}
+				}
+			}
+			$truncate .= $tag[1];
+
+			$contentLength = mb_strlen( preg_replace( '/&[0-9a-z]{2,8};|&#[0-9]{1,7};|&#x[0-9a-f]{1,6};/i', ' ', $tag[3] ) );
+			if ( $contentLength + $totalLength > $length ) {
+				$left = $length - $totalLength;
+				$entitiesLength = 0;
+				if ( preg_match_all( '/&[0-9a-z]{2,8};|&#[0-9]{1,7};|&#x[0-9a-f]{1,6};/i', $tag[3], $entities, PREG_OFFSET_CAPTURE ) ) {
+					foreach ( $entities[0] as $entity ) {
+						if ( $entity[1] + 1 - $entitiesLength <= $left ) {
+							$left--;
+							$entitiesLength += mb_strlen( $entity[0] );
+						} else {
+							break;
+						}
+					}
+				}
+
+				$truncate .= mb_substr( $tag[3], 0 , $left + $entitiesLength );
+				break;
+			} else {
+				$truncate .= $tag[3];
+				$totalLength += $contentLength;
+			}
+			if ( $totalLength >= $length ) {
+				break;
+			}
+		}
+	} else {
+		if ( mb_strlen( $text ) <= $length ) {
+			return $text;
+		} else {
+			$truncate = mb_substr( $text, 0, $length - mb_strlen( $ending ) );
+		}
+	}
+
+	// If $exact is false, we can't break on words
+	if ( empty( $exact ) ) {
+		$spacepos = mb_strrpos( $truncate, ' ' );
+		if ( isset( $spacepos ) ) {
+			if ( $html ) {
+				$bits = mb_substr( $truncate, $spacepos );
+				preg_match_all( '/<\/([a-z]+)>/', $bits, $droppedTags, PREG_SET_ORDER );
+				if ( !empty( $droppedTags ) ) {
+					foreach ( $droppedTags as $closingTag ) {
+						if ( !in_array( $closingTag[1], $openTags ) ) {
+							array_unshift( $openTags, $closingTag[1] );
+						}
+					}
+				}
+			}
+			$truncate = mb_substr( $truncate, 0, $spacepos );
+		}
+	}
+	$truncate .= $ending;
+
+	if ( $html ) {
+		foreach ( $openTags as $tag ) {
+			$truncate .= '</' . $tag . '>';
+		}
+	}
+
+	return apply_filters( 'bp_create_excerpt', $truncate, $original_text, $length, $options );
+
+}
+add_filter( 'bp_create_excerpt', 'stripslashes_deep' );
+add_filter( 'bp_create_excerpt', 'force_balance_tags' );
+
+/**
+ * Output the total member count for the site.
+ */
+function bp_total_member_count() {
+	echo bp_get_total_member_count();
+}
+	/**
+	 * Return the total member count in your BP instance.
+	 *
+	 * Since BuddyPress 1.6, this function has used bp_core_get_active_member_count(),
+	 * which counts non-spam, non-deleted users who have last_activity.
+	 * This value will correctly match the total member count number used
+	 * for pagination on member directories.
+	 *
+	 * Before BuddyPress 1.6, this function used bp_core_get_total_member_count(),
+	 * which did not take into account last_activity, and thus often
+	 * resulted in higher counts than shown by member directory pagination.
+	 *
+	 * @return int Member count.
+	 */
+	function bp_get_total_member_count() {
+		return apply_filters( 'bp_get_total_member_count', bp_core_get_active_member_count() );
+	}
+	add_filter( 'bp_get_total_member_count', 'bp_core_number_format' );
+
+/**
+ * Output whether blog signup is allowed.
+ *
+ * @todo Deprecate. It doesn't make any sense to echo a boolean.
+ */
+function bp_blog_signup_allowed() {
+	echo bp_get_blog_signup_allowed();
+}
+	/**
+	 * Is blog signup allowed?
+	 *
+	 * Returns true if is_multisite() and blog creation is enabled at
+	 * Network Admin > Settings.
+	 *
+	 * @return bool True if blog signup is allowed, otherwise false.
+	 */
+	function bp_get_blog_signup_allowed() {
+		global $bp;
+
+		if ( !is_multisite() )
+			return false;
+
+		$status = $bp->site_options['registration'];
+		if ( 'none' != $status && 'user' != $status )
+			return true;
+
+		return false;
+	}
+
+/**
+ * Check whether an activation has just been completed.
+ *
+ * @return bool True if the activation_complete global flag has been set,
+ *         otherwise false.
+ */
+function bp_account_was_activated() {
+	global $bp;
+
+	$activation_complete = !empty( $bp->activation_complete ) ? $bp->activation_complete : false;
+
+	return $activation_complete;
+}
+
+/**
+ * Check whether registrations require activation on this installation.
+ *
+ * On a normal BuddyPress installation, all registrations require email
+ * activation. This filter exists so that customizations that omit activation
+ * can remove certain notification text from the registration screen.
+ *
+ * @return bool True by default.
+ */
+function bp_registration_needs_activation() {
+	return apply_filters( 'bp_registration_needs_activation', true );
+}
+
+/**
+ * Retrieve a client friendly version of the root blog name.
+ *
+ * The blogname option is escaped with esc_html on the way into the database in
+ * sanitize_option, we want to reverse this for the plain text arena of emails.
+ *
+ * @since BuddyPress (1.7.0)
+ *
+ * @see http://buddypress.trac.wordpress.org/ticket/4401
+ *
+ * @param array $args {
+ *     Array of optional parameters.
+ *     @type string $before String to appear before the site name in the
+ *           email subject. Default: '['.
+ *     @type string $after String to appear after the site name in the
+ *           email subject. Default: ']'.
+ *     @type string $default The default site name, to be used when none is
+ *           found in the database. Default: 'Community'.
+ *     @type string $text Text to append to the site name (ie, the main text of
+ *           the email subject).
+ * }
+ * @return string Sanitized email subject.
+ */
+function bp_get_email_subject( $args = array() ) {
+
+	$r = wp_parse_args( $args, array(
+		'before'  => '[',
+		'after'   => ']',
+		'default' => __( 'Community', 'buddypress' ),
+		'text'    => ''
+	) );
+
+	$subject = $r['before'] . wp_specialchars_decode( bp_get_option( 'blogname', $r['default'] ), ENT_QUOTES ) . $r['after'] . ' ' . $r['text'];
+
+	return apply_filters( 'bp_get_email_subject', $subject, $r );
+}
+
+/**
+ * Allow templates to pass parameters directly into the template loops via AJAX.
+ *
+ * For the most part this will be filtered in a theme's functions.php for
+ * example in the default theme it is filtered via bp_dtheme_ajax_querystring().
+ *
+ * By using this template tag in the templates it will stop them from showing
+ * errors if someone copies the templates from the default theme into another
+ * WordPress theme without coping the functions from functions.php.
+ *
+ * @param string $object
+ * @return string The AJAX querystring.
+ */
+function bp_ajax_querystring( $object = false ) {
+	global $bp;
+
+	if ( !isset( $bp->ajax_querystring ) )
+		$bp->ajax_querystring = '';
+
+	return apply_filters( 'bp_ajax_querystring', $bp->ajax_querystring, $object );
+}
+
+/** Template Classes and _is functions ****************************************/
+
+/**
+ * Return the name of the current component.
+ *
+ * @return string Component name.
+ */
+function bp_current_component() {
+	global $bp;
+	$current_component = !empty( $bp->current_component ) ? $bp->current_component : false;
+	return apply_filters( 'bp_current_component', $current_component );
+}
+
+/**
+ * Return the name of the current action.
+ *
+ * @return string Action name.
+ */
+function bp_current_action() {
+	global $bp;
+	$current_action = !empty( $bp->current_action ) ? $bp->current_action : '';
+	return apply_filters( 'bp_current_action', $current_action );
+}
+
+/**
+ * Return the name of the current item.
+ *
+ * @return unknown
+ */
+function bp_current_item() {
+	global $bp;
+	$current_item = !empty( $bp->current_item ) ? $bp->current_item : false;
+	return apply_filters( 'bp_current_item', $current_item );
+}
+
+/**
+ * Return the value of $bp->action_variables.
+ *
+ * @return array|bool $action_variables The action variables array, or false
+ *         if the array is empty.
+ */
+function bp_action_variables() {
+	global $bp;
+	$action_variables = !empty( $bp->action_variables ) ? $bp->action_variables : false;
+	return apply_filters( 'bp_action_variables', $action_variables );
+}
+
+/**
+ * Return the value of a given action variable.
+ *
+ * @since BuddyPress (1.5.0)
+ *
+ * @param int $position The key of the action_variables array that you want.
+ * @return string|bool $action_variable The value of that position in the
+ *         array, or false if not found.
+ */
+function bp_action_variable( $position = 0 ) {
+	$action_variables = bp_action_variables();
+	$action_variable  = isset( $action_variables[$position] ) ? $action_variables[$position] : false;
+
+	return apply_filters( 'bp_action_variable', $action_variable, $position );
+}
+
+/**
+ * Output the "root domain", the URL of the BP root blog.
+ */
+function bp_root_domain() {
+	echo bp_get_root_domain();
+}
+	/**
+	 * Return the "root domain", the URL of the BP root blog.
+	 *
+	 * @return string URL of the BP root blog.
+	 */
+	function bp_get_root_domain() {
+		global $bp;
+
+		if ( isset( $bp->root_domain ) && !empty( $bp->root_domain ) ) {
+			$domain = $bp->root_domain;
+		} else {
+			$domain          = bp_core_get_root_domain();
+			$bp->root_domain = $domain;
+		}
+
+		return apply_filters( 'bp_get_root_domain', $domain );
+	}
+
+/**
+ * Output the root slug for a given component.
+ *
+ * @since BuddyPress (1.5.0)
+ *
+ * @param string $component The component name.
+ */
+function bp_root_slug( $component = '' ) {
+	echo bp_get_root_slug( $component );
+}
+	/**
+	 * Get the root slug for given component.
+	 *
+	 * The "root slug" is the string used when concatenating component
+	 * directory URLs. For example, on an installation where the Groups
+	 * component's directory is located at http://example.com/groups/, the
+	 * root slug for the Groups component is 'groups'. This string
+	 * generally corresponds to page_name of the component's directory
+	 * page.
+	 *
+	 * In order to maintain backward compatibility, the following procedure
+	 * is used:
+	 * 1) Use the short slug to get the canonical component name from the
+	 *    active component array
+	 * 2) Use the component name to get the root slug out of the
+	 *    appropriate part of the $bp global
+	 * 3) If nothing turns up, it probably means that $component is itself
+	 *    a root slug
+	 *
+	 * Example: If your groups directory is at /community/companies, this
+	 * function first uses the short slug 'companies' (ie the current
+	 * component) to look up the canonical name 'groups' in
+	 * $bp->active_components. Then it uses 'groups' to get the root slug,
+	 * from $bp->groups->root_slug.
+	 *
+	 * @since BuddyPress (1.5.0)
+	 *
+	 * @global BuddyPress $bp The one true BuddyPress instance.
+	 *
+	 * @param string $component Optional. Defaults to the current component.
+	 * @return string $root_slug The root slug.
+	 */
+	function bp_get_root_slug( $component = '' ) {
+		global $bp;
+
+		$root_slug = '';
+
+		// Use current global component if none passed
+		if ( empty( $component ) )
+			$component = bp_current_component();
+
+		// Component is active
+		if ( !empty( $bp->active_components[$component] ) ) {
+			// Backward compatibility: in legacy plugins, the canonical component id
+			// was stored as an array value in $bp->active_components
+			$component_name = '1' == $bp->active_components[$component] ? $component : $bp->active_components[$component];
+
+			// Component has specific root slug
+			if ( !empty( $bp->{$component_name}->root_slug ) ) {
+				$root_slug = $bp->{$component_name}->root_slug;
+			}
+		}
+
+		// No specific root slug, so fall back to component slug
+		if ( empty( $root_slug ) )
+			$root_slug = $component;
+
+		return apply_filters( 'bp_get_root_slug', $root_slug, $component );
+	}
+
+/**
+ * Return the component name based on a root slug.
+ *
+ * @since BuddyPress (1.5.0)
+ *
+ * @global BuddyPress $bp The one true BuddyPress instance.
+ *
+ * @param string $root_slug Needle to our active component haystack.
+ * @return mixed False if none found, component name if found.
+ */
+function bp_get_name_from_root_slug( $root_slug = '' ) {
+	global $bp;
+
+	// If no slug is passed, look at current_component
+	if ( empty( $root_slug ) )
+		$root_slug = bp_current_component();
+
+	// No current component or root slug, so flee
+	if ( empty( $root_slug ) )
+		return false;
+
+	// Loop through active components and look for a match
+	foreach ( array_keys( $bp->active_components ) as $component ) {
+		if ( ( !empty( $bp->{$component}->slug ) && ( $bp->{$component}->slug == $root_slug ) ) || ( !empty( $bp->{$component}->root_slug ) && ( $bp->{$component}->root_slug == $root_slug ) ) ) {
+			return $bp->{$component}->name;
+		}
+	}
+
+	return false;
+}
+
+function bp_user_has_access() {
+	$has_access = ( bp_current_user_can( 'bp_moderate' ) || bp_is_my_profile() ) ? true : false;
+
+	return apply_filters( 'bp_user_has_access', $has_access );
+}
+
+/**
+ * Output the search slug.
+ *
+ * @since BuddyPress (1.5.0)
+ *
+ * @uses bp_get_search_slug()
+ */
+function bp_search_slug() {
+	echo bp_get_search_slug();
+}
+	/**
+	 * Return the search slug.
+	 *
+	 * @since BuddyPress (1.5.0)
+	 *
+	 * @return string The search slug. Default: 'search'.
+	 */
+	function bp_get_search_slug() {
+		return apply_filters( 'bp_get_search_slug', BP_SEARCH_SLUG );
+	}
+
+/**
+ * Get the ID of the currently displayed user.
+ *
+ * @uses apply_filters() Filter 'bp_displayed_user_id' to change this value.
+ *
+ * @return int ID of the currently displayed user.
+ */
+function bp_displayed_user_id() {
+	$bp = buddypress();
+	$id = !empty( $bp->displayed_user->id ) ? $bp->displayed_user->id : 0;
+
+	return (int) apply_filters( 'bp_displayed_user_id', $id );
+}
+
+/**
+ * Get the ID of the currently logged-in user.
+ *
+ * @uses apply_filters() Filter 'bp_loggedin_user_id' to change this value.
+ *
+ * @return int ID of the logged-in user.
+ */
+function bp_loggedin_user_id() {
+	$bp = buddypress();
+	$id = !empty( $bp->loggedin_user->id ) ? $bp->loggedin_user->id : 0;
+
+	return (int) apply_filters( 'bp_loggedin_user_id', $id );
+}
+
+/** is_() functions to determine the current page *****************************/
+
+/**
+ * Check to see whether the current page belongs to the specified component.
+ *
+ * This function is designed to be generous, accepting several different kinds
+ * of value for the $component parameter. It checks $component_name against:
+ * - the component's root_slug, which matches the page slug in $bp->pages
+ * - the component's regular slug
+ * - the component's id, or 'canonical' name
+ *
+ * @since BuddyPress (1.5.0)
+ *
+ * @param string $component Name of the component being checked.
+ * @return bool Returns true if the component matches, or else false.
+ */
+function bp_is_current_component( $component ) {
+	global $bp, $wp_query;
+
+	$is_current_component = false;
+
+	// Always return false if a null value is passed to the function
+	if ( empty( $component ) ) {
+		return false;
+	}
+
+	// Backward compatibility: 'xprofile' should be read as 'profile'
+	if ( 'xprofile' == $component )
+		$component = 'profile';
+
+	if ( ! empty( $bp->current_component ) ) {
+
+		// First, check to see whether $component_name and the current
+		// component are a simple match
+		if ( $bp->current_component == $component ) {
+			$is_current_component = true;
+
+		// Since the current component is based on the visible URL slug let's
+		// check the component being passed and see if its root_slug matches
+		} elseif ( isset( $bp->{$component}->root_slug ) && $bp->{$component}->root_slug == $bp->current_component ) {
+			$is_current_component = true;
+
+		// Because slugs can differ from root_slugs, we should check them too
+		} elseif ( isset( $bp->{$component}->slug ) && $bp->{$component}->slug == $bp->current_component ) {
+			$is_current_component = true;
+
+		// Next, check to see whether $component is a canonical,
+		// non-translatable component name. If so, we can return its
+		// corresponding slug from $bp->active_components.
+		} else if ( $key = array_search( $component, $bp->active_components ) ) {
+			if ( strstr( $bp->current_component, $key ) ) {
+				$is_current_component = true;
+			}
+
+		// If we haven't found a match yet, check against the root_slugs
+		// created by $bp->pages, as well as the regular slugs
+		} else {
+			foreach ( $bp->active_components as $id ) {
+				// If the $component parameter does not match the current_component,
+				// then move along, these are not the droids you are looking for
+				if ( empty( $bp->{$id}->root_slug ) || $bp->{$id}->root_slug != $bp->current_component ) {
+					continue;
+				}
+
+				if ( $id == $component ) {
+					$is_current_component = true;
+					break;
+				}
+			}
+		}
+
+	// Page template fallback check if $bp->current_component is empty
+	} elseif ( !is_admin() && is_a( $wp_query, 'WP_Query' ) && is_page() ) {
+		global $wp_query;
+		$page          = $wp_query->get_queried_object();
+		$custom_fields = get_post_custom_values( '_wp_page_template', $page->ID );
+		$page_template = $custom_fields[0];
+
+		// Component name is in the page template name
+		if ( !empty( $page_template ) && strstr( strtolower( $page_template ), strtolower( $component ) ) ) {
+			$is_current_component = true;
+		}
+	}
+
+ 	return apply_filters( 'bp_is_current_component', $is_current_component, $component );
+}
+
+/**
+ * Check to see whether the current page matches a given action.
+ *
+ * Along with bp_is_current_component() and bp_is_action_variable(), this
+ * function is mostly used to help determine when to use a given screen
+ * function.
+ *
+ * In BP parlance, the current_action is the URL chunk that comes directly
+ * after the current item slug. E.g., in
+ *   http://example.com/groups/my-group/members
+ * the current_action is 'members'.
+ *
+ * @since BuddyPress (1.5.0)
+ *
+ * @param string $action The action being tested against.
+ * @return bool True if the current action matches $action.
+ */
+function bp_is_current_action( $action = '' ) {
+	if ( $action == bp_current_action() )
+		return true;
+
+	return false;
+}
+
+/**
+ * Check to see whether the current page matches a given action_variable.
+ *
+ * Along with bp_is_current_component() and bp_is_current_action(), this
+ * function is mostly used to help determine when to use a given screen
+ * function.
+ *
+ * In BP parlance, action_variables are an array made up of the URL chunks
+ * appearing after the current_action in a URL. For example,
+ *   http://example.com/groups/my-group/admin/group-settings
+ * $action_variables[0] is 'group-settings'.
+ *
+ * @since BuddyPress (1.5.0)
+ *
+ * @param string $action_variable The action_variable being tested against.
+ * @param int $position Optional. The array key you're testing against. If you
+ *        don't provide a $position, the function will return true if the
+ *        $action_variable is found *anywhere* in the action variables array.
+ * @return bool True if $action_variable matches at the $position provided.
+ */
+function bp_is_action_variable( $action_variable = '', $position = false ) {
+	$is_action_variable = false;
+
+	if ( false !== $position ) {
+		// When a $position is specified, check that slot in the action_variables array
+		if ( $action_variable ) {
+			$is_action_variable = $action_variable == bp_action_variable( $position );
+		} else {
+			// If no $action_variable is provided, we are essentially checking to see
+			// whether the slot is empty
+			$is_action_variable = !bp_action_variable( $position );
+		}
+	} else {
+		// When no $position is specified, check the entire array
+		$is_action_variable = in_array( $action_variable, (array)bp_action_variables() );
+	}
+
+	return apply_filters( 'bp_is_action_variable', $is_action_variable, $action_variable, $position );
+}
+
+/**
+ * Check against the current_item.
+ *
+ * @param string $item The item being checked.
+ * @return bool True if $item is the current item.
+ */
+function bp_is_current_item( $item = '' ) {
+	if ( !empty( $item ) && $item == bp_current_item() )
+		return true;
+
+	return false;
+}
+
+/**
+ * Are we looking at a single item? (group, user, etc)
+ *
+ * @return bool True if looking at a single item, otherwise false.
+ */
+function bp_is_single_item() {
+	global $bp;
+
+	if ( !empty( $bp->is_single_item ) )
+		return true;
+
+	return false;
+}
+
+/**
+ * Is the logged-in user an admin for the current item?
+ *
+ * @return bool True if the current user is an admin for the current item,
+ *         otherwise false.
+ */
+function bp_is_item_admin() {
+	global $bp;
+
+	if ( !empty( $bp->is_item_admin ) )
+		return true;
+
+	return false;
+}
+
+/**
+ * Is the logged-in user a mod for the current item?
+ *
+ * @return bool True if the current user is a mod for the current item,
+ *         otherwise false.
+ */
+function bp_is_item_mod() {
+	global $bp;
+
+	if ( !empty( $bp->is_item_mod ) )
+		return true;
+
+	return false;
+}
+
+/**
+ * Is this a component directory page?
+ *
+ * @return bool True if the current page is a component directory, otherwise
+ *         false.
+ */
+function bp_is_directory() {
+	global $bp;
+
+	if ( !empty( $bp->is_directory ) )
+		return true;
+
+	return false;
+}
+
+/**
+ * Check to see if a component's URL should be in the root, not under a member page.
+ *
+ *   Yes ('groups' is root): http://domain.com/groups/the-group
+ *   No ('groups' is not-root):  http://domain.com/members/andy/groups/the-group
+ *
+ * @return bool True if root component, else false.
+ */
+function bp_is_root_component( $component_name ) {
+	global $bp;
+
+	if ( !isset( $bp->active_components ) )
+		return false;
+
+	foreach ( (array) $bp->active_components as $key => $slug ) {
+		if ( $key == $component_name || $slug == $component_name )
+			return true;
+	}
+
+	return false;
+}
+
+/**
+ * Check if the specified BuddyPress component directory is set to be the front page.
+ *
+ * Corresponds to the setting in wp-admin's Settings > Reading screen.
+ *
+ * @since BuddyPress (1.5.0)
+ *
+ * @global BuddyPress $bp The one true BuddyPress instance.
+ * @global $current_blog WordPress global for the current blog.
+ *
+ * @param string $component Optional. Name of the component to check for.
+ *        Default: current component.
+ * @return bool True if the specified component is set to be the site's front
+ *         page, otherwise false.
+ */
+function bp_is_component_front_page( $component = '' ) {
+	global $bp, $current_blog;
+
+	if ( !$component && !empty( $bp->current_component ) )
+		$component = $bp->current_component;
+
+	$path = is_main_site() ? bp_core_get_site_path() : $current_blog->path;
+
+	if ( 'page' != get_option( 'show_on_front' ) || !$component || empty( $bp->pages->{$component} ) || $_SERVER['REQUEST_URI'] != $path )
+		return false;
+
+	return apply_filters( 'bp_is_component_front_page', ( $bp->pages->{$component}->id == get_option( 'page_on_front' ) ), $component );
+}
+
+/**
+ * Is this a blog page, ie a non-BP page?
+ *
+ * You can tell if a page is displaying BP content by whether the
+ * current_component has been defined.
+ *
+ * @return bool True if it's a non-BP page, false otherwise.
+ */
+function bp_is_blog_page() {
+
+	$is_blog_page = false;
+
+	// Generally, we can just check to see that there's no current component. The one exception
+	// is single user home tabs, where $bp->current_component is unset. Thus the addition
+	// of the bp_is_user() check.
+	if ( !bp_current_component() && !bp_is_user() )
+		$is_blog_page = true;
+
+	return apply_filters( 'bp_is_blog_page', $is_blog_page );
+}
+
+/**
+ * Is this a BuddyPress component?
+ *
+ * You can tell if a page is displaying BP content by whether the
+ * current_component has been defined.
+ *
+ * Generally, we can just check to see that there's no current component.
+ * The one exception is single user home tabs, where $bp->current_component
+ * is unset. Thus the addition of the bp_is_user() check.
+ *
+ * @since BuddyPress (1.7.0)
+ *
+ * @return bool True if it's a BuddyPress page, false otherwise.
+ */
+function is_buddypress() {
+	$retval = (bool) ( bp_current_component() || bp_is_user() );
+
+	return apply_filters( 'is_buddypress', $retval );
+}
+
+/** Components ****************************************************************/
+
+/**
+ * Check whether a given component has been activated by the admin.
+ *
+ * @param string $component The component name.
+ * @return bool True if the component is active, otherwise false.
+ */
+function bp_is_active( $component ) {
+	global $bp;
+
+	if ( isset( $bp->active_components[$component] ) || 'core' == $component )
+		return true;
+
+	return false;
+}
+
+/**
+ * Check whether the current page is part of the Members component.
+ *
+ * @return bool True if the current page is part of the Members component.
+ */
+function bp_is_members_component() {
+	if ( bp_is_current_component( 'members' ) )
+		return true;
+
+	return false;
+}
+
+/**
+ * Check whether the current page is part of the Profile component.
+ *
+ * @return bool True if the current page is part of the Profile component.
+ */
+function bp_is_profile_component() {
+	if ( bp_is_current_component( 'xprofile' ) )
+		return true;
+
+	return false;
+}
+
+/**
+ * Check whether the current page is part of the Activity component.
+ *
+ * @return bool True if the current page is part of the Activity component.
+ */
+function bp_is_activity_component() {
+	if ( bp_is_current_component( 'activity' ) )
+		return true;
+
+	return false;
+}
+
+/**
+ * Check whether the current page is part of the Blogs component.
+ *
+ * @return bool True if the current page is part of the Blogs component.
+ */
+function bp_is_blogs_component() {
+	if ( is_multisite() && bp_is_current_component( 'blogs' ) )
+		return true;
+
+	return false;
+}
+
+/**
+ * Check whether the current page is part of the Messages component.
+ *
+ * @return bool True if the current page is part of the Messages component.
+ */
+function bp_is_messages_component() {
+	if ( bp_is_current_component( 'messages' ) )
+		return true;
+
+	return false;
+}
+
+/**
+ * Check whether the current page is part of the Friends component.
+ *
+ * @return bool True if the current page is part of the Friends component.
+ */
+function bp_is_friends_component() {
+	if ( bp_is_current_component( 'friends' ) )
+		return true;
+
+	return false;
+}
+
+/**
+ * Check whether the current page is part of the Groups component.
+ *
+ * @return bool True if the current page is part of the Groups component.
+ */
+function bp_is_groups_component() {
+	if ( bp_is_current_component( 'groups' ) )
+		return true;
+
+	return false;
+}
+
+/**
+ * Check whether the current page is part of the Forums component.
+ *
+ * @return bool True if the current page is part of the Forums component.
+ */
+function bp_is_forums_component() {
+	if ( bp_is_current_component( 'forums' ) )
+		return true;
+
+	return false;
+}
+
+/**
+ * Check whether the current page is part of the Notifications component.
+ *
+ * @since BuddyPress (1.9.0)
+ *
+ * @return bool True if the current page is part of the Notifications component.
+ */
+function bp_is_notifications_component() {
+	if ( bp_is_current_component( 'notifications' ) ) {
+		return true;
+	}
+
+	return false;
+}
+
+/**
+ * Check whether the current page is part of the Settings component.
+ *
+ * @return bool True if the current page is part of the Settings component.
+ */
+function bp_is_settings_component() {
+	if ( bp_is_current_component( 'settings' ) )
+		return true;
+
+	return false;
+}
+
+/**
+ * Is the current component an active core component?
+ *
+ * Use this function when you need to check if the current component is an
+ * active core component of BuddyPress. If the current component is inactive, it
+ * will return false. If the current component is not part of BuddyPress core,
+ * it will return false. If the current component is active, and is part of
+ * BuddyPress core, it will return true.
+ *
+ * @return bool True if the current component is active and is one of BP's
+ *         packaged components.
+ */
+function bp_is_current_component_core() {
+	$retval            = false;
+	$active_components = apply_filters( 'bp_active_components', bp_get_option( 'bp-active-components' ) );
+
+	foreach ( array_keys( $active_components ) as $active_component ) {
+		if ( bp_is_current_component( $active_component ) ) {
+			$retval = true;
+			break;
+		}
+	}
+
+	return $retval;
+}
+
+/** Activity ******************************************************************/
+
+/**
+ * Is the current page a single activity item permalink?
+ *
+ * @return True if the current page is a single activity item permalink.
+ */
+function bp_is_single_activity() {
+	if ( bp_is_activity_component() && is_numeric( bp_current_action() ) )
+		return true;
+
+	return false;
+}
+
+/** User **********************************************************************/
+
+/**
+ * Is the current page part of the profile of the logged-in user?
+ *
+ * Will return true for any subpage of the logged-in user's profile, eg
+ * http://example.com/members/joe/friends/.
+ *
+ * @return True if the current page is part of the profile of the logged-in user.
+ */
+function bp_is_my_profile() {
+	if ( is_user_logged_in() && bp_loggedin_user_id() == bp_displayed_user_id() )
+		$my_profile = true;
+	else
+		$my_profile = false;
+
+	return apply_filters( 'bp_is_my_profile', $my_profile );
+}
+
+/**
+ * Is the current page a user page?
+ *
+ * Will return true anytime there is a displayed user.
+ *
+ * @return True if the current page is a user page.
+ */
+function bp_is_user() {
+	if ( bp_displayed_user_id() )
+		return true;
+
+	return false;
+}
+
+/**
+ * Is the current page a user's activity stream page?
+ *
+ * Eg http://example.com/members/joe/activity/ (or any subpages thereof).
+ *
+ * @return True if the current page is a user's activity stream page.
+ */
+function bp_is_user_activity() {
+	if ( bp_is_user() && bp_is_activity_component() )
+		return true;
+
+	return false;
+}
+
+/**
+ * Is the current page a user's Friends activity stream?
+ *
+ * Eg http://example.com/members/joe/friends/
+ *
+ * @return True if the current page is a user's Friends activity stream.
+ */
+function bp_is_user_friends_activity() {
+
+	if ( !bp_is_active( 'friends' ) )
+		return false;
+
+	$slug = bp_get_friends_slug();
+
+	if ( empty( $slug ) )
+		$slug = 'friends';
+
+	if ( bp_is_user_activity() && bp_is_current_action( $slug ) )
+		return true;
+
+	return false;
+}
+
+/**
+ * Is the current page a user's Groups activity stream?
+ *
+ * Eg http://example.com/members/joe/groups/
+ *
+ * @return True if the current page is a user's Groups activity stream.
+ */
+function bp_is_user_groups_activity() {
+
+	if ( !bp_is_active( 'groups' ) )
+		return false;
+
+	$slug = bp_get_groups_slug();
+
+	if ( empty( $slug ) )
+		$slug = 'groups';
+
+	if ( bp_is_user_activity() && bp_is_current_action( $slug ) )
+		return true;
+
+	return false;
+}
+
+/**
+ * Is the current page part of a user's extended profile?
+ *
+ * Eg http://example.com/members/joe/profile/ (or a subpage thereof).
+ *
+ * @return True if the current page is part of a user's extended profile.
+ */
+function bp_is_user_profile() {
+	if ( bp_is_profile_component() || bp_is_current_component( 'profile' ) )
+		return true;
+
+	return false;
+}
+
+/**
+ * Is the current page part of a user's profile editing section?
+ *
+ * Eg http://example.com/members/joe/profile/edit/ (or a subpage thereof).
+ *
+ * @return True if the current page is a user's profile edit page.
+ */
+function bp_is_user_profile_edit() {
+	if ( bp_is_profile_component() && bp_is_current_action( 'edit' ) )
+		return true;
+
+	return false;
+}
+
+function bp_is_user_change_avatar() {
+	if ( bp_is_profile_component() && bp_is_current_action( 'change-avatar' ) )
+		return true;
+
+	return false;
+}
+
+/**
+ * Is this a user's forums page?
+ *
+ * Eg http://example.com/members/joe/forums/ (or a subpage thereof).
+ *
+ * @return bool True if the current page is a user's forums page.
+ */
+function bp_is_user_forums() {
+
+	if ( ! bp_is_active( 'forums' ) )
+		return false;
+
+	if ( bp_is_user() && bp_is_forums_component() )
+		return true;
+
+	return false;
+}
+
+/**
+ * Is this a user's "Topics Started" page?
+ *
+ * Eg http://example.com/members/joe/forums/topics/.
+ *
+ * @since BuddyPress (1.5.0)
+ *
+ * @return bool True if the current page is a user's Topics Started page.
+ */
+function bp_is_user_forums_started() {
+	if ( bp_is_user_forums() && bp_is_current_action( 'topics' ) )
+		return true;
+
+	return false;
+}
+
+/**
+ * Is this a user's "Replied To" page?
+ *
+ * Eg http://example.com/members/joe/forums/replies/.
+ *
+ * @since BuddyPress (1.5.0)
+ *
+ * @return bool True if the current page is a user's Replied To forums page.
+ */
+function bp_is_user_forums_replied_to() {
+	if ( bp_is_user_forums() && bp_is_current_action( 'replies' ) )
+		return true;
+
+	return false;
+}
+
+/**
+ * Is the current page part of a user's Groups page?
+ *
+ * Eg http://example.com/members/joe/groups/ (or a subpage thereof).
+ *
+ * @return bool True if the current page is a user's Groups page.
+ */
+function bp_is_user_groups() {
+	if ( bp_is_user() && bp_is_groups_component() )
+		return true;
+
+	return false;
+}
+
+/**
+ * Is the current page part of a user's Blogs page?
+ *
+ * Eg http://example.com/members/joe/blogs/ (or a subpage thereof).
+ *
+ * @return bool True if the current page is a user's Blogs page.
+ */
+function bp_is_user_blogs() {
+	if ( bp_is_user() && bp_is_blogs_component() )
+		return true;
+
+	return false;
+}
+
+/**
+ * Is the current page a user's Recent Blog Posts page?
+ *
+ * Eg http://example.com/members/joe/blogs/recent-posts/.
+ *
+ * @return bool True if the current page is a user's Recent Blog Posts page.
+ */
+function bp_is_user_recent_posts() {
+	if ( bp_is_user_blogs() && bp_is_current_action( 'recent-posts' ) )
+		return true;
+
+	return false;
+}
+
+/**
+ * Is the current page a user's Recent Blog Comments page?
+ *
+ * Eg http://example.com/members/joe/blogs/recent-comments/.
+ *
+ * @return bool True if the current page is a user's Recent Blog Comments page.
+ */
+function bp_is_user_recent_commments() {
+	if ( bp_is_user_blogs() && bp_is_current_action( 'recent-comments' ) )
+		return true;
+
+	return false;
+}
+
+/**
+ * Is the current page a user's Friends page?
+ *
+ * Eg http://example.com/members/joe/blogs/friends/ (or a subpage thereof).
+ *
+ * @return bool True if the current page is a user's Friends page.
+ */
+function bp_is_user_friends() {
+	if ( bp_is_user() && bp_is_friends_component() )
+		return true;
+
+	return false;
+}
+
+/**
+ * Is the current page a user's Friend Requests page?
+ *
+ * Eg http://example.com/members/joe/friends/requests/.
+ *
+ * @return bool True if the current page is a user's Friends Requests page.
+ */
+function bp_is_user_friend_requests() {
+	if ( bp_is_user_friends() && bp_is_current_action( 'requests' ) )
+		return true;
+
+	return false;
+}
+
+/**
+ * Is this a user's notifications page?
+ *
+ * Eg http://example.com/members/joe/notifications/ (or a subpage thereof).
+ *
+ * @since BuddyPress (1.9.0)
+ *
+ * @return bool True if the current page is a user's Notifications page.
+ */
+function bp_is_user_notifications() {
+	if ( bp_is_user() && bp_is_notifications_component() ) {
+		return true;
+	}
+
+	return false;
+}
+
+/**
+ * Is this a user's settings page?
+ *
+ * Eg http://example.com/members/joe/settings/ (or a subpage thereof).
+ *
+ * @return bool True if the current page is a user's Settings page.
+ */
+function bp_is_user_settings() {
+	if ( bp_is_user() && bp_is_settings_component() )
+		return true;
+
+	return false;
+}
+
+/**
+ * Is this a user's General Settings page?
+ *
+ * Eg http://example.com/members/joe/settings/general/.
+ *
+ * @since BuddyPress (1.5.0)
+ *
+ * @return bool True if the current page is a user's General Settings page.
+ */
+function bp_is_user_settings_general() {
+	if ( bp_is_user_settings() && bp_is_current_action( 'general' ) )
+		return true;
+
+	return false;
+}
+
+/**
+ * Is this a user's Notification Settings page?
+ *
+ * Eg http://example.com/members/joe/settings/notifications/.
+ *
+ * @since BuddyPress (1.5.0)
+ *
+ * @return bool True if the current page is a user's Notification Settings page.
+ */
+function bp_is_user_settings_notifications() {
+	if ( bp_is_user_settings() && bp_is_current_action( 'notifications' ) )
+		return true;
+
+	return false;
+}
+
+/**
+ * Is this a user's Account Deletion page?
+ *
+ * Eg http://example.com/members/joe/settings/delete-account/.
+ *
+ * @since BuddyPress (1.5.0)
+ *
+ * @return bool True if the current page is a user's Delete Account page.
+ */
+function bp_is_user_settings_account_delete() {
+	if ( bp_is_user_settings() && bp_is_current_action( 'delete-account' ) )
+		return true;
+
+	return false;
+}
+
+/** Groups ********************************************************************/
+
+/**
+ * Does the current page belong to a single group?
+ *
+ * Will return true for any subpage of a single group.
+ *
+ * @return bool True if the current page is part of a single group.
+ */
+function bp_is_group() {
+	global $bp;
+
+	if ( bp_is_groups_component() && isset( $bp->groups->current_group ) && $bp->groups->current_group )
+		return true;
+
+	return false;
+}
+
+/**
+ * Is the current page a single group's home page?
+ *
+ * URL will vary depending on which group tab is set to be the "home". By
+ * default, it's the group's recent activity.
+ *
+ * @return bool True if the current page is a single group's home page.
+ */
+function bp_is_group_home() {
+	if ( bp_is_single_item() && bp_is_groups_component() && ( !bp_current_action() || bp_is_current_action( 'home' ) ) )
+		return true;
+
+	return false;
+}
+
+/**
+ * Is the current page part of the group creation process?
+ *
+ * @return bool True if the current page is part of the group creation process.
+ */
+function bp_is_group_create() {
+	if ( bp_is_groups_component() && bp_is_current_action( 'create' ) )
+		return true;
+
+	return false;
+}
+
+/**
+ * Is the current page part of a single group's admin screens?
+ *
+ * Eg http://example.com/groups/mygroup/admin/settings/.
+ *
+ * @return bool True if the current page is part of a single group's admin.
+ */
+function bp_is_group_admin_page() {
+	if ( bp_is_single_item() && bp_is_groups_component() && bp_is_current_action( 'admin' ) )
+		return true;
+
+	return false;
+}
+
+/**
+ * Is the current page a group's forum page?
+ *
+ * Only applies to legacy bbPress forums.
+ *
+ * @return bool True if the current page is a group forum page.
+ */
+function bp_is_group_forum() {
+	$retval = false;
+
+	// At a forum URL
+	if ( bp_is_single_item() && bp_is_groups_component() && bp_is_current_action( 'forum' ) ) {
+		$retval = true;
+
+		// If at a forum URL, set back to false if forums are inactive, or not
+		// installed correctly.
+		if ( ! bp_is_active( 'forums' ) || ! bp_forums_is_installed_correctly() ) {
+			$retval = false;
+		}
+	}
+
+	return $retval;
+}
+
+/**
+ * Is the current page a group's activity page?
+ *
+ * @return True if the current page is a group's activity page.
+ */
+function bp_is_group_activity() {
+	if ( bp_is_single_item() && bp_is_groups_component() && bp_is_current_action( 'activity' ) )
+		return true;
+
+	return false;
+}
+
+/**
+ * Is the current page a group forum topic?
+ *
+ * Only applies to legacy bbPress (1.x) forums.
+ *
+ * @return bool True if the current page is part of a group forum topic.
+ */
+function bp_is_group_forum_topic() {
+	if ( bp_is_single_item() && bp_is_groups_component() && bp_is_current_action( 'forum' ) && bp_is_action_variable( 'topic', 0 ) )
+		return true;
+
+	return false;
+}
+
+/**
+ * Is the current page a group forum topic edit page?
+ *
+ * Only applies to legacy bbPress (1.x) forums.
+ *
+ * @return bool True if the current page is part of a group forum topic edit page.
+ */
+function bp_is_group_forum_topic_edit() {
+	if ( bp_is_single_item() && bp_is_groups_component() && bp_is_current_action( 'forum' ) && bp_is_action_variable( 'topic', 0 ) && bp_is_action_variable( 'edit', 2 ) )
+		return true;
+
+	return false;
+}
+
+/**
+ * Is the current page a group's Members page?
+ *
+ * Eg http://example.com/groups/mygroup/members/.
+ *
+ * @return bool True if the current page is part of a group's Members page.
+ */
+function bp_is_group_members() {
+	if ( bp_is_single_item() && bp_is_groups_component() && bp_is_current_action( 'members' ) )
+		return true;
+
+	return false;
+}
+
+/**
+ * Is the current page a group's Invites page?
+ *
+ * Eg http://example.com/groups/mygroup/send-invites/.
+ *
+ * @return bool True if the current page is a group's Send Invites page.
+ */
+function bp_is_group_invites() {
+	if ( bp_is_groups_component() && bp_is_current_action( 'send-invites' ) )
+		return true;
+
+	return false;
+}
+
+/**
+ * Is the current page a group's Request Membership page?
+ *
+ * Eg http://example.com/groups/mygroup/request-membership/.
+ *
+ * @return bool True if the current page is a group's Request Membership page.
+ */
+function bp_is_group_membership_request() {
+	if ( bp_is_groups_component() && bp_is_current_action( 'request-membership' ) )
+		return true;
+
+	return false;
+}
+
+/**
+ * Is the current page a leave group attempt?
+ *
+ * @return bool True if the current page is a Leave Group attempt.
+ */
+function bp_is_group_leave() {
+
+	if ( bp_is_groups_component() && bp_is_single_item() && bp_is_current_action( 'leave-group' ) )
+		return true;
+
+	return false;
+}
+
+/**
+ * Is the current page part of a single group?
+ *
+ * Not currently used by BuddyPress.
+ *
+ * @todo How is this functionally different from bp_is_group()?
+ *
+ * @return bool True if the current page is part of a single group.
+ */
+function bp_is_group_single() {
+	if ( bp_is_groups_component() && bp_is_single_item() )
+		return true;
+
+	return false;
+}
+
+/**
+ * Is the current page the Create a Blog page?
+ *
+ * Eg http://example.com/sites/create/.
+ *
+ * @return bool True if the current page is the Create a Blog page.
+ */
+function bp_is_create_blog() {
+	if ( bp_is_blogs_component() && bp_is_current_action( 'create' ) )
+		return true;
+
+	return false;
+}
+
+/** Messages ******************************************************************/
+
+/**
+ * Is the current page part of a user's Messages pages?
+ *
+ * Eg http://example.com/members/joe/messages/ (or a subpage thereof).
+ *
+ * @return bool True if the current page is part of a user's Messages pages.
+ */
+function bp_is_user_messages() {
+	if ( bp_is_user() && bp_is_messages_component() )
+		return true;
+
+	return false;
+}
+
+/**
+ * Is the current page a user's Messages Inbox?
+ *
+ * Eg http://example.com/members/joe/messages/inbox/.
+ *
+ * @return bool True if the current page is a user's Messages Inbox.
+ */
+function bp_is_messages_inbox() {
+	if ( bp_is_user_messages() && ( !bp_current_action() || bp_is_current_action( 'inbox' ) ) )
+		return true;
+
+	return false;
+}
+
+/**
+ * Is the current page a user's Messages Sentbox?
+ *
+ * Eg http://example.com/members/joe/messages/sentbox/.
+ *
+ * @return bool True if the current page is a user's Messages Sentbox.
+ */
+function bp_is_messages_sentbox() {
+	if ( bp_is_user_messages() && bp_is_current_action( 'sentbox' ) )
+		return true;
+
+	return false;
+}
+
+/**
+ * Is the current page a user's Messages Compose screen??
+ *
+ * Eg http://example.com/members/joe/messages/compose/.
+ *
+ * @return bool True if the current page is a user's Messages Compose screen.
+ */
+function bp_is_messages_compose_screen() {
+	if ( bp_is_user_messages() && bp_is_current_action( 'compose' ) )
+		return true;
+
+	return false;
+}
+
+/**
+ * Is the current page the Notices screen?
+ *
+ * Eg http://example.com/members/joe/messages/notices/.
+ *
+ * @return bool True if the current page is the Notices screen.
+ */
+function bp_is_notices() {
+	if ( bp_is_user_messages() && bp_is_current_action( 'notices' ) )
+		return true;
+
+	return false;
+}
+
+/**
+ * Is the current page a single Messages conversation thread?
+ *
+ * @return bool True if the current page a single Messages conversation thread?
+ */
+function bp_is_messages_conversation() {
+	if ( bp_is_user_messages() && ( bp_is_current_action( 'view' ) ) )
+		return true;
+
+	return false;
+}
+
+/**
+ * Not currently used by BuddyPress.
+ *
+ * @return bool
+ */
+function bp_is_single( $component, $callback ) {
+	if ( bp_is_current_component( $component ) && ( true === call_user_func( $callback ) ) )
+		return true;
+
+	return false;
+}
+
+/** Registration **************************************************************/
+
+/**
+ * Is the current page the Activate page?
+ *
+ * Eg http://example.com/activate/.
+ *
+ * @return bool True if the current page is the Activate page.
+ */
+function bp_is_activation_page() {
+	if ( bp_is_current_component( 'activate' ) )
+		return true;
+
+	return false;
+}
+
+/**
+ * Is the current page the Register page?
+ *
+ * Eg http://example.com/register/.
+ *
+ * @return bool True if the current page is the Register page.
+ */
+function bp_is_register_page() {
+	if ( bp_is_current_component( 'register' ) )
+		return true;
+
+	return false;
+}
+
+/**
+ * Customize the body class, according to the currently displayed BP content.
+ *
+ * Uses the above is_() functions to output a body class for each scenario.
+ *
+ * @param array $wp_classes The body classes coming from WP.
+ * @param array $custom_classes Classes that were passed to get_body_class().
+ * @return array $classes The BP-adjusted body classes.
+ */
+function bp_the_body_class() {
+	echo bp_get_the_body_class();
+}
+	function bp_get_the_body_class( $wp_classes = array(), $custom_classes = false ) {
+
+		$bp_classes = array();
+
+		/** Pages *************************************************************/
+
+		if ( is_front_page() )
+			$bp_classes[] = 'home-page';
+
+		if ( bp_is_directory() )
+			$bp_classes[] = 'directory';
+
+		if ( bp_is_single_item() )
+			$bp_classes[] = 'single-item';
+
+		/** Components ********************************************************/
+
+		if ( !bp_is_blog_page() ) :
+			if ( bp_is_user_profile() )
+				$bp_classes[] = 'xprofile';
+
+			if ( bp_is_activity_component() )
+				$bp_classes[] = 'activity';
+
+			if ( bp_is_blogs_component() )
+				$bp_classes[] = 'blogs';
+
+			if ( bp_is_messages_component() )
+				$bp_classes[] = 'messages';
+
+			if ( bp_is_friends_component() )
+				$bp_classes[] = 'friends';
+
+			if ( bp_is_groups_component() )
+				$bp_classes[] = 'groups';
+
+			if ( bp_is_settings_component()  )
+				$bp_classes[] = 'settings';
+		endif;
+
+		/** User **************************************************************/
+
+		if ( bp_is_user() )
+			$bp_classes[] = 'bp-user';
+
+		if ( !bp_is_directory() ) :
+			if ( bp_is_user_blogs() )
+				$bp_classes[] = 'my-blogs';
+
+			if ( bp_is_user_groups() )
+				$bp_classes[] = 'my-groups';
+
+			if ( bp_is_user_activity() )
+				$bp_classes[] = 'my-activity';
+		endif;
+
+		if ( bp_is_my_profile() )
+			$bp_classes[] = 'my-account';
+
+		if ( bp_is_user_profile() )
+			$bp_classes[] = 'my-profile';
+
+		if ( bp_is_user_friends() )
+			$bp_classes[] = 'my-friends';
+
+		if ( bp_is_user_messages() )
+			$bp_classes[] = 'my-messages';
+
+		if ( bp_is_user_recent_commments() )
+			$bp_classes[] = 'recent-comments';
+
+		if ( bp_is_user_recent_posts() )
+			$bp_classes[] = 'recent-posts';
+
+		if ( bp_is_user_change_avatar() )
+			$bp_classes[] = 'change-avatar';
+
+		if ( bp_is_user_profile_edit() )
+			$bp_classes[] = 'profile-edit';
+
+		if ( bp_is_user_friends_activity() )
+			$bp_classes[] = 'friends-activity';
+
+		if ( bp_is_user_groups_activity() )
+			$bp_classes[] = 'groups-activity';
+
+		if ( is_user_logged_in() )
+			$bp_classes[] = 'logged-in';
+
+		/** Messages **********************************************************/
+
+		if ( bp_is_messages_inbox() )
+			$bp_classes[] = 'inbox';
+
+		if ( bp_is_messages_sentbox() )
+			$bp_classes[] = 'sentbox';
+
+		if ( bp_is_messages_compose_screen() )
+			$bp_classes[] = 'compose';
+
+		if ( bp_is_notices() )
+			$bp_classes[] = 'notices';
+
+		if ( bp_is_user_friend_requests() )
+			$bp_classes[] = 'friend-requests';
+
+		if ( bp_is_create_blog() )
+			$bp_classes[] = 'create-blog';
+
+		/** Groups ************************************************************/
+
+		if ( bp_is_group_leave() )
+			$bp_classes[] = 'leave-group';
+
+		if ( bp_is_group_invites() )
+			$bp_classes[] = 'group-invites';
+
+		if ( bp_is_group_members() )
+			$bp_classes[] = 'group-members';
+
+		if ( bp_is_group_forum_topic() )
+			$bp_classes[] = 'group-forum-topic';
+
+		if ( bp_is_group_forum_topic_edit() )
+			$bp_classes[] = 'group-forum-topic-edit';
+
+		if ( bp_is_group_forum() )
+			$bp_classes[] = 'group-forum';
+
+		if ( bp_is_group_admin_page() ) {
+			$bp_classes[] = 'group-admin';
+			$bp_classes[] = bp_get_group_current_admin_tab();
+		}
+
+		if ( bp_is_group_create() ) {
+			$bp_classes[] = 'group-create';
+			$bp_classes[] = bp_get_groups_current_create_step();
+		}
+
+		if ( bp_is_group_home() )
+			$bp_classes[] = 'group-home';
+
+		if ( bp_is_single_activity() )
+			$bp_classes[] = 'activity-permalink';
+
+		/** Registration ******************************************************/
+
+		if ( bp_is_register_page() )
+			$bp_classes[] = 'registration';
+
+		if ( bp_is_activation_page() )
+			$bp_classes[] = 'activation';
+
+		/** Current Component & Action ****************************************/
+
+		if ( !bp_is_blog_page() ) {
+			$bp_classes[] = bp_current_component();
+			$bp_classes[] = bp_current_action();
+		}
+
+		/** is_buddypress *****************************************************/
+
+		// Add BuddyPress class if we are within a BuddyPress page
+		if ( ! bp_is_blog_page() ) {
+			$bp_classes[] = 'buddypress';
+		}
+
+		/** Clean up***********************************************************/
+
+		// We don't want WordPress blog classes to appear on non-blog pages.
+		if ( !bp_is_blog_page() ) {
+
+			// Observe WP custom background body class
+			if ( in_array( 'custom-background', (array) $wp_classes ) )
+				$bp_classes[] = 'custom-background';
+
+			// Observe WP admin bar body classes
+			if ( in_array( 'admin-bar', (array) $wp_classes ) )
+				$bp_classes[] = 'admin-bar';
+			if ( in_array( 'no-customize-support', (array) $wp_classes ) )
+				$bp_classes[] = 'no-customize-support';
+
+			// Preserve any custom classes already set
+			if ( !empty( $custom_classes ) ) {
+				$wp_classes = (array) $custom_classes;
+			} else {
+				$wp_classes = array();
+			}
+		}
+
+		// Merge WP classes with BP classes and remove any duplicates
+		$classes = array_unique( array_merge( (array) $bp_classes, (array) $wp_classes ) );
+
+		return apply_filters( 'bp_get_the_body_class', $classes, $bp_classes, $wp_classes, $custom_classes );
+	}
+	add_filter( 'body_class', 'bp_get_the_body_class', 10, 2 );
+
+/**
+ * Sort BuddyPress nav menu items by their position property.
+ *
+ * This is an internal convenience function and it will probably be removed in
+ * a later release. Do not use.
+ *
+ * @access private
+ * @since BuddyPress (1.7.0)
+ *
+ * @param array $a First item.
+ * @param array $b Second item.
+ * @return int Returns an integer less than, equal to, or greater than zero if
+ *         the first argument is considered to be respectively less than, equal to, or greater than the second.
+ */
+function _bp_nav_menu_sort( $a, $b ) {
+	if ( $a["position"] == $b["position"] )
+		return 0;
+
+	else if ( $a["position"] < $b["position"] )
+		return -1;
+
+	else
+		return 1;
+}
+
+/**
+ * Get the items registered in the primary and secondary BuddyPress navigation menus.
+ *
+ * @since BuddyPress (1.7.0)
+ *
+ * @return array A multidimensional array of all navigation items.
+ */
+function bp_get_nav_menu_items() {
+	$menus = $selected_menus = array();
+
+	// Get the second level menus
+	foreach ( (array) buddypress()->bp_options_nav as $parent_menu => $sub_menus ) {
+
+		// The root menu's ID is "xprofile", but the Profile submenus are using "profile". See BP_Core::setup_nav().
+		if ( 'profile' == $parent_menu )
+			$parent_menu = 'xprofile';
+
+		// Sort the items in this menu's navigation by their position property
+		$second_level_menus = (array) $sub_menus;
+		usort( $second_level_menus, '_bp_nav_menu_sort' );
+
+		// Iterate through the second level menus
+		foreach( $second_level_menus as $sub_nav ) {
+
+			// Skip items we don't have access to
+			if ( ! $sub_nav['user_has_access'] )
+				continue;
+
+			// Add this menu
+			$menu         = new stdClass;
+			$menu->class  = array();
+			$menu->css_id = $sub_nav['css_id'];
+			$menu->link   = $sub_nav['link'];
+			$menu->name   = $sub_nav['name'];
+			$menu->parent = $parent_menu;  // Associate this sub nav with a top-level menu
+
+			// If we're viewing this item's screen, record that we need to mark its parent menu to be selected
+			if ( $sub_nav['slug'] == bp_current_action() ) {
+				$menu->class      = array( 'current-menu-item' );
+				$selected_menus[] = $parent_menu;
+			}
+
+			$menus[] = $menu;
+		}
+	}
+
+	// Get the top-level menu parts (Friends, Groups, etc) and sort by their position property
+	$top_level_menus = (array) buddypress()->bp_nav;
+	usort( $top_level_menus, '_bp_nav_menu_sort' );
+
+	// Iterate through the top-level menus
+	foreach ( $top_level_menus as $nav ) {
+
+		// Skip items marked as user-specific if you're not on your own profile
+		if ( ! $nav['show_for_displayed_user'] && ! bp_core_can_edit_settings()  )
+			continue;
+
+		// Get the correct menu link. See http://buddypress.trac.wordpress.org/ticket/4624
+		$link = bp_loggedin_user_domain() ? str_replace( bp_loggedin_user_domain(), bp_displayed_user_domain(), $nav['link'] ) : trailingslashit( bp_displayed_user_domain() . $nav['link'] );
+
+		// Add this menu
+		$menu         = new stdClass;
+		$menu->class  = array();
+		$menu->css_id = $nav['css_id'];
+		$menu->link   = $link;
+		$menu->name   = $nav['name'];
+		$menu->parent = 0;
+
+		// Check if we need to mark this menu as selected
+		if ( in_array( $nav['css_id'], $selected_menus ) )
+			$menu->class = array( 'current-menu-parent' );
+
+		$menus[] = $menu;
+	}
+
+	return apply_filters( 'bp_get_nav_menu_items', $menus );
+}
+
+/**
+ * Display a navigation menu.
+ *
+ * @since BuddyPress (1.7.0)
+ *
+ * @param string|array $args {
+ *     An array of optional arguments.
+ *     @type string $after Text after the link text. Default: ''.
+ *     @type string $before Text before the link text. Default: ''.
+ *     @type string $container The name of the element to wrap the navigation
+ *           with. 'div' or 'nav'. Default: 'div'.
+ *     @type string $container_class The class that is applied to the container.
+ *           Default: 'menu-bp-container'.
+ *     @type string $container_id The ID that is applied to the container.
+ *           Default: ''.
+ *     @type int depth How many levels of the hierarchy are to be included. 0
+ *           means all. Default: 0.
+ *     @type bool $echo True to echo the menu, false to return it.
+ *           Default: true.
+ *     @type bool $fallback_cb If the menu doesn't exist, should a callback
+ *           function be fired? Default: false (no fallback).
+ *     @type string $items_wrap How the list items should be wrapped. Should be
+ *           in the form of a printf()-friendly string, using numbered
+ *           placeholders. Default: '<ul id="%1$s" class="%2$s">%3$s</ul>'.
+ *     @type string $link_after Text after the link. Default: ''.
+ *     @type string $link_before Text before the link. Default: ''.
+ *     @type string $menu_class CSS class to use for the <ul> element which
+ *           forms the menu. Default: 'menu'.
+ *     @type string $menu_id The ID that is applied to the <ul> element which
+ *           forms the menu. Default: 'menu-bp', incremented.
+ *     @type string $walker Allows a custom walker class to be specified.
+ *           Default: 'BP_Walker_Nav_Menu'.
+ * }
+ * @return string|null If $echo is false, returns a string containing the nav
+ *         menu markup.
+ */
+function bp_nav_menu( $args = array() ) {
+	static $menu_id_slugs = array();
+
+	$defaults = array(
+		'after'           => '',
+		'before'          => '',
+		'container'       => 'div',
+		'container_class' => '',
+		'container_id'    => '',
+		'depth'           => 0,
+		'echo'            => true,
+		'fallback_cb'     => false,
+		'items_wrap'      => '<ul id="%1$s" class="%2$s">%3$s</ul>',
+		'link_after'      => '',
+		'link_before'     => '',
+		'menu_class'      => 'menu',
+		'menu_id'         => '',
+		'walker'          => '',
+	);
+	$args = wp_parse_args( $args, $defaults );
+	$args = apply_filters( 'bp_nav_menu_args', $args );
+	$args = (object) $args;
+
+	$items = $nav_menu = '';
+	$show_container = false;
+
+	// Create custom walker if one wasn't set
+	if ( empty( $args->walker ) )
+		$args->walker = new BP_Walker_Nav_Menu;
+
+	// Sanitise values for class and ID
+	$args->container_class = sanitize_html_class( $args->container_class );
+	$args->container_id    = sanitize_html_class( $args->container_id );
+
+	// Whether to wrap the ul, and what to wrap it with
+	if ( $args->container ) {
+		$allowed_tags = apply_filters( 'wp_nav_menu_container_allowedtags', array( 'div', 'nav', ) );
+
+		if ( in_array( $args->container, $allowed_tags ) ) {
+			$show_container = true;
+
+			$class     = $args->container_class ? ' class="' . esc_attr( $args->container_class ) . '"' : ' class="menu-bp-container"';
+			$id        = $args->container_id    ? ' id="' . esc_attr( $args->container_id ) . '"'       : '';
+			$nav_menu .= '<' . $args->container . $id . $class . '>';
+		}
+	}
+
+	// Get the BuddyPress menu items
+	$menu_items = apply_filters( 'bp_nav_menu_objects', bp_get_nav_menu_items(), $args );
+	$items      = walk_nav_menu_tree( $menu_items, $args->depth, $args );
+	unset( $menu_items );
+
+	// Set the ID that is applied to the ul element which forms the menu.
+	if ( ! empty( $args->menu_id ) ) {
+		$wrap_id = $args->menu_id;
+
+	} else {
+		$wrap_id = 'menu-bp';
+
+		// If a specific ID wasn't requested, and there are multiple menus on the same screen, make sure the autogenerated ID is unique
+		while ( in_array( $wrap_id, $menu_id_slugs ) ) {
+			if ( preg_match( '#-(\d+)$#', $wrap_id, $matches ) )
+				$wrap_id = preg_replace('#-(\d+)$#', '-' . ++$matches[1], $wrap_id );
+			else
+				$wrap_id = $wrap_id . '-1';
+		}
+	}
+	$menu_id_slugs[] = $wrap_id;
+
+	// Allow plugins to hook into the menu to add their own <li>'s
+	$items = apply_filters( 'bp_nav_menu_items', $items, $args );
+
+	// Build the output
+	$wrap_class  = $args->menu_class ? $args->menu_class : '';
+	$nav_menu   .= sprintf( $args->items_wrap, esc_attr( $wrap_id ), esc_attr( $wrap_class ), $items );
+	unset( $items );
+
+	// If we've wrapped the ul, close it
+	if ( $show_container )
+		$nav_menu .= '</' . $args->container . '>';
+
+	// Final chance to modify output
+	$nav_menu = apply_filters( 'bp_nav_menu', $nav_menu, $args );
+
+	if ( $args->echo )
+		echo $nav_menu;
+	else
+		return $nav_menu;
+}
Index: /tags/1.9/bp-core/bp-core-theme-compatibility.php
===================================================================
--- /tags/1.9/bp-core/bp-core-theme-compatibility.php	(revision 7684)
+++ /tags/1.9/bp-core/bp-core-theme-compatibility.php	(revision 7684)
@@ -0,0 +1,821 @@
+<?php
+
+/**
+ * BuddyPress Core Theme Compatibility.
+ *
+ * @package BuddyPress
+ * @subpackage ThemeCompatibility
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/** Theme Compat **************************************************************/
+
+/**
+ * What follows is an attempt at intercepting the natural page load process
+ * to replace the_content() with the appropriate BuddyPress content.
+ *
+ * To do this, BuddyPress does several direct manipulations of global variables
+ * and forces them to do what they are not supposed to be doing.
+ *
+ * Don't try anything you're about to witness here, at home. Ever.
+ */
+
+/** Base Class ****************************************************************/
+
+/**
+ * Theme Compatibility base class.
+ *
+ * This is only intended to be extended, and is included here as a basic guide
+ * for future Theme Packs to use. {@link BP_Legacy} is a good example of
+ * extending this class.
+ *
+ * @since BuddyPress (1.7.0)
+ *
+ * @todo We should probably do something similar to BP_Component::start().
+ * @todo If this is only intended to be extended, it should be abstract.
+ *
+ * @param array $properties {
+ *     An array of properties describing the theme compat package.
+ *     @type string $id ID of the package. Must be unique.
+ *     @type string $name Name of the theme. This should match the name given
+ *           in style.css.
+ *     @type string $version Theme version. Used for busting script and style
+ *           browser caches.
+ *     @type string $dir Filesystem path of the theme.
+ *     @type string $url Base URL of the theme.
+ * }
+ */
+class BP_Theme_Compat {
+
+	/**
+	 * Template package properties, as passed to the constructor.
+	 *
+	 * @var array
+	 */
+	protected $_data = array();
+
+	/**
+	 * Pass the $properties to the object on creation.
+	 *
+	 * @since BuddyPress (1.7.0)
+	 */
+    	public function __construct( Array $properties = array() ) {
+		$this->_data = $properties;
+	}
+
+	/**
+	 * Set up the BuddyPress-specific theme compat methods.
+	 *
+	 * Themes shoud use this method in their constructor.
+	 *
+	 * @since BuddyPress (1.7.0)
+	 */
+	protected function start() {
+		// Sanity check
+		if ( ! bp_use_theme_compat_with_current_theme() ) {
+			return;
+		}
+
+		// Setup methods
+		$this->setup_globals();
+		$this->setup_actions();
+	}
+
+	/**
+	 * Set up global data for your template package.
+	 *
+	 * Meant to be overridden in your class. See
+	 * {@link BP_Legacy::setup_globals()} for an example.
+	 *
+	 * @since BuddyPress (1.7.0)
+	 */
+	protected function setup_globals() {}
+
+	/**
+	 * Set up theme hooks for your template package.
+	 *
+	 * Meant to be overridden in your class. See
+	 * {@link BP_Legacy::setup_actions()} for an example.
+	 *
+	 * @since BuddyPress (1.7.0)
+	 */
+	protected function setup_actions() {}
+
+	/**
+	 * Set a theme's property.
+	 *
+	 * @since BuddyPress (1.7.0)
+	 *
+	 * @param string $property Property name.
+	 * @param mixed $value Property value.
+	 * @return bool True on success, false on failure.
+	 */
+	public function __set( $property, $value ) {
+		return $this->_data[$property] = $value;
+	}
+
+	/**
+	 * Get a theme's property.
+	 *
+	 * @since BuddyPress (1.7.0)
+	 *
+	 * @param string $property Property name.
+	 * @return mixed The value of the property if it exists, otherwise an
+	 *         empty string.
+	 */
+	public function __get( $property ) {
+		return array_key_exists( $property, $this->_data ) ? $this->_data[$property] : '';
+	}
+}
+
+/** Functions *****************************************************************/
+
+/**
+ * Set up the default theme compat theme.
+ *
+ * @since BuddyPress (1.7.0)
+ *
+ * @param string $theme Optional. The unique ID identifier of a theme package.
+ */
+function bp_setup_theme_compat( $theme = '' ) {
+	$bp = buddypress();
+
+	// Make sure theme package is available, set to default if not
+	if ( ! isset( $bp->theme_compat->packages[$theme] ) || ! is_a( $bp->theme_compat->packages[$theme], 'BP_Theme_Compat' ) ) {
+		$theme = 'legacy';
+	}
+
+	// Set the active theme compat theme
+	$bp->theme_compat->theme = $bp->theme_compat->packages[$theme];
+}
+
+/**
+ * Get the ID of the theme package being used.
+ *
+ * This can be filtered or set manually. Tricky theme authors can override the
+ * default and include their own BuddyPress compatability layers for their themes.
+ *
+ * @since BuddyPress (1.7.0)
+ *
+ * @uses apply_filters()
+ *
+ * @return string ID of the theme package in use.
+ */
+function bp_get_theme_compat_id() {
+	return apply_filters( 'bp_get_theme_compat_id', buddypress()->theme_compat->theme->id );
+}
+
+/**
+ * Get the name of the theme package being used.
+ *
+ * This can be filtered or set manually. Tricky theme authors can override the
+ * default and include their own BuddyPress compatability layers for their themes.
+ *
+ * @since BuddyPress (1.7.0)
+ *
+ * @uses apply_filters()
+ *
+ * @return string Name of the theme package currently in use.
+ */
+function bp_get_theme_compat_name() {
+	return apply_filters( 'bp_get_theme_compat_name', buddypress()->theme_compat->theme->name );
+}
+
+/**
+ * Get the version of the theme package being used.
+ *
+ * This can be filtered or set manually. Tricky theme authors can override the
+ * default and include their own BuddyPress compatability layers for their themes.
+ *
+ * @since BuddyPress (1.7.0)
+ *
+ * @uses apply_filters()
+ *
+ * @return string The version string of the theme package currently in use.
+ */
+function bp_get_theme_compat_version() {
+	return apply_filters( 'bp_get_theme_compat_version', buddypress()->theme_compat->theme->version );
+}
+
+/**
+ * Get the absolute path of the theme package being used.
+ *
+ * or set manually. Tricky theme authors can override the default and include
+ * their own BuddyPress compatability layers for their themes.
+ *
+ * @since BuddyPress (1.7.0)
+ *
+ * @uses apply_filters()
+ *
+ * @return string The absolute path of the theme package currently in use.
+ */
+function bp_get_theme_compat_dir() {
+	return apply_filters( 'bp_get_theme_compat_dir', buddypress()->theme_compat->theme->dir );
+}
+
+/**
+ * Get the URL of the theme package being used.
+ *
+ * This can be filtered, or set manually. Tricky theme authors can override
+ * the default and include their own BuddyPress compatability layers for their
+ * themes.
+ *
+ * @since BuddyPress (1.7.0)
+ *
+ * @uses apply_filters()
+ *
+ * @return string URL of the theme package currently in use.
+ */
+function bp_get_theme_compat_url() {
+	return apply_filters( 'bp_get_theme_compat_url', buddypress()->theme_compat->theme->url );
+}
+
+/**
+ * Should we use theme compat for this theme?
+ *
+ * If the current theme's need for theme compat hasn't yet been detected, we
+ * do so using bp_detect_theme_compat_with_current_theme().
+ *
+ * @since BuddyPress (1.9.0)
+ *
+ * @uses bp_detect_theme_compat_with_current_theme()
+ *
+ * @return bool True if the current theme needs theme compatibility.
+ */
+function bp_use_theme_compat_with_current_theme() {
+	if ( ! isset( buddypress()->theme_compat->use_with_current_theme ) ) {
+		bp_detect_theme_compat_with_current_theme();
+	}
+
+	return apply_filters( 'bp_use_theme_compat_with_current_theme', buddypress()->theme_compat->use_with_current_theme );
+}
+
+/**
+ * Set our flag to determine whether theme compat should be enabled.
+ *
+ * Theme compat is disabled when a theme meets one of the following criteria:
+ * 1) It declares BP support with add_theme_support( 'buddypress' )
+ * 2) It is bp-default, or a child theme of bp-default
+ * 3) A legacy template is found at members/members-loop.php. This is a
+ *    fallback check for themes that were derived from bp-default, and have
+ *    not been updated for BP 1.7+; we make the assumption that any theme in
+ *    this category will have the members-loop.php template, and so use its
+ *    presence as an indicator that theme compatibility is not required
+ *
+ * @since BuddyPress (1.9.0)
+ *
+ * @return bool True if the current theme needs theme compatibility.
+ */
+function bp_detect_theme_compat_with_current_theme() {
+	if ( isset( buddypress()->theme_compat->use_with_current_theme ) ) {
+		return buddypress()->theme_compat->use_with_current_theme;
+	}
+
+	// theme compat enabled by default
+	$theme_compat = true;
+
+	// If the theme supports 'buddypress', bail.
+	if ( current_theme_supports( 'buddypress' ) ) {
+		$theme_compat = false;
+
+	// If the theme doesn't support BP, do some additional checks
+	} else {
+		// Bail if theme is a derivative of bp-default
+		if ( in_array( 'bp-default', array( get_template(), get_stylesheet() ) ) ) {
+			$theme_compat = false;
+
+		// Bruteforce check for a BP template
+		// Examples are clones of bp-default
+		} else if ( locate_template( 'members/members-loop.php', false, false ) ) {
+			$theme_compat = false;
+		}
+	}
+
+	// set a flag in the buddypress() singleton so we don't have to run this again
+	buddypress()->theme_compat->use_with_current_theme = $theme_compat;
+
+	return $theme_compat;
+}
+
+/**
+ * Is the current page using theme compatibility?
+ *
+ * @since BuddyPress (1.7.0)
+ *
+ * @return bool True if the current page uses theme compatibility.
+ */
+function bp_is_theme_compat_active() {
+	$bp = buddypress();
+
+	if ( empty( $bp->theme_compat->active ) )
+		return false;
+
+	return $bp->theme_compat->active;
+}
+
+/**
+ * Set the flag that tells whether the current page is using theme compatibility.
+ *
+ * @since BuddyPress (1.7.0)
+ *
+ * @param bool $set True to set the flag to true, false to set it to false.
+ * @return bool Returns the value of $set.
+ */
+function bp_set_theme_compat_active( $set = true ) {
+	buddypress()->theme_compat->active = $set;
+
+	return (bool) buddypress()->theme_compat->active;
+}
+
+/**
+ * Set the theme compat templates global.
+ *
+ * Stash possible template files for the current query. Useful if plugins want
+ * to override them, or see what files are being scanned for inclusion.
+ *
+ * @since BuddyPress (1.7.0)
+ *
+ * @param array $templates The template stack.
+ * @return array The template stack (value of $templates).
+ */
+function bp_set_theme_compat_templates( $templates = array() ) {
+	buddypress()->theme_compat->templates = $templates;
+
+	return buddypress()->theme_compat->templates;
+}
+
+/**
+ * Set the theme compat template global.
+ *
+ * Stash the template file for the current query. Useful if plugins want
+ * to override it, or see what file is being included.
+ *
+ * @since BuddyPress (1.7.0)
+ *
+ * @param string $template The template currently in use.
+ * @return string The template currently in use (value of $template).
+ */
+function bp_set_theme_compat_template( $template = '' ) {
+	buddypress()->theme_compat->template = $template;
+
+	return buddypress()->theme_compat->template;
+}
+
+/**
+ * Set the theme compat original_template global.
+ *
+ * Stash the original template file for the current query. Useful for checking
+ * if BuddyPress was able to find a more appropriate template.
+ *
+ * @since BuddyPress (1.7.0)
+ *
+ * @param string $template The template originally selected by WP.
+ * @return string The template originally selected by WP (value of $template).
+ */
+function bp_set_theme_compat_original_template( $template = '' ) {
+	buddypress()->theme_compat->original_template = $template;
+
+	return buddypress()->theme_compat->original_template;
+}
+
+/**
+ * Check whether a given template is the one that WP originally selected to display current page.
+ *
+ * @since BuddyPress (1.7.0)
+ *
+ * @param string $template The template name to check.
+ * @return bool True if the value of $template is the same as the
+ *         "original_template" originally selected by WP. Otherwise false.
+ */
+function bp_is_theme_compat_original_template( $template = '' ) {
+	$bp = buddypress();
+
+	if ( empty( $bp->theme_compat->original_template ) )
+		return false;
+
+	return (bool) ( $bp->theme_compat->original_template == $template );
+}
+
+/**
+ * Register a new BuddyPress theme package in the active theme packages array.
+ *
+ * For an example of how this function is used, see:
+ * {@link BuddyPress::register_theme_packages()}.
+ *
+ * @since BuddyPress (1.7)
+ *
+ * @see BP_Theme_Compat for a description of the $theme parameter arguments.
+ *
+ * @param array $theme See {@link BP_Theme_Compat}.
+ * @param bool $override If true, overrides whatever package is currently set.
+ *        Default: true.
+ */
+function bp_register_theme_package( $theme = array(), $override = true ) {
+
+	// Create new BP_Theme_Compat object from the $theme array
+	if ( is_array( $theme ) ) {
+		$theme = new BP_Theme_Compat( $theme );
+	}
+
+	// Bail if $theme isn't a proper object
+	if ( ! is_a( $theme, 'BP_Theme_Compat' ) ) {
+		return;
+	}
+
+	// Load up BuddyPress
+	$bp = buddypress();
+
+	// Only set if the theme package was not previously registered or if the
+	// override flag is set
+	if ( empty( $bp->theme_compat->packages[$theme->id] ) || ( true === $override ) ) {
+		$bp->theme_compat->packages[$theme->id] = $theme;
+	}
+}
+
+/**
+ * Populate various WordPress globals with dummy data to prevent errors.
+ *
+ * This dummy data is necessary because theme compatibility essentially fakes
+ * WordPress into thinking that there is content where, in fact, there is none
+ * (at least, no WordPress post content). By providing dummy data, we ensure
+ * that template functions - things like is_page() - don't throw errors.
+ *
+ * @since BuddyPress (1.7.0)
+ *
+ * @global WP_Query $wp_query WordPress database access object.
+ * @global object $post Current post object.
+ *
+ * @param array $args Array of optional arguments. Arguments parallel the
+ *        properties of {@link WP_Post}; see that class for more details.
+ */
+function bp_theme_compat_reset_post( $args = array() ) {
+	global $wp_query, $post;
+
+	// Switch defaults if post is set
+	if ( isset( $wp_query->post ) ) {
+		$dummy = wp_parse_args( $args, array(
+			'ID'                    => $wp_query->post->ID,
+			'post_status'           => $wp_query->post->post_status,
+			'post_author'           => $wp_query->post->post_author,
+			'post_parent'           => $wp_query->post->post_parent,
+			'post_type'             => $wp_query->post->post_type,
+			'post_date'             => $wp_query->post->post_date,
+			'post_date_gmt'         => $wp_query->post->post_date_gmt,
+			'post_modified'         => $wp_query->post->post_modified,
+			'post_modified_gmt'     => $wp_query->post->post_modified_gmt,
+			'post_content'          => $wp_query->post->post_content,
+			'post_title'            => $wp_query->post->post_title,
+			'post_excerpt'          => $wp_query->post->post_excerpt,
+			'post_content_filtered' => $wp_query->post->post_content_filtered,
+			'post_mime_type'        => $wp_query->post->post_mime_type,
+			'post_password'         => $wp_query->post->post_password,
+			'post_name'             => $wp_query->post->post_name,
+			'guid'                  => $wp_query->post->guid,
+			'menu_order'            => $wp_query->post->menu_order,
+			'pinged'                => $wp_query->post->pinged,
+			'to_ping'               => $wp_query->post->to_ping,
+			'ping_status'           => $wp_query->post->ping_status,
+			'comment_status'        => $wp_query->post->comment_status,
+			'comment_count'         => $wp_query->post->comment_count,
+			'filter'                => $wp_query->post->filter,
+
+			'is_404'                => false,
+			'is_page'               => false,
+			'is_single'             => false,
+			'is_archive'            => false,
+			'is_tax'                => false,
+		) );
+	} else {
+		$dummy = wp_parse_args( $args, array(
+			'ID'                    => -9999,
+			'post_status'           => 'public',
+			'post_author'           => 0,
+			'post_parent'           => 0,
+			'post_type'             => 'page',
+			'post_date'             => 0,
+			'post_date_gmt'         => 0,
+			'post_modified'         => 0,
+			'post_modified_gmt'     => 0,
+			'post_content'          => '',
+			'post_title'            => '',
+			'post_excerpt'          => '',
+			'post_content_filtered' => '',
+			'post_mime_type'        => '',
+			'post_password'         => '',
+			'post_name'             => '',
+			'guid'                  => '',
+			'menu_order'            => 0,
+			'pinged'                => '',
+			'to_ping'               => '',
+			'ping_status'           => '',
+			'comment_status'        => 'closed',
+			'comment_count'         => 0,
+			'filter'                => 'raw',
+
+			'is_404'                => false,
+			'is_page'               => false,
+			'is_single'             => false,
+			'is_archive'            => false,
+			'is_tax'                => false,
+		) );
+	}
+
+	// Bail if dummy post is empty
+	if ( empty( $dummy ) ) {
+		return;
+	}
+
+	// Set the $post global
+	$post = new WP_Post( (object) $dummy );
+
+	// Copy the new post global into the main $wp_query
+	$wp_query->post       = $post;
+	$wp_query->posts      = array( $post );
+
+	// Prevent comments form from appearing
+	$wp_query->post_count = 1;
+	$wp_query->is_404     = $dummy['is_404'];
+	$wp_query->is_page    = $dummy['is_page'];
+	$wp_query->is_single  = $dummy['is_single'];
+	$wp_query->is_archive = $dummy['is_archive'];
+	$wp_query->is_tax     = $dummy['is_tax'];
+
+	// Clean up the dummy post
+	unset( $dummy );
+
+	/**
+	 * Force the header back to 200 status if not a deliberate 404
+	 *
+	 * @see http://bbpress.trac.wordpress.org/ticket/1973
+	 */
+	if ( ! $wp_query->is_404() ) {
+		status_header( 200 );
+	}
+
+	// If we are resetting a post, we are in theme compat
+	bp_set_theme_compat_active( true );
+}
+
+/**
+ * Reset main query vars and filter 'the_content' to output a BuddyPress template part as needed.
+ *
+ * @since BuddyPress (1.7.0)
+ *
+ * @uses bp_is_single_user() To check if page is single user.
+ * @uses bp_get_single_user_template() To get user template.
+ * @uses bp_is_single_user_edit() To check if page is single user edit.
+ * @uses bp_get_single_user_edit_template() To get user edit template.
+ * @uses bp_is_single_view() To check if page is single view.
+ * @uses bp_get_single_view_template() To get view template.
+ * @uses bp_is_forum_edit() To check if page is forum edit.
+ * @uses bp_get_forum_edit_template() To get forum edit template.
+ * @uses bp_is_topic_merge() To check if page is topic merge.
+ * @uses bp_get_topic_merge_template() To get topic merge template.
+ * @uses bp_is_topic_split() To check if page is topic split.
+ * @uses bp_get_topic_split_template() To get topic split template.
+ * @uses bp_is_topic_edit() To check if page is topic edit.
+ * @uses bp_get_topic_edit_template() To get topic edit template.
+ * @uses bp_is_reply_edit() To check if page is reply edit.
+ * @uses bp_get_reply_edit_template() To get reply edit template.
+ * @uses bp_set_theme_compat_template() To set the global theme compat template.
+ *
+ * @param string $template Template name.
+ * @return string $template Template name.
+ */
+function bp_template_include_theme_compat( $template = '' ) {
+
+	// If the current theme doesn't need theme compat, bail at this point.
+	if ( ! bp_use_theme_compat_with_current_theme() ) {
+		return $template;
+	}
+
+	/**
+	 * Use this action to execute code that will communicate to BuddyPress's
+	 * theme compatibility layer whether or not we're replacing the_content()
+	 * with some other template part.
+	 */
+	do_action( 'bp_template_include_reset_dummy_post_data' );
+
+	// Bail if the template already matches a BuddyPress template
+	if ( !empty( buddypress()->theme_compat->found_template ) )
+		return $template;
+
+	/**
+	 * If we are relying on BuddyPress's built in theme compatibility to load
+	 * the proper content, we need to intercept the_content, replace the
+	 * output, and display ours instead.
+	 *
+	 * To do this, we first remove all filters from 'the_content' and hook
+	 * our own function into it, which runs a series of checks to determine
+	 * the context, and then uses the built in shortcodes to output the
+	 * correct results from inside an output buffer.
+	 *
+	 * Uses bp_get_theme_compat_templates() to provide fall-backs that
+	 * should be coded without superfluous mark-up and logic (prev/next
+	 * navigation, comments, date/time, etc...)
+	 *
+	 * Hook into 'bp_get_buddypress_template' to override the array of
+	 * possible templates, or 'bp_buddypress_template' to override the result.
+	 */
+	if ( bp_is_theme_compat_active() ) {
+		$template = bp_get_theme_compat_templates();
+
+		add_filter( 'the_content', 'bp_replace_the_content' );
+
+		// Add BuddyPress's head action to wp_head
+		if ( ! has_action( 'wp_head', 'bp_head' ) ) {
+			add_action( 'wp_head', 'bp_head' );
+		}
+	}
+
+	return apply_filters( 'bp_template_include_theme_compat', $template );
+}
+
+/**
+ * Conditionally replace 'the_content'.
+ *
+ * Replaces the_content() if the post_type being displayed is one that would
+ * normally be handled by BuddyPress, but proper single page templates do not
+ * exist in the currently active theme.
+ *
+ * @since BuddyPress (1.7.0)
+ *
+ * @param string $content Original post content.
+ * @return string $content Post content, potentially modified.
+ */
+function bp_replace_the_content( $content = '' ) {
+
+	// Bail if not the main loop where theme compat is happening
+	if ( ! bp_do_theme_compat() )
+		return $content;
+
+	// Set theme compat to false early, to avoid recursion from nested calls to
+	// the_content() that execute before theme compat has unhooked itself.
+	bp_set_theme_compat_active( false );
+
+	// Do we have new content to replace the old content?
+	$new_content = apply_filters( 'bp_replace_the_content', $content );
+
+	// Juggle the content around and try to prevent unsightly comments
+	if ( !empty( $new_content ) && ( $new_content !== $content ) ) {
+
+		// Set the content to be the new content
+		$content = $new_content;
+
+		// Clean up after ourselves
+		unset( $new_content );
+
+		// Reset the $post global
+		wp_reset_postdata();
+	}
+
+	// Return possibly hi-jacked content
+	return $content;
+}
+
+/**
+ * Are we currently replacing the_content?
+ *
+ * @since BuddyPress (1.8.0)
+ *
+ * @return bool True if the_content is currently in the process of being
+ *         filtered and replaced.
+ */
+function bp_do_theme_compat() {
+	return (bool) ( ! bp_is_template_included() && in_the_loop() && bp_is_theme_compat_active() );
+}
+
+/** Filters *******************************************************************/
+
+/**
+ * Remove all filters from a WordPress filter hook.
+ *
+ * Removed filters are stashed in the $bp global, in case they need to be
+ * restored later.
+ *
+ * @since BuddyPress (1.7.0)
+ *
+ * @global WP_filter $wp_filter
+ * @global array $merged_filters
+ *
+ * @param string $tag The filter tag to remove filters from.
+ * @param int $priority Optional. If present, only those callbacks attached
+ *        at a given priority will be removed. Otherwise, all callbacks
+ *        attached to the tag will be removed, regardless of priority.
+ * @return bool True on success.
+ */
+function bp_remove_all_filters( $tag, $priority = false ) {
+	global $wp_filter, $merged_filters;
+
+	$bp = buddypress();
+
+	// Filters exist
+	if ( isset( $wp_filter[$tag] ) ) {
+
+		// Filters exist in this priority
+		if ( !empty( $priority ) && isset( $wp_filter[$tag][$priority] ) ) {
+
+			// Store filters in a backup
+			$bp->filters->wp_filter[$tag][$priority] = $wp_filter[$tag][$priority];
+
+			// Unset the filters
+			unset( $wp_filter[$tag][$priority] );
+
+		// Priority is empty
+		} else {
+
+			// Store filters in a backup
+			$bp->filters->wp_filter[$tag] = $wp_filter[$tag];
+
+			// Unset the filters
+			unset( $wp_filter[$tag] );
+		}
+	}
+
+	// Check merged filters
+	if ( isset( $merged_filters[$tag] ) ) {
+
+		// Store filters in a backup
+		$bp->filters->merged_filters[$tag] = $merged_filters[$tag];
+
+		// Unset the filters
+		unset( $merged_filters[$tag] );
+	}
+
+	return true;
+}
+
+/**
+ * Restore filters that were removed using bp_remove_all_filters().
+ *
+ * @since BuddyPress (1.7.0)
+ *
+ * @global WP_filter $wp_filter
+ * @global array $merged_filters
+ *
+ * @param string $tag The tag to which filters should be restored.
+ * @param int $priority Optional. If present, only those filters that were
+ *        originally attached to the tag with $priority will be restored.
+ *        Otherwise, all available filters will be restored, regardless of
+ *        priority.
+ * @return bool True on success.
+ */
+function bp_restore_all_filters( $tag, $priority = false ) {
+	global $wp_filter, $merged_filters;
+
+	$bp = buddypress();
+
+	// Filters exist
+	if ( isset( $bp->filters->wp_filter[$tag] ) ) {
+
+		// Filters exist in this priority
+		if ( !empty( $priority ) && isset( $bp->filters->wp_filter[$tag][$priority] ) ) {
+
+			// Store filters in a backup
+			$wp_filter[$tag][$priority] = $bp->filters->wp_filter[$tag][$priority];
+
+			// Unset the filters
+			unset( $bp->filters->wp_filter[$tag][$priority] );
+
+		// Priority is empty
+		} else {
+
+			// Store filters in a backup
+			$wp_filter[$tag] = $bp->filters->wp_filter[$tag];
+
+			// Unset the filters
+			unset( $bp->filters->wp_filter[$tag] );
+		}
+	}
+
+	// Check merged filters
+	if ( isset( $bp->filters->merged_filters[$tag] ) ) {
+
+		// Store filters in a backup
+		$merged_filters[$tag] = $bp->filters->merged_filters[$tag];
+
+		// Unset the filters
+		unset( $bp->filters->merged_filters[$tag] );
+	}
+
+	return true;
+}
+
+/**
+ * Force comments_status to 'closed' for BuddyPress post types.
+ *
+ * @since BuddyPress (1.7.0)
+ *
+ * @param bool $open True if open, false if closed.
+ * @param int $post_id ID of the post to check.
+ * @return bool True if open, false if closed.
+ */
+function bp_comments_open( $open, $post_id = 0 ) {
+
+	$retval = is_buddypress() ? false : $open;
+
+	// Allow override of the override
+	return apply_filters( 'bp_force_comment_status', $retval, $open, $post_id );
+}
Index: /tags/1.9/bp-core/bp-core-update.php
===================================================================
--- /tags/1.9/bp-core/bp-core-update.php	(revision 7684)
+++ /tags/1.9/bp-core/bp-core-update.php	(revision 7684)
@@ -0,0 +1,391 @@
+<?php
+
+/**
+ * BuddyPress Updater.
+ *
+ * @package BuddyPress
+ * @subpackage Updater
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/**
+ * Is this a fresh installation of BuddyPress?
+ *
+ * If there is no raw DB version, we infer that this is the first installation.
+ *
+ * @since BuddyPress (1.7.0)
+ *
+ * @uses get_option()
+ * @uses bp_get_db_version() To get BuddyPress's database version.
+ *
+ * @return bool True if this is a fresh BP install, otherwise false.
+ */
+function bp_is_install() {
+	return ! bp_get_db_version_raw();
+}
+
+/**
+ * Is this a BuddyPress update?
+ *
+ * Determined by comparing the registered BuddyPress version to the version
+ * number stored in the database. If the registered version is greater, it's
+ * an update.
+ *
+ * @since BuddyPress (1.6.0)
+ *
+ * @uses get_option()
+ * @uses bp_get_db_version() To get BuddyPress's database version.
+ *
+ * @return bool True if update, otherwise false.
+ */
+function bp_is_update() {
+
+	// Current DB version of this site (per site in a multisite network)
+	$current_db   = bp_get_option( '_bp_db_version' );
+	$current_live = bp_get_db_version();
+
+	// Compare versions (cast as int and bool to be safe)
+	$is_update = (bool) ( (int) $current_db < (int) $current_live );
+
+	// Return the product of version comparison
+	return $is_update;
+}
+
+/**
+ * Determine whether BuddyPress is in the process of being activated.
+ *
+ * @since BuddyPress (1.6.0)
+ *
+ * @uses buddypress()
+ *
+ * @return bool True if activating BuddyPress, false if not.
+ */
+function bp_is_activation( $basename = '' ) {
+	$bp     = buddypress();
+	$action = false;
+
+	if ( ! empty( $_REQUEST['action'] ) && ( '-1' != $_REQUEST['action'] ) ) {
+		$action = $_REQUEST['action'];
+	} elseif ( ! empty( $_REQUEST['action2'] ) && ( '-1' != $_REQUEST['action2'] ) ) {
+		$action = $_REQUEST['action2'];
+	}
+
+	// Bail if not activating
+	if ( empty( $action ) || !in_array( $action, array( 'activate', 'activate-selected' ) ) ) {
+		return false;
+	}
+
+	// The plugin(s) being activated
+	if ( $action == 'activate' ) {
+		$plugins = isset( $_GET['plugin'] ) ? array( $_GET['plugin'] ) : array();
+	} else {
+		$plugins = isset( $_POST['checked'] ) ? (array) $_POST['checked'] : array();
+	}
+
+	// Set basename if empty
+	if ( empty( $basename ) && !empty( $bp->basename ) ) {
+		$basename = $bp->basename;
+	}
+
+	// Bail if no basename
+	if ( empty( $basename ) ) {
+		return false;
+	}
+
+	// Is BuddyPress being activated?
+	return in_array( $basename, $plugins );
+}
+
+/**
+ * Determine whether BuddyPress is in the process of being deactivated.
+ *
+ * @since BuddyPress (1.6.0)
+ *
+ * @uses buddypress()
+ *
+ * @return bool True if deactivating BuddyPress, false if not.
+ */
+function bp_is_deactivation( $basename = '' ) {
+	$bp     = buddypress();
+	$action = false;
+
+	if ( ! empty( $_REQUEST['action'] ) && ( '-1' != $_REQUEST['action'] ) ) {
+		$action = $_REQUEST['action'];
+	} elseif ( ! empty( $_REQUEST['action2'] ) && ( '-1' != $_REQUEST['action2'] ) ) {
+		$action = $_REQUEST['action2'];
+	}
+
+	// Bail if not deactivating
+	if ( empty( $action ) || !in_array( $action, array( 'deactivate', 'deactivate-selected' ) ) ) {
+		return false;
+	}
+
+	// The plugin(s) being deactivated
+	if ( 'deactivate' == $action ) {
+		$plugins = isset( $_GET['plugin'] ) ? array( $_GET['plugin'] ) : array();
+	} else {
+		$plugins = isset( $_POST['checked'] ) ? (array) $_POST['checked'] : array();
+	}
+
+	// Set basename if empty
+	if ( empty( $basename ) && !empty( $bp->basename ) ) {
+		$basename = $bp->basename;
+	}
+
+	// Bail if no basename
+	if ( empty( $basename ) ) {
+		return false;
+	}
+
+	// Is bbPress being deactivated?
+	return in_array( $basename, $plugins );
+}
+
+/**
+ * Update the BP version stored in the database to the current version.
+ *
+ * @since BuddyPress (1.6.0)
+ *
+ * @uses bp_get_db_version() To get BuddyPress's database version.
+ * @uses bp_update_option() To update BuddyPress's database version.
+ */
+function bp_version_bump() {
+	bp_update_option( '_bp_db_version', bp_get_db_version() );
+}
+
+/**
+ * Set up the BuddyPress updater.
+ *
+ * @since BuddyPress (1.6.0)
+ */
+function bp_setup_updater() {
+
+	// Are we running an outdated version of BuddyPress?
+	if ( ! bp_is_update() )
+		return;
+
+	bp_version_updater();
+}
+
+/**
+ * Initialize an update or installation of BuddyPress.
+ *
+ * BuddyPress's version updater looks at what the current database version is,
+ * and runs whatever other code is needed - either the "update" or "install"
+ * code.
+ *
+ * This is most often used when the data schema changes, but should also be used
+ * to correct issues with BuddyPress metadata silently on software update.
+ *
+ * @since BuddyPress (1.7.0)
+ */
+function bp_version_updater() {
+
+	// Get the raw database version
+	$raw_db_version = (int) bp_get_db_version_raw();
+
+	$default_components = apply_filters( 'bp_new_install_default_components', array(
+		'activity'      => 1,
+		'members'       => 1,
+		'settings'      => 1,
+		'xprofile'      => 1,
+		'notifications' => 1,
+	) );
+
+	require_once( BP_PLUGIN_DIR . '/bp-core/admin/bp-core-schema.php' );
+
+	// Install BP schema and activate only Activity and XProfile
+	if ( bp_is_install() ) {
+
+		// Apply schema and set Activity and XProfile components as active
+		bp_core_install( $default_components );
+		bp_update_option( 'bp-active-components', $default_components );
+		bp_core_add_page_mappings( $default_components, 'delete' );
+
+	// Upgrades
+	} else {
+
+		// Run the schema install to update tables
+		bp_core_install();
+
+		// 1.5
+		if ( $raw_db_version < 1801 ) {
+			bp_update_to_1_5();
+			bp_core_add_page_mappings( $default_components, 'delete' );
+		}
+
+		// 1.6
+		if ( $raw_db_version < 6067 ) {
+			bp_update_to_1_6();
+		}
+
+		// 1.9
+		if ( $raw_db_version < 7553 ) {
+			bp_update_to_1_9();
+		}
+	}
+
+	/** All done! *************************************************************/
+
+	// Bump the version
+	bp_version_bump();
+}
+
+/**
+ * Remove unused metadata from database when upgrading from < 1.5.
+ *
+ * Database update methods based on version numbers.
+ *
+ * @since BuddyPress (1.7.0)
+ */
+function bp_update_to_1_5() {
+
+	// Delete old database version options
+	delete_site_option( 'bp-activity-db-version' );
+	delete_site_option( 'bp-blogs-db-version'    );
+	delete_site_option( 'bp-friends-db-version'  );
+	delete_site_option( 'bp-groups-db-version'   );
+	delete_site_option( 'bp-messages-db-version' );
+	delete_site_option( 'bp-xprofile-db-version' );
+}
+
+/**
+ * Remove unused metadata from database when upgrading from < 1.6.
+ *
+ * Database update methods based on version numbers.
+ *
+ * @since BuddyPress (1.7.0)
+ */
+function bp_update_to_1_6() {
+
+	// Delete possible site options
+	delete_site_option( 'bp-db-version'       );
+	delete_site_option( '_bp_db_version'      );
+	delete_site_option( 'bp-core-db-version'  );
+	delete_site_option( '_bp-core-db-version' );
+
+	// Delete possible blog options
+	delete_blog_option( bp_get_root_blog_id(), 'bp-db-version'       );
+	delete_blog_option( bp_get_root_blog_id(), 'bp-core-db-version'  );
+	delete_site_option( bp_get_root_blog_id(), '_bp-core-db-version' );
+	delete_site_option( bp_get_root_blog_id(), '_bp_db_version'      );
+}
+
+/**
+ * Add the notifications component to active components.
+ *
+ * Notifications was added in 1.9.0, and previous installations will already
+ * have the core notifications API active. We need to add the new Notifications
+ * component to the active components option to retain existing functionality.
+ *
+ * @since BuddyPress (1.9.0)
+ */
+function bp_update_to_1_9() {
+
+	// Setup hardcoded keys
+	$active_components_key      = 'bp-active-components';
+	$notifications_component_id = 'notifications';
+
+	// Get the active components
+	$active_components          = bp_get_option( $active_components_key );
+
+	// Add notifications
+	if ( ! in_array( $notifications_component_id, $active_components ) ) {
+		$active_components[ $notifications_component_id ] = 1;
+	}
+
+	// Update the active components option
+	bp_update_option( $active_components_key, $active_components );
+}
+
+/**
+ * Redirect user to BP's What's New page on first page load after activation.
+ *
+ * @since BuddyPress (1.7.0)
+ *
+ * @internal Used internally to redirect BuddyPress to the about page on activation.
+ *
+ * @uses set_transient() To drop the activation transient for 30 seconds.
+ */
+function bp_add_activation_redirect() {
+
+	// Bail if activating from network, or bulk
+	if ( isset( $_GET['activate-multi'] ) )
+		return;
+
+	// Record that this is a new installation, so we show the right
+	// welcome message
+	if ( bp_is_install() ) {
+		set_transient( '_bp_is_new_install', true, 30 );
+	}
+
+	// Add the transient to redirect
+	set_transient( '_bp_activation_redirect', true, 30 );
+}
+
+/** Activation Actions ********************************************************/
+
+/**
+ * Fire activation hooks and events.
+ *
+ * Runs on BuddyPress activation.
+ *
+ * @since BuddyPress (1.6.0)
+ *
+ * @uses do_action() Calls 'bp_activation' hook.
+ */
+function bp_activation() {
+
+	// Force refresh theme roots.
+	delete_site_transient( 'theme_roots' );
+
+	// Use as of (1.6)
+	do_action( 'bp_activation' );
+
+	// @deprecated as of (1.6)
+	do_action( 'bp_loader_activate' );
+}
+
+/**
+ * Fire deactivation hooks and events.
+ *
+ * Runs on BuddyPress deactivation.
+ *
+ * @since BuddyPress (1.6.0)
+ *
+ * @uses do_action() Calls 'bp_deactivation' hook.
+ */
+function bp_deactivation() {
+
+	// Force refresh theme roots.
+	delete_site_transient( 'theme_roots' );
+
+	// Switch to WordPress's default theme if current parent or child theme
+	// depend on bp-default. This is to prevent white screens of doom.
+	if ( in_array( 'bp-default', array( get_template(), get_stylesheet() ) ) ) {
+		switch_theme( WP_DEFAULT_THEME, WP_DEFAULT_THEME );
+		update_option( 'template_root',   get_raw_theme_root( WP_DEFAULT_THEME, true ) );
+		update_option( 'stylesheet_root', get_raw_theme_root( WP_DEFAULT_THEME, true ) );
+	}
+
+	// Use as of (1.6)
+	do_action( 'bp_deactivation' );
+
+	// @deprecated as of (1.6)
+	do_action( 'bp_loader_deactivate' );
+}
+
+/**
+ * Fire uninstall hook.
+ *
+ * Runs when uninstalling BuddyPress.
+ *
+ * @since BuddyPress (1.6.0)
+ *
+ * @uses do_action() Calls 'bp_uninstall' hook.
+ */
+function bp_uninstall() {
+	do_action( 'bp_uninstall' );
+}
Index: /tags/1.9/bp-core/bp-core-widgets.php
===================================================================
--- /tags/1.9/bp-core/bp-core-widgets.php	(revision 7684)
+++ /tags/1.9/bp-core/bp-core-widgets.php	(revision 7684)
@@ -0,0 +1,536 @@
+<?php
+/**
+ * BuddyPress Core Component Widgets.
+ *
+ * @package BuddyPress
+ * @subpackage Core
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/**
+ * Register bp-core widgets.
+ */
+function bp_core_register_widgets() {
+	add_action('widgets_init', create_function('', 'return register_widget("BP_Core_Login_Widget");') );
+	add_action('widgets_init', create_function('', 'return register_widget("BP_Core_Members_Widget");') );
+	add_action('widgets_init', create_function('', 'return register_widget("BP_Core_Whos_Online_Widget");') );
+	add_action('widgets_init', create_function('', 'return register_widget("BP_Core_Recently_Active_Widget");') );
+}
+add_action( 'bp_register_widgets', 'bp_core_register_widgets' );
+
+/**
+ * BuddyPress Login Widget.
+ *
+ * @since BuddyPress (1.9.0)
+ */
+class BP_Core_Login_Widget extends WP_Widget {
+
+	/**
+	 * Constructor method.
+	 */
+	public function __construct() {
+		parent::__construct(
+			false,
+			_x( '(BuddyPress) Log In', 'Title of the login widget', 'buddypress' ),
+			array(
+				'description' => __( 'Show a Log In form to logged-out visitors, and a Log Out link to those who are logged in.', 'buddypress' ),
+				'classname' => 'widget_bp_core_login_widget buddypress widget',
+			)
+		);
+	}
+
+	/**
+	 * Display the login widget.
+	 *
+	 * @see WP_Widget::widget() for description of parameters.
+	 *
+	 * @param array $args Widget arguments.
+	 * @param array $instance Widget settings, as saved by the user.
+	 */
+	public function widget( $args, $instance ) {
+		$title = apply_filters( 'widget_title', $instance['title'] );
+
+		echo $args['before_widget'];
+
+		echo $args['before_title'] . esc_html( $title ) . $args['after_title']; ?>
+
+		<?php if ( is_user_logged_in() ) : ?>
+
+			<?php do_action( 'bp_before_login_widget_loggedin' ); ?>
+
+			<div class="bp-login-widget-user-avatar">
+				<a href="<?php echo bp_loggedin_user_domain(); ?>">
+					<?php bp_loggedin_user_avatar( 'type=thumb&width=50&height=50' ); ?>
+				</a>
+			</div>
+
+			<div class="bp-login-widget-user-links">
+				<div class="bp-login-widget-user-link"><?php echo bp_core_get_userlink( bp_loggedin_user_id() ); ?></div>
+				<div class="bp-login-widget-user-logout"><a class="logout" href="<?php echo wp_logout_url( wp_guess_url() ); ?>"><?php _e( 'Log Out', 'buddypress' ); ?></a></div>
+			</div>
+
+			<?php do_action( 'bp_after_login_widget_loggedin' ); ?>
+
+		<?php else : ?>
+
+			<?php do_action( 'bp_before_login_widget_loggedout' ); ?>
+
+			<form name="bp-login-form" id="bp-login-widget-form" class="standard-form" action="<?php echo esc_url( site_url( 'wp-login.php', 'login_post' ) ); ?>" method="post">
+				<label for="bp-login-widget-user-login"><?php _e( 'Username', 'buddypress' ); ?></label>
+				<input type="text" name="log" id="bp-login-widget-user-login" class="input" value="" />
+
+				<label for="bp-login-widget-user-pass"><?php _e( 'Password', 'buddypress' ); ?></label>
+				<input type="password" name="pwd" id="bp-login-widget-user-pass" class="input" value=""  />
+
+				<div class="forgetmenot"><label><input name="rememberme" type="checkbox" id="bp-login-widget-rememberme" value="forever" /> <?php _e( 'Remember Me', 'buddypress' ); ?></label></div>
+
+				<input type="submit" name="wp-submit" id="bp-login-widget-submit" value="<?php _e( 'Log In', 'buddypress' ); ?>" />
+
+				<?php if ( bp_get_signup_allowed() ) : ?>
+
+					<span class="bp-login-widget-register-link"><?php printf( __( '<a href="%s" title="Register for a new account">Register</a>', 'buddypress' ), bp_get_signup_page() ); ?></span>
+
+				<?php endif; ?>
+
+			</form>
+
+			<?php do_action( 'bp_after_login_widget_loggedout' ); ?>
+
+		<?php endif;
+
+		echo $args['after_widget'];
+	}
+
+	/**
+	 * Update the login widget options.
+	 *
+	 * @param array $new_instance The new instance options.
+	 * @param array $old_instance The old instance options.
+	 * @return array $instance The parsed options to be saved.
+	 */
+	public function update( $new_instance, $old_instance ) {
+		$instance             = $old_instance;
+		$instance['title']    = strip_tags( $new_instance['title'] );
+		$instance['register'] = esc_url_raw( $new_instance['register'] );
+		$instance['lostpass'] = esc_url_raw( $new_instance['lostpass'] );
+
+		return $instance;
+	}
+
+	/**
+	 * Output the login widget options form.
+	 *
+	 * @param $instance Settings for this widget.
+	 */
+	public function form( $instance = array() ) {
+
+		$settings = wp_parse_args( $instance, array(
+			'title' => '',
+		) ); ?>
+
+		<p>
+			<label for="<?php echo $this->get_field_id( 'title' ); ?>"><?php _e( 'Title:', 'buddypress' ); ?>
+			<input class="widefat" id="<?php echo $this->get_field_id( 'title' ); ?>" name="<?php echo $this->get_field_name( 'title' ); ?>" type="text" value="<?php echo esc_attr( $settings['title'] ); ?>" /></label>
+		</p>
+
+		<?php
+	}
+}
+
+/**
+ * Members Widget.
+ */
+class BP_Core_Members_Widget extends WP_Widget {
+
+	/**
+	 * Constructor method.
+	 */
+	function __construct() {
+		$widget_ops = array(
+			'description' => __( 'A dynamic list of recently active, popular, and newest members', 'buddypress' ),
+			'classname' => 'widget_bp_core_members_widget buddypress widget',
+		);
+		parent::__construct( false, $name = _x( '(BuddyPress) Members', 'widget name', 'buddypress' ), $widget_ops );
+
+		if ( is_active_widget( false, false, $this->id_base ) && !is_admin() && !is_network_admin() ) {
+			$min = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min';
+			wp_enqueue_script( 'bp_core_widget_members-js', BP_PLUGIN_URL . "bp-core/js/widget-members{$min}.js", array( 'jquery' ), bp_get_version() );
+		}
+	}
+
+	/**
+	 * Display the Members widget.
+	 *
+	 * @see WP_Widget::widget() for description of parameters.
+	 *
+	 * @param array $args Widget arguments.
+	 * @param array $instance Widget settings, as saved by the user.
+	 */
+	function widget( $args, $instance ) {
+
+		extract( $args );
+
+		if ( !$instance['member_default'] )
+			$instance['member_default'] = 'active';
+
+		$title = apply_filters( 'widget_title', $instance['title'] );
+
+		echo $before_widget;
+
+		$title = $instance['link_title'] ? '<a href="' . trailingslashit( bp_get_root_domain() . '/' . bp_get_members_root_slug() ) . '">' . $title . '</a>' : $title;
+
+		echo $before_title
+		   . $title
+		   . $after_title; ?>
+
+		<?php if ( bp_has_members( 'user_id=0&type=' . $instance['member_default'] . '&max=' . $instance['max_members'] . '&populate_extras=1' ) ) : ?>
+			<div class="item-options" id="members-list-options">
+				<a href="<?php bp_members_directory_permalink(); ?>" id="newest-members" <?php if ( $instance['member_default'] == 'newest' ) : ?>class="selected"<?php endif; ?>><?php _e( 'Newest', 'buddypress' ) ?></a>
+				|  <a href="<?php bp_members_directory_permalink(); ?>" id="recently-active-members" <?php if ( $instance['member_default'] == 'active' ) : ?>class="selected"<?php endif; ?>><?php _e( 'Active', 'buddypress' ) ?></a>
+
+				<?php if ( bp_is_active( 'friends' ) ) : ?>
+
+					| <a href="<?php bp_members_directory_permalink(); ?>" id="popular-members" <?php if ( $instance['member_default'] == 'popular' ) : ?>class="selected"<?php endif; ?>><?php _e( 'Popular', 'buddypress' ) ?></a>
+
+				<?php endif; ?>
+			</div>
+
+			<ul id="members-list" class="item-list">
+				<?php while ( bp_members() ) : bp_the_member(); ?>
+					<li class="vcard">
+						<div class="item-avatar">
+							<a href="<?php bp_member_permalink() ?>" title="<?php bp_member_name() ?>"><?php bp_member_avatar() ?></a>
+						</div>
+
+						<div class="item">
+							<div class="item-title fn"><a href="<?php bp_member_permalink() ?>" title="<?php bp_member_name() ?>"><?php bp_member_name() ?></a></div>
+							<div class="item-meta">
+								<span class="activity">
+								<?php
+									if ( 'newest' == $instance['member_default'] )
+										bp_member_registered();
+									if ( 'active' == $instance['member_default'] )
+										bp_member_last_active();
+									if ( 'popular' == $instance['member_default'] )
+										bp_member_total_friend_count();
+								?>
+								</span>
+							</div>
+						</div>
+					</li>
+
+				<?php endwhile; ?>
+			</ul>
+			<?php wp_nonce_field( 'bp_core_widget_members', '_wpnonce-members' ); ?>
+			<input type="hidden" name="members_widget_max" id="members_widget_max" value="<?php echo esc_attr( $instance['max_members'] ); ?>" />
+
+		<?php else: ?>
+
+			<div class="widget-error">
+				<?php _e('No one has signed up yet!', 'buddypress') ?>
+			</div>
+
+		<?php endif; ?>
+
+		<?php echo $after_widget; ?>
+	<?php
+	}
+
+	/**
+	 * Update the Members widget options.
+	 *
+	 * @param array $new_instance The new instance options.
+	 * @param array $old_instance The old instance options.
+	 * @return array $instance The parsed options to be saved.
+	 */
+	function update( $new_instance, $old_instance ) {
+		$instance = $old_instance;
+
+		$instance['title'] 	    = strip_tags( $new_instance['title'] );
+		$instance['max_members']    = strip_tags( $new_instance['max_members'] );
+		$instance['member_default'] = strip_tags( $new_instance['member_default'] );
+		$instance['link_title']	    = (bool)$new_instance['link_title'];
+
+		return $instance;
+	}
+
+	/**
+	 * Output the Members widget options form.
+	 *
+	 * @param $instance Settings for this widget.
+	 */
+	function form( $instance ) {
+		$defaults = array(
+			'title' 	 => __( 'Members', 'buddypress' ),
+			'max_members' 	 => 5,
+			'member_default' => 'active',
+			'link_title' 	 => false
+		);
+		$instance = wp_parse_args( (array) $instance, $defaults );
+
+		$title 		= strip_tags( $instance['title'] );
+		$max_members 	= strip_tags( $instance['max_members'] );
+		$member_default = strip_tags( $instance['member_default'] );
+		$link_title	= (bool)$instance['link_title'];
+		?>
+
+		<p><label for="bp-core-widget-title"><?php _e('Title:', 'buddypress'); ?> <input class="widefat" id="<?php echo $this->get_field_id( 'title' ); ?>" name="<?php echo $this->get_field_name( 'title' ); ?>" type="text" value="<?php echo esc_attr( $title ); ?>" style="width: 100%" /></label></p>
+
+		<p><label for="<?php echo $this->get_field_name('link_title') ?>"><input type="checkbox" name="<?php echo $this->get_field_name('link_title') ?>" value="1" <?php checked( $link_title ) ?> /> <?php _e( 'Link widget title to Members directory', 'buddypress' ) ?></label></p>
+
+		<p><label for="bp-core-widget-members-max"><?php _e('Max members to show:', 'buddypress'); ?> <input class="widefat" id="<?php echo $this->get_field_id( 'max_members' ); ?>" name="<?php echo $this->get_field_name( 'max_members' ); ?>" type="text" value="<?php echo esc_attr( $max_members ); ?>" style="width: 30%" /></label></p>
+
+		<p>
+			<label for="bp-core-widget-groups-default"><?php _e('Default members to show:', 'buddypress'); ?>
+			<select name="<?php echo $this->get_field_name( 'member_default' ) ?>">
+				<option value="newest" <?php if ( $member_default == 'newest' ) : ?>selected="selected"<?php endif; ?>><?php _e( 'Newest', 'buddypress' ) ?></option>
+				<option value="active" <?php if ( $member_default == 'active' ) : ?>selected="selected"<?php endif; ?>><?php _e( 'Active', 'buddypress' ) ?></option>
+				<option value="popular"  <?php if ( $member_default == 'popular' ) : ?>selected="selected"<?php endif; ?>><?php _e( 'Popular', 'buddypress' ) ?></option>
+			</select>
+			</label>
+		</p>
+
+	<?php
+	}
+}
+
+/*** WHO'S ONLINE WIDGET *****************/
+
+class BP_Core_Whos_Online_Widget extends WP_Widget {
+
+	/**
+	 * Constructor method.
+	 */
+	function __construct() {
+		$widget_ops = array(
+			'description' => __( 'Avatars of users who are currently online', 'buddypress' ),
+			'classname' => 'widget_bp_core_whos_online_widget buddypress widget',
+		);
+		parent::__construct( false, $name = _x( "(BuddyPress) Who's Online", 'widget name', 'buddypress' ), $widget_ops );
+	}
+
+	/**
+	 * Display the Who's Online widget.
+	 *
+	 * @see WP_Widget::widget() for description of parameters.
+	 *
+	 * @param array $args Widget arguments.
+	 * @param array $instance Widget settings, as saved by the user.
+	 */
+	function widget($args, $instance) {
+
+		extract( $args );
+
+		$title = apply_filters( 'widget_title', $instance['title'] );
+
+		echo $before_widget;
+		echo $before_title
+		   . $title
+		   . $after_title; ?>
+
+		<?php if ( bp_has_members( 'user_id=0&type=online&per_page=' . $instance['max_members'] . '&max=' . $instance['max_members'] . '&populate_extras=1' ) ) : ?>
+			<div class="avatar-block">
+				<?php while ( bp_members() ) : bp_the_member(); ?>
+					<div class="item-avatar">
+						<a href="<?php bp_member_permalink() ?>" title="<?php bp_member_name() ?>"><?php bp_member_avatar() ?></a>
+					</div>
+				<?php endwhile; ?>
+			</div>
+		<?php else: ?>
+
+			<div class="widget-error">
+				<?php _e( 'There are no users currently online', 'buddypress' ) ?>
+			</div>
+
+		<?php endif; ?>
+
+		<?php echo $after_widget; ?>
+	<?php
+	}
+
+	/**
+	 * Update the Who's Online widget options.
+	 *
+	 * @param array $new_instance The new instance options.
+	 * @param array $old_instance The old instance options.
+	 * @return array $instance The parsed options to be saved.
+	 */
+	function update( $new_instance, $old_instance ) {
+		$instance = $old_instance;
+		$instance['title'] = strip_tags( $new_instance['title'] );
+		$instance['max_members'] = strip_tags( $new_instance['max_members'] );
+
+		return $instance;
+	}
+
+	/**
+	 * Output the Who's Online widget options form.
+	 *
+	 * @param $instance Settings for this widget.
+	 */
+	function form( $instance ) {
+		$defaults = array(
+			'title' => __( "Who's Online", 'buddypress' ),
+			'max_members' => 15
+		);
+		$instance = wp_parse_args( (array) $instance, $defaults );
+
+		$title = strip_tags( $instance['title'] );
+		$max_members = strip_tags( $instance['max_members'] );
+		?>
+
+		<p><label for="bp-core-widget-title"><?php _e('Title:', 'buddypress'); ?> <input class="widefat" id="<?php echo $this->get_field_id( 'title' ); ?>" name="<?php echo $this->get_field_name( 'title' ); ?>" type="text" value="<?php echo esc_attr( $title ); ?>" style="width: 100%" /></label></p>
+
+		<p><label for="bp-core-widget-members-max"><?php _e('Max Members to show:', 'buddypress'); ?> <input class="widefat" id="<?php echo $this->get_field_id( 'max_members' ); ?>" name="<?php echo $this->get_field_name( 'max_members' ); ?>" type="text" value="<?php echo esc_attr( $max_members ); ?>" style="width: 30%" /></label></p>
+	<?php
+	}
+}
+
+/*** RECENTLY ACTIVE WIDGET *****************/
+
+class BP_Core_Recently_Active_Widget extends WP_Widget {
+
+	/**
+	 * Constructor method.
+	 */
+	function __construct() {
+		$widget_ops = array(
+			'description' => __( 'Avatars of recently active members', 'buddypress' ),
+			'classname' => 'widget_bp_core_recently_active_widget buddypress widget',
+		);
+		parent::__construct( false, $name = _x( '(BuddyPress) Recently Active Members', 'widget name', 'buddypress' ), $widget_ops );
+	}
+
+	/**
+	 * Display the Recently Active widget.
+	 *
+	 * @see WP_Widget::widget() for description of parameters.
+	 *
+	 * @param array $args Widget arguments.
+	 * @param array $instance Widget settings, as saved by the user.
+	 */
+	function widget( $args, $instance ) {
+
+		extract( $args );
+
+		$title = apply_filters( 'widget_title', $instance['title'] );
+
+		echo $before_widget;
+		echo $before_title
+		   . $title
+		   . $after_title; ?>
+
+		<?php if ( bp_has_members( 'user_id=0&type=active&per_page=' . $instance['max_members'] . '&max=' . $instance['max_members'] . '&populate_extras=1' ) ) : ?>
+			<div class="avatar-block">
+				<?php while ( bp_members() ) : bp_the_member(); ?>
+					<div class="item-avatar">
+						<a href="<?php bp_member_permalink() ?>" title="<?php bp_member_name() ?>"><?php bp_member_avatar() ?></a>
+					</div>
+				<?php endwhile; ?>
+			</div>
+		<?php else: ?>
+
+			<div class="widget-error">
+				<?php _e( 'There are no recently active members', 'buddypress' ) ?>
+			</div>
+
+		<?php endif; ?>
+
+		<?php echo $after_widget; ?>
+	<?php
+	}
+
+	/**
+	 * Update the Recently Active widget options.
+	 *
+	 * @param array $new_instance The new instance options.
+	 * @param array $old_instance The old instance options.
+	 * @return array $instance The parsed options to be saved.
+	 */
+	function update( $new_instance, $old_instance ) {
+		$instance = $old_instance;
+		$instance['title'] = strip_tags( $new_instance['title'] );
+		$instance['max_members'] = strip_tags( $new_instance['max_members'] );
+
+		return $instance;
+	}
+
+	/**
+	 * Output the Recently Active widget options form.
+	 *
+	 * @param $instance Settings for this widget.
+	 */
+	function form( $instance ) {
+		$defaults = array(
+			'title' => __( 'Recently Active Members', 'buddypress' ),
+			'max_members' => 15
+		);
+		$instance = wp_parse_args( (array) $instance, $defaults );
+
+		$title = strip_tags( $instance['title'] );
+		$max_members = strip_tags( $instance['max_members'] );
+		?>
+
+		<p><label for="bp-core-widget-members-title"><?php _e('Title:', 'buddypress'); ?> <input class="widefat" id="<?php echo $this->get_field_id( 'title' ); ?>" name="<?php echo $this->get_field_name( 'title' ); ?>" type="text" value="<?php echo esc_attr( $title ); ?>" style="width: 100%" /></label></p>
+
+		<p><label for="bp-core-widget-members-max"><?php _e('Max Members to show:', 'buddypress'); ?> <input class="widefat" id="<?php echo $this->get_field_id( 'max_members' ); ?>" name="<?php echo $this->get_field_name( 'max_members' ); ?>" type="text" value="<?php echo esc_attr( $max_members ); ?>" style="width: 30%" /></label></p>
+	<?php
+	}
+}
+
+/**
+ * AJAX request handler for Members widgets.
+ */
+function bp_core_ajax_widget_members() {
+
+	check_ajax_referer( 'bp_core_widget_members' );
+
+	switch ( $_POST['filter'] ) {
+		case 'newest-members':
+			$type = 'newest';
+			break;
+
+		case 'recently-active-members':
+			$type = 'active';
+			break;
+
+		case 'popular-members':
+			if ( bp_is_active( 'friends' ) )
+				$type = 'popular';
+			else
+				$type = 'active';
+
+			break;
+	}
+
+	if ( bp_has_members( 'user_id=0&type=' . $type . '&per_page=' . $_POST['max-members'] . '&max=' . $_POST['max-members'] . '&populate_extras=1' ) ) : ?>
+		<?php echo '0[[SPLIT]]'; // return valid result. TODO: remove this. ?>
+		<?php while ( bp_members() ) : bp_the_member(); ?>
+			<li class="vcard">
+				<div class="item-avatar">
+					<a href="<?php bp_member_permalink() ?>"><?php bp_member_avatar() ?></a>
+				</div>
+
+				<div class="item">
+					<div class="item-title fn"><a href="<?php bp_member_permalink() ?>" title="<?php bp_member_name() ?>"><?php bp_member_name() ?></a></div>
+					<?php if ( 'active' == $type ) : ?>
+						<div class="item-meta"><span class="activity"><?php bp_member_last_active() ?></span></div>
+					<?php elseif ( 'newest' == $type ) : ?>
+						<div class="item-meta"><span class="activity"><?php bp_member_registered() ?></span></div>
+					<?php elseif ( bp_is_active( 'friends' ) ) : ?>
+						<div class="item-meta"><span class="activity"><?php bp_member_total_friend_count() ?></span></div>
+					<?php endif; ?>
+				</div>
+			</li>
+		<?php endwhile; ?>
+
+	<?php else: ?>
+		<?php echo "-1[[SPLIT]]<li>"; ?>
+		<?php _e( 'There were no members found, please try another filter.', 'buddypress' ) ?>
+		<?php echo "</li>"; ?>
+	<?php endif;
+}
+add_action( 'wp_ajax_widget_members', 'bp_core_ajax_widget_members' );
+add_action( 'wp_ajax_nopriv_widget_members', 'bp_core_ajax_widget_members' );
Index: /tags/1.9/bp-core/bp-core-wpabstraction.php
===================================================================
--- /tags/1.9/bp-core/bp-core-wpabstraction.php	(revision 7684)
+++ /tags/1.9/bp-core/bp-core-wpabstraction.php	(revision 7684)
@@ -0,0 +1,210 @@
+<?php
+/**
+ * WordPress Abstraction.
+ *
+ * The functions within this file will detect the version of WordPress you are
+ * running and will alter the environment so BuddyPress can run regardless.
+ *
+ * The code below mostly contains function mappings. This file is subject to
+ * change at any time.
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/**
+ * Parse the WordPress core version number into the major release.
+ *
+ * @since BuddyPress (1.5.2)
+ *
+ * @global string $wp_version
+ * @return string $wp_version
+ */
+function bp_get_major_wp_version() {
+	global $wp_version;
+
+	return (float) $wp_version;
+}
+
+/**
+ * Only add MS-specific abstraction functions if WordPress is not in multisite mode
+ */
+if ( !is_multisite() ) {
+	global $wpdb;
+
+	$wpdb->base_prefix = $wpdb->prefix;
+	$wpdb->blogid      = BP_ROOT_BLOG;
+
+	if ( !function_exists( 'get_blog_option' ) ) {
+		/**
+		 * @see get_blog_option()
+		 */
+		function get_blog_option( $blog_id, $option_name, $default = false ) {
+			return get_option( $option_name, $default );
+		}
+	}
+
+	if ( !function_exists( 'update_blog_option' ) ) {
+		/**
+		 * @see update_blog_option()
+		 */
+		function update_blog_option( $blog_id, $option_name, $value ) {
+			return update_option( $option_name, $value );
+		}
+	}
+
+	if ( !function_exists( 'delete_blog_option' ) ) {
+		/**
+		 * @see delete_blog_option()
+		 */
+		function delete_blog_option( $blog_id, $option_name ) {
+			return delete_option( $option_name );
+		}
+	}
+
+	if ( !function_exists( 'switch_to_blog' ) ) {
+		/**
+		 * @see switch_to_blog()
+		 */
+		function switch_to_blog() {
+			return bp_get_root_blog_id();
+		}
+	}
+
+	if ( !function_exists( 'restore_current_blog' ) ) {
+		/**
+		 * @see restore_current_blog()
+		 */
+		function restore_current_blog() {
+			return bp_get_root_blog_id();
+		}
+	}
+
+	if ( !function_exists( 'get_blogs_of_user' ) ) {
+		/**
+		 * @see get_blogs_of_user()
+		 */
+		function get_blogs_of_user() {
+			return false;
+		}
+	}
+
+	if ( !function_exists( 'update_blog_status' ) ) {
+		/**
+		 * @see update_blog_status()
+		 */
+		function update_blog_status() {
+			return true;
+		}
+	}
+
+	if ( !function_exists( 'is_subdomain_install' ) ) {
+		/**
+		 * @see is_subdomain_install()
+		 */
+		function is_subdomain_install() {
+			if ( ( defined( 'VHOST' ) && 'yes' == VHOST ) || ( defined( 'SUBDOMAIN_INSTALL' ) && SUBDOMAIN_INSTALL ) )
+				return true;
+
+			return false;
+		}
+	}
+}
+
+/**
+ * Get SQL chunk for filtering spam users from member queries.
+ *
+ * @internal
+ * @todo Why is this function defined in this file?
+ *
+ * @param string $prefix Global table prefix.
+ * @return string SQL chunk.
+ */
+function bp_core_get_status_sql( $prefix = false ) {
+	if ( !is_multisite() )
+		return "{$prefix}user_status = 0";
+	else
+		return "{$prefix}spam = 0 AND {$prefix}deleted = 0 AND {$prefix}user_status = 0";
+}
+
+/**
+ * Multibyte encoding fallback functions
+ *
+ * The PHP multibyte encoding extension is not enabled by default. In cases where it is not enabled,
+ * these functions provide a fallback.
+ *
+ * Borrowed from MediaWiki, under the GPLv2. Thanks!
+ */
+if ( !function_exists( 'mb_strlen' ) ) {
+	/**
+	 * Fallback implementation of mb_strlen(), hardcoded to UTF-8.
+	 *
+	 * @param string $str String to be measured.
+	 * @param string $enc Optional. Encoding type. Ignored.
+	 * @return int String length.
+	 */
+	function mb_strlen( $str, $enc = '' ) {
+		$counts = count_chars( $str );
+		$total = 0;
+
+		// Count ASCII bytes
+		for( $i = 0; $i < 0x80; $i++ ) {
+			$total += $counts[$i];
+		}
+
+		// Count multibyte sequence heads
+		for( $i = 0xc0; $i < 0xff; $i++ ) {
+			$total += $counts[$i];
+		}
+		return $total;
+	}
+}
+
+if ( !function_exists( 'mb_strpos' ) ) {
+	/**
+	 * Fallback implementation of mb_strpos(), hardcoded to UTF-8.
+	 *
+	 * @param string $haystack String to search in.
+	 * @param string $needle String to search for.
+	 * @param int $offset Optional. Start position for the search. Default: 0.
+	 * @param string $enc Optional. Encoding type. Ignored.
+	 * @return int|bool Position of needle in haystack if found, else false.
+	 */
+	function mb_strpos( $haystack, $needle, $offset = 0, $encoding = '' ) {
+		$needle = preg_quote( $needle, '/' );
+
+		$ar = array();
+		preg_match( '/' . $needle . '/u', $haystack, $ar, PREG_OFFSET_CAPTURE, $offset );
+
+		if( isset( $ar[0][1] ) ) {
+			return $ar[0][1];
+		} else {
+			return false;
+		}
+	}
+}
+
+if ( !function_exists( 'mb_strrpos' ) ) {
+	/**
+	 * Fallback implementation of mb_strrpos(), hardcoded to UTF-8.
+	 *
+	 * @param string $haystack String to search in.
+	 * @param string $needle String to search for.
+	 * @param int $offset Optional. Start position for the search. Default: 0.
+	 * @param string $enc Optional. Encoding type. Ignored.
+	 * @return int Position of last needle in haystack if found, else false.
+	 */
+	function mb_strrpos( $haystack, $needle, $offset = 0, $encoding = '' ) {
+		$needle = preg_quote( $needle, '/' );
+
+		$ar = array();
+		preg_match_all( '/' . $needle . '/u', $haystack, $ar, PREG_OFFSET_CAPTURE, $offset );
+
+		if( isset( $ar[0] ) && count( $ar[0] ) > 0 &&
+			isset( $ar[0][count( $ar[0] ) - 1][1] ) ) {
+			return $ar[0][count( $ar[0] ) - 1][1];
+		} else {
+			return false;
+		}
+	}
+}
Index: /tags/1.9/bp-core/css/admin-bar-rtl.css
===================================================================
--- /tags/1.9/bp-core/css/admin-bar-rtl.css	(revision 7684)
+++ /tags/1.9/bp-core/css/admin-bar-rtl.css	(revision 7684)
@@ -0,0 +1,27 @@
+#wpadminbar .quicklinks li#wp-admin-bar-my-account ul,
+#wpadminbar .quicklinks li#wp-admin-bar-my-account-with-avatar ul {
+	left: auto;
+	right: 0;
+}
+#wpadminbar .quicklinks li#wp-admin-bar-user-admin-with-avatar > a img,
+#wpadminbar .quicklinks li#wp-admin-bar-group-admin-with-avatar > a img {
+	margin: -2px -5px 0 23px;
+}
+#wpadminbar .quicklinks li#wp-admin-bar-user-admin-with-avatar ul,
+#wpadminbar .quicklinks li#wp-admin-bar-group-admin-with-avatar ul {
+	left: auto;
+	right: 30px;
+}
+#wpadminbar .quicklinks li#wp-admin-bar-user-admin-with-avatar ul ul,
+#wpadminbar .quicklinks li#wp-admin-bar-group-admin-with-avatar ul ul {
+	left: auto;
+ 	right: 0;
+}
+#wpadminbar .quicklinks li#wp-admin-bar-group-admin-with-avatar ul {
+	left: auto;
+ 	right: 0;
+}
+#wpadminbar .quicklinks li#wp-admin-bar-group-admin-with-avatar ul ul {
+	left: auto;
+ 	right: 0;
+}
Index: /tags/1.9/bp-core/css/admin-bar-rtl.min.css
===================================================================
--- /tags/1.9/bp-core/css/admin-bar-rtl.min.css	(revision 7684)
+++ /tags/1.9/bp-core/css/admin-bar-rtl.min.css	(revision 7684)
@@ -0,0 +1,1 @@
+#wpadminbar .quicklinks li#wp-admin-bar-my-account ul,#wpadminbar .quicklinks li#wp-admin-bar-my-account-with-avatar ul{left:auto;right:0}#wpadminbar .quicklinks li#wp-admin-bar-user-admin-with-avatar>a img,#wpadminbar .quicklinks li#wp-admin-bar-group-admin-with-avatar>a img{margin:-2px -5px 0 23px}#wpadminbar .quicklinks li#wp-admin-bar-user-admin-with-avatar ul,#wpadminbar .quicklinks li#wp-admin-bar-group-admin-with-avatar ul{left:auto;right:30px}#wpadminbar .quicklinks li#wp-admin-bar-user-admin-with-avatar ul ul,#wpadminbar .quicklinks li#wp-admin-bar-group-admin-with-avatar ul ul{left:auto;right:0}#wpadminbar .quicklinks li#wp-admin-bar-group-admin-with-avatar ul{left:auto;right:0}#wpadminbar .quicklinks li#wp-admin-bar-group-admin-with-avatar ul ul{left:auto;right:0}
Index: /tags/1.9/bp-core/css/admin-bar.css
===================================================================
--- /tags/1.9/bp-core/css/admin-bar.css	(revision 7684)
+++ /tags/1.9/bp-core/css/admin-bar.css	(revision 7684)
@@ -0,0 +1,58 @@
+/* Displayed User */
+#wpadminbar .quicklinks li#wp-admin-bar-user-admin-with-avatar > a img,
+#wpadminbar .quicklinks li#wp-admin-bar-group-admin-with-avatar > a img {
+	width: 16px;
+	height: 16px;
+	display: inline;
+	border: 1px solid #999;
+	vertical-align: middle;
+	margin: -2px 10px 0 -5px;
+	padding: 0;
+	background: #eee;
+	float: none;
+}
+
+/* Displayed Group */
+#wpadminbar .quicklinks li#wp-admin-bar-group-admin-with-avatar ul {
+	left: 0;
+}
+#wpadminbar .quicklinks li#wp-admin-bar-group-admin-with-avatar ul ul {
+ 	left: 0;
+}
+
+/* Notifications */
+#wpadminbar .quicklinks li#wp-admin-bar-my-account a span.count,
+#wpadminbar .quicklinks li#wp-admin-bar-my-account-with-avatar a span.count,
+#wpadminbar .quicklinks li#wp-admin-bar-bp-notifications #ab-pending-notifications {
+	background: #21759B;
+	color: #fff;
+	text-shadow: none;
+	display: inline;
+	padding: 2px 5px;
+	font-size: 10px;
+	font-weight: bold;
+	-moz-border-radius: 10px;
+	-khtml-border-radius: 10px;
+	-webkit-border-radius: 10px;
+	border-radius: 10px;
+}
+
+#wpadminbar .quicklinks li#wp-admin-bar-bp-notifications #ab-pending-notifications {
+	background: #ddd;
+	color: #333;
+	margin: 0
+}
+
+#wpadminbar .quicklinks li#wp-admin-bar-bp-notifications #ab-pending-notifications.alert {
+	background-color: #1fb3dd;
+	color: #fff;
+}
+
+#wpadminbar .quicklinks li#wp-admin-bar-bp-notifications > a {
+	padding: 0 .5em;
+}
+
+#wp-admin-bar-user-info img.avatar {
+	height: 64px;
+	width: 64px;
+}
Index: /tags/1.9/bp-core/css/admin-bar.min.css
===================================================================
--- /tags/1.9/bp-core/css/admin-bar.min.css	(revision 7684)
+++ /tags/1.9/bp-core/css/admin-bar.min.css	(revision 7684)
@@ -0,0 +1,1 @@
+#wpadminbar .quicklinks li#wp-admin-bar-user-admin-with-avatar>a img,#wpadminbar .quicklinks li#wp-admin-bar-group-admin-with-avatar>a img{width:16px;height:16px;display:inline;border:1px solid #999;vertical-align:middle;margin:-2px 10px 0 -5px;padding:0;background:#eee;float:none}#wpadminbar .quicklinks li#wp-admin-bar-group-admin-with-avatar ul{left:0}#wpadminbar .quicklinks li#wp-admin-bar-group-admin-with-avatar ul ul{left:0}#wpadminbar .quicklinks li#wp-admin-bar-my-account a span.count,#wpadminbar .quicklinks li#wp-admin-bar-my-account-with-avatar a span.count,#wpadminbar .quicklinks li#wp-admin-bar-bp-notifications #ab-pending-notifications{background:#21759b;color:#fff;text-shadow:none;display:inline;padding:2px 5px;font-size:10px;font-weight:bold;-moz-border-radius:10px;-khtml-border-radius:10px;-webkit-border-radius:10px;border-radius:10px}#wpadminbar .quicklinks li#wp-admin-bar-bp-notifications #ab-pending-notifications{background:#ddd;color:#333;margin:0}#wpadminbar .quicklinks li#wp-admin-bar-bp-notifications #ab-pending-notifications.alert{background-color:#1fb3dd;color:#fff}#wpadminbar .quicklinks li#wp-admin-bar-bp-notifications>a{padding:0 .5em}#wp-admin-bar-user-info img.avatar{height:64px;width:64px}
Index: /tags/1.9/bp-core/css/buddybar-rtl.css
===================================================================
--- /tags/1.9/bp-core/css/buddybar-rtl.css	(revision 7684)
+++ /tags/1.9/bp-core/css/buddybar-rtl.css	(revision 7684)
@@ -0,0 +1,77 @@
+#wp-admin-bar {
+	right: 0;
+	left: auto;
+}
+#wp-admin-bar div#admin-bar-logo {
+	right: 10px;
+	left: auto;
+}
+#wp-admin-bar li {
+	text-align: right;
+}
+#wp-admin-bar li.no-arrow a {
+	padding-left: 15px;
+	padding-right: 0;
+}
+#admin-bar-logo {
+	float: right;
+}
+
+#wp-admin-bar ul li {/* all list items */
+	float: right;
+	background: url('../images/admin-menu-arrow.gif') 12% 53% no-repeat;
+	padding-left: 11px;
+	padding-right: 0;
+}
+#wp-admin-bar ul li.no-arrow {
+	padding-left: 0;
+}
+#wp-admin-bar ul li.align-right {
+	left: 0;
+	right: auto;
+}
+
+/* second-level lists */
+#wp-admin-bar ul li ul {
+	right: -999em;
+	left: auto;
+	margin-right: 0;
+}
+#wp-admin-bar ul li ul li {
+	float: right;
+}
+
+/* third-and-above-level lists */
+#wp-admin-bar ul li ul ul {
+	margin: -25px 184px 0 0;
+}
+#wp-admin-bar ul li:hover ul,
+#wp-admin-bar ul li li:hover ul,
+#wp-admin-bar ul li.sfhover ul,
+#wp-admin-bar ul li ul li.sfhover ul {/* lists nested under hovered list items */
+	right: auto;
+}
+#wp-admin-bar ul li.align-right:hover ul {
+	left: 0;
+	right: auto;
+}
+#wp-admin-bar ul li:hover ul ul,
+#wp-admin-bar li.sfhover ul li ul {
+	right: -999em;
+	left: auto;
+}
+
+/* Menu item css */
+#wp-admin-bar img.avatar {
+	float: right;
+	margin-left: 8px;
+	margin-right: 0;
+}
+#wp-admin-bar span.activity {
+	margin-right: 34px;
+	margin-left: 0;
+}
+#wp-admin-bar ul li#bp-adminbar-notifications-menu a span {
+	margin-right: 2px;
+	margin-left: 0;
+}
Index: /tags/1.9/bp-core/css/buddybar-rtl.min.css
===================================================================
--- /tags/1.9/bp-core/css/buddybar-rtl.min.css	(revision 7684)
+++ /tags/1.9/bp-core/css/buddybar-rtl.min.css	(revision 7684)
@@ -0,0 +1,1 @@
+#wp-admin-bar{right:0;left:auto}#wp-admin-bar div#admin-bar-logo{right:10px;left:auto}#wp-admin-bar li{text-align:right}#wp-admin-bar li.no-arrow a{padding-left:15px;padding-right:0}#admin-bar-logo{float:right}#wp-admin-bar ul li{float:right;background:url('../images/admin-menu-arrow.gif') 12% 53% no-repeat;padding-left:11px;padding-right:0}#wp-admin-bar ul li.no-arrow{padding-left:0}#wp-admin-bar ul li.align-right{left:0;right:auto}#wp-admin-bar ul li ul{right:-999em;left:auto;margin-right:0}#wp-admin-bar ul li ul li{float:right}#wp-admin-bar ul li ul ul{margin:-25px 184px 0 0}#wp-admin-bar ul li:hover ul,#wp-admin-bar ul li li:hover ul,#wp-admin-bar ul li.sfhover ul,#wp-admin-bar ul li ul li.sfhover ul{right:auto}#wp-admin-bar ul li.align-right:hover ul{left:0;right:auto}#wp-admin-bar ul li:hover ul ul,#wp-admin-bar li.sfhover ul li ul{right:-999em;left:auto}#wp-admin-bar img.avatar{float:right;margin-left:8px;margin-right:0}#wp-admin-bar span.activity{margin-right:34px;margin-left:0}#wp-admin-bar ul li#bp-adminbar-notifications-menu a span{margin-right:2px;margin-left:0}
Index: /tags/1.9/bp-core/css/buddybar.css
===================================================================
--- /tags/1.9/bp-core/css/buddybar.css	(revision 7684)
+++ /tags/1.9/bp-core/css/buddybar.css	(revision 7684)
@@ -0,0 +1,203 @@
+body:not(.wp-admin) {
+	padding-top: 25px !important;
+}
+#wp-admin-bar {
+	position: fixed;
+	top: 0;
+	left: 0;
+	height: 25px;
+	font-size: 11px;
+	width: 100%;
+	z-index: 9999;
+}
+#wp-admin-bar .padder {
+	position: relative;
+	padding: 0;
+	width: 100%;
+	margin: 0 auto;
+	background: url('../images/60pc_black.png');
+	height: 25px;
+}
+body#bp-default #wp-admin-bar .padder {
+	max-width: 1250px;
+}
+#wp-admin-bar * {
+	z-index: 999;
+}
+#wp-admin-bar div#admin-bar-logo {
+	position: absolute;
+	top: 5px;
+	left: 10px;
+}
+#wp-admin-bar a img {
+	border: none;
+}
+#wp-admin-bar li {
+	list-style: none;
+	margin: 0;
+	padding: 0;
+	line-height: 100%;
+	text-align: left;
+}
+#wp-admin-bar li a {
+	padding: 7px 15px 7px 15px;
+	color: #eee;
+	text-decoration: none;
+	font-size: 11px;
+}
+#wp-admin-bar li.alt {
+	border: none;
+}
+#wp-admin-bar li.no-arrow a {
+	padding-right: 15px;
+}
+#wp-admin-bar ul li ul li a span {
+	display: none;
+}
+#wp-admin-bar li:hover,
+#wp-admin-bar li.hover {
+	position: static;
+}
+#admin-bar-logo {
+	float: left;
+	font-weight: bold;
+	font-size: 11px;
+	padding: 5px 8px;
+	margin: 0;
+	text-decoration: none;
+	color: #fff;
+}
+body#bp-default #admin-bar-logo {
+	padding: 2px 8px;
+}
+
+/* all lists */
+#wp-admin-bar ul {
+	margin: 0;
+	list-style: none;
+	line-height: 1;
+	cursor: pointer;
+	height: auto;
+	padding: 0;
+}
+
+/* all list items */
+#wp-admin-bar ul li {
+	padding: 0;
+	float: left;
+	position: relative;
+	background: url('../images/admin-menu-arrow.gif') 88% 53% no-repeat;
+	padding-right: 11px;
+}
+#wp-admin-bar ul li.no-arrow {
+	background: none;
+	padding-right: 0;
+}
+#wp-admin-bar ul li ul li {
+	background-image: none;
+}
+#wp-admin-bar ul li.align-right {
+	position: absolute;
+	right: 0;
+}
+#wp-admin-bar ul li a {
+	display: block;
+}
+#wp-admin-bar ul.main-nav li:hover,
+#wp-admin-bar ul.main-nav li.sfhover,
+#wp-admin-bar ul.main-nav li ul li.sfhover {
+	background-color: #333;
+}
+
+/* second-level lists */
+#wp-admin-bar ul li ul {
+	position: absolute;
+	width: 185px;
+	left: -999em;
+	margin-left: 0;
+	background: #333;
+	border: 1px solid #222;
+	-moz-box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
+	-webkit-box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
+	-moz-border-radius: 3px;
+	-webkit-border-radius: 3px;
+	-moz-border-radius-topleft: 0;
+	-webkit-border-top-left-radius: 0;
+	-moz-border-radius-topright: 0;
+	-webkit-border-top-right-radius: 0;
+}
+#wp-admin-bar ul li > ul {
+	border-top: none;
+}
+#wp-admin-bar ul li ul a {
+	color: #eee;
+}
+#wp-admin-bar ul li ul li {
+	float: left;
+	width: 174px;
+	margin: 0;
+}
+#wp-admin-bar ul li ul li:hover a {
+	color: #fff;
+}
+#wp-admin-bar ul li div.admin-bar-clear {
+	clear: both;
+}
+#wp-admin-bar ul.main-nav li ul li:hover,
+#wp-admin-bar ul.main-nav li ul li.sfhover,
+#wp-admin-bar ul.main-nav li ul li.sfhover {
+	background-color: #222;
+}
+
+/* third-and-above-level lists */
+#wp-admin-bar ul li ul ul {
+	margin: -25px 0 0 184px;
+	-moz-border-radius: 3px;
+	-webkit-border-radius: 3px;
+}
+#wp-admin-bar ul li ul li:hover ul li a {
+	color: #eee;
+}
+#wp-admin-bar ul li ul li ul li:hover a {
+	color: #fff;
+}
+#wp-admin-bar ul li:hover ul,
+#wp-admin-bar ul li ul li:hover ul,
+#wp-admin-bar ul li.sfhover ul,
+#wp-admin-bar ul li ul li.sfhover ul {
+	left: auto;
+}
+#wp-admin-bar ul li.align-right:hover ul {
+	right: 0;
+}
+#wp-admin-bar ul li:hover ul ul,
+#wp-admin-bar li.sfhover ul li ul {
+	left: -999em;
+}
+
+/* Menu item css */
+#wp-admin-bar img.avatar {
+	float: left;
+	margin-right: 8px;
+}
+#wp-admin-bar span.activity {
+	display: block;
+	margin-left: 34px;
+	padding: 0;
+}
+#wp-admin-bar ul.author-list li a {
+	height: 17px;
+}
+#wp-admin-bar ul li#bp-adminbar-notifications-menu a span {
+	padding: 0 6px;
+	margin-left: 2px;
+	background: #fff;
+	color: #000;
+	-moz-border-radius: 3px;
+	-webkit-border-radius: 3px;
+	border-radius: 3px;
+}
+#wp-admin-bar-user-info img.avatar { 
+	height: 64px; 
+	width: 64px; 
+}
Index: /tags/1.9/bp-core/css/buddybar.min.css
===================================================================
--- /tags/1.9/bp-core/css/buddybar.min.css	(revision 7684)
+++ /tags/1.9/bp-core/css/buddybar.min.css	(revision 7684)
@@ -0,0 +1,1 @@
+body:not(.wp-admin){padding-top:25px!important}#wp-admin-bar{position:fixed;top:0;left:0;height:25px;font-size:11px;width:100%;z-index:9999}#wp-admin-bar .padder{position:relative;padding:0;width:100%;margin:0 auto;background:url('../images/60pc_black.png');height:25px}body#bp-default #wp-admin-bar .padder{max-width:1250px}#wp-admin-bar *{z-index:999}#wp-admin-bar div#admin-bar-logo{position:absolute;top:5px;left:10px}#wp-admin-bar a img{border:0}#wp-admin-bar li{list-style:none;margin:0;padding:0;line-height:100%;text-align:left}#wp-admin-bar li a{padding:7px 15px 7px 15px;color:#eee;text-decoration:none;font-size:11px}#wp-admin-bar li.alt{border:0}#wp-admin-bar li.no-arrow a{padding-right:15px}#wp-admin-bar ul li ul li a span{display:none}#wp-admin-bar li:hover,#wp-admin-bar li.hover{position:static}#admin-bar-logo{float:left;font-weight:bold;font-size:11px;padding:5px 8px;margin:0;text-decoration:none;color:#fff}body#bp-default #admin-bar-logo{padding:2px 8px}#wp-admin-bar ul{margin:0;list-style:none;line-height:1;cursor:pointer;height:auto;padding:0}#wp-admin-bar ul li{padding:0;float:left;position:relative;background:url('../images/admin-menu-arrow.gif') 88% 53% no-repeat;padding-right:11px}#wp-admin-bar ul li.no-arrow{background:0;padding-right:0}#wp-admin-bar ul li ul li{background-image:none}#wp-admin-bar ul li.align-right{position:absolute;right:0}#wp-admin-bar ul li a{display:block}#wp-admin-bar ul.main-nav li:hover,#wp-admin-bar ul.main-nav li.sfhover,#wp-admin-bar ul.main-nav li ul li.sfhover{background-color:#333}#wp-admin-bar ul li ul{position:absolute;width:185px;left:-999em;margin-left:0;background:#333;border:1px solid #222;-moz-box-shadow:0 4px 8px rgba(0,0,0,0.1);-webkit-box-shadow:0 4px 8px rgba(0,0,0,0.1);-moz-border-radius:3px;-webkit-border-radius:3px;-moz-border-radius-topleft:0;-webkit-border-top-left-radius:0;-moz-border-radius-topright:0;-webkit-border-top-right-radius:0}#wp-admin-bar ul li>ul{border-top:0}#wp-admin-bar ul li ul a{color:#eee}#wp-admin-bar ul li ul li{float:left;width:174px;margin:0}#wp-admin-bar ul li ul li:hover a{color:#fff}#wp-admin-bar ul li div.admin-bar-clear{clear:both}#wp-admin-bar ul.main-nav li ul li:hover,#wp-admin-bar ul.main-nav li ul li.sfhover,#wp-admin-bar ul.main-nav li ul li.sfhover{background-color:#222}#wp-admin-bar ul li ul ul{margin:-25px 0 0 184px;-moz-border-radius:3px;-webkit-border-radius:3px}#wp-admin-bar ul li ul li:hover ul li a{color:#eee}#wp-admin-bar ul li ul li ul li:hover a{color:#fff}#wp-admin-bar ul li:hover ul,#wp-admin-bar ul li ul li:hover ul,#wp-admin-bar ul li.sfhover ul,#wp-admin-bar ul li ul li.sfhover ul{left:auto}#wp-admin-bar ul li.align-right:hover ul{right:0}#wp-admin-bar ul li:hover ul ul,#wp-admin-bar li.sfhover ul li ul{left:-999em}#wp-admin-bar img.avatar{float:left;margin-right:8px}#wp-admin-bar span.activity{display:block;margin-left:34px;padding:0}#wp-admin-bar ul.author-list li a{height:17px}#wp-admin-bar ul li#bp-adminbar-notifications-menu a span{padding:0 6px;margin-left:2px;background:#fff;color:#000;-moz-border-radius:3px;-webkit-border-radius:3px;border-radius:3px}#wp-admin-bar-user-info img.avatar{height:64px;width:64px}
Index: /tags/1.9/bp-core/deprecated/1.2.php
===================================================================
--- /tags/1.9/bp-core/deprecated/1.2.php	(revision 7684)
+++ /tags/1.9/bp-core/deprecated/1.2.php	(revision 7684)
@@ -0,0 +1,54 @@
+<?php
+/**
+ * Deprecated Functions
+ *
+ * @package BuddyPress
+ * @subpackage Core
+ */
+
+/**
+ * Retrieve sitewide activity
+ *
+ * You should use bp_activity_get() instead
+ *
+ * @since BuddyPress (1.0)
+ * @deprecated BuddyPress (1.2)
+ *
+ * @param array $args
+ *
+ * @uses BP_Activity_Activity::get() {@link BP_Activity_Activity}
+ *
+ * @return object $activity The activity/activities object
+ */
+function bp_activity_get_sitewide( $args = '' ) {
+	_deprecated_function( __FUNCTION__, '1.2', 'bp_activity_get()' );
+
+	$defaults = array(
+		'max' => false, // Maximum number of results to return
+		'page' => 1, // page 1 without a per_page will result in no pagination.
+		'per_page' => false, // results per page
+		'sort' => 'DESC', // sort ASC or DESC
+		'display_comments' => false, // false for no comments. 'stream' for within stream display, 'threaded' for below each activity item
+
+		'search_terms' => false, // Pass search terms as a string
+		'show_hidden' => false, // Show activity items that are hidden site-wide?
+
+		/**
+		 * Pass filters as an array:
+		 * array(
+		 * 	'user_id' => false, // user_id to filter on
+		 *	'object' => false, // object to filter on e.g. groups, profile, status, friends
+		 *	'action' => false, // action to filter on e.g. new_wire_post, new_forum_post, profile_updated
+		 *	'primary_id' => false, // object ID to filter on e.g. a group_id or forum_id or blog_id etc.
+		 *	'secondary_id' => false, // secondary object ID to filter on e.g. a post_id
+		 * );
+		 */
+		'filter' => array()
+	);
+
+	$args = wp_parse_args( $args, $defaults );
+
+	return apply_filters( 'bp_activity_get_sitewide', BP_Activity_Activity::get( $args ), $r );
+}
+
+
Index: /tags/1.9/bp-core/deprecated/1.5.php
===================================================================
--- /tags/1.9/bp-core/deprecated/1.5.php	(revision 7684)
+++ /tags/1.9/bp-core/deprecated/1.5.php	(revision 7684)
@@ -0,0 +1,707 @@
+<?php
+/**
+ * Deprecated Functions
+ *
+ * @package BuddyPress
+ * @subpackage Core
+ * @deprecated Since 1.5
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/** Loader ********************************************************************/
+
+/**
+ * @deprecated BuddyPress (1.5)
+ */
+function bp_setup_root_components() {
+	do_action( 'bp_setup_root_components' );
+}
+add_action( 'bp_init', 'bp_setup_root_components', 6 );
+
+/** WP Abstraction ************************************************************/
+
+/**
+ * bp_core_is_multisite()
+ *
+ * This function originally served as a wrapper when WordPress and WordPress MU were separate entities.
+ * Use is_multisite() instead.
+ *
+ * @deprecated BuddyPress (1.5)
+ * @deprecated Use is_multisite()
+ */
+function bp_core_is_multisite() {
+	_deprecated_function( __FUNCTION__, '1.5', 'is_multisite()' );
+	return is_multisite();
+}
+
+/**
+ * bp_core_is_main_site
+ *
+ * Checks if current blog is root blog of site. Deprecated in 1.5.
+ *
+ * @deprecated BuddyPress (1.5)
+ * @deprecated Use is_main_site()
+ * @package BuddyPress
+ * @param int $blog_id optional blog id to test (default current blog)
+ * @return bool True if not multisite or $blog_id is main site
+ * @since BuddyPress (1.2.6)
+ */
+function bp_core_is_main_site( $blog_id = '' ) {
+	_deprecated_function( __FUNCTION__, '1.5', 'is_main_site()' );
+	return is_main_site( $blog_id );
+}
+
+/**
+ * WPMU version of is_super_admin()
+ *
+ * @deprecated BuddyPress (1.5)
+ * @deprecated Use is_super_admin()
+ * @param int $user_id Optional. Defaults to logged-in user
+ * @return bool True if is super admin
+ */
+if ( !function_exists( 'is_site_admin' ) ) {
+	function is_site_admin( $user_id = false ) {
+		_deprecated_function( __FUNCTION__, '1.5', 'is_super_admin()' );
+		return is_super_admin( $user_id );
+	}
+}
+
+/** Admin ******************************************************************/
+
+/**
+ * In BuddyPress 1.1 - 1.2.x, this function provided a better version of add_menu_page()
+ * that allowed positioning of menus. Deprecated in 1.5 in favour of a WP core function.
+ *
+ * @deprecated BuddyPress (1.5)
+ * @deprecated Use add_menu_page().
+ * @since BuddyPress (1.1)
+ */
+function bp_core_add_admin_menu_page( $args = '' ) {
+	global $_registered_pages, $admin_page_hooks, $menu;
+
+	_deprecated_function( __FUNCTION__, '1.5', 'Use add_menu_page()' );
+
+	$defaults = array(
+		'access_level' => 2,
+		'file'         => false,
+		'function'     => false,
+		'icon_url'     => false,
+		'menu_title'   => '',
+		'page_title'   => '',
+		'position'     => 100
+	);
+
+	$r = wp_parse_args( $args, $defaults );
+	extract( $r, EXTR_SKIP );
+
+	$file     = plugin_basename( $file );
+	$hookname = get_plugin_page_hookname( $file, '' );
+
+	$admin_page_hooks[$file] = sanitize_title( $menu_title );
+
+	if ( !empty( $function ) && !empty ( $hookname ) )
+		add_action( $hookname, $function );
+
+	if ( empty( $icon_url ) )
+		$icon_url = 'images/generic.png';
+	elseif ( is_ssl() && 0 === strpos( $icon_url, 'http://' ) )
+		$icon_url = 'https://' . substr( $icon_url, 7 );
+
+	do {
+		$position++;
+	} while ( !empty( $menu[$position] ) );
+
+	$menu[$position] = array ( $menu_title, $access_level, $file, $page_title, 'menu-top ' . $hookname, $hookname, $icon_url );
+	$_registered_pages[$hookname] = true;
+
+	return $hookname;
+}
+/** Activity ******************************************************************/
+
+/**
+ * @deprecated BuddyPress (1.5)
+ */
+function bp_is_activity_permalink() {
+	_deprecated_function( __FUNCTION__, '1.5', 'bp_is_single_activity' );
+	bp_is_single_activity();
+}
+
+/** Core **********************************************************************/
+
+/**
+ * @deprecated BuddyPress (1.5)
+ */
+function bp_core_get_wp_profile() {
+	_deprecated_function( __FUNCTION__, '1.5' );
+
+	$ud = get_userdata( bp_displayed_user_id() ); ?>
+
+<div class="bp-widget wp-profile">
+	<h4><?php _e( 'My Profile' ) ?></h4>
+
+	<table class="wp-profile-fields">
+
+		<?php if ( $ud->display_name ) : ?>
+
+			<tr id="wp_displayname">
+				<td class="label"><?php _e( 'Name', 'buddypress' ); ?></td>
+				<td class="data"><?php echo $ud->display_name; ?></td>
+			</tr>
+
+		<?php endif; ?>
+
+		<?php if ( $ud->user_description ) : ?>
+
+			<tr id="wp_desc">
+				<td class="label"><?php _e( 'About Me', 'buddypress' ); ?></td>
+				<td class="data"><?php echo $ud->user_description; ?></td>
+			</tr>
+
+		<?php endif; ?>
+
+		<?php if ( $ud->user_url ) : ?>
+
+			<tr id="wp_website">
+				<td class="label"><?php _e( 'Website', 'buddypress' ); ?></td>
+				<td class="data"><?php echo make_clickable( $ud->user_url ); ?></td>
+			</tr>
+
+		<?php endif; ?>
+
+		<?php if ( $ud->jabber ) : ?>
+
+			<tr id="wp_jabber">
+				<td class="label"><?php _e( 'Jabber', 'buddypress' ); ?></td>
+				<td class="data"><?php echo $ud->jabber; ?></td>
+			</tr>
+
+		<?php endif; ?>
+
+		<?php if ( $ud->aim ) : ?>
+
+			<tr id="wp_aim">
+				<td class="label"><?php _e( 'AOL Messenger', 'buddypress' ); ?></td>
+				<td class="data"><?php echo $ud->aim; ?></td>
+			</tr>
+
+		<?php endif; ?>
+
+		<?php if ( $ud->yim ) : ?>
+
+			<tr id="wp_yim">
+				<td class="label"><?php _e( 'Yahoo Messenger', 'buddypress' ); ?></td>
+				<td class="data"><?php echo $ud->yim; ?></td>
+			</tr>
+
+		<?php endif; ?>
+
+	</table>
+</div>
+
+<?php
+}
+
+/**
+ * @deprecated BuddyPress (1.5)
+ * @deprecated Use bp_is_my_profile()
+ */
+function bp_is_home() {
+	_deprecated_function( __FUNCTION__, '1.5', 'bp_is_my_profile' );
+	return bp_is_my_profile();
+}
+
+/**
+ * Is the user on the front page of the site?
+ *
+ * @deprecated BuddyPress (1.5)
+ * @deprecated Use is_front_page()
+ * @return bool
+ */
+function bp_is_front_page() {
+	_deprecated_function( __FUNCTION__, '1.5', "is_front_page()" );
+	return is_front_page();
+}
+
+/**
+ * Is the front page of the site set to the Activity component?
+ *
+ * @deprecated BuddyPress (1.5)
+ * @deprecated Use bp_is_component_front_page( 'activity' )
+ * @return bool
+ */
+function bp_is_activity_front_page() {
+	_deprecated_function( __FUNCTION__, '1.5', "bp_is_component_front_page( 'activity' )" );
+	return bp_is_component_front_page( 'activity' );
+}
+
+/**
+ * @deprecated BuddyPress (1.5)
+ * @deprecated use bp_is_user()
+ */
+function bp_is_member() {
+	_deprecated_function( __FUNCTION__, '1.5', 'bp_is_user' );
+	return bp_is_user();
+}
+
+/**
+ * @deprecated BuddyPress (1.5)
+ * @deprecated use bp_loggedin_user_link()
+ */
+function bp_loggedinuser_link() {
+	_deprecated_function( __FUNCTION__, '1.5', 'bp_loggedin_user_link' );
+	bp_loggedin_user_link();
+}
+
+/**
+ * Only show the search form if there are available objects to search for.
+ * Deprecated in 1.5; not used anymore.
+ *
+ * @deprecated BuddyPress (1.5)
+ * @return bool
+ */
+function bp_search_form_enabled() {
+	_deprecated_function( __FUNCTION__, '1.5', 'No longer required.' );
+	return apply_filters( 'bp_search_form_enabled', true );
+}
+
+/**
+ * Template tag version of bp_get_page_title()
+ *
+ * @deprecated BuddyPress (1.5)
+ * @deprecated Use wp_title()
+ * @since BuddyPress (1.0)
+ */
+function bp_page_title() {
+	echo bp_get_page_title();
+}
+	/**
+	 * Prior to BuddyPress 1.5, this was used to generate the page's <title> text.
+	 * Now, just simply use wp_title().
+	 *
+	 * @deprecated BuddyPress (1.5)
+	 * @deprecated Use wp_title()
+	 * @since BuddyPress (1.0)
+	 */
+	function bp_get_page_title() {
+		_deprecated_function( __FUNCTION__, '1.5', 'wp_title()' );
+		$title = wp_title( '|', false, 'right' ) . get_bloginfo( 'name', 'display' );
+
+		// Backpat for BP 1.2 filter
+		$title = apply_filters( 'bp_page_title', esc_attr( $title ), esc_attr( $title ) );
+
+		return apply_filters( 'bp_get_page_title', $title );
+	}
+
+/**
+ * Generate a link to log out. Last used in BP 1.2-beta. You should be using wp_logout_url().
+ *
+ * @deprecated BuddyPress (1.5)
+ * @deprecated Use wp_logout_url()
+ * @since BuddyPress (1.0)
+ */
+function bp_log_out_link() {
+	_deprecated_function( __FUNCTION__, '1.5', 'wp_logout_url()' );
+
+	$logout_link = '<a href="' . wp_logout_url( bp_get_root_domain() ) . '">' . __( 'Log Out', 'buddypress' ) . '</a>';
+	echo apply_filters( 'bp_logout_link', $logout_link );
+}
+
+/**
+ * Send an email and a BP notification on receipt of an @-mention in a group
+ *
+ * @deprecated BuddyPress (1.5)
+ * @deprecated Deprecated in favor of the more general bp_activity_at_message_notification()
+ */
+function groups_at_message_notification( $content, $poster_user_id, $group_id, $activity_id ) {
+	_deprecated_function( __FUNCTION__, '1.5', 'bp_activity_at_message_notification()' );
+
+	/* Scan for @username strings in an activity update. Notify each user. */
+	$pattern = '/[@]+([A-Za-z0-9-_\.@]+)/';
+	preg_match_all( $pattern, $content, $usernames );
+
+	/* Make sure there's only one instance of each username */
+	if ( !$usernames = array_unique( $usernames[1] ) )
+		return false;
+
+	$group = new BP_Groups_Group( $group_id );
+
+	foreach( (array) $usernames as $username ) {
+		if ( !$receiver_user_id = bp_core_get_userid( $username ) )
+			continue;
+
+		/* Check the user is a member of the group before sending the update. */
+		if ( !groups_is_user_member( $receiver_user_id, $group_id ) )
+			continue;
+
+		// Now email the user with the contents of the message (if they have enabled email notifications)
+		if ( 'no' != bp_get_user_meta( $receiver_user_id, 'notification_activity_new_mention', true ) ) {
+			$poster_name = bp_core_get_user_displayname( $poster_user_id );
+
+			$message_link  = bp_activity_get_permalink( $activity_id );
+			$settings_slug = function_exists( 'bp_get_settings_slug' ) ? bp_get_settings_slug() : 'settings';
+			$settings_link = bp_core_get_user_domain( $receiver_user_id ) . $settings_slug . '/notifications/';
+
+			$poster_name = stripslashes( $poster_name );
+			$content = bp_groups_filter_kses( stripslashes( $content ) );
+
+			// Set up and send the message
+			$ud = bp_core_get_core_userdata( $receiver_user_id );
+			$to = $ud->user_email;
+			$subject = bp_get_email_subject( array( 'text' => sprintf( __( '%1$s mentioned you in the group "%2$s"', 'buddypress' ), $poster_name, $group->name ) ) );
+
+$message = sprintf( __(
+'%1$s mentioned you in the group "%2$s":
+
+"%3$s"
+
+To view and respond to the message, log in and visit: %4$s
+
+---------------------
+', 'buddypress' ), $poster_name, $group->name, $content, $message_link );
+
+			$message .= sprintf( __( 'To disable these notifications please log in and go to: %s', 'buddypress' ), $settings_link );
+
+			/* Send the message */
+			$to = apply_filters( 'groups_at_message_notification_to', $to );
+			$subject = apply_filters( 'groups_at_message_notification_subject', $subject, $group, $poster_name );
+			$message = apply_filters( 'groups_at_message_notification_message', $message, $group, $poster_name, $content, $message_link, $settings_link );
+
+			wp_mail( $to, $subject, $message );
+		}
+	}
+
+	do_action( 'bp_groups_sent_mention_email', $usernames, $subject, $message, $content, $poster_user_id, $group_id, $activity_id );
+}
+
+/**
+ * BP 1.5 simplified notification functions a bit
+ * @deprecated BuddyPress (1.5)
+ */
+function bp_core_delete_notifications_for_user_by_type( $user_id, $component_name, $component_action ) {
+	_deprecated_function( __FUNCTION__, '1.5', 'bp_core_delete_notifications_by_type()' );
+	return BP_Core_Notification::delete_for_user_by_type( $user_id, $component_name, $component_action );
+}
+
+function bp_core_delete_notifications_for_user_by_item_id( $user_id, $item_id, $component_name, $component_action, $secondary_item_id = false ) {
+	_deprecated_function( __FUNCTION__, '1.5', 'bp_core_delete_notifications_by_item_id()' );
+	return BP_Core_Notification::delete_for_user_by_item_id( $user_id, $item_id, $component_name, $component_action, $secondary_item_id );
+}
+
+/**
+ * In BP 1.5, these functions were renamed for greater consistency
+ * @deprecated BuddyPress (1.5)
+ */
+function bp_forum_directory_permalink() {
+	_deprecated_function( __FUNCTION__, '1.5', 'bp_forums_directory_permalink()' );
+	bp_forums_directory_permalink();
+}
+	function bp_get_forum_directory_permalink() {
+		_deprecated_function( __FUNCTION__, '1.5', 'bp_get_forums_directory_permalink()' );
+		return bp_get_forums_directory_permalink();
+	}
+
+/**
+ * Last used by core in BP 1.1. The markup was merged into DTheme's header.php template.
+ * @deprecated BuddyPress (1.5)
+ */
+function bp_search_form() {
+	_deprecated_function( __FUNCTION__, '1.1', 'No longer required.' );
+
+	$form = '
+		<form action="' . bp_search_form_action() . '" method="post" id="search-form">
+			<input type="text" id="search-terms" name="search-terms" value="" />
+			' . bp_search_form_type_select() . '
+
+			<input type="submit" name="search-submit" id="search-submit" value="' . __( 'Search', 'buddypress' ) . '" />
+			' . wp_nonce_field( 'bp_search_form' ) . '
+		</form>
+	';
+
+	echo apply_filters( 'bp_search_form', $form );
+}
+
+/**
+ * Some _is_ function had their names normalized
+ * @deprecated BuddyPress (1.5)
+ */
+function bp_is_profile_edit() {
+	_deprecated_function( __FUNCTION__, '1.5', 'bp_is_user_profile_edit()' );
+	return bp_is_user_profile_edit();
+}
+
+/**
+ * @deprecated BuddyPress (1.5)
+ */
+function bp_is_change_avatar() {
+	_deprecated_function( __FUNCTION__, '1.5', 'bp_is_user_change_avatar()' );
+	return bp_is_user_change_avatar();
+}
+
+/**
+ * @deprecated BuddyPress (1.5)
+ */
+function bp_is_friend_requests() {
+	_deprecated_function( __FUNCTION__, '1.5', 'bp_is_user_friend_requests()' );
+	return bp_is_user_friend_requests();
+}
+
+/**
+ * Checks to see if a component's URL should be in the root, not under a member page:
+ * eg: http://domain.com/groups/the-group NOT http://domain.com/members/andy/groups/the-group
+ * You should be using bp_is_root_component().
+ *
+ * @deprecated BuddyPress (1.5)
+ * @deprecated bp_is_root_component()
+ * @return bool True if root component, else false.
+ */
+function bp_core_is_root_component( $component_name ) {
+	_deprecated_function( __FUNCTION__, '1.5', 'bp_is_root_component()' );
+	return bp_is_root_component( $component_name );
+}
+
+/** Theme *********************************************************************/
+
+/**
+ * Contains functions which were moved out of BP-Default's functions.php
+ * in BuddyPress 1.5.
+ *
+ * @deprecated BuddyPress (1.5)
+ * @since BuddyPress (1.5)
+ */
+function bp_dtheme_deprecated() {
+	if ( !function_exists( 'bp_dtheme_wp_pages_filter' ) ) :
+	/**
+	 * In BuddyPress 1.2.x, this function filtered the dropdown on the
+	 * Settings > Reading screen for selecting the page to show on front to
+	 * include "Activity Stream." As of 1.5.x, it is no longer required.
+	 *
+	 * @deprecated BuddyPress (1.5)
+	 * @deprecated No longer required.
+	 * @param string $page_html A list of pages as a dropdown (select list)
+	 * @return string
+	 * @see wp_dropdown_pages()
+	 * @since BuddyPress (1.2)
+	 */
+	function bp_dtheme_wp_pages_filter( $page_html ) {
+		_deprecated_function( __FUNCTION__, '1.5', "No longer required." );
+		return $page_html;
+	}
+	endif;
+
+	if ( !function_exists( 'bp_dtheme_page_on_front_update' ) ) :
+	/**
+	 * In BuddyPress 1.2.x, this function hijacked the saving of page on front setting to save the activity stream setting.
+	 * As of 1.5.x, it is no longer required.
+	 *
+	 * @deprecated BuddyPress (1.5)
+	 * @deprecated No longer required.
+	 * @param string $oldvalue Previous value of get_option( 'page_on_front' )
+	 * @param string $oldvalue New value of get_option( 'page_on_front' )
+	 * @return string
+	 * @since BuddyPress (1.2)
+	 */
+	function bp_dtheme_page_on_front_update( $oldvalue, $newvalue ) {
+		_deprecated_function( __FUNCTION__, '1.5', "No longer required." );
+		if ( !is_admin() || !bp_current_user_can( 'bp_moderate' ) )
+			return false;
+
+		return $oldvalue;
+	}
+	endif;
+
+	if ( !function_exists( 'bp_dtheme_page_on_front_template' ) ) :
+	/**
+	 * In BuddyPress 1.2.x, this function loaded the activity stream template if the front page display settings allow.
+	 * As of 1.5.x, it is no longer required.
+	 *
+	 * @deprecated BuddyPress (1.5)
+	 * @deprecated No longer required.
+	 * @param string $template Absolute path to the page template
+	 * @return string
+	 * @since BuddyPress (1.2)
+	 */
+	function bp_dtheme_page_on_front_template( $template ) {
+		_deprecated_function( __FUNCTION__, '1.5', "No longer required." );
+		return $template;
+	}
+	endif;
+
+	if ( !function_exists( 'bp_dtheme_fix_get_posts_on_activity_front' ) ) :
+	/**
+	 * In BuddyPress 1.2.x, this forced the page ID as a string to stop the get_posts query from kicking up a fuss.
+	 * As of 1.5.x, it is no longer required.
+	 *
+	 * @deprecated BuddyPress (1.5)
+	 * @deprecated No longer required.
+	 * @since BuddyPress (1.2)
+	 */
+	function bp_dtheme_fix_get_posts_on_activity_front() {
+		_deprecated_function( __FUNCTION__, '1.5', "No longer required." );
+	}
+	endif;
+
+	if ( !function_exists( 'bp_dtheme_fix_the_posts_on_activity_front' ) ) :
+	/**
+	 * In BuddyPress 1.2.x, this was used as part of the code that set the activity stream to be on the front page.
+	 * As of 1.5.x, it is no longer required.
+	 *
+	 * @deprecated BuddyPress (1.5)
+	 * @deprecated No longer required.
+	 * @param array $posts Posts as retrieved by WP_Query
+	 * @return array
+	 * @since BuddyPress (1.2.5)
+	 */
+	function bp_dtheme_fix_the_posts_on_activity_front( $posts ) {
+		_deprecated_function( __FUNCTION__, '1.5', "No longer required." );
+		return $posts;
+	}
+	endif;
+
+	if ( !function_exists( 'bp_dtheme_add_blog_comments_js' ) ) :
+	/**
+	 * In BuddyPress 1.2.x, this added the javascript needed for blog comment replies.
+	 * As of 1.5.x, we recommend that you enqueue the comment-reply javascript in your theme's header.php.
+	 *
+	 * @deprecated BuddyPress (1.5)
+	 * @deprecated Enqueue the comment-reply script in your theme's header.php.
+	 * @since BuddyPress (1.2)
+	 */
+	function bp_dtheme_add_blog_comments_js() {
+		_deprecated_function( __FUNCTION__, '1.5', "Enqueue the comment-reply script in your theme's header.php." );
+		if ( is_singular() && bp_is_blog_page() && get_option( 'thread_comments' ) )
+			wp_enqueue_script( 'comment-reply' );
+	}
+	endif;
+}
+add_action( 'after_setup_theme', 'bp_dtheme_deprecated', 15 );
+
+/**
+ * In BP 1.5, the Settings functions were moved out of the Core and Members
+ * components, and moved into a new Settings component. This function is no
+ * longer needed as the nav structure is set up by the {@link BP_Component} class.
+ *
+ * @deprecated BuddyPress (1.5)
+ * @since BuddyPress (1.6)
+ */
+function bp_core_add_settings_nav() {
+	_deprecated_function( __FUNCTION__, '1.5' );
+}
+
+/**
+ * In BP 1.5, the Settings functions were moved out of the Core and Members
+ * components, and moved into a new Settings component. This function is no
+ * longer needed as new template files for the Settings component were
+ * introduced.
+ *
+ * @deprecated BuddyPress (1.5)
+ * @since BuddyPress (1.6)
+ */
+function bp_core_screen_general_settings() {
+	_deprecated_function( __FUNCTION__, '1.5', 'Moved into theme template' );
+}
+
+/**
+ * In BP 1.5, the Settings functions were moved out of the Core and Members
+ * components, and moved into a new Settings component. This function is no
+ * longer needed as new template files for the Settings component were
+ * introduced.
+ *
+ * @deprecated BuddyPress (1.5)
+ * @since BuddyPress (1.6)
+ */
+function bp_core_screen_general_settings_title() {
+	_deprecated_function( __FUNCTION__, '1.5', 'Moved into theme template' );
+}
+
+/**
+ * In BP 1.5, the Settings functions were moved out of the Core and Members
+ * components, and moved into a new Settings component. This function is no
+ * longer needed as new template files for the Settings component were
+ * introduced.
+ *
+ * @deprecated BuddyPress (1.5)
+ * @since BuddyPress (1.6)
+ */
+function bp_core_screen_general_settings_content() {
+	_deprecated_function( __FUNCTION__, '1.5', 'Moved into theme template' );
+}
+
+/**
+ * In BP 1.5, the Settings functions were moved out of the Core and Members
+ * components, and moved into a new Settings component. This function is no
+ * longer needed as new template files for the Settings component were
+ * introduced.
+ *
+ * @deprecated BuddyPress (1.5)
+ * @since BuddyPress (1.6)
+ */
+function bp_core_screen_notification_settings() {
+	_deprecated_function( __FUNCTION__, '1.5', 'Moved into theme template' );
+}
+
+/**
+ * In BP 1.5, the Settings functions were moved out of the Core and Members
+ * components, and moved into a new Settings component. This function is no
+ * longer needed as new template files for the Settings component were
+ * introduced.
+ *
+ * @deprecated BuddyPress (1.5)
+ * @since BuddyPress (1.6)
+ */
+function bp_core_screen_notification_settings_title() {
+	_deprecated_function( __FUNCTION__, '1.5', 'Moved into theme template' );
+}
+
+/**
+ * In BP 1.5, the Settings functions were moved out of the Core and Members
+ * components, and moved into a new Settings component. This function is no
+ * longer needed as new template files for the Settings component were
+ * introduced.
+ *
+ * @deprecated BuddyPress (1.5)
+ * @since BuddyPress (1.6)
+ */
+function bp_core_screen_notification_settings_content() {
+	_deprecated_function( __FUNCTION__, '1.5', 'Moved into theme template' );
+}
+
+/**
+ * In BP 1.5, the Settings functions were moved out of the Core and Members
+ * components, and moved into a new Settings component. This function is no
+ * longer needed as new template files for the Settings component were
+ * introduced.
+ *
+ * @deprecated BuddyPress (1.5)
+ * @since BuddyPress (1.6)
+ */
+function bp_core_screen_delete_account() {
+	_deprecated_function( __FUNCTION__, '1.5', 'Moved into theme template' );
+}
+
+/**
+ * In BP 1.5, the Settings functions were moved out of the Core and Members
+ * components, and moved into a new Settings component. This function is no
+ * longer needed as new template files for the Settings component were
+ * introduced.
+ *
+ * @deprecated BuddyPress (1.5)
+ * @since BuddyPress (1.6)
+ */
+function bp_core_screen_delete_account_title() {
+	_deprecated_function( __FUNCTION__, '1.5', 'Moved into theme template' );
+}
+
+/**
+ * In BP 1.5, the Settings functions were moved out of the Core and Members
+ * components, and moved into a new Settings component. This function is no
+ * longer needed as new template files for the Settings component were
+ * introduced.
+ *
+ * @deprecated BuddyPress (1.5)
+ * @since BuddyPress (1.6)
+ */
+function bp_core_screen_delete_account_content() {
+	_deprecated_function( __FUNCTION__, '1.5', 'Moved into theme template' );
+}
Index: /tags/1.9/bp-core/deprecated/1.6.php
===================================================================
--- /tags/1.9/bp-core/deprecated/1.6.php	(revision 7684)
+++ /tags/1.9/bp-core/deprecated/1.6.php	(revision 7684)
@@ -0,0 +1,274 @@
+<?php
+
+/**
+ * Deprecated Functions
+ *
+ * @package BuddyPress
+ * @subpackage Core
+ * @deprecated Since 1.6
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/** Toolbar functions *********************************************************/
+
+/**
+ * @deprecated BuddyPress (1.6)
+ */
+function bp_admin_bar_remove_wp_menus() {
+	_deprecated_function( __FUNCTION__, '1.6' );
+}
+
+/**
+ * @deprecated BuddyPress (1.6)
+ */
+function bp_admin_bar_root_site() {
+	_deprecated_function( __FUNCTION__, '1.6' );
+}
+
+/**
+ * @deprecated BuddyPress (1.6)
+ */
+function bp_admin_bar_my_sites_menu() {
+	_deprecated_function( __FUNCTION__, '1.6' );
+}
+
+/**
+ * @deprecated BuddyPress (1.6)
+ */
+function bp_admin_bar_comments_menu( $wp_admin_bar = '' ) {
+	_deprecated_function( __FUNCTION__, '1.6' );
+}
+
+/**
+ * @deprecated BuddyPress (1.6)
+ */
+function bp_admin_bar_appearance_menu() {
+	_deprecated_function( __FUNCTION__, '1.6' );
+}
+
+/**
+ * @deprecated BuddyPress (1.6)
+ */
+function bp_admin_bar_updates_menu() {
+	_deprecated_function( __FUNCTION__, '1.6' );
+}
+
+/**
+ * @deprecated BuddyPress (1.6)
+ */
+function bp_members_admin_bar_my_account_logout() {
+	_deprecated_function( __FUNCTION__, '1.6' );
+}
+
+/**
+ * @deprecated BuddyPress (1.6)
+ */
+function bp_core_is_user_deleted( $user_id = 0 ) {
+	_deprecated_function( __FUNCTION__, '1.6' );
+	bp_is_user_deleted( $user_id );
+}
+
+/**
+ * @deprecated BuddyPress (1.6)
+ */
+function bp_core_is_user_spammer( $user_id = 0 ) {
+	_deprecated_function( __FUNCTION__, '1.6' );
+	bp_is_user_spammer( $user_id );
+}
+
+
+/**
+ * Blogs functions
+ */
+
+/**
+ * @deprecated BuddyPress (1.6)
+ * @deprecated No longer used; see bp_blogs_transition_activity_status()
+ */
+function bp_blogs_manage_comment( $comment_id, $comment_status ) {
+	_deprecated_function( __FUNCTION__, '1.6', 'No longer used' );
+}
+
+/**
+ * Core functions
+ */
+
+/**
+ * @deprecated BuddyPress (1.6)
+ * @deprecated No longer used; see BP_Admin::admin_menus()
+ */
+function bp_core_add_admin_menu() {
+	_deprecated_function( __FUNCTION__, '1.6', 'No longer used' );
+}
+
+/**
+ * @deprecated BuddyPress (1.6)
+ * @deprecated No longer used. We do ajax properly now.
+ */
+function bp_core_add_ajax_hook() {
+	_deprecated_function( __FUNCTION__, '1.6', 'No longer used' );
+}
+
+/**
+ * Friends functions
+ */
+
+/**
+ * Displays Friends header tabs
+ *
+ * @deprecated BuddyPress (1.6)
+ * @deprecated No longer used
+ */
+function bp_friends_header_tabs() {
+	_deprecated_function( __FUNCTION__, '1.6', 'Since BuddyPress 1.2, BP has not supported ordering of friend lists by URL parameters.' );
+?>
+
+	<li<?php if ( !bp_action_variable( 0 ) || bp_is_action_variable( 'recently-active', 0 ) ) : ?> class="current"<?php endif; ?>><a href="<?php echo trailingslashit( bp_displayed_user_domain() . bp_get_friends_slug() . '/my-friends/recently-active' ) ?>"><?php _e( 'Recently Active', 'buddypress' ) ?></a></li>
+	<li<?php if ( bp_is_action_variable( 'newest', 0 ) ) : ?> class="current"<?php endif; ?>><a href="<?php echo trailingslashit( bp_displayed_user_domain() . bp_get_friends_slug() . '/my-friends/newest' ) ?>"><?php _e( 'Newest', 'buddypress' ) ?></a></li>
+	<li<?php if ( bp_is_action_variable( 'alphabetically', 0 ) ) : ?> class="current"<?php endif; ?>><a href="<?php echo trailingslashit( bp_displayed_user_domain() . bp_get_friends_slug() . '/my-friends/alphabetically' ) ?>"><?php _e( 'Alphabetically', 'buddypress' ) ?></a></li>
+
+<?php
+	do_action( 'friends_header_tabs' );
+}
+
+/**
+ * Filters the title for the Friends component
+ *
+ * @deprecated BuddyPress (1.6)
+ * @deprecated No longer used
+ */
+function bp_friends_filter_title() {
+	_deprecated_function( __FUNCTION__, '1.6', 'Since BuddyPress 1.2, BP has not supported ordering of friend lists by URL parameters.' );
+
+	$current_filter = bp_action_variable( 0 );
+
+	switch ( $current_filter ) {
+		case 'recently-active': default:
+			_e( 'Recently Active', 'buddypress' );
+			break;
+		case 'newest':
+			_e( 'Newest', 'buddypress' );
+			break;
+		case 'alphabetically':
+			_e( 'Alphabetically', 'buddypress' );
+			break;
+	}
+}
+
+
+/** Groups functions **********************************************************/
+
+/**
+ * @deprecated BuddyPress (1.6)
+ * @deprecated Renamed to groups_get_id() for greater consistency
+ */
+function groups_check_group_exists( $group_slug ) {
+	_deprecated_function( __FUNCTION__, '1.6', 'groups_get_id()' );
+	return groups_get_id( $group_slug );
+}
+
+/** Admin functions ***********************************************************/
+
+/**
+ * Loads admin panel styles and scripts.
+ *
+ * @deprecated BuddyPress (1.6)
+ */
+function bp_core_add_admin_menu_styles() {
+	_deprecated_function( __FUNCTION__, '1.6' );
+}
+
+/** Activity functions ********************************************************/
+
+/**
+ * @deprecated BuddyPress (1.6)
+ */
+function updates_register_activity_actions() {
+	_deprecated_function( __FUNCTION__, '1.6' );
+}
+
+/**
+ * Sets the "From" address in emails sent
+ *
+ * @deprecated BuddyPress (1.6)
+ * @return string email address
+ */
+function bp_core_email_from_address_filter() {
+	_deprecated_function( __FUNCTION__, '1.6' );
+
+	$domain = (array) explode( '/', site_url() );
+	return apply_filters( 'bp_core_email_from_address_filter', 'noreply@' . $domain[2] );
+}
+
+/**
+ * Backward compatibility for AJAX callbacks that do not die() on their own
+ *
+ * In BuddyPress 1.6, BP was altered so that it uses admin-ajax.php (instead of wp-load.php) for
+ * AJAX requests. admin-ajax.php dies with an output of '0' (to signify an error), so that if an
+ * AJAX callback does not kill PHP execution, a '0' character will be erroneously appended to the
+ * output. All bp-default AJAX callbacks (/bp-themes/bp-default/_inc/ajax.php) have been updated
+ * for BP 1.6 so that they die() properly; any theme that dynamically includes this file will
+ * inherit the fixes. However, any theme that contains a copy of BP's pre-1.5 ajax.php file will
+ * continue to witness the 'trailing "0"' problem.
+ *
+ * This function provides a backward compatible workaround for these themes, by hooking to the
+ * BP wp_ajax_ actions that were problematic prior to BP 1.6, and killing PHP execution with die().
+ *
+ * Note that this hack only runs if the function bp_dtheme_register_actions() is not found (this
+ * function was introduced in BP 1.6 for related backward compatibility reasons).
+ *
+ * @deprecated BuddyPress (1.6)
+ */
+if ( !function_exists( 'bp_dtheme_register_actions' ) ) :
+	function bp_die_legacy_ajax_callbacks() {
+
+		// This is a list of the BP wp_ajax_ hook suffixes whose associated functions did
+		// not die properly before BP 1.6
+		$actions = array(
+			// Directory template loaders
+			'members_filter',
+			'groups_filter',
+			'blogs_filter',
+			'forums_filter',
+			'messages_filter',
+
+			// Activity
+			'activity_widget_filter',
+			'activity_get_older_updates',
+			'post_update',
+			'new_activity_comment',
+			'delete_activity',
+			'delete_activity_comment',
+			'spam_activity',
+			'spam_activity_comment',
+			'activity_mark_fav',
+			'activity_mark_unfav',
+
+			// Groups
+			'groups_invite_user',
+			'joinleave_group',
+
+			// Members
+			'addremove_friend',
+			'accept_friendship',
+			'reject_friendship',
+
+			// Messages
+			'messages_close_notice',
+			'messages_send_reply',
+			'messages_markunread',
+			'messages_markread',
+			'messages_delete',
+			'messages_autocomplete_results'
+		);
+
+		// For each of the problematic hooks, exit at the very end of execution
+		foreach( $actions as $action ) {
+			add_action( 'wp_ajax_'        . $action, create_function( '', 'exit;' ), 9999 );
+			add_action( 'wp_ajax_nopriv_' . $action, create_function( '', 'exit;' ), 9999 );
+		}
+	}
+	add_action( 'after_setup_theme', 'bp_die_legacy_ajax_callbacks', 20 );
+endif;
Index: /tags/1.9/bp-core/deprecated/1.7.php
===================================================================
--- /tags/1.9/bp-core/deprecated/1.7.php	(revision 7684)
+++ /tags/1.9/bp-core/deprecated/1.7.php	(revision 7684)
@@ -0,0 +1,163 @@
+<?php
+/**
+ * Deprecated Functions
+ *
+ * @package BuddyPress
+ * @subpackage Core
+ * @deprecated Since 1.7
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/**
+ * Output the BuddyPress maintenance mode
+ *
+ * @since BuddyPress (1.6)
+ * @deprecated BuddyPress (1.7)
+ * @uses bp_get_maintenance_mode() To get the BuddyPress maintenance mode
+ */
+function bp_maintenance_mode() {
+	echo bp_get_maintenance_mode();
+}
+	/**
+	 * Return the BuddyPress maintenance mode
+	 *
+	 * @since BuddyPress (1.6)
+	 * @deprecated BuddyPress (1.7)
+	 * @return string The BuddyPress maintenance mode
+	 */
+	function bp_get_maintenance_mode() {
+		return buddypress()->maintenance_mode;
+	}
+
+/**
+ * @deprecated BuddyPress (1.7)
+ */
+function xprofile_get_profile() {
+	_deprecated_function( __FUNCTION__, '1.7' );
+	bp_locate_template( array( 'profile/profile-loop.php' ), true );
+}
+
+/**
+ * @deprecated BuddyPress (1.7)
+ */
+function bp_get_profile_header() {
+	_deprecated_function( __FUNCTION__, '1.7' );
+	bp_locate_template( array( 'profile/profile-header.php' ), true );
+}
+
+/**
+ * @deprecated BuddyPress (1.7)
+ * @param string $component_name
+ * @return boolean
+ */
+function bp_exists( $component_name ) {
+	_deprecated_function( __FUNCTION__, '1.7' );
+	if ( function_exists( $component_name . '_install' ) )
+		return true;
+
+	return false;
+}
+
+/**
+ * @deprecated BuddyPress (1.7)
+ */
+function bp_get_plugin_sidebar() {
+	_deprecated_function( __FUNCTION__, '1.7' );
+	bp_locate_template( array( 'plugin-sidebar.php' ), true );
+}
+
+/**
+ * On multiblog installations you must first allow themes to be activated and
+ * show up on the theme selection screen. This function will let the BuddyPress
+ * bundled themes show up on the root blog selection screen and bypass this
+ * step. It also means that the themes won't show for selection on other blogs.
+ *
+ * @deprecated BuddyPress (1.7)
+ * @package BuddyPress Core
+ */
+function bp_core_allow_default_theme( $themes ) {
+	_deprecated_function( __FUNCTION__, '1.7' );
+
+	if ( !bp_current_user_can( 'bp_moderate' ) )
+		return $themes;
+
+	if ( bp_get_root_blog_id() != get_current_blog_id() )
+		return $themes;
+
+	if ( isset( $themes['bp-default'] ) )
+		return $themes;
+
+	$themes['bp-default'] = true;
+
+	return $themes;
+}
+
+/**
+ * No longer used by BuddyPress core
+ *
+ * @deprecated BuddyPress (1.7)
+ * @param string $page
+ * @return boolean True if is BuddyPress page
+ */
+function bp_is_page( $page = '' ) {
+	_deprecated_function( __FUNCTION__, '1.7' );
+
+	if ( !bp_is_user() && bp_is_current_component( $page )  )
+		return true;
+
+	if ( 'home' == $page )
+		return is_front_page();
+
+	return false;
+}
+
+/** Admin *********************************************************************/
+
+/**
+ * This function was originally used to update pre-1.1 schemas, but that was
+ * before we had a legitimate update process.
+ *
+ * @deprecated BuddyPress (1.7)
+ * @global WPDB $wpdb
+ */
+function bp_update_db_stuff() {
+	global $wpdb;
+
+	$bp        = buddypress();
+	$bp_prefix = bp_core_get_table_prefix();
+
+	// Rename the old user activity cached table if needed.
+	if ( $wpdb->get_var( "SHOW TABLES LIKE '%{$bp_prefix}bp_activity_user_activity_cached%'" ) ) {
+		$wpdb->query( "RENAME TABLE {$bp_prefix}bp_activity_user_activity_cached TO {$bp->activity->table_name}" );
+	}
+
+	// Rename fields from pre BP 1.2
+	if ( $wpdb->get_var( "SHOW TABLES LIKE '%{$bp->activity->table_name}%'" ) ) {
+		if ( $wpdb->get_var( "SHOW COLUMNS FROM {$bp->activity->table_name} LIKE 'component_action'" ) ) {
+			$wpdb->query( "ALTER TABLE {$bp->activity->table_name} CHANGE component_action type varchar(75) NOT NULL" );
+		}
+
+		if ( $wpdb->get_var( "SHOW COLUMNS FROM {$bp->activity->table_name} LIKE 'component_name'" ) ) {
+			$wpdb->query( "ALTER TABLE {$bp->activity->table_name} CHANGE component_name component varchar(75) NOT NULL" );
+		}
+	}
+
+	// On first installation - record all existing blogs in the system.
+	if ( !(int) $bp->site_options['bp-blogs-first-install'] ) {
+		bp_blogs_record_existing_blogs();
+		bp_update_option( 'bp-blogs-first-install', 1 );
+	}
+
+	if ( is_multisite() ) {
+		bp_core_add_illegal_names();
+	}
+
+	// Update and remove the message threads table if it exists
+	if ( $wpdb->get_var( "SHOW TABLES LIKE '%{$bp_prefix}bp_messages_threads%'" ) ) {
+		if ( BP_Messages_Thread::update_tables() ) {
+			$wpdb->query( "DROP TABLE {$bp_prefix}bp_messages_threads" );
+		}
+	}
+}
Index: /tags/1.9/bp-core/js/widget-members.js
===================================================================
--- /tags/1.9/bp-core/js/widget-members.js	(revision 7684)
+++ /tags/1.9/bp-core/js/widget-members.js	(revision 7684)
@@ -0,0 +1,49 @@
+jQuery(document).ready( function() {
+	jQuery(".widget div#members-list-options a").on('click',
+		function() {
+			var link = this;
+			jQuery(link).addClass('loading');
+
+			jQuery(".widget div#members-list-options a").removeClass("selected");
+			jQuery(this).addClass('selected');
+
+			jQuery.post( ajaxurl, {
+				action: 'widget_members',
+				'cookie': encodeURIComponent(document.cookie),
+				'_wpnonce': jQuery("input#_wpnonce-members").val(),
+				'max-members': jQuery("input#members_widget_max").val(),
+				'filter': jQuery(this).attr('id')
+			},
+			function(response)
+			{
+				jQuery(link).removeClass('loading');
+				member_wiget_response(response);
+			});
+
+			return false;
+		}
+	);
+});
+
+function member_wiget_response(response) {
+	response = response.substr(0, response.length-1);
+	response = response.split('[[SPLIT]]');
+
+	if ( response[0] != "-1" ) {
+		jQuery(".widget ul#members-list").fadeOut(200,
+			function() {
+				jQuery(".widget ul#members-list").html(response[1]);
+				jQuery(".widget ul#members-list").fadeIn(200);
+			}
+		);
+
+	} else {
+		jQuery(".widget ul#members-list").fadeOut(200,
+			function() {
+				var message = '<p>' + response[1] + '</p>';
+				jQuery(".widget ul#members-list").html(message);
+				jQuery(".widget ul#members-list").fadeIn(200);
+			}
+		);
+	}
+}
Index: /tags/1.9/bp-core/js/widget-members.min.js
===================================================================
--- /tags/1.9/bp-core/js/widget-members.min.js	(revision 7684)
+++ /tags/1.9/bp-core/js/widget-members.min.js	(revision 7684)
@@ -0,0 +1,1 @@
+jQuery(document).ready(function(){jQuery(".widget div#members-list-options a").on("click",function(){var a=this;jQuery(a).addClass("loading");jQuery(".widget div#members-list-options a").removeClass("selected");jQuery(this).addClass("selected");jQuery.post(ajaxurl,{action:"widget_members",cookie:encodeURIComponent(document.cookie),_wpnonce:jQuery("input#_wpnonce-members").val(),"max-members":jQuery("input#members_widget_max").val(),filter:jQuery(this).attr("id")},function(b){jQuery(a).removeClass("loading");member_wiget_response(b)});return false})});function member_wiget_response(a){a=a.substr(0,a.length-1);a=a.split("[[SPLIT]]");if(a[0]!="-1"){jQuery(".widget ul#members-list").fadeOut(200,function(){jQuery(".widget ul#members-list").html(a[1]);jQuery(".widget ul#members-list").fadeIn(200)})}else{jQuery(".widget ul#members-list").fadeOut(200,function(){var b="<p>"+a[1]+"</p>";jQuery(".widget ul#members-list").html(b);jQuery(".widget ul#members-list").fadeIn(200)})}};
Index: /tags/1.9/bp-forums/bb-config.php
===================================================================
--- /tags/1.9/bp-forums/bb-config.php	(revision 7684)
+++ /tags/1.9/bp-forums/bb-config.php	(revision 7684)
@@ -0,0 +1,10 @@
+<?php
+/***
+ * *** IMPORTANT ****
+ * This file will stop people from accessing your bbPress installation directly.
+ * It is very important from a security standpoint that this file is not moved.
+ * Your actual bb-config.php file will be installed in the root of your WordPress
+ * installation once you have set up the forums component in BuddyPress.
+ */
+
+header("HTTP/1.0 403 Forbidden"); die;
Index: /tags/1.9/bp-forums/bp-forums-actions.php
===================================================================
--- /tags/1.9/bp-forums/bp-forums-actions.php	(revision 7684)
+++ /tags/1.9/bp-forums/bp-forums-actions.php	(revision 7684)
@@ -0,0 +1,10 @@
+<?php
+/**
+ * BuddyPress Forums Actions.
+ *
+ * @package BuddyPress
+ * @subpackage Forums
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
Index: /tags/1.9/bp-forums/bp-forums-bbpress-sa.php
===================================================================
--- /tags/1.9/bp-forums/bp-forums-bbpress-sa.php	(revision 7684)
+++ /tags/1.9/bp-forums/bp-forums-bbpress-sa.php	(revision 7684)
@@ -0,0 +1,493 @@
+<?php
+/**
+ * BuddyPress bbPress 1.x integration.
+ *
+ * @package BuddyPress
+ * @subpackage Forums
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/**
+ * Bootstrap bbPress 1.x, and manipulate globals to integrate with BuddyPress.
+ *
+ * @return bool|null Returns false on failure.
+ */
+function bp_forums_load_bbpress() {
+	global $bp, $wpdb, $wp_roles, $current_user, $wp_users_object;
+	global $bb, $bbdb, $bb_table_prefix, $bb_current_user;
+	global $bb_roles, $wp_taxonomy_object, $bb_queries;
+
+	// Return if we've already run this function.
+	if ( is_object( $bbdb ) )
+		return;
+
+	if ( !bp_forums_is_installed_correctly() )
+		return false;
+
+	define( 'BB_PATH', BP_PLUGIN_DIR . '/bp-forums/bbpress/' );
+	define( 'BACKPRESS_PATH', BP_PLUGIN_DIR . '/bp-forums/bbpress/bb-includes/backpress/' );
+	define( 'BB_URL', BP_PLUGIN_URL . 'bp-forums/bbpress/' );
+	define( 'BB_INC', 'bb-includes/' );
+
+	require( BB_PATH . BB_INC . 'class.bb-query.php' );
+	require( BB_PATH . BB_INC . 'class.bb-walker.php' );
+
+	require( BB_PATH . BB_INC . 'functions.bb-core.php' );
+	require( BB_PATH . BB_INC . 'functions.bb-forums.php' );
+	require( BB_PATH . BB_INC . 'functions.bb-topics.php' );
+	require( BB_PATH . BB_INC . 'functions.bb-posts.php' );
+	require( BB_PATH . BB_INC . 'functions.bb-topic-tags.php' );
+	require( BB_PATH . BB_INC . 'functions.bb-capabilities.php' );
+	require( BB_PATH . BB_INC . 'functions.bb-meta.php' );
+	require( BB_PATH . BB_INC . 'functions.bb-pluggable.php' );
+	require( BB_PATH . BB_INC . 'functions.bb-formatting.php' );
+	require( BB_PATH . BB_INC . 'functions.bb-template.php' );
+
+	require( BACKPRESS_PATH . 'class.wp-taxonomy.php' );
+	require( BB_PATH . BB_INC . 'class.bb-taxonomy.php' );
+
+	require( BB_PATH . 'bb-admin/includes/functions.bb-admin.php' );
+
+	$bb = new stdClass();
+	require( bp_get_option(	'bb-config-location' ) );
+
+	// Setup the global database connection
+	$bbdb = new BPDB ( BBDB_USER, BBDB_PASSWORD, BBDB_NAME, BBDB_HOST );
+
+	// Set the table names
+	$bbdb->forums             = $bb_table_prefix . 'forums';
+	$bbdb->meta               = $bb_table_prefix . 'meta';
+	$bbdb->posts              = $bb_table_prefix . 'posts';
+	$bbdb->terms              = $bb_table_prefix . 'terms';
+	$bbdb->term_relationships = $bb_table_prefix . 'term_relationships';
+	$bbdb->term_taxonomy      = $bb_table_prefix . 'term_taxonomy';
+	$bbdb->topics             = $bb_table_prefix . 'topics';
+
+	if ( isset( $bb->custom_user_table ) )
+		$bbdb->users = $bb->custom_user_table;
+	else
+		$bbdb->users = $wpdb->users;
+
+	if ( isset( $bb->custom_user_meta_table ) )
+		$bbdb->usermeta = $bb->custom_user_meta_table;
+	else
+		$bbdb->usermeta = $wpdb->usermeta;
+
+	$bbdb->prefix = $bb_table_prefix;
+
+	define( 'BB_INSTALLING', false );
+
+	if ( is_object( $wp_roles ) ) {
+		$bb_roles = $wp_roles;
+		bb_init_roles( $bb_roles );
+	}
+
+	do_action( 'bb_got_roles' );
+	do_action( 'bb_init'      );
+	do_action( 'init_roles'   );
+
+	$bb_current_user = $current_user;
+	$wp_users_object = new BP_Forums_BB_Auth;
+
+	if ( !isset( $wp_taxonomy_object ) )
+		$wp_taxonomy_object = new BB_Taxonomy( $bbdb );
+
+	$wp_taxonomy_object->register_taxonomy( 'bb_topic_tag', 'bb_topic' );
+
+	// Set a site id if there isn't one already
+	if ( !isset( $bb->site_id ) )
+		$bb->site_id = bp_get_root_blog_id();
+
+	// Check if the tables are installed, if not, install them
+	if ( !$tables_installed = (boolean) $bbdb->get_results( 'DESCRIBE `' . $bbdb->forums . '`;', ARRAY_A ) ) {
+		require( BB_PATH . 'bb-admin/includes/defaults.bb-schema.php' );
+
+		// Backticks and "IF NOT EXISTS" break the dbDelta function.
+		bp_bb_dbDelta( str_replace( ' IF NOT EXISTS', '', str_replace( '`', '', $bb_queries ) ) );
+
+		require( BB_PATH . 'bb-admin/includes/functions.bb-upgrade.php' );
+		bb_update_db_version();
+
+		// Set the site admins as the keymasters
+		$site_admins = get_site_option( 'site_admins', array('admin') );
+		foreach ( (array) $site_admins as $site_admin )
+			bp_update_user_meta( bp_core_get_userid( $site_admin ), $bb_table_prefix . 'capabilities', array( 'keymaster' => true ) );
+
+		// Create the first forum.
+		bb_new_forum( array( 'forum_name' => 'Default Forum' ) );
+
+		// Set the site URI
+		bb_update_option( 'uri', BB_URL );
+	}
+
+	register_shutdown_function( create_function( '', 'do_action("bb_shutdown");' ) );
+}
+add_action( 'bbpress_init', 'bp_forums_load_bbpress' );
+
+/** WP to bbPress wrapper functions ******************************************/
+
+/**
+ * Get the current bbPress user.
+ *
+ * @return object $current_user Current user object from WordPress.
+ */
+function bb_get_current_user() { global $current_user; return $current_user; }
+
+/**
+ * Get userdata for a bbPress user.
+ *
+ * @param int $user_id User ID.
+ * @return object User data from WordPress.
+ */
+function bb_get_user( $user_id ) { return get_userdata( $user_id ); }
+
+/**
+ * Cache users.
+ *
+ * Noop.
+ *
+ * @param array $users
+ */
+function bb_cache_users( $users ) {}
+
+/**
+ * bbPress needs this class for its usermeta manipulation.
+ */
+class BP_Forums_BB_Auth {
+	function update_meta( $args = '' ) {
+		$defaults = array( 'id' => 0, 'meta_key' => null, 'meta_value' => null, 'meta_table' => 'usermeta', 'meta_field' => 'user_id', 'cache_group' => 'users' );
+		$args = wp_parse_args( $args, $defaults );
+		extract( $args, EXTR_SKIP );
+
+		return bp_update_user_meta( $id, $meta_key, $meta_value );
+	}
+}
+
+/**
+ * bbPress needs the DB class to be BPDB, but we want to use WPDB, so we can extend it and use this.
+ *
+ * The class is pluggable, so that plugins that swap out WPDB with a custom
+ * database class (such as HyperDB and SharDB) can provide their own versions
+ * of BPDB which extend the appropriate base class.
+ */
+if ( ! class_exists( 'BPDB' ) ) :
+	class BPDB extends WPDB {
+		var $db_servers = array();
+
+		/**
+		 * Constructor
+		 *
+		 * @see WPDB::__construct() for description of parameters.
+		 */
+		function __construct( $dbuser, $dbpassword, $dbname, $dbhost ) {
+			parent::__construct( $dbuser, $dbpassword, $dbname, $dbhost );
+
+			$args = func_get_args();
+			$args = call_user_func_array( array( &$this, 'init' ), $args );
+
+			if ( $args['host'] )
+				$this->db_servers['dbh_global'] = $args;
+		}
+
+		/**
+		 * Determine if a database supports a particular feature.
+		 *
+		 * Overriden here to work around differences between bbPress's
+		 * and WordPress's implementations. In particular, when
+		 * BuddyPress tries to run bbPress' SQL installation script,
+		 * the collation check always failed. The capability is long
+		 * supported by WordPress' minimum required MySQL version, so
+		 * this is safe.
+		 *
+		 * @see WPDB::has_cap() for a description of parameters and
+		 *      return values.
+		 *
+		 * @param string $db_cap See {@link WPDB::has_cap()}.
+		 * @param string $_table_name See {@link WPDB::has_cap()}.
+		 * @return bool See {@link WPDB::has_cap()}.
+		 */
+		function has_cap( $db_cap, $_table_name='' ) {
+			if ( 'collation' == $db_cap )
+				return true;
+
+			return parent::has_cap( $db_cap );
+		}
+
+		/**
+		 * Initialize the class variables based on provided arguments.
+		 *
+		 * Based on, and taken from, the BackPress class in turn taken
+		 * from the 1.0 branch of bbPress.
+		 *
+		 * @see BBDB::__construct() for a description of params.
+		 */
+		function init( $args ) {
+			if ( 4 == func_num_args() ) {
+				$args = array(
+						'user'     => $args,
+						'password' => func_get_arg( 1 ),
+						'name'     => func_get_arg( 2 ),
+						'host'     => func_get_arg( 3 ),
+						'charset'  => defined( 'BBDB_CHARSET' ) ? BBDB_CHARSET : false,
+						'collate'  => defined( 'BBDB_COLLATE' ) ? BBDB_COLLATE : false,
+					     );
+			}
+
+			$defaults = array(
+					'user'     => false,
+					'password' => false,
+					'name'     => false,
+					'host'     => 'localhost',
+					'charset'  => false,
+					'collate'  => false,
+					'errors'   => false
+					);
+
+			return wp_parse_args( $args, $defaults );
+		}
+
+		/**
+		 * Stub for escape_deep() compatibility.
+		 *
+		 * @see WPDB::escape_deep() for description of parameters and
+		 *      return values.
+		 *
+		 * @param mixed $data See {@link WPDB::escape_deep()}.
+		 * @return mixed $data See {@link WPDB::escape_deep()}.
+		 */
+		function escape_deep( $data ) {
+			return $this->escape( $data );
+		}
+	}
+endif; // class_exists( 'BPDB' )
+
+/**
+ * Convert object to given output format.
+ *
+ * bbPress needs this to convert vars.
+ *
+ * @param object $object Object to convert.
+ * @param string $output Type of object to return. OBJECT, ARRAY_A, or ARRAY_N.
+ */
+function backpress_convert_object( &$object, $output ) {
+	if ( is_array( $object ) ) {
+		foreach ( array_keys( $object ) as $key )
+			backpress_convert_object( $object[$key], $output );
+	} else {
+		switch ( $output ) {
+			case OBJECT  : break;
+			case ARRAY_A : $object = get_object_vars($object); break;
+			case ARRAY_N : $object = array_values(get_object_vars($object)); break;
+		}
+	}
+}
+
+/**
+ * Parse and execute queries for updating a set of database tables.
+ *
+ * Copied from wp-admin/includes/upgrade.php, this will take care of creating
+ * the bbPress stand-alone tables without loading a conflicting WP Admin.
+ *
+ * @see dbDelta() for a description of parameters and return value.
+ *
+ * @param array $queries See {@link dbDelta()}.
+ * @param bool $execute See {@link dbDelta()}.
+ * @return array See {@link dbDelta()}.
+ */
+function bp_bb_dbDelta($queries, $execute = true) {
+	global $wpdb;
+
+	// Separate individual queries into an array
+	if ( !is_array($queries) ) {
+		$queries = explode( ';', $queries );
+		if ('' == $queries[count($queries) - 1]) array_pop($queries);
+	}
+
+	$cqueries = array(); // Creation Queries
+	$iqueries = array(); // Insertion Queries
+	$for_update = array();
+
+	// Create a tablename index for an array ($cqueries) of queries
+	foreach($queries as $qry) {
+		if (preg_match("|CREATE TABLE ([^ ]*)|", $qry, $matches)) {
+			$cqueries[trim( strtolower($matches[1]), '`' )] = $qry;
+			$for_update[$matches[1]] = 'Created table '.$matches[1];
+		} else if (preg_match("|CREATE DATABASE ([^ ]*)|", $qry, $matches)) {
+			array_unshift($cqueries, $qry);
+		} else if (preg_match("|INSERT INTO ([^ ]*)|", $qry, $matches)) {
+			$iqueries[] = $qry;
+		} else if (preg_match("|UPDATE ([^ ]*)|", $qry, $matches)) {
+			$iqueries[] = $qry;
+		} else {
+			// Unrecognized query type
+		}
+	}
+
+	// Check to see which tables and fields exist
+	if ($tables = $wpdb->get_col('SHOW TABLES;')) {
+		// For every table in the database
+		foreach ($tables as $table) {
+			// Upgrade global tables only for the main site. Don't upgrade at all if DO_NOT_UPGRADE_GLOBAL_TABLES is defined.
+			if ( in_array($table, $wpdb->tables('global')) && ( !is_main_site() || defined('DO_NOT_UPGRADE_GLOBAL_TABLES') ) )
+				continue;
+
+			// If a table query exists for the database table...
+			if ( array_key_exists(strtolower($table), $cqueries) ) {
+				// Clear the field and index arrays
+				$cfields = $indices = array();
+				// Get all of the field names in the query from between the parens
+				preg_match("|\((.*)\)|ms", $cqueries[strtolower($table)], $match2);
+				$qryline = trim($match2[1]);
+
+				// Separate field lines into an array
+				$flds = explode("\n", $qryline);
+
+				//echo "<hr/><pre>\n".print_r(strtolower($table), true).":\n".print_r($cqueries, true)."</pre><hr/>";
+
+				// For every field line specified in the query
+				foreach ($flds as $fld) {
+					// Extract the field name
+					preg_match("|^([^ ]*)|", trim($fld), $fvals);
+					$fieldname = trim( $fvals[1], '`' );
+
+					// Verify the found field name
+					$validfield = true;
+					switch (strtolower($fieldname)) {
+					case '':
+					case 'primary':
+					case 'index':
+					case 'fulltext':
+					case 'unique':
+					case 'key':
+						$validfield = false;
+						$indices[] = trim(trim($fld), ", \n");
+						break;
+					}
+					$fld = trim($fld);
+
+					// If it's a valid field, add it to the field array
+					if ($validfield) {
+						$cfields[strtolower($fieldname)] = trim($fld, ", \n");
+					}
+				}
+
+				// Fetch the table column structure from the database
+				$tablefields = $wpdb->get_results("DESCRIBE {$table};");
+
+				// For every field in the table
+				foreach ($tablefields as $tablefield) {
+					// If the table field exists in the field array...
+					if (array_key_exists(strtolower($tablefield->Field), $cfields)) {
+						// Get the field type from the query
+						preg_match("|".$tablefield->Field." ([^ ]*( unsigned)?)|i", $cfields[strtolower($tablefield->Field)], $matches);
+						$fieldtype = $matches[1];
+
+						// Is actual field type different from the field type in query?
+						if ($tablefield->Type != $fieldtype) {
+							// Add a query to change the column type
+							$cqueries[] = "ALTER TABLE {$table} CHANGE COLUMN {$tablefield->Field} " . $cfields[strtolower($tablefield->Field)];
+							$for_update[$table.'.'.$tablefield->Field] = "Changed type of {$table}.{$tablefield->Field} from {$tablefield->Type} to {$fieldtype}";
+						}
+
+						// Get the default value from the array
+							//echo "{$cfields[strtolower($tablefield->Field)]}<br>";
+						if (preg_match("| DEFAULT '(.*)'|i", $cfields[strtolower($tablefield->Field)], $matches)) {
+							$default_value = $matches[1];
+							if ($tablefield->Default != $default_value) {
+								// Add a query to change the column's default value
+								$cqueries[] = "ALTER TABLE {$table} ALTER COLUMN {$tablefield->Field} SET DEFAULT '{$default_value}'";
+								$for_update[$table.'.'.$tablefield->Field] = "Changed default value of {$table}.{$tablefield->Field} from {$tablefield->Default} to {$default_value}";
+							}
+						}
+
+						// Remove the field from the array (so it's not added)
+						unset($cfields[strtolower($tablefield->Field)]);
+					} else {
+						// This field exists in the table, but not in the creation queries?
+					}
+				}
+
+				// For every remaining field specified for the table
+				foreach ($cfields as $fieldname => $fielddef) {
+					// Push a query line into $cqueries that adds the field to that table
+					$cqueries[] = "ALTER TABLE {$table} ADD COLUMN $fielddef";
+					$for_update[$table.'.'.$fieldname] = 'Added column '.$table.'.'.$fieldname;
+				}
+
+				// Index stuff goes here
+				// Fetch the table index structure from the database
+				$tableindices = $wpdb->get_results("SHOW INDEX FROM {$table};");
+
+				if ($tableindices) {
+					// Clear the index array
+					unset($index_ary);
+
+					// For every index in the table
+					foreach ($tableindices as $tableindex) {
+						// Add the index to the index data array
+						$keyname = $tableindex->Key_name;
+						$index_ary[$keyname]['columns'][] = array('fieldname' => $tableindex->Column_name, 'subpart' => $tableindex->Sub_part);
+						$index_ary[$keyname]['unique'] = ($tableindex->Non_unique == 0)?true:false;
+					}
+
+					// For each actual index in the index array
+					foreach ($index_ary as $index_name => $index_data) {
+						// Build a create string to compare to the query
+						$index_string = '';
+						if ($index_name == 'PRIMARY') {
+							$index_string .= 'PRIMARY ';
+						} else if($index_data['unique']) {
+							$index_string .= 'UNIQUE ';
+						}
+						$index_string .= 'KEY ';
+						if ($index_name != 'PRIMARY') {
+							$index_string .= $index_name;
+						}
+						$index_columns = '';
+						// For each column in the index
+						foreach ($index_data['columns'] as $column_data) {
+							if ($index_columns != '') $index_columns .= ',';
+							// Add the field to the column list string
+							$index_columns .= $column_data['fieldname'];
+							if ($column_data['subpart'] != '') {
+								$index_columns .= '('.$column_data['subpart'].')';
+							}
+						}
+						// Add the column list to the index create string
+						$index_string .= ' ('.$index_columns.')';
+						if (!(($aindex = array_search($index_string, $indices)) === false)) {
+							unset($indices[$aindex]);
+							//echo "<pre style=\"border:1px solid #ccc;margin-top:5px;\">{$table}:<br />Found index:".$index_string."</pre>\n";
+						}
+						//else echo "<pre style=\"border:1px solid #ccc;margin-top:5px;\">{$table}:<br /><b>Did not find index:</b>".$index_string."<br />".print_r($indices, true)."</pre>\n";
+					}
+				}
+
+				// For every remaining index specified for the table
+				foreach ( (array) $indices as $index ) {
+					// Push a query line into $cqueries that adds the index to that table
+					$cqueries[] = "ALTER TABLE {$table} ADD $index";
+					$for_update[$table.'.'.$fieldname] = 'Added index '.$table.' '.$index;
+				}
+
+				// Remove the original table creation query from processing
+				unset($cqueries[strtolower($table)]);
+				unset($for_update[strtolower($table)]);
+			} else {
+				// This table exists in the database, but not in the creation queries?
+			}
+		}
+	}
+
+	$allqueries = array_merge($cqueries, $iqueries);
+	if ($execute) {
+		foreach ($allqueries as $query) {
+			//echo "<pre style=\"border:1px solid #ccc;margin-top:5px;\">".print_r($query, true)."</pre>\n";
+			$wpdb->query($query);
+		}
+	}
+
+	return $for_update;
+}
Index: /tags/1.9/bp-forums/bp-forums-bbpress.php
===================================================================
--- /tags/1.9/bp-forums/bp-forums-bbpress.php	(revision 7684)
+++ /tags/1.9/bp-forums/bp-forums-bbpress.php	(revision 7684)
@@ -0,0 +1,7 @@
+<?php
+/**
+ * Placeholder for bbPress plugin bridge
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
Index: /tags/1.9/bp-forums/bp-forums-filters.php
===================================================================
--- /tags/1.9/bp-forums/bp-forums-filters.php	(revision 7684)
+++ /tags/1.9/bp-forums/bp-forums-filters.php	(revision 7684)
@@ -0,0 +1,234 @@
+<?php
+/**
+ * BuddyPress Forums Filters.
+ *
+ * @package BuddyPress
+ * @subpackage Forums
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/* Apply WordPress defined filters */
+add_filter( 'bp_forums_bbconfig_location', 'wp_filter_kses', 1 );
+add_filter( 'bp_forums_bbconfig_location', 'esc_attr', 1 );
+
+add_filter( 'bp_get_the_topic_title', 'wp_filter_kses', 1 );
+add_filter( 'bp_get_the_topic_latest_post_excerpt', 'bp_forums_filter_kses', 1 );
+add_filter( 'bp_get_the_topic_post_content', 'bp_forums_filter_kses', 1 );
+
+add_filter( 'bp_get_the_topic_title', 'force_balance_tags' );
+add_filter( 'bp_get_the_topic_latest_post_excerpt', 'force_balance_tags' );
+add_filter( 'bp_get_the_topic_post_content', 'force_balance_tags' );
+
+add_filter( 'bp_get_the_topic_title', 'wptexturize' );
+add_filter( 'bp_get_the_topic_poster_name', 'wptexturize' );
+add_filter( 'bp_get_the_topic_last_poster_name', 'wptexturize' );
+add_filter( 'bp_get_the_topic_post_content', 'wptexturize' );
+add_filter( 'bp_get_the_topic_post_poster_name', 'wptexturize' );
+
+add_filter( 'bp_get_the_topic_title', 'convert_smilies' );
+add_filter( 'bp_get_the_topic_latest_post_excerpt', 'convert_smilies' );
+add_filter( 'bp_get_the_topic_post_content', 'convert_smilies' );
+
+add_filter( 'bp_get_the_topic_title', 'convert_chars' );
+add_filter( 'bp_get_the_topic_latest_post_excerpt', 'convert_chars' );
+add_filter( 'bp_get_the_topic_post_content', 'convert_chars' );
+
+add_filter( 'bp_get_the_topic_post_content', 'wpautop' );
+add_filter( 'bp_get_the_topic_latest_post_excerpt', 'wpautop' );
+
+add_filter( 'bp_get_the_topic_post_content', 'stripslashes_deep' );
+add_filter( 'bp_get_the_topic_title', 'stripslashes_deep' );
+add_filter( 'bp_get_the_topic_latest_post_excerpt', 'stripslashes_deep' );
+add_filter( 'bp_get_the_topic_poster_name', 'stripslashes_deep' );
+add_filter( 'bp_get_the_topic_last_poster_name', 'stripslashes_deep' );
+add_filter( 'bp_get_the_topic_object_name', 'stripslashes_deep' );
+
+add_filter( 'bp_get_the_topic_post_content', 'make_clickable', 9 );
+
+add_filter( 'bp_get_forum_topic_count_for_user', 'bp_core_number_format' );
+add_filter( 'bp_get_forum_topic_count', 'bp_core_number_format' );
+
+add_filter( 'bp_get_the_topic_title', 'bp_forums_make_nofollow_filter' );
+add_filter( 'bp_get_the_topic_latest_post_excerpt', 'bp_forums_make_nofollow_filter' );
+add_filter( 'bp_get_the_topic_post_content', 'bp_forums_make_nofollow_filter' );
+
+/**
+ * Custom KSES filter for the Forums component.
+ *
+ * @param string $content Content to sanitize.
+ * @return string Sanitized string.
+ */
+function bp_forums_filter_kses( $content ) {
+	global $allowedtags;
+
+	$forums_allowedtags = $allowedtags;
+	$forums_allowedtags['span'] = array();
+	$forums_allowedtags['span']['class'] = array();
+	$forums_allowedtags['div'] = array();
+	$forums_allowedtags['div']['class'] = array();
+	$forums_allowedtags['div']['id'] = array();
+	$forums_allowedtags['a']['class'] = array();
+	$forums_allowedtags['img'] = array();
+	$forums_allowedtags['br'] = array();
+	$forums_allowedtags['p'] = array();
+	$forums_allowedtags['img']['src'] = array();
+	$forums_allowedtags['img']['alt'] = array();
+	$forums_allowedtags['img']['class'] = array();
+	$forums_allowedtags['img']['width'] = array();
+	$forums_allowedtags['img']['height'] = array();
+	$forums_allowedtags['img']['class'] = array();
+	$forums_allowedtags['img']['id'] = array();
+	$forums_allowedtags['code'] = array();
+	$forums_allowedtags['blockquote'] = array();
+
+	$forums_allowedtags = apply_filters( 'bp_forums_allowed_tags', $forums_allowedtags );
+	return wp_kses( $content, $forums_allowedtags );
+}
+
+/**
+ * Get a link for a forum topic tags directory.
+ *
+ * @param string $link Link passed from filter.
+ * @param string $tag Name of the tag.
+ * @param string $page Page number, passed from the filter.
+ * @param string $context Passed from the filter but unused here.
+ * @return string Link of the form http://example.com/forums/tag/tagname/.
+ */
+function bp_forums_filter_tag_link( $link, $tag, $page, $context ) {
+	global $bp;
+
+	return apply_filters( 'bp_forums_filter_tag_link', bp_get_root_domain() . '/' . bp_get_forums_root_slug() . '/tag/' . $tag . '/' );
+}
+add_filter( 'bb_get_tag_link', 'bp_forums_filter_tag_link', 10, 4);
+
+/**
+ * Add rel="nofollow" to bbPress content.
+ *
+ * @param string $text Post content.
+ * @return string Modified post content.
+ */
+function bp_forums_make_nofollow_filter( $text ) {
+	return preg_replace_callback( '|<a (.+?)>|i', 'bp_forums_make_nofollow_filter_callback', $text );
+}
+	/**
+	 * Callback for preg_replace_callback() in bp_forums_make_nofollow_filter().
+	 *
+	 * @param array $matches Regex matches from {@link bp_forums_make_nofollow_filter()}.
+	 * @return string Text with nofollow links.
+	 */
+	function bp_forums_make_nofollow_filter_callback( $matches ) {
+		$text = $matches[1];
+		$text = str_replace( array( ' rel="nofollow"', " rel='nofollow'"), '', $text );
+		return "<a $text rel=\"nofollow\">";
+	}
+
+/**
+ * Append forum topic to page title.
+ *
+ * @global object $bp Global BuddyPress settings object.
+ *
+ * @see bp_modify_page_title()
+ *
+ * @param string $title New page title; see {@link bp_modify_page_title()}.
+ * @param string $original_title Original page title.
+ * @param string $sep How to separate the various items within the page title.
+ * @param string $seplocation Direction to display title.
+ * @return string Page title with forum topic title appended.
+ */
+function bp_forums_add_forum_topic_to_page_title( $title, $original_title, $sep, $seplocation  ) {
+	global $bp;
+
+	if ( bp_is_current_action( 'forum' ) && bp_is_action_variable( 'topic', 0 ) )
+		if ( bp_has_forum_topic_posts() )
+			$title .= bp_get_the_topic_title() . " $sep ";
+
+	return $title;
+}
+add_filter( 'bp_modify_page_title', 'bp_forums_add_forum_topic_to_page_title', 9, 4 );
+
+/**
+ * Remove the anchor tag autogenerated for at-mentions when forum topics and posts are edited.
+ *
+ * Prevents embedded anchor tags.
+ *
+ * @global object $bp Global BuddyPress settings object.
+ *
+ * @param string $content Edited post content.
+ * @return string $content Sanitized post content.
+ */
+function bp_forums_strip_mentions_on_post_edit( $content ) {
+	global $bp;
+
+	$content = htmlspecialchars_decode( $content );
+
+	$pattern = "|<a href=&#039;" . bp_get_root_domain() . "/" . bp_get_members_root_slug() . "/[A-Za-z0-9-_\.]+/&#039; rel=&#039;nofollow&#039;>(@[A-Za-z0-9-_\.@]+)</a>|";
+
+	$content = preg_replace( $pattern, "$1", $content );
+
+	return $content;
+}
+add_filter( 'bp_get_the_topic_post_edit_text', 'bp_forums_strip_mentions_on_post_edit' );
+add_filter( 'bp_get_the_topic_text', 'bp_forums_strip_mentions_on_post_edit' );
+
+/** "Replied to" SQL filters *************************************************/
+
+/**
+ * Filter the get_topics_distinct portion of the Forums SQL when on a user's Replied To page.
+ *
+ * This filter is added in bp_has_forum_topics().
+ *
+ * @since BuddyPress (1.5.0)
+ *
+ * @param string $sql SQL fragment.
+ * @return string $sql SQL fragment of the form "DISTINCT t.topic_id, ".
+ */
+function bp_forums_add_replied_distinct_sql( $sql ) {
+	$sql = "DISTINCT t.topic_id, ";
+
+	return $sql;
+}
+
+/**
+ * Filter the get_topics_join portion of the Forums sql when on a user's Replied To page.
+ *
+ * This filter is added in bp_has_forum_topics().
+ *
+ * @since BuddyPress (1.5.0)
+ *
+ * @global object $bbdb The bbPress database global.
+ *
+ * @param string $sql SQL statement.
+ * @return string $sql SQL statement.
+ */
+function bp_forums_add_replied_join_sql( $sql ) {
+	global $bbdb;
+
+	$sql .= " LEFT JOIN {$bbdb->posts} p ON p.topic_id = t.topic_id ";
+
+	return $sql;
+}
+
+/**
+ * Filter the get_topics_where portion of the Forums sql when on a user's Replied To page.
+ *
+ * This filter is added in bp_has_forum_topics().
+ *
+ * @since BuddyPress (1.5.0)
+ *
+ * @global object $wpdb The WordPress database global.
+ *
+ * @param string $sql SQL fragment.
+ * @return string $sql SQL fragment.
+ */
+function bp_forums_add_replied_where_sql( $sql ) {
+	global $wpdb;
+
+	$sql .= $wpdb->prepare( " AND p.poster_id = %s ", bp_displayed_user_id() );
+
+	// Remove any topic_author information
+	$sql = str_replace( " AND t.topic_poster = '" . bp_displayed_user_id() . "'", '', $sql );
+
+	return $sql;
+}
Index: /tags/1.9/bp-forums/bp-forums-functions.php
===================================================================
--- /tags/1.9/bp-forums/bp-forums-functions.php	(revision 7684)
+++ /tags/1.9/bp-forums/bp-forums-functions.php	(revision 7684)
@@ -0,0 +1,982 @@
+<?php
+/**
+ * BuddyPress Forums Functions.
+ *
+ * @package BuddyPress
+ * @subpackage Forums
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/** bbPress 2.x ***************************************************************/
+
+/**
+ * Is see bbPress 2.x is installed and active?
+ *
+ * @since BuddyPress (1.6.0)
+ *
+ * @return boolean True if bbPress 2.x is active, false if not.
+ */
+function bp_forums_is_bbpress_active() {
+
+	// Single site
+	if ( is_plugin_active( 'bbpress/bbpress.php' ) )
+		return true;
+
+	// Network active
+	if ( is_plugin_active_for_network( 'bbpress/bbpress.php' ) )
+		return true;
+
+	// Nope
+	return false;
+}
+
+/** bbPress 1.x ***************************************************************/
+
+/**
+ * See if bbPress 1.x is installed correctly.
+ *
+ * "Installed correctly" means that the bb-config-location option is set, and
+ * the referenced file exists.
+ *
+ * @since BuddyPress (1.2.0)
+ *
+ * @return boolean True if option exists, false if not.
+ */
+function bp_forums_is_installed_correctly() {
+	$bp = buddypress();
+
+	if ( isset( $bp->forums->bbconfig ) && is_file( $bp->forums->bbconfig ) )
+		return true;
+
+	return false;
+}
+
+/**
+ * Does the forums component have a directory page registered?
+ *
+ * Checks $bp pages global and looks for directory page
+ *
+ * @since BuddyPress (1.5.0)
+ *
+ * @global BuddyPress $bp The one true BuddyPress instance.
+ *
+ * @return bool True if set, False if empty.
+ */
+function bp_forums_has_directory() {
+	return (bool) !empty( buddypress()->pages->forums->id );
+}
+
+/** Forum Functions ***********************************************************/
+
+/**
+ * Get a forum by ID.
+ *
+ * Wrapper for {@link bb_get_forum()}.
+ *
+ * @param int $forum_id ID of the forum being fetched.
+ * @return object bbPress forum object.
+ */
+function bp_forums_get_forum( $forum_id ) {
+	do_action( 'bbpress_init' );
+	return bb_get_forum( $forum_id );
+}
+
+/**
+ * Create a forum.
+ *
+ * Wrapper for {@link bb_new_forum()}.
+ *
+ * @param array $args {
+ *     Forum setup arguments.
+ *     @type string $forum_name Name of the forum.
+ *     @type string $forum_desc Description of the forum.
+ *     @type int $forum_parent_id ID of the forum parent. Default: value of
+ *           {@link bp_forums_parent_forums_id()}.
+ *     @type bool $forum_order Order.
+ *     @type int $forum_is_category Whether the forum is a category. Default: 0.
+ * }
+ * @return int ID of the newly created forum.
+ */
+function bp_forums_new_forum( $args = '' ) {
+	do_action( 'bbpress_init' );
+
+	$r = wp_parse_args( $args, array(
+		'forum_name'        => '',
+		'forum_desc'        => '',
+		'forum_parent_id'   => bp_forums_parent_forum_id(),
+		'forum_order'       => false,
+		'forum_is_category' => 0
+	) );
+	extract( $r, EXTR_SKIP );
+
+	return bb_new_forum( array( 'forum_name' => stripslashes( $forum_name ), 'forum_desc' => stripslashes( $forum_desc ), 'forum_parent' => $forum_parent_id, 'forum_order' => $forum_order, 'forum_is_category' => $forum_is_category ) );
+}
+
+/**
+ * Update a forum.
+ *
+ * Wrapper for {@link bb_update_forum(}.
+ *
+ * @param array $args {
+ *     Forum setup arguments.
+ *     @type int $forum_id ID of the forum to be updated.
+ *     @type string $forum_name Name of the forum.
+ *     @type string $forum_desc Description of the forum.
+ *     @type int $forum_parent_id ID of the forum parent. Default: value of
+ *           {@link bp_forums_parent_forums_id()}.
+ *     @type bool $forum_order Order.
+ *     @type int $forum_is_category Whether the forum is a category. Default: 0.
+ * }
+ * @return bool Ttrue on success, false on failure.
+ */
+function bp_forums_update_forum( $args = '' ) {
+	do_action( 'bbpress_init' );
+
+	$r = wp_parse_args( $args, array(
+		'forum_id'          => '',
+		'forum_name'        => '',
+		'forum_desc'        => '',
+		'forum_slug'        => '',
+		'forum_parent_id'   => bp_forums_parent_forum_id(),
+		'forum_order'       => false,
+		'forum_is_category' => 0
+	) );
+	extract( $r, EXTR_SKIP );
+
+	return bb_update_forum( array( 'forum_id' => (int) $forum_id, 'forum_name' => stripslashes( $forum_name ), 'forum_desc' => stripslashes( $forum_desc ), 'forum_slug' => stripslashes( $forum_slug ), 'forum_parent' => $forum_parent_id, 'forum_order' => $forum_order, 'forum_is_category' => $forum_is_category ) );
+}
+
+/**
+ * Delete a group forum by the group id.
+ *
+ * @param int $group_id ID of the group whose forum is to be deleted.
+ */
+function bp_forums_delete_group_forum( $group_id ) {
+	$forum_id = groups_get_groupmeta( $group_id, 'forum_id' );
+
+	if ( !empty( $forum_id ) && is_int( $forum_id ) ) {
+		do_action( 'bbpress_init' );
+		bb_delete_forum( $forum_id );
+	}
+}
+add_action( 'groups_delete_group', 'bp_forums_delete_group_forum' );
+
+/** Topic Functions ***********************************************************/
+
+/**
+ * Fetch a set of forum topics.
+ *
+ * @param array $args {
+ *     @type string @type Order or filter type. Default: 'newest'.
+ *     @type int $forum_id Optional. Pass a forum ID to limit results to topics
+ *           associated with that forum.
+ *     @type int $user_id Optional. Pass a user ID to limit results to topics
+ *           belonging to that user.
+ *     @type int $page Optional. Number of the results page to return.
+ *           Default: 1.
+ *     @type int $per_page Optional. Number of results to return per page.
+ *           Default: 15.
+ *     @type int $offset Optional. Numeric offset for results.
+ *     @type int $number
+ *     @type array $exclude Optional. Topic IDs to exclude.
+ *     @type string $show_stickies Whether to show sticky topics.
+ *     @type mixed $filter If $type = 'tag', filter is the tag name. Otherwise,
+ *           $filter is terms to search on.
+ * }
+ * @return array Found topics.
+ */
+function bp_forums_get_forum_topics( $args = '' ) {
+	do_action( 'bbpress_init' );
+
+	$r = wp_parse_args( $args, array(
+		'type'          => 'newest',
+		'forum_id'      => false,
+		'user_id'       => false,
+		'page'          => 1,
+		'per_page'      => 15,
+		'offset'        => false,
+		'number'        => false,
+		'exclude'       => false,
+		'show_stickies' => 'all',
+		'filter'        => false // if $type = tag then filter is the tag name, otherwise it's terms to search on.
+	) );
+	extract( $r, EXTR_SKIP );
+
+	if ( class_exists( 'BB_Query' ) ) {
+		switch ( $type ) {
+			case 'newest':
+				$query = new BB_Query( 'topic', array( 'forum_id' => $forum_id, 'topic_author_id' => $user_id, 'per_page' => $per_page, 'page' => $page, 'number' => $per_page, 'exclude' => $exclude, 'topic_title' => $filter, 'sticky' => $show_stickies, 'offset' => $offset, 'number' => $number ), 'get_latest_topics' );
+				$topics =& $query->results;
+				break;
+
+			case 'popular':
+				$query = new BB_Query( 'topic', array( 'forum_id' => $forum_id, 'topic_author_id' => $user_id, 'per_page' => $per_page, 'page' => $page, 'order_by' => 't.topic_posts', 'topic_title' => $filter, 'sticky' => $show_stickies, 'offset' => $offset, 'number' => $number ) );
+				$topics =& $query->results;
+				break;
+
+			case 'unreplied':
+				$query = new BB_Query( 'topic', array( 'forum_id' => $forum_id, 'topic_author_id' => $user_id, 'post_count' => 1, 'per_page' => $per_page, 'page' => $page, 'order_by' => 't.topic_time', 'topic_title' => $filter, 'sticky' => $show_stickies, 'offset' => $offset, 'number' => $number ) );
+				$topics =& $query->results;
+				break;
+
+			case 'tags':
+				$query = new BB_Query( 'topic', array( 'forum_id' => $forum_id, 'topic_author_id' => $user_id, 'tag' => $filter, 'per_page' => $per_page, 'page' => $page, 'order_by' => 't.topic_time', 'sticky' => $show_stickies, 'offset' => $offset, 'number' => $number ) );
+				$topics =& $query->results;
+				break;
+		}
+	} else {
+		$topics = array();
+	}
+
+	return apply_filters_ref_array( 'bp_forums_get_forum_topics', array( &$topics, &$r ) );
+}
+
+/**
+ * Get additional details about a given forum topic.
+ *
+ * @param int $topic_id ID of the topic for which you're fetching details.
+ * @return object Details about the topic.
+ */
+function bp_forums_get_topic_details( $topic_id ) {
+	do_action( 'bbpress_init' );
+
+	$query = new BB_Query( 'topic', 'topic_id=' . $topic_id . '&page=1' /* Page override so bbPress doesn't use the URI */ );
+
+	return $query->results[0];
+}
+
+/**
+ * Get the numeric ID of a topic from the topic slug.
+ *
+ * Wrapper for {@link bb_get_id_from_slug()}.
+ *
+ * @param string $topic_slug Slug of the topic.
+ * @return int|bool ID of the topic (if found), false on failure.
+ */
+function bp_forums_get_topic_id_from_slug( $topic_slug ) {
+	do_action( 'bbpress_init' );
+
+	if ( empty( $topic_slug ) )
+		return false;
+
+	return bb_get_id_from_slug( 'topic', $topic_slug );
+}
+
+/**
+ * Create a new forum topic.
+ *
+ * @param array $args {
+ *     @type string $topic_title Title of the new topic.
+ *     @type string $topic_slug Slug of the new topic.
+ *     @type string $topic_text Text of the new topic.
+ *     @type int $topic_poster ID of the user posting the topic. Default: ID of
+ *           the logged-in user.
+ *     @type string $topic_poster_name Display name of the user posting the
+ *           topic. Default: 'fullname' of the logged-in user.
+ *     @type id $topic_last_poster ID of the user who last posted to the topic.
+ *           Default: ID of the logged-in user.
+ *     @type string $topic_last_poster_name Display name of the user who last
+ *           posted to the topic. Default: 'fullname' of the logged-in user.
+ *     @type string $topic_start_time Date/time when the topic was created.
+ *           Default: the current time, as reported by bp_core_current_time().
+ *     @type string $topic_time Date/time when the topic was created.
+ *           Default: the current time, as reported by bp_core_current_time().
+ *     @type int $topic_open Whether the topic is open. Default: 1 (open).
+ *     @type array|string|bool $topic_tags Array or comma-separated list of
+ *           topic tags. False to leave empty. Default: false.
+ *     @type int $forum_id ID of the forum to which the topic belongs.
+ *           Default: 0.
+ * }
+ * @return object Details about the new topic, as returned by
+ *         {@link bp_forums_get_topic_details()}.
+ */
+function bp_forums_new_topic( $args = '' ) {
+	global $bp;
+
+	do_action( 'bbpress_init' );
+
+	$r = wp_parse_args( $args, array(
+		'topic_title'            => '',
+		'topic_slug'             => '',
+		'topic_text'             => '',
+		'topic_poster'           => bp_loggedin_user_id(),       // accepts ids
+		'topic_poster_name'      => $bp->loggedin_user->fullname, // accept names
+		'topic_last_poster'      => bp_loggedin_user_id(),       // accepts ids
+		'topic_last_poster_name' => $bp->loggedin_user->fullname, // accept names
+		'topic_start_time'       => bp_core_current_time(),
+		'topic_time'             => bp_core_current_time(),
+		'topic_open'             => 1,
+		'topic_tags'             => false, // accepts array or comma delim
+		'forum_id'               => 0      // accepts ids or slugs
+	) );
+	extract( $r, EXTR_SKIP );
+
+	$topic_title = strip_tags( $topic_title );
+
+	if ( empty( $topic_title ) || !strlen( trim( $topic_title ) ) )
+		return false;
+
+	if ( empty( $topic_poster ) )
+		return false;
+
+	if ( bp_is_user_inactive( $topic_poster ) )
+		return false;
+
+	if ( empty( $topic_slug ) )
+		$topic_slug = sanitize_title( $topic_title );
+
+	if ( !$topic_id = bb_insert_topic( array( 'topic_title' => stripslashes( $topic_title ), 'topic_slug' => $topic_slug, 'topic_poster' => $topic_poster, 'topic_poster_name' => $topic_poster_name, 'topic_last_poster' => $topic_last_poster, 'topic_last_poster_name' => $topic_last_poster_name, 'topic_start_time' => $topic_start_time, 'topic_time' => $topic_time, 'topic_open' => $topic_open, 'forum_id' => (int) $forum_id, 'tags' => $topic_tags ) ) )
+		return false;
+
+	// Now insert the first post.
+	if ( !bp_forums_insert_post( array( 'topic_id' => $topic_id, 'post_text' => $topic_text, 'post_time' => $topic_time, 'poster_id' => $topic_poster ) ) )
+		return false;
+
+	do_action( 'bp_forums_new_topic', $topic_id );
+
+	return $topic_id;
+}
+
+/**
+ * Update a topic's details.
+ *
+ * @param array $args {
+ *     Array of arguments.
+ *     @type int $topic_id ID of the topic being updated.
+ *     @type string $topic_title Updated title of the topic.
+ *     @type string $topic_title Updated text of the topic.
+ *     @type array|string|bool $topic_tags Array or comma-separated list of
+ *           topic tags. False to leave empty. Default: false.
+ * }
+ * @return object Details about the new topic, as returned by
+ *         {@link bp_forums_get_topic_details()}.
+ */
+function bp_forums_update_topic( $args = '' ) {
+	do_action( 'bbpress_init' );
+
+	$r = wp_parse_args( $args, array(
+		'topic_id'    => false,
+		'topic_title' => '',
+		'topic_text'  => '',
+		'topic_tags'  => false
+	) );
+	extract( $r, EXTR_SKIP );
+
+	// Check if the user is a spammer
+	if ( bp_is_user_inactive( bp_loggedin_user_id() ) )
+		return false;
+
+	// bb_insert_topic() will append tags, but not remove them. So we remove all existing tags.
+	bb_remove_topic_tags( $topic_id );
+
+	if ( !$topic_id = bb_insert_topic( array( 'topic_id' => $topic_id, 'topic_title' => stripslashes( $topic_title ), 'tags' => $topic_tags ) ) )
+		return false;
+
+	if ( !$post = bb_get_first_post( $topic_id ) )
+		return false;
+
+	// Update the first post
+	if ( !$post = bp_forums_insert_post( array( 'post_id' => $post->post_id, 'topic_id' => $topic_id, 'post_text' => $topic_text, 'post_time' => $post->post_time, 'poster_id' => $post->poster_id, 'poster_ip' => $post->poster_ip, 'post_status' => $post->post_status, 'post_position' => $post->post_position ) ) )
+		return false;
+
+	return bp_forums_get_topic_details( $topic_id );
+}
+
+function bp_forums_sticky_topic( $args = '' ) {
+	do_action( 'bbpress_init' );
+
+	$r = wp_parse_args( $args, array(
+		'topic_id' => false,
+		'mode'     => 'stick' // stick/unstick
+	) );
+	extract( $r, EXTR_SKIP );
+
+	if ( 'stick' == $mode )
+		return bb_stick_topic( $topic_id );
+	else if ( 'unstick' == $mode )
+		return bb_unstick_topic( $topic_id );
+
+	return false;
+}
+
+/**
+ * Set a topic's open/closed status.
+ *
+ * @param array $args {
+ *     @type int $topic_id ID of the topic whose status is being changed.
+ *     @type string $mode New status of the topic. 'open' or 'close'.
+ *           Default: 'close'.
+ * }
+ * @return bool True on success, false on failure.
+ */
+function bp_forums_openclose_topic( $args = '' ) {
+	do_action( 'bbpress_init' );
+
+	$r = wp_parse_args( $args, array(
+		'topic_id' => false,
+		'mode'     => 'close' // stick/unstick
+	) );
+	extract( $r, EXTR_SKIP );
+
+	if ( 'close' == $mode )
+		return bb_close_topic( $topic_id );
+	else if ( 'open' == $mode )
+		return bb_open_topic( $topic_id );
+
+	return false;
+}
+
+/**
+ * Delete a topic.
+ *
+ * @param array $args {
+ *     @type int $topic_id ID of the topic being deleted.
+ * }
+ * @return bool True on success, false on failure.
+ */
+function bp_forums_delete_topic( $args = '' ) {
+	do_action( 'bbpress_init' );
+
+	$r = wp_parse_args( $args, array(
+		'topic_id' => false
+	) );
+	extract( $r, EXTR_SKIP );
+
+	return bb_delete_topic( $topic_id, 1 );
+}
+
+/**
+ * Get a count of the total topics on the site.
+ *
+ * @return int $count Total topic count.
+ */
+function bp_forums_total_topic_count() {
+	global $bbdb;
+
+	do_action( 'bbpress_init' );
+
+	if ( isset( $bbdb ) ) {
+		if ( bp_is_active( 'groups' ) ) {
+			$groups_table_sql = groups_add_forum_tables_sql();
+			$groups_where_sql = groups_add_forum_where_sql( "t.topic_status = 0" );
+		} else {
+			$groups_table_sql = '';
+			$groups_where_sql = "t.topic_status = 0";
+		}
+		$count = $bbdb->get_results( "SELECT t.topic_id FROM {$bbdb->topics} AS t {$groups_table_sql} WHERE {$groups_where_sql}" );
+		$count = count( (array) $count );
+	} else {
+		$count = 0;
+	}
+
+	return apply_filters( 'bp_forums_total_topic_count', $count );
+}
+
+/**
+ * Check to see whether a user has already left this particular reply on a given post.
+ *
+ * Used to prevent dupes.
+ *
+ * @since BuddyPress (1.6.0)
+ *
+ * @param string $text The text of the comment.
+ * @param int $topic_id The topic id.
+ * @param int $user_id The user id.
+ * @return bool True if a duplicate reply exists, otherwise false.
+ */
+function bp_forums_reply_exists( $text = '', $topic_id = 0, $user_id = 0 ) {
+
+	$reply_exists = false;
+
+	if ( $text && $topic_id && $user_id ) {
+		do_action( 'bbpress_init' );
+
+		$args = array(
+			'post_author_id' => $user_id,
+			'topic_id'       => $topic_id
+		);
+
+		// Set the reply_exists_text so we can check it in the filter below
+		buddypress()->forums->reply_exists_text = $text;
+
+		// BB_Query's post_text parameter does a MATCH, while we need exact matches
+		add_filter( 'get_posts_where', '_bp_forums_reply_exists_posts_where' );
+		$query = new BB_Query( 'post', $args );
+		remove_filter( 'get_posts_where', '_bp_forums_reply_exists_posts_where' );
+
+		// Cleanup
+		unset( buddypress()->forums->reply_exists_text );
+
+		$reply_exists = (bool) !empty( $query->results );
+	}
+
+	return (bool) apply_filters( 'bp_forums_reply_exists', $reply_exists, $text, $topic_id, $user_id );
+}
+	/**
+	 * Private one-time-use function used in conjunction with bp_forums_reply_exists()
+	 *
+	 * @access private
+	 * @since BuddyPress (1.7.0)
+	 *
+	 * @global WPDB $wpdb WordPress database access object.
+	 *
+	 * @param string $where SQL fragment.
+	 * @return string SQL fragment.
+	 */
+	function _bp_forums_reply_exists_posts_where( $where = '' ) {
+		return $where . " AND p.post_text = '" . buddypress()->forums->reply_exists_text . "'";
+	}
+
+/**
+ * Get a total "Topics Started" count for a given user.
+ *
+ * @param int $user_id ID of the user being queried. Falls back on displayed
+ *        user, then loggedin.
+ * @param string $type The current filter/sort type. 'active', 'popular',
+ *        'unreplied'.
+ * @return int $count The topic count.
+ */
+function bp_forums_total_topic_count_for_user( $user_id = 0, $type = 'active' ) {
+	do_action( 'bbpress_init' );
+
+	if ( !$user_id )
+		$user_id = ( bp_displayed_user_id() ) ? bp_displayed_user_id() : bp_loggedin_user_id();
+
+	if ( class_exists( 'BB_Query' ) ) {
+		$args = array(
+			'topic_author_id' => $user_id,
+			'page' 		  => 1,
+			'per_page'	  => -1,
+			'count'		  => true
+		);
+
+		if ( 'unreplied' == $type )
+			$args['post_count'] = 1;
+
+		$query = new BB_Query( 'topic', $args );
+		$count = $query->count;
+		$query = null;
+	} else {
+		$count = 0;
+	}
+
+	return $count;
+}
+
+/**
+ * Return the total number of topics replied to by a given user.
+ *
+ * Uses an unfortunate technique to count unique topics, due to limitations in
+ * BB_Query.
+ *
+ * @since BuddyPress (1.5.0)
+ *
+ * @param int $user_id ID of the user whose replied topics are being counted.
+ *        Defaults to displayed user, then to logged-in user.
+ * @return int $count Topic count.
+ */
+function bp_forums_total_replied_count_for_user( $user_id = 0, $type = 'active' ) {
+	do_action( 'bbpress_init' );
+
+	if ( !$user_id )
+		$user_id = ( bp_displayed_user_id() ) ? bp_displayed_user_id() : bp_loggedin_user_id();
+
+	if ( !$user_id )
+		return 0;
+
+	if ( class_exists( 'BB_Query' ) ) {
+		$query = new BB_Query( 'post', array( 'post_author_id' => $user_id, 'page' => 1, 'per_page' => -1, 'count' => true ) );
+
+		// Count the unique topics. No better way to do this in the bbPress query API
+		$topics = array();
+		foreach( $query->results as $result ) {
+			if ( !in_array( $result->topic_id, $topics ) )
+				$topics[] = $result->topic_id;
+		}
+
+		// Even more unfortunate. If this is filtered by 'unreplied', we have to requery
+		if ( 'unreplied' == $type ) {
+			$topic_ids = implode( ',', $topics );
+			$topics_query = new BB_Query( 'topic', array( 'topic_id' => $topic_ids, 'page' => 1, 'per_page' => -1, 'post_count' => 1 ) );
+			$count = count( $topics_query->results );
+		} else {
+			$count = count( $topics );
+		}
+		$query = null;
+	} else {
+		$count = 0;
+	}
+
+	return apply_filters( 'bp_forums_total_replied_count_for_user', $count, $user_id );
+}
+
+/**
+ * Fetch BP-specific details for an array of topics.
+ *
+ * Done in one fell swoop to reduce query overhead. Currently determines the
+ * following:
+ * - details about the last poster
+ * - information about topic users that may have been deleted/spammed
+ *
+ * @param array $topics Array of topics.
+ * @return array $topics Topics with BP details added.
+ */
+function bp_forums_get_topic_extras( $topics ) {
+	global $wpdb, $bbdb;
+
+	if ( empty( $topics ) )
+		return $topics;
+
+	$bp = buddypress();
+
+	// Get the topic ids
+	foreach ( (array) $topics as $topic ) $topic_ids[] = $topic->topic_id;
+	$topic_ids = implode( ',', wp_parse_id_list( $topic_ids ) );
+
+	// Fetch the topic's last poster details
+	$poster_details = $wpdb->get_results( "SELECT t.topic_id, t.topic_last_poster, u.user_login, u.user_nicename, u.user_email, u.display_name FROM {$wpdb->users} u, {$bbdb->topics} t WHERE u.ID = t.topic_last_poster AND t.topic_id IN ( {$topic_ids} )" );
+	for ( $i = 0, $count = count( $topics ); $i < $count; ++$i ) {
+		foreach ( (array) $poster_details as $poster ) {
+			if ( $poster->topic_id == $topics[$i]->topic_id ) {
+				$topics[$i]->topic_last_poster_email       = $poster->user_email;
+				$topics[$i]->topic_last_poster_nicename    = $poster->user_nicename;
+				$topics[$i]->topic_last_poster_login       = $poster->user_login;
+				$topics[$i]->topic_last_poster_displayname = $poster->display_name;
+			}
+		}
+	}
+
+	// Fetch fullname for the topic's last poster
+	if ( bp_is_active( 'xprofile' ) ) {
+		$poster_names = $wpdb->get_results( "SELECT t.topic_id, pd.value FROM {$bp->profile->table_name_data} pd, {$bbdb->topics} t WHERE pd.user_id = t.topic_last_poster AND pd.field_id = 1 AND t.topic_id IN ( {$topic_ids} )" );
+		for ( $i = 0, $count = count( $topics ); $i < $count; ++$i ) {
+			foreach ( (array) $poster_names as $name ) {
+				if ( $name->topic_id == $topics[$i]->topic_id )
+					$topics[$i]->topic_last_poster_displayname = $name->value;
+			}
+		}
+	}
+
+	// Loop through to make sure that each topic has the proper values set. This covers the
+	// case of deleted users
+	foreach ( (array) $topics as $key => $topic ) {
+		if ( !isset( $topic->topic_last_poster_email ) )
+			$topics[$key]->topic_last_poster_email = '';
+
+		if ( !isset( $topic->topic_last_poster_nicename ) )
+			$topics[$key]->topic_last_poster_nicename = '';
+
+		if ( !isset( $topic->topic_last_poster_login ) )
+			$topics[$key]->topic_last_poster_login = '';
+
+		if ( !isset( $topic->topic_last_poster_displayname ) )
+			$topics[$key]->topic_last_poster_displayname = '';
+	}
+
+	return $topics;
+}
+
+/** Post Functions ************************************************************/
+
+/**
+ * Get the posts belonging to a topic.
+ *
+ * @param array $args {
+ *     @type int $topic_id ID of the topic for which posts are being fetched.
+ *     @type int $page Optional. Page of results to return. Default: 1.
+ *     @type int $page Optional. Number of results to return per page.
+ *           Default: 15.
+ *     @type string $order 'ASC' or 'DESC'. Default: 'ASC'.
+ * }
+ * @return array List of posts.
+ */
+function bp_forums_get_topic_posts( $args = '' ) {
+	do_action( 'bbpress_init' );
+
+	$defaults = array(
+		'topic_id' => false,
+		'page'     => 1,
+		'per_page' => 15,
+		'order'    => 'ASC'
+	);
+
+	$args  = wp_parse_args( $args, $defaults );
+	$query = new BB_Query( 'post', $args, 'get_thread' );
+
+	return bp_forums_get_post_extras( $query->results );
+}
+
+/**
+ * Get a single post object by ID.
+ *
+ * Wrapper for {@link bb_get_post()}.
+ *
+ * @param int $post_id ID of the post being fetched.
+ * @return object Post object.
+ */
+function bp_forums_get_post( $post_id ) {
+	do_action( 'bbpress_init' );
+	return bb_get_post( $post_id );
+}
+
+/**
+ * Delete a post.
+ *
+ * Wrapper for {@link bb_delete_post()}.
+ *
+ * @param array $args {
+ *     @type int $post_id ID of the post being deleted.
+ * }
+ * @return bool True on success, false on failure.
+ */
+function bp_forums_delete_post( $args = '' ) {
+	do_action( 'bbpress_init' );
+
+	$r = wp_parse_args( $args, array(
+		'post_id' => false
+	) );
+
+	extract( $r, EXTR_SKIP );
+
+	return bb_delete_post( $post_id, 1 );
+}
+
+/**
+ * Create a new post.
+ *
+ * @param array $args {
+ *     @type int $post_id Optional. ID of an existing post, if you want to
+ *           update rather than create. Default: false.
+ *     @type int $topic_id ID of the topic to which the post belongs.
+ *     @type string $post_text Contents of the post.
+ *     @type string $post_time Optional. Time when the post was recorded.
+ *           Default: current time, as reported by {@link bp_core_current_time()}.
+ *     @type int $poster_id Optional. ID of the user creating the post.
+ *           Default: ID of the logged-in user.
+ *     @type string $poster_ip Optional. IP address of the user creating the
+ *           post. Default: the IP address found in $_SERVER['REMOTE_ADDR'].
+ *     @type int $post_status Post status. Default: 0.
+ *     @type int $post_position Optional. Default: false (auto).
+ * }
+ * @return int|bool ID of the new post on success, false on failure.
+ */
+function bp_forums_insert_post( $args = '' ) {
+	do_action( 'bbpress_init' );
+
+	$defaults = array(
+		'post_id'       => false,
+		'topic_id'      => false,
+		'post_text'     => '',
+		'post_time'     => bp_core_current_time(),
+		'poster_id'     => bp_loggedin_user_id(), // accepts ids or names
+		'poster_ip'     => $_SERVER['REMOTE_ADDR'],
+		'post_status'   => 0, // use bb_delete_post() instead
+		'post_position' => false
+	);
+
+	$r = wp_parse_args( $args, $defaults );
+	extract( $r, EXTR_SKIP );
+
+	if ( !$post = bp_forums_get_post( $post_id ) )
+		$post_id = false;
+
+	if ( !isset( $topic_id ) )
+		$topic_id = $post->topic_id;
+
+	if ( empty( $post_text ) )
+		$post_text = $post->post_text;
+
+	if ( !isset( $post_time ) )
+		$post_time = $post->post_time;
+
+	if ( !isset( $post_position ) )
+		$post_position = $post->post_position;
+
+	if ( empty( $poster_id ) )
+		return false;
+
+	if ( bp_is_user_inactive( bp_loggedin_user_id() ) )
+		return false;
+
+	$post_id = bb_insert_post( array( 'post_id' => $post_id, 'topic_id' => $topic_id, 'post_text' => stripslashes( trim( $post_text ) ), 'post_time' => $post_time, 'poster_id' => $poster_id, 'poster_ip' => $poster_ip, 'post_status' => $post_status, 'post_position' => $post_position ) );
+
+	if ( !empty( $post_id ) )
+		do_action( 'bp_forums_new_post', $post_id );
+
+	return $post_id;
+}
+
+/**
+ * Get BP-specific details about a set of posts.
+ *
+ * Currently fetches the following:
+ * - WP userdata for each poster
+ * - BP fullname for each poster
+ *
+ * @param array $posts List of posts.
+ * @return array Posts with BP-data added.
+ */
+function bp_forums_get_post_extras( $posts ) {
+	global $bp, $wpdb;
+
+	if ( empty( $posts ) )
+		return $posts;
+
+	// Get the user ids
+	foreach ( (array) $posts as $post ) $user_ids[] = $post->poster_id;
+	$user_ids = implode( ',', wp_parse_id_list( $user_ids ) );
+
+	// Fetch the poster's user_email, user_nicename and user_login
+	$poster_details = $wpdb->get_results( "SELECT u.ID as user_id, u.user_login, u.user_nicename, u.user_email, u.display_name FROM {$wpdb->users} u WHERE u.ID IN ( {$user_ids} )" );
+
+	for ( $i = 0, $count = count( $posts ); $i < $count; ++$i ) {
+		foreach ( (array) $poster_details as $poster ) {
+			if ( $poster->user_id == $posts[$i]->poster_id ) {
+				$posts[$i]->poster_email    = $poster->user_email;
+				$posts[$i]->poster_login    = $poster->user_login;
+				$posts[$i]->poster_nicename = $poster->user_nicename;
+				$posts[$i]->poster_name     = $poster->display_name;
+			}
+		}
+	}
+
+	// Fetch fullname for each poster.
+	if ( bp_is_active( 'xprofile' ) ) {
+		$poster_names = $wpdb->get_results( "SELECT pd.user_id, pd.value FROM {$bp->profile->table_name_data} pd WHERE pd.user_id IN ( {$user_ids} )" );
+		for ( $i = 0, $count = count( $posts ); $i < $count; ++$i ) {
+			foreach ( (array) $poster_names as $name ) {
+				if ( isset( $topics[$i] ) && $name->user_id == $topics[$i]->user_id )
+				$posts[$i]->poster_name = $poster->value;
+			}
+		}
+	}
+
+	return apply_filters( 'bp_forums_get_post_extras', $posts );
+}
+
+/**
+ * Get topic and post counts for a given forum.
+ *
+ * @param int $forum_id ID of the forum.
+ * @return object Object with properties $topics (topic count) and $posts
+ *         (post count).
+ */
+function bp_forums_get_forum_topicpost_count( $forum_id ) {
+	global $wpdb, $bbdb;
+
+	do_action( 'bbpress_init' );
+
+	// Need to find a bbPress function that does this
+	return $wpdb->get_results( $wpdb->prepare( "SELECT topics, posts from {$bbdb->forums} WHERE forum_id = %d", $forum_id ) );
+}
+
+/**
+ * Map WordPress caps onto bbPress users, to ensure that they can post.
+ *
+ * @param array $allcaps Array of capabilities.
+ * @return array Caps array with bbPress caps added.
+ */
+function bp_forums_filter_caps( $allcaps ) {
+	global $wp_roles, $bb_table_prefix;
+
+	if ( !bp_loggedin_user_id() )
+		return $allcaps;
+
+	$bb_cap = bp_get_user_meta( bp_loggedin_user_id(), $bb_table_prefix . 'capabilities', true );
+
+	if ( empty( $bb_cap ) )
+		return $allcaps;
+
+	$bb_cap = array_keys($bb_cap);
+	$bb_cap = $wp_roles->get_role( $bb_cap[0] );
+	$bb_cap = $bb_cap->capabilities;
+
+	return array_merge( (array) $allcaps, (array) $bb_cap );
+}
+add_filter( 'user_has_cap', 'bp_forums_filter_caps' );
+
+/**
+ * Return the parent forum ID for the bbPress abstraction layer.
+ *
+ * @since BuddyPress (1.5.0)
+ *
+ * @return int Forum ID.
+ */
+function bp_forums_parent_forum_id() {
+	return apply_filters( 'bp_forums_parent_forum_id', BP_FORUMS_PARENT_FORUM_ID );
+}
+
+/**
+ * Should sticky topics be broken out of regular topic order on forum directories?
+ *
+ * Defaults to false. Define BP_FORUMS_ENABLE_GLOBAL_DIRECTORY_STICKIES, or
+ * filter 'bp_forums_enable_global_directory_stickies', to change this behavior.
+ *
+ * @since BuddyPress (1.5.0)
+ *
+ * @return bool True if stickies should be displayed at the top of the global
+ *         directory, otherwise false.
+ */
+function bp_forums_enable_global_directory_stickies() {
+	return apply_filters( 'bp_forums_enable_global_directory_stickies', defined( 'BP_FORUMS_ENABLE_GLOBAL_DIRECTORY_STICKIES' ) && BP_FORUMS_ENABLE_GLOBAL_DIRECTORY_STICKIES );
+}
+
+
+/** Caching ******************************************************************/
+
+/**
+ * Caching functions handle the clearing of cached objects and pages on specific
+ * actions throughout BuddyPress.
+ */
+
+// List actions to clear super cached pages on, if super cache is installed
+add_action( 'bp_forums_new_forum', 'bp_core_clear_cache' );
+add_action( 'bp_forums_new_topic', 'bp_core_clear_cache' );
+add_action( 'bp_forums_new_post',  'bp_core_clear_cache' );
+
+
+/** Embeds *******************************************************************/
+
+/**
+ * Attempt to retrieve the oEmbed cache for a forum topic.
+ *
+ * Grabs the topic post ID and attempts to retrieve the oEmbed cache (if it exists)
+ * during the forum topic loop.  If no cache and link is embeddable, cache it.
+ *
+ * @since BuddyPress (1.5.0)
+ *
+ * @see BP_Embed
+ * @see bp_embed_forum_cache()
+ * @see bp_embed_forum_save_cache()
+ */
+function bp_forums_embed() {
+	add_filter( 'embed_post_id',         'bp_get_the_topic_post_id'         );
+	add_filter( 'bp_embed_get_cache',    'bp_embed_forum_cache',      10, 3 );
+	add_action( 'bp_embed_update_cache', 'bp_embed_forum_save_cache', 10, 3 );
+}
+add_action( 'topic_loop_start', 'bp_forums_embed' );
+
+/**
+ * Used during {@link BP_Embed::parse_oembed()} via {@link bp_forums_embed()}.
+ *
+ * Wrapper function for {@link bb_get_postmeta()}.
+ *
+ * @package BuddyPress_Forums
+ * @since BuddyPress (1.5)
+ */
+function bp_embed_forum_cache( $cache, $id, $cachekey ) {
+	return bb_get_postmeta( $id, $cachekey );
+}
+
+/**
+ * Used during {@link BP_Embed::parse_oembed()} via {@link bp_forums_embed()}.
+ *
+ * Wrapper function for {@link bb_update_postmeta()}.
+ *
+ * @since BuddyPress (1.5.0)
+ */
+function bp_embed_forum_save_cache( $cache, $cachekey, $id ) {
+	bb_update_postmeta( $id, $cachekey, $cache );
+}
Index: /tags/1.9/bp-forums/bp-forums-loader.php
===================================================================
--- /tags/1.9/bp-forums/bp-forums-loader.php	(revision 7684)
+++ /tags/1.9/bp-forums/bp-forums-loader.php	(revision 7684)
@@ -0,0 +1,261 @@
+<?php
+
+/**
+ * BuddyPress Forums Loader
+ *
+ * A discussion forums component. Comes bundled with bbPress stand-alone.
+ *
+ * Note: The bp-forums component has been retired. Use the bbPress WordPress
+ * plugin instead.
+ *
+ * @package BuddyPress
+ * @subpackage Forums
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+class BP_Forums_Component extends BP_Component {
+
+	/**
+	 * Start the forums component creation process.
+	 *
+	 * @since BuddyPress (1.5.0)
+	 */
+	function __construct() {
+		parent::start(
+			'forums',
+			__( 'Discussion Forums', 'buddypress' ),
+			BP_PLUGIN_DIR,
+			array(
+				'adminbar_myaccount_order' => 80
+			)
+		);
+	}
+
+	/**
+	 * Set up bp-forums global settings.
+	 *
+	 * The BP_FORUMS_SLUG constant is deprecated, and only used here for
+	 * backwards compatibility.
+	 *
+	 * @since BuddyPress (1.5.0)
+	 *
+	 * @see BP_Component::setup_globals() for description of parameters.
+	 *
+	 * @param array $args See {@link BP_Component::setup_globals()}.
+	 */
+	public function setup_globals( $args = array() ) {
+		$bp = buddypress();
+
+		// Define the parent forum ID
+		if ( !defined( 'BP_FORUMS_PARENT_FORUM_ID' ) )
+			define( 'BP_FORUMS_PARENT_FORUM_ID', 1 );
+
+		// Define a slug, if necessary
+		if ( !defined( 'BP_FORUMS_SLUG' ) )
+			define( 'BP_FORUMS_SLUG', $this->id );
+
+		// The location of the bbPress stand-alone config file
+		if ( isset( $bp->site_options['bb-config-location'] ) )
+			$this->bbconfig = $bp->site_options['bb-config-location'];
+
+		// All globals for messaging component.
+		// Note that global_tables is included in this array.
+		$globals = array(
+			'slug'                  => BP_FORUMS_SLUG,
+			'root_slug'             => isset( $bp->pages->forums->slug ) ? $bp->pages->forums->slug : BP_FORUMS_SLUG,
+			'has_directory'         => true,
+			'notification_callback' => 'messages_format_notifications',
+			'search_string'         => __( 'Search Forums...', 'buddypress' ),
+		);
+
+		parent::setup_globals( $globals );
+	}
+
+	/**
+	 * Include bp-forums files.
+	 *
+	 * @see BP_Component::includes() for description of parameters.
+	 *
+	 * @param array $includes See {@link BP_Component::includes()}.
+	 */
+	public function includes( $includes = array() ) {
+
+		// Files to include
+		$includes = array(
+			'actions',
+			'screens',
+			'classes',
+			'filters',
+			'template',
+			'functions',
+		);
+
+		// bbPress stand-alone
+		if ( !defined( 'BB_PATH' ) )
+			$includes[] = 'bbpress-sa';
+
+		// Admin-specific code
+		if ( is_admin() ) {
+			$includes[] = 'deprecated/1.6';
+			$includes[] = 'deprecated/1.7';
+		}
+
+		parent::includes( $includes );
+	}
+
+	/**
+	 * Set up component navigation.
+	 *
+	 * @since BuddyPress (1.5.0)
+	 *
+	 * @see BP_Component::setup_nav() for a description of arguments.
+	 *
+	 * @param array $main_nav Optional. See BP_Component::setup_nav() for
+	 *        description.
+	 * @param array $sub_nav Optional. See BP_Component::setup_nav() for
+	 *        description.
+	 */
+	public function setup_nav( $main_nav = array(), $sub_nav = array() ) {
+
+		// Stop if forums haven't been set up yet
+		if ( !bp_forums_is_installed_correctly() )
+			return;
+
+		// Stop if there is no user displayed or logged in
+		if ( !is_user_logged_in() && !bp_displayed_user_id() )
+			return;
+
+		// Add 'Forums' to the main navigation
+		$main_nav = array(
+			'name'                => __( 'Forums', 'buddypress' ),
+			'slug'                => $this->slug,
+			'position'            => 80,
+			'screen_function'     => 'bp_member_forums_screen_topics',
+			'default_subnav_slug' => 'topics',
+			'item_css_id'         => $this->id
+		);
+
+		// Determine user to use
+		if ( bp_displayed_user_domain() ) {
+			$user_domain = bp_displayed_user_domain();
+		} elseif ( bp_loggedin_user_domain() ) {
+			$user_domain = bp_loggedin_user_domain();
+		} else {
+			return;
+		}
+
+		// User link
+		$forums_link = trailingslashit( $user_domain . $this->slug );
+
+		// Additional menu if friends is active
+		$sub_nav[] = array(
+			'name'            => __( 'Topics Started', 'buddypress' ),
+			'slug'            => 'topics',
+			'parent_url'      => $forums_link,
+			'parent_slug'     => $this->slug,
+			'screen_function' => 'bp_member_forums_screen_topics',
+			'position'        => 20,
+			'item_css_id'     => 'topics'
+		);
+
+		// Additional menu if friends is active
+		$sub_nav[] = array(
+			'name'            => __( 'Replied To', 'buddypress' ),
+			'slug'            => 'replies',
+			'parent_url'      => $forums_link,
+			'parent_slug'     => $this->slug,
+			'screen_function' => 'bp_member_forums_screen_replies',
+			'position'        => 40,
+			'item_css_id'     => 'replies'
+		);
+
+		parent::setup_nav( $main_nav, $sub_nav );
+	}
+
+	/**
+	 * Set up bp-forums integration with the WordPress admin bar.
+	 *
+	 * @since BuddyPress (1.5.0)
+	 *
+	 * @see BP_Component::setup_admin_bar() for a description of arguments.
+	 *
+	 * @param array $wp_admin_nav See BP_Component::setup_admin_bar()
+	 *        for description.
+	 */
+	public function setup_admin_bar( $wp_admin_nav = array() ) {
+
+		// Menus for logged in user
+		if ( is_user_logged_in() ) {
+
+			// Setup the logged in user variables
+			$forums_link = trailingslashit( bp_loggedin_user_domain() . $this->slug );
+
+			// Add the "My Account" sub menus
+			$wp_admin_nav[] = array(
+				'parent' => buddypress()->my_account_menu_id,
+				'id'     => 'my-account-' . $this->id,
+				'title'  => __( 'Forums', 'buddypress' ),
+				'href'   => trailingslashit( $forums_link )
+			);
+
+			// Topics
+			$wp_admin_nav[] = array(
+				'parent' => 'my-account-' . $this->id,
+				'id'     => 'my-account-' . $this->id . '-topics-started',
+				'title'  => __( 'Topics Started', 'buddypress' ),
+				'href'   => trailingslashit( $forums_link . 'topics' )
+			);
+
+			// Replies
+			$wp_admin_nav[] = array(
+				'parent' => 'my-account-' . $this->id,
+				'id'     => 'my-account-' . $this->id . '-replies',
+				'title'  => __( 'Replies', 'buddypress' ),
+				'href'   => trailingslashit( $forums_link . 'replies' )
+			);
+
+			// Favorites
+			$wp_admin_nav[] = array(
+				'parent' => 'my-account-' . $this->id,
+				'id'     => 'my-account-' . $this->id . '-favorite-topics',
+				'title'  => __( 'Favorite Topics', 'buddypress' ),
+				'href'   => trailingslashit( $forums_link . 'favorites' )
+			);
+		}
+
+		parent::setup_admin_bar( $wp_admin_nav );
+	}
+
+	/**
+	 * Set up the title for pages and the <title> element.
+	 */
+	function setup_title() {
+		$bp = buddypress();
+
+		// Adjust title based on view
+		if ( bp_is_forums_component() ) {
+			if ( bp_is_my_profile() ) {
+				$bp->bp_options_title = __( 'Forums', 'buddypress' );
+			} else {
+				$bp->bp_options_avatar = bp_core_fetch_avatar( array(
+					'item_id' => bp_displayed_user_id(),
+					'type'    => 'thumb',
+					'alt'     => sprintf( __( 'Profile picture of %s', 'buddypress' ), bp_get_displayed_user_fullname() )
+				) );
+				$bp->bp_options_title  = bp_get_displayed_user_fullname();
+			}
+		}
+
+		parent::setup_title();
+	}
+}
+
+/**
+ * Set up the bp-forums component.
+ */
+function bp_setup_forums() {
+	buddypress()->forums = new BP_Forums_Component();
+}
+add_action( 'bp_setup_components', 'bp_setup_forums', 6 );
Index: /tags/1.9/bp-forums/bp-forums-screens.php
===================================================================
--- /tags/1.9/bp-forums/bp-forums-screens.php	(revision 7684)
+++ /tags/1.9/bp-forums/bp-forums-screens.php	(revision 7684)
@@ -0,0 +1,235 @@
+<?php
+/**
+ * BuddyPress Forums Screen Functions.
+ *
+ * @package BuddyPress
+ * @subpackage Forums
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/**
+ * Load the Forums directory.
+ */
+function bp_forums_directory_forums_setup() {
+
+	// Get BuddyPress once
+	$bp = buddypress();
+
+	if ( bp_is_forums_component() && ( !bp_current_action() || ( 'tag' == bp_current_action() && bp_action_variables() ) ) && !bp_current_item() ) {
+		if ( !bp_forums_has_directory() )
+			return false;
+
+		if ( !bp_forums_is_installed_correctly() ) {
+			bp_core_add_message( __( 'The forums component has not been set up yet.', 'buddypress' ), 'error' );
+			bp_core_redirect( bp_get_root_domain() );
+		}
+
+		bp_update_is_directory( true, 'forums' );
+
+		do_action( 'bbpress_init' );
+
+		// Check to see if the user has posted a new topic from the forums page.
+		if ( isset( $_POST['submit_topic'] ) && bp_is_active( 'forums' ) ) {
+			check_admin_referer( 'bp_forums_new_topic' );
+
+			$bp->groups->current_group = groups_get_group( array( 'group_id' => $_POST['topic_group_id'] ) );
+			if ( !empty( $bp->groups->current_group->id ) ) {
+				// Auto join this user if they are not yet a member of this group
+				if ( !bp_current_user_can( 'bp_moderate' ) && 'public' == $bp->groups->current_group->status && !groups_is_user_member( bp_loggedin_user_id(), $bp->groups->current_group->id ) )
+					groups_join_group( $bp->groups->current_group->id );
+
+				$error_message = '';
+
+				$forum_id = groups_get_groupmeta( $bp->groups->current_group->id, 'forum_id' );
+				if ( !empty( $forum_id ) ) {
+					if ( empty( $_POST['topic_title'] ) )
+						$error_message = __( 'Please provide a title for your forum topic.', 'buddypress' );
+					else if ( empty( $_POST['topic_text'] ) )
+						$error_message = __( 'Forum posts cannot be empty. Please enter some text.', 'buddypress' );
+
+					if ( $error_message ) {
+						bp_core_add_message( $error_message, 'error' );
+						$redirect = bp_get_group_permalink( $bp->groups->current_group ) . 'forum';
+					} else {
+						if ( !$topic = groups_new_group_forum_topic( $_POST['topic_title'], $_POST['topic_text'], $_POST['topic_tags'], $forum_id ) ) {
+							bp_core_add_message( __( 'There was an error when creating the topic', 'buddypress'), 'error' );
+							$redirect = bp_get_group_permalink( $bp->groups->current_group ) . 'forum';
+						} else {
+							bp_core_add_message( __( 'The topic was created successfully', 'buddypress') );
+							$redirect = bp_get_group_permalink( $bp->groups->current_group ) . 'forum/topic/' . $topic->topic_slug . '/';
+						}
+					}
+
+					bp_core_redirect( $redirect );
+
+				} else {
+					bp_core_add_message( __( 'Please pick the group forum where you would like to post this topic.', 'buddypress' ), 'error' );
+					bp_core_redirect( add_query_arg( 'new', '', bp_get_forums_directory_permalink() ) );
+				}
+
+			}	 else {
+				bp_core_add_message( __( 'Please pick the group forum where you would like to post this topic.', 'buddypress' ), 'error' );
+				bp_core_redirect( add_query_arg( 'new', '', bp_get_forums_directory_permalink() ) );
+			}
+		}
+
+		do_action( 'bp_forums_directory_forums_setup' );
+
+		bp_core_load_template( apply_filters( 'bp_forums_template_directory_forums_setup', 'forums/index' ) );
+	}
+}
+add_action( 'bp_screens', 'bp_forums_directory_forums_setup', 2 );
+
+/**
+ * Load the Topics Started screen.
+ */
+function bp_member_forums_screen_topics() {
+	do_action( 'bp_member_forums_screen_topics' );
+
+	bp_core_load_template( apply_filters( 'bp_member_forums_screen_topics', 'members/single/home' ) );
+}
+
+/**
+ * Load the Replied To screen.
+ */
+function bp_member_forums_screen_replies() {
+	do_action( 'bp_member_forums_screen_replies' );
+
+	bp_core_load_template( apply_filters( 'bp_member_forums_screen_replies', 'members/single/home' ) );
+}
+
+/**
+ * Load the template content for a user's Favorites forum tab.
+ *
+ * Note that this feature is not fully implemented at the moment.
+ */
+function bp_member_forums_screen_favorites() {
+	do_action( 'bp_member_forums_screen_favorites' );
+
+	bp_core_load_template( apply_filters( 'bp_member_forums_screen_favorites', 'members/single/home' ) );
+}
+
+/**
+ * Load a single forum page.
+ */
+function bp_forums_screen_single_forum() {
+
+	if ( !bp_is_forums_component() || !bp_is_current_action( 'forum' ) || !bp_action_variable( 0 ) )
+		return false;
+
+	do_action( 'bp_forums_screen_single_forum' );
+
+	bp_core_load_template( apply_filters( 'bp_forums_screen_single_forum', 'forums/single/forum' ) );
+}
+add_action( 'bp_screens', 'bp_forums_screen_single_forum' );
+
+/**
+ * Load a single forum topic page.
+ */
+function bp_forums_screen_single_topic() {
+
+	if ( !bp_is_forums_component() || !bp_is_current_action( 'topic' ) || !bp_action_variable( 0 ) )
+		return false;
+
+	do_action( 'bp_forums_screen_single_topic' );
+
+	bp_core_load_template( apply_filters( 'bp_forums_screen_single_topic', 'forums/single/topic' ) );
+}
+add_action( 'bp_screens', 'bp_forums_screen_single_topic' );
+
+
+/** Theme Compatability *******************************************************/
+
+/**
+ * The main theme compat class for legacy BuddyPress forums.
+ *
+ * This class sets up the necessary theme compatability actions to safely output
+ * old forum template parts to the_title and the_content areas of a theme.
+ *
+ * @since BuddyPress (1.7.0)
+ */
+class BP_Forum_Legacy_Theme_Compat {
+
+	/**
+	 * Set up theme compatibility for the legacy forums component.
+	 *
+	 * @since BuddyPress (1.7.0)
+	 */
+	public function __construct() {
+		add_action( 'bp_setup_theme_compat', array( $this, 'is_legacy_forum' ) );
+	}
+
+	/**
+	 * Are we looking at something that needs old forum theme compatability?
+	 *
+	 * @since BuddyPress (1.7.0)
+	 */
+	public function is_legacy_forum() {
+
+		// Bail if not looking at a group
+		if ( ! bp_is_forums_component() )
+			return;
+
+		// forum Directory
+		if ( ( ! bp_current_action() || ( 'tag' == bp_current_action() && bp_action_variables() ) ) && ! bp_current_item() ) {
+
+			if ( ! bp_forums_has_directory() )
+				return false;
+
+			if ( ! bp_forums_is_installed_correctly() ) {
+				bp_core_add_message( __( 'The forums component has not been set up yet.', 'buddypress' ), 'error' );
+				bp_core_redirect( bp_get_root_domain() );
+			}
+
+			bp_update_is_directory( true, 'forums' );
+
+			do_action( 'bp_forums_directory_forums_setup' );
+
+			add_action( 'bp_template_include_reset_dummy_post_data', array( $this, 'directory_dummy_post' ) );
+			add_filter( 'bp_replace_the_content',                    array( $this, 'directory_content'    ) );
+
+		}
+
+	}
+
+	/** Directory *************************************************************/
+
+	/**
+	 * Update the global $post with directory data.
+	 *
+	 * @since BuddyPress (1.7.0)
+	 */
+	public function directory_dummy_post() {
+
+		// Title based on ability to create groups
+		if ( is_user_logged_in() ) {
+			$title = __( 'Forums', 'buddypress' ) . '&nbsp;<a class="button show-hide-new bp-title-button" href="#new-topic" id="new-topic-button">' . __( 'New Topic', 'buddypress' ) . '</a>';
+		} else {
+			$title = __( 'Forums', 'buddypress' );
+		}
+
+		bp_theme_compat_reset_post( array(
+			'ID'             => 0,
+			'post_title'     => $title,
+			'post_author'    => 0,
+			'post_date'      => 0,
+			'post_content'   => '',
+			'post_type'      => 'bp_forum',
+			'post_status'    => 'publish',
+			'is_archive'     => true,
+			'comment_status' => 'closed'
+		) );
+	}
+
+	/**
+	 * Filter the_content with the old forum index template part.
+	 *
+	 * @since BuddyPress (1.7.0)
+	 */
+	public function directory_content() {
+		return bp_buffer_template_part( 'forums/index', null, false );
+	}
+}
+new BP_Forum_Legacy_Theme_Compat();
Index: /tags/1.9/bp-forums/bp-forums-template.php
===================================================================
--- /tags/1.9/bp-forums/bp-forums-template.php	(revision 7684)
+++ /tags/1.9/bp-forums/bp-forums-template.php	(revision 7684)
@@ -0,0 +1,2422 @@
+<?php
+/**
+ * BuddyPress Forums Template Tags.
+ *
+ * @package BuddyPress
+ * @subpackage Forums
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/**
+ * Output the forums component slug.
+ *
+ * @since BuddyPress (1.5.0)
+ *
+ * @uses bp_get_forums_slug()
+ */
+function bp_forums_slug() {
+	echo bp_get_forums_slug();
+}
+	/**
+	 * Return the forums component slug.
+	 *
+	 * @since BuddyPress (1.5.0)
+	 *
+	 * @return string Slug for the forums component.
+	 */
+	function bp_get_forums_slug() {
+		global $bp;
+		return apply_filters( 'bp_get_forums_slug', $bp->forums->slug );
+	}
+
+/**
+ * Output the forums component root slug.
+ *
+ * @since BuddyPress (1.5.0)
+ *
+ * @uses bp_get_forums_root_slug()
+ */
+function bp_forums_root_slug() {
+	echo bp_get_forums_root_slug();
+}
+	/**
+	 * Return the forums component root slug.
+	 *
+	 * @since BuddyPress (1.5.0)
+	 *
+	 * @return string Root slug for the forums component.
+	 */
+	function bp_get_forums_root_slug() {
+		global $bp;
+		return apply_filters( 'bp_get_forums_root_slug', $bp->forums->root_slug );
+	}
+
+/**
+ * Output permalink for the forum directory.
+ *
+ * @since BuddyPress (1.5.0)
+ *
+ * @uses bp_get_forums_directory_permalink()
+ */
+function bp_forums_directory_permalink() {
+	echo bp_get_forums_directory_permalink();
+}
+	/**
+	 * Return permalink for the forum directory.
+	 *
+	 * @since BuddyPress (1.5.0)
+	 *
+	 * @uses apply_filters()
+	 * @uses traisingslashit()
+	 * @uses bp_get_root_domain()
+	 * @uses bp_get_forums_root_slug()
+	 *
+	 * @return string The permalink for the forums component directory.
+	 */
+	function bp_get_forums_directory_permalink() {
+		return apply_filters( 'bp_get_forums_directory_permalink', trailingslashit( bp_get_root_domain() . '/' . bp_get_forums_root_slug() ) );
+	}
+
+/**
+ * The main forums template loop class.
+ *
+ * Responsible for loading a group of forum topics into a loop for display.
+ */
+class BP_Forums_Template_Forum {
+	/**
+	 * The loop iterator.
+	 *
+	 * @access public
+	 * @var int
+	 */
+	var $current_topic = -1;
+
+	/**
+	 * The number of topics returned by the paged query.
+	 *
+	 * @access public
+	 * @var int
+	 */
+	var $topic_count;
+
+	/**
+	 * Array of topics located by the query.
+	 *
+	 * @access public
+	 * @var array
+	 */
+	var $topics;
+
+	/**
+	 * The topic object currently being iterated on.
+	 *
+	 * @access public
+	 * @var object
+	 */
+	var $topic;
+
+	/**
+	 * The ID of the forum whose topics are being queried.
+	 *
+	 * @access public
+	 * @var int
+	 */
+	var $forum_id;
+
+	/**
+	 * A flag for whether the loop is currently being iterated.
+	 *
+	 * @access public
+	 * @var bool
+	 */
+	var $in_the_loop;
+
+	/**
+	 * The page number being requested.
+	 *
+	 * @access public
+	 * @var public
+	 */
+	var $pag_page;
+
+	/**
+	 * The number of items being requested per page.
+	 *
+	 * @access public
+	 * @var public
+	 */
+	var $pag_num;
+
+	/**
+	 * An HTML string containing pagination links.
+	 *
+	 * @access public
+	 * @var string
+	 */
+	var $pag_links;
+
+	/**
+	 * The total number of topics matching the query parameters.
+	 *
+	 * @access public
+	 * @var int
+	 */
+	var $total_topic_count;
+
+	/**
+	 * Whether requesting a single topic. Not currently used.
+	 *
+	 * @access public
+	 * @var bool
+	 */
+	var $single_topic = false;
+
+	/**
+	 * Term to sort by. Not currently used.
+	 *
+	 * @access public
+	 * @var string
+	 */
+	var $sort_by;
+
+	/**
+	 * Sort order. Not currently used.
+	 *
+	 * @access public
+	 * @var string
+	 */
+	var $order;
+
+	/**
+	 * Constructor method.
+	 *
+	 * @param string $type The 'type' is the sort order/kind. 'newest',
+	 *        'popular', 'unreplied', 'tags'.
+	 * @param int $forum_id The ID of the forum for which topics are being
+	 *        queried.
+	 * @param int $user_id The ID of the user to whom topics should be
+	 *        limited. Pass false to remove this filter.
+	 * @param int $page The number of the page being requested.
+	 * @param int $per_page The number of items being requested perpage.
+	 * @param string $no_stickies Requested sticky format.
+	 * @param string $search_terms Filter results by a string.
+	 * @param int $offset Optional. Offset results by a given numeric value.
+	 * @param int $number Optional. Total number of items to retrieve.
+	 */
+	function __construct( $type, $forum_id, $user_id, $page, $per_page, $max, $no_stickies, $search_terms, $offset = false, $number = false ) {
+		global $bp;
+
+		$this->pag_page     = $page;
+		$this->pag_num      = $per_page;
+		$this->type         = $type;
+		$this->search_terms = $search_terms;
+		$this->forum_id     = $forum_id;
+		$this->offset	    = $offset;
+		$this->number	    = $number;
+
+		switch ( $type ) {
+			case 'newest': default:
+				$this->topics = bp_forums_get_forum_topics( array( 'user_id' => $user_id, 'forum_id' => $forum_id, 'filter' => $search_terms, 'page' => $this->pag_page, 'per_page' => $this->pag_num, 'show_stickies' => $no_stickies, 'offset' => $offset, 'number' => $number ) );
+				break;
+
+			case 'popular':
+				$this->topics = bp_forums_get_forum_topics( array( 'user_id' => $user_id, 'type' => 'popular', 'filter' => $search_terms, 'forum_id' => $forum_id, 'page' => $this->pag_page, 'per_page' => $this->pag_num, 'show_stickies' => $no_stickies, 'offset' => $offset, 'number' => $number ) );
+				break;
+
+			case 'unreplied':
+				$this->topics = bp_forums_get_forum_topics( array( 'user_id' => $user_id, 'type' => 'unreplied', 'filter' => $search_terms, 'forum_id' => $forum_id, 'page' => $this->pag_page, 'per_page' => $this->pag_num, 'show_stickies' => $no_stickies, 'offset' => $offset, 'number' => $number ) );
+				break;
+
+			case 'tags':
+				$this->topics = bp_forums_get_forum_topics( array( 'user_id' => $user_id, 'type' => 'tags', 'filter' => $search_terms, 'forum_id' => $forum_id, 'page' => $this->pag_page, 'per_page' => $this->pag_num, 'show_stickies' => $no_stickies, 'offset' => $offset, 'number' => $number ) );
+				break;
+		}
+
+		$this->topics = apply_filters( 'bp_forums_template_topics', $this->topics, $type, $forum_id, $per_page, $max, $no_stickies );
+
+		if ( !(int) $this->topics ) {
+			$this->topic_count       = 0;
+			$this->total_topic_count = 0;
+		} else {
+			// Get a total topic count, for use in pagination. This value will differ
+			// depending on scope
+			if ( !empty( $forum_id ) ) {
+				// Group forums
+				$topic_count = bp_forums_get_forum( $forum_id );
+				$topic_count = (int) $topic_count->topics;
+			} else if ( !empty( $bp->groups->current_group ) ) {
+				$topic_count = (int)groups_total_public_forum_topic_count( $type );
+			} else if ( bp_is_user_forums_started() || ( bp_is_directory() && $user_id ) ) {
+				// This covers the case of Profile > Forums > Topics Started, as
+				// well as Forum Directory > My Topics
+				$topic_count = bp_forums_total_topic_count_for_user( bp_displayed_user_id(), $type );
+			} else if ( bp_is_user_forums_replied_to() ) {
+				// Profile > Forums > Replied To
+				$topic_count = bp_forums_total_replied_count_for_user( bp_displayed_user_id(), $type );
+			} else if ( 'tags' == $type ) {
+				$tag         = bb_get_tag( $search_terms );
+				$topic_count = $tag->count;
+			} else {
+				// For forum directories (All Topics), get a true count
+				$status = bp_current_user_can( 'bp_moderate' ) ? 'all' : 'public'; // todo: member-of
+				$topic_count = (int)groups_total_forum_topic_count( $status, $search_terms );
+			}
+
+			if ( !$max || $max >= $topic_count ) {
+				$this->total_topic_count = $topic_count;
+			} else {
+				$this->total_topic_count = (int) $max;
+			}
+
+			if ( $max ) {
+				if ( $max >= count($this->topics) ) {
+					$this->topic_count = count( $this->topics );
+				} else {
+					$this->topic_count = (int) $max;
+				}
+			} else {
+				$this->topic_count = count( $this->topics );
+			}
+		}
+
+		$this->topic_count       = apply_filters_ref_array( 'bp_forums_template_topic_count',                                 array( $this->topic_count, &$this->topics, $type, $forum_id, $per_page, $max, $no_stickies ) );
+		$this->total_topic_count = apply_filters_ref_array( 'bp_forums_template_total_topic_count', array( $this->total_topic_count, $this->topic_count, &$this->topics, $type, $forum_id, $per_page, $max, $no_stickies ) );
+
+		// Fetch extra information for topics, so we don't have to query inside the loop
+		$this->topics = bp_forums_get_topic_extras( $this->topics );
+
+		if ( (int) $this->total_topic_count && (int) $this->pag_num ) {
+			$this->pag_links = paginate_links( array(
+				'base'      => add_query_arg( array( 'p' => '%#%', 'n' => $this->pag_num ) ),
+				'format'    => '',
+				'total'     => ceil( (int) $this->total_topic_count / (int) $this->pag_num),
+				'current'   => $this->pag_page,
+				'prev_text' => _x( '&larr;', 'Forum topic pagination previous text', 'buddypress' ),
+				'next_text' => _x( '&rarr;', 'Forum topic pagination next text', 'buddypress' ),
+				'mid_size'  => 1
+			) );
+		}
+	}
+
+	/**
+	 * Whether there are topics available in the loop.
+	 *
+	 * @see bp_has_forum_topics()
+	 *
+	 * @return bool True if there are items in the loop, otherwise false.
+	 */
+	function has_topics() {
+		if ( $this->topic_count )
+			return true;
+
+		return false;
+	}
+
+	/**
+	 * Set up the next topic and iterate index.
+	 *
+	 * @return object The next topic to iterate over.
+	 */
+	function next_topic() {
+		$this->current_topic++;
+		$this->topic = $this->topics[$this->current_topic];
+
+		return $this->topic;
+	}
+
+	/**
+	 * Rewind the topics and reset topic index.
+	 */
+	function rewind_topics() {
+		$this->current_topic = -1;
+		if ( $this->topic_count > 0 ) {
+			$this->topic = $this->topics[0];
+		}
+	}
+
+	/**
+	 * Whether there are blogs left in the loop to iterate over.
+	 *
+	 * This method is used by {@link bp_forum_topics()} as part of the while loop
+	 * that controls iteration inside the blogs loop, eg:
+	 *     while ( bp_forum_topics() ) { ...
+	 *
+	 * @see bp_forum_topics()
+	 *
+	 * @return bool True if there are more topics to show, otherwise false.
+	 */
+	function user_topics() {
+		if ( $this->current_topic + 1 < $this->topic_count ) {
+			return true;
+		} elseif ( $this->current_topic + 1 == $this->topic_count ) {
+			do_action('forum_loop_end');
+			// Do some cleaning up after the loop
+			$this->rewind_topics();
+		}
+
+		$this->in_the_loop = false;
+		return false;
+	}
+
+	/**
+	 * Set up the current topic in the loop.
+	 *
+	 * @see bp_the_forum_topic()
+	 */
+	function the_topic() {
+		global $topic;
+
+		$this->in_the_loop = true;
+		$this->topic = $this->next_topic();
+		$this->topic = (object)$this->topic;
+
+		if ( $this->current_topic == 0 ) // loop has just started
+			do_action('forum_loop_start');
+	}
+}
+
+/**
+ * Initiate the forum topics loop.
+ *
+ * Like other BuddyPress custom loops, the default arguments for this function
+ * are determined dynamically, depending on your current page. All of these
+ * $defaults can be overridden in the $args parameter.
+ *
+ * @uses apply_filters() Filter 'bp_has_topics' to manipulate the
+ *       $forums_template global before it's rendered, or to modify the value
+ *       of has_topics().
+ *
+ * @param array $args {
+ *     Arguments for limiting the contents of the forum topics loop.
+ *
+ *     @type string $type The 'type' is the sort order/kind. 'newest',
+ *           'popular', 'unreplied', 'tags'. Default: 'newest'.
+ *     @type int $forum_id The ID of the forum for which topics are being
+ *           queried. Default: the ID of the forum belonging to the current
+ *           group, if available.
+ *     @type int $user_id The ID of a user to whom to limit results. If viewing
+ *           a member's profile, defaults to that member's ID; otherwise
+ *           defaults to 0.
+ *     @type int $page The number of the page being requested. Default: 1, or
+ *           the value of $_GET['p'].
+ *     @type int $per_pag The number items to return per page. Default: 20, or
+ *           the value of $_GET['n'].
+ *     @type int $max Optional. Max records to return. Default: false (no max).
+ *     @type int $number Optional. Number of records to return. Default: false.
+ *     @type int $offset Optional. Offset results by a given value.
+ *           Default: false.
+ *     @type string $search_terms Optional. A string to which results should be
+ *           limited. Default: false, or the value of $_GET['fs'].
+ *     @type string|bool $do_stickies Whether to move stickies to the top of
+ *           the sort order. Default: true if looking at a group forum,
+ *           otherwise false.
+ * }
+ * @return bool True when forum topics are found corresponding to the args,
+ *         false otherwise.
+ */
+function bp_has_forum_topics( $args = '' ) {
+	global $forum_template, $bp;
+
+	/***
+	 * Set the defaults based on the current page. Any of these will be overridden
+	 * if arguments are directly passed into the loop. Custom plugins should always
+	 * pass their parameters directly to the loop.
+	 */
+	$type         = 'newest';
+	$user_id      = 0;
+	$forum_id     = false;
+	$search_terms = false;
+	$do_stickies  = false;
+
+	// User filtering
+	if ( bp_displayed_user_id() )
+		$user_id = bp_displayed_user_id();
+
+	// "Replied" query must be manually modified
+	if ( 'replies' == bp_current_action() ) {
+		$user_id = 0; // User id must be handled manually by the filter, not by BB_Query
+
+		add_filter( 'get_topics_distinct',   'bp_forums_add_replied_distinct_sql', 20 );
+		add_filter( 'get_topics_join', 	     'bp_forums_add_replied_join_sql', 20 );
+		add_filter( 'get_topics_where',      'bp_forums_add_replied_where_sql', 20  );
+	}
+
+	// If we're in a single group, set this group's forum_id
+	if ( !$forum_id && !empty( $bp->groups->current_group ) ) {
+		$bp->groups->current_group->forum_id = groups_get_groupmeta( $bp->groups->current_group->id, 'forum_id' );
+
+		// If it turns out there is no forum for this group, return false so
+		// we don't fetch all global topics
+		if ( empty( $bp->groups->current_group->forum_id ) )
+			return false;
+
+		$forum_id = $bp->groups->current_group->forum_id;
+	}
+
+	// If $_GET['fs'] is set, let's auto populate the search_terms var
+	if ( bp_is_directory() && !empty( $_GET['fs'] ) )
+		$search_terms = $_GET['fs'];
+
+	// Get the pagination arguments from $_REQUEST
+	$page     = isset( $_REQUEST['p'] ) ? intval( $_REQUEST['p'] ) : 1;
+	$per_page = isset( $_REQUEST['n'] ) ? intval( $_REQUEST['n'] ) : 20;
+
+	// By default, stickies are only pushed to the top of the order on individual group forums
+	if ( bp_is_group_forum() )
+		$do_stickies = true;
+
+	$defaults = array(
+		'type'         => $type,
+		'forum_id'     => $forum_id,
+		'user_id'      => $user_id,
+		'page'         => $page,
+		'per_page'     => $per_page,
+		'max'          => false,
+		'number'       => false,
+		'offset'       => false,
+		'search_terms' => $search_terms,
+		'do_stickies'  => $do_stickies
+	);
+
+	$r = wp_parse_args( $args, $defaults );
+	extract( $r );
+
+	// If we're viewing a tag URL in the directory, let's override the type and
+	// set it to tags and the filter to the tag name
+	if ( bp_is_current_action( 'tag' ) && $search_terms = bp_action_variable( 0 ) ) {
+		$type = 'tags';
+	}
+
+	/** Sticky logic ******************************************************************/
+
+	if ( $do_stickies ) {
+		// Fetch the stickies
+		$stickies_template = new BP_Forums_Template_Forum( $type, $forum_id, $user_id, 0, 0, $max, 'sticky', $search_terms );
+
+		// If stickies are found, try merging them
+		if ( $stickies_template->has_topics() ) {
+
+			// If stickies are for current $page
+			$page_start_num = ( ( $page - 1 ) * $per_page ) + 1;
+			$page_end_num 	= $page * $per_page <= $stickies_template->total_topic_count ? $page * $per_page : $stickies_template->total_topic_count;
+
+			// Calculate the number of sticky topics that will be shown on this page
+			if ( $stickies_template->topic_count < $page_start_num ) {
+				$this_page_stickies = 0;
+			} else {
+				$this_page_stickies = $stickies_template->topic_count - $per_page * floor( $stickies_template->topic_count / $per_page ) * ( $page - 1 ); // Total stickies minus sticky count through this page
+
+				// $this_page_stickies cannot be more than $per_page or less than 0
+				if ( $this_page_stickies > $per_page )
+					$this_page_stickies = $per_page;
+				else if ( $this_page_stickies < 0 )
+					$this_page_stickies = 0;
+			}
+
+			// Calculate the total number of topics that will be shown on this page
+			$this_page_topics = $stickies_template->total_topic_count >= ( $page * $per_page ) ? $per_page : $page_end_num - ( $page_start_num - 1 );
+
+			// If the number of stickies to be shown is less than $per_page, fetch some
+			// non-stickies to fill in the rest
+			if ( $this_page_stickies < $this_page_topics ) {
+				// How many non-stickies do we need?
+				$non_sticky_number = $this_page_topics - $this_page_stickies;
+
+				// Calculate the non-sticky offset
+				// How many non-stickies on all pages up to this point?
+				$non_sticky_total = $page_end_num - $stickies_template->topic_count;
+
+				// The offset is the number of total non-stickies, less the number
+				// to be shown on this page
+				$non_sticky_offset = $non_sticky_total - $non_sticky_number;
+
+				// Fetch the non-stickies
+				$forum_template = new BP_Forums_Template_Forum( $type, $forum_id, $user_id, 1, $per_page, $max, 'no', $search_terms, $non_sticky_offset, $non_sticky_number );
+
+				// If there are stickies to merge on this page, do it now
+				if ( $this_page_stickies ) {
+					// Correct the topic_count
+					$forum_template->topic_count += (int) $this_page_stickies;
+
+					// Figure out which stickies need to be included
+					$this_page_sticky_topics = array_slice( $stickies_template->topics, 0 - $this_page_stickies );
+
+					// Merge these topics into the forum template
+					$forum_template->topics = array_merge( $this_page_sticky_topics, (array) $forum_template->topics );
+				}
+			} else {
+				// This page has no non-stickies
+				$forum_template = $stickies_template;
+
+				// Adjust the topic count and trim the topics
+				$forum_template->topic_count = $this_page_stickies;
+				$forum_template->topics      = array_slice( $forum_template->topics, $page - 1 );
+			}
+
+			// Because we're using a manual offset and number for the topic query, we
+			// must set the page number manually, and recalculate the pagination links
+			$forum_template->pag_num     = $per_page;
+			$forum_template->pag_page    = $page;
+
+			$forum_template->pag_links = paginate_links( array(
+				'base'      => add_query_arg( array( 'p' => '%#%', 'n' => $forum_template->pag_num ) ),
+				'format'    => '',
+				'total'     => ceil( (int) $forum_template->total_topic_count / (int) $forum_template->pag_num ),
+				'current'   => $forum_template->pag_page,
+				'prev_text' => _x( '&larr;', 'Forum topic pagination previous text', 'buddypress' ),
+				'next_text' => _x( '&rarr;', 'Forum topic pagination next text', 'buddypress' ),
+				'mid_size'  => 1
+			) );
+
+		} else {
+			// Fetch the non-sticky topics if no stickies were found
+			$forum_template = new BP_Forums_Template_Forum( $type, $forum_id, $user_id, $page, $per_page, $max, 'all', $search_terms );
+		}
+	} else {
+		// When skipping the sticky logic, just pull up the forum topics like usual
+		$forum_template = new BP_Forums_Template_Forum( $type, $forum_id, $user_id, $page, $per_page, $max, 'all', $search_terms );
+	}
+
+	return apply_filters( 'bp_has_topics', $forum_template->has_topics(), $forum_template );
+}
+
+/**
+ * Determine whether there are still topics left in the loop.
+ *
+ * @global BP_Forums_Template_Forum $forum_template Template global.
+ *
+ * @return bool Returns true when topics are found.
+ */
+function bp_forum_topics() {
+	global $forum_template;
+	return $forum_template->user_topics();
+}
+
+/**
+ * Get the current topic object in the loop.
+ *
+ * @global BP_Forums_Template_Forum $forum_template Template global.
+ *
+ * @return object The current topic object.
+ */
+function bp_the_forum_topic() {
+	global $forum_template;
+	return $forum_template->the_topic();
+}
+
+/**
+ * Output the ID of the current topic in the loop.
+ */
+function bp_the_topic_id() {
+	echo bp_get_the_topic_id();
+}
+	/**
+	 * Return the ID of the current topic in the loop.
+	 *
+	 * @return int ID of the current topic in the loop.
+	 */
+	function bp_get_the_topic_id() {
+		global $forum_template;
+
+		return apply_filters( 'bp_get_the_topic_id', $forum_template->topic->topic_id );
+	}
+
+/**
+ * Output the title of the current topic in the loop.
+ */
+function bp_the_topic_title() {
+	echo bp_get_the_topic_title();
+}
+	/**
+	 * Return the title of the current topic in the loop.
+	 *
+	 * @return string Title of the current topic in the loop.
+	 */
+	function bp_get_the_topic_title() {
+		global $forum_template;
+
+		return apply_filters( 'bp_get_the_topic_title', stripslashes( $forum_template->topic->topic_title ) );
+	}
+
+/**
+ * Output the slug of the current topic in the loop.
+ */
+function bp_the_topic_slug() {
+	echo bp_get_the_topic_slug();
+}
+	/**
+	 * Return the slug of the current topic in the loop.
+	 *
+	 * @return string Slug of the current topic in the loop.
+	 */
+	function bp_get_the_topic_slug() {
+		global $forum_template;
+
+		return apply_filters( 'bp_get_the_topic_slug', $forum_template->topic->topic_slug );
+	}
+
+/**
+ * Output the text of the first post in the current topic in the loop.
+ */
+function bp_the_topic_text() {
+	echo bp_get_the_topic_text();
+}
+	/**
+	 * Return the text of the first post in the current topic in the loop.
+	 *
+	 * @return string Text of the first post in the current topic.
+	 */
+	function bp_get_the_topic_text() {
+		global $forum_template;
+
+		$post = bb_get_first_post( (int) $forum_template->topic->topic_id, false );
+		return apply_filters( 'bp_get_the_topic_text', esc_attr( $post->post_text ) );
+	}
+
+/**
+ * Output the ID of the user who posted the current topic in the loop.
+ */
+function bp_the_topic_poster_id() {
+	echo bp_get_the_topic_poster_id();
+}
+	/**
+	 * Return the ID of the user who posted the current topic in the loop.
+	 *
+	 * @return int ID of the user who posted the current topic.
+	 */
+	function bp_get_the_topic_poster_id() {
+		global $forum_template;
+
+		return apply_filters( 'bp_get_the_topic_poster_id', $forum_template->topic->topic_poster );
+	}
+
+/**
+ * Output the avatar of the user who posted the current topic in the loop.
+ *
+ * @see bp_get_the_topic_poster_avatar() for a description of arguments.
+ *
+ * @param array $args See {@link bp_get_the_topic_poster_avatar()}.
+ */
+function bp_the_topic_poster_avatar( $args = '' ) {
+	echo bp_get_the_topic_poster_avatar( $args );
+}
+	/**
+	 * Return the avatar of the user who posted the current topic in the loop.
+	 *
+	 * @param array $args {
+	 *     Arguments for building the avatar.
+	 *     @type string $type Avatar type. 'thumb' or 'full'. Default:
+	 *           'thumb'.
+	 *     @type int $width Width of the avatar, in pixels. Default: the
+	 *           width corresponding to $type.
+	 *           See {@link bp_core_fetch_avatar()}.
+	 *     @type int $height Height of the avatar, in pixels. Default: the
+	 *           height corresponding to $type.
+	 *           See {@link bp_core_fetch_avatar()}.
+	 *     @type string $alt The text of the image's 'alt' attribute.
+	 *           Default: 'Profile picture of [user name]'.
+	 * }
+	 * @return string HTML of user avatar.
+	 */
+	function bp_get_the_topic_poster_avatar( $args = '' ) {
+		global $forum_template;
+
+		$defaults = array(
+			'type'   => 'thumb',
+			'width'  => false,
+			'height' => false,
+			'alt'    => sprintf( __( 'Profile picture of %s', 'buddypress' ), bp_core_get_user_displayname( $forum_template->topic->topic_poster ) )
+		);
+
+		$r = wp_parse_args( $args, $defaults );
+		extract( $r, EXTR_SKIP );
+
+		return apply_filters( 'bp_get_the_topic_poster_avatar', bp_core_fetch_avatar( array( 'item_id' => $forum_template->topic->topic_poster, 'type' => $type, 'width' => $width, 'height' => $height, 'alt' => $alt ) ) );
+	}
+
+/**
+ * Output the name of the user who posted the current topic in the loop.
+ */
+function bp_the_topic_poster_name() {
+	echo bp_get_the_topic_poster_name();
+}
+	/**
+	 * Return the name of the user who posted the current topic in the loop.
+	 *
+	 * @return string Name of the user who posted the current topic.
+	 */
+	function bp_get_the_topic_poster_name() {
+		global $forum_template;
+
+		$poster_id = ( empty( $forum_template->topic->poster_id ) ) ? $forum_template->topic->topic_poster : $forum_template->topic->poster_id;
+
+		if ( !$name = bp_core_get_userlink( $poster_id ) )
+			return __( 'Deleted User', 'buddypress' );
+
+		return apply_filters( 'bp_get_the_topic_poster_name', $name );
+	}
+
+/**
+ * Output the ID of the object associated with the current topic in the loop.
+ */
+function bp_the_topic_object_id() {
+	echo bp_get_the_topic_object_id();
+}
+	/**
+	 * Return the ID of the object associated with the current topic in the loop.
+	 *
+	 * Objects are things like associated groups.
+	 *
+	 * @return int ID of the associated object.
+	 */
+	function bp_get_the_topic_object_id() {
+		global $forum_template;
+
+		return apply_filters( 'bp_get_the_topic_object_id', $forum_template->topic->object_id );
+	}
+
+/**
+ * Output the name of the object associated with the current topic in the loop.
+ */
+function bp_the_topic_object_name() {
+	echo bp_get_the_topic_object_name();
+}
+	/**
+	 * Return the name of the object associated with the current topic in the loop.
+	 *
+	 * Objects are things like groups. So this function would return the
+	 * name of the group associated with the forum topic, if it exists.
+	 *
+	 * @return string Object name.
+	 */
+	function bp_get_the_topic_object_name() {
+		global $forum_template;
+
+		if ( isset( $forum_template->topic->object_name ) )
+			$retval = $forum_template->topic->object_name;
+		else
+			$retval = '';
+
+		return apply_filters( 'bp_get_the_topic_object_name', $retval );
+	}
+
+/**
+ * Output the slug of the object associated with the current topic in the loop.
+ */
+function bp_the_topic_object_slug() {
+	echo bp_get_the_topic_object_slug();
+}
+	/**
+	 * Return the slug of the object associated with the current topic in the loop.
+	 *
+	 * Objects are things like groups. So this function would return the
+	 * slug of the group associated with the forum topic, if it exists.
+	 *
+	 * @return string Object slug.
+	 */
+	function bp_get_the_topic_object_slug() {
+		global $forum_template;
+
+		return apply_filters( 'bp_get_the_topic_object_slug', $forum_template->topic->object_slug );
+	}
+
+/**
+ * Output the permalink of the object associated with the current topic in the loop.
+ */
+function bp_the_topic_object_permalink() {
+	echo bp_get_the_topic_object_permalink();
+}
+	/**
+	 * Return the permalink of the object associated with the current topic in the loop.
+	 *
+	 * Objects are things like groups. So this function would return the
+	 * permalink of the group associated with the forum topic, if it exists.
+	 *
+	 * @return string Object permalink.
+	 */
+	function bp_get_the_topic_object_permalink() {
+
+		// Currently this will only work with group forums, extended support in the future
+		if ( bp_is_active( 'groups' ) )
+			$permalink = trailingslashit( bp_get_root_domain() . '/' . bp_get_groups_root_slug() . '/' . bp_get_the_topic_object_slug() . '/forum' );
+		else
+			$permalink = '';
+
+		return apply_filters( 'bp_get_the_topic_object_permalink', $permalink );
+	}
+
+/**
+ * Output the linked name of the user who last posted to the current topic in the loop.
+ */
+function bp_the_topic_last_poster_name() {
+	echo bp_get_the_topic_last_poster_name();
+}
+	/**
+	 * Return the linked name of the user who last posted to the current topic in the loop.
+	 *
+	 * @return string HTML link to the profile of the user who last posted
+	 *         to the current topic.
+	 */
+	function bp_get_the_topic_last_poster_name() {
+		global $forum_template;
+
+		$domain = bp_core_get_user_domain( $forum_template->topic->topic_last_poster, $forum_template->topic->topic_last_poster_nicename, $forum_template->topic->topic_last_poster_login ) ;
+
+		// In the case where no user is found, bp_core_get_user_domain() may return the URL
+		// of the Members directory
+		if ( !$domain || $domain == bp_core_get_root_domain() . '/' . bp_get_members_root_slug() . '/' )
+			return __( 'Deleted User', 'buddypress' );
+
+		return apply_filters( 'bp_get_the_topic_last_poster_name', '<a href="' . $domain . '">' . $forum_template->topic->topic_last_poster_displayname . '</a>' );
+	}
+
+/**
+ * Output the permalink of the object associated with the current topic in the loop.
+ *
+ * @see bp_get_the_topic_object_avatar() for description of arguments.
+ *
+ * @param array $args See {@bp_get_the_topic_object_avatar()}.
+ */
+function bp_the_topic_object_avatar( $args = '' ) {
+	echo bp_get_the_topic_object_avatar( $args );
+}
+	/**
+	 * Return the avatar of the object associated with the current topic in the loop.
+	 *
+	 * Objects are things like groups. So this function would return the
+	 * avatar of the group associated with the forum topic, if it exists.
+	 *
+	 * @param array $args {
+	 *     Arguments for building the avatar.
+	 *     @type string $type Avatar type. 'thumb' or 'full'. Default:
+	 *           'thumb'.
+	 *     @type int $width Width of the avatar, in pixels. Default: the
+	 *           width corresponding to $type.
+	 *           See {@link bp_core_fetch_avatar()}.
+	 *     @type int $height Height of the avatar, in pixels. Default:
+	 *           the height corresponding to $type.
+	 *           See {@link bp_core_fetch_avatar()}.
+	 *     @type string $alt The text of the image's 'alt' attribute.
+	 *           Default: 'Group logo for [group name]'.
+	 * }
+	 * @return string Object avatar.
+	 */
+	function bp_get_the_topic_object_avatar( $args = '' ) {
+		global $forum_template;
+
+		if ( !isset( $forum_template->topic->object_id ) )
+			return false;
+
+		$defaults = array(
+			'type'   => 'thumb',
+			'width'  => false,
+			'height' => false,
+			'alt'    => __( 'Group logo for %s', 'buddypress' )
+		);
+
+		$r = wp_parse_args( $args, $defaults );
+		extract( $r, EXTR_SKIP );
+
+		return apply_filters( 'bp_get_the_topic_object_avatar', bp_core_fetch_avatar( array( 'item_id' => $forum_template->topic->object_id, 'type' => $type, 'object' => 'group', 'width' => $width, 'height' => $height, 'alt' => $alt ) ) );
+	}
+
+/**
+ * Output the avatar for the user who last posted to the current topic in the loop.
+ *
+ * @see bp_get_the_topic_last_poster_avatar() for description of arguments.
+ *
+ * @param array $args See {@bp_get_the_topic_last_poster_avatar()}.
+ */
+function bp_the_topic_last_poster_avatar( $args = '' ) {
+	echo bp_get_the_topic_last_poster_avatar( $args );
+}
+	/**
+	 * Return the avatar for the user who last posted to the current topic in the loop.
+	 *
+	 * @param array $args {
+	 *     Arguments for building the avatar.
+	 *     @type string $type Avatar type. 'thumb' or 'full'. Default:
+	 *           'thumb'.
+	 *     @type int $width Width of the avatar, in pixels. Default: the
+	 *           width corresponding to $type.
+	 *           See {@link bp_core_fetch_avatar()}.
+	 *     @type int $height Height of the avatar, in pixels. Default:
+	 *           the height corresponding to $type.
+	 *           See {@link bp_core_fetch_avatar()}.
+	 *     @type string $alt The text of the image's 'alt' attribute.
+	 *           Default: 'Profile picture of [group name]'.
+	 * }
+	 * @return string User avatar.
+	 */
+	function bp_get_the_topic_last_poster_avatar( $args = '' ) {
+		global $forum_template;
+
+		$defaults = array(
+			'type'   => 'thumb',
+			'width'  => false,
+			'height' => false,
+			'alt'    => __( 'Profile picture of %s', 'buddypress' )
+		);
+
+		$r = wp_parse_args( $args, $defaults );
+		extract( $r, EXTR_SKIP );
+
+		return apply_filters( 'bp_get_the_topic_last_poster_avatar', bp_core_fetch_avatar( array( 'email' => $forum_template->topic->topic_last_poster_email, 'item_id' => $forum_template->topic->topic_last_poster, 'type' => $type, 'width' => $width, 'height' => $height, 'alt' => $alt ) ) );
+	}
+
+/**
+ * Output the start time of the current topic in the loop.
+ */
+function bp_the_topic_start_time() {
+	echo bp_get_the_topic_start_time();
+}
+	/**
+	 * Return the start time of the current topic in the loop.
+	 *
+	 * @return string Start time of the current topic.
+	 */
+	function bp_get_the_topic_start_time() {
+		global $forum_template;
+
+		return apply_filters( 'bp_get_the_topic_start_time', $forum_template->topic->topic_start_time );
+	}
+
+/**
+ * Output the topic time of the current topic in the loop.
+ */
+function bp_the_topic_time() {
+	echo bp_get_the_topic_time();
+}
+	/**
+	 * Return the topic time of the current topic in the loop.
+	 *
+	 * @return string Topic time of the current topic.
+	 */
+	function bp_get_the_topic_time() {
+		global $forum_template;
+
+		return apply_filters( 'bp_get_the_topic_time', $forum_template->topic->topic_time );
+	}
+
+/**
+ * Output the ID of the forum associated with the current topic in the loop.
+ */
+function bp_the_topic_forum_id() {
+	echo bp_get_the_topic_forum_id();
+}
+	/**
+	 * Return the ID of the forum associated with the current topic in the loop.
+	 *
+	 * @return int ID of the forum associated with the current topic.
+	 */
+	function bp_get_the_topic_forum_id() {
+		global $forum_template;
+
+		return apply_filters( 'bp_get_the_topic_forum_id', $forum_template->topic->forum_id );
+	}
+
+/**
+ * Output the status of the current topic in the loop.
+ */
+function bp_the_topic_status() {
+	echo bp_get_the_topic_status();
+}
+	/**
+	 * Return the status of the current topic in the loop.
+	 *
+	 * @return string Status of the current topic.
+	 */
+	function bp_get_the_topic_status() {
+		global $forum_template;
+
+		return apply_filters( 'bp_get_the_topic_status', $forum_template->topic->topic_status );
+	}
+
+/**
+ * Output whether the current topic in the loop is open.
+ */
+function bp_the_topic_is_topic_open() {
+	echo bp_get_the_topic_is_topic_open();
+}
+	/**
+	 * Return whether the current topic in the loop is open.
+	 *
+	 * @return unknown
+	 */
+	function bp_get_the_topic_is_topic_open() {
+		global $forum_template;
+
+		return apply_filters( 'bp_get_the_topic_is_topic_open', $forum_template->topic->topic_open );
+	}
+
+/**
+ * Output the ID of the last post in the current topic in the loop.
+ */
+function bp_the_topic_last_post_id() {
+	echo bp_get_the_topic_last_post_id();
+}
+	/**
+	 * Return the ID of the last post in the current topic in the loop.
+	 *
+	 * @return int ID of the last post in the current topic.
+	 */
+	function bp_get_the_topic_last_post_id() {
+		global $forum_template;
+
+		return apply_filters( 'bp_get_the_topic_last_post_id', $forum_template->topic->topic_last_post_id );
+	}
+
+/**
+ * Output whether the current topic in the loop is sticky.
+ */
+function bp_the_topic_is_sticky() {
+	echo bp_get_the_topic_is_sticky();
+}
+	/**
+	 * Return whether the current topic in the loop is sticky.
+	 *
+	 * @return unknown
+	 */
+	function bp_get_the_topic_is_sticky() {
+		global $forum_template;
+
+		return apply_filters( 'bp_get_the_topic_is_sticky', $forum_template->topic->topic_sticky );
+	}
+
+/**
+ * Output a 'x posts' string with the number of posts in the current topic.
+ */
+function bp_the_topic_total_post_count() {
+	echo bp_get_the_topic_total_post_count();
+}
+	/**
+	 * Return a 'x posts' string with the number of posts in the current topic.
+	 *
+	 * @return string String of the form 'x posts'.
+	 */
+	function bp_get_the_topic_total_post_count() {
+		global $forum_template;
+
+		if ( $forum_template->topic->topic_posts == 1 )
+			return apply_filters( 'bp_get_the_topic_total_post_count', sprintf( __( '%d post', 'buddypress' ), $forum_template->topic->topic_posts ) );
+		else
+			return apply_filters( 'bp_get_the_topic_total_post_count', sprintf( __( '%d posts', 'buddypress' ), $forum_template->topic->topic_posts ) );
+	}
+
+/**
+ * Output the total number of posts in the current topic in the loop.
+ */
+function bp_the_topic_total_posts() {
+	echo bp_get_the_topic_total_posts();
+}
+	/**
+	 * Return the total number of posts in the current topic in the loop.
+	 *
+	 * @return int Total number of posts in the current topic.
+	 */
+	function bp_get_the_topic_total_posts() {
+		global $forum_template;
+
+		return apply_filters( 'bp_get_the_topic_total_posts', $forum_template->topic->topic_posts );
+	}
+
+/**
+ * Output the tag count for the current topic in the loop.
+ */
+function bp_the_topic_tag_count() {
+	echo bp_get_the_topic_tag_count();
+}
+	/**
+	 * Return the tag count for the current topic in the loop.
+	 *
+	 * @return int Tag count for the current topic.
+	 */
+	function bp_get_the_topic_tag_count() {
+		global $forum_template;
+
+		return apply_filters( 'bp_get_the_topic_tag_count', $forum_template->topic->tag_count );
+	}
+
+/**
+ * Output the permalink of the current topic in the loop.
+ */
+function bp_the_topic_permalink() {
+	echo bp_get_the_topic_permalink();
+}
+	/**
+	 * Return the permalink for the current topic in the loop.
+	 *
+	 * @return string Permalink for the current topic.
+	 */
+	function bp_get_the_topic_permalink() {
+		global $forum_template, $bp;
+
+		// The topic is in a loop where its parent object is loaded
+		if ( bp_get_the_topic_object_slug() ) {
+			$permalink = trailingslashit( bp_get_root_domain() . '/' . bp_get_groups_root_slug() . '/' . bp_get_the_topic_object_slug() . '/forum' );
+
+		// We are viewing a single group topic, so use the current item
+		} elseif ( bp_is_group_forum_topic() ) {
+			$permalink = trailingslashit( bp_get_root_domain() . '/' . bp_get_groups_root_slug() . '/' . bp_current_item() . '/forum' );
+
+		// We are unsure what the context is, so fallback to forum root slug
+		} elseif ( bp_is_single_item() ) {
+			$permalink = trailingslashit( bp_get_root_domain() . '/' . bp_get_forums_root_slug() . '/' . bp_current_item() );
+
+		// This is some kind of error situation, so use forum root
+		} else {
+			$permalink = trailingslashit( bp_get_root_domain() . '/' . bp_get_forums_root_slug() );
+		}
+
+		return apply_filters( 'bp_get_the_topic_permalink', trailingslashit( $permalink . 'topic/' . $forum_template->topic->topic_slug ) );
+	}
+
+/**
+ * Output a 'since' string describing when the current topic was created.
+ */
+function bp_the_topic_time_since_created() {
+	echo bp_get_the_topic_time_since_created();
+}
+	/**
+	 * Return a 'since' string describing when the current topic was created.
+	 *
+	 * @see bp_core_time_since() for a description of return value.
+	 *
+	 * @return string
+	 */
+	function bp_get_the_topic_time_since_created() {
+		global $forum_template;
+
+		return apply_filters( 'bp_get_the_topic_time_since_created', bp_core_time_since( strtotime( $forum_template->topic->topic_start_time ) ) );
+	}
+
+/**
+ * Output an excerpt from the latest post of the current topic in the loop.
+ */
+function bp_the_topic_latest_post_excerpt( $args = '' ) {
+	echo bp_get_the_topic_latest_post_excerpt( $args );
+}
+	/**
+	 * Return an excerpt from the latest post of the current topic in the loop.
+	 *
+	 * @param array $args {
+	 *     @type int $length The length of the excerpted text. Default: 225.
+	 * }
+	 * @return string Post excerpt.
+	 */
+	function bp_get_the_topic_latest_post_excerpt( $args = '' ) {
+		global $forum_template;
+
+		$defaults = array(
+			'length' => 225
+		);
+
+		$r = wp_parse_args( $args, $defaults );
+		extract( $r, EXTR_SKIP );
+
+		$post = bp_forums_get_post( $forum_template->topic->topic_last_post_id );
+		$post = bp_create_excerpt( $post->post_text, $length );
+
+		return apply_filters( 'bp_get_the_topic_latest_post_excerpt', $post, $length );
+	}
+
+/**
+ * Output a 'since' string describing when the last post in the current topic was created.
+ */
+function bp_the_topic_time_since_last_post() {
+	echo bp_get_the_topic_time_since_last_post();
+}
+	/**
+	 * Return a 'since' string describing when the last post in the current topic was created.
+	 *
+	 * @see bp_core_time_since() for a description of return value.
+	 *
+	 * @return string
+	 */
+	function bp_get_the_topic_time_since_last_post() {
+		global $forum_template;
+
+		return apply_filters( 'bp_get_the_topic_time_since_last_post', bp_core_time_since( strtotime( $forum_template->topic->topic_time ) ) );
+	}
+
+/**
+ * Output whether the current topic in the loop belongs to the logged-in user.
+ */
+function bp_the_topic_is_mine() {
+	echo bp_get_the_topic_is_mine();
+}
+	/**
+	 * Does the current topic belong to the logged-in user?
+	 *
+	 * @return bool True if the current topic in the loop was created by
+	 *         the logged-in user, otherwise false.
+	 */
+	function bp_get_the_topic_is_mine() {
+		global $forum_template;
+
+		return bp_loggedin_user_id() == $forum_template->topic->topic_poster;
+	}
+
+/**
+ * Output the admin links for the current topic in the loop.
+ *
+ * @see bp_get_the_topic_admin_links() for a description of arguments.
+ *
+ * @param array $args See {@link bp_get_the_topic_admin_links()}.
+ */
+function bp_the_topic_admin_links( $args = '' ) {
+	echo bp_get_the_topic_admin_links( $args );
+}
+	/**
+	 * Return the admin links for the current topic in the loop.
+	 *
+	 * @param array $args {
+	 *     @type string $seperator The character to use when separating
+	 *           links. Default: '|'.
+	 * }
+	 * @return HTML string containing the admin links for the current topic.
+	 */
+	function bp_get_the_topic_admin_links( $args = '' ) {
+		global $forum_template;
+
+		$defaults = array(
+			'seperator' => '|'
+		);
+
+		$r = wp_parse_args( $args, $defaults );
+		extract( $r, EXTR_SKIP );
+
+		$links[] = '<a href="' . wp_nonce_url( bp_get_the_topic_permalink() . 'edit', 'bp_forums_edit_topic' ) . '">' . __( 'Edit Topic', 'buddypress' ) . '</a>';
+
+		if ( bp_is_item_admin() || bp_is_item_mod() || bp_current_user_can( 'bp_moderate' ) ) {
+			if ( 0 == (int) $forum_template->topic->topic_sticky )
+				$links[] = '<a href="' . wp_nonce_url( bp_get_the_topic_permalink() . 'stick', 'bp_forums_stick_topic' ) . '">' . __( 'Sticky Topic', 'buddypress' ) . '</a>';
+			else
+				$links[] = '<a href="' . wp_nonce_url( bp_get_the_topic_permalink() . 'unstick', 'bp_forums_unstick_topic' ) . '">' . __( 'Un-stick Topic', 'buddypress' ) . '</a>';
+
+			if ( 0 == (int) $forum_template->topic->topic_open )
+				$links[] = '<a href="' . wp_nonce_url( bp_get_the_topic_permalink() . 'open', 'bp_forums_open_topic' ) . '">' . __( 'Open Topic', 'buddypress' ) . '</a>';
+			else
+				$links[] = '<a href="' . wp_nonce_url( bp_get_the_topic_permalink() . 'close', 'bp_forums_close_topic' ) . '">' . __( 'Close Topic', 'buddypress' ) . '</a>';
+
+			$links[] = '<a class="confirm" id="topic-delete-link" href="' . wp_nonce_url( bp_get_the_topic_permalink() . 'delete', 'bp_forums_delete_topic' ) . '">' . __( 'Delete Topic', 'buddypress' ) . '</a>';
+		}
+
+		return implode( ' ' . $seperator . ' ', (array) $links );
+	}
+
+/**
+ * Output the CSS class for the current topic in the loop.
+ */
+function bp_the_topic_css_class() {
+	echo bp_get_the_topic_css_class();
+}
+	/**
+	 * Return the CSS class for the current topic in the loop.
+	 *
+	 * This class may contain keywords like 'alt', 'sticky', or 'closed',
+	 * based on context.
+	 *
+	 * @return string Contents of the 'class' attribute.
+	 */
+	function bp_get_the_topic_css_class() {
+		global $forum_template;
+
+		$class = false;
+
+		if ( $forum_template->current_topic % 2 == 1 )
+			$class .= 'alt';
+
+		if ( isset( $forum_template->topic->topic_sticky ) && 1 == (int) $forum_template->topic->topic_sticky )
+			$class .= ' sticky';
+
+		if ( !isset( $forum_template->topic->topic_open ) || 0 == (int) $forum_template->topic->topic_open )
+			$class .= ' closed';
+
+		return apply_filters( 'bp_get_the_topic_css_class', trim( $class ) );
+	}
+
+/**
+ * Output the permalink to the 'personal' topics tab.
+ */
+function bp_my_forum_topics_link() {
+	echo bp_get_my_forum_topics_link();
+}
+	/**
+	 * Return the permalink to the 'personal' topics tab.
+	 *
+	 * @return string Link to the 'personal' topics tab.
+	 */
+	function bp_get_my_forum_topics_link() {
+		global $bp;
+
+		return apply_filters( 'bp_get_my_forum_topics_link', bp_get_root_domain() . '/' . bp_get_forums_root_slug() . '/personal/' );
+	}
+
+/**
+ * Output the permalink to the 'unreplied' topics tab.
+ */
+function bp_unreplied_forum_topics_link() {
+	echo bp_get_unreplied_forum_topics_link();
+}
+	/**
+	 * Return the permalink to the 'unreplied' topics tab.
+	 *
+	 * @return string Link to the 'unreplied' topics tab.
+	 */
+	function bp_get_unreplied_forum_topics_link() {
+		global $bp;
+
+		return apply_filters( 'bp_get_unreplied_forum_topics_link', bp_get_root_domain() . '/' . bp_get_forums_root_slug() . '/unreplied/' );
+	}
+
+/**
+ * Output the permalink to the 'popular' topics tab.
+ */
+function bp_popular_forum_topics_link() {
+	echo bp_get_popular_forum_topics_link();
+}
+	/**
+	 * Return the permalink to the 'popular' topics tab.
+	 *
+	 * @return string Link to the 'popular' topics tab.
+	 */
+	function bp_get_popular_forum_topics_link() {
+		global $bp;
+
+		return apply_filters( 'bp_get_popular_forum_topics_link', bp_get_root_domain() . '/' . bp_get_forums_root_slug() . '/popular/' );
+	}
+
+/**
+ * Output the link to the forums directory.
+ */
+function bp_newest_forum_topics_link() {
+	echo bp_get_newest_forum_topics_link();
+}
+	/**
+	 * Return the link to the forums directory.
+	 *
+	 * @return string Link to the forums directory.
+	 */
+	function bp_get_newest_forum_topics_link() {
+		global $bp;
+
+		return apply_filters( 'bp_get_newest_forum_topics_link', bp_get_root_domain() . '/' . bp_get_forums_root_slug() . '/' );
+	}
+
+/**
+ * Output the currently viewed topic list type.
+ */
+function bp_forum_topic_type() {
+	echo bp_get_forum_topic_type();
+}
+	/**
+	 * Return the currently viewed topic list type.
+	 *
+	 * Eg, 'newest', 'popular', etc.
+	 *
+	 * @return string Type of the currently viewed topic list.
+	 */
+	function bp_get_forum_topic_type() {
+		global $bp;
+
+		if ( !bp_is_directory() || !bp_current_action() )
+			return 'newest';
+
+		return apply_filters( 'bp_get_forum_topic_type', bp_current_action() );
+	}
+
+/**
+ * Output the value of bp_get_forum_topic_new_reply_link().
+ *
+ * @since BuddyPress (1.5.0)
+ */
+function bp_forum_topic_new_reply_link() {
+	echo bp_get_forum_topic_new_reply_link();
+}
+	/**
+	 * Return the permalink for the New Reply button at the top of forum topics.
+	 *
+	 * @since BuddyPress (1.5.0)
+	 *
+	 * @uses apply_filters() Filter bp_get_forum_topic_new_reply_link to
+	 *       modify.
+	 * @return string The URL for the New Reply link.
+	 */
+	function bp_get_forum_topic_new_reply_link() {
+		global $topic_template;
+
+		if ( $topic_template->pag->total_pages == $topic_template->pag_page ) {
+			// If we are on the last page, no need for a URL base
+			$link = '';
+		} else {
+			// Create a link to the last page for the topic
+			$link = add_query_arg( array(
+				'topic_page' =>	$topic_template->pag->total_pages,
+				'num'        => $topic_template->pag_num
+			), bp_get_the_topic_permalink() );
+		}
+
+		// Tack on the #post-topic-reply anchor before returning
+		return apply_filters( 'bp_get_forum_topic_new_reply_link', $link . '#post-topic-reply', $link );
+	}
+
+/**
+ * Output the currently viewed tag name.
+ *
+ * @todo Deprecate?
+ */
+function bp_forums_tag_name() {
+	echo bp_get_forums_tag_name();
+}
+	/**
+	 * Return the currently viewed tag name.
+	 *
+	 * @todo Deprecate? Seems unused
+	 */
+	function bp_get_forums_tag_name() {
+		$tag_name = bp_is_directory() && bp_is_forums_component() ? bp_action_variable( 0 ) : false;
+
+		return apply_filters( 'bp_get_forums_tag_name', $tag_name );
+	}
+
+/**
+ * Output the pagination links for the current topic list.
+ */
+function bp_forum_pagination() {
+	echo bp_get_forum_pagination();
+}
+	/**
+	 * Return the pagination links for the current topic list.
+	 *
+	 * @return string HTML pagination links.
+	 */
+	function bp_get_forum_pagination() {
+		global $forum_template;
+
+		return apply_filters( 'bp_get_forum_pagination', $forum_template->pag_links );
+	}
+
+/**
+ * Output the pagination count for the current topic list.
+ */
+function bp_forum_pagination_count() {
+	echo bp_get_forum_pagination_count();
+}
+	/**
+	 * Return the pagination count for the current topic list.
+	 *
+	 * The "count" is a string of the form "Viewing x of y topics".
+	 *
+	 * @return string
+	 */
+	function bp_get_forum_pagination_count() {
+		global $bp, $forum_template;
+
+		$start_num  = intval( ( $forum_template->pag_page - 1 ) * $forum_template->pag_num ) + 1;
+		$from_num   = bp_core_number_format( $start_num );
+		$to_num     = bp_core_number_format( ( $start_num + ( $forum_template->pag_num - 1  ) > $forum_template->total_topic_count ) ? $forum_template->total_topic_count : $start_num + ( $forum_template->pag_num - 1 ) );
+		$total      = bp_core_number_format( $forum_template->total_topic_count );
+		$pag_filter = false;
+
+		if ( 'tags' == $forum_template->type && !empty( $forum_template->search_terms ) )
+			$pag_filter = sprintf( __( ' matching tag "%s"', 'buddypress' ), $forum_template->search_terms );
+
+		return apply_filters( 'bp_get_forum_pagination_count', sprintf( _n( 'Viewing topic %s to %s (of %d topic%s)', 'Viewing topic %s to %s (of %d total topics%s)', $total, 'buddypress' ), $from_num, $to_num, $total, $pag_filter ), $from_num, $to_num, $total );
+	}
+
+/**
+ * Are we currently on an Edit Topic screen?
+ *
+ * @return bool True if currently editing a topic, otherwise false.
+ */
+function bp_is_edit_topic() {
+	global $bp;
+
+	if ( bp_is_action_variable( 'post' ) && bp_is_action_variable( 'edit' ) )
+		return false;
+
+	return true;
+}
+
+/**
+ * The single forum topic template loop class.
+ *
+ * Responsible for loading a topic's posts into a loop for display.
+ */
+class BP_Forums_Template_Topic {
+	/**
+	 * The loop iterator.
+	 *
+	 * @access public
+	 * @var int
+	 */
+	var $current_post = -1;
+
+	/**
+	 * The number of posts returned by the paged query.
+	 *
+	 * @access public
+	 * @var int
+	 */
+	var $post_count;
+
+	/**
+	 * Array of posts located by the query.
+	 *
+	 * @access public
+	 * @var array
+	 */
+	var $posts;
+
+	/**
+	 * The post object currently being iterated on.
+	 *
+	 * @access public
+	 * @var object
+	 */
+	var $post;
+
+	/**
+	 * The ID of the forum whose topic is being queried.
+	 *
+	 * @access public
+	 * @var int
+	 */
+	var $forum_id;
+
+	/**
+	 * The ID of the topic whose posts are being queried.
+	 *
+	 * @access public
+	 * @var int
+	 */
+	var $topic_id;
+
+	/**
+	 * The topic object to which the posts belong.
+	 *
+	 * @access public
+	 * @var object
+	 */
+	var $topic;
+
+	/**
+	 * A flag for whether the loop is currently being iterated.
+	 *
+	 * @access public
+	 * @var bool
+	 */
+	var $in_the_loop;
+
+	/**
+	 * Contains a 'total_pages' property holding total number of pages in
+	 * this loop.
+	 *
+	 * @since BuddyPress (1.2.0)
+	 * @var stdClass
+	 */
+	public $pag;
+
+	/**
+	 * The page number being requested.
+	 *
+	 * @access public
+	 * @var public
+	 */
+	var $pag_page;
+
+	/**
+	 * The number of items being requested per page.
+	 *
+	 * @access public
+	 * @var public
+	 */
+	var $pag_num;
+
+	/**
+	 * An HTML string containing pagination links.
+	 *
+	 * @access public
+	 * @var string
+	 */
+	var $pag_links;
+
+	/**
+	 * The total number of posts matching the query parameters.
+	 *
+	 * @access public
+	 * @var int
+	 */
+	var $total_post_count;
+
+	/**
+	 * Whether requesting a single topic. Not currently used.
+	 *
+	 * @access public
+	 * @var bool
+	 */
+	var $single_post = false;
+
+	/**
+	 * Term to sort by.
+	 *
+	 * @access public
+	 * @var string
+	 */
+	var $sort_by;
+
+	/**
+	 * Sort order.
+	 *
+	 * @access public
+	 * @var string
+	 */
+	var $order;
+
+	/**
+	 * Constructor method.
+	 *
+	 * @param int $topic_id ID of the topic whose posts are being requested.
+	 * @param int $per_page Number of items to return per page.
+	 * @param int $max Max records to return.
+	 * @param string $order Direction to order results.
+	 */
+	function __construct( $topic_id, $per_page, $max, $order ) {
+		global $bp, $current_user, $forum_template;
+
+                if ( !isset( $forum_template ) ) {
+                        $forum_template = new stdClass;
+                }
+
+		$this->pag_page        = isset( $_REQUEST['topic_page'] ) ? intval( $_REQUEST['topic_page'] ) : 1;
+		$this->pag_num         = isset( $_REQUEST['num'] ) ? intval( $_REQUEST['num'] ) : $per_page;
+
+		$this->order           = $order;
+		$this->topic_id        = $topic_id;
+		$forum_template->topic = (object) bp_forums_get_topic_details( $this->topic_id );
+		$this->forum_id        = $forum_template->topic->forum_id;
+
+		$this->posts           = bp_forums_get_topic_posts( array( 'topic_id' => $this->topic_id, 'page' => $this->pag_page, 'per_page' => $this->pag_num, 'order' => $this->order ) );
+
+		if ( !$this->posts ) {
+			$this->post_count       = 0;
+			$this->total_post_count = 0;
+		} else {
+			if ( !$max || $max >= (int) $forum_template->topic->topic_posts ) {
+				$this->total_post_count = (int) $forum_template->topic->topic_posts;
+			} else {
+				$this->total_post_count = (int) $max;
+			}
+
+			if ( $max ) {
+				if ( $max >= count( $this->posts ) ) {
+					$this->post_count = count( $this->posts );
+				} else {
+					$this->post_count = (int) $max;
+				}
+			} else {
+				$this->post_count = count( $this->posts );
+			}
+		}
+
+		// Load topic tags
+		$this->topic_tags = bb_get_topic_tags( $this->topic_id );
+
+		$this->pag = new stdClass;
+
+		if ( (int) $this->total_post_count && (int) $this->pag_num ) {
+			$this->pag_links = paginate_links( array(
+				'base'      => add_query_arg( array( 'topic_page' => '%#%', 'num' => (int) $this->pag_num ) ),
+				'format'    => '',
+				'total'     => ceil( (int) $this->total_post_count / (int) $this->pag_num ),
+				'current'   => $this->pag_page,
+				'prev_text' => _x( '&larr;', 'Forum thread pagination previous text', 'buddypress' ),
+				'next_text' => _x( '&rarr;', 'Forum thread pagination next text', 'buddypress' ),
+				'mid_size'  => 1
+			) );
+
+			$this->pag->total_pages = ceil( (int) $this->total_post_count / (int) $this->pag_num );
+		} else {
+			$this->pag->total_pages = 1;
+		}
+	}
+
+	/**
+	 * Whether there are posts available in the loop.
+	 *
+	 * @see bp_has_forum_topic_posts()
+	 *
+	 * @return bool True if there are items in the loop, otherwise false.
+	 */
+	function has_posts() {
+		if ( $this->post_count )
+			return true;
+
+		return false;
+	}
+
+	/**
+	 * Set up the next post and iterate index.
+	 *
+	 * @return object The next post to iterate over.
+	 */
+	function next_post() {
+		$this->current_post++;
+		$this->post = $this->posts[$this->current_post];
+
+		return $this->post;
+	}
+
+	/**
+	 * Rewind the posts and reset post index.
+	 */
+	function rewind_posts() {
+		$this->current_post = -1;
+		if ( $this->post_count > 0 ) {
+			$this->post = $this->posts[0];
+		}
+	}
+
+	/**
+	 * Whether there are posts left in the loop to iterate over.
+	 *
+	 * This method is used by {@link bp_forum_topic_posts()} as part of
+	 * the while loop that controls iteration inside the blogs loop, eg:
+	 *     while ( bp_forum_topic_posts() ) { ...
+	 *
+	 * @see bp_forum_topic_posts()
+	 *
+	 * @return bool True if there are more posts to show, otherwise false.
+	 */
+	function user_posts() {
+		if ( $this->current_post + 1 < $this->post_count ) {
+			return true;
+		} elseif ( $this->current_post + 1 == $this->post_count ) {
+			do_action('topic_loop_end');
+			// Do some cleaning up after the loop
+			$this->rewind_posts();
+		}
+
+		$this->in_the_loop = false;
+		return false;
+	}
+
+	/**
+	 * Set up the current topic in the loop.
+	 *
+	 * @see bp_the_forum_topic_post()
+	 */
+	function the_post() {
+		global $post;
+
+		$this->in_the_loop = true;
+		$this->post = $this->next_post();
+		$this->post = (object)$this->post;
+
+		if ( $this->current_post == 0 ) // loop has just started
+			do_action('topic_loop_start');
+	}
+}
+
+/**
+ * Initiate the loop for a single topic's posts.
+ *
+ * @param array $args {
+ *     Arguments for limiting the contents of the topic posts loop.
+ *     @type int $topic_id ID of the topic to which the posts belong.
+ *     @type int $per_page Number of items to return per page. Default: 15.
+ *     @type int $max Max items to return. Default: false.
+ *     @type string $order 'ASC' or 'DESC'.
+ * }
+ * @return bool True when posts are found corresponding to the args,
+ *         otherwise false.
+ */
+function bp_has_forum_topic_posts( $args = '' ) {
+	global $topic_template;
+
+	$defaults = array(
+		'topic_id' => false,
+		'per_page' => 15,
+		'max'      => false,
+		'order'    => 'ASC'
+	);
+
+	$r = wp_parse_args( $args, $defaults );
+	extract( $r, EXTR_SKIP );
+
+	if ( empty( $topic_id ) && bp_is_groups_component() && bp_is_current_action( 'forum' ) && bp_is_action_variable( 'topic', 0 ) && bp_action_variable( 1 ) )
+		$topic_id = bp_forums_get_topic_id_from_slug( bp_action_variable( 1 ) );
+	elseif ( empty( $topic_id ) && bp_is_forums_component() && bp_is_current_action( 'topic' ) && bp_action_variable( 0 ) )
+		$topic_id = bp_forums_get_topic_id_from_slug( bp_action_variable( 0 ) );
+
+	if ( empty( $topic_id ) ) {
+		return false;
+
+	} else {
+		$topic_template = new BP_Forums_Template_Topic( (int) $topic_id, $per_page, $max, $order );
+
+		// Current topic forum_id needs to match current_group forum_id
+		if ( bp_is_groups_component() && $topic_template->forum_id != groups_get_groupmeta( bp_get_current_group_id(), 'forum_id' ) )
+			return false;
+	}
+
+	return apply_filters( 'bp_has_topic_posts', $topic_template->has_posts(), $topic_template );
+}
+
+/**
+ * Determine whether there are posts left in the loop.
+ *
+ * @return bool True when posts are found.
+ */
+function bp_forum_topic_posts() {
+	global $topic_template;
+	return $topic_template->user_posts();
+}
+
+/**
+ * Set up the current post in the loop.
+ *
+ * @return object
+ */
+function bp_the_forum_topic_post() {
+	global $topic_template;
+	return $topic_template->the_post();
+}
+
+/**
+ * Output the ID of the current post in the loop.
+ */
+function bp_the_topic_post_id() {
+	echo bp_get_the_topic_post_id();
+}
+	/**
+	 * Return the ID of the current post in the loop.
+	 *
+	 * @return int ID of the current post in the loop.
+	 */
+	function bp_get_the_topic_post_id() {
+		global $topic_template;
+
+		return apply_filters( 'bp_get_the_topic_post_id', $topic_template->post->post_id );
+	}
+
+/**
+ * Output the content of the current post in the loop.
+ */
+function bp_the_topic_post_content() {
+	echo bp_get_the_topic_post_content();
+}
+	/**
+	 * Return the content of the current post in the loop.
+	 *
+	 * @return string Content of the current post.
+	 */
+	function bp_get_the_topic_post_content() {
+		global $topic_template;
+
+		return apply_filters( 'bp_get_the_topic_post_content', stripslashes( $topic_template->post->post_text ) );
+	}
+
+/**
+ * Output the CSS class of the current post in the loop.
+ */
+function bp_the_topic_post_css_class() {
+	echo bp_get_the_topic_post_css_class();
+}
+	/**
+	 * Return the CSS class of the current post in the loop.
+	 *
+	 * May contain strings 'alt', 'deleted', or 'open', depending on
+	 * context.
+	 *
+	 * @return string String to put in the 'class' attribute of the current
+	 *         post.
+	 */
+	function bp_get_the_topic_post_css_class() {
+		global $topic_template;
+
+		$class = false;
+
+		if ( $topic_template->current_post % 2 == 1 )
+			$class .= 'alt';
+
+		if ( 1 == (int) $topic_template->post->post_status )
+			$class .= ' deleted';
+
+		if ( 0 == (int) $topic_template->post->post_status )
+			$class .= ' open';
+
+		return apply_filters( 'bp_get_the_topic_post_css_class', trim( $class ) );
+	}
+
+/**
+ * Output the avatar of the user who posted the current post in the loop.
+ *
+ * @see bp_get_the_topic_post_poster_avatar() for a description of arguments.
+ *
+ * @param array $args See {@link bp_get_the_topic_post_poster_avatar()}.
+ */
+function bp_the_topic_post_poster_avatar( $args = '' ) {
+	echo bp_get_the_topic_post_poster_avatar( $args );
+}
+	/**
+	 * Return the avatar of the user who posted the current post in the loop.
+	 *
+	 * @param array $args {
+	 *     Arguments for building the avatar.
+	 *     @type string $type Avatar type. 'thumb' or 'full'. Default:
+	 *           'thumb'.
+	 *     @type int $width Width of the avatar, in pixels. Default: the
+	 *           width corresponding to $type.
+	 *           See {@link bp_core_fetch_avatar()}.
+	 *     @type int $height Height of the avatar, in pixels. Default: the
+	 *           height corresponding to $type.
+	 *           See {@link bp_core_fetch_avatar()}.
+	 *     @type string $alt The text of the image's 'alt' attribute.
+	 *           Default: 'Profile picture of [user name]'.
+	 * }
+	 * @return string HTML of user avatar.
+	 */
+	function bp_get_the_topic_post_poster_avatar( $args = '' ) {
+		global $topic_template;
+
+		$defaults = array(
+			'type' => 'thumb',
+			'width' => 20,
+			'height' => 20,
+			'alt' => __( 'Profile picture of %s', 'buddypress' )
+		);
+
+		$r = wp_parse_args( $args, $defaults );
+		extract( $r, EXTR_SKIP );
+
+		return apply_filters( 'bp_get_the_topic_post_poster_avatar', bp_core_fetch_avatar( array( 'item_id' => $topic_template->post->poster_id, 'type' => $type, 'width' => $width, 'height' => $height, 'alt' => $alt ) ) );
+	}
+
+/**
+ * Output the name of the user who posted the current post in the loop.
+ */
+function bp_the_topic_post_poster_name() {
+	echo bp_get_the_topic_post_poster_name();
+}
+	/**
+	 * Return the name of the user who posted the current post in the loop.
+	 *
+	 * @return string Name of the user who posted the current post.
+	 */
+	function bp_get_the_topic_post_poster_name() {
+		global $topic_template;
+
+		if ( empty( $topic_template->post->poster_name ) || ( !$link = bp_core_get_user_domain( $topic_template->post->poster_id ) ) )
+			return __( 'Deleted User', 'buddypress' );
+
+		return apply_filters( 'bp_get_the_topic_post_poster_name', '<a href="' . $link . '" title="' . $topic_template->post->poster_name . '">' . $topic_template->post->poster_name . '</a>' );
+	}
+
+/**
+ * Output a link to the profile of the user who posted the current post.
+ */
+function bp_the_topic_post_poster_link() {
+	echo bp_get_the_topic_post_poster_link();
+}
+	/**
+	 * Return a link to the profile of the user who posted the current post.
+	 *
+	 * @return string Link to the profile of the user who posted the
+	 *         current post.
+	 */
+	function bp_get_the_topic_post_poster_link() {
+		global $topic_template;
+
+		return apply_filters( 'bp_the_topic_post_poster_link', bp_core_get_user_domain( $topic_template->post->poster_id ) );
+	}
+
+/**
+ * Output a 'since' string describing when the current post in the loop was posted.
+ */
+function bp_the_topic_post_time_since() {
+	echo bp_get_the_topic_post_time_since();
+}
+	/**
+	 * Return a 'since' string describing when the current post in the loop was posted.
+	 *
+	 * @see bp_core_time_since() for a description of return value.
+	 *
+	 * @return string
+	 */
+	function bp_get_the_topic_post_time_since() {
+		global $topic_template;
+
+		return apply_filters( 'bp_get_the_topic_post_time_since', bp_core_time_since( strtotime( $topic_template->post->post_time ) ) );
+	}
+
+/**
+ * Output whether the current post in the loop belongs to the logged-in user.
+ */
+function bp_the_topic_post_is_mine() {
+	echo bp_the_topic_post_is_mine();
+}
+	/**
+	 * Does the current post belong to the logged-in user?
+	 *
+	 * @return bool True if the current post in the loop was created by
+	 *         the logged-in user, otherwise false.
+	 */
+	function bp_get_the_topic_post_is_mine() {
+		global $bp, $topic_template;
+
+		return bp_loggedin_user_id() == $topic_template->post->poster_id;
+	}
+
+/**
+ * Output the admin links for the current post in the loop.
+ *
+ * @see bp_get_the_post_admin_links() for a description of arguments.
+ *
+ * @param array $args See {@link bp_get_the_post_admin_links()}.
+ */
+function bp_the_topic_post_admin_links( $args = '' ) {
+	echo bp_get_the_topic_post_admin_links( $args );
+}
+	/**
+	 * Return the admin links for the current post in the loop.
+	 *
+	 * @param array $args {
+	 *     @type string $separator The character to use when separating
+	 *           links. Default: '|'.
+	 * }
+	 * @return HTML string containing the admin links for the current post.
+	 */
+	function bp_get_the_topic_post_admin_links( $args = '' ) {
+		global $topic_template;
+
+		// Never show for the first post in a topic.
+		if ( 0 == $topic_template->current_post && 1 == $topic_template->pag_page )
+			return;
+
+		$defaults = array(
+			'separator' => ' | '
+		);
+
+		$r = wp_parse_args( $args, $defaults );
+		extract( $r, EXTR_SKIP );
+
+		$query_vars = '';
+		if ( $_SERVER['QUERY_STRING'] )
+			$query_vars = '?' . $_SERVER['QUERY_STRING'];
+
+		$links    = array();
+		$links[]  = '<a href="' . wp_nonce_url( bp_get_the_topic_permalink() . 'edit/post/' . $topic_template->post->post_id . '/' . $query_vars, 'bp_forums_edit_post' ) . '">' . __( 'Edit', 'buddypress' ) . '</a>';
+		$links[] .= '<a class="confirm" id="post-delete-link" href="' . wp_nonce_url( bp_get_the_topic_permalink() . 'delete/post/' . $topic_template->post->post_id, 'bp_forums_delete_post' ) . '">' . __( 'Delete', 'buddypress' ) . '</a>';
+
+		return apply_filters( 'bp_get_the_topic_post_admin_links', implode( $separator, $links ), $links, $r );
+	}
+
+/**
+ * Output the text to edit when editing a post.
+ */
+function bp_the_topic_post_edit_text() {
+	echo bp_get_the_topic_post_edit_text();
+}
+	/**
+	 * Return the text to edit when editing a post.
+	 *
+	 * @return string Editable text.
+	 */
+	function bp_get_the_topic_post_edit_text() {
+		$post = bp_forums_get_post( bp_action_variable( 4 ) );
+		return apply_filters( 'bp_get_the_topic_post_edit_text', esc_attr( $post->post_text ) );
+	}
+
+/**
+ * Output the pagination links for the current topic.
+ */
+function bp_the_topic_pagination() {
+	echo bp_get_the_topic_pagination();
+}
+	/**
+	 * Return the pagination links for the current topic page.
+	 *
+	 * @return string HTML pagination links.
+	 */
+	function bp_get_the_topic_pagination() {
+		global $topic_template;
+
+		return apply_filters( 'bp_get_the_topic_pagination', $topic_template->pag_links );
+	}
+
+/**
+ * Return the pagination count for the current topic page.
+ *
+ * The "count" is a string of the form "Viewing x of y posts".
+ *
+ * @return string
+ */
+function bp_the_topic_pagination_count() {
+	global $bp, $topic_template;
+
+	$start_num = intval( ( $topic_template->pag_page - 1 ) * $topic_template->pag_num ) + 1;
+	$from_num = bp_core_number_format( $start_num );
+	$to_num = bp_core_number_format( ( $start_num + ( $topic_template->pag_num - 1  ) > $topic_template->total_post_count ) ? $topic_template->total_post_count : $start_num + ( $topic_template->pag_num - 1 ) );
+	$total = bp_core_number_format( $topic_template->total_post_count );
+
+	echo apply_filters( 'bp_the_topic_pagination_count', sprintf( _n( 'Viewing post %1$s to %2$s (%3$s post)', 'Viewing post %1$s to %2$s (%3$s total posts)', $total, 'buddypress' ), $from_num, $to_num, $total ), $from_num, $to_num, $total );
+}
+
+/**
+ * Output whether this is the last page in the current topic.
+ */
+function bp_the_topic_is_last_page() {
+	echo bp_get_the_topic_is_last_page();
+}
+	/**
+	 * Is this the last page in the current topic?
+	 *
+	 * @return bool True if this is the last page of posts for the current
+	 *         topic, otherwise false.
+	 */
+	function bp_get_the_topic_is_last_page() {
+		global $topic_template;
+
+		return apply_filters( 'bp_get_the_topic_is_last_page', $topic_template->pag_page == $topic_template->pag->total_pages );
+	}
+
+/**
+ * Output the forums directory search form.
+ */
+function bp_directory_forums_search_form() {
+	$default_search_value = bp_get_search_default_text( 'forums' );
+	$search_value = !empty( $_REQUEST['fs'] ) ? stripslashes( $_REQUEST['fs'] ) : $default_search_value;
+
+	$search_form_html = '<form action="" method="get" id="search-forums-form">
+		<label><input type="text" name="s" id="forums_search" placeholder="'. esc_attr( $search_value ) .'" /></label>
+		<input type="submit" id="forums_search_submit" name="forums_search_submit" value="' . __( 'Search', 'buddypress' ) . '" />
+	</form>';
+
+	echo apply_filters( 'bp_directory_forums_search_form', $search_form_html );
+}
+
+/**
+ * Output the link to a given forum.
+ *
+ * @see bp_get_forum_permalink() for a description of arguments.
+ *
+ * @param int $forum_id See {@link bp_get_forum_permalink()}.
+ */
+function bp_forum_permalink( $forum_id = 0 ) {
+	echo bp_get_forum_permalink( $forum_id );
+}
+	/**
+	 * Return the permalink to a given forum.
+	 *
+	 * @param int $forum_id Optional. Defaults to the current forum, if
+	 *        there is one.
+	 * @return string|bool False on failure, a URL on success.
+	 */
+	function bp_get_forum_permalink( $forum_id = 0 ) {
+		global $bp;
+
+		if ( bp_is_groups_component() ) {
+			$permalink = trailingslashit( bp_get_root_domain() . '/' . bp_get_groups_root_slug() . '/' . bp_current_item() . '/forum' );
+		} else {
+			if ( empty( $forum_id ) ) {
+				global $topic_template;
+				if ( isset( $topic_template->forum_id ) )
+					$forum_id = $topic_template->forum_id;
+			}
+
+			if ( $forum = bp_forums_get_forum( $forum_id ) )
+				$permalink = trailingslashit( bp_get_root_domain() . '/' . bp_get_forums_root_slug() . '/forum/' . $forum->forum_slug );
+			else
+				return false;
+		}
+
+		return apply_filters( 'bp_get_forum_permalink', trailingslashit( $permalink ) );
+	}
+
+/**
+ * Output the name of a given forum.
+ *
+ * @see bp_get_forum_name() for a description of parameters.
+ *
+ * @param int $forum_id See {@link bp_get_forum_name()}.
+ */
+function bp_forum_name( $forum_id = 0 ) {
+	echo bp_get_forum_name( $forum_id );
+}
+	/**
+	 * Return the name of a given forum.
+	 *
+	 * @param int $forum_id Optional. Defaults to the current forum, if
+	 *        there is one.
+	 * @return string|bool False on failure, a name on success.
+	 */
+	function bp_get_forum_name( $forum_id = 0 ) {
+		global $bp;
+
+		if ( empty( $forum_id ) ) {
+			global $topic_template;
+			if ( isset( $topic_template->forum_id ) )
+				$forum_id = $topic_template->forum_id;
+		}
+
+		if ( $forum = bp_forums_get_forum( $forum_id ) )
+			return apply_filters( 'bp_get_forum_name', $forum->forum_name, $forum->forum_id );
+		else
+			return false;
+	}
+
+/**
+ * Get a heatmap of forum tags for the installation.
+ *
+ * A wrapper for {@link bb_tag_heat_map}, which provides it with BP-friendly
+ * defaults.
+ *
+ * @param array $args {
+ *     An array of optional arguments.
+ *     @type int $smallest Size of the smallest link. Default: 10.
+ *     @type int $largest Size of the largest link. Default: 42.
+ *     @type string $sizing Unit for $largest and $smallest. Default: 'px'.
+ *     @type int $limit Max number of tags to display. Default: 50.
+ * }
+ */
+function bp_forums_tag_heat_map( $args = '' ) {
+	$defaults = array(
+		'smallest' => '10',
+		'largest'  => '42',
+		'sizing'   => 'px',
+		'limit'    => '50'
+	);
+
+	$r = wp_parse_args( $args, $defaults );
+	extract( $r, EXTR_SKIP );
+
+	bb_tag_heat_map( $smallest, $largest, $sizing, $limit );
+}
+
+/**
+ * Output the current topic's tag list, comma-separated
+ *
+ * @since BuddyPress (1.5.0)
+ */
+function bp_forum_topic_tag_list() {
+	echo bp_get_forum_topic_tag_list();
+}
+	/**
+	 * Get the current topic's tag list.
+	 *
+	 * @since BuddyPress (1.5.0)
+	 *
+	 * @param string $format 'string' returns comma-separated string;
+	 *        otherwise returns array.
+	 * @return mixed $tags
+	 */
+	function bp_get_forum_topic_tag_list( $format = 'string' ) {
+		global $topic_template;
+
+		$tags_data = !empty( $topic_template->topic_tags ) ? $topic_template->topic_tags : false;
+
+		$tags = array();
+
+		if ( $tags_data ) {
+			foreach( $tags_data as $tag_data ) {
+				$tags[] = $tag_data->name;
+			}
+		}
+
+		if ( 'string' == $format )
+			$tags = implode( ', ', $tags );
+
+		return apply_filters( 'bp_forum_topic_tag_list', $tags, $format );
+	}
+
+/**
+ * Does the current topic have any tags?
+ *
+ * @since BuddyPress (1.5.0)
+ *
+ * @return bool True if the current topic has tags, otherwise false.
+ */
+function bp_forum_topic_has_tags() {
+	global $topic_template;
+
+	$has_tags = false;
+
+	if ( !empty( $topic_template->topic_tags ) )
+		$has_tags = true;
+
+	return apply_filters( 'bp_forum_topic_has_tags', $has_tags );
+}
+
+/**
+ * Output a URL to use in as a forum form 'action'.
+ */
+function bp_forum_action() {
+	echo bp_get_forum_action();
+}
+	/**
+	 * Get a URL to use in as a forum form 'action'.
+	 *
+	 * @return string URL of the current page, minus query args.
+	 */
+	function bp_get_forum_action() {
+		global $topic_template;
+
+		return apply_filters( 'bp_get_forum_action', bp_get_root_domain() . esc_attr( $_SERVER['REQUEST_URI'] ) );
+	}
+
+/**
+ * Output a URL to use in as a forum topic form 'action'.
+ */
+function bp_forum_topic_action() {
+	echo bp_get_forum_topic_action();
+}
+	/**
+	 * Get a URL to use in as a forum topic form 'action'.
+	 *
+	 * @return string URL of the current page, minus query args.
+	 */
+	function bp_get_forum_topic_action() {
+		return apply_filters( 'bp_get_forum_topic_action', $_SERVER['REQUEST_URI'] );
+	}
+
+/**
+ * Output the total topic count for a given user.
+ *
+ * @see bp_get_forum_topic_count_for_user() for description of parameters.
+ *
+ * @param int $user_id See {@link bp_get_forum_topic_count_for_user()}.
+ */
+function bp_forum_topic_count_for_user( $user_id = 0 ) {
+	echo bp_get_forum_topic_count_for_user( $user_id );
+}
+	/**
+	 * Return the total topic count for a given user.
+	 *
+	 * @param int $user_id See {@link bp_forums_total_topic_count_for_user}.
+	 */
+	function bp_get_forum_topic_count_for_user( $user_id = 0 ) {
+		return apply_filters( 'bp_get_forum_topic_count_for_user', bp_forums_total_topic_count_for_user( $user_id ) );
+	}
+
+/**
+ * Output the total topic count for a given user.
+ *
+ * @see bp_get_forum_topic_count() for description of parameters.
+ *
+ * @param int $user_id See {@link bp_get_forum_topic_count()}.
+ */
+function bp_forum_topic_count( $user_id = 0 ) {
+	echo bp_get_forum_topic_count( $user_id );
+}
+	/**
+	 * Return the total topic count for a given user.
+	 *
+	 * @param int $user_id See {@link bp_forums_total_topic_count()}.
+	 */
+	function bp_get_forum_topic_count( $user_id = 0 ) {
+		return apply_filters( 'bp_get_forum_topic_count', bp_forums_total_topic_count( $user_id ) );
+	}
Index: /tags/1.9/bp-forums/deprecated/1.6.php
===================================================================
--- /tags/1.9/bp-forums/deprecated/1.6.php	(revision 7684)
+++ /tags/1.9/bp-forums/deprecated/1.6.php	(revision 7684)
@@ -0,0 +1,255 @@
+<?php
+
+/**
+ * BuddyPress Forums Deprecated Functions
+ *
+ * This file contains all the deprecated functions for BuddyPress forums since
+ * version 1.6. This was a major update for the forums component, moving from
+ * bbPress 1.x to bbPress 2.x.
+ *
+ * @package BuddyPress
+ * @subpackage Forums
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/**
+ * Outputs the markup for the bb-forums-admin panel
+ */
+function bp_forums_bbpress_admin() {
+
+	// The text and URL of the Site Wide Forums button differs depending on whether bbPress
+	// is running
+	if ( is_plugin_active( 'bbpress/bbpress.php' ) ) {
+		// The bbPress admin page will always be on the root blog. switch_to_blog() will
+		// pass through if we're already there.
+		switch_to_blog( bp_get_root_blog_id() );
+		$button_url = admin_url( add_query_arg( array( 'page' => 'bbpress' ), 'options-general.php' ) );
+		restore_current_blog();
+
+		$button_text = __( 'Configure bbPress', 'buddypress' );
+	} else {
+		$button_url = bp_get_admin_url( add_query_arg( array( 'tab' => 'plugin-information', 'plugin' => 'bbpress', 'TB_iframe' => 'true', 'width' => '640', 'height' => '500' ), 'plugin-install.php' ) );
+		$button_text = __( 'Install bbPress', 'buddypress' );
+	}
+
+	$action = bp_get_admin_url( 'admin.php?page=bb-forums-setup&reinstall=1' ); ?>
+
+	<div class="wrap">
+		<?php screen_icon( 'buddypress' ); ?>
+
+		<h2 class="nav-tab-wrapper"><?php bp_core_admin_tabs( __( 'Forums', 'buddypress' ) ); ?></h2>
+
+		<?php if ( isset( $_POST['submit'] ) ) : ?>
+
+			<div id="message" class="updated fade">
+				<p><?php _e( 'Settings Saved.', 'buddypress' ) ?></p>
+			</div>
+
+		<?php endif; ?>
+
+		<?php
+
+		if ( isset( $_REQUEST['reinstall'] ) || !bp_forums_is_installed_correctly() ) :
+
+			// Delete the bb-config.php location option
+			bp_delete_option( 'bb-config-location' );
+
+			// Now delete the bb-config.php file
+			@unlink( ABSPATH . 'bb-config.php' );
+
+			// show the updated wizard
+			bp_forums_bbpress_install_wizard();
+
+		else : ?>
+
+			<div style="width: 45%; float: left; margin-top: 20px;">
+				<h3><?php _e( '(Installed)', 'buddypress' ); ?> <?php _e( 'Forums for Groups', 'buddypress' ) ?></h3>
+
+				<p><?php _e( 'Give each individual group its own discussion forum. Choose this if you\'d like to keep your members\' conversations separated into distinct areas.' , 'buddypress' ); ?></p>
+
+				<p><?php _e( 'Note: This component is retired and will not be receiving any updates in the future.  Only use this component if your current site relies on it.' , 'buddypress' ); ?></p>
+
+				<h4 style="margin-bottom: 10px;"><?php _e( 'Features', 'buddypress' ); ?></h4>
+				<ul class="description" style="list-style: square; margin-left: 30px;">
+					<li><?php _e( 'Group Integration',           'buddypress' ); ?></p></li>
+					<li><?php _e( 'Member Profile Integration',  'buddypress' ); ?></p></li>
+					<li><?php _e( 'Activity Stream Integration', 'buddypress' ); ?></p></li>
+					<li><?php _e( '@ Mention Integration',       'buddypress' ); ?></p></li>
+				</ul>
+
+				<div>
+					<a class="button button-primary confirm" href="<?php echo $action ?>"><?php _e( 'Uninstall Group Forums', 'buddypress' ) ?></a> &nbsp;
+				</div>
+			</div>
+
+			<div style="width: 45%; float: left; margin: 20px 0 20px 20px; padding: 0 20px 20px 20px; border: 1px solid #ddd; background-color: #fff;">
+				<h3><?php _e( 'New! bbPress', 'buddypress' ) ?></h3>
+				<p><?php _e( 'bbPress is a brand-new forum plugin from one of the lead developers of BuddyPress.', 'buddypress' ) ?></p>
+
+				<p><?php _e( 'It boasts a bunch of cool features that the BP Legacy Discussion Forums does not have including:', 'buddypress' ) ?></p>
+
+				<ul class="description" style="list-style: square; margin-left: 30px;">
+					<li><?php _e( 'Non-group specific forum creation', 'buddypress' ); ?></p></li>
+					<li><?php _e( 'Moderation via the WP admin dashboard', 'buddypress' ); ?></p></li>
+					<li><?php _e( 'Topic splitting', 'buddypress' ); ?></p></li>
+					<li><?php _e( 'Revisions', 'buddypress' ); ?></p></li>
+					<li><?php _e( 'Spam management', 'buddypress' ); ?></p></li>
+					<li><?php _e( 'Subscriptions', 'buddypress' ); ?></p></li>
+					<li><?php _e( 'And more!', 'buddypress' ); ?></p></li>
+				</ul>
+
+				<p><?php printf( __( 'If you decide to use bbPress, you will need to deactivate the legacy group forum component.  For more info, <a href="%s">read this codex article</a>.', 'buddypress' ), 'http://codex.buddypress.org/user/setting-up-a-new-installation/installing-group-and-sitewide-forums/using-bbpress-2-2-with-buddypress/' ) ?></p>
+
+				<div>
+					<a class="button thickbox button-primary" href="<?php echo esc_attr( $button_url ) ?>"><?php echo esc_html( $button_text ) ?></a> &nbsp;
+				</div>
+			</div>
+
+		<?php endif; ?>
+
+	</div>
+<?php
+}
+
+function bp_forums_bbpress_install_wizard() {
+	$post_url                 = bp_get_admin_url( 'admin.php?page=bb-forums-setup' );
+	$bbpress_plugin_is_active = false;
+
+	$step = isset( $_REQUEST['step'] ) ? $_REQUEST['step'] : '';
+
+	// The text and URL of the Site Wide Forums button differs depending on whether bbPress
+	// is running
+	if ( is_plugin_active( 'bbpress/bbpress.php' ) ) {
+		$bbpress_plugin_is_active = true;
+
+		// The bbPress admin page will always be on the root blog. switch_to_blog() will
+		// pass through if we're already there.
+		switch_to_blog( bp_get_root_blog_id() );
+		$button_url = admin_url( add_query_arg( array( 'page' => 'bbpress' ), 'options-general.php' ) );
+		restore_current_blog();
+
+		$button_text = __( 'Configure bbPress', 'buddypress' );
+	} else {
+		$button_url = bp_get_admin_url( add_query_arg( array( 'tab' => 'plugin-information', 'plugin' => 'bbpress', 'TB_iframe' => 'true', 'width' => '640', 'height' => '500' ), 'plugin-install.php' ) );
+		$button_text = __( 'Install bbPress', 'buddypress' );
+	}
+
+	switch( $step ) {
+		case 'existing':
+			if ( isset( $_REQUEST['doinstall'] ) && ( 1 == (int) $_REQUEST['doinstall'] ) ) {
+				if ( !bp_forums_configure_existing_install() ) {
+					_e( 'The bb-config.php file was not found at that location, please try again.', 'buddypress' );
+				} else {
+					?>
+					<h3><?php _e( 'Forums were set up correctly using your existing bbPress install!', 'buddypress' ) ?></h3>
+					<p><?php _e( 'BuddyPress will now use its internal copy of bbPress to run the forums on your site. If you wish, you can remove your old bbPress installation files, as long as you keep the bb-config.php file in the same location.', 'buddypress' ) ?></p><?php
+				}
+			} else { ?>
+
+					<form action="" method="post">
+						<h3><?php _e( 'Existing bbPress Installation', 'buddypress' ) ?></h3>
+						<p><?php _e( "BuddyPress can make use of your existing bbPress install. Just provide the location of your <code>bb-config.php</code> file, and BuddyPress will do the rest.", 'buddypress' ) ?></p>
+						<p><label><code>bb-config.php</code> file location:</label><br /><input style="width: 50%" type="text" name="bbconfigloc" id="bbconfigloc" value="<?php echo str_replace( 'buddypress', '', $_SERVER['DOCUMENT_ROOT'] ) ?>" /></p>
+						<p><input type="submit" class="button-primary" value="<?php _e( 'Complete Installation', 'buddypress' ) ?>" /></p>
+						<input type="hidden" name="step" value="existing" />
+						<input type="hidden" name="doinstall" value="1" />
+						<?php wp_nonce_field( 'bp_forums_existing_install_init' ) ?>
+					</form>
+
+				<?php
+			}
+		break;
+
+		case 'new':
+			if ( isset( $_REQUEST['doinstall'] ) && 1 == (int)$_REQUEST['doinstall'] ) {
+				$result = bp_forums_bbpress_install();
+
+				switch ( $result ) {
+					case 1:
+						_e( '<p>All done! Configuration settings have been saved to the file <code>bb-config.php</code> in the root of your WordPress install.</p>', 'buddypress' );
+						break;
+					default:
+						// Just write the contents to screen
+						_e( '<p>A configuration file could not be created. No problem, but you will need to save the text shown below into a file named <code>bb-config.php</code> in the root directory of your WordPress installation before you can start using the forum functionality.</p>', 'buddypress' ); ?>
+
+						<textarea style="display:block; margin-top: 30px; width: 80%;" rows="50"><?php echo htmlspecialchars( $result ); ?></textarea>
+
+					<?php
+						break;
+				}
+			} else { ?>
+
+				<h3><?php _e( 'New bbPress Installation', 'buddypress' ) ?></h3>
+				<p><?php _e( "You've decided to set up a new installation of bbPress for forum management in BuddyPress. This is very simple and is usually just a one click
+				process. When you're ready, hit the link below.", 'buddypress' ) ?></p>
+				<p><a class="button-primary" href="<?php echo wp_nonce_url( $post_url . '&step=new&doinstall=1', 'bp_forums_new_install_init' ) ?>"><?php _e( 'Complete Installation', 'buddypress' ) ?></a></p>
+
+				<?php
+			}
+		break;
+
+		default:
+			if ( !file_exists( BP_PLUGIN_DIR . '/bp-forums/bbpress/' ) ) { ?>
+
+				<div id="message" class="error">
+					<p><?php printf( __( 'bbPress files were not found. To install the forums component you must download a copy of bbPress and make sure it is in the folder: "%s"', 'buddypress' ), 'wp-content/plugins/buddypress/bp-forums/bbpress/' ) ?></p>
+				</div>
+
+			<?php } else {
+
+				// Include the plugin install
+
+				add_thickbox();
+				wp_enqueue_script( 'plugin-install' );
+				wp_admin_css( 'plugin-install' );
+			?>
+
+				<div style="width: 45%; float: left;  margin-top: 20px;">
+					<h3><?php _e( 'Forums for Groups', 'buddypress' ) ?></h3>
+
+					<p><?php _e( 'Give each individual group its own discussion forum. Choose this if you\'d like to keep your members\' conversations separated into distinct areas.' , 'buddypress' ); ?></p>
+
+					<p><?php _e( 'Note: This component is retired and will not be receiving any updates in the future.  Only use this component if your current site relies on it.' , 'buddypress' ); ?></p>
+
+					<h4 style="margin-bottom: 10px;"><?php _e( 'Features', 'buddypress' ); ?></h4>
+					<ul class="description" style="list-style: square; margin-left: 30px;">
+						<li><?php _e( 'Group Integration',           'buddypress' ); ?></p></li>
+						<li><?php _e( 'Member Profile Integration',  'buddypress' ); ?></p></li>
+						<li><?php _e( 'Activity Stream Integration', 'buddypress' ); ?></p></li>
+						<li><?php _e( '@ Mention Integration',       'buddypress' ); ?></p></li>
+					</ul>
+
+					<div>
+						<a class="button button-primary" href="<?php echo $post_url . '&step=new' ?>"><?php _e( 'Install Group Forums', 'buddypress' ) ?></a> &nbsp;
+						<a class="button" href="<?php echo $post_url . '&step=existing' ?>"><?php _e( 'Use Existing Installation', 'buddypress' ) ?></a>
+					</div>
+				</div>
+
+				<div style="width: 45%; float: left; margin: 20px 0 20px 20px; padding: 0 20px 20px 20px; border: 1px solid #ddd; background-color: #fff;">
+					<h3><?php _e( 'New! bbPress', 'buddypress' ) ?></h3>
+					<p><?php _e( 'bbPress is a brand-new forum plugin from one of the lead developers of BuddyPress.', 'buddypress' ) ?></p>
+
+					<p><?php _e( 'It boasts a bunch of cool features that the BP Legacy Discussion Forums does not have including:', 'buddypress' ) ?></p>
+
+					<ul class="description" style="list-style: square; margin-left: 30px;">
+						<li><?php _e( 'Non-group specific forum creation', 'buddypress' ); ?></p></li>
+						<li><?php _e( 'Moderation via the WP admin dashboard', 'buddypress' ); ?></p></li>
+						<li><?php _e( 'Topic splitting', 'buddypress' ); ?></p></li>
+						<li><?php _e( 'Revisions', 'buddypress' ); ?></p></li>
+						<li><?php _e( 'Spam management', 'buddypress' ); ?></p></li>
+						<li><?php _e( 'Subscriptions', 'buddypress' ); ?></p></li>
+						<li><?php _e( 'And more!', 'buddypress' ); ?></p></li>
+					</ul>
+
+					<p><?php printf( __( 'If you decide to use bbPress, you will need to deactivate the legacy group forum component.  For more info, <a href="%s">read this codex article</a>.', 'buddypress' ), 'http://codex.buddypress.org/user/setting-up-a-new-installation/installing-group-and-sitewide-forums/using-bbpress-2-2-with-buddypress/' ) ?></p>
+					<div>
+						<a class="button button-primary <?php if ( ! $bbpress_plugin_is_active ) { echo esc_attr( 'thickbox' ); }?>" href="<?php echo esc_attr( $button_url ) ?>"><?php echo esc_html( $button_text ) ?></a> &nbsp;
+					</div>
+				</div>
+
+			<?php }
+		break;
+	}
+}
Index: /tags/1.9/bp-forums/deprecated/1.7.php
===================================================================
--- /tags/1.9/bp-forums/deprecated/1.7.php	(revision 7684)
+++ /tags/1.9/bp-forums/deprecated/1.7.php	(revision 7684)
@@ -0,0 +1,205 @@
+<?php
+
+/**
+ * BuddyPress Forums Deprecated Functions
+ *
+ * This file contains all the deprecated functions for BuddyPress forums since
+ * version 1.7. This was a major update for the forums component, moving from
+ * bbPress 1.x to bbPress 2.x.
+ *
+ * @package BuddyPress
+ * @subpackage Forums
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+function bp_forums_add_admin_menu() {
+
+	if ( !is_super_admin() )
+		return false;
+
+	$page  = bp_core_do_network_admin()  ? 'settings.php' : 'options-general.php';
+
+	// Add the administration tab under the "Site Admin" tab for site administrators
+	$hook = add_submenu_page( $page, __( 'Forums', 'buddypress' ), __( 'Forums', 'buddypress' ), 'manage_options', 'bb-forums-setup', "bp_forums_bbpress_admin" );
+
+	// Fudge the highlighted subnav item when on the BuddyPress Forums admin page
+	add_action( "admin_head-$hook", 'bp_core_modify_admin_menu_highlight' );
+}
+add_action( bp_core_admin_hook(), 'bp_forums_add_admin_menu' );
+
+function bp_forums_configure_existing_install() {
+	global $wpdb, $bbdb;
+
+	check_admin_referer( 'bp_forums_existing_install_init' );
+
+	// Sanitize $_REQUEST['bbconfigloc']
+	$_REQUEST['bbconfigloc'] = apply_filters( 'bp_forums_bbconfig_location', $_REQUEST['bbconfigloc'] );
+
+	if ( false === strpos( $_REQUEST['bbconfigloc'], 'bb-config.php' ) ) {
+		if ( '/' != substr( $_REQUEST['bbconfigloc'], -1, 1 ) )
+			$_REQUEST['bbconfigloc'] .= '/';
+
+		$_REQUEST['bbconfigloc'] .= 'bb-config.php';
+	}
+
+	bp_update_option( 'bb-config-location', $_REQUEST['bbconfigloc'] );
+
+	if ( !file_exists( $_REQUEST['bbconfigloc'] ) ) {
+		return false;
+	}
+
+	return true;
+}
+
+function bp_forums_bbpress_install( $location = '' ) {
+	global $wpdb, $bbdb, $bp;
+
+	check_admin_referer( 'bp_forums_new_install_init' );
+
+	if ( empty( $location ) ) {
+		$location = ABSPATH . 'bb-config.php';
+	}
+
+	// Create the bb-config.php file
+	$initial_write = bp_forums_bbpress_write(
+		BP_PLUGIN_DIR . '/bp-forums/bbpress/bb-config-sample.php',
+		$location,
+		array(
+			"define( 'BBDB_NAME',"  => array( "'bbpress'",                     	"'" . DB_NAME . "'" ),
+			"define( 'BBDB_USER',"  => array( "'username'",                    	"'" . DB_USER . "'" ),
+			"define( 'BBDB_PASSWO"  => array( "'password'",                    	"'" . DB_PASSWORD . "'" ),
+			"define( 'BBDB_HOST',"  => array( "'localhost'",                   	"'" . DB_HOST . "'" ),
+			"define( 'BBDB_CHARSE"  => array( "'utf8'",                        	"'" . DB_CHARSET . "'" ),
+			"define( 'BBDB_COLLAT"  => array( "''",                            	"'" . DB_COLLATE . "'" ),
+			"define( 'BB_AUTH_KEY"  => array( "'put your unique phrase here'",  "'" . addslashes( AUTH_KEY ) . "'" ),
+			"define( 'BB_SECURE_A"  => array( "'put your unique phrase here'",  "'" . addslashes( SECURE_AUTH_KEY ) . "'" ),
+			"define( 'BB_LOGGED_I"  => array( "'put your unique phrase here'",  "'" . addslashes( LOGGED_IN_KEY ) . "'" ),
+			"define( 'BB_NONCE_KE"  => array( "'put your unique phrase here'",  "'" . addslashes( NONCE_KEY ) . "'" ),
+			"\$bb_table_prefix = '" => array( "'bb_'",                          "'" . $bp->table_prefix . "bb_'" ),
+			"define( 'BB_LANG', '"  => array( "''",                             "'" . get_locale() . "'" )
+		)
+	);
+
+	// Add the custom user and usermeta entries to the config file
+	if ( $initial_write == 1 ) {
+		$file = file_get_contents( $location );
+	} else {
+		$file = &$initial_write;
+	}
+
+	$file = trim( $file );
+	if ( '?>' == substr( $file, -2, 2 ) ) {
+		$file = substr( $file, 0, -2 );
+	}
+
+	$file .= "\n" .   '$bb->custom_user_table = \'' . $wpdb->users . '\';';
+	$file .= "\n" .   '$bb->custom_user_meta_table = \'' . $wpdb->usermeta . '\';';
+	$file .= "\n\n" . '$bb->uri = \'' . BP_PLUGIN_URL . '/bp-forums/bbpress/\';';
+	$file .= "\n" .   '$bb->name = \'' . get_blog_option( bp_get_root_blog_id(), 'blogname' ) . ' ' . __( 'Forums', 'buddypress' ) . '\';';
+
+	if ( is_multisite() ) {
+		$file .= "\n" .   '$bb->wordpress_mu_primary_blog_id = ' . bp_get_root_blog_id() . ';';
+	}
+
+	if ( defined( 'AUTH_SALT' ) ) {
+		$file .= "\n\n" . 'define(\'BB_AUTH_SALT\', \'' . addslashes( AUTH_SALT ) . '\');';
+	}
+
+	if ( defined( 'LOGGED_IN_SALT' ) ) {
+		$file .= "\n" .   'define(\'BB_LOGGED_IN_SALT\', \'' . addslashes( LOGGED_IN_SALT ) . '\');';
+	}
+
+	if ( defined( 'SECURE_AUTH_SALT' ) ) {
+		$file .= "\n" .   'define(\'BB_SECURE_AUTH_SALT\', \'' . addslashes( SECURE_AUTH_SALT ) . '\');';
+	}
+
+	$file .= "\n\n" . 'define(\'WP_AUTH_COOKIE_VERSION\', 2);';
+	$file .= "\n\n" . '?>';
+
+	if ( $initial_write == 1 ) {
+		$file_handle = fopen( $location, 'w' );
+		fwrite( $file_handle, $file );
+		fclose( $file_handle );
+	} else {
+		$initial_write = $file;
+	}
+
+	bp_update_option( 'bb-config-location', $location );
+	return $initial_write;
+}
+
+function bp_forums_bbpress_write( $file_source, $file_target, $alterations ) {
+
+	if ( empty( $file_source ) || !file_exists( $file_source ) || !is_file( $file_source ) ) {
+		return -1;
+	}
+
+	if ( empty( $file_target ) ) {
+		$file_target = $file_source;
+	}
+
+	if ( empty( $alterations ) || !is_array( $alterations ) ) {
+		return -2;
+	}
+
+	// Get the existing lines in the file
+	$lines = file( $file_source );
+
+	// Initialise an array to store the modified lines
+	$modified_lines = array();
+
+	// Loop through the lines and modify them
+	foreach ( (array) $lines as $line ) {
+		if ( isset( $alterations[substr( $line, 0, 20 )] ) ) {
+			$alteration = $alterations[substr( $line, 0, 20 )];
+			$modified_lines[] = str_replace( $alteration[0], $alteration[1], $line );
+		} else {
+			$modified_lines[] = $line;
+		}
+	}
+
+	$writable = true;
+	if ( file_exists( $file_target ) ) {
+		if ( !is_writable( $file_target ) ) {
+			$writable = false;
+		}
+	} else {
+		$dir_target = dirname( $file_target );
+
+		if ( file_exists( $dir_target ) ) {
+			if ( !is_writable( $dir_target ) || !is_dir( $dir_target ) ) {
+				$writable = false;
+			}
+		} else {
+			$writable = false;
+		}
+	}
+
+	if ( empty( $writable ) ) {
+		return trim( join( null, $modified_lines ) );
+	}
+
+	// Open the file for writing - rewrites the whole file
+	$file_handle = fopen( $file_target, 'w' );
+
+	// Write lines one by one to avoid OS specific newline hassles
+	foreach ( (array) $modified_lines as $modified_line ) {
+		if ( strlen( $modified_line ) - 2 === strrpos( $modified_line, '?>' ) ) {
+			$modified_line = '?>';
+		}
+
+		fwrite( $file_handle, $modified_line );
+		if ( $modified_line == '?>' ) {
+			break;
+		}
+	}
+
+	// Close the config file
+	fclose( $file_handle );
+
+	@chmod( $file_target, 0666 );
+
+	return 1;
+}
Index: /tags/1.9/bp-friends/bp-friends-actions.php
===================================================================
--- /tags/1.9/bp-friends/bp-friends-actions.php	(revision 7684)
+++ /tags/1.9/bp-friends/bp-friends-actions.php	(revision 7684)
@@ -0,0 +1,91 @@
+<?php
+
+/**
+ * BuddyPress Friends Actions
+ *
+ * Action functions are exactly the same as screen functions, however they do
+ * not have a template screen associated with them. Usually they will send the
+ * user back to the default screen after execution.
+ *
+ * @package BuddyPress
+ * @subpackage FriendsActions
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/**
+ * Catch and process friendship requests.
+ */
+function friends_action_add_friend() {
+	if ( !bp_is_friends_component() || !bp_is_current_action( 'add-friend' ) )
+		return false;
+
+	if ( !$potential_friend_id = (int)bp_action_variable( 0 ) )
+		return false;
+
+	if ( $potential_friend_id == bp_loggedin_user_id() )
+		return false;
+
+	$friendship_status = BP_Friends_Friendship::check_is_friend( bp_loggedin_user_id(), $potential_friend_id );
+
+	if ( 'not_friends' == $friendship_status ) {
+
+		if ( !check_admin_referer( 'friends_add_friend' ) )
+			return false;
+
+		if ( !friends_add_friend( bp_loggedin_user_id(), $potential_friend_id ) ) {
+			bp_core_add_message( __( 'Friendship could not be requested.', 'buddypress' ), 'error' );
+		} else {
+			bp_core_add_message( __( 'Friendship requested', 'buddypress' ) );
+		}
+
+	} else if ( 'is_friend' == $friendship_status ) {
+		bp_core_add_message( __( 'You are already friends with this user', 'buddypress' ), 'error' );
+	} else {
+		bp_core_add_message( __( 'You already have a pending friendship request with this user', 'buddypress' ), 'error' );
+	}
+
+	bp_core_redirect( wp_get_referer() );
+
+	return false;
+}
+add_action( 'bp_init', 'friends_action_add_friend' );
+
+/**
+ * Catch and process Remove Friendship requests.
+ */
+function friends_action_remove_friend() {
+	if ( !bp_is_friends_component() || !bp_is_current_action( 'remove-friend' ) )
+		return false;
+
+	if ( !$potential_friend_id = (int)bp_action_variable( 0 ) )
+		return false;
+
+	if ( $potential_friend_id == bp_loggedin_user_id() )
+		return false;
+
+	$friendship_status = BP_Friends_Friendship::check_is_friend( bp_loggedin_user_id(), $potential_friend_id );
+
+	if ( 'is_friend' == $friendship_status ) {
+
+		if ( !check_admin_referer( 'friends_remove_friend' ) )
+			return false;
+
+		if ( !friends_remove_friend( bp_loggedin_user_id(), $potential_friend_id ) ) {
+			bp_core_add_message( __( 'Friendship could not be canceled.', 'buddypress' ), 'error' );
+		} else {
+			bp_core_add_message( __( 'Friendship canceled', 'buddypress' ) );
+		}
+
+	} else if ( 'is_friends' == $friendship_status ) {
+		bp_core_add_message( __( 'You are not yet friends with this user', 'buddypress' ), 'error' );
+	} else {
+		bp_core_add_message( __( 'You have a pending friendship request with this user', 'buddypress' ), 'error' );
+	}
+
+	bp_core_redirect( wp_get_referer() );
+
+	return false;
+}
+add_action( 'bp_init', 'friends_action_remove_friend' );
Index: /tags/1.9/bp-friends/bp-friends-activity.php
===================================================================
--- /tags/1.9/bp-friends/bp-friends-activity.php	(revision 7684)
+++ /tags/1.9/bp-friends/bp-friends-activity.php	(revision 7684)
@@ -0,0 +1,146 @@
+<?php
+
+/**
+ * BuddyPress Friends Activity Functions
+ *
+ * These functions handle the recording, deleting and formatting of activity
+ * for the user and for this specific component.
+ *
+ * @package BuddyPress
+ * @subpackage FriendsActivity
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/**
+ * Record an activity item related to the Friends component.
+ *
+ * A wrapper for {@link bp_activity_add()} that provides some Friends-specific
+ * defaults.
+ *
+ * @see bp_activity_add() for more detailed description of parameters and
+ *      return values.
+ *
+ * @param array $args {
+ *     An array of arguments for the new activity item. Accepts all parameters
+ *     of {@link bp_activity_add()}. The one difference is the following
+ *     argument, which has a different default here:
+ *     @type string $component Default: the id of your Friends component
+ *           (usually 'friends').
+ * }
+ * @return bool See {@link bp_activity_add()}.
+ */
+function friends_record_activity( $args = '' ) {
+
+	if ( ! bp_is_active( 'activity' ) ) {
+		return false;
+	}
+
+	$r = wp_parse_args( $args, array(
+		'user_id'           => bp_loggedin_user_id(),
+		'action'            => '',
+		'content'           => '',
+		'primary_link'      => '',
+		'component'         => buddypress()->friends->id,
+		'type'              => false,
+		'item_id'           => false,
+		'secondary_item_id' => false,
+		'recorded_time'     => bp_core_current_time(),
+		'hide_sitewide'     => false
+	) );
+
+	return bp_activity_add( $r );
+}
+
+/**
+ * Delete an activity item related to the Friends component.
+ *
+ * @param array $args {
+ *     An array of arguments for the item to delete.
+ *     @type int $item_id ID of the 'item' associated with the activity item.
+ *           For Friends activity items, this is usually the user ID of one
+ *           of the friends.
+ *     @type string $type The 'type' of the activity item (eg
+ *           'friendship_accepted').
+ *     @type int $user_id ID of the user associated with the activity item.
+ * }
+ * @return bool True on success, false on failure.
+ */
+function friends_delete_activity( $args ) {
+	if ( ! bp_is_active( 'activity' ) ) {
+		return;
+	}
+
+	bp_activity_delete_by_item_id( array(
+		'component' => buddypress()->friends->id,
+		'item_id'   => $args['item_id'],
+		'type'      => $args['type'],
+		'user_id'   => $args['user_id']
+	) );
+}
+
+/**
+ * Register the activity actions for bp-friends.
+ */
+function friends_register_activity_actions() {
+
+	if ( !bp_is_active( 'activity' ) ) {
+		return false;
+	}
+
+	$bp = buddypress();
+
+	// These two added in BP 1.6
+	bp_activity_set_action( $bp->friends->id, 'friendship_accepted', __( 'Friendships accepted', 'buddypress' ) );
+	bp_activity_set_action( $bp->friends->id, 'friendship_created',  __( 'New friendships',      'buddypress' ) );
+
+	// < BP 1.6 backpat
+	bp_activity_set_action( $bp->friends->id, 'friends_register_activity_action', __( 'New friendship created', 'buddypress' ) );
+
+	do_action( 'friends_register_activity_actions' );
+}
+add_action( 'bp_register_activity_actions', 'friends_register_activity_actions' );
+
+/**
+ * Add activity stream items when one members accepts another members request
+ * for virtual friendship.
+ *
+ * @since BuddyPress (1.9.0)
+ *
+ * @param int $friendship_id
+ * @param int $initiator_user_id
+ * @param int $friend_user_id
+ * @param object $friendship Optional
+ */
+function bp_friends_friendship_accepted_activity( $friendship_id, $initiator_user_id, $friend_user_id, $friendship = false ) {
+
+	// Bail if Activity component is not active
+	if ( ! bp_is_active( 'activity' ) ) {
+		return;
+	}
+
+	// Get links to both members profiles
+	$initiator_link = bp_core_get_userlink( $initiator_user_id );
+	$friend_link    = bp_core_get_userlink( $friend_user_id    );
+
+	// Record in activity streams for the initiator
+	friends_record_activity( array(
+		'user_id'           => $initiator_user_id,
+		'type'              => 'friendship_created',
+		'action'            => apply_filters( 'friends_activity_friendship_accepted_action', sprintf( __( '%1$s and %2$s are now friends', 'buddypress' ), $initiator_link, $friend_link ), $friendship ),
+		'item_id'           => $friendship_id,
+		'secondary_item_id' => $friend_user_id
+	) );
+
+	// Record in activity streams for the friend
+	friends_record_activity( array(
+		'user_id'           => $friend_user_id,
+		'type'              => 'friendship_created',
+		'action'            => apply_filters( 'friends_activity_friendship_accepted_action', sprintf( __( '%1$s and %2$s are now friends', 'buddypress' ), $friend_link, $initiator_link ), $friendship ),
+		'item_id'           => $friendship_id,
+		'secondary_item_id' => $initiator_user_id,
+		'hide_sitewide'     => true // We've already got the first entry site wide
+	) );
+}
+add_action( 'friends_friendship_accepted', 'bp_friends_friendship_accepted_activity', 10, 4 );
Index: /tags/1.9/bp-friends/bp-friends-cache.php
===================================================================
--- /tags/1.9/bp-friends/bp-friends-cache.php	(revision 7684)
+++ /tags/1.9/bp-friends/bp-friends-cache.php	(revision 7684)
@@ -0,0 +1,38 @@
+<?php
+
+/**
+ * BuddyPress Friends Caching.
+ *
+ * Caching functions handle the clearing of cached objects and pages on specific
+ * actions throughout BuddyPress.
+ *
+ * @package BuddyPress
+ * @subpackage FriendsCaching
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/**
+ * Clear friends-related cache for members of a specific friendship.
+ *
+ * @param int $friendship_id ID of the friendship whose two members should
+ *        have their friends cache busted.
+ */
+function friends_clear_friend_object_cache( $friendship_id ) {
+	if ( !$friendship = new BP_Friends_Friendship( $friendship_id ) )
+		return false;
+
+	wp_cache_delete( 'friends_friend_ids_' .    $friendship->initiator_user_id, 'bp' );
+	wp_cache_delete( 'friends_friend_ids_' .    $friendship->friend_user_id,    'bp' );
+}
+
+// List actions to clear object caches on
+add_action( 'friends_friendship_accepted', 'friends_clear_friend_object_cache' );
+add_action( 'friends_friendship_deleted',  'friends_clear_friend_object_cache' );
+
+// List actions to clear super cached pages on, if super cache is installed
+add_action( 'friends_friendship_rejected',  'bp_core_clear_cache' );
+add_action( 'friends_friendship_accepted',  'bp_core_clear_cache' );
+add_action( 'friends_friendship_deleted',   'bp_core_clear_cache' );
+add_action( 'friends_friendship_requested', 'bp_core_clear_cache' );
Index: /tags/1.9/bp-friends/bp-friends-classes.php
===================================================================
--- /tags/1.9/bp-friends/bp-friends-classes.php	(revision 7684)
+++ /tags/1.9/bp-friends/bp-friends-classes.php	(revision 7684)
@@ -0,0 +1,597 @@
+<?php
+/**
+ * BuddyPress Friends Classes
+ *
+ * @package BuddyPress
+ * @subpackage FriendsClasses
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/**
+ * BuddyPress Friendship object.
+ */
+class BP_Friends_Friendship {
+
+	/**
+	 * ID of the friendship.
+	 *
+	 * @access public
+	 * @var int
+	 */
+	public $id;
+
+	/**
+	 * User ID of the friendship initiator.
+	 *
+	 * @access public
+	 * @var int
+	 */
+	public $initiator_user_id;
+
+	/**
+	 * User ID of the 'friend' - the one invited to the friendship.
+	 *
+	 * @access public
+	 * @var int
+	 */
+	public $friend_user_id;
+
+	/**
+	 * Has the friendship been confirmed/accepted?
+	 *
+	 * @access public
+	 * @var int
+	 */
+	public $is_confirmed;
+
+	/**
+	 * Is this a "limited" friendship?
+	 *
+	 * Not currently used by BuddyPress.
+	 *
+	 * @access public
+	 * @var int
+	 */
+	public $is_limited;
+
+	/**
+	 * Date the friendship was created.
+	 *
+	 * @access public
+	 * @var string
+	 */
+	public $date_created;
+
+	/**
+	 * Is this a request?
+	 *
+	 * Not currently used in BuddyPress.
+	 *
+	 * @access public
+	 * @var unknown
+	 */
+	public $is_request;
+
+	/**
+	 * Should additional friend details be queried?
+	 *
+	 * @access public
+	 * @var bool
+	 */
+	public $populate_friend_details;
+
+	/**
+	 * Details about the friend.
+	 *
+	 * @access public
+	 * @var BP_Core_User
+	 */
+	public $friend;
+
+	/**
+	 * Constructor method.
+	 *
+	 * @param int $id Optional. The ID of an existing friendship.
+	 * @param bool $is_request Deprecated.
+	 * @param bool $populate_friend_details True if friend details should
+	 *        be queried.
+	 */
+	public function __construct( $id = null, $is_request = false, $populate_friend_details = true ) {
+		$this->is_request = $is_request;
+
+		if ( !empty( $id ) ) {
+			$this->id                      = $id;
+			$this->populate_friend_details = $populate_friend_details;
+			$this->populate( $this->id );
+		}
+	}
+
+	/**
+	 * Set up data about the current friendship.
+	 */
+	public function populate() {
+		global $wpdb, $bp;
+
+		if ( $friendship = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$bp->friends->table_name} WHERE id = %d", $this->id ) ) ) {
+			$this->initiator_user_id = $friendship->initiator_user_id;
+			$this->friend_user_id    = $friendship->friend_user_id;
+			$this->is_confirmed      = $friendship->is_confirmed;
+			$this->is_limited        = $friendship->is_limited;
+			$this->date_created      = $friendship->date_created;
+		}
+
+		if ( !empty( $this->populate_friend_details ) ) {
+			if ( $this->friend_user_id == bp_displayed_user_id() ) {
+				$this->friend = new BP_Core_User( $this->initiator_user_id );
+			} else {
+				$this->friend = new BP_Core_User( $this->friend_user_id );
+			}
+		}
+	}
+
+	/**
+	 * Save the current friendship to the database.
+	 *
+	 * @return bool True on success, false on failure.
+	 */
+	public function save() {
+		global $wpdb, $bp;
+
+		$this->initiator_user_id = apply_filters( 'friends_friendship_initiator_user_id_before_save', $this->initiator_user_id, $this->id );
+		$this->friend_user_id    = apply_filters( 'friends_friendship_friend_user_id_before_save',    $this->friend_user_id,    $this->id );
+		$this->is_confirmed      = apply_filters( 'friends_friendship_is_confirmed_before_save',      $this->is_confirmed,      $this->id );
+		$this->is_limited        = apply_filters( 'friends_friendship_is_limited_before_save',        $this->is_limited,        $this->id );
+		$this->date_created      = apply_filters( 'friends_friendship_date_created_before_save',      $this->date_created,      $this->id );
+
+		do_action_ref_array( 'friends_friendship_before_save', array( &$this ) );
+
+		// Update
+		if (!empty( $this->id ) ) {
+			$result = $wpdb->query( $wpdb->prepare( "UPDATE {$bp->friends->table_name} SET initiator_user_id = %d, friend_user_id = %d, is_confirmed = %d, is_limited = %d, date_created = %s ) WHERE id = %d", $this->initiator_user_id, $this->friend_user_id, $this->is_confirmed, $this->is_limited, $this->date_created, $this->id ) );
+
+		// Save
+		} else {
+			$result = $wpdb->query( $wpdb->prepare( "INSERT INTO {$bp->friends->table_name} ( initiator_user_id, friend_user_id, is_confirmed, is_limited, date_created ) VALUES ( %d, %d, %d, %d, %s )", $this->initiator_user_id, $this->friend_user_id, $this->is_confirmed, $this->is_limited, $this->date_created ) );
+			$this->id = $wpdb->insert_id;
+		}
+
+		do_action( 'friends_friendship_after_save', array( &$this ) );
+
+		return $result;
+	}
+
+	public function delete() {
+		global $wpdb, $bp;
+		return $wpdb->query( $wpdb->prepare( "DELETE FROM {$bp->friends->table_name} WHERE id = %d", $this->id ) );
+	}
+
+	/** Static Methods ********************************************************/
+
+	/**
+	 * Get the IDs of a given user's friends.
+	 *
+	 * @param int $user_id ID of the user whose friends are being retreived.
+	 * @param bool $friend_requests_only Optional. Whether to fetch
+	 *        unaccepted requests only. Default: false.
+	 * @param bool $assoc_arr Optional. True to receive an array of arrays
+	 *        keyed as 'user_id' => $user_id; false to get a one-dimensional
+	 *        array of user IDs. Default: false.
+	 */
+	public static function get_friend_user_ids( $user_id, $friend_requests_only = false, $assoc_arr = false ) {
+		global $wpdb, $bp;
+
+		if ( !empty( $friend_requests_only ) ) {
+			$oc_sql = 'AND is_confirmed = 0';
+			$friend_sql = $wpdb->prepare( " WHERE friend_user_id = %d", $user_id );
+		} else {
+			$oc_sql = 'AND is_confirmed = 1';
+			$friend_sql = $wpdb->prepare( " WHERE (initiator_user_id = %d OR friend_user_id = %d)", $user_id, $user_id );
+		}
+
+		$friends = $wpdb->get_results( "SELECT friend_user_id, initiator_user_id FROM {$bp->friends->table_name} {$friend_sql} {$oc_sql} ORDER BY date_created DESC" );
+		$fids = array();
+
+		for ( $i = 0, $count = count( $friends ); $i < $count; ++$i ) {
+			if ( !empty( $assoc_arr ) ) {
+				$fids[] = array( 'user_id' => ( $friends[$i]->friend_user_id == $user_id ) ? $friends[$i]->initiator_user_id : $friends[$i]->friend_user_id );
+			} else {
+				$fids[] = ( $friends[$i]->friend_user_id == $user_id ) ? $friends[$i]->initiator_user_id : $friends[$i]->friend_user_id;
+			}
+		}
+
+		return $fids;
+	}
+
+	/**
+	 * Get the ID of the friendship object, if any, between a pair of users.
+	 *
+	 * @param int $user_id The ID of the first user.
+	 * @param int $friend_id The ID of the second user.
+	 * @return int|bool The ID of the friendship object if found, otherwise
+	 *         false.
+	 */
+	public static function get_friendship_id( $user_id, $friend_id ) {
+		global $wpdb, $bp;
+
+		return $wpdb->get_var( $wpdb->prepare( "SELECT id FROM {$bp->friends->table_name} WHERE ( initiator_user_id = %d AND friend_user_id = %d ) OR ( initiator_user_id = %d AND friend_user_id = %d ) AND is_confirmed = 1", $user_id, $friend_id, $friend_id, $user_id ) );
+	}
+
+	/**
+	 * Get a list of IDs of users who have requested friendship of a given user.
+	 *
+	 * @param int $user_id The ID of the user who has received the
+	 *        friendship requests.
+	 * @return array|bool An array of user IDs, or false if none are found.
+	 */
+	public static function get_friendship_request_user_ids( $user_id ) {
+		global $wpdb, $bp;
+
+		return $wpdb->get_col( $wpdb->prepare( "SELECT initiator_user_id FROM {$bp->friends->table_name} WHERE friend_user_id = %d AND is_confirmed = 0", $user_id ) );
+	}
+
+	/**
+	 * Get a total friend count for a given user.
+	 *
+	 * @param int $user_id Optional. ID of the user whose friendships you
+	 *        are counting. Default: displayed user (if any), otherwise
+	 *        logged-in user.
+	 * @return int Friend count for the user.
+	 */
+	public static function total_friend_count( $user_id = 0 ) {
+		global $wpdb, $bp;
+
+		if ( empty( $user_id ) )
+			$user_id = ( bp_displayed_user_id() ) ? bp_displayed_user_id() : bp_loggedin_user_id();
+
+		/* This is stored in 'total_friend_count' usermeta.
+		   This function will recalculate, update and return. */
+
+		$count = $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(id) FROM {$bp->friends->table_name} WHERE (initiator_user_id = %d OR friend_user_id = %d) AND is_confirmed = 1", $user_id, $user_id ) );
+
+		// Do not update meta if user has never had friends
+		if ( empty( $count ) && !bp_get_user_meta( $user_id, 'total_friend_count', true ) )
+			return 0;
+
+		bp_update_user_meta( $user_id, 'total_friend_count', (int) $count );
+
+		return absint( $count );
+	}
+
+	/**
+	 * Search the friends of a user by a search string.
+	 *
+	 * @param string $filter The search string, matched against xprofile
+	 *        fields (if available), or usermeta 'nickname' field.
+	 * @param int $user_id ID of the user whose friends are being searched.
+	 * @param int $limit Optional. Max number of friends to return.
+	 * @param int $page Optional. The page of results to return. Default:
+	 *        null (no pagination - return all results).
+	 * @return array|bool On success, an array: {
+	 *     @type array $friends IDs of friends returned by the query.
+	 *     @type int $count Total number of friends (disregarding
+	 *           pagination) who match the search.
+	 * }. Returns false on failure.
+	 */
+	public static function search_friends( $filter, $user_id, $limit = null, $page = null ) {
+		global $wpdb, $bp;
+
+		// TODO: Optimize this function.
+
+		if ( empty( $user_id ) )
+			$user_id = bp_loggedin_user_id();
+
+		$filter = esc_sql( like_escape( $filter ) );
+
+		$pag_sql = '';
+		if ( !empty( $limit ) && !empty( $page ) )
+			$pag_sql = $wpdb->prepare( " LIMIT %d, %d", intval( ( $page - 1 ) * $limit), intval( $limit ) );
+
+		if ( !$friend_ids = BP_Friends_Friendship::get_friend_user_ids( $user_id ) )
+			return false;
+
+		// Get all the user ids for the current user's friends.
+		$fids = implode( ',', wp_parse_id_list( $friend_ids ) );
+
+		if ( empty( $fids ) )
+			return false;
+
+		// filter the user_ids based on the search criteria.
+		if ( bp_is_active( 'xprofile' ) ) {
+			$sql       = "SELECT DISTINCT user_id FROM {$bp->profile->table_name_data} WHERE user_id IN ({$fids}) AND value LIKE '{$filter}%%' {$pag_sql}";
+			$total_sql = "SELECT COUNT(DISTINCT user_id) FROM {$bp->profile->table_name_data} WHERE user_id IN ({$fids}) AND value LIKE '{$filter}%%'";
+		} else {
+			$sql       = "SELECT DISTINCT user_id FROM {$wpdb->usermeta} WHERE user_id IN ({$fids}) AND meta_key = 'nickname' AND meta_value LIKE '{$filter}%%' {$pag_sql}";
+			$total_sql = "SELECT COUNT(DISTINCT user_id) FROM {$wpdb->usermeta} WHERE user_id IN ({$fids}) AND meta_key = 'nickname' AND meta_value LIKE '{$filter}%%'";
+		}
+
+		$filtered_friend_ids = $wpdb->get_col( $sql );
+		$total_friend_ids    = $wpdb->get_var( $total_sql );
+
+		if ( empty( $filtered_friend_ids ) )
+			return false;
+
+		return array( 'friends' => $filtered_friend_ids, 'total' => (int) $total_friend_ids );
+	}
+
+	/**
+	 * Check friendship status between two users.
+	 *
+	 * Note that 'pending' means that $initiator_userid has sent a friend
+	 * request to $possible_friend_userid that has not yet been approved,
+	 * while 'awaiting_response' is the other way around ($possible_friend_userid
+	 * sent the initial request)
+	 *
+	 * @param int $initiator_userid The ID of the user who is the initiator
+	 *        of the potential friendship/request.
+	 * @param int $possible_friend_userid The ID of the user who is the
+	 *        recipient of the potential friendship/request.
+	 * @return string The friendship status, from among 'not_friends',
+	 *        'is_friend', 'pending', and 'awaiting_response'.
+	 */
+	public static function check_is_friend( $initiator_userid, $possible_friend_userid ) {
+		global $wpdb, $bp;
+
+		if ( empty( $initiator_userid ) || empty( $possible_friend_userid ) ) {
+			return false;
+		}
+
+		$result = $wpdb->get_results( $wpdb->prepare( "SELECT id, initiator_user_id, is_confirmed FROM {$bp->friends->table_name} WHERE (initiator_user_id = %d AND friend_user_id = %d) OR (initiator_user_id = %d AND friend_user_id = %d)", $initiator_userid, $possible_friend_userid, $possible_friend_userid, $initiator_userid ) );
+
+		if ( ! empty( $result ) ) {
+			if ( 0 == (int) $result[0]->is_confirmed ) {
+				$status = $initiator_userid == $result[0]->initiator_user_id ? 'pending' : 'awaiting_response';
+			} else {
+				$status = 'is_friend';
+			}
+		} else {
+			$status = 'not_friends';
+		}
+
+		return $status;
+	}
+
+	/**
+	 * Get the last active date of many users at once.
+	 *
+	 * @todo Why is this in the Friends component?
+	 *
+	 * @param array $user_ids IDs of users whose last_active meta is
+	 *        being queried.
+	 * @return array Array of last_active values + user_ids.
+	 */
+	public static function get_bulk_last_active( $user_ids ) {
+		global $wpdb;
+
+		$user_ids = implode( ',', wp_parse_id_list( $user_ids ) );
+
+		return $wpdb->get_results( $wpdb->prepare( "SELECT meta_value as last_activity, user_id FROM {$wpdb->usermeta} WHERE meta_key = %s AND user_id IN ( {$user_ids} ) ORDER BY meta_value DESC", bp_get_user_meta_key( 'last_activity' ) ) );
+	}
+
+	/**
+	 * Mark a friendship as accepted.
+	 *
+	 * @param int $friendship_id ID of the friendship to be accepted.
+	 * @return int Number of database rows updated.
+	 */
+	public static function accept($friendship_id) {
+		global $wpdb, $bp;
+	 	return $wpdb->query( $wpdb->prepare( "UPDATE {$bp->friends->table_name} SET is_confirmed = 1, date_created = %s WHERE id = %d AND friend_user_id = %d", bp_core_current_time(), $friendship_id, bp_loggedin_user_id() ) );
+	}
+
+	/**
+	 * Remove a friendship or a friendship request INITIATED BY the logged-in user.
+	 *
+	 * @param int $friendship_id ID of the friendship to be withdrawn.
+	 * @return int Number of database rows deleted.
+	 */
+	public static function withdraw($friendship_id) {
+		global $wpdb, $bp;
+		return $wpdb->query( $wpdb->prepare( "DELETE FROM {$bp->friends->table_name} WHERE id = %d AND initiator_user_id = %d", $friendship_id, bp_loggedin_user_id() ) );
+	}
+
+	/**
+	 * Remove a friendship or a friendship request MADE OF the logged-in user.
+	 *
+	 * @param int $friendship_id ID of the friendship to be rejected.
+	 * @return int Number of database rows deleted.
+	 */
+	public static function reject($friendship_id) {
+		global $wpdb, $bp;
+		return $wpdb->query( $wpdb->prepare( "DELETE FROM {$bp->friends->table_name} WHERE id = %d AND friend_user_id = %d", $friendship_id, bp_loggedin_user_id() ) );
+	}
+
+	/**
+	 * Search users.
+	 *
+	 * @todo Why does this exist, and why is it in bp-friends?
+	 *
+	 * @param string $filter String to search by.
+	 * @param int $user_id A user ID param that is unused.
+	 * @param int $limit Optional. Max number of records to return.
+	 * @param int $page Optional. Number of the page to return. Default:
+	 *        false (no pagination - return all results).
+	 * @return array $filtered_ids IDs of users who match the query.
+	 */
+	public static function search_users( $filter, $user_id, $limit = null, $page = null ) {
+		global $wpdb, $bp;
+
+		$filter = esc_sql( like_escape( $filter ) );
+
+		$usermeta_table = $wpdb->base_prefix . 'usermeta';
+		$users_table    = $wpdb->base_prefix . 'users';
+
+		$pag_sql = '';
+		if ( !empty( $limit ) && !empty( $page ) )
+			$pag_sql = $wpdb->prepare( " LIMIT %d, %d", intval( ( $page - 1 ) * intval( $limit ) ), intval( $limit ) );
+
+		// filter the user_ids based on the search criteria.
+		if ( bp_is_active( 'xprofile' ) ) {
+			$sql = "SELECT DISTINCT d.user_id as id FROM {$bp->profile->table_name_data} d, {$users_table} u WHERE d.user_id = u.id AND d.value LIKE '{$filter}%%' ORDER BY d.value DESC {$pag_sql}";
+		} else {
+			$sql = "SELECT DISTINCT user_id as id FROM {$usermeta_table} WHERE meta_value LIKE '{$filter}%%' ORDER BY d.value DESC {$pag_sql}";
+		}
+
+		$filtered_fids = $wpdb->get_col($sql);
+
+		if ( empty( $filtered_fids ) )
+			return false;
+
+		return $filtered_fids;
+	}
+
+	/**
+	 * Get a count of users who match a search term.
+	 *
+	 * @todo Why does this exist, and why is it in bp-friends?
+	 *
+	 * @param string $filter Search term.
+	 * @return int Count of users matching the search term.
+	 */
+	public static function search_users_count( $filter ) {
+		global $wpdb, $bp;
+
+		$filter = esc_sql( like_escape( $filter ) );
+
+		$usermeta_table = $wpdb->prefix . 'usermeta';
+		$users_table    = $wpdb->base_prefix . 'users';
+
+		// filter the user_ids based on the search criteria.
+		if ( bp_is_active( 'xprofile' ) ) {
+			$sql = "SELECT COUNT(DISTINCT d.user_id) FROM {$bp->profile->table_name_data} d, {$users_table} u WHERE d.user_id = u.id AND d.value LIKE '{$filter}%%'";
+		} else {
+			$sql = "SELECT COUNT(DISTINCT user_id) FROM {$usermeta_table} WHERE meta_value LIKE '{$filter}%%'";
+		}
+
+		$user_count = $wpdb->get_col($sql);
+
+		if ( empty( $user_count ) )
+			return false;
+
+		return $user_count[0];
+	}
+
+	/**
+	 * Sort a list of user IDs by their display names.
+	 *
+	 * @todo Why does this exist, and why is it in bp-friends?
+	 *
+	 * @param array $user_ids Array of user IDs.
+	 * @return array User IDs, sorted by the associated display names.
+	 */
+	public static function sort_by_name( $user_ids ) {
+		global $wpdb, $bp;
+
+		if ( !bp_is_active( 'xprofile' ) )
+			return false;
+
+		$user_ids = implode( ',', wp_parse_id_list( $user_ids ) );
+
+		return $wpdb->get_results( $wpdb->prepare( "SELECT user_id FROM {$bp->profile->table_name_data} pd, {$bp->profile->table_name_fields} pf WHERE pf.id = pd.field_id AND pf.name = %s AND pd.user_id IN ( {$user_ids} ) ORDER BY pd.value ASC", bp_xprofile_fullname_field_name() ) );
+	}
+
+	/**
+	 * Get a list of random friend IDs.
+	 *
+	 * @param int $user_id ID of the user whose friends are being retrieved.
+	 * @param int $total_friends Optional. Number of random friends to get.
+	 *        Default: 5.
+	 * @return array|bool An array of random friend user IDs on success;
+	 *         false if none are found.
+	 */
+	public static function get_random_friends( $user_id, $total_friends = 5 ) {
+		global $wpdb, $bp;
+
+		$fids    = array();
+		$sql     = $wpdb->prepare( "SELECT friend_user_id, initiator_user_id FROM {$bp->friends->table_name} WHERE (friend_user_id = %d || initiator_user_id = %d) && is_confirmed = 1 ORDER BY rand() LIMIT %d", $user_id, $user_id, $total_friends );
+		$results = $wpdb->get_results( $sql );
+
+		for ( $i = 0, $count = count( $results ); $i < $count; ++$i ) {
+			$fids[] = ( $results[$i]->friend_user_id == $user_id ) ? $results[$i]->initiator_user_id : $results[$i]->friend_user_id;
+		}
+
+		// remove duplicates
+		if ( count( $fids ) > 0 )
+			return array_flip( array_flip( $fids ) );
+		else
+			return false;
+	}
+
+	/**
+	 * Get a count of a user's friends who can be invited to a given group.
+	 *
+	 * Users can invite any of their friends except:
+	 *
+	 * - users who are already in the group
+	 * - users who have a pending invite to the group
+	 * - users who have been banned from the group
+	 *
+	 * @param int $user_id ID of the user whose friends are being counted.
+	 * @param int $group_id ID of the group friends are being invited to.
+	 * @return int $invitable_count Eligible friend count.
+	 */
+	public static function get_invitable_friend_count( $user_id, $group_id ) {
+
+		// Setup some data we'll use below
+		$is_group_admin  = BP_Groups_Member::check_is_admin( $user_id, $group_id );
+		$friend_ids      = BP_Friends_Friendship::get_friend_user_ids( $user_id );
+		$invitable_count = 0;
+
+		for ( $i = 0, $count = count( $friend_ids ); $i < $count; ++$i ) {
+
+			// If already a member, they cannot be invited again
+			if ( BP_Groups_Member::check_is_member( (int) $friend_ids[$i], $group_id ) )
+				continue;
+
+			// If user already has invite, they cannot be added
+			if ( BP_Groups_Member::check_has_invite( (int) $friend_ids[$i], $group_id )  )
+				continue;
+
+			// If user is not group admin and friend is banned, they cannot be invited
+			if ( ( false === $is_group_admin ) && BP_Groups_Member::check_is_banned( (int) $friend_ids[$i], $group_id ) )
+				continue;
+
+			$invitable_count++;
+		}
+
+		return $invitable_count;
+	}
+
+	/**
+	 * Get the friend user IDs for a given friendship.
+	 *
+	 * @param int $friendship_id ID of the friendship.
+	 * @return object friend_user_id and initiator_user_id.
+	 */
+	public static function get_user_ids_for_friendship( $friendship_id ) {
+		global $wpdb, $bp;
+		return $wpdb->get_row( $wpdb->prepare( "SELECT friend_user_id, initiator_user_id FROM {$bp->friends->table_name} WHERE id = %d", $friendship_id ) );
+	}
+
+	/**
+	 * Delete all friendships and friend notifications related to a user.
+	 *
+	 * @param int $user_id ID of the user being expunged.
+	 */
+	public static function delete_all_for_user( $user_id ) {
+		global $wpdb, $bp;
+
+		// Get friends of $user_id
+		$friend_ids = BP_Friends_Friendship::get_friend_user_ids( $user_id );
+
+		// Delete all friendships related to $user_id
+		$wpdb->query( $wpdb->prepare( "DELETE FROM {$bp->friends->table_name} WHERE friend_user_id = %d OR initiator_user_id = %d", $user_id, $user_id ) );
+
+		// Delete friend request notifications for members who have a
+		// notification from this user.
+		if ( bp_is_active( 'notifications' ) ) {
+			$wpdb->query( $wpdb->prepare( "DELETE FROM {$bp->notifications->table_name} WHERE component_name = 'friends' AND ( component_action = 'friendship_request' OR component_action = 'friendship_accepted' ) AND item_id = %d", $user_id ) );
+		}
+
+		// Loop through friend_ids and update their counts
+		foreach ( (array) $friend_ids as $friend_id ) {
+			BP_Friends_Friendship::total_friend_count( $friend_id );
+		}
+	}
+}
Index: /tags/1.9/bp-friends/bp-friends-filters.php
===================================================================
--- /tags/1.9/bp-friends/bp-friends-filters.php	(revision 7684)
+++ /tags/1.9/bp-friends/bp-friends-filters.php	(revision 7684)
@@ -0,0 +1,37 @@
+<?php
+
+/**
+ * BuddyPress Friend Filters
+ *
+ * @package BuddyPress
+ * @subpackage FriendsFilters
+ */
+
+/**
+ * Filter BP_User_Query::populate_extras to override each queried users fullname.
+ *
+ * @since BuddyPress (1.7.0)
+ *
+ * @global BuddyPress $bp Global BuddyPress settings.
+ * @global WPDB $wpdb WordPress database access object.
+ *
+ * @param BP_User_Query $user_query The BP_User_Query object.
+ * @param string $user_ids_sql Comma-separated list of user IDs to fetch extra
+ *        data for, as determined by BP_User_Query.
+ */
+function bp_friends_filter_user_query_populate_extras( BP_User_Query $user_query, $user_ids_sql ) {
+	global $bp, $wpdb;
+
+	// Fetch whether or not the user is a friend of the current user
+	$friend_status = $wpdb->get_results( $wpdb->prepare( "SELECT initiator_user_id, friend_user_id, is_confirmed FROM {$bp->friends->table_name} WHERE (initiator_user_id = %d AND friend_user_id IN ( {$user_ids_sql} ) ) OR (initiator_user_id IN ( {$user_ids_sql} ) AND friend_user_id = %d )", bp_loggedin_user_id(), bp_loggedin_user_id() ) );
+
+	// The "friend" is the user ID in the pair who is *not* the logged in user
+	foreach ( (array) $friend_status as $fs ) {
+		$friend_id = bp_loggedin_user_id() == $fs->initiator_user_id ? $fs->friend_user_id : $fs->initiator_user_id;
+
+		if ( isset( $user_query->results[ $friend_id ] ) ) {
+			$user_query->results[ $friend_id ]->is_friend = $fs->is_confirmed;
+		}
+	}
+}
+add_filter( 'bp_user_query_populate_extras', 'bp_friends_filter_user_query_populate_extras', 4, 2 );
Index: /tags/1.9/bp-friends/bp-friends-functions.php
===================================================================
--- /tags/1.9/bp-friends/bp-friends-functions.php	(revision 7684)
+++ /tags/1.9/bp-friends/bp-friends-functions.php	(revision 7684)
@@ -0,0 +1,548 @@
+<?php
+
+/**
+ * BuddyPress Friends Functions
+ *
+ * Functions are where all the magic happens in BuddyPress. They will
+ * handle the actual saving or manipulation of information. Usually they will
+ * hand off to a database class for data access, then return
+ * true or false on success or failure.
+ *
+ * @package BuddyPress
+ * @subpackage FriendsFunctions
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/**
+ * Create a new friendship.
+ *
+ * @param int $initiator_userid ID of the "initiator" user (the user who is
+ *        sending the friendship request).
+ * @param int $friend_userid ID of the "friend" user (the user whose friendship
+ *        is being requested).
+ * @param bool $force_accept Optional. Whether to force acceptance. When false,
+ *        running friends_add_friend() will result in a friendship request.
+ *        When true, running friends_add_friend() will result in an accepted
+ *        friendship, with no notifications being sent. Default: false.
+ * @return bool True on success, false on failure.
+ */
+function friends_add_friend( $initiator_userid, $friend_userid, $force_accept = false ) {
+
+	// Check if already friends, and bail if so
+	$friendship = new BP_Friends_Friendship;
+	if ( (int) $friendship->is_confirmed ) {
+		return true;
+	}
+
+	// Setup the friendship data
+	$friendship->initiator_user_id = $initiator_userid;
+	$friendship->friend_user_id    = $friend_userid;
+	$friendship->is_confirmed      = 0;
+	$friendship->is_limited        = 0;
+	$friendship->date_created      = bp_core_current_time();
+
+	if ( !empty( $force_accept ) ) {
+		$friendship->is_confirmed = 1;
+	}
+
+	// Bail if friendship could not be saved (how sad!)
+	if ( ! $friendship->save() ) {
+		return false;
+	}
+
+	// Send notifications
+	if ( empty( $force_accept ) ) {
+		$action = 'friends_friendship_requested';
+
+	// Update friend totals
+	} else {
+		$action = 'friends_friendship_accepted';
+		friends_update_friend_totals( $friendship->initiator_user_id, $friendship->friend_user_id, 'add' );
+	}
+
+	// Call the above titled action and pass friendship data into it
+	do_action( $action, $friendship->id, $friendship->initiator_user_id, $friendship->friend_user_id, $friendship );
+
+	return true;
+}
+
+/**
+ * Remove a friendship.
+ *
+ * Will also delete the related "friendship_accepted" activity item.
+ *
+ * @param int $initiator_userid ID of the friendship initiator.
+ * @param int $friend_userid ID of the friend user.
+ * @return bool True on success, false on failure.
+ */
+function friends_remove_friend( $initiator_userid, $friend_userid ) {
+
+	$friendship_id = BP_Friends_Friendship::get_friendship_id( $initiator_userid, $friend_userid );
+	$friendship    = new BP_Friends_Friendship( $friendship_id );
+
+	do_action( 'friends_before_friendship_delete', $friendship_id, $initiator_userid, $friend_userid );
+
+	// Remove the activity stream item for the user who canceled the friendship
+	friends_delete_activity( array( 'item_id' => $friendship_id, 'type' => 'friendship_accepted', 'user_id' => bp_displayed_user_id() ) );
+
+	// This hook is misleadingly named - the friendship is not yet deleted.
+	// This is your last chance to do something while the friendship exists
+	do_action( 'friends_friendship_deleted', $friendship_id, $initiator_userid, $friend_userid );
+
+	if ( $friendship->delete() ) {
+		friends_update_friend_totals( $initiator_userid, $friend_userid, 'remove' );
+
+		do_action( 'friends_friendship_post_delete', $initiator_userid, $friend_userid );
+
+		return true;
+	}
+
+	return false;
+}
+
+/**
+ * Mark a friendship request as accepted.
+ *
+ * Also initiates a "friendship_accepted" activity item.
+ *
+ * @param int $friendship_id ID of the pending friendship object.
+ * @return bool True on success, false on failure.
+ */
+function friends_accept_friendship( $friendship_id ) {
+
+	// Get the friesdhip data
+	$friendship = new BP_Friends_Friendship( $friendship_id, true, false );
+
+	// Accepting friendship
+	if ( empty( $friendship->is_confirmed ) && BP_Friends_Friendship::accept( $friendship_id ) ) {
+
+		// Bump the friendship counts
+		friends_update_friend_totals( $friendship->initiator_user_id, $friendship->friend_user_id );
+
+		do_action( 'friends_friendship_accepted', $friendship->id, $friendship->initiator_user_id, $friendship->friend_user_id, $friendship );
+
+		return true;
+	}
+
+	return false;
+}
+
+/**
+ * Mark a friendship request as rejected.
+ *
+ * @param int $friendship_id ID of the pending friendship object.
+ * @return bool True on success, false on failure.
+ */
+function friends_reject_friendship( $friendship_id ) {
+	$friendship = new BP_Friends_Friendship( $friendship_id, true, false );
+
+	if ( empty( $friendship->is_confirmed ) && BP_Friends_Friendship::reject( $friendship_id ) ) {
+		do_action_ref_array( 'friends_friendship_rejected', array( $friendship_id, &$friendship ) );
+		return true;
+	}
+
+	return false;
+}
+
+/**
+ * Withdraw a friendship request.
+ *
+ * @param int $initiator_userid ID of the friendship initiator - this is the
+ *            user who requested the friendship, and is doing the withdrawing.
+ * @param int $friend_userid ID of the requested friend.
+ * @return bool True on success, false on failure.
+ */
+function friends_withdraw_friendship( $initiator_userid, $friend_userid ) {
+	$friendship_id = BP_Friends_Friendship::get_friendship_id( $initiator_userid, $friend_userid );
+	$friendship    = new BP_Friends_Friendship( $friendship_id, true, false );
+
+	if ( empty( $friendship->is_confirmed ) && BP_Friends_Friendship::withdraw( $friendship_id ) ) {
+
+		// @deprecated Since 1.9
+		do_action_ref_array( 'friends_friendship_whithdrawn', array( $friendship_id, &$friendship ) );
+
+		// @since 1.9
+		do_action_ref_array( 'friends_friendship_withdrawn',  array( $friendship_id, &$friendship ) );
+
+		return true;
+	}
+
+	return false;
+}
+
+/**
+ * Check whether two users are friends.
+ *
+ * @param int $user_id ID of the first user.
+ * @param int $possible_friend_id ID of the other user.
+ * @return bool Returns true if the two users are friends, otherwise false.
+ */
+function friends_check_friendship( $user_id, $possible_friend_id ) {
+
+	if ( 'is_friend' == BP_Friends_Friendship::check_is_friend( $user_id, $possible_friend_id ) )
+		return true;
+
+	return false;
+}
+
+/**
+ * Get the friendship status of two friends.
+ *
+ * Will return 'is_friends', 'not_friends', or 'pending'.
+ *
+ * @param int $user_id ID of the first user.
+ * @param int $possible_friend_id ID of the other user.
+ * @return string Friend status of the two users.
+ */
+function friends_check_friendship_status( $user_id, $possible_friend_id ) {
+	return BP_Friends_Friendship::check_is_friend( $user_id, $possible_friend_id );
+}
+
+/**
+ * Get the friend count of a given user.
+ *
+ * @param int $user_id ID of the user whose friends are being counted.
+ * @return int Friend count of the user.
+ */
+function friends_get_total_friend_count( $user_id = 0 ) {
+	if ( empty( $user_id ) )
+		$user_id = ( bp_displayed_user_id() ) ? bp_displayed_user_id() : bp_loggedin_user_id();
+
+	$count = bp_get_user_meta( $user_id, 'total_friend_count', true );
+	if ( empty( $count ) )
+		$count = 0;
+
+	return apply_filters( 'friends_get_total_friend_count', $count );
+}
+
+/**
+ * Check whether a given user has any friends.
+ *
+ * @param int $user_id ID of the user whose friends are being checked.
+ * @return bool True if the user has friends, otherwise false.
+ */
+function friends_check_user_has_friends( $user_id ) {
+	$friend_count = friends_get_total_friend_count( $user_id );
+
+	if ( empty( $friend_count ) )
+		return false;
+
+	if ( !(int) $friend_count )
+		return false;
+
+	return true;
+}
+
+/**
+ * Get the ID of two users' friendship, if it exists.
+ *
+ * @param int $initiator_user_id ID of the first user.
+ * @param int $friend_user_id ID of the second user.
+ * @return int|bool ID of the friendship if found, otherwise false.
+ */
+function friends_get_friendship_id( $initiator_user_id, $friend_user_id ) {
+	return BP_Friends_Friendship::get_friendship_id( $initiator_user_id, $friend_user_id );
+}
+
+/**
+ * Get the IDs of a given user's friends.
+ *
+ * @param int $user_id ID of the user whose friends are being retreived.
+ * @param bool $friend_requests_only Optional. Whether to fetch unaccepted
+ *        requests only. Default: false.
+ * @param bool $assoc_arr Optional. True to receive an array of arrays keyed as
+ *        'user_id' => $user_id; false to get a one-dimensional array of user
+ *        IDs. Default: false.
+ */
+function friends_get_friend_user_ids( $user_id, $friend_requests_only = false, $assoc_arr = false ) {
+	return BP_Friends_Friendship::get_friend_user_ids( $user_id, $friend_requests_only, $assoc_arr );
+}
+
+/**
+ * Search the friends of a user by a search string.
+ *
+ * @param string $filter The search string, matched against xprofile fields (if
+ *        available), or usermeta 'nickname' field.
+ * @param int $user_id ID of the user whose friends are being searched.
+ * @param int $limit Optional. Max number of friends to return.
+ * @param int $page Optional. The page of results to return. Default: null (no
+ *        pagination - return all results).
+ * @return array|bool On success, an array: {
+ *     @type array $friends IDs of friends returned by the query.
+ *     @type int $count Total number of friends (disregarding
+ *           pagination) who match the search.
+ * }. Returns false on failure.
+ */
+function friends_search_friends( $search_terms, $user_id, $pag_num = 10, $pag_page = 1 ) {
+	return BP_Friends_Friendship::search_friends( $search_terms, $user_id, $pag_num, $pag_page );
+}
+
+/**
+ * Get a list of IDs of users who have requested friendship of a given user.
+ *
+ * @param int $user_id The ID of the user who has received the friendship
+ *        requests.
+ * @return array|bool An array of user IDs, or false if none are found.
+ */
+function friends_get_friendship_request_user_ids( $user_id ) {
+	return BP_Friends_Friendship::get_friendship_request_user_ids( $user_id );
+}
+
+/**
+ * Get a user's most recently active friends.
+ *
+ * @see BP_Core_User::get_users() for a description of return value.
+ *
+ * @param int $user_id ID of the user whose friends are being retreived.
+ * @param int $per_page Optional. Number of results to return per page.
+ *        Default: 0 (no pagination; show all results).
+ * @param int $page Optional. Number of the page of results to return.
+ *        Default: 0 (no pagination; show all results).
+ * @param string $filter Optional. Limit results to those matching a search
+ *        string.
+ * @return array See {@link BP_Core_User::get_users()}.
+ */
+function friends_get_recently_active( $user_id, $per_page = 0, $page = 0, $filter = '' ) {
+	return apply_filters( 'friends_get_recently_active', BP_Core_User::get_users( 'active', $per_page, $page, $user_id, $filter ) );
+}
+
+/**
+ * Get a user's friends, in alphabetical order.
+ *
+ * @see BP_Core_User::get_users() for a description of return value.
+ *
+ * @param int $user_id ID of the user whose friends are being retreived.
+ * @param int $per_page Optional. Number of results to return per page.
+ *        Default: 0 (no pagination; show all results).
+ * @param int $page Optional. Number of the page of results to return.
+ *        Default: 0 (no pagination; show all results).
+ * @param string $filter Optional. Limit results to those matching a search
+ *        string.
+ * @return array See {@link BP_Core_User::get_users()}.
+ */
+function friends_get_alphabetically( $user_id, $per_page = 0, $page = 0, $filter = '' ) {
+	return apply_filters( 'friends_get_alphabetically', BP_Core_User::get_users( 'alphabetical', $per_page, $page, $user_id, $filter ) );
+}
+
+/**
+ * Get a user's friends, in the order in which they joined the site.
+ *
+ * @see BP_Core_User::get_users() for a description of return value.
+ *
+ * @param int $user_id ID of the user whose friends are being retreived.
+ * @param int $per_page Optional. Number of results to return per page.
+ *        Default: 0 (no pagination; show all results).
+ * @param int $page Optional. Number of the page of results to return.
+ *        Default: 0 (no pagination; show all results).
+ * @param string $filter Optional. Limit results to those matching a search
+ *        string.
+ * @return array See {@link BP_Core_User::get_users()}.
+ */
+function friends_get_newest( $user_id, $per_page = 0, $page = 0, $filter = '' ) {
+	return apply_filters( 'friends_get_newest', BP_Core_User::get_users( 'newest', $per_page, $page, $user_id, $filter ) );
+}
+
+/**
+ * Get the last active date of many users at once.
+ *
+ * @see BP_Friends_Friendship::get_bulk_last_active() for a description of
+ *      arguments and return value.
+ *
+ * @param array $user_ids See BP_Friends_Friendship::get_bulk_last_active().
+ * @return array $user_ids See BP_Friends_Friendship::get_bulk_last_active().
+ */
+function friends_get_bulk_last_active( $friend_ids ) {
+	return BP_Friends_Friendship::get_bulk_last_active( $friend_ids );
+}
+
+/**
+ * Get a list of friends that a user can invite into this group.
+ *
+ * Excludes friends that are already in the group, and banned friends if the
+ * user is not a group admin.
+ *
+ * @since BuddyPress (1.0.0)
+ *
+ * @param int $user_id User ID whose friends to see can be invited. Default:
+ *        ID of the logged-in user.
+ * @param int $group_id Group to check possible invitations against.
+ * @return mixed False if no friends, array of users if friends.
+ */
+function friends_get_friends_invite_list( $user_id = 0, $group_id = 0 ) {
+
+	// Default to logged in user id
+	if ( empty( $user_id ) )
+		$user_id = bp_loggedin_user_id();
+
+	// Only group admins can invited previously banned users
+	$user_is_admin = (bool) groups_is_user_admin( $user_id, $group_id );
+
+	// Assume no friends
+	$friends = array();
+
+	// Default args
+	$args = apply_filters( 'bp_friends_pre_get_invite_list', array(
+		'user_id'  => $user_id,
+		'type'     => 'alphabetical',
+		'per_page' => 0
+	) );
+
+	// User has friends
+	if ( bp_has_members( $args ) ) {
+
+		/**
+		 * Loop through all friends and try to add them to the invitation list.
+		 *
+		 * Exclude friends that:
+		 *     1. are already members of the group
+		 *     2. are banned from this group if the current user is also not a
+		 *        group admin.
+		 */
+		while ( bp_members() ) :
+
+			// Load the member
+			bp_the_member();
+
+			// Get the user ID of the friend
+			$friend_user_id = bp_get_member_user_id();
+
+			// Skip friend if already in the group
+			if ( groups_is_user_member( $friend_user_id, $group_id ) )
+				continue;
+
+			// Skip friend if not group admin and user banned from group
+			if ( ( false === $user_is_admin ) && groups_is_user_banned( $friend_user_id, $group_id ) )
+				continue;
+
+			// Friend is safe, so add it to the array of possible friends
+			$friends[] = array(
+				'id'        => $friend_user_id,
+				'full_name' => bp_get_member_name()
+			);
+
+		endwhile;
+	}
+
+	// If no friends, explicitly set to false
+	if ( empty( $friends ) )
+		$friends = false;
+
+	// Allow friends to be filtered
+	return apply_filters( 'bp_friends_get_invite_list', $friends, $user_id, $group_id );
+}
+
+/**
+ * Get a count of a user's friends who can be invited to a given group.
+ *
+ * Users can invite any of their friends except:
+ *
+ * - users who are already in the group
+ * - users who have a pending invite to the group
+ * - users who have been banned from the group
+ *
+ * @param int $user_id ID of the user whose friends are being counted.
+ * @param int $group_id ID of the group friends are being invited to.
+ * @return int $invitable_count Eligible friend count.
+ */
+function friends_count_invitable_friends( $user_id, $group_id ) {
+	return BP_Friends_Friendship::get_invitable_friend_count( $user_id, $group_id );
+}
+
+/**
+ * Get a total friend count for a given user.
+ *
+ * @param int $user_id Optional. ID of the user whose friendships you are
+ *        counting. Default: displayed user (if any), otherwise logged-in user.
+ * @return int Friend count for the user.
+ */
+function friends_get_friend_count_for_user( $user_id ) {
+	return BP_Friends_Friendship::total_friend_count( $user_id );
+}
+
+/**
+ * Return a list of a user's friends, filtered by a search term.
+ *
+ * @param string $search_terms Search term to filter on.
+ * @param int $user_id ID of the user whose friends are being searched.
+ * @param int $pag_num Number of results to return per page. Default: 0 (no
+ *        pagination - show all results).
+ * @param int $pag_num Number of the page being requested. Default: 0 (no
+ *        pagination - show all results).
+ * @return array Array of BP_Core_User objects corresponding to friends.
+ */
+function friends_search_users( $search_terms, $user_id, $pag_num = 0, $pag_page = 0 ) {
+
+	$user_ids = BP_Friends_Friendship::search_users( $search_terms, $user_id, $pag_num, $pag_page );
+
+	if ( empty( $user_ids ) )
+		return false;
+
+	$users = array();
+	for ( $i = 0, $count = count( $user_ids ); $i < $count; ++$i )
+		$users[] = new BP_Core_User( $user_ids[$i] );
+
+	return array( 'users' => $users, 'count' => BP_Friends_Friendship::search_users_count( $search_terms ) );
+}
+
+/**
+ * Has a friendship been confirmed (accepted)?
+ *
+ * @param int $friendship_id The ID of the friendship being checked.
+ * @return bool True if the friendship is confirmed, otherwise false.
+ */
+function friends_is_friendship_confirmed( $friendship_id ) {
+	$friendship = new BP_Friends_Friendship( $friendship_id );
+	return $friendship->is_confirmed;
+}
+
+/**
+ * Update user friend counts.
+ *
+ * Friend counts are cached in usermeta for performance reasons. After a
+ * friendship event (acceptance, deletion), call this function to regenerate
+ * the cached values.
+ *
+ * @param int $initiator_user_id ID of the first user.
+ * @param int $friend_user_id ID of the second user.
+ * @param string $status Optional. The friendship event that's been triggered.
+ *        'add' will ++ each user's friend counts, while any other string
+ *        will --.
+ */
+function friends_update_friend_totals( $initiator_user_id, $friend_user_id, $status = 'add' ) {
+
+	if ( 'add' == $status ) {
+		bp_update_user_meta( $initiator_user_id, 'total_friend_count', (int)bp_get_user_meta( $initiator_user_id, 'total_friend_count', true ) + 1 );
+		bp_update_user_meta( $friend_user_id, 'total_friend_count', (int)bp_get_user_meta( $friend_user_id, 'total_friend_count', true ) + 1 );
+	} else {
+		bp_update_user_meta( $initiator_user_id, 'total_friend_count', (int)bp_get_user_meta( $initiator_user_id, 'total_friend_count', true ) - 1 );
+		bp_update_user_meta( $friend_user_id, 'total_friend_count', (int)bp_get_user_meta( $friend_user_id, 'total_friend_count', true ) - 1 );
+	}
+}
+
+/**
+ * Remove all friends-related data concerning a given user.
+ *
+ * Removes the following:
+ *
+ * - Friendships of which the user is a member
+ * - Cached friend count for the user
+ * - Notifications of friendship requests sent by the user
+ *
+ * @param int $user_id ID of the user whose friend data is being removed.
+ */
+function friends_remove_data( $user_id ) {
+
+	do_action( 'friends_before_remove_data', $user_id );
+
+	BP_Friends_Friendship::delete_all_for_user( $user_id );
+
+	// Remove usermeta
+	bp_delete_user_meta( $user_id, 'total_friend_count' );
+
+	do_action( 'friends_remove_data', $user_id );
+}
+add_action( 'wpmu_delete_user',  'friends_remove_data' );
+add_action( 'delete_user',       'friends_remove_data' );
+add_action( 'bp_make_spam_user', 'friends_remove_data' );
Index: /tags/1.9/bp-friends/bp-friends-loader.php
===================================================================
--- /tags/1.9/bp-friends/bp-friends-loader.php	(revision 7684)
+++ /tags/1.9/bp-friends/bp-friends-loader.php	(revision 7684)
@@ -0,0 +1,247 @@
+<?php
+/**
+ * BuddyPress Friends Streams Loader
+ *
+ * The friends component is for users to create relationships with each other.
+ *
+ * @package BuddyPress
+ * @subpackage Friends
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+class BP_Friends_Component extends BP_Component {
+
+	/**
+	 * Start the friends component creation process.
+	 *
+	 * @since BuddyPress (1.5.0)
+	 */
+	function __construct() {
+		parent::start(
+			'friends',
+			__( 'Friend Connections', 'buddypress' ),
+			BP_PLUGIN_DIR,
+			array(
+				'adminbar_myaccount_order' => 60
+			)
+		);
+	}
+
+	/**
+	 * Include bp-friends files.
+	 *
+	 * @see BP_Component::includes() for description of parameters.
+	 *
+	 * @param array $includes See {@link BP_Component::includes()}.
+	 */
+	public function includes( $includes = array() ) {
+		$includes = array(
+			'actions',
+			'screens',
+			'filters',
+			'classes',
+			'activity',
+			'template',
+			'functions',
+			'notifications',
+			'widgets',
+		);
+
+		parent::includes( $includes );
+	}
+
+	/**
+	 * Set up bp-friends global settings.
+	 *
+	 * The BP_FRIENDS_SLUG constant is deprecated, and only used here for
+	 * backwards compatibility.
+	 *
+	 * @since BuddyPress (1.5.0)
+	 *
+	 * @see BP_Component::setup_globals() for description of parameters.
+	 *
+	 * @param array $args See {@link BP_Component::setup_globals()}.
+	 */
+	public function setup_globals( $args = array() ) {
+		$bp = buddypress();
+
+		// Deprecated. Do not use.
+		// Defined conditionally to support unit tests.
+		if ( ! defined( 'BP_FRIENDS_DB_VERSION' ) ) {
+			define( 'BP_FRIENDS_DB_VERSION', '1800' );
+		}
+
+		// Define a slug, if necessary
+		if ( !defined( 'BP_FRIENDS_SLUG' ) )
+			define( 'BP_FRIENDS_SLUG', $this->id );
+
+		// Global tables for the friends component
+		$global_tables = array(
+			'table_name'      => $bp->table_prefix . 'bp_friends',
+			'table_name_meta' => $bp->table_prefix . 'bp_friends_meta',
+		);
+
+		// All globals for the friends component.
+		// Note that global_tables is included in this array.
+		$args = array(
+			'slug'                  => BP_FRIENDS_SLUG,
+			'has_directory'         => false,
+			'search_string'         => __( 'Search Friends...', 'buddypress' ),
+			'notification_callback' => 'friends_format_notifications',
+			'global_tables'         => $global_tables
+		);
+
+		parent::setup_globals( $args );
+	}
+
+	/**
+	 * Set up component navigation.
+	 *
+	 * @since BuddyPress (1.5.0)
+	 *
+	 * @see BP_Component::setup_nav() for a description of arguments.
+	 *
+	 * @param array $main_nav Optional. See BP_Component::setup_nav() for
+	 *        description.
+	 * @param array $sub_nav Optional. See BP_Component::setup_nav() for
+	 *        description.
+	 */
+	public function setup_nav( $main_nav = array(), $sub_nav = array() ) {
+		$bp = buddypress();
+
+		// Add 'Friends' to the main navigation
+		$main_nav = array(
+			'name'                => sprintf( __( 'Friends <span>%d</span>', 'buddypress' ), friends_get_total_friend_count() ),
+			'slug'                => $this->slug,
+			'position'            => 60,
+			'screen_function'     => 'friends_screen_my_friends',
+			'default_subnav_slug' => 'my-friends',
+			'item_css_id'         => $bp->friends->id
+		);
+
+		// Determine user to use
+		if ( bp_displayed_user_domain() ) {
+			$user_domain = bp_displayed_user_domain();
+		} elseif ( bp_loggedin_user_domain() ) {
+			$user_domain = bp_loggedin_user_domain();
+		} else {
+			return;
+		}
+
+		$friends_link = trailingslashit( $user_domain . bp_get_friends_slug() );
+
+		// Add the subnav items to the friends nav item
+		$sub_nav[] = array(
+			'name'            => __( 'Friendships', 'buddypress' ),
+			'slug'            => 'my-friends',
+			'parent_url'      => $friends_link,
+			'parent_slug'     => bp_get_friends_slug(),
+			'screen_function' => 'friends_screen_my_friends',
+			'position'        => 10,
+			'item_css_id'     => 'friends-my-friends'
+		);
+
+		$sub_nav[] = array(
+			'name'            => __( 'Requests',   'buddypress' ),
+			'slug'            => 'requests',
+			'parent_url'      => $friends_link,
+			'parent_slug'     => bp_get_friends_slug(),
+			'screen_function' => 'friends_screen_requests',
+			'position'        => 20,
+			'user_has_access' => bp_core_can_edit_settings()
+		);
+
+		parent::setup_nav( $main_nav, $sub_nav );
+	}
+
+	/**
+	 * Set up bp-friends integration with the WordPress admin bar.
+	 *
+	 * @since BuddyPress (1.5.0)
+	 *
+	 * @see BP_Component::setup_admin_bar() for a description of arguments.
+	 *
+	 * @param array $wp_admin_nav See BP_Component::setup_admin_bar()
+	 *        for description.
+	 */
+	public function setup_admin_bar( $wp_admin_nav = array() ) {
+		$bp = buddypress();
+
+		// Menus for logged in user
+		if ( is_user_logged_in() ) {
+
+			// Setup the logged in user variables
+			$user_domain  = bp_loggedin_user_domain();
+			$friends_link = trailingslashit( $user_domain . $this->slug );
+
+			// Pending friend requests
+			$count = count( friends_get_friendship_request_user_ids( bp_loggedin_user_id() ) );
+			if ( !empty( $count ) ) {
+				$title   = sprintf( __( 'Friends <span class="count">%s</span>',          'buddypress' ), number_format_i18n( $count ) );
+				$pending = sprintf( __( 'Pending Requests <span class="count">%s</span>', 'buddypress' ), number_format_i18n( $count ) );
+			} else {
+				$title   = __( 'Friends',             'buddypress' );
+				$pending = __( 'No Pending Requests', 'buddypress' );
+			}
+
+			// Add the "My Account" sub menus
+			$wp_admin_nav[] = array(
+				'parent' => $bp->my_account_menu_id,
+				'id'     => 'my-account-' . $this->id,
+				'title'  => $title,
+				'href'   => trailingslashit( $friends_link )
+			);
+
+			// My Groups
+			$wp_admin_nav[] = array(
+				'parent' => 'my-account-' . $this->id,
+				'id'     => 'my-account-' . $this->id . '-friendships',
+				'title'  => __( 'Friendships', 'buddypress' ),
+				'href'   => trailingslashit( $friends_link )
+			);
+
+			// Requests
+			$wp_admin_nav[] = array(
+				'parent' => 'my-account-' . $this->id,
+				'id'     => 'my-account-' . $this->id . '-requests',
+				'title'  => $pending,
+				'href'   => trailingslashit( $friends_link . 'requests' )
+			);
+		}
+
+		parent::setup_admin_bar( $wp_admin_nav );
+	}
+
+	/**
+	 * Set up the title for pages and <title>.
+	 */
+	function setup_title() {
+		$bp = buddypress();
+
+		// Adjust title
+		if ( bp_is_friends_component() ) {
+			if ( bp_is_my_profile() ) {
+				$bp->bp_options_title = __( 'Friendships', 'buddypress' );
+			} else {
+				$bp->bp_options_avatar = bp_core_fetch_avatar( array(
+					'item_id' => bp_displayed_user_id(),
+					'type'    => 'thumb',
+					'alt'     => sprintf( __( 'Profile picture of %s', 'buddypress' ), bp_get_displayed_user_fullname() )
+				) );
+				$bp->bp_options_title = bp_get_displayed_user_fullname();
+			}
+		}
+
+		parent::setup_title();
+	}
+}
+
+/**
+ * Set up the bp-forums component.
+ */
+function bp_setup_friends() {
+	buddypress()->friends = new BP_Friends_Component();
+}
+add_action( 'bp_setup_components', 'bp_setup_friends', 6 );
Index: /tags/1.9/bp-friends/bp-friends-notifications.php
===================================================================
--- /tags/1.9/bp-friends/bp-friends-notifications.php	(revision 7684)
+++ /tags/1.9/bp-friends/bp-friends-notifications.php	(revision 7684)
@@ -0,0 +1,309 @@
+<?php
+
+/**
+ * BuddyPress Friends Activity Functions
+ *
+ * These functions handle the recording, deleting and formatting of activity
+ * for the user and for this specific component.
+ *
+ * @package BuddyPress
+ * @subpackage FriendsActivity
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/** Emails ********************************************************************/
+
+/**
+ * Send notifications related to a new friendship request.
+ *
+ * When a friendship is requested, an email and a BP notification are sent to
+ * the user of whom friendship has been requested ($friend_id).
+ *
+ * @param int $friendship_id ID of the friendship object.
+ * @param int $initiator_id ID of the user who initiated the request.
+ * @param int $friend_id ID of the request recipient.
+ */
+function friends_notification_new_request( $friendship_id, $initiator_id, $friend_id ) {
+
+	$initiator_name = bp_core_get_user_displayname( $initiator_id );
+
+	if ( 'no' == bp_get_user_meta( (int) $friend_id, 'notification_friends_friendship_request', true ) )
+		return false;
+
+	$ud                = get_userdata( $friend_id );
+	$all_requests_link = bp_core_get_user_domain( $friend_id ) . bp_get_friends_slug() . '/requests/';
+	$settings_slug     = function_exists( 'bp_get_settings_slug' ) ? bp_get_settings_slug() : 'settings';
+	$settings_link     = trailingslashit( bp_core_get_user_domain( $friend_id ) .  $settings_slug . '/notifications' );
+	$initiator_link    = bp_core_get_user_domain( $initiator_id );
+
+	// Set up and send the message
+	$to       = $ud->user_email;
+	$subject  = bp_get_email_subject( array( 'text' => sprintf( __( 'New friendship request from %s', 'buddypress' ), $initiator_name ) ) );
+	$message  = sprintf( __(
+'%1$s wants to add you as a friend.
+
+To view all of your pending friendship requests: %2$s
+
+To view %3$s\'s profile: %4$s
+
+---------------------
+', 'buddypress' ), $initiator_name, $all_requests_link, $initiator_name, $initiator_link );
+
+	// Only show the disable notifications line if the settings component is enabled
+	if ( bp_is_active( 'settings' ) ) {
+		$message .= sprintf( __( 'To disable these notifications please log in and go to: %s', 'buddypress' ), $settings_link );
+	}
+
+	// Send the message
+	$to      = apply_filters( 'friends_notification_new_request_to', $to );
+	$subject = apply_filters( 'friends_notification_new_request_subject', $subject, $initiator_name );
+	$message = apply_filters( 'friends_notification_new_request_message', $message, $initiator_name, $initiator_link, $all_requests_link, $settings_link );
+
+	wp_mail( $to, $subject, $message );
+
+	do_action( 'bp_friends_sent_request_email', $friend_id, $subject, $message, $friendship_id, $initiator_id );
+}
+add_action( 'friends_friendship_requested', 'friends_notification_new_request', 10, 3 );
+
+/**
+ * Send notifications related to the acceptance of a friendship request.
+ *
+ * When a friendship request is accepted, an email and a BP notification are
+ * sent to the user who requested the friendship ($initiator_id).
+ *
+ * @param int $friendship_id ID of the friendship object.
+ * @param int $initiator_id ID of the user who initiated the request.
+ * @param int $friend_id ID of the request recipient.
+ */
+function friends_notification_accepted_request( $friendship_id, $initiator_id, $friend_id ) {
+
+	$friend_name = bp_core_get_user_displayname( $friend_id );
+
+	if ( 'no' == bp_get_user_meta( (int) $initiator_id, 'notification_friends_friendship_accepted', true ) )
+		return false;
+
+	$ud            = get_userdata( $initiator_id );
+	$friend_link   = bp_core_get_user_domain( $friend_id );
+	$settings_slug = function_exists( 'bp_get_settings_slug' ) ? bp_get_settings_slug() : 'settings';
+	$settings_link = trailingslashit( bp_core_get_user_domain( $initiator_id ) . $settings_slug . '/notifications' );
+
+	// Set up and send the message
+	$to       = $ud->user_email;
+	$subject  = bp_get_email_subject( array( 'text' => sprintf( __( '%s accepted your friendship request', 'buddypress' ), $friend_name ) ) );
+	$message  = sprintf( __(
+'%1$s accepted your friend request.
+
+To view %2$s\'s profile: %3$s
+
+---------------------
+', 'buddypress' ), $friend_name, $friend_name, $friend_link );
+
+	// Only show the disable notifications line if the settings component is enabled
+	if ( bp_is_active( 'settings' ) ) {
+		$message .= sprintf( __( 'To disable these notifications please log in and go to: %s', 'buddypress' ), $settings_link );
+	}
+
+	// Send the message
+	$to      = apply_filters( 'friends_notification_accepted_request_to', $to );
+	$subject = apply_filters( 'friends_notification_accepted_request_subject', $subject, $friend_name );
+	$message = apply_filters( 'friends_notification_accepted_request_message', $message, $friend_name, $friend_link, $settings_link );
+
+	wp_mail( $to, $subject, $message );
+
+	do_action( 'bp_friends_sent_accepted_email', $initiator_id, $subject, $message, $friendship_id, $friend_id );
+}
+add_action( 'friends_friendship_accepted', 'friends_notification_accepted_request', 10, 3 );
+
+/** Notifications *************************************************************/
+
+/**
+ * Notification formatting callback for bp-friends notifications.
+ *
+ * @param string $action The kind of notification being rendered.
+ * @param int $item_id The primary item ID.
+ * @param int $secondary_item_id The secondary item ID.
+ * @param int $total_items The total number of messaging-related notifications
+ *        waiting for the user.
+ * @param string $format 'string' for BuddyBar-compatible notifications;
+ *        'array' for WP Toolbar. Default: 'string'.
+ * @return array|string
+ */
+function friends_format_notifications( $action, $item_id, $secondary_item_id, $total_items, $format = 'string' ) {
+
+	switch ( $action ) {
+		case 'friendship_accepted':
+			$link = trailingslashit( bp_loggedin_user_domain() . bp_get_friends_slug() . '/my-friends' );
+
+			// Set up the string and the filter
+			if ( (int) $total_items > 1 ) {
+				$text = sprintf( __( '%d friends accepted your friendship requests', 'buddypress' ), (int) $total_items );
+				$filter = 'bp_friends_multiple_friendship_accepted_notification';
+			} else {
+				$text = sprintf( __( '%s accepted your friendship request', 'buddypress' ),  bp_core_get_user_displayname( $item_id ) );
+				$filter = 'bp_friends_single_friendship_accepted_notification';
+			}
+
+			break;
+
+		case 'friendship_request':
+			$link = bp_loggedin_user_domain() . bp_get_friends_slug() . '/requests/?new';
+
+			// Set up the string and the filter
+			if ( (int) $total_items > 1 ) {
+				$text = sprintf( __( 'You have %d pending friendship requests', 'buddypress' ), (int) $total_items );
+				$filter = 'bp_friends_multiple_friendship_request_notification';
+			} else {
+				$text = sprintf( __( 'You have a friendship request from %s', 'buddypress' ),  bp_core_get_user_displayname( $item_id ) );
+				$filter = 'bp_friends_single_friendship_request_notification';
+			}
+
+			break;
+	}
+
+	// Return either an HTML link or an array, depending on the requested format
+	if ( 'string' == $format ) {
+		$return = apply_filters( $filter, '<a href="' . esc_url( $link ) . '">' . esc_html( $text ) . '</a>', (int) $total_items );
+	} else {
+		$return = apply_filters( $filter, array(
+			'link' => $link,
+			'text' => $text
+		), (int) $total_items );
+	}
+
+	do_action( 'friends_format_notifications', $action, $item_id, $secondary_item_id, $total_items, $return );
+
+	return $return;
+}
+
+/**
+ * Clear friend-related notifications when ?new=1
+ */
+function friends_clear_friend_notifications() {
+	if ( isset( $_GET['new'] ) && bp_is_active( 'notifications' ) ) {
+		bp_notifications_mark_notifications_by_type( bp_loggedin_user_id(), buddypress()->friends->id, 'friendship_accepted' );
+	}
+}
+add_action( 'bp_activity_screen_my_activity', 'friends_clear_friend_notifications' );
+
+/**
+ * Delete any friendship request notifications for the logged in user.
+ *
+ * @since BuddyPress (1.9.0)
+ */
+function bp_friends_mark_friendship_request_notifications_by_type() {
+	if ( isset( $_GET['new'] ) && bp_is_active( 'notifications' ) ) {
+		bp_notifications_mark_notifications_by_type( bp_loggedin_user_id(), buddypress()->friends->id, 'friendship_request' );
+	}
+}
+add_action( 'friends_screen_requests', 'bp_friends_mark_friendship_request_notifications_by_type' );
+
+/**
+ * Delete any friendship acceptance notifications for the logged in user.
+ *
+ * @since BuddyPress (1.9.0)
+ */
+function bp_friends_mark_friendship_accepted_notifications_by_type() {
+	if ( bp_is_active( 'notifications' ) ) {
+		bp_notifications_mark_notifications_by_type( bp_loggedin_user_id(), buddypress()->friends->id, 'friendship_accepted' );
+	}
+}
+add_action( 'friends_screen_my_friends', 'bp_friends_mark_friendship_accepted_notifications_by_type' );
+
+/**
+ * Notify one use that another user has requested their virtual friendship.
+ *
+ * @since BuddyPress (1.9.0)
+ * @param int $friendship_id The unique ID of the friendship
+ * @param int $initiator_user_id The friendship initiator user ID
+ * @param int $friend_user_id The friendship request reciever user ID
+ */
+function bp_friends_friendship_requested_notification( $friendship_id, $initiator_user_id, $friend_user_id ) {
+	if ( bp_is_active( 'notifications' ) ) {
+		bp_notifications_add_notification( array(
+			'user_id'           => $friend_user_id,
+			'item_id'           => $initiator_user_id,
+			'secondary_item_id' => $friendship_id,
+			'component_name'    => buddypress()->friends->id,
+			'component_action'  => 'friendship_request',
+			'date_notified'     => bp_core_current_time(),
+			'is_new'            => 1,
+		) );
+	}
+}
+add_action( 'friends_friendship_requested', 'bp_friends_friendship_requested_notification', 10, 3 );
+
+/**
+ * Remove friend request notice when a member rejects another members
+ *
+ * @since BuddyPress (1.9.0)
+ *
+ * @param int $friendship_id (not used)
+ * @param object $friendship
+ */
+function bp_friends_mark_friendship_rejected_notifications_by_item_id( $friendship_id, $friendship ) {
+	if ( bp_is_active( 'notifications' ) ) {
+		bp_notifications_mark_notifications_by_item_id( $friendship->friend_user_id, $friendship->initiator_user_id, buddypress()->friends->id, 'friendship_request' );
+	}
+}
+add_action( 'friends_friendship_rejected', 'bp_friends_mark_friendship_rejected_notifications_by_item_id', 10, 2 );
+
+/**
+ * Notify a member when another member accepts their virtual friendship request.
+ *
+ * @since BuddyPress (1.9.0)
+ * @param int $friendship_id The unique ID of the friendship
+ * @param int $initiator_user_id The friendship initiator user ID
+ * @param int $friend_user_id The friendship request reciever user ID
+ */
+function bp_friends_add_friendship_accepted_notification( $friendship_id, $initiator_user_id, $friend_user_id ) {
+
+	// Bail if notifications is not active
+	if ( ! bp_is_active( 'notifications' ) ) {
+		return;
+	}
+
+	// Remove the friend request notice
+	bp_notifications_mark_notifications_by_item_id( $friend_user_id, $initiator_user_id, buddypress()->friends->id, 'friendship_request' );
+
+	// Add a friend accepted notice for the initiating user
+	bp_notifications_add_notification(  array(
+		'user_id'           => $initiator_user_id,
+		'item_id'           => $friend_user_id,
+		'secondary_item_id' => $friendship_id,
+		'component_name'    => buddypress()->friends->id,
+		'component_action'  => 'friendship_accepted',
+		'date_notified'     => bp_core_current_time(),
+		'is_new'            => 1,
+	) );
+}
+add_action( 'friends_friendship_accepted', 'bp_friends_add_friendship_accepted_notification', 10, 3 );
+
+/**
+ * Remove friend request notice when a member withdraws their friend request
+ *
+ * @since BuddyPress (1.9.0)
+ *
+ * @param int $friendship_id (not used)
+ * @param object $friendship
+ */
+function bp_friends_mark_friendship_withdrawn_notifications_by_item_id( $friendship_id, $friendship ) {
+	if ( bp_is_active( 'notifications' ) ) {
+		bp_notifications_delete_notifications_by_item_id( $friendship->friend_user_id, $friendship->initiator_user_id, buddypress()->friends->id, 'friendship_request' );
+	}
+}
+add_action( 'friends_friendship_withdrawn', 'bp_friends_mark_friendship_withdrawn_notifications_by_item_id', 10, 2 );
+
+/**
+ * Remove friendship requests FROM user, used primarily when a user is deleted
+ *
+ * @since BuddyPress (1.9.0)
+ * @param int $user_id
+ */
+function bp_friends_remove_notifications_data( $user_id = 0 ) {
+	if ( bp_is_active( 'notifications' ) ) {
+		bp_notifications_delete_notifications_from_user( $user_id, buddypress()->friends->id, 'friendship_request' );
+	}
+}
+add_action( 'friends_remove_data', 'bp_friends_remove_notifications_data', 10, 1 );
Index: /tags/1.9/bp-friends/bp-friends-screens.php
===================================================================
--- /tags/1.9/bp-friends/bp-friends-screens.php	(revision 7684)
+++ /tags/1.9/bp-friends/bp-friends-screens.php	(revision 7684)
@@ -0,0 +1,112 @@
+<?php
+
+/**
+ * BuddyPress Friends Screen Functions
+ *
+ * Screen functions are the controllers of BuddyPress. They will execute when
+ * their specific URL is caught. They will first save or manipulate data using
+ * business functions, then pass on the user to a template file.
+ *
+ * @package BuddyPress
+ * @subpackage FriendsScreens
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/**
+ * Catch and process the My Friends page.
+ */
+function friends_screen_my_friends() {
+
+	do_action( 'friends_screen_my_friends' );
+
+	bp_core_load_template( apply_filters( 'friends_template_my_friends', 'members/single/home' ) );
+}
+
+/**
+ * Catch and process the Requests page.
+ */
+function friends_screen_requests() {
+	if ( bp_is_action_variable( 'accept', 0 ) && is_numeric( bp_action_variable( 1 ) ) ) {
+		// Check the nonce
+		check_admin_referer( 'friends_accept_friendship' );
+
+		if ( friends_accept_friendship( bp_action_variable( 1 ) ) )
+			bp_core_add_message( __( 'Friendship accepted', 'buddypress' ) );
+		else
+			bp_core_add_message( __( 'Friendship could not be accepted', 'buddypress' ), 'error' );
+
+		bp_core_redirect( trailingslashit( bp_loggedin_user_domain() . bp_current_component() . '/' . bp_current_action() ) );
+
+	} elseif ( bp_is_action_variable( 'reject', 0 ) && is_numeric( bp_action_variable( 1 ) ) ) {
+		// Check the nonce
+		check_admin_referer( 'friends_reject_friendship' );
+
+		if ( friends_reject_friendship( bp_action_variable( 1 ) ) )
+			bp_core_add_message( __( 'Friendship rejected', 'buddypress' ) );
+		else
+			bp_core_add_message( __( 'Friendship could not be rejected', 'buddypress' ), 'error' );
+
+		bp_core_redirect( trailingslashit( bp_loggedin_user_domain() . bp_current_component() . '/' . bp_current_action() ) );
+
+	} elseif ( bp_is_action_variable( 'cancel', 0 ) && is_numeric( bp_action_variable( 1 ) ) ) {
+		// Check the nonce
+		check_admin_referer( 'friends_withdraw_friendship' );
+
+		if ( friends_withdraw_friendship( bp_loggedin_user_id(), bp_action_variable( 1 ) ) )
+			bp_core_add_message( __( 'Friendship request withdrawn', 'buddypress' ) );
+		else
+			bp_core_add_message( __( 'Friendship request could not be withdrawn', 'buddypress' ), 'error' );
+
+		bp_core_redirect( trailingslashit( bp_loggedin_user_domain() . bp_current_component() . '/' . bp_current_action() ) );
+	}
+
+	do_action( 'friends_screen_requests' );
+
+	bp_core_load_template( apply_filters( 'friends_template_requests', 'members/single/home' ) );
+}
+
+/**
+ * Add Friends-related settings to the Settings > Notifications page.
+ */
+function friends_screen_notification_settings() {
+
+	if ( !$send_requests = bp_get_user_meta( bp_displayed_user_id(), 'notification_friends_friendship_request', true ) )
+		$send_requests   = 'yes';
+
+	if ( !$accept_requests = bp_get_user_meta( bp_displayed_user_id(), 'notification_friends_friendship_accepted', true ) )
+		$accept_requests = 'yes'; ?>
+
+	<table class="notification-settings" id="friends-notification-settings">
+		<thead>
+			<tr>
+				<th class="icon"></th>
+				<th class="title"><?php _e( 'Friends', 'buddypress' ) ?></th>
+				<th class="yes"><?php _e( 'Yes', 'buddypress' ) ?></th>
+				<th class="no"><?php _e( 'No', 'buddypress' )?></th>
+			</tr>
+		</thead>
+
+		<tbody>
+			<tr id="friends-notification-settings-request">
+				<td></td>
+				<td><?php _e( 'A member sends you a friendship request', 'buddypress' ) ?></td>
+				<td class="yes"><input type="radio" name="notifications[notification_friends_friendship_request]" value="yes" <?php checked( $send_requests, 'yes', true ) ?>/></td>
+				<td class="no"><input type="radio" name="notifications[notification_friends_friendship_request]" value="no" <?php checked( $send_requests, 'no', true ) ?>/></td>
+			</tr>
+			<tr id="friends-notification-settings-accepted">
+				<td></td>
+				<td><?php _e( 'A member accepts your friendship request', 'buddypress' ) ?></td>
+				<td class="yes"><input type="radio" name="notifications[notification_friends_friendship_accepted]" value="yes" <?php checked( $accept_requests, 'yes', true ) ?>/></td>
+				<td class="no"><input type="radio" name="notifications[notification_friends_friendship_accepted]" value="no" <?php checked( $accept_requests, 'no', true ) ?>/></td>
+			</tr>
+
+			<?php do_action( 'friends_screen_notification_settings' ); ?>
+
+		</tbody>
+	</table>
+
+<?php
+}
+add_action( 'bp_notification_settings', 'friends_screen_notification_settings' );
Index: /tags/1.9/bp-friends/bp-friends-template.php
===================================================================
--- /tags/1.9/bp-friends/bp-friends-template.php	(revision 7684)
+++ /tags/1.9/bp-friends/bp-friends-template.php	(revision 7684)
@@ -0,0 +1,542 @@
+<?php
+
+/**
+ * BuddyPress Friends Template Functions.
+ *
+ * @package BuddyPress
+ * @subpackage FriendsTemplate
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/**
+ * Output the friends component slug.
+ *
+ * @since BuddyPress (1.5.0)
+ *
+ * @uses bp_get_friends_slug()
+ */
+function bp_friends_slug() {
+	echo bp_get_friends_slug();
+}
+	/**
+	 * Return the friends component slug.
+	 *
+	 * @since BuddyPress (1.5.0)
+	 */
+	function bp_get_friends_slug() {
+		global $bp;
+		return apply_filters( 'bp_get_friends_slug', $bp->friends->slug );
+	}
+
+/**
+ * Output the friends component root slug.
+ *
+ * @since BuddyPress (1.5.0)
+ *
+ * @uses bp_get_friends_root_slug()
+ */
+function bp_friends_root_slug() {
+	echo bp_get_friends_root_slug();
+}
+	/**
+	 * Return the friends component root slug.
+	 *
+	 * @since BuddyPress (1.5.0)
+	 */
+	function bp_get_friends_root_slug() {
+		global $bp;
+		return apply_filters( 'bp_get_friends_root_slug', $bp->friends->root_slug );
+	}
+
+/**
+ * Output a block of random friends.
+ *
+ * No longer used in BuddyPress.
+ *
+ * @todo Deprecate
+ */
+function bp_friends_random_friends() {
+
+	if ( !$friend_ids = wp_cache_get( 'friends_friend_ids_' . bp_displayed_user_id(), 'bp' ) ) {
+		$friend_ids = BP_Friends_Friendship::get_random_friends( bp_displayed_user_id() );
+		wp_cache_set( 'friends_friend_ids_' . bp_displayed_user_id(), $friend_ids, 'bp' );
+	} ?>
+
+	<div class="info-group">
+		<h4><?php bp_word_or_name( __( "My Friends", 'buddypress' ), __( "%s's Friends", 'buddypress' ) ) ?>  (<?php echo BP_Friends_Friendship::total_friend_count( bp_displayed_user_id() ) ?>) <span><a href="<?php echo trailingslashit( bp_displayed_user_domain() . bp_get_friends_slug() ) ?>"><?php _e('See All', 'buddypress') ?></a></span></h4>
+
+		<?php if ( $friend_ids ) { ?>
+
+			<ul class="horiz-gallery">
+
+			<?php for ( $i = 0, $count = count( $friend_ids ); $i < $count; ++$i ) { ?>
+
+				<li>
+					<a href="<?php echo bp_core_get_user_domain( $friend_ids[$i] ) ?>"><?php echo bp_core_fetch_avatar( array( 'item_id' => $friend_ids[$i], 'type' => 'thumb' ) ) ?></a>
+					<h5><?php echo bp_core_get_userlink($friend_ids[$i]) ?></h5>
+				</li>
+
+			<?php } ?>
+
+			</ul>
+
+		<?php } else { ?>
+
+			<div id="message" class="info">
+				<p><?php bp_word_or_name( __( "You haven't added any friend connections yet.", 'buddypress' ), __( "%s hasn't created any friend connections yet.", 'buddypress' ) ) ?></p>
+			</div>
+
+		<?php } ?>
+
+		<div class="clear"></div>
+	</div>
+
+<?php
+}
+
+/**
+ * Pull up a group of random members, and display some profile data about them.
+ *
+ * This function is no longer used by BuddyPress core.
+ *
+ * @todo Deprecate
+ *
+ * @param int $total_members The number of members to retrieve.
+ */
+function bp_friends_random_members( $total_members = 5 ) {
+
+	if ( !$user_ids = wp_cache_get( 'friends_random_users', 'bp' ) ) {
+		$user_ids = BP_Core_User::get_users( 'random', $total_members );
+		wp_cache_set( 'friends_random_users', $user_ids, 'bp' );
+	}
+
+	?>
+
+	<?php if ( $user_ids['users'] ) { ?>
+
+		<ul class="item-list" id="random-members-list">
+
+		<?php for ( $i = 0, $count = count( $user_ids['users'] ); $i < $count; ++$i ) { ?>
+
+			<li>
+				<a href="<?php echo bp_core_get_user_domain( $user_ids['users'][$i]->id ) ?>"><?php echo bp_core_fetch_avatar( array( 'item_id' => $user_ids['users'][$i]->id, 'type' => 'thumb' ) ) ?></a>
+				<h5><?php echo bp_core_get_userlink( $user_ids['users'][$i]->id ) ?></h5>
+
+				<?php if ( bp_is_active( 'xprofile' ) ) { ?>
+
+					<?php $random_data = xprofile_get_random_profile_data( $user_ids['users'][$i]->id, true ); ?>
+
+					<div class="profile-data">
+						<p class="field-name"><?php echo $random_data[0]->name ?></p>
+
+						<?php echo $random_data[0]->value ?>
+
+					</div>
+
+				<?php } ?>
+
+				<div class="action">
+
+					<?php if ( bp_is_active( 'friends' ) ) { ?>
+
+						<?php bp_add_friend_button( $user_ids['users'][$i]->id ) ?>
+
+					<?php } ?>
+
+				</div>
+			</li>
+
+		<?php } ?>
+
+		</ul>
+
+	<?php } else { ?>
+
+		<div id="message" class="info">
+			<p><?php _e( "There aren't enough site members to show a random sample just yet.", 'buddypress' ) ?></p>
+		</div>
+
+	<?php } ?>
+<?php
+}
+
+/**
+ * Display a Friends search form.
+ *
+ * No longer used in BuddyPress.
+ *
+ * @todo Deprecate
+ */
+function bp_friend_search_form() {
+
+	$action = bp_displayed_user_domain() . bp_get_friends_slug() . '/my-friends/search/';
+	$label  = __( 'Filter Friends', 'buddypress' ); ?>
+
+		<form action="<?php echo $action ?>" id="friend-search-form" method="post">
+
+			<label for="friend-search-box" id="friend-search-label"><?php echo $label ?></label>
+			<input type="search" name="friend-search-box" id="friend-search-box" value="<?php echo $value ?>"<?php echo $disabled ?> />
+
+			<?php wp_nonce_field( 'friends_search', '_wpnonce_friend_search' ) ?>
+
+			<input type="hidden" name="initiator" id="initiator" value="<?php echo esc_attr( bp_displayed_user_id() ) ?>" />
+
+		</form>
+
+	<?php
+}
+
+/**
+ * Output the Add Friend button in member directories.
+ */
+function bp_member_add_friend_button() {
+	global $members_template;
+
+	if ( !isset( $members_template->member->is_friend ) || null === $members_template->member->is_friend )
+		$friend_status = 'not_friends';
+	else
+		$friend_status = ( 0 == $members_template->member->is_friend ) ? 'pending' : 'is_friend';
+
+	echo bp_get_add_friend_button( $members_template->member->id, $friend_status );
+}
+add_action( 'bp_directory_members_actions', 'bp_member_add_friend_button' );
+
+/**
+ * Output the friend count for the current member in the loop.
+ */
+function bp_member_total_friend_count() {
+	echo bp_get_member_total_friend_count();
+}
+	/**
+	 * Return the friend count for the current member in the loop.
+	 *
+	 * Return value is a string of the form "x friends".
+	 *
+	 * @return string A string of the form "x friends".
+	 */
+	function bp_get_member_total_friend_count() {
+		global $members_template;
+
+		if ( 1 == (int) $members_template->member->total_friend_count )
+			return apply_filters( 'bp_get_member_total_friend_count', sprintf( __( '%d friend', 'buddypress' ), (int) $members_template->member->total_friend_count ) );
+		else
+			return apply_filters( 'bp_get_member_total_friend_count', sprintf( __( '%d friends', 'buddypress' ), (int) $members_template->member->total_friend_count ) );
+	}
+
+/**
+ * Output the ID of the current user in the friend request loop.
+ *
+ * @see bp_get_potential_friend_id() for a description of arguments.
+ *
+ * @param int $user_id See {@link bp_get_potential_friend_id()}.
+ */
+function bp_potential_friend_id( $user_id = 0 ) {
+	echo bp_get_potential_friend_id( $user_id );
+}
+	/**
+	 * Return the ID of current user in the friend request loop.
+	 *
+	 * @global object $friends_template
+	 *
+	 * @param int $user_id Optional. If provided, the function will simply
+	 *        return this value.
+	 * @return int ID of potential friend.
+	 */
+	function bp_get_potential_friend_id( $user_id = 0 ) {
+		global $friends_template;
+
+		if ( empty( $user_id ) && isset( $friends_template->friendship->friend ) )
+			$user_id = $friends_template->friendship->friend->id;
+		else if ( empty( $user_id ) && !isset( $friends_template->friendship->friend ) )
+			$user_id = bp_displayed_user_id();
+
+		return apply_filters( 'bp_get_potential_friend_id', (int) $user_id );
+	}
+
+/**
+ * Check whether a given user is a friend of the logged-in user.
+ *
+ * Returns - 'is_friend', 'not_friends', 'pending'.
+ *
+ * @param int $user_id ID of the potential friend. Default: the value of
+ *        {@link bp_get_potential_friend_id()}.
+ * @return string 'is_friend', 'not_friends', or 'pending'.
+ */
+function bp_is_friend( $user_id = 0 ) {
+
+	if ( !is_user_logged_in() )
+		return false;
+
+	if ( empty( $user_id ) )
+		$user_id = bp_get_potential_friend_id( $user_id );
+
+	if ( bp_loggedin_user_id() == $user_id )
+		return false;
+
+	return apply_filters( 'bp_is_friend', friends_check_friendship_status( bp_loggedin_user_id(), $user_id ), $user_id );
+}
+
+/**
+ * Output the Add Friend button.
+ *
+ * @see bp_get_add_friend_button() for information on arguments.
+ *
+ * @param int $potential_friend_id See {@link bp_get_add_friend_button()}.
+ * @param int $friend_status See {@link bp_get_add_friend_button()}.
+ */
+function bp_add_friend_button( $potential_friend_id = 0, $friend_status = false ) {
+	echo bp_get_add_friend_button( $potential_friend_id, $friend_status );
+}
+	/**
+	 * Create the Add Friend button.
+	 *
+	 * @param int $potential_friend_id ID of the user to whom the button
+	 *        applies. Default: value of {@link bp_get_potential_friend_id()}.
+	 * @param bool $friend_status Not currently used.
+	 * @return string HTML for the Add Friend button.
+	 */
+	function bp_get_add_friend_button( $potential_friend_id = 0, $friend_status = false ) {
+
+		if ( empty( $potential_friend_id ) )
+			$potential_friend_id = bp_get_potential_friend_id( $potential_friend_id );
+
+		$is_friend = bp_is_friend( $potential_friend_id );
+
+		if ( empty( $is_friend ) )
+			return false;
+
+		switch ( $is_friend ) {
+			case 'pending' :
+				$button = array(
+					'id'                => 'pending',
+					'component'         => 'friends',
+					'must_be_logged_in' => true,
+					'block_self'        => true,
+					'wrapper_class'     => 'friendship-button pending_friend',
+					'wrapper_id'        => 'friendship-button-' . $potential_friend_id,
+					'link_href'         => wp_nonce_url( bp_loggedin_user_domain() . bp_get_friends_slug() . '/requests/cancel/' . $potential_friend_id . '/', 'friends_withdraw_friendship' ),
+					'link_text'         => __( 'Cancel Friendship Request', 'buddypress' ),
+					'link_title'        => __( 'Cancel Friendship Requested', 'buddypress' ),
+					'link_id'			=> 'friend-' . $potential_friend_id,
+					'link_rel'			=> 'remove',
+					'link_class'        => 'friendship-button pending_friend requested'
+				);
+				break;
+
+			case 'awaiting_response' :
+				$button = array(
+					'id'                => 'awaiting_response',
+					'component'         => 'friends',
+					'must_be_logged_in' => true,
+					'block_self'        => true,
+					'wrapper_class'     => 'friendship-button awaiting_response_friend',
+					'wrapper_id'        => 'friendship-button-' . $potential_friend_id,
+					'link_href'         => bp_loggedin_user_domain() . bp_get_friends_slug() . '/requests/',
+					'link_text'         => __( 'Friendship Requested', 'buddypress' ),
+					'link_title'        => __( 'Friendship Requested', 'buddypress' ),
+					'link_id'           => 'friend-' . $potential_friend_id,
+					'link_rel'          => 'remove',
+					'link_class'        => 'friendship-button awaiting_response_friend requested'
+				);
+				break;
+
+			case 'is_friend' :
+				$button = array(
+					'id'                => 'is_friend',
+					'component'         => 'friends',
+					'must_be_logged_in' => true,
+					'block_self'        => false,
+					'wrapper_class'     => 'friendship-button is_friend',
+					'wrapper_id'        => 'friendship-button-' . $potential_friend_id,
+					'link_href'         => wp_nonce_url( bp_loggedin_user_domain() . bp_get_friends_slug() . '/remove-friend/' . $potential_friend_id . '/', 'friends_remove_friend' ),
+					'link_text'         => __( 'Cancel Friendship', 'buddypress' ),
+					'link_title'        => __( 'Cancel Friendship', 'buddypress' ),
+					'link_id'           => 'friend-' . $potential_friend_id,
+					'link_rel'          => 'remove',
+					'link_class'        => 'friendship-button is_friend remove'
+				);
+				break;
+
+			default:
+				$button = array(
+					'id'                => 'not_friends',
+					'component'         => 'friends',
+					'must_be_logged_in' => true,
+					'block_self'        => true,
+					'wrapper_class'     => 'friendship-button not_friends',
+					'wrapper_id'        => 'friendship-button-' . $potential_friend_id,
+					'link_href'         => wp_nonce_url( bp_loggedin_user_domain() . bp_get_friends_slug() . '/add-friend/' . $potential_friend_id . '/', 'friends_add_friend' ),
+					'link_text'         => __( 'Add Friend', 'buddypress' ),
+					'link_title'        => __( 'Add Friend', 'buddypress' ),
+					'link_id'           => 'friend-' . $potential_friend_id,
+					'link_rel'          => 'add',
+					'link_class'        => 'friendship-button not_friends add'
+				);
+				break;
+		}
+
+		// Filter and return the HTML button
+		return bp_get_button( apply_filters( 'bp_get_add_friend_button', $button ) );
+	}
+
+/**
+ * Get a comma-separated list of IDs of a user's friends.
+ *
+ * @param int $user_id Optional. Default: the displayed user's ID, or the
+ *        logged-in user's ID.
+ * @return string|bool A comma-separated list of friend IDs if any are found,
+ *         otherwise false.
+ */
+function bp_get_friend_ids( $user_id = 0 ) {
+
+	if ( empty( $user_id ) )
+		$user_id = ( bp_displayed_user_id() ) ? bp_displayed_user_id() : bp_loggedin_user_id();
+
+	$friend_ids = friends_get_friend_user_ids( $user_id );
+
+	if ( empty( $friend_ids ) )
+		return false;
+
+	return implode( ',', friends_get_friend_user_ids( $user_id ) );
+}
+
+/**
+ * Get a user's friendship requests.
+ *
+ * Note that we return a 0 if no pending requests are found. This is necessary
+ * because of the structure of the $include parameter in bp_has_members().
+ *
+ * @param int $user_id ID of the user whose requests are being retrieved.
+ *        Defaults to displayed user.
+ * @return array|int An array of user IDs if found, or a 0 if none are found.
+ */
+function bp_get_friendship_requests( $user_id = 0 ) {
+	if ( !$user_id ) {
+		$user_id = bp_displayed_user_id();
+	}
+
+	if ( !$user_id ) {
+		return 0;
+	}
+
+	$requests = friends_get_friendship_request_user_ids( $user_id );
+
+	if ( !empty( $requests ) ) {
+		$requests = implode( ',', (array) $requests );
+	} else {
+		$requests = 0;
+	}
+
+	return apply_filters( 'bp_get_friendship_requests', $requests );
+}
+
+/**
+ * Output the ID of the friendship between the logged-in user and the current user in the loop.
+ */
+function bp_friend_friendship_id() {
+	echo bp_get_friend_friendship_id();
+}
+	/**
+	 * Return the ID of the frinedship between the logged-in user and the current user in the loop.
+	 *
+	 * @return int ID of the friendship.
+	 */
+	function bp_get_friend_friendship_id() {
+		global $members_template;
+
+		if ( !$friendship_id = wp_cache_get( 'friendship_id_' . $members_template->member->id . '_' . bp_loggedin_user_id() ) ) {
+			$friendship_id = friends_get_friendship_id( $members_template->member->id, bp_loggedin_user_id() );
+			wp_cache_set( 'friendship_id_' . $members_template->member->id . '_' . bp_loggedin_user_id(), $friendship_id, 'bp' );
+		}
+
+		return apply_filters( 'bp_get_friend_friendship_id', $friendship_id );
+	}
+
+/**
+ * Output the URL for accepting the current friendship request in the loop.
+ */
+function bp_friend_accept_request_link() {
+	echo bp_get_friend_accept_request_link();
+}
+	/**
+	 * Return the URL for accepting the current friendship request in the loop.
+	 *
+	 * @return string accept-friendship URL.
+	 */
+	function bp_get_friend_accept_request_link() {
+		global $members_template;
+
+		if ( !$friendship_id = wp_cache_get( 'friendship_id_' . $members_template->member->id . '_' . bp_loggedin_user_id() ) ) {
+			$friendship_id = friends_get_friendship_id( $members_template->member->id, bp_loggedin_user_id() );
+			wp_cache_set( 'friendship_id_' . $members_template->member->id . '_' . bp_loggedin_user_id(), $friendship_id, 'bp' );
+		}
+
+		return apply_filters( 'bp_get_friend_accept_request_link', wp_nonce_url( bp_loggedin_user_domain() . bp_get_friends_slug() . '/requests/accept/' . $friendship_id, 'friends_accept_friendship' ) );
+	}
+
+/**
+ * Output the URL for rejecting the current friendship request in the loop.
+ */
+function bp_friend_reject_request_link() {
+	echo bp_get_friend_reject_request_link();
+}
+	/**
+	 * Return the URL for rejecting the current friendship request in the loop.
+	 *
+	 * @return string reject-friendship URL.
+	 */
+	function bp_get_friend_reject_request_link() {
+		global $members_template;
+
+		if ( !$friendship_id = wp_cache_get( 'friendship_id_' . $members_template->member->id . '_' . bp_loggedin_user_id() ) ) {
+			$friendship_id = friends_get_friendship_id( $members_template->member->id, bp_loggedin_user_id() );
+			wp_cache_set( 'friendship_id_' . $members_template->member->id . '_' . bp_loggedin_user_id(), $friendship_id, 'bp' );
+		}
+
+		return apply_filters( 'bp_get_friend_reject_request_link', wp_nonce_url( bp_loggedin_user_domain() . bp_get_friends_slug() . '/requests/reject/' . $friendship_id, 'friends_reject_friendship' ) );
+	}
+
+/**
+ * Output the total friend count for a given user.
+ *
+ * @param int $user_id See {@link friends_get_total_friend_count()}.
+ */
+function bp_total_friend_count( $user_id = 0 ) {
+	echo bp_get_total_friend_count( $user_id );
+}
+	/**
+	 * Return the total friend count for a given user.
+	 *
+	 * @param int $user_id See {@link friends_get_total_friend_count()}.
+	 * @return int Total friend count.
+	 */
+	function bp_get_total_friend_count( $user_id = 0 ) {
+		return apply_filters( 'bp_get_total_friend_count', friends_get_total_friend_count( $user_id ) );
+	}
+	add_filter( 'bp_get_total_friend_count', 'bp_core_number_format' );
+
+/**
+ * Output the total friendship request count for a given user.
+ *
+ * @see bp_friend_get_total_requests_count() for description of arguments.
+ *
+ * @param int $user_id See {@link bp_friend_get_total_requests_count().
+ */
+function bp_friend_total_requests_count( $user_id = 0 ) {
+	echo bp_friend_get_total_requests_count( $user_id );
+}
+	/**
+	 * Return the total friendship request count for a given user.
+	 *
+	 * @param int $user_id ID of the user whose requests are being counted.
+	 *        Default: ID of the logged-in user.
+	 * @return int Friend count.
+	 */
+	function bp_friend_get_total_requests_count( $user_id = 0 ) {
+		if ( empty( $user_id ) )
+			$user_id = bp_loggedin_user_id();
+
+		return apply_filters( 'bp_friend_get_total_requests_count', count( BP_Friends_Friendship::get_friend_user_ids( $user_id, true ) ) );
+	}
Index: /tags/1.9/bp-friends/bp-friends-widgets.php
===================================================================
--- /tags/1.9/bp-friends/bp-friends-widgets.php	(revision 7684)
+++ /tags/1.9/bp-friends/bp-friends-widgets.php	(revision 7684)
@@ -0,0 +1,250 @@
+<?php
+/**
+ * BuddyPress Widgets
+ *
+ * @package BuddyPress
+ * @subpackage Friends
+ * @since BuddyPress (1.9.0)
+ */
+
+// Exit if accessed directly
+if ( ! defined( 'ABSPATH' ) ) exit;
+
+/**
+ * Register the friends widget.
+ *
+ * @since BuddyPress (1.9.0)
+ */
+function bp_friends_register_widgets() {
+	if ( ! bp_is_active( 'friends' ) ) {
+		return;
+	}
+
+	add_action( 'widgets_init', create_function( '', 'return register_widget("BP_Core_Friends_Widget");' ) );
+}
+add_action( 'bp_register_widgets', 'bp_friends_register_widgets' );
+
+/*** MEMBER FRIENDS WIDGET *****************/
+
+/**
+ * The User Friends widget class.
+ *
+ * @since BuddyPress (1.9.0)
+ */
+class BP_Core_Friends_Widget extends WP_Widget {
+
+	/**
+	 * Class constructor.
+	 */
+	function __construct() {
+		$widget_ops = array(
+			'description' => __( 'A dynamic list of recently active, popular, and newest Friends of the displayed member.  Widget is only shown when viewing a member profile.', 'buddypress' ),
+			'classname' => 'widget_bp_core_friends_widget buddypress widget',
+		);
+		parent::__construct( false, $name = _x( '(BuddyPress) Friends', 'widget name', 'buddypress' ), $widget_ops );
+
+	}
+
+	/**
+	 * Display the widget.
+	 *
+	 * @param array $args Widget arguments.
+	 * @param array $instance The widget settings, as saved by the user.
+	 */
+	function widget( $args, $instance ) {
+		extract( $args );
+
+		if ( ! bp_displayed_user_id() ) {
+			return;
+		}
+
+		$min = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min';
+		wp_enqueue_script( 'bp_core_widget_friends-js', BP_PLUGIN_URL . "bp-friends/js/widget-friends{$min}.js", array( 'jquery' ), bp_get_version() );
+
+		$user_id = bp_displayed_user_id();
+		$link = trailingslashit( bp_displayed_user_domain() . bp_get_friends_slug() );
+		$instance['title'] = sprintf( __( '%s&#8217;s Friends', 'buddypress' ), bp_get_displayed_user_fullname() );
+
+		if ( empty( $instance['friend_default'] ) ) {
+			$instance['friend_default'] = 'active';
+		}
+
+		$title = apply_filters( 'widget_title', $instance['title'] );
+
+		echo $before_widget;
+
+		$title = $instance['link_title'] ? '<a href="' . esc_url( $link ) . '">' . esc_html( $title ) . '</a>' : esc_html( $title );
+
+		echo $before_title . $title . $after_title;
+
+		$members_args = array(
+			'user_id'         => absint( $user_id ),
+			'type'            => sanitize_text_field( $instance['friend_default'] ),
+			'max'             => absint( $instance['max_friends'] ),
+			'populate_extras' => 1,
+		);
+
+		?>
+
+		<?php if ( bp_has_members( $members_args ) ) : ?>
+			<div class="item-options" id="friends-list-options">
+				<a href="<?php bp_members_directory_permalink(); ?>" id="newest-friends" <?php if ( $instance['friend_default'] == 'newest' ) : ?>class="selected"<?php endif; ?>><?php _e( 'Newest', 'buddypress' ) ?></a>
+				| <a href="<?php bp_members_directory_permalink(); ?>" id="recently-active-friends" <?php if ( $instance['friend_default'] == 'active' ) : ?>class="selected"<?php endif; ?>><?php _e( 'Active', 'buddypress' ) ?></a>
+				| <a href="<?php bp_members_directory_permalink(); ?>" id="popular-friends" <?php if ( $instance['friend_default'] == 'popular' ) : ?>class="selected"<?php endif; ?>><?php _e( 'Popular', 'buddypress' ) ?></a>
+			</div>
+
+			<ul id="friends-list" class="item-list">
+				<?php while ( bp_members() ) : bp_the_member(); ?>
+					<li class="vcard">
+						<div class="item-avatar">
+							<a href="<?php bp_member_permalink() ?>" title="<?php bp_member_name() ?>"><?php bp_member_avatar() ?></a>
+						</div>
+
+						<div class="item">
+							<div class="item-title fn"><a href="<?php bp_member_permalink() ?>" title="<?php bp_member_name() ?>"><?php bp_member_name() ?></a></div>
+							<div class="item-meta">
+								<span class="activity">
+								<?php
+									if ( 'newest' == $instance['friend_default'] )
+										bp_member_registered();
+									if ( 'active' == $instance['friend_default'] )
+										bp_member_last_active();
+									if ( 'popular' == $instance['friend_default'] )
+										bp_member_total_friend_count();
+								?>
+								</span>
+							</div>
+						</div>
+					</li>
+
+				<?php endwhile; ?>
+			</ul>
+			<?php wp_nonce_field( 'bp_core_widget_friends', '_wpnonce-friends' ); ?>
+			<input type="hidden" name="friends_widget_max" id="friends_widget_max" value="<?php echo absint( $instance['max_friends'] ); ?>" />
+
+		<?php else: ?>
+
+			<div class="widget-error">
+				<?php _e( 'Sorry, no members were found.', 'buddypress' ); ?>
+			</div>
+
+		<?php endif; ?>
+
+		<?php echo $after_widget; ?>
+	<?php
+	}
+
+	/**
+	 * Process a widget save.
+	 *
+	 * @param array $new_instance The parameters saved by the user.
+	 * @param array $old_instance The paramaters as previously saved to the database.
+	 * @return array $instance The processed settings to save.
+	 */
+	function update( $new_instance, $old_instance ) {
+		$instance = $old_instance;
+
+		$instance['max_friends']    = absint( $new_instance['max_friends'] );
+		$instance['friend_default'] = sanitize_text_field( $new_instance['friend_default'] );
+		$instance['link_title']	    = (bool) $new_instance['link_title'];
+
+		return $instance;
+	}
+
+	/**
+	 * Render the widget edit form.
+	 *
+	 * @param array $instance The saved widget settings.
+	 */
+	function form( $instance ) {
+		$defaults = array(
+			'max_friends' 	 => 5,
+			'friend_default' => 'active',
+			'link_title' 	 => false
+		);
+		$instance = wp_parse_args( (array) $instance, $defaults );
+
+		$max_friends 	= $instance['max_friends'];
+		$friend_default = $instance['friend_default'];
+		$link_title	= (bool) $instance['link_title'];
+		?>
+
+		<p><label for="<?php echo $this->get_field_name( 'link_title' ) ?>"><input type="checkbox" name="<?php echo $this->get_field_name('link_title') ?>" value="1" <?php checked( $link_title ) ?> /> <?php _e( 'Link widget title to Members directory', 'buddypress' ) ?></label></p>
+
+		<p><label for="bp-core-widget-friends-max"><?php _e( 'Max friends to show:', 'buddypress' ); ?> <input class="widefat" id="<?php echo $this->get_field_id( 'max_friends' ); ?>" name="<?php echo $this->get_field_name( 'max_friends' ); ?>" type="text" value="<?php echo absint( $max_friends ); ?>" style="width: 30%" /></label></p>
+
+		<p>
+			<label for="bp-core-widget-friends-default"><?php _e( 'Default friends to show:', 'buddypress' ); ?>
+			<select name="<?php echo $this->get_field_name( 'friend_default' ) ?>">
+				<option value="newest" <?php selected( $friend_default, 'newest' ); ?>><?php _e( 'Newest', 'buddypress' ) ?></option>
+				<option value="active" <?php selected( $friend_default, 'active' );?>><?php _e( 'Active', 'buddypress' ) ?></option>
+				<option value="popular"  <?php selected( $friend_default, 'popular' ); ?>><?php _e( 'Popular', 'buddypress' ) ?></option>
+			</select>
+			</label>
+		</p>
+
+	<?php
+	}
+}
+
+/** Widget AJAX ***************************************************************/
+
+/**
+ * Process AJAX pagination or filtering for the Friends widget.
+ *
+ * @since BuddyPress (1.9.0)
+ */
+function bp_core_ajax_widget_friends() {
+
+	check_ajax_referer( 'bp_core_widget_friends' );
+
+	switch ( $_POST['filter'] ) {
+		case 'newest-friends':
+			$type = 'newest';
+			break;
+
+		case 'recently-active-friends':
+			$type = 'active';
+			break;
+
+		case 'popular-friends':
+			$type = 'popular';
+			break;
+	}
+
+	$members_args = array(
+		'user_id'         => bp_displayed_user_id(),
+		'type'            => $type,
+		'max'             => absint( $_POST['max-friends'] ),
+		'populate_extras' => 1,
+	);
+
+	if ( bp_has_members( $members_args ) ) : ?>
+		<?php echo '0[[SPLIT]]'; // return valid result. TODO: remove this. ?>
+		<?php while ( bp_members() ) : bp_the_member(); ?>
+			<li class="vcard">
+				<div class="item-avatar">
+					<a href="<?php bp_member_permalink() ?>"><?php bp_member_avatar() ?></a>
+				</div>
+
+				<div class="item">
+					<div class="item-title fn"><a href="<?php bp_member_permalink() ?>" title="<?php bp_member_name() ?>"><?php bp_member_name() ?></a></div>
+					<?php if ( 'active' == $type ) : ?>
+						<div class="item-meta"><span class="activity"><?php bp_member_last_active() ?></span></div>
+					<?php elseif ( 'newest' == $type ) : ?>
+						<div class="item-meta"><span class="activity"><?php bp_member_registered() ?></span></div>
+					<?php elseif ( bp_is_active( 'friends' ) ) : ?>
+						<div class="item-meta"><span class="activity"><?php bp_member_total_friend_count() ?></span></div>
+					<?php endif; ?>
+				</div>
+			</li>
+		<?php endwhile; ?>
+
+	<?php else: ?>
+		<?php echo "-1[[SPLIT]]<li>"; ?>
+		<?php _e( 'There were no members found, please try another filter.', 'buddypress' ) ?>
+		<?php echo "</li>"; ?>
+	<?php endif;
+}
+add_action( 'wp_ajax_widget_friends', 'bp_core_ajax_widget_friends' );
+add_action( 'wp_ajax_nopriv_widget_friends', 'bp_core_ajax_widget_friends' );
Index: /tags/1.9/bp-friends/js/widget-friends.js
===================================================================
--- /tags/1.9/bp-friends/js/widget-friends.js	(revision 7684)
+++ /tags/1.9/bp-friends/js/widget-friends.js	(revision 7684)
@@ -0,0 +1,49 @@
+jQuery(document).ready( function() {
+	jQuery(".widget div#friends-list-options a").on('click',
+		function() {
+			var link = this;
+			jQuery(link).addClass('loading');
+
+			jQuery(".widget div#friends-list-options a").removeClass("selected");
+			jQuery(this).addClass('selected');
+
+			jQuery.post( ajaxurl, {
+				action: 'widget_friends',
+				'cookie': encodeURIComponent(document.cookie),
+				'_wpnonce': jQuery("input#_wpnonce-friends").val(),
+				'max-friends': jQuery("input#friends_widget_max").val(),
+				'filter': jQuery(this).attr('id')
+			},
+			function(response)
+			{
+				jQuery(link).removeClass('loading');
+				friend_wiget_response(response);
+			});
+
+			return false;
+		}
+	);
+});
+
+function friend_wiget_response(response) {
+	response = response.substr(0, response.length-1);
+	response = response.split('[[SPLIT]]');
+
+	if ( response[0] != "-1" ) {
+		jQuery(".widget ul#friends-list").fadeOut(200,
+			function() {
+				jQuery(".widget ul#friends-list").html(response[1]);
+				jQuery(".widget ul#friends-list").fadeIn(200);
+			}
+		);
+
+	} else {
+		jQuery(".widget ul#friends-list").fadeOut(200,
+			function() {
+				var message = '<p>' + response[1] + '</p>';
+				jQuery(".widget ul#friends-list").html(message);
+				jQuery(".widget ul#friends-list").fadeIn(200);
+			}
+		);
+	}
+}
Index: /tags/1.9/bp-friends/js/widget-friends.min.js
===================================================================
--- /tags/1.9/bp-friends/js/widget-friends.min.js	(revision 7684)
+++ /tags/1.9/bp-friends/js/widget-friends.min.js	(revision 7684)
@@ -0,0 +1,1 @@
+jQuery(document).ready(function(){jQuery(".widget div#friends-list-options a").on("click",function(){var a=this;jQuery(a).addClass("loading");jQuery(".widget div#friends-list-options a").removeClass("selected");jQuery(this).addClass("selected");jQuery.post(ajaxurl,{action:"widget_friends",cookie:encodeURIComponent(document.cookie),_wpnonce:jQuery("input#_wpnonce-friends").val(),"max-friends":jQuery("input#friends_widget_max").val(),filter:jQuery(this).attr("id")},function(b){jQuery(a).removeClass("loading");friend_wiget_response(b)});return false})});function friend_wiget_response(a){a=a.substr(0,a.length-1);a=a.split("[[SPLIT]]");if(a[0]!="-1"){jQuery(".widget ul#friends-list").fadeOut(200,function(){jQuery(".widget ul#friends-list").html(a[1]);jQuery(".widget ul#friends-list").fadeIn(200)})}else{jQuery(".widget ul#friends-list").fadeOut(200,function(){var b="<p>"+a[1]+"</p>";jQuery(".widget ul#friends-list").html(b);jQuery(".widget ul#friends-list").fadeIn(200)})}};
Index: /tags/1.9/bp-groups/admin/css/admin.css
===================================================================
--- /tags/1.9/bp-groups/admin/css/admin.css	(revision 7684)
+++ /tags/1.9/bp-groups/admin/css/admin.css	(revision 7684)
@@ -0,0 +1,57 @@
+body.toplevel_page_bp-groups table.groups th#status,
+body.toplevel_page_bp-groups table.groups th#members {
+	width: 10%;
+}
+
+body.toplevel_page_bp-groups table.groups th#last_active {
+	width: 15%;
+}
+
+#bp-groups-edit-form input {
+	outline: medium none;
+	padding: 3px 8px;
+}
+#bp-groups-edit-form input#bp-groups-name {
+	font-size: 1.7em;
+	width: 100%;
+}
+#bp-groups-edit-form input#bp-groups-new-members {
+	width: 100%;
+	max-width: 90%;
+	border: 0;
+}
+.bp-groups-settings-section {
+	margin-bottom: 15px;
+}
+.bp-groups-member-type {
+	position: relative;
+	padding-bottom: 1.7em;
+}
+.bp-groups-member-type > h4 {
+	margin-bottom: .5em;
+}
+ul.bp-group-delete-list {
+	list-style-type: disc;
+	margin: 4px 26px;
+}
+.bp-group-admin-pagination {
+	position: absolute;
+	text-align: right;
+	width: 100%;
+}
+.bp-group-admin-pagination.table-top {
+	top: 0;
+}
+.bp-group-admin-pagination.table-bottom {
+	bottom: 0;
+}
+.bp-group-admin-pagination-viewing {
+	font-family: Georgia, "Times New Roman", "Bitstream Charter", Times, serif;
+	color: #777;
+	font-size: 12px;
+	font-style: italic;
+}
+.bp-group-admin-pagination-links {
+	white-space: nowrap;
+	padding-left: 15px;
+}
Index: /tags/1.9/bp-groups/admin/css/admin.min.css
===================================================================
--- /tags/1.9/bp-groups/admin/css/admin.min.css	(revision 7684)
+++ /tags/1.9/bp-groups/admin/css/admin.min.css	(revision 7684)
@@ -0,0 +1,1 @@
+body.toplevel_page_bp-groups table.groups th#status,body.toplevel_page_bp-groups table.groups th#members{width:10%}body.toplevel_page_bp-groups table.groups th#last_active{width:15%}#bp-groups-edit-form input{outline:medium none;padding:3px 8px}#bp-groups-edit-form input#bp-groups-name{font-size:1.7em;width:100%}#bp-groups-edit-form input#bp-groups-new-members{width:100%;max-width:90%;border:0}.bp-groups-settings-section{margin-bottom:15px}.bp-groups-member-type{position:relative;padding-bottom:1.7em}.bp-groups-member-type>h4{margin-bottom:.5em}ul.bp-group-delete-list{list-style-type:disc;margin:4px 26px}.bp-group-admin-pagination{position:absolute;text-align:right;width:100%}.bp-group-admin-pagination.table-top{top:0}.bp-group-admin-pagination.table-bottom{bottom:0}.bp-group-admin-pagination-viewing{font-family:Georgia,"Times New Roman","Bitstream Charter",Times,serif;color:#777;font-size:12px;font-style:italic}.bp-group-admin-pagination-links{white-space:nowrap;padding-left:15px}
Index: /tags/1.9/bp-groups/admin/js/admin.js
===================================================================
--- /tags/1.9/bp-groups/admin/js/admin.js	(revision 7684)
+++ /tags/1.9/bp-groups/admin/js/admin.js	(revision 7684)
@@ -0,0 +1,47 @@
+(function($) {
+	function add_member_to_list( e, ui ) {
+		var remove_id = 'bp-groups-remove-new-member-' + ui.item.value;
+		$('#bp-groups-new-members-list').append('<li><a href="#" class="bp-groups-remove-new-member" id="' + remove_id + '">x</a> ' + ui.item.label + '</li>');
+		$('#' + remove_id).bind('click', function(e) { remove_member_from_list(e); return false; });
+
+		$('#bp-groups-new-members-list').after('<input name="new_members[]" type="hidden" value="' + ui.item.value + '" />');
+	}
+
+	function remove_member_from_list( e ) {
+		$(e.target).closest('li').remove();
+	}
+
+	var id = 'undefined' !== typeof group_id ? '&group_id=' + group_id : '';
+	$(document).ready( function() {
+		window.warn_on_leave = false;
+
+		/* Initialize autocomplete */
+		$( '.bp-suggest-user' ).autocomplete({
+			source:    ajaxurl + '?action=bp_group_admin_member_autocomplete' + id,
+			delay:     500,
+			minLength: 2,
+			position:  ( 'undefined' !== typeof isRtl && isRtl ) ? { my: 'right top', at: 'right bottom', offset: '0, -1' } : { offset: '0, -1' },
+			open:      function() { $(this).addClass('open'); },
+			close:     function() { $(this).removeClass('open'); $(this).val(''); },
+			select:    function( event, ui ) { add_member_to_list( event, ui ); }
+		});
+		
+		/* Replace noscript placeholder */
+		$( '#bp-groups-new-members' ).attr( 'placeholder', BP_Group_Admin.add_member_placeholder );
+
+		/* Warn before leaving unsaved changes */
+		$(document).on( 'change', 'input#bp-groups-name, input#bp-groups-description, select.bp-groups-role, #bp-groups-settings-section-status input[type="radio"]', function() {
+			window.warn_on_leave = true;
+		});
+
+		$( 'input#save' ).on( 'click', function() {
+			window.warn_on_leave = false;
+		});
+
+		window.onbeforeunload = function(e) {
+			if ( window.warn_on_leave ) {
+				return BP_Group_Admin.warn_on_leave;
+			}
+		};
+	});
+})(jQuery);
Index: /tags/1.9/bp-groups/admin/js/admin.min.js
===================================================================
--- /tags/1.9/bp-groups/admin/js/admin.min.js	(revision 7684)
+++ /tags/1.9/bp-groups/admin/js/admin.min.js	(revision 7684)
@@ -0,0 +1,1 @@
+(function(c){function b(h,f){var g="bp-groups-remove-new-member-"+f.item.value;c("#bp-groups-new-members-list").append('<li><a href="#" class="bp-groups-remove-new-member" id="'+g+'">x</a> '+f.item.label+"</li>");c("#"+g).bind("click",function(i){a(i);return false});c("#bp-groups-new-members-list").after('<input name="new_members[]" type="hidden" value="'+f.item.value+'" />')}function a(f){c(f.target).closest("li").remove()}var d="undefined"!==typeof group_id?"&group_id="+group_id:"";c(document).ready(function(){window.warn_on_leave=false;c(".bp-suggest-user").autocomplete({source:ajaxurl+"?action=bp_group_admin_member_autocomplete"+d,delay:500,minLength:2,position:("undefined"!==typeof isRtl&&isRtl)?{my:"right top",at:"right bottom",offset:"0, -1"}:{offset:"0, -1"},open:function(){c(this).addClass("open")},close:function(){c(this).removeClass("open");c(this).val("")},select:function(e,f){b(e,f)}});c("#bp-groups-new-members").attr("placeholder",BP_Group_Admin.add_member_placeholder);c(document).on("change",'input#bp-groups-name, input#bp-groups-description, select.bp-groups-role, #bp-groups-settings-section-status input[type="radio"]',function(){window.warn_on_leave=true});c("input#save").on("click",function(){window.warn_on_leave=false});window.onbeforeunload=function(f){if(window.warn_on_leave){return BP_Group_Admin.warn_on_leave}}})})(jQuery);
Index: /tags/1.9/bp-groups/bp-groups-actions.php
===================================================================
--- /tags/1.9/bp-groups/bp-groups-actions.php	(revision 7684)
+++ /tags/1.9/bp-groups/bp-groups-actions.php	(revision 7684)
@@ -0,0 +1,367 @@
+<?php
+
+/**
+ * BuddyPress Groups Actions
+ *
+ * Action functions are exactly the same as screen functions, however they do
+ * not have a template screen associated with them. Usually they will send the
+ * user back to the default screen after execution.
+ *
+ * @package BuddyPress
+ * @subpackage GroupsActions
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/**
+ * Catch and process group creation form submissions.
+ */
+function groups_action_create_group() {
+	global $bp;
+
+	// If we're not at domain.org/groups/create/ then return false
+	if ( !bp_is_groups_component() || !bp_is_current_action( 'create' ) )
+		return false;
+
+	if ( !is_user_logged_in() )
+		return false;
+
+ 	if ( !bp_user_can_create_groups() ) {
+		bp_core_add_message( __( 'Sorry, you are not allowed to create groups.', 'buddypress' ), 'error' );
+		bp_core_redirect( trailingslashit( bp_get_root_domain() . '/' . bp_get_groups_root_slug() ) );
+	}
+
+	// Make sure creation steps are in the right order
+	groups_action_sort_creation_steps();
+
+	// If no current step is set, reset everything so we can start a fresh group creation
+	$bp->groups->current_create_step = bp_action_variable( 1 );
+	if ( !bp_get_groups_current_create_step() ) {
+		unset( $bp->groups->current_create_step );
+		unset( $bp->groups->completed_create_steps );
+
+		setcookie( 'bp_new_group_id', false, time() - 1000, COOKIEPATH );
+		setcookie( 'bp_completed_create_steps', false, time() - 1000, COOKIEPATH );
+
+		$reset_steps = true;
+		$keys        = array_keys( $bp->groups->group_creation_steps );
+		bp_core_redirect( bp_get_root_domain() . '/' . bp_get_groups_root_slug() . '/create/step/' . array_shift( $keys ) . '/' );
+	}
+
+	// If this is a creation step that is not recognized, just redirect them back to the first screen
+	if ( bp_get_groups_current_create_step() && empty( $bp->groups->group_creation_steps[bp_get_groups_current_create_step()] ) ) {
+		bp_core_add_message( __('There was an error saving group details. Please try again.', 'buddypress'), 'error' );
+		bp_core_redirect( bp_get_root_domain() . '/' . bp_get_groups_root_slug() . '/create/' );
+	}
+
+	// Fetch the currently completed steps variable
+	if ( isset( $_COOKIE['bp_completed_create_steps'] ) && !isset( $reset_steps ) )
+		$bp->groups->completed_create_steps = unserialize( stripslashes( $_COOKIE['bp_completed_create_steps'] ) );
+
+	// Set the ID of the new group, if it has already been created in a previous step
+	if ( isset( $_COOKIE['bp_new_group_id'] ) ) {
+		$bp->groups->new_group_id = $_COOKIE['bp_new_group_id'];
+		$bp->groups->current_group = groups_get_group( array( 'group_id' => $bp->groups->new_group_id ) );
+	}
+
+	// If the save, upload or skip button is hit, lets calculate what we need to save
+	if ( isset( $_POST['save'] ) ) {
+
+		// Check the nonce
+		check_admin_referer( 'groups_create_save_' . bp_get_groups_current_create_step() );
+
+		if ( 'group-details' == bp_get_groups_current_create_step() ) {
+			if ( empty( $_POST['group-name'] ) || empty( $_POST['group-desc'] ) || !strlen( trim( $_POST['group-name'] ) ) || !strlen( trim( $_POST['group-desc'] ) ) ) {
+				bp_core_add_message( __( 'Please fill in all of the required fields', 'buddypress' ), 'error' );
+				bp_core_redirect( bp_get_root_domain() . '/' . bp_get_groups_root_slug() . '/create/step/' . bp_get_groups_current_create_step() . '/' );
+			}
+
+			$new_group_id = isset( $bp->groups->new_group_id ) ? $bp->groups->new_group_id : 0;
+
+			if ( !$bp->groups->new_group_id = groups_create_group( array( 'group_id' => $new_group_id, 'name' => $_POST['group-name'], 'description' => $_POST['group-desc'], 'slug' => groups_check_slug( sanitize_title( esc_attr( $_POST['group-name'] ) ) ), 'date_created' => bp_core_current_time(), 'status' => 'public' ) ) ) {
+				bp_core_add_message( __( 'There was an error saving group details, please try again.', 'buddypress' ), 'error' );
+				bp_core_redirect( bp_get_root_domain() . '/' . bp_get_groups_root_slug() . '/create/step/' . bp_get_groups_current_create_step() . '/' );
+			}
+		}
+
+		if ( 'group-settings' == bp_get_groups_current_create_step() ) {
+			$group_status = 'public';
+			$group_enable_forum = 1;
+
+			if ( !isset($_POST['group-show-forum']) ) {
+				$group_enable_forum = 0;
+			} else {
+				// Create the forum if enable_forum = 1
+				if ( bp_is_active( 'forums' ) && !groups_get_groupmeta( $bp->groups->new_group_id, 'forum_id' ) ) {
+					groups_new_group_forum();
+				}
+			}
+
+			if ( 'private' == $_POST['group-status'] )
+				$group_status = 'private';
+			else if ( 'hidden' == $_POST['group-status'] )
+				$group_status = 'hidden';
+
+			if ( !$bp->groups->new_group_id = groups_create_group( array( 'group_id' => $bp->groups->new_group_id, 'status' => $group_status, 'enable_forum' => $group_enable_forum ) ) ) {
+				bp_core_add_message( __( 'There was an error saving group details, please try again.', 'buddypress' ), 'error' );
+				bp_core_redirect( bp_get_root_domain() . '/' . bp_get_groups_root_slug() . '/create/step/' . bp_get_groups_current_create_step() . '/' );
+			}
+
+			// Set the invite status
+			// Checked against a whitelist for security
+			$allowed_invite_status = apply_filters( 'groups_allowed_invite_status', array( 'members', 'mods', 'admins' ) );
+			$invite_status	       = !empty( $_POST['group-invite-status'] ) && in_array( $_POST['group-invite-status'], (array) $allowed_invite_status ) ? $_POST['group-invite-status'] : 'members';
+
+			groups_update_groupmeta( $bp->groups->new_group_id, 'invite_status', $invite_status );
+		}
+
+		if ( 'group-invites' == bp_get_groups_current_create_step() )
+			groups_send_invites( bp_loggedin_user_id(), $bp->groups->new_group_id );
+
+		do_action( 'groups_create_group_step_save_' . bp_get_groups_current_create_step() );
+		do_action( 'groups_create_group_step_complete' ); // Mostly for clearing cache on a generic action name
+
+		/**
+		 * Once we have successfully saved the details for this step of the creation process
+		 * we need to add the current step to the array of completed steps, then update the cookies
+		 * holding the information
+		 */
+		$completed_create_steps = isset( $bp->groups->completed_create_steps ) ? $bp->groups->completed_create_steps : array();
+		if ( !in_array( bp_get_groups_current_create_step(), $completed_create_steps ) )
+			$bp->groups->completed_create_steps[] = bp_get_groups_current_create_step();
+
+		// Reset cookie info
+		setcookie( 'bp_new_group_id', $bp->groups->new_group_id, time()+60*60*24, COOKIEPATH );
+		setcookie( 'bp_completed_create_steps', serialize( $bp->groups->completed_create_steps ), time()+60*60*24, COOKIEPATH );
+
+		// If we have completed all steps and hit done on the final step we
+		// can redirect to the completed group
+		$keys = array_keys( $bp->groups->group_creation_steps );
+		if ( count( $bp->groups->completed_create_steps ) == count( $keys ) && bp_get_groups_current_create_step() == array_pop( $keys ) ) {
+			unset( $bp->groups->current_create_step );
+			unset( $bp->groups->completed_create_steps );
+
+			// Once we compelete all steps, record the group creation in the activity stream.
+			groups_record_activity( array(
+				'action' => apply_filters( 'groups_activity_created_group_action', sprintf( __( '%1$s created the group %2$s', 'buddypress'), bp_core_get_userlink( bp_loggedin_user_id() ), '<a href="' . bp_get_group_permalink( $bp->groups->current_group ) . '">' . esc_attr( $bp->groups->current_group->name ) . '</a>' ) ),
+				'type' => 'created_group',
+				'item_id' => $bp->groups->new_group_id
+			) );
+
+			do_action( 'groups_group_create_complete', $bp->groups->new_group_id );
+
+			bp_core_redirect( bp_get_group_permalink( $bp->groups->current_group ) );
+		} else {
+			/**
+			 * Since we don't know what the next step is going to be (any plugin can insert steps)
+			 * we need to loop the step array and fetch the next step that way.
+			 */
+			foreach ( $keys as $key ) {
+				if ( $key == bp_get_groups_current_create_step() ) {
+					$next = 1;
+					continue;
+				}
+
+				if ( isset( $next ) ) {
+					$next_step = $key;
+					break;
+				}
+			}
+
+			bp_core_redirect( bp_get_root_domain() . '/' . bp_get_groups_root_slug() . '/create/step/' . $next_step . '/' );
+		}
+	}
+
+	// Group avatar is handled separately
+	if ( 'group-avatar' == bp_get_groups_current_create_step() && isset( $_POST['upload'] ) ) {
+		if ( ! isset( $bp->avatar_admin ) ) {
+			$bp->avatar_admin = new stdClass();
+		}
+
+		if ( !empty( $_FILES ) && isset( $_POST['upload'] ) ) {
+			// Normally we would check a nonce here, but the group save nonce is used instead
+
+			// Pass the file to the avatar upload handler
+			if ( bp_core_avatar_handle_upload( $_FILES, 'groups_avatar_upload_dir' ) ) {
+				$bp->avatar_admin->step = 'crop-image';
+
+				// Make sure we include the jQuery jCrop file for image cropping
+				add_action( 'wp_print_scripts', 'bp_core_add_jquery_cropper' );
+			}
+		}
+
+		// If the image cropping is done, crop the image and save a full/thumb version
+		if ( isset( $_POST['avatar-crop-submit'] ) && isset( $_POST['upload'] ) ) {
+			// Normally we would check a nonce here, but the group save nonce is used instead
+
+			if ( !bp_core_avatar_handle_crop( array( 'object' => 'group', 'avatar_dir' => 'group-avatars', 'item_id' => $bp->groups->current_group->id, 'original_file' => $_POST['image_src'], 'crop_x' => $_POST['x'], 'crop_y' => $_POST['y'], 'crop_w' => $_POST['w'], 'crop_h' => $_POST['h'] ) ) )
+				bp_core_add_message( __( 'There was an error saving the group avatar, please try uploading again.', 'buddypress' ), 'error' );
+			else
+				bp_core_add_message( __( 'The group avatar was uploaded successfully!', 'buddypress' ) );
+		}
+	}
+
+	bp_core_load_template( apply_filters( 'groups_template_create_group', 'groups/create' ) );
+}
+add_action( 'bp_actions', 'groups_action_create_group' );
+
+function groups_action_join_group() {
+	global $bp;
+
+	if ( !bp_is_single_item() || !bp_is_groups_component() || !bp_is_current_action( 'join' ) )
+		return false;
+
+	// Nonce check
+	if ( !check_admin_referer( 'groups_join_group' ) )
+		return false;
+
+	// Skip if banned or already a member
+	if ( !groups_is_user_member( bp_loggedin_user_id(), $bp->groups->current_group->id ) && !groups_is_user_banned( bp_loggedin_user_id(), $bp->groups->current_group->id ) ) {
+
+		// User wants to join a group that is not public
+		if ( $bp->groups->current_group->status != 'public' ) {
+			if ( !groups_check_user_has_invite( bp_loggedin_user_id(), $bp->groups->current_group->id ) ) {
+				bp_core_add_message( __( 'There was an error joining the group.', 'buddypress' ), 'error' );
+				bp_core_redirect( bp_get_group_permalink( $bp->groups->current_group ) );
+			}
+		}
+
+		// User wants to join any group
+		if ( !groups_join_group( $bp->groups->current_group->id ) )
+			bp_core_add_message( __( 'There was an error joining the group.', 'buddypress' ), 'error' );
+		else
+			bp_core_add_message( __( 'You joined the group!', 'buddypress' ) );
+
+		bp_core_redirect( bp_get_group_permalink( $bp->groups->current_group ) );
+	}
+
+	bp_core_load_template( apply_filters( 'groups_template_group_home', 'groups/single/home' ) );
+}
+add_action( 'bp_actions', 'groups_action_join_group' );
+
+/**
+ * Catch and process "Leave Group" button clicks.
+ *
+ * When a group member clicks on the "Leave Group" button from a group's page,
+ * this function is run.
+ *
+ * Note: When leaving a group from the group directory, AJAX is used and
+ * another function handles this. See {@link bp_legacy_theme_ajax_joinleave_group()}.
+ *
+ * @since BuddyPress (1.2.4)
+ */
+function groups_action_leave_group() {
+	if ( ! bp_is_single_item() || ! bp_is_groups_component() || ! bp_is_current_action( 'leave-group' ) ) {
+		return false;
+	}
+
+	// Nonce check
+	if ( ! check_admin_referer( 'groups_leave_group' ) ) {
+		return false;
+	}
+
+	// User wants to leave any group
+	if ( groups_is_user_member( bp_loggedin_user_id(), bp_get_current_group_id() ) ) {
+		$bp = buddypress();
+
+		// Stop sole admins from abandoning their group
+		$group_admins = groups_get_group_admins( bp_get_current_group_id() );
+
+	 	if ( 1 == count( $group_admins ) && $group_admins[0]->user_id == bp_loggedin_user_id() ) {
+			bp_core_add_message( __( 'This group must have at least one admin', 'buddypress' ), 'error' );
+		} elseif ( ! groups_leave_group( $bp->groups->current_group->id ) ) {
+			bp_core_add_message( __( 'There was an error leaving the group.', 'buddypress' ), 'error' );
+		} else {
+			bp_core_add_message( __( 'You successfully left the group.', 'buddypress' ) );
+		}
+			
+		$redirect = bp_get_group_permalink( groups_get_current_group() );
+		
+		if( 'hidden' == $bp->groups->current_group->status ) {
+			$redirect = trailingslashit( bp_loggedin_user_domain() . bp_get_groups_slug() );
+		}
+
+		bp_core_redirect( $redirect );
+	}
+
+	bp_core_load_template( apply_filters( 'groups_template_group_home', 'groups/single/home' ) );
+}
+add_action( 'bp_actions', 'groups_action_leave_group' );
+
+/**
+ * Sort the group creation steps.
+ */
+function groups_action_sort_creation_steps() {
+	global $bp;
+
+	if ( !bp_is_groups_component() || !bp_is_current_action( 'create' ) )
+		return false;
+
+	if ( !is_array( $bp->groups->group_creation_steps ) )
+		return false;
+
+	foreach ( (array) $bp->groups->group_creation_steps as $slug => $step ) {
+		while ( !empty( $temp[$step['position']] ) )
+			$step['position']++;
+
+		$temp[$step['position']] = array( 'name' => $step['name'], 'slug' => $slug );
+	}
+
+	// Sort the steps by their position key
+	ksort($temp);
+	unset($bp->groups->group_creation_steps);
+
+	foreach( (array) $temp as $position => $step )
+		$bp->groups->group_creation_steps[$step['slug']] = array( 'name' => $step['name'], 'position' => $position );
+}
+
+/**
+ * Catch requests for a random group page (example.com/groups/?random-group) and redirect.
+ */
+function groups_action_redirect_to_random_group() {
+
+	if ( bp_is_groups_component() && isset( $_GET['random-group'] ) ) {
+		$group = BP_Groups_Group::get_random( 1, 1 );
+
+		bp_core_redirect( bp_get_root_domain() . '/' . bp_get_groups_root_slug() . '/' . $group['groups'][0]->slug . '/' );
+	}
+}
+add_action( 'bp_actions', 'groups_action_redirect_to_random_group' );
+
+/**
+ * Load the activity feed for the current group.
+ *
+ * @since BuddyPress (1.2.0)
+ */
+function groups_action_group_feed() {
+
+	// get current group
+	$group = groups_get_current_group();
+
+	if ( ! bp_is_active( 'activity' ) || ! bp_is_groups_component() || ! $group || ! bp_is_current_action( 'feed' ) )
+		return false;
+
+	// if group isn't public or if logged-in user is not a member of the group, do
+	// not output the group activity feed
+	if ( ! bp_group_is_visible( $group ) ) {
+		return false;
+	}
+
+	// setup the feed
+	buddypress()->activity->feed = new BP_Activity_Feed( array(
+		'id'            => 'group',
+
+		/* translators: Group activity RSS title - "[Site Name] | [Group Name] | Activity" */
+		'title'         => sprintf( __( '%1$s | %2$s | Activity', 'buddypress' ), bp_get_site_name(), bp_get_current_group_name() ),
+
+		'link'          => bp_get_group_permalink( $group ),
+		'description'   => sprintf( __( "Activity feed for the group, %s.", 'buddypress' ), bp_get_current_group_name() ),
+		'activity_args' => array(
+			'object'           => buddypress()->groups->id,
+			'primary_id'       => bp_get_current_group_id(),
+			'display_comments' => 'threaded'
+		)
+	) );
+}
+add_action( 'bp_actions', 'groups_action_group_feed' );
Index: /tags/1.9/bp-groups/bp-groups-activity.php
===================================================================
--- /tags/1.9/bp-groups/bp-groups-activity.php	(revision 7684)
+++ /tags/1.9/bp-groups/bp-groups-activity.php	(revision 7684)
@@ -0,0 +1,195 @@
+<?php
+
+/**
+ * BuddyPress Groups Activity Functions
+ *
+ * These functions handle the recording, deleting and formatting of activity
+ * for the user and for this specific component.
+ *
+ * @package BuddyPress
+ * @subpackage GroupsActivity
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/**
+ * Register activity actions for the Groups component.
+ */
+function groups_register_activity_actions() {
+	global $bp;
+
+	if ( ! bp_is_active( 'activity' ) ) {
+		return false;
+	}
+
+	bp_activity_set_action( $bp->groups->id, 'created_group',   __( 'Created a group',       'buddypress' ) );
+	bp_activity_set_action( $bp->groups->id, 'joined_group',    __( 'Joined a group',        'buddypress' ) );
+
+	// These actions are for the legacy forums
+	// Since the bbPress plugin also shares the same 'forums' identifier, we also
+	// check for the legacy forums loader class to be extra cautious
+	if ( bp_is_active( 'forums' ) && class_exists( 'BP_Forums_Component' ) ) {
+		bp_activity_set_action( $bp->groups->id, 'new_forum_topic', __( 'New group forum topic', 'buddypress' ) );
+		bp_activity_set_action( $bp->groups->id, 'new_forum_post',  __( 'New group forum post',  'buddypress' ) );
+	}
+
+	do_action( 'groups_register_activity_actions' );
+}
+add_action( 'bp_register_activity_actions', 'groups_register_activity_actions' );
+
+/**
+ * Record an activity item related to the Groups component.
+ *
+ * A wrapper for {@link bp_activity_add()} that provides some Groups-specific
+ * defaults.
+ *
+ * @see bp_activity_add() for more detailed description of parameters and
+ *      return values.
+ *
+ * @param array $args {
+ *     An array of arguments for the new activity item. Accepts all parameters
+ *     of {@link bp_activity_add()}. However, this wrapper provides some
+ *     additional defaults, as described below:
+ *     @type string $component Default: the id of your Groups component
+ *           (usually 'groups').
+ *     @type bool $hide_sitewide Default: True if the current group is not
+ *           public, otherwise false.
+ * }
+ * @return bool See {@link bp_activity_add()}.
+ */
+function groups_record_activity( $args = '' ) {
+
+	if ( ! bp_is_active( 'activity' ) ) {
+		return false;
+	}
+
+	// Set the default for hide_sitewide by checking the status of the group
+	$hide_sitewide = false;
+	if ( !empty( $args['item_id'] ) ) {
+		if ( bp_get_current_group_id() == $args['item_id'] ) {
+			$group = groups_get_current_group();
+		} else {
+			$group = groups_get_group( array( 'group_id' => $args['item_id'] ) );
+		}
+
+		if ( isset( $group->status ) && 'public' != $group->status ) {
+			$hide_sitewide = true;
+		}
+	}
+
+	$r = wp_parse_args( $args, array(
+		'id'                => false,
+		'user_id'           => bp_loggedin_user_id(),
+		'action'            => '',
+		'content'           => '',
+		'primary_link'      => '',
+		'component'         => buddypress()->groups->id,
+		'type'              => false,
+		'item_id'           => false,
+		'secondary_item_id' => false,
+		'recorded_time'     => bp_core_current_time(),
+		'hide_sitewide'     => $hide_sitewide
+	) );
+
+	return bp_activity_add( $r );
+}
+
+/**
+ * Update the last_activity meta value for a given group.
+ *
+ * @param int $group_id Optional. The ID of the group whose last_activity is
+ *        being updated. Default: the current group's ID.
+ */
+function groups_update_last_activity( $group_id = 0 ) {
+
+	if ( empty( $group_id ) ) {
+		$group_id = buddypress()->groups->current_group->id;
+	}
+
+	if ( empty( $group_id ) ) {
+		return false;
+	}
+
+	groups_update_groupmeta( $group_id, 'last_activity', bp_core_current_time() );
+}
+add_action( 'groups_leave_group',          'groups_update_last_activity' );
+add_action( 'groups_created_group',        'groups_update_last_activity' );
+add_action( 'groups_new_forum_topic',      'groups_update_last_activity' );
+add_action( 'groups_new_forum_topic_post', 'groups_update_last_activity' );
+
+/**
+ * Add an activity stream item when a member joins a group
+ *
+ * @since BuddyPress (1.9.0)
+ * @param int $user_id
+ * @param int $group_id
+ */
+function bp_groups_membership_accepted_add_activity( $user_id, $group_id ) {
+
+	// Bail if Activity is not active
+	if ( ! bp_is_active( 'activity' ) ) {
+		return false;
+	}
+
+	// Get the group so we can get it's name
+	$group = groups_get_group( array( 'group_id' => $group_id ) );
+
+	// Record in activity streams
+	groups_record_activity( array(
+		'action'  => apply_filters_ref_array( 'groups_activity_membership_accepted_action', array( sprintf( __( '%1$s joined the group %2$s', 'buddypress' ), bp_core_get_userlink( $user_id ), '<a href="' . bp_get_group_permalink( $group ) . '">' . esc_attr( $group->name ) . '</a>' ), $user_id, &$group ) ),
+		'type'    => 'joined_group',
+		'item_id' => $group_id,
+		'user_id' => $user_id
+	) );	
+}
+add_action( 'groups_membership_accepted', 'bp_groups_membership_accepted_add_activity', 10, 2 );
+
+/**
+ * Delete all group activity from activity streams
+ *
+ * @since BuddyPress (1.9.0)
+ */
+function bp_groups_delete_group_delete_all_activity( $group_id ) {
+	if ( bp_is_active( 'activity' ) ) {
+		bp_activity_delete_by_item_id( array(
+			'item_id'   => $group_id,
+			'component' => buddypress()->groups->id
+		) );
+	}
+}
+add_action( 'groups_delete_group', 'bp_groups_delete_group_delete_all_activity', 10 );
+
+/**
+ * Delete group member activity if they leave or are removed within 5 minutes of
+ * membership modification.
+ *
+ * If the user joined this group less than five minutes ago, remove the
+ * joined_group activity so users cannot flood the activity stream by
+ * joining/leaving the group in quick succession.
+ *
+ * @since BuddyPress (1.9.0)
+ */
+function bp_groups_leave_group_delete_recent_activity( $group_id, $user_id ) {
+
+	// Bail if Activity component is not active
+	if ( ! bp_is_active( 'activity' ) ) {
+		return;
+	}
+
+	// Get the member's group membership information
+	$membership = new BP_Groups_Member( $user_id, $group_id );
+
+	// Check the time period, and maybe delete their recent group activity
+	if ( time() <= strtotime( '+5 minutes', (int) strtotime( $membership->date_modified ) ) ) {
+		bp_activity_delete( array(
+			'component' => buddypress()->groups->id,
+			'type'      => 'joined_group',
+			'user_id'   => $user_id,
+			'item_id'   => $group_id
+		) );
+	}
+}
+add_action( 'groups_leave_group',   'bp_groups_leave_group_delete_recent_activity', 10, 2 );
+add_action( 'groups_remove_member', 'bp_groups_leave_group_delete_recent_activity', 10, 2 );
+add_action( 'groups_ban_member',    'bp_groups_leave_group_delete_recent_activity', 10, 2 );
Index: /tags/1.9/bp-groups/bp-groups-admin.php
===================================================================
--- /tags/1.9/bp-groups/bp-groups-admin.php	(revision 7684)
+++ /tags/1.9/bp-groups/bp-groups-admin.php	(revision 7684)
@@ -0,0 +1,1478 @@
+<?php
+/**
+ * BuddyPress Groups component admin screen
+ *
+ * Props to WordPress core for the Comments admin screen, and its contextual
+ * help text, on which this implementation is heavily based.
+ *
+ * @package BuddyPress
+ * @since BuddyPress (1.7.0)
+ * @subpackage Groups
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+// Include WP's list table class
+if ( !class_exists( 'WP_List_Table' ) ) require( ABSPATH . 'wp-admin/includes/class-wp-list-table.php' );
+
+// per_page screen option. Has to be hooked in extremely early.
+if ( is_admin() && ! empty( $_REQUEST['page'] ) && 'bp-groups' == $_REQUEST['page'] )
+	add_filter( 'set-screen-option', 'bp_groups_admin_screen_options', 10, 3 );
+
+/**
+ * Register the Groups component admin screen.
+ *
+ * @since BuddyPress (1.7.0)
+ */
+function bp_groups_add_admin_menu() {
+
+	// Add our screen
+	$hook = add_menu_page(
+		__( 'Groups', 'buddypress' ),
+		__( 'Groups', 'buddypress' ),
+		'bp_moderate',
+		'bp-groups',
+		'bp_groups_admin',
+		'div'
+	);
+
+	// Hook into early actions to load custom CSS and our init handler.
+	add_action( "load-$hook", 'bp_groups_admin_load' );
+}
+add_action( bp_core_admin_hook(), 'bp_groups_add_admin_menu' );
+
+/**
+ * Add groups component to custom menus array.
+ *
+ * This ensures that the Groups menu item appears in the proper order on the
+ * main Dashboard menu.
+ *
+ * @since BuddyPress (1.7.0)
+ *
+ * @param array $custom_menus Array of BP top-level menu items.
+ * @return array Menu item array, with Groups added.
+ */
+function bp_groups_admin_menu_order( $custom_menus = array() ) {
+	array_push( $custom_menus, 'bp-groups' );
+	return $custom_menus;
+}
+add_filter( 'bp_admin_menu_order', 'bp_groups_admin_menu_order' );
+
+/**
+ * Set up the Groups admin page.
+ *
+ * Loaded before the page is rendered, this function does all initial setup,
+ * including: processing form requests, registering contextual help, and
+ * setting up screen options.
+ *
+ * @since BuddyPress (1.7.0)
+ *
+ * @global object $bp BuddyPress global settings
+ * @global BP_Groups_List_Table $bp_groups_list_table Groups screen list table
+ */
+function bp_groups_admin_load() {
+	global $bp_groups_list_table;
+
+	// Build redirection URL
+	$redirect_to = remove_query_arg( array( 'action', 'action2', 'gid', 'deleted', 'error', 'updated', 'success_new', 'error_new', 'success_modified', 'error_modified' ), $_SERVER['REQUEST_URI'] );
+
+	// Decide whether to load the dev version of the CSS and JavaScript
+	$min = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : 'min.';
+
+	$doaction = bp_admin_list_table_current_bulk_action();
+
+	// Call an action for plugins to hook in early
+	do_action( 'bp_groups_admin_load', $doaction );
+
+	// Edit screen
+	if ( 'do_delete' == $doaction && ! empty( $_GET['gid'] ) ) {
+
+		check_admin_referer( 'bp-groups-delete' );
+
+		$group_ids = wp_parse_id_list( $_GET['gid'] );
+
+		$count = 0;
+		foreach ( $group_ids as $group_id ) {
+			if ( groups_delete_group( $group_id ) ) {
+				$count++;
+			}
+		}
+
+		$redirect_to = add_query_arg( 'deleted', $count, $redirect_to );
+
+		bp_core_redirect( $redirect_to );
+
+	} else if ( 'edit' == $doaction && ! empty( $_GET['gid'] ) ) {
+		// columns screen option
+		add_screen_option( 'layout_columns', array( 'default' => 2, 'max' => 2, ) );
+
+		get_current_screen()->add_help_tab( array(
+			'id'      => 'bp-group-edit-overview',
+			'title'   => __( 'Overview', 'buddypress' ),
+			'content' =>
+				'<p>' . __( 'This page is a convenient way to edit the details associated with one of your groups.', 'buddypress' ) . '</p>' .
+				'<p>' . __( 'The Name and Description box is fixed in place, but you can reposition all the other boxes using drag and drop, and can minimize or expand them by clicking the title bar of each box. Use the Screen Options tab to hide or unhide, or to choose a 1- or 2-column layout for this screen.', 'buddypress' ) . '</p>'
+		) );
+
+		// Help panel - sidebar links
+		get_current_screen()->set_help_sidebar(
+			'<p><strong>' . __( 'For more information:', 'buddypress' ) . '</strong></p>' .
+			'<p><a href="http://buddypress.org/support">' . __( 'Support Forums', 'buddypress' ) . '</a></p>'
+		);
+
+		// Register metaboxes for the edit screen.
+		add_meta_box( 'submitdiv', _x( 'Save', 'group admin edit screen', 'buddypress' ), 'bp_groups_admin_edit_metabox_status', get_current_screen()->id, 'side', 'high' );
+		add_meta_box( 'bp_group_settings', _x( 'Settings', 'group admin edit screen', 'buddypress' ), 'bp_groups_admin_edit_metabox_settings', get_current_screen()->id, 'side', 'core' );
+		add_meta_box( 'bp_group_add_members', _x( 'Add New Members', 'group admin edit screen', 'buddypress' ), 'bp_groups_admin_edit_metabox_add_new_members', get_current_screen()->id, 'normal', 'core' );
+		add_meta_box( 'bp_group_members', _x( 'Manage Members', 'group admin edit screen', 'buddypress' ), 'bp_groups_admin_edit_metabox_members', get_current_screen()->id, 'normal', 'core' );
+
+		do_action( 'bp_groups_admin_meta_boxes' );
+
+		// Enqueue javascripts
+		wp_enqueue_script( 'postbox' );
+		wp_enqueue_script( 'dashboard' );
+		wp_enqueue_script( 'comment' );
+
+	// Index screen
+	} else {
+		// Create the Groups screen list table
+		$bp_groups_list_table = new BP_Groups_List_Table();
+
+		// per_page screen option
+		add_screen_option( 'per_page', array( 'label' => _x( 'Groups', 'Groups per page (screen options)', 'buddypress' )) );
+
+		// Help panel - overview text
+		get_current_screen()->add_help_tab( array(
+			'id'      => 'bp-groups-overview',
+			'title'   => __( 'Overview', 'buddypress' ),
+			'content' =>
+				'<p>' . __( 'You can manage groups much like you can manage comments and other content. This screen is customizable in the same ways as other management screens, and you can act on groups by using the on-hover action links or the Bulk Actions.', 'buddypress' ) . '</p>',
+		) );
+
+		get_current_screen()->add_help_tab( array(
+			'id'      => 'bp-groups-overview-actions',
+			'title'   => __( 'Group Actions', 'buddypress' ),
+			'content' =>
+				'<p>' . __( 'Clicking "Visit" will take you to the group&#8217;s public page. Use this link to see what the group looks like on the front end of your site.', 'buddypress' ) . '</p>' .
+				'<p>' . __( 'Clicking "Edit" will take you to a Dashboard panel where you can manage various details about the group, such as its name and description, its members, and other settings.', 'buddypress' ) . '</p>' .
+				'<p>' . __( 'If you click "Delete" under a specific group, or select a number of groups and then choose Delete from the Bulk Actions menu, you will be led to a page where you&#8217;ll be asked to confirm the permanent deletion of the group(s).', 'buddypress' ) . '</p>',
+		) );
+
+		// Help panel - sidebar links
+		get_current_screen()->set_help_sidebar(
+			'<p><strong>' . __( 'For more information:', 'buddypress' ) . '</strong></p>' .
+			'<p>' . __( '<a href="http://buddypress.org/support/">Support Forums</a>', 'buddypress' ) . '</p>'
+		);
+	}
+
+	// Enqueue CSS and JavaScript
+	wp_enqueue_script( 'bp_groups_admin_js', BP_PLUGIN_URL . "bp-groups/admin/js/admin.{$min}js", array( 'jquery', 'wp-ajax-response', 'jquery-ui-autocomplete' ), bp_get_version(), true );
+	wp_enqueue_style( 'bp_groups_admin_css', BP_PLUGIN_URL . "bp-groups/admin/css/admin.{$min}css", array(), bp_get_version() );
+
+	wp_localize_script( 'bp_groups_admin_js', 'BP_Group_Admin', array(
+		'add_member_placeholder' => __( 'Start typing a username to add a new member.', 'buddypress' ),
+		'warn_on_leave'          => __( 'If you leave this page, you will lose any unsaved changes you have made to the group.', 'buddypress' ),
+	) );
+
+	if ( $doaction && 'save' == $doaction ) {
+		// Get group ID
+		$group_id = isset( $_REQUEST['gid'] ) ? (int) $_REQUEST['gid'] : '';
+
+		$redirect_to = add_query_arg( array(
+			'gid'    => (int) $group_id,
+			'action' => 'edit'
+		), $redirect_to );
+
+		// Check this is a valid form submission
+		check_admin_referer( 'edit-group_' . $group_id );
+
+		// Get the group from the database
+		$group = groups_get_group( 'group_id=' . $group_id );
+
+		// If the group doesn't exist, just redirect back to the index
+		if ( empty( $group->slug ) ) {
+			wp_redirect( $redirect_to );
+			exit;
+		}
+
+		// Check the form for the updated properties
+
+		// Store errors
+		$error = 0;
+		$success_new = $error_new = $success_modified = $error_modified = array();
+
+		// Group name and description are handled with
+		// groups_edit_base_group_details()
+		if ( !groups_edit_base_group_details( $group_id, $_POST['bp-groups-name'], $_POST['bp-groups-description'], 0 ) ) {
+			$error = $group_id;
+		}
+
+		// Enable discussion forum
+		$enable_forum   = ( isset( $_POST['group-show-forum'] ) ) ? 1 : 0;
+
+		// Privacy setting
+		$allowed_status = apply_filters( 'groups_allowed_status', array( 'public', 'private', 'hidden' ) );
+		$status         = ( in_array( $_POST['group-status'], (array) $allowed_status ) ) ? $_POST['group-status'] : 'public';
+
+		// Invite status
+		$allowed_invite_status = apply_filters( 'groups_allowed_invite_status', array( 'members', 'mods', 'admins' ) );
+		$invite_status	       = in_array( $_POST['group-invite-status'], (array) $allowed_invite_status ) ? $_POST['group-invite-status'] : 'members';
+
+		if ( !groups_edit_group_settings( $group_id, $enable_forum, $status, $invite_status ) ) {
+			$error = $group_id;
+		}
+
+		// Process new members
+		$user_names = array();
+
+		if ( ! empty( $_POST['bp-groups-new-members'] ) ) {
+			$user_names = array_merge( $user_names, explode( ',', $_POST['bp-groups-new-members'] ) );
+		}
+
+		if ( ! empty( $_POST['new_members'] ) ) {
+			$user_names = array_merge( $user_names, $_POST['new_members'] );
+		}
+
+		if ( ! empty( $user_names ) ) {
+
+			foreach( array_values( $user_names ) as $user_name ) {
+				$un = trim( $user_name );
+
+				// Make sure the user exists before attempting
+				// to add to the group
+				$user = get_user_by( 'slug', $un );
+
+				if ( empty( $user ) ) {
+					$error_new[] = $un;
+				} else {
+					if ( ! groups_join_group( $group_id, $user->ID ) ) {
+						$error_new[]   = $un;
+					} else {
+						$success_new[] = $un;
+					}
+				}
+			}
+		}
+
+		// Process member role changes
+		if ( ! empty( $_POST['bp-groups-role'] ) && ! empty( $_POST['bp-groups-existing-role'] ) ) {
+
+			// Before processing anything, make sure you're not
+			// attempting to remove the all user admins
+			$admin_count = 0;
+			foreach ( (array) $_POST['bp-groups-role'] as $new_role ) {
+				if ( 'admin' == $new_role ) {
+					$admin_count++;
+					break;
+				}
+			}
+
+			if ( ! $admin_count ) {
+
+				$redirect_to = add_query_arg( 'no_admins', 1, $redirect_to );
+				$error = $group_id;
+
+			} else {
+
+				// Process only those users who have had their roles changed
+				foreach ( (array) $_POST['bp-groups-role'] as $user_id => $new_role ) {
+
+					$existing_role = isset( $_POST['bp-groups-existing-role'][$user_id] ) ? $_POST['bp-groups-existing-role'][$user_id] : '';
+
+					if ( $existing_role != $new_role ) {
+
+						switch ( $new_role ) {
+							case 'mod' :
+								// Admin to mod is a demotion. Demote to
+								// member, then fall through
+								if ( 'admin' == $existing_role ) {
+									groups_demote_member( $user_id, $group_id );
+								}
+
+							case 'admin' :
+								// If the user was banned, we must
+								// unban first
+								if ( 'banned' == $existing_role ) {
+									groups_unban_member( $user_id, $group_id );
+								}
+
+								// At this point, each existing_role
+								// is a member, so promote
+								$result = groups_promote_member( $user_id, $group_id, $new_role );
+
+								break;
+
+							case 'member' :
+
+								if ( 'admin' == $existing_role || 'mod' == $existing_role ) {
+									$result = groups_demote_member( $user_id, $group_id );
+								} else if ( 'banned' == $existing_role ) {
+									$result = groups_unban_member( $user_id, $group_id );
+								}
+
+								break;
+
+							case 'banned' :
+
+								$result = groups_ban_member( $user_id, $group_id );
+
+								break;
+
+							case 'remove' :
+
+								$result = groups_remove_member( $user_id, $group_id );
+
+								break;
+						}
+
+						// Store the success or failure
+						if ( $result ) {
+							$success_modified[] = $user_id;
+						} else {
+							$error_modified[]   = $user_id;
+						}
+					}
+				}
+			}
+		}
+
+		// Call actions for plugins to do something before we redirect
+		do_action( 'bp_group_admin_edit_after', $group_id );
+
+		// Create the redirect URL
+
+		if ( $error ) {
+			// This means there was an error updating group details
+			$redirect_to = add_query_arg( 'error', (int) $error, $redirect_to );
+		} else {
+			// Group details were update successfully
+			$redirect_to = add_query_arg( 'updated', 1, $redirect_to );
+		}
+
+		if ( !empty( $success_new ) ) {
+			$success_new = implode( ',', array_filter( $success_new, 'urlencode' ) );
+			$redirect_to = add_query_arg( 'success_new', $success_new, $redirect_to );
+		}
+
+		if ( !empty( $error_new ) ) {
+			$error_new = implode( ',', array_filter( $error_new, 'urlencode' ) );
+			$redirect_to = add_query_arg( 'error_new', $error_new, $redirect_to );
+		}
+
+		if ( !empty( $success_modified ) ) {
+			$success_modified = implode( ',', array_filter( $success_modified, 'urlencode' ) );
+			$redirect_to = add_query_arg( 'success_modified', $success_modified, $redirect_to );
+		}
+
+		if ( !empty( $error_modified ) ) {
+			$error_modified = implode( ',', array_filter( $error_modified, 'urlencode' ) );
+			$redirect_to = add_query_arg( 'error_modified', $error_modified, $redirect_to );
+		}
+
+		// Redirect
+		wp_redirect( apply_filters( 'bp_group_admin_edit_redirect', $redirect_to ) );
+		exit;
+
+
+	// If a referrer and a nonce is supplied, but no action, redirect back.
+	} elseif ( ! empty( $_GET['_wp_http_referer'] ) ) {
+		wp_redirect( remove_query_arg( array( '_wp_http_referer', '_wpnonce' ), stripslashes( $_SERVER['REQUEST_URI'] ) ) );
+		exit;
+	}
+}
+
+/**
+ * Handle save/update of screen options for the Groups component admin screen.
+ *
+ * @since BuddyPress (1.7.0)
+ *
+ * @param string $value Will always be false unless another plugin filters it first.
+ * @param string $option Screen option name.
+ * @param string $new_value Screen option form value.
+ * @return string Option value. False to abandon update.
+ */
+function bp_groups_admin_screen_options( $value, $option, $new_value ) {
+	if ( 'toplevel_page_bp_groups_per_page' != $option && 'toplevel_page_bp_groups_network_per_page' != $option )
+		return $value;
+
+	// Per page
+	$new_value = (int) $new_value;
+	if ( $new_value < 1 || $new_value > 999 )
+		return $value;
+
+	return $new_value;
+}
+
+/**
+ * Select the appropirate Groups admin screen, and output it.
+ *
+ * @since BuddyPress (1.7.0)
+ */
+function bp_groups_admin() {
+	// Decide whether to load the index or edit screen
+	$doaction = bp_admin_list_table_current_bulk_action();
+
+	// Display the single group edit screen
+	if ( 'edit' == $doaction && ! empty( $_GET['gid'] ) ) {
+		bp_groups_admin_edit();
+
+	// Display the group deletion confirmation screen
+	} else if ( 'delete' == $doaction && ! empty( $_GET['gid'] ) ) {
+		bp_groups_admin_delete();
+
+	// Otherwise, display the groups index screen
+	} else {
+		bp_groups_admin_index();
+	}
+}
+
+/**
+ * Display the single groups edit screen.
+ *
+ * @since BuddyPress (1.7.0)
+ */
+function bp_groups_admin_edit() {
+
+	if ( ! current_user_can( 'bp_moderate' ) )
+		die( '-1' );
+
+	$messages = array();
+
+	// If the user has just made a change to a group, build status messages
+	if ( !empty( $_REQUEST['no_admins'] ) || ! empty( $_REQUEST['error'] ) || ! empty( $_REQUEST['updated'] ) || ! empty( $_REQUEST['error_new'] ) || ! empty( $_REQUEST['success_new'] ) || ! empty( $_REQUEST['error_modified'] ) || ! empty( $_REQUEST['success_modified'] ) ) {
+		$no_admins        = ! empty( $_REQUEST['no_admins']        ) ? 1                                             : 0;
+		$errors           = ! empty( $_REQUEST['error']            ) ? $_REQUEST['error']                            : '';
+		$updated          = ! empty( $_REQUEST['updated']          ) ? $_REQUEST['updated']                          : '';
+		$error_new        = ! empty( $_REQUEST['error_new']        ) ? explode( ',', $_REQUEST['error_new'] )        : array();
+		$success_new      = ! empty( $_REQUEST['success_new']      ) ? explode( ',', $_REQUEST['success_new'] )      : array();
+		$error_modified   = ! empty( $_REQUEST['error_modified']   ) ? explode( ',', $_REQUEST['error_modified'] )   : array();
+		$success_modified = ! empty( $_REQUEST['success_modified'] ) ? explode( ',', $_REQUEST['success_modified'] ) : array();
+
+		if ( ! empty( $no_admins ) ) {
+			$messages[] = __( 'You cannot remove all administrators from a group.', 'buddypress' );
+		}
+
+		if ( ! empty( $errors ) ) {
+			$messages[] = __( 'An error occurred when trying to update your group details.', 'buddypress' );
+		} else if ( ! empty( $updated ) ) {
+			$messages[] = __( 'The group has been updated successfully.', 'buddypress' );
+		}
+
+		if ( ! empty( $error_new ) ) {
+			$messages[] = sprintf( __( 'The following users could not be added to the group: <em>%s</em>', 'buddypress' ), implode( ', ', $error_new ) );
+		}
+
+		if ( ! empty( $success_new ) ) {
+			$messages[] = sprintf( __( 'The following users were successfully added to the group: <em>%s</em>', 'buddypress' ), implode( ', ', $success_new ) );
+		}
+
+		if ( ! empty( $error_modified ) ) {
+			$error_modified = bp_groups_admin_get_usernames_from_ids( $error_modified );
+			$messages[] = sprintf( __( 'An error occurred when trying to modify the following members: <em>%s</em>', 'buddypress' ), implode( ', ', $error_modified ) );
+		}
+
+		if ( ! empty( $success_modified ) ) {
+			$success_modified = bp_groups_admin_get_usernames_from_ids( $success_modified );
+			$messages[] = sprintf( __( 'The following members were successfully modified: <em>%s</em>', 'buddypress' ), implode( ', ', $success_modified ) );
+		}
+	}
+
+	$is_error = ! empty( $no_admins ) || ! empty( $errors ) || ! empty( $error_new ) || ! empty( $error_modified );
+
+	// Get the group from the database
+	$group      = groups_get_group( 'group_id=' . $_GET['gid'] );
+	$group_name = isset( $group->name ) ? apply_filters( 'bp_get_group_name', $group->name ) : '';
+
+	// Construct URL for form
+	$form_url = remove_query_arg( array( 'action', 'deleted', 'no_admins', 'error', 'error_new', 'success_new', 'error_modified', 'success_modified' ), $_SERVER['REQUEST_URI'] );
+	$form_url = add_query_arg( 'action', 'save', $form_url );
+
+	// Call an action for plugins to modify the group before we display the edit form
+	do_action_ref_array( 'bp_groups_admin_edit', array( &$group ) ); ?>
+
+	<div class="wrap">
+		<?php screen_icon( 'buddypress-groups' ); ?>
+		<h2><?php _e( 'Edit Group', 'buddypress' ); ?>
+
+			<?php if ( is_user_logged_in() && bp_user_can_create_groups() ) : ?>
+				<a class="add-new-h2" href="<?php echo trailingslashit( bp_get_root_domain() . '/' . bp_get_groups_root_slug() . '/create' ); ?>"><?php _e( 'Add New', 'buddypress' ); ?></a>
+			<?php endif; ?>
+
+		</h2>
+
+		<?php // If the user has just made a change to an group, display the status messages ?>
+		<?php if ( !empty( $messages ) ) : ?>
+			<div id="moderated" class="<?php echo ( $is_error ) ? 'error' : 'updated'; ?>"><p><?php echo implode( "<br/>\n", $messages ); ?></p></div>
+		<?php endif; ?>
+
+		<?php if ( ! empty( $group ) ) : ?>
+
+			<form action="<?php echo esc_attr( $form_url ); ?>" id="bp-groups-edit-form" method="post">
+				<div id="poststuff">
+
+					<div id="post-body" class="metabox-holder columns-<?php echo 1 == get_current_screen()->get_columns() ? '1' : '2'; ?>">
+						<div id="post-body-content">
+							<div id="postdiv">
+								<div id="bp_groups_name" class="postbox">
+									<h3><?php _e( 'Name and Description', 'buddypress' ); ?></h3>
+									<div class="inside">
+										<input type="text" name="bp-groups-name" id="bp-groups-name" value="<?php echo esc_attr( stripslashes( $group_name ) ) ?>" />
+
+										<?php wp_editor( stripslashes( $group->description ), 'bp-groups-description', array( 'media_buttons' => false, 'teeny' => true, 'textarea_rows' => 5, 'quicktags' => array( 'buttons' => 'strong,em,link,block,del,ins,img,code,spell,close' ) ) ); ?>
+									</div>
+								</div>
+							</div>
+						</div><!-- #post-body-content -->
+
+						<div id="postbox-container-1" class="postbox-container">
+							<?php do_meta_boxes( get_current_screen()->id, 'side', $group ); ?>
+						</div>
+
+						<div id="postbox-container-2" class="postbox-container">
+							<?php do_meta_boxes( get_current_screen()->id, 'normal', $group ); ?>
+							<?php do_meta_boxes( get_current_screen()->id, 'advanced', $group ); ?>
+						</div>
+					</div><!-- #post-body -->
+
+				</div><!-- #poststuff -->
+				<?php wp_nonce_field( 'closedpostboxes', 'closedpostboxesnonce', false ); ?>
+				<?php wp_nonce_field( 'meta-box-order', 'meta-box-order-nonce', false ); ?>
+				<?php wp_nonce_field( 'edit-group_' . $group->id ); ?>
+			</form>
+
+		<?php else : ?>
+			<p><?php printf( __( 'No group found with this ID. <a href="%s">Go back and try again</a>.', 'buddypress' ), esc_url( bp_get_admin_url( 'admin.php?page=bp-groups' ) ) ); ?></p>
+		<?php endif; ?>
+
+	</div><!-- .wrap -->
+
+<?php
+}
+
+/**
+ * Display the Group delete confirmation screen.
+ *
+ * We include a separate confirmation because group deletion is truly
+ * irreversible.
+ *
+ * @since BuddyPress (1.7.0)
+ */
+function bp_groups_admin_delete() {
+
+	if ( ! is_super_admin() )
+		die( '-1' );
+
+	$group_ids = isset( $_REQUEST['gid'] ) ? $_REQUEST['gid'] : 0;
+	if ( ! is_array( $group_ids ) ) {
+		$group_ids = explode( ',', $group_ids );
+	}
+	$group_ids = wp_parse_id_list( $group_ids );
+	$groups    = groups_get_groups( array(
+		'include'     => $group_ids,
+		'show_hidden' => true,
+		'per_page'    => null, // Return all results
+	) );
+
+	// Create a new list of group ids, based on those that actually exist
+	$gids = array();
+	foreach ( $groups['groups'] as $group ) {
+		$gids[] = $group->id;
+	}
+
+	$base_url  = remove_query_arg( array( 'action', 'action2', 'paged', 's', '_wpnonce', 'gid' ), $_SERVER['REQUEST_URI'] ); ?>
+
+	<div class="wrap">
+		<?php screen_icon( 'buddypress-groups' ); ?>
+		<h2><?php _e( 'Delete Groups', 'buddypress' ) ?></h2>
+		<p><?php _e( 'You are about to delete the following groups:', 'buddypress' ) ?></p>
+
+		<ul class="bp-group-delete-list">
+		<?php foreach ( $groups['groups'] as $group ) : ?>
+			<li><?php echo esc_html( $group->name ) ?></li>
+		<?php endforeach; ?>
+		</ul>
+
+		<p><strong><?php _e( 'This action cannot be undone.', 'buddypress' ) ?></strong></p>
+
+		<a class="button-primary" href="<?php echo wp_nonce_url( add_query_arg( array( 'action' => 'do_delete', 'gid' => implode( ',', $gids ) ), $base_url ), 'bp-groups-delete' ) ?>"><?php _e( 'Delete Permanently', 'buddypress' ) ?></a>
+		<a class="button" href="<?php echo esc_attr( $base_url ); ?>"><?php _e( 'Cancel', 'buddypress' ) ?></a>
+	</div>
+
+	<?php
+}
+
+/**
+ * Display the Groups admin index screen.
+ *
+ * This screen contains a list of all BuddyPress groups.
+ *
+ * @since BuddyPress (1.7.0)
+ *
+ * @global BP_Group_List_Table $bp_groups_list_table Group screen list table.
+ * @global string $plugin_page Currently viewed plugin page.
+ */
+function bp_groups_admin_index() {
+	global $bp_groups_list_table, $plugin_page;
+
+	$messages = array();
+
+	// If the user has just made a change to a group, build status messages
+	if ( ! empty( $_REQUEST['deleted'] ) ) {
+		$deleted  = ! empty( $_REQUEST['deleted'] ) ? (int) $_REQUEST['deleted'] : 0;
+
+		if ( $deleted > 0 ) {
+			$messages[] = sprintf( _n( '%s group has been permanently deleted.', '%s groups have been permanently deleted.', $deleted, 'buddypress' ), number_format_i18n( $deleted ) );
+		}
+	}
+
+	// Prepare the group items for display
+	$bp_groups_list_table->prepare_items();
+
+	// Call an action for plugins to modify the messages before we display the edit form
+	do_action( 'bp_groups_admin_index', $messages ); ?>
+
+	<div class="wrap">
+		<?php screen_icon( 'buddypress-groups' ); ?>
+		<h2>
+			<?php _e( 'Groups', 'buddypress' ); ?>
+
+			<?php if ( is_user_logged_in() && bp_user_can_create_groups() ) : ?>
+				<a class="add-new-h2" href="<?php echo trailingslashit( bp_get_root_domain() . '/' . bp_get_groups_root_slug() . '/create' ); ?>"><?php _e( 'Add New', 'buddypress' ); ?></a>
+			<?php endif; ?>
+
+			<?php if ( !empty( $_REQUEST['s'] ) ) : ?>
+				<span class="subtitle"><?php printf( __( 'Search results for &#8220;%s&#8221;', 'buddypress' ), wp_html_excerpt( esc_html( stripslashes( $_REQUEST['s'] ) ), 50 ) ); ?></span>
+			<?php endif; ?>
+		</h2>
+
+		<?php // If the user has just made a change to an group, display the status messages ?>
+		<?php if ( !empty( $messages ) ) : ?>
+			<div id="moderated" class="<?php echo ( ! empty( $_REQUEST['error'] ) ) ? 'error' : 'updated'; ?>"><p><?php echo implode( "<br/>\n", $messages ); ?></p></div>
+		<?php endif; ?>
+
+		<?php // Display each group on its own row ?>
+		<?php $bp_groups_list_table->views(); ?>
+
+		<form id="bp-groups-form" action="" method="get">
+			<?php $bp_groups_list_table->search_box( __( 'Search all Groups', 'buddypress' ), 'bp-groups' ); ?>
+			<input type="hidden" name="page" value="<?php echo esc_attr( $plugin_page ); ?>" />
+			<?php $bp_groups_list_table->display(); ?>
+		</form>
+
+	</div>
+
+<?php
+}
+
+/**
+ * Markup for the single group's Settings metabox.
+ *
+ * @since BuddyPress (1.7.0)
+ *
+ * @param object $item Information about the current group.
+ */
+function bp_groups_admin_edit_metabox_settings( $item ) {
+
+	$invite_status = groups_get_groupmeta( $item->id, 'invite_status' ); ?>
+
+	<?php if ( bp_is_active( 'forums' ) ) : ?>
+		<div class="bp-groups-settings-section" id="bp-groups-settings-section-forum">
+			<label for="group-show-forum"><input type="checkbox" name="group-show-forum" id="group-show-forum" <?php checked( $item->enable_forum ) ?> /> <?php _e( 'Enable discussion forum', 'buddypress' ) ?><br />
+		</div>
+	<?php endif; ?>
+
+	<div class="bp-groups-settings-section" id="bp-groups-settings-section-status">
+		<label for="group-status"><?php _e( 'Privacy', 'buddypress' ); ?></label>
+
+		<ul>
+			<li><input type="radio" name="group-status" id="bp-group-status-public" value="public" <?php checked( $item->status, 'public' ) ?> /> <?php _e( 'Public', 'buddypress' ) ?></li>
+			<li><input type="radio" name="group-status" id="bp-group-status-private" value="private" <?php checked( $item->status, 'private' ) ?> /> <?php _e( 'Private', 'buddypress' ) ?></li>
+			<li><input type="radio" name="group-status" id="bp-group-status-hidden" value="hidden" <?php checked( $item->status, 'hidden' ) ?> /> <?php _e( 'Hidden', 'buddypress' ) ?></li>
+	</div>
+
+	<div class="bp-groups-settings-section" id="bp-groups-settings-section-invite-status">
+		<label for="group-invite-status"><?php _e( 'Who can invite others to this group?', 'buddypress' ); ?></label>
+
+		<ul>
+			<li><input type="radio" name="group-invite-status" id="bp-group-invite-status-members" value="members" <?php checked( $invite_status, 'members' ) ?> /> <?php _e( 'All group members', 'buddypress' ) ?></li>
+			<li><input type="radio" name="group-invite-status" id="bp-group-invite-status-mods" value="mods" <?php checked( $invite_status, 'mods' ) ?> /> <?php _e( 'Group admins and mods only', 'buddypress' ) ?></li>
+			<li><input type="radio" name="group-invite-status" id="bp-group-invite-status-admins" value="admins" <?php checked( $invite_status, 'admins' ) ?> /> <?php _e( 'Group admins only', 'buddypress' ) ?></li>
+		</ul>
+	</div>
+
+<?php
+}
+
+/**
+ * Output the markup for a single group's Add New Members metabox.
+ *
+ * @since BuddyPress (1.7.0)
+ */
+function bp_groups_admin_edit_metabox_add_new_members( $item ) {
+	?>
+
+	<input name="bp-groups-new-members" id="bp-groups-new-members" class="bp-suggest-user" placeholder="<?php _e( 'Enter a comma-separated list of user logins.', 'buddypress' ) ?>" />
+	<ul id="bp-groups-new-members-list"></ul>
+	<?php
+}
+
+/**
+ * Renders the Members metabox on single group pages.
+ *
+ * @since BuddyPress (1.7.0)
+ *
+ * @param BP_Groups_Group $item The BP_Groups_Group object for the current
+ *        group.
+ */
+function bp_groups_admin_edit_metabox_members( $item ) {
+	global $members_template;
+
+	// Pull up a list of group members, so we can separate out the types
+	// We'll also keep track of group members here to place them into a
+	// javascript variable, which will help with group member autocomplete
+	$members = array(
+		'admin'  => array(),
+		'mod'    => array(),
+		'member' => array(),
+		'banned' => array(),
+	);
+
+	$pagination = array(
+		'admin'  => array(),
+		'mod'    => array(),
+		'member' => array(),
+		'banned' => array(),
+	);
+
+	foreach ( $members as $type => &$member_type_users ) {
+		$page_qs_key = $type . '_page';
+		$current_type_page = isset( $_GET[ $page_qs_key ] ) ? absint( $_GET[ $page_qs_key ] ) : 1;
+		$member_type_query = new BP_Group_Member_Query( array(
+			'group_id'   => $item->id,
+			'group_role' => array( $type ),
+			'type'       => 'alphabetical',
+			'per_page'   => 10,
+			'page'       => $current_type_page,
+		) );
+
+		$member_type_users = $member_type_query->results;
+
+		$pagination[ $type ] = bp_groups_admin_create_pagination_links( $member_type_query, $type );
+	}
+
+	// Echo out the javascript variable
+	echo '<script type="text/javascript">var group_id = "' . $item->id . '";</script>';
+
+	// Loop through each member type
+	foreach ( $members as $member_type => $type_users ) : ?>
+
+		<div class="bp-groups-member-type" id="bp-groups-member-type-<?php echo esc_attr( $member_type ) ?>">
+
+			<h4>
+				<?php switch ( $member_type ) :
+					case 'admin'  : _e( 'Administrators', 'buddypress' ); break;
+					case 'mod'    : _e( 'Moderators',     'buddypress' ); break;
+					case 'member' : _e( 'Members',        'buddypress' ); break;
+					case 'banned' : _e( 'Banned Users',   'buddypress' ); break;
+				endswitch; ?>
+			</h4>
+
+			<div class="bp-group-admin-pagination table-top">
+				<?php echo $pagination[ $member_type ] ?>
+			</div>
+
+		<?php if ( !empty( $type_users ) ) : ?>
+
+			<table class="widefat bp-group-members">
+				<thead>
+				<tr>
+					<th scope="col" class="uid-column"><?php _ex( 'ID', 'Group member user_id in group admin', 'buddypress' ) ?></th>
+					<th scope="col" class="uname-column"><?php _ex( 'Name', 'Group member name in group admin', 'buddypress' ) ?></th>
+					<th scope="col" class="urole-column"><?php _ex( 'Group Role', 'Group member role in group admin', 'buddypress' ) ?></th>
+				</tr>
+				</thead>
+
+				<tbody>
+
+				<?php foreach ( $type_users as $type_user ) : ?>
+					<tr>
+						<th scope="row" class="uid-column"><?php echo esc_html( $type_user->ID ); ?></th>
+
+						<td class="uname-column">
+							<a style="float: left;" href="<?php echo bp_core_get_user_domain( $type_user->ID ); ?>"><?php echo bp_core_fetch_avatar( array(
+								'item_id' => $type_user->ID,
+								'width'   => '32',
+								'height'  => '32'
+							) ); ?></a>
+
+							<span style="margin: 8px; float: left;"><?php echo bp_core_get_userlink( $type_user->ID ) ?></span>
+						</td>
+
+						<td class="urole-column">
+							<select class="bp-groups-role" id="bp-groups-role-<?php echo esc_attr( $type_user->ID ); ?>" name="bp-groups-role[<?php echo esc_attr( $type_user->ID ); ?>]">
+								<option value="admin" <?php selected( 'admin', $member_type ) ?>><?php _e( 'Administrator', 'buddypress' ) ?></option>
+								<option value="mod" <?php selected( 'mod', $member_type ) ?>><?php _e( 'Moderator', 'buddypress' ) ?></option>
+								<option value="member" <?php selected( 'member', $member_type ) ?>><?php _e( 'Member', 'buddypress' ) ?></option>
+								<option class="banned" value="banned" <?php selected( 'banned', $member_type ) ?>><?php _e( 'Banned', 'buddypress' ) ?></option>
+								<option class="remove" value="remove"><?php _e( 'Remove From Group', 'buddypress' ) ?></option>
+							</select>
+
+							<?php
+							/**
+							 * Store the current role for this user,
+							 * so we can easily detect changes.
+							 *
+							 * @todo remove this, and do database detection on save
+							 */ ?>
+							<input type="hidden" name="bp-groups-existing-role[<?php echo esc_attr( $type_user->ID ); ?>]" value="<?php echo esc_attr( $member_type ); ?>" />
+						</td>
+					</tr>
+
+					<?php if ( has_filter( 'bp_groups_admin_manage_member_row' ) ) : ?>
+						<tr>
+							<td colspan="3">
+								<?php do_action( 'bp_groups_admin_manage_member_row', $type_user->ID, $item ); ?>
+							</td>
+						</tr>
+					<?php endif; ?>
+
+				<?php endforeach; ?>
+
+				</tbody>
+			</table>
+
+			<div class="bp-group-admin-pagination table-bottom">
+				<?php echo $pagination[ $member_type ] ?>
+			</div>
+
+		<?php else : ?>
+
+			<p class="bp-groups-no-members description"><?php _e( 'No members of this type', 'buddypress' ) ?></p>
+
+		<?php endif; ?>
+
+		</div><!-- .bp-groups-member-type -->
+
+	<?php endforeach;
+
+}
+
+/**
+ * Renders the Status metabox for the Groups admin edit screen.
+ *
+ * @since BuddyPress (1.7.0)
+ *
+ * @param object $item Information about the currently displayed group.
+ */
+function bp_groups_admin_edit_metabox_status( $item ) {
+	$base_url = add_query_arg( array(
+		'page' => 'bp-groups',
+		'gid'  => $item->id
+	), bp_get_admin_url( 'admin.php' ) ); ?>
+
+	<div id="submitcomment" class="submitbox">
+		<div id="major-publishing-actions">
+			<div id="delete-action">
+				<a class="submitdelete deletion" href="<?php echo wp_nonce_url( add_query_arg( 'action', 'delete', $base_url ), 'bp-groups-delete' ) ?>"><?php _e( 'Delete Group', 'buddypress' ) ?></a>
+			</div>
+
+			<div id="publishing-action">
+				<?php submit_button( __( 'Save Changes', 'buddypress' ), 'primary', 'save', false, array( 'tabindex' => '4' ) ); ?>
+			</div>
+			<div class="clear"></div>
+		</div><!-- #major-publishing-actions -->
+	</div><!-- #submitcomment -->
+
+<?php
+}
+
+/**
+ * Create pagination links out of a BP_Group_Member_Query.
+ *
+ * This function is intended to create pagination links for use under the
+ * Manage Members section of the Groups Admin Dashboard pages. It is a stopgap
+ * measure until a more general pagination solution is in place for BuddyPress.
+ * Plugin authors should not use this function, as it is likely to be
+ * deprecated soon.
+ *
+ * @since BuddyPress (1.8.0)
+ *
+ * @param BP_Group_Member_Query $query A BP_Group_Member_Query object.
+ * @param string $member_type member|mod|admin|banned.
+ * @return string Pagination links HTML.
+ */
+function bp_groups_admin_create_pagination_links( BP_Group_Member_Query $query, $member_type ) {
+	$pagination = '';
+
+	if ( ! in_array( $member_type, array( 'admin', 'mod', 'member', 'banned' ) ) ) {
+		return $pagination;
+	}
+
+	// The key used to paginate this member type in the $_GET global
+	$qs_key = $member_type . '_page';
+	$url_base = remove_query_arg( array( $qs_key, 'updated', 'success_modified' ), $_SERVER['REQUEST_URI'] );
+
+	$page     = isset( $_GET[ $qs_key ] ) ? absint( $_GET[ $qs_key ] ) : 1;
+	$per_page = 10; // @todo Make this customizable?
+
+	// Don't show anything if there's no pagination
+	if ( 1 === $page && $query->total_users <= $per_page ) {
+		return $pagination;
+	}
+
+	$current_page_start = ( ( $page - 1 ) * $per_page ) + 1;
+	$current_page_end   = $page * $per_page > intval( $query->total_users ) ? $query->total_users : $page * $per_page;
+
+	$pag_links = paginate_links( array(
+		'base'      => add_query_arg( $qs_key, '%#%', $url_base ),
+		'format'    => '',
+		'prev_text' => __( '&laquo;' ),
+		'next_text' => __( '&raquo;' ),
+		'total'     => ceil( $query->total_users / $per_page ),
+		'current'   => $page,
+	) );
+
+	$viewing_text = sprintf(
+		__( 'Viewing %1$s - %2$s of %3$s', 'buddypress' ),
+		number_format_i18n( $current_page_start ),
+		number_format_i18n( $current_page_end ),
+		sprintf( _n( '%s member', '%s members', $query->total_users, 'buddypress' ), $query->total_users )
+	);
+
+	$pagination .= '<span class="bp-group-admin-pagination-viewing">' . $viewing_text . '</span>';
+	$pagination .= '<span class="bp-group-admin-pagination-links">' . $pag_links . '</span>';
+
+	return $pagination;
+}
+
+/**
+ * Get a set of usernames corresponding to a set of user IDs.
+ *
+ * @since BuddyPress (1.7.0)
+ *
+ * @param array $user_ids Array of user IDs.
+ * @return array Array of user_logins corresponding to $user_ids.
+ */
+function bp_groups_admin_get_usernames_from_ids( $user_ids = array() ) {
+
+	$usernames = array();
+	$users     = new WP_User_Query( array( 'blog_id' => 0, 'include' => $user_ids ) );
+
+	foreach ( (array) $users->results as $user ) {
+		$usernames[] = $user->user_login;
+	}
+
+	return $usernames;
+}
+
+/**
+ * AJAX handler for group member autocomplete requests.
+ *
+ * @since BuddyPress (1.7.0)
+ */
+function bp_groups_admin_autocomplete_handler() {
+
+	// Bail if user user shouldn't be here, or is a large network
+	if ( ! current_user_can( 'bp_moderate' ) || ( is_multisite() && wp_is_large_network( 'users' ) ) )
+		wp_die( -1 );
+
+	$return = array();
+
+	// Exclude current group members
+	$group_id = isset( $_GET['group_id'] ) ? wp_parse_id_list( $_GET['group_id'] ) : array();
+	$group_member_query = new BP_Group_Member_Query( array(
+		'group_id'        => $group_id,
+		'per_page'        => 0, // show all
+		'group_role'      => array( 'member', 'mod', 'admin', ),
+		'populate_extras' => false,
+		'count_total'     => false,
+	) );
+
+	$group_members = ! empty( $group_member_query->results ) ? wp_list_pluck( $group_member_query->results, 'ID' ) : array();
+
+	$terms = isset( $_GET['term'] ) ? $_GET['term'] : '';
+	$users = get_users( array(
+		'blog_id'        => false,
+		'search'         => '*' . $terms . '*',
+		'exclude'        => $group_members,
+		'search_columns' => array( 'user_login', 'user_nicename', 'user_email', 'display_name' ),
+		'number'         => 10
+	) );
+
+	foreach ( (array) $users as $user ) {
+		$return[] = array(
+			/* translators: 1: user_login, 2: user_email */
+			'label' => sprintf( __( '%1$s (%2$s)' ), bp_is_username_compatibility_mode() ? $user->user_login : $user->user_nicename, $user->user_email ),
+			'value' => $user->user_nicename,
+		);
+	}
+
+	wp_die( json_encode( $return ) );
+}
+add_action( 'wp_ajax_bp_group_admin_member_autocomplete', 'bp_groups_admin_autocomplete_handler' );
+
+/**
+ * List table class for the Groups component admin page.
+ *
+ * @since BuddyPress (1.7.0)
+ */
+class BP_Groups_List_Table extends WP_List_Table {
+
+	/**
+	 * The type of view currently being displayed.
+	 *
+	 * e.g. "All", "Pending", "Approved", "Spam"...
+	 *
+	 * @since BuddyPress (1.7.0)
+	 *
+	 * @access public
+	 * @var string
+	 */
+	public $view = 'all';
+
+	/**
+	 * Group counts for each group type.
+	 *
+	 * @since BuddyPress (1.7.0)
+	 *
+	 * @access public
+	 * @var int
+	 */
+	public $group_counts = 0;
+
+	/**
+	 * Constructor
+	 *
+	 * @since BuddyPress (1.7.0)
+	 */
+	public function __construct() {
+
+		// Define singular and plural labels, as well as whether we support AJAX.
+		parent::__construct( array(
+			'ajax'     => false,
+			'plural'   => 'groups',
+			'singular' => 'group',
+		) );
+	}
+
+	/**
+	 * Set up items for display in the list table.
+	 *
+	 * Handles filtering of data, sorting, pagination, and any other data
+	 * manipulation required prior to rendering.
+	 *
+	 * @since BuddyPress (1.7.0)
+	 */
+	function prepare_items() {
+		global $groups_template;
+
+		$screen = get_current_screen();
+
+		// Option defaults
+		$include_id   = false;
+		$search_terms = false;
+
+		// Set current page
+		$page = $this->get_pagenum();
+
+		// Set per page from the screen options
+		$per_page = $this->get_items_per_page( str_replace( '-', '_', "{$screen->id}_per_page" ) );
+
+		// Sort order.
+		$order = 'DESC';
+		if ( !empty( $_REQUEST['order'] ) ) {
+			$order = ( 'desc' == strtolower( $_REQUEST['order'] ) ) ? 'DESC' : 'ASC';
+		}
+
+		// Order by - default to newest
+		$orderby = 'last_activity';
+		if ( ! empty( $_REQUEST['orderby'] ) ) {
+			switch ( $_REQUEST['orderby'] ) {
+				case 'name' :
+					$orderby = 'name';
+					break;
+				case 'id' :
+					$orderby = 'date_created';
+					break;
+				case 'members' :
+					$orderby = 'total_member_count';
+					break;
+				case 'last_active' :
+					$orderby = 'last_activity';
+					break;
+			}
+		}
+
+		// Are we doing a search?
+		if ( !empty( $_REQUEST['s'] ) )
+			$search_terms = $_REQUEST['s'];
+
+		// Check if user has clicked on a specific group (if so, fetch only that group).
+		if ( !empty( $_REQUEST['gid'] ) )
+			$include_id = (int) $_REQUEST['gid'];
+
+		// Set the current view
+		if ( isset( $_GET['group_status'] ) && in_array( $_GET['group_status'], array( 'public', 'private', 'hidden' ) ) ) {
+			$this->view = $_GET['group_status'];
+		}
+
+		// We'll use the ids of group types for the 'include' param
+		$this->group_type_ids = BP_Groups_Group::get_group_type_ids();
+
+		// Pass a dummy array if there are no groups of this type
+		$include = false;
+		if ( 'all' != $this->view && isset( $this->group_type_ids[ $this->view ] ) ) {
+			$include = ! empty( $this->group_type_ids[ $this->view ] ) ? $this->group_type_ids[ $this->view ] : array( 0 );
+		}
+
+		// Get group type counts for display in the filter tabs
+		$this->group_counts = array();
+		foreach ( $this->group_type_ids as $group_type => $group_ids ) {
+			$this->group_counts[ $group_type ] = count( $group_ids );
+		}
+
+		// If we're viewing a specific group, flatten all activites into a single array.
+		if ( $include_id ) {
+			$groups = array( (array) groups_get_group( 'group_id=' . $include_id ) );
+		} else {
+			$groups_args = array(
+				'include'  => $include,
+				'per_page' => $per_page,
+				'page'     => $page,
+				'orderby'  => $orderby,
+				'order'    => $order
+			);
+
+			$groups = array();
+			if ( bp_has_groups( $groups_args ) ) {
+				while ( bp_groups() ) {
+					bp_the_group();
+					$groups[] = (array) $groups_template->group;
+				}
+			}
+		}
+
+		// Set raw data to display
+		$this->items = $groups;
+
+		// Store information needed for handling table pagination
+		$this->set_pagination_args( array(
+			'per_page'    => $per_page,
+			'total_items' => $groups_template->total_group_count,
+			'total_pages' => ceil( $groups_template->total_group_count / $per_page )
+		) );
+	}
+
+	/**
+	 * Get an array of all the columns on the page.
+	 *
+	 * @since BuddyPress (1.7.0)
+	 *
+	 * @return array Array of column headers.
+	 */
+	function get_column_info() {
+		$this->_column_headers = array(
+			$this->get_columns(),
+			array(),
+			$this->get_sortable_columns(),
+		);
+
+		return $this->_column_headers;
+	}
+
+	/**
+	 * Display a message on screen when no items are found ("No groups found").
+	 *
+	 * @since BuddyPress (1.7.0)
+	 */
+	function no_items() {
+		_e( 'No groups found.', 'buddypress' );
+	}
+
+	/**
+	 * Output the Groups data table.
+	 *
+	 * @since BuddyPress (1.7.0)
+	*/
+	function display() {
+		extract( $this->_args );
+
+		$this->display_tablenav( 'top' ); ?>
+
+		<table class="<?php echo implode( ' ', $this->get_table_classes() ); ?>" cellspacing="0">
+			<thead>
+				<tr>
+					<?php $this->print_column_headers(); ?>
+				</tr>
+			</thead>
+
+			<tfoot>
+				<tr>
+					<?php $this->print_column_headers( false ); ?>
+				</tr>
+			</tfoot>
+
+			<tbody id="the-comment-list">
+				<?php $this->display_rows_or_placeholder(); ?>
+			</tbody>
+		</table>
+		<?php
+
+		$this->display_tablenav( 'bottom' );
+	}
+
+	/**
+	 * Generate content for a single row of the table.
+	 *
+	 * @since BuddyPress (1.7.0)
+	 *
+	 * @param object $item The current group item in the loop.
+	 */
+	function single_row( $item = array() ) {
+		static $even = false;
+
+		$row_classes = array();
+
+		if ( $even ) {
+			$row_classes = array( 'even' );
+		} else {
+			$row_classes = array( 'alternate', 'odd' );
+		}
+
+		$row_classes = apply_filters( 'bp_groups_admin_row_class', $row_classes, $item['id'] );
+		$row_class = ' class="' . implode( ' ', $row_classes ) . '"';
+
+		echo '<tr' . $row_class . ' id="group-' . esc_attr( $item['id'] ) . '" data-parent_id="' . esc_attr( $item['id'] ) . '" data-root_id="' . esc_attr( $item['id'] ) . '">';
+		echo $this->single_row_columns( $item );
+		echo '</tr>';
+
+		$even = ! $even;
+	}
+
+	/**
+	 * Get the list of views available on this table (e.g. "all", "public").
+	 *
+	 * @since BuddyPress (1.7.0)
+	 */
+	function get_views() {
+		$url_base = bp_get_admin_url( 'admin.php?page=bp-groups' ); ?>
+
+		<ul class="subsubsub">
+			<li class="all"><a href="<?php echo esc_attr( esc_url( $url_base ) ); ?>" class="<?php if ( 'all' == $this->view ) echo 'current'; ?>"><?php _e( 'All', 'buddypress' ); ?></a> |</li>
+			<li class="public"><a href="<?php echo esc_attr( esc_url( add_query_arg( 'group_status', 'public', $url_base ) ) ); ?>" class="<?php if ( 'public' == $this->view ) echo 'current'; ?>"><?php printf( __( 'Public <span class="count">(%s)</span>', 'buddypress' ), number_format_i18n( $this->group_counts['public'] ) ); ?></a> |</li>
+			<li class="private"><a href="<?php echo esc_attr( esc_url( add_query_arg( 'group_status', 'private', $url_base ) ) ); ?>" class="<?php if ( 'private' == $this->view ) echo 'current'; ?>"><?php printf( __( 'Private <span class="count">(%s)</span>', 'buddypress' ), number_format_i18n( $this->group_counts['private'] ) ); ?></a> |</li>
+			<li class="hidden"><a href="<?php echo esc_attr( esc_url( add_query_arg( 'group_status', 'hidden', $url_base ) ) ); ?>" class="<?php if ( 'hidden' == $this->view ) echo 'current'; ?>"><?php printf( __( 'Hidden <span class="count">(%s)</span>', 'buddypress' ), number_format_i18n( $this->group_counts['hidden'] ) ); ?></a></li>
+
+			<?php do_action( 'bp_groups_list_table_get_views', $url_base, $this->view ); ?>
+		</ul>
+	<?php
+	}
+
+	/**
+	 * Get bulk actions for single group row.
+	 *
+	 * @since BuddyPress (1.7.0)
+	 *
+	 * @return array Key/value pairs for the bulk actions dropdown.
+	 */
+	function get_bulk_actions() {
+		return apply_filters( 'bp_groups_list_table_get_bulk_actions', array(
+			'delete' => __( 'Delete', 'buddypress' )
+		) );
+	}
+
+	/**
+	 * Get the table column titles.
+	 *
+	 * @since BuddyPress (1.7.0)
+	 *
+	 * @see WP_List_Table::single_row_columns()
+	 *
+	 * @return array Array of column titles.
+	 */
+	function get_columns() {
+		return array(
+			'cb'          => '<input name type="checkbox" />',
+			'comment'     => _x( 'Name', 'Groups admin Group Name column header',               'buddypress' ),
+			'description' => _x( 'Description', 'Groups admin Group Description column header', 'buddypress' ),
+			'status'      => _x( 'Status', 'Groups admin Privacy Status column header',         'buddypress' ),
+			'members'     => _x( '# Members', 'Groups admin Members column header',             'buddypress' ),
+			'last_active' => _x( 'Last Active', 'Groups admin Last Active column header',       'buddypress' )
+		);
+	}
+
+	/**
+	 * Get the column names for sortable columns
+	 *
+	 * Note: It's not documented in WP, but the second item in the
+	 * nested arrays below is $desc_first. Normally, we would set
+	 * last_active to be desc_first (since you're generally interested in
+	 * the *most* recently active group, not the *least*). But because
+	 * the default sort for the Groups admin screen is DESC by last_active,
+	 * we want the first click on the Last Active column header to switch
+	 * the sort order - ie, to make it ASC. Thus last_active is set to
+	 * $desc_first = false.
+	 *
+	 * @since BuddyPress (1.7.0)
+	 *
+	 * @return array Array of sortable column names.
+	 */
+	function get_sortable_columns() {
+		return array(
+			'gid'         => array( 'gid', false ),
+			'comment'     => array( 'name', false ),
+			'members'     => array( 'members', false ),
+			'last_active' => array( 'last_active', false ),
+		);
+	}
+
+	/**
+	 * Markup for the Checkbox column.
+	 *
+	 * @since BuddyPress (1.7.0)
+	 *
+	 * @see WP_List_Table::single_row_columns()
+	 *
+	 * @param array $item A singular item (one full row).
+	 */
+	function column_cb( $item = array() ) {
+		printf( '<label class="screen-reader-text" for="gid-%1$d">' . __( 'Select group %1$d', 'buddypress' ) . '</label><input type="checkbox" name="gid[]" value="%1$d" id="gid-%1$d" />', $item['id'] );
+	}
+
+	/**
+	 * Markup for the Group ID column.
+	 *
+	 * @since BuddyPress (1.7.0)
+	 *
+	 * @see WP_List_Table::single_row_columns()
+	 *
+	 * @param array $item A singular item (one full row).
+	 */
+	function column_gid( $item = array() ) {
+		echo '<strong>' . $item['id'] . '</strong>';
+	}
+
+	/**
+	 * Name column, and "quick admin" rollover actions.
+	 *
+	 * Called "comment" in the CSS so we can re-use some WP core CSS.
+	 *
+	 * @since BuddyPress (1.7.0)
+	 *
+	 * @see WP_List_Table::single_row_columns()
+	 *
+	 * @param array $item A singular item (one full row).
+	 */
+	function column_comment( $item = array() ) {
+
+		// Preorder items: Visit | Edit | Delete
+		$actions = array(
+			'visit'  => '',
+			'edit'   => '',
+			'delete' => '',
+		);
+
+		// We need the group object for some BP functions
+		$item_obj = (object) $item;
+
+		// Build actions URLs
+		$base_url   = bp_get_admin_url( 'admin.php?page=bp-groups&amp;gid=' . $item['id'] );
+		$delete_url = wp_nonce_url( $base_url . "&amp;action=delete", 'bp-groups-delete' );
+		$edit_url   = $base_url . '&amp;action=edit';
+		$visit_url  = bp_get_group_permalink( $item_obj );
+
+		// Rollover actions
+
+		// Visit
+		$actions['visit'] = sprintf( '<a href="%s">%s</a>', esc_url( $visit_url ), __( 'Visit', 'buddypress' ) );
+
+		// Edit
+		$actions['edit'] = sprintf( '<a href="%s">%s</a>', esc_url( $edit_url ), __( 'Edit', 'buddypress' ) );
+
+		// Delete
+		$actions['delete'] = sprintf( '<a href="%s">%s</a>', esc_url( $delete_url ), __( 'Delete', 'buddypress' ) );
+
+		// Other plugins can filter which actions are shown
+		$actions = apply_filters( 'bp_groups_admin_comment_row_actions', array_filter( $actions ), $item );
+
+		// Get group name and avatar
+		$avatar  = bp_core_fetch_avatar( array(
+			'item_id'    => $item['id'],
+			'object'     => 'group',
+			'type'       => 'thumb',
+			'avatar_dir' => 'group-avatars',
+			'alt'        => sprintf( __( 'Group logo of %s', 'buddypress' ), $item['name'] ),
+			'width'      => '32',
+			'height'     => '32',
+			'title'      => $item['name']
+		) );
+
+		$content = apply_filters_ref_array( 'bp_get_group_name', array( $item['name'], $item ) );
+
+		echo $avatar . ' ' . $content . ' ' . $this->row_actions( $actions );
+	}
+
+	/**
+	 * Markup for the Description column.
+	 *
+	 * @since BuddyPress (1.7.0)
+	 *
+	 * @param array Information about the current row.
+	 */
+	function column_description( $item = array() ) {
+		echo apply_filters_ref_array( 'bp_get_group_description', array( $item['description'], $item ) );
+	}
+
+	/**
+	 * Markup for the Status column.
+	 *
+	 * @since BuddyPress (1.7.0)
+	 *
+	 * @param array Information about the current row.
+	 */
+	function column_status( $item = array() ) {
+		$status      = $item['status'];
+		$status_desc = '';
+
+		// @todo This should be abstracted out somewhere for the whole
+		// Groups component
+		switch ( $status ) {
+			case 'public' :
+				$status_desc = __( 'Public', 'buddypress' );
+				break;
+			case 'private' :
+				$status_desc = __( 'Private', 'buddypress' );
+				break;
+			case 'hidden' :
+				$status_desc = __( 'Hidden', 'buddypress' );
+				break;
+		}
+
+		echo apply_filters_ref_array( 'bp_groups_admin_get_group_status', array( $status_desc, $item ) );
+	}
+
+	/**
+	 * Markup for the Number of Members column.
+	 *
+	 * @since BuddyPress (1.7.0)
+	 *
+	 * @param array Information about the current row.
+	 */
+	function column_members( $item = array() ) {
+		$count = groups_get_groupmeta( $item['id'], 'total_member_count' );
+		echo apply_filters_ref_array( 'bp_groups_admin_get_group_member_count', array( (int) $count, $item ) );
+	}
+
+	/**
+	 * Markup for the Last Active column.
+	 *
+	 * @since BuddyPress (1.7.0)
+	 *
+	 * @param array Information about the current row.
+	 */
+	function column_last_active( $item = array() ) {
+		$last_active = groups_get_groupmeta( $item['id'], 'last_activity' );
+		echo apply_filters_ref_array( 'bp_groups_admin_get_group_last_active', array( $last_active, $item ) );
+	}
+}
Index: /tags/1.9/bp-groups/bp-groups-adminbar.php
===================================================================
--- /tags/1.9/bp-groups/bp-groups-adminbar.php	(revision 7684)
+++ /tags/1.9/bp-groups/bp-groups-adminbar.php	(revision 7684)
@@ -0,0 +1,117 @@
+<?php
+
+/**
+ * BuddyPress Groups Toolbar
+ *
+ * Handles the groups functions related to the WordPress Toolbar.
+ *
+ * @package BuddyPress
+ * @subpackage Groups
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/**
+ * Add the Group Admin top-level menu when viewing group pages.
+ *
+ * @since BuddyPress (1.5.0)
+ *
+ * @todo Add dynamic menu items for group extensions.
+ */
+function bp_groups_group_admin_menu() {
+	global $wp_admin_bar, $bp;
+
+	// Only show if viewing a group
+	if ( !bp_is_group() )
+		return false;
+
+	// Only show this menu to group admins and super admins
+	if ( !bp_current_user_can( 'bp_moderate' ) && !bp_group_is_admin() )
+		return false;
+
+	// Unique ID for the 'Edit Group' menu
+	$bp->group_admin_menu_id = 'group-admin';
+
+	// Add the top-level Group Admin button
+	$wp_admin_bar->add_menu( array(
+		'id'    => $bp->group_admin_menu_id,
+		'title' => __( 'Edit Group', 'buddypress' ),
+		'href'  => bp_get_group_permalink( $bp->groups->current_group )
+	) );
+
+	// Group Admin > Edit details
+	$wp_admin_bar->add_menu( array(
+		'parent' => $bp->group_admin_menu_id,
+		'id'     => 'edit-details',
+		'title'  => __( 'Edit Details', 'buddypress' ),
+		'href'   =>  bp_get_groups_action_link( 'admin/edit-details' )
+	) );
+
+	// Group Admin > Group settings
+	$wp_admin_bar->add_menu( array(
+		'parent' => $bp->group_admin_menu_id,
+		'id'     => 'group-settings',
+		'title'  => __( 'Edit Settings', 'buddypress' ),
+		'href'   =>  bp_get_groups_action_link( 'admin/group-settings' )
+	) );
+
+	// Group Admin > Group avatar
+	if ( !(int)bp_get_option( 'bp-disable-avatar-uploads' ) ) {
+		$wp_admin_bar->add_menu( array(
+			'parent' => $bp->group_admin_menu_id,
+			'id'     => 'group-avatar',
+			'title'  => __( 'Edit Avatar', 'buddypress' ),
+			'href'   =>  bp_get_groups_action_link( 'admin/group-avatar' )
+		) );
+	}
+
+	// Group Admin > Manage invitations
+	if ( bp_is_active( 'friends' ) ) {
+		$wp_admin_bar->add_menu( array(
+			'parent' => $bp->group_admin_menu_id,
+			'id'     => 'manage-invitations',
+			'title'  => __( 'Manage Invitations', 'buddypress' ),
+			'href'   =>  bp_get_groups_action_link( 'send-invites' )
+		) );
+	}
+
+	// Group Admin > Manage members
+	$wp_admin_bar->add_menu( array(
+		'parent' => $bp->group_admin_menu_id,
+		'id'     => 'manage-members',
+		'title'  => __( 'Manage Members', 'buddypress' ),
+		'href'   =>  bp_get_groups_action_link( 'admin/manage-members' )
+	) );
+
+	// Group Admin > Membership Requests
+	if ( bp_get_group_status( $bp->groups->current_group ) == 'private' ) {
+		$wp_admin_bar->add_menu( array(
+			'parent' => $bp->group_admin_menu_id,
+			'id'     => 'membership-requests',
+			'title'  => __( 'Membership Requests', 'buddypress' ),
+			'href'   =>  bp_get_groups_action_link( 'admin/membership-requests' )
+		) );
+	}
+
+	// Delete Group
+	$wp_admin_bar->add_menu( array(
+		'parent' => $bp->group_admin_menu_id,
+		'id'     => 'delete-group',
+		'title'  => __( 'Delete Group', 'buddypress' ),
+		'href'   =>  bp_get_groups_action_link( 'admin/delete-group' )
+	) );
+}
+add_action( 'admin_bar_menu', 'bp_groups_group_admin_menu', 99 );
+
+/**
+ * Remove rogue WP core Edit menu when viewing a single group.
+ *
+ * @since BuddyPress (1.6.0)
+ */
+function bp_groups_remove_edit_page_menu() {
+	if ( bp_is_group() ) {
+		remove_action( 'admin_bar_menu', 'wp_admin_bar_edit_menu', 80 );
+	}
+}
+add_action( 'bp_init', 'bp_groups_remove_edit_page_menu', 99 );
Index: /tags/1.9/bp-groups/bp-groups-buddybar.php
===================================================================
--- /tags/1.9/bp-groups/bp-groups-buddybar.php	(revision 7684)
+++ /tags/1.9/bp-groups/bp-groups-buddybar.php	(revision 7684)
@@ -0,0 +1,67 @@
+<?php
+
+/**
+ * BuddyPress Groups BuddyBar
+ *
+ * @package BuddyPress
+ * @subpackage GroupsBuddyBar
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/**
+ * Add menu items to the BuddyBar.
+ *
+ * @since BuddyPress (1.0.0)
+ *
+ * @global BuddyPress $bp
+ */
+function bp_groups_adminbar_admin_menu() {
+	global $bp;
+
+	if ( empty( $bp->groups->current_group ) )
+		return false;
+
+	// Only group admins and site admins can see this menu
+	if ( !current_user_can( 'edit_users' ) && !bp_current_user_can( 'bp_moderate' ) && !bp_is_item_admin() )
+		return false; ?>
+
+	<li id="bp-adminbar-adminoptions-menu">
+		<a href="<?php bp_groups_action_link( 'admin' ); ?>"><?php _e( 'Admin Options', 'buddypress' ); ?></a>
+
+		<ul>
+			<li><a href="<?php bp_groups_action_link( 'admin/edit-details' ); ?>"><?php _e( 'Edit Details', 'buddypress' ); ?></a></li>
+
+			<li><a href="<?php bp_groups_action_link( 'admin/group-settings' );  ?>"><?php _e( 'Group Settings', 'buddypress' ); ?></a></li>
+
+			<?php if ( !(int)bp_get_option( 'bp-disable-avatar-uploads' ) ) : ?>
+
+				<li><a href="<?php bp_groups_action_link( 'admin/group-avatar' ); ?>"><?php _e( 'Group Avatar', 'buddypress' ); ?></a></li>
+
+			<?php endif; ?>
+
+			<?php if ( bp_is_active( 'friends' ) ) : ?>
+
+				<li><a href="<?php bp_groups_action_link( 'send-invites' ); ?>"><?php _e( 'Manage Invitations', 'buddypress' ); ?></a></li>
+
+			<?php endif; ?>
+
+			<li><a href="<?php bp_groups_action_link( 'admin/manage-members' ); ?>"><?php _e( 'Manage Members', 'buddypress' ); ?></a></li>
+
+			<?php if ( $bp->groups->current_group->status == 'private' ) : ?>
+
+				<li><a href="<?php bp_groups_action_link( 'admin/membership-requests' ); ?>"><?php _e( 'Membership Requests', 'buddypress' ); ?></a></li>
+
+			<?php endif; ?>
+
+			<li><a class="confirm" href="<?php echo wp_nonce_url( bp_get_group_permalink( $bp->groups->current_group ) . 'admin/delete-group/', 'groups_delete_group' ); ?>&amp;delete-group-button=1&amp;delete-group-understand=1"><?php _e( "Delete Group", 'buddypress' ) ?></a></li>
+
+			<?php do_action( 'bp_groups_adminbar_admin_menu' ) ?>
+
+		</ul>
+	</li>
+
+	<?php
+}
+add_action( 'bp_adminbar_menus', 'bp_groups_adminbar_admin_menu', 20 );
Index: /tags/1.9/bp-groups/bp-groups-cache.php
===================================================================
--- /tags/1.9/bp-groups/bp-groups-cache.php	(revision 7684)
+++ /tags/1.9/bp-groups/bp-groups-cache.php	(revision 7684)
@@ -0,0 +1,137 @@
+<?php
+
+/**
+ * BuddyPress Groups Caching
+ *
+ * Caching functions handle the clearing of cached objects and pages on specific
+ * actions throughout BuddyPress.
+ *
+ * @package BuddyPress
+ * @subpackage Groups
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/**
+ * Slurp up metadata for a set of groups.
+ *
+ * This function is called in two places in the BP_Groups_Group class:
+ *   - in the populate() method, when single group objects are populated
+ *   - in the get() method, when multiple groups are queried
+ *
+ * It grabs all groupmeta associated with all of the groups passed in
+ * $group_ids and adds it to WP cache. This improves efficiency when using
+ * groupmeta within a loop context.
+ *
+ * @param int|str|array $group_ids Accepts a single group_id, or a
+ *        comma-separated list or array of group ids.
+ */
+function bp_groups_update_meta_cache( $group_ids = false ) {
+	global $bp;
+
+	$cache_args = array(
+		'object_ids' 	   => $group_ids,
+		'object_type' 	   => $bp->groups->id,
+		'object_column'    => 'group_id',
+		'meta_table' 	   => $bp->groups->table_name_groupmeta,
+		'cache_key_prefix' => 'bp_groups_groupmeta'
+	);
+
+	bp_update_meta_cache( $cache_args );
+}
+
+/**
+ * Clear the cached group count.
+ *
+ * @param $group_id Not used.
+ */
+function groups_clear_group_object_cache( $group_id ) {
+	wp_cache_delete( 'bp_total_group_count', 'bp' );
+}
+add_action( 'groups_group_deleted',              'groups_clear_group_object_cache' );
+add_action( 'groups_settings_updated',           'groups_clear_group_object_cache' );
+add_action( 'groups_details_updated',            'groups_clear_group_object_cache' );
+add_action( 'groups_group_avatar_updated',       'groups_clear_group_object_cache' );
+add_action( 'groups_create_group_step_complete', 'groups_clear_group_object_cache' );
+
+/**
+ * Bust group caches when editing or deleting.
+ *
+ * @since BuddyPress (1.7.0)
+ *
+ * @param int $group_id The group being edited.
+ */
+function bp_groups_delete_group_cache( $group_id = 0 ) {
+	wp_cache_delete( 'bp_groups_group_' . $group_id . '_load_users', 'bp' );
+	wp_cache_delete( 'bp_groups_group_' . $group_id . '_noload_users', 'bp' );
+}
+add_action( 'groups_delete_group',     'bp_groups_delete_group_cache' );
+add_action( 'groups_update_group',     'bp_groups_delete_group_cache' );
+add_action( 'groups_details_updated',  'bp_groups_delete_group_cache' );
+add_action( 'groups_settings_updated', 'bp_groups_delete_group_cache' );
+
+/**
+ * Clear caches for the group creator when a group is created.
+ *
+ * @since BuddyPress (1.6.0)
+ *
+ * @param int $group_id ID of the group.
+ * @param BP_Groups_Group $group_obj Group object.
+ */
+function bp_groups_clear_group_creator_cache( $group_id, $group_obj ) {
+	// Clears the 'total groups' for this user
+	groups_clear_group_user_object_cache( $group_obj->id, $group_obj->creator_id );
+}
+add_action( 'groups_created_group', 'bp_groups_clear_group_creator_cache', 10, 2 );
+
+/**
+ * Clears caches for all members in a group when a group is deleted
+ *
+ * @since BuddyPress (1.6.0)
+ *
+ * @param BP_Groups_Group $group_obj Group object.
+ * @param array User IDs who were in this group.
+ */
+function bp_groups_clear_group_members_caches( $group_obj, $user_ids ) {
+	// Clears the 'total groups' cache for each member in a group
+	foreach ( (array) $user_ids as $user_id )
+		groups_clear_group_user_object_cache( $group_obj->id, $user_id );
+}
+add_action( 'bp_groups_delete_group', 'bp_groups_clear_group_members_caches', 10, 2 );
+
+/**
+ * Clear a user's cached group count.
+ *
+ * @param int $group_id ID of the group. Not used in this function.
+ * @param int $user_id ID of the user whose group count is being changed.
+ */
+function groups_clear_group_user_object_cache( $group_id, $user_id ) {
+	wp_cache_delete( 'bp_total_groups_for_user_' . $user_id, 'bp' );
+}
+add_action( 'groups_join_group',    'groups_clear_group_user_object_cache', 10, 2 );
+add_action( 'groups_leave_group',   'groups_clear_group_user_object_cache', 10, 2 );
+add_action( 'groups_ban_member',    'groups_clear_group_user_object_cache', 10, 2 );
+add_action( 'groups_unban_member',  'groups_clear_group_user_object_cache', 10, 2 );
+add_action( 'groups_uninvite_user', 'groups_clear_group_user_object_cache', 10, 2 );
+add_action( 'groups_remove_member', 'groups_clear_group_user_object_cache', 10, 2 );
+
+/* List actions to clear super cached pages on, if super cache is installed */
+add_action( 'groups_join_group',                 'bp_core_clear_cache' );
+add_action( 'groups_leave_group',                'bp_core_clear_cache' );
+add_action( 'groups_accept_invite',              'bp_core_clear_cache' );
+add_action( 'groups_reject_invite',              'bp_core_clear_cache' );
+add_action( 'groups_invite_user',                'bp_core_clear_cache' );
+add_action( 'groups_uninvite_user',              'bp_core_clear_cache' );
+add_action( 'groups_details_updated',            'bp_core_clear_cache' );
+add_action( 'groups_settings_updated',           'bp_core_clear_cache' );
+add_action( 'groups_unban_member',               'bp_core_clear_cache' );
+add_action( 'groups_ban_member',                 'bp_core_clear_cache' );
+add_action( 'groups_demote_member',              'bp_core_clear_cache' );
+add_action( 'groups_promote_member',             'bp_core_clear_cache' );
+add_action( 'groups_membership_rejected',        'bp_core_clear_cache' );
+add_action( 'groups_membership_accepted',        'bp_core_clear_cache' );
+add_action( 'groups_membership_requested',       'bp_core_clear_cache' );
+add_action( 'groups_create_group_step_complete', 'bp_core_clear_cache' );
+add_action( 'groups_created_group',              'bp_core_clear_cache' );
+add_action( 'groups_group_avatar_updated',       'bp_core_clear_cache' );
Index: /tags/1.9/bp-groups/bp-groups-classes.php
===================================================================
--- /tags/1.9/bp-groups/bp-groups-classes.php	(revision 7684)
+++ /tags/1.9/bp-groups/bp-groups-classes.php	(revision 7684)
@@ -0,0 +1,3838 @@
+<?php
+
+/**
+ * BuddyPress Groups Classes
+ *
+ * @package BuddyPress
+ * @subpackage GroupsClasses
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/**
+ * BuddyPress Group object.
+ */
+class BP_Groups_Group {
+
+	/**
+	 * ID of the group.
+	 *
+	 * @access public
+	 * @var int
+	 */
+	public $id;
+
+	/**
+	 * User ID of the group's creator.
+	 *
+	 * @access public
+	 * @var int
+	 */
+	public $creator_id;
+
+	/**
+	 * Name of the group.
+	 *
+	 * @access public
+	 * @var string
+	 */
+	public $name;
+
+	/**
+	 * Group slug.
+	 *
+	 * @access public
+	 * @var string
+	 */
+	public $slug;
+
+	/**
+	 * Group description.
+	 *
+	 * @access public
+	 * @var string
+	 */
+	public $description;
+
+	/**
+	 * Group status.
+	 *
+	 * Core statuses are 'public', 'private', and 'hidden'.
+	 *
+	 * @access public
+	 * @var string
+	 */
+	public $status;
+
+	/**
+	 * Should (legacy) bbPress forums be enabled for this group?
+	 *
+	 * @access public
+	 * @var int
+	 */
+	public $enable_forum;
+
+	/**
+	 * Date the group was created.
+	 *
+	 * @access public
+	 * @var string
+	 */
+	public $date_created;
+
+	/**
+	 * Data about the group's admins.
+	 *
+	 * @access public
+	 * @var array
+	 */
+	public $admins;
+
+	/**
+	 * Data about the group's moderators.
+	 *
+	 * @access public
+	 * @var array
+	 */
+	public $mods;
+
+	/**
+	 * Total count of group members.
+	 *
+	 * @access public
+	 * @var int
+	 */
+	public $total_member_count;
+
+	/**
+	 * Is the current user a member of this group?
+	 *
+	 * @since BuddyPress (1.2.0)
+	 * @var bool
+	 */
+	public $is_member;
+
+	/**
+	 * Does the current user have an outstanding invitation to this group?
+	 *
+	 * @since BuddyPress (1.9.0)
+	 * @var bool
+	 */
+	public $is_invited;
+
+	/**
+	 * Does the current user have a pending membership request to this group?
+	 *
+	 * @since BuddyPress (1.9.0)
+	 * @var bool
+	 */
+	public $is_pending;
+
+	/**
+	 * Timestamp of the last activity that happened in this group.
+	 *
+	 * @since BuddyPress (1.2.0)
+	 * @var string
+	 */
+	public $last_activity;
+
+	/**
+	 * If this is a private or hidden group, does the current user have access?
+	 *
+	 * @since BuddyPress (1.6.0)
+	 * @var bool
+	 */
+	public $user_has_access;
+
+	/**
+	 * Constructor method.
+	 *
+	 * @param int $id Optional. If the ID of an existing group is provided,
+	 *        the object will be pre-populated with info about that group.
+	 */
+	public function __construct( $id = null ) {
+		if ( !empty( $id ) ) {
+			$this->id = $id;
+			$this->populate();
+		}
+	}
+
+	/**
+	 * Set up data about the current group.
+	 */
+	public function populate() {
+		global $wpdb, $bp;
+
+		if ( $group = $wpdb->get_row( $wpdb->prepare( "SELECT g.* FROM {$bp->groups->table_name} g WHERE g.id = %d", $this->id ) ) ) {
+			bp_groups_update_meta_cache( $this->id );
+
+			$this->id                 = $group->id;
+			$this->creator_id         = $group->creator_id;
+			$this->name               = stripslashes($group->name);
+			$this->slug               = $group->slug;
+			$this->description        = stripslashes($group->description);
+			$this->status             = $group->status;
+			$this->enable_forum       = $group->enable_forum;
+			$this->date_created       = $group->date_created;
+			$this->last_activity      = groups_get_groupmeta( $this->id, 'last_activity' );
+			$this->total_member_count = groups_get_groupmeta( $this->id, 'total_member_count' );
+			$this->is_member          = BP_Groups_Member::check_is_member( bp_loggedin_user_id(), $this->id );
+			$this->is_invited         = BP_Groups_Member::check_has_invite( bp_loggedin_user_id(), $this->id );
+			$this->is_pending         = BP_Groups_Member::check_for_membership_request( bp_loggedin_user_id(), $this->id );
+
+			// If this is a private or hidden group, does the current user have access?
+			if ( 'private' == $this->status || 'hidden' == $this->status ) {
+				if ( $this->is_member && is_user_logged_in() || bp_current_user_can( 'bp_moderate' ) )
+					$this->user_has_access = true;
+				else
+					$this->user_has_access = false;
+			} else {
+				$this->user_has_access = true;
+			}
+
+			// Get group admins and mods
+			$admin_mods = $wpdb->get_results( apply_filters( 'bp_group_admin_mods_user_join_filter', $wpdb->prepare( "SELECT u.ID as user_id, u.user_login, u.user_email, u.user_nicename, m.is_admin, m.is_mod FROM {$wpdb->users} u, {$bp->groups->table_name_members} m WHERE u.ID = m.user_id AND m.group_id = %d AND ( m.is_admin = 1 OR m.is_mod = 1 )", $this->id ) ) );
+			foreach( (array) $admin_mods as $user ) {
+				if ( (int) $user->is_admin )
+					$this->admins[] = $user;
+				else
+					$this->mods[] = $user;
+			}
+		} else {
+			$this->id = 0;
+		}
+	}
+
+	/**
+	 * Save the current group to the database.
+	 *
+	 * @return bool True on success, false on failure.
+	 */
+	public function save() {
+		global $wpdb, $bp;
+
+		$this->creator_id   = apply_filters( 'groups_group_creator_id_before_save',   $this->creator_id,   $this->id );
+		$this->name         = apply_filters( 'groups_group_name_before_save',         $this->name,         $this->id );
+ 		$this->slug         = apply_filters( 'groups_group_slug_before_save',         $this->slug,         $this->id );
+		$this->description  = apply_filters( 'groups_group_description_before_save',  $this->description,  $this->id );
+ 		$this->status       = apply_filters( 'groups_group_status_before_save',       $this->status,       $this->id );
+		$this->enable_forum = apply_filters( 'groups_group_enable_forum_before_save', $this->enable_forum, $this->id );
+		$this->date_created = apply_filters( 'groups_group_date_created_before_save', $this->date_created, $this->id );
+
+		do_action_ref_array( 'groups_group_before_save', array( &$this ) );
+
+		if ( !empty( $this->id ) ) {
+			$sql = $wpdb->prepare(
+				"UPDATE {$bp->groups->table_name} SET
+					creator_id = %d,
+					name = %s,
+					slug = %s,
+					description = %s,
+					status = %s,
+					enable_forum = %d,
+					date_created = %s
+				WHERE
+					id = %d
+				",
+					$this->creator_id,
+					$this->name,
+					$this->slug,
+					$this->description,
+					$this->status,
+					$this->enable_forum,
+					$this->date_created,
+					$this->id
+			);
+		} else {
+			$sql = $wpdb->prepare(
+				"INSERT INTO {$bp->groups->table_name} (
+					creator_id,
+					name,
+					slug,
+					description,
+					status,
+					enable_forum,
+					date_created
+				) VALUES (
+					%d, %s, %s, %s, %s, %d, %s
+				)",
+					$this->creator_id,
+					$this->name,
+					$this->slug,
+					$this->description,
+					$this->status,
+					$this->enable_forum,
+					$this->date_created
+			);
+		}
+
+		if ( false === $wpdb->query($sql) )
+			return false;
+
+		if ( empty( $this->id ) )
+			$this->id = $wpdb->insert_id;
+
+		do_action_ref_array( 'groups_group_after_save', array( &$this ) );
+
+		wp_cache_delete( 'bp_groups_group_' . $this->id, 'bp' );
+
+		return true;
+	}
+
+	/**
+	 * Delete the current group.
+	 *
+	 * @return bool True on success, false on failure.
+	 */
+	public function delete() {
+		global $wpdb, $bp;
+
+		// Delete groupmeta for the group
+		groups_delete_groupmeta( $this->id );
+
+		// Fetch the user IDs of all the members of the group
+		$user_ids    = BP_Groups_Member::get_group_member_ids( $this->id );
+		$user_id_str = esc_sql( implode( ',', wp_parse_id_list( $user_ids ) ) );
+
+		// Modify group count usermeta for members
+		$wpdb->query( "UPDATE {$wpdb->usermeta} SET meta_value = meta_value - 1 WHERE meta_key = 'total_group_count' AND user_id IN ( {$user_id_str} )" );
+
+		// Now delete all group member entries
+		BP_Groups_Member::delete_all( $this->id );
+
+		do_action_ref_array( 'bp_groups_delete_group', array( &$this, $user_ids ) );
+
+		wp_cache_delete( 'bp_groups_group_' . $this->id, 'bp' );
+
+		// Finally remove the group entry from the DB
+		if ( !$wpdb->query( $wpdb->prepare( "DELETE FROM {$bp->groups->table_name} WHERE id = %d", $this->id ) ) )
+			return false;
+
+		return true;
+	}
+
+	/** Static Methods ****************************************************/
+
+	/**
+	 * Get whether a group exists for a given slug.
+	 *
+	 * @param string $slug Slug to check.
+	 * @param string $table_name Optional. Name of the table to check
+	 *        against. Default: $bp->groups->table_name.
+	 * @return string|null ID of the group, if one is found, else null.
+	 */
+	public static function group_exists( $slug, $table_name = false ) {
+		global $wpdb, $bp;
+
+		if ( empty( $table_name ) )
+			$table_name = $bp->groups->table_name;
+
+		if ( empty( $slug ) )
+			return false;
+
+		return $wpdb->get_var( $wpdb->prepare( "SELECT id FROM {$table_name} WHERE slug = %s", strtolower( $slug ) ) );
+	}
+
+	/**
+	 * Get the ID of a group by the group's slug.
+	 *
+	 * Alias of {@link BP_Groups_Group::group_exists()}.
+	 *
+	 * @param string $slug See {@link BP_Groups_Group::group_exists()}.
+	 * @return string|null See {@link BP_Groups_Group::group_exists()}.
+	 */
+	public static function get_id_from_slug( $slug ) {
+		return BP_Groups_Group::group_exists( $slug );
+	}
+
+	/**
+	 * Get IDs of users with outstanding invites to a given group from a specified user.
+	 *
+	 * @param int $user_id ID of the inviting user.
+	 * @param int $group_id ID of the group.
+	 * @return array IDs of users who have been invited to the group by the
+	 *         user but have not yet accepted.
+	 */
+	public static function get_invites( $user_id, $group_id ) {
+		global $wpdb, $bp;
+		return $wpdb->get_col( $wpdb->prepare( "SELECT user_id FROM {$bp->groups->table_name_members} WHERE group_id = %d and is_confirmed = 0 AND inviter_id = %d", $group_id, $user_id ) );
+	}
+
+	/**
+	 * Get a list of a user's groups, filtered by a search string.
+	 *
+	 * @param string $filter Search term. Matches against 'name' and
+	 *        'description' fields.
+	 * @param int $user_id ID of the user whose groups are being searched.
+	 *        Default: the displayed user.
+	 * @param mixed $order Not used.
+	 * @param int $limit Optional. The max number of results to return.
+	 *        Default: null (no limit).
+	 * @param int $page Optional. The page offset of results to return.
+	 *        Default: null (no limit).
+	 * @return array {
+	 *     @type array $groups Array of matched and paginated group objects.
+	 *     @type int $total Total count of groups matching the query.
+	 * }
+	 */
+	public static function filter_user_groups( $filter, $user_id = 0, $order = false, $limit = null, $page = null ) {
+		global $wpdb, $bp;
+
+		if ( empty( $user_id ) )
+			$user_id = bp_displayed_user_id();
+
+		$filter = esc_sql( like_escape( $filter ) );
+
+		$pag_sql = $order_sql = $hidden_sql = '';
+
+		if ( !empty( $limit ) && !empty( $page ) )
+			$pag_sql = $wpdb->prepare( " LIMIT %d, %d", intval( ( $page - 1 ) * $limit), intval( $limit ) );
+
+		// Get all the group ids for the current user's groups.
+		$gids = BP_Groups_Member::get_group_ids( $user_id );
+
+		if ( empty( $gids['groups'] ) )
+			return false;
+
+		$gids = esc_sql( implode( ',', wp_parse_id_list( $gids['groups'] ) ) );
+
+		$paged_groups = $wpdb->get_results( "SELECT id as group_id FROM {$bp->groups->table_name} WHERE ( name LIKE '{$filter}%%' OR description LIKE '{$filter}%%' ) AND id IN ({$gids}) {$pag_sql}" );
+		$total_groups = $wpdb->get_var( "SELECT COUNT(id) FROM {$bp->groups->table_name} WHERE ( name LIKE '{$filter}%%' OR description LIKE '{$filter}%%' ) AND id IN ({$gids})" );
+
+		return array( 'groups' => $paged_groups, 'total' => $total_groups );
+	}
+
+	/**
+	 * Get a list of groups, filtered by a search string.
+	 *
+	 * @param string $filter Search term. Matches against 'name' and
+	 *        'description' fields.
+	 * @param int $limit Optional. The max number of results to return.
+	 *        Default: null (no limit).
+	 * @param int $page Optional. The page offset of results to return.
+	 *        Default: null (no limit).
+	 * @param string $sort_by Column to sort by. Default: false (default
+	 *        sort).
+	 * @param string $order ASC or DESC. Default: false (default sort).
+	 * @return array {
+	 *     @type array $groups Array of matched and paginated group objects.
+	 *     @type int $total Total count of groups matching the query.
+	 * }
+	 */
+	public static function search_groups( $filter, $limit = null, $page = null, $sort_by = false, $order = false ) {
+		global $wpdb, $bp;
+
+		$filter = esc_sql( like_escape( $filter ) );
+
+		$pag_sql = $order_sql = $hidden_sql = '';
+
+		if ( !empty( $limit ) && !empty( $page ) )
+			$pag_sql = $wpdb->prepare( " LIMIT %d, %d", intval( ( $page - 1 ) * $limit), intval( $limit ) );
+
+		if ( !empty( $sort_by ) && !empty( $order ) ) {
+			$sort_by   = esc_sql( $sort_by );
+			$order     = esc_sql( $order );
+			$order_sql = "ORDER BY {$sort_by} {$order}";
+		}
+
+		if ( !bp_current_user_can( 'bp_moderate' ) )
+			$hidden_sql = "AND status != 'hidden'";
+
+		$paged_groups = $wpdb->get_results( "SELECT id as group_id FROM {$bp->groups->table_name} WHERE ( name LIKE '%%{$filter}%%' OR description LIKE '%%{$filter}%%' ) {$hidden_sql} {$order_sql} {$pag_sql}" );
+		$total_groups = $wpdb->get_var( "SELECT COUNT(id) FROM {$bp->groups->table_name} WHERE ( name LIKE '%%{$filter}%%' OR description LIKE '%%{$filter}%%' ) {$hidden_sql}" );
+
+		return array( 'groups' => $paged_groups, 'total' => $total_groups );
+	}
+
+	/**
+	 * Check for the existence of a slug.
+	 *
+	 * @param string $slug Slug to check.
+	 * @return string|null The slug, if found. Otherwise null.
+	 */
+	public static function check_slug( $slug ) {
+		global $wpdb, $bp;
+
+		return $wpdb->get_var( $wpdb->prepare( "SELECT slug FROM {$bp->groups->table_name} WHERE slug = %s", $slug ) );
+	}
+
+	/**
+	 * Get the slug for a given group ID.
+	 *
+	 * @param int $group_id ID of the group.
+	 * @return string|null The slug, if found. Otherwise null.
+	 */
+	public static function get_slug( $group_id ) {
+		global $wpdb, $bp;
+
+		return $wpdb->get_var( $wpdb->prepare( "SELECT slug FROM {$bp->groups->table_name} WHERE id = %d", $group_id ) );
+	}
+
+	/**
+	 * Check whether a given group has any members.
+	 *
+	 * @param int $group_id ID of the group.
+	 * @return bool True if the group has members, otherwise false.
+	 */
+	public static function has_members( $group_id ) {
+		global $wpdb, $bp;
+
+		$members = $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(id) FROM {$bp->groups->table_name_members} WHERE group_id = %d", $group_id ) );
+
+		if ( empty( $members ) )
+			return false;
+
+		return true;
+	}
+
+	/**
+	 * Check whether a group has outstanding membership requests.
+	 *
+	 * @param int $group_id ID of the group.
+	 * @return int|null The number of outstanding requests, or null if
+	 *         none are found.
+	 */
+	public static function has_membership_requests( $group_id ) {
+		global $wpdb, $bp;
+
+		return $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(id) FROM {$bp->groups->table_name_members} WHERE group_id = %d AND is_confirmed = 0", $group_id ) );
+	}
+
+	/**
+	 * Get outstanding membership requests for a group.
+	 *
+	 * @param int $group_id ID of the group.
+	 * @param int $limit Optional. Max number of results to return.
+	 *        Default: null (no limit).
+	 * @param int $page Optional. Page offset of results returned. Default:
+	 *        null (no limit).
+	 * @return array {
+	 *     @type array $requests The requested page of located requests.
+	 *     @type int $total Total number of requests outstanding for the
+	 *           group.
+	 * }
+	 */
+	public static function get_membership_requests( $group_id, $limit = null, $page = null ) {
+		global $wpdb, $bp;
+
+		if ( !empty( $limit ) && !empty( $page ) ) {
+			$pag_sql = $wpdb->prepare( " LIMIT %d, %d", intval( ( $page - 1 ) * $limit), intval( $limit ) );
+		}
+
+		$paged_requests = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM {$bp->groups->table_name_members} WHERE group_id = %d AND is_confirmed = 0 AND inviter_id = 0{$pag_sql}", $group_id ) );
+		$total_requests = $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(id) FROM {$bp->groups->table_name_members} WHERE group_id = %d AND is_confirmed = 0 AND inviter_id = 0", $group_id ) );
+
+		return array( 'requests' => $paged_requests, 'total' => $total_requests );
+	}
+
+	/**
+	 * Query for groups.
+	 *
+	 * @see WP_Meta_Query::queries for a description of the 'meta_query'
+	 *      parameter format.
+	 *
+	 * @param array {
+	 *     Array of parameters. All items are optional.
+	 *     @type string $type Optional. Shorthand for certain orderby/
+	 *           order combinations. 'newest', 'active', 'popular',
+	 *           'alphabetical', 'random'. When present, will override
+	 *           orderby and order params. Default: null.
+	 *     @type string $orderby Optional. Property to sort by.
+	 *           'date_created', 'last_activity', 'total_member_count',
+	 *           'name', 'random'. Default: 'date_created'.
+	 *     @type string $order Optional. Sort order. 'ASC' or 'DESC'.
+	 *           Default: 'DESC'.
+	 *     @type int $per_page Optional. Number of items to return per page
+	 *           of results. Default: null (no limit).
+	 *     @type int $page Optional. Page offset of results to return.
+	 *           Default: null (no limit).
+	 *     @type int $user_id Optional. If provided, results will be limited
+	 *           to groups of which the specified user is a member. Default:
+	 *           null.
+	 *     @type string $search_terms Optional. If provided, only groups
+	 *           whose names or descriptions match the search terms will be
+	 *           returned. Default: false.
+	 *     @type array $meta_query Optional. An array of meta_query
+	 *           conditions. See {@link WP_Meta_Query::queries} for
+	 *           description.
+	 *     @type array|string Optional. Array or comma-separated list of
+	 *           group IDs. Results will be limited to groups within the
+	 *           list. Default: false.
+	 *     @type bool $populate_extras Whether to fetch additional
+	 *           information (such as member count) about groups. Default:
+	 *           true.
+	 *     @type array|string Optional. Array or comma-separated list of
+	 *           group IDs. Results will exclude the listed groups.
+	 *           Default: false.
+	 *     @type bool $show_hidden Whether to include hidden groups in
+	 *           results. Default: false.
+	 * }
+	 * @return array {
+	 *     @type array $groups Array of group objects returned by the
+	 *           paginated query.
+	 *     @type int $total Total count of all groups matching non-
+	 *           paginated query params.
+	 * }
+	 */
+	public static function get( $args = array() ) {
+		global $wpdb, $bp;
+
+		// Backward compatibility with old method of passing arguments
+		if ( ! is_array( $args ) || func_num_args() > 1 ) {
+			_deprecated_argument( __METHOD__, '1.7', sprintf( __( 'Arguments passed to %1$s should be in an associative array. See the inline documentation at %2$s for more details.', 'buddypress' ), __METHOD__, __FILE__ ) );
+
+			$old_args_keys = array(
+				0 => 'type',
+				1 => 'per_page',
+				2 => 'page',
+				3 => 'user_id',
+				4 => 'search_terms',
+				5 => 'include',
+				6 => 'populate_extras',
+				7 => 'exclude',
+				8 => 'show_hidden',
+			);
+
+			$func_args = func_get_args();
+			$args      = bp_core_parse_args_array( $old_args_keys, $func_args );
+		}
+
+		$defaults = array(
+			'type'            => null,
+			'orderby'         => 'date_created',
+			'order'           => 'DESC',
+			'per_page'        => null,
+			'page'            => null,
+			'user_id'         => 0,
+			'search_terms'    => false,
+			'meta_query'      => false,
+			'include'         => false,
+			'populate_extras' => true,
+			'exclude'         => false,
+			'show_hidden'     => false,
+		);
+
+		$r = wp_parse_args( $args, $defaults );
+
+		$sql       = array();
+		$total_sql = array();
+
+		$sql['select'] = "SELECT DISTINCT g.id, g.*, gm1.meta_value AS total_member_count, gm2.meta_value AS last_activity";
+		$sql['from']   = " FROM {$bp->groups->table_name_groupmeta} gm1, {$bp->groups->table_name_groupmeta} gm2,";
+
+		if ( ! empty( $r['user_id'] ) ) {
+			$sql['members_from'] = " {$bp->groups->table_name_members} m,";
+		}
+
+		$sql['group_from'] = " {$bp->groups->table_name} g WHERE";
+
+		if ( ! empty( $r['user_id'] ) ) {
+			$sql['user_where'] = " g.id = m.group_id AND";
+		}
+
+		$sql['where'] = " g.id = gm1.group_id AND g.id = gm2.group_id AND gm2.meta_key = 'last_activity' AND gm1.meta_key = 'total_member_count'";
+
+		if ( empty( $r['show_hidden'] ) ) {
+			$sql['hidden'] = " AND g.status != 'hidden'";
+		}
+
+		if ( ! empty( $r['search_terms'] ) ) {
+			$search_terms = esc_sql( like_escape( $r['search_terms'] ) );
+			$sql['search'] = " AND ( g.name LIKE '%%{$search_terms}%%' OR g.description LIKE '%%{$search_terms}%%' )";
+		}
+
+		$meta_query_sql = self::get_meta_query_sql( $r['meta_query'] );
+
+		if ( ! empty( $meta_query_sql['join'] ) ) {
+			$sql['from'] .= $meta_query_sql['join'];
+		}
+
+		if ( ! empty( $meta_query_sql['where'] ) ) {
+			$sql['meta'] = $meta_query_sql['where'];
+		}
+
+		if ( ! empty( $r['user_id'] ) ) {
+			$sql['user'] = $wpdb->prepare( " AND m.user_id = %d AND m.is_confirmed = 1 AND m.is_banned = 0", $r['user_id'] );
+		}
+
+		if ( ! empty( $r['include'] ) ) {
+			$include        = implode( ',', wp_parse_id_list( $r['include'] ) );
+			$sql['include'] = " AND g.id IN ({$include})";
+		}
+
+		if ( ! empty( $r['exclude'] ) ) {
+			$exclude        = implode( ',', wp_parse_id_list( $r['exclude'] ) );
+			$sql['exclude'] = " AND g.id NOT IN ({$exclude})";
+		}
+
+		/** Order/orderby ********************************************/
+
+		$order   = $r['order'];
+		$orderby = $r['orderby'];
+
+		// If a 'type' parameter was passed, parse it and overwrite
+		// 'order' and 'orderby' params passed to the function
+		if (  ! empty( $r['type'] ) ) {
+			$order_orderby = self::convert_type_to_order_orderby( $r['type'] );
+
+			// If an invalid type is passed, $order_orderby will be
+			// an array with empty values. In this case, we stick
+			// with the default values of $order and $orderby
+			if ( ! empty( $order_orderby['order'] ) ) {
+				$order = $order_orderby['order'];
+			}
+
+			if ( ! empty( $order_orderby['orderby'] ) ) {
+				$orderby = $order_orderby['orderby'];
+			}
+		}
+
+		// Sanitize 'order'
+		$order = bp_esc_sql_order( $order );
+
+		// Convert 'orderby' into the proper ORDER BY term
+		$orderby = self::convert_orderby_to_order_by_term( $orderby );
+
+		// Random order is a special case
+		if ( 'rand()' === $orderby ) {
+			$sql[] = "ORDER BY rand()";
+		} else {
+			$sql[] = "ORDER BY {$orderby} {$order}";
+		}
+
+		if ( ! empty( $r['per_page'] ) && ! empty( $r['page'] ) ) {
+			$sql['pagination'] = $wpdb->prepare( "LIMIT %d, %d", intval( ( $r['page'] - 1 ) * $r['per_page']), intval( $r['per_page'] ) );
+		}
+
+		// Get paginated results
+		$paged_groups_sql = apply_filters( 'bp_groups_get_paged_groups_sql', join( ' ', (array) $sql ), $sql, $r );
+		$paged_groups     = $wpdb->get_results( $paged_groups_sql );
+
+		$total_sql['select'] = "SELECT COUNT(DISTINCT g.id) FROM {$bp->groups->table_name} g, {$bp->groups->table_name_members} gm1, {$bp->groups->table_name_groupmeta} gm2";
+
+		if ( ! empty( $r['user_id'] ) ) {
+			$total_sql['select'] .= ", {$bp->groups->table_name_members} m";
+		}
+
+		if ( ! empty( $sql['hidden'] ) ) {
+			$total_sql['where'][] = "g.status != 'hidden'";
+		}
+
+		if ( ! empty( $sql['search'] ) ) {
+			$total_sql['where'][] = "( g.name LIKE '%%{$search_terms}%%' OR g.description LIKE '%%{$search_terms}%%' )";
+		}
+
+		if ( ! empty( $r['user_id'] ) ) {
+			$total_sql['where'][] = $wpdb->prepare( "m.group_id = g.id AND m.user_id = %d AND m.is_confirmed = 1 AND m.is_banned = 0", $r['user_id'] );
+		}
+
+		// Temporary implementation of meta_query for total count
+		// See #5099
+		if ( ! empty( $meta_query_sql['where'] ) ) {
+			// Join the groupmeta table
+			$total_sql['select'] .= ", ". substr( $meta_query_sql['join'], 0, -2 );
+
+			// Modify the meta_query clause from paged_sql for our syntax
+			$meta_query_clause = preg_replace( '/^\s*AND/', '', $meta_query_sql['where'] );
+			$total_sql['where'][] = $meta_query_clause;
+		}
+
+		// Already escaped in the paginated results block
+		if ( ! empty( $include ) ) {
+			$total_sql['where'][] = "g.id IN ({$include})";
+		}
+
+		// Already escaped in the paginated results block
+		if ( ! empty( $exclude ) ) {
+			$total_sql['where'][] = "g.id NOT IN ({$exclude})";
+		}
+
+		$total_sql['where'][] = "g.id = gm1.group_id";
+		$total_sql['where'][] = "g.id = gm2.group_id";
+		$total_sql['where'][] = "gm2.meta_key = 'last_activity'";
+
+		$t_sql = $total_sql['select'];
+
+		if ( ! empty( $total_sql['where'] ) ) {
+			$t_sql .= " WHERE " . join( ' AND ', (array) $total_sql['where'] );
+		}
+
+		// Get total group results
+		$total_groups_sql = apply_filters( 'bp_groups_get_total_groups_sql', $t_sql, $total_sql, $r );
+		$total_groups     = $wpdb->get_var( $total_groups_sql );
+
+		$group_ids = array();
+		foreach ( (array) $paged_groups as $group ) {
+			$group_ids[] = $group->id;
+		}
+
+		// Populate some extra information instead of querying each time in the loop
+		if ( !empty( $r['populate_extras'] ) ) {
+			$paged_groups = BP_Groups_Group::get_group_extras( $paged_groups, $group_ids, $r['type'] );
+		}
+
+		// Grab all groupmeta
+		bp_groups_update_meta_cache( $group_ids );
+
+		unset( $sql, $total_sql );
+
+		return array( 'groups' => $paged_groups, 'total' => $total_groups );
+	}
+
+	/**
+	 * Get the SQL for the 'meta_query' param in BP_Activity_Activity::get()
+	 *
+	 * We use WP_Meta_Query to do the heavy lifting of parsing the
+	 * meta_query array and creating the necessary SQL clauses. However,
+	 * since BP_Activity_Activity::get() builds its SQL differently than
+	 * WP_Query, we have to alter the return value (stripping the leading
+	 * AND keyword from the 'where' clause).
+	 *
+	 * @since BuddyPress (1.8.0)
+	 * @access protected
+	 *
+	 * @param array $meta_query An array of meta_query filters. See the
+	 *        documentation for {@link WP_Meta_Query} for details.
+	 * @return array $sql_array 'join' and 'where' clauses.
+	 */
+	protected static function get_meta_query_sql( $meta_query = array() ) {
+		global $wpdb;
+
+		$sql_array = array(
+			'join'  => '',
+			'where' => '',
+		);
+
+		if ( ! empty( $meta_query ) ) {
+			$groups_meta_query = new WP_Meta_Query( $meta_query );
+
+			// WP_Meta_Query expects the table name at
+			// $wpdb->group
+			$wpdb->groupmeta = buddypress()->groups->table_name_groupmeta;
+
+			$meta_sql = $groups_meta_query->get_sql( 'group', 'g', 'id' );
+
+			// BP_Groups_Group::get uses the comma syntax for table
+			// joins, which means that we have to do some regex to
+			// convert the INNER JOIN and move the ON clause to a
+			// WHERE condition
+			//
+			// @todo It may be better in the long run to refactor
+			// the more general query syntax to accord better with
+			// BP/WP convention
+			preg_match_all( '/INNER JOIN (.*) ON/', $meta_sql['join'], $matches_a );
+			preg_match_all( '/ON \((.*)\)/', $meta_sql['join'], $matches_b );
+
+			if ( ! empty( $matches_a[1] ) && ! empty( $matches_b[1] ) ) {
+				$sql_array['join']  = implode( ',', $matches_a[1] ). ', ';
+
+				$sql_array['where'] = '';
+
+				$meta_query_where_clauses = explode( "\n", $meta_sql['where'] );
+				foreach( $matches_b[1] as $key => $group_id_clause ) {
+					$sql_array['where'] .= ' ' . preg_replace( '/^(AND\s+[\(\s]+)/', '$1' . $group_id_clause . ' AND ', ltrim( $meta_query_where_clauses[ $key ] ) );
+				}
+
+			}
+		}
+
+		return $sql_array;
+	}
+
+	/**
+	 * Convert the 'type' parameter to 'order' and 'orderby'.
+	 *
+	 * @since BuddyPress (1.8.0)
+	 * @access protected
+	 *
+	 * @param string $type The 'type' shorthand param.
+	 * @return array {
+	 *	@type string $order SQL-friendly order string.
+	 *	@type string $orderby SQL-friendly orderby column name.
+	 * }
+	 */
+	protected static function convert_type_to_order_orderby( $type = '' ) {
+		$order = $orderby = '';
+
+		switch ( $type ) {
+			case 'newest' :
+				$order   = 'DESC';
+				$orderby = 'date_created';
+				break;
+
+			case 'active' :
+				$order   = 'DESC';
+				$orderby = 'last_activity';
+				break;
+
+			case 'popular' :
+				$order   = 'DESC';
+				$orderby = 'total_member_count';
+				break;
+
+			case 'alphabetical' :
+				$order   = 'ASC';
+				$orderby = 'name';
+				break;
+
+			case 'random' :
+				$order   = '';
+				$orderby = 'random';
+				break;
+		}
+
+		return array( 'order' => $order, 'orderby' => $orderby );
+	}
+
+	/**
+	 * Convert the 'orderby' param into a proper SQL term/column.
+	 *
+	 * @since BuddyPress (1.8.0)
+	 * @access protected
+	 *
+	 * @param string $orderby Orderby term as passed to get().
+	 * @return string $order_by_term SQL-friendly orderby term.
+	 */
+	protected static function convert_orderby_to_order_by_term( $orderby ) {
+		$order_by_term = '';
+
+		switch ( $orderby ) {
+			case 'date_created' :
+			default :
+				$order_by_term = 'g.date_created';
+				break;
+
+			case 'last_activity' :
+				$order_by_term = 'last_activity';
+				break;
+
+			case 'total_member_count' :
+				$order_by_term = 'CONVERT(gm1.meta_value, SIGNED)';
+				break;
+
+			case 'name' :
+				$order_by_term = 'g.name';
+				break;
+
+			case 'random' :
+				$order_by_term = 'rand()';
+				break;
+		}
+
+		return $order_by_term;
+	}
+
+	/**
+	 * Get a list of groups, sorted by those that have the most legacy forum topics.
+	 *
+	 * @param int $limit Optional. The max number of results to return.
+	 *        Default: null (no limit).
+	 * @param int $page Optional. The page offset of results to return.
+	 *        Default: null (no limit).
+	 * @param int $user_id Optional. If present, groups will be limited to
+	 *        those of which the specified user is a member.
+	 * @param string $search_terms Optional. Limit groups to those whose
+	 *        name or description field contain the search string.
+	 * @param bool $populate_extras Optional. Whether to fetch extra
+	 *        information about the groups. Default: true.
+	 * @param string|array Optional. Array or comma-separated list of group
+	 *        IDs to exclude from results.
+	 * @return array {
+	 *     @type array $groups Array of group objects returned by the
+	 *           paginated query.
+	 *     @type int $total Total count of all groups matching non-
+	 *           paginated query params.
+	 * }
+	 */
+	public static function get_by_most_forum_topics( $limit = null, $page = null, $user_id = 0, $search_terms = false, $populate_extras = true, $exclude = false ) {
+		global $wpdb, $bp, $bbdb;
+
+		if ( empty( $bbdb ) )
+			do_action( 'bbpress_init' );
+
+		if ( !empty( $limit ) && !empty( $page ) ) {
+			$pag_sql = $wpdb->prepare( " LIMIT %d, %d", intval( ( $page - 1 ) * $limit), intval( $limit ) );
+		}
+
+		if ( !is_user_logged_in() || ( !bp_current_user_can( 'bp_moderate' ) && ( $user_id != bp_loggedin_user_id() ) ) )
+			$hidden_sql = " AND g.status != 'hidden'";
+
+		if ( !empty( $search_terms ) ) {
+			$search_terms = esc_sql( like_escape( $search_terms ) );
+			$search_sql = " AND ( g.name LIKE '%%{$search_terms}%%' OR g.description LIKE '%%{$search_terms}%%' )";
+		}
+
+		if ( !empty( $exclude ) ) {
+			$exclude     = implode( ',', wp_parse_id_list( $exclude ) );
+			$exclude_sql = " AND g.id NOT IN ({$exclude})";
+		}
+
+		if ( !empty( $user_id ) ) {
+			$user_id      = absint( esc_sql( $user_id ) );
+			$paged_groups = $wpdb->get_results( "SELECT DISTINCT g.*, gm1.meta_value as total_member_count, gm2.meta_value as last_activity FROM {$bp->groups->table_name_groupmeta} gm1, {$bp->groups->table_name_groupmeta} gm2, {$bp->groups->table_name_groupmeta} gm3, {$bp->groups->table_name_members} m, {$bbdb->forums} f, {$bp->groups->table_name} g WHERE g.id = m.group_id AND g.id = gm1.group_id AND g.id = gm2.group_id AND g.id = gm3.group_id AND gm2.meta_key = 'last_activity' AND gm1.meta_key = 'total_member_count' AND (gm3.meta_key = 'forum_id' AND gm3.meta_value = f.forum_id) AND f.topics > 0 {$hidden_sql} {$search_sql} AND m.user_id = {$user_id} AND m.is_confirmed = 1 AND m.is_banned = 0 {$exclude_sql} ORDER BY f.topics DESC {$pag_sql}" );
+			$total_groups = $wpdb->get_var( "SELECT COUNT(DISTINCT g.id) FROM {$bp->groups->table_name_groupmeta} gm1, {$bp->groups->table_name_groupmeta} gm2, {$bp->groups->table_name_groupmeta} gm3, {$bbdb->forums} f, {$bp->groups->table_name} g WHERE g.id = gm1.group_id AND g.id = gm2.group_id AND g.id = gm3.group_id AND gm2.meta_key = 'last_activity' AND gm1.meta_key = 'total_member_count' AND (gm3.meta_key = 'forum_id' AND gm3.meta_value = f.forum_id) AND f.topics > 0 {$hidden_sql} {$search_sql} AND m.user_id = {$user_id} AND m.is_confirmed = 1 AND m.is_banned = 0 {$exclude_sql}" );
+		} else {
+			$paged_groups = $wpdb->get_results( "SELECT DISTINCT g.*, gm1.meta_value as total_member_count, gm2.meta_value as last_activity FROM {$bp->groups->table_name_groupmeta} gm1, {$bp->groups->table_name_groupmeta} gm2, {$bp->groups->table_name_groupmeta} gm3, {$bbdb->forums} f, {$bp->groups->table_name} g WHERE g.id = gm1.group_id AND g.id = gm2.group_id AND g.id = gm3.group_id AND gm2.meta_key = 'last_activity' AND gm1.meta_key = 'total_member_count' AND (gm3.meta_key = 'forum_id' AND gm3.meta_value = f.forum_id) AND f.topics > 0 {$hidden_sql} {$search_sql} {$exclude_sql} ORDER BY f.topics DESC {$pag_sql}" );
+			$total_groups = $wpdb->get_var( "SELECT COUNT(DISTINCT g.id) FROM {$bp->groups->table_name_groupmeta} gm1, {$bp->groups->table_name_groupmeta} gm2, {$bp->groups->table_name_groupmeta} gm3, {$bbdb->forums} f, {$bp->groups->table_name} g WHERE g.id = gm1.group_id AND g.id = gm2.group_id AND g.id = gm3.group_id AND gm2.meta_key = 'last_activity' AND gm1.meta_key = 'total_member_count' AND (gm3.meta_key = 'forum_id' AND gm3.meta_value = f.forum_id) AND f.topics > 0 {$hidden_sql} {$search_sql} {$exclude_sql}" );
+		}
+
+		if ( !empty( $populate_extras ) ) {
+			foreach ( (array) $paged_groups as $group ) {
+				$group_ids[] = $group->id;
+			}
+			$paged_groups = BP_Groups_Group::get_group_extras( $paged_groups, $group_ids, 'newest' );
+		}
+
+		return array( 'groups' => $paged_groups, 'total' => $total_groups );
+	}
+
+	/**
+	 * Get a list of groups, sorted by those that have the most legacy forum posts.
+	 *
+	 * @param int $limit Optional. The max number of results to return.
+	 *        Default: null (no limit).
+	 * @param int $page Optional. The page offset of results to return.
+	 *        Default: null (no limit).
+	 * @param int $user_id Optional. If present, groups will be limited to
+	 *        those of which the specified user is a member.
+	 * @param string $search_terms Optional. Limit groups to those whose
+	 *        name or description field contain the search string.
+	 * @param bool $populate_extras Optional. Whether to fetch extra
+	 *        information about the groups. Default: true.
+	 * @param string|array Optional. Array or comma-separated list of group
+	 *        IDs to exclude from results.
+	 * @return array {
+	 *     @type array $groups Array of group objects returned by the
+	 *           paginated query.
+	 *     @type int $total Total count of all groups matching non-
+	 *           paginated query params.
+	 * }
+	 */
+	public static function get_by_most_forum_posts( $limit = null, $page = null, $search_terms = false, $populate_extras = true, $exclude = false ) {
+		global $wpdb, $bp, $bbdb;
+
+		if ( empty( $bbdb ) )
+			do_action( 'bbpress_init' );
+
+		if ( !empty( $limit ) && !empty( $page ) ) {
+			$pag_sql = $wpdb->prepare( " LIMIT %d, %d", intval( ( $page - 1 ) * $limit), intval( $limit ) );
+		}
+
+		if ( !is_user_logged_in() || ( !bp_current_user_can( 'bp_moderate' ) && ( $user_id != bp_loggedin_user_id() ) ) )
+			$hidden_sql = " AND g.status != 'hidden'";
+
+		if ( !empty( $search_terms ) ) {
+			$search_terms = esc_sql( like_escape( $search_terms ) );
+			$search_sql = " AND ( g.name LIKE '%%{$search_terms}%%' OR g.description LIKE '%%{$search_terms}%%' )";
+		}
+
+		if ( !empty( $exclude ) ) {
+			$exclude     = implode( ',', wp_parse_id_list( $exclude ) );
+			$exclude_sql = " AND g.id NOT IN ({$exclude})";
+		}
+
+		if ( !empty( $user_id ) ) {
+			$user_id = esc_sql( $user_id );
+			$paged_groups = $wpdb->get_results( "SELECT DISTINCT g.*, gm1.meta_value as total_member_count, gm2.meta_value as last_activity FROM {$bp->groups->table_name_groupmeta} gm1, {$bp->groups->table_name_groupmeta} gm2, {$bp->groups->table_name_groupmeta} gm3, {$bp->groups->table_name_members} m, {$bbdb->forums} f, {$bp->groups->table_name} g WHERE g.id = m.group_id AND g.id = gm1.group_id AND g.id = gm2.group_id AND g.id = gm3.group_id AND gm2.meta_key = 'last_activity' AND gm1.meta_key = 'total_member_count' AND (gm3.meta_key = 'forum_id' AND gm3.meta_value = f.forum_id) {$hidden_sql} {$search_sql} AND m.user_id = {$user_id} AND m.is_confirmed = 1 AND m.is_banned = 0 {$exclude_sql} ORDER BY f.posts ASC {$pag_sql}" );
+			$total_groups = $wpdb->get_results( "SELECT COUNT(DISTINCT g.id) FROM {$bp->groups->table_name_groupmeta} gm1, {$bp->groups->table_name_groupmeta} gm2, {$bp->groups->table_name_groupmeta} gm3, {$bp->groups->table_name_members} m, {$bbdb->forums} f, {$bp->groups->table_name} g WHERE g.id = m.group_id AND g.id = gm1.group_id AND g.id = gm2.group_id AND g.id = gm3.group_id AND gm2.meta_key = 'last_activity' AND gm1.meta_key = 'total_member_count' AND (gm3.meta_key = 'forum_id' AND gm3.meta_value = f.forum_id) AND f.posts > 0 {$hidden_sql} {$search_sql} AND m.user_id = {$user_id} AND m.is_confirmed = 1 AND m.is_banned = 0 {$exclude_sql} " );
+		} else {
+			$paged_groups = $wpdb->get_results( "SELECT DISTINCT g.*, gm1.meta_value as total_member_count, gm2.meta_value as last_activity FROM {$bp->groups->table_name_groupmeta} gm1, {$bp->groups->table_name_groupmeta} gm2, {$bp->groups->table_name_groupmeta} gm3, {$bbdb->forums} f, {$bp->groups->table_name} g WHERE g.id = gm1.group_id AND g.id = gm2.group_id AND g.id = gm3.group_id AND gm2.meta_key = 'last_activity' AND gm1.meta_key = 'total_member_count' AND (gm3.meta_key = 'forum_id' AND gm3.meta_value = f.forum_id) AND f.posts > 0 {$hidden_sql} {$search_sql} {$exclude_sql} ORDER BY f.posts ASC {$pag_sql}" );
+			$total_groups = $wpdb->get_var( "SELECT COUNT(DISTINCT g.id) FROM {$bp->groups->table_name_groupmeta} gm1, {$bp->groups->table_name_groupmeta} gm2, {$bp->groups->table_name_groupmeta} gm3, {$bbdb->forums} f, {$bp->groups->table_name} g WHERE g.id = gm1.group_id AND g.id = gm2.group_id AND g.id = gm3.group_id AND gm2.meta_key = 'last_activity' AND gm1.meta_key = 'total_member_count' AND (gm3.meta_key = 'forum_id' AND gm3.meta_value = f.forum_id) {$hidden_sql} {$search_sql} {$exclude_sql}" );
+		}
+
+		if ( !empty( $populate_extras ) ) {
+			foreach ( (array) $paged_groups as $group ) {
+				$group_ids[] = $group->id;
+			}
+			$paged_groups = BP_Groups_Group::get_group_extras( $paged_groups, $group_ids, 'newest' );
+		}
+
+		return array( 'groups' => $paged_groups, 'total' => $total_groups );
+	}
+
+	/**
+	 * Get a list of groups whose names start with a given letter.
+	 *
+	 * @param string $letter The letter.
+	 * @param int $limit Optional. The max number of results to return.
+	 *        Default: null (no limit).
+	 * @param int $page Optional. The page offset of results to return.
+	 *        Default: null (no limit).
+	 * @param bool $populate_extras Optional. Whether to fetch extra
+	 *        information about the groups. Default: true.
+	 * @param string|array Optional. Array or comma-separated list of group
+	 *        IDs to exclude from results.
+	 * @return array {
+	 *     @type array $groups Array of group objects returned by the
+	 *           paginated query.
+	 *     @type int $total Total count of all groups matching non-
+	 *           paginated query params.
+	 * }
+	 */
+	public static function get_by_letter( $letter, $limit = null, $page = null, $populate_extras = true, $exclude = false ) {
+		global $wpdb, $bp;
+
+		$pag_sql = $hidden_sql = $exclude_sql = '';
+
+		// Multibyte compliance
+		if ( function_exists( 'mb_strlen' ) ) {
+			if ( mb_strlen( $letter, 'UTF-8' ) > 1 || is_numeric( $letter ) || !$letter ) {
+				return false;
+			}
+		} else {
+			if ( strlen( $letter ) > 1 || is_numeric( $letter ) || !$letter ) {
+				return false;
+			}
+		}
+
+		if ( !empty( $exclude ) ) {
+			$exclude     = implode( ',', wp_parse_id_list( $exclude ) );
+			$exclude_sql = " AND g.id NOT IN ({$exclude})";
+		}
+
+		if ( !bp_current_user_can( 'bp_moderate' ) )
+			$hidden_sql = " AND status != 'hidden'";
+
+		$letter = esc_sql( like_escape( $letter ) );
+
+		if ( !empty( $limit ) && !empty( $page ) ) {
+			$pag_sql      = $wpdb->prepare( " LIMIT %d, %d", intval( ( $page - 1 ) * $limit), intval( $limit ) );
+		}
+
+		$total_groups = $wpdb->get_var( "SELECT COUNT(DISTINCT g.id) FROM {$bp->groups->table_name_groupmeta} gm1, {$bp->groups->table_name_groupmeta} gm2, {$bp->groups->table_name} g WHERE g.id = gm1.group_id AND g.id = gm2.group_id AND gm2.meta_key = 'last_activity' AND gm1.meta_key = 'total_member_count' AND g.name LIKE '{$letter}%%' {$hidden_sql} {$exclude_sql}" );
+
+		$paged_groups = $wpdb->get_results( "SELECT g.*, gm1.meta_value as total_member_count, gm2.meta_value as last_activity FROM {$bp->groups->table_name_groupmeta} gm1, {$bp->groups->table_name_groupmeta} gm2, {$bp->groups->table_name} g WHERE g.id = gm1.group_id AND g.id = gm2.group_id AND gm2.meta_key = 'last_activity' AND gm1.meta_key = 'total_member_count' AND g.name LIKE '{$letter}%%' {$hidden_sql} {$exclude_sql} ORDER BY g.name ASC {$pag_sql}" );
+
+		if ( !empty( $populate_extras ) ) {
+			foreach ( (array) $paged_groups as $group ) {
+				$group_ids[] = $group->id;
+			}
+			$paged_groups = BP_Groups_Group::get_group_extras( $paged_groups, $group_ids, 'newest' );
+		}
+
+		return array( 'groups' => $paged_groups, 'total' => $total_groups );
+	}
+
+	/**
+	 * Get a list of random groups.
+	 *
+	 * Use BP_Groups_Group::get() with 'type' = 'random' instead.
+	 *
+	 * @param int $limit Optional. The max number of results to return.
+	 *        Default: null (no limit).
+	 * @param int $page Optional. The page offset of results to return.
+	 *        Default: null (no limit).
+	 * @param int $user_id Optional. If present, groups will be limited to
+	 *        those of which the specified user is a member.
+	 * @param string $search_terms Optional. Limit groups to those whose
+	 *        name or description field contain the search string.
+	 * @param bool $populate_extras Optional. Whether to fetch extra
+	 *        information about the groups. Default: true.
+	 * @param string|array Optional. Array or comma-separated list of group
+	 *        IDs to exclude from results.
+	 * @return array {
+	 *     @type array $groups Array of group objects returned by the
+	 *           paginated query.
+	 *     @type int $total Total count of all groups matching non-
+	 *           paginated query params.
+	 * }
+	 */
+	public static function get_random( $limit = null, $page = null, $user_id = 0, $search_terms = false, $populate_extras = true, $exclude = false ) {
+		global $wpdb, $bp;
+
+		$pag_sql = $hidden_sql = $search_sql = $exclude_sql = '';
+
+		if ( !empty( $limit ) && !empty( $page ) )
+			$pag_sql = $wpdb->prepare( " LIMIT %d, %d", intval( ( $page - 1 ) * $limit), intval( $limit ) );
+
+		if ( !is_user_logged_in() || ( !bp_current_user_can( 'bp_moderate' ) && ( $user_id != bp_loggedin_user_id() ) ) )
+			$hidden_sql = "AND g.status != 'hidden'";
+
+		if ( !empty( $search_terms ) ) {
+			$search_terms = esc_sql( like_escape( $search_terms ) );
+			$search_sql = " AND ( g.name LIKE '%%{$search_terms}%%' OR g.description LIKE '%%{$search_terms}%%' )";
+		}
+
+		if ( !empty( $exclude ) ) {
+			$exclude     = wp_parse_id_list( $exclude );
+			$exclude     = esc_sql( implode( ',', $exclude ) );
+			$exclude_sql = " AND g.id NOT IN ({$exclude})";
+		}
+
+		if ( !empty( $user_id ) ) {
+			$user_id = esc_sql( $user_id );
+			$paged_groups = $wpdb->get_results( "SELECT g.*, gm1.meta_value as total_member_count, gm2.meta_value as last_activity FROM {$bp->groups->table_name_groupmeta} gm1, {$bp->groups->table_name_groupmeta} gm2, {$bp->groups->table_name_members} m, {$bp->groups->table_name} g WHERE g.id = m.group_id AND g.id = gm1.group_id AND g.id = gm2.group_id AND gm2.meta_key = 'last_activity' AND gm1.meta_key = 'total_member_count' {$hidden_sql} {$search_sql} AND m.user_id = {$user_id} AND m.is_confirmed = 1 AND m.is_banned = 0 {$exclude_sql} ORDER BY rand() {$pag_sql}" );
+			$total_groups = $wpdb->get_var( "SELECT COUNT(DISTINCT m.group_id) FROM {$bp->groups->table_name_members} m LEFT JOIN {$bp->groups->table_name_groupmeta} gm ON m.group_id = gm.group_id INNER JOIN {$bp->groups->table_name} g ON m.group_id = g.id WHERE gm.meta_key = 'last_activity'{$hidden_sql} {$search_sql} AND m.user_id = {$user_id} AND m.is_confirmed = 1 AND m.is_banned = 0 {$exclude_sql}" );
+		} else {
+			$paged_groups = $wpdb->get_results( "SELECT g.*, gm1.meta_value as total_member_count, gm2.meta_value as last_activity FROM {$bp->groups->table_name_groupmeta} gm1, {$bp->groups->table_name_groupmeta} gm2, {$bp->groups->table_name} g WHERE g.id = gm1.group_id AND g.id = gm2.group_id AND gm2.meta_key = 'last_activity' AND gm1.meta_key = 'total_member_count' {$hidden_sql} {$search_sql} {$exclude_sql} ORDER BY rand() {$pag_sql}" );
+			$total_groups = $wpdb->get_var( "SELECT COUNT(DISTINCT g.id) FROM {$bp->groups->table_name_groupmeta} gm INNER JOIN {$bp->groups->table_name} g ON gm.group_id = g.id WHERE gm.meta_key = 'last_activity'{$hidden_sql} {$search_sql} {$exclude_sql}" );
+		}
+
+		if ( !empty( $populate_extras ) ) {
+			foreach ( (array) $paged_groups as $group ) {
+				$group_ids[] = $group->id;
+			}
+			$paged_groups = BP_Groups_Group::get_group_extras( $paged_groups, $group_ids, 'newest' );
+		}
+
+		return array( 'groups' => $paged_groups, 'total' => $total_groups );
+	}
+
+	/**
+	 * Fetch extra data for a list of groups.
+	 *
+	 * This method is used throughout the class, by methods that take a
+	 * $populate_extras parameter.
+	 *
+	 * Data fetched:
+	 *
+	 *     - Logged-in user's status within each group (is_member,
+	 *       is_confirmed, is_pending, is_banned)
+	 *
+	 * @param array $paged_groups Array of groups.
+	 * @param string|array Array or comma-separated list of IDs matching
+	 *        $paged_groups.
+	 * @param string $type Not used.
+	 * @return array $paged_groups
+	 */
+	public static function get_group_extras( &$paged_groups, &$group_ids, $type = false ) {
+		global $bp, $wpdb;
+
+		if ( empty( $group_ids ) )
+			return $paged_groups;
+
+		// Sanitize group IDs
+		$group_ids = implode( ',', wp_parse_id_list( $group_ids ) );
+
+		// Fetch the logged-in user's status within each group
+		$user_status_results = $wpdb->get_results( $wpdb->prepare( "SELECT group_id, is_confirmed, invite_sent FROM {$bp->groups->table_name_members} WHERE user_id = %d AND group_id IN ( {$group_ids} ) AND is_banned = 0", bp_loggedin_user_id() ) );
+
+		// Reindex
+		$user_status = array();
+		foreach ( $user_status_results as $user_status_result ) {
+			$user_status[ $user_status_result->group_id ] = $user_status_result;
+		}
+
+		for ( $i = 0, $count = count( $paged_groups ); $i < $count; ++$i ) {
+			$is_member = $is_invited = $is_pending = '0';
+			$gid = $paged_groups[ $i ]->id;
+
+			if ( isset( $user_status[ $gid ] ) ) {
+
+				// is_confirmed means the user is a member
+				if ( $user_status[ $gid ]->is_confirmed ) {
+					$is_member = '1';
+
+				// invite_sent means the user has been invited
+				} else if ( $user_status[ $gid ]->invite_sent ) {
+					$is_invited = '1';
+
+				// User has sent request, but has not been confirmed
+				} else {
+					$is_pending = '1';
+				}
+			}
+
+			$paged_groups[ $i ]->is_member = $is_member;
+			$paged_groups[ $i ]->is_invited = $is_invited;
+			$paged_groups[ $i ]->is_pending = $is_pending;
+		}
+
+		$user_banned = $wpdb->get_col( $wpdb->prepare( "SELECT group_id FROM {$bp->groups->table_name_members} WHERE is_banned = 1 AND user_id = %d AND group_id IN ( {$group_ids} )", bp_loggedin_user_id() ) );
+		for ( $i = 0, $count = count( $paged_groups ); $i < $count; ++$i ) {
+			$paged_groups[$i]->is_banned = false;
+
+			foreach ( (array) $user_banned as $group_id ) {
+				if ( $group_id == $paged_groups[$i]->id ) {
+					$paged_groups[$i]->is_banned = true;
+				}
+			}
+		}
+
+		return $paged_groups;
+	}
+
+	/**
+	 * Delete all invitations to a given group.
+	 *
+	 * @param int $group_id ID of the group whose invitations are being
+	 *        deleted.
+	 * @return int|null Number of rows records deleted on success, null on
+	 *         failure.
+	 */
+	public static function delete_all_invites( $group_id ) {
+		global $wpdb, $bp;
+
+		return $wpdb->query( $wpdb->prepare( "DELETE FROM {$bp->groups->table_name_members} WHERE group_id = %d AND invite_sent = 1", $group_id ) );
+	}
+
+	/**
+	 * Get a total group count for the site.
+	 *
+	 * Will include hidden groups in the count only if
+	 * current_user_can( 'bp_moderate' ).
+	 *
+	 * @return int Group count.
+	 */
+	public static function get_total_group_count() {
+		global $wpdb, $bp;
+
+		$hidden_sql = '';
+		if ( !bp_current_user_can( 'bp_moderate' ) )
+			$hidden_sql = "WHERE status != 'hidden'";
+
+		return $wpdb->get_var( "SELECT COUNT(id) FROM {$bp->groups->table_name} {$hidden_sql}" );
+	}
+
+	/**
+	 * Get global count of forum topics in public groups (legacy forums).
+	 *
+	 * @param $type Optional. If 'unreplied', count will be limited to
+	 *        those topics that have received no replies.
+	 * @return int Forum topic count.
+	 */
+	public static function get_global_forum_topic_count( $type ) {
+		global $bbdb, $wpdb, $bp;
+
+		if ( 'unreplied' == $type )
+			$bp->groups->filter_sql = ' AND t.topic_posts = 1';
+
+		// https://buddypress.trac.wordpress.org/ticket/4306
+		$extra_sql = apply_filters( 'get_global_forum_topic_count_extra_sql', $bp->groups->filter_sql, $type );
+
+		// Make sure the $extra_sql begins with an AND
+		if ( 'AND' != substr( trim( strtoupper( $extra_sql ) ), 0, 3 ) )
+			$extra_sql = ' AND ' . $extra_sql;
+
+		return $wpdb->get_var( "SELECT COUNT(t.topic_id) FROM {$bbdb->topics} AS t, {$bp->groups->table_name} AS g LEFT JOIN {$bp->groups->table_name_groupmeta} AS gm ON g.id = gm.group_id WHERE (gm.meta_key = 'forum_id' AND gm.meta_value = t.forum_id) AND g.status = 'public' AND t.topic_status = '0' AND t.topic_sticky != '2' {$extra_sql} " );
+	}
+
+	/**
+	 * Get the member count for a group.
+	 *
+	 * @param int $group_id Group ID.
+	 * @return int Count of confirmed members for the group.
+	 */
+	public static function get_total_member_count( $group_id ) {
+		global $wpdb, $bp;
+
+		return $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(id) FROM {$bp->groups->table_name_members} WHERE group_id = %d AND is_confirmed = 1 AND is_banned = 0", $group_id ) );
+	}
+
+	/**
+	 * Get a total count of all topics of a given status, across groups/forums
+	 *
+	 * @since BuddyPress (1.5.0)
+	 *
+	 * @param string $status Which group type to count. 'public', 'private',
+	 *        'hidden', or 'all'. Default: 'public'.
+	 * @return int The topic count
+	 */
+	public static function get_global_topic_count( $status = 'public', $search_terms = false ) {
+		global $bbdb, $wpdb, $bp;
+
+		switch ( $status ) {
+			case 'all' :
+				$status_sql = '';
+				break;
+
+			case 'hidden' :
+				$status_sql = "AND g.status = 'hidden'";
+				break;
+
+			case 'private' :
+				$status_sql = "AND g.status = 'private'";
+				break;
+
+			case 'public' :
+			default :
+				$status_sql = "AND g.status = 'public'";
+				break;
+		}
+
+		$sql = array();
+
+		$sql['select'] = "SELECT COUNT(t.topic_id)";
+		$sql['from']   = "FROM {$bbdb->topics} AS t INNER JOIN {$bp->groups->table_name_groupmeta} AS gm ON t.forum_id = gm.meta_value INNER JOIN {$bp->groups->table_name} AS g ON gm.group_id = g.id";
+		$sql['where']  = "WHERE gm.meta_key = 'forum_id' {$status_sql} AND t.topic_status = '0' AND t.topic_sticky != '2'";
+
+		if ( !empty( $search_terms ) ) {
+			$st = esc_sql( like_escape( $search_terms ) );
+			$sql['where'] .= " AND (  t.topic_title LIKE '%{$st}%' )";
+		}
+
+		return $wpdb->get_var( implode( ' ', $sql ) );
+	}
+
+	/**
+	 * Get an array containing ids for each group type.
+	 *
+	 * A bit of a kludge workaround for some issues
+	 * with bp_has_groups().
+	 *
+	 * @since BuddyPress (1.7.0)
+	 *
+	 * @return array
+	 */
+	public static function get_group_type_ids() {
+		global $wpdb, $bp;
+
+		$ids = array();
+
+		$ids['all']     = $wpdb->get_col( "SELECT id FROM {$bp->groups->table_name}" );
+		$ids['public']  = $wpdb->get_col( "SELECT id FROM {$bp->groups->table_name} WHERE status = 'public'" );
+		$ids['private'] = $wpdb->get_col( "SELECT id FROM {$bp->groups->table_name} WHERE status = 'private'" );
+		$ids['hidden']  = $wpdb->get_col( "SELECT id FROM {$bp->groups->table_name} WHERE status = 'hidden'" );
+
+		return $ids;
+	}
+}
+
+/**
+ * Query for the members of a group.
+ *
+ * @since BuddyPress (1.8.0)
+ */
+class BP_Group_Member_Query extends BP_User_Query {
+
+	/**
+	 * Array of group member ids, cached to prevent redundant lookups.
+	 *
+	 * @since BuddyPress (1.8.1)
+	 * @var null|array Null if not yet defined, otherwise an array of ints.
+	 */
+	protected $group_member_ids;
+
+	/**
+	 * Set up action hooks.
+	 *
+	 * @since BuddyPress (1.8.0)
+	 */
+	public function setup_hooks() {
+		// Take this early opportunity to set the default 'type' param
+		// to 'last_modified', which will ensure that BP_User_Query
+		// trusts our order and does not try to apply its own
+		if ( empty( $this->query_vars_raw['type'] ) ) {
+			$this->query_vars_raw['type'] = 'last_modified';
+		}
+
+		// Set the sort order
+		add_action( 'bp_pre_user_query', array( $this, 'set_orderby' ) );
+
+		// Set up our populate_extras method
+		add_action( 'bp_user_query_populate_extras', array( $this, 'populate_group_member_extras' ), 10, 2 );
+	}
+
+	/**
+	 * Get a list of user_ids to include in the IN clause of the main query.
+	 *
+	 * Overrides BP_User_Query::get_include_ids(), adding our additional
+	 * group-member logic.
+	 *
+	 * @since BuddyPress (1.8.0)
+	 *
+	 * @param array $include Existing group IDs in the $include parameter,
+	 *        as calculated in BP_User_Query.
+	 * @return array
+	 */
+	public function get_include_ids( $include = array() ) {
+		// The following args are specific to group member queries, and
+		// are not present in the query_vars of a normal BP_User_Query.
+		// We loop through to make sure that defaults are set (though
+		// values passed to the constructor will, as usual, override
+		// these defaults).
+		$this->query_vars = wp_parse_args( $this->query_vars, array(
+			'group_id'     => 0,
+			'group_role'   => array( 'member' ),
+			'is_confirmed' => true,
+		) );
+
+		$group_member_ids = $this->get_group_member_ids();
+
+		// If the group member query returned no users, bail with an
+		// array that will guarantee no matches for BP_User_Query
+		if ( empty( $group_member_ids ) ) {
+			return array( 0 );
+		}
+
+		if ( ! empty( $include ) ) {
+			$group_member_ids = array_intersect( $include, $group_member_ids );
+		}
+
+		return $group_member_ids;
+	}
+
+	/**
+	 * Get the members of the queried group.
+	 *
+	 * @since BuddyPress (1.8.0)
+	 *
+	 * @return array $ids User IDs of relevant group member ids.
+	 */
+	protected function get_group_member_ids() {
+		global $wpdb;
+
+		if ( is_array( $this->group_member_ids ) ) {
+			return $this->group_member_ids;
+		}
+
+		$bp  = buddypress();
+		$sql = array(
+			'select'  => "SELECT user_id FROM {$bp->groups->table_name_members}",
+			'where'   => array(),
+			'orderby' => '',
+			'order'   => '',
+			'limit'   => '',
+		);
+
+		/** WHERE clauses *****************************************************/
+
+		// Group id
+		$sql['where'][] = $wpdb->prepare( "group_id = %d", $this->query_vars['group_id'] );
+
+		// is_confirmed
+		$is_confirmed = ! empty( $this->query_vars['is_confirmed'] ) ? 1 : 0;
+		$sql['where'][] = $wpdb->prepare( "is_confirmed = %d", $is_confirmed );
+
+		// Role information is stored as follows: admins have
+		// is_admin = 1, mods have is_mod = 1, banned have is_banned =
+		// 1, and members have all three set to 0.
+		$roles = !empty( $this->query_vars['group_role'] ) ? $this->query_vars['group_role'] : array();
+		if ( is_string( $roles ) ) {
+			$roles = explode( ',', $roles );
+		}
+
+		// Sanitize: Only 'admin', 'mod', 'member', and 'banned' are valid
+		$allowed_roles = array( 'admin', 'mod', 'member', 'banned' );
+		foreach ( $roles as $role_key => $role_value ) {
+			if ( ! in_array( $role_value, $allowed_roles ) ) {
+				unset( $roles[ $role_key ] );
+			}
+		}
+
+		$roles = array_unique( $roles );
+
+		// When querying for a set of roles containing 'member' (for
+		// which there is no dedicated is_ column), figure out a list
+		// of columns *not* to match
+		$roles_sql = '';
+		if ( in_array( 'member', $roles ) ) {
+			$role_columns = array();
+			foreach ( array_diff( $allowed_roles, $roles ) as $excluded_role ) {
+				$role_columns[] = 'is_' . $excluded_role . ' = 0';
+			}
+
+			if ( ! empty( $role_columns ) ) {
+				$roles_sql = '(' . implode( ' AND ', $role_columns ) . ')';
+			}
+
+		// When querying for a set of roles *not* containing 'member',
+		// simply construct a list of is_* = 1 clauses
+		} else {
+			$role_columns = array();
+			foreach ( $roles as $role ) {
+				$role_columns[] = 'is_' . $role . ' = 1';
+			}
+
+			if ( ! empty( $role_columns ) ) {
+				$roles_sql = '(' . implode( ' OR ', $role_columns ) . ')';
+			}
+		}
+
+		if ( ! empty( $roles_sql ) ) {
+			$sql['where'][] = $roles_sql;
+		}
+
+		$sql['where'] = ! empty( $sql['where'] ) ? 'WHERE ' . implode( ' AND ', $sql['where'] ) : '';
+
+		/** ORDER BY clause ***************************************************/
+
+		// @todo For now, mimicking legacy behavior of
+		// bp_group_has_members(), which has us order by date_modified
+		// only. Should abstract it in the future
+		$sql['orderby'] = "ORDER BY date_modified";
+		$sql['order']   = "DESC";
+
+		/** LIMIT clause ******************************************************/
+		$this->group_member_ids = $wpdb->get_col( "{$sql['select']} {$sql['where']} {$sql['orderby']} {$sql['order']} {$sql['limit']}" );
+
+		return $this->group_member_ids;
+	}
+
+	/**
+	 * Tell BP_User_Query to order by the order of our query results.
+	 *
+	 * This implementation assumes the 'last_modified' sort order
+	 * hardcoded in BP_Group_Member_Query::get_group_member_ids().
+	 *
+	 * @param BP_User_Query $query BP_User_Query object.
+	 */
+	public function set_orderby( $query ) {
+		$gm_ids = $this->get_group_member_ids();
+		if ( empty( $gm_ids ) ) {
+			$gm_ids = array( 0 );
+		}
+
+		// The first param in the FIELD() clause is the sort column id
+		$gm_ids = array_merge( array( 'u.id' ), wp_parse_id_list( $gm_ids ) );
+		$gm_ids_sql = implode( ',', $gm_ids );
+
+		$query->uid_clauses['orderby'] = "ORDER BY FIELD(" . $gm_ids_sql . ")";
+
+		// Prevent this filter from running on future BP_User_Query
+		// instances on the same page
+		remove_action( 'bp_pre_user_query', array( $this, 'set_orderby' ) );
+	}
+
+	/**
+	 * Fetch additional data required in bp_group_has_members() loops.
+	 *
+	 * Additional data fetched:
+	 *
+	 *      - is_banned
+	 *      - date_modified
+	 *
+	 * @since BuddyPress (1.8.0)
+	 *
+	 * @param object $query BP_User_Query object. Because we're filtering
+	 *   the current object, we use $this inside of the method instead
+	 * @param string $user_ids_sql Sanitized, comma-separated string of
+	 *   the user ids returned by the main query
+	 */
+	public function populate_group_member_extras( $query, $user_ids_sql ) {
+		global $wpdb;
+
+		$bp     = buddypress();
+		$extras = $wpdb->get_results( $wpdb->prepare( "SELECT user_id, date_modified, is_banned FROM {$bp->groups->table_name_members} WHERE user_id IN ({$user_ids_sql}) AND group_id = %d", $this->query_vars['group_id'] ) );
+
+		foreach ( (array) $extras as $extra ) {
+			if ( isset( $this->results[ $extra->user_id ] ) ) {
+				// user_id is provided for backward compatibility
+				$this->results[ $extra->user_id ]->user_id       = (int) $extra->user_id;
+				$this->results[ $extra->user_id ]->is_banned     = (int) $extra->is_banned;
+				$this->results[ $extra->user_id ]->date_modified = $extra->date_modified;
+			}
+		}
+
+		// Don't filter other BP_User_Query objects on the same page
+		remove_action( 'bp_user_query_populate_extras', array( $this, 'populate_group_member_extras' ), 10, 2 );
+	}
+}
+
+/**
+ * BuddyPress Group Membership objects.
+ */
+class BP_Groups_Member {
+
+	/**
+	 * ID of the membership.
+	 *
+	 * @access public
+	 * @var int
+	 */
+	var $id;
+
+	/**
+	 * ID of the group associated with the membership.
+	 *
+	 * @access public
+	 * @var int
+	 */
+	var $group_id;
+
+	/**
+	 * ID of the user associated with the membership.
+	 *
+	 * @access public
+	 * @var int
+	 */
+	var $user_id;
+
+	/**
+	 * ID of the user whose invitation initiated the membership.
+	 *
+	 * @access public
+	 * @var int
+	 */
+	var $inviter_id;
+
+	/**
+	 * Whether the member is an admin of the group.
+	 *
+	 * @access public
+	 * @var int
+	 */
+	var $is_admin;
+
+	/**
+	 * Whether the member is a mod of the group.
+	 *
+	 * @access public
+	 * @var int
+	 */
+	var $is_mod;
+
+	/**
+	 * Whether the member is banned from the group.
+	 *
+	 * @access public
+	 * @var int
+	 */
+	var $is_banned;
+
+	/**
+	 * Title used to describe the group member's role in the group.
+	 *
+	 * Eg, 'Group Admin'.
+	 *
+	 * @access public
+	 * @var int
+	 */
+	var $user_title;
+
+	/**
+	 * Last modified date of the membership.
+	 *
+	 * This value is updated when, eg, invitations are accepted.
+	 *
+	 * @access public
+	 * @var string
+	 */
+	var $date_modified;
+
+	/**
+	 * Whether the membership has been confirmed.
+	 *
+	 * @access public
+	 * @var int
+	 */
+	var $is_confirmed;
+
+	/**
+	 * Comments associated with the membership.
+	 *
+	 * In BP core, these are limited to the optional message users can
+	 * include when requesting membership to a private group.
+	 *
+	 * @access public
+	 * @var string
+	 */
+	var $comments;
+
+	/**
+	 * Whether an invitation has been sent for this membership.
+	 *
+	 * The purpose of this flag is to mark when an invitation has been
+	 * "drafted" (the user has been added via the interface at Send
+	 * Invites), but the Send button has not been pressed, so the
+	 * invitee has not yet been notified.
+	 *
+	 * @access public
+	 * @var int
+	 */
+	var $invite_sent;
+
+	/**
+	 * WP_User object representing the membership's user.
+	 *
+	 * @access public
+	 * @var WP_User
+	 */
+	var $user;
+
+	/**
+	 * Constructor method.
+	 *
+	 * @param int $user_id Optional. Along with $group_id, can be used to
+	 *        look up a membership.
+	 * @param int $group_id Optional. Along with $user_id, can be used to
+	 *        look up a membership.
+	 * @param int $id Optional. The unique ID of the membership object.
+	 * @param bool $populate Whether to populate the properties of the
+	 *        located membership. Default: true.
+	 */
+	public function __construct( $user_id = 0, $group_id = 0, $id = false, $populate = true ) {
+
+		// User and group are not empty, and ID is
+		if ( !empty( $user_id ) && !empty( $group_id ) && empty( $id ) ) {
+			$this->user_id  = $user_id;
+			$this->group_id = $group_id;
+
+			if ( !empty( $populate ) ) {
+				$this->populate();
+			}
+		}
+
+		// ID is not empty
+		if ( !empty( $id ) ) {
+			$this->id = $id;
+
+			if ( !empty( $populate ) ) {
+				$this->populate();
+			}
+		}
+	}
+
+	/**
+	 * Populate the object's properties.
+	 */
+	public function populate() {
+		global $wpdb, $bp;
+
+		if ( $this->user_id && $this->group_id && !$this->id )
+			$sql = $wpdb->prepare( "SELECT * FROM {$bp->groups->table_name_members} WHERE user_id = %d AND group_id = %d", $this->user_id, $this->group_id );
+
+		if ( !empty( $this->id ) )
+			$sql = $wpdb->prepare( "SELECT * FROM {$bp->groups->table_name_members} WHERE id = %d", $this->id );
+
+		$member = $wpdb->get_row($sql);
+
+		if ( !empty( $member ) ) {
+			$this->id            = $member->id;
+			$this->group_id      = $member->group_id;
+			$this->user_id       = $member->user_id;
+			$this->inviter_id    = $member->inviter_id;
+			$this->is_admin      = $member->is_admin;
+			$this->is_mod        = $member->is_mod;
+			$this->is_banned     = $member->is_banned;
+			$this->user_title    = $member->user_title;
+			$this->date_modified = $member->date_modified;
+			$this->is_confirmed  = $member->is_confirmed;
+			$this->comments      = $member->comments;
+			$this->invite_sent   = $member->invite_sent;
+
+			$this->user = new BP_Core_User( $this->user_id );
+		}
+	}
+
+	/**
+	 * Save the membership data to the database.
+	 *
+	 * @return bool True on success, false on failure.
+	 */
+	public function save() {
+		global $wpdb, $bp;
+
+		$this->user_id       = apply_filters( 'groups_member_user_id_before_save',       $this->user_id,       $this->id );
+		$this->group_id      = apply_filters( 'groups_member_group_id_before_save',      $this->group_id,      $this->id );
+		$this->inviter_id    = apply_filters( 'groups_member_inviter_id_before_save',    $this->inviter_id,    $this->id );
+		$this->is_admin      = apply_filters( 'groups_member_is_admin_before_save',      $this->is_admin,      $this->id );
+		$this->is_mod        = apply_filters( 'groups_member_is_mod_before_save',        $this->is_mod,        $this->id );
+		$this->is_banned     = apply_filters( 'groups_member_is_banned_before_save',     $this->is_banned,     $this->id );
+		$this->user_title    = apply_filters( 'groups_member_user_title_before_save',    $this->user_title,    $this->id );
+		$this->date_modified = apply_filters( 'groups_member_date_modified_before_save', $this->date_modified, $this->id );
+		$this->is_confirmed  = apply_filters( 'groups_member_is_confirmed_before_save',  $this->is_confirmed,  $this->id );
+		$this->comments      = apply_filters( 'groups_member_comments_before_save',      $this->comments,      $this->id );
+		$this->invite_sent   = apply_filters( 'groups_member_invite_sent_before_save',   $this->invite_sent,   $this->id );
+
+		do_action_ref_array( 'groups_member_before_save', array( &$this ) );
+
+		if ( !empty( $this->id ) ) {
+			$sql = $wpdb->prepare( "UPDATE {$bp->groups->table_name_members} SET inviter_id = %d, is_admin = %d, is_mod = %d, is_banned = %d, user_title = %s, date_modified = %s, is_confirmed = %d, comments = %s, invite_sent = %d WHERE id = %d", $this->inviter_id, $this->is_admin, $this->is_mod, $this->is_banned, $this->user_title, $this->date_modified, $this->is_confirmed, $this->comments, $this->invite_sent, $this->id );
+		} else {
+			// Ensure that user is not already a member of the group before inserting
+			if ( $wpdb->get_var( $wpdb->prepare( "SELECT id FROM {$bp->groups->table_name_members} WHERE user_id = %d AND group_id = %d AND is_confirmed = 1 LIMIT 1", $this->user_id, $this->group_id ) ) ) {
+				return false;
+			}
+
+			$sql = $wpdb->prepare( "INSERT INTO {$bp->groups->table_name_members} ( user_id, group_id, inviter_id, is_admin, is_mod, is_banned, user_title, date_modified, is_confirmed, comments, invite_sent ) VALUES ( %d, %d, %d, %d, %d, %d, %s, %s, %d, %s, %d )", $this->user_id, $this->group_id, $this->inviter_id, $this->is_admin, $this->is_mod, $this->is_banned, $this->user_title, $this->date_modified, $this->is_confirmed, $this->comments, $this->invite_sent );
+		}
+
+		if ( !$wpdb->query( $sql ) )
+			return false;
+
+		$this->id = $wpdb->insert_id;
+
+		// Update the user's group count
+		self::refresh_total_group_count_for_user( $this->user_id );
+
+		// Update the group's member count
+		self::refresh_total_member_count_for_group( $this->group_id );
+
+		do_action_ref_array( 'groups_member_after_save', array( &$this ) );
+
+		return true;
+	}
+
+	/**
+	 * Promote a member to a new status.
+	 *
+	 * @param string $status The new status. 'mod' or 'admin'.
+	 * @return bool True on success, false on failure.
+	 */
+	public function promote( $status = 'mod' ) {
+		if ( 'mod' == $status ) {
+			$this->is_admin   = 0;
+			$this->is_mod     = 1;
+			$this->user_title = __( 'Group Mod', 'buddypress' );
+		}
+
+		if ( 'admin' == $status ) {
+			$this->is_admin   = 1;
+			$this->is_mod     = 0;
+			$this->user_title = __( 'Group Admin', 'buddypress' );
+		}
+
+		return $this->save();
+	}
+
+	/**
+	 * Demote membership to Member status (non-admin, non-mod).
+	 *
+	 * @return bool True on success, false on failure.
+	 */
+	public function demote() {
+		$this->is_mod     = 0;
+		$this->is_admin   = 0;
+		$this->user_title = false;
+
+		return $this->save();
+	}
+
+	/**
+	 * Ban the user from the group.
+	 *
+	 * @return bool True on success, false on failure.
+	 */
+	public function ban() {
+		if ( !empty( $this->is_admin ) )
+			return false;
+
+		$this->is_mod = 0;
+		$this->is_banned = 1;
+
+		return $this->save();
+	}
+
+	/**
+	 * Unban the user from the group.
+	 *
+	 * @return bool True on success, false on failure.
+	 */
+	public function unban() {
+		if ( !empty( $this->is_admin ) )
+			return false;
+
+		$this->is_banned = 0;
+
+		return $this->save();
+	}
+
+	/**
+	 * Mark a pending invitation as accepted.
+	 */
+	public function accept_invite() {
+		$this->inviter_id    = 0;
+		$this->is_confirmed  = 1;
+		$this->date_modified = bp_core_current_time();
+	}
+
+	/**
+	 * Confirm a membership request.
+	 */
+	public function accept_request() {
+		$this->is_confirmed = 1;
+		$this->date_modified = bp_core_current_time();
+	}
+
+	/**
+	 * Remove the current membership.
+	 *
+	 * @return bool True on success, false on failure.
+	 */
+	public function remove() {
+		global $wpdb, $bp;
+
+		$sql = $wpdb->prepare( "DELETE FROM {$bp->groups->table_name_members} WHERE user_id = %d AND group_id = %d", $this->user_id, $this->group_id );
+
+		if ( !$result = $wpdb->query( $sql ) )
+			return false;
+
+		// Update the user's group count
+		self::refresh_total_group_count_for_user( $this->user_id );
+
+		// Update the group's member count
+		self::refresh_total_member_count_for_group( $this->group_id );
+
+		return $result;
+	}
+
+	/** Static Methods ****************************************************/
+
+	/**
+	 * Refresh the total_group_count for a user.
+	 *
+	 * @since BuddyPress (1.8.0)
+	 *
+	 * @param int $user_id ID of the user.
+	 * @return bool True on success, false on failure.
+	 */
+	public static function refresh_total_group_count_for_user( $user_id ) {
+		return bp_update_user_meta( $user_id, 'total_group_count', (int) self::total_group_count( $user_id ) );
+	}
+
+	/**
+	 * Refresh the total_member_count for a group.
+	 *
+	 * @since BuddyPress (1.8.0)
+	 *
+	 * @param int $group_id ID of the group.
+	 * @return bool True on success, false on failure.
+	 */
+	public static function refresh_total_member_count_for_group( $group_id ) {
+		return groups_update_groupmeta( $group_id, 'total_member_count', (int) BP_Groups_Group::get_total_member_count( $group_id ) );
+	}
+
+	/**
+	 * Delete a membership, based on user + group IDs.
+	 *
+	 * @param int $user_id ID of the user.
+	 * @param int $group_id ID of the group.
+	 * @return True on success, false on failure.
+	 */
+	public static function delete( $user_id, $group_id ) {
+		global $wpdb, $bp;
+
+		$remove = $wpdb->query( $wpdb->prepare( "DELETE FROM {$bp->groups->table_name_members} WHERE user_id = %d AND group_id = %d", $user_id, $group_id ) );
+
+		// Update the user's group count
+		self::refresh_total_group_count_for_user( $user_id );
+
+		// Update the group's member count
+		self::refresh_total_member_count_for_group( $group_id );
+
+		return $remove;
+	}
+
+	/**
+	 * Get the IDs of the groups of which a specified user is a member.
+	 *
+	 * @param int $user_id ID of the user.
+	 * @param int $limit Optional. Max number of results to return.
+	 *        Default: false (no limit).
+	 * @param int $page Optional. Page offset of results to return.
+	 *        Default: false (no limit).
+	 * @return array {
+	 *     @type array $groups Array of groups returned by paginated query.
+	 *     @type int $total Count of groups matching query.
+	 * }
+	 */
+	public static function get_group_ids( $user_id, $limit = false, $page = false ) {
+		global $wpdb, $bp;
+
+		$pag_sql = '';
+		if ( !empty( $limit ) && !empty( $page ) )
+			$pag_sql = $wpdb->prepare( " LIMIT %d, %d", intval( ( $page - 1 ) * $limit), intval( $limit ) );
+
+		// If the user is logged in and viewing their own groups, we can show hidden and private groups
+		if ( $user_id != bp_loggedin_user_id() ) {
+			$group_sql = $wpdb->prepare( "SELECT DISTINCT m.group_id FROM {$bp->groups->table_name_members} m, {$bp->groups->table_name} g WHERE g.status != 'hidden' AND m.user_id = %d AND m.is_confirmed = 1 AND m.is_banned = 0{$pag_sql}", $user_id );
+			$total_groups = $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(DISTINCT m.group_id) FROM {$bp->groups->table_name_members} m, {$bp->groups->table_name} g WHERE g.status != 'hidden' AND m.user_id = %d AND m.is_confirmed = 1 AND m.is_banned = 0", $user_id ) );
+		} else {
+			$group_sql = $wpdb->prepare( "SELECT DISTINCT group_id FROM {$bp->groups->table_name_members} WHERE user_id = %d AND is_confirmed = 1 AND is_banned = 0{$pag_sql}", $user_id );
+			$total_groups = $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(DISTINCT group_id) FROM {$bp->groups->table_name_members} WHERE user_id = %d AND is_confirmed = 1 AND is_banned = 0", $user_id ) );
+		}
+
+		$groups = $wpdb->get_col( $group_sql );
+
+		return array( 'groups' => $groups, 'total' => (int) $total_groups );
+	}
+
+	/**
+	 * Get the IDs of the groups of which a specified user is a member, sorted by the date joined.
+	 *
+	 * @param int $user_id ID of the user.
+	 * @param int $limit Optional. Max number of results to return.
+	 *        Default: false (no limit).
+	 * @param int $page Optional. Page offset of results to return.
+	 *        Default: false (no limit).
+	 * @param string $filter Optional. Limit results to groups whose name or
+	 *        description field matches search terms.
+	 * @return array {
+	 *     @type array $groups Array of groups returned by paginated query.
+	 *     @type int $total Count of groups matching query.
+	 * }
+	 */
+	public static function get_recently_joined( $user_id, $limit = false, $page = false, $filter = false ) {
+		global $wpdb, $bp;
+
+		$pag_sql = $hidden_sql = $filter_sql = '';
+
+		if ( !empty( $limit ) && !empty( $page ) )
+			$pag_sql = $wpdb->prepare( " LIMIT %d, %d", intval( ( $page - 1 ) * $limit), intval( $limit ) );
+
+		if ( !empty( $filter ) ) {
+			$filter     = esc_sql( like_escape( $filter ) );
+			$filter_sql = " AND ( g.name LIKE '%%{$filter}%%' OR g.description LIKE '%%{$filter}%%' )";
+		}
+
+		if ( $user_id != bp_loggedin_user_id() )
+			$hidden_sql = " AND g.status != 'hidden'";
+
+		$paged_groups = $wpdb->get_results( $wpdb->prepare( "SELECT g.*, gm1.meta_value as total_member_count, gm2.meta_value as last_activity FROM {$bp->groups->table_name_groupmeta} gm1, {$bp->groups->table_name_groupmeta} gm2, {$bp->groups->table_name_members} m, {$bp->groups->table_name} g WHERE g.id = m.group_id AND g.id = gm1.group_id AND g.id = gm2.group_id AND gm2.meta_key = 'last_activity' AND gm1.meta_key = 'total_member_count'{$hidden_sql}{$filter_sql} AND m.user_id = %d AND m.is_confirmed = 1 AND m.is_banned = 0 ORDER BY m.date_modified DESC {$pag_sql}", $user_id ) );
+		$total_groups = $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(DISTINCT m.group_id) FROM {$bp->groups->table_name_members} m, {$bp->groups->table_name} g WHERE m.group_id = g.id{$hidden_sql}{$filter_sql} AND m.user_id = %d AND m.is_banned = 0 AND m.is_confirmed = 1 ORDER BY m.date_modified DESC", $user_id ) );
+
+		return array( 'groups' => $paged_groups, 'total' => $total_groups );
+	}
+
+	/**
+	 * Get the IDs of the groups of which a specified user is an admin.
+	 *
+	 * @param int $user_id ID of the user.
+	 * @param int $limit Optional. Max number of results to return.
+	 *        Default: false (no limit).
+	 * @param int $page Optional. Page offset of results to return.
+	 *        Default: false (no limit).
+	 * @param string $filter Optional. Limit results to groups whose name or
+	 *        description field matches search terms.
+	 * @return array {
+	 *     @type array $groups Array of groups returned by paginated query.
+	 *     @type int $total Count of groups matching query.
+	 * }
+	 */
+	public static function get_is_admin_of( $user_id, $limit = false, $page = false, $filter = false ) {
+		global $wpdb, $bp;
+
+		$pag_sql = $hidden_sql = $filter_sql = '';
+
+		if ( !empty( $limit ) && !empty( $page ) )
+			$pag_sql = $wpdb->prepare( " LIMIT %d, %d", intval( ( $page - 1 ) * $limit), intval( $limit ) );
+
+		if ( !empty( $filter ) ) {
+			$filter     = esc_sql( like_escape( $filter ) );
+			$filter_sql = " AND ( g.name LIKE '%%{$filter}%%' OR g.description LIKE '%%{$filter}%%' )";
+		}
+
+		if ( $user_id != bp_loggedin_user_id() )
+			$hidden_sql = " AND g.status != 'hidden'";
+
+		$paged_groups = $wpdb->get_results( $wpdb->prepare( "SELECT g.*, gm1.meta_value as total_member_count, gm2.meta_value as last_activity FROM {$bp->groups->table_name_groupmeta} gm1, {$bp->groups->table_name_groupmeta} gm2, {$bp->groups->table_name_members} m, {$bp->groups->table_name} g WHERE g.id = m.group_id AND g.id = gm1.group_id AND g.id = gm2.group_id AND gm2.meta_key = 'last_activity' AND gm1.meta_key = 'total_member_count'{$hidden_sql}{$filter_sql} AND m.user_id = %d AND m.is_confirmed = 1 AND m.is_banned = 0 AND m.is_admin = 1 ORDER BY m.date_modified ASC {$pag_sql}", $user_id ) );
+		$total_groups = $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(DISTINCT m.group_id) FROM {$bp->groups->table_name_members} m, {$bp->groups->table_name} g WHERE m.group_id = g.id{$hidden_sql}{$filter_sql} AND m.user_id = %d AND m.is_confirmed = 1 AND m.is_banned = 0 AND m.is_admin = 1 ORDER BY date_modified ASC", $user_id ) );
+
+		return array( 'groups' => $paged_groups, 'total' => $total_groups );
+	}
+
+	/**
+	 * Get the IDs of the groups of which a specified user is a moderator.
+	 *
+	 * @param int $user_id ID of the user.
+	 * @param int $limit Optional. Max number of results to return.
+	 *        Default: false (no limit).
+	 * @param int $page Optional. Page offset of results to return.
+	 *        Default: false (no limit).
+	 * @param string $filter Optional. Limit results to groups whose name or
+	 *        description field matches search terms.
+	 * @return array {
+	 *     @type array $groups Array of groups returned by paginated query.
+	 *     @type int $total Count of groups matching query.
+	 * }
+	 */
+	public static function get_is_mod_of( $user_id, $limit = false, $page = false, $filter = false ) {
+		global $wpdb, $bp;
+
+		$pag_sql = $hidden_sql = $filter_sql = '';
+
+		if ( !empty( $limit ) && !empty( $page ) )
+			$pag_sql = $wpdb->prepare( " LIMIT %d, %d", intval( ( $page - 1 ) * $limit), intval( $limit ) );
+
+		if ( !empty( $filter ) ) {
+			$filter     = esc_sql( like_escape( $filter ) );
+			$filter_sql = " AND ( g.name LIKE '%%{$filter}%%' OR g.description LIKE '%%{$filter}%%' )";
+		}
+
+		if ( $user_id != bp_loggedin_user_id() )
+			$hidden_sql = " AND g.status != 'hidden'";
+
+		$paged_groups = $wpdb->get_results( $wpdb->prepare( "SELECT g.*, gm1.meta_value as total_member_count, gm2.meta_value as last_activity FROM {$bp->groups->table_name_groupmeta} gm1, {$bp->groups->table_name_groupmeta} gm2, {$bp->groups->table_name_members} m, {$bp->groups->table_name} g WHERE g.id = m.group_id AND g.id = gm1.group_id AND g.id = gm2.group_id AND gm2.meta_key = 'last_activity' AND gm1.meta_key = 'total_member_count'{$hidden_sql}{$filter_sql} AND m.user_id = %d AND m.is_confirmed = 1 AND m.is_banned = 0 AND m.is_mod = 1 ORDER BY m.date_modified ASC {$pag_sql}", $user_id ) );
+		$total_groups = $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(DISTINCT m.group_id) FROM {$bp->groups->table_name_members} m, {$bp->groups->table_name} g WHERE m.group_id = g.id{$hidden_sql}{$filter_sql} AND m.user_id = %d AND m.is_confirmed = 1 AND m.is_banned = 0 AND m.is_mod = 1 ORDER BY date_modified ASC", $user_id ) );
+
+		return array( 'groups' => $paged_groups, 'total' => $total_groups );
+	}
+
+	/**
+	 * Get the count of groups of which the specified user is a member.
+	 *
+	 * @param int $user_id Optional. Default: ID of the displayed user.
+	 * @return int Group count.
+	 */
+	public static function total_group_count( $user_id = 0 ) {
+		global $bp, $wpdb;
+
+		if ( empty( $user_id ) )
+			$user_id = bp_displayed_user_id();
+
+		if ( $user_id != bp_loggedin_user_id() && !bp_current_user_can( 'bp_moderate' ) ) {
+			return $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(DISTINCT m.group_id) FROM {$bp->groups->table_name_members} m, {$bp->groups->table_name} g WHERE m.group_id = g.id AND g.status != 'hidden' AND m.user_id = %d AND m.is_confirmed = 1 AND m.is_banned = 0", $user_id ) );
+		} else {
+			return $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(DISTINCT m.group_id) FROM {$bp->groups->table_name_members} m, {$bp->groups->table_name} g WHERE m.group_id = g.id AND m.user_id = %d AND m.is_confirmed = 1 AND m.is_banned = 0", $user_id ) );
+		}
+	}
+
+	/**
+	 * Get a user's outstanding group invitations.
+	 *
+	 * @param int $user_id ID of the invitee.
+	 * @param int $limit Optional. Max number of results to return.
+	 *        Default: false (no limit).
+	 * @param int $page Optional. Page offset of results to return.
+	 *        Default: false (no limit).
+	 * @param string|array $exclude Optional. Array or comma-separated list
+	 *        of group IDs to exclude from results.
+	 * @return array {
+	 *     @type array $groups Array of groups returned by paginated query.
+	 *     @type int $total Count of groups matching query.
+	 * }
+	 */
+	public static function get_invites( $user_id, $limit = false, $page = false, $exclude = false ) {
+		global $wpdb, $bp;
+
+		$pag_sql = ( !empty( $limit ) && !empty( $page ) ) ? $wpdb->prepare( " LIMIT %d, %d", intval( ( $page - 1 ) * $limit), intval( $limit ) ) : '';
+
+		if ( !empty( $exclude ) ) {
+			$exclude     = implode( ',', wp_parse_id_list( $exclude ) );
+			$exclude_sql = " AND g.id NOT IN ({$exclude})";
+		} else {
+			$exclude_sql = '';
+		}
+
+		$paged_groups = $wpdb->get_results( $wpdb->prepare( "SELECT g.*, gm1.meta_value as total_member_count, gm2.meta_value as last_activity FROM {$bp->groups->table_name_groupmeta} gm1, {$bp->groups->table_name_groupmeta} gm2, {$bp->groups->table_name_members} m, {$bp->groups->table_name} g WHERE g.id = m.group_id AND g.id = gm1.group_id AND g.id = gm2.group_id AND gm2.meta_key = 'last_activity' AND gm1.meta_key = 'total_member_count' AND m.is_confirmed = 0 AND m.inviter_id != 0 AND m.invite_sent = 1 AND m.user_id = %d {$exclude_sql} ORDER BY m.date_modified ASC {$pag_sql}", $user_id ) );
+		$total_groups = $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(DISTINCT m.group_id) FROM {$bp->groups->table_name_members} m, {$bp->groups->table_name} g WHERE m.group_id = g.id AND m.is_confirmed = 0 AND m.inviter_id != 0 AND m.invite_sent = 1 AND m.user_id = %d {$exclude_sql} ORDER BY date_modified ASC", $user_id ) );
+
+		return array( 'groups' => $paged_groups, 'total' => $total_groups );
+	}
+
+	/**
+	 * Check whether a user has an outstanding invitation to a given group.
+	 *
+	 * @param int $user_id ID of the potential invitee.
+	 * @param int $group_id ID of the group.
+	 * @param string $type If 'sent', results are limited to those
+	 *        invitations that have actually been sent (non-draft).
+	 *        Default: 'sent'.
+	 * @return int|null The ID of the invitation if found, otherwise null.
+	 */
+	public static function check_has_invite( $user_id, $group_id, $type = 'sent' ) {
+		global $wpdb, $bp;
+
+		if ( empty( $user_id ) )
+			return false;
+
+		$sql = "SELECT id FROM {$bp->groups->table_name_members} WHERE user_id = %d AND group_id = %d AND is_confirmed = 0 AND inviter_id != 0";
+
+		if ( 'sent' == $type )
+			$sql .= " AND invite_sent = 1";
+
+		return $wpdb->get_var( $wpdb->prepare( $sql, $user_id, $group_id ) );
+	}
+
+	/**
+	 * Delete an invitation, by specifying user ID and group ID.
+	 *
+	 * @param int $user_id ID of the user.
+	 * @param int $group_id ID of the group.
+	 * @return int Number of records deleted.
+	 */
+	public static function delete_invite( $user_id, $group_id ) {
+		global $wpdb, $bp;
+
+		if ( empty( $user_id ) )
+			return false;
+
+		return $wpdb->query( $wpdb->prepare( "DELETE FROM {$bp->groups->table_name_members} WHERE user_id = %d AND group_id = %d AND is_confirmed = 0 AND inviter_id != 0 AND invite_sent = 1", $user_id, $group_id ) );
+	}
+
+	/**
+	 * Delete an unconfirmed membership request, by user ID and group ID.
+	 *
+	 * @param int $user_id ID of the user.
+	 * @param int $group_id ID of the group.
+	 * @return int Number of records deleted.
+	 */
+	public static function delete_request( $user_id, $group_id ) {
+		global $wpdb, $bp;
+
+		if ( empty( $user_id ) )
+			return false;
+
+ 		return $wpdb->query( $wpdb->prepare( "DELETE FROM {$bp->groups->table_name_members} WHERE user_id = %d AND group_id = %d AND is_confirmed = 0 AND inviter_id = 0 AND invite_sent = 0", $user_id, $group_id ) );
+	}
+
+	/**
+	 * Check whether a user is an admin of a given group.
+	 *
+	 * @param int $user_id ID of the user.
+	 * @param int $group_id ID of the group.
+	 * @param int|null ID of the membership if the user is an admin,
+	 *        otherwise null.
+	 */
+	public static function check_is_admin( $user_id, $group_id ) {
+		global $wpdb, $bp;
+
+		if ( empty( $user_id ) )
+			return false;
+
+		return $wpdb->query( $wpdb->prepare( "SELECT id FROM {$bp->groups->table_name_members} WHERE user_id = %d AND group_id = %d AND is_admin = 1 AND is_banned = 0", $user_id, $group_id ) );
+	}
+
+	/**
+	 * Check whether a user is a mod of a given group.
+	 *
+	 * @param int $user_id ID of the user.
+	 * @param int $group_id ID of the group.
+	 * @param int|null ID of the membership if the user is a mod,
+	 *        otherwise null.
+	 */
+	public static function check_is_mod( $user_id, $group_id ) {
+		global $wpdb, $bp;
+
+		if ( empty( $user_id ) )
+			return false;
+
+		return $wpdb->query( $wpdb->prepare( "SELECT id FROM {$bp->groups->table_name_members} WHERE user_id = %d AND group_id = %d AND is_mod = 1 AND is_banned = 0", $user_id, $group_id ) );
+	}
+
+	/**
+	 * Check whether a user is a member of a given group.
+	 *
+	 * @param int $user_id ID of the user.
+	 * @param int $group_id ID of the group.
+	 * @param int|null ID of the membership if the user is a member,
+	 *        otherwise null.
+	 */
+	public static function check_is_member( $user_id, $group_id ) {
+		global $wpdb, $bp;
+
+		if ( empty( $user_id ) )
+			return false;
+
+		return $wpdb->query( $wpdb->prepare( "SELECT id FROM {$bp->groups->table_name_members} WHERE user_id = %d AND group_id = %d AND is_confirmed = 1 AND is_banned = 0", $user_id, $group_id ) );
+	}
+
+	/**
+	 * Check whether a user is banned from a given group.
+	 *
+	 * @param int $user_id ID of the user.
+	 * @param int $group_id ID of the group.
+	 * @param int|null ID of the membership if the user is banned,
+	 *        otherwise null.
+	 */
+	public static function check_is_banned( $user_id, $group_id ) {
+		global $wpdb, $bp;
+
+		if ( empty( $user_id ) )
+			return false;
+
+		return $wpdb->get_var( $wpdb->prepare( "SELECT is_banned FROM {$bp->groups->table_name_members} WHERE user_id = %d AND group_id = %d", $user_id, $group_id ) );
+	}
+
+	/**
+	 * Is the specified user the creator of the group?
+	 *
+	 * @since BuddyPress (1.2.6)
+	 *
+	 * @param int $user_id ID of the user.
+	 * @param int $group_id ID of the group.
+	 * @return int|null ID of the group if the user is the creator,
+	 *         otherwise false.
+	 */
+	public static function check_is_creator( $user_id, $group_id ) {
+		global $bp, $wpdb;
+
+		if ( empty( $user_id ) )
+			return false;
+
+		return $wpdb->get_var( $wpdb->prepare( "SELECT id FROM {$bp->groups->table_name} WHERE creator_id = %d AND id = %d", $user_id, $group_id ) );
+	}
+
+	/**
+	 * Check whether a user has an outstanding membership request for a given group.
+	 *
+	 * @param int $user_id ID of the user.
+	 * @param int $group_id ID of the group.
+	 * @return int|null ID of the membership if found, otherwise false.
+	 */
+	public static function check_for_membership_request( $user_id, $group_id ) {
+		global $wpdb, $bp;
+
+		if ( empty( $user_id ) )
+			return false;
+
+		return $wpdb->query( $wpdb->prepare( "SELECT id FROM {$bp->groups->table_name_members} WHERE user_id = %d AND group_id = %d AND is_confirmed = 0 AND is_banned = 0 AND inviter_id = 0", $user_id, $group_id ) );
+	}
+
+	/**
+	 * Get a list of randomly selected IDs of groups that the member belongs to.
+	 *
+	 * @param int $user_id ID of the user.
+	 * @param int $total_groups Max number of group IDs to return. Default: 5.
+	 * @return array Group IDs.
+	 */
+	public static function get_random_groups( $user_id = 0, $total_groups = 5 ) {
+		global $wpdb, $bp;
+
+		// If the user is logged in and viewing their random groups, we can show hidden and private groups
+		if ( bp_is_my_profile() ) {
+			return $wpdb->get_col( $wpdb->prepare( "SELECT DISTINCT group_id FROM {$bp->groups->table_name_members} WHERE user_id = %d AND is_confirmed = 1 AND is_banned = 0 ORDER BY rand() LIMIT %d", $user_id, $total_groups ) );
+		} else {
+			return $wpdb->get_col( $wpdb->prepare( "SELECT DISTINCT m.group_id FROM {$bp->groups->table_name_members} m, {$bp->groups->table_name} g WHERE m.group_id = g.id AND g.status != 'hidden' AND m.user_id = %d AND m.is_confirmed = 1 AND m.is_banned = 0 ORDER BY rand() LIMIT %d", $user_id, $total_groups ) );
+		}
+	}
+
+	/**
+	 * Get the IDs of all a given group's members.
+	 *
+	 * @param int $group_id ID of the group.
+	 * @return array IDs of all group members.
+	 */
+	public static function get_group_member_ids( $group_id ) {
+		global $bp, $wpdb;
+
+		return $wpdb->get_col( $wpdb->prepare( "SELECT user_id FROM {$bp->groups->table_name_members} WHERE group_id = %d AND is_confirmed = 1 AND is_banned = 0", $group_id ) );
+	}
+
+	/**
+	 * Get a list of all a given group's admins.
+	 *
+	 * @param int $group_id ID of the group.
+	 * @return array Info about group admins (user_id + date_modified).
+	 */
+	public static function get_group_administrator_ids( $group_id ) {
+		global $bp, $wpdb;
+
+		return $wpdb->get_results( $wpdb->prepare( "SELECT user_id, date_modified FROM {$bp->groups->table_name_members} WHERE group_id = %d AND is_admin = 1 AND is_banned = 0", $group_id ) );
+	}
+
+	/**
+	 * Get a list of all a given group's moderators.
+	 *
+	 * @param int $group_id ID of the group.
+	 * @return array Info about group mods (user_id + date_modified).
+	 */
+	public static function get_group_moderator_ids( $group_id ) {
+		global $bp, $wpdb;
+
+		return $wpdb->get_results( $wpdb->prepare( "SELECT user_id, date_modified FROM {$bp->groups->table_name_members} WHERE group_id = %d AND is_mod = 1 AND is_banned = 0", $group_id ) );
+	}
+
+	/**
+	 * Get the IDs users with outstanding membership requests to the group.
+	 *
+	 * @param int $group_id ID of the group.
+	 * @return array IDs of users with outstanding membership requests.
+	 */
+	public static function get_all_membership_request_user_ids( $group_id ) {
+		global $bp, $wpdb;
+
+		return $wpdb->get_col( $wpdb->prepare( "SELECT user_id FROM {$bp->groups->table_name_members} WHERE group_id = %d AND is_confirmed = 0 AND inviter_id = 0", $group_id ) );
+	}
+
+	/**
+	 * Get members of a group.
+	 *
+	 * @deprecated BuddyPress (1.8.0)
+	 */
+	public static function get_all_for_group( $group_id, $limit = false, $page = false, $exclude_admins_mods = true, $exclude_banned = true, $exclude = false ) {
+		global $bp, $wpdb;
+
+		_deprecated_function( __METHOD__, '1.8', 'BP_Group_Member_Query' );
+
+		$pag_sql = '';
+		if ( !empty( $limit ) && !empty( $page ) )
+			$pag_sql = $wpdb->prepare( "LIMIT %d, %d", intval( ( $page - 1 ) * $limit), intval( $limit ) );
+
+		$exclude_admins_sql = '';
+		if ( !empty( $exclude_admins_mods ) )
+			$exclude_admins_sql = "AND is_admin = 0 AND is_mod = 0";
+
+		$banned_sql = '';
+		if ( !empty( $exclude_banned ) )
+			$banned_sql = " AND is_banned = 0";
+
+		$exclude_sql = '';
+		if ( !empty( $exclude ) ) {
+			$exclude     = implode( ',', wp_parse_id_list( $exclude ) );
+			$exclude_sql = " AND m.user_id NOT IN ({$exclude})";
+		}
+
+		if ( bp_is_active( 'xprofile' ) ) {
+			$members = $wpdb->get_results( apply_filters( 'bp_group_members_user_join_filter', $wpdb->prepare( "SELECT m.user_id, m.date_modified, m.is_banned, u.user_login, u.user_nicename, u.user_email, pd.value as display_name FROM {$bp->groups->table_name_members} m, {$wpdb->users} u, {$bp->profile->table_name_data} pd WHERE u.ID = m.user_id AND u.ID = pd.user_id AND pd.field_id = 1 AND group_id = %d AND is_confirmed = 1 {$banned_sql} {$exclude_admins_sql} {$exclude_sql} ORDER BY m.date_modified DESC {$pag_sql}", $group_id ) ) );
+		} else {
+			$members = $wpdb->get_results( apply_filters( 'bp_group_members_user_join_filter', $wpdb->prepare( "SELECT m.user_id, m.date_modified, m.is_banned, u.user_login, u.user_nicename, u.user_email, u.display_name FROM {$bp->groups->table_name_members} m, {$wpdb->users} u WHERE u.ID = m.user_id AND group_id = %d AND is_confirmed = 1 {$banned_sql} {$exclude_admins_sql} {$exclude_sql} ORDER BY m.date_modified DESC {$pag_sql}", $group_id ) ) );
+		}
+
+		if ( empty( $members ) ) {
+			return false;
+		}
+
+		if ( empty( $pag_sql ) ) {
+			$total_member_count = count( $members );
+		} else {
+			$total_member_count = $wpdb->get_var( apply_filters( 'bp_group_members_count_user_join_filter', $wpdb->prepare( "SELECT COUNT(user_id) FROM {$bp->groups->table_name_members} m WHERE group_id = %d AND is_confirmed = 1 {$banned_sql} {$exclude_admins_sql} {$exclude_sql}", $group_id ) ) );
+		}
+
+		// Fetch whether or not the user is a friend
+		foreach ( (array) $members as $user )
+			$user_ids[] = $user->user_id;
+
+		$user_ids = implode( ',', wp_parse_id_list( $user_ids ) );
+
+		if ( bp_is_active( 'friends' ) ) {
+			$friend_status = $wpdb->get_results( $wpdb->prepare( "SELECT initiator_user_id, friend_user_id, is_confirmed FROM {$bp->friends->table_name} WHERE (initiator_user_id = %d AND friend_user_id IN ( {$user_ids} ) ) OR (initiator_user_id IN ( {$user_ids} ) AND friend_user_id = %d )", bp_loggedin_user_id(), bp_loggedin_user_id() ) );
+			for ( $i = 0, $count = count( $members ); $i < $count; ++$i ) {
+				foreach ( (array) $friend_status as $status ) {
+					if ( $status->initiator_user_id == $members[$i]->user_id || $status->friend_user_id == $members[$i]->user_id ) {
+						$members[$i]->is_friend = $status->is_confirmed;
+					}
+				}
+			}
+		}
+
+		return array( 'members' => $members, 'count' => $total_member_count );
+	}
+
+	/**
+	 * Delete all memberships for a given group.
+	 *
+	 * @param int $group_id ID of the group.
+	 * @return int Number of records deleted.
+	 */
+	public static function delete_all( $group_id ) {
+		global $wpdb, $bp;
+
+		return $wpdb->query( $wpdb->prepare( "DELETE FROM {$bp->groups->table_name_members} WHERE group_id = %d", $group_id ) );
+	}
+
+	/**
+	 * Delete all group membership information for the specified user.
+	 *
+	 * @since BuddyPress (1.0.0)
+	 *
+	 * @param int $user_id ID of the user.
+	 */
+	public static function delete_all_for_user( $user_id ) {
+		global $bp, $wpdb;
+
+		// Get all the group ids for the current user's groups and update counts
+		$group_ids = BP_Groups_Member::get_group_ids( $user_id );
+		foreach ( $group_ids['groups'] as $group_id ) {
+			groups_update_groupmeta( $group_id, 'total_member_count', groups_get_total_member_count( $group_id ) - 1 );
+
+			// If current user is the creator of a group and is the sole admin, delete that group to avoid counts going out-of-sync
+			if ( groups_is_user_admin( $user_id, $group_id ) && count( groups_get_group_admins( $group_id ) ) < 2 && groups_is_user_creator( $user_id, $group_id ) )
+				groups_delete_group( $group_id );
+		}
+
+		return $wpdb->query( $wpdb->prepare( "DELETE FROM {$bp->groups->table_name_members} WHERE user_id = %d", $user_id ) );
+	}
+}
+
+/**
+ * API for creating group extensions without having to hardcode the content into
+ * the theme.
+ *
+ * To implement, extend this class. In your constructor, pass an optional array
+ * of arguments to parent::init() to configure your widget. The config array
+ * supports the following values:
+ *   - 'slug' A unique identifier for your extension. This value will be used
+ *     to build URLs, so make it URL-safe
+ *   - 'name' A translatable name for your extension. This value is used to
+       populate the navigation tab, as well as the default titles for admin/
+       edit/create tabs.
+ *   - 'visibility' Set to 'public' (default) for your extension (the main tab
+ *     as well as the widget) to be available to anyone who can access the
+ *     group, 'private' otherwise.
+ *   - 'nav_item_position' An integer explaining where the nav item should
+ *     appear in the tab list
+ *   - 'enable_nav_item' Set to true for your extension's main tab to be
+ *     available to anyone who can access the group.
+ *   - 'nav_item_name' The translatable text you want to appear in the nav tab.
+ *     Defaults to the value of 'name'.
+ *   - 'display_hook' The WordPress action that the widget_display() method is
+ *     hooked to
+ *   - 'template_file' The template file that will be used to load the content
+ *     of your main extension tab. Defaults to 'groups/single/plugins.php'.
+ *   - 'screens' A multi-dimensional array, described below
+ *
+ * BP_Group_Extension uses the concept of "settings screens". There are three
+ * contexts for settings screens:
+ *   - 'create', which inserts a new step into the group creation process
+ *   - 'edit', which adds a tab for your extension into the Admin section of
+ *     a group
+ *   - 'admin', which adds a metabox to the Groups administration panel in the
+ *     WordPress Dashboard
+ * Each of these settings screens is populated by a pair of methods: one that
+ * creates the markup for the screen, and one that processes form data
+ * submitted from the screen. If your plugin needs screens in all three
+ * contexts, and if the markup and form processing logic will be the same in
+ * each case, you can define two methods to handle all of the screens:
+ *   function settings_screen() {}
+ *   function settings_screen_save() {}
+ * If one or more of your settings screen needs separate logic, you may define
+ * context-specific methods, for example:
+ *   function edit_screen() {}
+ *   function edit_screen_save() {}
+ * BP_Group_Extension will use the more specific methods if they are available.
+ *
+ * You can further customize the settings screens (tab names, etc) by passing
+ * an optional 'screens' parameter to the init array. The format is as follows:
+ *   'screens' => array(
+ *       'create' => array(
+ *	     'slug' => 'foo',
+ *	     'name' => 'Foo',
+ *	     'position' => 55,
+ *	     'screen_callback' => 'my_create_screen_callback',
+ *	     'screen_save_callback' => 'my_create_screen_save_callback',
+ *	 ),
+ *	 'edit' => array( // ...
+ *   ),
+ * Only provide those arguments that you actually want to change from the
+ * default configuration. BP_Group_Extension will do the rest.
+ *
+ * Note that the 'edit' screen accepts an additional parameter: 'submit_text',
+ * which defines the text of the Submit button automatically added to the Edit
+ * screen of the extension (defaults to 'Save Changes'). Also, the 'admin'
+ * screen accepts two additional parameters: 'metabox_priority' and
+ * 'metabox_context'. See the docs for add_meta_box() for more details on these
+ * arguments.
+ *
+ * Prior to BuddyPress 1.7, group extension configurations were set slightly
+ * differently. The legacy method is still supported, though deprecated.
+ *
+ * @package BuddyPress
+ * @subpackage Groups
+ * @since BuddyPress (1.1.0)
+ */
+class BP_Group_Extension {
+
+	/** Public ************************************************************/
+
+	/**
+	 * Information about this extension's screens.
+	 *
+	 * @since BuddyPress (1.8.0)
+	 * @var array
+	 */
+	public $screens = array();
+
+	/**
+	 * The name of the extending class.
+	 *
+	 * @since BuddyPress (1.8.0)
+	 * @var string
+	 */
+	public $class_name = '';
+
+	/**
+	 * A ReflectionClass object of the current extension.
+	 *
+	 * @since BuddyPress (1.8.0)
+	 * @var ReflectionClass
+	 */
+	public $class_reflection = null;
+
+	/**
+	 * Parsed configuration paramaters for the extension.
+	 *
+	 * @since BuddyPress (1.8.0)
+	 * @var array
+	 */
+	public $params = array();
+
+	/**
+	 * The ID of the current group.
+	 *
+	 * @since BuddyPress (1.8.0)
+	 * @var int
+	 */
+	public $group_id = 0;
+
+	/**
+	 * The slug of the current extension.
+	 *
+	 * @var string
+	 */
+	public $slug = '';
+
+	/**
+	 * The translatable name of the current extension.
+	 *
+	 * @var string
+	 */
+	public $name = '';
+
+	/**
+	 * The visibility of the extension tab. 'public' or 'private'.
+	 *
+	 * @var string
+	 */
+	public $visibility = 'public';
+
+	/**
+	 * The numeric position of the main nav item.
+	 *
+	 * @var int
+	 */
+	public $nav_item_position = 81;
+
+	/**
+	 * Whether to show the nav item.
+	 *
+	 * @var bool
+	 */
+	public $enable_nav_item = true;
+
+	/**
+	 * The text of the nav item. Defaults to self::name.
+	 *
+	 * @var string
+	 */
+	public $nav_item_name = '';
+
+	/**
+	 * The WP action that self::widget_display() is attached to.
+	 *
+	 * Default: 'groups_custom_group_boxes'.
+	 *
+	 * @var string
+	 */
+	public $display_hook = 'groups_custom_group_boxes';
+
+	/**
+	 * The template file used to load the plugin content.
+	 *
+	 * Default: 'groups/single/plugins'.
+	 *
+	 * @var string
+	 */
+	public $template_file = 'groups/single/plugins';
+
+	/** Protected *********************************************************/
+
+	/**
+	 * Has the extension been initialized?
+	 *
+	 * @since BuddyPress (1.8.0)
+	 * @var bool
+	 */
+	protected $initialized = false;
+
+	/**
+	 * Extension properties as set by legacy extensions.
+	 *
+	 * @since BuddyPress (1.8.0)
+	 * @var array
+	 */
+	protected $legacy_properties = array();
+
+	/**
+	 * Converted legacy parameters.
+	 *
+	 * These are the extension properties as set by legacy extensions, but
+	 * then converted to match the new format for params.
+	 *
+	 * @since BuddyPress (1.8.0)
+	 * @var array
+	 */
+	protected $legacy_properties_converted = array();
+
+	/**
+	 * Miscellaneous data as set by the __set() magic method.
+	 *
+	 * @since BuddyPress (1.8.0)
+	 * @var array
+	 */
+	protected $data = array();
+
+	/** Screen Overrides **************************************************/
+
+	/*
+	 * Screen override methods are how your extension will display content
+	 * and handle form submits. Your extension should only override those
+	 * methods that it needs for its purposes.
+	 */
+
+	// The content of the group tab
+	public function display() {}
+
+	// Content displayed in a widget sidebar, if applicable
+	public function widget_display() {}
+
+	// *_screen() displays the settings form for the given context
+	// *_screen_save() processes data submitted via the settings form
+	// The settings_* methods are generic fallbacks, which can optionally
+	// be overridden by the more specific edit_*, create_*, and admin_*
+	// versions.
+	public function settings_screen( $group_id = null ) {}
+	public function settings_screen_save( $group_id = null ) {}
+	public function edit_screen( $group_id = null ) {}
+	public function edit_screen_save( $group_id = null ) {}
+	public function create_screen( $group_id = null ) {}
+	public function create_screen_save( $group_id = null ) {}
+	public function admin_screen( $group_id = null ) {}
+	public function admin_screen_save( $group_id = null ) {}
+
+	/** Setup *************************************************************/
+
+	/**
+	 * Initialize the extension, using your config settings
+	 *
+	 * Your plugin should call this method at the very end of its
+	 * constructor, like so:
+	 *
+	 *   public function __construct() {
+	 *       $args = array(
+	 *           'slug' => 'my-group-extension',
+	 *           'name' => 'My Group Extension',
+	 *           // ...
+	 *       );
+	 *
+	 *       parent::init( $args );
+	 *   }
+	 *
+	 * @since BuddyPress (1.8)
+	 * @param array $args {
+	 *     Array of initialization arguments.
+	 *     @type string $slug Unique, URL-safe identifier for your
+	 *           extension.
+	 *     @type string $name Translatable name for your extension. Used to
+	 *           populate navigation items.
+	 *     @type string $visibility Optional. Set to 'public' for your
+	 *           extension (the main tab as well as the widget) to be
+	 *           available to anyone who can access the group; set to
+	 *           'private' otherwise. Default: 'public'.
+	 *     @type int $nav_item_position Optional. Location of the nav item
+	 *           in the tab list. Default: 81.
+	 *     @type bool $enable_nav_item Optional. Whether the extension's
+	 *           tab should be accessible to anyone who can view the group.
+	 *           Default: true.
+	 *     @type string $nav_item_name Optional. The translatable text you
+	 *           want to appear in the nav tab. Default: the value of $name.
+	 *     @type string $display_hook Optional. The WordPress action that
+	 *           the widget_display() method is hooked to.
+	 *           Default: 'groups_custom_group_boxes'.
+	 *     @type string $template_file Optional. Theme-relative path to the
+	 *           template file BP should use to load the content of your
+	 *           main extension tab. Default: 'groups/single/plugins.php'.
+	 *     @type array $screens A multi-dimensional array of configuration
+	 *           information for the extension screens. See docblock of
+	 *           {@link BP_Group_Extension} for more details.
+	 * }
+	 */
+	public function init( $args = array() ) {
+
+		// Before this init() method was introduced, plugins were
+		// encouraged to set their config directly. For backward
+		// compatibility with these plugins, we detect whether this is
+		// one of those legacy plugins, and parse any legacy arguments
+		// with those passed to init()
+		$this->parse_legacy_properties();
+		$args = $this->parse_args_r( $args, $this->legacy_properties_converted );
+
+		// Parse with defaults
+		$this->params = $this->parse_args_r( $args, array(
+			'slug'              => $this->slug,
+			'name'              => $this->name,
+			'visibility'        => $this->visibility,
+			'nav_item_position' => $this->nav_item_position,
+			'enable_nav_item'   => (bool) $this->enable_nav_item,
+			'nav_item_name'     => $this->nav_item_name,
+			'display_hook'      => $this->display_hook,
+			'template_file'     => $this->template_file,
+			'screens'           => $this->get_default_screens(),
+		) );
+
+		$this->initialized = true;
+	}
+
+	/**
+	 * The main setup routine for the extension.
+	 *
+	 * This method contains the primary logic for setting up an extension's
+	 * configuration, setting up backward compatibility for legacy plugins,
+	 * and hooking the extension's screen functions into WP and BP.
+	 *
+	 * Marked 'public' because it must be accessible to add_action().
+	 * However, you should never need to invoke this method yourself - it
+	 * is called automatically at the right point in the load order by
+	 * bp_register_group_extension().
+	 *
+	 * @since BuddyPress (1.1.0)
+	 */
+	public function _register() {
+
+		// Detect and parse properties set by legacy extensions
+		$this->parse_legacy_properties();
+
+		// Initialize, if necessary. This should only happen for
+		// legacy extensions that don't call parent::init() themselves
+		if ( true !== $this->initialized ) {
+			$this->init();
+		}
+
+		// Set some config values, based on the parsed params
+		$this->group_id          = $this->get_group_id();
+		$this->slug              = $this->params['slug'];
+		$this->name              = $this->params['name'];
+		$this->visibility        = $this->params['visibility'];
+		$this->nav_item_position = $this->params['nav_item_position'];
+		$this->nav_item_name     = $this->params['nav_item_name'];
+		$this->display_hook      = $this->params['display_hook'];
+		$this->template_file     = $this->params['template_file'];
+
+		// Configure 'screens': create, admin, and edit contexts
+		$this->setup_screens();
+
+		// Mirror configuration data so it's accessible to plugins
+		// that look for it in its old locations
+		$this->setup_legacy_properties();
+
+		// Hook the extension into BuddyPress
+		$this->setup_display_hooks();
+		$this->setup_create_hooks();
+		$this->setup_edit_hooks();
+		$this->setup_admin_hooks();
+	}
+
+	/**
+	 * Set up some basic info about the Extension.
+	 *
+	 * Here we collect the name of the extending class, as well as a
+	 * ReflectionClass that is used in get_screen_callback() to determine
+	 * whether your extension overrides certain callback methods.
+	 *
+	 * @since BuddyPress (1.8.0)
+	 */
+	protected function setup_class_info() {
+		if ( empty( $this->class_name ) ) {
+			$this->class_name = get_class( $this );
+		}
+
+		if ( is_null( $this->class_reflection ) ) {
+			$this->class_reflection = new ReflectionClass( $this->class_name );
+		}
+	}
+
+	/**
+	 * Get the current group ID.
+	 *
+	 * Check for:
+	 *   - current group
+	 *   - new group
+	 *   - group admin
+	 *
+	 * @since BuddyPress (1.8.0)
+	 */
+	public static function get_group_id() {
+
+		// Usually this will work
+		$group_id = bp_get_current_group_id();
+
+		// On the admin, get the group id out of the $_GET params
+		if ( empty( $group_id ) && is_admin() && ( isset( $_GET['page'] ) && ( 'bp-groups' === $_GET['page'] ) ) && ! empty( $_GET['gid'] ) ) {
+			$group_id = (int) $_GET['gid'];
+		}
+
+		// This fallback will only be hit when the create step is very
+		// early
+		if ( empty( $group_id ) && bp_get_new_group_id() ) {
+			$group_id = bp_get_new_group_id();
+		}
+
+		// On some setups, the group id has to be fetched out of the
+		// $_POST array
+		// @todo Figure out why this is happening during group creation
+		if ( empty( $group_id ) && isset( $_POST['group_id'] ) ) {
+			$group_id = (int) $_POST['group_id'];
+		}
+
+		return $group_id;
+	}
+
+	/**
+	 * Gather configuration data about your screens.
+	 *
+	 * @since BuddyPress (1.8.0)
+	 */
+	protected function get_default_screens() {
+		$this->setup_class_info();
+
+		$screens = array(
+			'create' => array(
+				'position' => 81,
+			),
+			'edit'   => array(
+				'submit_text' => __( 'Save Changes', 'buddypress' ),
+			),
+			'admin'  => array(
+				'metabox_context'  => 'normal',
+				'metabox_priority' => 'core',
+			),
+		);
+
+		foreach ( $screens as $context => &$screen ) {
+			$screen['enabled']     = true;
+			$screen['name']        = $this->name;
+			$screen['slug']        = $this->slug;
+
+			$screen['screen_callback']      = $this->get_screen_callback( $context, 'screen'      );
+			$screen['screen_save_callback'] = $this->get_screen_callback( $context, 'screen_save' );
+		}
+
+		return $screens;
+	}
+
+	/**
+	 * Set up screens array based on params.
+	 *
+	 * @since BuddyPress (1.8.0)
+	 */
+	protected function setup_screens() {
+		foreach ( (array) $this->params['screens'] as $context => $screen ) {
+			if ( empty( $screen['slug'] ) ) {
+				$screen['slug'] = $this->slug;
+			}
+
+			if ( empty( $screen['name'] ) ) {
+				$screen['name'] = $this->name;
+			}
+
+			$this->screens[ $context ] = $screen;
+		}
+	}
+
+	/** Display ***********************************************************/
+
+	/**
+	 * Hook this extension's group tab into BuddyPress, if necessary.
+	 *
+	 * @since BuddyPress (1.8.0)
+	 */
+	protected function setup_display_hooks() {
+
+		// Bail if not a group
+		if ( ! bp_is_group() ) {
+			return;
+		}
+
+		// Bail if the current user doesn't have access
+		if ( ( 'public' !== $this->visibility ) && ! buddypress()->groups->current_group->user_has_access ) {
+			return;
+		}
+
+		if ( true === $this->enable_nav_item ) {
+			bp_core_new_subnav_item( array(
+				'name'            => ! $this->nav_item_name ? $this->name : $this->nav_item_name,
+				'slug'            => $this->slug,
+				'parent_slug'     => bp_get_current_group_slug(),
+				'parent_url'      => bp_get_group_permalink( groups_get_current_group() ),
+				'position'        => $this->nav_item_position,
+				'item_css_id'     => 'nav-' . $this->slug,
+				'screen_function' => array( &$this, '_display_hook' ),
+				'user_has_access' => $this->enable_nav_item
+			) );
+
+			// When we are viewing the extension display page, set the title and options title
+			if ( bp_is_current_action( $this->slug ) ) {
+				add_action( 'bp_template_content_header', create_function( '', 'echo "' . esc_attr( $this->name ) . '";' ) );
+				add_action( 'bp_template_title',          create_function( '', 'echo "' . esc_attr( $this->name ) . '";' ) );
+			}
+		}
+
+		// Hook the group home widget
+		if ( ! bp_current_action() && bp_is_current_action( 'home' ) ) {
+			add_action( $this->display_hook, array( &$this, 'widget_display' ) );
+		}
+	}
+
+	/**
+	 * Hook the main display method, and loads the template file
+	 */
+	public function _display_hook() {
+		add_action( 'bp_template_content', array( &$this, 'display' ) );
+		bp_core_load_template( apply_filters( 'bp_core_template_plugin', $this->template_file ) );
+	}
+
+	/** Create ************************************************************/
+
+	/**
+	 * Hook this extension's Create step into BuddyPress, if necessary.
+	 *
+	 * @since BuddyPress (1.8.0)
+	 */
+	protected function setup_create_hooks() {
+		if ( ! $this->is_screen_enabled( 'create' ) ) {
+			return;
+		}
+
+		$screen = $this->screens['create'];
+
+		// Insert the group creation step for the new group extension
+		buddypress()->groups->group_creation_steps[ $screen['slug'] ] = array(
+			'name'     => $screen['name'],
+			'slug'     => $screen['slug'],
+			'position' => $screen['position'],
+		);
+
+		// The maybe_ methods check to see whether the create_*
+		// callbacks should be invoked (ie, are we on the
+		// correct group creation step). Hooked in separate
+		// methods because current creation step info not yet
+		// available at this point
+		add_action( 'groups_custom_create_steps', array( $this, 'maybe_create_screen' ) );
+		add_action( 'groups_create_group_step_save_' . $screen['slug'], array( $this, 'maybe_create_screen_save' ) );
+	}
+
+	/**
+	 * Call the create_screen() method, if we're on the right page.
+	 *
+	 * @since BuddyPress (1.8.0)
+	 */
+	public function maybe_create_screen() {
+		if ( ! bp_is_group_creation_step( $this->screens['create']['slug'] ) ) {
+			return;
+		}
+
+		call_user_func( $this->screens['create']['screen_callback'], $this->group_id );
+		$this->nonce_field( 'create' );
+
+		// The create screen requires an additional nonce field
+		// due to a quirk in the way the templates are built
+		wp_nonce_field( 'groups_create_save_' . bp_get_groups_current_create_step(), '_wpnonce', false );
+	}
+
+	/**
+	 * Call the create_screen_save() method, if we're on the right page.
+	 *
+	 * @since BuddyPress (1.8.0)
+	 */
+	public function maybe_create_screen_save() {
+		if ( ! bp_is_group_creation_step( $this->screens['create']['slug'] ) ) {
+			return;
+		}
+
+		$this->check_nonce( 'create' );
+		call_user_func( $this->screens['create']['screen_save_callback'], $this->group_id );
+	}
+
+	/** Edit **************************************************************/
+
+	/**
+	 * Hook this extension's Edit panel into BuddyPress, if necessary.
+	 *
+	 * @since BuddyPress (1.8.0)
+	 */
+	protected function setup_edit_hooks() {
+
+		// Bail if not an edit screen
+		if ( ! $this->is_screen_enabled( 'edit' ) || ! bp_is_item_admin() ) {
+			return;
+		}
+
+		$screen = $this->screens['edit'];
+
+		$position = isset( $screen['position'] ) ? (int) $screen['position'] : 10;
+
+		// Add the tab
+		// @todo BP should be using bp_core_new_subnav_item()
+		add_action( 'groups_admin_tabs', create_function( '$current, $group_slug',
+			'$selected = "";
+			if ( "' . esc_attr( $screen['slug'] ) . '" == $current )
+				$selected = " class=\"current\"";
+			echo "<li{$selected}><a href=\"' . trailingslashit( bp_get_root_domain() . '/' . bp_get_groups_root_slug() . '/{$group_slug}/admin/' . esc_attr( $screen['slug'] ) ) . '\">' . esc_attr( $screen['name'] ) . '</a></li>";'
+		), $position, 2 );
+
+		// Catch the edit screen and forward it to the plugin template
+		if ( bp_is_groups_component() && bp_is_current_action( 'admin' ) && bp_is_action_variable( $screen['slug'], 0 ) ) {
+			$this->call_edit_screen_save( $this->group_id );
+
+			add_action( 'groups_custom_edit_steps', array( &$this, 'call_edit_screen' ) );
+
+			// Determine the proper template and save for later
+			// loading
+			if ( '' !== bp_locate_template( array( 'groups/single/home.php' ), false ) ) {
+				$this->edit_screen_template = '/groups/single/home';
+			} else {
+				add_action( 'bp_template_content_header', create_function( '', 'echo "<ul class=\"content-header-nav\">"; bp_group_admin_tabs(); echo "</ul>";' ) );
+				add_action( 'bp_template_content', array( &$this, 'call_edit_screen' ) );
+				$this->edit_screen_template = '/groups/single/plugins';
+			}
+
+			// We load the template at bp_screens, to give all
+			// extensions a chance to load
+			add_action( 'bp_screens', array( $this, 'call_edit_screen_template_loader' ) );
+		}
+	}
+
+	/**
+	 * Call the edit_screen() method.
+	 *
+	 * Previous versions of BP_Group_Extension required plugins to provide
+	 * their own Submit button and nonce fields when building markup. In
+	 * BP 1.8, this requirement was lifted - BP_Group_Extension now handles
+	 * all required submit buttons and nonces.
+	 *
+	 * We put the edit screen markup into an output buffer before echoing.
+	 * This is so that we can check for the presence of a hardcoded submit
+	 * button, as would be present in legacy plugins; if one is found, we
+	 * do not auto-add our own button.
+	 *
+	 * @since BuddyPress (1.8.0)
+	 */
+	public function call_edit_screen() {
+		ob_start();
+		call_user_func( $this->screens['edit']['screen_callback'], $this->group_id );
+		$screen = ob_get_contents();
+		ob_end_clean();
+
+		echo $this->maybe_add_submit_button( $screen );
+
+		$this->nonce_field( 'edit' );
+	}
+
+	/**
+	 * Check the nonce, and call the edit_screen_save() method.
+	 *
+	 * @since BuddyPress (1.8.0)
+	 */
+	public function call_edit_screen_save() {
+		if ( empty( $_POST ) ) {
+			return;
+		}
+
+		// When DOING_AJAX, the POST global will be populated, but we
+		// should assume it's a save
+		if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
+			return;
+		}
+
+		$this->check_nonce( 'edit' );
+		call_user_func( $this->screens['edit']['screen_save_callback'], $this->group_id );
+	}
+
+	/**
+	 * Load the template that houses the Edit screen.
+	 *
+	 * Separated out into a callback so that it can run after all other
+	 * Group Extensions have had a chance to register their navigation, to
+	 * avoid missing tabs.
+	 *
+	 * Hooked to 'bp_screens'.
+	 *
+	 * @since BuddyPress (1.8.0)
+	 * @access public So that do_action() has access. Do not call directly.
+	 *
+	 * @see BP_Group_Extension::setup_edit_hooks()
+	 */
+	public function call_edit_screen_template_loader() {
+		bp_core_load_template( $this->edit_screen_template );
+	}
+
+	/**
+	 * Add a submit button to the edit form, if it needs one.
+	 *
+	 * There's an inconsistency in the way that the group Edit and Create
+	 * screens are rendered: the Create screen has a submit button built
+	 * in, but the Edit screen does not. This function allows plugin
+	 * authors to write markup that does not contain the submit button for
+	 * use on both the Create and Edit screens - BP will provide the button
+	 * if one is not found.
+	 *
+	 * @since BuddyPress (1.8.0)
+	 *
+	 * @param string $screen The screen markup, captured in the output
+	 *        buffer.
+	 * @param string $screen The same markup, with a submit button added.
+	 */
+	protected function maybe_add_submit_button( $screen = '' ) {
+		if ( $this->has_submit_button( $screen ) ) {
+			return $screen;
+		}
+
+		return $screen . sprintf(
+			'<div id="%s"><input type="submit" name="save" value="%s" id="%s"></div>',
+			'bp-group-edit-' . $this->slug . '-submit-wrapper',
+			$this->screens['edit']['submit_text'],
+			'bp-group-edit-' . $this->slug . '-submit'
+		);
+	}
+
+	/**
+	 * Does the given markup have a submit button?
+	 *
+	 * @since BuddyPress (1.8.0)
+	 *
+	 * @param string $screen The markup to check.
+	 * @return bool True if a Submit button is found, otherwise false.
+	 */
+	public static function has_submit_button( $screen = '' ) {
+		$pattern = "/<input[^>]+type=[\'\"]submit[\'\"]/";
+		preg_match( $pattern, $screen, $matches );
+		return ! empty( $matches[0] );
+	}
+
+	/** Admin *************************************************************/
+
+	/**
+	 * Hook this extension's Admin metabox into BuddyPress, if necessary.
+	 *
+	 * @since BuddyPress (1.8.0)
+	 */
+	protected function setup_admin_hooks() {
+		if ( ! $this->is_screen_enabled( 'admin' ) || ! is_admin() ) {
+			return;
+		}
+
+		// Hook the admin screen markup function to the content hook
+		add_action( 'bp_groups_admin_meta_box_content_' . $this->slug, array( $this, 'call_admin_screen' ) );
+
+		// Initialize the metabox
+		add_action( 'bp_groups_admin_meta_boxes', array( $this, '_meta_box_display_callback' ) );
+
+		// Catch the metabox save
+		add_action( 'bp_group_admin_edit_after', array( $this, 'call_admin_screen_save' ), 10 );
+	}
+
+	/**
+	 * Call the admin_screen() method, and add a nonce field.
+	 *
+	 * @since BuddyPress (1.8.0)
+	 */
+	public function call_admin_screen() {
+		call_user_func( $this->screens['admin']['screen_callback'], $this->group_id );
+		$this->nonce_field( 'admin' );
+	}
+
+	/**
+	 * Check the nonce, and call the admin_screen_save() method
+	 *
+	 * @since BuddyPress (1.8.0)
+	 */
+	public function call_admin_screen_save() {
+		$this->check_nonce( 'admin' );
+		call_user_func( $this->screens['admin']['screen_save_callback'], $this->group_id );
+	}
+
+	/**
+	 * Create the Dashboard meta box for this extension.
+	 *
+	 * @since BuddyPress (1.7.0)
+	 */
+	public function _meta_box_display_callback() {
+		$group_id = isset( $_GET['gid'] ) ? (int) $_GET['gid'] : 0;
+		$screen   = $this->screens['admin'];
+
+		add_meta_box(
+			$screen['slug'],
+			$screen['name'],
+			create_function( '', 'do_action( "bp_groups_admin_meta_box_content_' . $this->slug . '", ' . $group_id . ' );' ),
+			get_current_screen()->id,
+			$screen['metabox_context'],
+			$screen['metabox_priority']
+		);
+	}
+
+
+	/** Utilities *********************************************************/
+
+	/**
+	 * Generate the nonce fields for a settings form.
+	 *
+	 * The nonce field name (the second param passed to wp_nonce_field)
+	 * contains this extension's slug and is thus unique to this extension.
+	 * This is necessary because in some cases (namely, the Dashboard),
+	 * more than one extension may generate nonces on the same page, and we
+	 * must avoid name clashes.
+	 *
+	 * @since BuddyPress (1.8.0)
+	 *
+	 * @uses wp_nonce_field()
+	 *
+	 * @param string $context Screen context. 'create', 'edit', or 'admin'.
+	 */
+	public function nonce_field( $context = '' ) {
+		wp_nonce_field( 'bp_group_extension_' . $this->slug . '_' . $context, '_bp_group_' . $context . '_nonce_' . $this->slug );
+	}
+
+	/**
+	 * Check the nonce on a submitted settings form.
+	 *
+	 * @since BuddyPress (1.8.0)
+	 *
+	 * @uses check_admin_referer()
+	 *
+	 * @param string $context Screen context. 'create', 'edit', or 'admin'.
+	 */
+	public function check_nonce( $context = '' ) {
+		check_admin_referer( 'bp_group_extension_' . $this->slug . '_' . $context, '_bp_group_' . $context . '_nonce_' . $this->slug );
+	}
+
+	/**
+	 * Is the specified screen enabled?
+	 *
+	 * To be enabled, a screen must both have the 'enabled' key set to true
+	 * (legacy: $this->enable_create_step, etc), and its screen_callback
+	 * must also exist and be callable.
+	 *
+	 * @since BuddyPress (1.8.0)
+	 *
+	 * @param string $context Screen context. 'create', 'edit', or 'admin'.
+	 *
+	 * @return bool True if the screen is enabled, otherwise false.
+	 */
+	public function is_screen_enabled( $context = '' ) {
+		$enabled = false;
+
+		if ( isset( $this->screens[ $context ] ) ) {
+			$enabled = $this->screens[ $context ]['enabled'] && is_callable( $this->screens[ $context ]['screen_callback'] );
+		}
+
+		return (bool) $enabled;
+	}
+
+	/**
+	 * Get the appropriate screen callback for the specified context/type.
+	 *
+	 * BP Group Extensions have three special "screen contexts": create,
+	 * admin, and edit. Each of these contexts has a corresponding
+	 * _screen() and _screen_save() method, which allow group extension
+	 * plugins to define different markup and logic for each context.
+	 *
+	 * BP also supports fallback settings_screen() and
+	 * settings_screen_save() methods, which can be used to define markup
+	 * and logic that is shared between context. For each context, you may
+	 * either provide context-specific methods, or you can let BP fall back
+	 * on the shared settings_* callbacks.
+	 *
+	 * For example, consider a BP_Group_Extension implementation that looks
+	 * like this:
+	 *
+	 *   // ...
+	 *   function create_screen( $group_id ) { ... }
+	 *   function create_screen_save( $group_id ) { ... }
+	 *   function settings_screen( $group_id ) { ... }
+	 *   function settings_screen_save( $group_id ) { ... }
+	 *   // ...
+	 *
+	 * BP_Group_Extension will use your create_* methods for the Create
+	 * steps, and will use your generic settings_* methods for the Edit
+	 * and Admin contexts. This schema allows plugin authors maximum
+	 * flexibility without having to repeat themselves.
+	 *
+	 * The get_screen_callback() method uses a ReflectionClass object to
+	 * determine whether your extension has provided a given callback.
+	 *
+	 * @since BuddyPress (1.8.0)
+	 *
+	 * @param string $context Screen context. 'create', 'edit', or 'admin'.
+	 * @param string $type Screen type. 'screen' or 'screen_save'. Default:
+	 *        'screen'.
+	 * @return callable A callable function handle.
+	 */
+	public function get_screen_callback( $context = '', $type = 'screen' ) {
+		$callback = '';
+
+		// Try the context-specific callback first
+		$method  = $context . '_' . $type;
+		$rmethod = $this->class_reflection->getMethod( $method );
+		if ( isset( $rmethod->class ) && $this->class_name === $rmethod->class ) {
+			$callback = array( $this, $method );
+		}
+
+		if ( empty( $callback ) ) {
+			$fallback_method  = 'settings_' . $type;
+			$rfallback_method = $this->class_reflection->getMethod( $fallback_method );
+			if ( isset( $rfallback_method->class ) && $this->class_name === $rfallback_method->class ) {
+				$callback = array( $this, $fallback_method );
+			}
+		}
+
+		return $callback;
+	}
+
+	/**
+	 * Recursive argument parsing.
+	 *
+	 * This acts like a multi-dimensional version of wp_parse_args() (minus
+	 * the querystring parsing - you must pass arrays).
+	 *
+	 * Values from $a override those from $b; keys in $b that don't exist
+	 * in $a are passed through.
+	 *
+	 * This is different from array_merge_recursive(), both because of the
+	 * order of preference ($a overrides $b) and because of the fact that
+	 * array_merge_recursive() combines arrays deep in the tree, rather
+	 * than overwriting the b array with the a array.
+	 *
+	 * The implementation of this function is specific to the needs of
+	 * BP_Group_Extension, where we know that arrays will always be
+	 * associative, and that an argument under a given key in one array
+	 * will be matched by a value of identical depth in the other one. The
+	 * function is NOT designed for general use, and will probably result
+	 * in unexpected results when used with data in the wild. See, eg,
+	 * http://core.trac.wordpress.org/ticket/19888
+	 *
+	 * @since BuddyPress (1.8.0)
+	 *
+	 * @param array $a First set of arguments.
+	 * @param array $b Second set of arguments.
+	 * @return array Parsed arguments.
+	 */
+	public static function parse_args_r( &$a, $b ) {
+		$a = (array) $a;
+		$b = (array) $b;
+		$r = $b;
+
+		foreach ( $a as $k => &$v ) {
+			if ( is_array( $v ) && isset( $r[ $k ] ) ) {
+				$r[ $k ] = self::parse_args_r( $v, $r[ $k ] );
+			} else {
+				$r[ $k ] = $v;
+			}
+		}
+
+		return $r;
+	}
+
+	/** Legacy Support ********************************************************/
+
+	/*
+	 * In BuddyPress 1.8, the recommended technique for configuring
+	 * extensions changed from directly setting various object properties
+	 * in the class constructor, to passing a configuration array to
+	 * parent::init(). The following methods ensure that extensions created
+	 * in the old way continue to work, by converting legacy configuration
+	 * data to the new format.
+	 */
+
+	/**
+	 * Provide access to otherwise unavailable object properties.
+	 *
+	 * This magic method is here for backward compatibility with plugins
+	 * that refer to config properties that have moved to a different
+	 * location (such as enable_create_step, which is now at
+	 * $this->screens['create']['enabled']
+	 *
+	 * The legacy_properties array is set up in
+	 * self::setup_legacy_properties().
+	 *
+	 * @since BuddyPress (1.8.0)
+	 *
+	 * @param string $key Property name.
+	 * @return mixed The value if found, otherwise null.
+	 */
+	public function __get( $key ) {
+		if ( isset( $this->legacy_properties[ $key ] ) ) {
+			return $this->legacy_properties[ $key ];
+		} elseif ( isset( $this->data[ $key ] ) ) {
+			return $this->data[ $key ];
+		} else {
+			return null;
+		}
+	}
+
+	/**
+	 * Provide a fallback for isset( $this->foo ) when foo is unavailable.
+	 *
+	 * This magic method is here for backward compatibility with plugins
+	 * that have set their class config options directly in the class
+	 * constructor. The parse_legacy_properties() method of the current
+	 * class needs to check whether any legacy keys have been put into the
+	 * $this->data array.
+	 *
+	 * @since BuddyPress (1.8.0)
+	 *
+	 * @param string $key Property name.
+	 * @return bool True if the value is set, otherwise false.
+	 */
+	public function __isset( $key ) {
+		if ( isset( $this->legacy_properties[ $key ] ) ) {
+			return true;
+		} elseif ( isset( $this->data[ $key ] ) ) {
+			return true;
+		} else {
+			return false;
+		}
+	}
+
+	/**
+	 * Allow plugins to set otherwise unavailable object properties.
+	 *
+	 * This magic method is here for backward compatibility with plugins
+	 * that may attempt to modify the group extension by manually assigning
+	 * a value to an object property that no longer exists, such as
+	 * $this->enable_create_step.
+	 *
+	 * @since BuddyPress (1.8.0)
+	 *
+	 * @param string $key Property name.
+	 * @param mixed $value Property value.
+	 */
+	public function __set( $key, $value ) {
+
+		if ( empty( $this->initialized ) ) {
+			$this->data[ $key ] = $value;
+		}
+
+		switch ( $key ) {
+			case 'enable_create_step' :
+				$this->screens['create']['enabled'] = $value;
+				break;
+
+			case 'enable_edit_item' :
+				$this->screens['edit']['enabled'] = $value;
+				break;
+
+			case 'enable_admin_item' :
+				$this->screens['admin']['enabled'] = $value;
+				break;
+
+			case 'create_step_position' :
+				$this->screens['create']['position'] = $value;
+				break;
+
+			// Note: 'admin' becomes 'edit' to distinguish from Dashboard 'admin'
+			case 'admin_name' :
+				$this->screens['edit']['name'] = $value;
+				break;
+
+			case 'admin_slug' :
+				$this->screens['edit']['slug'] = $value;
+				break;
+
+			case 'create_name' :
+				$this->screens['create']['name'] = $value;
+				break;
+
+			case 'create_slug' :
+				$this->screens['create']['slug'] = $value;
+				break;
+
+			case 'admin_metabox_context' :
+				$this->screens['admin']['metabox_context'] = $value;
+				break;
+
+			case 'admin_metabox_priority' :
+				$this->screens['admin']['metabox_priority'] = $value;
+				break;
+
+			default :
+				$this->data[ $key ] = $value;
+				break;
+		}
+	}
+
+	/**
+	 * Return a list of legacy properties.
+	 *
+	 * The legacy implementation of BP_Group_Extension used all of these
+	 * object properties for configuration. Some have been moved.
+	 *
+	 * @since BuddyPress (1.8.0)
+	 *
+	 * @return array List of legacy property keys.
+	 */
+	protected function get_legacy_property_list() {
+		return array(
+			'name',
+			'slug',
+			'admin_name',
+			'admin_slug',
+			'create_name',
+			'create_slug',
+			'visibility',
+			'create_step_position',
+			'nav_item_position',
+			'admin_metabox_context',
+			'admin_metabox_priority',
+			'enable_create_step',
+			'enable_nav_item',
+			'enable_edit_item',
+			'enable_admin_item',
+			'nav_item_name',
+			'display_hook',
+			'template_file',
+		);
+	}
+
+	/**
+	 * Parse legacy properties.
+	 *
+	 * The old standard for BP_Group_Extension was for plugins to register
+	 * their settings as properties in their constructor. The new method is
+	 * to pass a config array to the init() method. In order to support
+	 * legacy plugins, we slurp up legacy properties, and later on we'll
+	 * parse them into the new init() array.
+	 *
+	 * @since BuddyPress (1.8.0)
+	 */
+	protected function parse_legacy_properties() {
+
+		// Only run this one time
+		if ( ! empty( $this->legacy_properties_converted ) ) {
+			return;
+		}
+
+		$properties = $this->get_legacy_property_list();
+
+		// By-reference variable for convenience
+		$lpc =& $this->legacy_properties_converted;
+
+		foreach ( $properties as $property ) {
+
+			// No legacy config exists for this key
+			if ( ! isset( $this->{$property} ) ) {
+				continue;
+			}
+
+			// Grab the value and record it as appropriate
+			$value = $this->{$property};
+
+			switch ( $property ) {
+				case 'enable_create_step' :
+					$lpc['screens']['create']['enabled'] = (bool) $value;
+					break;
+
+				case 'enable_edit_item' :
+					$lpc['screens']['edit']['enabled'] = (bool) $value;
+					break;
+
+				case 'enable_admin_item' :
+					$lpc['screens']['admin']['enabled'] = (bool) $value;
+					break;
+
+				case 'create_step_position' :
+					$lpc['screens']['create']['position'] = $value;
+					break;
+
+				// Note: 'admin' becomes 'edit' to distinguish from Dashboard 'admin'
+				case 'admin_name' :
+					$lpc['screens']['edit']['name'] = $value;
+					break;
+
+				case 'admin_slug' :
+					$lpc['screens']['edit']['slug'] = $value;
+					break;
+
+				case 'create_name' :
+					$lpc['screens']['create']['name'] = $value;
+					break;
+
+				case 'create_slug' :
+					$lpc['screens']['create']['slug'] = $value;
+					break;
+
+				case 'admin_metabox_context' :
+					$lpc['screens']['admin']['metabox_context'] = $value;
+					break;
+
+				case 'admin_metabox_priority' :
+					$lpc['screens']['admin']['metabox_priority'] = $value;
+					break;
+
+				default :
+					$lpc[ $property ] = $value;
+					break;
+			}
+		}
+	}
+
+	/**
+	 * Set up legacy properties.
+	 *
+	 * This method is responsible for ensuring that all legacy config
+	 * properties are stored in an array $this->legacy_properties, so that
+	 * they remain available to plugins that reference the variables at
+	 * their old locations.
+	 *
+	 * @since BuddyPress (1.8.0)
+	 *
+	 * @see BP_Group_Extension::__get()
+	 */
+	protected function setup_legacy_properties() {
+
+		// Only run this one time
+		if ( ! empty( $this->legacy_properties ) ) {
+			return;
+		}
+
+		$properties = $this->get_legacy_property_list();
+		$params     = $this->params;
+		$lp         =& $this->legacy_properties;
+
+		foreach ( $properties as $property ) {
+			switch ( $property ) {
+				case 'enable_create_step' :
+					$lp['enable_create_step'] = $params['screens']['create']['enabled'];
+					break;
+
+				case 'enable_edit_item' :
+					$lp['enable_edit_item'] = $params['screens']['edit']['enabled'];
+					break;
+
+				case 'enable_admin_item' :
+					$lp['enable_admin_item'] = $params['screens']['admin']['enabled'];
+					break;
+
+				case 'create_step_position' :
+					$lp['create_step_position'] = $params['screens']['create']['position'];
+					break;
+
+				// Note: 'admin' becomes 'edit' to distinguish from Dashboard 'admin'
+				case 'admin_name' :
+					$lp['admin_name'] = $params['screens']['edit']['name'];
+					break;
+
+				case 'admin_slug' :
+					$lp['admin_slug'] = $params['screens']['edit']['slug'];
+					break;
+
+				case 'create_name' :
+					$lp['create_name'] = $params['screens']['create']['name'];
+					break;
+
+				case 'create_slug' :
+					$lp['create_slug'] = $params['screens']['create']['slug'];
+					break;
+
+				case 'admin_metabox_context' :
+					$lp['admin_metabox_context'] = $params['screens']['admin']['metabox_context'];
+					break;
+
+				case 'admin_metabox_priority' :
+					$lp['admin_metabox_priority'] = $params['screens']['admin']['metabox_priority'];
+					break;
+
+				default :
+					// All other items get moved over
+					$lp[ $property ] = $params[ $property ];
+
+					// Also reapply to the object, for backpat
+					$this->{$property} = $params[ $property ];
+
+					break;
+			}
+		}
+	}
+}
+
+/**
+ * Register a new Group Extension.
+ *
+ * @param string Name of the Extension class.
+ * @return bool|null Returns false on failure, otherwise null.
+ */
+function bp_register_group_extension( $group_extension_class = '' ) {
+
+	if ( ! class_exists( $group_extension_class ) ) {
+		return false;
+	}
+
+	// Register the group extension on the bp_init action so we have access
+	// to all plugins.
+	add_action( 'bp_init', create_function( '', '
+		$extension = new ' . $group_extension_class . ';
+		add_action( "bp_actions", array( &$extension, "_register" ), 8 );
+		add_action( "admin_init", array( &$extension, "_register" ) );
+	' ), 11 );
+}
Index: /tags/1.9/bp-groups/bp-groups-filters.php
===================================================================
--- /tags/1.9/bp-groups/bp-groups-filters.php	(revision 7684)
+++ /tags/1.9/bp-groups/bp-groups-filters.php	(revision 7684)
@@ -0,0 +1,171 @@
+<?php
+
+/**
+ * BuddyPress Groups Filters
+ *
+ * @package BuddyPress
+ * @subpackage GroupsFilters
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+// Filter bbPress template locations
+
+add_filter( 'bp_groups_get_directory_template', 'bp_add_template_locations' );
+add_filter( 'bp_get_single_group_template',    'bp_add_template_locations' );
+
+/* Apply WordPress defined filters */
+add_filter( 'bp_get_group_description',         'wptexturize' );
+add_filter( 'bp_get_group_description_excerpt', 'wptexturize' );
+add_filter( 'bp_get_group_name',                'wptexturize' );
+
+add_filter( 'bp_get_group_description',         'convert_smilies' );
+add_filter( 'bp_get_group_description_excerpt', 'convert_smilies' );
+
+add_filter( 'bp_get_group_description',         'convert_chars' );
+add_filter( 'bp_get_group_description_excerpt', 'convert_chars' );
+add_filter( 'bp_get_group_name',                'convert_chars' );
+
+add_filter( 'bp_get_group_description',         'wpautop' );
+add_filter( 'bp_get_group_description_excerpt', 'wpautop' );
+
+add_filter( 'bp_get_group_description',         'make_clickable', 9 );
+add_filter( 'bp_get_group_description_excerpt', 'make_clickable', 9 );
+
+add_filter( 'bp_get_group_name',                    'wp_filter_kses', 1 );
+add_filter( 'bp_get_group_permalink',               'wp_filter_kses', 1 );
+add_filter( 'bp_get_group_description',             'bp_groups_filter_kses', 1 );
+add_filter( 'bp_get_group_description_excerpt',     'wp_filter_kses', 1 );
+add_filter( 'groups_group_name_before_save',        'wp_filter_kses', 1 );
+add_filter( 'groups_group_description_before_save', 'wp_filter_kses', 1 );
+
+add_filter( 'bp_get_group_description',         'stripslashes' );
+add_filter( 'bp_get_group_description_excerpt', 'stripslashes' );
+add_filter( 'bp_get_group_name',                'stripslashes' );
+add_filter( 'bp_get_group_member_name',         'stripslashes' );
+add_filter( 'bp_get_group_member_link',         'stripslashes' );
+
+add_filter( 'groups_new_group_forum_desc', 'bp_create_excerpt' );
+
+add_filter( 'groups_group_name_before_save',        'force_balance_tags' );
+add_filter( 'groups_group_description_before_save', 'force_balance_tags' );
+
+add_filter( 'bp_get_total_group_count',      'bp_core_number_format' );
+add_filter( 'bp_get_group_total_for_member', 'bp_core_number_format' );
+add_filter( 'bp_get_group_total_members',    'bp_core_number_format' );
+
+function bp_groups_filter_kses( $content ) {
+	global $allowedtags;
+
+	$groups_allowedtags                  = $allowedtags;
+	$groups_allowedtags['a']['class']    = array();
+	$groups_allowedtags['img']           = array();
+	$groups_allowedtags['img']['src']    = array();
+	$groups_allowedtags['img']['alt']    = array();
+	$groups_allowedtags['img']['class']  = array();
+	$groups_allowedtags['img']['width']  = array();
+	$groups_allowedtags['img']['height'] = array();
+	$groups_allowedtags['img']['class']  = array();
+	$groups_allowedtags['img']['id']     = array();
+	$groups_allowedtags['code']          = array();
+	$groups_allowedtags = apply_filters( 'bp_groups_filter_kses', $groups_allowedtags );
+
+	return wp_kses( $content, $groups_allowedtags );
+}
+
+/** Group forums **************************************************************/
+
+/**
+ * Only filter the forum SQL on group pages or on the forums directory
+ */
+function groups_add_forum_privacy_sql() {
+	add_filter( 'get_topics_fields', 'groups_add_forum_fields_sql' );
+	add_filter( 'get_topics_join', 	 'groups_add_forum_tables_sql' );
+	add_filter( 'get_topics_where',  'groups_add_forum_where_sql'  );
+}
+add_filter( 'bbpress_init', 'groups_add_forum_privacy_sql' );
+
+function groups_add_forum_fields_sql( $sql = '' ) {
+	$sql = 't.*, g.id as object_id, g.name as object_name, g.slug as object_slug';
+	return $sql;
+}
+
+function groups_add_forum_tables_sql( $sql = '' ) {
+	global $bp;
+
+	$sql .= 'JOIN ' . $bp->groups->table_name . ' AS g LEFT JOIN ' . $bp->groups->table_name_groupmeta . ' AS gm ON g.id = gm.group_id ';
+
+	return $sql;
+}
+
+function groups_add_forum_where_sql( $sql = '' ) {
+	global $bp;
+
+	// Define locale variable
+	$parts = array();
+
+	// Set this for groups
+	$parts['groups'] = "(gm.meta_key = 'forum_id' AND gm.meta_value = t.forum_id)";
+
+	// Restrict to public...
+	$parts['private'] = "g.status = 'public'";
+
+	/**
+	 * ...but do some checks to possibly remove public restriction.
+	 *
+	 * Decide if private are visible
+	 */
+	// Are we in our own profile?
+	if ( bp_is_my_profile() )
+		unset( $parts['private'] );
+
+	// Are we a super admin?
+	elseif ( bp_current_user_can( 'bp_moderate' ) )
+		unset( $parts['private'] );
+
+	// No need to filter on a single item
+	elseif ( bp_is_single_item() )
+		unset( $parts['private'] );
+
+	// Check the SQL filter that was passed
+	if ( !empty( $sql ) )
+		$parts['passed'] = $sql;
+
+	// Assemble Voltron
+	$parts_string = implode( ' AND ', $parts );
+
+	// Set it to the global filter
+	$bp->groups->filter_sql = $parts_string;
+
+	// Return the global filter
+	return $bp->groups->filter_sql;
+}
+
+function groups_filter_bbpress_caps( $value, $cap, $args ) {
+	global $bp;
+
+	if ( bp_current_user_can( 'bp_moderate' ) )
+		return true;
+
+	if ( 'add_tag_to' == $cap )
+		if ( $bp->groups->current_group->user_has_access ) return true;
+
+	if ( 'manage_forums' == $cap && is_user_logged_in() )
+		return true;
+
+	return $value;
+}
+add_filter( 'bb_current_user_can', 'groups_filter_bbpress_caps', 10, 3 );
+
+/**
+ * Amends the forum directory's "last active" bbPress SQL query to stop it fetching
+ * information we aren't going to use. This speeds up the query.
+ *
+ * @see BB_Query::_filter_sql()
+ * @since BuddyPress (1.5)
+ */
+function groups_filter_forums_root_page_sql( $sql ) {
+	return apply_filters( 'groups_filter_bbpress_root_page_sql', 't.topic_id' );
+}
+add_filter( 'get_latest_topics_fields', 'groups_filter_forums_root_page_sql' );
Index: /tags/1.9/bp-groups/bp-groups-forums.php
===================================================================
--- /tags/1.9/bp-groups/bp-groups-forums.php	(revision 7684)
+++ /tags/1.9/bp-groups/bp-groups-forums.php	(revision 7684)
@@ -0,0 +1,409 @@
+<?php
+
+/**
+ * BuddyPress Groups Forums
+ *
+ * Action functions are exactly the same as screen functions, however they do not
+ * have a template screen associated with them. Usually they will send the user
+ * back to the default screen after execution.
+ *
+ * Note that this file is only used for the retired version of bbPress (1.x) and
+ * will see minimal updates as of BuddyPress 1.9.0.
+ *
+ * @package BuddyPress
+ * @subpackage GroupsForums
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/**
+ * Creates a new forum inside a specific BuddyPress group.
+ *
+ * Uses the bundled version of bbPress packaged with BuddyPress.
+ *
+ * @param int $group_id The group ID that the new forum should be attached to
+ * @param string $group_name The group name
+ * @param string $group_description The group description
+ *
+ * @since BuddyPress (1.0)
+ */
+function groups_new_group_forum( $group_id = 0, $group_name = '', $group_desc = '' ) {
+	global $bp;
+
+	if ( empty( $group_id ) )
+		$group_id = bp_get_current_group_id();
+
+	if ( empty( $group_name ) )
+		$group_name = bp_get_current_group_name();
+
+	if ( empty( $group_desc ) )
+		$group_desc = $bp->groups->current_group->description;
+
+	$forum_id = bp_forums_new_forum( array( 'forum_name' => $group_name, 'forum_desc' => $group_desc ) );
+
+	groups_update_groupmeta( $group_id, 'forum_id', $forum_id );
+
+	do_action( 'groups_new_group_forum', $forum_id, $group_id );
+}
+
+/**
+ * Updates group forum metadata (title, description, slug) when the group's details are edited
+ *
+ * @package BuddyPress
+ * @subpackage Groups
+ *
+ * @param int $group_id Group id, passed from groups_details_updated
+ *
+ * @since BuddyPress (1.1)
+ */
+function groups_update_group_forum( $group_id ) {
+
+	$group = groups_get_group( array( 'group_id' => $group_id ) );
+
+	/**
+	 * Bail in the following three situations:
+	 *  1. Forums are not enabled for this group
+	 *  2. The BP Forum component is not enabled
+	 *  3. The built-in bbPress forums are not correctly installed (usually means they've been
+	 *     uninstalled)
+	 */
+	if ( empty( $group->enable_forum ) || !bp_is_active( 'forums' ) || ( function_exists( 'bp_forums_is_installed_correctly' ) && !bp_forums_is_installed_correctly() ) )
+		return false;
+
+	$args = array(
+		'forum_id'      => groups_get_groupmeta( $group_id, 'forum_id' ),
+		'forum_name'    => $group->name,
+		'forum_desc'    => $group->description,
+		'forum_slug'    => $group->slug
+	);
+
+	bp_forums_update_forum( apply_filters( 'groups_update_group_forum', $args ) );
+}
+add_action( 'groups_details_updated', 'groups_update_group_forum' );
+
+/**
+ * Creates a new group forum post.
+ *
+ * Uses the bundled version of bbPress packaged with BuddyPress.
+ *
+ * @param string $post_text The text for the forum post
+ * @param int $topic_id The topic ID used so we can identify where the new forum post should reside
+ * @param mixed $page The page number where the new forum post should reside. Defaults to boolean false.
+ * @return mixed The new forum post ID on success. Boolean false on failure.
+ *
+ * @since BuddyPress (1.0)
+ */
+function groups_new_group_forum_post( $post_text, $topic_id, $page = false ) {
+	if ( empty( $post_text ) )
+		return false;
+
+	$post_text = apply_filters( 'group_forum_post_text_before_save', $post_text );
+	$topic_id  = apply_filters( 'group_forum_post_topic_id_before_save', $topic_id );
+
+	if ( $post_id = bp_forums_insert_post( array( 'post_text' => $post_text, 'topic_id' => $topic_id ) ) ) {
+		$topic = bp_forums_get_topic_details( $topic_id );
+
+		$activity_action = sprintf( __( '%1$s replied to the forum topic %2$s in the group %3$s', 'buddypress'), bp_core_get_userlink( bp_loggedin_user_id() ), '<a href="' . bp_get_group_permalink( groups_get_current_group() ) . 'forum/topic/' . $topic->topic_slug .'/">' . esc_attr( $topic->topic_title ) . '</a>', '<a href="' . bp_get_group_permalink( groups_get_current_group() ) . '">' . esc_attr( bp_get_current_group_name() ) . '</a>' );
+		$activity_content = bp_create_excerpt( $post_text );
+		$primary_link = bp_get_group_permalink( groups_get_current_group() ) . 'forum/topic/' . $topic->topic_slug . '/';
+
+		if ( $page )
+			$primary_link .= "?topic_page=" . $page;
+
+		// Record this in activity streams
+		groups_record_activity( array(
+			'action'            => apply_filters_ref_array( 'groups_activity_new_forum_post_action',  array( $activity_action,  $post_id, $post_text, &$topic ) ),
+			'content'           => apply_filters_ref_array( 'groups_activity_new_forum_post_content', array( $activity_content, $post_id, $post_text, &$topic ) ),
+			'primary_link'      => apply_filters( 'groups_activity_new_forum_post_primary_link', "{$primary_link}#post-{$post_id}" ),
+			'type'              => 'new_forum_post',
+			'item_id'           => bp_get_current_group_id(),
+			'secondary_item_id' => $post_id
+		) );
+
+		do_action( 'groups_new_forum_topic_post', bp_get_current_group_id(), $post_id );
+
+		return $post_id;
+	}
+
+	return false;
+}
+
+/**
+ * Creates a new group forum topic.
+ *
+ * Uses the bundled version of bbPress packaged with BuddyPress.
+ *
+ * @param string $topic_title The title for the forum topic
+ * @param string $topic_text The text for the forum topic
+ * @param string $topic_tags A comma-delimited string of topic tags
+ * @param int $forum_id The forum ID this forum topic resides in
+ * @return mixed The new topic object on success. Boolean false on failure.
+ *
+ * @since BuddyPress (1.0)
+ */
+function groups_new_group_forum_topic( $topic_title, $topic_text, $topic_tags, $forum_id ) {
+	if ( empty( $topic_title ) || empty( $topic_text ) )
+		return false;
+
+	$topic_title = apply_filters( 'group_forum_topic_title_before_save', $topic_title );
+	$topic_text  = apply_filters( 'group_forum_topic_text_before_save', $topic_text );
+	$topic_tags  = apply_filters( 'group_forum_topic_tags_before_save', $topic_tags );
+	$forum_id    = apply_filters( 'group_forum_topic_forum_id_before_save', $forum_id );
+
+	if ( $topic_id = bp_forums_new_topic( array( 'topic_title' => $topic_title, 'topic_text' => $topic_text, 'topic_tags' => $topic_tags, 'forum_id' => $forum_id ) ) ) {
+		$topic = bp_forums_get_topic_details( $topic_id );
+
+		$activity_action = sprintf( __( '%1$s started the forum topic %2$s in the group %3$s', 'buddypress'), bp_core_get_userlink( bp_loggedin_user_id() ), '<a href="' . bp_get_group_permalink( groups_get_current_group() ) . 'forum/topic/' . $topic->topic_slug .'/">' . esc_attr( $topic->topic_title ) . '</a>', '<a href="' . bp_get_group_permalink( groups_get_current_group() ) . '">' . esc_attr( bp_get_current_group_name() ) . '</a>' );
+		$activity_content = bp_create_excerpt( $topic_text );
+
+		// Record this in activity streams
+		groups_record_activity( array(
+			'action'            => apply_filters_ref_array( 'groups_activity_new_forum_topic_action',  array( $activity_action,  $topic_text, &$topic ) ),
+			'content'           => apply_filters_ref_array( 'groups_activity_new_forum_topic_content', array( $activity_content, $topic_text, &$topic ) ),
+			'primary_link'      => apply_filters( 'groups_activity_new_forum_topic_primary_link', bp_get_group_permalink( groups_get_current_group() ) . 'forum/topic/' . $topic->topic_slug . '/' ),
+			'type'              => 'new_forum_topic',
+			'item_id'           => bp_get_current_group_id(),
+			'secondary_item_id' => $topic->topic_id
+		) );
+
+		do_action_ref_array( 'groups_new_forum_topic', array( bp_get_current_group_id(), &$topic ) );
+
+		return $topic;
+	}
+
+	return false;
+}
+
+/**
+ * Updates an existing group forum topic.
+ *
+ * Uses the bundled version of bbPress packaged with BuddyPress.
+ *
+ * @param int $topic_id The topic ID of the existing forum topic
+ * @param string $topic_title The title for the forum topic
+ * @param string $topic_text The text for the forum topic
+ * @param mixed $topic_tags A comma-delimited string of topic tags. Defaults to boolean false.
+ * @return mixed The topic object on success. Boolean false on failure.
+ *
+ * @since BuddyPress (1.1)
+ */
+function groups_update_group_forum_topic( $topic_id, $topic_title, $topic_text, $topic_tags = false ) {
+	global $bp;
+
+	$topic_title = apply_filters( 'group_forum_topic_title_before_save', $topic_title );
+	$topic_text  = apply_filters( 'group_forum_topic_text_before_save',  $topic_text  );
+
+	if ( $topic = bp_forums_update_topic( array( 'topic_title' => $topic_title, 'topic_text' => $topic_text, 'topic_id' => $topic_id, 'topic_tags' => $topic_tags ) ) ) {
+
+		// Get the corresponding activity item
+		if ( bp_is_active( 'activity' ) ) {
+			$id = bp_activity_get_activity_id( array(
+					'item_id'           => bp_get_current_group_id(),
+					'secondary_item_id' => $topic_id,
+					'component'         => $bp->groups->id,
+					'type'              => 'new_forum_topic'
+			) );
+		}
+
+		$activity_action = sprintf( __( '%1$s edited the forum topic %2$s in the group %3$s', 'buddypress'), bp_core_get_userlink( $topic->topic_poster ), '<a href="' . bp_get_group_permalink( groups_get_current_group() ) . 'forum/topic/' . $topic->topic_slug .'/">' . esc_attr( $topic->topic_title ) . '</a>', '<a href="' . bp_get_group_permalink( groups_get_current_group() ) . '">' . esc_attr( bp_get_current_group_name() ) . '</a>' );
+		$activity_content = bp_create_excerpt( $topic_text );
+
+		// Record this in activity streams
+		groups_record_activity( array(
+			'id'                => $id,
+			'action'            => apply_filters_ref_array( 'groups_activity_new_forum_topic_action',  array( $activity_action,  $topic_text, &$topic ) ),
+			'content'           => apply_filters_ref_array( 'groups_activity_new_forum_topic_content', array( $activity_content, $topic_text, &$topic ) ),
+			'primary_link'      => apply_filters( 'groups_activity_new_forum_topic_primary_link', bp_get_group_permalink( groups_get_current_group() ) . 'forum/topic/' . $topic->topic_slug . '/' ),
+			'type'              => 'new_forum_topic',
+			'item_id'           => (int) bp_get_current_group_id(),
+			'user_id'           => (int) $topic->topic_poster,
+			'secondary_item_id' => $topic->topic_id,
+			'recorded_time '    => $topic->topic_time
+		) );
+
+		do_action_ref_array( 'groups_update_group_forum_topic', array( &$topic ) );
+
+		return $topic;
+	}
+
+	return false;
+}
+
+/**
+ * Updates an existing group forum post.
+ *
+ * Uses the bundled version of bbPress packaged with BuddyPress.
+ *
+ * @param int $post_id The post ID of the existing forum post
+ * @param string $post_text The text for the forum post
+ * @param int $topic_id The topic ID of the existing forum topic
+ * @param mixed $page The page number where the new forum post should reside. Defaults to boolean false.
+ * @return mixed The forum post ID on success. Boolean false on failure.
+ *
+ * @since BuddyPress (1.1)
+ */
+function groups_update_group_forum_post( $post_id, $post_text, $topic_id, $page = false ) {
+	global $bp;
+
+	$post_text = apply_filters( 'group_forum_post_text_before_save', $post_text );
+	$topic_id  = apply_filters( 'group_forum_post_topic_id_before_save', $topic_id );
+	$post      = bp_forums_get_post( $post_id );
+
+	if ( $post_id = bp_forums_insert_post( array( 'post_id' => $post_id, 'post_text' => $post_text, 'post_time' => $post->post_time, 'topic_id' => $topic_id, 'poster_id' => $post->poster_id ) ) ) {
+		$topic = bp_forums_get_topic_details( $topic_id );
+
+		$activity_action = sprintf( __( '%1$s replied to the forum topic %2$s in the group %3$s', 'buddypress'), bp_core_get_userlink( $post->poster_id ), '<a href="' . bp_get_group_permalink( groups_get_current_group() ) . 'forum/topic/' . $topic->topic_slug .'">' . esc_attr( $topic->topic_title ) . '</a>', '<a href="' . bp_get_group_permalink( groups_get_current_group() ) . '">' . esc_attr( bp_get_current_group_name() ) . '</a>' );
+		$activity_content = bp_create_excerpt( $post_text );
+		$primary_link = bp_get_group_permalink( groups_get_current_group() ) . 'forum/topic/' . $topic->topic_slug . '/';
+
+		if ( $page )
+			$primary_link .= "?topic_page=" . $page;
+
+		// Get the corresponding activity item
+		if ( bp_is_active( 'activity' ) ) {
+			$id = bp_activity_get_activity_id( array(
+				'user_id'           => $post->poster_id,
+				'component'         => $bp->groups->id,
+				'type'              => 'new_forum_post',
+				'item_id'           => bp_get_current_group_id(),
+				'secondary_item_id' => $post_id
+			 ) );
+		}
+
+		// Update the entry in activity streams
+		groups_record_activity( array(
+			'id'                => $id,
+			'action'            => apply_filters_ref_array( 'groups_activity_new_forum_post_action',  array( $activity_action,  $post_text, &$topic, &$topic ) ),
+			'content'           => apply_filters_ref_array( 'groups_activity_new_forum_post_content', array( $activity_content, $post_text, &$topic, &$topic ) ),
+			'primary_link'      => apply_filters( 'groups_activity_new_forum_post_primary_link', $primary_link . "#post-" . $post_id ),
+			'type'              => 'new_forum_post',
+			'item_id'           => (int) bp_get_current_group_id(),
+			'user_id'           => (int) $post->poster_id,
+			'secondary_item_id' => $post_id,
+			'recorded_time'     => $post->post_time
+		) );
+
+		do_action_ref_array( 'groups_update_group_forum_post', array( $post, &$topic ) );
+
+		return $post_id;
+	}
+
+	return false;
+}
+
+/**
+ * Deletes a group forum topic and also any corresponding activity items.
+ *
+ * Uses the bundled version of bbPress packaged with BuddyPress.
+ *
+ * @package BuddyPress
+ *
+ * @uses bp_activity_delete() to delete corresponding activity items
+ * @uses bp_forums_get_topic_posts() to get the child posts
+ * @uses bp_forums_delete_topic() to do the deletion itself
+ * @param int $topic_id The id of the topic to be deleted
+ * @return bool True if the delete routine went through properly
+ *
+ * @since BuddyPress (1.1)
+ */
+function groups_delete_group_forum_topic( $topic_id ) {
+	global $bp;
+
+	// Before deleting the thread, get the post ids so that their activity items can be deleted
+	$posts = bp_forums_get_topic_posts( array( 'topic_id' => $topic_id, 'per_page' => -1 ) );
+
+	if ( bp_forums_delete_topic( array( 'topic_id' => $topic_id ) ) ) {
+		do_action( 'groups_before_delete_group_forum_topic', $topic_id );
+
+		// Delete the corresponding activity stream items
+		if ( bp_is_active( 'activity' ) ) {
+			// The activity item for the initial topic
+			bp_activity_delete( array(
+				'item_id'           => bp_get_current_group_id(),
+				'secondary_item_id' => $topic_id,
+				'component'         => $bp->groups->id,
+				'type'              => 'new_forum_topic'
+			) );
+
+			// The activity item for each post
+			foreach ( (array) $posts as $post ) {
+				bp_activity_delete( array(
+					'item_id'           => bp_get_current_group_id(),
+					'secondary_item_id' => $post->post_id,
+					'component'         => $bp->groups->id,
+					'type'              => 'new_forum_post'
+				) );
+			}
+		}
+
+		do_action( 'groups_delete_group_forum_topic', $topic_id );
+
+		return true;
+	}
+
+	return false;
+}
+
+/**
+ * Deletes a group forum post and its corresponding activity item.
+ *
+ * Uses the bundled version of bbPress packaged with BuddyPress.
+ *
+ * @package BuddyPress
+ *
+ * @param int $post_id The id of the post you want to delete
+ * @param int $topic_id Optional. The topic to which the post belongs. This value isn't used in the
+ *   function but is passed along to do_action() hooks.
+ * @return bool True on success.
+ *
+ * @since BuddyPress (1.1)
+ */
+function groups_delete_group_forum_post( $post_id, $topic_id = false ) {
+	global $bp;
+
+	if ( bp_forums_delete_post( array( 'post_id' => $post_id ) ) ) {
+		do_action( 'groups_before_delete_group_forum_post', $post_id, $topic_id );
+
+		// Delete the corresponding activity stream item
+		if ( bp_is_active( 'activity' ) )
+			bp_activity_delete( array(
+				'item_id'           => bp_get_current_group_id(),
+				'secondary_item_id' => $post_id,
+				'component'         => $bp->groups->id,
+				'type'              => 'new_forum_post'
+			) );
+
+		do_action( 'groups_delete_group_forum_post', $post_id, $topic_id );
+
+		return true;
+	}
+
+	return false;
+}
+
+/**
+ * Get a total count of all public topics of a given type, across groups/forums
+ *
+ * @package BuddyPress
+ * @since BuddyPress (1.5)
+ *
+ * @param string $type Either 'newest', 'popular', 'unreplied', 'tags'.  Defaults to 'newest'.
+ * @return int The topic count
+ */
+function groups_total_public_forum_topic_count( $type = 'newest' ) {
+	return apply_filters( 'groups_total_public_forum_topic_count', BP_Groups_Group::get_global_forum_topic_count( $type ) );
+}
+
+/**
+ * Get a total count of all topics of a given status, across groups/forums
+ *
+ * @package BuddyPress
+ * @since BuddyPress (1.5)
+ *
+ * @param string $status 'public', 'private', 'hidden', 'all' Which group types to count
+ * @return int The topic count
+ */
+function groups_total_forum_topic_count( $status = 'public', $search_terms = false ) {
+	return apply_filters( 'groups_total_forum_topic_count', BP_Groups_Group::get_global_topic_count( $status, $search_terms ) );
+}
Index: /tags/1.9/bp-groups/bp-groups-functions.php
===================================================================
--- /tags/1.9/bp-groups/bp-groups-functions.php	(revision 7684)
+++ /tags/1.9/bp-groups/bp-groups-functions.php	(revision 7684)
@@ -0,0 +1,1058 @@
+<?php
+
+/**
+ * BuddyPress Groups Functions
+ *
+ * Functions are where all the magic happens in BuddyPress. They will
+ * handle the actual saving or manipulation of information. Usually they will
+ * hand off to a database class for data access, then return
+ * true or false on success or failure.
+ *
+ * @package BuddyPress
+ * @subpackage GroupsFunctions
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/**
+ * Checks $bp pages global and looks for directory page
+ *
+ * @since BuddyPress (1.5)
+ *
+ * @global BuddyPress $bp The one true BuddyPress instance
+ * @return bool True if set, False if empty
+ */
+function bp_groups_has_directory() {
+	global $bp;
+
+	return (bool) !empty( $bp->pages->groups->id );
+}
+
+/**
+ * Pulls up the database object corresponding to a group
+ *
+ * When calling up a group object, you should always use this function instead
+ * of instantiating BP_Groups_Group directly, so that you will inherit cache
+ * support and pass through the groups_get_group filter.
+ *
+ * @param string $args The load_users parameter is deprecated and does nothing.
+ * @return BP_Groups_Group $group The group object
+ */
+function groups_get_group( $args = '' ) {
+	$defaults = array(
+		'group_id'   => false,
+		'load_users' => false
+	);
+
+	$args = wp_parse_args( $args, $defaults );
+	extract( $args, EXTR_SKIP );
+
+	$cache_key = 'bp_groups_group_' . $group_id . ( $load_users ? '_load_users' : '_noload_users' );
+
+	if ( !$group = wp_cache_get( $cache_key, 'bp' ) ) {
+		$group = new BP_Groups_Group( $group_id, true, $load_users );
+		wp_cache_set( $cache_key, $group, 'bp' );
+	}
+
+	return apply_filters( 'groups_get_group', $group );
+}
+
+/*** Group Creation, Editing & Deletion *****************************************/
+
+function groups_create_group( $args = '' ) {
+
+	extract( $args );
+
+	/**
+	 * Possible parameters (pass as assoc array):
+	 *	'group_id'
+	 *	'creator_id'
+	 *	'name'
+	 *	'description'
+	 *	'slug'
+	 *	'status'
+	 *	'enable_forum'
+	 *	'date_created'
+	 */
+
+	if ( !empty( $group_id ) )
+		$group = groups_get_group( array( 'group_id' => $group_id ) );
+	else
+		$group = new BP_Groups_Group;
+
+	if ( !empty( $creator_id ) )
+		$group->creator_id = $creator_id;
+	else
+		$group->creator_id = bp_loggedin_user_id();
+
+	if ( isset( $name ) )
+		$group->name = $name;
+
+	if ( isset( $description ) )
+		$group->description = $description;
+
+	if ( isset( $slug ) && groups_check_slug( $slug ) )
+		$group->slug = $slug;
+
+	if ( isset( $status ) ) {
+		if ( groups_is_valid_status( $status ) ) {
+			$group->status = $status;
+		}
+	}
+
+	if ( isset( $enable_forum ) )
+		$group->enable_forum = $enable_forum;
+	else if ( empty( $group_id ) && !isset( $enable_forum ) )
+		$group->enable_forum = 1;
+
+	if ( isset( $date_created ) )
+		$group->date_created = $date_created;
+
+	if ( !$group->save() )
+		return false;
+
+	// If this is a new group, set up the creator as the first member and admin
+	if ( empty( $group_id ) ) {
+		$member                = new BP_Groups_Member;
+		$member->group_id      = $group->id;
+		$member->user_id       = $group->creator_id;
+		$member->is_admin      = 1;
+		$member->user_title    = __( 'Group Admin', 'buddypress' );
+		$member->is_confirmed  = 1;
+		$member->date_modified = bp_core_current_time();
+		$member->save();
+
+		groups_update_groupmeta( $group->id, 'last_activity', bp_core_current_time() );
+
+		do_action( 'groups_create_group', $group->id, $member, $group );
+
+	} else {
+		do_action( 'groups_update_group', $group->id, $group );
+	}
+
+	do_action( 'groups_created_group', $group->id, $group );
+
+	return $group->id;
+}
+
+function groups_edit_base_group_details( $group_id, $group_name, $group_desc, $notify_members ) {
+
+	if ( empty( $group_name ) || empty( $group_desc ) )
+		return false;
+
+	$group              = groups_get_group( array( 'group_id' => $group_id ) );
+	$group->name        = $group_name;
+	$group->description = $group_desc;
+
+	if ( !$group->save() )
+		return false;
+
+	if ( $notify_members ) {
+		groups_notification_group_updated( $group->id );
+	}
+
+	do_action( 'groups_details_updated', $group->id );
+
+	return true;
+}
+
+function groups_edit_group_settings( $group_id, $enable_forum, $status, $invite_status = false ) {
+
+	$group = groups_get_group( array( 'group_id' => $group_id ) );
+	$group->enable_forum = $enable_forum;
+
+	/***
+	 * Before we potentially switch the group status, if it has been changed to public
+	 * from private and there are outstanding membership requests, auto-accept those requests.
+	 */
+	if ( 'private' == $group->status && 'public' == $status )
+		groups_accept_all_pending_membership_requests( $group->id );
+
+	// Now update the status
+	$group->status = $status;
+
+	if ( !$group->save() )
+		return false;
+
+	// If forums have been enabled, and a forum does not yet exist, we need to create one.
+	if ( $group->enable_forum ) {
+		if ( bp_is_active( 'forums' ) && !groups_get_groupmeta( $group->id, 'forum_id' ) ) {
+			groups_new_group_forum( $group->id, $group->name, $group->description );
+		}
+	}
+
+	// Set the invite status
+	if ( $invite_status )
+		groups_update_groupmeta( $group->id, 'invite_status', $invite_status );
+
+	groups_update_groupmeta( $group->id, 'last_activity', bp_core_current_time() );
+	do_action( 'groups_settings_updated', $group->id );
+
+	return true;
+}
+
+/**
+ * Delete a group and all of its associated meta
+ *
+ * @global object $bp BuddyPress global settings
+ * @param int $group_id
+ * @since BuddyPress (1.0)
+ */
+function groups_delete_group( $group_id ) {
+
+	do_action( 'groups_before_delete_group', $group_id );
+
+	// Get the group object
+	$group = groups_get_group( array( 'group_id' => $group_id ) );
+
+	// Bail if group cannot be deleted
+	if ( ! $group->delete() ) {
+		return false;
+	}
+
+	// Remove all outstanding invites for this group
+	groups_delete_all_group_invites( $group_id );
+
+	do_action( 'groups_delete_group', $group_id );
+
+	return true;
+}
+
+function groups_is_valid_status( $status ) {
+	global $bp;
+
+	return in_array( $status, (array) $bp->groups->valid_status );
+}
+
+function groups_check_slug( $slug ) {
+	global $bp;
+
+	if ( 'wp' == substr( $slug, 0, 2 ) )
+		$slug = substr( $slug, 2, strlen( $slug ) - 2 );
+
+	if ( in_array( $slug, (array) $bp->groups->forbidden_names ) )
+		$slug = $slug . '-' . rand();
+
+	if ( BP_Groups_Group::check_slug( $slug ) ) {
+		do {
+			$slug = $slug . '-' . rand();
+		}
+		while ( BP_Groups_Group::check_slug( $slug ) );
+	}
+
+	return $slug;
+}
+
+/**
+ * Get a group slug by its ID
+ *
+ * @param int $group_id The numeric ID of the group
+ * @return string The group's slug
+ */
+function groups_get_slug( $group_id ) {
+	$group = groups_get_group( array( 'group_id' => $group_id ) );
+	return !empty( $group->slug ) ? $group->slug : '';
+}
+
+/**
+ * Get a group ID by its slug
+ *
+ * @since BuddyPress (1.6)
+ *
+ * @param string $group_slug The group's slug
+ * @return int The ID
+ */
+function groups_get_id( $group_slug ) {
+	return (int)BP_Groups_Group::group_exists( $group_slug );
+}
+
+/*** User Actions ***************************************************************/
+
+function groups_leave_group( $group_id, $user_id = 0 ) {
+	global $bp;
+
+	if ( empty( $user_id ) )
+		$user_id = bp_loggedin_user_id();
+
+	// Don't let single admins leave the group.
+	if ( count( groups_get_group_admins( $group_id ) ) < 2 ) {
+		if ( groups_is_user_admin( $user_id, $group_id ) ) {
+			bp_core_add_message( __( 'As the only Admin, you cannot leave the group.', 'buddypress' ), 'error' );
+			return false;
+		}
+	}
+
+	// This is exactly the same as deleting an invite, just is_confirmed = 1 NOT 0.
+	if ( !groups_uninvite_user( $user_id, $group_id ) ) {
+		return false;
+	}
+
+	bp_core_add_message( __( 'You successfully left the group.', 'buddypress' ) );
+
+	do_action( 'groups_leave_group', $group_id, $user_id );
+
+	return true;
+}
+
+function groups_join_group( $group_id, $user_id = 0 ) {
+	global $bp;
+
+	if ( empty( $user_id ) )
+		$user_id = bp_loggedin_user_id();
+
+	// Check if the user has an outstanding invite. If so, delete it.
+	if ( groups_check_user_has_invite( $user_id, $group_id ) )
+		groups_delete_invite( $user_id, $group_id );
+
+	// Check if the user has an outstanding request. If so, delete it.
+	if ( groups_check_for_membership_request( $user_id, $group_id ) )
+		groups_delete_membership_request( $user_id, $group_id );
+
+	// User is already a member, just return true
+	if ( groups_is_user_member( $user_id, $group_id ) )
+		return true;
+
+	$new_member                = new BP_Groups_Member;
+	$new_member->group_id      = $group_id;
+	$new_member->user_id       = $user_id;
+	$new_member->inviter_id    = 0;
+	$new_member->is_admin      = 0;
+	$new_member->user_title    = '';
+	$new_member->date_modified = bp_core_current_time();
+	$new_member->is_confirmed  = 1;
+
+	if ( !$new_member->save() )
+		return false;
+
+	if ( !isset( $bp->groups->current_group ) || !$bp->groups->current_group || $group_id != $bp->groups->current_group->id )
+		$group = groups_get_group( array( 'group_id' => $group_id ) );
+	else
+		$group = $bp->groups->current_group;
+
+	// Record this in activity streams
+	groups_record_activity( array(
+		'action'  => apply_filters( 'groups_activity_joined_group', sprintf( __( '%1$s joined the group %2$s', 'buddypress'), bp_core_get_userlink( $user_id ), '<a href="' . bp_get_group_permalink( $group ) . '">' . esc_attr( bp_get_group_name( $group ) ) . '</a>' ) ),
+		'type'    => 'joined_group',
+		'item_id' => $group_id,
+		'user_id' => $user_id
+	) );
+
+	// Modify group meta
+	groups_update_groupmeta( $group_id, 'last_activity', bp_core_current_time() );
+
+	do_action( 'groups_join_group', $group_id, $user_id );
+
+	return true;
+}
+
+/*** General Group Functions ****************************************************/
+
+function groups_get_group_admins( $group_id ) {
+	return BP_Groups_Member::get_group_administrator_ids( $group_id );
+}
+
+function groups_get_group_mods( $group_id ) {
+	return BP_Groups_Member::get_group_moderator_ids( $group_id );
+}
+
+/**
+ * Fetch the members of a group
+ *
+ * Since BuddyPress 1.8, a procedural wrapper for BP_Group_Member_Query.
+ * Previously called BP_Groups_Member::get_all_for_group().
+ *
+ * To use the legacy query, filter 'bp_use_legacy_group_member_query',
+ * returning true.
+ *
+ * @param int $group_id
+ * @param int $limit Maximum members to return
+ * @param int $page The page of results to return (requires $limit)
+ * @param bool $exclude_admins_mods Whether to exclude admins and mods
+ * @param bool $exclude_banned Whether to exclude banned users
+ * @param array|string $exclude Array or comma-sep list of users to exclude
+ * @return array Multi-d array of 'members' list and 'count'
+ */
+function groups_get_group_members( $group_id, $limit = false, $page = false, $exclude_admins_mods = true, $exclude_banned = true, $exclude = false, $group_role = false ) {
+
+	// For legacy users. Use of BP_Groups_Member::get_all_for_group()
+	// is deprecated. func_get_args() can't be passed to a function in PHP
+	// 5.2.x, so we create a variable
+	$func_args = func_get_args();
+	if ( apply_filters( 'bp_use_legacy_group_member_query', false, __FUNCTION__, $func_args ) ) {
+		$retval = BP_Groups_Member::get_all_for_group( $group_id, $limit, $page, $exclude_admins_mods, $exclude_banned, $exclude );
+	} else {
+
+		// exclude_admins_mods and exclude_banned are legacy arguments.
+		// Convert to group_role
+		if ( empty( $group_role ) ) {
+			$group_role = array( 'member' );
+
+			if ( ! $exclude_admins_mods ) {
+				$group_role[] = 'mod';
+				$group_role[] = 'admin';
+			}
+
+			if ( ! $exclude_banned ) {
+				$group_role[] = 'banned';
+			}
+		}
+
+		// Perform the group member query (extends BP_User_Query)
+		$members = new BP_Group_Member_Query( array(
+			'group_id'       => $group_id,
+			'per_page'       => $limit,
+			'page'           => $page,
+			'group_role'     => $group_role,
+			'exclude'        => $exclude,
+			'type'           => 'last_modified',
+		) );
+
+		// Structure the return value as expected by the template functions
+		$retval = array(
+			'members' => array_values( $members->results ),
+			'count'   => $members->total_users,
+		);
+	}
+
+	return $retval;
+}
+
+function groups_get_total_member_count( $group_id ) {
+	return BP_Groups_Group::get_total_member_count( $group_id );
+}
+
+/*** Group Fetching, Filtering & Searching  *************************************/
+
+/**
+ * Get a collection of groups, based on the parameters passed
+ *
+ * @uses apply_filters_ref_array() Filter 'groups_get_groups' to modify return value
+ * @uses BP_Groups_Group::get()
+ * @param array $args See inline documentation for details
+ * @return array
+ */
+function groups_get_groups( $args = '' ) {
+
+	$defaults = array(
+		'type'            => false,    // active, newest, alphabetical, random, popular, most-forum-topics or most-forum-posts
+		'order'           => 'DESC',   // 'ASC' or 'DESC'
+		'orderby'         => 'date_created', // date_created, last_activity, total_member_count, name, random
+		'user_id'         => false,    // Pass a user_id to limit to only groups that this user is a member of
+		'include'         => false,    // Only include these specific groups (group_ids)
+		'exclude'         => false,    // Do not include these specific groups (group_ids)
+		'search_terms'    => false,    // Limit to groups that match these search terms
+		'meta_query'      => false,    // Filter by groupmeta. See WP_Meta_Query for syntax
+		'show_hidden'     => false,    // Show hidden groups to non-admins
+		'per_page'        => 20,       // The number of results to return per page
+		'page'            => 1,        // The page to return if limiting per page
+		'populate_extras' => true,     // Fetch meta such as is_banned and is_member
+	);
+
+	$r = wp_parse_args( $args, $defaults );
+
+	$groups = BP_Groups_Group::get( array(
+		'type'            => $r['type'],
+		'user_id'         => $r['user_id'],
+		'include'         => $r['include'],
+		'exclude'         => $r['exclude'],
+		'search_terms'    => $r['search_terms'],
+		'meta_query'      => $r['meta_query'],
+		'show_hidden'     => $r['show_hidden'],
+		'per_page'        => $r['per_page'],
+		'page'            => $r['page'],
+		'populate_extras' => $r['populate_extras'],
+		'order'           => $r['order'],
+		'orderby'         => $r['orderby'],
+	) );
+
+	return apply_filters_ref_array( 'groups_get_groups', array( &$groups, &$r ) );
+}
+
+function groups_get_total_group_count() {
+	if ( !$count = wp_cache_get( 'bp_total_group_count', 'bp' ) ) {
+		$count = BP_Groups_Group::get_total_group_count();
+		wp_cache_set( 'bp_total_group_count', $count, 'bp' );
+	}
+
+	return $count;
+}
+
+function groups_get_user_groups( $user_id = 0, $pag_num = 0, $pag_page = 0 ) {
+
+	if ( empty( $user_id ) )
+		$user_id = bp_displayed_user_id();
+
+	return BP_Groups_Member::get_group_ids( $user_id, $pag_num, $pag_page );
+}
+
+function groups_total_groups_for_user( $user_id = 0 ) {
+
+	if ( empty( $user_id ) )
+		$user_id = ( bp_displayed_user_id() ) ? bp_displayed_user_id() : bp_loggedin_user_id();
+
+	if ( !$count = wp_cache_get( 'bp_total_groups_for_user_' . $user_id, 'bp' ) ) {
+		$count = BP_Groups_Member::total_group_count( $user_id );
+		wp_cache_set( 'bp_total_groups_for_user_' . $user_id, $count, 'bp' );
+	}
+
+	return $count;
+}
+
+/**
+ * Returns the group object for the group currently being viewed
+ *
+ * @package BuddyPress
+ * @since BuddyPress (1.5)
+ *
+ * @return BP_Groups_Group The current group object
+ */
+function groups_get_current_group() {
+	global $bp;
+
+	$current_group = isset( $bp->groups->current_group ) ? $bp->groups->current_group : false;
+
+	return apply_filters( 'groups_get_current_group', $current_group );
+}
+
+/*** Group Avatars *************************************************************/
+
+function groups_avatar_upload_dir( $group_id = 0 ) {
+	global $bp;
+
+	if ( !$group_id )
+		$group_id = $bp->groups->current_group->id;
+
+	$path    = bp_core_avatar_upload_path() . '/group-avatars/' . $group_id;
+	$newbdir = $path;
+
+	if ( !file_exists( $path ) )
+		@wp_mkdir_p( $path );
+
+	$newurl    = bp_core_avatar_url() . '/group-avatars/' . $group_id;
+	$newburl   = $newurl;
+	$newsubdir = '/group-avatars/' . $group_id;
+
+	return apply_filters( 'groups_avatar_upload_dir', array( 'path' => $path, 'url' => $newurl, 'subdir' => $newsubdir, 'basedir' => $newbdir, 'baseurl' => $newburl, 'error' => false ) );
+}
+
+/*** Group Member Status Checks ************************************************/
+
+function groups_is_user_admin( $user_id, $group_id ) {
+	return BP_Groups_Member::check_is_admin( $user_id, $group_id );
+}
+
+function groups_is_user_mod( $user_id, $group_id ) {
+	return BP_Groups_Member::check_is_mod( $user_id, $group_id );
+}
+
+function groups_is_user_member( $user_id, $group_id ) {
+	return BP_Groups_Member::check_is_member( $user_id, $group_id );
+}
+
+function groups_is_user_banned( $user_id, $group_id ) {
+	return BP_Groups_Member::check_is_banned( $user_id, $group_id );
+}
+
+/**
+ * Is the specified user the creator of the group?
+ *
+ * @param int $user_id
+ * @param int $group_id
+ * @since BuddyPress (1.2.6)
+ * @uses BP_Groups_Member
+ */
+function groups_is_user_creator( $user_id, $group_id ) {
+	return BP_Groups_Member::check_is_creator( $user_id, $group_id );
+}
+
+/*** Group Activity Posting **************************************************/
+
+function groups_post_update( $args = '' ) {
+	global $bp;
+
+	$defaults = array(
+		'content'  => false,
+		'user_id'  => bp_loggedin_user_id(),
+		'group_id' => 0
+	);
+
+	$r = wp_parse_args( $args, $defaults );
+	extract( $r, EXTR_SKIP );
+
+	if ( empty( $group_id ) && !empty( $bp->groups->current_group->id ) )
+		$group_id = $bp->groups->current_group->id;
+
+	if ( empty( $content ) || !strlen( trim( $content ) ) || empty( $user_id ) || empty( $group_id ) )
+		return false;
+
+	$bp->groups->current_group = groups_get_group( array( 'group_id' => $group_id ) );
+
+	// Be sure the user is a member of the group before posting.
+	if ( !bp_current_user_can( 'bp_moderate' ) && !groups_is_user_member( $user_id, $group_id ) )
+		return false;
+
+	// Record this in activity streams
+	$activity_action  = sprintf( __( '%1$s posted an update in the group %2$s', 'buddypress'), bp_core_get_userlink( $user_id ), '<a href="' . bp_get_group_permalink( $bp->groups->current_group ) . '">' . esc_attr( $bp->groups->current_group->name ) . '</a>' );
+	$activity_content = $content;
+
+	$activity_id = groups_record_activity( array(
+		'user_id' => $user_id,
+		'action'  => apply_filters( 'groups_activity_new_update_action',  $activity_action  ),
+		'content' => apply_filters( 'groups_activity_new_update_content', $activity_content ),
+		'type'    => 'activity_update',
+		'item_id' => $group_id
+	) );
+
+	groups_update_groupmeta( $group_id, 'last_activity', bp_core_current_time() );
+	do_action( 'bp_groups_posted_update', $content, $user_id, $group_id, $activity_id );
+
+	return $activity_id;
+}
+
+/*** Group Invitations *********************************************************/
+
+function groups_get_invites_for_user( $user_id = 0, $limit = false, $page = false, $exclude = false ) {
+
+	if ( empty( $user_id ) )
+		$user_id = bp_loggedin_user_id();
+
+	return BP_Groups_Member::get_invites( $user_id, $limit, $page, $exclude );
+}
+
+function groups_invite_user( $args = '' ) {
+
+	$defaults = array(
+		'user_id'       => false,
+		'group_id'      => false,
+		'inviter_id'    => bp_loggedin_user_id(),
+		'date_modified' => bp_core_current_time(),
+		'is_confirmed'  => 0
+	);
+
+	$args = wp_parse_args( $args, $defaults );
+	extract( $args, EXTR_SKIP );
+
+	if ( empty( $user_id ) || empty( $group_id ) )
+		return false;
+
+	// if the user has already requested membership, accept the request
+	if ( $membership_id = groups_check_for_membership_request( $user_id, $group_id ) ) {
+		groups_accept_membership_request( $membership_id, $user_id, $group_id );
+
+	// Otherwise, create a new invitation
+	} else if ( ! groups_is_user_member( $user_id, $group_id ) && ! groups_check_user_has_invite( $user_id, $group_id, 'all' ) ) {
+		$invite                = new BP_Groups_Member;
+		$invite->group_id      = $group_id;
+		$invite->user_id       = $user_id;
+		$invite->date_modified = $date_modified;
+		$invite->inviter_id    = $inviter_id;
+		$invite->is_confirmed  = $is_confirmed;
+
+		if ( !$invite->save() )
+			return false;
+
+		do_action( 'groups_invite_user', $args );
+	}
+
+	return true;
+}
+
+function groups_uninvite_user( $user_id, $group_id ) {
+
+	if ( !BP_Groups_Member::delete( $user_id, $group_id ) )
+		return false;
+
+	do_action( 'groups_uninvite_user', $group_id, $user_id );
+
+	return true;
+}
+
+/**
+ * Process the acceptance of a group invitation.
+ *
+ * Returns true if a user is already a member of the group.
+ *
+ * @param int $user_id
+ * @param int $group_id
+ * @return bool True when the user is a member of the group, otherwise false
+ */
+function groups_accept_invite( $user_id, $group_id ) {
+
+	// If the user is already a member (because BP at one point allowed two invitations to
+	// slip through), delete all existing invitations/requests and return true
+	if ( groups_is_user_member( $user_id, $group_id ) ) {
+		if ( groups_check_user_has_invite( $user_id, $group_id ) ) {
+			groups_delete_invite( $user_id, $group_id );
+		}
+
+		if ( groups_check_for_membership_request( $user_id, $group_id ) ) {
+			groups_delete_membership_request( $user_id, $group_id );
+		}
+
+		return true;
+	}
+
+	$member = new BP_Groups_Member( $user_id, $group_id );
+	$member->accept_invite();
+
+	if ( !$member->save() ) {
+		return false;
+	}
+
+	// Remove request to join
+	if ( $member->check_for_membership_request( $user_id, $group_id ) ) {
+		$member->delete_request( $user_id, $group_id );
+	}
+
+	// Modify group meta
+	groups_update_groupmeta( $group_id, 'last_activity', bp_core_current_time() );
+
+	do_action( 'groups_accept_invite', $user_id, $group_id );
+
+	return true;
+}
+
+function groups_reject_invite( $user_id, $group_id ) {
+	if ( ! BP_Groups_Member::delete( $user_id, $group_id ) )
+		return false;
+
+	do_action( 'groups_reject_invite', $user_id, $group_id );
+
+	return true;
+}
+
+function groups_delete_invite( $user_id, $group_id ) {
+	if ( ! BP_Groups_Member::delete_invite( $user_id, $group_id ) )
+		return false;
+
+	do_action( 'groups_delete_invite', $user_id, $group_id );
+
+	return true;
+}
+
+function groups_send_invites( $user_id, $group_id ) {
+
+	if ( empty( $user_id ) )
+		$user_id = bp_loggedin_user_id();
+
+	// Send friend invites.
+	$invited_users = groups_get_invites_for_group( $user_id, $group_id );
+	$group = groups_get_group( array( 'group_id' => $group_id ) );
+
+	for ( $i = 0, $count = count( $invited_users ); $i < $count; ++$i ) {
+		$member = new BP_Groups_Member( $invited_users[$i], $group_id );
+
+		// Send the actual invite
+		groups_notification_group_invites( $group, $member, $user_id );
+
+		$member->invite_sent = 1;
+		$member->save();
+	}
+
+	do_action( 'groups_send_invites', $group_id, $invited_users );
+}
+
+function groups_get_invites_for_group( $user_id, $group_id ) {
+	return BP_Groups_Group::get_invites( $user_id, $group_id );
+}
+
+/**
+ * Check to see whether a user has already been invited to a group
+ *
+ * By default, the function checks for invitations that have been sent. Entering 'all' as the $type
+ * parameter will return unsent invitations as well (useful to make sure AJAX requests are not
+ * duplicated)
+ *
+ * @package BuddyPress Groups
+ *
+ * @param int $user_id Potential group member
+ * @param int $group_id Potential group
+ * @param string $type Optional. Use 'sent' to check for sent invites, 'all' to check for all
+ * @return bool Returns true if an invitation is found
+ */
+function groups_check_user_has_invite( $user_id, $group_id, $type = 'sent' ) {
+	return BP_Groups_Member::check_has_invite( $user_id, $group_id, $type );
+}
+
+function groups_delete_all_group_invites( $group_id ) {
+	return BP_Groups_Group::delete_all_invites( $group_id );
+}
+
+/*** Group Promotion & Banning *************************************************/
+
+function groups_promote_member( $user_id, $group_id, $status ) {
+
+	if ( ! bp_is_item_admin() )
+		return false;
+
+	$member = new BP_Groups_Member( $user_id, $group_id );
+
+	// Don't use this action. It's deprecated as of BuddyPress 1.6.
+	do_action( 'groups_premote_member', $group_id, $user_id, $status );
+
+	// Use this action instead.
+	do_action( 'groups_promote_member', $group_id, $user_id, $status );
+
+	return $member->promote( $status );
+}
+
+function groups_demote_member( $user_id, $group_id ) {
+
+	if ( ! bp_is_item_admin() )
+		return false;
+
+	$member = new BP_Groups_Member( $user_id, $group_id );
+
+	do_action( 'groups_demote_member', $group_id, $user_id );
+
+	return $member->demote();
+}
+
+function groups_ban_member( $user_id, $group_id ) {
+
+	if ( ! bp_is_item_admin() )
+		return false;
+
+	$member = new BP_Groups_Member( $user_id, $group_id );
+
+	do_action( 'groups_ban_member', $group_id, $user_id );
+
+	return $member->ban();
+}
+
+function groups_unban_member( $user_id, $group_id ) {
+
+	if ( ! bp_is_item_admin() )
+		return false;
+
+	$member = new BP_Groups_Member( $user_id, $group_id );
+
+	do_action( 'groups_unban_member', $group_id, $user_id );
+
+	return $member->unban();
+}
+
+/*** Group Removal *******************************************************/
+
+function groups_remove_member( $user_id, $group_id ) {
+
+	if ( ! bp_is_item_admin() )
+		return false;
+
+	$member = new BP_Groups_Member( $user_id, $group_id );
+
+	do_action( 'groups_remove_member', $group_id, $user_id );
+
+	return $member->remove();
+}
+
+/*** Group Membership ****************************************************/
+
+function groups_send_membership_request( $requesting_user_id, $group_id ) {
+
+	// Prevent duplicate requests
+	if ( groups_check_for_membership_request( $requesting_user_id, $group_id ) )
+		return false;
+
+	// Check if the user is already a member or is banned
+	if ( groups_is_user_member( $requesting_user_id, $group_id ) || groups_is_user_banned( $requesting_user_id, $group_id ) )
+		return false;
+
+	// Check if the user is already invited - if so, simply accept invite
+	if ( groups_check_user_has_invite( $requesting_user_id, $group_id ) ) {
+		groups_accept_invite( $requesting_user_id, $group_id );
+		return true;
+	}
+
+	$requesting_user                = new BP_Groups_Member;
+	$requesting_user->group_id      = $group_id;
+	$requesting_user->user_id       = $requesting_user_id;
+	$requesting_user->inviter_id    = 0;
+	$requesting_user->is_admin      = 0;
+	$requesting_user->user_title    = '';
+	$requesting_user->date_modified = bp_core_current_time();
+	$requesting_user->is_confirmed  = 0;
+	$requesting_user->comments      = isset( $_POST['group-request-membership-comments'] ) ? $_POST['group-request-membership-comments'] : '';
+
+	if ( $requesting_user->save() ) {
+		$admins = groups_get_group_admins( $group_id );
+
+		// Saved okay, now send the email notification
+		for ( $i = 0, $count = count( $admins ); $i < $count; ++$i )
+			groups_notification_new_membership_request( $requesting_user_id, $admins[$i]->user_id, $group_id, $requesting_user->id );
+
+		do_action( 'groups_membership_requested', $requesting_user_id, $admins, $group_id, $requesting_user->id );
+
+		return true;
+	}
+
+	return false;
+}
+
+function groups_accept_membership_request( $membership_id, $user_id = 0, $group_id = 0 ) {
+
+	if ( !empty( $user_id ) && !empty( $group_id ) ) {
+		$membership = new BP_Groups_Member( $user_id, $group_id );
+	} else {
+		$membership = new BP_Groups_Member( false, false, $membership_id );
+	}
+
+	$membership->accept_request();
+
+	if ( !$membership->save() ) {
+		return false;
+	}
+
+	// Check if the user has an outstanding invite, if so delete it.
+	if ( groups_check_user_has_invite( $membership->user_id, $membership->group_id ) ) {
+		groups_delete_invite( $membership->user_id, $membership->group_id );
+	}
+
+	do_action( 'groups_membership_accepted', $membership->user_id, $membership->group_id, true );
+
+	return true;
+}
+
+function groups_reject_membership_request( $membership_id, $user_id = 0, $group_id = 0 ) {
+	if ( !$membership = groups_delete_membership_request( $membership_id, $user_id, $group_id ) ) {
+		return false;
+	}
+
+	do_action( 'groups_membership_rejected', $membership->user_id, $membership->group_id, false );
+
+	return true;
+}
+
+function groups_delete_membership_request( $membership_id, $user_id = 0, $group_id = 0 ) {
+	if ( !empty( $user_id ) && !empty( $group_id ) )
+		$membership = new BP_Groups_Member( $user_id, $group_id );
+	else
+		$membership = new BP_Groups_Member( false, false, $membership_id );
+
+	if ( !BP_Groups_Member::delete( $membership->user_id, $membership->group_id ) )
+		return false;
+
+	return $membership;
+}
+
+function groups_check_for_membership_request( $user_id, $group_id ) {
+	return BP_Groups_Member::check_for_membership_request( $user_id, $group_id );
+}
+
+function groups_accept_all_pending_membership_requests( $group_id ) {
+	$user_ids = BP_Groups_Member::get_all_membership_request_user_ids( $group_id );
+
+	if ( !$user_ids )
+		return false;
+
+	foreach ( (array) $user_ids as $user_id )
+		groups_accept_membership_request( false, $user_id, $group_id );
+
+	do_action( 'groups_accept_all_pending_membership_requests', $group_id );
+
+	return true;
+}
+
+/*** Group Meta ****************************************************/
+
+function groups_delete_groupmeta( $group_id, $meta_key = false, $meta_value = false ) {
+	global $wpdb, $bp;
+
+	if ( !is_numeric( $group_id ) )
+		return false;
+
+	$meta_key = preg_replace( '|[^a-z0-9_]|i', '', $meta_key );
+
+	if ( is_array( $meta_value ) || is_object( $meta_value ) )
+		$meta_value = serialize($meta_value);
+
+	$meta_value = trim( $meta_value );
+
+	if ( !$meta_key )
+		$wpdb->query( $wpdb->prepare( "DELETE FROM " . $bp->groups->table_name_groupmeta . " WHERE group_id = %d", $group_id ) );
+	else if ( $meta_value )
+		$wpdb->query( $wpdb->prepare( "DELETE FROM " . $bp->groups->table_name_groupmeta . " WHERE group_id = %d AND meta_key = %s AND meta_value = %s", $group_id, $meta_key, $meta_value ) );
+	else
+		$wpdb->query( $wpdb->prepare( "DELETE FROM " . $bp->groups->table_name_groupmeta . " WHERE group_id = %d AND meta_key = %s", $group_id, $meta_key ) );
+
+	// Delete the cached object
+	wp_cache_delete( 'bp_groups_groupmeta_' . $group_id . '_' . $meta_key, 'bp' );
+
+	return true;
+}
+
+function groups_get_groupmeta( $group_id, $meta_key = '') {
+	global $wpdb, $bp;
+
+	$group_id = (int) $group_id;
+
+	if ( !$group_id )
+		return false;
+
+	if ( !empty($meta_key) ) {
+		$meta_key = preg_replace( '|[^a-z0-9_]|i', '', $meta_key );
+
+		$metas = wp_cache_get( 'bp_groups_groupmeta_' . $group_id . '_' . $meta_key, 'bp' );
+		if ( false === $metas ) {
+			$metas = $wpdb->get_col( $wpdb->prepare("SELECT meta_value FROM " . $bp->groups->table_name_groupmeta . " WHERE group_id = %d AND meta_key = %s", $group_id, $meta_key ) );
+			wp_cache_set( 'bp_groups_groupmeta_' . $group_id . '_' . $meta_key, $metas, 'bp' );
+		}
+	} else {
+		$metas = $wpdb->get_col( $wpdb->prepare("SELECT meta_value FROM " . $bp->groups->table_name_groupmeta . " WHERE group_id = %d", $group_id ) );
+	}
+
+	if ( empty( $metas ) ) {
+		if ( empty( $meta_key ) )
+			return array();
+		else
+			return '';
+	}
+
+	$metas = array_map( 'maybe_unserialize', (array) $metas );
+
+	if ( 1 == count( $metas ) )
+		return $metas[0];
+	else
+		return $metas;
+}
+
+function groups_update_groupmeta( $group_id, $meta_key, $meta_value ) {
+	global $wpdb, $bp;
+
+	if ( !is_numeric( $group_id ) )
+		return false;
+
+	$meta_key = preg_replace( '|[^a-z0-9_]|i', '', $meta_key );
+
+	if ( is_string( $meta_value ) ) {
+		$meta_value = stripslashes( $meta_value );
+	}
+
+	$meta_value = maybe_serialize( $meta_value );
+
+	$cur = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM " . $bp->groups->table_name_groupmeta . " WHERE group_id = %d AND meta_key = %s", $group_id, $meta_key ) );
+
+	if ( !$cur )
+		$wpdb->query( $wpdb->prepare( "INSERT INTO " . $bp->groups->table_name_groupmeta . " ( group_id, meta_key, meta_value ) VALUES ( %d, %s, %s )", $group_id, $meta_key, $meta_value ) );
+	else if ( $cur->meta_value != $meta_value )
+		$wpdb->query( $wpdb->prepare( "UPDATE " . $bp->groups->table_name_groupmeta . " SET meta_value = %s WHERE group_id = %d AND meta_key = %s", $meta_value, $group_id, $meta_key ) );
+	else
+		return false;
+
+	// Update the cached object and recache
+	wp_cache_set( 'bp_groups_groupmeta_' . $group_id . '_' . $meta_key, $meta_value, 'bp' );
+
+	return true;
+}
+
+/*** Group Cleanup Functions ****************************************************/
+
+function groups_remove_data_for_user( $user_id ) {
+	BP_Groups_Member::delete_all_for_user( $user_id );
+
+	do_action( 'groups_remove_data_for_user', $user_id );
+}
+add_action( 'wpmu_delete_user',  'groups_remove_data_for_user' );
+add_action( 'delete_user',       'groups_remove_data_for_user' );
+add_action( 'bp_make_spam_user', 'groups_remove_data_for_user' );
Index: /tags/1.9/bp-groups/bp-groups-loader.php
===================================================================
--- /tags/1.9/bp-groups/bp-groups-loader.php	(revision 7684)
+++ /tags/1.9/bp-groups/bp-groups-loader.php	(revision 7684)
@@ -0,0 +1,607 @@
+<?php
+
+/**
+ * BuddyPress Groups Loader
+ *
+ * A groups component, for users to group themselves together. Includes a
+ * robust sub-component API that allows Groups to be extended.
+ * Comes preconfigured with an activity stream, discussion forums, and settings.
+ *
+ * @package BuddyPress
+ * @subpackage GroupsLoader
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+class BP_Groups_Component extends BP_Component {
+
+	/**
+	 * Auto join group when non group member performs group activity
+	 *
+	 * @since BuddyPress (1.5)
+	 * @var bool
+	 */
+	public $auto_join;
+
+	/**
+	 * The group being currently accessed
+	 *
+	 * @since BuddyPress (1.5)
+	 * @var BP_Groups_Group
+	 */
+	public $current_group;
+
+	/**
+	 * Default group extension
+	 *
+	 * @since BuddyPress (1.6)
+	 * @todo Is this used anywhere? Is this a duplicate of $default_extension?
+	 */
+	var $default_component;
+
+	/**
+	 * Default group extension
+	 *
+	 * @since BuddyPress (1.6)
+	 * @var string
+	 */
+	public $default_extension;
+
+	/**
+	 * Illegal group names/slugs
+	 *
+	 * @since BuddyPress (1.5)
+	 * @var array
+	 */
+	public $forbidden_names;
+
+	/**
+	 * Group creation/edit steps (e.g. Details, Settings, Avatar, Invites)
+	 *
+	 * @since BuddyPress (1.5)
+	 * @var array
+	 */
+	public $group_creation_steps;
+
+	/**
+	 * Types of group statuses (Public, Private, Hidden)
+	 *
+	 * @since BuddyPress (1.5)
+	 * @var array
+	 */
+	public $valid_status;
+
+	/**
+	 * Start the groups component creation process
+	 *
+	 * @since BuddyPress (1.5)
+	 */
+	function __construct() {
+		parent::start(
+			'groups',
+			__( 'User Groups', 'buddypress' ),
+			BP_PLUGIN_DIR,
+			array(
+				'adminbar_myaccount_order' => 70
+			)
+		);
+	}
+
+	/**
+	 * Include files
+	 */
+	public function includes( $includes = array() ) {
+		$includes = array(
+			'cache',
+			'forums',
+			'actions',
+			'filters',
+			'screens',
+			'classes',
+			'widgets',
+			'activity',
+			'template',
+			'buddybar',
+			'adminbar',
+			'functions',
+			'notifications'
+		);
+
+		if ( is_admin() )
+			$includes[] = 'admin';
+
+		parent::includes( $includes );
+	}
+
+	/**
+	 * Setup globals
+	 *
+	 * The BP_GROUPS_SLUG constant is deprecated, and only used here for
+	 * backwards compatibility.
+	 *
+	 * @since BuddyPress (1.5)
+	 */
+	public function setup_globals( $args = array() ) {
+		$bp = buddypress();
+
+		// Define a slug, if necessary
+		if ( !defined( 'BP_GROUPS_SLUG' ) )
+			define( 'BP_GROUPS_SLUG', $this->id );
+
+		// Global tables for messaging component
+		$global_tables = array(
+			'table_name'           => $bp->table_prefix . 'bp_groups',
+			'table_name_members'   => $bp->table_prefix . 'bp_groups_members',
+			'table_name_groupmeta' => $bp->table_prefix . 'bp_groups_groupmeta'
+		);
+
+		// All globals for groups component.
+		// Note that global_tables is included in this array.
+		$args = array(
+			'slug'                  => BP_GROUPS_SLUG,
+			'root_slug'             => isset( $bp->pages->groups->slug ) ? $bp->pages->groups->slug : BP_GROUPS_SLUG,
+			'has_directory'         => true,
+			'notification_callback' => 'groups_format_notifications',
+			'search_string'         => __( 'Search Groups...', 'buddypress' ),
+			'global_tables'         => $global_tables
+		);
+
+		parent::setup_globals( $args );
+
+		/** Single Group Globals **********************************************/
+
+		// Are we viewing a single group?
+		if ( bp_is_groups_component() && $group_id = BP_Groups_Group::group_exists( bp_current_action() ) ) {
+
+			$bp->is_single_item  = true;
+			$current_group_class = apply_filters( 'bp_groups_current_group_class', 'BP_Groups_Group' );
+			$this->current_group = apply_filters( 'bp_groups_current_group_object', new $current_group_class( $group_id ) );
+
+			// When in a single group, the first action is bumped down one because of the
+			// group name, so we need to adjust this and set the group name to current_item.
+			$bp->current_item   = bp_current_action();
+			$bp->current_action = bp_action_variable( 0 );
+			array_shift( $bp->action_variables );
+
+			// Using "item" not "group" for generic support in other components.
+			if ( bp_current_user_can( 'bp_moderate' ) )
+				bp_update_is_item_admin( true, 'groups' );
+			else
+				bp_update_is_item_admin( groups_is_user_admin( bp_loggedin_user_id(), $this->current_group->id ), 'groups' );
+
+			// If the user is not an admin, check if they are a moderator
+			if ( !bp_is_item_admin() )
+				bp_update_is_item_mod  ( groups_is_user_mod  ( bp_loggedin_user_id(), $this->current_group->id ), 'groups' );
+
+			// Is the logged in user a member of the group?
+			if ( ( is_user_logged_in() && groups_is_user_member( bp_loggedin_user_id(), $this->current_group->id ) ) )
+				$this->current_group->is_user_member = true;
+			else
+				$this->current_group->is_user_member = false;
+
+			// Should this group be visible to the logged in user?
+			if ( 'public' == $this->current_group->status || $this->current_group->is_user_member )
+				$this->current_group->is_visible = true;
+			else
+				$this->current_group->is_visible = false;
+
+			// If this is a private or hidden group, does the user have access?
+			if ( 'private' == $this->current_group->status || 'hidden' == $this->current_group->status ) {
+				if ( $this->current_group->is_user_member && is_user_logged_in() || bp_current_user_can( 'bp_moderate' ) )
+					$this->current_group->user_has_access = true;
+				else
+					$this->current_group->user_has_access = false;
+			} else {
+				$this->current_group->user_has_access = true;
+			}
+
+		// Set current_group to 0 to prevent debug errors
+		} else {
+			$this->current_group = 0;
+		}
+
+		// Illegal group names/slugs
+		$this->forbidden_names = apply_filters( 'groups_forbidden_names', array(
+			'my-groups',
+			'create',
+			'invites',
+			'send-invites',
+			'forum',
+			'delete',
+			'add',
+			'admin',
+			'request-membership',
+			'members',
+			'settings',
+			'avatar',
+			$this->slug,
+			$this->root_slug,
+		) );
+
+		// If the user was attempting to access a group, but no group by that name was found, 404
+		if ( bp_is_groups_component() && empty( $this->current_group ) && bp_current_action() && !in_array( bp_current_action(), $this->forbidden_names ) ) {
+			bp_do_404();
+			return;
+		}
+
+		if ( bp_is_groups_component() && !empty( $this->current_group ) ) {
+
+			$this->default_extension = apply_filters( 'bp_groups_default_extension', defined( 'BP_GROUPS_DEFAULT_EXTENSION' ) ? BP_GROUPS_DEFAULT_EXTENSION : 'home' );
+
+			if ( !bp_current_action() ) {
+				$bp->current_action = $this->default_extension;
+			}
+
+			// Prepare for a redirect to the canonical URL
+			$bp->canonical_stack['base_url'] = bp_get_group_permalink( $this->current_group );
+
+			if ( bp_current_action() ) {
+				$bp->canonical_stack['action'] = bp_current_action();
+			}
+
+			if ( !empty( $bp->action_variables ) ) {
+				$bp->canonical_stack['action_variables'] = bp_action_variables();
+			}
+
+			// When viewing the default extension, the canonical URL should not have
+			// that extension's slug, unless more has been tacked onto the URL via
+			// action variables
+			if ( bp_is_current_action( $this->default_extension ) && empty( $bp->action_variables ) )  {
+				unset( $bp->canonical_stack['action'] );
+			}
+
+		}
+
+		// Group access control
+		if ( bp_is_groups_component() && !empty( $this->current_group ) ) {
+			if ( !$this->current_group->user_has_access ) {
+
+				// Hidden groups should return a 404 for non-members.
+				// Unset the current group so that you're not redirected
+				// to the default group tab
+				if ( 'hidden' == $this->current_group->status ) {
+					$this->current_group = 0;
+					$bp->is_single_item  = false;
+					bp_do_404();
+					return;
+
+				// Skip the no_access check on home and membership request pages
+				} elseif ( !bp_is_current_action( 'home' ) && !bp_is_current_action( 'request-membership' ) ) {
+
+					// Off-limits to this user. Throw an error and redirect to the group's home page
+					if ( is_user_logged_in() ) {
+						bp_core_no_access( array(
+							'message'  => __( 'You do not have access to this group.', 'buddypress' ),
+							'root'     => bp_get_group_permalink( $bp->groups->current_group ) . 'home/',
+							'redirect' => false
+						) );
+
+					// User does not have access, and does not get a message
+					} else {
+						bp_core_no_access();
+					}
+				}
+			}
+
+			// Protect the admin tab from non-admins
+			if ( bp_is_current_action( 'admin' ) && !bp_is_item_admin() ) {
+				bp_core_no_access( array(
+					'message'  => __( 'You are not an admin of this group.', 'buddypress' ),
+					'root'     => bp_get_group_permalink( $bp->groups->current_group ),
+					'redirect' => false
+				) );
+			}
+		}
+
+		// Preconfigured group creation steps
+		$this->group_creation_steps = apply_filters( 'groups_create_group_steps', array(
+			'group-details'  => array(
+				'name'       => __( 'Details',  'buddypress' ),
+				'position'   => 0
+			),
+			'group-settings' => array(
+				'name'       => __( 'Settings', 'buddypress' ),
+				'position'   => 10
+			)
+		) );
+
+		// If avatar uploads are not disabled, add avatar option
+		if ( ! (int) buddypress()->site_options['bp-disable-avatar-uploads'] ) {
+			$this->group_creation_steps['group-avatar'] = array(
+				'name'     => __( 'Avatar',   'buddypress' ),
+				'position' => 20
+			);
+		}
+
+		// If friends component is active, add invitations
+		if ( bp_is_active( 'friends' ) ) {
+			$this->group_creation_steps['group-invites'] = array(
+				'name'     => __( 'Invites', 'buddypress' ),
+				'position' => 30
+			);
+		}
+
+		// Groups statuses
+		$this->valid_status = apply_filters( 'groups_valid_status', array(
+			'public',
+			'private',
+			'hidden'
+		) );
+
+		// Auto join group when non group member performs group activity
+		$this->auto_join = defined( 'BP_DISABLE_AUTO_GROUP_JOIN' ) && BP_DISABLE_AUTO_GROUP_JOIN ? false : true;
+	}
+
+	/**
+	 * Setup BuddyBar navigation
+	 *
+	 * @global BuddyPress $bp The one true BuddyPress instance
+	 */
+	public function setup_nav( $main_nav = array(), $sub_nav = array() ) {
+
+		// Add 'Groups' to the main navigation
+		$main_nav = array(
+			'name'                => sprintf( __( 'Groups <span>%s</span>', 'buddypress' ), bp_get_total_group_count_for_user() ),
+			'slug'                => $this->slug,
+			'position'            => 70,
+			'screen_function'     => 'groups_screen_my_groups',
+			'default_subnav_slug' => 'my-groups',
+			'item_css_id'         => $this->id
+		);
+
+		// Determine user to use
+		if ( bp_displayed_user_domain() ) {
+			$user_domain = bp_displayed_user_domain();
+		} elseif ( bp_loggedin_user_domain() ) {
+			$user_domain = bp_loggedin_user_domain();
+		} else {
+			$user_domain = false;
+		}
+
+		if ( !empty( $user_domain ) ) {
+			$groups_link = trailingslashit( $user_domain . $this->slug );
+
+			// Add the My Groups nav item
+			$sub_nav[] = array(
+				'name'            => __( 'Memberships', 'buddypress' ),
+				'slug'            => 'my-groups',
+				'parent_url'      => $groups_link,
+				'parent_slug'     => $this->slug,
+				'screen_function' => 'groups_screen_my_groups',
+				'position'        => 10,
+				'item_css_id'     => 'groups-my-groups'
+			);
+
+			// Add the Group Invites nav item
+			$sub_nav[] = array(
+				'name'            => __( 'Invitations', 'buddypress' ),
+				'slug'            => 'invites',
+				'parent_url'      => $groups_link,
+				'parent_slug'     => $this->slug,
+				'screen_function' => 'groups_screen_group_invites',
+				'user_has_access' => bp_core_can_edit_settings(),
+				'position'        => 30
+			);
+
+			parent::setup_nav( $main_nav, $sub_nav );
+		}
+
+		if ( bp_is_groups_component() && bp_is_single_item() ) {
+
+			// Reset sub nav
+			$sub_nav = array();
+
+			// Add 'Groups' to the main navigation
+			$main_nav = array(
+				'name'                => __( 'Memberships', 'buddypress' ),
+				'slug'                => $this->current_group->slug,
+				'position'            => -1, // Do not show in BuddyBar
+				'screen_function'     => 'groups_screen_group_home',
+				'default_subnav_slug' => $this->default_extension,
+				'item_css_id'         => $this->id
+			);
+
+			$group_link = bp_get_group_permalink( $this->current_group );
+
+			// Add the "Home" subnav item, as this will always be present
+			$sub_nav[] = array(
+				'name'            =>  _x( 'Home', 'Group home navigation title', 'buddypress' ),
+				'slug'            => 'home',
+				'parent_url'      => $group_link,
+				'parent_slug'     => $this->current_group->slug,
+				'screen_function' => 'groups_screen_group_home',
+				'position'        => 10,
+				'item_css_id'     => 'home'
+			);
+
+			// If this is a private group, and the user is not a
+			// member and does not have an outstanding invitation,
+			// show a "Request Membership" nav item.
+			if ( is_user_logged_in() &&
+				 ! bp_current_user_can( 'bp_moderate' ) &&
+				 ! $this->current_group->is_user_member &&
+				 ! groups_check_for_membership_request( bp_loggedin_user_id(), $this->current_group->id ) &&
+				 $this->current_group->status == 'private' &&
+				 ! groups_check_user_has_invite( bp_loggedin_user_id(), $this->current_group->id )
+				) {
+
+				$sub_nav[] = array(
+					'name'               => __( 'Request Membership', 'buddypress' ),
+					'slug'               => 'request-membership',
+					'parent_url'         => $group_link,
+					'parent_slug'        => $this->current_group->slug,
+					'screen_function'    => 'groups_screen_group_request_membership',
+					'position'           => 30
+				);
+			}
+
+			// Forums are enabled and turned on
+			if ( $this->current_group->enable_forum && bp_is_active( 'forums' ) ) {
+				$sub_nav[] = array(
+					'name'            => __( 'Forum', 'buddypress' ),
+					'slug'            => 'forum',
+					'parent_url'      => $group_link,
+					'parent_slug'     => $this->current_group->slug,
+					'screen_function' => 'groups_screen_group_forum',
+					'position'        => 40,
+					'user_has_access' => $this->current_group->user_has_access,
+					'item_css_id'     => 'forums'
+				);
+			}
+
+			$sub_nav[] = array(
+				'name'            => sprintf( __( 'Members <span>%s</span>', 'buddypress' ), number_format( $this->current_group->total_member_count ) ),
+				'slug'            => 'members',
+				'parent_url'      => $group_link,
+				'parent_slug'     => $this->current_group->slug,
+				'screen_function' => 'groups_screen_group_members',
+				'position'        => 60,
+				'user_has_access' => $this->current_group->user_has_access,
+				'item_css_id'     => 'members'
+			);
+
+			if ( bp_is_active( 'friends' ) && bp_groups_user_can_send_invites() ) {
+				$sub_nav[] = array(
+					'name'            => __( 'Send Invites', 'buddypress' ),
+					'slug'            => 'send-invites',
+					'parent_url'      => $group_link,
+					'parent_slug'     => $this->current_group->slug,
+					'screen_function' => 'groups_screen_group_invite',
+					'item_css_id'     => 'invite',
+					'position'        => 70,
+					'user_has_access' => $this->current_group->user_has_access
+				);
+			}
+
+			// If the user is a group admin, then show the group admin nav item
+			if ( bp_is_item_admin() ) {
+				$sub_nav[] = array(
+					'name'            => __( 'Admin', 'buddypress' ),
+					'slug'            => 'admin',
+					'parent_url'      => $group_link,
+					'parent_slug'     => $this->current_group->slug,
+					'screen_function' => 'groups_screen_group_admin',
+					'position'        => 1000,
+					'user_has_access' => true,
+					'item_css_id'     => 'admin'
+				);
+			}
+
+			parent::setup_nav( $main_nav, $sub_nav );
+		}
+
+		if ( isset( $this->current_group->user_has_access ) ) {
+			do_action( 'groups_setup_nav', $this->current_group->user_has_access );
+		} else {
+			do_action( 'groups_setup_nav');
+		}
+	}
+
+	/**
+	 * Set up the Toolbar
+	 */
+	public function setup_admin_bar( $wp_admin_nav = array() ) {
+		$bp = buddypress();
+
+		// Menus for logged in user
+		if ( is_user_logged_in() ) {
+
+			// Setup the logged in user variables
+			$user_domain = bp_loggedin_user_domain();
+			$groups_link = trailingslashit( $user_domain . $this->slug );
+
+			// Pending group invites
+			$count   = groups_get_invites_for_user( bp_loggedin_user_id() );
+			$title   = __( 'Groups',             'buddypress' );
+			$pending = __( 'No Pending Invites', 'buddypress' );
+
+			if ( !empty( $count['total'] ) ) {
+				$title   = sprintf( __( 'Groups <span class="count">%s</span>',          'buddypress' ), $count['total'] );
+				$pending = sprintf( __( 'Pending Invites <span class="count">%s</span>', 'buddypress' ), $count['total'] );
+			}
+
+			// Add the "My Account" sub menus
+			$wp_admin_nav[] = array(
+				'parent' => $bp->my_account_menu_id,
+				'id'     => 'my-account-' . $this->id,
+				'title'  => $title,
+				'href'   => trailingslashit( $groups_link )
+			);
+
+			// My Groups
+			$wp_admin_nav[] = array(
+				'parent' => 'my-account-' . $this->id,
+				'id'     => 'my-account-' . $this->id . '-memberships',
+				'title'  => __( 'Memberships', 'buddypress' ),
+				'href'   => trailingslashit( $groups_link )
+			);
+
+			// Invitations
+			$wp_admin_nav[] = array(
+				'parent' => 'my-account-' . $this->id,
+				'id'     => 'my-account-' . $this->id . '-invites',
+				'title'  => $pending,
+				'href'   => trailingslashit( $groups_link . 'invites' )
+			);
+
+			// Create a Group
+			if ( bp_user_can_create_groups() ) {
+				$wp_admin_nav[] = array(
+					'parent' => 'my-account-' . $this->id,
+					'id'     => 'my-account-' . $this->id . '-create',
+					'title'  => __( 'Create a Group', 'buddypress' ),
+					'href'   => trailingslashit( bp_get_groups_directory_permalink() . 'create' )
+				);
+			}
+		}
+
+		parent::setup_admin_bar( $wp_admin_nav );
+	}
+
+	/**
+	 * Sets up the title for pages and <title>
+	 */
+	function setup_title() {
+		$bp = buddypress();
+
+		if ( bp_is_groups_component() ) {
+
+			if ( bp_is_my_profile() && !bp_is_single_item() ) {
+				$bp->bp_options_title = __( 'Memberships', 'buddypress' );
+
+			} else if ( !bp_is_my_profile() && !bp_is_single_item() ) {
+				$bp->bp_options_avatar = bp_core_fetch_avatar( array(
+					'item_id' => bp_displayed_user_id(),
+					'type'    => 'thumb',
+					'alt'     => sprintf( __( 'Profile picture of %s', 'buddypress' ), bp_get_displayed_user_fullname() )
+				) );
+				$bp->bp_options_title = bp_get_displayed_user_fullname();
+
+			// We are viewing a single group, so set up the
+			// group navigation menu using the $this->current_group global.
+			} else if ( bp_is_single_item() ) {
+				$bp->bp_options_title  = $this->current_group->name;
+				$bp->bp_options_avatar = bp_core_fetch_avatar( array(
+					'item_id'    => $this->current_group->id,
+					'object'     => 'group',
+					'type'       => 'thumb',
+					'avatar_dir' => 'group-avatars',
+					'alt'        => __( 'Group Avatar', 'buddypress' )
+				) );
+
+				if ( empty( $bp->bp_options_avatar ) ) {
+					$bp->bp_options_avatar = bp_group_current_avatar();
+				}
+			}
+		}
+
+		parent::setup_title();
+	}
+}
+
+
+function bp_setup_groups() {
+	buddypress()->groups = new BP_Groups_Component();
+}
+add_action( 'bp_setup_components', 'bp_setup_groups', 6 );
Index: /tags/1.9/bp-groups/bp-groups-notifications.php
===================================================================
--- /tags/1.9/bp-groups/bp-groups-notifications.php	(revision 7684)
+++ /tags/1.9/bp-groups/bp-groups-notifications.php	(revision 7684)
@@ -0,0 +1,633 @@
+<?php
+
+/**
+ * BuddyPress Groups Notification Functions
+ *
+ * These functions handle the recording, deleting and formatting of notifications
+ * for the user and for this specific component.
+ *
+ * @package BuddyPress
+ * @subpackage GroupsActivity
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/** Emails ********************************************************************/
+
+function groups_notification_group_updated( $group_id ) {
+
+	$group    = groups_get_group( array( 'group_id' => $group_id ) );
+	$subject  = bp_get_email_subject( array( 'text' => __( 'Group Details Updated', 'buddypress' ) ) );
+	$user_ids = BP_Groups_Member::get_group_member_ids( $group->id );
+
+	foreach ( (array) $user_ids as $user_id ) {
+		if ( 'no' == bp_get_user_meta( $user_id, 'notification_groups_group_updated', true ) ) continue;
+
+		$ud = bp_core_get_core_userdata( $user_id );
+
+		// Set up and send the message
+		$to = $ud->user_email;
+
+		$group_link    = bp_get_group_permalink( $group );
+		$settings_slug = function_exists( 'bp_get_settings_slug' ) ? bp_get_settings_slug() : 'settings';
+		$settings_link = bp_core_get_user_domain( $user_id ) . $settings_slug . '/notifications/';
+
+		$message = sprintf( __(
+'Group details for the group "%1$s" were updated:
+
+To view the group: %2$s
+
+---------------------
+', 'buddypress' ), $group->name, $group_link );
+
+		$message .= sprintf( __( 'To disable these notifications please log in and go to: %s', 'buddypress' ), $settings_link );
+
+		/* Send the message */
+		$to      = apply_filters( 'groups_notification_group_updated_to', $to );
+		$subject = apply_filters_ref_array( 'groups_notification_group_updated_subject', array( $subject, &$group ) );
+		$message = apply_filters_ref_array( 'groups_notification_group_updated_message', array( $message, &$group, $group_link, $settings_link ) );
+
+		wp_mail( $to, $subject, $message );
+
+		unset( $message, $to );
+	}
+
+	do_action( 'bp_groups_sent_updated_email', $user_ids, $subject, '', $group_id );
+}
+
+function groups_notification_new_membership_request( $requesting_user_id, $admin_id, $group_id, $membership_id ) {
+
+	if ( bp_is_active( 'notifications' ) ) {
+		bp_notifications_add_notification( array(
+			'user_id'           => $admin_id,
+			'item_id'           => $requesting_user_id,
+			'secondary_item_id' => $group_id,
+			'component_name'    => buddypress()->groups->id,
+			'component_action'  => 'new_membership_request'
+		) );
+	}
+
+	if ( 'no' == bp_get_user_meta( $admin_id, 'notification_groups_membership_request', true ) )
+		return false;
+
+	$requesting_user_name = bp_core_get_user_displayname( $requesting_user_id );
+	$group                = groups_get_group( array( 'group_id' => $group_id ) );
+
+	$ud             = bp_core_get_core_userdata( $admin_id );
+	$group_requests = bp_get_group_permalink( $group ) . 'admin/membership-requests';
+	$profile_link   = bp_core_get_user_domain( $requesting_user_id );
+	$settings_slug  = function_exists( 'bp_get_settings_slug' ) ? bp_get_settings_slug() : 'settings';
+	$settings_link  = bp_core_get_user_domain( $requesting_user_id ) . $settings_slug . '/notifications/';
+
+	// Set up and send the message
+	$to       = $ud->user_email;
+	$subject  = bp_get_email_subject( array( 'text' => sprintf( __( 'Membership request for group: %s', 'buddypress' ), $group->name ) ) );
+
+$message = sprintf( __(
+'%1$s wants to join the group "%2$s".
+
+Because you are the administrator of this group, you must either accept or reject the membership request.
+
+To view all pending membership requests for this group, please visit:
+%3$s
+
+To view %4$s\'s profile: %5$s
+
+---------------------
+', 'buddypress' ), $requesting_user_name, $group->name, $group_requests, $requesting_user_name, $profile_link );
+
+	// Only show the disable notifications line if the settings component is enabled
+	if ( bp_is_active( 'settings' ) ) {
+		$message .= sprintf( __( 'To disable these notifications please log in and go to: %s', 'buddypress' ), $settings_link );
+	}
+
+	/* Send the message */
+	$to      = apply_filters( 'groups_notification_new_membership_request_to', $to );
+	$subject = apply_filters_ref_array( 'groups_notification_new_membership_request_subject', array( $subject, &$group ) );
+	$message = apply_filters_ref_array( 'groups_notification_new_membership_request_message', array( $message, &$group, $requesting_user_name, $profile_link, $group_requests, $settings_link ) );
+
+	wp_mail( $to, $subject, $message );
+
+	do_action( 'bp_groups_sent_membership_request_email', $admin_id, $subject, $message, $requesting_user_id, $group_id, $membership_id );
+}
+
+function groups_notification_membership_request_completed( $requesting_user_id, $group_id, $accepted = true ) {
+
+	// Post a screen notification first.
+	if ( bp_is_active( 'notifications' ) ) {
+
+		$type = ! empty( $accepted ) ? 'membership_request_accepted' : 'membership_request_rejected' ;
+
+		bp_notifications_add_notification( array(
+			'user_id'           => $requesting_user_id,
+			'item_id'           => $group_id,
+			'component_name'    => buddypress()->groups->id,
+			'component_action'  => $type
+		) );
+	}
+
+	if ( 'no' == bp_get_user_meta( $requesting_user_id, 'notification_membership_request_completed', true ) )
+		return false;
+
+	$group = groups_get_group( array( 'group_id' => $group_id ) );
+
+	$ud = bp_core_get_core_userdata($requesting_user_id);
+
+	$group_link   = bp_get_group_permalink( $group );
+	$settings_slug = function_exists( 'bp_get_settings_slug' ) ? bp_get_settings_slug() : 'settings';
+	$settings_link = bp_core_get_user_domain( $requesting_user_id ) . $settings_slug . '/notifications/';
+
+	// Set up and send the message
+	$to       = $ud->user_email;
+
+	if ( $accepted ) {
+		$subject = bp_get_email_subject( array( 'text' => sprintf( __( 'Membership request for group "%s" accepted', 'buddypress' ), $group->name ) ) );
+		$message = sprintf( __(
+'Your membership request for the group "%1$s" has been accepted.
+
+To view the group please login and visit: %2$s
+
+---------------------
+', 'buddypress' ), $group->name, $group_link );
+
+	} else {
+		$subject = bp_get_email_subject( array( 'text' => sprintf( __( 'Membership request for group "%s" rejected', 'buddypress' ), $group->name ) ) );
+		$message = sprintf( __(
+'Your membership request for the group "%1$s" has been rejected.
+
+To submit another request please log in and visit: %2$s
+
+---------------------
+', 'buddypress' ), $group->name, $group_link );
+	}
+
+	// Only show the disable notifications line if the settings component is enabled
+	if ( bp_is_active( 'settings' ) ) {
+		$message .= sprintf( __( 'To disable these notifications please log in and go to: %s', 'buddypress' ), $settings_link );
+	}
+
+	/* Send the message */
+	$to      = apply_filters( 'groups_notification_membership_request_completed_to', $to );
+	$subject = apply_filters_ref_array( 'groups_notification_membership_request_completed_subject', array( $subject, &$group ) );
+	$message = apply_filters_ref_array( 'groups_notification_membership_request_completed_message', array( $message, &$group, $group_link, $settings_link ) );
+
+	wp_mail( $to, $subject, $message );
+
+	do_action( 'bp_groups_sent_membership_approved_email', $requesting_user_id, $subject, $message, $group_id );
+}
+add_action( 'groups_membership_accepted', 'groups_notification_membership_request_completed', 10, 3 );
+add_action( 'groups_membership_rejected', 'groups_notification_membership_request_completed', 10, 3 );
+
+function groups_notification_promoted_member( $user_id, $group_id ) {
+
+	if ( groups_is_user_admin( $user_id, $group_id ) ) {
+		$promoted_to = __( 'an administrator', 'buddypress' );
+		$type = 'member_promoted_to_admin';
+	} else {
+		$promoted_to = __( 'a moderator', 'buddypress' );
+		$type = 'member_promoted_to_mod';
+	}
+
+	// Post a screen notification first.
+	if ( bp_is_active( 'notifications' ) ) {
+		bp_notifications_add_notification( array(
+			'user_id'           => $user_id,
+			'item_id'           => $group_id,
+			'component_name'    => buddypress()->groups->id,
+			'component_action'  => $type,
+			'date_notified'     => bp_core_current_time(),
+			'is_new'            => 1,
+		) );
+	}
+
+	if ( 'no' == bp_get_user_meta( $user_id, 'notification_groups_admin_promotion', true ) )
+		return false;
+
+	$group         = groups_get_group( array( 'group_id' => $group_id ) );
+	$ud            = bp_core_get_core_userdata($user_id);
+	$group_link    = bp_get_group_permalink( $group );
+	$settings_slug = function_exists( 'bp_get_settings_slug' ) ? bp_get_settings_slug() : 'settings';
+	$settings_link = bp_core_get_user_domain( $user_id ) . $settings_slug . '/notifications/';
+
+	// Set up and send the message
+	$to       = $ud->user_email;
+	$subject  = bp_get_email_subject( array( 'text' => sprintf( __( 'You have been promoted in the group: "%s"', 'buddypress' ), $group->name ) ) );
+	$message  = sprintf( __(
+'You have been promoted to %1$s for the group: "%2$s".
+
+To view the group please visit: %3$s
+
+---------------------
+', 'buddypress' ), $promoted_to, $group->name, $group_link );
+
+	// Only show the disable notifications line if the settings component is enabled
+	if ( bp_is_active( 'settings' ) ) {
+		$message .= sprintf( __( 'To disable these notifications please log in and go to: %s', 'buddypress' ), $settings_link );
+	}
+
+	/* Send the message */
+	$to      = apply_filters( 'groups_notification_promoted_member_to', $to );
+	$subject = apply_filters_ref_array( 'groups_notification_promoted_member_subject', array( $subject, &$group ) );
+	$message = apply_filters_ref_array( 'groups_notification_promoted_member_message', array( $message, &$group, $promoted_to, $group_link, $settings_link ) );
+
+	wp_mail( $to, $subject, $message );
+
+	do_action( 'bp_groups_sent_promoted_email', $user_id, $subject, $message, $group_id );
+}
+add_action( 'groups_promoted_member', 'groups_notification_promoted_member', 10, 2 );
+
+function groups_notification_group_invites( &$group, &$member, $inviter_user_id ) {
+
+	// @todo $inviter_up may be used for caching, test without it
+	$inviter_ud   = bp_core_get_core_userdata( $inviter_user_id );
+	$inviter_name = bp_core_get_userlink( $inviter_user_id, true, false, true );
+	$inviter_link = bp_core_get_user_domain( $inviter_user_id );
+
+	$group_link = bp_get_group_permalink( $group );
+
+	if ( !$member->invite_sent ) {
+		$invited_user_id = $member->user_id;
+
+		// Post a screen notification first.
+		if ( bp_is_active( 'notifications' ) ) {
+			bp_notifications_add_notification( array(
+				'user_id'           => $invited_user_id,
+				'item_id'           => $group->id,
+				'component_name'    => buddypress()->groups->id,
+				'component_action'  => 'group_invite'
+			) );
+		}
+
+		if ( 'no' == bp_get_user_meta( $invited_user_id, 'notification_groups_invite', true ) )
+			return false;
+
+		$invited_ud    = bp_core_get_core_userdata($invited_user_id);
+		$settings_slug = function_exists( 'bp_get_settings_slug' ) ? bp_get_settings_slug() : 'settings';
+		$settings_link = bp_core_get_user_domain( $invited_user_id ) . $settings_slug . '/notifications/';
+		$invited_link  = bp_core_get_user_domain( $invited_user_id );
+		$invites_link  = trailingslashit( $invited_link . bp_get_groups_slug() . '/invites' );
+
+		// Set up and send the message
+		$to       = $invited_ud->user_email;
+		$subject  = bp_get_email_subject( array( 'text' => sprintf( __( 'You have an invitation to the group: "%s"', 'buddypress' ), $group->name ) ) );
+
+		$message = sprintf( __(
+'One of your friends %1$s has invited you to the group: "%2$s".
+
+To view your group invites visit: %3$s
+
+To view the group visit: %4$s
+
+To view %5$s\'s profile visit: %6$s
+
+---------------------
+', 'buddypress' ), $inviter_name, $group->name, $invites_link, $group_link, $inviter_name, $inviter_link );
+
+		// Only show the disable notifications line if the settings component is enabled
+		if ( bp_is_active( 'settings' ) ) {
+			$message .= sprintf( __( 'To disable these notifications please log in and go to: %s', 'buddypress' ), $settings_link );
+		}
+
+		/* Send the message */
+		$to      = apply_filters( 'groups_notification_group_invites_to', $to );
+		$subject = apply_filters_ref_array( 'groups_notification_group_invites_subject', array( $subject, &$group ) );
+		$message = apply_filters_ref_array( 'groups_notification_group_invites_message', array( $message, &$group, $inviter_name, $inviter_link, $invites_link, $group_link, $settings_link ) );
+
+		wp_mail( $to, $subject, $message );
+
+		do_action( 'bp_groups_sent_invited_email', $invited_user_id, $subject, $message, $group );
+	}
+}
+
+/** Notifications *************************************************************/
+
+/**
+ * Format the BuddyBar/Toolbar notifications for the Groups component
+ *
+ * @since BuddyPress (1.0)
+ * @param string $action The kind of notification being rendered
+ * @param int $item_id The primary item id
+ * @param int $secondary_item_id The secondary item id
+ * @param int $total_items The total number of messaging-related notifications waiting for the user
+ * @param string $format 'string' for BuddyBar-compatible notifications; 'array' for WP Toolbar
+ */
+function groups_format_notifications( $action, $item_id, $secondary_item_id, $total_items, $format = 'string' ) {
+
+	switch ( $action ) {
+		case 'new_membership_request':
+			$group_id = $secondary_item_id;
+			$requesting_user_id = $item_id;
+
+			$group = groups_get_group( array( 'group_id' => $group_id ) );
+			$group_link = bp_get_group_permalink( $group );
+
+			// Set up the string and the filter
+			// Because different values are passed to the filters, we'll return the
+			// values inline
+			if ( (int) $total_items > 1 ) {
+				$text = sprintf( __( '%1$d new membership requests for the group "%2$s"', 'buddypress' ), (int) $total_items, $group->name );
+				$filter = 'bp_groups_multiple_new_membership_requests_notification';
+				$notification_link = $group_link . 'admin/membership-requests/?n=1';
+
+				if ( 'string' == $format ) {
+					return apply_filters( $filter, '<a href="' . $notification_link . '" title="' . __( 'Group Membership Requests', 'buddypress' ) . '">' . $text . '</a>', $group_link, $total_items, $group->name, $text, $notification_link );
+				} else {
+					return apply_filters( $filter, array(
+						'link' => $notification_link,
+						'text' => $text
+					), $group_link, $total_items, $group->name, $text, $notification_link );
+				}
+			} else {
+				$user_fullname = bp_core_get_user_displayname( $requesting_user_id );
+				$text = sprintf( __( '%s requests group membership', 'buddypress' ), $user_fullname );
+				$filter = 'bp_groups_single_new_membership_request_notification';
+				$notification_link = $group_link . 'admin/membership-requests/?n=1';
+
+				if ( 'string' == $format ) {
+					return apply_filters( $filter, '<a href="' . $notification_link . '" title="' . sprintf( __( '%s requests group membership', 'buddypress' ), $user_fullname ) . '">' . $text . '</a>', $group_link, $user_fullname, $group->name, $text, $notification_link );
+				} else {
+					return apply_filters( $filter, array(
+						'link' => $notification_link,
+						'text' => $text
+					), $group_link, $user_fullname, $group->name, $text, $notification_link );
+				}
+			}
+
+			break;
+
+		case 'membership_request_accepted':
+			$group_id = $item_id;
+
+			$group = groups_get_group( array( 'group_id' => $group_id ) );
+			$group_link = bp_get_group_permalink( $group );
+
+			if ( (int) $total_items > 1 ) {
+				$text = sprintf( __( '%d accepted group membership requests', 'buddypress' ), (int) $total_items, $group->name );
+				$filter = 'bp_groups_multiple_membership_request_accepted_notification';
+				$notification_link = trailingslashit( bp_loggedin_user_domain() . bp_get_groups_slug() ) . '?n=1';
+
+				if ( 'string' == $format ) {
+					return apply_filters( $filter, '<a href="' . $notification_link . '" title="' . __( 'Groups', 'buddypress' ) . '">' . $text . '</a>', $total_items, $group->name, $text, $notification_link );
+				} else {
+					return apply_filters( $filter, array(
+						'link' => $notification_link,
+						'text' => $text
+					), $total_items, $group->name, $text, $notification_link );
+				}
+			} else {
+				$text = sprintf( __( 'Membership for group "%s" accepted', 'buddypress' ), $group->name );
+				$filter = 'bp_groups_single_membership_request_accepted_notification';
+				$notification_link = $group_link . '?n=1';
+
+				if ( 'string' == $format ) {
+					return apply_filters( $filter, '<a href="' . $notification_link . '">' . $text . '</a>', $group_link, $group->name, $text, $notification_link );
+				} else {
+					return apply_filters( $filter, array(
+						'link' => $notification_link,
+						'text' => $text
+					), $group_link, $group->name, $text, $notification_link );
+				}
+			}
+
+			break;
+
+		case 'membership_request_rejected':
+			$group_id = $item_id;
+
+			$group = groups_get_group( array( 'group_id' => $group_id ) );
+			$group_link = bp_get_group_permalink( $group );
+
+			if ( (int) $total_items > 1 ) {
+				$text = sprintf( __( '%d rejected group membership requests', 'buddypress' ), (int) $total_items, $group->name );
+				$filter = 'bp_groups_multiple_membership_request_rejected_notification';
+				$notification_link = trailingslashit( bp_loggedin_user_domain() . bp_get_groups_slug() ) . '?n=1';
+
+				if ( 'string' == $format ) {
+					return apply_filters( $filter, '<a href="' . $notification_link . '" title="' . __( 'Groups', 'buddypress' ) . '">' . $text . '</a>', $total_items, $group->name );
+				} else {
+					return apply_filters( $filter, array(
+						'link' => $notification_link,
+						'text' => $text
+					), $total_items, $group->name, $text, $notification_link );
+				}
+			} else {
+				$text = sprintf( __( 'Membership for group "%s" rejected', 'buddypress' ), $group->name );
+				$filter = 'bp_groups_single_membership_request_rejected_notification';
+				$notification_link = $group_link . '?n=1';
+
+				if ( 'string' == $format ) {
+					return apply_filters( $filter, '<a href="' . $notification_link . '">' . $text . '</a>', $group_link, $group->name, $text, $notification_link );
+				} else {
+					return apply_filters( $filter, array(
+						'link' => $notification_link,
+						'text' => $text
+					), $group_link, $group->name, $text, $notification_link );
+				}
+			}
+
+			break;
+
+		case 'member_promoted_to_admin':
+			$group_id = $item_id;
+
+			$group = groups_get_group( array( 'group_id' => $group_id ) );
+			$group_link = bp_get_group_permalink( $group );
+
+			if ( (int) $total_items > 1 ) {
+				$text = sprintf( __( 'You were promoted to an admin in %d groups', 'buddypress' ), (int) $total_items );
+				$filter = 'bp_groups_multiple_member_promoted_to_admin_notification';
+				$notification_link = trailingslashit( bp_loggedin_user_domain() . bp_get_groups_slug() ) . '?n=1';
+
+				if ( 'string' == $format ) {
+					return apply_filters( $filter, '<a href="' . $notification_link . '" title="' . __( 'Groups', 'buddypress' ) . '">' . $text . '</a>', $total_items, $text, $notification_link );
+				} else {
+					return apply_filters( $filter, array(
+						'link' => $notification_link,
+						'text' => $text
+					), $total_items, $text, $notification_link );
+				}
+			} else {
+				$text = sprintf( __( 'You were promoted to an admin in the group "%s"', 'buddypress' ), $group->name );
+				$filter = 'bp_groups_single_member_promoted_to_admin_notification';
+				$notification_link = $group_link . '?n=1';
+
+				if ( 'string' == $format ) {
+					return apply_filters( $filter, '<a href="' . $notification_link . '">' . $text . '</a>', $group_link, $group->name, $text, $notification_link );
+				} else {
+					return apply_filters( $filter, array(
+						'link' => $notification_link,
+						'text' => $text
+					), $group_link, $group->name, $text, $notification_link );
+				}
+			}
+
+			break;
+
+		case 'member_promoted_to_mod':
+			$group_id = $item_id;
+
+			$group = groups_get_group( array( 'group_id' => $group_id ) );
+			$group_link = bp_get_group_permalink( $group );
+
+			if ( (int) $total_items > 1 ) {
+				$text = sprintf( __( 'You were promoted to a mod in %d groups', 'buddypress' ), (int) $total_items );
+				$filter = 'bp_groups_multiple_member_promoted_to_mod_notification';
+				$notification_link = trailingslashit( bp_loggedin_user_domain() . bp_get_groups_slug() ) . '?n=1';
+
+				if ( 'string' == $format ) {
+					return apply_filters( $filter, '<a href="' . $notification_link . '" title="' . __( 'Groups', 'buddypress' ) . '">' . $text . '</a>', $total_items, $text, $notification_link );
+				} else {
+					return apply_filters( $filter, array(
+						'link' => $notification_link,
+						'text' => $text
+					), $total_items, $text, $notification_link );
+				}
+			} else {
+				$text = sprintf( __( 'You were promoted to a mod in the group "%s"', 'buddypress' ), $group->name );
+				$filter = 'bp_groups_single_member_promoted_to_mod_notification';
+				$notification_link = $group_link . '?n=1';
+
+				if ( 'string' == $format ) {
+					return apply_filters( $filter, '<a href="' . $notification_link . '">' . $text . '</a>', $group_link, $group->name, $text, $notification_link );
+				} else {
+					return apply_filters( $filter, array(
+						'link' => $notification_link,
+						'text' => $text
+					), $group_link, $group->name, $text, $notification_link );
+				}
+			}
+
+			break;
+
+		case 'group_invite':
+			$group_id = $item_id;
+			$group = groups_get_group( array( 'group_id' => $group_id ) );
+			$group_link = bp_get_group_permalink( $group );
+
+			$notification_link = bp_loggedin_user_domain() . bp_get_groups_slug() . '/invites/?n=1';
+
+			if ( (int) $total_items > 1 ) {
+				$text = sprintf( __( 'You have %d new group invitations', 'buddypress' ), (int) $total_items );
+				$filter = 'bp_groups_multiple_group_invite_notification';
+
+				if ( 'string' == $format ) {
+					return apply_filters( $filter, '<a href="' . $notification_link . '" title="' . __( 'Group Invites', 'buddypress' ) . '">' . $text . '</a>', $total_items, $text, $notification_link );
+				} else {
+					return apply_filters( $filter, array(
+						'link' => $notification_link,
+						'text' => $text
+					), $total_items, $text, $notification_link );
+				}
+			} else {
+				$text = sprintf( __( 'You have an invitation to the group: %s', 'buddypress' ), $group->name );
+				$filter = 'bp_groups_single_group_invite_notification';
+
+				if ( 'string' == $format ) {
+					return apply_filters( $filter, '<a href="' . $notification_link . '">' . $text . '</a>', $group_link, $group->name, $text, $notification_link );
+				} else {
+					return apply_filters( $filter, array(
+						'link' => $notification_link,
+						'text' => $text
+					), $group_link, $group->name, $text, $notification_link );
+				}
+			}
+
+			break;
+	}
+
+	do_action( 'groups_format_notifications', $action, $item_id, $secondary_item_id, $total_items );
+
+	return false;
+}
+
+/**
+ * Remove all notifications for any member belonging to a specific group
+ *
+ * @since BuddyPress (1.9.0)
+ */
+function bp_groups_delete_group_delete_all_notifications( $group_id ) {
+	if ( bp_is_active( 'notifications' ) ) {
+		bp_notifications_delete_all_notifications_by_type( $group_id, buddypress()->groups->id );
+	}	
+}
+add_action( 'groups_delete_group', 'bp_groups_delete_group_delete_all_notifications', 10 );
+
+/**
+ * Mark notifications read when a member accepts a group invitation
+ *
+ * @since BuddyPress (1.9.0)
+ * @param int $user_id
+ * @param int $group_id
+ */
+function bp_groups_accept_invite_mark_notifications( $user_id, $group_id ) {
+	if ( bp_is_active( 'notifications' ) ) {
+		bp_notifications_mark_notifications_by_item_id( $user_id, $group_id, buddypress()->groups->id, 'group_invite' );
+	}
+}
+add_action( 'groups_accept_invite', 'bp_groups_accept_invite_mark_notifications', 10, 2 );
+add_action( 'groups_reject_invite', 'bp_groups_accept_invite_mark_notifications', 10, 2 );
+add_action( 'groups_delete_invite', 'bp_groups_accept_invite_mark_notifications', 10, 2 );
+
+/**
+ * Mark notifications read when a member views their group memberships
+ *
+ * @since BuddyPress (1.9.0)
+ */
+function bp_groups_screen_my_groups_mark_notifications() {
+
+	// Delete group request notifications for the user
+	if ( isset( $_GET['n'] ) && bp_is_active( 'notifications' ) ) {
+
+		// Get the necessary ID's
+		$group_id = buddypress()->groups->id;
+		$user_id  = bp_loggedin_user_id();
+
+		// Mark notifications read
+		bp_notifications_mark_notifications_by_type( $user_id, $group_id, 'membership_request_accepted' );
+		bp_notifications_mark_notifications_by_type( $user_id, $group_id, 'membership_request_rejected' );
+		bp_notifications_mark_notifications_by_type( $user_id, $group_id, 'member_promoted_to_mod'      );
+		bp_notifications_mark_notifications_by_type( $user_id, $group_id, 'member_promoted_to_admin'    );
+	}
+}
+add_action( 'groups_screen_my_groups',  'bp_groups_screen_my_groups_mark_notifications', 10 );
+add_action( 'groups_screen_group_home', 'bp_groups_screen_my_groups_mark_notifications', 10 );
+
+/**
+ * Mark group invitation notifications read when a member views their invitations
+ *
+ * @since BuddyPress (1.9.0)
+ */
+function bp_groups_screen_invites_mark_notifications() {
+	if ( bp_is_active( 'notifications' ) ) {
+		bp_notifications_mark_notifications_by_type( bp_loggedin_user_id(), buddypress()->groups->id, 'group_invite' );
+	}
+}
+add_action( 'groups_screen_group_invites', 'bp_groups_screen_invites_mark_notifications', 10 );
+
+/**
+ * Mark group join requests read when an admin or moderator visits the group
+ * administration area.
+ *
+ * @since BuddyPress (1.9.0)
+ * @param int $group_id
+ */
+function bp_groups_screen_group_admin_requests_mark_notifications( $group_id ) {
+	if ( bp_is_active( 'notifications' ) ) {
+		bp_notifications_mark_notifications_by_type( bp_loggedin_user_id(), buddypress()->groups->id, 'new_membership_request' );
+	}
+}
+add_action( 'groups_screen_group_admin_requests', 'bp_groups_screen_group_admin_requests_mark_notifications', 10 );
+
+/**
+ * Delete new group membership notifications when a user is being deleted.
+ *
+ * @since BuddyPress (1.9.0)
+ * @param int $user_id
+ */
+function bp_groups_remove_data_for_user_notifications( $user_id ) {
+	if ( bp_is_active( 'notifications' ) ) {
+		bp_notifications_delete_notifications_from_user( $user_id, buddypress()->groups->id, 'new_membership_request' );
+	}
+}
+add_action( 'groups_remove_data_for_user', 'bp_groups_remove_data_for_user_notifications', 10 );
Index: /tags/1.9/bp-groups/bp-groups-screens.php
===================================================================
--- /tags/1.9/bp-groups/bp-groups-screens.php	(revision 7684)
+++ /tags/1.9/bp-groups/bp-groups-screens.php	(revision 7684)
@@ -0,0 +1,1174 @@
+<?php
+
+/**
+ * BuddyPress Groups Screen Functions
+ *
+ * Screen functions are the controllers of BuddyPress. They will execute when their
+ * specific URL is caught. They will first save or manipulate data using business
+ * functions, then pass on the user to a template file.
+ *
+ * @package BuddyPress
+ * @subpackage GroupsScreens
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+function groups_directory_groups_setup() {
+	if ( bp_is_groups_component() && !bp_current_action() && !bp_current_item() ) {
+		bp_update_is_directory( true, 'groups' );
+
+		do_action( 'groups_directory_groups_setup' );
+
+		bp_core_load_template( apply_filters( 'groups_template_directory_groups', 'groups/index' ) );
+	}
+}
+add_action( 'bp_screens', 'groups_directory_groups_setup', 2 );
+
+function groups_screen_my_groups() {
+
+	do_action( 'groups_screen_my_groups' );
+
+	bp_core_load_template( apply_filters( 'groups_template_my_groups', 'members/single/home' ) );
+}
+
+function groups_screen_group_invites() {
+	$group_id = (int)bp_action_variable( 1 );
+
+	if ( bp_is_action_variable( 'accept' ) && is_numeric( $group_id ) ) {
+		// Check the nonce
+		if ( !check_admin_referer( 'groups_accept_invite' ) )
+			return false;
+
+		if ( !groups_accept_invite( bp_loggedin_user_id(), $group_id ) ) {
+			bp_core_add_message( __('Group invite could not be accepted', 'buddypress'), 'error' );
+		} else {
+			bp_core_add_message( __('Group invite accepted', 'buddypress') );
+
+			// Record this in activity streams
+			$group = groups_get_group( array( 'group_id' => $group_id ) );
+
+			groups_record_activity( array(
+				'action'  => apply_filters_ref_array( 'groups_activity_accepted_invite_action', array( sprintf( __( '%1$s joined the group %2$s', 'buddypress'), bp_core_get_userlink( bp_loggedin_user_id() ), '<a href="' . bp_get_group_permalink( $group ) . '">' . esc_attr( $group->name ) . '</a>' ), bp_loggedin_user_id(), &$group ) ),
+				'type'    => 'joined_group',
+				'item_id' => $group->id
+			) );
+		}
+
+		if ( isset( $_GET['redirect_to'] ) ) {
+			$redirect_to = urldecode( $_GET['redirect_to'] );
+		} else {
+			$redirect_to = trailingslashit( bp_loggedin_user_domain() . bp_get_groups_slug() . '/' . bp_current_action() );
+		}
+
+		bp_core_redirect( $redirect_to );
+
+	} else if ( bp_is_action_variable( 'reject' ) && is_numeric( $group_id ) ) {
+		// Check the nonce
+		if ( !check_admin_referer( 'groups_reject_invite' ) )
+			return false;
+
+		if ( !groups_reject_invite( bp_loggedin_user_id(), $group_id ) ) {
+			bp_core_add_message( __( 'Group invite could not be rejected', 'buddypress' ), 'error' );
+		} else {
+			bp_core_add_message( __( 'Group invite rejected', 'buddypress' ) );
+		}
+
+		if ( isset( $_GET['redirect_to'] ) ) {
+			$redirect_to = urldecode( $_GET['redirect_to'] );
+		} else {
+			$redirect_to = trailingslashit( bp_loggedin_user_domain() . bp_get_groups_slug() . '/' . bp_current_action() );
+		}
+
+		bp_core_redirect( $redirect_to );
+	}
+
+	do_action( 'groups_screen_group_invites', $group_id );
+
+	bp_core_load_template( apply_filters( 'groups_template_group_invites', 'members/single/home' ) );
+}
+
+function groups_screen_group_home() {
+
+	if ( ! bp_is_single_item() ) {
+		return false;
+	}
+
+	do_action( 'groups_screen_group_home' );
+
+	bp_core_load_template( apply_filters( 'groups_template_group_home', 'groups/single/home' ) );
+}
+
+/**
+ * This screen function handles actions related to group forums
+ *
+ * @package BuddyPress
+ */
+function groups_screen_group_forum() {
+
+	if ( !bp_is_active( 'forums' ) || !bp_forums_is_installed_correctly() )
+		return false;
+
+	if ( bp_action_variable( 0 ) && !bp_is_action_variable( 'topic', 0 ) ) {
+		bp_do_404();
+		return;
+	}
+
+	$bp = buddypress();
+
+	if ( !$bp->groups->current_group->user_has_access ) {
+		bp_core_no_access();
+		return;
+	}
+
+	if ( ! bp_is_single_item() )
+		return false;
+
+	// Fetch the details we need
+	$topic_slug	= (string)bp_action_variable( 1 );
+	$topic_id       = bp_forums_get_topic_id_from_slug( $topic_slug );
+	$forum_id       = groups_get_groupmeta( $bp->groups->current_group->id, 'forum_id' );
+	$user_is_banned = false;
+
+	if ( !bp_current_user_can( 'bp_moderate' ) && groups_is_user_banned( bp_loggedin_user_id(), $bp->groups->current_group->id ) )
+		$user_is_banned = true;
+
+	if ( !empty( $topic_slug ) && !empty( $topic_id ) ) {
+
+		// Posting a reply
+		if ( !$user_is_banned && !bp_action_variable( 2 ) && isset( $_POST['submit_reply'] ) ) {
+			// Check the nonce
+			check_admin_referer( 'bp_forums_new_reply' );
+
+			// Auto join this user if they are not yet a member of this group
+			if ( bp_groups_auto_join() && !bp_current_user_can( 'bp_moderate' ) && 'public' == $bp->groups->current_group->status && !groups_is_user_member( bp_loggedin_user_id(), $bp->groups->current_group->id ) ) {
+				groups_join_group( $bp->groups->current_group->id, bp_loggedin_user_id() );
+			}
+
+			$topic_page = isset( $_GET['topic_page'] ) ? $_GET['topic_page'] : false;
+
+			// Don't allow reply flooding
+			if ( bp_forums_reply_exists( $_POST['reply_text'], $topic_id, bp_loggedin_user_id() ) ) {
+				bp_core_add_message( __( 'It looks like you\'ve already said that!', 'buddypress' ), 'error' );
+			} else {
+				if ( !$post_id = groups_new_group_forum_post( $_POST['reply_text'], $topic_id, $topic_page ) ) {
+					bp_core_add_message( __( 'There was an error when replying to that topic', 'buddypress'), 'error' );
+				} else {
+					bp_core_add_message( __( 'Your reply was posted successfully', 'buddypress') );
+				}
+			}
+
+			$query_vars = isset( $_SERVER['QUERY_STRING'] ) ? '?' . $_SERVER['QUERY_STRING'] : '';
+
+			$redirect = bp_get_group_permalink( groups_get_current_group() ) . 'forum/topic/' . $topic_slug . '/' . $query_vars;
+
+			if ( !empty( $post_id ) ) {
+				$redirect .= '#post-' . $post_id;
+			}
+
+			bp_core_redirect( $redirect );
+		}
+
+		// Sticky a topic
+		else if ( bp_is_action_variable( 'stick', 2 ) && ( bp_is_item_admin() || bp_is_item_mod() ) ) {
+			// Check the nonce
+			check_admin_referer( 'bp_forums_stick_topic' );
+
+			if ( !bp_forums_sticky_topic( array( 'topic_id' => $topic_id ) ) ) {
+				bp_core_add_message( __( 'There was an error when making that topic a sticky', 'buddypress' ), 'error' );
+			} else {
+				bp_core_add_message( __( 'The topic was made sticky successfully', 'buddypress' ) );
+			}
+
+			do_action( 'groups_stick_forum_topic', $topic_id );
+			bp_core_redirect( wp_get_referer() );
+		}
+
+		// Un-Sticky a topic
+		else if ( bp_is_action_variable( 'unstick', 2 ) && ( bp_is_item_admin() || bp_is_item_mod() ) ) {
+			// Check the nonce
+			check_admin_referer( 'bp_forums_unstick_topic' );
+
+			if ( !bp_forums_sticky_topic( array( 'topic_id' => $topic_id, 'mode' => 'unstick' ) ) ) {
+				bp_core_add_message( __( 'There was an error when unsticking that topic', 'buddypress'), 'error' );
+			} else {
+				bp_core_add_message( __( 'The topic was unstuck successfully', 'buddypress') );
+			}
+
+			do_action( 'groups_unstick_forum_topic', $topic_id );
+			bp_core_redirect( wp_get_referer() );
+		}
+
+		// Close a topic
+		else if ( bp_is_action_variable( 'close', 2 ) && ( bp_is_item_admin() || bp_is_item_mod() ) ) {
+			// Check the nonce
+			check_admin_referer( 'bp_forums_close_topic' );
+
+			if ( !bp_forums_openclose_topic( array( 'topic_id' => $topic_id ) ) ) {
+				bp_core_add_message( __( 'There was an error when closing that topic', 'buddypress'), 'error' );
+			} else {
+				bp_core_add_message( __( 'The topic was closed successfully', 'buddypress') );
+			}
+
+			do_action( 'groups_close_forum_topic', $topic_id );
+			bp_core_redirect( wp_get_referer() );
+		}
+
+		// Open a topic
+		else if ( bp_is_action_variable( 'open', 2 ) && ( bp_is_item_admin() || bp_is_item_mod() ) ) {
+			// Check the nonce
+			check_admin_referer( 'bp_forums_open_topic' );
+
+			if ( !bp_forums_openclose_topic( array( 'topic_id' => $topic_id, 'mode' => 'open' ) ) ) {
+				bp_core_add_message( __( 'There was an error when opening that topic', 'buddypress'), 'error' );
+			} else {
+				bp_core_add_message( __( 'The topic was opened successfully', 'buddypress') );
+			}
+
+			do_action( 'groups_open_forum_topic', $topic_id );
+			bp_core_redirect( wp_get_referer() );
+		}
+
+		// Delete a topic
+		else if ( empty( $user_is_banned ) && bp_is_action_variable( 'delete', 2 ) && !bp_action_variable( 3 ) ) {
+			// Fetch the topic
+			$topic = bp_forums_get_topic_details( $topic_id );
+
+			/* Check the logged in user can delete this topic */
+			if ( ! bp_is_item_admin() && ! bp_is_item_mod() && ( (int) bp_loggedin_user_id() != (int) $topic->topic_poster ) ) {
+				bp_core_redirect( wp_get_referer() );
+			}
+
+			// Check the nonce
+			check_admin_referer( 'bp_forums_delete_topic' );
+
+			do_action( 'groups_before_delete_forum_topic', $topic_id );
+
+			if ( !groups_delete_group_forum_topic( $topic_id ) ) {
+				bp_core_add_message( __( 'There was an error deleting the topic', 'buddypress' ), 'error' );
+			} else {
+				bp_core_add_message( __( 'The topic was deleted successfully', 'buddypress' ) );
+			}
+
+			do_action( 'groups_delete_forum_topic', $topic_id );
+			bp_core_redirect( bp_get_group_permalink( groups_get_current_group() ) . 'forum/' );
+		}
+
+		// Editing a topic
+		else if ( empty( $user_is_banned ) && bp_is_action_variable( 'edit', 2 ) && !bp_action_variable( 3 ) ) {
+			// Fetch the topic
+			$topic = bp_forums_get_topic_details( $topic_id );
+
+			// Check the logged in user can edit this topic
+			if ( ! bp_is_item_admin() && ! bp_is_item_mod() && ( (int) bp_loggedin_user_id() != (int) $topic->topic_poster ) ) {
+				bp_core_redirect( wp_get_referer() );
+			}
+
+			if ( isset( $_POST['save_changes'] ) ) {
+				// Check the nonce
+				check_admin_referer( 'bp_forums_edit_topic' );
+
+				$topic_tags = !empty( $_POST['topic_tags'] ) ? $_POST['topic_tags'] : false;
+
+				if ( !groups_update_group_forum_topic( $topic_id, $_POST['topic_title'], $_POST['topic_text'], $topic_tags ) ) {
+					bp_core_add_message( __( 'There was an error when editing that topic', 'buddypress'), 'error' );
+				} else {
+					bp_core_add_message( __( 'The topic was edited successfully', 'buddypress') );
+				}
+
+				do_action( 'groups_edit_forum_topic', $topic_id );
+				bp_core_redirect( bp_get_group_permalink( groups_get_current_group() ) . 'forum/topic/' . $topic_slug . '/' );
+			}
+
+			bp_core_load_template( apply_filters( 'groups_template_group_forum_topic_edit', 'groups/single/home' ) );
+
+		// Delete a post
+		} else if ( empty( $user_is_banned ) && bp_is_action_variable( 'delete', 2 ) && $post_id = bp_action_variable( 4 ) ) {
+			// Fetch the post
+			$post = bp_forums_get_post( $post_id );
+
+			// Check the logged in user can edit this topic
+			if ( ! bp_is_item_admin() && ! bp_is_item_mod() && ( (int) bp_loggedin_user_id() != (int) $post->poster_id ) ) {
+				bp_core_redirect( wp_get_referer() );
+			}
+
+			// Check the nonce
+			check_admin_referer( 'bp_forums_delete_post' );
+
+			do_action( 'groups_before_delete_forum_post', $post_id );
+
+			if ( !groups_delete_group_forum_post( $post_id ) ) {
+				bp_core_add_message( __( 'There was an error deleting that post', 'buddypress'), 'error' );
+			} else {
+				bp_core_add_message( __( 'The post was deleted successfully', 'buddypress') );
+			}
+
+			do_action( 'groups_delete_forum_post', $post_id );
+			bp_core_redirect( wp_get_referer() );
+
+		// Editing a post
+		} else if ( empty( $user_is_banned ) && bp_is_action_variable( 'edit', 2 ) && $post_id = bp_action_variable( 4 ) ) {
+
+			// Fetch the post
+			$post = bp_forums_get_post( $post_id );
+
+			// Check the logged in user can edit this topic
+			if ( ! bp_is_item_admin() && ! bp_is_item_mod() && ( (int) bp_loggedin_user_id() != (int) $post->poster_id ) ) {
+				bp_core_redirect( wp_get_referer() );
+			}
+
+			if ( isset( $_POST['save_changes'] ) ) {
+				// Check the nonce
+				check_admin_referer( 'bp_forums_edit_post' );
+
+				$topic_page = isset( $_GET['topic_page'] ) ? $_GET['topic_page'] : false;
+
+				if ( !$post_id = groups_update_group_forum_post( $post_id, $_POST['post_text'], $topic_id, $topic_page ) ) {
+					bp_core_add_message( __( 'There was an error when editing that post', 'buddypress'), 'error' );
+				} else {
+					bp_core_add_message( __( 'The post was edited successfully', 'buddypress') );
+				}
+
+				if ( $_SERVER['QUERY_STRING'] ) {
+					$query_vars = '?' . $_SERVER['QUERY_STRING'];
+				}
+
+				do_action( 'groups_edit_forum_post', $post_id );
+				bp_core_redirect( bp_get_group_permalink( $bp->groups->current_group ) . 'forum/topic/' . $topic_slug . '/' . $query_vars . '#post-' . $post_id );
+			}
+
+			bp_core_load_template( apply_filters( 'groups_template_group_forum_topic_edit', 'groups/single/home' ) );
+
+		// Standard topic display
+		} else {
+			if ( !empty( $user_is_banned ) ) {
+				bp_core_add_message( __( "You have been banned from this group.", 'buddypress' ) );
+			}
+
+			bp_core_load_template( apply_filters( 'groups_template_group_forum_topic', 'groups/single/home' ) );
+		}
+
+	// Forum topic does not exist
+	} elseif ( !empty( $topic_slug ) && empty( $topic_id ) ) {
+		bp_do_404();
+		return;
+
+	} else {
+		// Posting a topic
+		if ( isset( $_POST['submit_topic'] ) && bp_is_active( 'forums' ) ) {
+
+			// Check the nonce
+			check_admin_referer( 'bp_forums_new_topic' );
+
+			if ( $user_is_banned ) {
+				$error_message = __( "You have been banned from this group.", 'buddypress' );
+
+			} elseif ( bp_groups_auto_join() && !bp_current_user_can( 'bp_moderate' ) && 'public' == $bp->groups->current_group->status && !groups_is_user_member( bp_loggedin_user_id(), $bp->groups->current_group->id ) ) {
+				// Auto join this user if they are not yet a member of this group
+				groups_join_group( $bp->groups->current_group->id, bp_loggedin_user_id() );
+			}
+
+			if ( empty( $_POST['topic_title'] ) ) {
+				$error_message = __( 'Please provide a title for your forum topic.', 'buddypress' );
+			} else if ( empty( $_POST['topic_text'] ) ) {
+				$error_message = __( 'Forum posts cannot be empty. Please enter some text.', 'buddypress' );
+			}
+
+			if ( empty( $forum_id ) ) {
+				$error_message = __( 'This group does not have a forum setup yet.', 'buddypress' );
+			}
+
+			if ( isset( $error_message ) ) {
+				bp_core_add_message( $error_message, 'error' );
+				$redirect = bp_get_group_permalink( $bp->groups->current_group ) . 'forum';
+			} else {
+				if ( !$topic = groups_new_group_forum_topic( $_POST['topic_title'], $_POST['topic_text'], $_POST['topic_tags'], $forum_id ) ) {
+					bp_core_add_message( __( 'There was an error when creating the topic', 'buddypress'), 'error' );
+					$redirect = bp_get_group_permalink( $bp->groups->current_group ) . 'forum';
+				} else {
+					bp_core_add_message( __( 'The topic was created successfully', 'buddypress') );
+					$redirect = bp_get_group_permalink( $bp->groups->current_group ) . 'forum/topic/' . $topic->topic_slug . '/';
+				}
+			}
+
+			bp_core_redirect( $redirect );
+		}
+
+		do_action( 'groups_screen_group_forum', $topic_id, $forum_id );
+
+		bp_core_load_template( apply_filters( 'groups_template_group_forum', 'groups/single/home' ) );
+	}
+}
+
+function groups_screen_group_members() {
+
+	if ( !bp_is_single_item() )
+		return false;
+
+	$bp = buddypress();
+
+	// Refresh the group member count meta
+	groups_update_groupmeta( $bp->groups->current_group->id, 'total_member_count', groups_get_total_member_count( $bp->groups->current_group->id ) );
+
+	do_action( 'groups_screen_group_members', $bp->groups->current_group->id );
+	bp_core_load_template( apply_filters( 'groups_template_group_members', 'groups/single/home' ) );
+}
+
+function groups_screen_group_invite() {
+
+	if ( !bp_is_single_item() )
+		return false;
+
+	$bp = buddypress();
+
+	if ( bp_is_action_variable( 'send', 0 ) ) {
+
+		if ( !check_admin_referer( 'groups_send_invites', '_wpnonce_send_invites' ) )
+			return false;
+
+		if ( !empty( $_POST['friends'] ) ) {
+			foreach( (array) $_POST['friends'] as $friend ) {
+				groups_invite_user( array( 'user_id' => $friend, 'group_id' => $bp->groups->current_group->id ) );
+			}
+		}
+
+		// Send the invites.
+		groups_send_invites( bp_loggedin_user_id(), $bp->groups->current_group->id );
+		bp_core_add_message( __('Group invites sent.', 'buddypress') );
+		do_action( 'groups_screen_group_invite', $bp->groups->current_group->id );
+		bp_core_redirect( bp_get_group_permalink( $bp->groups->current_group ) );
+
+	} elseif ( !bp_action_variable( 0 ) ) {
+		// Show send invite page
+		bp_core_load_template( apply_filters( 'groups_template_group_invite', 'groups/single/home' ) );
+
+	} else {
+		bp_do_404();
+	}
+}
+
+function groups_screen_group_request_membership() {
+	global $bp;
+
+	if ( !is_user_logged_in() )
+		return false;
+
+	$bp = buddypress();
+
+	if ( 'private' != $bp->groups->current_group->status )
+		return false;
+
+	// If the user is already invited, accept invitation
+	if ( groups_check_user_has_invite( bp_loggedin_user_id(), $bp->groups->current_group->id ) ) {
+		if ( groups_accept_invite( bp_loggedin_user_id(), $bp->groups->current_group->id ) )
+			bp_core_add_message( __( 'Group invite accepted', 'buddypress' ) );
+		else
+			bp_core_add_message( __( 'There was an error accepting the group invitation, please try again.', 'buddypress' ), 'error' );
+		bp_core_redirect( bp_get_group_permalink( $bp->groups->current_group ) );
+	}
+
+	// If the user has submitted a request, send it.
+	if ( isset( $_POST['group-request-send']) ) {
+
+		// Check the nonce
+		if ( !check_admin_referer( 'groups_request_membership' ) )
+			return false;
+
+		if ( !groups_send_membership_request( bp_loggedin_user_id(), $bp->groups->current_group->id ) ) {
+			bp_core_add_message( __( 'There was an error sending your group membership request, please try again.', 'buddypress' ), 'error' );
+		} else {
+			bp_core_add_message( __( 'Your membership request was sent to the group administrator successfully. You will be notified when the group administrator responds to your request.', 'buddypress' ) );
+		}
+		bp_core_redirect( bp_get_group_permalink( $bp->groups->current_group ) );
+	}
+
+	do_action( 'groups_screen_group_request_membership', $bp->groups->current_group->id );
+
+	bp_core_load_template( apply_filters( 'groups_template_group_request_membership', 'groups/single/home' ) );
+}
+
+function groups_screen_group_activity_permalink() {
+
+	if ( !bp_is_groups_component() || !bp_is_active( 'activity' ) || ( bp_is_active( 'activity' ) && !bp_is_current_action( bp_get_activity_slug() ) ) || !bp_action_variable( 0 ) )
+		return false;
+
+	buddypress()->is_single_item = true;
+
+	bp_core_load_template( apply_filters( 'groups_template_group_home', 'groups/single/home' ) );
+}
+add_action( 'bp_screens', 'groups_screen_group_activity_permalink' );
+
+function groups_screen_group_admin() {
+	if ( !bp_is_groups_component() || !bp_is_current_action( 'admin' ) )
+		return false;
+
+	if ( bp_action_variables() )
+		return false;
+
+	bp_core_redirect( bp_get_group_permalink( groups_get_current_group() ) . 'admin/edit-details/' );
+}
+
+function groups_screen_group_admin_edit_details() {
+
+	if ( 'edit-details' != bp_get_group_current_admin_tab() )
+		return false;
+
+	if ( bp_is_item_admin() ) {
+
+		$bp = buddypress();
+
+		// If the edit form has been submitted, save the edited details
+		if ( isset( $_POST['save'] ) ) {
+			// Check the nonce
+			if ( !check_admin_referer( 'groups_edit_group_details' ) )
+				return false;
+
+			$group_notify_members = isset( $_POST['group-notify-members'] ) ? (int) $_POST['group-notify-members'] : 0;
+
+			if ( !groups_edit_base_group_details( $_POST['group-id'], $_POST['group-name'], $_POST['group-desc'], $group_notify_members ) ) {
+				bp_core_add_message( __( 'There was an error updating group details, please try again.', 'buddypress' ), 'error' );
+			} else {
+				bp_core_add_message( __( 'Group details were successfully updated.', 'buddypress' ) );
+			}
+
+			do_action( 'groups_group_details_edited', $bp->groups->current_group->id );
+
+			bp_core_redirect( bp_get_group_permalink( groups_get_current_group() ) . 'admin/edit-details/' );
+		}
+
+		do_action( 'groups_screen_group_admin_edit_details', $bp->groups->current_group->id );
+
+		bp_core_load_template( apply_filters( 'groups_template_group_admin', 'groups/single/home' ) );
+	}
+}
+add_action( 'bp_screens', 'groups_screen_group_admin_edit_details' );
+
+function groups_screen_group_admin_settings() {
+
+	if ( 'group-settings' != bp_get_group_current_admin_tab() )
+		return false;
+
+	if ( ! bp_is_item_admin() )
+		return false;
+
+	$bp = buddypress();
+
+	// If the edit form has been submitted, save the edited details
+	if ( isset( $_POST['save'] ) ) {
+		$enable_forum   = ( isset($_POST['group-show-forum'] ) ) ? 1 : 0;
+
+		// Checked against a whitelist for security
+		$allowed_status = apply_filters( 'groups_allowed_status', array( 'public', 'private', 'hidden' ) );
+		$status         = ( in_array( $_POST['group-status'], (array) $allowed_status ) ) ? $_POST['group-status'] : 'public';
+
+		// Checked against a whitelist for security
+		$allowed_invite_status = apply_filters( 'groups_allowed_invite_status', array( 'members', 'mods', 'admins' ) );
+		$invite_status	       = isset( $_POST['group-invite-status'] ) && in_array( $_POST['group-invite-status'], (array) $allowed_invite_status ) ? $_POST['group-invite-status'] : 'members';
+
+		// Check the nonce
+		if ( !check_admin_referer( 'groups_edit_group_settings' ) )
+			return false;
+
+		if ( !groups_edit_group_settings( $_POST['group-id'], $enable_forum, $status, $invite_status ) ) {
+			bp_core_add_message( __( 'There was an error updating group settings, please try again.', 'buddypress' ), 'error' );
+		} else {
+			bp_core_add_message( __( 'Group settings were successfully updated.', 'buddypress' ) );
+		}
+
+		do_action( 'groups_group_settings_edited', $bp->groups->current_group->id );
+
+		bp_core_redirect( bp_get_group_permalink( groups_get_current_group() ) . 'admin/group-settings/' );
+	}
+
+	do_action( 'groups_screen_group_admin_settings', $bp->groups->current_group->id );
+
+	bp_core_load_template( apply_filters( 'groups_template_group_admin_settings', 'groups/single/home' ) );
+}
+add_action( 'bp_screens', 'groups_screen_group_admin_settings' );
+
+function groups_screen_group_admin_avatar() {
+
+	if ( 'group-avatar' != bp_get_group_current_admin_tab() )
+		return false;
+
+	// If the logged-in user doesn't have permission or if avatar uploads are disabled, then stop here
+	if ( ! bp_is_item_admin() || (int) bp_get_option( 'bp-disable-avatar-uploads' ) )
+		return false;
+
+	$bp = buddypress();
+
+	// If the group admin has deleted the admin avatar
+	if ( bp_is_action_variable( 'delete', 1 ) ) {
+
+		// Check the nonce
+		check_admin_referer( 'bp_group_avatar_delete' );
+
+		if ( bp_core_delete_existing_avatar( array( 'item_id' => $bp->groups->current_group->id, 'object' => 'group' ) ) ) {
+			bp_core_add_message( __( 'Your avatar was deleted successfully!', 'buddypress' ) );
+		} else {
+			bp_core_add_message( __( 'There was a problem deleting that avatar, please try again.', 'buddypress' ), 'error' );
+		}
+	}
+
+	if ( ! isset( $bp->avatar_admin ) ) {
+		$bp->avatar_admin = new stdClass();
+	}
+
+	$bp->avatar_admin->step = 'upload-image';
+
+	if ( !empty( $_FILES ) ) {
+
+		// Check the nonce
+		check_admin_referer( 'bp_avatar_upload' );
+
+		// Pass the file to the avatar upload handler
+		if ( bp_core_avatar_handle_upload( $_FILES, 'groups_avatar_upload_dir' ) ) {
+			$bp->avatar_admin->step = 'crop-image';
+
+			// Make sure we include the jQuery jCrop file for image cropping
+			add_action( 'wp_print_scripts', 'bp_core_add_jquery_cropper' );
+		}
+
+	}
+
+	// If the image cropping is done, crop the image and save a full/thumb version
+	if ( isset( $_POST['avatar-crop-submit'] ) ) {
+
+		// Check the nonce
+		check_admin_referer( 'bp_avatar_cropstore' );
+
+		$args = array(
+			'object'        => 'group',
+			'avatar_dir'    => 'group-avatars',
+			'item_id'       => $bp->groups->current_group->id,
+			'original_file' => $_POST['image_src'],
+			'crop_x'        => $_POST['x'],
+			'crop_y'        => $_POST['y'],
+			'crop_w'        => $_POST['w'],
+			'crop_h'        => $_POST['h']
+		);
+
+		if ( !bp_core_avatar_handle_crop( $args ) ) {
+			bp_core_add_message( __( 'There was a problem cropping the avatar.', '       buddypress' ), 'error' );
+		} else {
+			bp_core_add_message( __( 'The new group avatar was uploaded successfully.', 'buddypress' )          );
+		}
+	}
+
+	do_action( 'groups_screen_group_admin_avatar', $bp->groups->current_group->id );
+
+	bp_core_load_template( apply_filters( 'groups_template_group_admin_avatar', 'groups/single/home' ) );
+}
+add_action( 'bp_screens', 'groups_screen_group_admin_avatar' );
+
+/**
+ * This function handles actions related to member management on the group admin.
+ *
+ * @package BuddyPress
+ */
+function groups_screen_group_admin_manage_members() {
+
+	if ( 'manage-members' != bp_get_group_current_admin_tab() )
+		return false;
+
+	if ( ! bp_is_item_admin() )
+		return false;
+
+	$bp = buddypress();
+
+	if ( bp_action_variable( 1 ) && bp_action_variable( 2 ) && bp_action_variable( 3 ) ) {
+		if ( bp_is_action_variable( 'promote', 1 ) && ( bp_is_action_variable( 'mod', 2 ) || bp_is_action_variable( 'admin', 2 ) ) && is_numeric( bp_action_variable( 3 ) ) ) {
+			$user_id = bp_action_variable( 3 );
+			$status  = bp_action_variable( 2 );
+
+			// Check the nonce first.
+			if ( !check_admin_referer( 'groups_promote_member' ) )
+				return false;
+
+			// Promote a user.
+			if ( !groups_promote_member( $user_id, $bp->groups->current_group->id, $status ) )
+				bp_core_add_message( __( 'There was an error when promoting that user, please try again', 'buddypress' ), 'error' );
+			else
+				bp_core_add_message( __( 'User promoted successfully', 'buddypress' ) );
+
+			do_action( 'groups_promoted_member', $user_id, $bp->groups->current_group->id );
+
+			bp_core_redirect( bp_get_group_permalink( groups_get_current_group() ) . 'admin/manage-members/' );
+		}
+	}
+
+	if ( bp_action_variable( 1 ) && bp_action_variable( 2 ) ) {
+		if ( bp_is_action_variable( 'demote', 1 ) && is_numeric( bp_action_variable( 2 ) ) ) {
+			$user_id = bp_action_variable( 2 );
+
+			// Check the nonce first.
+			if ( !check_admin_referer( 'groups_demote_member' ) )
+				return false;
+
+			// Stop sole admins from abandoning their group
+			$group_admins = groups_get_group_admins( $bp->groups->current_group->id );
+			if ( 1 == count( $group_admins ) && $group_admins[0]->user_id == $user_id )
+				bp_core_add_message( __( 'This group must have at least one admin', 'buddypress' ), 'error' );
+
+			// Demote a user.
+			elseif ( !groups_demote_member( $user_id, $bp->groups->current_group->id ) )
+				bp_core_add_message( __( 'There was an error when demoting that user, please try again', 'buddypress' ), 'error' );
+			else
+				bp_core_add_message( __( 'User demoted successfully', 'buddypress' ) );
+
+			do_action( 'groups_demoted_member', $user_id, $bp->groups->current_group->id );
+
+			bp_core_redirect( bp_get_group_permalink( groups_get_current_group() ) . 'admin/manage-members/' );
+		}
+
+		if ( bp_is_action_variable( 'ban', 1 ) && is_numeric( bp_action_variable( 2 ) ) ) {
+			$user_id = bp_action_variable( 2 );
+
+			// Check the nonce first.
+			if ( !check_admin_referer( 'groups_ban_member' ) )
+				return false;
+
+			// Ban a user.
+			if ( !groups_ban_member( $user_id, $bp->groups->current_group->id ) )
+				bp_core_add_message( __( 'There was an error when banning that user, please try again', 'buddypress' ), 'error' );
+			else
+				bp_core_add_message( __( 'User banned successfully', 'buddypress' ) );
+
+			do_action( 'groups_banned_member', $user_id, $bp->groups->current_group->id );
+
+			bp_core_redirect( bp_get_group_permalink( groups_get_current_group() ) . 'admin/manage-members/' );
+		}
+
+		if ( bp_is_action_variable( 'unban', 1 ) && is_numeric( bp_action_variable( 2 ) ) ) {
+			$user_id = bp_action_variable( 2 );
+
+			// Check the nonce first.
+			if ( !check_admin_referer( 'groups_unban_member' ) )
+				return false;
+
+			// Remove a ban for user.
+			if ( !groups_unban_member( $user_id, $bp->groups->current_group->id ) )
+				bp_core_add_message( __( 'There was an error when unbanning that user, please try again', 'buddypress' ), 'error' );
+			else
+				bp_core_add_message( __( 'User ban removed successfully', 'buddypress' ) );
+
+			do_action( 'groups_unbanned_member', $user_id, $bp->groups->current_group->id );
+
+			bp_core_redirect( bp_get_group_permalink( groups_get_current_group() ) . 'admin/manage-members/' );
+		}
+
+		if ( bp_is_action_variable( 'remove', 1 ) && is_numeric( bp_action_variable( 2 ) ) ) {
+			$user_id = bp_action_variable( 2 );
+
+			// Check the nonce first.
+			if ( !check_admin_referer( 'groups_remove_member' ) )
+				return false;
+
+			// Remove a user.
+			if ( !groups_remove_member( $user_id, $bp->groups->current_group->id ) )
+				bp_core_add_message( __( 'There was an error removing that user from the group, please try again', 'buddypress' ), 'error' );
+			else
+				bp_core_add_message( __( 'User removed successfully', 'buddypress' ) );
+
+			do_action( 'groups_removed_member', $user_id, $bp->groups->current_group->id );
+
+			bp_core_redirect( bp_get_group_permalink( groups_get_current_group() ) . 'admin/manage-members/' );
+		}
+	}
+
+	do_action( 'groups_screen_group_admin_manage_members', $bp->groups->current_group->id );
+
+	bp_core_load_template( apply_filters( 'groups_template_group_admin_manage_members', 'groups/single/home' ) );
+}
+add_action( 'bp_screens', 'groups_screen_group_admin_manage_members' );
+
+function groups_screen_group_admin_requests() {
+	$bp = buddypress();
+
+	if ( 'membership-requests' != bp_get_group_current_admin_tab() ) {
+		return false;
+	}
+
+	if ( ! bp_is_item_admin() || ( 'public' == $bp->groups->current_group->status ) ) {
+		return false;
+	}
+
+	$request_action = (string) bp_action_variable( 1 );
+	$membership_id  = (int) bp_action_variable( 2 );
+
+	if ( !empty( $request_action ) && !empty( $membership_id ) ) {
+		if ( 'accept' == $request_action && is_numeric( $membership_id ) ) {
+
+			// Check the nonce first.
+			if ( !check_admin_referer( 'groups_accept_membership_request' ) )
+				return false;
+
+			// Accept the membership request
+			if ( !groups_accept_membership_request( $membership_id ) )
+				bp_core_add_message( __( 'There was an error accepting the membership request, please try again.', 'buddypress' ), 'error' );
+			else
+				bp_core_add_message( __( 'Group membership request accepted', 'buddypress' ) );
+
+		} elseif ( 'reject' == $request_action && is_numeric( $membership_id ) ) {
+			/* Check the nonce first. */
+			if ( !check_admin_referer( 'groups_reject_membership_request' ) )
+				return false;
+
+			// Reject the membership request
+			if ( !groups_reject_membership_request( $membership_id ) )
+				bp_core_add_message( __( 'There was an error rejecting the membership request, please try again.', 'buddypress' ), 'error' );
+			else
+				bp_core_add_message( __( 'Group membership request rejected', 'buddypress' ) );
+		}
+
+		do_action( 'groups_group_request_managed', $bp->groups->current_group->id, $request_action, $membership_id );
+		bp_core_redirect( bp_get_group_permalink( groups_get_current_group() ) . 'admin/membership-requests/' );
+	}
+
+	do_action( 'groups_screen_group_admin_requests', $bp->groups->current_group->id );
+	bp_core_load_template( apply_filters( 'groups_template_group_admin_requests', 'groups/single/home' ) );
+}
+add_action( 'bp_screens', 'groups_screen_group_admin_requests' );
+
+function groups_screen_group_admin_delete_group() {
+	global $bp;
+
+	if ( 'delete-group' != bp_get_group_current_admin_tab() )
+		return false;
+
+	if ( ! bp_is_item_admin() && !bp_current_user_can( 'bp_moderate' ) )
+		return false;
+
+	if ( isset( $_REQUEST['delete-group-button'] ) && isset( $_REQUEST['delete-group-understand'] ) ) {
+
+		// Check the nonce first.
+		if ( !check_admin_referer( 'groups_delete_group' ) ) {
+			return false;
+		}
+
+		do_action( 'groups_before_group_deleted', $bp->groups->current_group->id );
+
+		// Group admin has deleted the group, now do it.
+		if ( !groups_delete_group( $bp->groups->current_group->id ) ) {
+			bp_core_add_message( __( 'There was an error deleting the group, please try again.', 'buddypress' ), 'error' );
+		} else {
+			bp_core_add_message( __( 'The group was deleted successfully', 'buddypress' ) );
+
+			do_action( 'groups_group_deleted', $bp->groups->current_group->id );
+
+			bp_core_redirect( trailingslashit( bp_loggedin_user_domain() . bp_get_groups_slug() ) );
+		}
+
+		bp_core_redirect( trailingslashit( bp_loggedin_user_domain() . bp_get_groups_slug() ) );
+	}
+
+	do_action( 'groups_screen_group_admin_delete_group', $bp->groups->current_group->id );
+
+	bp_core_load_template( apply_filters( 'groups_template_group_admin_delete_group', 'groups/single/home' ) );
+}
+add_action( 'bp_screens', 'groups_screen_group_admin_delete_group' );
+
+/**
+ * Renders the group settings fields on the Notification Settings page
+ *
+ * @package BuddyPress
+ */
+function groups_screen_notification_settings() {
+
+	if ( !$group_invite = bp_get_user_meta( bp_displayed_user_id(), 'notification_groups_invite', true ) )
+		$group_invite  = 'yes';
+
+	if ( !$group_update = bp_get_user_meta( bp_displayed_user_id(), 'notification_groups_group_updated', true ) )
+		$group_update  = 'yes';
+
+	if ( !$group_promo = bp_get_user_meta( bp_displayed_user_id(), 'notification_groups_admin_promotion', true ) )
+		$group_promo   = 'yes';
+
+	if ( !$group_request = bp_get_user_meta( bp_displayed_user_id(), 'notification_groups_membership_request', true ) )
+		$group_request = 'yes'; ?>
+
+	<table class="notification-settings" id="groups-notification-settings">
+		<thead>
+			<tr>
+				<th class="icon"></th>
+				<th class="title"><?php _e( 'Groups', 'buddypress' ) ?></th>
+				<th class="yes"><?php _e( 'Yes', 'buddypress' ) ?></th>
+				<th class="no"><?php _e( 'No', 'buddypress' )?></th>
+			</tr>
+		</thead>
+
+		<tbody>
+			<tr id="groups-notification-settings-invitation">
+				<td></td>
+				<td><?php _e( 'A member invites you to join a group', 'buddypress' ) ?></td>
+				<td class="yes"><input type="radio" name="notifications[notification_groups_invite]" value="yes" <?php checked( $group_invite, 'yes', true ) ?>/></td>
+				<td class="no"><input type="radio" name="notifications[notification_groups_invite]" value="no" <?php checked( $group_invite, 'no', true ) ?>/></td>
+			</tr>
+			<tr id="groups-notification-settings-info-updated">
+				<td></td>
+				<td><?php _e( 'Group information is updated', 'buddypress' ) ?></td>
+				<td class="yes"><input type="radio" name="notifications[notification_groups_group_updated]" value="yes" <?php checked( $group_update, 'yes', true ) ?>/></td>
+				<td class="no"><input type="radio" name="notifications[notification_groups_group_updated]" value="no" <?php checked( $group_update, 'no', true ) ?>/></td>
+			</tr>
+			<tr id="groups-notification-settings-promoted">
+				<td></td>
+				<td><?php _e( 'You are promoted to a group administrator or moderator', 'buddypress' ) ?></td>
+				<td class="yes"><input type="radio" name="notifications[notification_groups_admin_promotion]" value="yes" <?php checked( $group_promo, 'yes', true ) ?>/></td>
+				<td class="no"><input type="radio" name="notifications[notification_groups_admin_promotion]" value="no" <?php checked( $group_promo, 'no', true ) ?>/></td>
+			</tr>
+			<tr id="groups-notification-settings-request">
+				<td></td>
+				<td><?php _e( 'A member requests to join a private group for which you are an admin', 'buddypress' ) ?></td>
+				<td class="yes"><input type="radio" name="notifications[notification_groups_membership_request]" value="yes" <?php checked( $group_request, 'yes', true ) ?>/></td>
+				<td class="no"><input type="radio" name="notifications[notification_groups_membership_request]" value="no" <?php checked( $group_request, 'no', true ) ?>/></td>
+			</tr>
+
+			<?php do_action( 'groups_screen_notification_settings' ); ?>
+
+		</tbody>
+	</table>
+
+<?php
+}
+add_action( 'bp_notification_settings', 'groups_screen_notification_settings' );
+
+/** Theme Compatability *******************************************************/
+
+/**
+ * The main theme compat class for BuddyPress Groups
+ *
+ * This class sets up the necessary theme compatability actions to safely output
+ * group template parts to the_title and the_content areas of a theme.
+ *
+ * @since BuddyPress (1.7)
+ */
+class BP_Groups_Theme_Compat {
+
+	/**
+	 * Setup the groups component theme compatibility
+	 *
+	 * @since BuddyPress (1.7)
+	 */
+	public function __construct() {
+		add_action( 'bp_setup_theme_compat', array( $this, 'is_group' ) );
+	}
+
+	/**
+	 * Are we looking at something that needs group theme compatability?
+	 *
+	 * @since BuddyPress (1.7)
+	 */
+	public function is_group() {
+
+		// Bail if not looking at a group
+		if ( ! bp_is_groups_component() )
+			return;
+
+		// Group Directory
+		if ( ! bp_current_action() && ! bp_current_item() ) {
+			bp_update_is_directory( true, 'groups' );
+
+			do_action( 'groups_directory_groups_setup' );
+
+			add_filter( 'bp_get_buddypress_template',                array( $this, 'directory_template_hierarchy' ) );
+			add_action( 'bp_template_include_reset_dummy_post_data', array( $this, 'directory_dummy_post' ) );
+			add_filter( 'bp_replace_the_content',                    array( $this, 'directory_content'    ) );
+
+		// Creating a group
+		} elseif ( bp_is_groups_component() && bp_is_current_action( 'create' ) ) {
+			add_filter( 'bp_get_buddypress_template',                array( $this, 'create_template_hierarchy' ) );
+			add_action( 'bp_template_include_reset_dummy_post_data', array( $this, 'create_dummy_post' ) );
+			add_filter( 'bp_replace_the_content',                    array( $this, 'create_content'    ) );
+
+		// Group page
+		} elseif ( bp_is_single_item() ) {
+			add_filter( 'bp_get_buddypress_template',                array( $this, 'single_template_hierarchy' ) );
+			add_action( 'bp_template_include_reset_dummy_post_data', array( $this, 'single_dummy_post' ) );
+			add_filter( 'bp_replace_the_content',                    array( $this, 'single_content'    ) );
+
+		}
+	}
+
+	/** Directory *************************************************************/
+
+	/**
+	 * Add template hierarchy to theme compat for the group directory page.
+	 *
+	 * This is to mirror how WordPress has {@link https://codex.wordpress.org/Template_Hierarchy template hierarchy}.
+	 *
+	 * @since BuddyPress (1.8)
+	 *
+	 * @param string $templates The templates from bp_get_theme_compat_templates()
+	 * @return array $templates Array of custom templates to look for.
+	 */
+	public function directory_template_hierarchy( $templates ) {
+		// Setup our templates based on priority
+		$new_templates = apply_filters( 'bp_template_hierarchy_groups_directory', array(
+			'groups/index-directory.php'
+		) );
+
+		// Merge new templates with existing stack
+		// @see bp_get_theme_compat_templates()
+		$templates = array_merge( (array) $new_templates, $templates );
+
+		return $templates;
+	}
+
+	/**
+	 * Update the global $post with directory data
+	 *
+	 * @since BuddyPress (1.7)
+	 */
+	public function directory_dummy_post() {
+
+		// Title based on ability to create groups
+		if ( is_user_logged_in() && bp_user_can_create_groups() ) {
+			$title = __( 'Groups', 'buddypress' ) . '&nbsp;<a class="button bp-title-button" href="' . trailingslashit( bp_get_root_domain() . '/' . bp_get_groups_root_slug() . '/create' ) . '">' . __( 'Create a Group', 'buddypress' ) . '</a>';
+		} else {
+			$title = __( 'Groups', 'buddypress' );
+		}
+
+		bp_theme_compat_reset_post( array(
+			'ID'             => 0,
+			'post_title'     => $title,
+			'post_author'    => 0,
+			'post_date'      => 0,
+			'post_content'   => '',
+			'post_type'      => 'bp_group',
+			'post_status'    => 'publish',
+			'is_archive'     => true,
+			'comment_status' => 'closed'
+		) );
+	}
+
+	/**
+	 * Filter the_content with the groups index template part
+	 *
+	 * @since BuddyPress (1.7)
+	 */
+	public function directory_content() {
+		return bp_buffer_template_part( 'groups/index', null, false );
+	}
+
+	/** Create ****************************************************************/
+
+	/**
+	 * Add custom template hierarchy to theme compat for the group create page.
+	 *
+	 * This is to mirror how WordPress has {@link https://codex.wordpress.org/Template_Hierarchy template hierarchy}.
+	 *
+	 * @since BuddyPress (1.8)
+	 *
+	 * @param string $templates The templates from bp_get_theme_compat_templates()
+	 * @return array $templates Array of custom templates to look for.
+	 */
+	public function create_template_hierarchy( $templates ) {
+		// Setup our templates based on priority
+		$new_templates = apply_filters( 'bp_template_hierarchy_groups_create', array(
+			'groups/index-create.php'
+		) );
+
+		// Merge new templates with existing stack
+		// @see bp_get_theme_compat_templates()
+		$templates = array_merge( $new_templates, $templates );
+
+		return $templates;
+	}
+
+	/**
+	 * Update the global $post with create screen data
+	 *
+	 * @since BuddyPress (1.7)
+	 */
+	public function create_dummy_post() {
+
+		// Title based on ability to create groups
+		if ( is_user_logged_in() && bp_user_can_create_groups() ) {
+			$title = '<a class="button" href="' . trailingslashit( bp_get_root_domain() . '/' . bp_get_groups_root_slug() ) . '">' . __( 'Groups', 'buddypress' ) . '</a>&nbsp;' . __( 'Create a Group', 'buddypress' );
+		} else {
+			$title = __( 'Groups', 'buddypress' );
+		}
+
+		bp_theme_compat_reset_post( array(
+			'ID'             => 0,
+			'post_title'     => $title,
+			'post_author'    => 0,
+			'post_date'      => 0,
+			'post_content'   => '',
+			'post_type'      => 'bp_group',
+			'post_status'    => 'publish',
+			'is_archive'     => true,
+			'comment_status' => 'closed'
+		) );
+	}
+
+	/**
+	 * Filter the_content with the create screen template part
+	 *
+	 * @since BuddyPress (1.7)
+	 */
+	public function create_content() {
+		return bp_buffer_template_part( 'groups/create', null, false );
+	}
+
+	/** Single ****************************************************************/
+
+	/**
+	 * Add custom template hierarchy to theme compat for group pages. 
+	 *
+	 * This is to mirror how WordPress has {@link https://codex.wordpress.org/Template_Hierarchy template hierarchy}.
+	 *
+	 * @since BuddyPress (1.8)
+	 *
+	 * @param string $templates The templates from bp_get_theme_compat_templates()
+	 * @return array $templates Array of custom templates to look for.
+	 */
+	public function single_template_hierarchy( $templates ) {
+		// Setup some variables we're going to reference in our custom templates
+		$group = groups_get_current_group();
+
+		// Setup our templates based on priority
+		$new_templates = apply_filters( 'bp_template_hierarchy_groups_single_item', array(
+			'groups/single/index-id-'     . sanitize_file_name( bp_get_current_group_id() )   . '.php',
+			'groups/single/index-slug-'   . sanitize_file_name( bp_get_current_group_slug() ) . '.php',
+			'groups/single/index-action-' . sanitize_file_name( bp_current_action() )         . '.php',
+			'groups/single/index-status-' . sanitize_file_name( $group->status )              . '.php',
+			'groups/single/index.php'
+		) );
+
+		// Merge new templates with existing stack
+		// @see bp_get_theme_compat_templates()
+		$templates = array_merge( (array) $new_templates, $templates );
+
+		return $templates;
+	}
+
+	/**
+	 * Update the global $post with single group data
+	 *
+	 * @since BuddyPress (1.7)
+	 */
+	public function single_dummy_post() {
+		bp_theme_compat_reset_post( array(
+			'ID'             => 0,
+			'post_title'     => '<a href="' . bp_get_group_permalink( groups_get_current_group() ) . '">' . bp_get_current_group_name() . '</a>',
+			'post_author'    => 0,
+			'post_date'      => 0,
+			'post_content'   => '',
+			'post_type'      => 'bp_group',
+			'post_status'    => 'publish',
+			'is_archive'     => true,
+			'comment_status' => 'closed'
+		) );
+	}
+
+	/**
+	 * Filter the_content with the single group template part
+	 *
+	 * @since BuddyPress (1.7)
+	 */
+	public function single_content() {
+		return bp_buffer_template_part( 'groups/single/home', null, false );
+	}
+}
+new BP_Groups_Theme_Compat();
Index: /tags/1.9/bp-groups/bp-groups-template.php
===================================================================
--- /tags/1.9/bp-groups/bp-groups-template.php	(revision 7684)
+++ /tags/1.9/bp-groups/bp-groups-template.php	(revision 7684)
@@ -0,0 +1,3137 @@
+<?php
+
+/**
+ * BuddyPress Groups Template Functions
+ *
+ * @package BuddyPress
+ * @subpackage GroupsTemplate
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/**
+ * Output the groups component slug
+ *
+ * @package BuddyPress
+ * @subpackage Groups Template
+ * @since BuddyPress (1.5)
+ *
+ * @uses bp_get_groups_slug()
+ */
+function bp_groups_slug() {
+	echo bp_get_groups_slug();
+}
+	/**
+	 * Return the groups component slug
+	 *
+	 * @package BuddyPress
+	 * @subpackage Groups Template
+	 * @since BuddyPress (1.5)
+	 */
+	function bp_get_groups_slug() {
+		global $bp;
+		return apply_filters( 'bp_get_groups_slug', $bp->groups->slug );
+	}
+
+/**
+ * Output the groups component root slug
+ *
+ * @package BuddyPress
+ * @subpackage Groups Template
+ * @since BuddyPress (1.5)
+ *
+ * @uses bp_get_groups_root_slug()
+ */
+function bp_groups_root_slug() {
+	echo bp_get_groups_root_slug();
+}
+	/**
+	 * Return the groups component root slug
+	 *
+	 * @package BuddyPress
+	 * @subpackage Groups Template
+	 * @since BuddyPress (1.5)
+	 */
+	function bp_get_groups_root_slug() {
+		global $bp;
+		return apply_filters( 'bp_get_groups_root_slug', $bp->groups->root_slug );
+	}
+
+/**
+ * Output group directory permalink
+ *
+ * @package BuddyPress
+ * @subpackage Groups Template
+ * @since BuddyPress (1.5)
+ * @uses bp_get_groups_directory_permalink()
+ */
+function bp_groups_directory_permalink() {
+	echo bp_get_groups_directory_permalink();
+}
+	/**
+	 * Return group directory permalink
+	 *
+	 * @package BuddyPress
+	 * @subpackage Groups Template
+	 * @since BuddyPress (1.5)
+	 * @uses apply_filters()
+	 * @uses traisingslashit()
+	 * @uses bp_get_root_domain()
+	 * @uses bp_get_groups_root_slug()
+	 * @return string
+	 */
+	function bp_get_groups_directory_permalink() {
+		return apply_filters( 'bp_get_groups_directory_permalink', trailingslashit( bp_get_root_domain() . '/' . bp_get_groups_root_slug() ) );
+	}
+
+/*****************************************************************************
+ * Groups Template Class/Tags
+ **/
+
+class BP_Groups_Template {
+	var $current_group = -1;
+	var $group_count;
+	var $groups;
+	var $group;
+
+	var $in_the_loop;
+
+	var $pag_page;
+	var $pag_num;
+	var $pag_links;
+	var $total_group_count;
+
+	var $single_group = false;
+
+	var $sort_by;
+	var $order;
+
+	function __construct( $args = array() ){
+
+		// Backward compatibility with old method of passing arguments
+		if ( ! is_array( $args ) || func_num_args() > 1 ) {
+			_deprecated_argument( __METHOD__, '1.7', sprintf( __( 'Arguments passed to %1$s should be in an associative array. See the inline documentation at %2$s for more details.', 'buddypress' ), __METHOD__, __FILE__ ) );
+
+			$old_args_keys = array(
+				0  => 'user_id',
+				1  => 'type',
+				2  => 'page',
+				3  => 'per_page',
+				4  => 'max',
+				5  => 'slug',
+				6  => 'search_terms',
+				7  => 'populate_extras',
+				8  => 'include',
+				9  => 'exclude',
+				10 => 'show_hidden',
+				11 => 'page_arg',
+			);
+
+			$func_args = func_get_args();
+			$args      = bp_core_parse_args_array( $old_args_keys, $func_args );
+		}
+
+		$defaults = array(
+			'type'            => 'active',
+			'page'            => 1,
+			'per_page'        => 20,
+			'max'             => false,
+			'show_hidden'     => false,
+			'page_arg'        => 'grpage',
+			'user_id'         => 0,
+			'slug'            => false,
+			'include'         => false,
+			'exclude'         => false,
+			'search_terms'    => '',
+			'meta_query'      => false,
+			'populate_extras' => true
+		);
+
+		$r = wp_parse_args( $args, $defaults );
+		extract( $r );
+
+		$this->pag_page = isset( $_REQUEST[$page_arg] ) ? intval( $_REQUEST[$page_arg] ) : $page;
+		$this->pag_num  = isset( $_REQUEST['num'] ) ? intval( $_REQUEST['num'] ) : $per_page;
+
+		if ( bp_current_user_can( 'bp_moderate' ) || ( is_user_logged_in() && $user_id == bp_loggedin_user_id() ) )
+			$show_hidden = true;
+
+		if ( 'invites' == $type ) {
+			$this->groups = groups_get_invites_for_user( $user_id, $this->pag_num, $this->pag_page, $exclude );
+		} else if ( 'single-group' == $type ) {
+			$group           = new stdClass;
+			$group->group_id = BP_Groups_Group::get_id_from_slug( $slug );
+			$this->groups    = array( $group );
+		} else {
+			$this->groups = groups_get_groups( array(
+				'type'            => $type,
+				'order'           => $order,
+				'orderby'         => $orderby,
+				'per_page'        => $this->pag_num,
+				'page'            => $this->pag_page,
+				'user_id'         => $user_id,
+				'search_terms'    => $search_terms,
+				'meta_query'      => $meta_query,
+				'include'         => $include,
+				'exclude'         => $exclude,
+				'populate_extras' => $populate_extras,
+				'show_hidden'     => $show_hidden
+			) );
+		}
+
+		if ( 'invites' == $type ) {
+			$this->total_group_count = (int) $this->groups['total'];
+			$this->group_count       = (int) $this->groups['total'];
+			$this->groups            = $this->groups['groups'];
+		} else if ( 'single-group' == $type ) {
+			$this->single_group      = true;
+			$this->total_group_count = 1;
+			$this->group_count       = 1;
+		} else {
+			if ( empty( $max ) || $max >= (int) $this->groups['total'] ) {
+				$this->total_group_count = (int) $this->groups['total'];
+			} else {
+				$this->total_group_count = (int) $max;
+			}
+
+			$this->groups = $this->groups['groups'];
+
+			if ( !empty( $max ) ) {
+				if ( $max >= count( $this->groups ) ) {
+					$this->group_count = count( $this->groups );
+				} else {
+					$this->group_count = (int) $max;
+				}
+			} else {
+				$this->group_count = count( $this->groups );
+			}
+		}
+
+		// Build pagination links
+		if ( (int) $this->total_group_count && (int) $this->pag_num ) {
+			$this->pag_links = paginate_links( array(
+				'base'      => add_query_arg( array( $page_arg => '%#%', 'num' => $this->pag_num, 's' => $search_terms, 'sortby' => $this->sort_by, 'order' => $this->order ) ),
+				'format'    => '',
+				'total'     => ceil( (int) $this->total_group_count / (int) $this->pag_num ),
+				'current'   => $this->pag_page,
+				'prev_text' => _x( '&larr;', 'Group pagination previous text', 'buddypress' ),
+				'next_text' => _x( '&rarr;', 'Group pagination next text', 'buddypress' ),
+				'mid_size'  => 1
+			) );
+		}
+	}
+
+	function has_groups() {
+		if ( $this->group_count )
+			return true;
+
+		return false;
+	}
+
+	function next_group() {
+		$this->current_group++;
+		$this->group = $this->groups[$this->current_group];
+
+		return $this->group;
+	}
+
+	function rewind_groups() {
+		$this->current_group = -1;
+		if ( $this->group_count > 0 ) {
+			$this->group = $this->groups[0];
+		}
+	}
+
+	function groups() {
+		if ( $this->current_group + 1 < $this->group_count ) {
+			return true;
+		} elseif ( $this->current_group + 1 == $this->group_count ) {
+			do_action('group_loop_end');
+			// Do some cleaning up after the loop
+			$this->rewind_groups();
+		}
+
+		$this->in_the_loop = false;
+		return false;
+	}
+
+	function the_group() {
+		$this->in_the_loop = true;
+		$this->group       = $this->next_group();
+
+		if ( $this->single_group )
+			$this->group = groups_get_group( array( 'group_id' => $this->group->group_id ) );
+
+		if ( 0 == $this->current_group ) // loop has just started
+			do_action('group_loop_start');
+	}
+}
+
+/**
+ * Start the Groups Template Loop
+ *
+ * See the $defaults definition below for a description of parameters.
+ *
+ * Note that the 'type' parameter overrides 'order' and 'orderby'. See
+ * BP_Groups_Group::get() for more details.
+ *
+ * @param array $args
+ * @return bool True if there are groups to display that match the params
+ */
+function bp_has_groups( $args = '' ) {
+	global $groups_template, $bp;
+
+	/***
+	 * Set the defaults based on the current page. Any of these will be overridden
+	 * if arguments are directly passed into the loop. Custom plugins should always
+	 * pass their parameters directly to the loop.
+	 */
+	$slug    = false;
+	$type    = '';
+	$user_id = 0;
+	$order   = '';
+
+	// User filtering
+	if ( bp_displayed_user_id() )
+		$user_id = bp_displayed_user_id();
+
+	// Type
+	// @todo What is $order? At some point it was removed incompletely?
+	if ( bp_is_current_action( 'my-groups' ) ) {
+		if ( 'most-popular' == $order ) {
+			$type = 'popular';
+		} elseif ( 'alphabetically' == $order ) {
+			$type = 'alphabetical';
+		}
+	} elseif ( bp_is_current_action( 'invites' ) ) {
+		$type = 'invites';
+	} elseif ( isset( $bp->groups->current_group->slug ) && $bp->groups->current_group->slug ) {
+		$type = 'single-group';
+		$slug = $bp->groups->current_group->slug;
+	}
+
+	$defaults = array(
+		'type'            => $type, // 'type' is an override for 'order' and 'orderby'. See docblock.
+		'order'           => 'DESC',
+		'orderby'         => 'last_activity',
+		'page'            => 1,
+		'per_page'        => 20,
+		'max'             => false,
+		'show_hidden'     => false,
+
+		'page_arg'        => 'grpage', // See https://buddypress.trac.wordpress.org/ticket/3679
+
+		'user_id'         => $user_id, // Pass a user ID to limit to groups this user has joined
+		'slug'            => $slug,    // Pass a group slug to only return that group
+		'search_terms'    => '',       // Pass search terms to return only matching groups
+		'meta_query'      => false,    // Filter by groupmeta. See WP_Meta_Query for format
+		'include'         => false,    // Pass comma separated list or array of group ID's to return only these groups
+		'exclude'         => false,    // Pass comma separated list or array of group ID's to exclude these groups
+
+		'populate_extras' => true,     // Get extra meta - is_member, is_banned
+	);
+
+	$r = wp_parse_args( $args, $defaults );
+
+	if ( empty( $r['search_terms'] ) ) {
+		if ( isset( $_REQUEST['group-filter-box'] ) && !empty( $_REQUEST['group-filter-box'] ) )
+			$r['search_terms'] = $_REQUEST['group-filter-box'];
+		elseif ( isset( $_REQUEST['s'] ) && !empty( $_REQUEST['s'] ) )
+			$r['search_terms'] = $_REQUEST['s'];
+		else
+			$r['search_terms'] = false;
+	}
+
+	$groups_template = new BP_Groups_Template( array(
+		'type'            => $r['type'],
+		'order'           => $r['order'],
+		'orderby'         => $r['orderby'],
+		'page'            => (int) $r['page'],
+		'per_page'        => (int) $r['per_page'],
+		'max'             => (int) $r['max'],
+		'show_hidden'     => $r['show_hidden'],
+		'page_arg'        => $r['page_arg'],
+		'user_id'         => (int) $r['user_id'],
+		'slug'            => $r['slug'],
+		'search_terms'    => $r['search_terms'],
+		'meta_query'      => $r['meta_query'],
+		'include'         => $r['include'],
+		'exclude'         => $r['exclude'],
+		'populate_extras' => (bool) $r['populate_extras']
+	) );
+
+	return apply_filters( 'bp_has_groups', $groups_template->has_groups(), $groups_template, $r );
+}
+
+function bp_groups() {
+	global $groups_template;
+	return $groups_template->groups();
+}
+
+function bp_the_group() {
+	global $groups_template;
+	return $groups_template->the_group();
+}
+
+function bp_group_is_visible( $group = false ) {
+	global $groups_template;
+
+	if ( bp_current_user_can( 'bp_moderate' ) )
+		return true;
+
+	if ( empty( $group ) )
+		$group =& $groups_template->group;
+
+	if ( 'public' == $group->status ) {
+		return true;
+	} else {
+		if ( groups_is_user_member( bp_loggedin_user_id(), $group->id ) ) {
+			return true;
+		}
+	}
+
+	return false;
+}
+
+function bp_group_id( $group = false ) {
+	echo bp_get_group_id( $group );
+}
+	function bp_get_group_id( $group = false ) {
+		global $groups_template;
+
+		if ( empty( $group ) )
+			$group =& $groups_template->group;
+
+		return apply_filters( 'bp_get_group_id', $group->id );
+	}
+
+/**
+ * Output the row class of a group
+ *
+ * @since BuddyPress (1.7)
+ */
+function bp_group_class() {
+	echo bp_get_group_class();
+}
+	/**
+	 * Return the row class of a group
+	 *
+	 * @global BP_Groups_Template $groups_template
+	 * @return string Row class of the group
+	 * @since BuddyPress (1.7)
+	 */
+	function bp_get_group_class() {
+		global $groups_template;
+
+		$classes      = array();
+		$pos_in_loop  = (int) $groups_template->current_group;
+
+		// If we've only one group in the loop, don't both with odd and even.
+		if ( $groups_template->group_count > 1 )
+			$classes[] = ( $pos_in_loop % 2 ) ? 'even' : 'odd';
+		else
+			$classes[] = 'bp-single-group';
+
+		// Group type - public, private, hidden.
+		$classes[] = esc_attr( $groups_template->group->status );
+
+		// User's group status
+		if ( bp_is_user_active() ) {
+			if ( bp_group_is_admin() )
+				$classes[] = 'is-admin';
+
+			if ( bp_group_is_member() )
+				$classes[] = 'is-member';
+
+			if ( bp_group_is_mod() )
+				$classes[] = 'is-mod';
+		}
+
+		$classes = apply_filters( 'bp_get_group_class', $classes );
+		$classes = array_merge( $classes, array() );
+		$retval = 'class="' . join( ' ', $classes ) . '"';
+
+		return $retval;
+	}
+
+function bp_group_name( $group = false ) {
+	echo bp_get_group_name( $group );
+}
+	function bp_get_group_name( $group = false ) {
+		global $groups_template;
+
+		if ( empty( $group ) )
+			$group =& $groups_template->group;
+
+		return apply_filters( 'bp_get_group_name', $group->name );
+	}
+
+function bp_group_type( $group = false ) {
+	echo bp_get_group_type( $group );
+}
+	function bp_get_group_type( $group = false ) {
+		global $groups_template;
+
+		if ( empty( $group ) )
+			$group =& $groups_template->group;
+
+		if ( 'public' == $group->status ) {
+			$type = __( "Public Group", "buddypress" );
+		} else if ( 'hidden' == $group->status ) {
+			$type = __( "Hidden Group", "buddypress" );
+		} else if ( 'private' == $group->status ) {
+			$type = __( "Private Group", "buddypress" );
+		} else {
+			$type = ucwords( $group->status ) . ' ' . __( 'Group', 'buddypress' );
+		}
+
+		return apply_filters( 'bp_get_group_type', $type );
+	}
+
+function bp_group_status( $group = false ) {
+	echo bp_get_group_status( $group );
+}
+	function bp_get_group_status( $group = false ) {
+		global $groups_template;
+
+		if ( empty( $group ) )
+			$group =& $groups_template->group;
+
+		return apply_filters( 'bp_get_group_status', $group->status );
+	}
+
+function bp_group_avatar( $args = '' ) {
+	echo bp_get_group_avatar( $args );
+}
+	function bp_get_group_avatar( $args = '' ) {
+		global $bp, $groups_template;
+
+		$defaults = array(
+			'type'   => 'full',
+			'width'  => false,
+			'height' => false,
+			'class'  => 'avatar',
+			'id'     => false,
+			'alt'    => sprintf( __( 'Group logo of %s', 'buddypress' ), $groups_template->group->name )
+		);
+
+		$r = wp_parse_args( $args, $defaults );
+		extract( $r, EXTR_SKIP );
+
+		/* Fetch the avatar from the folder, if not provide backwards compat. */
+		if ( !$avatar = bp_core_fetch_avatar( array( 'item_id' => $groups_template->group->id, 'object' => 'group', 'type' => $type, 'avatar_dir' => 'group-avatars', 'alt' => $alt, 'css_id' => $id, 'class' => $class, 'width' => $width, 'height' => $height, 'title' => $groups_template->group->name, 'alt' => $alt ) ) )
+			$avatar = '<img src="' . esc_url( $groups_template->group->avatar_thumb ) . '" class="avatar" alt="' . esc_attr( $groups_template->group->name ) . '" />';
+
+		return apply_filters( 'bp_get_group_avatar', $avatar );
+	}
+
+function bp_group_avatar_thumb( $group = false ) {
+	echo bp_get_group_avatar_thumb( $group );
+}
+	function bp_get_group_avatar_thumb( $group = false ) {
+		return bp_get_group_avatar( 'type=thumb' );
+	}
+
+function bp_group_avatar_mini( $group = false ) {
+	echo bp_get_group_avatar_mini( $group );
+}
+	function bp_get_group_avatar_mini( $group = false ) {
+		return bp_get_group_avatar( 'type=thumb&width=30&height=30' );
+	}
+
+function bp_group_last_active( $group = false ) {
+	echo bp_get_group_last_active( $group );
+}
+	function bp_get_group_last_active( $group = false ) {
+		global $groups_template;
+
+		if ( empty( $group ) )
+			$group =& $groups_template->group;
+
+		$last_active = $group->last_activity;
+
+		if ( !$last_active )
+			$last_active = groups_get_groupmeta( $group->id, 'last_activity' );
+
+		if ( empty( $last_active ) ) {
+			return __( 'not yet active', 'buddypress' );
+		} else {
+			return apply_filters( 'bp_get_group_last_active', bp_core_time_since( $last_active ) );
+		}
+	}
+
+function bp_group_permalink( $group = false ) {
+	echo bp_get_group_permalink( $group );
+}
+	function bp_get_group_permalink( $group = false ) {
+		global $groups_template;
+
+		if ( empty( $group ) )
+			$group =& $groups_template->group;
+
+		return apply_filters( 'bp_get_group_permalink', trailingslashit( bp_get_root_domain() . '/' . bp_get_groups_root_slug() . '/' . $group->slug . '/' ) );
+	}
+
+function bp_group_admin_permalink( $group = false ) {
+	echo bp_get_group_admin_permalink( $group );
+}
+	function bp_get_group_admin_permalink( $group = false ) {
+		global $groups_template;
+
+		if ( empty( $group ) )
+			$group =& $groups_template->group;
+
+		return apply_filters( 'bp_get_group_admin_permalink', trailingslashit( bp_get_group_permalink( $group ) . 'admin' ) );
+	}
+
+function bp_group_slug( $group = false ) {
+	echo bp_get_group_slug( $group );
+}
+	function bp_get_group_slug( $group = false ) {
+		global $groups_template;
+
+		if ( empty( $group ) )
+			$group =& $groups_template->group;
+
+		return apply_filters( 'bp_get_group_slug', $group->slug );
+	}
+
+function bp_group_description( $group = false ) {
+	echo bp_get_group_description( $group );
+}
+	function bp_get_group_description( $group = false ) {
+		global $groups_template;
+
+		if ( empty( $group ) )
+			$group =& $groups_template->group;
+
+		return apply_filters( 'bp_get_group_description', stripslashes($group->description) );
+	}
+
+function bp_group_description_editable( $group = false ) {
+	echo bp_get_group_description_editable( $group );
+}
+	function bp_get_group_description_editable( $group = false ) {
+		global $groups_template;
+
+		if ( empty( $group ) )
+			$group =& $groups_template->group;
+
+		return apply_filters( 'bp_get_group_description_editable', $group->description );
+	}
+
+function bp_group_description_excerpt( $group = false ) {
+	echo bp_get_group_description_excerpt( $group );
+}
+	function bp_get_group_description_excerpt( $group = false ) {
+		global $groups_template;
+
+		if ( empty( $group ) )
+			$group =& $groups_template->group;
+
+		return apply_filters( 'bp_get_group_description_excerpt', bp_create_excerpt( $group->description ) );
+	}
+
+
+function bp_group_public_status( $group = false ) {
+	echo bp_get_group_public_status( $group );
+}
+	function bp_get_group_public_status( $group = false ) {
+		global $groups_template;
+
+		if ( empty( $group ) )
+			$group =& $groups_template->group;
+
+		if ( $group->is_public ) {
+			return __( 'Public', 'buddypress' );
+		} else {
+			return __( 'Private', 'buddypress' );
+		}
+	}
+
+function bp_group_is_public( $group = false ) {
+	echo bp_get_group_is_public( $group );
+}
+	function bp_get_group_is_public( $group = false ) {
+		global $groups_template;
+
+		if ( empty( $group ) )
+			$group =& $groups_template->group;
+
+		return apply_filters( 'bp_get_group_is_public', $group->is_public );
+	}
+
+function bp_group_date_created( $group = false ) {
+	echo bp_get_group_date_created( $group );
+}
+	function bp_get_group_date_created( $group = false ) {
+		global $groups_template;
+
+		if ( empty( $group ) )
+			$group =& $groups_template->group;
+
+		return apply_filters( 'bp_get_group_date_created', bp_core_time_since( strtotime( $group->date_created ) ) );
+	}
+
+function bp_group_creator_username( $group = false ) {
+	echo bp_get_group_creator_username( $group );
+}
+	function bp_get_group_creator_username( $group = false ) {
+		global $groups_template;
+
+		if ( empty( $group ) )
+			$group =& $groups_template->group;
+
+		return apply_filters( 'bp_get_group_creator_username', bp_core_get_user_displayname( $group->creator_id ) );
+	}
+
+function bp_group_creator_id( $group = false ) {
+	echo bp_get_group_creator_id( $group );
+}
+	function bp_get_group_creator_id( $group = false ) {
+		global $groups_template;
+
+		if ( empty( $group ) )
+			$group =& $groups_template->group;
+
+		return apply_filters( 'bp_get_group_creator_id', $group->creator_id );
+	}
+
+function bp_group_creator_permalink( $group = false ) {
+	echo bp_get_group_creator_permalink( $group );
+}
+	function bp_get_group_creator_permalink( $group = false ) {
+		global $groups_template;
+
+		if ( empty( $group ) )
+			$group =& $groups_template->group;
+
+		return apply_filters( 'bp_get_group_creator_permalink', bp_core_get_user_domain( $group->creator_id ) );
+	}
+
+function bp_is_group_creator( $group = false, $user_id = 0 ) {
+	global $groups_template;
+
+	if ( empty( $group ) )
+		$group =& $groups_template->group;
+
+	if ( empty( $user_id ) )
+		$user_id = bp_loggedin_user_id();
+
+	return (bool) ( $group->creator_id == $user_id );
+}
+
+function bp_group_creator_avatar( $group = false, $args = array() ) {
+	echo bp_get_group_creator_avatar( $group, $args );
+}
+	function bp_get_group_creator_avatar( $group = false, $args = array() ) {
+		global $groups_template;
+
+		if ( empty( $group ) )
+			$group =& $groups_template->group;
+
+		$defaults = array(
+			'type'   => 'full',
+			'width'  => false,
+			'height' => false,
+			'class'  => 'avatar',
+			'id'     => false,
+			'alt'    => sprintf( __( 'Group creator avatar of %s', 'buddypress' ),  bp_core_get_user_displayname( $group->creator_id ) )
+		);
+
+		$r = wp_parse_args( $args, $defaults );
+		extract( $r, EXTR_SKIP );
+
+		$avatar = bp_core_fetch_avatar( array( 'item_id' => $group->creator_id, 'type' => $type, 'css_id' => $id, 'class' => $class, 'width' => $width, 'height' => $height, 'alt' => $alt ) );
+
+		return apply_filters( 'bp_get_group_creator_avatar', $avatar );
+	}
+
+
+function bp_group_is_admin() {
+	return bp_is_item_admin();
+}
+
+function bp_group_is_mod() {
+	return bp_is_item_mod();
+}
+
+function bp_group_list_admins( $group = false ) {
+	global $groups_template;
+
+	if ( empty( $group ) )
+		$group =& $groups_template->group;
+
+	if ( !empty( $group->admins ) ) { ?>
+		<ul id="group-admins">
+			<?php foreach( (array) $group->admins as $admin ) { ?>
+				<li>
+					<a href="<?php echo bp_core_get_user_domain( $admin->user_id, $admin->user_nicename, $admin->user_login ) ?>"><?php echo bp_core_fetch_avatar( array( 'item_id' => $admin->user_id, 'email' => $admin->user_email, 'alt' => sprintf( __( 'Profile picture of %s', 'buddypress' ), bp_core_get_user_displayname( $admin->user_id ) ) ) ) ?></a>
+				</li>
+			<?php } ?>
+		</ul>
+	<?php } else { ?>
+		<span class="activity"><?php _e( 'No Admins', 'buddypress' ) ?></span>
+	<?php } ?>
+<?php
+}
+
+function bp_group_list_mods( $group = false ) {
+	global $groups_template;
+
+	if ( empty( $group ) )
+		$group =& $groups_template->group;
+
+	if ( !empty( $group->mods ) ) : ?>
+
+		<ul id="group-mods">
+
+			<?php foreach( (array) $group->mods as $mod ) { ?>
+
+				<li>
+					<a href="<?php echo bp_core_get_user_domain( $mod->user_id, $mod->user_nicename, $mod->user_login ) ?>"><?php echo bp_core_fetch_avatar( array( 'item_id' => $mod->user_id, 'email' => $mod->user_email, 'alt' => sprintf( __( 'Profile picture of %s', 'buddypress' ), bp_core_get_user_displayname( $mod->user_id ) ) ) ) ?></a>
+				</li>
+
+			<?php } ?>
+
+		</ul>
+
+<?php else : ?>
+
+		<span class="activity"><?php _e( 'No Mods', 'buddypress' ) ?></span>
+
+<?php endif;
+
+}
+
+/**
+ * Return a list of user_ids for a group's admins
+ *
+ * @package BuddyPress
+ * @since BuddyPress (1.5)
+ *
+ * @param BP_Groups_Group $group (optional) The group being queried. Defaults to the current group in the loop
+ * @param string $format 'string' to get a comma-separated string, 'array' to get an array
+ * @return mixed $admin_ids A string or array of user_ids
+ */
+function bp_group_admin_ids( $group = false, $format = 'string' ) {
+	global $groups_template;
+
+	if ( empty( $group ) )
+		$group =& $groups_template->group;
+
+	$admin_ids = array();
+
+	if ( $group->admins ) {
+		foreach( $group->admins as $admin ) {
+			$admin_ids[] = $admin->user_id;
+		}
+	}
+
+	if ( 'string' == $format )
+		$admin_ids = implode( ',', $admin_ids );
+
+	return apply_filters( 'bp_group_admin_ids', $admin_ids );
+}
+
+/**
+ * Return a list of user_ids for a group's moderators
+ *
+ * @package BuddyPress
+ * @since BuddyPress (1.5)
+ *
+ * @param BP_Groups_Group $group (optional) The group being queried. Defaults to the current group in the loop
+ * @param string $format 'string' to get a comma-separated string, 'array' to get an array
+ * @return mixed $mod_ids A string or array of user_ids
+ */
+function bp_group_mod_ids( $group = false, $format = 'string' ) {
+	global $groups_template;
+
+	if ( empty( $group ) )
+		$group =& $groups_template->group;
+
+	$mod_ids = array();
+
+	if ( $group->mods ) {
+		foreach( $group->mods as $mod ) {
+			$mod_ids[] = $mod->user_id;
+		}
+	}
+
+	if ( 'string' == $format )
+		$mod_ids = implode( ',', $mod_ids );
+
+	return apply_filters( 'bp_group_mod_ids', $mod_ids );
+}
+
+function bp_group_all_members_permalink() {
+	echo bp_get_group_all_members_permalink();
+}
+	function bp_get_group_all_members_permalink( $group = false ) {
+		global $groups_template;
+
+		if ( empty( $group ) )
+			$group =& $groups_template->group;
+
+		return apply_filters( 'bp_get_group_all_members_permalink', bp_get_group_permalink( $group ) . 'members' );
+	}
+
+function bp_group_search_form() {
+	global $bp;
+
+	$action = bp_displayed_user_domain() . bp_get_groups_slug() . '/my-groups/search/';
+	$label = __('Filter Groups', 'buddypress');
+	$name = 'group-filter-box';
+
+	$search_form_html = '<form action="' . $action . '" id="group-search-form" method="post">
+		<label for="'. $name .'" id="'. $name .'-label">'. $label .'</label>
+		<input type="search" name="'. $name . '" id="'. $name .'" value="'. $value .'"'.  $disabled .' />
+
+		'. wp_nonce_field( 'group-filter-box', '_wpnonce_group_filter', true, false ) .'
+		</form>';
+
+	echo apply_filters( 'bp_group_search_form', $search_form_html );
+}
+
+function bp_group_show_no_groups_message() {
+	if ( !groups_total_groups_for_user( bp_displayed_user_id() ) )
+		return true;
+
+	return false;
+}
+
+function bp_group_is_activity_permalink() {
+
+	if ( !bp_is_single_item() || !bp_is_groups_component() || !bp_is_current_action( bp_get_activity_slug() ) )
+		return false;
+
+	return true;
+}
+
+function bp_groups_pagination_links() {
+	echo bp_get_groups_pagination_links();
+}
+	function bp_get_groups_pagination_links() {
+		global $groups_template;
+
+		return apply_filters( 'bp_get_groups_pagination_links', $groups_template->pag_links );
+	}
+
+function bp_groups_pagination_count() {
+	echo bp_get_groups_pagination_count();
+}
+	function bp_get_groups_pagination_count() {
+		global $groups_template;
+
+		$start_num = intval( ( $groups_template->pag_page - 1 ) * $groups_template->pag_num ) + 1;
+		$from_num  = bp_core_number_format( $start_num );
+		$to_num    = bp_core_number_format( ( $start_num + ( $groups_template->pag_num - 1 ) > $groups_template->total_group_count ) ? $groups_template->total_group_count : $start_num + ( $groups_template->pag_num - 1 ) );
+		$total     = bp_core_number_format( $groups_template->total_group_count );
+
+		return apply_filters( 'bp_get_groups_pagination_count', sprintf( _n( 'Viewing group %1$s to %2$s (of %3$s group)', 'Viewing group %1$s to %2$s (of %3$s groups)', $total, 'buddypress' ), $from_num, $to_num, $total ), $from_num, $to_num, $total );
+	}
+
+function bp_groups_auto_join() {
+	global $bp;
+
+	return apply_filters( 'bp_groups_auto_join', (bool)$bp->groups->auto_join );
+}
+
+function bp_group_total_members( $group = false ) {
+	echo bp_get_group_total_members( $group );
+}
+	function bp_get_group_total_members( $group = false ) {
+		global $groups_template;
+
+		if ( empty( $group ) )
+			$group =& $groups_template->group;
+
+		return apply_filters( 'bp_get_group_total_members', $group->total_member_count );
+	}
+
+function bp_group_member_count() {
+	echo bp_get_group_member_count();
+}
+	function bp_get_group_member_count() {
+		global $groups_template;
+
+		if ( 1 == (int) $groups_template->group->total_member_count )
+			return apply_filters( 'bp_get_group_member_count', sprintf( __( '%s member', 'buddypress' ), bp_core_number_format( $groups_template->group->total_member_count ) ) );
+		else
+			return apply_filters( 'bp_get_group_member_count', sprintf( __( '%s members', 'buddypress' ), bp_core_number_format( $groups_template->group->total_member_count ) ) );
+	}
+
+function bp_group_forum_permalink() {
+	echo bp_get_group_forum_permalink();
+}
+	function bp_get_group_forum_permalink( $group = false ) {
+		global $groups_template;
+
+		if ( empty( $group ) )
+			$group =& $groups_template->group;
+
+		return apply_filters( 'bp_get_group_forum_permalink', bp_get_group_permalink( $group ) . 'forum' );
+	}
+
+function bp_group_forum_topic_count( $args = '' ) {
+	echo bp_get_group_forum_topic_count( $args );
+}
+	function bp_get_group_forum_topic_count( $args = '' ) {
+		global $groups_template;
+
+		$defaults = array(
+			'showtext' => false
+		);
+
+		$r = wp_parse_args( $args, $defaults );
+		extract( $r, EXTR_SKIP );
+
+		if ( !$forum_id = groups_get_groupmeta( $groups_template->group->id, 'forum_id' ) )
+			return false;
+
+		if ( !bp_is_active( 'forums' ) )
+			return false;
+
+		if ( !$groups_template->group->forum_counts )
+			$groups_template->group->forum_counts = bp_forums_get_forum_topicpost_count( (int) $forum_id );
+
+		if ( (bool) $showtext ) {
+			if ( 1 == (int) $groups_template->group->forum_counts[0]->topics )
+				$total_topics = sprintf( __( '%d topic', 'buddypress' ), (int) $groups_template->group->forum_counts[0]->topics );
+			else
+				$total_topics = sprintf( __( '%d topics', 'buddypress' ), (int) $groups_template->group->forum_counts[0]->topics );
+		} else {
+			$total_topics = (int) $groups_template->group->forum_counts[0]->topics;
+		}
+
+		return apply_filters( 'bp_get_group_forum_topic_count', $total_topics, (bool)$showtext );
+	}
+
+function bp_group_forum_post_count( $args = '' ) {
+	echo bp_get_group_forum_post_count( $args );
+}
+	function bp_get_group_forum_post_count( $args = '' ) {
+		global $groups_template;
+
+		$defaults = array(
+			'showtext' => false
+		);
+
+		$r = wp_parse_args( $args, $defaults );
+		extract( $r, EXTR_SKIP );
+
+		if ( !$forum_id = groups_get_groupmeta( $groups_template->group->id, 'forum_id' ) )
+			return false;
+
+		if ( !bp_is_active( 'forums' ) )
+			return false;
+
+		if ( !$groups_template->group->forum_counts )
+			$groups_template->group->forum_counts = bp_forums_get_forum_topicpost_count( (int) $forum_id );
+
+		if ( (bool) $showtext ) {
+			if ( 1 == (int) $groups_template->group->forum_counts[0]->posts )
+				$total_posts = sprintf( __( '%d post', 'buddypress' ), (int) $groups_template->group->forum_counts[0]->posts );
+			else
+				$total_posts = sprintf( __( '%d posts', 'buddypress' ), (int) $groups_template->group->forum_counts[0]->posts );
+		} else {
+			$total_posts = (int) $groups_template->group->forum_counts[0]->posts;
+		}
+
+		return apply_filters( 'bp_get_group_forum_post_count', $total_posts, (bool)$showtext );
+	}
+
+function bp_group_is_forum_enabled( $group = false ) {
+	global $groups_template;
+
+	if ( empty( $group ) )
+		$group =& $groups_template->group;
+
+	if ( ! empty( $group->enable_forum ) )
+		return true;
+
+	return false;
+}
+
+function bp_group_show_forum_setting( $group = false ) {
+	global $groups_template;
+
+	if ( empty( $group ) )
+		$group =& $groups_template->group;
+
+	if ( $group->enable_forum )
+		echo ' checked="checked"';
+}
+
+function bp_group_show_status_setting( $setting, $group = false ) {
+	global $groups_template;
+
+	if ( empty( $group ) )
+		$group =& $groups_template->group;
+
+	if ( $setting == $group->status )
+		echo ' checked="checked"';
+}
+
+/**
+ * Get the 'checked' value, if needed, for a given invite_status on the group create/admin screens
+ *
+ * @package BuddyPress
+ * @subpackage Groups Template
+ * @since BuddyPress (1.5)
+ *
+ * @param string $setting The setting you want to check against ('members', 'mods', or 'admins')
+ * @param BP_Groups_Group $group (optional) The group whose status you want to check
+ */
+function bp_group_show_invite_status_setting( $setting, $group = false ) {
+	$group_id = isset( $group->id ) ? $group->id : false;
+
+	$invite_status = bp_group_get_invite_status( $group_id );
+
+	if ( $setting == $invite_status )
+		echo ' checked="checked"';
+}
+
+/**
+ * Get the invite status of a group
+ *
+ * 'invite_status' became part of BuddyPress in BP 1.5. In order to provide backward compatibility,
+ * groups without a status set will default to 'members', ie all members in a group can send
+ * invitations. Filter 'bp_group_invite_status_fallback' to change this fallback behavior.
+ *
+ * This function can be used either in or out of the loop.
+ *
+ * @package BuddyPress
+ * @subpackage Groups Template
+ * @since BuddyPress (1.5)
+ *
+ * @param int $group_id (optional) The id of the group whose status you want to check
+ * @return mixed Returns false when no group can be found. Otherwise returns the group invite
+ *    status, from among 'members', 'mods', and 'admins'
+ */
+function bp_group_get_invite_status( $group_id = false ) {
+	global $bp, $groups_template;
+
+	if ( !$group_id ) {
+		if ( isset( $bp->groups->current_group->id ) ) {
+			// Default to the current group first
+			$group_id = $bp->groups->current_group->id;
+		} else if ( isset( $groups_template->group->id ) ) {
+			// Then see if we're in the loop
+			$group_id = $groups_template->group->id;
+		} else {
+			return false;
+		}
+	}
+
+	$invite_status = groups_get_groupmeta( $group_id, 'invite_status' );
+
+	// Backward compatibility. When 'invite_status' is not set, fall back to a default value
+	if ( !$invite_status ) {
+		$invite_status = apply_filters( 'bp_group_invite_status_fallback', 'members' );
+	}
+
+	return apply_filters( 'bp_group_get_invite_status', $invite_status, $group_id );
+}
+
+/**
+ * Can the logged-in user send invitations in the specified group?
+ *
+ * @package BuddyPress
+ * @subpackage Groups Template
+ * @since BuddyPress (1.5)
+ *
+ * @param int $group_id (optional) The id of the group whose status you want to check
+ * @return bool $can_send_invites
+ */
+function bp_groups_user_can_send_invites( $group_id = false ) {
+	global $bp;
+
+	$can_send_invites = false;
+	$invite_status    = false;
+
+	if ( is_user_logged_in() ) {
+		if ( bp_current_user_can( 'bp_moderate' ) ) {
+			// Super admins can always send invitations
+			$can_send_invites = true;
+
+		} else {
+			// If no $group_id is provided, default to the current group id
+			if ( !$group_id )
+				$group_id = isset( $bp->groups->current_group->id ) ? $bp->groups->current_group->id : 0;
+
+			// If no group has been found, bail
+			if ( !$group_id )
+				return false;
+
+			$invite_status = bp_group_get_invite_status( $group_id );
+			if ( !$invite_status )
+				return false;
+
+			switch ( $invite_status ) {
+				case 'admins' :
+					if ( groups_is_user_admin( bp_loggedin_user_id(), $group_id ) )
+						$can_send_invites = true;
+					break;
+
+				case 'mods' :
+					if ( groups_is_user_mod( bp_loggedin_user_id(), $group_id ) || groups_is_user_admin( bp_loggedin_user_id(), $group_id ) )
+						$can_send_invites = true;
+					break;
+
+				case 'members' :
+					if ( groups_is_user_member( bp_loggedin_user_id(), $group_id ) )
+						$can_send_invites = true;
+					break;
+			}
+		}
+	}
+
+	return apply_filters( 'bp_groups_user_can_send_invites', $can_send_invites, $group_id, $invite_status );
+}
+
+/**
+ * Since BuddyPress 1.0, this generated the group settings admin/member screen.
+ * As of BuddyPress 1.5 (r4489), and because this function outputs HTML, it was moved into /bp-default/groups/single/admin.php.
+ *
+ * @deprecated 1.5
+ * @deprecated No longer used.
+ * @since BuddyPress (1.0)
+ * @todo Remove in 1.4
+ */
+function bp_group_admin_memberlist( $admin_list = false, $group = false ) {
+	global $groups_template;
+
+	_deprecated_function( __FUNCTION__, '1.5', 'No longer used. See /bp-default/groups/single/admin.php' );
+
+	if ( empty( $group ) )
+		$group =& $groups_template->group;
+
+
+	if ( $admins = groups_get_group_admins( $group->id ) ) : ?>
+
+		<ul id="admins-list" class="item-list<?php if ( !empty( $admin_list ) ) : ?> single-line<?php endif; ?>">
+
+		<?php foreach ( (array) $admins as $admin ) { ?>
+
+			<?php if ( !empty( $admin_list ) ) : ?>
+
+			<li>
+
+				<?php echo bp_core_fetch_avatar( array( 'item_id' => $admin->user_id, 'type' => 'thumb', 'width' => 30, 'height' => 30, 'alt' => sprintf( __( 'Profile picture of %s', 'buddypress' ), bp_core_get_user_displayname( $admin->user_id ) ) ) ) ?>
+
+				<h5>
+
+					<?php echo bp_core_get_userlink( $admin->user_id ); ?>
+
+					<span class="small">
+						<a class="button confirm admin-demote-to-member" href="<?php bp_group_member_demote_link($admin->user_id) ?>"><?php _e( 'Demote to Member', 'buddypress' ) ?></a>
+					</span>
+				</h5>
+			</li>
+
+			<?php else : ?>
+
+			<li>
+
+				<?php echo bp_core_fetch_avatar( array( 'item_id' => $admin->user_id, 'type' => 'thumb', 'alt' => sprintf( __( 'Profile picture of %s', 'buddypress' ), bp_core_get_user_displayname( $admin->user_id ) ) ) ) ?>
+
+				<h5><?php echo bp_core_get_userlink( $admin->user_id ) ?></h5>
+				<span class="activity">
+					<?php echo bp_core_get_last_activity( strtotime( $admin->date_modified ), __( 'joined %s', 'buddypress') ); ?>
+				</span>
+
+				<?php if ( bp_is_active( 'friends' ) ) : ?>
+
+					<div class="action">
+
+						<?php bp_add_friend_button( $admin->user_id ); ?>
+
+					</div>
+
+				<?php endif; ?>
+
+			</li>
+
+			<?php endif;
+		} ?>
+
+		</ul>
+
+	<?php else : ?>
+
+		<div id="message" class="info">
+			<p><?php _e( 'This group has no administrators', 'buddypress' ); ?></p>
+		</div>
+
+	<?php endif;
+}
+
+function bp_group_mod_memberlist( $admin_list = false, $group = false ) {
+	global $groups_template;
+
+	if ( empty( $group ) )
+		$group =& $groups_template->group;
+
+	if ( $group_mods = groups_get_group_mods( $group->id ) ) { ?>
+
+		<ul id="mods-list" class="item-list<?php if ( $admin_list ) { ?> single-line<?php } ?>">
+
+		<?php foreach ( (array) $group_mods as $mod ) { ?>
+
+			<?php if ( !empty( $admin_list ) ) { ?>
+
+			<li>
+
+				<?php echo bp_core_fetch_avatar( array( 'item_id' => $mod->user_id, 'type' => 'thumb', 'width' => 30, 'height' => 30, 'alt' => sprintf( __( 'Profile picture of %s', 'buddypress' ), bp_core_get_user_displayname( $mod->user_id ) ) ) ) ?>
+
+				<h5>
+					<?php echo bp_core_get_userlink( $mod->user_id ); ?>
+
+					<span class="small">
+						<a href="<?php bp_group_member_promote_admin_link( array( 'user_id' => $mod->user_id ) ) ?>" class="button confirm mod-promote-to-admin" title="<?php _e( 'Promote to Admin', 'buddypress' ); ?>"><?php _e( 'Promote to Admin', 'buddypress' ); ?></a>
+						<a class="button confirm mod-demote-to-member" href="<?php bp_group_member_demote_link($mod->user_id) ?>"><?php _e( 'Demote to Member', 'buddypress' ) ?></a>
+					</span>
+				</h5>
+			</li>
+
+			<?php } else { ?>
+
+			<li>
+
+				<?php echo bp_core_fetch_avatar( array( 'item_id' => $mod->user_id, 'type' => 'thumb', 'alt' => sprintf( __( 'Profile picture of %s', 'buddypress' ), bp_core_get_user_displayname( $mod->user_id ) ) ) ) ?>
+
+				<h5><?php echo bp_core_get_userlink( $mod->user_id ) ?></h5>
+
+				<span class="activity"><?php echo bp_core_get_last_activity( strtotime( $mod->date_modified ), __( 'joined %s', 'buddypress') ); ?></span>
+
+				<?php if ( bp_is_active( 'friends' ) ) : ?>
+
+					<div class="action">
+						<?php bp_add_friend_button( $mod->user_id ) ?>
+					</div>
+
+				<?php endif; ?>
+
+			</li>
+
+			<?php } ?>
+		<?php } ?>
+
+		</ul>
+
+	<?php } else { ?>
+
+		<div id="message" class="info">
+			<p><?php _e( 'This group has no moderators', 'buddypress' ); ?></p>
+		</div>
+
+	<?php }
+}
+
+function bp_group_has_moderators( $group = false ) {
+	global $groups_template;
+
+	if ( empty( $group ) )
+		$group =& $groups_template->group;
+
+	return apply_filters( 'bp_group_has_moderators', groups_get_group_mods( $group->id ) );
+}
+
+function bp_group_member_promote_mod_link( $args = '' ) {
+	echo bp_get_group_member_promote_mod_link( $args );
+}
+	function bp_get_group_member_promote_mod_link( $args = '' ) {
+		global $members_template, $groups_template;
+
+		$defaults = array(
+			'user_id' => $members_template->member->user_id,
+			'group'   => &$groups_template->group
+		);
+
+		$r = wp_parse_args( $args, $defaults );
+		extract( $r, EXTR_SKIP );
+
+		return apply_filters( 'bp_get_group_member_promote_mod_link', wp_nonce_url( bp_get_group_permalink( $group ) . 'admin/manage-members/promote/mod/' . $user_id, 'groups_promote_member' ) );
+	}
+
+function bp_group_member_promote_admin_link( $args = '' ) {
+	echo bp_get_group_member_promote_admin_link( $args );
+}
+	function bp_get_group_member_promote_admin_link( $args = '' ) {
+		global $members_template, $groups_template;
+
+		$defaults = array(
+			'user_id' => !empty( $members_template->member->user_id ) ? $members_template->member->user_id : false,
+			'group'   => &$groups_template->group
+		);
+
+		$r = wp_parse_args( $args, $defaults );
+		extract( $r, EXTR_SKIP );
+
+		return apply_filters( 'bp_get_group_member_promote_admin_link', wp_nonce_url( bp_get_group_permalink( $group ) . 'admin/manage-members/promote/admin/' . $user_id, 'groups_promote_member' ) );
+	}
+
+function bp_group_member_demote_link( $user_id = 0 ) {
+	global $members_template;
+
+	if ( !$user_id )
+		$user_id = $members_template->member->user_id;
+
+	echo bp_get_group_member_demote_link( $user_id );
+}
+	function bp_get_group_member_demote_link( $user_id = 0, $group = false ) {
+		global $members_template, $groups_template;
+
+		if ( empty( $group ) )
+			$group =& $groups_template->group;
+
+		if ( !$user_id )
+			$user_id = $members_template->member->user_id;
+
+		return apply_filters( 'bp_get_group_member_demote_link', wp_nonce_url( bp_get_group_permalink( $group ) . 'admin/manage-members/demote/' . $user_id, 'groups_demote_member' ) );
+	}
+
+function bp_group_member_ban_link( $user_id = 0 ) {
+	global $members_template;
+
+	if ( !$user_id )
+		$user_id = $members_template->member->user_id;
+
+	echo bp_get_group_member_ban_link( $user_id );
+}
+	function bp_get_group_member_ban_link( $user_id = 0, $group = false ) {
+		global $groups_template;
+
+		if ( empty( $group ) )
+			$group =& $groups_template->group;
+
+		return apply_filters( 'bp_get_group_member_ban_link', wp_nonce_url( bp_get_group_permalink( $group ) . 'admin/manage-members/ban/' . $user_id, 'groups_ban_member' ) );
+	}
+
+function bp_group_member_unban_link( $user_id = 0 ) {
+	global $members_template;
+
+	if ( !$user_id )
+		$user_id = $members_template->member->user_id;
+
+	echo bp_get_group_member_unban_link( $user_id );
+}
+	function bp_get_group_member_unban_link( $user_id = 0, $group = false ) {
+		global $members_template, $groups_template;
+
+		if ( !$user_id )
+			$user_id = $members_template->member->user_id;
+
+		if ( empty( $group ) )
+			$group =& $groups_template->group;
+
+		return apply_filters( 'bp_get_group_member_unban_link', wp_nonce_url( bp_get_group_permalink( $group ) . 'admin/manage-members/unban/' . $user_id, 'groups_unban_member' ) );
+	}
+
+
+function bp_group_member_remove_link( $user_id = 0 ) {
+	global $members_template;
+
+	if ( !$user_id )
+		$user_id = $members_template->member->user_id;
+
+	echo bp_get_group_member_remove_link( $user_id );
+}
+	function bp_get_group_member_remove_link( $user_id = 0, $group = false ) {
+		global $groups_template;
+
+		if ( empty( $group ) )
+			$group =& $groups_template->group;
+
+		return apply_filters( 'bp_get_group_member_remove_link', wp_nonce_url( bp_get_group_permalink( $group ) . 'admin/manage-members/remove/' . $user_id, 'groups_remove_member' ) );
+	}
+
+function bp_group_admin_tabs( $group = false ) {
+	global $bp, $groups_template;
+
+	if ( empty( $group ) )
+		$group = ( $groups_template->group ) ? $groups_template->group : $bp->groups->current_group;
+
+	$current_tab = bp_get_group_current_admin_tab();
+
+	if ( bp_is_item_admin() ) : ?>
+
+		<li<?php if ( 'edit-details' == $current_tab || empty( $current_tab ) ) : ?> class="current"<?php endif; ?>><a href="<?php echo trailingslashit( bp_get_group_permalink( $group ) . 'admin/edit-details' ) ?>"><?php _e( 'Details', 'buddypress' ); ?></a></li>
+
+	<?php endif; ?>
+
+	<?php if ( ! bp_is_item_admin() )
+			return false; ?>
+
+	<li<?php if ( 'group-settings' == $current_tab ) : ?> class="current"<?php endif; ?>><a href="<?php echo trailingslashit( bp_get_group_permalink( $group ) . 'admin/group-settings' ) ?>"><?php _e( 'Settings', 'buddypress' ); ?></a></li>
+
+	<?php if ( !(int)bp_get_option( 'bp-disable-avatar-uploads' ) ) : ?>
+
+		<li<?php if ( 'group-avatar'   == $current_tab ) : ?> class="current"<?php endif; ?>><a href="<?php echo trailingslashit( bp_get_group_permalink( $group ) . 'admin/group-avatar' ) ?>"><?php _e( 'Avatar', 'buddypress' ); ?></a></li>
+
+	<?php endif; ?>
+
+	<li<?php if ( 'manage-members' == $current_tab ) : ?> class="current"<?php endif; ?>><a href="<?php echo trailingslashit( bp_get_group_permalink( $group ) . 'admin/manage-members' ) ?>"><?php _e( 'Members', 'buddypress' ); ?></a></li>
+
+	<?php if ( $groups_template->group->status == 'private' ) : ?>
+
+		<li<?php if ( 'membership-requests' == $current_tab ) : ?> class="current"<?php endif; ?>><a href="<?php echo trailingslashit( bp_get_group_permalink( $group ) . 'admin/membership-requests' ) ?>"><?php _e( 'Requests', 'buddypress' ); ?></a></li>
+
+	<?php endif; ?>
+
+	<?php do_action( 'groups_admin_tabs', $current_tab, $group->slug ) ?>
+
+	<li<?php if ( 'delete-group' == $current_tab ) : ?> class="current"<?php endif; ?>><a href="<?php echo trailingslashit( bp_get_group_permalink( $group ) . 'admin/delete-group' ) ?>"><?php _e( 'Delete', 'buddypress' ); ?></a></li>
+
+<?php
+}
+
+function bp_group_total_for_member() {
+	echo bp_get_group_total_for_member();
+}
+	function bp_get_group_total_for_member() {
+		return apply_filters( 'bp_get_group_total_for_member', BP_Groups_Member::total_group_count() );
+	}
+
+function bp_group_form_action( $page ) {
+	echo bp_get_group_form_action( $page );
+}
+	function bp_get_group_form_action( $page, $group = false ) {
+		global $groups_template;
+
+		if ( empty( $group ) )
+			$group =& $groups_template->group;
+
+		return apply_filters( 'bp_group_form_action', bp_get_group_permalink( $group ) . $page );
+	}
+
+function bp_group_admin_form_action( $page = false ) {
+	echo bp_get_group_admin_form_action( $page );
+}
+	function bp_get_group_admin_form_action( $page = false, $group = false ) {
+		global $groups_template;
+
+		if ( empty( $group ) )
+			$group =& $groups_template->group;
+
+		if ( empty( $page ) )
+			$page = bp_action_variable( 0 );
+
+		return apply_filters( 'bp_group_admin_form_action', bp_get_group_permalink( $group ) . 'admin/' . $page );
+	}
+
+function bp_group_has_requested_membership( $group = false ) {
+	global $groups_template;
+
+	if ( empty( $group ) )
+		$group =& $groups_template->group;
+
+	if ( groups_check_for_membership_request( bp_loggedin_user_id(), $group->id ) )
+		return true;
+
+	return false;
+}
+
+/**
+ * bp_group_is_member()
+ *
+ * Checks if current user is member of a group.
+ *
+ * @uses bp_current_user_can() Check if current user is super admin
+ * @uses apply_filters Creates bp_group_is_member filter and passes $is_member
+ * @usedby groups/activity.php, groups/single/forum/edit.php, groups/single/forum/topic.php to determine template part visibility
+ * @global object $groups_template Current Group (usually in template loop)
+ * @param object $group Group to check is_member
+ * @return bool If user is member of group or not
+ */
+function bp_group_is_member( $group = false ) {
+	global $groups_template;
+
+	// Site admins always have access
+	if ( bp_current_user_can( 'bp_moderate' ) )
+		return true;
+
+	if ( empty( $group ) )
+		$group =& $groups_template->group;
+
+	return apply_filters( 'bp_group_is_member', !empty( $group->is_member ) );
+}
+
+/**
+ * Checks if a user is banned from a group.
+ *
+ * If this function is invoked inside the groups template loop (e.g. the group directory), then
+ * check $groups_template->group->is_banned instead of making another SQL query.
+ * However, if used in a single group's pages, we must use groups_is_user_banned().
+ *
+ * @global BP_Groups_Template $groups_template Group template loop object
+ * @param object $group Group to check if user is banned from the group
+ * @param int $user_id
+ * @return bool If user is banned from the group or not
+ * @since BuddyPress (1.5)
+ */
+function bp_group_is_user_banned( $group = false, $user_id = 0 ) {
+	global $groups_template;
+
+	// Site admins always have access
+	if ( bp_current_user_can( 'bp_moderate' ) )
+		return false;
+
+	if ( empty( $group ) ) {
+		$group =& $groups_template->group;
+
+		if ( !$user_id && isset( $group->is_banned ) )
+			return apply_filters( 'bp_group_is_user_banned', $group->is_banned );
+	}
+
+	if ( !$user_id )
+		$user_id = bp_loggedin_user_id();
+
+	return apply_filters( 'bp_group_is_user_banned', groups_is_user_banned( $user_id, $group->id ) );
+}
+
+function bp_group_accept_invite_link() {
+	echo bp_get_group_accept_invite_link();
+}
+	function bp_get_group_accept_invite_link( $group = false ) {
+		global $groups_template, $bp;
+
+		if ( empty( $group ) )
+			$group =& $groups_template->group;
+
+		return apply_filters( 'bp_get_group_accept_invite_link', wp_nonce_url( trailingslashit( bp_loggedin_user_domain() . bp_get_groups_slug() . '/invites/accept/' . $group->id ), 'groups_accept_invite' ) );
+	}
+
+function bp_group_reject_invite_link() {
+	echo bp_get_group_reject_invite_link();
+}
+	function bp_get_group_reject_invite_link( $group = false ) {
+		global $groups_template, $bp;
+
+		if ( empty( $group ) )
+			$group =& $groups_template->group;
+
+		return apply_filters( 'bp_get_group_reject_invite_link', wp_nonce_url( trailingslashit( bp_loggedin_user_domain() . bp_get_groups_slug() . '/invites/reject/' . $group->id ), 'groups_reject_invite' ) );
+	}
+
+function bp_group_leave_confirm_link() {
+	echo bp_get_group_leave_confirm_link();
+}
+	function bp_get_group_leave_confirm_link( $group = false ) {
+		global $groups_template;
+
+		if ( empty( $group ) )
+			$group =& $groups_template->group;
+
+		return apply_filters( 'bp_group_leave_confirm_link', wp_nonce_url( bp_get_group_permalink( $group ) . 'leave-group/yes', 'groups_leave_group' ) );
+	}
+
+function bp_group_leave_reject_link() {
+	echo bp_get_group_leave_reject_link();
+}
+	function bp_get_group_leave_reject_link( $group = false ) {
+		global $groups_template;
+
+		if ( empty( $group ) )
+			$group =& $groups_template->group;
+
+		return apply_filters( 'bp_get_group_leave_reject_link', bp_get_group_permalink( $group ) );
+	}
+
+function bp_group_send_invite_form_action() {
+	echo bp_get_group_send_invite_form_action();
+}
+	function bp_get_group_send_invite_form_action( $group = false ) {
+		global $groups_template;
+
+		if ( empty( $group ) )
+			$group =& $groups_template->group;
+
+		return apply_filters( 'bp_group_send_invite_form_action', bp_get_group_permalink( $group ) . 'send-invites/send' );
+	}
+
+function bp_has_friends_to_invite( $group = false ) {
+	global $groups_template;
+
+	if ( !bp_is_active( 'friends' ) )
+		return false;
+
+	if ( empty( $group ) )
+		$group =& $groups_template->group;
+
+	if ( !friends_check_user_has_friends( bp_loggedin_user_id() ) || !friends_count_invitable_friends( bp_loggedin_user_id(), $group->id ) )
+		return false;
+
+	return true;
+}
+
+/**
+ * Outputs a 'New Topic' button for a group.
+ *
+ * @since BuddyPress (1.2.7)
+ *
+ * @param BP_Groups_Group|bool $group The BP Groups_Group object if passed, boolean false if not passed.
+ * @uses bp_get_group_new_topic_button() Returns the 'New Topic' button
+ */
+function bp_group_new_topic_button( $group = false ) {
+	echo bp_get_group_new_topic_button( $group );
+}
+	/**
+	 * Returns a 'New Topic' button for a group.
+	 *
+	 * @since BuddyPress (1.2.7)
+	 *
+	 * @param BP_Groups_Group|bool $group The BP Groups_Group object if passed, boolean false if not passed.
+	 * @uses is_user_logged_in() Is there a user logged in?
+	 * @uses bp_group_is_user_banned() Is the current user banned from the current group?
+	 * @uses bp_is_group_forum() Are we on a group forum page?
+	 * @uses bp_is_group_forum_topic() Are we on a group topic page?
+	 * @uses bp_get_button() Renders a button
+	 * @return string HTML code for the button
+	 */
+	function bp_get_group_new_topic_button( $group = false ) {
+		global $groups_template;
+
+		if ( empty( $group ) )
+			$group =& $groups_template->group;
+
+		if ( !is_user_logged_in() || bp_group_is_user_banned() || !bp_is_group_forum() || bp_is_group_forum_topic() )
+			return false;
+
+		$button = array(
+			'id'                => 'new_topic',
+			'component'         => 'groups',
+			'must_be_logged_in' => true,
+			'block_self'        => true,
+			'wrapper_class'     => 'group-button',
+			'link_href'         => '#post-new',
+			'link_class'        => 'group-button show-hide-new',
+			'link_id'           => 'new-topic-button',
+			'link_text'         => __( 'New Topic', 'buddypress' ),
+			'link_title'        => __( 'New Topic', 'buddypress' ),
+		);
+
+		// Filter and return the HTML button
+		return bp_get_button( apply_filters( 'bp_get_group_new_topic_button', $button ) );
+	}
+
+function bp_group_join_button( $group = false ) {
+	echo bp_get_group_join_button( $group );
+}
+	function bp_get_group_join_button( $group = false ) {
+		global $groups_template;
+
+		if ( empty( $group ) )
+			$group =& $groups_template->group;
+
+		if ( !is_user_logged_in() || bp_group_is_user_banned( $group ) )
+			return false;
+
+		// Group creation was not completed or status is unknown
+		if ( !$group->status )
+			return false;
+
+		// Already a member
+		if ( isset( $group->is_member ) && $group->is_member ) {
+
+			// Stop sole admins from abandoning their group
+	 		$group_admins = groups_get_group_admins( $group->id );
+		 	if ( 1 == count( $group_admins ) && $group_admins[0]->user_id == bp_loggedin_user_id() )
+				return false;
+
+			$button = array(
+				'id'                => 'leave_group',
+				'component'         => 'groups',
+				'must_be_logged_in' => true,
+				'block_self'        => false,
+				'wrapper_class'     => 'group-button ' . $group->status,
+				'wrapper_id'        => 'groupbutton-' . $group->id,
+				'link_href'         => wp_nonce_url( bp_get_group_permalink( $group ) . 'leave-group', 'groups_leave_group' ),
+				'link_text'         => __( 'Leave Group', 'buddypress' ),
+				'link_title'        => __( 'Leave Group', 'buddypress' ),
+				'link_class'        => 'group-button leave-group',
+			);
+
+		// Not a member
+		} else {
+
+			// Show different buttons based on group status
+			switch ( $group->status ) {
+				case 'hidden' :
+					return false;
+					break;
+
+				case 'public':
+					$button = array(
+						'id'                => 'join_group',
+						'component'         => 'groups',
+						'must_be_logged_in' => true,
+						'block_self'        => false,
+						'wrapper_class'     => 'group-button ' . $group->status,
+						'wrapper_id'        => 'groupbutton-' . $group->id,
+						'link_href'         => wp_nonce_url( bp_get_group_permalink( $group ) . 'join', 'groups_join_group' ),
+						'link_text'         => __( 'Join Group', 'buddypress' ),
+						'link_title'        => __( 'Join Group', 'buddypress' ),
+						'link_class'        => 'group-button join-group',
+					);
+					break;
+
+				case 'private' :
+
+					// Member has outstanding invitation -
+					// show an "Accept Invitation" button
+					if ( $group->is_invited ) {
+						$button = array(
+							'id'                => 'accept_invite',
+							'component'         => 'groups',
+							'must_be_logged_in' => true,
+							'block_self'        => false,
+							'wrapper_class'     => 'group-button ' . $group->status,
+							'wrapper_id'        => 'groupbutton-' . $group->id,
+							'link_href'         => add_query_arg( 'redirect_to', bp_get_group_permalink( $group ), bp_get_group_accept_invite_link( $group ) ),
+							'link_text'         => __( 'Accept Invitation', 'buddypress' ),
+							'link_title'        => __( 'Accept Invitation', 'buddypress' ),
+							'link_class'        => 'group-button accept-invite',
+						);
+
+					// Member has requested membership but request is pending -
+					// show a "Request Sent" button
+					} elseif ( $group->is_pending ) {
+						$button = array(
+							'id'                => 'membership_requested',
+							'component'         => 'groups',
+							'must_be_logged_in' => true,
+							'block_self'        => false,
+							'wrapper_class'     => 'group-button pending ' . $group->status,
+							'wrapper_id'        => 'groupbutton-' . $group->id,
+							'link_href'         => bp_get_group_permalink( $group ),
+							'link_text'         => __( 'Request Sent', 'buddypress' ),
+							'link_title'        => __( 'Request Sent', 'buddypress' ),
+							'link_class'        => 'group-button pending membership-requested',
+						);
+
+					// Member has not requested membership yet -
+					// show a "Request Membership" button
+					} else {
+						$button = array(
+							'id'                => 'request_membership',
+							'component'         => 'groups',
+							'must_be_logged_in' => true,
+							'block_self'        => false,
+							'wrapper_class'     => 'group-button ' . $group->status,
+							'wrapper_id'        => 'groupbutton-' . $group->id,
+							'link_href'         => wp_nonce_url( bp_get_group_permalink( $group ) . 'request-membership', 'groups_request_membership' ),
+							'link_text'         => __( 'Request Membership', 'buddypress' ),
+							'link_title'        => __( 'Request Membership', 'buddypress' ),
+							'link_class'        => 'group-button request-membership',
+						);
+					}
+
+					break;
+			}
+		}
+
+		// Filter and return the HTML button
+		return bp_get_button( apply_filters( 'bp_get_group_join_button', $button ) );
+	}
+
+/**
+ * Prints a message if the group is not visible to the current user (it is a
+ * hidden or private group, and the user does not have access).
+ *
+ * @global BP_Groups_Template $groups_template Groups template object
+ * @param object $group Group to get status message for. Optional; defaults to current group.
+ * @since BuddyPress (1.0)
+ */
+function bp_group_status_message( $group = null ) {
+	global $groups_template;
+
+	if ( ! $group )
+		$group =& $groups_template->group;
+
+	if ( 'private' == $group->status ) {
+ 		if ( ! bp_group_has_requested_membership() ) {
+			if ( is_user_logged_in() )
+				$message = __( 'This is a private group and you must request group membership in order to join.', 'buddypress' );
+			else
+				$message = __( 'This is a private group. To join you must be a registered site member and request group membership.', 'buddypress' );
+
+		} else {
+			$message = __( 'This is a private group. Your membership request is awaiting approval from the group administrator.', 'buddypress' );
+		}
+
+	} else {
+		$message = __( 'This is a hidden group and only invited members can join.', 'buddypress' );
+	}
+
+	echo apply_filters( 'bp_group_status_message', $message, $group );
+}
+
+function bp_group_hidden_fields() {
+	if ( isset( $_REQUEST['s'] ) ) {
+		echo '<input type="hidden" id="search_terms" value="' . esc_attr( $_REQUEST['s'] ) . '" name="search_terms" />';
+	}
+
+	if ( isset( $_REQUEST['letter'] ) ) {
+		echo '<input type="hidden" id="selected_letter" value="' . esc_attr( $_REQUEST['letter'] ) . '" name="selected_letter" />';
+	}
+
+	if ( isset( $_REQUEST['groups_search'] ) ) {
+		echo '<input type="hidden" id="search_terms" value="' . esc_attr( $_REQUEST['groups_search'] ) . '" name="search_terms" />';
+	}
+}
+
+function bp_total_group_count() {
+	echo bp_get_total_group_count();
+}
+	function bp_get_total_group_count() {
+		return apply_filters( 'bp_get_total_group_count', groups_get_total_group_count() );
+	}
+
+function bp_total_group_count_for_user( $user_id = 0 ) {
+	echo bp_get_total_group_count_for_user( $user_id );
+}
+	function bp_get_total_group_count_for_user( $user_id = 0 ) {
+		return apply_filters( 'bp_get_total_group_count_for_user', groups_total_groups_for_user( $user_id ), $user_id );
+	}
+	add_filter( 'bp_get_total_group_count_for_user', 'bp_core_number_format' );
+
+
+/***************************************************************************
+ * Group Members Template Tags
+ **/
+
+class BP_Groups_Group_Members_Template {
+	var $current_member = -1;
+	var $member_count;
+	var $members;
+	var $member;
+
+	var $in_the_loop;
+
+	var $pag_page;
+	var $pag_num;
+	var $pag_links;
+	var $total_group_count;
+
+	function __construct( $group_id, $per_page, $max, $exclude_admins_mods, $exclude_banned, $exclude, $group_role = false ) {
+
+		$this->pag_page = isset( $_REQUEST['mlpage'] ) ? intval( $_REQUEST['mlpage'] ) : 1;
+		$this->pag_num  = isset( $_REQUEST['num'] ) ? intval( $_REQUEST['num'] ) : $per_page;
+		$this->members  = groups_get_group_members( $group_id, $this->pag_num, $this->pag_page, $exclude_admins_mods, $exclude_banned, $exclude, $group_role );
+
+		if ( !$max || $max >= (int) $this->members['count'] )
+			$this->total_member_count = (int) $this->members['count'];
+		else
+			$this->total_member_count = (int) $max;
+
+		$this->members = $this->members['members'];
+
+		if ( $max ) {
+			if ( $max >= count($this->members) )
+				$this->member_count = count($this->members);
+			else
+				$this->member_count = (int) $max;
+		} else {
+			$this->member_count = count($this->members);
+		}
+
+		$this->pag_links = paginate_links( array(
+			'base' => add_query_arg( 'mlpage', '%#%' ),
+			'format' => '',
+			'total' => !empty( $this->pag_num ) ? ceil( $this->total_member_count / $this->pag_num ) : $this->total_member_count,
+			'current' => $this->pag_page,
+			'prev_text' => '&larr;',
+			'next_text' => '&rarr;',
+			'mid_size' => 1
+		));
+	}
+
+	function has_members() {
+		if ( $this->member_count )
+			return true;
+
+		return false;
+	}
+
+	function next_member() {
+		$this->current_member++;
+		$this->member = $this->members[$this->current_member];
+
+		return $this->member;
+	}
+
+	function rewind_members() {
+		$this->current_member = -1;
+		if ( $this->member_count > 0 ) {
+			$this->member = $this->members[0];
+		}
+	}
+
+	function members() {
+		if ( $this->current_member + 1 < $this->member_count ) {
+			return true;
+		} elseif ( $this->current_member + 1 == $this->member_count ) {
+			do_action('loop_end');
+			// Do some cleaning up after the loop
+			$this->rewind_members();
+		}
+
+		$this->in_the_loop = false;
+		return false;
+	}
+
+	function the_member() {
+
+		$this->in_the_loop = true;
+		$this->member      = $this->next_member();
+
+		if ( 0 == $this->current_member ) // loop has just started
+			do_action('loop_start');
+	}
+}
+
+function bp_group_has_members( $args = '' ) {
+	global $members_template;
+
+	$r = wp_parse_args( $args, array(
+		'group_id' => bp_get_current_group_id(),
+		'per_page' => 20,
+		'max' => false,
+		'exclude' => false,
+		'exclude_admins_mods' => 1,
+		'exclude_banned' => 1,
+		'group_role' => false,
+	) );
+
+	$members_template = new BP_Groups_Group_Members_Template( $r['group_id'], $r['per_page'], $r['max'], (int) $r['exclude_admins_mods'], (int) $r['exclude_banned'], $r['exclude'], $r['group_role'] );
+	return apply_filters( 'bp_group_has_members', $members_template->has_members(), $members_template );
+}
+
+function bp_group_members() {
+	global $members_template;
+
+	return $members_template->members();
+}
+
+function bp_group_the_member() {
+	global $members_template;
+
+	return $members_template->the_member();
+}
+
+function bp_group_member_avatar() {
+	echo bp_get_group_member_avatar();
+}
+	function bp_get_group_member_avatar() {
+		global $members_template;
+
+		return apply_filters( 'bp_get_group_member_avatar', bp_core_fetch_avatar( array( 'item_id' => $members_template->member->user_id, 'type' => 'full', 'email' => $members_template->member->user_email, 'alt' => sprintf( __( 'Profile picture of %s', 'buddypress' ), $members_template->member->display_name ) ) ) );
+	}
+
+function bp_group_member_avatar_thumb() {
+	echo bp_get_group_member_avatar_thumb();
+}
+	function bp_get_group_member_avatar_thumb() {
+		global $members_template;
+
+		return apply_filters( 'bp_get_group_member_avatar_thumb', bp_core_fetch_avatar( array( 'item_id' => $members_template->member->user_id, 'type' => 'thumb', 'email' => $members_template->member->user_email, 'alt' => sprintf( __( 'Profile picture of %s', 'buddypress' ), $members_template->member->display_name ) ) ) );
+	}
+
+function bp_group_member_avatar_mini( $width = 30, $height = 30 ) {
+	echo bp_get_group_member_avatar_mini( $width, $height );
+}
+	function bp_get_group_member_avatar_mini( $width = 30, $height = 30 ) {
+		global $members_template;
+
+		return apply_filters( 'bp_get_group_member_avatar_mini', bp_core_fetch_avatar( array( 'item_id' => $members_template->member->user_id, 'type' => 'thumb', 'width' => $width, 'height' => $height, 'email' => $members_template->member->user_email, 'alt' => sprintf( __( 'Profile picture of %s', 'buddypress' ), $members_template->member->display_name ) ) ) );
+	}
+
+function bp_group_member_name() {
+	echo bp_get_group_member_name();
+}
+	function bp_get_group_member_name() {
+		global $members_template;
+
+		return apply_filters( 'bp_get_group_member_name', $members_template->member->display_name );
+	}
+
+function bp_group_member_url() {
+	echo bp_get_group_member_url();
+}
+	function bp_get_group_member_url() {
+		global $members_template;
+
+		return apply_filters( 'bp_get_group_member_url', bp_core_get_user_domain( $members_template->member->user_id, $members_template->member->user_nicename, $members_template->member->user_login ) );
+	}
+
+function bp_group_member_link() {
+	echo bp_get_group_member_link();
+}
+	function bp_get_group_member_link() {
+		global $members_template;
+
+		return apply_filters( 'bp_get_group_member_link', '<a href="' . bp_core_get_user_domain( $members_template->member->user_id, $members_template->member->user_nicename, $members_template->member->user_login ) . '">' . $members_template->member->display_name . '</a>' );
+	}
+
+function bp_group_member_domain() {
+	echo bp_get_group_member_domain();
+}
+	function bp_get_group_member_domain() {
+		global $members_template;
+
+		return apply_filters( 'bp_get_group_member_domain', bp_core_get_user_domain( $members_template->member->user_id, $members_template->member->user_nicename, $members_template->member->user_login ) );
+	}
+
+function bp_group_member_is_friend() {
+	echo bp_get_group_member_is_friend();
+}
+	function bp_get_group_member_is_friend() {
+		global $members_template;
+
+		if ( !isset( $members_template->member->is_friend ) )
+			$friend_status = 'not_friends';
+		else
+			$friend_status = ( 0 == $members_template->member->is_friend ) ? 'pending' : 'is_friend';
+
+		return apply_filters( 'bp_get_group_member_is_friend', $friend_status );
+	}
+
+function bp_group_member_is_banned() {
+	echo bp_get_group_member_is_banned();
+}
+	function bp_get_group_member_is_banned() {
+		global $members_template;
+
+		return apply_filters( 'bp_get_group_member_is_banned', $members_template->member->is_banned );
+	}
+
+function bp_group_member_css_class() {
+	global $members_template;
+
+	if ( $members_template->member->is_banned )
+		echo apply_filters( 'bp_group_member_css_class', 'banned-user' );
+}
+
+function bp_group_member_joined_since() {
+	echo bp_get_group_member_joined_since();
+}
+	function bp_get_group_member_joined_since() {
+		global $members_template;
+
+		return apply_filters( 'bp_get_group_member_joined_since', bp_core_get_last_activity( $members_template->member->date_modified, __( 'joined %s', 'buddypress') ) );
+	}
+
+function bp_group_member_id() {
+	echo bp_get_group_member_id();
+}
+	function bp_get_group_member_id() {
+		global $members_template;
+
+		return apply_filters( 'bp_get_group_member_id', $members_template->member->user_id );
+	}
+
+function bp_group_member_needs_pagination() {
+	global $members_template;
+
+	if ( $members_template->total_member_count > $members_template->pag_num )
+		return true;
+
+	return false;
+}
+
+function bp_group_pag_id() {
+	echo bp_get_group_pag_id();
+}
+	function bp_get_group_pag_id() {
+		return apply_filters( 'bp_get_group_pag_id', 'pag' );
+	}
+
+function bp_group_member_pagination() {
+	echo bp_get_group_member_pagination();
+	wp_nonce_field( 'bp_groups_member_list', '_member_pag_nonce' );
+}
+	function bp_get_group_member_pagination() {
+		global $members_template;
+		return apply_filters( 'bp_get_group_member_pagination', $members_template->pag_links );
+	}
+
+function bp_group_member_pagination_count() {
+	echo bp_get_group_member_pagination_count();
+}
+	function bp_get_group_member_pagination_count() {
+		global $members_template;
+
+		$start_num = intval( ( $members_template->pag_page - 1 ) * $members_template->pag_num ) + 1;
+		$from_num = bp_core_number_format( $start_num );
+		$to_num = bp_core_number_format( ( $start_num + ( $members_template->pag_num - 1 ) > $members_template->total_member_count ) ? $members_template->total_member_count : $start_num + ( $members_template->pag_num - 1 ) );
+		$total = bp_core_number_format( $members_template->total_member_count );
+
+		return apply_filters( 'bp_get_group_member_pagination_count', sprintf( _n( 'Viewing member %1$s to %2$s (of %3$s member)', 'Viewing members %1$s to %2$s (of %3$s members)', $total, 'buddypress' ), $from_num, $to_num, $total ), $from_num, $to_num, $total );
+	}
+
+function bp_group_member_admin_pagination() {
+	echo bp_get_group_member_admin_pagination();
+	wp_nonce_field( 'bp_groups_member_admin_list', '_member_admin_pag_nonce' );
+}
+	function bp_get_group_member_admin_pagination() {
+		global $members_template;
+
+		return $members_template->pag_links;
+	}
+
+
+/***************************************************************************
+ * Group Creation Process Template Tags
+ **/
+
+/**
+ * Determine if the current logged in user can create groups.
+ *
+ * @package BuddyPress Groups
+ * @since BuddyPress (1.5)
+ *
+ * @uses apply_filters() To call 'bp_user_can_create_groups'.
+ * @uses bp_get_option() To retrieve value of 'bp_restrict_group_creation'. Defaults to 0.
+ * @uses bp_current_user_can() To determine if current user if super admin.
+ *
+ * @return bool True if user can create groups. False otherwise.
+ */
+function bp_user_can_create_groups() {
+	// Super admin can always create groups
+	if ( bp_current_user_can( 'bp_moderate' ) )
+		return true;
+
+	// Get group creation option, default to 0 (allowed)
+	$restricted = (int) bp_get_option( 'bp_restrict_group_creation', 0 );
+
+	// Allow by default
+	$can_create = true;
+
+	// Are regular users restricted?
+	if ( $restricted )
+		$can_create = false;
+
+	return apply_filters( 'bp_user_can_create_groups', $can_create, $restricted );
+}
+
+function bp_group_creation_tabs() {
+	global $bp;
+
+	if ( !is_array( $bp->groups->group_creation_steps ) )
+		return false;
+
+	if ( !bp_get_groups_current_create_step() ) {
+		$keys = array_keys( $bp->groups->group_creation_steps );
+		$bp->groups->current_create_step = array_shift( $keys );
+	}
+
+	$counter = 1;
+
+	foreach ( (array) $bp->groups->group_creation_steps as $slug => $step ) {
+		$is_enabled = bp_are_previous_group_creation_steps_complete( $slug ); ?>
+
+		<li<?php if ( bp_get_groups_current_create_step() == $slug ) : ?> class="current"<?php endif; ?>><?php if ( $is_enabled ) : ?><a href="<?php echo bp_get_root_domain() . '/' . bp_get_groups_root_slug() ?>/create/step/<?php echo $slug ?>/"><?php else: ?><span><?php endif; ?><?php echo $counter ?>. <?php echo $step['name'] ?><?php if ( $is_enabled ) : ?></a><?php else: ?></span><?php endif ?></li><?php
+		$counter++;
+	}
+
+	unset( $is_enabled );
+
+	do_action( 'groups_creation_tabs' );
+}
+
+function bp_group_creation_stage_title() {
+	global $bp;
+
+	echo apply_filters( 'bp_group_creation_stage_title', '<span>&mdash; ' . $bp->groups->group_creation_steps[bp_get_groups_current_create_step()]['name'] . '</span>' );
+}
+
+function bp_group_creation_form_action() {
+	echo bp_get_group_creation_form_action();
+}
+	function bp_get_group_creation_form_action() {
+		global $bp;
+
+		if ( !bp_action_variable( 1 ) ) {
+			$keys = array_keys( $bp->groups->group_creation_steps );
+			$bp->action_variables[1] = array_shift( $keys );
+		}
+
+		return apply_filters( 'bp_get_group_creation_form_action', trailingslashit( bp_get_root_domain() . '/' . bp_get_groups_root_slug() . '/create/step/' . bp_action_variable( 1 ) ) );
+	}
+
+function bp_is_group_creation_step( $step_slug ) {
+	global $bp;
+
+	/* Make sure we are in the groups component */
+	if ( !bp_is_groups_component() || !bp_is_current_action( 'create' ) )
+		return false;
+
+	/* If this the first step, we can just accept and return true */
+	$keys = array_keys( $bp->groups->group_creation_steps );
+	if ( !bp_action_variable( 1 ) && array_shift( $keys ) == $step_slug )
+		return true;
+
+	/* Before allowing a user to see a group creation step we must make sure previous steps are completed */
+	if ( !bp_is_first_group_creation_step() ) {
+		if ( !bp_are_previous_group_creation_steps_complete( $step_slug ) )
+			return false;
+	}
+
+	/* Check the current step against the step parameter */
+	if ( bp_is_action_variable( $step_slug ) )
+		return true;
+
+	return false;
+}
+
+function bp_is_group_creation_step_complete( $step_slugs ) {
+	global $bp;
+
+	if ( !isset( $bp->groups->completed_create_steps ) )
+		return false;
+
+	if ( is_array( $step_slugs ) ) {
+		$found = true;
+
+		foreach ( (array) $step_slugs as $step_slug ) {
+			if ( !in_array( $step_slug, $bp->groups->completed_create_steps ) )
+				$found = false;
+		}
+
+		return $found;
+	} else {
+		return in_array( $step_slugs, $bp->groups->completed_create_steps );
+	}
+
+	return true;
+}
+
+function bp_are_previous_group_creation_steps_complete( $step_slug ) {
+	global $bp;
+
+	/* If this is the first group creation step, return true */
+	$keys = array_keys( $bp->groups->group_creation_steps );
+	if ( array_shift( $keys ) == $step_slug )
+		return true;
+
+	reset( $bp->groups->group_creation_steps );
+	unset( $previous_steps );
+
+	/* Get previous steps */
+	foreach ( (array) $bp->groups->group_creation_steps as $slug => $name ) {
+		if ( $slug == $step_slug )
+			break;
+
+		$previous_steps[] = $slug;
+	}
+
+	return bp_is_group_creation_step_complete( $previous_steps );
+}
+
+function bp_new_group_id() {
+	echo bp_get_new_group_id();
+}
+	function bp_get_new_group_id() {
+		global $bp;
+
+		if ( isset( $bp->groups->new_group_id ) )
+			$new_group_id = $bp->groups->new_group_id;
+		else
+			$new_group_id = 0;
+
+		return apply_filters( 'bp_get_new_group_id', $new_group_id );
+	}
+
+function bp_new_group_name() {
+	echo bp_get_new_group_name();
+}
+	function bp_get_new_group_name() {
+		global $bp;
+
+		if ( isset( $bp->groups->current_group->name ) )
+			$name = $bp->groups->current_group->name;
+		else
+			$name = '';
+
+		return apply_filters( 'bp_get_new_group_name', $name );
+	}
+
+function bp_new_group_description() {
+	echo bp_get_new_group_description();
+}
+	function bp_get_new_group_description() {
+		global $bp;
+
+		if ( isset( $bp->groups->current_group->description ) )
+			$description = $bp->groups->current_group->description;
+		else
+			$description = '';
+
+		return apply_filters( 'bp_get_new_group_description', $description );
+	}
+
+function bp_new_group_enable_forum() {
+	echo bp_get_new_group_enable_forum();
+}
+	function bp_get_new_group_enable_forum() {
+		global $bp;
+		return (int) apply_filters( 'bp_get_new_group_enable_forum', $bp->groups->current_group->enable_forum );
+	}
+
+function bp_new_group_status() {
+	echo bp_get_new_group_status();
+}
+	function bp_get_new_group_status() {
+		global $bp;
+		return apply_filters( 'bp_get_new_group_status', $bp->groups->current_group->status );
+	}
+
+function bp_new_group_avatar( $args = '' ) {
+	echo bp_get_new_group_avatar( $args );
+}
+	function bp_get_new_group_avatar( $args = '' ) {
+		global $bp;
+
+		$defaults = array(
+			'type' => 'full',
+			'width' => false,
+			'height' => false,
+			'class' => 'avatar',
+			'id' => 'avatar-crop-preview',
+			'alt' => __( 'Group avatar', 'buddypress' ),
+			'no_grav' => false
+		);
+
+		$r = wp_parse_args( $args, $defaults );
+		extract( $r, EXTR_SKIP );
+
+		return apply_filters( 'bp_get_new_group_avatar', bp_core_fetch_avatar( array( 'item_id' => $bp->groups->current_group->id, 'object' => 'group', 'type' => $type, 'avatar_dir' => 'group-avatars', 'alt' => $alt, 'width' => $width, 'height' => $height, 'class' => $class, 'no_grav' => $no_grav ) ) );
+	}
+
+function bp_group_creation_previous_link() {
+	echo bp_get_group_creation_previous_link();
+}
+	function bp_get_group_creation_previous_link() {
+		global $bp;
+
+		foreach ( (array) $bp->groups->group_creation_steps as $slug => $name ) {
+			if ( bp_is_action_variable( $slug ) )
+				break;
+
+			$previous_steps[] = $slug;
+		}
+
+		return apply_filters( 'bp_get_group_creation_previous_link', trailingslashit( bp_get_root_domain() ) . bp_get_groups_root_slug() . '/create/step/' . array_pop( $previous_steps ) );
+	}
+
+/**
+ * Echoes the current group creation step
+ *
+ * @since BuddyPress (1.6)
+ */
+function bp_groups_current_create_step() {
+	echo bp_get_groups_current_create_step();
+}
+	/**
+	 * Returns the current group creation step. If none is found, returns an empty string
+	 *
+	 * @since BuddyPress (1.6)
+	 *
+	 * @uses apply_filters() Filter bp_get_groups_current_create_step to modify
+	 * @return string $current_create_step
+	 */
+	function bp_get_groups_current_create_step() {
+		global $bp;
+
+		if ( !empty( $bp->groups->current_create_step ) ) {
+			$current_create_step = $bp->groups->current_create_step;
+		} else {
+			$current_create_step = '';
+		}
+
+		return apply_filters( 'bp_get_groups_current_create_step', $current_create_step );
+	}
+
+function bp_is_last_group_creation_step() {
+	global $bp;
+
+	$keys      = array_keys( $bp->groups->group_creation_steps );
+	$last_step = array_pop( $keys );
+
+	if ( $last_step == bp_get_groups_current_create_step() )
+		return true;
+
+	return false;
+}
+
+function bp_is_first_group_creation_step() {
+	global $bp;
+
+	$keys       = array_keys( $bp->groups->group_creation_steps );
+	$first_step = array_shift( $keys );
+
+	if ( $first_step == bp_get_groups_current_create_step() )
+		return true;
+
+	return false;
+}
+
+function bp_new_group_invite_friend_list() {
+	echo bp_get_new_group_invite_friend_list();
+}
+	function bp_get_new_group_invite_friend_list( $args = '' ) {
+		global $bp;
+
+		if ( !bp_is_active( 'friends' ) )
+			return false;
+
+		$defaults = array(
+			'group_id'  => false,
+			'separator' => 'li'
+		);
+
+		$r = wp_parse_args( $args, $defaults );
+		extract( $r, EXTR_SKIP );
+
+		if ( empty( $group_id ) )
+			$group_id = !empty( $bp->groups->new_group_id ) ? $bp->groups->new_group_id : $bp->groups->current_group->id;
+
+		if ( $friends = friends_get_friends_invite_list( bp_loggedin_user_id(), $group_id ) ) {
+			$invites = groups_get_invites_for_group( bp_loggedin_user_id(), $group_id );
+
+			for ( $i = 0, $count = count( $friends ); $i < $count; ++$i ) {
+				$checked = '';
+
+				if ( !empty( $invites ) ) {
+					if ( in_array( $friends[$i]['id'], $invites ) )
+						$checked = ' checked="checked"';
+				}
+
+				$items[] = '<' . $separator . '><input' . $checked . ' type="checkbox" name="friends[]" id="f-' . $friends[$i]['id'] . '" value="' . esc_attr( $friends[$i]['id'] ) . '" /> ' . $friends[$i]['full_name'] . '</' . $separator . '>';
+			}
+		}
+
+		if ( !empty( $items ) )
+			return implode( "\n", (array) $items );
+
+		return false;
+	}
+
+function bp_directory_groups_search_form() {
+
+	$default_search_value = bp_get_search_default_text( 'groups' );
+	$search_value         = !empty( $_REQUEST['s'] ) ? stripslashes( $_REQUEST['s'] ) : $default_search_value;
+
+	$search_form_html = '<form action="" method="get" id="search-groups-form">
+		<label><input type="text" name="s" id="groups_search" placeholder="'. esc_attr( $search_value ) .'" /></label>
+		<input type="submit" id="groups_search_submit" name="groups_search_submit" value="'. __( 'Search', 'buddypress' ) .'" />
+	</form>';
+
+	echo apply_filters( 'bp_directory_groups_search_form', $search_form_html );
+
+}
+
+/**
+ * Displays group header tabs
+ *
+ * @package BuddyPress
+ * @todo Deprecate?
+ */
+function bp_groups_header_tabs() {
+	global $bp;?>
+
+	<li<?php if ( !bp_action_variable( 0 ) || bp_is_action_variable( 'recently-active', 0 ) ) : ?> class="current"<?php endif; ?>><a href="<?php echo trailingslashit( bp_displayed_user_domain() . bp_get_groups_slug() . '/my-groups/recently-active' ) ?>"><?php _e( 'Recently Active', 'buddypress' ) ?></a></li>
+	<li<?php if ( bp_is_action_variable( 'recently-joined', 0 ) ) : ?> class="current"<?php endif; ?>><a href="<?php echo trailingslashit( bp_displayed_user_domain() . bp_get_groups_slug() . '/my-groups/recently-joined' ) ?>"><?php _e( 'Recently Joined', 'buddypress' ) ?></a></li>
+	<li<?php if ( bp_is_action_variable( 'most-popular', 0 ) ) : ?> class="current"<?php endif; ?>><a href="<?php echo trailingslashit( bp_displayed_user_domain() . bp_get_groups_slug() . '/my-groups/most-popular' ) ?>"><?php _e( 'Most Popular', 'buddypress' ) ?></a></li>
+	<li<?php if ( bp_is_action_variable( 'admin-of', 0 ) ) : ?> class="current"<?php endif; ?>><a href="<?php echo trailingslashit( bp_displayed_user_domain() . bp_get_groups_slug() . '/my-groups/admin-of' ) ?>"><?php _e( 'Administrator Of', 'buddypress' ) ?></a></li>
+	<li<?php if ( bp_is_action_variable( 'mod-of', 0 ) ) : ?> class="current"<?php endif; ?>><a href="<?php echo trailingslashit( bp_displayed_user_domain() . bp_get_groups_slug() . '/my-groups/mod-of' ) ?>"><?php _e( 'Moderator Of', 'buddypress' ) ?></a></li>
+	<li<?php if ( bp_is_action_variable( 'alphabetically' ) ) : ?> class="current"<?php endif; ?>><a href="<?php echo trailingslashit( bp_displayed_user_domain() . bp_get_groups_slug() . '/my-groups/alphabetically' ) ?>"><?php _e( 'Alphabetically', 'buddypress' ) ?></a></li>
+
+<?php
+	do_action( 'groups_header_tabs' );
+}
+
+/**
+ * Displays group filter titles
+ *
+ * @package BuddyPress
+ * @todo Deprecate?
+ */
+function bp_groups_filter_title() {
+	$current_filter = bp_action_variable( 0 );
+
+	switch ( $current_filter ) {
+		case 'recently-active': default:
+			_e( 'Recently Active', 'buddypress' );
+			break;
+		case 'recently-joined':
+			_e( 'Recently Joined', 'buddypress' );
+			break;
+		case 'most-popular':
+			_e( 'Most Popular', 'buddypress' );
+			break;
+		case 'admin-of':
+			_e( 'Administrator Of', 'buddypress' );
+			break;
+		case 'mod-of':
+			_e( 'Moderator Of', 'buddypress' );
+			break;
+		case 'alphabetically':
+			_e( 'Alphabetically', 'buddypress' );
+		break;
+	}
+	do_action( 'bp_groups_filter_title' );
+}
+
+function bp_is_group_admin_screen( $slug ) {
+	if ( !bp_is_groups_component() || !bp_is_current_action( 'admin' ) )
+		return false;
+
+	if ( bp_is_action_variable( $slug ) )
+		return true;
+
+	return false;
+}
+
+/**
+ * Echoes the current group admin tab slug
+ *
+ * @since BuddyPress (1.6)
+ */
+function bp_group_current_admin_tab() {
+	echo bp_get_group_current_admin_tab();
+}
+	/**
+	 * Returns the current group admin tab slug
+	 *
+	 * @since BuddyPress (1.6)
+	 *
+	 * @uses apply_filters() Filter bp_get_current_group_admin_tab to modify return value
+	 * @return string $tab The current tab's slug
+	 */
+	function bp_get_group_current_admin_tab() {
+		if ( bp_is_groups_component() && bp_is_current_action( 'admin' ) ) {
+			$tab = bp_action_variable( 0 );
+		} else {
+			$tab = '';
+		}
+
+		return apply_filters( 'bp_get_current_group_admin_tab', $tab );
+	}
+
+/************************************************************************************
+ * Group Avatar Template Tags
+ **/
+
+function bp_group_current_avatar() {
+	global $bp;
+
+	if ( $bp->groups->current_group->avatar_full ) { ?>
+
+		<img src="<?php echo esc_url( $bp->groups->current_group->avatar_full ); ?>" alt="<?php _e( 'Group Avatar', 'buddypress' ) ?>" class="avatar" />
+
+	<?php } else { ?>
+
+		<img src="<?php echo esc_url( $bp->groups->image_base . '/none.gif' ); ?>" alt="<?php _e( 'No Group Avatar', 'buddypress' ) ?>" class="avatar" />
+
+	<?php }
+}
+
+function bp_get_group_has_avatar() {
+	global $bp;
+
+	if ( !empty( $_FILES ) || !bp_core_fetch_avatar( array( 'item_id' => $bp->groups->current_group->id, 'object' => 'group', 'no_grav' => true ) ) )
+		return false;
+
+	return true;
+}
+
+function bp_group_avatar_delete_link() {
+	echo bp_get_group_avatar_delete_link();
+}
+	function bp_get_group_avatar_delete_link() {
+		global $bp;
+
+		return apply_filters( 'bp_get_group_avatar_delete_link', wp_nonce_url( bp_get_group_permalink( $bp->groups->current_group ) . 'admin/group-avatar/delete', 'bp_group_avatar_delete' ) );
+	}
+
+function bp_group_avatar_edit_form() {
+	groups_avatar_upload();
+}
+
+function bp_custom_group_boxes() {
+	do_action( 'groups_custom_group_boxes' );
+}
+
+function bp_custom_group_admin_tabs() {
+	do_action( 'groups_custom_group_admin_tabs' );
+}
+
+function bp_custom_group_fields_editable() {
+	do_action( 'groups_custom_group_fields_editable' );
+}
+
+function bp_custom_group_fields() {
+	do_action( 'groups_custom_group_fields' );
+}
+
+
+/************************************************************************************
+ * Membership Requests Template Tags
+ **/
+
+class BP_Groups_Membership_Requests_Template {
+	var $current_request = -1;
+	var $request_count;
+	var $requests;
+	var $request;
+
+	var $in_the_loop;
+
+	var $pag_page;
+	var $pag_num;
+	var $pag_links;
+	var $total_request_count;
+
+	function __construct( $group_id, $per_page, $max ) {
+
+		$this->pag_page = isset( $_REQUEST['mrpage'] ) ? intval( $_REQUEST['mrpage'] ) : 1;
+		$this->pag_num  = isset( $_REQUEST['num'] ) ? intval( $_REQUEST['num'] ) : $per_page;
+		$this->requests = BP_Groups_Group::get_membership_requests( $group_id, $this->pag_num, $this->pag_page );
+
+		if ( !$max || $max >= (int) $this->requests['total'] )
+			$this->total_request_count = (int) $this->requests['total'];
+		else
+			$this->total_request_count = (int) $max;
+
+		$this->requests = $this->requests['requests'];
+
+		if ( $max ) {
+			if ( $max >= count($this->requests) )
+				$this->request_count = count($this->requests);
+			else
+				$this->request_count = (int) $max;
+		} else {
+			$this->request_count = count($this->requests);
+		}
+
+		$this->pag_links = paginate_links( array(
+			'base' => add_query_arg( 'mrpage', '%#%' ),
+			'format' => '',
+			'total' => ceil( $this->total_request_count / $this->pag_num ),
+			'current' => $this->pag_page,
+			'prev_text' => '&larr;',
+			'next_text' => '&rarr;',
+			'mid_size' => 1
+		) );
+	}
+
+	function has_requests() {
+		if ( $this->request_count )
+			return true;
+
+		return false;
+	}
+
+	function next_request() {
+		$this->current_request++;
+		$this->request = $this->requests[$this->current_request];
+
+		return $this->request;
+	}
+
+	function rewind_requests() {
+		$this->current_request = -1;
+
+		if ( $this->request_count > 0 )
+			$this->request = $this->requests[0];
+	}
+
+	function requests() {
+		if ( $this->current_request + 1 < $this->request_count ) {
+			return true;
+		} elseif ( $this->current_request + 1 == $this->request_count ) {
+			do_action('group_request_loop_end');
+			// Do some cleaning up after the loop
+			$this->rewind_requests();
+		}
+
+		$this->in_the_loop = false;
+		return false;
+	}
+
+	function the_request() {
+		$this->in_the_loop = true;
+		$this->request     = $this->next_request();
+
+		if ( 0 == $this->current_request ) // loop has just started
+			do_action('group_request_loop_start');
+	}
+}
+
+function bp_group_has_membership_requests( $args = '' ) {
+	global $requests_template, $groups_template;
+
+	$defaults = array(
+		'group_id' => $groups_template->group->id,
+		'per_page' => 10,
+		'max'      => false
+	);
+
+	$r = wp_parse_args( $args, $defaults );
+	extract( $r, EXTR_SKIP );
+
+	$requests_template = new BP_Groups_Membership_Requests_Template( $group_id, $per_page, $max );
+	return apply_filters( 'bp_group_has_membership_requests', $requests_template->has_requests(), $requests_template );
+}
+
+function bp_group_membership_requests() {
+	global $requests_template;
+
+	return $requests_template->requests();
+}
+
+function bp_group_the_membership_request() {
+	global $requests_template;
+
+	return $requests_template->the_request();
+}
+
+function bp_group_request_user_avatar_thumb() {
+	global $requests_template;
+
+	echo apply_filters( 'bp_group_request_user_avatar_thumb', bp_core_fetch_avatar( array( 'item_id' => $requests_template->request->user_id, 'type' => 'thumb', 'alt' => sprintf( __( 'Profile picture of %s', 'buddypress' ), bp_core_get_user_displayname( $requests_template->request->user_id ) ) ) ) );
+}
+
+function bp_group_request_reject_link() {
+	echo bp_get_group_request_reject_link();
+}
+	function bp_get_group_request_reject_link() {
+		global $requests_template, $groups_template;
+
+		return apply_filters( 'bp_get_group_request_reject_link', wp_nonce_url( bp_get_group_permalink( $groups_template->group ) . 'admin/membership-requests/reject/' . $requests_template->request->id, 'groups_reject_membership_request' ) );
+	}
+
+function bp_group_request_accept_link() {
+	echo bp_get_group_request_accept_link();
+}
+	function bp_get_group_request_accept_link() {
+		global $requests_template, $groups_template;
+
+		return apply_filters( 'bp_get_group_request_accept_link', wp_nonce_url( bp_get_group_permalink( $groups_template->group ) . 'admin/membership-requests/accept/' . $requests_template->request->id, 'groups_accept_membership_request' ) );
+	}
+
+function bp_group_request_user_link() {
+	echo bp_get_group_request_user_link();
+}
+	function bp_get_group_request_user_link() {
+		global $requests_template;
+
+		return apply_filters( 'bp_get_group_request_user_link', bp_core_get_userlink( $requests_template->request->user_id ) );
+	}
+
+function bp_group_request_time_since_requested() {
+	global $requests_template;
+
+	echo apply_filters( 'bp_group_request_time_since_requested', sprintf( __( 'requested %s', 'buddypress' ), bp_core_time_since( strtotime( $requests_template->request->date_modified ) ) ) );
+}
+
+function bp_group_request_comment() {
+	global $requests_template;
+
+	echo apply_filters( 'bp_group_request_comment', strip_tags( stripslashes( $requests_template->request->comments ) ) );
+}
+
+/************************************************************************************
+ * Invite Friends Template Tags
+ **/
+
+class BP_Groups_Invite_Template {
+	var $current_invite = -1;
+	var $invite_count;
+	var $invites;
+	var $invite;
+
+	var $in_the_loop;
+
+	var $pag_page;
+	var $pag_num;
+	var $pag_links;
+	var $total_invite_count;
+
+	function __construct( $user_id, $group_id ) {
+		$this->invites      = groups_get_invites_for_group( $user_id, $group_id );
+		$this->invite_count = count( $this->invites );
+	}
+
+	function has_invites() {
+		if ( $this->invite_count )
+			return true;
+
+		return false;
+	}
+
+	function next_invite() {
+		$this->current_invite++;
+		$this->invite = $this->invites[$this->current_invite];
+
+		return $this->invite;
+	}
+
+	function rewind_invites() {
+		$this->current_invite = -1;
+		if ( $this->invite_count > 0 )
+			$this->invite = $this->invites[0];
+	}
+
+	function invites() {
+		if ( $this->current_invite + 1 < $this->invite_count ) {
+			return true;
+		} elseif ( $this->current_invite + 1 == $this->invite_count ) {
+			do_action('loop_end');
+			// Do some cleaning up after the loop
+			$this->rewind_invites();
+		}
+
+		$this->in_the_loop = false;
+		return false;
+	}
+
+	function the_invite() {
+		global $group_id;
+
+		$this->in_the_loop      = true;
+		$user_id                = $this->next_invite();
+		$this->invite           = new stdClass;
+		$this->invite->user     = new BP_Core_User( $user_id );
+		$this->invite->group_id = $group_id; // Globaled in bp_group_has_invites()
+
+		if ( 0 == $this->current_invite ) // loop has just started
+			do_action('loop_start');
+	}
+}
+
+function bp_group_has_invites( $args = '' ) {
+	global $bp, $invites_template, $group_id;
+
+	$defaults = array(
+		'group_id' => false,
+		'user_id' => bp_loggedin_user_id()
+	);
+
+	$r = wp_parse_args( $args, $defaults );
+	extract( $r, EXTR_SKIP );
+
+	if ( !$group_id ) {
+		// Backwards compatibility
+		if ( !empty( $bp->groups->current_group ) )
+			$group_id = $bp->groups->current_group->id;
+
+		if ( !empty( $bp->groups->new_group_id ) )
+			$group_id = $bp->groups->new_group_id;
+	}
+
+	if ( !$group_id )
+		return false;
+
+	$invites_template = new BP_Groups_Invite_Template( $user_id, $group_id );
+	return apply_filters( 'bp_group_has_invites', $invites_template->has_invites(), $invites_template );
+}
+
+function bp_group_invites() {
+	global $invites_template;
+
+	return $invites_template->invites();
+}
+
+function bp_group_the_invite() {
+	global $invites_template;
+
+	return $invites_template->the_invite();
+}
+
+function bp_group_invite_item_id() {
+	echo bp_get_group_invite_item_id();
+}
+	function bp_get_group_invite_item_id() {
+		global $invites_template;
+
+		return apply_filters( 'bp_get_group_invite_item_id', 'uid-' . $invites_template->invite->user->id );
+	}
+
+function bp_group_invite_user_avatar() {
+	echo bp_get_group_invite_user_avatar();
+}
+	function bp_get_group_invite_user_avatar() {
+		global $invites_template;
+
+		return apply_filters( 'bp_get_group_invite_user_avatar', $invites_template->invite->user->avatar_thumb );
+	}
+
+function bp_group_invite_user_link() {
+	echo bp_get_group_invite_user_link();
+}
+	function bp_get_group_invite_user_link() {
+		global $invites_template;
+
+		return apply_filters( 'bp_get_group_invite_user_link', bp_core_get_userlink( $invites_template->invite->user->id ) );
+	}
+
+function bp_group_invite_user_last_active() {
+	echo bp_get_group_invite_user_last_active();
+}
+	function bp_get_group_invite_user_last_active() {
+		global $invites_template;
+
+		return apply_filters( 'bp_get_group_invite_user_last_active', $invites_template->invite->user->last_active );
+	}
+
+function bp_group_invite_user_remove_invite_url() {
+	echo bp_get_group_invite_user_remove_invite_url();
+}
+	function bp_get_group_invite_user_remove_invite_url() {
+		global $invites_template;
+
+		return wp_nonce_url( site_url( bp_get_groups_slug() . '/' . $invites_template->invite->group_id . '/invites/remove/' . $invites_template->invite->user->id ), 'groups_invite_uninvite_user' );
+	}
+
+/***
+ * Groups RSS Feed Template Tags
+ */
+
+/**
+ * Hook group activity feed to <head>
+ *
+ * @since BuddyPress (1.5)
+ */
+function bp_groups_activity_feed() {
+	if ( !bp_is_active( 'groups' ) || !bp_is_active( 'activity' ) || !bp_is_group() )
+		return; ?>
+
+	<link rel="alternate" type="application/rss+xml" title="<?php bloginfo( 'name' ) ?> | <?php bp_current_group_name() ?> | <?php _e( 'Group Activity RSS Feed', 'buddypress' ) ?>" href="<?php bp_group_activity_feed_link() ?>" />
+
+<?php
+}
+add_action( 'bp_head', 'bp_groups_activity_feed' );
+
+function bp_group_activity_feed_link() {
+	echo bp_get_group_activity_feed_link();
+}
+	function bp_get_group_activity_feed_link() {
+		global $bp;
+
+		return apply_filters( 'bp_get_group_activity_feed_link', bp_get_group_permalink( $bp->groups->current_group ) . 'feed/' );
+	}
+
+/**
+ * Echoes the output of bp_get_current_group_id()
+ *
+ * @package BuddyPress
+ * @since BuddyPress (1.5)
+ */
+function bp_current_group_id() {
+	echo bp_get_current_group_id();
+}
+	/**
+	 * Returns the ID of the current group
+	 *
+	 * @package BuddyPress
+	 * @since BuddyPress (1.5)
+	 * @uses apply_filters() Filter bp_get_current_group_id to modify this output
+	 *
+	 * @return int $current_group_id The id of the current group, if there is one
+	 */
+	function bp_get_current_group_id() {
+		$current_group = groups_get_current_group();
+
+		$current_group_id = isset( $current_group->id ) ? (int) $current_group->id : 0;
+
+		return apply_filters( 'bp_get_current_group_id', $current_group_id, $current_group );
+	}
+
+/**
+ * Echoes the output of bp_get_current_group_slug()
+ *
+ * @package BuddyPress
+ * @since BuddyPress (1.5)
+ */
+function bp_current_group_slug() {
+	echo bp_get_current_group_slug();
+}
+	/**
+	 * Returns the slug of the current group
+	 *
+	 * @package BuddyPress
+	 * @since BuddyPress (1.5)
+	 * @uses apply_filters() Filter bp_get_current_group_slug to modify this output
+	 *
+	 * @return string $current_group_slug The slug of the current group, if there is one
+	 */
+	function bp_get_current_group_slug() {
+		$current_group = groups_get_current_group();
+
+		$current_group_slug = isset( $current_group->slug ) ? $current_group->slug : '';
+
+		return apply_filters( 'bp_get_current_group_slug', $current_group_slug, $current_group );
+	}
+
+/**
+ * Echoes the output of bp_get_current_group_name()
+ *
+ * @package BuddyPress
+ */
+function bp_current_group_name() {
+	echo bp_get_current_group_name();
+}
+	/**
+	 * Returns the name of the current group
+	 *
+	 * @package BuddyPress
+	 * @since BuddyPress (1.5)
+	 * @uses apply_filters() Filter bp_get_current_group_name to modify this output
+	 *
+	 * @return string The name of the current group, if there is one
+	 */
+	function bp_get_current_group_name() {
+		global $bp;
+
+		$name = apply_filters( 'bp_get_group_name', $bp->groups->current_group->name );
+		return apply_filters( 'bp_get_current_group_name', $name );
+	}
+
+function bp_groups_action_link( $action = '', $query_args = '', $nonce = false ) {
+	echo bp_get_groups_action_link( $action, $query_args, $nonce );
+}
+	function bp_get_groups_action_link( $action = '', $query_args = '', $nonce = false ) {
+		global $bp;
+
+		// Must be a group
+		if ( empty( $bp->groups->current_group->id ) )
+			return;
+
+		// Append $action to $url if provided
+		if ( !empty( $action ) )
+			$url = bp_get_group_permalink( groups_get_current_group() ) . $action;
+		else
+			$url = bp_get_group_permalink( groups_get_current_group() );
+
+		// Add a slash at the end of our user url
+		$url = trailingslashit( $url );
+
+		// Add possible query arg
+		if ( !empty( $query_args ) && is_array( $query_args ) )
+			$url = add_query_arg( $query_args, $url );
+
+		// To nonce, or not to nonce...
+		if ( true === $nonce )
+			$url = wp_nonce_url( $url );
+		elseif ( is_string( $nonce ) )
+			$url = wp_nonce_url( $url, $nonce );
+
+		// Return the url, if there is one
+		if ( !empty( $url ) )
+			return $url;
+	}
Index: /tags/1.9/bp-groups/bp-groups-widgets.php
===================================================================
--- /tags/1.9/bp-groups/bp-groups-widgets.php	(revision 7684)
+++ /tags/1.9/bp-groups/bp-groups-widgets.php	(revision 7684)
@@ -0,0 +1,210 @@
+<?php
+
+/**
+ * BuddyPress Groups Widgets
+ *
+ * @package BuddyPress
+ * @subpackage GroupsWidgets
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/* Register widgets for groups component */
+function groups_register_widgets() {
+	add_action('widgets_init', create_function('', 'return register_widget("BP_Groups_Widget");') );
+}
+add_action( 'bp_register_widgets', 'groups_register_widgets' );
+
+/*** GROUPS WIDGET *****************/
+
+class BP_Groups_Widget extends WP_Widget {
+	function __construct() {
+		$widget_ops = array(
+			'description' => __( 'A dynamic list of recently active, popular, and newest groups', 'buddypress' ),
+			'classname' => 'widget_bp_groups_widget buddypress widget',
+		);
+		parent::__construct( false, _x( '(BuddyPress) Groups', 'widget name', 'buddypress' ), $widget_ops );
+
+		if ( is_active_widget( false, false, $this->id_base ) && !is_admin() && !is_network_admin() ) {
+			$min = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min';
+			wp_enqueue_script( 'groups_widget_groups_list-js', BP_PLUGIN_URL . "bp-groups/js/widget-groups{$min}.js", array( 'jquery' ), bp_get_version() );
+		}
+	}
+
+	/**
+	 * PHP4 constructor
+	 *
+	 * For backward compatibility only
+	 */
+	function bp_groups_widget() {
+		$this->_construct();
+	}
+
+	function widget( $args, $instance ) {
+		$user_id = apply_filters( 'bp_group_widget_user_id', '0' );
+
+		extract( $args );
+
+		if ( empty( $instance['group_default'] ) )
+			$instance['group_default'] = 'popular';
+
+		if ( empty( $instance['title'] ) )
+			$instance['title'] = __( 'Groups', 'buddypress' );
+
+		$title = apply_filters( 'widget_title', $instance['title'] );
+
+		echo $before_widget;
+
+		$title = !empty( $instance['link_title'] ) ? '<a href="' . trailingslashit( bp_get_root_domain() . '/' . bp_get_groups_root_slug() ) . '">' . $title . '</a>' : $title;
+
+		echo $before_title . $title . $after_title; ?>
+
+		<?php if ( bp_has_groups( 'user_id=' . $user_id . '&type=' . $instance['group_default'] . '&max=' . $instance['max_groups'] ) ) : ?>
+			<div class="item-options" id="groups-list-options">
+				<a href="<?php bp_groups_directory_permalink(); ?>" id="newest-groups"<?php if ( $instance['group_default'] == 'newest' ) : ?> class="selected"<?php endif; ?>><?php _e("Newest", 'buddypress') ?></a> |
+				<a href="<?php bp_groups_directory_permalink(); ?>" id="recently-active-groups"<?php if ( $instance['group_default'] == 'active' ) : ?> class="selected"<?php endif; ?>><?php _e("Active", 'buddypress') ?></a> |
+				<a href="<?php bp_groups_directory_permalink(); ?>" id="popular-groups" <?php if ( $instance['group_default'] == 'popular' ) : ?> class="selected"<?php endif; ?>><?php _e("Popular", 'buddypress') ?></a>
+			</div>
+
+			<ul id="groups-list" class="item-list">
+				<?php while ( bp_groups() ) : bp_the_group(); ?>
+					<li <?php bp_group_class(); ?>>
+						<div class="item-avatar">
+							<a href="<?php bp_group_permalink() ?>" title="<?php bp_group_name() ?>"><?php bp_group_avatar_thumb() ?></a>
+						</div>
+
+						<div class="item">
+							<div class="item-title"><a href="<?php bp_group_permalink() ?>" title="<?php bp_group_name() ?>"><?php bp_group_name() ?></a></div>
+							<div class="item-meta">
+								<span class="activity">
+								<?php
+									if ( 'newest' == $instance['group_default'] )
+										printf( __( 'created %s', 'buddypress' ), bp_get_group_date_created() );
+									if ( 'active' == $instance['group_default'] )
+										printf( __( 'active %s', 'buddypress' ), bp_get_group_last_active() );
+									else if ( 'popular' == $instance['group_default'] )
+										bp_group_member_count();
+								?>
+								</span>
+							</div>
+						</div>
+					</li>
+
+				<?php endwhile; ?>
+			</ul>
+			<?php wp_nonce_field( 'groups_widget_groups_list', '_wpnonce-groups' ); ?>
+			<input type="hidden" name="groups_widget_max" id="groups_widget_max" value="<?php echo esc_attr( $instance['max_groups'] ); ?>" />
+
+		<?php else: ?>
+
+			<div class="widget-error">
+				<?php _e('There are no groups to display.', 'buddypress') ?>
+			</div>
+
+		<?php endif; ?>
+
+		<?php echo $after_widget; ?>
+	<?php
+	}
+
+	function update( $new_instance, $old_instance ) {
+		$instance = $old_instance;
+
+		$instance['title']         = strip_tags( $new_instance['title'] );
+		$instance['max_groups']    = strip_tags( $new_instance['max_groups'] );
+		$instance['group_default'] = strip_tags( $new_instance['group_default'] );
+		$instance['link_title']    = (bool)$new_instance['link_title'];
+
+		return $instance;
+	}
+
+	function form( $instance ) {
+		$defaults = array(
+			'title'         => __( 'Groups', 'buddypress' ),
+			'max_groups'    => 5,
+			'group_default' => 'active',
+			'link_title'    => false
+		);
+		$instance = wp_parse_args( (array) $instance, $defaults );
+
+		$title 	       = strip_tags( $instance['title'] );
+		$max_groups    = strip_tags( $instance['max_groups'] );
+		$group_default = strip_tags( $instance['group_default'] );
+		$link_title    = (bool)$instance['link_title'];
+		?>
+
+		<p><label for="bp-groups-widget-title"><?php _e('Title:', 'buddypress'); ?> <input class="widefat" id="<?php echo $this->get_field_id( 'title' ); ?>" name="<?php echo $this->get_field_name( 'title' ); ?>" type="text" value="<?php echo esc_attr( $title ); ?>" style="width: 100%" /></label></p>
+
+		<p><label for="<?php echo $this->get_field_name('link_title') ?>"><input type="checkbox" name="<?php echo $this->get_field_name('link_title') ?>" value="1" <?php checked( $link_title ) ?> /> <?php _e( 'Link widget title to Groups directory', 'buddypress' ) ?></label></p>
+
+		<p><label for="bp-groups-widget-groups-max"><?php _e('Max groups to show:', 'buddypress'); ?> <input class="widefat" id="<?php echo $this->get_field_id( 'max_groups' ); ?>" name="<?php echo $this->get_field_name( 'max_groups' ); ?>" type="text" value="<?php echo esc_attr( $max_groups ); ?>" style="width: 30%" /></label></p>
+
+		<p>
+			<label for="bp-groups-widget-groups-default"><?php _e('Default groups to show:', 'buddypress'); ?>
+			<select name="<?php echo $this->get_field_name( 'group_default' ); ?>">
+				<option value="newest" <?php if ( $group_default == 'newest' ) : ?>selected="selected"<?php endif; ?>><?php _e( 'Newest', 'buddypress' ) ?></option>
+				<option value="active" <?php if ( $group_default == 'active' ) : ?>selected="selected"<?php endif; ?>><?php _e( 'Active', 'buddypress' ) ?></option>
+				<option value="popular"  <?php if ( $group_default == 'popular' ) : ?>selected="selected"<?php endif; ?>><?php _e( 'Popular', 'buddypress' ) ?></option>
+			</select>
+			</label>
+		</p>
+	<?php
+	}
+}
+
+function groups_ajax_widget_groups_list() {
+
+	check_ajax_referer('groups_widget_groups_list');
+
+	switch ( $_POST['filter'] ) {
+		case 'newest-groups':
+			$type = 'newest';
+		break;
+		case 'recently-active-groups':
+			$type = 'active';
+		break;
+		case 'popular-groups':
+			$type = 'popular';
+		break;
+	}
+
+	if ( bp_has_groups( 'type=' . $type . '&per_page=' . $_POST['max_groups'] . '&max=' . $_POST['max_groups'] ) ) : ?>
+		<?php echo "0[[SPLIT]]"; ?>
+		<?php while ( bp_groups() ) : bp_the_group(); ?>
+			<li <?php bp_group_class(); ?>>
+				<div class="item-avatar">
+					<a href="<?php bp_group_permalink() ?>"><?php bp_group_avatar_thumb() ?></a>
+				</div>
+
+				<div class="item">
+					<div class="item-title"><a href="<?php bp_group_permalink() ?>" title="<?php bp_group_name() ?>"><?php bp_group_name() ?></a></div>
+					<div class="item-meta">
+						<span class="activity">
+							<?php
+							if ( 'newest-groups' == $_POST['filter'] ) {
+								printf( __( 'created %s', 'buddypress' ), bp_get_group_date_created() );
+							} else if ( 'recently-active-groups' == $_POST['filter'] ) {
+								printf( __( 'active %s', 'buddypress' ), bp_get_group_last_active() );
+							} else if ( 'popular-groups' == $_POST['filter'] ) {
+								bp_group_member_count();
+							}
+							?>
+						</span>
+					</div>
+				</div>
+			</li>
+		<?php endwhile; ?>
+
+		<?php wp_nonce_field( 'groups_widget_groups_list', '_wpnonce-groups' ); ?>
+		<input type="hidden" name="groups_widget_max" id="groups_widget_max" value="<?php echo esc_attr( $_POST['max_groups'] ); ?>" />
+
+	<?php else: ?>
+
+		<?php echo "-1[[SPLIT]]<li>" . __("No groups matched the current filter.", 'buddypress'); ?>
+
+	<?php endif;
+
+}
+add_action( 'wp_ajax_widget_groups_list',        'groups_ajax_widget_groups_list' );
+add_action( 'wp_ajax_nopriv_widget_groups_list', 'groups_ajax_widget_groups_list' );
Index: /tags/1.9/bp-groups/js/widget-groups.js
===================================================================
--- /tags/1.9/bp-groups/js/widget-groups.js	(revision 7684)
+++ /tags/1.9/bp-groups/js/widget-groups.js	(revision 7684)
@@ -0,0 +1,49 @@
+jQuery(document).ready( function() {
+	jQuery(".widget div#groups-list-options a").on('click',
+		function() {
+			var link = this;
+			jQuery(link).addClass('loading');
+
+			jQuery(".widget div#groups-list-options a").removeClass("selected");
+			jQuery(this).addClass('selected');
+
+			jQuery.post( ajaxurl, {
+				action: 'widget_groups_list',
+				'cookie': encodeURIComponent(document.cookie),
+				'_wpnonce': jQuery("input#_wpnonce-groups").val(),
+				'max_groups': jQuery("input#groups_widget_max").val(),
+				'filter': jQuery(this).attr('id')
+			},
+			function(response)
+			{
+				jQuery(link).removeClass('loading');
+				groups_wiget_response(response);
+			});
+
+			return false;
+		}
+	);
+});
+
+function groups_wiget_response(response) {
+	response = response.substr(0, response.length-1);
+	response = response.split('[[SPLIT]]');
+
+	if ( response[0] != "-1" ) {
+		jQuery(".widget ul#groups-list").fadeOut(200,
+			function() {
+				jQuery(".widget ul#groups-list").html(response[1]);
+				jQuery(".widget ul#groups-list").fadeIn(200);
+			}
+		);
+
+	} else {
+		jQuery(".widget ul#groups-list").fadeOut(200,
+			function() {
+				var message = '<p>' + response[1] + '</p>';
+				jQuery(".widget ul#groups-list").html(message);
+				jQuery(".widget ul#groups-list").fadeIn(200);
+			}
+		);
+	}
+}
Index: /tags/1.9/bp-groups/js/widget-groups.min.js
===================================================================
--- /tags/1.9/bp-groups/js/widget-groups.min.js	(revision 7684)
+++ /tags/1.9/bp-groups/js/widget-groups.min.js	(revision 7684)
@@ -0,0 +1,1 @@
+jQuery(document).ready(function(){jQuery(".widget div#groups-list-options a").on("click",function(){var a=this;jQuery(a).addClass("loading");jQuery(".widget div#groups-list-options a").removeClass("selected");jQuery(this).addClass("selected");jQuery.post(ajaxurl,{action:"widget_groups_list",cookie:encodeURIComponent(document.cookie),_wpnonce:jQuery("input#_wpnonce-groups").val(),max_groups:jQuery("input#groups_widget_max").val(),filter:jQuery(this).attr("id")},function(b){jQuery(a).removeClass("loading");groups_wiget_response(b)});return false})});function groups_wiget_response(a){a=a.substr(0,a.length-1);a=a.split("[[SPLIT]]");if(a[0]!="-1"){jQuery(".widget ul#groups-list").fadeOut(200,function(){jQuery(".widget ul#groups-list").html(a[1]);jQuery(".widget ul#groups-list").fadeIn(200)})}else{jQuery(".widget ul#groups-list").fadeOut(200,function(){var b="<p>"+a[1]+"</p>";jQuery(".widget ul#groups-list").html(b);jQuery(".widget ul#groups-list").fadeIn(200)})}};
Index: /tags/1.9/bp-languages/buddypress.pot
===================================================================
--- /tags/1.9/bp-languages/buddypress.pot	(revision 7684)
+++ /tags/1.9/bp-languages/buddypress.pot	(revision 7684)
@@ -0,0 +1,6556 @@
+# Copyright (C) 2013 BuddyPress
+# This file is distributed under the same license as the BuddyPress package.
+msgid ""
+msgstr ""
+"Project-Id-Version: BuddyPress \n"
+"Report-Msgid-Bugs-To: http://wppolyglots.wordpress.com\n"
+"POT-Creation-Date: 2013-12-17 00:35:15+00:00\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"PO-Revision-Date: 2013-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+
+#: bp-activity/bp-activity-actions.php:157
+msgid "Activity deleted successfully"
+msgstr ""
+
+#: bp-activity/bp-activity-actions.php:159
+msgid "There was an error when deleting that activity"
+msgstr ""
+
+#: bp-activity/bp-activity-actions.php:214
+msgid "The activity item has been marked as spam and is no longer visible."
+msgstr ""
+
+#: bp-activity/bp-activity-actions.php:269
+#: bp-templates/bp-legacy/buddypress-functions.php:625
+#: bp-themes/bp-default/_inc/ajax.php:276
+msgid "Please enter some content to post."
+msgstr ""
+
+#: bp-activity/bp-activity-actions.php:290
+msgid "Update Posted!"
+msgstr ""
+
+#: bp-activity/bp-activity-actions.php:292
+msgid "There was an error when posting your update, please try again."
+msgstr ""
+
+#: bp-activity/bp-activity-actions.php:329
+#: bp-templates/bp-legacy/buddypress-functions.php:673
+#: bp-themes/bp-default/_inc/ajax.php:324
+msgid "Please do not leave the comment area blank."
+msgstr ""
+
+#: bp-activity/bp-activity-actions.php:340
+msgid "Reply Posted!"
+msgstr ""
+
+#: bp-activity/bp-activity-actions.php:342
+#: bp-templates/bp-legacy/buddypress-functions.php:676
+#: bp-templates/bp-legacy/buddypress-functions.php:685
+#: bp-themes/bp-default/_inc/ajax.php:327
+#: bp-themes/bp-default/_inc/ajax.php:336
+msgid "There was an error posting that reply, please try again."
+msgstr ""
+
+#: bp-activity/bp-activity-actions.php:374
+msgid "Activity marked as favorite."
+msgstr ""
+
+#: bp-activity/bp-activity-actions.php:376
+msgid "There was an error marking that activity as a favorite, please try again."
+msgstr ""
+
+#: bp-activity/bp-activity-actions.php:408
+msgid "Activity removed as favorite."
+msgstr ""
+
+#: bp-activity/bp-activity-actions.php:410
+msgid "There was an error removing that activity as a favorite, please try again."
+msgstr ""
+
+#. translators: Sitewide activity RSS title - "[Site Name] | Site Wide
+#. Activity"
+
+#: bp-activity/bp-activity-actions.php:440
+msgid "%s | Site Wide Activity"
+msgstr ""
+
+#: bp-activity/bp-activity-actions.php:443
+msgid "Activity feed for the entire site."
+msgstr ""
+
+#. translators: Personal activity RSS title - "[Site Name] | [User Display
+#. Name] | Activity"
+#. translators: Group activity RSS title - "[Site Name] | [Group Name] |
+#. Activity"
+
+#: bp-activity/bp-activity-actions.php:470 bp-groups/bp-groups-actions.php:356
+msgid "%1$s | %2$s | Activity"
+msgstr ""
+
+#: bp-activity/bp-activity-actions.php:473
+msgid "Activity feed for %s."
+msgstr ""
+
+#. translators: Friends activity RSS title - "[Site Name] | [User Display Name]
+#. | Friends Activity"
+
+#: bp-activity/bp-activity-actions.php:503
+msgid "%1$s | %2$s | Friends Activity"
+msgstr ""
+
+#: bp-activity/bp-activity-actions.php:506
+msgid "Activity feed for %s's friends."
+msgstr ""
+
+#. translators: Member groups activity RSS title - "[Site Name] | [User Display
+#. Name] | Groups Activity"
+
+#: bp-activity/bp-activity-actions.php:540
+msgid "%1$s | %2$s | Group Activity"
+msgstr ""
+
+#: bp-activity/bp-activity-actions.php:543
+msgid "Public group activity feed of which %s is a member of."
+msgstr ""
+
+#. translators: User mentions activity RSS title - "[Site Name] | [User Display
+#. Name] | Mentions"
+
+#: bp-activity/bp-activity-actions.php:579
+msgid "%1$s | %2$s | Mentions"
+msgstr ""
+
+#: bp-activity/bp-activity-actions.php:582
+msgid "Activity feed mentioning %s."
+msgstr ""
+
+#. translators: User activity favorites RSS title - "[Site Name] | [User
+#. Display Name] | Favorites"
+
+#: bp-activity/bp-activity-actions.php:616
+msgid "%1$s | %2$s | Favorites"
+msgstr ""
+
+#: bp-activity/bp-activity-actions.php:619
+msgid "Activity feed of %s's favorites."
+msgstr ""
+
+#: bp-activity/bp-activity-admin.php:32 bp-activity/bp-activity-admin.php:33
+#: bp-activity/bp-activity-admin.php:871 bp-activity/bp-activity-admin.php:1204
+#: bp-activity/bp-activity-loader.php:132
+#: bp-activity/bp-activity-loader.php:261
+#: bp-activity/bp-activity-screens.php:270
+#: bp-activity/bp-activity-screens.php:437 bp-core/bp-core-admin.php:466
+msgid "Activity"
+msgstr ""
+
+#: bp-activity/bp-activity-admin.php:88
+msgid "ERROR: Please type a reply."
+msgstr ""
+
+#: bp-activity/bp-activity-admin.php:93
+msgid "ERROR: The item you are trying to reply to cannot be found, or it has been deleted."
+msgstr ""
+
+#: bp-activity/bp-activity-admin.php:209 bp-activity/bp-activity-admin.php:256
+#: bp-core/admin/bp-core-functions.php:444
+#: bp-core/admin/bp-core-functions.php:462
+#: bp-core/admin/bp-core-functions.php:481
+#: bp-core/admin/bp-core-functions.php:500 bp-groups/bp-groups-admin.php:112
+#: bp-groups/bp-groups-admin.php:148
+msgid "Overview"
+msgstr ""
+
+#: bp-activity/bp-activity-admin.php:211
+msgid "You edit activities made on your site similar to the way you edit a comment. This is useful if you need to change which page the activity links to, or when you notice that the author has made a typographical error."
+msgstr ""
+
+#: bp-activity/bp-activity-admin.php:212
+msgid "The two big editing areas for the activity title and content are fixed in place, but you can reposition all the other boxes using drag and drop, and can minimize or expand them by clicking the title bar of each box. Use the Screen Options tab to unhide more boxes (Primary Item/Secondary Item, Link, Type, Author ID) or to choose a 1- or 2-column layout for this screen."
+msgstr ""
+
+#: bp-activity/bp-activity-admin.php:213
+msgid "You can also moderate the activity from this screen using the Status box, where you can also change the timestamp of the activity."
+msgstr ""
+
+#: bp-activity/bp-activity-admin.php:218
+msgid "Item, Link, Type"
+msgstr ""
+
+#: bp-activity/bp-activity-admin.php:220
+msgid "<strong>Primary Item/Secondary Item</strong> - These identify the object that created the activity. For example, the fields could reference a comment left on a specific site. Some types of activity may only use one, or none, of these fields."
+msgstr ""
+
+#: bp-activity/bp-activity-admin.php:221
+msgid "<strong>Link</strong> - Activity generated by posts and comments, forum topics and replies, and some plugins, uses the link field for a permalink back to the content item. Some types of activity may not use this field, even if it has been set."
+msgstr ""
+
+#: bp-activity/bp-activity-admin.php:222
+msgid "<strong>Type</strong> - Each distinct kind of activity has its own type. For example, <code>created_group</code> is used when a group is created and <code>joined_group</code> is used when a user joins a group."
+msgstr ""
+
+#: bp-activity/bp-activity-admin.php:223
+msgid "For information about when and how BuddyPress uses all of these settings, see the Managing Activity link in the panel to the side."
+msgstr ""
+
+#: bp-activity/bp-activity-admin.php:228 bp-activity/bp-activity-admin.php:273
+#: bp-core/admin/bp-core-functions.php:450
+#: bp-core/admin/bp-core-functions.php:468
+#: bp-core/admin/bp-core-functions.php:487
+#: bp-core/admin/bp-core-functions.php:506 bp-groups/bp-groups-admin.php:120
+#: bp-groups/bp-groups-admin.php:164
+msgid "For more information:"
+msgstr ""
+
+#: bp-activity/bp-activity-admin.php:229
+msgid "<a href=\"http://codex.buddypress.org/buddypress-site-administration/managing-activity/\">Managing Activity</a>"
+msgstr ""
+
+#: bp-activity/bp-activity-admin.php:230 bp-activity/bp-activity-admin.php:274
+#: bp-core/admin/bp-core-functions.php:452
+#: bp-core/admin/bp-core-functions.php:470
+#: bp-core/admin/bp-core-functions.php:489
+#: bp-core/admin/bp-core-functions.php:508 bp-groups/bp-groups-admin.php:165
+msgid "<a href=\"http://buddypress.org/support/\">Support Forums</a>"
+msgstr ""
+
+#: bp-activity/bp-activity-admin.php:234
+msgctxt "activity admin edit screen"
+msgid "Status"
+msgstr ""
+
+#: bp-activity/bp-activity-admin.php:235
+msgctxt "activity admin edit screen"
+msgid "Primary Item/Secondary Item"
+msgstr ""
+
+#: bp-activity/bp-activity-admin.php:236
+msgctxt "activity admin edit screen"
+msgid "Link"
+msgstr ""
+
+#: bp-activity/bp-activity-admin.php:237
+msgctxt "activity admin edit screen"
+msgid "Type"
+msgstr ""
+
+#: bp-activity/bp-activity-admin.php:238
+msgctxt "activity admin edit screen"
+msgid "Author ID"
+msgstr ""
+
+#: bp-activity/bp-activity-admin.php:251
+msgctxt "Activity items per page (screen options)"
+msgid "Activity"
+msgstr ""
+
+#: bp-activity/bp-activity-admin.php:258
+msgid "You can manage activities made on your site similar to the way you manage comments and other content. This screen is customizable in the same ways as other management screens, and you can act on activities using the on-hover action links or the Bulk Actions."
+msgstr ""
+
+#: bp-activity/bp-activity-admin.php:259
+msgid "There are many different types of activities. Some are generated automatically by BuddyPress and other plugins, and some are entered directly by a user in the form of status update. To help manage the different activity types, use the filter dropdown box to switch between them."
+msgstr ""
+
+#: bp-activity/bp-activity-admin.php:265
+msgid "Moderating Activity"
+msgstr ""
+
+#: bp-activity/bp-activity-admin.php:267
+msgid "In the <strong>Activity</strong> column, above each activity it says &#8220;Submitted on,&#8221; followed by the date and time the activity item was generated on your site. Clicking on the date/time link will take you to that activity on your live site. Hovering over any activity gives you options to reply, edit, spam mark, or delete that activity."
+msgstr ""
+
+#: bp-activity/bp-activity-admin.php:268
+msgid "In the <strong>In Response To</strong> column, if the activity was in reply to another activity, it shows that activity's author's picture and name, and a link to that activity on your live site. If there is a small bubble, the number in it shows how many other activities are related to this one; these are usually comments. Clicking the bubble will filter the activity screen to show only related activity items."
+msgstr ""
+
+#: bp-activity/bp-activity-admin.php:593
+msgid "Editing Activity (ID #%s)"
+msgstr ""
+
+#: bp-activity/bp-activity-admin.php:604
+msgid "Action"
+msgstr ""
+
+#: bp-activity/bp-activity-admin.php:611
+msgid "Content"
+msgstr ""
+
+#: bp-activity/bp-activity-admin.php:636
+msgid "No activity found with this ID. <a href=\"%s\">Go back and try again</a>."
+msgstr ""
+
+#: bp-activity/bp-activity-admin.php:659
+msgid "View Activity"
+msgstr ""
+
+#: bp-activity/bp-activity-admin.php:667
+msgid "Approved"
+msgstr ""
+
+#: bp-activity/bp-activity-admin.php:668 bp-activity/bp-activity-admin.php:1336
+#: bp-activity/bp-activity-akismet.php:197
+#: bp-activity/bp-activity-akismet.php:226
+msgid "Spam"
+msgstr ""
+
+#. translators: Publish box date format, see http:php.net/date
+
+#: bp-activity/bp-activity-admin.php:674
+msgid "M j, Y @ G:i"
+msgstr ""
+
+#: bp-activity/bp-activity-admin.php:677
+msgid "Submitted on: <strong>%1$s</strong>"
+msgstr ""
+
+#: bp-activity/bp-activity-admin.php:677 bp-activity/bp-activity-admin.php:1329
+#: bp-forums/bp-forums-template.php:2112 bp-groups/bp-groups-admin.php:1391
+#: bp-themes/bp-default/functions.php:509 bp-xprofile/bp-xprofile-admin.php:456
+#: bp-xprofile/bp-xprofile-loader.php:193
+#: bp-xprofile/bp-xprofile-loader.php:251
+msgid "Edit"
+msgstr ""
+
+#: bp-activity/bp-activity-admin.php:690
+msgid "Update"
+msgstr ""
+
+#: bp-activity/bp-activity-admin.php:710
+msgid "Link"
+msgstr ""
+
+#: bp-activity/bp-activity-admin.php:712
+msgid "Activity generated by posts and comments, forum topics and replies, and some plugins, uses the link field for a permalink back to the content item."
+msgstr ""
+
+#: bp-activity/bp-activity-admin.php:727
+msgid "Author ID"
+msgstr ""
+
+#: bp-activity/bp-activity-admin.php:781
+msgid "Primary Item ID"
+msgstr ""
+
+#: bp-activity/bp-activity-admin.php:785
+msgid "Secondary Item ID"
+msgstr ""
+
+#: bp-activity/bp-activity-admin.php:788
+msgid "These identify the object that created this activity. For example, the fields could reference a pair of site and comment IDs."
+msgstr ""
+
+#: bp-activity/bp-activity-admin.php:828
+msgid "%s activity item has been permanently deleted."
+msgid_plural "%s activity items have been permanently deleted."
+msgstr[0] ""
+msgstr[1] ""
+
+#: bp-activity/bp-activity-admin.php:832
+msgid "An error occurred when trying to update activity ID #%s."
+msgstr ""
+
+#: bp-activity/bp-activity-admin.php:835
+msgid "Errors occurred when trying to update these activity items:"
+msgstr ""
+
+#. Translators: This is a bulleted list of item IDs
+
+#: bp-activity/bp-activity-admin.php:841
+msgid "#%s"
+msgstr ""
+
+#: bp-activity/bp-activity-admin.php:850
+msgid "%s activity item has been successfully spammed."
+msgid_plural "%s activity items have been successfully spammed."
+msgstr[0] ""
+msgstr[1] ""
+
+#: bp-activity/bp-activity-admin.php:853
+msgid "%s activity item has been successfully unspammed."
+msgid_plural "%s activity items have been successfully unspammed."
+msgstr[0] ""
+msgstr[1] ""
+
+#: bp-activity/bp-activity-admin.php:856
+msgid "The activity item has been updated succesfully."
+msgstr ""
+
+#: bp-activity/bp-activity-admin.php:869
+msgid "Activity related to ID #%s"
+msgstr ""
+
+#: bp-activity/bp-activity-admin.php:875 bp-groups/bp-groups-admin.php:645
+msgid "Search results for &#8220;%s&#8221;"
+msgstr ""
+
+#: bp-activity/bp-activity-admin.php:888
+msgid "Search all Activity"
+msgstr ""
+
+#: bp-activity/bp-activity-admin.php:899
+msgid "Reply to Activity"
+msgstr ""
+
+#: bp-activity/bp-activity-admin.php:903 bp-groups/bp-groups-admin.php:599
+#: bp-templates/bp-legacy/buddypress/activity/entry.php:102
+#: bp-templates/bp-legacy/buddypress/forums/index.php:116
+#: bp-themes/bp-default/forums/index.php:134
+#: bp-xprofile/bp-xprofile-classes.php:407
+#: bp-xprofile/bp-xprofile-classes.php:877
+msgid "Cancel"
+msgstr ""
+
+#: bp-activity/bp-activity-admin.php:904 bp-activity/bp-activity-admin.php:1326
+#: bp-templates/bp-legacy/buddypress/activity/comment.php:37
+#: bp-templates/bp-legacy/buddypress/groups/single/forum/edit.php:10
+#: bp-themes/bp-default/activity/comment.php:40
+#: bp-themes/bp-default/groups/single/forum/edit.php:10
+msgid "Reply"
+msgstr ""
+
+#: bp-activity/bp-activity-admin.php:1094
+msgid "No activities found."
+msgstr ""
+
+#: bp-activity/bp-activity-admin.php:1167 bp-groups/bp-groups-admin.php:1262
+#: bp-messages/bp-messages-template.php:477
+msgid "All"
+msgstr ""
+
+#: bp-activity/bp-activity-admin.php:1168
+msgid "Spam <span class=\"count\">(%s)</span>"
+msgstr ""
+
+#: bp-activity/bp-activity-admin.php:1184
+msgid "Mark as Spam"
+msgstr ""
+
+#: bp-activity/bp-activity-admin.php:1185
+#: bp-activity/bp-activity-admin.php:1334
+msgid "Not Spam"
+msgstr ""
+
+#: bp-activity/bp-activity-admin.php:1186
+#: bp-activity/bp-activity-admin.php:1339 bp-groups/bp-groups-admin.php:598
+msgid "Delete Permanently"
+msgstr ""
+
+#: bp-activity/bp-activity-admin.php:1203
+msgid "Author"
+msgstr ""
+
+#: bp-activity/bp-activity-admin.php:1205
+msgid "In Response To"
+msgstr ""
+
+#: bp-activity/bp-activity-admin.php:1248
+msgid "Show all activity types"
+msgstr ""
+
+#: bp-activity/bp-activity-admin.php:1255
+msgid "Filter"
+msgstr ""
+
+#: bp-activity/bp-activity-admin.php:1271
+msgid "Select activity item %1$d"
+msgstr ""
+
+#: bp-activity/bp-activity-admin.php:1339 bp-core/bp-core-cssjs.php:29
+msgid "Are you sure?"
+msgstr ""
+
+#. translators: 2: activity admin ui date/time
+
+#: bp-activity/bp-activity-admin.php:1348
+msgid "Submitted on <a href=\"%1$s\">%2$s at %3$s</a>"
+msgstr ""
+
+#: bp-activity/bp-activity-admin.php:1380
+msgid "%s related activity"
+msgid_plural "%s related activities"
+msgstr[0] ""
+msgstr[1] ""
+
+#: bp-activity/bp-activity-admin.php:1391
+msgid "<a href=\"%1$s\">View Activity</a>"
+msgstr ""
+
+#: bp-activity/bp-activity-akismet.php:86
+msgid "Flagged as spam by Akismet"
+msgstr ""
+
+#: bp-activity/bp-activity-akismet.php:89
+msgid "Cleared by Akismet"
+msgstr ""
+
+#: bp-activity/bp-activity-akismet.php:95
+msgid "Flagged as spam by %s"
+msgstr ""
+
+#: bp-activity/bp-activity-akismet.php:97
+msgid "Un-spammed by %s"
+msgstr ""
+
+#: bp-activity/bp-activity-akismet.php:106
+msgid "History"
+msgstr ""
+
+#: bp-activity/bp-activity-akismet.php:373
+msgid "%s reported this activity as spam"
+msgstr ""
+
+#: bp-activity/bp-activity-akismet.php:390
+msgid "%s reported this activity as not spam"
+msgstr ""
+
+#: bp-activity/bp-activity-akismet.php:414
+msgid "Akismet caught this item as spam"
+msgstr ""
+
+#: bp-activity/bp-activity-akismet.php:419
+msgid "Akismet cleared this item"
+msgstr ""
+
+#: bp-activity/bp-activity-akismet.php:424
+msgid "Akismet was unable to check this item (response: %s), will automatically retry again later."
+msgstr ""
+
+#: bp-activity/bp-activity-akismet.php:538
+msgid "Activity History"
+msgstr ""
+
+#: bp-activity/bp-activity-akismet.php:558
+msgctxt "x hours ago - akismet cleared this item"
+msgid "<span>%1$s</span> &mdash; %2$s"
+msgstr ""
+
+#: bp-activity/bp-activity-classes.php:257
+#: bp-activity/bp-activity-template.php:143 bp-groups/bp-groups-classes.php:583
+#: bp-groups/bp-groups-template.php:114
+msgid "Arguments passed to %1$s should be in an associative array. See the inline documentation at %2$s for more details."
+msgstr ""
+
+#: bp-activity/bp-activity-classes.php:1156
+msgid "RSS feed 'id' must be defined"
+msgstr ""
+
+#: bp-activity/bp-activity-classes.php:1269
+msgid "In reply to"
+msgstr ""
+
+#: bp-activity/bp-activity-filters.php:361
+msgid "[Read more]"
+msgstr ""
+
+#: bp-activity/bp-activity-filters.php:366
+msgid "&hellip;"
+msgstr ""
+
+#: bp-activity/bp-activity-functions.php:875
+msgid "Posted a status update"
+msgstr ""
+
+#: bp-activity/bp-activity-functions.php:876
+msgid "Replied to a status update"
+msgstr ""
+
+#: bp-activity/bp-activity-functions.php:1164
+msgid "%s posted an update"
+msgstr ""
+
+#: bp-activity/bp-activity-functions.php:1244
+#: tests/testcases/activity/class.BP_Activity_Activity.php:202
+msgid "%s posted a new activity comment"
+msgstr ""
+
+#: bp-activity/bp-activity-functions.php:1627
+msgid "Thumbnail"
+msgstr ""
+
+#: bp-activity/bp-activity-loader.php:30
+#: bp-core/admin/bp-core-components.php:379
+msgid "Activity Streams"
+msgstr ""
+
+#: bp-activity/bp-activity-loader.php:104
+msgid "Search Activity..."
+msgstr ""
+
+#: bp-activity/bp-activity-loader.php:158
+#: bp-activity/bp-activity-loader.php:279
+msgid "Personal"
+msgstr ""
+
+#: bp-activity/bp-activity-loader.php:169
+#: bp-activity/bp-activity-loader.php:253
+#: bp-templates/bp-legacy/buddypress/activity/index.php:59
+#: bp-themes/bp-default/activity/index.php:79
+msgid "Mentions"
+msgstr ""
+
+#: bp-activity/bp-activity-loader.php:181
+#: bp-activity/bp-activity-loader.php:287
+msgid "Favorites"
+msgstr ""
+
+#: bp-activity/bp-activity-loader.php:193
+#: bp-activity/bp-activity-loader.php:296 bp-friends/bp-friends-loader.php:185
+#: bp-friends/bp-friends-screens.php:85
+msgid "Friends"
+msgstr ""
+
+#: bp-activity/bp-activity-loader.php:206
+#: bp-activity/bp-activity-loader.php:306 bp-core/bp-core-template.php:364
+#: bp-groups/bp-groups-admin.php:32 bp-groups/bp-groups-admin.php:33
+#: bp-groups/bp-groups-admin.php:638 bp-groups/bp-groups-loader.php:516
+#: bp-groups/bp-groups-notifications.php:371
+#: bp-groups/bp-groups-notifications.php:407
+#: bp-groups/bp-groups-notifications.php:443
+#: bp-groups/bp-groups-notifications.php:479
+#: bp-groups/bp-groups-screens.php:894 bp-groups/bp-groups-screens.php:1026
+#: bp-groups/bp-groups-screens.php:1028 bp-groups/bp-groups-screens.php:1087
+#: bp-groups/bp-groups-screens.php:1089 bp-groups/bp-groups-widgets.php:53
+#: bp-groups/bp-groups-widgets.php:124
+msgid "Groups"
+msgstr ""
+
+#: bp-activity/bp-activity-loader.php:251
+msgid "Mentions <span class=\"count\">%s</span>"
+msgstr ""
+
+#: bp-activity/bp-activity-loader.php:330
+msgid "My Activity"
+msgstr ""
+
+#: bp-activity/bp-activity-loader.php:335
+#: bp-activity/bp-activity-template.php:1167
+#: bp-activity/bp-activity-template.php:1313
+#: bp-activity/bp-activity-template.php:1324 bp-blogs/bp-blogs-loader.php:231
+#: bp-forums/bp-forums-loader.php:245 bp-forums/bp-forums-template.php:730
+#: bp-forums/bp-forums-template.php:960 bp-forums/bp-forums-template.php:1990
+#: bp-friends/bp-friends-loader.php:231 bp-groups/bp-groups-loader.php:577
+#: bp-groups/bp-groups-template.php:770 bp-groups/bp-groups-template.php:793
+#: bp-groups/bp-groups-template.php:1222 bp-groups/bp-groups-template.php:1238
+#: bp-groups/bp-groups-template.php:1287 bp-groups/bp-groups-template.php:1303
+#: bp-groups/bp-groups-template.php:2031 bp-groups/bp-groups-template.php:2040
+#: bp-groups/bp-groups-template.php:2049 bp-groups/bp-groups-template.php:2806
+#: bp-members/bp-members-buddybar.php:64 bp-members/bp-members-loader.php:208
+#: bp-members/bp-members-template.php:520
+#: bp-members/bp-members-template.php:820
+#: bp-members/bp-members-template.php:839
+#: bp-messages/bp-messages-loader.php:258
+#: bp-messages/bp-messages-template.php:356
+#: bp-notifications/bp-notifications-loader.php:227
+#: bp-templates/bp-legacy/buddypress/groups/single/admin.php:185
+#: bp-templates/bp-legacy/buddypress/groups/single/admin.php:212
+#: bp-themes/bp-default/groups/single/admin.php:185
+#: bp-themes/bp-default/groups/single/admin.php:212
+#: bp-xprofile/bp-xprofile-loader.php:281
+msgid "Profile picture of %s"
+msgstr ""
+
+#: bp-activity/bp-activity-notifications.php:73
+msgid "%s mentioned you in an update"
+msgstr ""
+
+#: bp-activity/bp-activity-notifications.php:76 bp-core/deprecated/1.5.php:354
+msgid ""
+"%1$s mentioned you in the group \"%2$s\":\n"
+"\n"
+"\"%3$s\"\n"
+"\n"
+"To view and respond to the message, log in and visit: %4$s\n"
+"\n"
+"---------------------\n"
+msgstr ""
+
+#: bp-activity/bp-activity-notifications.php:86
+msgid ""
+"%1$s mentioned you in an update:\n"
+"\n"
+"\"%2$s\"\n"
+"\n"
+"To view and respond to the message, log in and visit: %3$s\n"
+"\n"
+"---------------------\n"
+msgstr ""
+
+#: bp-activity/bp-activity-notifications.php:99
+#: bp-activity/bp-activity-notifications.php:177
+#: bp-activity/bp-activity-notifications.php:226 bp-core/deprecated/1.5.php:364
+#: bp-friends/bp-friends-notifications.php:56
+#: bp-friends/bp-friends-notifications.php:105
+#: bp-groups/bp-groups-notifications.php:44
+#: bp-groups/bp-groups-notifications.php:102
+#: bp-groups/bp-groups-notifications.php:167
+#: bp-groups/bp-groups-notifications.php:226
+#: bp-groups/bp-groups-notifications.php:289
+#: bp-messages/bp-messages-notifications.php:85
+msgid "To disable these notifications please log in and go to: %s"
+msgstr ""
+
+#: bp-activity/bp-activity-notifications.php:164
+msgid "%s replied to one of your updates"
+msgstr ""
+
+#: bp-activity/bp-activity-notifications.php:165
+msgid ""
+"%1$s replied to one of your updates:\n"
+"\n"
+"\"%2$s\"\n"
+"\n"
+"To view your original update and all comments, log in and visit: %3$s\n"
+"\n"
+"---------------------\n"
+msgstr ""
+
+#: bp-activity/bp-activity-notifications.php:209
+msgid "%s replied to one of your comments"
+msgstr ""
+
+#: bp-activity/bp-activity-notifications.php:214
+msgid ""
+"%1$s replied to one of your comments:\n"
+"\n"
+"\"%2$s\"\n"
+"\n"
+"To view the original activity, your comment and all replies, log in and visit: %3$s\n"
+"\n"
+"---------------------\n"
+msgstr ""
+
+#: bp-activity/bp-activity-notifications.php:280
+msgid "@%s Mentions"
+msgstr ""
+
+#: bp-activity/bp-activity-notifications.php:283
+msgid "You have %1$d new mentions"
+msgstr ""
+
+#: bp-activity/bp-activity-notifications.php:287
+msgid "%1$s mentioned you"
+msgstr ""
+
+#: bp-activity/bp-activity-screens.php:231
+msgid "You do not have access to this activity."
+msgstr ""
+
+#: bp-activity/bp-activity-screens.php:271 bp-blogs/bp-blogs-template.php:982
+#: bp-friends/bp-friends-screens.php:86 bp-groups/bp-groups-screens.php:895
+#: bp-messages/bp-messages-screens.php:169
+#: bp-templates/bp-legacy/buddypress/members/register.php:227
+#: bp-themes/bp-default/registration/register.php:232
+msgid "Yes"
+msgstr ""
+
+#: bp-activity/bp-activity-screens.php:272 bp-blogs/bp-blogs-template.php:986
+#: bp-friends/bp-friends-screens.php:87 bp-groups/bp-groups-screens.php:896
+#: bp-messages/bp-messages-screens.php:170
+#: bp-templates/bp-legacy/buddypress/members/register.php:228
+#: bp-themes/bp-default/registration/register.php:233
+msgid "No"
+msgstr ""
+
+#: bp-activity/bp-activity-screens.php:280
+msgid "A member mentions you in an update using \"@%s\""
+msgstr ""
+
+#: bp-activity/bp-activity-screens.php:288
+msgid "A member replies to an update or comment you've posted"
+msgstr ""
+
+#: bp-activity/bp-activity-screens.php:384
+msgid "Sitewide Activity"
+msgstr ""
+
+#: bp-activity/bp-activity-template.php:244
+msgctxt "Activity pagination previous text"
+msgid "&larr;"
+msgstr ""
+
+#: bp-activity/bp-activity-template.php:245
+msgctxt "Activity pagination next text"
+msgid "&rarr;"
+msgstr ""
+
+#: bp-activity/bp-activity-template.php:701
+msgid "Viewing item %1$s to %2$s (of %3$s item)"
+msgid_plural "Viewing item %1$s to %2$s (of %3$s items)"
+msgstr[0] ""
+msgstr[1] ""
+
+#: bp-activity/bp-activity-template.php:1167
+msgid "Profile picture"
+msgstr ""
+
+#: bp-activity/bp-activity-template.php:1289
+msgid "Group logo"
+msgstr ""
+
+#: bp-activity/bp-activity-template.php:1292 bp-groups/bp-groups-admin.php:1405
+#: bp-groups/bp-groups-template.php:516
+msgid "Group logo of %s"
+msgstr ""
+
+#: bp-activity/bp-activity-template.php:1303
+msgid "Profile picture of the author of the site %s"
+msgstr ""
+
+#: bp-activity/bp-activity-template.php:1533
+msgid "View Discussion"
+msgstr ""
+
+#: bp-activity/bp-activity-template.php:2417
+#: bp-forums/bp-forums-template.php:2113 bp-groups/bp-groups-admin.php:1281
+#: bp-groups/bp-groups-admin.php:1394 bp-groups/bp-groups-template.php:1486
+#: bp-notifications/bp-notifications-template.php:826
+#: bp-templates/bp-legacy/buddypress/activity/comment.php:43
+#: bp-templates/bp-legacy/buddypress/members/single/messages/messages-loop.php:51
+#: bp-templates/bp-legacy/buddypress/members/single/messages/single.php:24
+#: bp-themes/bp-default/activity/comment.php:46
+#: bp-themes/bp-default/members/single/messages/messages-loop.php:51
+#: bp-themes/bp-default/members/single/messages/single.php:24
+#: bp-xprofile/bp-xprofile-admin.php:460
+msgid "Delete"
+msgstr ""
+
+#: bp-activity/bp-activity-template.php:2465
+#: bp-core/admin/bp-core-slugs.php:109 bp-core/admin/bp-core-slugs.php:172
+#: bp-core/bp-core-loader.php:238 bp-members/bp-members-loader.php:182
+#: bp-members/bp-members-template.php:625
+#: bp-templates/bp-legacy/buddypress-functions.php:244
+#: bp-themes/bp-default/activity/entry.php:37
+#: bp-themes/bp-default/functions.php:166
+#: bp-xprofile/bp-xprofile-loader.php:183
+#: bp-xprofile/bp-xprofile-loader.php:243
+msgid "View"
+msgstr ""
+
+#: bp-activity/bp-activity-template.php:2563
+msgid "Clear Filter"
+msgstr ""
+
+#: bp-activity/bp-activity-template.php:2759
+msgid "a user"
+msgstr ""
+
+#: bp-activity/bp-activity-template.php:2813
+msgid "Send a public message on your activity stream."
+msgstr ""
+
+#: bp-activity/bp-activity-template.php:2814
+msgid "Public Message"
+msgstr ""
+
+#: bp-activity/bp-activity-template.php:3267
+msgid "Site Wide Activity RSS Feed"
+msgstr ""
+
+#: bp-blogs/bp-blogs-activity.php:31
+msgid "New site created"
+msgstr ""
+
+#: bp-blogs/bp-blogs-activity.php:34
+msgid "New post published"
+msgstr ""
+
+#: bp-blogs/bp-blogs-activity.php:35
+msgid "New post comment posted"
+msgstr ""
+
+#: bp-blogs/bp-blogs-buddybar.php:42 bp-blogs/bp-blogs-loader.php:144
+#: bp-blogs/bp-blogs-loader.php:194 bp-blogs/bp-blogs-loader.php:222
+msgid "My Sites"
+msgstr ""
+
+#: bp-blogs/bp-blogs-buddybar.php:54 bp-core/bp-core-buddybar.php:621
+msgid "Dashboard"
+msgstr ""
+
+#: bp-blogs/bp-blogs-buddybar.php:55 bp-core/bp-core-buddybar.php:625
+msgid "New Post"
+msgstr ""
+
+#: bp-blogs/bp-blogs-buddybar.php:56 bp-core/bp-core-buddybar.php:626
+msgid "Manage Posts"
+msgstr ""
+
+#: bp-blogs/bp-blogs-buddybar.php:57 bp-core/bp-core-buddybar.php:627
+msgid "Manage Comments"
+msgstr ""
+
+#: bp-blogs/bp-blogs-buddybar.php:70
+msgid "Create a Site!"
+msgstr ""
+
+#: bp-blogs/bp-blogs-functions.php:206
+msgid "%s created the site %s"
+msgstr ""
+
+#: bp-blogs/bp-blogs-functions.php:331
+msgid "%1$s wrote a new post, %2$s, on the site %3$s"
+msgstr ""
+
+#: bp-blogs/bp-blogs-functions.php:333
+msgid "%1$s wrote a new post, %2$s"
+msgstr ""
+
+#: bp-blogs/bp-blogs-functions.php:440
+msgid "%1$s commented on the post, %2$s, on the site %3$s"
+msgstr ""
+
+#: bp-blogs/bp-blogs-functions.php:442
+msgid "%1$s commented on the post, %2$s"
+msgstr ""
+
+#: bp-blogs/bp-blogs-loader.php:25 bp-core/admin/bp-core-components.php:395
+msgid "Site Tracking"
+msgstr ""
+
+#: bp-blogs/bp-blogs-loader.php:64
+msgid "Search sites..."
+msgstr ""
+
+#: bp-blogs/bp-blogs-loader.php:124
+msgid "Sites <span>%d</span>"
+msgstr ""
+
+#: bp-blogs/bp-blogs-loader.php:186 bp-blogs/bp-blogs-screens.php:146
+#: bp-blogs/bp-blogs-screens.php:148 bp-blogs/bp-blogs-screens.php:209
+#: bp-blogs/bp-blogs-screens.php:211
+msgid "Sites"
+msgstr ""
+
+#: bp-blogs/bp-blogs-loader.php:203 bp-blogs/bp-blogs-screens.php:209
+#: bp-blogs/bp-blogs-template.php:1099 bp-core/bp-core-filters.php:413
+#: bp-themes/bp-default/blogs/create.php:21
+#: bp-themes/bp-default/blogs/index.php:21
+msgid "Create a Site"
+msgstr ""
+
+#: bp-blogs/bp-blogs-screens.php:146
+msgid "Create a Sites"
+msgstr ""
+
+#: bp-blogs/bp-blogs-template.php:206
+msgctxt "Blog pagination previous text"
+msgid "&larr;"
+msgstr ""
+
+#: bp-blogs/bp-blogs-template.php:207
+msgctxt "Blog pagination next text"
+msgid "&rarr;"
+msgstr ""
+
+#: bp-blogs/bp-blogs-template.php:424
+msgid "Viewing site %1$s to %2$s (of %3$s site)"
+msgid_plural "Viewing site %1$s to %2$s (of %3$s sites)"
+msgstr[0] ""
+msgstr[1] ""
+
+#: bp-blogs/bp-blogs-template.php:489
+msgid "Profile picture of site author %s"
+msgstr ""
+
+#: bp-blogs/bp-blogs-template.php:633 bp-core/bp-core-classes.php:804
+#: bp-groups/bp-groups-widgets.php:85 bp-groups/bp-groups-widgets.php:188
+#: bp-members/bp-members-template.php:596
+#: bp-members/bp-members-template.php:871
+#: bp-templates/bp-legacy/buddypress/groups/groups-loop.php:47
+#: bp-templates/bp-legacy/buddypress/groups/single/group-header.php:42
+#: bp-themes/bp-default/groups/groups-loop.php:47
+#: bp-themes/bp-default/groups/single/group-header.php:42
+msgid "active %s"
+msgstr ""
+
+#: bp-blogs/bp-blogs-template.php:653
+msgid "Latest Post: %s"
+msgstr ""
+
+#: bp-blogs/bp-blogs-template.php:900
+msgid "There was a problem, please correct the form below and try again."
+msgstr ""
+
+#: bp-blogs/bp-blogs-template.php:903
+msgid "By filling out the form below, you can <strong>add a site to your account</strong>. There is no limit to the number of sites that you can have, so create to your heart's content, but blog responsibly!"
+msgstr ""
+
+#: bp-blogs/bp-blogs-template.php:905
+msgid "If you&#8217;re not going to use a great domain, leave it for a new user. Now have at it!"
+msgstr ""
+
+#: bp-blogs/bp-blogs-template.php:914
+msgid "Create Site"
+msgstr ""
+
+#: bp-blogs/bp-blogs-template.php:936
+msgid "Site Name:"
+msgstr ""
+
+#: bp-blogs/bp-blogs-template.php:938
+msgid "Site Domain:"
+msgstr ""
+
+#: bp-blogs/bp-blogs-template.php:952
+msgid "Your address will be "
+msgstr ""
+
+#: bp-blogs/bp-blogs-template.php:955
+msgid "blogname"
+msgstr ""
+
+#: bp-blogs/bp-blogs-template.php:957
+msgid "domain."
+msgstr ""
+
+#: bp-blogs/bp-blogs-template.php:960
+msgid "Must be at least 4 characters, letters and numbers only. It cannot be changed so choose carefully!)"
+msgstr ""
+
+#: bp-blogs/bp-blogs-template.php:966
+msgid "Site Title:"
+msgstr ""
+
+#: bp-blogs/bp-blogs-template.php:977
+msgid "Privacy:"
+msgstr ""
+
+#: bp-blogs/bp-blogs-template.php:978
+#: bp-templates/bp-legacy/buddypress/members/register.php:224
+#: bp-themes/bp-default/registration/register.php:229
+msgid "I would like my site to appear in search engines, and in public listings around this network."
+msgstr ""
+
+#: bp-blogs/bp-blogs-template.php:1085
+msgid "Congratulations! You have successfully registered a new site."
+msgstr ""
+
+#: bp-blogs/bp-blogs-template.php:1087
+msgid "<a href=\"%1$s\">%2$s</a> is your new site.  <a href=\"%3$s\">Login</a> as \"%4$s\" using your existing password."
+msgstr ""
+
+#: bp-blogs/bp-blogs-template.php:1116
+msgid "%s's Sites"
+msgstr ""
+
+#: bp-blogs/bp-blogs-template.php:1117
+msgid "%s's Recent Posts"
+msgstr ""
+
+#: bp-blogs/bp-blogs-template.php:1118
+msgid "%s's Recent Comments"
+msgstr ""
+
+#: bp-blogs/bp-blogs-template.php:1134 bp-core/deprecated/1.5.php:417
+#: bp-forums/bp-forums-template.php:2196 bp-groups/bp-groups-template.php:2530
+#: bp-members/bp-members-template.php:710
+#: bp-messages/bp-messages-template.php:410 bp-themes/bp-default/header.php:30
+#: bp-themes/bp-default/searchform.php:5
+msgid "Search"
+msgstr ""
+
+#: bp-blogs/bp-blogs-template.php:1180 bp-blogs/bp-blogs-template.php:1181
+msgid "Visit Site"
+msgstr ""
+
+#: bp-blogs/bp-blogs-widgets.php:34
+msgid "A list of recently published posts from across your network."
+msgstr ""
+
+#: bp-blogs/bp-blogs-widgets.php:37
+msgctxt "widget name"
+msgid "(BuddyPress) Recent Networkwide Posts"
+msgstr ""
+
+#: bp-blogs/bp-blogs-widgets.php:50 bp-blogs/bp-blogs-widgets.php:122
+msgid "Recent Networkwide Posts"
+msgstr ""
+
+#: bp-blogs/bp-blogs-widgets.php:91
+msgid "Sorry, there were no posts found. Why not write one?"
+msgstr ""
+
+#: bp-blogs/bp-blogs-widgets.php:133
+msgctxt "Label for the Title field of the Recent Networkwide Posts widget"
+msgid "Title:"
+msgstr ""
+
+#: bp-blogs/bp-blogs-widgets.php:134
+msgid "Link widget title to Blogs directory"
+msgstr ""
+
+#: bp-blogs/bp-blogs-widgets.php:135
+msgid "Max posts to show:"
+msgstr ""
+
+#: bp-core/admin/bp-core-components.php:26
+#: bp-core/admin/bp-core-functions.php:382
+msgid "Components"
+msgstr ""
+
+#: bp-core/admin/bp-core-components.php:32
+#: bp-core/admin/bp-core-settings.php:267 bp-core/admin/bp-core-slugs.php:32
+msgid "Save Settings"
+msgstr ""
+
+#: bp-core/admin/bp-core-components.php:59
+#: bp-core/admin/bp-core-components.php:363
+#: bp-xprofile/bp-xprofile-loader.php:41
+msgid "Extended Profiles"
+msgstr ""
+
+#: bp-core/admin/bp-core-components.php:60
+#: bp-core/admin/bp-core-components.php:364
+msgid "Customize your community with fully editable profile fields that allow your users to describe themselves."
+msgstr ""
+
+#: bp-core/admin/bp-core-components.php:63
+#: bp-core/admin/bp-core-components.php:367
+msgid "Account Settings"
+msgstr ""
+
+#: bp-core/admin/bp-core-components.php:64
+#: bp-core/admin/bp-core-components.php:368
+msgid "Allow your users to modify their account and notification settings directly from within their profiles."
+msgstr ""
+
+#: bp-core/admin/bp-core-components.php:67
+#: bp-core/admin/bp-core-components.php:383
+#: bp-notifications/bp-notifications-buddybar.php:28
+#: bp-notifications/bp-notifications-loader.php:26
+#: bp-notifications/bp-notifications-loader.php:179
+#: bp-notifications/bp-notifications-loader.php:222
+msgid "Notifications"
+msgstr ""
+
+#: bp-core/admin/bp-core-components.php:68
+#: bp-core/admin/bp-core-components.php:384
+msgid "Notify members of relevant activity with a toolbar bubble and/or via email, and allow them to customize their notification settings."
+msgstr ""
+
+#: bp-core/admin/bp-core-components.php:144
+msgctxt "plugins"
+msgid "All <span class=\"count\">(%s)</span>"
+msgid_plural "All <span class=\"count\">(%s)</span>"
+msgstr[0] ""
+msgstr[1] ""
+
+#: bp-core/admin/bp-core-components.php:145
+msgid "Active <span class=\"count\">(%s)</span>"
+msgid_plural "Active <span class=\"count\">(%s)</span>"
+msgstr[0] ""
+msgstr[1] ""
+
+#: bp-core/admin/bp-core-components.php:146
+msgid "Inactive <span class=\"count\">(%s)</span>"
+msgid_plural "Inactive <span class=\"count\">(%s)</span>"
+msgstr[0] ""
+msgstr[1] ""
+
+#: bp-core/admin/bp-core-components.php:147
+msgid "Must-Use <span class=\"count\">(%s)</span>"
+msgid_plural "Must-Use <span class=\"count\">(%s)</span>"
+msgstr[0] ""
+msgstr[1] ""
+
+#: bp-core/admin/bp-core-components.php:148
+msgid "Retired <span class=\"count\">(%s)</span>"
+msgid_plural "Retired <span class=\"count\">(%s)</span>"
+msgstr[0] ""
+msgstr[1] ""
+
+#: bp-core/admin/bp-core-components.php:155
+#: bp-core/admin/bp-core-components.php:163
+msgid "Component"
+msgstr ""
+
+#: bp-core/admin/bp-core-components.php:156
+#: bp-core/admin/bp-core-components.php:164
+msgid "Description"
+msgstr ""
+
+#: bp-core/admin/bp-core-components.php:189
+msgid "Select %s"
+msgstr ""
+
+#: bp-core/admin/bp-core-components.php:214
+msgid "No components found."
+msgstr ""
+
+#: bp-core/admin/bp-core-components.php:343 bp-core/bp-core-loader.php:27
+msgid "BuddyPress Core"
+msgstr ""
+
+#: bp-core/admin/bp-core-components.php:344
+msgid "It&#8216;s what makes <del>time travel</del> BuddyPress possible!"
+msgstr ""
+
+#: bp-core/admin/bp-core-components.php:347
+msgid "Community Members"
+msgstr ""
+
+#: bp-core/admin/bp-core-components.php:348
+msgid "Everything in a BuddyPress community revolves around its members."
+msgstr ""
+
+#: bp-core/admin/bp-core-components.php:355
+#: bp-templates/bp-legacy/buddypress/groups/create.php:105
+#: bp-themes/bp-default/groups/create.php:112
+msgid "Group Forums"
+msgstr ""
+
+#: bp-core/admin/bp-core-components.php:356
+msgid "BuddyPress Forums are retired. Use %s."
+msgstr ""
+
+#: bp-core/admin/bp-core-components.php:371 bp-friends/bp-friends-loader.php:24
+msgid "Friend Connections"
+msgstr ""
+
+#: bp-core/admin/bp-core-components.php:372
+msgid "Let your users make connections so they can track the activity of others and focus on the people they care about the most."
+msgstr ""
+
+#: bp-core/admin/bp-core-components.php:375
+msgid "Private Messaging"
+msgstr ""
+
+#: bp-core/admin/bp-core-components.php:376
+msgid "Allow your users to talk to each other directly and in private. Not just limited to one-on-one discussions, messages can be sent between any number of members."
+msgstr ""
+
+#: bp-core/admin/bp-core-components.php:380
+msgid "Global, personal, and group activity streams with threaded commenting, direct posting, favoriting, and @mentions, all with full RSS feed and email notification support."
+msgstr ""
+
+#: bp-core/admin/bp-core-components.php:387 bp-groups/bp-groups-loader.php:83
+msgid "User Groups"
+msgstr ""
+
+#: bp-core/admin/bp-core-components.php:388
+msgid "Groups allow your users to organize themselves into specific public, private or hidden sections with separate activity streams and member listings."
+msgstr ""
+
+#: bp-core/admin/bp-core-components.php:391
+msgid "Group Forums (Legacy)"
+msgstr ""
+
+#: bp-core/admin/bp-core-components.php:392
+msgid "Group forums allow for focused, bulletin-board style conversations."
+msgstr ""
+
+#: bp-core/admin/bp-core-components.php:396
+msgid "Record activity for new posts and comments from your site."
+msgstr ""
+
+#: bp-core/admin/bp-core-components.php:403
+msgid "Record activity for new sites, posts, and comments across your network."
+msgstr ""
+
+#: bp-core/admin/bp-core-functions.php:99
+msgid "Why have all my BuddyPress menus disappeared?"
+msgstr ""
+
+#: bp-core/admin/bp-core-functions.php:101
+msgid "Don't worry! We've moved the BuddyPress options into more convenient and easier to find locations. You're seeing this page because you are running a legacy BuddyPress plugin which has not been updated."
+msgstr ""
+
+#: bp-core/admin/bp-core-functions.php:102
+msgid "Components, Pages, Settings, and Forums, have been moved to <a href=\"%s\">Settings &gt; BuddyPress</a>. Profile Fields has been moved into the <a href=\"%s\">Users</a> menu."
+msgstr ""
+
+#: bp-core/admin/bp-core-functions.php:243
+msgid "<strong>BuddyPress is almost ready</strong>. You must <a href=\"%s\">update your permalink structure</a> to something other than the default for it to work."
+msgstr ""
+
+#: bp-core/admin/bp-core-functions.php:267 bp-core/admin/bp-core-slugs.php:135
+#: bp-messages/bp-messages-template.php:601
+#: bp-templates/bp-legacy/buddypress/members/activate.php:29
+#: bp-themes/bp-default/registration/activate.php:38
+msgid "Activate"
+msgstr ""
+
+#: bp-core/admin/bp-core-functions.php:272 bp-core/admin/bp-core-slugs.php:134
+#: bp-members/bp-members-adminbar.php:60
+msgid "Register"
+msgstr ""
+
+#: bp-core/admin/bp-core-functions.php:298
+msgid "The following active BuddyPress Components do not have associated WordPress Pages: %2$s. <a href=\"%1$s\">Repair</a>"
+msgstr ""
+
+#: bp-core/admin/bp-core-functions.php:320
+msgid "Each BuddyPress Component needs its own WordPress page. The following WordPress Pages have more than one component associated with them: %2$s. <a href=\"%1$s\">Repair</a>"
+msgstr ""
+
+#: bp-core/admin/bp-core-functions.php:386 bp-core/admin/bp-core-slugs.php:26
+msgid "Pages"
+msgstr ""
+
+#: bp-core/admin/bp-core-functions.php:390
+#: bp-core/admin/bp-core-settings.php:258 bp-core/bp-core-admin.php:375
+#: bp-groups/bp-groups-loader.php:304 bp-groups/bp-groups-template.php:1468
+#: bp-settings/bp-settings-loader.php:23 bp-settings/bp-settings-loader.php:73
+#: bp-settings/bp-settings-loader.php:163
+msgid "Settings"
+msgstr ""
+
+#: bp-core/admin/bp-core-functions.php:403 bp-core/bp-core-template.php:370
+#: bp-forums/bp-forums-loader.php:132 bp-forums/bp-forums-loader.php:199
+#: bp-forums/bp-forums-loader.php:240 bp-forums/bp-forums-screens.php:208
+#: bp-forums/bp-forums-screens.php:210 bp-forums/deprecated/1.6.php:42
+#: bp-forums/deprecated/1.7.php:25 bp-forums/deprecated/1.7.php:100
+msgid "Forums"
+msgstr ""
+
+#: bp-core/admin/bp-core-functions.php:451
+msgid "<a href=\"http://codex.buddypress.org/getting-started/configure-buddypress-components/#settings-buddypress-components\">Managing Components</a>"
+msgstr ""
+
+#: bp-core/admin/bp-core-functions.php:469
+msgid "<a href=\"http://codex.buddypress.org/getting-started/configure-buddypress-components/#settings-buddypress-pages\">Managing Pages</a>"
+msgstr ""
+
+#: bp-core/admin/bp-core-functions.php:488
+msgid "<a href=\"http://codex.buddypress.org/getting-started/configure-buddypress-components/#settings-buddypress-settings\">Managing Settings</a>"
+msgstr ""
+
+#: bp-core/admin/bp-core-functions.php:507
+msgid "<a href=\"http://codex.buddypress.org/getting-started/configure-buddypress-components/#users-profile-fields\">Managing Profile Fields</a>"
+msgstr ""
+
+#: bp-core/admin/bp-core-functions.php:525
+msgid "By default, all BuddyPress components are enabled. You can selectively disable any of the components by using the form. Your BuddyPress installation will continue to function. However, the features of the disabled components will no longer be accessible to anyone using the site."
+msgstr ""
+
+#: bp-core/admin/bp-core-functions.php:529
+msgid "BuddyPress Components use WordPress Pages for their root directory/archive pages. Here you can change the page associations for each active component."
+msgstr ""
+
+#: bp-core/admin/bp-core-functions.php:533
+msgid "Extra configuration settings."
+msgstr ""
+
+#: bp-core/admin/bp-core-functions.php:537
+msgid "Your users will distinguish themselves through their profile page. Create relevant profile fields that will show on each users profile.</br></br>Note: Any fields in the first group will appear on the signup page."
+msgstr ""
+
+#: bp-core/admin/bp-core-functions.php:697 bp-core/bp-core-admin.php:200
+#: bp-core/bp-core-admin.php:201 bp-core/bp-core-admin.php:221
+msgid "BuddyPress"
+msgstr ""
+
+#: bp-core/admin/bp-core-functions.php:719
+#: bp-core/admin/bp-core-functions.php:728
+msgid "Logged-In"
+msgstr ""
+
+#: bp-core/admin/bp-core-functions.php:722
+#: bp-core/admin/bp-core-functions.php:737
+msgid "Logged-Out"
+msgstr ""
+
+#: bp-core/admin/bp-core-functions.php:729
+msgid "<em>Logged-In</em> links are relative to the current user, and are not visible to visitors who are not logged in."
+msgstr ""
+
+#: bp-core/admin/bp-core-functions.php:738
+msgid "<em>Logged-Out</em> links are not visible to users who are logged in."
+msgstr ""
+
+#: bp-core/admin/bp-core-functions.php:748
+msgid "Add to Menu"
+msgstr ""
+
+#: bp-core/admin/bp-core-schema.php:251
+msgctxt "First field-group name"
+msgid "General"
+msgstr ""
+
+#: bp-core/admin/bp-core-schema.php:255
+msgctxt "Display name field"
+msgid "Display Name"
+msgstr ""
+
+#: bp-core/admin/bp-core-settings.php:31
+msgid "Show the Toolbar for logged out users"
+msgstr ""
+
+#: bp-core/admin/bp-core-settings.php:47
+msgid "Allow registered members to delete their own accounts"
+msgstr ""
+
+#: bp-core/admin/bp-core-settings.php:62
+msgid "Switch to WordPress Toolbar"
+msgstr ""
+
+#: bp-core/admin/bp-core-settings.php:87
+msgid "Allow Akismet to scan for activity stream spam"
+msgstr ""
+
+#: bp-core/admin/bp-core-settings.php:101
+msgid "Allow activity stream commenting on blog and forum posts"
+msgstr ""
+
+#: bp-core/admin/bp-core-settings.php:153
+msgid "Enable BuddyPress to WordPress profile syncing"
+msgstr ""
+
+#: bp-core/admin/bp-core-settings.php:169
+msgid "Allow registered members to upload avatars"
+msgstr ""
+
+#: bp-core/admin/bp-core-settings.php:194
+msgid "Enable group creation for all users"
+msgstr ""
+
+#: bp-core/admin/bp-core-settings.php:195
+msgid "Administrators can always create groups, regardless of this setting."
+msgstr ""
+
+#: bp-core/admin/bp-core-settings.php:226
+msgid "Attempt to save a new config file."
+msgstr ""
+
+#: bp-core/admin/bp-core-settings.php:226
+msgid "Repair"
+msgstr ""
+
+#: bp-core/admin/bp-core-settings.php:227
+msgid "File does not exist"
+msgstr ""
+
+#: bp-core/admin/bp-core-settings.php:231
+msgid "Absolute path to your bbPress configuration file."
+msgstr ""
+
+#: bp-core/admin/bp-core-slugs.php:79
+msgid "Directories"
+msgstr ""
+
+#: bp-core/admin/bp-core-slugs.php:81
+msgid "Associate a WordPress Page with each BuddyPress component directory."
+msgstr ""
+
+#: bp-core/admin/bp-core-slugs.php:100 bp-core/admin/bp-core-slugs.php:163
+msgid "- None -"
+msgstr ""
+
+#: bp-core/admin/bp-core-slugs.php:104 bp-core/admin/bp-core-slugs.php:167
+msgid "New Page"
+msgstr ""
+
+#: bp-core/admin/bp-core-slugs.php:105 bp-core/admin/bp-core-slugs.php:168
+#: bp-templates/bp-legacy/buddypress/members/single/settings/capabilities.php:13
+#: bp-themes/bp-default/members/single/settings/capabilities.php:61
+#: bp-xprofile/bp-xprofile-classes.php:402
+#: bp-xprofile/bp-xprofile-classes.php:874
+msgid "Save"
+msgstr ""
+
+#: bp-core/admin/bp-core-slugs.php:142
+msgid "Registration"
+msgstr ""
+
+#: bp-core/admin/bp-core-slugs.php:144
+msgid "Associate WordPress Pages with the following BuddyPress Registration pages."
+msgstr ""
+
+#: bp-core/bp-core-admin.php:180 bp-core/bp-core-admin.php:181
+#: bp-core/bp-core-admin.php:189 bp-core/bp-core-admin.php:190
+msgid "Welcome to BuddyPress"
+msgstr ""
+
+#: bp-core/bp-core-admin.php:210
+msgid "BuddyPress Help"
+msgstr ""
+
+#: bp-core/bp-core-admin.php:211
+msgid "Help"
+msgstr ""
+
+#: bp-core/bp-core-admin.php:220
+msgid "BuddyPress Components"
+msgstr ""
+
+#: bp-core/bp-core-admin.php:229 bp-core/bp-core-admin.php:230
+msgid "BuddyPress Pages"
+msgstr ""
+
+#: bp-core/bp-core-admin.php:238 bp-core/bp-core-admin.php:239
+msgid "BuddyPress Settings"
+msgstr ""
+
+#: bp-core/bp-core-admin.php:265
+msgid "Main Settings"
+msgstr ""
+
+#: bp-core/bp-core-admin.php:268 bp-core/bp-core-admin.php:273
+msgid "Toolbar"
+msgstr ""
+
+#: bp-core/bp-core-admin.php:278
+msgid "Account Deletion"
+msgstr ""
+
+#: bp-core/bp-core-admin.php:286
+msgid "Profile Settings"
+msgstr ""
+
+#: bp-core/bp-core-admin.php:289
+msgid "Avatar Uploads"
+msgstr ""
+
+#: bp-core/bp-core-admin.php:293
+msgid "Profile Syncing"
+msgstr ""
+
+#: bp-core/bp-core-admin.php:302
+msgid "Groups Settings"
+msgstr ""
+
+#: bp-core/bp-core-admin.php:305
+msgid "Group Creation"
+msgstr ""
+
+#: bp-core/bp-core-admin.php:314
+msgid "Legacy Group Forums"
+msgstr ""
+
+#: bp-core/bp-core-admin.php:317
+msgid "bbPress Configuration"
+msgstr ""
+
+#: bp-core/bp-core-admin.php:326
+msgid "Activity Settings"
+msgstr ""
+
+#: bp-core/bp-core-admin.php:329
+msgid "Blog &amp; Forum Comments"
+msgstr ""
+
+#: bp-core/bp-core-admin.php:334
+msgid "Akismet"
+msgstr ""
+
+#: bp-core/bp-core-admin.php:352
+msgid "About BuddyPress"
+msgstr ""
+
+#: bp-core/bp-core-admin.php:376
+msgid "About"
+msgstr ""
+
+#: bp-core/bp-core-admin.php:427 bp-core/bp-core-admin.php:552
+msgid "Welcome to BuddyPress %s"
+msgstr ""
+
+#: bp-core/bp-core-admin.php:430
+msgid "It&#8217;s a great time to use BuddyPress! %s is our first version with a new component in over two years. Not only that, there are plenty of new features, enhancements, and bug fixes."
+msgstr ""
+
+#: bp-core/bp-core-admin.php:432
+msgid "Thanks for updating! BuddyPress %s is our first version with a new component in over two years. Not only that, there are plenty of new features, enhancements, and bug fixes."
+msgstr ""
+
+#: bp-core/bp-core-admin.php:437
+msgid "Check out the highlights:"
+msgstr ""
+
+#: bp-core/bp-core-admin.php:440
+msgid "You can now add dynamic BuddyPress links to custom navigation menus."
+msgstr ""
+
+#: bp-core/bp-core-admin.php:441
+msgid "Notifications have been moved into their own component."
+msgstr ""
+
+#: bp-core/bp-core-admin.php:442
+msgid "Three new widgets, allowing easier site customization."
+msgstr ""
+
+#: bp-core/bp-core-admin.php:446 bp-core/bp-core-admin.php:554
+msgid "Version %s"
+msgstr ""
+
+#: bp-core/bp-core-admin.php:450 bp-core/bp-core-admin.php:558
+msgid "What&#8217;s New"
+msgstr ""
+
+#: bp-core/bp-core-admin.php:452 bp-core/bp-core-admin.php:560
+msgid "Credits"
+msgstr ""
+
+#: bp-core/bp-core-admin.php:457
+msgid "Getting Started"
+msgstr ""
+
+#: bp-core/bp-core-admin.php:460
+msgid "Your Default Setup"
+msgstr ""
+
+#: bp-core/bp-core-admin.php:464
+msgid "BuddyPress&#8217;s powerful features help your users connect and collaborate. To help get your community started, we&#8217;ve activated two of the most commonly used tools in BP: <strong>Extended Profiles</strong> and <strong>Activity Streams</strong>. See these components in action at the %1$s and %2$s directories, and be sure to spend a few minutes <a href=\"%3$s\">configuring user profiles</a>. Want to explore more of BP&#8217;s features? Visit the <a href=\"%4$s\">Components panel</a>."
+msgstr ""
+
+#: bp-core/bp-core-admin.php:465 bp-core/bp-core-template.php:361
+#: bp-core/bp-core-widgets.php:266 bp-groups/bp-groups-admin.php:776
+#: bp-groups/bp-groups-template.php:1476 bp-members/bp-members-loader.php:24
+#: bp-members/bp-members-screens.php:368
+#: bp-templates/bp-legacy/buddypress/groups/single/admin.php:231
+#: bp-themes/bp-default/groups/single/admin.php:231
+msgid "Members"
+msgstr ""
+
+#: bp-core/bp-core-admin.php:473
+msgid "BuddyPress&#8217;s powerful features help your users connect and collaborate. Want to explore BP&#8217;s features? Visit the <a href=\"%s\">Components panel</a>."
+msgstr ""
+
+#: bp-core/bp-core-admin.php:479
+msgid "Community and Support"
+msgstr ""
+
+#: bp-core/bp-core-admin.php:480
+msgid "Looking for help? The <a href=\"http://codex.buddypress.org/\">BuddyPress Codex</a> has you covered, with dozens of user-contributed guides on how to configure and use your BP site. Can&#8217;t find what you need? Stop by <a href=\"http://buddypress.org/support/\">our support forums</a>, where a vibrant community of BuddyPress users and developers is waiting to share tips, show off their sites, talk about the future of BuddyPress, and much more."
+msgstr ""
+
+#: bp-core/bp-core-admin.php:487
+msgid "Dynamic links for custom navigation menus"
+msgstr ""
+
+#: bp-core/bp-core-admin.php:490
+msgid "It&#8217;s now easy to add BuddyPress-specific links to your menus through <a href=\"%s\">Appearance &gt; Menus</a>. For example, you can now add a link to a specific user profile screen, and each person will end up at that screen inside their own user profile."
+msgstr ""
+
+#: bp-core/bp-core-admin.php:496
+msgid "Notifications component"
+msgstr ""
+
+#: bp-core/bp-core-admin.php:499
+msgid "The notification features have been promoted into a new component. Use it to keep your site&#8217;s members abreast of the latest connections and @mentions within the site, via email notifications and Toolbar alerts."
+msgstr ""
+
+#: bp-core/bp-core-admin.php:506
+msgid "Widgets"
+msgstr ""
+
+#: bp-core/bp-core-admin.php:510
+msgid "<strong>Friends Widget</strong>: a list of recently active, popular, and newest friends of the displayed member."
+msgstr ""
+
+#: bp-core/bp-core-admin.php:511
+msgid "<strong>Log In Widget</strong>: adds a simple &ldquo;Log In&rdquo; form to your site."
+msgstr ""
+
+#: bp-core/bp-core-admin.php:512
+msgid "<strong>Sitewide Notices Widget</strong>: display Sitewide Notices from the Private Messaging component."
+msgstr ""
+
+#: bp-core/bp-core-admin.php:519
+msgid "Developer changes"
+msgstr ""
+
+#: bp-core/bp-core-admin.php:523
+msgid "<code>bp_redirect_canonical()</code> functionality has been reinstated"
+msgstr ""
+
+#: bp-core/bp-core-admin.php:524
+msgid "Improved phpDoc inline documentation"
+msgstr ""
+
+#: bp-core/bp-core-admin.php:525
+msgid "Improved compatibility with <a href=\"%s\">develop.svn.wordpress.org</a> unit-test suite"
+msgstr ""
+
+#: bp-core/bp-core-admin.php:526
+msgid "<a href=\"%s\">&hellip;and lots more!</a>"
+msgstr ""
+
+#: bp-core/bp-core-admin.php:531 bp-core/bp-core-admin.php:662
+msgid "Go to the BuddyPress Settings page"
+msgstr ""
+
+#: bp-core/bp-core-admin.php:553
+msgid "BuddyPress %s is our first version with a new component in over two years. Not only that, there are plenty of new features, enhancements, and bug fixes."
+msgstr ""
+
+#: bp-core/bp-core-admin.php:564
+msgid "BuddyPress is created by a worldwide network of friendly folks."
+msgstr ""
+
+#: bp-core/bp-core-admin.php:566
+msgid "Project Leaders"
+msgstr ""
+
+#: bp-core/bp-core-admin.php:571
+msgid "Founding Developer"
+msgstr ""
+
+#: bp-core/bp-core-admin.php:576
+msgid "Project Lead"
+msgstr ""
+
+#: bp-core/bp-core-admin.php:581 bp-core/bp-core-admin.php:586
+msgid "Lead Developer"
+msgstr ""
+
+#: bp-core/bp-core-admin.php:590
+msgid "Core Developers"
+msgstr ""
+
+#: bp-core/bp-core-admin.php:598
+msgid "Recent Rockstars"
+msgstr ""
+
+#: bp-core/bp-core-admin.php:618
+msgid "Contributors to BuddyPress 1.9"
+msgstr ""
+
+#: bp-core/bp-core-adminbar.php:36 bp-core/bp-core-buddybar.php:571
+msgid "My Account"
+msgstr ""
+
+#: bp-core/bp-core-avatars.php:309
+msgid "Avatar Image"
+msgstr ""
+
+#: bp-core/bp-core-avatars.php:584
+msgid "The image was uploaded successfully"
+msgstr ""
+
+#: bp-core/bp-core-avatars.php:585 bp-core/bp-core-avatars.php:586
+msgid "The image exceeds the maximum allowed file size of: "
+msgstr ""
+
+#: bp-core/bp-core-avatars.php:587
+msgid "The uploaded file was only partially uploaded."
+msgstr ""
+
+#: bp-core/bp-core-avatars.php:588
+msgid "The image was not uploaded."
+msgstr ""
+
+#: bp-core/bp-core-avatars.php:589
+msgid "Missing a temporary folder."
+msgstr ""
+
+#: bp-core/bp-core-avatars.php:593
+msgid "Your upload failed, please try again. Error was: %s"
+msgstr ""
+
+#: bp-core/bp-core-avatars.php:598
+msgid "The file you uploaded is too big. Please upload a file under %s"
+msgstr ""
+
+#: bp-core/bp-core-avatars.php:603
+msgid "Please upload only JPG, GIF or PNG photos."
+msgstr ""
+
+#: bp-core/bp-core-avatars.php:620 bp-core/bp-core-avatars.php:657
+msgid "Upload Failed! Error was: %s"
+msgstr ""
+
+#: bp-core/bp-core-avatars.php:675
+msgid "Upload failed! Error was: %s"
+msgstr ""
+
+#: bp-core/bp-core-avatars.php:831 bp-core/bp-core-classes.php:801
+#: bp-core/bp-core-classes.php:802 bp-core/bp-core-classes.php:803
+#: bp-core/bp-core-template.php:135 bp-core/bp-core-template.php:151
+msgid "Avatar of %s"
+msgstr ""
+
+#: bp-core/bp-core-buddybar.php:356
+msgid "You do not have access to this page."
+msgstr ""
+
+#: bp-core/bp-core-buddybar.php:552 bp-core/bp-core-functions.php:1718
+#: bp-core/bp-core-widgets.php:89 bp-themes/bp-default/sidebar.php:52
+msgid "Log In"
+msgstr ""
+
+#: bp-core/bp-core-buddybar.php:556
+msgid "Sign Up"
+msgstr ""
+
+#: bp-core/bp-core-buddybar.php:613 bp-core/bp-core-functions.php:1651
+#: bp-core/bp-core-widgets.php:71 bp-core/deprecated/1.5.php:307
+#: bp-members/bp-members-template.php:774 bp-themes/bp-default/sidebar.php:18
+msgid "Log Out"
+msgstr ""
+
+#: bp-core/bp-core-buddybar.php:645 bp-groups/bp-groups-admin.php:1388
+msgid "Visit"
+msgstr ""
+
+#: bp-core/bp-core-buddybar.php:647
+msgid "Random Member"
+msgstr ""
+
+#: bp-core/bp-core-buddybar.php:651
+msgid "Random Group"
+msgstr ""
+
+#: bp-core/bp-core-buddybar.php:657
+msgid "Random Site"
+msgstr ""
+
+#: bp-core/bp-core-caps.php:258 bp-core/bp-core-caps.php:270
+#: bp-core/bp-core-caps.php:284 bp-core/bp-core-caps.php:294
+msgid "Special community roles no longer exist. Use mapped capabilities instead"
+msgstr ""
+
+#: bp-core/bp-core-catchuri.php:276
+msgid "This user has been marked as a spammer. Only site admins can view this profile."
+msgstr ""
+
+#: bp-core/bp-core-catchuri.php:471 bp-core/bp-core-catchuri.php:531
+msgid "You must log in to access the page you requested."
+msgstr ""
+
+#: bp-core/bp-core-classes.php:818
+msgid "%d group"
+msgid_plural "%d groups"
+msgstr[0] ""
+msgstr[1] ""
+
+#: bp-core/bp-core-dependency.php:81
+msgid "The current user is being initialized without using $wp->init()."
+msgstr ""
+
+#: bp-core/bp-core-filters.php:216 bp-core/bp-core-filters.php:242
+msgid "[User Set]"
+msgstr ""
+
+#: bp-core/bp-core-filters.php:271
+msgid ""
+"Thanks for registering! To complete the activation of your account and blog, please click the following link:\n"
+"\n"
+"%1$s\n"
+"\n"
+"\n"
+"\n"
+"After you activate, you can visit your blog here:\n"
+"\n"
+"%2$s"
+msgstr ""
+
+#: bp-core/bp-core-filters.php:272
+msgid "Activate %s"
+msgstr ""
+
+#: bp-core/bp-core-filters.php:310 bp-members/bp-members-functions.php:1471
+msgid ""
+"Thanks for registering! To complete the activation of your account please click the following link:\n"
+"\n"
+"%1$s\n"
+"\n"
+msgstr ""
+
+#: bp-core/bp-core-filters.php:311 bp-members/bp-members-functions.php:1472
+msgid "Activate Your Account"
+msgstr ""
+
+#: bp-core/bp-core-filters.php:378
+msgctxt "Construct the page title. 1 = user name, 2 = component name, 3 = seperator"
+msgid "%1$s %3$s %2$s"
+msgstr ""
+
+#. translators: "group name | group nav section name"
+
+#: bp-core/bp-core-filters.php:384
+msgid "%1$s | %2$s"
+msgstr ""
+
+#. translators: "component item name | component nav section name | root
+#. component name"
+
+#: bp-core/bp-core-filters.php:389
+msgid "%1$s | %2$s | %3$s"
+msgstr ""
+
+#: bp-core/bp-core-filters.php:394 bp-core/bp-core-filters.php:396
+msgid "%s Directory"
+msgstr ""
+
+#: bp-core/bp-core-filters.php:401 bp-members/bp-members-screens.php:525
+#: bp-themes/bp-default/registration/register.php:23
+msgid "Create an Account"
+msgstr ""
+
+#: bp-core/bp-core-filters.php:405 bp-members/bp-members-screens.php:533
+#: bp-themes/bp-default/registration/activate.php:13
+msgid "Activate your Account"
+msgstr ""
+
+#: bp-core/bp-core-filters.php:409 bp-groups/bp-groups-loader.php:553
+#: bp-groups/bp-groups-screens.php:1026 bp-groups/bp-groups-screens.php:1087
+#: bp-themes/bp-default/groups/create.php:18
+#: bp-themes/bp-default/groups/index.php:21
+msgid "Create a Group"
+msgstr ""
+
+#: bp-core/bp-core-functions.php:387
+msgctxt "Page title for the Activity directory."
+msgid "Activity"
+msgstr ""
+
+#: bp-core/bp-core-functions.php:388
+msgctxt "Page title for the Groups directory."
+msgid "Groups"
+msgstr ""
+
+#: bp-core/bp-core-functions.php:389
+msgctxt "Page title for the Sites directory."
+msgid "Sites"
+msgstr ""
+
+#: bp-core/bp-core-functions.php:390
+msgctxt "Page title for the user account activation screen."
+msgid "Activate"
+msgstr ""
+
+#: bp-core/bp-core-functions.php:391
+msgctxt "Page title for the Members directory."
+msgid "Members"
+msgstr ""
+
+#: bp-core/bp-core-functions.php:392
+msgctxt "Page title for the user registration screen."
+msgid "Register"
+msgstr ""
+
+#: bp-core/bp-core-functions.php:690
+msgid "sometime"
+msgstr ""
+
+#: bp-core/bp-core-functions.php:691
+msgid "right now"
+msgstr ""
+
+#: bp-core/bp-core-functions.php:692
+msgid "%s ago"
+msgstr ""
+
+#: bp-core/bp-core-functions.php:753
+msgid "%s year"
+msgid_plural "%s years"
+msgstr[0] ""
+msgstr[1] ""
+
+#: bp-core/bp-core-functions.php:756 bp-core/bp-core-functions.php:790
+msgid "%s month"
+msgid_plural "%s months"
+msgstr[0] ""
+msgstr[1] ""
+
+#: bp-core/bp-core-functions.php:759 bp-core/bp-core-functions.php:793
+msgid "%s week"
+msgid_plural "%s weeks"
+msgstr[0] ""
+msgstr[1] ""
+
+#: bp-core/bp-core-functions.php:762 bp-core/bp-core-functions.php:796
+msgid "%s day"
+msgid_plural "%s days"
+msgstr[0] ""
+msgstr[1] ""
+
+#: bp-core/bp-core-functions.php:765 bp-core/bp-core-functions.php:799
+msgid "%s hour"
+msgid_plural "%s hours"
+msgstr[0] ""
+msgstr[1] ""
+
+#: bp-core/bp-core-functions.php:768 bp-core/bp-core-functions.php:802
+msgid "%s minute"
+msgid_plural "%s minutes"
+msgstr[0] ""
+msgstr[1] ""
+
+#: bp-core/bp-core-functions.php:771 bp-core/bp-core-functions.php:805
+msgid "%s second"
+msgid_plural "%s seconds"
+msgstr[0] ""
+msgstr[1] ""
+
+#: bp-core/bp-core-functions.php:786
+msgctxt "Separator in time since"
+msgid ","
+msgstr ""
+
+#: bp-core/bp-core-functions.php:971
+msgid "Not recently active"
+msgstr ""
+
+#: bp-core/bp-core-loader.php:227 bp-members/bp-members-loader.php:168
+#: bp-xprofile/bp-xprofile-loader.php:162
+#: bp-xprofile/bp-xprofile-loader.php:235
+msgid "Profile"
+msgstr ""
+
+#: bp-core/bp-core-template.php:81
+msgid "Options"
+msgstr ""
+
+#: bp-core/bp-core-template.php:279
+msgid "%1$s at %2$s"
+msgstr ""
+
+#: bp-core/bp-core-template.php:367
+msgid "Blogs"
+msgstr ""
+
+#: bp-core/bp-core-template.php:372
+#: bp-templates/bp-legacy/buddypress/activity/index.php:83
+#: bp-templates/bp-legacy/buddypress/forums/forums-loop.php:40
+#: bp-templates/bp-legacy/buddypress/members/single/activity.php:27
+#: bp-themes/bp-default/activity/index.php:103
+#: bp-themes/bp-default/forums/forums-loop.php:40
+#: bp-themes/bp-default/members/single/activity.php:27
+msgid "Posts"
+msgstr ""
+
+#: bp-core/bp-core-template.php:375
+msgid "Search these:"
+msgstr ""
+
+#: bp-core/bp-core-template.php:413
+msgid "Search anything..."
+msgstr ""
+
+#: bp-core/bp-core-template.php:515
+msgid " [&hellip;]"
+msgstr ""
+
+#: bp-core/bp-core-template.php:736
+msgid "Community"
+msgstr ""
+
+#: bp-core/bp-core-widgets.php:36
+msgctxt "Title of the login widget"
+msgid "(BuddyPress) Log In"
+msgstr ""
+
+#: bp-core/bp-core-widgets.php:38
+msgid "Show a Log In form to logged-out visitors, and a Log Out link to those who are logged in."
+msgstr ""
+
+#: bp-core/bp-core-widgets.php:81
+#: bp-templates/bp-legacy/buddypress/members/register.php:32
+#: bp-themes/bp-default/registration/register.php:37
+#: bp-themes/bp-default/sidebar.php:44
+msgid "Username"
+msgstr ""
+
+#: bp-core/bp-core-widgets.php:84 bp-themes/bp-default/sidebar.php:47
+msgid "Password"
+msgstr ""
+
+#: bp-core/bp-core-widgets.php:87 bp-themes/bp-default/sidebar.php:50
+msgid "Remember Me"
+msgstr ""
+
+#: bp-core/bp-core-widgets.php:93
+msgid "<a href=\"%s\" title=\"Register for a new account\">Register</a>"
+msgstr ""
+
+#: bp-core/bp-core-widgets.php:134 bp-core/bp-core-widgets.php:279
+#: bp-core/bp-core-widgets.php:384 bp-core/bp-core-widgets.php:476
+#: bp-groups/bp-groups-widgets.php:137 bp-messages/bp-messages-widgets.php:110
+#: bp-templates/bp-legacy/buddypress/forums/index.php:86
+#: bp-templates/bp-legacy/buddypress/groups/single/forum/edit.php:47
+#: bp-templates/bp-legacy/buddypress/groups/single/forum.php:75
+#: bp-themes/bp-default/forums/index.php:104
+#: bp-themes/bp-default/groups/single/forum/edit.php:47
+#: bp-themes/bp-default/groups/single/forum.php:75
+msgid "Title:"
+msgstr ""
+
+#: bp-core/bp-core-widgets.php:152
+msgid "A dynamic list of recently active, popular, and newest members"
+msgstr ""
+
+#: bp-core/bp-core-widgets.php:155
+msgctxt "widget name"
+msgid "(BuddyPress) Members"
+msgstr ""
+
+#: bp-core/bp-core-widgets.php:190 bp-core/bp-core-widgets.php:288
+#: bp-core/deprecated/1.6.php:129 bp-core/deprecated/1.6.php:152
+#: bp-friends/bp-friends-widgets.php:91 bp-friends/bp-friends-widgets.php:179
+#: bp-groups/bp-groups-widgets.php:65 bp-groups/bp-groups-widgets.php:146
+#: bp-templates/bp-legacy/buddypress/blogs/index.php:39
+#: bp-templates/bp-legacy/buddypress/members/single/blogs.php:22
+#: bp-themes/bp-default/blogs/index.php:56
+#: bp-themes/bp-default/members/single/blogs.php:22
+msgid "Newest"
+msgstr ""
+
+#: bp-core/bp-core-widgets.php:191 bp-core/bp-core-widgets.php:289
+#: bp-friends/bp-friends-widgets.php:92 bp-friends/bp-friends-widgets.php:180
+#: bp-groups/bp-groups-widgets.php:66 bp-groups/bp-groups-widgets.php:147
+msgid "Active"
+msgstr ""
+
+#: bp-core/bp-core-widgets.php:195 bp-core/bp-core-widgets.php:290
+#: bp-friends/bp-friends-widgets.php:93 bp-friends/bp-friends-widgets.php:181
+#: bp-groups/bp-groups-widgets.php:67 bp-groups/bp-groups-widgets.php:148
+msgid "Popular"
+msgstr ""
+
+#: bp-core/bp-core-widgets.php:232
+msgid "No one has signed up yet!"
+msgstr ""
+
+#: bp-core/bp-core-widgets.php:281 bp-friends/bp-friends-widgets.php:172
+msgid "Link widget title to Members directory"
+msgstr ""
+
+#: bp-core/bp-core-widgets.php:283
+msgid "Max members to show:"
+msgstr ""
+
+#: bp-core/bp-core-widgets.php:286
+msgid "Default members to show:"
+msgstr ""
+
+#: bp-core/bp-core-widgets.php:308
+msgid "Avatars of users who are currently online"
+msgstr ""
+
+#: bp-core/bp-core-widgets.php:311
+msgctxt "widget name"
+msgid "(BuddyPress) Who's Online"
+msgstr ""
+
+#: bp-core/bp-core-widgets.php:344
+msgid "There are no users currently online"
+msgstr ""
+
+#: bp-core/bp-core-widgets.php:375
+msgid "Who's Online"
+msgstr ""
+
+#: bp-core/bp-core-widgets.php:386 bp-core/bp-core-widgets.php:478
+msgid "Max Members to show:"
+msgstr ""
+
+#: bp-core/bp-core-widgets.php:400
+msgid "Avatars of recently active members"
+msgstr ""
+
+#: bp-core/bp-core-widgets.php:403
+msgctxt "widget name"
+msgid "(BuddyPress) Recently Active Members"
+msgstr ""
+
+#: bp-core/bp-core-widgets.php:436
+msgid "There are no recently active members"
+msgstr ""
+
+#: bp-core/bp-core-widgets.php:467
+msgid "Recently Active Members"
+msgstr ""
+
+#: bp-core/bp-core-widgets.php:531 bp-friends/bp-friends-widgets.php:245
+msgid "There were no members found, please try another filter."
+msgstr ""
+
+#: bp-core/deprecated/1.5.php:142
+#: bp-templates/bp-legacy/buddypress/activity/post-form.php:45
+#: bp-templates/bp-legacy/buddypress/members/single/profile/profile-wp.php:8
+#: bp-themes/bp-default/activity/post-form.php:45
+#: bp-themes/bp-default/members/single/profile/profile-wp.php:8
+#: bp-xprofile/bp-xprofile-loader.php:276
+msgid "My Profile"
+msgstr ""
+
+#: bp-core/deprecated/1.5.php:149
+#: bp-templates/bp-legacy/buddypress/members/single/profile/profile-wp.php:15
+#: bp-themes/bp-default/functions.php:643
+#: bp-themes/bp-default/members/single/profile/profile-wp.php:15
+msgid "Name"
+msgstr ""
+
+#: bp-core/deprecated/1.5.php:158
+#: bp-templates/bp-legacy/buddypress/members/single/profile/profile-wp.php:24
+#: bp-themes/bp-default/members/single/profile/profile-wp.php:24
+msgid "About Me"
+msgstr ""
+
+#: bp-core/deprecated/1.5.php:167
+#: bp-templates/bp-legacy/buddypress/members/single/profile/profile-wp.php:33
+#: bp-themes/bp-default/functions.php:647
+#: bp-themes/bp-default/members/single/profile/profile-wp.php:33
+msgid "Website"
+msgstr ""
+
+#: bp-core/deprecated/1.5.php:176
+#: bp-templates/bp-legacy/buddypress/members/single/profile/profile-wp.php:42
+#: bp-themes/bp-default/members/single/profile/profile-wp.php:42
+msgid "Jabber"
+msgstr ""
+
+#: bp-core/deprecated/1.5.php:185
+#: bp-templates/bp-legacy/buddypress/members/single/profile/profile-wp.php:51
+#: bp-themes/bp-default/members/single/profile/profile-wp.php:51
+msgid "AOL Messenger"
+msgstr ""
+
+#: bp-core/deprecated/1.5.php:194
+#: bp-templates/bp-legacy/buddypress/members/single/profile/profile-wp.php:60
+#: bp-themes/bp-default/members/single/profile/profile-wp.php:60
+msgid "Yahoo Messenger"
+msgstr ""
+
+#: bp-core/deprecated/1.5.php:352
+msgid "%1$s mentioned you in the group \"%2$s\""
+msgstr ""
+
+#: bp-core/deprecated/1.6.php:128 bp-core/deprecated/1.6.php:149
+#: bp-groups/bp-groups-template.php:2546 bp-groups/bp-groups-template.php:2568
+msgid "Recently Active"
+msgstr ""
+
+#: bp-core/deprecated/1.6.php:130 bp-core/deprecated/1.6.php:155
+#: bp-groups/bp-groups-template.php:2551 bp-groups/bp-groups-template.php:2583
+msgid "Alphabetically"
+msgstr ""
+
+#: bp-forums/bp-forums-loader.php:28
+msgid "Discussion Forums"
+msgstr ""
+
+#: bp-forums/bp-forums-loader.php:70
+msgid "Search Forums..."
+msgstr ""
+
+#: bp-forums/bp-forums-loader.php:154 bp-forums/bp-forums-loader.php:207
+msgid "Topics Started"
+msgstr ""
+
+#: bp-forums/bp-forums-loader.php:165
+msgid "Replied To"
+msgstr ""
+
+#: bp-forums/bp-forums-loader.php:215
+msgid "Replies"
+msgstr ""
+
+#: bp-forums/bp-forums-loader.php:223
+msgid "Favorite Topics"
+msgstr ""
+
+#: bp-forums/bp-forums-screens.php:25 bp-forums/bp-forums-screens.php:182
+msgid "The forums component has not been set up yet."
+msgstr ""
+
+#: bp-forums/bp-forums-screens.php:48 bp-groups/bp-groups-screens.php:372
+msgid "Please provide a title for your forum topic."
+msgstr ""
+
+#: bp-forums/bp-forums-screens.php:50 bp-groups/bp-groups-screens.php:374
+msgid "Forum posts cannot be empty. Please enter some text."
+msgstr ""
+
+#: bp-forums/bp-forums-screens.php:57 bp-groups/bp-groups-screens.php:386
+msgid "There was an error when creating the topic"
+msgstr ""
+
+#: bp-forums/bp-forums-screens.php:60 bp-groups/bp-groups-screens.php:389
+msgid "The topic was created successfully"
+msgstr ""
+
+#: bp-forums/bp-forums-screens.php:68 bp-forums/bp-forums-screens.php:73
+msgid "Please pick the group forum where you would like to post this topic."
+msgstr ""
+
+#: bp-forums/bp-forums-screens.php:208 bp-groups/bp-groups-template.php:1712
+#: bp-groups/bp-groups-template.php:1713
+#: bp-templates/bp-legacy/buddypress/groups/single/forum.php:19
+#: bp-themes/bp-default/forums/index.php:23
+#: bp-themes/bp-default/groups/single/forum.php:19
+msgid "New Topic"
+msgstr ""
+
+#: bp-forums/bp-forums-template.php:296 bp-forums/bp-forums-template.php:568
+msgctxt "Forum topic pagination previous text"
+msgid "&larr;"
+msgstr ""
+
+#: bp-forums/bp-forums-template.php:297 bp-forums/bp-forums-template.php:569
+msgctxt "Forum topic pagination next text"
+msgid "&rarr;"
+msgstr ""
+
+#: bp-forums/bp-forums-template.php:756 bp-forums/bp-forums-template.php:870
+#: bp-forums/bp-forums-template.php:2014
+#: bp-messages/bp-messages-classes.php:270
+#: bp-messages/bp-messages-template.php:884
+#: bp-messages/bp-messages-template.php:966
+msgid "Deleted User"
+msgstr ""
+
+#: bp-forums/bp-forums-template.php:916
+msgid "Group logo for %s"
+msgstr ""
+
+#: bp-forums/bp-forums-template.php:1103 bp-groups/bp-groups-template.php:1035
+msgid "%d post"
+msgstr ""
+
+#: bp-forums/bp-forums-template.php:1105 bp-groups/bp-groups-template.php:1037
+msgid "%d posts"
+msgstr ""
+
+#: bp-forums/bp-forums-template.php:1291
+msgid "Edit Topic"
+msgstr ""
+
+#: bp-forums/bp-forums-template.php:1295
+msgid "Sticky Topic"
+msgstr ""
+
+#: bp-forums/bp-forums-template.php:1297
+msgid "Un-stick Topic"
+msgstr ""
+
+#: bp-forums/bp-forums-template.php:1300
+msgid "Open Topic"
+msgstr ""
+
+#: bp-forums/bp-forums-template.php:1302
+msgid "Close Topic"
+msgstr ""
+
+#: bp-forums/bp-forums-template.php:1304
+msgid "Delete Topic"
+msgstr ""
+
+#: bp-forums/bp-forums-template.php:1525
+msgid " matching tag \"%s\""
+msgstr ""
+
+#: bp-forums/bp-forums-template.php:1527
+msgid "Viewing topic %s to %s (of %d topic%s)"
+msgid_plural "Viewing topic %s to %s (of %d total topics%s)"
+msgstr[0] ""
+msgstr[1] ""
+
+#: bp-forums/bp-forums-template.php:1736
+msgctxt "Forum thread pagination previous text"
+msgid "&larr;"
+msgstr ""
+
+#: bp-forums/bp-forums-template.php:1737
+msgctxt "Forum thread pagination next text"
+msgid "&rarr;"
+msgstr ""
+
+#: bp-forums/bp-forums-template.php:2166
+msgid "Viewing post %1$s to %2$s (%3$s post)"
+msgid_plural "Viewing post %1$s to %2$s (%3$s total posts)"
+msgstr[0] ""
+msgstr[1] ""
+
+#: bp-forums/deprecated/1.6.php:31 bp-forums/deprecated/1.6.php:133
+msgid "Configure bbPress"
+msgstr ""
+
+#: bp-forums/deprecated/1.6.php:34 bp-forums/deprecated/1.6.php:136
+msgid "Install bbPress"
+msgstr ""
+
+#: bp-forums/deprecated/1.6.php:47
+msgid "Settings Saved."
+msgstr ""
+
+#: bp-forums/deprecated/1.6.php:68
+msgid "(Installed)"
+msgstr ""
+
+#: bp-forums/deprecated/1.6.php:68 bp-forums/deprecated/1.6.php:210
+msgid "Forums for Groups"
+msgstr ""
+
+#: bp-forums/deprecated/1.6.php:70 bp-forums/deprecated/1.6.php:212
+msgid "Give each individual group its own discussion forum. Choose this if you'd like to keep your members' conversations separated into distinct areas."
+msgstr ""
+
+#: bp-forums/deprecated/1.6.php:72 bp-forums/deprecated/1.6.php:214
+msgid "Note: This component is retired and will not be receiving any updates in the future.  Only use this component if your current site relies on it."
+msgstr ""
+
+#: bp-forums/deprecated/1.6.php:74 bp-forums/deprecated/1.6.php:216
+msgid "Features"
+msgstr ""
+
+#: bp-forums/deprecated/1.6.php:76 bp-forums/deprecated/1.6.php:218
+msgid "Group Integration"
+msgstr ""
+
+#: bp-forums/deprecated/1.6.php:77 bp-forums/deprecated/1.6.php:219
+msgid "Member Profile Integration"
+msgstr ""
+
+#: bp-forums/deprecated/1.6.php:78 bp-forums/deprecated/1.6.php:220
+msgid "Activity Stream Integration"
+msgstr ""
+
+#: bp-forums/deprecated/1.6.php:79 bp-forums/deprecated/1.6.php:221
+msgid "@ Mention Integration"
+msgstr ""
+
+#: bp-forums/deprecated/1.6.php:83
+msgid "Uninstall Group Forums"
+msgstr ""
+
+#: bp-forums/deprecated/1.6.php:88 bp-forums/deprecated/1.6.php:231
+msgid "New! bbPress"
+msgstr ""
+
+#: bp-forums/deprecated/1.6.php:89 bp-forums/deprecated/1.6.php:232
+msgid "bbPress is a brand-new forum plugin from one of the lead developers of BuddyPress."
+msgstr ""
+
+#: bp-forums/deprecated/1.6.php:91 bp-forums/deprecated/1.6.php:234
+msgid "It boasts a bunch of cool features that the BP Legacy Discussion Forums does not have including:"
+msgstr ""
+
+#: bp-forums/deprecated/1.6.php:94 bp-forums/deprecated/1.6.php:237
+msgid "Non-group specific forum creation"
+msgstr ""
+
+#: bp-forums/deprecated/1.6.php:95 bp-forums/deprecated/1.6.php:238
+msgid "Moderation via the WP admin dashboard"
+msgstr ""
+
+#: bp-forums/deprecated/1.6.php:96 bp-forums/deprecated/1.6.php:239
+msgid "Topic splitting"
+msgstr ""
+
+#: bp-forums/deprecated/1.6.php:97 bp-forums/deprecated/1.6.php:240
+msgid "Revisions"
+msgstr ""
+
+#: bp-forums/deprecated/1.6.php:98 bp-forums/deprecated/1.6.php:241
+msgid "Spam management"
+msgstr ""
+
+#: bp-forums/deprecated/1.6.php:99 bp-forums/deprecated/1.6.php:242
+msgid "Subscriptions"
+msgstr ""
+
+#: bp-forums/deprecated/1.6.php:100 bp-forums/deprecated/1.6.php:243
+msgid "And more!"
+msgstr ""
+
+#: bp-forums/deprecated/1.6.php:103 bp-forums/deprecated/1.6.php:246
+msgid "If you decide to use bbPress, you will need to deactivate the legacy group forum component.  For more info, <a href=\"%s\">read this codex article</a>."
+msgstr ""
+
+#: bp-forums/deprecated/1.6.php:143
+msgid "The bb-config.php file was not found at that location, please try again."
+msgstr ""
+
+#: bp-forums/deprecated/1.6.php:146
+msgid "Forums were set up correctly using your existing bbPress install!"
+msgstr ""
+
+#: bp-forums/deprecated/1.6.php:147
+msgid "BuddyPress will now use its internal copy of bbPress to run the forums on your site. If you wish, you can remove your old bbPress installation files, as long as you keep the bb-config.php file in the same location."
+msgstr ""
+
+#: bp-forums/deprecated/1.6.php:152
+msgid "Existing bbPress Installation"
+msgstr ""
+
+#: bp-forums/deprecated/1.6.php:153
+msgid "BuddyPress can make use of your existing bbPress install. Just provide the location of your <code>bb-config.php</code> file, and BuddyPress will do the rest."
+msgstr ""
+
+#: bp-forums/deprecated/1.6.php:155 bp-forums/deprecated/1.6.php:187
+msgid "Complete Installation"
+msgstr ""
+
+#: bp-forums/deprecated/1.6.php:171
+msgid "<p>All done! Configuration settings have been saved to the file <code>bb-config.php</code> in the root of your WordPress install.</p>"
+msgstr ""
+
+#: bp-forums/deprecated/1.6.php:175
+msgid "<p>A configuration file could not be created. No problem, but you will need to save the text shown below into a file named <code>bb-config.php</code> in the root directory of your WordPress installation before you can start using the forum functionality.</p>"
+msgstr ""
+
+#: bp-forums/deprecated/1.6.php:184
+msgid "New bbPress Installation"
+msgstr ""
+
+#: bp-forums/deprecated/1.6.php:185
+msgid ""
+"You've decided to set up a new installation of bbPress for forum management in BuddyPress. This is very simple and is usually just a one click\n"
+"\t\t\t\tprocess. When you're ready, hit the link below."
+msgstr ""
+
+#: bp-forums/deprecated/1.6.php:197
+msgid "bbPress files were not found. To install the forums component you must download a copy of bbPress and make sure it is in the folder: \"%s\""
+msgstr ""
+
+#: bp-forums/deprecated/1.6.php:225
+msgid "Install Group Forums"
+msgstr ""
+
+#: bp-forums/deprecated/1.6.php:226
+msgid "Use Existing Installation"
+msgstr ""
+
+#: bp-friends/bp-friends-actions.php:38
+msgid "Friendship could not be requested."
+msgstr ""
+
+#: bp-friends/bp-friends-actions.php:40
+msgid "Friendship requested"
+msgstr ""
+
+#: bp-friends/bp-friends-actions.php:44
+msgid "You are already friends with this user"
+msgstr ""
+
+#: bp-friends/bp-friends-actions.php:46
+msgid "You already have a pending friendship request with this user"
+msgstr ""
+
+#: bp-friends/bp-friends-actions.php:76
+#: bp-templates/bp-legacy/buddypress-functions.php:987
+#: bp-themes/bp-default/_inc/ajax.php:646
+msgid "Friendship could not be canceled."
+msgstr ""
+
+#: bp-friends/bp-friends-actions.php:78
+msgid "Friendship canceled"
+msgstr ""
+
+#: bp-friends/bp-friends-actions.php:82
+msgid "You are not yet friends with this user"
+msgstr ""
+
+#: bp-friends/bp-friends-actions.php:84
+msgid "You have a pending friendship request with this user"
+msgstr ""
+
+#: bp-friends/bp-friends-activity.php:95
+msgid "Friendships accepted"
+msgstr ""
+
+#: bp-friends/bp-friends-activity.php:96
+msgid "New friendships"
+msgstr ""
+
+#: bp-friends/bp-friends-activity.php:99
+msgid "New friendship created"
+msgstr ""
+
+#: bp-friends/bp-friends-activity.php:131
+#: bp-friends/bp-friends-activity.php:140
+msgid "%1$s and %2$s are now friends"
+msgstr ""
+
+#: bp-friends/bp-friends-loader.php:91
+msgid "Search Friends..."
+msgstr ""
+
+#: bp-friends/bp-friends-loader.php:116
+msgid "Friends <span>%d</span>"
+msgstr ""
+
+#: bp-friends/bp-friends-loader.php:137 bp-friends/bp-friends-loader.php:201
+#: bp-friends/bp-friends-loader.php:226
+#: bp-templates/bp-legacy/buddypress/activity/index.php:104
+#: bp-templates/bp-legacy/buddypress/members/single/activity.php:35
+#: bp-themes/bp-default/activity/index.php:124
+#: bp-themes/bp-default/members/single/activity.php:35
+msgid "Friendships"
+msgstr ""
+
+#: bp-friends/bp-friends-loader.php:147 bp-groups/bp-groups-template.php:1480
+msgid "Requests"
+msgstr ""
+
+#: bp-friends/bp-friends-loader.php:182
+msgid "Friends <span class=\"count\">%s</span>"
+msgstr ""
+
+#: bp-friends/bp-friends-loader.php:183
+msgid "Pending Requests <span class=\"count\">%s</span>"
+msgstr ""
+
+#: bp-friends/bp-friends-loader.php:186
+msgid "No Pending Requests"
+msgstr ""
+
+#: bp-friends/bp-friends-notifications.php:43
+msgid "New friendship request from %s"
+msgstr ""
+
+#: bp-friends/bp-friends-notifications.php:44
+msgid ""
+"%1$s wants to add you as a friend.\n"
+"\n"
+"To view all of your pending friendship requests: %2$s\n"
+"\n"
+"To view %3$s's profile: %4$s\n"
+"\n"
+"---------------------\n"
+msgstr ""
+
+#: bp-friends/bp-friends-notifications.php:94
+#: bp-friends/bp-friends-notifications.php:144
+msgid "%s accepted your friendship request"
+msgstr ""
+
+#: bp-friends/bp-friends-notifications.php:95
+msgid ""
+"%1$s accepted your friend request.\n"
+"\n"
+"To view %2$s's profile: %3$s\n"
+"\n"
+"---------------------\n"
+msgstr ""
+
+#: bp-friends/bp-friends-notifications.php:141
+msgid "%d friends accepted your friendship requests"
+msgstr ""
+
+#: bp-friends/bp-friends-notifications.php:155
+msgid "You have %d pending friendship requests"
+msgstr ""
+
+#: bp-friends/bp-friends-notifications.php:158
+msgid "You have a friendship request from %s"
+msgstr ""
+
+#: bp-friends/bp-friends-screens.php:36
+msgid "Friendship accepted"
+msgstr ""
+
+#: bp-friends/bp-friends-screens.php:38
+msgid "Friendship could not be accepted"
+msgstr ""
+
+#: bp-friends/bp-friends-screens.php:47
+msgid "Friendship rejected"
+msgstr ""
+
+#: bp-friends/bp-friends-screens.php:49
+msgid "Friendship could not be rejected"
+msgstr ""
+
+#: bp-friends/bp-friends-screens.php:58
+msgid "Friendship request withdrawn"
+msgstr ""
+
+#: bp-friends/bp-friends-screens.php:60
+msgid "Friendship request could not be withdrawn"
+msgstr ""
+
+#: bp-friends/bp-friends-screens.php:94
+msgid "A member sends you a friendship request"
+msgstr ""
+
+#: bp-friends/bp-friends-screens.php:100
+msgid "A member accepts your friendship request"
+msgstr ""
+
+#: bp-friends/bp-friends-template.php:68 bp-xprofile/bp-xprofile-loader.php:129
+msgid "My Friends"
+msgstr ""
+
+#: bp-friends/bp-friends-template.php:68
+msgid "%s's Friends"
+msgstr ""
+
+#: bp-friends/bp-friends-template.php:68
+msgid "See All"
+msgstr ""
+
+#: bp-friends/bp-friends-template.php:88
+msgid "You haven't added any friend connections yet."
+msgstr ""
+
+#: bp-friends/bp-friends-template.php:88
+msgid "%s hasn't created any friend connections yet."
+msgstr ""
+
+#: bp-friends/bp-friends-template.php:158
+msgid "There aren't enough site members to show a random sample just yet."
+msgstr ""
+
+#: bp-friends/bp-friends-template.php:175
+msgid "Filter Friends"
+msgstr ""
+
+#: bp-friends/bp-friends-template.php:223
+msgid "%d friend"
+msgstr ""
+
+#: bp-friends/bp-friends-template.php:225
+msgid "%d friends"
+msgstr ""
+
+#: bp-friends/bp-friends-template.php:320
+#: bp-templates/bp-legacy/buddypress-functions.php:999
+#: bp-themes/bp-default/_inc/ajax.php:658
+msgid "Cancel Friendship Request"
+msgstr ""
+
+#: bp-friends/bp-friends-template.php:321
+msgid "Cancel Friendship Requested"
+msgstr ""
+
+#: bp-friends/bp-friends-template.php:337
+#: bp-friends/bp-friends-template.php:338
+msgid "Friendship Requested"
+msgstr ""
+
+#: bp-friends/bp-friends-template.php:354
+#: bp-friends/bp-friends-template.php:355
+msgid "Cancel Friendship"
+msgstr ""
+
+#: bp-friends/bp-friends-template.php:371
+#: bp-friends/bp-friends-template.php:372
+#: bp-templates/bp-legacy/buddypress-functions.php:989
+#: bp-templates/bp-legacy/buddypress-functions.php:1007
+#: bp-themes/bp-default/_inc/ajax.php:648
+#: bp-themes/bp-default/_inc/ajax.php:666
+msgid "Add Friend"
+msgstr ""
+
+#: bp-friends/bp-friends-widgets.php:41
+msgid "A dynamic list of recently active, popular, and newest Friends of the displayed member.  Widget is only shown when viewing a member profile."
+msgstr ""
+
+#: bp-friends/bp-friends-widgets.php:44
+msgctxt "widget name"
+msgid "(BuddyPress) Friends"
+msgstr ""
+
+#: bp-friends/bp-friends-widgets.php:66
+msgid "%s&#8217;s Friends"
+msgstr ""
+
+#: bp-friends/bp-friends-widgets.php:128
+#: bp-templates/bp-legacy/buddypress/members/members-loop.php:108
+#: bp-themes/bp-default/members/members-loop.php:108
+msgid "Sorry, no members were found."
+msgstr ""
+
+#: bp-friends/bp-friends-widgets.php:174
+msgid "Max friends to show:"
+msgstr ""
+
+#: bp-friends/bp-friends-widgets.php:177
+msgid "Default friends to show:"
+msgstr ""
+
+#: bp-groups/bp-groups-actions.php:31
+msgid "Sorry, you are not allowed to create groups."
+msgstr ""
+
+#: bp-groups/bp-groups-actions.php:54
+msgid "There was an error saving group details. Please try again."
+msgstr ""
+
+#: bp-groups/bp-groups-actions.php:76
+msgid "Please fill in all of the required fields"
+msgstr ""
+
+#: bp-groups/bp-groups-actions.php:83 bp-groups/bp-groups-actions.php:107
+msgid "There was an error saving group details, please try again."
+msgstr ""
+
+#: bp-groups/bp-groups-actions.php:147
+msgid "%1$s created the group %2$s"
+msgstr ""
+
+#: bp-groups/bp-groups-actions.php:199
+msgid "There was an error saving the group avatar, please try uploading again."
+msgstr ""
+
+#: bp-groups/bp-groups-actions.php:201
+msgid "The group avatar was uploaded successfully!"
+msgstr ""
+
+#: bp-groups/bp-groups-actions.php:225 bp-groups/bp-groups-actions.php:232
+msgid "There was an error joining the group."
+msgstr ""
+
+#: bp-groups/bp-groups-actions.php:234
+msgid "You joined the group!"
+msgstr ""
+
+#: bp-groups/bp-groups-actions.php:272 bp-groups/bp-groups-screens.php:711
+msgid "This group must have at least one admin"
+msgstr ""
+
+#: bp-groups/bp-groups-actions.php:274
+msgid "There was an error leaving the group."
+msgstr ""
+
+#: bp-groups/bp-groups-actions.php:276 bp-groups/bp-groups-functions.php:291
+msgid "You successfully left the group."
+msgstr ""
+
+#: bp-groups/bp-groups-actions.php:359
+msgid "Activity feed for the group, %s."
+msgstr ""
+
+#: bp-groups/bp-groups-activity.php:26
+msgid "Created a group"
+msgstr ""
+
+#: bp-groups/bp-groups-activity.php:27
+msgid "Joined a group"
+msgstr ""
+
+#: bp-groups/bp-groups-activity.php:33
+msgid "New group forum topic"
+msgstr ""
+
+#: bp-groups/bp-groups-activity.php:34
+msgid "New group forum post"
+msgstr ""
+
+#: bp-groups/bp-groups-activity.php:140 bp-groups/bp-groups-functions.php:335
+#: bp-groups/bp-groups-screens.php:52
+msgid "%1$s joined the group %2$s"
+msgstr ""
+
+#: bp-groups/bp-groups-admin.php:114
+msgid "This page is a convenient way to edit the details associated with one of your groups."
+msgstr ""
+
+#: bp-groups/bp-groups-admin.php:115
+msgid "The Name and Description box is fixed in place, but you can reposition all the other boxes using drag and drop, and can minimize or expand them by clicking the title bar of each box. Use the Screen Options tab to hide or unhide, or to choose a 1- or 2-column layout for this screen."
+msgstr ""
+
+#: bp-groups/bp-groups-admin.php:121
+msgid "Support Forums"
+msgstr ""
+
+#: bp-groups/bp-groups-admin.php:125
+msgctxt "group admin edit screen"
+msgid "Save"
+msgstr ""
+
+#: bp-groups/bp-groups-admin.php:126
+msgctxt "group admin edit screen"
+msgid "Settings"
+msgstr ""
+
+#: bp-groups/bp-groups-admin.php:127
+msgctxt "group admin edit screen"
+msgid "Add New Members"
+msgstr ""
+
+#: bp-groups/bp-groups-admin.php:128
+msgctxt "group admin edit screen"
+msgid "Manage Members"
+msgstr ""
+
+#: bp-groups/bp-groups-admin.php:143
+msgctxt "Groups per page (screen options)"
+msgid "Groups"
+msgstr ""
+
+#: bp-groups/bp-groups-admin.php:150
+msgid "You can manage groups much like you can manage comments and other content. This screen is customizable in the same ways as other management screens, and you can act on groups by using the on-hover action links or the Bulk Actions."
+msgstr ""
+
+#: bp-groups/bp-groups-admin.php:155
+msgid "Group Actions"
+msgstr ""
+
+#: bp-groups/bp-groups-admin.php:157
+msgid "Clicking \"Visit\" will take you to the group&#8217;s public page. Use this link to see what the group looks like on the front end of your site."
+msgstr ""
+
+#: bp-groups/bp-groups-admin.php:158
+msgid "Clicking \"Edit\" will take you to a Dashboard panel where you can manage various details about the group, such as its name and description, its members, and other settings."
+msgstr ""
+
+#: bp-groups/bp-groups-admin.php:159
+msgid "If you click \"Delete\" under a specific group, or select a number of groups and then choose Delete from the Bulk Actions menu, you will be led to a page where you&#8217;ll be asked to confirm the permanent deletion of the group(s)."
+msgstr ""
+
+#: bp-groups/bp-groups-admin.php:174
+msgid "Start typing a username to add a new member."
+msgstr ""
+
+#: bp-groups/bp-groups-admin.php:175
+msgid "If you leave this page, you will lose any unsaved changes you have made to the group."
+msgstr ""
+
+#: bp-groups/bp-groups-admin.php:453
+msgid "You cannot remove all administrators from a group."
+msgstr ""
+
+#: bp-groups/bp-groups-admin.php:457
+msgid "An error occurred when trying to update your group details."
+msgstr ""
+
+#: bp-groups/bp-groups-admin.php:459
+msgid "The group has been updated successfully."
+msgstr ""
+
+#: bp-groups/bp-groups-admin.php:463
+msgid "The following users could not be added to the group: <em>%s</em>"
+msgstr ""
+
+#: bp-groups/bp-groups-admin.php:467
+msgid "The following users were successfully added to the group: <em>%s</em>"
+msgstr ""
+
+#: bp-groups/bp-groups-admin.php:472
+msgid "An error occurred when trying to modify the following members: <em>%s</em>"
+msgstr ""
+
+#: bp-groups/bp-groups-admin.php:477
+msgid "The following members were successfully modified: <em>%s</em>"
+msgstr ""
+
+#: bp-groups/bp-groups-admin.php:496 bp-groups/bp-groups-adminbar.php:39
+#: bp-xprofile/bp-xprofile-admin.php:114
+msgid "Edit Group"
+msgstr ""
+
+#: bp-groups/bp-groups-admin.php:499 bp-groups/bp-groups-admin.php:641
+msgid "Add New"
+msgstr ""
+
+#: bp-groups/bp-groups-admin.php:518
+msgid "Name and Description"
+msgstr ""
+
+#: bp-groups/bp-groups-admin.php:545
+msgid "No group found with this ID. <a href=\"%s\">Go back and try again</a>."
+msgstr ""
+
+#: bp-groups/bp-groups-admin.php:587
+msgid "Delete Groups"
+msgstr ""
+
+#: bp-groups/bp-groups-admin.php:588
+msgid "You are about to delete the following groups:"
+msgstr ""
+
+#: bp-groups/bp-groups-admin.php:596
+msgid "This action cannot be undone."
+msgstr ""
+
+#: bp-groups/bp-groups-admin.php:625
+msgid "%s group has been permanently deleted."
+msgid_plural "%s groups have been permanently deleted."
+msgstr[0] ""
+msgstr[1] ""
+
+#: bp-groups/bp-groups-admin.php:658
+msgid "Search all Groups"
+msgstr ""
+
+#: bp-groups/bp-groups-admin.php:681
+#: bp-templates/bp-legacy/buddypress/groups/create.php:112
+#: bp-templates/bp-legacy/buddypress/groups/single/admin.php:47
+#: bp-themes/bp-default/groups/create.php:119
+#: bp-themes/bp-default/groups/single/admin.php:47
+msgid "Enable discussion forum"
+msgstr ""
+
+#: bp-groups/bp-groups-admin.php:686
+msgid "Privacy"
+msgstr ""
+
+#: bp-groups/bp-groups-admin.php:689 bp-groups/bp-groups-admin.php:1442
+#: bp-groups/bp-groups-template.php:647
+msgid "Public"
+msgstr ""
+
+#: bp-groups/bp-groups-admin.php:690 bp-groups/bp-groups-admin.php:1445
+#: bp-groups/bp-groups-template.php:649
+msgid "Private"
+msgstr ""
+
+#: bp-groups/bp-groups-admin.php:691 bp-groups/bp-groups-admin.php:1448
+msgid "Hidden"
+msgstr ""
+
+#: bp-groups/bp-groups-admin.php:695
+msgid "Who can invite others to this group?"
+msgstr ""
+
+#: bp-groups/bp-groups-admin.php:698
+#: bp-templates/bp-legacy/buddypress/groups/create.php:89
+#: bp-templates/bp-legacy/buddypress/groups/single/admin.php:99
+#: bp-themes/bp-default/groups/create.php:96
+#: bp-themes/bp-default/groups/single/admin.php:99
+msgid "All group members"
+msgstr ""
+
+#: bp-groups/bp-groups-admin.php:699
+#: bp-templates/bp-legacy/buddypress/groups/create.php:94
+#: bp-templates/bp-legacy/buddypress/groups/single/admin.php:104
+#: bp-themes/bp-default/groups/create.php:101
+#: bp-themes/bp-default/groups/single/admin.php:104
+msgid "Group admins and mods only"
+msgstr ""
+
+#: bp-groups/bp-groups-admin.php:700
+#: bp-templates/bp-legacy/buddypress/groups/create.php:99
+#: bp-templates/bp-legacy/buddypress/groups/single/admin.php:109
+#: bp-themes/bp-default/groups/create.php:106
+#: bp-themes/bp-default/groups/single/admin.php:109
+msgid "Group admins only"
+msgstr ""
+
+#: bp-groups/bp-groups-admin.php:715
+msgid "Enter a comma-separated list of user logins."
+msgstr ""
+
+#: bp-groups/bp-groups-admin.php:774
+#: bp-templates/bp-legacy/buddypress/groups/single/admin.php:177
+#: bp-themes/bp-default/groups/single/admin.php:177
+msgid "Administrators"
+msgstr ""
+
+#: bp-groups/bp-groups-admin.php:775
+#: bp-templates/bp-legacy/buddypress/groups/single/admin.php:205
+#: bp-themes/bp-default/groups/single/admin.php:205
+msgid "Moderators"
+msgstr ""
+
+#: bp-groups/bp-groups-admin.php:777
+msgid "Banned Users"
+msgstr ""
+
+#: bp-groups/bp-groups-admin.php:790
+msgctxt "Group member user_id in group admin"
+msgid "ID"
+msgstr ""
+
+#: bp-groups/bp-groups-admin.php:791
+msgctxt "Group member name in group admin"
+msgid "Name"
+msgstr ""
+
+#: bp-groups/bp-groups-admin.php:792
+msgctxt "Group member role in group admin"
+msgid "Group Role"
+msgstr ""
+
+#: bp-groups/bp-groups-admin.php:814
+msgid "Administrator"
+msgstr ""
+
+#: bp-groups/bp-groups-admin.php:815
+msgid "Moderator"
+msgstr ""
+
+#: bp-groups/bp-groups-admin.php:816
+msgid "Member"
+msgstr ""
+
+#: bp-groups/bp-groups-admin.php:817
+msgid "Banned"
+msgstr ""
+
+#: bp-groups/bp-groups-admin.php:818
+msgid "Remove From Group"
+msgstr ""
+
+#: bp-groups/bp-groups-admin.php:851
+msgid "No members of this type"
+msgstr ""
+
+#: bp-groups/bp-groups-admin.php:877 bp-groups/bp-groups-adminbar.php:101
+#: bp-groups/bp-groups-buddybar.php:58
+#: bp-templates/bp-legacy/buddypress/groups/single/admin.php:360
+#: bp-themes/bp-default/groups/single/admin.php:360
+#: bp-xprofile/bp-xprofile-admin.php:118
+msgid "Delete Group"
+msgstr ""
+
+#: bp-groups/bp-groups-admin.php:881 bp-groups/bp-groups-classes.php:2965
+#: bp-templates/bp-legacy/buddypress/groups/single/admin.php:32
+#: bp-templates/bp-legacy/buddypress/groups/single/admin.php:117
+#: bp-templates/bp-legacy/buddypress/groups/single/forum/edit.php:58
+#: bp-templates/bp-legacy/buddypress/groups/single/forum/edit.php:74
+#: bp-templates/bp-legacy/buddypress/members/single/profile/edit.php:148
+#: bp-templates/bp-legacy/buddypress/members/single/settings/general.php:22
+#: bp-templates/bp-legacy/buddypress/members/single/settings/notifications.php:11
+#: bp-themes/bp-default/groups/single/admin.php:32
+#: bp-themes/bp-default/groups/single/admin.php:117
+#: bp-themes/bp-default/groups/single/forum/edit.php:58
+#: bp-themes/bp-default/groups/single/forum/edit.php:74
+#: bp-themes/bp-default/members/single/profile/edit.php:148
+#: bp-themes/bp-default/members/single/settings/general.php:72
+#: bp-themes/bp-default/members/single/settings/notifications.php:61
+#: bp-xprofile/bp-xprofile-classes.php:361
+msgid "Save Changes"
+msgstr ""
+
+#: bp-groups/bp-groups-admin.php:930
+msgid "&laquo;"
+msgstr ""
+
+#: bp-groups/bp-groups-admin.php:931
+msgid "&raquo;"
+msgstr ""
+
+#: bp-groups/bp-groups-admin.php:937
+msgid "Viewing %1$s - %2$s of %3$s"
+msgstr ""
+
+#: bp-groups/bp-groups-admin.php:940 bp-groups/bp-groups-template.php:960
+msgid "%s member"
+msgid_plural "%s members"
+msgstr[0] ""
+msgstr[1] ""
+
+#. translators: 1: user_login, 2: user_email
+
+#: bp-groups/bp-groups-admin.php:1006
+msgid "%1$s (%2$s)"
+msgstr ""
+
+#: bp-groups/bp-groups-admin.php:1190
+msgid "No groups found."
+msgstr ""
+
+#: bp-groups/bp-groups-admin.php:1263
+msgid "Public <span class=\"count\">(%s)</span>"
+msgstr ""
+
+#: bp-groups/bp-groups-admin.php:1264
+msgid "Private <span class=\"count\">(%s)</span>"
+msgstr ""
+
+#: bp-groups/bp-groups-admin.php:1265
+msgid "Hidden <span class=\"count\">(%s)</span>"
+msgstr ""
+
+#: bp-groups/bp-groups-admin.php:1297
+msgctxt "Groups admin Group Name column header"
+msgid "Name"
+msgstr ""
+
+#: bp-groups/bp-groups-admin.php:1298
+msgctxt "Groups admin Group Description column header"
+msgid "Description"
+msgstr ""
+
+#: bp-groups/bp-groups-admin.php:1299
+msgctxt "Groups admin Privacy Status column header"
+msgid "Status"
+msgstr ""
+
+#: bp-groups/bp-groups-admin.php:1300
+msgctxt "Groups admin Members column header"
+msgid "# Members"
+msgstr ""
+
+#: bp-groups/bp-groups-admin.php:1301
+msgctxt "Groups admin Last Active column header"
+msgid "Last Active"
+msgstr ""
+
+#: bp-groups/bp-groups-admin.php:1340
+msgid "Select group %1$d"
+msgstr ""
+
+#: bp-groups/bp-groups-adminbar.php:47 bp-groups/bp-groups-buddybar.php:34
+msgid "Edit Details"
+msgstr ""
+
+#: bp-groups/bp-groups-adminbar.php:55
+msgid "Edit Settings"
+msgstr ""
+
+#: bp-groups/bp-groups-adminbar.php:64 bp-members/bp-members-adminbar.php:108
+msgid "Edit Avatar"
+msgstr ""
+
+#: bp-groups/bp-groups-adminbar.php:74 bp-groups/bp-groups-buddybar.php:46
+msgid "Manage Invitations"
+msgstr ""
+
+#: bp-groups/bp-groups-adminbar.php:83 bp-groups/bp-groups-buddybar.php:50
+msgid "Manage Members"
+msgstr ""
+
+#: bp-groups/bp-groups-adminbar.php:92 bp-groups/bp-groups-buddybar.php:54
+msgid "Membership Requests"
+msgstr ""
+
+#: bp-groups/bp-groups-buddybar.php:31 bp-members/bp-members-buddybar.php:94
+msgid "Admin Options"
+msgstr ""
+
+#: bp-groups/bp-groups-buddybar.php:36
+msgid "Group Settings"
+msgstr ""
+
+#: bp-groups/bp-groups-buddybar.php:40 bp-groups/bp-groups-loader.php:590
+#: bp-groups/bp-groups-template.php:2634
+msgid "Group Avatar"
+msgstr ""
+
+#: bp-groups/bp-groups-classes.php:1868
+msgid "Group Mod"
+msgstr ""
+
+#: bp-groups/bp-groups-classes.php:1874 bp-groups/bp-groups-functions.php:121
+msgid "Group Admin"
+msgstr ""
+
+#: bp-groups/bp-groups-forums.php:107 bp-groups/bp-groups-forums.php:256
+msgid "%1$s replied to the forum topic %2$s in the group %3$s"
+msgstr ""
+
+#: bp-groups/bp-groups-forums.php:157
+msgid "%1$s started the forum topic %2$s in the group %3$s"
+msgstr ""
+
+#: bp-groups/bp-groups-forums.php:209
+msgid "%1$s edited the forum topic %2$s in the group %3$s"
+msgstr ""
+
+#: bp-groups/bp-groups-functions.php:281
+msgid "As the only Admin, you cannot leave the group."
+msgstr ""
+
+#: bp-groups/bp-groups-functions.php:596
+msgid "%1$s posted an update in the group %2$s"
+msgstr ""
+
+#: bp-groups/bp-groups-loader.php:146
+msgid "Search Groups..."
+msgstr ""
+
+#: bp-groups/bp-groups-loader.php:275
+msgid "You do not have access to this group."
+msgstr ""
+
+#: bp-groups/bp-groups-loader.php:290
+msgid "You are not an admin of this group."
+msgstr ""
+
+#: bp-groups/bp-groups-loader.php:300 bp-groups/bp-groups-template.php:1461
+msgid "Details"
+msgstr ""
+
+#: bp-groups/bp-groups-loader.php:312 bp-groups/bp-groups-template.php:1472
+msgid "Avatar"
+msgstr ""
+
+#: bp-groups/bp-groups-loader.php:320
+msgid "Invites"
+msgstr ""
+
+#: bp-groups/bp-groups-loader.php:345
+msgid "Groups <span>%s</span>"
+msgstr ""
+
+#: bp-groups/bp-groups-loader.php:367 bp-groups/bp-groups-loader.php:397
+#: bp-groups/bp-groups-loader.php:536 bp-groups/bp-groups-loader.php:571
+msgid "Memberships"
+msgstr ""
+
+#: bp-groups/bp-groups-loader.php:378
+msgid "Invitations"
+msgstr ""
+
+#: bp-groups/bp-groups-loader.php:409
+msgctxt "Group home navigation title"
+msgid "Home"
+msgstr ""
+
+#: bp-groups/bp-groups-loader.php:430 bp-groups/bp-groups-template.php:1826
+#: bp-groups/bp-groups-template.php:1827
+#: bp-templates/bp-legacy/buddypress-functions.php:1121
+#: bp-themes/bp-default/_inc/ajax.php:780
+msgid "Request Membership"
+msgstr ""
+
+#: bp-groups/bp-groups-loader.php:442
+msgid "Forum"
+msgstr ""
+
+#: bp-groups/bp-groups-loader.php:454
+msgid "Members <span>%s</span>"
+msgstr ""
+
+#: bp-groups/bp-groups-loader.php:466
+#: bp-templates/bp-legacy/buddypress/groups/single/send-invites.php:60
+#: bp-themes/bp-default/groups/single/send-invites.php:60
+msgid "Send Invites"
+msgstr ""
+
+#: bp-groups/bp-groups-loader.php:480
+msgid "Admin"
+msgstr ""
+
+#: bp-groups/bp-groups-loader.php:517
+msgid "No Pending Invites"
+msgstr ""
+
+#: bp-groups/bp-groups-loader.php:520
+msgid "Groups <span class=\"count\">%s</span>"
+msgstr ""
+
+#: bp-groups/bp-groups-loader.php:521
+msgid "Pending Invites <span class=\"count\">%s</span>"
+msgstr ""
+
+#: bp-groups/bp-groups-notifications.php:21
+msgid "Group Details Updated"
+msgstr ""
+
+#: bp-groups/bp-groups-notifications.php:36
+msgid ""
+"Group details for the group \"%1$s\" were updated:\n"
+"\n"
+"To view the group: %2$s\n"
+"\n"
+"---------------------\n"
+msgstr ""
+
+#: bp-groups/bp-groups-notifications.php:85
+msgid "Membership request for group: %s"
+msgstr ""
+
+#: bp-groups/bp-groups-notifications.php:87
+msgid ""
+"%1$s wants to join the group \"%2$s\".\n"
+"\n"
+"Because you are the administrator of this group, you must either accept or reject the membership request.\n"
+"\n"
+"To view all pending membership requests for this group, please visit:\n"
+"%3$s\n"
+"\n"
+"To view %4$s's profile: %5$s\n"
+"\n"
+"---------------------\n"
+msgstr ""
+
+#: bp-groups/bp-groups-notifications.php:145
+msgid "Membership request for group \"%s\" accepted"
+msgstr ""
+
+#: bp-groups/bp-groups-notifications.php:146
+msgid ""
+"Your membership request for the group \"%1$s\" has been accepted.\n"
+"\n"
+"To view the group please login and visit: %2$s\n"
+"\n"
+"---------------------\n"
+msgstr ""
+
+#: bp-groups/bp-groups-notifications.php:155
+msgid "Membership request for group \"%s\" rejected"
+msgstr ""
+
+#: bp-groups/bp-groups-notifications.php:156
+msgid ""
+"Your membership request for the group \"%1$s\" has been rejected.\n"
+"\n"
+"To submit another request please log in and visit: %2$s\n"
+"\n"
+"---------------------\n"
+msgstr ""
+
+#: bp-groups/bp-groups-notifications.php:185
+msgid "an administrator"
+msgstr ""
+
+#: bp-groups/bp-groups-notifications.php:188
+msgid "a moderator"
+msgstr ""
+
+#: bp-groups/bp-groups-notifications.php:215
+msgid "You have been promoted in the group: \"%s\""
+msgstr ""
+
+#: bp-groups/bp-groups-notifications.php:216
+msgid ""
+"You have been promoted to %1$s for the group: \"%2$s\".\n"
+"\n"
+"To view the group please visit: %3$s\n"
+"\n"
+"---------------------\n"
+msgstr ""
+
+#: bp-groups/bp-groups-notifications.php:273
+msgid "You have an invitation to the group: \"%s\""
+msgstr ""
+
+#: bp-groups/bp-groups-notifications.php:275
+msgid ""
+"One of your friends %1$s has invited you to the group: \"%2$s\".\n"
+"\n"
+"To view your group invites visit: %3$s\n"
+"\n"
+"To view the group visit: %4$s\n"
+"\n"
+"To view %5$s's profile visit: %6$s\n"
+"\n"
+"---------------------\n"
+msgstr ""
+
+#: bp-groups/bp-groups-notifications.php:329
+msgid "%1$d new membership requests for the group \"%2$s\""
+msgstr ""
+
+#: bp-groups/bp-groups-notifications.php:334
+msgid "Group Membership Requests"
+msgstr ""
+
+#: bp-groups/bp-groups-notifications.php:343
+#: bp-groups/bp-groups-notifications.php:348
+msgid "%s requests group membership"
+msgstr ""
+
+#: bp-groups/bp-groups-notifications.php:366
+msgid "%d accepted group membership requests"
+msgstr ""
+
+#: bp-groups/bp-groups-notifications.php:379
+msgid "Membership for group \"%s\" accepted"
+msgstr ""
+
+#: bp-groups/bp-groups-notifications.php:402
+msgid "%d rejected group membership requests"
+msgstr ""
+
+#: bp-groups/bp-groups-notifications.php:415
+msgid "Membership for group \"%s\" rejected"
+msgstr ""
+
+#: bp-groups/bp-groups-notifications.php:438
+msgid "You were promoted to an admin in %d groups"
+msgstr ""
+
+#: bp-groups/bp-groups-notifications.php:451
+msgid "You were promoted to an admin in the group \"%s\""
+msgstr ""
+
+#: bp-groups/bp-groups-notifications.php:474
+msgid "You were promoted to a mod in %d groups"
+msgstr ""
+
+#: bp-groups/bp-groups-notifications.php:487
+msgid "You were promoted to a mod in the group \"%s\""
+msgstr ""
+
+#: bp-groups/bp-groups-notifications.php:511
+msgid "You have %d new group invitations"
+msgstr ""
+
+#: bp-groups/bp-groups-notifications.php:515
+msgid "Group Invites"
+msgstr ""
+
+#: bp-groups/bp-groups-notifications.php:523
+msgid "You have an invitation to the group: %s"
+msgstr ""
+
+#: bp-groups/bp-groups-screens.php:44
+msgid "Group invite could not be accepted"
+msgstr ""
+
+#: bp-groups/bp-groups-screens.php:46 bp-groups/bp-groups-screens.php:464
+msgid "Group invite accepted"
+msgstr ""
+
+#: bp-groups/bp-groups-screens.php:72
+msgid "Group invite could not be rejected"
+msgstr ""
+
+#: bp-groups/bp-groups-screens.php:74
+msgid "Group invite rejected"
+msgstr ""
+
+#: bp-groups/bp-groups-screens.php:152
+msgid "It looks like you've already said that!"
+msgstr ""
+
+#: bp-groups/bp-groups-screens.php:155
+msgid "There was an error when replying to that topic"
+msgstr ""
+
+#: bp-groups/bp-groups-screens.php:157
+msgid "Your reply was posted successfully"
+msgstr ""
+
+#: bp-groups/bp-groups-screens.php:178
+msgid "There was an error when making that topic a sticky"
+msgstr ""
+
+#: bp-groups/bp-groups-screens.php:180
+msgid "The topic was made sticky successfully"
+msgstr ""
+
+#: bp-groups/bp-groups-screens.php:193
+msgid "There was an error when unsticking that topic"
+msgstr ""
+
+#: bp-groups/bp-groups-screens.php:195
+msgid "The topic was unstuck successfully"
+msgstr ""
+
+#: bp-groups/bp-groups-screens.php:208
+msgid "There was an error when closing that topic"
+msgstr ""
+
+#: bp-groups/bp-groups-screens.php:210
+msgid "The topic was closed successfully"
+msgstr ""
+
+#: bp-groups/bp-groups-screens.php:223
+msgid "There was an error when opening that topic"
+msgstr ""
+
+#: bp-groups/bp-groups-screens.php:225
+msgid "The topic was opened successfully"
+msgstr ""
+
+#: bp-groups/bp-groups-screens.php:248
+msgid "There was an error deleting the topic"
+msgstr ""
+
+#: bp-groups/bp-groups-screens.php:250
+msgid "The topic was deleted successfully"
+msgstr ""
+
+#: bp-groups/bp-groups-screens.php:274
+msgid "There was an error when editing that topic"
+msgstr ""
+
+#: bp-groups/bp-groups-screens.php:276
+msgid "The topic was edited successfully"
+msgstr ""
+
+#: bp-groups/bp-groups-screens.php:301
+msgid "There was an error deleting that post"
+msgstr ""
+
+#: bp-groups/bp-groups-screens.php:303
+msgid "The post was deleted successfully"
+msgstr ""
+
+#: bp-groups/bp-groups-screens.php:327
+msgid "There was an error when editing that post"
+msgstr ""
+
+#: bp-groups/bp-groups-screens.php:329
+msgid "The post was edited successfully"
+msgstr ""
+
+#: bp-groups/bp-groups-screens.php:345 bp-groups/bp-groups-screens.php:364
+msgid "You have been banned from this group."
+msgstr ""
+
+#: bp-groups/bp-groups-screens.php:378
+msgid "This group does not have a forum setup yet."
+msgstr ""
+
+#: bp-groups/bp-groups-screens.php:437
+msgid "Group invites sent."
+msgstr ""
+
+#: bp-groups/bp-groups-screens.php:466
+msgid "There was an error accepting the group invitation, please try again."
+msgstr ""
+
+#: bp-groups/bp-groups-screens.php:478
+msgid "There was an error sending your group membership request, please try again."
+msgstr ""
+
+#: bp-groups/bp-groups-screens.php:480
+msgid "Your membership request was sent to the group administrator successfully. You will be notified when the group administrator responds to your request."
+msgstr ""
+
+#: bp-groups/bp-groups-screens.php:529
+msgid "There was an error updating group details, please try again."
+msgstr ""
+
+#: bp-groups/bp-groups-screens.php:531
+msgid "Group details were successfully updated."
+msgstr ""
+
+#: bp-groups/bp-groups-screens.php:573
+msgid "There was an error updating group settings, please try again."
+msgstr ""
+
+#: bp-groups/bp-groups-screens.php:575
+msgid "Group settings were successfully updated."
+msgstr ""
+
+#: bp-groups/bp-groups-screens.php:607 bp-xprofile/bp-xprofile-actions.php:39
+msgid "Your avatar was deleted successfully!"
+msgstr ""
+
+#: bp-groups/bp-groups-screens.php:609 bp-xprofile/bp-xprofile-actions.php:41
+msgid "There was a problem deleting that avatar, please try again."
+msgstr ""
+
+#: bp-groups/bp-groups-screens.php:652
+msgid "There was a problem cropping the avatar."
+msgstr ""
+
+#: bp-groups/bp-groups-screens.php:654
+msgid "The new group avatar was uploaded successfully."
+msgstr ""
+
+#: bp-groups/bp-groups-screens.php:690
+msgid "There was an error when promoting that user, please try again"
+msgstr ""
+
+#: bp-groups/bp-groups-screens.php:692
+msgid "User promoted successfully"
+msgstr ""
+
+#: bp-groups/bp-groups-screens.php:715
+msgid "There was an error when demoting that user, please try again"
+msgstr ""
+
+#: bp-groups/bp-groups-screens.php:717
+msgid "User demoted successfully"
+msgstr ""
+
+#: bp-groups/bp-groups-screens.php:733
+msgid "There was an error when banning that user, please try again"
+msgstr ""
+
+#: bp-groups/bp-groups-screens.php:735
+msgid "User banned successfully"
+msgstr ""
+
+#: bp-groups/bp-groups-screens.php:751
+msgid "There was an error when unbanning that user, please try again"
+msgstr ""
+
+#: bp-groups/bp-groups-screens.php:753
+msgid "User ban removed successfully"
+msgstr ""
+
+#: bp-groups/bp-groups-screens.php:769
+msgid "There was an error removing that user from the group, please try again"
+msgstr ""
+
+#: bp-groups/bp-groups-screens.php:771
+msgid "User removed successfully"
+msgstr ""
+
+#: bp-groups/bp-groups-screens.php:808
+msgid "There was an error accepting the membership request, please try again."
+msgstr ""
+
+#: bp-groups/bp-groups-screens.php:810
+msgid "Group membership request accepted"
+msgstr ""
+
+#: bp-groups/bp-groups-screens.php:819
+msgid "There was an error rejecting the membership request, please try again."
+msgstr ""
+
+#: bp-groups/bp-groups-screens.php:821
+msgid "Group membership request rejected"
+msgstr ""
+
+#: bp-groups/bp-groups-screens.php:853
+msgid "There was an error deleting the group, please try again."
+msgstr ""
+
+#: bp-groups/bp-groups-screens.php:855
+msgid "The group was deleted successfully"
+msgstr ""
+
+#: bp-groups/bp-groups-screens.php:903
+msgid "A member invites you to join a group"
+msgstr ""
+
+#: bp-groups/bp-groups-screens.php:909
+msgid "Group information is updated"
+msgstr ""
+
+#: bp-groups/bp-groups-screens.php:915
+msgid "You are promoted to a group administrator or moderator"
+msgstr ""
+
+#: bp-groups/bp-groups-screens.php:921
+msgid "A member requests to join a private group for which you are an admin"
+msgstr ""
+
+#: bp-groups/bp-groups-template.php:218
+msgctxt "Group pagination previous text"
+msgid "&larr;"
+msgstr ""
+
+#: bp-groups/bp-groups-template.php:219
+msgctxt "Group pagination next text"
+msgid "&rarr;"
+msgstr ""
+
+#: bp-groups/bp-groups-template.php:480
+msgid "Public Group"
+msgstr ""
+
+#: bp-groups/bp-groups-template.php:482
+msgid "Hidden Group"
+msgstr ""
+
+#: bp-groups/bp-groups-template.php:484
+msgid "Private Group"
+msgstr ""
+
+#: bp-groups/bp-groups-template.php:486
+msgid "Group"
+msgstr ""
+
+#: bp-groups/bp-groups-template.php:558
+msgid "not yet active"
+msgstr ""
+
+#: bp-groups/bp-groups-template.php:740
+msgid "Group creator avatar of %s"
+msgstr ""
+
+#: bp-groups/bp-groups-template.php:775
+msgid "No Admins"
+msgstr ""
+
+#: bp-groups/bp-groups-template.php:802
+msgid "No Mods"
+msgstr ""
+
+#: bp-groups/bp-groups-template.php:884
+msgid "Filter Groups"
+msgstr ""
+
+#: bp-groups/bp-groups-template.php:932
+msgid "Viewing group %1$s to %2$s (of %3$s group)"
+msgid_plural "Viewing group %1$s to %2$s (of %3$s groups)"
+msgstr[0] ""
+msgstr[1] ""
+
+#: bp-groups/bp-groups-template.php:962
+msgid "%s members"
+msgstr ""
+
+#: bp-groups/bp-groups-template.php:1001
+msgid "%d topic"
+msgstr ""
+
+#: bp-groups/bp-groups-template.php:1003
+msgid "%d topics"
+msgstr ""
+
+#: bp-groups/bp-groups-template.php:1229 bp-groups/bp-groups-template.php:1294
+#: bp-templates/bp-legacy/buddypress/groups/single/admin.php:190
+#: bp-templates/bp-legacy/buddypress/groups/single/admin.php:217
+#: bp-themes/bp-default/groups/single/admin.php:190
+#: bp-themes/bp-default/groups/single/admin.php:217
+msgid "Demote to Member"
+msgstr ""
+
+#: bp-groups/bp-groups-template.php:1242 bp-groups/bp-groups-template.php:1307
+#: bp-groups/bp-groups-template.php:2124
+msgid "joined %s"
+msgstr ""
+
+#: bp-groups/bp-groups-template.php:1265
+msgid "This group has no administrators"
+msgstr ""
+
+#: bp-groups/bp-groups-template.php:1293
+#: bp-templates/bp-legacy/buddypress/groups/single/admin.php:216
+#: bp-templates/bp-legacy/buddypress/groups/single/admin.php:272
+#: bp-themes/bp-default/groups/single/admin.php:216
+#: bp-themes/bp-default/groups/single/admin.php:272
+msgid "Promote to Admin"
+msgstr ""
+
+#: bp-groups/bp-groups-template.php:1327
+msgid "This group has no moderators"
+msgstr ""
+
+#: bp-groups/bp-groups-template.php:1752 bp-groups/bp-groups-template.php:1753
+#: bp-templates/bp-legacy/buddypress-functions.php:1085
+#: bp-templates/bp-legacy/buddypress-functions.php:1098
+#: bp-themes/bp-default/_inc/ajax.php:744
+#: bp-themes/bp-default/_inc/ajax.php:757
+msgid "Leave Group"
+msgstr ""
+
+#: bp-groups/bp-groups-template.php:1775 bp-groups/bp-groups-template.php:1776
+#: bp-templates/bp-legacy/buddypress-functions.php:1119
+#: bp-themes/bp-default/_inc/ajax.php:778
+msgid "Join Group"
+msgstr ""
+
+#: bp-groups/bp-groups-template.php:1794 bp-groups/bp-groups-template.php:1795
+msgid "Accept Invitation"
+msgstr ""
+
+#: bp-groups/bp-groups-template.php:1810 bp-groups/bp-groups-template.php:1811
+msgid "Request Sent"
+msgstr ""
+
+#: bp-groups/bp-groups-template.php:1857
+msgid "This is a private group and you must request group membership in order to join."
+msgstr ""
+
+#: bp-groups/bp-groups-template.php:1859
+msgid "This is a private group. To join you must be a registered site member and request group membership."
+msgstr ""
+
+#: bp-groups/bp-groups-template.php:1862
+msgid "This is a private group. Your membership request is awaiting approval from the group administrator."
+msgstr ""
+
+#: bp-groups/bp-groups-template.php:1866
+msgid "This is a hidden group and only invited members can join."
+msgstr ""
+
+#: bp-groups/bp-groups-template.php:2172 bp-members/bp-members-template.php:353
+msgid "Viewing member %1$s to %2$s (of %3$s member)"
+msgid_plural "Viewing members %1$s to %2$s (of %3$s members)"
+msgstr[0] ""
+msgstr[1] ""
+
+#: bp-groups/bp-groups-template.php:2404
+msgid "Group avatar"
+msgstr ""
+
+#: bp-groups/bp-groups-template.php:2547 bp-groups/bp-groups-template.php:2571
+msgid "Recently Joined"
+msgstr ""
+
+#: bp-groups/bp-groups-template.php:2548 bp-groups/bp-groups-template.php:2574
+msgid "Most Popular"
+msgstr ""
+
+#: bp-groups/bp-groups-template.php:2549 bp-groups/bp-groups-template.php:2577
+msgid "Administrator Of"
+msgstr ""
+
+#: bp-groups/bp-groups-template.php:2550 bp-groups/bp-groups-template.php:2580
+msgid "Moderator Of"
+msgstr ""
+
+#: bp-groups/bp-groups-template.php:2638
+msgid "No Group Avatar"
+msgstr ""
+
+#: bp-groups/bp-groups-template.php:2839
+msgid "requested %s"
+msgstr ""
+
+#: bp-groups/bp-groups-template.php:3014
+msgid "Group Activity RSS Feed"
+msgstr ""
+
+#: bp-groups/bp-groups-widgets.php:24
+msgid "A dynamic list of recently active, popular, and newest groups"
+msgstr ""
+
+#: bp-groups/bp-groups-widgets.php:27
+msgctxt "widget name"
+msgid "(BuddyPress) Groups"
+msgstr ""
+
+#: bp-groups/bp-groups-widgets.php:83 bp-groups/bp-groups-widgets.php:186
+msgid "created %s"
+msgstr ""
+
+#: bp-groups/bp-groups-widgets.php:102
+msgid "There are no groups to display."
+msgstr ""
+
+#: bp-groups/bp-groups-widgets.php:139
+msgid "Link widget title to Groups directory"
+msgstr ""
+
+#: bp-groups/bp-groups-widgets.php:141
+msgid "Max groups to show:"
+msgstr ""
+
+#: bp-groups/bp-groups-widgets.php:144
+msgid "Default groups to show:"
+msgstr ""
+
+#: bp-groups/bp-groups-widgets.php:204
+msgid "No groups matched the current filter."
+msgstr ""
+
+#: bp-loader.php:165 bp-loader.php:172
+msgid "Cheatin&#8217; huh?"
+msgstr ""
+
+#: bp-loader.php:562
+msgid "BuddyPress Default"
+msgstr ""
+
+#: bp-members/bp-members-actions.php:51
+msgid "User marked as spammer. Spam users are visible only to site admins."
+msgstr ""
+
+#: bp-members/bp-members-actions.php:53
+msgid "User removed as spammer."
+msgstr ""
+
+#: bp-members/bp-members-actions.php:86
+msgid "%s has been deleted from the system."
+msgstr ""
+
+#: bp-members/bp-members-actions.php:88
+msgid "There was an error deleting %s from the system. Please try again."
+msgstr ""
+
+#: bp-members/bp-members-adminbar.php:38
+msgid "Edit My Profile"
+msgstr ""
+
+#: bp-members/bp-members-adminbar.php:52
+msgid "Log in"
+msgstr ""
+
+#: bp-members/bp-members-adminbar.php:91
+msgid "Edit Member"
+msgstr ""
+
+#: bp-members/bp-members-adminbar.php:100
+#: bp-xprofile/bp-xprofile-template.php:921
+#: bp-xprofile/bp-xprofile-template.php:922
+msgid "Edit Profile"
+msgstr ""
+
+#: bp-members/bp-members-adminbar.php:118
+#: bp-members/bp-members-buddybar.php:105
+msgid "User Capabilities"
+msgstr ""
+
+#: bp-members/bp-members-adminbar.php:126
+#: bp-settings/bp-settings-loader.php:131
+#: bp-settings/bp-settings-loader.php:188
+#: bp-templates/bp-legacy/buddypress/members/single/settings/delete-account.php:27
+#: bp-themes/bp-default/members/single/settings/delete-account.php:50
+#: bp-themes/bp-default/members/single/settings/delete-account.php:76
+msgid "Delete Account"
+msgstr ""
+
+#: bp-members/bp-members-buddybar.php:49
+msgid "Blog Authors"
+msgstr ""
+
+#: bp-members/bp-members-buddybar.php:99
+msgid "Edit %s's Profile"
+msgstr ""
+
+#: bp-members/bp-members-buddybar.php:103
+msgid "Edit %s's Avatar"
+msgstr ""
+
+#: bp-members/bp-members-buddybar.php:107
+msgid "Delete %s's Account"
+msgstr ""
+
+#: bp-members/bp-members-functions.php:977
+#: bp-members/bp-members-functions.php:1599
+msgid "<strong>ERROR</strong>: Your account has been marked as a spammer."
+msgstr ""
+
+#: bp-members/bp-members-functions.php:1158
+msgid "Please check your email address."
+msgstr ""
+
+#: bp-members/bp-members-functions.php:1161
+#: bp-members/bp-members-functions.php:1164
+msgid "Sorry, that email address is not allowed!"
+msgstr ""
+
+#: bp-members/bp-members-functions.php:1167
+msgid "Sorry, that email address is already used!"
+msgstr ""
+
+#: bp-members/bp-members-functions.php:1198
+msgid "Please enter a username"
+msgstr ""
+
+#: bp-members/bp-members-functions.php:1204
+msgid "That username is not allowed"
+msgstr ""
+
+#: bp-members/bp-members-functions.php:1209
+msgid "Usernames can contain only letters, numbers, ., -, and @"
+msgstr ""
+
+#: bp-members/bp-members-functions.php:1214
+msgid "Username must be at least 4 characters"
+msgstr ""
+
+#: bp-members/bp-members-functions.php:1219
+msgid "Sorry, usernames may not contain the character \"_\"!"
+msgstr ""
+
+#: bp-members/bp-members-functions.php:1226
+msgid "Sorry, usernames must have letters too!"
+msgstr ""
+
+#: bp-members/bp-members-functions.php:1231
+msgid "Sorry, that username already exists!"
+msgstr ""
+
+#: bp-members/bp-members-functions.php:1282
+msgid "<strong>ERROR</strong>: Couldn&#8217;t register you... please contact the <a href=\"mailto:%s\">webmaster</a> !"
+msgstr ""
+
+#: bp-members/bp-members-functions.php:1380
+#: bp-members/bp-members-functions.php:1384
+msgid "Invalid activation key"
+msgstr ""
+
+#: bp-members/bp-members-functions.php:1421
+msgid "%s became a registered member"
+msgstr ""
+
+#: bp-members/bp-members-functions.php:1505
+msgid "<strong>ERROR</strong>: Your account has not been activated. Check your email for the activation link."
+msgstr ""
+
+#: bp-members/bp-members-loader.php:70
+msgid "Search Members..."
+msgstr ""
+
+#: bp-members/bp-members-loader.php:203
+msgid "You"
+msgstr ""
+
+#: bp-members/bp-members-screens.php:94
+msgid "Please make sure you enter your password twice"
+msgstr ""
+
+#: bp-members/bp-members-screens.php:98
+msgid "The passwords you entered do not match."
+msgstr ""
+
+#: bp-members/bp-members-screens.php:121
+msgid "This is a required field"
+msgstr ""
+
+#: bp-members/bp-members-screens.php:267
+msgid "Your account is now active!"
+msgstr ""
+
+#: bp-members/bp-members-screens.php:528
+#: bp-themes/bp-default/registration/register.php:259
+msgid "Check Your Email To Activate Your Account!"
+msgstr ""
+
+#: bp-members/bp-members-screens.php:536
+#: bp-themes/bp-default/registration/activate.php:11
+msgid "Account Activated"
+msgstr ""
+
+#: bp-members/bp-members-template.php:206
+msgctxt "Member pagination previous text"
+msgid "&larr;"
+msgstr ""
+
+#: bp-members/bp-members-template.php:207
+msgctxt "Member pagination next text"
+msgid "&rarr;"
+msgstr ""
+
+#: bp-members/bp-members-template.php:347
+msgid "Viewing member %1$s to %2$s (of %3$s active member)"
+msgid_plural "Viewing member %1$s to %2$s (of %3$s active members)"
+msgstr[0] ""
+msgstr[1] ""
+
+#: bp-members/bp-members-template.php:349
+msgid "Viewing member %1$s to %2$s (of %3$s member with friends)"
+msgid_plural "Viewing member %1$s to %2$s (of %3$s members with friends)"
+msgstr[0] ""
+msgstr[1] ""
+
+#: bp-members/bp-members-template.php:351
+msgid "Viewing member %1$s to %2$s (of %3$s member online)"
+msgid_plural "Viewing member %1$s to %2$s (of %3$s members online)"
+msgstr[0] ""
+msgstr[1] ""
+
+#: bp-members/bp-members-template.php:598
+msgid "Never active"
+msgstr ""
+
+#: bp-members/bp-members-template.php:620
+msgctxt "member latest update in member directory"
+msgid "- &quot;%s &quot;"
+msgstr ""
+
+#: bp-members/bp-members-template.php:677
+msgctxt "Records the timestamp that the user registered into the activy stream"
+msgid "registered %s"
+msgstr ""
+
+#: bp-members/bp-members-template.php:1146
+msgid "Your Avatar"
+msgstr ""
+
+#: bp-members/bp-members-template.php:1216
+msgid "Activity RSS Feed"
+msgstr ""
+
+#: bp-messages/bp-messages-actions.php:35
+msgid "Your reply was sent successfully"
+msgstr ""
+
+#: bp-messages/bp-messages-actions.php:37
+msgid "There was a problem sending your reply, please try again"
+msgstr ""
+
+#: bp-messages/bp-messages-actions.php:65
+msgid "There was an error deleting that message."
+msgstr ""
+
+#: bp-messages/bp-messages-actions.php:67
+msgid "Message deleted."
+msgstr ""
+
+#: bp-messages/bp-messages-actions.php:89
+msgid "There was an error deleting messages."
+msgstr ""
+
+#: bp-messages/bp-messages-actions.php:91
+#: bp-templates/bp-legacy/buddypress-functions.php:1280
+#: bp-themes/bp-default/_inc/ajax.php:927
+msgid "Messages deleted."
+msgstr ""
+
+#: bp-messages/bp-messages-classes.php:262
+msgid "%s Recipients"
+msgstr ""
+
+#: bp-messages/bp-messages-functions.php:53
+msgid "Re: %s"
+msgstr ""
+
+#: bp-messages/bp-messages-functions.php:61
+msgid "No Subject"
+msgstr ""
+
+#: bp-messages/bp-messages-loader.php:33
+msgid "Private Messages"
+msgstr ""
+
+#: bp-messages/bp-messages-loader.php:91
+msgid "Search Messages..."
+msgstr ""
+
+#: bp-messages/bp-messages-loader.php:105
+#: bp-messages/bp-messages-screens.php:104
+msgid "Messages <span>%s</span>"
+msgstr ""
+
+#: bp-messages/bp-messages-loader.php:132
+#: bp-messages/bp-messages-loader.php:196
+#: bp-messages/bp-messages-notifications.php:117
+msgid "Inbox"
+msgstr ""
+
+#: bp-messages/bp-messages-loader.php:142
+#: bp-messages/bp-messages-loader.php:219
+msgid "Sent"
+msgstr ""
+
+#: bp-messages/bp-messages-loader.php:152
+#: bp-messages/bp-messages-loader.php:227
+msgid "Compose"
+msgstr ""
+
+#: bp-messages/bp-messages-loader.php:163
+msgid "Notices"
+msgstr ""
+
+#: bp-messages/bp-messages-loader.php:192
+msgid "Messages <span class=\"count\">%s</span>"
+msgstr ""
+
+#: bp-messages/bp-messages-loader.php:193
+msgid "Inbox <span class=\"count\">%s</span>"
+msgstr ""
+
+#: bp-messages/bp-messages-loader.php:195
+#: bp-messages/bp-messages-screens.php:168
+msgid "Messages"
+msgstr ""
+
+#: bp-messages/bp-messages-loader.php:236
+msgid "All Member Notices"
+msgstr ""
+
+#: bp-messages/bp-messages-loader.php:253
+msgid "My Messages"
+msgstr ""
+
+#: bp-messages/bp-messages-notifications.php:69
+msgid "New message from %s"
+msgstr ""
+
+#: bp-messages/bp-messages-notifications.php:71
+msgid ""
+"%1$s sent you a new message:\n"
+"\n"
+"Subject: %2$s\n"
+"\n"
+"\"%3$s\"\n"
+"\n"
+"To view and read your messages please log in and visit: %4$s\n"
+"\n"
+"---------------------\n"
+msgstr ""
+
+#: bp-messages/bp-messages-notifications.php:120
+msgid "You have %d new messages"
+msgstr ""
+
+#: bp-messages/bp-messages-notifications.php:124
+msgid "You have %d new message from %s"
+msgstr ""
+
+#: bp-messages/bp-messages-notifications.php:126
+msgid "You have %d new message"
+msgstr ""
+
+#: bp-messages/bp-messages-screens.php:56
+#: bp-messages/bp-messages-screens.php:78
+msgid "There was an error sending that message, please try again"
+msgstr ""
+
+#: bp-messages/bp-messages-screens.php:61
+msgid "Notice sent successfully!"
+msgstr ""
+
+#: bp-messages/bp-messages-screens.php:64
+msgid "There was an error sending that notice, please try again"
+msgstr ""
+
+#: bp-messages/bp-messages-screens.php:75
+msgid "Message sent successfully!"
+msgstr ""
+
+#: bp-messages/bp-messages-screens.php:125
+msgid "There was a problem deactivating that notice."
+msgstr ""
+
+#: bp-messages/bp-messages-screens.php:127
+msgid "Notice deactivated."
+msgstr ""
+
+#: bp-messages/bp-messages-screens.php:131
+msgid "There was a problem activating that notice."
+msgstr ""
+
+#: bp-messages/bp-messages-screens.php:133
+msgid "Notice activated."
+msgstr ""
+
+#: bp-messages/bp-messages-screens.php:137
+msgid "There was a problem deleting that notice."
+msgstr ""
+
+#: bp-messages/bp-messages-screens.php:139
+msgid "Notice deleted."
+msgstr ""
+
+#: bp-messages/bp-messages-screens.php:177
+msgid "A member sends you a new message"
+msgstr ""
+
+#: bp-messages/bp-messages-template.php:84
+msgctxt "Message pagination previous text"
+msgid "&larr;"
+msgstr ""
+
+#: bp-messages/bp-messages-template.php:85
+msgctxt "Message pagination next text"
+msgid "&rarr;"
+msgstr ""
+
+#: bp-messages/bp-messages-template.php:395
+msgid "Viewing message %1$s to %2$s (of %3$s message)"
+msgid_plural "Viewing message %1$s to %2$s (of %3$s messages)"
+msgstr[0] ""
+msgstr[1] ""
+
+#: bp-messages/bp-messages-template.php:471
+msgid "Select:"
+msgstr ""
+
+#: bp-messages/bp-messages-template.php:475
+#: bp-notifications/bp-notifications-loader.php:142
+#: bp-notifications/bp-notifications-loader.php:203
+#: bp-notifications/bp-notifications-template.php:733
+msgid "Read"
+msgstr ""
+
+#: bp-messages/bp-messages-template.php:476
+#: bp-notifications/bp-notifications-loader.php:131
+#: bp-notifications/bp-notifications-loader.php:180
+#: bp-notifications/bp-notifications-template.php:763
+msgid "Unread"
+msgstr ""
+
+#: bp-messages/bp-messages-template.php:482
+msgid "Mark as Read"
+msgstr ""
+
+#: bp-messages/bp-messages-template.php:483
+msgid "Mark as Unread"
+msgstr ""
+
+#: bp-messages/bp-messages-template.php:487
+msgid "Delete Selected"
+msgstr ""
+
+#: bp-messages/bp-messages-template.php:532
+msgid "Currently Active"
+msgstr ""
+
+#: bp-messages/bp-messages-template.php:599
+msgid "Deactivate"
+msgstr ""
+
+#: bp-messages/bp-messages-template.php:648
+#: bp-templates/bp-legacy/buddypress/members/register.php:168
+#: bp-templates/bp-legacy/buddypress/members/single/profile/edit.php:130
+#: bp-templates/bp-legacy/buddypress-functions.php:233
+#: bp-themes/bp-default/functions.php:165
+#: bp-themes/bp-default/members/single/profile/edit.php:130
+#: bp-themes/bp-default/registration/register.php:173
+msgid "Close"
+msgstr ""
+
+#: bp-messages/bp-messages-template.php:693
+msgid "Send a private message to this user."
+msgstr ""
+
+#: bp-messages/bp-messages-template.php:694
+msgid "Private Message"
+msgstr ""
+
+#: bp-messages/bp-messages-template.php:877
+msgid "%d Recipients"
+msgstr ""
+
+#: bp-messages/bp-messages-template.php:986
+#: bp-templates/bp-legacy/buddypress-functions.php:1186
+#: bp-themes/bp-default/_inc/ajax.php:833
+msgid "Sent %s"
+msgstr ""
+
+#: bp-messages/bp-messages-widgets.php:34
+msgid "(BuddyPress) Sitewide Notices"
+msgstr ""
+
+#: bp-messages/bp-messages-widgets.php:37
+msgid "Display Sitewide Notices posted by the site administrator"
+msgstr ""
+
+#: bp-notifications/bp-notifications-actions.php:43
+msgid "Notification successfully marked read."
+msgstr ""
+
+#: bp-notifications/bp-notifications-actions.php:45
+#: bp-notifications/bp-notifications-actions.php:81
+msgid "There was a problem marking that notification."
+msgstr ""
+
+#: bp-notifications/bp-notifications-actions.php:79
+msgid "Notification successfully marked unread."
+msgstr ""
+
+#: bp-notifications/bp-notifications-actions.php:115
+msgid "Notification successfully deleted."
+msgstr ""
+
+#: bp-notifications/bp-notifications-actions.php:117
+msgid "There was a problem deleting that notification."
+msgstr ""
+
+#: bp-notifications/bp-notifications-adminbar.php:54
+msgid "No new notifications"
+msgstr ""
+
+#: bp-notifications/bp-notifications-buddybar.php:49
+msgid "No new notifications."
+msgstr ""
+
+#: bp-notifications/bp-notifications-loader.php:85
+msgid "Search Notifications..."
+msgstr ""
+
+#: bp-notifications/bp-notifications-loader.php:109
+msgid "Notifications <span>%d</span>"
+msgstr ""
+
+#: bp-notifications/bp-notifications-loader.php:176
+msgid "Notifications <span class=\"count\">%s</span>"
+msgstr ""
+
+#: bp-notifications/bp-notifications-loader.php:177
+msgid "Unread <span class=\"count\">%s</span>"
+msgstr ""
+
+#: bp-notifications/bp-notifications-template.php:327
+msgctxt "Notifications pagination previous text"
+msgid "&larr;"
+msgstr ""
+
+#: bp-notifications/bp-notifications-template.php:328
+msgctxt "Notifications pagination next text"
+msgid "&rarr;"
+msgstr ""
+
+#: bp-notifications/bp-notifications-template.php:664
+msgid "Date not found"
+msgstr ""
+
+#: bp-notifications/bp-notifications-template.php:895
+msgid "Viewing %1$s to %2$s (of %3$s notification)"
+msgid_plural "Viewing %1$s to %2$s (of %3$s notifications)"
+msgstr[0] ""
+msgstr[1] ""
+
+#: bp-notifications/bp-notifications-template.php:940
+#: bp-templates/bp-legacy/buddypress/blogs/index.php:36
+#: bp-templates/bp-legacy/buddypress/forums/index.php:42
+#: bp-templates/bp-legacy/buddypress/groups/index.php:36
+#: bp-templates/bp-legacy/buddypress/groups/single/forum.php:36
+#: bp-templates/bp-legacy/buddypress/members/index.php:35
+#: bp-templates/bp-legacy/buddypress/members/single/blogs.php:19
+#: bp-templates/bp-legacy/buddypress/members/single/forums.php:18
+#: bp-templates/bp-legacy/buddypress/members/single/friends.php:20
+#: bp-templates/bp-legacy/buddypress/members/single/groups.php:20
+#: bp-themes/bp-default/blogs/index.php:53
+#: bp-themes/bp-default/forums/index.php:60
+#: bp-themes/bp-default/groups/index.php:55
+#: bp-themes/bp-default/groups/single/forum.php:36
+#: bp-themes/bp-default/members/index.php:55
+#: bp-themes/bp-default/members/single/blogs.php:19
+#: bp-themes/bp-default/members/single/forums.php:18
+#: bp-themes/bp-default/members/single/friends.php:20
+#: bp-themes/bp-default/members/single/groups.php:20
+msgid "Order By:"
+msgstr ""
+
+#: bp-notifications/bp-notifications-template.php:943
+msgid "Newest First"
+msgstr ""
+
+#: bp-notifications/bp-notifications-template.php:944
+msgid "Oldest First"
+msgstr ""
+
+#: bp-notifications/bp-notifications-template.php:948
+msgid "Go"
+msgstr ""
+
+#: bp-settings/bp-settings-actions.php:159
+msgid "That email address is invalid. Check the formatting and try again."
+msgstr ""
+
+#: bp-settings/bp-settings-actions.php:162
+msgid "That email address is currently unavailable for use."
+msgstr ""
+
+#: bp-settings/bp-settings-actions.php:165
+msgid "That email address is already taken."
+msgstr ""
+
+#: bp-settings/bp-settings-actions.php:168
+msgid "Email address cannot be empty."
+msgstr ""
+
+#: bp-settings/bp-settings-actions.php:178
+msgid "Your current password is invalid."
+msgstr ""
+
+#: bp-settings/bp-settings-actions.php:181
+msgid "The new password fields did not match."
+msgstr ""
+
+#: bp-settings/bp-settings-actions.php:184
+msgid "One of the password fields was empty."
+msgstr ""
+
+#: bp-settings/bp-settings-actions.php:193
+msgid "Your settings have been saved."
+msgstr ""
+
+#: bp-settings/bp-settings-actions.php:199
+msgid "No changes were made to your account."
+msgstr ""
+
+#: bp-settings/bp-settings-actions.php:201
+msgid "No changes were made to this account."
+msgstr ""
+
+#: bp-settings/bp-settings-actions.php:249
+msgid "Your notification settings have been saved."
+msgstr ""
+
+#: bp-settings/bp-settings-actions.php:251
+msgid "This user's notification settings have been saved."
+msgstr ""
+
+#: bp-settings/bp-settings-actions.php:346
+msgid "%s was successfully deleted."
+msgstr ""
+
+#: bp-settings/bp-settings-loader.php:94 bp-settings/bp-settings-loader.php:171
+msgid "General"
+msgstr ""
+
+#: bp-settings/bp-settings-loader.php:106
+#: bp-settings/bp-settings-loader.php:179
+#: bp-themes/bp-default/functions.php:645
+msgid "Email"
+msgstr ""
+
+#: bp-settings/bp-settings-loader.php:118
+#: bp-themes/bp-default/members/single/settings/capabilities.php:49
+msgid "Capabilities"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/activity/activity-loop.php:28
+#: bp-themes/bp-default/activity/activity-loop.php:41
+msgid "Load More"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/activity/activity-loop.php:42
+#: bp-themes/bp-default/activity/activity-loop.php:55
+msgid "Sorry, there was no activity found. Please try a different filter."
+msgstr ""
+
+#. translators: 1: user profile link, 2: user name, 3: activity permalink, 4:
+#. activity timestamp
+
+#: bp-templates/bp-legacy/buddypress/activity/comment.php:27
+#: bp-themes/bp-default/activity/comment.php:30
+msgid "<a href=\"%1$s\">%2$s</a> replied <a href=\"%3$s\" class=\"activity-time-since\"><span class=\"time-since\">%4$s</span></a>"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/activity/entry.php:50
+msgid "View Conversation"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/activity/entry.php:58
+#: bp-themes/bp-default/activity/entry.php:60
+msgid "Comment <span>%s</span>"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/activity/entry.php:66
+#: bp-themes/bp-default/activity/entry.php:68
+msgid "Mark as Favorite"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/activity/entry.php:66
+#: bp-templates/bp-legacy/buddypress-functions.php:236
+#: bp-templates/bp-legacy/buddypress-functions.php:834
+#: bp-templates/bp-legacy/buddypress-functions.php:851
+#: bp-themes/bp-default/_inc/ajax.php:494
+#: bp-themes/bp-default/_inc/ajax.php:511
+#: bp-themes/bp-default/activity/entry.php:68
+#: bp-themes/bp-default/functions.php:167
+msgid "Favorite"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/activity/entry.php:70
+#: bp-templates/bp-legacy/buddypress-functions.php:239
+#: bp-templates/bp-legacy/buddypress-functions.php:832
+#: bp-templates/bp-legacy/buddypress-functions.php:853
+#: bp-themes/bp-default/_inc/ajax.php:492
+#: bp-themes/bp-default/_inc/ajax.php:513
+#: bp-themes/bp-default/activity/entry.php:72
+#: bp-themes/bp-default/functions.php:168
+msgid "Remove Favorite"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/activity/entry.php:102
+#: bp-themes/bp-default/activity/entry.php:104
+msgid "Post"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/activity/index.php:19
+#: bp-themes/bp-default/activity/index.php:39
+msgid "The public activity for everyone on this site."
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/activity/index.php:19
+#: bp-templates/bp-legacy/buddypress/members/index.php:19
+#: bp-themes/bp-default/activity/index.php:39
+#: bp-themes/bp-default/members/index.php:35
+msgid "All Members <span>%s</span>"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/activity/index.php:29
+#: bp-themes/bp-default/activity/index.php:49
+msgid "The activity of my friends only."
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/activity/index.php:29
+#: bp-templates/bp-legacy/buddypress/members/index.php:22
+#: bp-themes/bp-default/activity/index.php:49
+#: bp-themes/bp-default/members/index.php:39
+msgid "My Friends <span>%s</span>"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/activity/index.php:41
+#: bp-themes/bp-default/activity/index.php:61
+msgid "The activity of groups I am a member of."
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/activity/index.php:41
+#: bp-templates/bp-legacy/buddypress/groups/index.php:22
+#: bp-themes/bp-default/activity/index.php:61
+#: bp-themes/bp-default/groups/index.php:39
+msgid "My Groups <span>%s</span>"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/activity/index.php:51
+#: bp-themes/bp-default/activity/index.php:71
+msgid "The activity I've marked as a favorite."
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/activity/index.php:51
+#: bp-themes/bp-default/activity/index.php:71
+msgid "My Favorites <span>%s</span>"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/activity/index.php:59
+#: bp-themes/bp-default/activity/index.php:79
+msgid "Activity that I have been mentioned in."
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/activity/index.php:59
+#: bp-themes/bp-default/activity/index.php:79
+msgctxt "Number of new activity mentions"
+msgid "%s new"
+msgid_plural "%s new"
+msgstr[0] ""
+msgstr[1] ""
+
+#: bp-templates/bp-legacy/buddypress/activity/index.php:71
+#: bp-templates/bp-legacy/buddypress/groups/single/activity.php:3
+#: bp-themes/bp-default/activity/index.php:91
+#: bp-themes/bp-default/groups/single/activity.php:3
+msgid "RSS Feed"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/activity/index.php:71
+#: bp-templates/bp-legacy/buddypress/groups/single/activity.php:3
+#: bp-themes/bp-default/activity/index.php:91
+#: bp-themes/bp-default/groups/single/activity.php:3
+msgid "RSS"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/activity/index.php:76
+#: bp-templates/bp-legacy/buddypress/groups/single/activity.php:8
+#: bp-templates/bp-legacy/buddypress/members/single/activity.php:18
+#: bp-themes/bp-default/activity/index.php:96
+#: bp-themes/bp-default/groups/single/activity.php:8
+#: bp-themes/bp-default/members/single/activity.php:18
+msgid "Show:"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/activity/index.php:78
+#: bp-templates/bp-legacy/buddypress/groups/single/activity.php:10
+#: bp-templates/bp-legacy/buddypress/members/single/activity.php:20
+#: bp-themes/bp-default/activity/index.php:98
+#: bp-themes/bp-default/groups/single/activity.php:10
+#: bp-themes/bp-default/members/single/activity.php:20
+msgid "Everything"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/activity/index.php:79
+#: bp-templates/bp-legacy/buddypress/groups/single/activity.php:11
+#: bp-templates/bp-legacy/buddypress/members/single/activity.php:21
+#: bp-themes/bp-default/activity/index.php:99
+#: bp-themes/bp-default/groups/single/activity.php:11
+#: bp-themes/bp-default/members/single/activity.php:21
+msgid "Updates"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/activity/index.php:84
+#: bp-templates/bp-legacy/buddypress/members/single/activity.php:28
+#: bp-themes/bp-default/activity/index.php:104
+#: bp-themes/bp-default/members/single/activity.php:28
+msgid "Comments"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/activity/index.php:90
+#: bp-templates/bp-legacy/buddypress/groups/single/activity.php:14
+#: bp-templates/bp-legacy/buddypress/members/single/activity.php:43
+#: bp-themes/bp-default/activity/index.php:110
+#: bp-themes/bp-default/groups/single/activity.php:14
+#: bp-themes/bp-default/members/single/activity.php:43
+msgid "Forum Topics"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/activity/index.php:91
+#: bp-templates/bp-legacy/buddypress/groups/single/activity.php:15
+#: bp-templates/bp-legacy/buddypress/members/single/activity.php:44
+#: bp-themes/bp-default/activity/index.php:111
+#: bp-themes/bp-default/groups/single/activity.php:15
+#: bp-themes/bp-default/members/single/activity.php:44
+msgid "Forum Replies"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/activity/index.php:97
+#: bp-templates/bp-legacy/buddypress/members/single/activity.php:50
+#: bp-themes/bp-default/activity/index.php:117
+#: bp-themes/bp-default/members/single/activity.php:50
+msgid "New Groups"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/activity/index.php:98
+#: bp-templates/bp-legacy/buddypress/groups/single/activity.php:18
+#: bp-templates/bp-legacy/buddypress/members/single/activity.php:51
+#: bp-themes/bp-default/activity/index.php:118
+#: bp-themes/bp-default/groups/single/activity.php:18
+#: bp-themes/bp-default/members/single/activity.php:51
+msgid "Group Memberships"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/activity/index.php:108
+#: bp-themes/bp-default/activity/index.php:128
+msgid "New Members"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/activity/post-form.php:23
+#: bp-themes/bp-default/activity/post-form.php:23
+msgid "What's new in %s, %s?"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/activity/post-form.php:25
+#: bp-themes/bp-default/activity/post-form.php:25
+msgid "What's new, %s?"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/activity/post-form.php:35
+#: bp-themes/bp-default/activity/post-form.php:35
+msgid "Post Update"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/activity/post-form.php:42
+#: bp-themes/bp-default/activity/post-form.php:42
+msgid "Post in"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/blogs/blogs-loop.php:90
+#: bp-themes/bp-default/blogs/blogs-loop.php:90
+msgid "Sorry, there were no sites found."
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/blogs/create.php:14
+#: bp-themes/bp-default/blogs/create.php:32
+msgid "Site registration is currently disabled"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/blogs/index.php:16
+#: bp-themes/bp-default/blogs/index.php:33
+msgid "All Sites <span>%s</span>"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/blogs/index.php:20
+#: bp-themes/bp-default/blogs/index.php:37
+msgid "My Sites <span>%s</span>"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/blogs/index.php:38
+#: bp-templates/bp-legacy/buddypress/forums/index.php:44
+#: bp-templates/bp-legacy/buddypress/groups/index.php:39
+#: bp-templates/bp-legacy/buddypress/groups/single/forum.php:38
+#: bp-templates/bp-legacy/buddypress/members/index.php:37
+#: bp-templates/bp-legacy/buddypress/members/single/blogs.php:21
+#: bp-templates/bp-legacy/buddypress/members/single/forums.php:20
+#: bp-templates/bp-legacy/buddypress/members/single/friends.php:22
+#: bp-templates/bp-legacy/buddypress/members/single/groups.php:22
+#: bp-themes/bp-default/blogs/index.php:55
+#: bp-themes/bp-default/forums/index.php:62
+#: bp-themes/bp-default/groups/index.php:57
+#: bp-themes/bp-default/groups/single/forum.php:38
+#: bp-themes/bp-default/members/index.php:57
+#: bp-themes/bp-default/members/single/blogs.php:21
+#: bp-themes/bp-default/members/single/forums.php:20
+#: bp-themes/bp-default/members/single/friends.php:22
+#: bp-themes/bp-default/members/single/groups.php:22
+msgid "Last Active"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/blogs/index.php:40
+#: bp-templates/bp-legacy/buddypress/groups/index.php:42
+#: bp-templates/bp-legacy/buddypress/members/index.php:41
+#: bp-templates/bp-legacy/buddypress/members/single/blogs.php:23
+#: bp-templates/bp-legacy/buddypress/members/single/friends.php:24
+#: bp-templates/bp-legacy/buddypress/members/single/groups.php:25
+#: bp-themes/bp-default/blogs/index.php:57
+#: bp-themes/bp-default/groups/index.php:60
+#: bp-themes/bp-default/members/index.php:62
+#: bp-themes/bp-default/members/single/blogs.php:23
+#: bp-themes/bp-default/members/single/friends.php:24
+#: bp-themes/bp-default/members/single/groups.php:25
+msgid "Alphabetical"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/forums/forums-loop.php:39
+#: bp-themes/bp-default/forums/forums-loop.php:39
+msgid "Topic"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/forums/forums-loop.php:41
+#: bp-themes/bp-default/forums/forums-loop.php:41
+msgid "Freshness"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/forums/forums-loop.php:54
+#: bp-templates/bp-legacy/buddypress/groups/single/forum/topic.php:95
+#: bp-themes/bp-default/forums/forums-loop.php:54
+#: bp-themes/bp-default/groups/single/forum/topic.php:95
+msgid "Permanent link to this post"
+msgstr ""
+
+#. translators: "started by [poster] in [forum]"
+
+#: bp-templates/bp-legacy/buddypress/forums/forums-loop.php:61
+#: bp-themes/bp-default/forums/forums-loop.php:61
+msgid "Started by %1$s"
+msgstr ""
+
+#. translators: "started by [poster] in [forum]"
+
+#: bp-templates/bp-legacy/buddypress/forums/forums-loop.php:72
+#: bp-themes/bp-default/forums/forums-loop.php:72
+msgid "in %1$s"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/forums/forums-loop.php:122
+#: bp-themes/bp-default/forums/forums-loop.php:122
+msgid "Sorry, there were no forum topics found."
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/forums/index.php:22
+#: bp-themes/bp-default/forums/index.php:40
+msgid "All Topics <span>%s</span>"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/forums/index.php:26
+#: bp-themes/bp-default/forums/index.php:44
+msgid "My Topics <span>%s</span>"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/forums/index.php:45
+#: bp-templates/bp-legacy/buddypress/groups/single/forum.php:39
+#: bp-templates/bp-legacy/buddypress/members/single/forums.php:21
+#: bp-themes/bp-default/forums/index.php:63
+#: bp-themes/bp-default/groups/single/forum.php:39
+#: bp-themes/bp-default/members/single/forums.php:21
+msgid "Most Posts"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/forums/index.php:46
+#: bp-templates/bp-legacy/buddypress/groups/single/forum.php:40
+#: bp-templates/bp-legacy/buddypress/members/single/forums.php:22
+#: bp-themes/bp-default/forums/index.php:64
+#: bp-themes/bp-default/groups/single/forum.php:40
+#: bp-themes/bp-default/members/single/forums.php:22
+msgid "Unreplied"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/forums/index.php:82
+#: bp-themes/bp-default/forums/index.php:100
+msgid "Create New Topic:"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/forums/index.php:89
+#: bp-templates/bp-legacy/buddypress/groups/single/forum/edit.php:50
+#: bp-templates/bp-legacy/buddypress/groups/single/forum.php:78
+#: bp-themes/bp-default/forums/index.php:107
+#: bp-themes/bp-default/groups/single/forum/edit.php:50
+#: bp-themes/bp-default/groups/single/forum.php:78
+msgid "Content:"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/forums/index.php:92
+#: bp-templates/bp-legacy/buddypress/groups/single/forum/edit.php:53
+#: bp-templates/bp-legacy/buddypress/groups/single/forum.php:81
+#: bp-themes/bp-default/forums/index.php:110
+#: bp-themes/bp-default/groups/single/forum/edit.php:53
+#: bp-themes/bp-default/groups/single/forum.php:81
+msgid "Tags (comma separated):"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/forums/index.php:95
+#: bp-themes/bp-default/forums/index.php:113
+msgid "Post In Group Forum:"
+msgstr ""
+
+#. translators: no option picked in select box
+
+#: bp-templates/bp-legacy/buddypress/forums/index.php:98
+#: bp-themes/bp-default/forums/index.php:116
+#: bp-xprofile/bp-xprofile-template.php:471
+msgid "----"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/forums/index.php:115
+#: bp-templates/bp-legacy/buddypress/groups/single/forum.php:87
+#: bp-themes/bp-default/forums/index.php:133
+#: bp-themes/bp-default/groups/single/forum.php:87
+msgid "Post Topic"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/forums/index.php:127
+#: bp-themes/bp-default/forums/index.php:145
+msgid "You are not a member of any groups so you don't have any group forums you can post in. To start posting, first find a group that matches the topic subject you'd like to start. If this group does not exist, why not <a href='%s'>create a new group</a>? Once you have joined or created the group you can post your topic in that group's forum."
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/groups/create.php:29
+#: bp-templates/bp-legacy/buddypress/groups/single/admin.php:16
+#: bp-themes/bp-default/groups/create.php:39
+#: bp-themes/bp-default/groups/single/admin.php:16
+msgid "Group Name (required)"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/groups/create.php:34
+#: bp-templates/bp-legacy/buddypress/groups/single/admin.php:19
+#: bp-themes/bp-default/groups/create.php:42
+#: bp-themes/bp-default/groups/single/admin.php:19
+msgid "Group Description (required)"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/groups/create.php:51
+#: bp-templates/bp-legacy/buddypress/groups/single/admin.php:56
+#: bp-themes/bp-default/groups/create.php:58
+#: bp-themes/bp-default/groups/single/admin.php:56
+msgid "Privacy Options"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/groups/create.php:55
+#: bp-templates/bp-legacy/buddypress/groups/single/admin.php:61
+#: bp-themes/bp-default/groups/create.php:62
+#: bp-themes/bp-default/groups/single/admin.php:61
+msgid "This is a public group"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/groups/create.php:57
+#: bp-templates/bp-legacy/buddypress/groups/single/admin.php:63
+#: bp-themes/bp-default/groups/create.php:64
+#: bp-themes/bp-default/groups/single/admin.php:63
+msgid "Any site member can join this group."
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/groups/create.php:58
+#: bp-templates/bp-legacy/buddypress/groups/create.php:67
+#: bp-templates/bp-legacy/buddypress/groups/single/admin.php:64
+#: bp-templates/bp-legacy/buddypress/groups/single/admin.php:74
+#: bp-themes/bp-default/groups/create.php:65
+#: bp-themes/bp-default/groups/create.php:74
+#: bp-themes/bp-default/groups/single/admin.php:64
+#: bp-themes/bp-default/groups/single/admin.php:74
+msgid "This group will be listed in the groups directory and in search results."
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/groups/create.php:59
+#: bp-templates/bp-legacy/buddypress/groups/single/admin.php:65
+#: bp-themes/bp-default/groups/create.php:66
+#: bp-themes/bp-default/groups/single/admin.php:65
+msgid "Group content and activity will be visible to any site member."
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/groups/create.php:64
+#: bp-templates/bp-legacy/buddypress/groups/single/admin.php:71
+#: bp-themes/bp-default/groups/create.php:71
+#: bp-themes/bp-default/groups/single/admin.php:71
+msgid "This is a private group"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/groups/create.php:66
+#: bp-templates/bp-legacy/buddypress/groups/single/admin.php:73
+#: bp-themes/bp-default/groups/create.php:73
+#: bp-themes/bp-default/groups/single/admin.php:73
+msgid "Only users who request membership and are accepted can join the group."
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/groups/create.php:68
+#: bp-templates/bp-legacy/buddypress/groups/create.php:77
+#: bp-templates/bp-legacy/buddypress/groups/single/admin.php:75
+#: bp-templates/bp-legacy/buddypress/groups/single/admin.php:85
+#: bp-themes/bp-default/groups/create.php:75
+#: bp-themes/bp-default/groups/create.php:84
+#: bp-themes/bp-default/groups/single/admin.php:75
+#: bp-themes/bp-default/groups/single/admin.php:85
+msgid "Group content and activity will only be visible to members of the group."
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/groups/create.php:73
+#: bp-templates/bp-legacy/buddypress/groups/single/admin.php:81
+#: bp-themes/bp-default/groups/create.php:80
+#: bp-themes/bp-default/groups/single/admin.php:81
+msgid "This is a hidden group"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/groups/create.php:75
+#: bp-templates/bp-legacy/buddypress/groups/single/admin.php:83
+#: bp-themes/bp-default/groups/create.php:82
+#: bp-themes/bp-default/groups/single/admin.php:83
+msgid "Only users who are invited can join the group."
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/groups/create.php:76
+#: bp-templates/bp-legacy/buddypress/groups/single/admin.php:84
+#: bp-themes/bp-default/groups/create.php:83
+#: bp-themes/bp-default/groups/single/admin.php:84
+msgid "This group will not be listed in the groups directory or search results."
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/groups/create.php:82
+#: bp-templates/bp-legacy/buddypress/groups/single/admin.php:92
+#: bp-themes/bp-default/groups/create.php:89
+#: bp-themes/bp-default/groups/single/admin.php:92
+msgid "Group Invitations"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/groups/create.php:84
+#: bp-templates/bp-legacy/buddypress/groups/single/admin.php:94
+#: bp-themes/bp-default/groups/create.php:91
+#: bp-themes/bp-default/groups/single/admin.php:94
+msgid "Which members of this group are allowed to invite others?"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/groups/create.php:109
+#: bp-themes/bp-default/groups/create.php:116
+msgid "Should this group have a forum?"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/groups/create.php:116
+#: bp-themes/bp-default/groups/create.php:123
+msgid "<strong>Attention Site Admin:</strong> Group forums require the <a href=\"%s\">correct setup and configuration</a> of a bbPress installation."
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/groups/create.php:142
+#: bp-templates/bp-legacy/buddypress/groups/single/admin.php:127
+#: bp-themes/bp-default/groups/create.php:149
+#: bp-themes/bp-default/groups/single/admin.php:127
+msgid "Upload an image to use as an avatar for this group. The image will be shown on the main group page, and in search results."
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/groups/create.php:146
+#: bp-templates/bp-legacy/buddypress/groups/single/admin.php:131
+#: bp-templates/bp-legacy/buddypress/members/single/profile/change-avatar.php:18
+#: bp-themes/bp-default/groups/create.php:153
+#: bp-themes/bp-default/groups/single/admin.php:131
+#: bp-themes/bp-default/members/single/profile/change-avatar.php:18
+msgid "Upload Image"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/groups/create.php:150
+#: bp-themes/bp-default/groups/create.php:157
+msgid "To skip the avatar upload process, hit the \"Next Step\" button."
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/groups/create.php:157
+#: bp-themes/bp-default/groups/create.php:164
+msgid "Crop Group Avatar"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/groups/create.php:159
+#: bp-templates/bp-legacy/buddypress/groups/single/admin.php:151
+#: bp-templates/bp-legacy/buddypress/members/single/profile/change-avatar.php:33
+#: bp-themes/bp-default/groups/create.php:166
+#: bp-themes/bp-default/groups/single/admin.php:151
+#: bp-themes/bp-default/members/single/profile/change-avatar.php:33
+msgid "Avatar to crop"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/groups/create.php:162
+#: bp-templates/bp-legacy/buddypress/groups/single/admin.php:154
+#: bp-templates/bp-legacy/buddypress/members/single/profile/change-avatar.php:36
+#: bp-themes/bp-default/groups/create.php:169
+#: bp-themes/bp-default/groups/single/admin.php:154
+#: bp-themes/bp-default/members/single/profile/change-avatar.php:36
+msgid "Avatar preview"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/groups/create.php:165
+#: bp-templates/bp-legacy/buddypress/groups/single/admin.php:157
+#: bp-templates/bp-legacy/buddypress/members/single/profile/change-avatar.php:39
+#: bp-themes/bp-default/groups/create.php:172
+#: bp-themes/bp-default/groups/single/admin.php:157
+#: bp-themes/bp-default/members/single/profile/change-avatar.php:39
+msgid "Crop Image"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/groups/create.php:204
+#: bp-templates/bp-legacy/buddypress/groups/single/send-invites.php:22
+#: bp-themes/bp-default/groups/create.php:211
+#: bp-themes/bp-default/groups/single/send-invites.php:22
+msgid "Select people to invite from your friends list."
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/groups/create.php:222
+#: bp-templates/bp-legacy/buddypress/groups/single/send-invites.php:42
+#: bp-templates/bp-legacy/buddypress-functions.php:938
+#: bp-themes/bp-default/_inc/ajax.php:598
+#: bp-themes/bp-default/groups/create.php:229
+#: bp-themes/bp-default/groups/single/send-invites.php:42
+msgid "Remove Invite"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/groups/create.php:239
+#: bp-templates/bp-legacy/buddypress/groups/single/send-invites.php:73
+#: bp-themes/bp-default/groups/create.php:246
+#: bp-themes/bp-default/groups/single/send-invites.php:73
+msgid "Once you have built up friend connections you will be able to invite others to your group."
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/groups/create.php:261
+#: bp-themes/bp-default/groups/create.php:268
+msgid "Back to Previous Step"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/groups/create.php:268
+#: bp-themes/bp-default/groups/create.php:275
+msgid "Next Step"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/groups/create.php:275
+#: bp-themes/bp-default/groups/create.php:282
+msgid "Create Group and Continue"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/groups/create.php:282
+#: bp-themes/bp-default/groups/create.php:289
+msgid "Finish"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/groups/groups-loop.php:95
+#: bp-themes/bp-default/groups/groups-loop.php:95
+msgid "There were no groups found."
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/groups/index.php:19
+#: bp-themes/bp-default/groups/index.php:35
+msgid "All Groups <span>%s</span>"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/groups/index.php:40
+#: bp-templates/bp-legacy/buddypress/members/single/groups.php:23
+#: bp-themes/bp-default/groups/index.php:58
+#: bp-themes/bp-default/members/single/groups.php:23
+msgid "Most Members"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/groups/index.php:41
+#: bp-templates/bp-legacy/buddypress/members/single/groups.php:24
+#: bp-themes/bp-default/groups/index.php:59
+#: bp-themes/bp-default/members/single/groups.php:24
+msgid "Newly Created"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/groups/single/admin.php:26
+#: bp-themes/bp-default/groups/single/admin.php:26
+msgid "Notify group members of these changes via email"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/groups/single/admin.php:137
+#: bp-themes/bp-default/groups/single/admin.php:137
+msgid "If you'd like to remove the existing avatar but not upload a new one, please use the delete avatar button."
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/groups/single/admin.php:139
+#: bp-templates/bp-legacy/buddypress/members/single/profile/change-avatar.php:24
+#: bp-themes/bp-default/groups/single/admin.php:139
+#: bp-themes/bp-default/members/single/profile/change-avatar.php:24
+msgid "Delete Avatar"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/groups/single/admin.php:149
+#: bp-themes/bp-default/groups/single/admin.php:149
+msgid "Crop Avatar"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/groups/single/admin.php:260
+#: bp-themes/bp-default/groups/single/admin.php:260
+msgid "(banned)"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/groups/single/admin.php:266
+#: bp-themes/bp-default/groups/single/admin.php:266
+msgid "Unban this member"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/groups/single/admin.php:266
+#: bp-themes/bp-default/groups/single/admin.php:266
+msgid "Remove Ban"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/groups/single/admin.php:270
+#: bp-themes/bp-default/groups/single/admin.php:270
+msgid "Kick and ban this member"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/groups/single/admin.php:270
+#: bp-themes/bp-default/groups/single/admin.php:270
+msgid "Kick &amp; Ban"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/groups/single/admin.php:271
+#: bp-themes/bp-default/groups/single/admin.php:271
+msgid "Promote to Mod"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/groups/single/admin.php:276
+#: bp-themes/bp-default/groups/single/admin.php:276
+msgid "Remove this member"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/groups/single/admin.php:276
+#: bp-themes/bp-default/groups/single/admin.php:276
+msgid "Remove from group"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/groups/single/admin.php:290
+#: bp-templates/bp-legacy/buddypress/groups/single/members.php:87
+#: bp-themes/bp-default/groups/single/admin.php:290
+#: bp-themes/bp-default/groups/single/members.php:87
+msgid "This group has no members."
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/groups/single/admin.php:320
+#: bp-templates/bp-legacy/buddypress/members/single/friends/requests.php:37
+#: bp-templates/bp-legacy/buddypress/members/single/groups/invites.php:23
+#: bp-themes/bp-default/groups/single/admin.php:320
+#: bp-themes/bp-default/members/single/friends/requests.php:37
+#: bp-themes/bp-default/members/single/groups/invites.php:23
+msgid "Accept"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/groups/single/admin.php:322
+#: bp-templates/bp-legacy/buddypress/members/single/friends/requests.php:38
+#: bp-templates/bp-legacy/buddypress/members/single/groups/invites.php:24
+#: bp-themes/bp-default/groups/single/admin.php:322
+#: bp-themes/bp-default/members/single/friends/requests.php:38
+#: bp-themes/bp-default/members/single/groups/invites.php:24
+msgid "Reject"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/groups/single/admin.php:335
+#: bp-themes/bp-default/groups/single/admin.php:335
+msgid "There are no pending membership requests."
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/groups/single/admin.php:352
+#: bp-themes/bp-default/groups/single/admin.php:352
+msgid "WARNING: Deleting this group will completely remove ALL content associated with it. There is no way back, please be careful with this option."
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/groups/single/admin.php:355
+#: bp-themes/bp-default/groups/single/admin.php:355
+msgid "I understand the consequences of deleting this group."
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/groups/single/forum/edit.php:16
+#: bp-templates/bp-legacy/buddypress/groups/single/forum/topic.php:17
+#: bp-templates/bp-legacy/buddypress/groups/single/forum.php:27
+#: bp-themes/bp-default/groups/single/forum/edit.php:16
+#: bp-themes/bp-default/groups/single/forum/topic.php:17
+#: bp-themes/bp-default/groups/single/forum.php:27
+msgid "Forum Directory"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/groups/single/forum/edit.php:25
+#: bp-themes/bp-default/groups/single/forum/edit.php:25
+msgid "Edit:"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/groups/single/forum/edit.php:87
+#: bp-themes/bp-default/groups/single/forum/edit.php:87
+msgid "This topic does not exist."
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/groups/single/forum/topic.php:9
+#: bp-themes/bp-default/groups/single/forum/topic.php:9
+msgid "New Reply"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/groups/single/forum/topic.php:32
+#: bp-themes/bp-default/groups/single/forum/topic.php:32
+msgid "Topic tags:"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/groups/single/forum/topic.php:81
+#: bp-themes/bp-default/groups/single/forum/topic.php:81
+msgid "%1$s said %2$s:"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/groups/single/forum/topic.php:119
+#: bp-themes/bp-default/groups/single/forum/topic.php:119
+msgid "There are no posts for this topic."
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/groups/single/forum/topic.php:134
+#: bp-themes/bp-default/groups/single/forum/topic.php:134
+msgid "You will auto join this group when you reply to this topic."
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/groups/single/forum/topic.php:139
+#: bp-themes/bp-default/groups/single/forum/topic.php:139
+msgid "Add a reply:"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/groups/single/forum/topic.php:144
+#: bp-themes/bp-default/groups/single/forum/topic.php:144
+msgid "Post Reply"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/groups/single/forum/topic.php:155
+#: bp-themes/bp-default/groups/single/forum/topic.php:155
+msgid "This topic is closed, replies are no longer accepted."
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/groups/single/forum.php:69
+#: bp-themes/bp-default/groups/single/forum.php:69
+msgid "You will auto join this group when you start a new topic."
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/groups/single/forum.php:73
+#: bp-themes/bp-default/groups/single/forum.php:73
+msgid "Post a New Topic:"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/groups/single/group-header.php:11
+#: bp-themes/bp-default/groups/single/group-header.php:11
+msgid "Group Admins"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/groups/single/group-header.php:20
+#: bp-themes/bp-default/groups/single/group-header.php:20
+msgid "Group Mods"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/groups/single/request-membership.php:4
+#: bp-themes/bp-default/groups/single/request-membership.php:4
+msgid "You are requesting to become a member of the group '%s'."
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/groups/single/request-membership.php:7
+#: bp-themes/bp-default/groups/single/request-membership.php:7
+msgid "Comments (optional)"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/groups/single/request-membership.php:12
+#: bp-themes/bp-default/groups/single/request-membership.php:12
+msgid "Send Request"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/members/activate.php:14
+#: bp-themes/bp-default/registration/activate.php:23
+msgid "Your account was activated successfully! Your account details have been sent to you in a separate email."
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/members/activate.php:16
+#: bp-themes/bp-default/registration/activate.php:25
+msgid "Your account was activated successfully! You can now <a href=\"%s\">log in</a> with the username and password you provided when you signed up."
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/members/activate.php:21
+#: bp-themes/bp-default/registration/activate.php:30
+msgid "Please provide a valid activation key."
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/members/activate.php:25
+#: bp-themes/bp-default/registration/activate.php:34
+msgid "Activation Key:"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/members/index.php:38
+#: bp-templates/bp-legacy/buddypress/members/single/friends.php:23
+#: bp-themes/bp-default/members/index.php:58
+#: bp-themes/bp-default/members/single/friends.php:23
+msgid "Newest Registered"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/members/register.php:13
+#: bp-themes/bp-default/registration/register.php:16
+msgid "User registration is currently not allowed."
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/members/register.php:22
+msgid "Registering for this site is easy. Just fill in the fields below, and we'll get a new account set up for you in no time."
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/members/register.php:30
+#: bp-themes/bp-default/registration/register.php:35
+msgid "Account Details"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/members/register.php:32
+#: bp-templates/bp-legacy/buddypress/members/register.php:36
+#: bp-templates/bp-legacy/buddypress/members/register.php:40
+#: bp-templates/bp-legacy/buddypress/members/register.php:44
+#: bp-templates/bp-legacy/buddypress/members/register.php:73
+#: bp-templates/bp-legacy/buddypress/members/register.php:81
+#: bp-templates/bp-legacy/buddypress/members/register.php:89
+#: bp-templates/bp-legacy/buddypress/members/register.php:99
+#: bp-templates/bp-legacy/buddypress/members/register.php:110
+#: bp-templates/bp-legacy/buddypress/members/register.php:125
+#: bp-templates/bp-legacy/buddypress/members/register.php:136
+#: bp-templates/bp-legacy/buddypress/members/register.php:211
+#: bp-templates/bp-legacy/buddypress/members/register.php:220
+#: bp-templates/bp-legacy/buddypress/members/single/profile/edit.php:26
+#: bp-templates/bp-legacy/buddypress/members/single/profile/edit.php:33
+#: bp-templates/bp-legacy/buddypress/members/single/profile/edit.php:40
+#: bp-templates/bp-legacy/buddypress/members/single/profile/edit.php:49
+#: bp-templates/bp-legacy/buddypress/members/single/profile/edit.php:67
+#: bp-templates/bp-legacy/buddypress/members/single/profile/edit.php:83
+#: bp-templates/bp-legacy/buddypress/members/single/profile/edit.php:93
+#: bp-themes/bp-default/members/single/profile/edit.php:26
+#: bp-themes/bp-default/members/single/profile/edit.php:33
+#: bp-themes/bp-default/members/single/profile/edit.php:40
+#: bp-themes/bp-default/members/single/profile/edit.php:49
+#: bp-themes/bp-default/members/single/profile/edit.php:67
+#: bp-themes/bp-default/members/single/profile/edit.php:83
+#: bp-themes/bp-default/members/single/profile/edit.php:93
+#: bp-themes/bp-default/registration/register.php:37
+#: bp-themes/bp-default/registration/register.php:41
+#: bp-themes/bp-default/registration/register.php:45
+#: bp-themes/bp-default/registration/register.php:49
+#: bp-themes/bp-default/registration/register.php:78
+#: bp-themes/bp-default/registration/register.php:86
+#: bp-themes/bp-default/registration/register.php:94
+#: bp-themes/bp-default/registration/register.php:104
+#: bp-themes/bp-default/registration/register.php:115
+#: bp-themes/bp-default/registration/register.php:130
+#: bp-themes/bp-default/registration/register.php:141
+#: bp-themes/bp-default/registration/register.php:216
+#: bp-themes/bp-default/registration/register.php:225
+msgid "(required)"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/members/register.php:36
+#: bp-themes/bp-default/registration/register.php:41
+msgid "Email Address"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/members/register.php:40
+#: bp-themes/bp-default/registration/register.php:45
+msgid "Choose a Password"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/members/register.php:44
+#: bp-themes/bp-default/registration/register.php:49
+msgid "Confirm Password"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/members/register.php:62
+#: bp-themes/bp-default/registration/register.php:67
+msgid "Profile Details"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/members/register.php:116
+#: bp-templates/bp-legacy/buddypress/members/single/profile/edit.php:58
+#: bp-templates/bp-legacy/buddypress/members/single/profile/edit.php:73
+#: bp-themes/bp-default/members/single/profile/edit.php:58
+#: bp-themes/bp-default/members/single/profile/edit.php:73
+#: bp-themes/bp-default/registration/register.php:121
+#: bp-xprofile/bp-xprofile-admin.php:415
+msgid "Clear"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/members/register.php:158
+#: bp-templates/bp-legacy/buddypress/members/register.php:173
+#: bp-templates/bp-legacy/buddypress/members/single/profile/edit.php:120
+#: bp-templates/bp-legacy/buddypress/members/single/profile/edit.php:134
+#: bp-themes/bp-default/members/single/profile/edit.php:120
+#: bp-themes/bp-default/members/single/profile/edit.php:134
+#: bp-themes/bp-default/registration/register.php:163
+#: bp-themes/bp-default/registration/register.php:178
+msgid "This field can be seen by: <span class=\"current-visibility-level\">%s</span>"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/members/register.php:158
+#: bp-themes/bp-default/registration/register.php:163
+msgctxt "Change profile field visibility level"
+msgid "Change"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/members/register.php:163
+#: bp-templates/bp-legacy/buddypress/members/single/profile/edit.php:125
+#: bp-themes/bp-default/members/single/profile/edit.php:125
+#: bp-themes/bp-default/registration/register.php:168
+msgid "Who can see this field?"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/members/register.php:205
+#: bp-themes/bp-default/registration/register.php:210
+msgid "Blog Details"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/members/register.php:207
+#: bp-themes/bp-default/registration/register.php:212
+msgid "Yes, I'd like to create a new site"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/members/register.php:211
+#: bp-themes/bp-default/registration/register.php:216
+msgid "Blog URL"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/members/register.php:220
+#: bp-themes/bp-default/registration/register.php:225
+msgid "Site Title"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/members/register.php:243
+#: bp-themes/bp-default/registration/register.php:248
+msgid "Complete Sign Up"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/members/register.php:258
+#: bp-themes/bp-default/registration/register.php:265
+msgid "You have successfully created your account! To begin using this site you will need to activate your account via the email we have just sent to your address."
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/members/register.php:260
+#: bp-themes/bp-default/registration/register.php:267
+msgid "You have successfully created your account! Please log in using the username and password you have just created."
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/members/single/friends/requests.php:68
+#: bp-themes/bp-default/members/single/friends/requests.php:68
+msgid "You have no pending friendship requests."
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/members/single/groups/invites.php:14
+#: bp-themes/bp-default/members/single/groups/invites.php:14
+msgid "1 member"
+msgid_plural "%d members"
+msgstr[0] ""
+msgstr[1] ""
+
+#: bp-templates/bp-legacy/buddypress/members/single/groups/invites.php:37
+#: bp-themes/bp-default/members/single/groups/invites.php:37
+msgid "You have no outstanding group invites."
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/members/single/messages/compose.php:5
+#: bp-themes/bp-default/members/single/messages/compose.php:5
+msgid "Send To (Username or Friend's Name)"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/members/single/messages/compose.php:14
+#: bp-themes/bp-default/members/single/messages/compose.php:14
+msgid "This is a notice to all users."
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/members/single/messages/compose.php:17
+#: bp-themes/bp-default/members/single/messages/compose.php:17
+msgid "Subject"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/members/single/messages/compose.php:20
+#: bp-themes/bp-default/members/single/messages/compose.php:20
+msgid "Message"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/members/single/messages/compose.php:28
+#: bp-themes/bp-default/members/single/messages/compose.php:28
+msgid "Send Message"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/members/single/messages/messages-loop.php:32
+#: bp-themes/bp-default/members/single/messages/messages-loop.php:32
+msgid "From:"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/members/single/messages/messages-loop.php:37
+#: bp-themes/bp-default/members/single/messages/messages-loop.php:37
+msgid "To:"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/members/single/messages/messages-loop.php:43
+#: bp-themes/bp-default/members/single/messages/messages-loop.php:43
+msgid "View Message"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/members/single/messages/messages-loop.php:51
+#: bp-templates/bp-legacy/buddypress/members/single/messages/notices-loop.php:43
+#: bp-templates/bp-legacy/buddypress/members/single/messages/single.php:24
+#: bp-themes/bp-default/members/single/messages/messages-loop.php:51
+#: bp-themes/bp-default/members/single/messages/notices-loop.php:43
+#: bp-themes/bp-default/members/single/messages/single.php:24
+msgid "Delete Message"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/members/single/messages/messages-loop.php:69
+#: bp-themes/bp-default/members/single/messages/messages-loop.php:69
+msgid "Sorry, no messages were found."
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/members/single/messages/notices-loop.php:36
+#: bp-themes/bp-default/members/single/messages/notices-loop.php:36
+msgid "Sent:"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/members/single/messages/notices-loop.php:54
+#: bp-themes/bp-default/members/single/messages/notices-loop.php:54
+msgid "Sorry, no notices were found."
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/members/single/messages/single.php:14
+#: bp-themes/bp-default/members/single/messages/single.php:14
+msgid "You are alone in this conversation."
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/members/single/messages/single.php:18
+#: bp-themes/bp-default/members/single/messages/single.php:18
+msgid "Conversation between %s and you."
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/members/single/messages/single.php:86
+#: bp-themes/bp-default/members/single/messages/single.php:75
+msgid "Send a Reply"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/members/single/messages/single.php:102
+#: bp-themes/bp-default/members/single/messages/single.php:91
+msgid "Send Reply"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/members/single/notifications/feedback-no-notifications.php:7
+msgid "You have no unread notifications."
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/members/single/notifications/feedback-no-notifications.php:11
+msgid "This member has no unread notifications."
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/members/single/notifications/feedback-no-notifications.php:19
+msgid "You have no notifications."
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/members/single/notifications/feedback-no-notifications.php:23
+msgid "This member has no notifications."
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/members/single/notifications/notifications-loop.php:5
+msgid "Notification"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/members/single/notifications/notifications-loop.php:6
+msgid "Date Received"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/members/single/notifications/notifications-loop.php:7
+msgid "Actions"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/members/single/profile/change-avatar.php:1
+#: bp-themes/bp-default/members/single/profile/change-avatar.php:1
+#: bp-xprofile/bp-xprofile-loader.php:204
+#: bp-xprofile/bp-xprofile-loader.php:259
+msgid "Change Avatar"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/members/single/profile/change-avatar.php:7
+#: bp-themes/bp-default/members/single/profile/change-avatar.php:7
+msgid "Your avatar will be used on your profile and throughout the site. If there is a <a href=\"http://gravatar.com\">Gravatar</a> associated with your account email we will use that, or you can upload an image from your computer."
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/members/single/profile/change-avatar.php:14
+#: bp-themes/bp-default/members/single/profile/change-avatar.php:14
+msgid "Click below to select a JPG, GIF or PNG format photo from your computer and then click 'Upload Image' to proceed."
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/members/single/profile/change-avatar.php:23
+#: bp-themes/bp-default/members/single/profile/change-avatar.php:23
+msgid "If you'd like to delete your current avatar but not upload a new one, please use the delete avatar button."
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/members/single/profile/change-avatar.php:24
+#: bp-themes/bp-default/members/single/profile/change-avatar.php:24
+msgid "Delete My Avatar"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/members/single/profile/change-avatar.php:31
+#: bp-themes/bp-default/members/single/profile/change-avatar.php:31
+msgid "Crop Your New Avatar"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/members/single/profile/change-avatar.php:55
+#: bp-themes/bp-default/members/single/profile/change-avatar.php:55
+msgid "Your avatar will be used on your profile and throughout the site. To change your avatar, please create an account with <a href=\"http://gravatar.com\">Gravatar</a> using the same email address as you used to register with this site."
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/members/single/profile/edit.php:10
+#: bp-themes/bp-default/members/single/profile/edit.php:10
+msgid "Editing '%s' Profile Group"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/members/single/profile/edit.php:120
+#: bp-themes/bp-default/members/single/profile/edit.php:120
+msgid "Change"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/members/single/profile/profile-wp.php:8
+#: bp-themes/bp-default/members/single/profile/profile-wp.php:8
+msgid "%s's Profile"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/members/single/settings/capabilities.php:9
+#: bp-themes/bp-default/members/single/settings/capabilities.php:57
+msgid "This user is a spammer."
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/members/single/settings/delete-account.php:7
+#: bp-themes/bp-default/members/single/settings/delete-account.php:56
+msgid "Deleting your account will delete all of the content you have created. It will be completely irrecoverable."
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/members/single/settings/delete-account.php:11
+#: bp-themes/bp-default/members/single/settings/delete-account.php:60
+msgid "Deleting this account will delete all of the content it has created. It will be completely irrecoverable."
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/members/single/settings/delete-account.php:23
+#: bp-themes/bp-default/members/single/settings/delete-account.php:72
+msgid "I understand the consequences."
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/members/single/settings/general.php:7
+#: bp-themes/bp-default/members/single/settings/general.php:57
+msgid "Current Password <span>(required to update email or change current password)</span>"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/members/single/settings/general.php:8
+#: bp-themes/bp-default/members/single/settings/general.php:58
+msgid "Password Lost and Found"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/members/single/settings/general.php:8
+#: bp-themes/bp-default/members/single/settings/general.php:58
+msgid "Lost your password?"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/members/single/settings/general.php:12
+#: bp-themes/bp-default/members/single/settings/general.php:62
+msgid "Account Email"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/members/single/settings/general.php:15
+#: bp-themes/bp-default/members/single/settings/general.php:65
+msgid "Change Password <span>(leave blank for no change)</span>"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/members/single/settings/general.php:16
+#: bp-themes/bp-default/members/single/settings/general.php:66
+msgid "New Password"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/members/single/settings/general.php:17
+#: bp-themes/bp-default/members/single/settings/general.php:67
+msgid "Repeat New Password"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress/members/single/settings/notifications.php:4
+#: bp-themes/bp-default/members/single/settings/notifications.php:54
+msgid "Send an email notice when:"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress-functions.php:63
+msgid "BuddyPress Legacy"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress-functions.php:232
+#: bp-themes/bp-default/functions.php:159
+msgid "Accepted"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress-functions.php:234
+#: bp-themes/bp-default/functions.php:164
+msgid "comments"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress-functions.php:235
+msgid "Are you sure you want to leave this group?"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress-functions.php:237
+#: bp-themes/bp-default/functions.php:158
+msgid "My Favorites"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress-functions.php:238
+#: bp-themes/bp-default/functions.php:160
+msgid "Rejected"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress-functions.php:240
+#: bp-themes/bp-default/functions.php:163
+msgid "Show all"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress-functions.php:241
+#: bp-themes/bp-default/functions.php:161
+msgid "Show all comments for this thread"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress-functions.php:242
+#: bp-themes/bp-default/functions.php:162
+msgid "Show all %d comments"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress-functions.php:243
+#: bp-themes/bp-default/functions.php:169
+msgid "Your profile has unsaved changes. If you leave the page, the changes will be lost."
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress-functions.php:640
+#: bp-themes/bp-default/_inc/ajax.php:291
+msgid "There was a problem posting your update, please try again."
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress-functions.php:734
+#: bp-templates/bp-legacy/buddypress-functions.php:770
+#: bp-themes/bp-default/_inc/ajax.php:393
+#: bp-themes/bp-default/_inc/ajax.php:429
+msgid "There was a problem when deleting. Please try again."
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress-functions.php:942
+#: bp-themes/bp-default/_inc/ajax.php:602
+msgid "%s has previously requested to join this group. Sending an invitation will automatically add the member to the group."
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress-functions.php:997
+#: bp-themes/bp-default/_inc/ajax.php:656
+msgid " Friendship could not be requested."
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress-functions.php:1009
+#: bp-themes/bp-default/_inc/ajax.php:668
+msgid "Friendship request could not be cancelled."
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress-functions.php:1014
+#: bp-themes/bp-default/_inc/ajax.php:673
+msgid "Request Pending"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress-functions.php:1034
+#: bp-themes/bp-default/_inc/ajax.php:693
+msgid "There was a problem accepting that request. Please try again."
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress-functions.php:1053
+#: bp-themes/bp-default/_inc/ajax.php:712
+msgid "There was a problem rejecting that request. Please try again."
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress-functions.php:1083
+#: bp-themes/bp-default/_inc/ajax.php:742
+msgid "Error joining group"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress-functions.php:1096
+#: bp-templates/bp-legacy/buddypress-functions.php:1106
+#: bp-themes/bp-default/_inc/ajax.php:755
+#: bp-themes/bp-default/_inc/ajax.php:765
+msgid "Error requesting membership"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress-functions.php:1108
+#: bp-themes/bp-default/_inc/ajax.php:767
+msgid "Membership Requested"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress-functions.php:1117
+#: bp-themes/bp-default/_inc/ajax.php:776
+msgid "Error leaving group"
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress-functions.php:1140
+#: bp-themes/bp-default/_inc/ajax.php:799
+msgid "There was a problem closing the notice."
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress-functions.php:1203
+#: bp-themes/bp-default/_inc/ajax.php:850
+msgid "There was a problem sending that reply. Please try again."
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress-functions.php:1221
+#: bp-themes/bp-default/_inc/ajax.php:868
+msgid "There was a problem marking messages as unread."
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress-functions.php:1246
+#: bp-themes/bp-default/_inc/ajax.php:893
+msgid "There was a problem marking messages as read."
+msgstr ""
+
+#: bp-templates/bp-legacy/buddypress-functions.php:1271
+#: bp-themes/bp-default/_inc/ajax.php:918
+msgid "There was a problem deleting messages."
+msgstr ""
+
+#: bp-themes/bp-default/404.php:7
+msgid "Page not found"
+msgstr ""
+
+#: bp-themes/bp-default/404.php:9
+msgid "We're sorry, but we can't find the page that you're looking for. Perhaps searching will help."
+msgstr ""
+
+#: bp-themes/bp-default/activity/entry.php:37
+msgid "In reply to: "
+msgstr ""
+
+#: bp-themes/bp-default/activity/entry.php:37
+msgid "View Thread / Permalink"
+msgstr ""
+
+#: bp-themes/bp-default/activity/entry.php:104
+msgid "or press esc to cancel."
+msgstr ""
+
+#: bp-themes/bp-default/activity/index.php:21
+msgid "Site Activity"
+msgstr ""
+
+#: bp-themes/bp-default/archive.php:10
+msgid "You are browsing the archive for %1$s."
+msgstr ""
+
+#: bp-themes/bp-default/archive.php:24 bp-themes/bp-default/attachment.php:18
+#: bp-themes/bp-default/index.php:24 bp-themes/bp-default/search.php:26
+#: bp-themes/bp-default/single.php:16
+msgctxt "Post written by..."
+msgid "by %s"
+msgstr ""
+
+#: bp-themes/bp-default/archive.php:28 bp-themes/bp-default/attachment.php:22
+#: bp-themes/bp-default/index.php:32 bp-themes/bp-default/search.php:30
+msgid "Permanent Link to"
+msgstr ""
+
+#: bp-themes/bp-default/archive.php:30 bp-themes/bp-default/index.php:34
+#: bp-themes/bp-default/search.php:32 bp-themes/bp-default/single.php:23
+msgid "%1$s <span>in %2$s</span>"
+msgstr ""
+
+#: bp-themes/bp-default/archive.php:33 bp-themes/bp-default/index.php:37
+#: bp-themes/bp-default/search.php:35 bp-themes/bp-default/single.php:28
+msgid "Read the rest of this entry &rarr;"
+msgstr ""
+
+#: bp-themes/bp-default/archive.php:34 bp-themes/bp-default/index.php:38
+#: bp-themes/bp-default/onecolumn-page.php:31 bp-themes/bp-default/page.php:20
+#: bp-themes/bp-default/single.php:30
+msgid "Pages: "
+msgstr ""
+
+#: bp-themes/bp-default/archive.php:37 bp-themes/bp-default/index.php:41
+#: bp-themes/bp-default/search.php:38 bp-themes/bp-default/single.php:33
+msgid "Tags: "
+msgstr ""
+
+#: bp-themes/bp-default/archive.php:37 bp-themes/bp-default/index.php:41
+#: bp-themes/bp-default/search.php:38
+msgid "No Comments &#187;"
+msgstr ""
+
+#: bp-themes/bp-default/archive.php:37 bp-themes/bp-default/index.php:41
+#: bp-themes/bp-default/search.php:38
+msgid "1 Comment &#187;"
+msgstr ""
+
+#: bp-themes/bp-default/archive.php:37 bp-themes/bp-default/index.php:41
+#: bp-themes/bp-default/search.php:38
+msgid "% Comments &#187;"
+msgstr ""
+
+#: bp-themes/bp-default/archive.php:50 bp-themes/bp-default/index.php:54
+msgid "Not Found"
+msgstr ""
+
+#: bp-themes/bp-default/attachment.php:26 bp-themes/bp-default/single.php:24
+msgid "Edit this entry"
+msgstr ""
+
+#: bp-themes/bp-default/attachment.php:40
+msgid "Full size is %s pixels"
+msgstr ""
+
+#: bp-themes/bp-default/attachment.php:43
+msgid "Link to full size image"
+msgstr ""
+
+#: bp-themes/bp-default/attachment.php:62
+msgid "Sorry, no attachments matched your criteria."
+msgstr ""
+
+#: bp-themes/bp-default/blogs/create.php:21
+#: bp-themes/bp-default/blogs/index.php:21
+msgid "Site Directory"
+msgstr ""
+
+#: bp-themes/bp-default/comments.php:12
+msgid "Password Protected"
+msgstr ""
+
+#: bp-themes/bp-default/comments.php:13
+msgid "Enter the password to view comments."
+msgstr ""
+
+#: bp-themes/bp-default/comments.php:31
+msgid "1 response to %2$s"
+msgid_plural "%1$s responses to %2$s"
+msgstr[0] ""
+msgstr[1] ""
+
+#: bp-themes/bp-default/comments.php:55
+msgid "Comments are closed, but <a href=\"%1$s\" title=\"Trackback URL for this post\">trackbacks</a> and pingbacks are open."
+msgstr ""
+
+#: bp-themes/bp-default/comments.php:59
+msgid "Comments are closed."
+msgstr ""
+
+#: bp-themes/bp-default/comments.php:70
+msgid "1 trackback"
+msgid_plural "%d trackbacks"
+msgstr[0] ""
+msgstr[1] ""
+
+#: bp-themes/bp-default/footer.php:15
+msgid "Proudly powered by <a href=\"%1$s\">WordPress</a> and <a href=\"%2$s\">BuddyPress</a>."
+msgstr ""
+
+#: bp-themes/bp-default/forums/index.php:23
+msgid "Forums Directory"
+msgstr ""
+
+#: bp-themes/bp-default/functions.php:85
+msgid "Primary Navigation"
+msgstr ""
+
+#: bp-themes/bp-default/functions.php:391
+msgid "The sidebar widget area"
+msgstr ""
+
+#: bp-themes/bp-default/functions.php:400
+msgid "First Footer Widget Area"
+msgstr ""
+
+#: bp-themes/bp-default/functions.php:402
+msgid "The first footer widget area"
+msgstr ""
+
+#: bp-themes/bp-default/functions.php:411
+msgid "Second Footer Widget Area"
+msgstr ""
+
+#: bp-themes/bp-default/functions.php:413
+msgid "The second footer widget area"
+msgstr ""
+
+#: bp-themes/bp-default/functions.php:422
+msgid "Third Footer Widget Area"
+msgstr ""
+
+#: bp-themes/bp-default/functions.php:424
+msgid "The third footer widget area"
+msgstr ""
+
+#: bp-themes/bp-default/functions.php:433
+msgid "Fourth Footer Widget Area"
+msgstr ""
+
+#: bp-themes/bp-default/functions.php:435
+msgid "The fourth footer widget area"
+msgstr ""
+
+#. translators: 1: comment author url, 2: comment author name, 3: comment
+#. permalink, 4: comment date/timestamp
+
+#: bp-themes/bp-default/functions.php:490
+msgid "<a href=\"%1$s\" rel=\"nofollow\">%2$s</a> said on <a href=\"%3$s\"><span class=\"time-since\">%4$s</span></a>"
+msgstr ""
+
+#: bp-themes/bp-default/functions.php:497
+msgid "Your comment is awaiting moderation."
+msgstr ""
+
+#: bp-themes/bp-default/functions.php:509
+msgid "Edit comment"
+msgstr ""
+
+#: bp-themes/bp-default/functions.php:579
+msgid "Theme activated! This theme contains <a href=\"%s\">custom header image</a> support and <a href=\"%s\">sidebar widgets</a>."
+msgstr ""
+
+#: bp-themes/bp-default/functions.php:655
+msgid "You must be <a href=\"%1$s\">logged in</a> to post a comment."
+msgstr ""
+
+#: bp-themes/bp-default/functions.php:656
+msgid "Leave a reply"
+msgstr ""
+
+#: bp-themes/bp-default/functions.php:743
+msgid "&larr; Previous Entries"
+msgstr ""
+
+#: bp-themes/bp-default/functions.php:744
+msgid "Next Entries &rarr;"
+msgstr ""
+
+#: bp-themes/bp-default/groups/create.php:18
+#: bp-themes/bp-default/groups/index.php:21
+msgid "Groups Directory"
+msgstr ""
+
+#: bp-themes/bp-default/header.php:22
+msgctxt "Home page banner link title"
+msgid "Home"
+msgstr ""
+
+#: bp-themes/bp-default/header.php:25
+msgid "Search for:"
+msgstr ""
+
+#: bp-themes/bp-default/index.php:27
+msgctxt "Sticky post"
+msgid "Featured"
+msgstr ""
+
+#: bp-themes/bp-default/index.php:55
+msgid "Sorry, but you are looking for something that isn't here."
+msgstr ""
+
+#: bp-themes/bp-default/links.php:16
+msgid "Links"
+msgstr ""
+
+#: bp-themes/bp-default/members/index.php:21
+msgid "Members Directory"
+msgstr ""
+
+#: bp-themes/bp-default/members/single/settings/general.php:49
+msgid "General Settings"
+msgstr ""
+
+#: bp-themes/bp-default/members/single/settings/notifications.php:49
+msgid "Email Notification"
+msgstr ""
+
+#: bp-themes/bp-default/onecolumn-page.php:29 bp-themes/bp-default/page.php:18
+msgid "<p class=\"serif\">Read the rest of this page &rarr;</p>"
+msgstr ""
+
+#: bp-themes/bp-default/onecolumn-page.php:32 bp-themes/bp-default/page.php:21
+msgid "Edit this page."
+msgstr ""
+
+#: bp-themes/bp-default/registration/register.php:27
+msgid "Registering for this site is easy, just fill in the fields below and we'll get a new account set up for you in no time."
+msgstr ""
+
+#: bp-themes/bp-default/search.php:10
+msgid "Site"
+msgstr ""
+
+#: bp-themes/bp-default/search.php:14
+msgid "Search Results"
+msgstr ""
+
+#: bp-themes/bp-default/search.php:51
+msgid "No posts found. Try a different search?"
+msgstr ""
+
+#: bp-themes/bp-default/sidebar.php:37
+msgid "Please <a href=\"%s\" title=\"Create an account\">create an account</a> to get started."
+msgstr ""
+
+#: bp-themes/bp-default/sidebar.php:65
+msgid "Forum Topic Tags"
+msgstr ""
+
+#: bp-themes/bp-default/single.php:35
+msgctxt "Previous post link"
+msgid "&larr;"
+msgstr ""
+
+#: bp-themes/bp-default/single.php:36
+msgctxt "Next post link"
+msgid "&rarr;"
+msgstr ""
+
+#: bp-themes/bp-default/single.php:45
+msgid "Sorry, no posts matched your criteria."
+msgstr ""
+
+#: bp-xprofile/bp-xprofile-activity.php:20
+msgid "Member changed profile picture"
+msgstr ""
+
+#: bp-xprofile/bp-xprofile-activity.php:21
+msgid "New member registered"
+msgstr ""
+
+#: bp-xprofile/bp-xprofile-activity.php:22
+msgid "Updated Profile"
+msgstr ""
+
+#: bp-xprofile/bp-xprofile-activity.php:129
+msgid "%s changed their profile picture"
+msgstr ""
+
+#: bp-xprofile/bp-xprofile-admin.php:27 bp-xprofile/bp-xprofile-admin.php:71
+msgid "Profile Fields"
+msgstr ""
+
+#: bp-xprofile/bp-xprofile-admin.php:72 bp-xprofile/bp-xprofile-classes.php:355
+msgid "Add New Field Group"
+msgstr ""
+
+#: bp-xprofile/bp-xprofile-admin.php:75
+msgid "Fields in the \"%s\" group will appear on the signup page."
+msgstr ""
+
+#: bp-xprofile/bp-xprofile-admin.php:98 bp-xprofile/bp-xprofile-admin.php:382
+msgid "(Primary)"
+msgstr ""
+
+#: bp-xprofile/bp-xprofile-admin.php:113
+msgid "Add New Field"
+msgstr ""
+
+#: bp-xprofile/bp-xprofile-admin.php:152
+msgid "There are no fields in this group."
+msgstr ""
+
+#: bp-xprofile/bp-xprofile-admin.php:161
+msgid "You have no groups."
+msgstr ""
+
+#: bp-xprofile/bp-xprofile-admin.php:162
+msgid "Add New Group"
+msgstr ""
+
+#: bp-xprofile/bp-xprofile-admin.php:189
+msgid "There was an error saving the group. Please try again"
+msgstr ""
+
+#: bp-xprofile/bp-xprofile-admin.php:192
+msgid "The group was saved successfully."
+msgstr ""
+
+#: bp-xprofile/bp-xprofile-admin.php:221
+msgid "There was an error deleting the group. Please try again"
+msgstr ""
+
+#: bp-xprofile/bp-xprofile-admin.php:224
+msgid "The group was deleted successfully."
+msgstr ""
+
+#: bp-xprofile/bp-xprofile-admin.php:265
+msgid "There was an error saving the field. Please try again"
+msgstr ""
+
+#: bp-xprofile/bp-xprofile-admin.php:272
+msgid "The field was saved successfully."
+msgstr ""
+
+#: bp-xprofile/bp-xprofile-admin.php:316
+msgid "field"
+msgstr ""
+
+#: bp-xprofile/bp-xprofile-admin.php:316
+msgid "option"
+msgstr ""
+
+#: bp-xprofile/bp-xprofile-admin.php:320
+msgid "There was an error deleting the %s. Please try again"
+msgstr ""
+
+#: bp-xprofile/bp-xprofile-admin.php:323
+msgid "The %s was deleted successfully!"
+msgstr ""
+
+#: bp-xprofile/bp-xprofile-admin.php:382
+msgid "(Required)"
+msgstr ""
+
+#: bp-xprofile/bp-xprofile-classes.php:272
+msgid "Please make sure you give the group a name."
+msgstr ""
+
+#: bp-xprofile/bp-xprofile-classes.php:357
+msgid "Create Field Group"
+msgstr ""
+
+#: bp-xprofile/bp-xprofile-classes.php:359
+msgid "Edit Field Group"
+msgstr ""
+
+#: bp-xprofile/bp-xprofile-classes.php:385
+#: bp-xprofile/bp-xprofile-classes.php:386
+msgid "Field Group Title"
+msgstr ""
+
+#: bp-xprofile/bp-xprofile-classes.php:392
+msgid "Group Description"
+msgstr ""
+
+#: bp-xprofile/bp-xprofile-classes.php:754
+msgid "Please enter options for this Field:"
+msgstr ""
+
+#: bp-xprofile/bp-xprofile-classes.php:757
+msgid "Sort Order:"
+msgstr ""
+
+#: bp-xprofile/bp-xprofile-classes.php:759
+msgid "Custom"
+msgstr ""
+
+#: bp-xprofile/bp-xprofile-classes.php:760
+msgid "Ascending"
+msgstr ""
+
+#: bp-xprofile/bp-xprofile-classes.php:761
+msgid "Descending"
+msgstr ""
+
+#: bp-xprofile/bp-xprofile-classes.php:790
+#: bp-xprofile/bp-xprofile-classes.php:807
+msgid "Default Value"
+msgstr ""
+
+#: bp-xprofile/bp-xprofile-classes.php:814
+msgid "Add Another Option"
+msgstr ""
+
+#: bp-xprofile/bp-xprofile-classes.php:823
+msgid "Add Field"
+msgstr ""
+
+#: bp-xprofile/bp-xprofile-classes.php:835
+msgid "Edit Field"
+msgstr ""
+
+#: bp-xprofile/bp-xprofile-classes.php:859
+msgid "Field Description"
+msgstr ""
+
+#: bp-xprofile/bp-xprofile-classes.php:868
+msgid "Submit"
+msgstr ""
+
+#: bp-xprofile/bp-xprofile-classes.php:890
+msgid "Default Visibility"
+msgstr ""
+
+#: bp-xprofile/bp-xprofile-classes.php:908
+msgid "Per-Member Visibility"
+msgstr ""
+
+#: bp-xprofile/bp-xprofile-classes.php:913
+msgid "Let members change this field's visibility"
+msgstr ""
+
+#: bp-xprofile/bp-xprofile-classes.php:917
+msgid "Enforce the default visibility for all members"
+msgstr ""
+
+#: bp-xprofile/bp-xprofile-classes.php:932
+msgid "Field Requirement"
+msgstr ""
+
+#: bp-xprofile/bp-xprofile-classes.php:935
+msgid "Not Required"
+msgstr ""
+
+#: bp-xprofile/bp-xprofile-classes.php:936
+msgid "Required"
+msgstr ""
+
+#: bp-xprofile/bp-xprofile-classes.php:942
+msgid "Field Type"
+msgstr ""
+
+#: bp-xprofile/bp-xprofile-classes.php:945
+msgid "Single Fields"
+msgstr ""
+
+#: bp-xprofile/bp-xprofile-classes.php:946
+msgid "Text Box"
+msgstr ""
+
+#: bp-xprofile/bp-xprofile-classes.php:947
+msgid "Multi-line Text Area"
+msgstr ""
+
+#: bp-xprofile/bp-xprofile-classes.php:948
+msgid "Date Selector"
+msgstr ""
+
+#: bp-xprofile/bp-xprofile-classes.php:950
+msgid "Multi Fields"
+msgstr ""
+
+#: bp-xprofile/bp-xprofile-classes.php:951
+msgid "Radio Buttons"
+msgstr ""
+
+#: bp-xprofile/bp-xprofile-classes.php:952
+msgid "Drop Down Select Box"
+msgstr ""
+
+#: bp-xprofile/bp-xprofile-classes.php:953
+msgid "Multi Select Box"
+msgstr ""
+
+#: bp-xprofile/bp-xprofile-classes.php:954
+msgid "Checkboxes"
+msgstr ""
+
+#: bp-xprofile/bp-xprofile-classes.php:988
+msgid "Please make sure you fill out all required fields."
+msgstr ""
+
+#: bp-xprofile/bp-xprofile-classes.php:991
+msgid "Radio button field types require at least one option. Please add options below."
+msgstr ""
+
+#: bp-xprofile/bp-xprofile-classes.php:994
+#: bp-xprofile/bp-xprofile-classes.php:997
+msgid "Select box field types require at least one option. Please add options below."
+msgstr ""
+
+#: bp-xprofile/bp-xprofile-classes.php:1000
+msgid "Checkbox field types require at least one option. Please add options below."
+msgstr ""
+
+#: bp-xprofile/bp-xprofile-loader.php:114
+msgid "Everyone"
+msgstr ""
+
+#: bp-xprofile/bp-xprofile-loader.php:118
+msgid "Only Me"
+msgstr ""
+
+#: bp-xprofile/bp-xprofile-loader.php:122
+msgid "All Members"
+msgstr ""
+
+#: bp-xprofile/bp-xprofile-screens.php:96
+msgid "Please make sure you fill in all required fields in this profile field group before saving."
+msgstr ""
+
+#: bp-xprofile/bp-xprofile-screens.php:129
+msgid "There was a problem updating some of your profile information, please try again."
+msgstr ""
+
+#: bp-xprofile/bp-xprofile-screens.php:131
+msgid "Changes saved."
+msgstr ""
+
+#: bp-xprofile/bp-xprofile-screens.php:199
+msgid "There was a problem cropping your avatar."
+msgstr ""
+
+#: bp-xprofile/bp-xprofile-screens.php:202
+msgid "Your new avatar was uploaded successfully."
+msgstr ""
+
+#: bp-xprofile/bp-xprofile-template.php:675
+msgid "January"
+msgstr ""
+
+#: bp-xprofile/bp-xprofile-template.php:676
+msgid "February"
+msgstr ""
+
+#: bp-xprofile/bp-xprofile-template.php:677
+msgid "March"
+msgstr ""
+
+#: bp-xprofile/bp-xprofile-template.php:678
+msgid "April"
+msgstr ""
+
+#: bp-xprofile/bp-xprofile-template.php:679
+msgid "May"
+msgstr ""
+
+#: bp-xprofile/bp-xprofile-template.php:680
+msgid "June"
+msgstr ""
+
+#: bp-xprofile/bp-xprofile-template.php:681
+msgid "July"
+msgstr ""
+
+#: bp-xprofile/bp-xprofile-template.php:682
+msgid "August"
+msgstr ""
+
+#: bp-xprofile/bp-xprofile-template.php:683
+msgid "September"
+msgstr ""
+
+#: bp-xprofile/bp-xprofile-template.php:684
+msgid "October"
+msgstr ""
+
+#: bp-xprofile/bp-xprofile-template.php:685
+msgid "November"
+msgstr ""
+
+#: bp-xprofile/bp-xprofile-template.php:686
+msgid "December"
+msgstr ""
+
+#: bp-xprofile/bp-xprofile-template.php:869
+msgid "Avatar uploads are currently disabled. Why not use a <a href=\"http://gravatar.com\" target=\"_blank\">gravatar</a> instead?"
+msgstr ""
+
+#: bp-xprofile/bp-xprofile-template.php:877
+msgid "Profile not recently updated"
+msgstr ""
+
+#: bp-xprofile/bp-xprofile-template.php:887
+msgid "Profile updated %s"
+msgstr ""
Index: /tags/1.9/bp-loader.php
===================================================================
--- /tags/1.9/bp-loader.php	(revision 7684)
+++ /tags/1.9/bp-loader.php	(revision 7684)
@@ -0,0 +1,620 @@
+<?php
+/**
+ * The BuddyPress Plugin
+ *
+ * BuddyPress is social networking software with a twist from the creators of WordPress.
+ *
+ * $Id$
+ *
+ * @package BuddyPress
+ * @subpackage Main
+ */
+
+/**
+ * Plugin Name: BuddyPress
+ * Plugin URI:  http://buddypress.org
+ * Description: Social networking in a box. Build a social network for your company, school, sports team or niche community all based on the power and flexibility of WordPress.
+ * Author:      The BuddyPress Community
+ * Author URI:  http://buddypress.org/community/members/
+ * Version:     1.9
+ * Text Domain: buddypress
+ * Domain Path: /bp-languages/
+ * License:     GPLv2 or later (license.txt)
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/** Constants *****************************************************************/
+
+if ( !class_exists( 'BuddyPress' ) ) :
+/**
+ * Main BuddyPress Class
+ *
+ * Tap tap tap... Is this thing on?
+ *
+ * @since BuddyPress (1.6)
+ */
+class BuddyPress {
+
+	/** Magic *****************************************************************/
+
+	/**
+	 * BuddyPress uses many variables, most of which can be filtered to customize
+	 * the way that it works. To prevent unauthorized access, these variables
+	 * are stored in a private array that is magically updated using PHP 5.2+
+	 * methods. This is to prevent third party plugins from tampering with
+	 * essential information indirectly, which would cause issues later.
+	 *
+	 * @see BuddyPress::setup_globals()
+	 * @var array
+	 */
+	private $data;
+
+	/** Not Magic *************************************************************/
+
+	/**
+	 * @var array Primary BuddyPress navigation
+	 */
+	public $bp_nav = array();
+
+	/**
+	 * @var array Secondary BuddyPress navigation to $bp_nav
+	 */
+	public $bp_options_nav = array();
+
+	/**
+	 * @var array The unfiltered URI broken down into chunks
+	 * @see bp_core_set_uri_globals()
+	 */
+	public $unfiltered_uri = array();
+
+	/**
+	 * @var array The canonical URI stack
+	 * @see bp_redirect_canonical()
+	 * @see bp_core_new_nav_item()
+	 */
+	public $canonical_stack = array();
+
+	/**
+	 * @var array Additional navigation elements (supplemental)
+	 */
+	public $action_variables = array();
+
+	/**
+	 * @var array Required components (core, members)
+	 */
+	public $required_components = array();
+
+	/**
+	 * @var array Additional active components
+	 */
+	public $loaded_components = array();
+
+	/**
+	 * @var array Active components
+	 */
+	public $active_components = array();
+
+	/** Option Overload *******************************************************/
+
+	/**
+	 * @var array Optional Overloads default options retrieved from get_option()
+	 */
+	public $options = array();
+
+	/** Singleton *************************************************************/
+
+	/**
+	 * Main BuddyPress Instance
+	 *
+	 * BuddyPress is great
+	 * Please load it only one time
+	 * For this, we thank you
+	 *
+	 * Insures that only one instance of BuddyPress exists in memory at any one
+	 * time. Also prevents needing to define globals all over the place.
+	 *
+	 * @since BuddyPress (1.7)
+	 *
+	 * @staticvar object $instance
+	 * @uses BuddyPress::constants() Setup the constants (mostly deprecated)
+	 * @uses BuddyPress::setup_globals() Setup the globals needed
+	 * @uses BuddyPress::legacy_constants() Setup the legacy constants (deprecated)
+	 * @uses BuddyPress::includes() Include the required files
+	 * @uses BuddyPress::setup_actions() Setup the hooks and actions
+	 * @see buddypress()
+	 *
+	 * @return BuddyPress The one true BuddyPress
+	 */
+	public static function instance() {
+
+		// Store the instance locally to avoid private static replication
+		static $instance = null;
+
+		// Only run these methods if they haven't been ran previously
+		if ( null === $instance ) {
+			$instance = new BuddyPress;
+			$instance->constants();
+			$instance->setup_globals();
+			$instance->legacy_constants();
+			$instance->includes();
+			$instance->setup_actions();
+		}
+
+		// Always return the instance
+		return $instance;
+	}
+
+	/** Magic Methods *********************************************************/
+
+	/**
+	 * A dummy constructor to prevent BuddyPress from being loaded more than once.
+	 *
+	 * @since BuddyPress (1.7)
+	 * @see BuddyPress::instance()
+	 * @see buddypress()
+	 */
+	private function __construct() { /* Do nothing here */ }
+
+	/**
+	 * A dummy magic method to prevent BuddyPress from being cloned
+	 *
+	 * @since BuddyPress (1.7)
+	 */
+	public function __clone() { _doing_it_wrong( __FUNCTION__, __( 'Cheatin&#8217; huh?', 'buddypress' ), '1.7' ); }
+
+	/**
+	 * A dummy magic method to prevent BuddyPress from being unserialized
+	 *
+	 * @since BuddyPress (1.7)
+	 */
+	public function __wakeup() { _doing_it_wrong( __FUNCTION__, __( 'Cheatin&#8217; huh?', 'buddypress' ), '1.7' ); }
+
+	/**
+	 * Magic method for checking the existence of a certain custom field
+	 *
+	 * @since BuddyPress (1.7)
+	 */
+	public function __isset( $key ) { return isset( $this->data[$key] ); }
+
+	/**
+	 * Magic method for getting BuddyPress varibles
+	 *
+	 * @since BuddyPress (1.7)
+	 */
+	public function __get( $key ) { return isset( $this->data[$key] ) ? $this->data[$key] : null; }
+
+	/**
+	 * Magic method for setting BuddyPress varibles
+	 *
+	 * @since BuddyPress (1.7)
+	 */
+	public function __set( $key, $value ) { $this->data[$key] = $value; }
+
+	/**
+	 * Magic method for unsetting BuddyPress variables
+	 *
+	 * @since BuddyPress (1.7)
+	 */
+	public function __unset( $key ) { if ( isset( $this->data[$key] ) ) unset( $this->data[$key] ); }
+
+	/**
+	 * Magic method to prevent notices and errors from invalid method calls
+	 *
+	 * @since BuddyPress (1.7)
+	 */
+	public function __call( $name = '', $args = array() ) { unset( $name, $args ); return null; }
+
+	/** Private Methods *******************************************************/
+
+	/**
+	 * Bootstrap constants
+	 *
+	 * @since BuddyPress (1.6)
+	 *
+	 * @uses is_multisite()
+	 * @uses get_current_site()
+	 * @uses get_current_blog_id()
+	 * @uses plugin_dir_path()
+	 * @uses plugin_dir_url()
+	 */
+	private function constants() {
+
+		// Place your custom code (actions/filters) in a file called
+		// '/plugins/bp-custom.php' and it will be loaded before anything else.
+		if ( file_exists( WP_PLUGIN_DIR . '/bp-custom.php' ) )
+			require( WP_PLUGIN_DIR . '/bp-custom.php' );
+
+		// Path and URL
+		if ( ! defined( 'BP_PLUGIN_DIR' ) ) {
+			define( 'BP_PLUGIN_DIR', trailingslashit( plugin_dir_path( __FILE__ ) ) );
+		}
+
+		if ( ! defined( 'BP_PLUGIN_URL' ) ) {
+			$plugin_url = plugin_dir_url( __FILE__ );
+
+			// If we're using https, update the protocol. Workaround for WP13941, WP15928, WP19037.
+			if ( is_ssl() )
+				$plugin_url = str_replace( 'http://', 'https://', $plugin_url );
+
+			define( 'BP_PLUGIN_URL', $plugin_url );
+		}
+
+		// Define on which blog ID BuddyPress should run
+		if ( ! defined( 'BP_ROOT_BLOG' ) ) {
+
+			// Default to use current blog ID
+			// Fulfills non-network installs and BP_ENABLE_MULTIBLOG installs
+			$root_blog_id = get_current_blog_id();
+
+			// Multisite check
+			if ( is_multisite() ) {
+
+				// Multiblog isn't enabled
+				if ( ! defined( 'BP_ENABLE_MULTIBLOG' ) || ( defined( 'BP_ENABLE_MULTIBLOG' ) && (int) constant( 'BP_ENABLE_MULTIBLOG' ) === 0 ) ) {
+					// Check to see if BP is network-activated
+					// We're not using is_plugin_active_for_network() b/c you need to include the
+					// /wp-admin/includes/plugin.php file in order to use that function.
+
+					// get network-activated plugins
+					$plugins = get_site_option( 'active_sitewide_plugins');
+
+					// basename
+					$basename = plugin_basename( constant( 'BP_PLUGIN_DIR' ) . 'bp-loader.php' );
+
+					// plugin is network-activated; use main site ID instead
+					if ( isset( $plugins[ $basename ] ) ) {
+						$current_site = get_current_site();
+						$root_blog_id = $current_site->blog_id;
+					}
+				}
+
+			}
+
+			define( 'BP_ROOT_BLOG', $root_blog_id );
+		}
+
+		// The search slug has to be defined nice and early because of the way
+		// search requests are loaded
+		//
+		// @todo Make this better
+		if ( !defined( 'BP_SEARCH_SLUG' ) )
+			define( 'BP_SEARCH_SLUG', 'search' );
+	}
+
+	/**
+	 * Component global variables
+	 *
+	 * @since BuddyPress (1.6)
+	 * @access private
+	 *
+	 * @uses plugin_dir_path() To generate BuddyPress plugin path
+	 * @uses plugin_dir_url() To generate BuddyPress plugin url
+	 * @uses apply_filters() Calls various filters
+	 */
+	private function setup_globals() {
+
+		/** Versions **********************************************************/
+
+		$this->version    = '1.9-7682';
+		$this->db_version = 7553;
+
+		/** Loading ***********************************************************/
+
+		$this->load_deprecated  = true;
+
+		/** Toolbar ***********************************************************/
+
+		/**
+		 * @var string The primary toolbar ID
+		 */
+		$this->my_account_menu_id = '';
+
+		/** URI's *************************************************************/
+
+		/**
+		 * @var int The current offset of the URI
+		 * @see bp_core_set_uri_globals()
+		 */
+		$this->unfiltered_uri_offset = 0;
+
+		/**
+		 * @var bool Are status headers already sent?
+		 */
+		$this->no_status_set = false;
+
+		/** Components ********************************************************/
+
+		/**
+		 * @var string Name of the current BuddyPress component (primary)
+		 */
+		$this->current_component = '';
+
+		/**
+		 * @var string Name of the current BuddyPress item (secondary)
+		 */
+		$this->current_item = '';
+
+		/**
+		 * @var string Name of the current BuddyPress action (tertiary)
+		 */
+		$this->current_action = '';
+
+		/**
+		 * @var bool Displaying custom 2nd level navigation menu (I.E a group)
+		 */
+		$this->is_single_item = false;
+
+		/** Root **************************************************************/
+
+		// BuddyPress Root blog ID
+		$this->root_blog_id = (int) apply_filters( 'bp_get_root_blog_id', BP_ROOT_BLOG );
+
+		/** Paths *************************************************************/
+
+		// BuddyPress root directory
+		$this->file           = __FILE__;
+		$this->basename       = plugin_basename( $this->file );
+		$this->plugin_dir     = BP_PLUGIN_DIR;
+		$this->plugin_url     = BP_PLUGIN_URL;
+
+		// Languages
+		$this->lang_dir       = $this->plugin_dir . 'bp-languages';
+
+		// Templates (theme compatability)
+		$this->themes_dir     = $this->plugin_dir . 'bp-templates';
+		$this->themes_url     = $this->plugin_url . 'bp-templates';
+
+		// Themes (for bp-default)
+		$this->old_themes_dir = $this->plugin_dir . 'bp-themes';
+		$this->old_themes_url = $this->plugin_url . 'bp-themes';
+
+		/** Theme Compat ******************************************************/
+
+		$this->theme_compat   = new stdClass(); // Base theme compatibility class
+		$this->filters        = new stdClass(); // Used when adding/removing filters
+
+		/** Users *************************************************************/
+
+		$this->current_user   = new stdClass();
+		$this->displayed_user = new stdClass();
+	}
+
+	/**
+	 * Legacy BuddyPress constants
+	 *
+	 * Try to avoid using these. Their values have been moved into variables
+	 * in the instance, and have matching functions to get/set their values.
+	 *
+	 * @since BuddyPress (1.7)
+	 */
+	private function legacy_constants() {
+
+		// Define the BuddyPress version
+		if ( !defined( 'BP_VERSION'    ) ) define( 'BP_VERSION',    $this->version   );
+
+		// Define the database version
+		if ( !defined( 'BP_DB_VERSION' ) ) define( 'BP_DB_VERSION', $this->db_version );
+	}
+
+	/**
+	 * Include required files
+	 *
+	 * @since BuddyPress (1.6)
+	 * @access private
+	 *
+	 * @uses is_admin() If in WordPress admin, load additional file
+	 */
+	private function includes() {
+
+		// Load the WP abstraction file so BuddyPress can run on all WordPress setups.
+		require( BP_PLUGIN_DIR . '/bp-core/bp-core-wpabstraction.php' );
+
+		// Setup the versions (after we include multisite abstraction above)
+		$this->versions();
+
+		/** Update/Install ****************************************************/
+
+		// Theme compatability
+		require( $this->plugin_dir . 'bp-core/bp-core-template-loader.php'     );
+		require( $this->plugin_dir . 'bp-core/bp-core-theme-compatibility.php' );
+
+		// Require all of the BuddyPress core libraries
+		require( $this->plugin_dir . 'bp-core/bp-core-dependency.php' );
+		require( $this->plugin_dir . 'bp-core/bp-core-actions.php'    );
+		require( $this->plugin_dir . 'bp-core/bp-core-caps.php'       );
+		require( $this->plugin_dir . 'bp-core/bp-core-cache.php'      );
+		require( $this->plugin_dir . 'bp-core/bp-core-cssjs.php'      );
+		require( $this->plugin_dir . 'bp-core/bp-core-update.php'     );
+		require( $this->plugin_dir . 'bp-core/bp-core-options.php'    );
+		require( $this->plugin_dir . 'bp-core/bp-core-classes.php'    );
+		require( $this->plugin_dir . 'bp-core/bp-core-filters.php'    );
+		require( $this->plugin_dir . 'bp-core/bp-core-avatars.php'    );
+		require( $this->plugin_dir . 'bp-core/bp-core-widgets.php'    );
+		require( $this->plugin_dir . 'bp-core/bp-core-template.php'   );
+		require( $this->plugin_dir . 'bp-core/bp-core-adminbar.php'   );
+		require( $this->plugin_dir . 'bp-core/bp-core-buddybar.php'   );
+		require( $this->plugin_dir . 'bp-core/bp-core-catchuri.php'   );
+		require( $this->plugin_dir . 'bp-core/bp-core-component.php'  );
+		require( $this->plugin_dir . 'bp-core/bp-core-functions.php'  );
+		require( $this->plugin_dir . 'bp-core/bp-core-moderation.php' );
+		require( $this->plugin_dir . 'bp-core/bp-core-loader.php'     );
+
+		// Skip or load deprecated content
+		if ( false !== $this->load_deprecated ) {
+			require( $this->plugin_dir . 'bp-core/deprecated/1.2.php' );
+			require( $this->plugin_dir . 'bp-core/deprecated/1.5.php' );
+			require( $this->plugin_dir . 'bp-core/deprecated/1.6.php' );
+			require( $this->plugin_dir . 'bp-core/deprecated/1.7.php' );
+		}
+	}
+
+	/**
+	 * Setup the default hooks and actions
+	 *
+	 * @since BuddyPress (1.6)
+	 * @access private
+	 *
+	 * @uses register_activation_hook() To register the activation hook
+	 * @uses register_deactivation_hook() To register the deactivation hook
+	 * @uses add_action() To add various actions
+	 */
+	private function setup_actions() {
+
+		// Add actions to plugin activation and deactivation hooks
+		add_action( 'activate_'   . $this->basename, 'bp_activation'   );
+		add_action( 'deactivate_' . $this->basename, 'bp_deactivation' );
+
+		// If BuddyPress is being deactivated, do not add any actions
+		if ( bp_is_deactivation( $this->basename ) )
+			return;
+
+		// Array of BuddyPress core actions
+		$actions = array(
+			'setup_theme',              // Setup the default theme compat
+			'setup_current_user',       // Setup currently logged in user
+			'register_post_types',      // Register post types
+			'register_post_statuses',   // Register post statuses
+			'register_taxonomies',      // Register taxonomies
+			'register_views',           // Register the views
+			'register_theme_directory', // Register the theme directory
+			'register_theme_packages',  // Register bundled theme packages (bp-themes)
+			'load_textdomain',          // Load textdomain
+			'add_rewrite_tags',         // Add rewrite tags
+			'generate_rewrite_rules'    // Generate rewrite rules
+		);
+
+		// Add the actions
+		foreach( $actions as $class_action )
+			add_action( 'bp_' . $class_action, array( $this, $class_action ), 5 );
+
+		// All BuddyPress actions are setup (includes bbp-core-hooks.php)
+		do_action_ref_array( 'bp_after_setup_actions', array( &$this ) );
+	}
+
+	/**
+	 * Private method to align the active and database versions
+	 *
+	 * @since BuddyPress (1.7)
+	 */
+	private function versions() {
+
+		// Get the possible DB versions (boy is this gross)
+		$versions               = array();
+		$versions['1.6-single'] = get_blog_option( $this->root_blog_id, '_bp_db_version' );
+
+		// 1.6-single exists, so trust it
+		if ( !empty( $versions['1.6-single'] ) ) {
+			$this->db_version_raw = (int) $versions['1.6-single'];
+
+		// If no 1.6-single exists, use the max of the others
+		} else {
+			$versions['1.2']        = get_site_option(                      'bp-core-db-version' );
+			$versions['1.5-multi']  = get_site_option(                           'bp-db-version' );
+			$versions['1.6-multi']  = get_site_option(                          '_bp_db_version' );
+			$versions['1.5-single'] = get_blog_option( $this->root_blog_id,      'bp-db-version' );
+
+			// Remove empty array items
+			$versions             = array_filter( $versions );
+			$this->db_version_raw = (int) ( !empty( $versions ) ) ? (int) max( $versions ) : 0;
+		}
+	}
+
+	/** Public Methods ********************************************************/
+
+	/**
+	 * Set up BuddyPress's legacy theme directory.
+	 *
+	 * Starting with version 1.2, and ending with version 1.8, BuddyPress
+	 * registered a custom theme directory - bp-themes - which contained
+	 * the bp-default theme. Since BuddyPress 1.9, bp-themes is no longer
+	 * registered (and bp-default no longer offered) on new installations.
+	 * Sites using bp-default (or a child theme of bp-default) will
+	 * continue to have bp-themes registered as before.
+	 *
+	 * @since BuddyPress (1.5.0)
+	 *
+	 * @todo Move bp-default to wordpress.org/extend/themes and remove this.
+	 */
+	public function register_theme_directory() {
+		if ( ! bp_do_register_theme_directory() ) {
+			return;
+		}
+
+		register_theme_directory( $this->old_themes_dir );
+	}
+
+	/**
+	 * Register bundled theme packages
+	 *
+	 * Note that since we currently have complete control over bp-themes and
+	 * the bp-legacy folders, it's fine to hardcode these here. If at a
+	 * later date we need to automate this, an API will need to be built.
+	 *
+	 * @since BuddyPress (1.7)
+	 */
+	public function register_theme_packages() {
+
+		// Register the default theme compatibility package
+		bp_register_theme_package( array(
+			'id'      => 'legacy',
+			'name'    => __( 'BuddyPress Default', 'buddypress' ),
+			'version' => bp_get_version(),
+			'dir'     => trailingslashit( $this->themes_dir . '/bp-legacy' ),
+			'url'     => trailingslashit( $this->themes_url . '/bp-legacy' )
+		) );
+
+		// Register the basic theme stack. This is really dope.
+		bp_register_template_stack( 'get_stylesheet_directory', 10 );
+		bp_register_template_stack( 'get_template_directory',   12 );
+		bp_register_template_stack( 'bp_get_theme_compat_dir',  14 );
+	}
+
+	/**
+	 * Setup the default BuddyPress theme compatability location.
+	 *
+	 * @since BuddyPress (1.7)
+	 */
+	public function setup_theme() {
+
+		// Bail if something already has this under control
+		if ( ! empty( $this->theme_compat->theme ) )
+			return;
+
+		// Setup the theme package to use for compatibility
+		bp_setup_theme_compat( bp_get_theme_package_id() );
+	}
+}
+
+/**
+ * The main function responsible for returning the one true BuddyPress Instance
+ * to functions everywhere.
+ *
+ * Use this function like you would a global variable, except without needing
+ * to declare the global.
+ *
+ * Example: <?php $bp = buddypress(); ?>
+ *
+ * @return BuddyPress The one true BuddyPress Instance
+ */
+function buddypress() {
+	return BuddyPress::instance();
+}
+
+/**
+ * Hook BuddyPress early onto the 'plugins_loaded' action.
+ *
+ * This gives all other plugins the chance to load before BuddyPress, to get
+ * their actions, filters, and overrides setup without BuddyPress being in the
+ * way.
+ */
+if ( defined( 'BUDDYPRESS_LATE_LOAD' ) ) {
+	add_action( 'plugins_loaded', 'buddypress', (int) BUDDYPRESS_LATE_LOAD );
+
+// "And now here's something we hope you'll really like!"
+} else {
+	$GLOBALS['bp'] = buddypress();
+}
+
+endif;
Index: /tags/1.9/bp-members/bp-members-actions.php
===================================================================
--- /tags/1.9/bp-members/bp-members-actions.php	(revision 7684)
+++ /tags/1.9/bp-members/bp-members-actions.php	(revision 7684)
@@ -0,0 +1,117 @@
+<?php
+
+/**
+ * BuddyPress Members Actions
+ *
+ * Action functions are exactly the same as screen functions, however they do not
+ * have a template screen associated with them. Usually they will send the user
+ * back to the default screen after execution.
+ *
+ * @package BuddyPress
+ * @subpackage MembersActions
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/**
+ * When a site admin selects "Mark as Spammer/Not Spammer" from the admin menu
+ * this action will fire and mark or unmark the user and their blogs as spam.
+ * Must be a site admin for this function to run.
+ *
+ * @package BuddyPress Core
+ * @param int $user_id Optional user ID to mark as spam
+ * @global object $wpdb Global WordPress Database object
+ */
+function bp_core_action_set_spammer_status( $user_id = 0 ) {
+
+	// Only super admins can currently spam users (but they can't spam
+	// themselves)
+	if ( ! is_super_admin() || bp_is_my_profile() ) {
+		return;
+	}
+
+	// Use displayed user if it's not yourself
+	if ( empty( $user_id ) )
+		$user_id = bp_displayed_user_id();
+
+	if ( bp_is_current_component( 'admin' ) && ( in_array( bp_current_action(), array( 'mark-spammer', 'unmark-spammer' ) ) ) ) {
+
+		// Check the nonce
+		check_admin_referer( 'mark-unmark-spammer' );
+
+		// To spam or not to spam
+		$status = bp_is_current_action( 'mark-spammer' ) ? 'spam' : 'ham';
+
+		// The heavy lifting
+		bp_core_process_spammer_status( $user_id, $status );
+
+		// Add feedback message. @todo - Error reporting
+		if ( 'spam' == $status ) {
+			bp_core_add_message( __( 'User marked as spammer. Spam users are visible only to site admins.', 'buddypress' ) );
+		} else {
+			bp_core_add_message( __( 'User removed as spammer.', 'buddypress' ) );
+		}
+
+		// Deprecated. Use bp_core_process_spammer_status.
+		$is_spam = 'spam' == $status;
+		do_action( 'bp_core_action_set_spammer_status', bp_displayed_user_id(), $is_spam );
+
+		// Redirect back to where we came from
+		bp_core_redirect( wp_get_referer() );
+	}
+}
+// Unhooked in BuddyPress (1.6) - moved to settings
+//add_action( 'bp_actions', 'bp_core_action_set_spammer_status' );
+
+/**
+ * Allows a site admin to delete a user from the adminbar menu.
+ *
+ * @package BuddyPress Core
+ */
+function bp_core_action_delete_user() {
+
+	if ( !bp_current_user_can( 'bp_moderate' ) || bp_is_my_profile() || !bp_displayed_user_id() )
+		return false;
+
+	if ( bp_is_current_component( 'admin' ) && bp_is_current_action( 'delete-user' ) ) {
+
+		// Check the nonce
+		check_admin_referer( 'delete-user' );
+
+		$errors = false;
+		do_action( 'bp_core_before_action_delete_user', $errors );
+
+		if ( bp_core_delete_account( bp_displayed_user_id() ) ) {
+			bp_core_add_message( sprintf( __( '%s has been deleted from the system.', 'buddypress' ), bp_get_displayed_user_fullname() ) );
+		} else {
+			bp_core_add_message( sprintf( __( 'There was an error deleting %s from the system. Please try again.', 'buddypress' ), bp_get_displayed_user_fullname() ), 'error' );
+			$errors = true;
+		}
+
+		do_action( 'bp_core_action_delete_user', $errors );
+
+		if ( $errors )
+			bp_core_redirect( bp_displayed_user_domain() );
+		else
+			bp_core_redirect( bp_loggedin_user_domain() );
+	}
+}
+// Unhooked in BuddyPress (1.6) - moved to settings
+//add_action( 'bp_actions', 'bp_core_action_delete_user' );
+
+/**
+ * Returns the user_id for a user based on their username.
+ *
+ * @package BuddyPress Core
+ * @param string $username Username to check.
+ * @since BuddyPress (1.0)
+ */
+function bp_core_get_random_member() {
+	if ( ! isset( $_GET['random-member'] ) )
+		return;
+
+	$user = bp_core_get_users( array( 'type' => 'random', 'per_page' => 1 ) );
+	bp_core_redirect( bp_core_get_user_domain( $user['users'][0]->id ) );
+}
+add_action( 'bp_actions', 'bp_core_get_random_member' );
Index: /tags/1.9/bp-members/bp-members-adminbar.php
===================================================================
--- /tags/1.9/bp-members/bp-members-adminbar.php	(revision 7684)
+++ /tags/1.9/bp-members/bp-members-adminbar.php	(revision 7684)
@@ -0,0 +1,162 @@
+<?php
+
+/**
+ * BuddyPress Members Toolbar
+ *
+ * Handles the member functions related to the WordPress Toolbar
+ *
+ * @package BuddyPress
+ * @subpackage MembersAdminBar
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/**
+ * Add the "My Account" menu and all submenus.
+ *
+ * @since BuddyPress (1.6)
+ * @todo Deprecate WP 3.2 Toolbar compatibility when we drop 3.2 support
+ */
+function bp_members_admin_bar_my_account_menu() {
+	global $bp, $wp_admin_bar;
+
+	// Bail if this is an ajax request
+	if ( defined( 'DOING_AJAX' ) )
+		return;
+
+	// Logged in user
+	if ( is_user_logged_in() ) {
+
+		// Stored in the global so we can add menus easily later on
+		$bp->my_account_menu_id = 'my-account-buddypress';
+
+		// Create the main 'My Account' menu
+		$wp_admin_bar->add_menu( array(
+			'id'     => $bp->my_account_menu_id,
+			'group'  => true,
+			'title'  => __( 'Edit My Profile', 'buddypress' ),
+			'href'   => bp_loggedin_user_domain(),
+			'meta'   => array(
+			'class'  => 'ab-sub-secondary'
+		) ) );
+
+	// Show login and sign-up links
+	} elseif ( !empty( $wp_admin_bar ) ) {
+
+		add_filter ( 'show_admin_bar', '__return_true' );
+
+		// Create the main 'My Account' menu
+		$wp_admin_bar->add_menu( array(
+			'id'    => 'bp-login',
+			'title' => __( 'Log in', 'buddypress' ),
+			'href'  => wp_login_url( wp_guess_url() )
+		) );
+
+		// Sign up
+		if ( bp_get_signup_allowed() ) {
+			$wp_admin_bar->add_menu( array(
+				'id'    => 'bp-register',
+				'title' => __( 'Register', 'buddypress' ),
+				'href'  => bp_get_signup_page()
+			) );
+		}
+	}
+}
+add_action( 'bp_setup_admin_bar', 'bp_members_admin_bar_my_account_menu', 4 );
+
+/**
+ * Adds the User Admin top-level menu to user pages
+ *
+ * @package BuddyPress
+ * @since BuddyPress (1.5)
+ */
+function bp_members_admin_bar_user_admin_menu() {
+	global $bp, $wp_admin_bar;
+
+	// Only show if viewing a user
+	if ( !bp_is_user() )
+		return false;
+
+	// Don't show this menu to non site admins or if you're viewing your own profile
+	if ( !current_user_can( 'edit_users' ) || bp_is_my_profile() )
+		return false;
+
+	// Unique ID for the 'My Account' menu
+	$bp->user_admin_menu_id = 'user-admin';
+
+	// Add the top-level User Admin button
+	$wp_admin_bar->add_menu( array(
+		'id'    => $bp->user_admin_menu_id,
+		'title' => __( 'Edit Member', 'buddypress' ),
+		'href'  => bp_displayed_user_domain()
+	) );
+
+	if( bp_is_active( 'xprofile' ) ) {
+		// User Admin > Edit this user's profile
+		$wp_admin_bar->add_menu( array(
+			'parent' => $bp->user_admin_menu_id,
+			'id'     => $bp->user_admin_menu_id . '-edit-profile',
+			'title'  => __( "Edit Profile", 'buddypress' ),
+			'href'   => bp_get_members_component_link( 'profile', 'edit' )
+		) );
+
+		// User Admin > Edit this user's avatar
+		$wp_admin_bar->add_menu( array(
+			'parent' => $bp->user_admin_menu_id,
+			'id'     => $bp->user_admin_menu_id . '-change-avatar',
+			'title'  => __( "Edit Avatar", 'buddypress' ),
+			'href'   => bp_get_members_component_link( 'profile', 'change-avatar' )
+		) );
+	}
+
+	if ( bp_is_active( 'settings' ) ) {
+		// User Admin > Spam/unspam
+		$wp_admin_bar->add_menu( array(
+			'parent' => $bp->user_admin_menu_id,
+			'id'     => $bp->user_admin_menu_id . '-user-capabilities',
+			'title'  => __( 'User Capabilities', 'buddypress' ),
+			'href'   => bp_displayed_user_domain() . 'settings/capabilities/'
+		) );
+
+		// User Admin > Delete Account
+		$wp_admin_bar->add_menu( array(
+			'parent' => $bp->user_admin_menu_id,
+			'id'     => $bp->user_admin_menu_id . '-delete-user',
+			'title'  => __( 'Delete Account', 'buddypress' ),
+			'href'   => bp_displayed_user_domain() . 'settings/delete-account/'
+		) );
+
+	}
+
+}
+add_action( 'admin_bar_menu', 'bp_members_admin_bar_user_admin_menu', 99 );
+
+/**
+ * Build the "Notifications" dropdown
+ *
+ * @package BuddyPress
+ * @since BuddyPress (1.5)
+ */
+function bp_members_admin_bar_notifications_menu() {
+
+	// Bail if notifications is not active
+	if ( ! bp_is_active( 'notifications' ) ) {
+		return false;
+	}
+
+	bp_notifications_toolbar_menu();
+}
+add_action( 'admin_bar_menu', 'bp_members_admin_bar_notifications_menu', 90 );
+
+/**
+ * Remove rogue WP core edit menu when viewing a single user
+ *
+ * @since BuddyPress (1.6)
+ */
+function bp_members_remove_edit_page_menu() {
+	if ( bp_is_user() ) {
+		remove_action( 'admin_bar_menu', 'wp_admin_bar_edit_menu', 80 );
+	}
+}
+add_action( 'bp_init', 'bp_members_remove_edit_page_menu', 99 );
Index: /tags/1.9/bp-members/bp-members-buddybar.php
===================================================================
--- /tags/1.9/bp-members/bp-members-buddybar.php	(revision 7684)
+++ /tags/1.9/bp-members/bp-members-buddybar.php	(revision 7684)
@@ -0,0 +1,116 @@
+<?php
+
+/**
+ * BuddyPress Members BuddyBar
+ *
+ * Handles the member functions related to the BuddyBar
+ *
+ * @package BuddyPress
+ * @subpackage MembersBuddyBar
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/**
+ * Notifications Menu
+ */
+function bp_adminbar_notifications_menu() {
+
+	// Bail if notifications is not active
+	if ( ! bp_is_active( 'notifications' ) ) {
+		return false;
+	}
+
+	bp_notifications_buddybar_menu();
+}
+add_action( 'bp_adminbar_menus', 'bp_adminbar_notifications_menu', 8 );
+
+/**
+ * Blog Authors Menu (visible when not logged in)
+ */
+function bp_adminbar_authors_menu() {
+	global $wpdb;
+
+	// Only for multisite
+	if ( !is_multisite() )
+		return false;
+
+	// Hide on root blog
+	if ( $wpdb->blogid == bp_get_root_blog_id() || !bp_is_active( 'blogs' ) )
+		return false;
+
+	$blog_prefix = $wpdb->get_blog_prefix( $wpdb->blogid );
+	$authors     = $wpdb->get_results( "SELECT user_id, user_login, user_nicename, display_name, user_email, meta_value as caps FROM $wpdb->users u, $wpdb->usermeta um WHERE u.ID = um.user_id AND meta_key = '{$blog_prefix}capabilities' ORDER BY um.user_id" );
+
+	if ( !empty( $authors ) ) {
+		// This is a blog, render a menu with links to all authors
+		echo '<li id="bp-adminbar-authors-menu"><a href="/">';
+		_e('Blog Authors', 'buddypress');
+		echo '</a>';
+
+		echo '<ul class="author-list">';
+		foreach( (array) $authors as $author ) {
+			$caps = maybe_unserialize( $author->caps );
+			if ( isset( $caps['subscriber'] ) || isset( $caps['contributor'] ) ) continue;
+
+			echo '<li>';
+			echo '<a href="' . bp_core_get_user_domain( $author->user_id, $author->user_nicename, $author->user_login ) . '">';
+			echo bp_core_fetch_avatar( array(
+				'item_id' => $author->user_id,
+				'email'   => $author->user_email,
+				'width'   => 15,
+				'height'  => 15,
+				'alt'     => sprintf( __( 'Profile picture of %s', 'buddypress' ), $author->display_name )
+			) );
+ 			echo ' ' . $author->display_name . '</a>';
+			echo '<div class="admin-bar-clear"></div>';
+			echo '</li>';
+		}
+		echo '</ul>';
+		echo '</li>';
+	}
+}
+add_action( 'bp_adminbar_menus', 'bp_adminbar_authors_menu', 12 );
+
+/**
+ * Adds an Toolbar menu to any profile page providing site moderator actions
+ * that allow capable users to clean up a users account.
+ *
+ * @package BuddyPress XProfile
+ */
+function bp_members_adminbar_admin_menu() {
+
+	// Only show if viewing a user
+	if ( !bp_displayed_user_id() )
+		return false;
+
+	// Don't show this menu to non site admins or if you're viewing your own profile
+	if ( !current_user_can( 'edit_users' ) || bp_is_my_profile() )
+		return false; ?>
+
+	<li id="bp-adminbar-adminoptions-menu">
+
+		<a href=""><?php _e( 'Admin Options', 'buddypress' ) ?></a>
+
+		<ul>
+			<?php if ( bp_is_active( 'xprofile' ) ) : ?>
+
+				<li><a href="<?php bp_members_component_link( 'profile', 'edit' ); ?>"><?php printf( __( "Edit %s's Profile", 'buddypress' ), esc_attr( bp_get_displayed_user_fullname() ) ) ?></a></li>
+
+			<?php endif ?>
+
+			<li><a href="<?php bp_members_component_link( 'profile', 'change-avatar' ); ?>"><?php printf( __( "Edit %s's Avatar", 'buddypress' ), esc_attr( bp_get_displayed_user_fullname() ) ) ?></a></li>
+
+			<li><a href="<?php bp_members_component_link( 'settings', 'capabilities' ); ?>"><?php _e( 'User Capabilities', 'buddypress' ); ?></a></li>
+
+			<li><a href="<?php bp_members_component_link( 'settings', 'delete-account' ); ?>"><?php printf( __( "Delete %s's Account", 'buddypress' ), esc_attr( bp_get_displayed_user_fullname() ) ); ?></a></li>
+
+			<?php do_action( 'bp_members_adminbar_admin_menu' ) ?>
+
+		</ul>
+	</li>
+
+	<?php
+}
+add_action( 'bp_adminbar_menus', 'bp_members_adminbar_admin_menu', 20 );
Index: /tags/1.9/bp-members/bp-members-filters.php
===================================================================
--- /tags/1.9/bp-members/bp-members-filters.php	(revision 7684)
+++ /tags/1.9/bp-members/bp-members-filters.php	(revision 7684)
@@ -0,0 +1,78 @@
+<?php
+
+/**
+ * BuddyPress Members Filters
+ *
+ * Member specific filters
+ *
+ * @package BuddyPress
+ * @subpackage MembersFilters
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/**
+ * Escape commonly used fullname output functions
+ */
+add_filter( 'bp_displayed_user_fullname',    'esc_html' );
+add_filter( 'bp_get_loggedin_user_fullname', 'esc_html' );
+
+/**
+ * Load additional sign-up sanitization filters on bp_loaded. These are used
+ * to prevent XSS in the BuddyPress sign-up process. You can unhook these to
+ * allow for customization of your registration fields, however it is highly
+ * recommended that you leave these in place for the safety of your network.
+ *
+ * @since BuddyPress (1.5)
+ * @uses add_filter()
+ */
+function bp_members_signup_sanitization() {
+
+	// Filters on sign-up fields
+	$fields = array (
+		'bp_get_signup_username_value',
+		'bp_get_signup_email_value',
+		'bp_get_signup_with_blog_value',
+		'bp_get_signup_blog_url_value',
+		'bp_get_signup_blog_title_value',
+		'bp_get_signup_blog_privacy_value',
+		'bp_get_signup_avatar_dir_value',
+	);
+
+	// Add the filters to each field
+	foreach( $fields as $filter ) {
+		add_filter( $filter, 'esc_html',       1 );
+		add_filter( $filter, 'wp_filter_kses', 2 );
+		add_filter( $filter, 'stripslashes',   3 );
+	}
+
+	// Sanitize email
+	add_filter( 'bp_get_signup_email_value', 'sanitize_email' );
+}
+add_action( 'bp_loaded', 'bp_members_signup_sanitization' );
+
+/**
+ * Filter the user profile URL to point to BuddyPress profile edit
+ *
+ * @since BuddyPress 1.6
+ *
+ * @param string $url
+ * @param int $user_id
+ * @param string $scheme
+ * @return string
+ */
+function bp_members_edit_profile_url( $url, $user_id, $scheme = 'admin' ) {
+
+	// If xprofile is active, use profile domain link
+	if ( ! is_admin() && bp_is_active( 'xprofile' ) ) {
+		$profile_link = trailingslashit( bp_core_get_user_domain( $user_id ) . buddypress()->profile->slug . '/edit' );
+
+	// Default to $url
+	} else {
+		$profile_link = $url;
+	}
+
+	return apply_filters( 'bp_members_edit_profile_url', $profile_link, $url, $user_id, $scheme );
+}
+add_filter( 'edit_profile_url', 'bp_members_edit_profile_url', 10, 3 );
Index: /tags/1.9/bp-members/bp-members-functions.php
===================================================================
--- /tags/1.9/bp-members/bp-members-functions.php	(revision 7684)
+++ /tags/1.9/bp-members/bp-members-functions.php	(revision 7684)
@@ -0,0 +1,1604 @@
+<?php
+
+/**
+ * BuddyPress Member Functions
+ *
+ * Functions specific to the members component.
+ *
+ * @package BuddyPress
+ * @subpackage MembersFunctions
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/**
+ * Checks $bp pages global and looks for directory page
+ *
+ * @since BuddyPress (1.5)
+ *
+ * @global BuddyPress $bp The one true BuddyPress instance
+ * @return bool True if set, False if empty
+ */
+function bp_members_has_directory() {
+	global $bp;
+
+	return (bool) !empty( $bp->pages->members->id );
+}
+
+/**
+ * Define the slugs used for BuddyPress pages, based on the slugs of the WP pages used.
+ * These can be overridden manually by defining these slugs in wp-config.php.
+ *
+ * The fallback values are only used during initial BP page creation, when no slugs have been
+ * explicitly defined.
+ *
+ * @package BuddyPress Core Core
+ * @global BuddyPress $bp The one true BuddyPress instance
+ */
+function bp_core_define_slugs() {
+	global $bp;
+
+	// No custom members slug
+	if ( !defined( 'BP_MEMBERS_SLUG' ) ) {
+		if ( !empty( $bp->pages->members ) ) {
+			define( 'BP_MEMBERS_SLUG', $bp->pages->members->slug );
+		} else {
+			define( 'BP_MEMBERS_SLUG', 'members' );
+		}
+	}
+
+	// No custom registration slug
+	if ( !defined( 'BP_REGISTER_SLUG' ) ) {
+		if ( !empty( $bp->pages->register ) ) {
+			define( 'BP_REGISTER_SLUG', $bp->pages->register->slug );
+		} else {
+			define( 'BP_REGISTER_SLUG', 'register' );
+		}
+	}
+
+	// No custom activation slug
+	if ( !defined( 'BP_ACTIVATION_SLUG' ) ) {
+		if ( !empty( $bp->pages->activate ) ) {
+			define( 'BP_ACTIVATION_SLUG', $bp->pages->activate->slug );
+		} else {
+			define( 'BP_ACTIVATION_SLUG', 'activate' );
+		}
+	}
+}
+add_action( 'bp_setup_globals', 'bp_core_define_slugs', 11 );
+
+/**
+ * Return an array of users IDs based on the parameters passed.
+ *
+ * Since BuddyPress 1.7, bp_core_get_users() uses BP_User_Query. If you
+ * need backward compatibility with BP_Core_User::get_users(), filter the
+ * bp_use_legacy_user_query value, returning true.
+ *
+ * @package BuddyPress Core
+ */
+function bp_core_get_users( $args = '' ) {
+
+	// Parse the user query arguments
+	$params = wp_parse_args( $args, array(
+		'type'            => 'active',     // active, newest, alphabetical, random or popular
+		'user_id'         => false,        // Pass a user_id to limit to only friend connections for this user
+		'exclude'         => false,        // Users to exclude from results
+		'search_terms'    => false,        // Limit to users that match these search terms
+		'meta_key'        => false,        // Limit to users who have this piece of usermeta
+		'meta_value'      => false,        // With meta_key, limit to users where usermeta matches this value
+		'include'         => false,        // Pass comma separated list of user_ids to limit to only these users
+		'per_page'        => 20,           // The number of results to return per page
+		'page'            => 1,            // The page to return if limiting per page
+		'populate_extras' => true,         // Fetch the last active, where the user is a friend, total friend count, latest update
+		'count_total'     => 'count_query' // What kind of total user count to do, if any. 'count_query', 'sql_calc_found_rows', or false
+	) );
+
+	// For legacy users. Use of BP_Core_User::get_users() is deprecated.
+	if ( apply_filters( 'bp_use_legacy_user_query', false, __FUNCTION__, $params ) ) {
+		extract( $params, EXTR_SKIP );
+		$retval = BP_Core_User::get_users( $type, $per_page, $page, $user_id, $include, $search_terms, $populate_extras, $exclude, $meta_key, $meta_value );
+
+	// Default behavior as of BuddyPress 1.7
+	} else {
+
+		// Get users like we were asked to do...
+		$users = new BP_User_Query( $params );
+
+		// ...but reformat the results to match bp_core_get_users() behavior.
+		$retval = array(
+			'users' => array_values( $users->results ),
+			'total' => $users->total_users
+		);
+	}
+
+	return apply_filters( 'bp_core_get_users', $retval, $params );
+}
+
+/**
+ * Returns the domain for the passed user: e.g. http://domain.com/members/andy/
+ *
+ * @package BuddyPress Core
+ * @global $current_user WordPress global variable containing current logged in user information
+ * @param int $user_id The ID of the user.
+ */
+function bp_core_get_user_domain( $user_id, $user_nicename = false, $user_login = false ) {
+
+	if ( empty( $user_id ) )
+		return;
+
+	if ( !$domain = wp_cache_get( 'bp_user_domain_' . $user_id, 'bp' ) ) {
+		$username = bp_core_get_username( $user_id, $user_nicename, $user_login );
+
+		if ( bp_is_username_compatibility_mode() )
+			$username = rawurlencode( $username );
+
+		$after_domain = bp_core_enable_root_profiles() ? $username : bp_get_members_root_slug() . '/' . $username;
+		$domain       = trailingslashit( bp_get_root_domain() . '/' . $after_domain );
+		$domain       = apply_filters( 'bp_core_get_user_domain_pre_cache', $domain, $user_id, $user_nicename, $user_login );
+
+		// Cache the link
+		if ( !empty( $domain ) ) {
+			wp_cache_set( 'bp_user_domain_' . $user_id, $domain, 'bp' );
+		}
+	}
+
+	return apply_filters( 'bp_core_get_user_domain', $domain, $user_id, $user_nicename, $user_login );
+}
+
+/**
+ * Fetch everything in the wp_users table for a user, without any usermeta.
+ *
+ * @package BuddyPress Core
+ * @param int $user_id The ID of the user.
+ * @uses BP_Core_User::get_core_userdata() Performs the query.
+ */
+function bp_core_get_core_userdata( $user_id ) {
+	if ( empty( $user_id ) )
+		return false;
+
+	if ( !$userdata = wp_cache_get( 'bp_core_userdata_' . $user_id, 'bp' ) ) {
+		$userdata = BP_Core_User::get_core_userdata( $user_id );
+		wp_cache_set( 'bp_core_userdata_' . $user_id, $userdata, 'bp' );
+	}
+	return apply_filters( 'bp_core_get_core_userdata', $userdata );
+}
+
+/**
+ * Returns the user id for the user that is currently being displayed.
+ * eg: http://andy.domain.com/ or http://domain.com/andy/
+ *
+ * @package BuddyPress Core
+ * @uses bp_core_get_userid_from_user_login() Returns the user id for the username passed
+ * @return int The user id for the user that is currently being displayed, return zero if this is not a user home and just a normal blog.
+ */
+function bp_core_get_displayed_userid( $user_login ) {
+	return apply_filters( 'bp_core_get_displayed_userid', bp_core_get_userid( $user_login ) );
+}
+
+/**
+ * Returns the user_id for a user based on their username.
+ *
+ * @package BuddyPress Core
+ * @param string $username Username to check.
+ * @global $wpdb WordPress DB access object.
+ * @return int|bool The ID of the matched user, or false.
+ */
+function bp_core_get_userid( $username ) {
+	global $wpdb;
+
+	if ( empty( $username ) )
+		return false;
+
+	return apply_filters( 'bp_core_get_userid', $wpdb->get_var( $wpdb->prepare( "SELECT ID FROM {$wpdb->users} WHERE user_login = %s", $username ) ), $username );
+}
+
+/**
+ * Returns the user_id for a user based on their user_nicename.
+ *
+ * @package BuddyPress Core
+ * @param string $username Username to check.
+ * @global $wpdb WordPress DB access object.
+ * @return int|bool The ID of the matched user, or false.
+ */
+function bp_core_get_userid_from_nicename( $user_nicename ) {
+	global $wpdb;
+
+	if ( empty( $user_nicename ) )
+		return false;
+
+	return apply_filters( 'bp_core_get_userid_from_nicename', $wpdb->get_var( $wpdb->prepare( "SELECT ID FROM {$wpdb->users} WHERE user_nicename = %s", $user_nicename ) ), $user_nicename );
+}
+
+/**
+ * Returns the username for a user based on their user id.
+ *
+ * @package BuddyPress Core
+ * @param int $uid User ID to check.
+ * @uses bp_core_get_core_userdata() Fetch the userdata for a user ID
+ * @return string|bool The username of the matched user, or false.
+ */
+function bp_core_get_username( $user_id = 0, $user_nicename = false, $user_login = false ) {
+	$bp = buddypress();
+
+	// Check cache for user nicename
+	$username = wp_cache_get( 'bp_user_username_' . $user_id, 'bp' );
+	if ( false === $username ) {
+
+		// Cache not found so prepare to update it
+		$update_cache = true;
+
+		// Nicename and login were not passed
+		if ( empty( $user_nicename ) && empty( $user_login ) ) {
+
+			// User ID matches logged in user
+			if ( bp_loggedin_user_id() == $user_id ) {
+				$userdata = &$bp->loggedin_user->userdata;
+
+			// User ID matches displayed in user
+			} elseif ( bp_displayed_user_id() == $user_id ) {
+				$userdata = &$bp->displayed_user->userdata;
+
+			// No user ID match
+			} else {
+				$userdata = false;
+			}
+
+			// No match so go dig
+			if ( empty( $userdata ) ) {
+
+				// User not found so return false
+				if ( !$userdata = bp_core_get_core_userdata( $user_id ) ) {
+					return false;
+				}
+			}
+
+			// Update the $user_id for later
+			$user_id       = $userdata->ID;
+
+			// Two possible options
+			$user_nicename = $userdata->user_nicename;
+			$user_login    = $userdata->user_login;
+		}
+
+		// Pull an audible and maybe use the login over the nicename
+		$username = bp_is_username_compatibility_mode() ? $user_login : $user_nicename;
+
+	// Username found in cache so don't update it again
+	} else {
+		$update_cache = false;
+	}
+
+	// Add this to cache
+	if ( ( true === $update_cache ) && !empty( $username ) ) {
+		wp_cache_set( 'bp_user_username_' . $user_id, $username, 'bp' );
+
+	// @todo bust this cache if no $username found?
+	//} else {
+	//	wp_cache_delete( 'bp_user_username_' . $user_id );
+	}
+
+	return apply_filters( 'bp_core_get_username', $username );
+}
+
+/**
+ * Returns the user_nicename for a user based on their user_id. This should be
+ * used for linking to user profiles and anywhere else a sanitized and unique
+ * slug to a user is needed.
+ *
+ * @since BuddyPress (1.5)
+ *
+ * @package BuddyPress Core
+ * @param int $uid User ID to check.
+ * @global $userdata WordPress user data for the current logged in user.
+ * @uses get_userdata() WordPress function to fetch the userdata for a user ID
+ * @return string|bool The username of the matched user, or false.
+ */
+function bp_members_get_user_nicename( $user_id ) {
+	global $bp;
+
+	if ( !$user_nicename = wp_cache_get( 'bp_members_user_nicename_' . $user_id, 'bp' ) ) {
+		$update_cache = true;
+
+		// User ID matches logged in user
+		if ( bp_loggedin_user_id() == $user_id ) {
+			$userdata = &$bp->loggedin_user->userdata;
+
+		// User ID matches displayed in user
+		} elseif ( bp_displayed_user_id() == $user_id ) {
+			$userdata = &$bp->displayed_user->userdata;
+
+		// No user ID match
+		} else {
+			$userdata = false;
+		}
+
+		// No match so go dig
+		if ( empty( $userdata ) ) {
+
+			// User not found so return false
+			if ( !$userdata = bp_core_get_core_userdata( $user_id ) ) {
+				return false;
+			}
+		}
+
+		// User nicename found
+		$user_nicename = $userdata->user_nicename;
+
+	// Nicename found in cache so don't update it again
+	} else {
+		$update_cache = false;
+	}
+
+	// Add this to cache
+	if ( true == $update_cache && !empty( $user_nicename ) )
+		wp_cache_set( 'bp_members_user_nicename_' . $user_id, $user_nicename, 'bp' );
+
+	return apply_filters( 'bp_members_get_user_nicename', $user_nicename );
+}
+
+/**
+ * Returns the email address for the user based on user ID
+ *
+ * @package BuddyPress Core
+ * @param int $uid User ID to check.
+ * @uses get_userdata() WordPress function to fetch the userdata for a user ID
+ * @return string The email for the matched user. Empty string if no user matched the $uid.
+ */
+function bp_core_get_user_email( $uid ) {
+
+	if ( !$email = wp_cache_get( 'bp_user_email_' . $uid, 'bp' ) ) {
+		// User exists
+		if ( $ud = bp_core_get_core_userdata( $uid ) )
+			$email = $ud->user_email;
+
+		// User was deleted
+		else
+			$email = '';
+
+		wp_cache_set( 'bp_user_email_' . $uid, $email, 'bp' );
+	}
+
+	return apply_filters( 'bp_core_get_user_email', $email );
+}
+
+/**
+ * Returns a HTML formatted link for a user with the user's full name as the link text.
+ * eg: <a href="http://andy.domain.com/">Andy Peatling</a>
+ * Optional parameters will return just the name or just the URL.
+ *
+ * @param int $user_id User ID to check.
+ * @param bool $no_anchor Disable URL and HTML and just return full name. Default false.
+ * @param bool $just_link Disable full name and HTML and just return the URL text. Default false.
+ * @return string|bool The link text based on passed parameters, or false on no match.
+ * @todo This function needs to be cleaned up or split into separate functions
+ */
+function bp_core_get_userlink( $user_id, $no_anchor = false, $just_link = false ) {
+	$display_name = bp_core_get_user_displayname( $user_id );
+
+	if ( empty( $display_name ) )
+		return false;
+
+	if ( $no_anchor )
+		return $display_name;
+
+	if ( !$url = bp_core_get_user_domain( $user_id ) )
+		return false;
+
+	if ( $just_link )
+		return $url;
+
+	return apply_filters( 'bp_core_get_userlink', '<a href="' . $url . '" title="' . $display_name . '">' . $display_name . '</a>', $user_id );
+}
+
+
+/**
+ * Fetch the display name for a user. This will use the "Name" field in xprofile if it is installed.
+ * Otherwise, it will fall back to the normal WP display_name, or user_nicename, depending on what has been set.
+ *
+ * @package BuddyPress Core
+ * @global BuddyPress $bp The one true BuddyPress instance
+ * @uses wp_cache_get() Will try and fetch the value from the cache, rather than querying the DB again.
+ * @uses get_userdata() Fetches the WP userdata for a specific user.
+ * @uses xprofile_set_field_data() Will update the field data for a user based on field name and user id.
+ * @uses wp_cache_set() Adds a value to the cache.
+ * @return string|bool The display name for the user in question, or false if user not found.
+ */
+function bp_core_get_user_displayname( $user_id_or_username ) {
+	global $bp;
+
+	$fullname = '';
+
+	if ( !$user_id_or_username )
+		return false;
+
+	if ( !is_numeric( $user_id_or_username ) )
+		$user_id = bp_core_get_userid( $user_id_or_username );
+	else
+		$user_id = $user_id_or_username;
+
+	if ( !$user_id )
+		return false;
+
+	if ( !$fullname = wp_cache_get( 'bp_user_fullname_' . $user_id, 'bp' ) ) {
+		if ( bp_is_active( 'xprofile' ) ) {
+			$fullname = xprofile_get_field_data( 1, $user_id );
+
+			if ( empty($fullname) ) {
+				$ud = bp_core_get_core_userdata( $user_id );
+
+				if ( !empty( $ud->display_name ) )
+					$fullname = $ud->display_name;
+				elseif ( !empty( $ud->user_nicename ) )
+					$fullname = $ud->user_nicename;
+
+				xprofile_set_field_data( 1, $user_id, $fullname );
+			}
+		} else {
+			$ud = bp_core_get_core_userdata($user_id);
+
+			if ( !empty( $ud->display_name ) )
+				$fullname = $ud->display_name;
+			elseif ( !empty( $ud->user_nicename ) )
+				$fullname = $ud->user_nicename;
+		}
+
+		if ( !empty( $fullname ) )
+			wp_cache_set( 'bp_user_fullname_' . $user_id, $fullname, 'bp' );
+	}
+
+	return apply_filters( 'bp_core_get_user_displayname', $fullname, $user_id );
+}
+add_filter( 'bp_core_get_user_displayname', 'strip_tags', 1 );
+add_filter( 'bp_core_get_user_displayname', 'trim'          );
+add_filter( 'bp_core_get_user_displayname', 'stripslashes'  );
+add_filter( 'bp_core_get_user_displayname', 'esc_html'      );
+
+/**
+ * Returns the user link for the user based on user email address
+ *
+ * @package BuddyPress Core
+ * @param string $email The email address for the user.
+ * @uses bp_core_get_userlink() BuddyPress function to get a userlink by user ID.
+ * @uses get_user_by() WordPress function to get userdata via an email address
+ * @return string The link to the users home base. False on no match.
+ */
+function bp_core_get_userlink_by_email( $email ) {
+	$user = get_user_by( 'email', $email );
+	return apply_filters( 'bp_core_get_userlink_by_email', bp_core_get_userlink( $user->ID, false, false, true ) );
+}
+
+/**
+ * Returns the user link for the user based on the supplied identifier
+ *
+ * @param string $username If BP_ENABLE_USERNAME_COMPATIBILITY_MODE is set, this will be user_login, otherwise it will be user_nicename.
+ * @return string|bool The link to the users home base, false on no match.
+ */
+function bp_core_get_userlink_by_username( $username ) {
+	if ( bp_is_username_compatibility_mode() )
+		$user_id = bp_core_get_userid( $username );
+	else
+		$user_id = bp_core_get_userid_from_nicename( $username );
+
+	return apply_filters( 'bp_core_get_userlink_by_username', bp_core_get_userlink( $user_id, false, false, true ) );
+}
+
+/**
+ * Returns the total number of members for the installation.
+ *
+ * @package BuddyPress Core
+ * @return int The total number of members.
+ */
+function bp_core_get_total_member_count() {
+	global $wpdb;
+
+	if ( !$count = wp_cache_get( 'bp_total_member_count', 'bp' ) ) {
+		$status_sql = bp_core_get_status_sql();
+		$count = $wpdb->get_var( "SELECT COUNT(ID) FROM {$wpdb->users} WHERE {$status_sql}" );
+		wp_cache_set( 'bp_total_member_count', $count, 'bp' );
+	}
+
+	return apply_filters( 'bp_core_get_total_member_count', $count );
+}
+
+/**
+ * Returns the total number of members, limited to those members with last_activity
+ *
+ * @return int The number of active members
+ */
+function bp_core_get_active_member_count() {
+	global $wpdb;
+
+	if ( !$count = get_transient( 'bp_active_member_count' ) ) {
+		// Avoid a costly join by splitting the lookup
+		if ( is_multisite() ) {
+			$sql = "SELECT ID FROM {$wpdb->users} WHERE (user_status != 0 OR deleted != 0 OR user_status != 0)";
+		} else {
+			$sql = "SELECT ID FROM {$wpdb->users} WHERE user_status != 0";
+		}
+
+		$exclude_users     = $wpdb->get_col( $sql );
+		$exclude_users_sql = !empty( $exclude_users ) ? "AND user_id NOT IN (" . implode( ',', wp_parse_id_list( $exclude_users ) ) . ")" : '';
+		$count             = (int) $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(user_id) FROM {$wpdb->usermeta} WHERE meta_key = %s {$exclude_users_sql}", bp_get_user_meta_key( 'last_activity' ) ) );
+
+		set_transient( 'bp_active_member_count', $count );
+	}
+
+	return apply_filters( 'bp_core_get_active_member_count', $count );
+}
+
+/**
+ * Process a spammed or unspammed user.
+ *
+ * This function is called from three places:
+ *
+ * - in bp_settings_action_capabilities() (from the front-end)
+ * - by bp_core_mark_user_spam_admin()    (from wp-admin)
+ * - bp_core_mark_user_ham_admin()        (from wp-admin)
+ *
+ * @since BuddyPress (1.6.0)
+ *
+ * @param int $user_id The ID of the user being spammed/hammed.
+ * @param string $status 'spam' if being marked as spam, 'ham' otherwise.
+ */
+function bp_core_process_spammer_status( $user_id, $status ) {
+	global $wpdb;
+
+	// Bail if no user ID
+	if ( empty( $user_id ) )
+		return;
+
+	// Bail if user ID is super admin
+	if ( is_super_admin( $user_id ) )
+		return;
+
+	// Get the functions file
+	if ( is_multisite() ) {
+		require_once( ABSPATH . 'wp-admin/includes/ms.php' );
+	}
+
+	$is_spam = ( 'spam' == $status );
+
+	// Only you can prevent infinite loops
+	remove_action( 'make_spam_user', 'bp_core_mark_user_spam_admin' );
+	remove_action( 'make_ham_user',  'bp_core_mark_user_ham_admin'  );
+
+	// When marking as spam in the Dashboard, these actions are handled by WordPress
+	if ( !is_admin() ) {
+
+		// Get the blogs for the user
+		$blogs = get_blogs_of_user( $user_id, true );
+
+		foreach ( (array) $blogs as $key => $details ) {
+
+			// Do not mark the main or current root blog as spam
+			if ( 1 == $details->userblog_id || bp_get_root_blog_id() == $details->userblog_id ) {
+				continue;
+			}
+
+			// Update the blog status
+			update_blog_status( $details->userblog_id, 'spam', $is_spam );
+		}
+
+		// Finally, mark this user as a spammer
+		if ( is_multisite() ) {
+			update_user_status( $user_id, 'spam', $is_spam );
+		}
+
+		// Always set single site status
+		$wpdb->update( $wpdb->users, array( 'user_status' => $is_spam ), array( 'ID' => $user_id ) );
+
+		// Call multisite actions in single site mode for good measure
+		if ( !is_multisite() ) {
+			$wp_action = ( true === $is_spam ) ? 'make_spam_user' : 'make_ham_user';
+			do_action( $wp_action, bp_displayed_user_id() );
+		}
+	}
+
+	// Hide this user's activity
+	if ( ( true === $is_spam ) && bp_is_active( 'activity' ) ) {
+		bp_activity_hide_user_activity( $user_id );
+	}
+
+	// We need a special hook for is_spam so that components can delete data at spam time
+	$bp_action = ( true === $is_spam ) ? 'bp_make_spam_user' : 'bp_make_ham_user';
+	do_action( $bp_action, $user_id );
+
+	// Allow plugins to do neat things
+	do_action( 'bp_core_process_spammer_status', $user_id, $is_spam );
+
+	// Put things back how we found them
+	add_action( 'make_spam_user', 'bp_core_mark_user_spam_admin' );
+	add_action( 'make_ham_user',  'bp_core_mark_user_ham_admin'  );
+
+	return true;
+}
+
+/**
+ * Hook to WP's make_spam_user and run our custom BP spam functions
+ *
+ * @since BuddyPress (1.6)
+ *
+ * @param int $user_id The user id passed from the make_spam_user hook
+ */
+function bp_core_mark_user_spam_admin( $user_id ) {
+	bp_core_process_spammer_status( $user_id, 'spam' );
+}
+add_action( 'make_spam_user', 'bp_core_mark_user_spam_admin' );
+
+/**
+ * Hook to WP's make_ham_user and run our custom BP spam functions
+ *
+ * @since BuddyPress (1.6)
+ *
+ * @param int $user_id The user id passed from the make_ham_user hook
+ */
+function bp_core_mark_user_ham_admin( $user_id ) {
+	bp_core_process_spammer_status( $user_id, 'ham' );
+}
+add_action( 'make_ham_user', 'bp_core_mark_user_ham_admin' );
+
+/**
+ * Checks if the user has been marked as a spammer.
+ *
+ * @package BuddyPress Core
+ * @param int $user_id int The id for the user.
+ * @return bool True if spammer, False if not.
+ */
+function bp_is_user_spammer( $user_id = 0 ) {
+
+	// No user to check
+	if ( empty( $user_id ) )
+		return false;
+
+	$bp = buddypress();
+
+	// Assume user is not spam
+	$is_spammer = false;
+
+	// Setup our user
+	$user = false;
+
+	// Get locally-cached data if available
+	switch ( $user_id ) {
+		case bp_loggedin_user_id() :
+			$user = ! empty( $bp->loggedin_user->userdata ) ? $bp->loggedin_user->userdata : false;
+			break;
+
+		case bp_displayed_user_id() :
+			$user = ! empty( $bp->displayed_user->userdata ) ? $bp->displayed_user->userdata : false;
+			break;
+	}
+
+	// Manually get userdata if still empty
+	if ( empty( $user ) ) {
+		$user = get_userdata( $user_id );
+	}
+
+	// No user found
+	if ( empty( $user ) ) {
+		$is_spammer = false;
+
+	// User found
+	} else {
+
+		// Check if spam
+		if ( !empty( $user->spam ) )
+			$is_spammer = true;
+
+		if ( 1 == $user->user_status )
+			$is_spammer = true;
+	}
+
+	return apply_filters( 'bp_is_user_spammer', (bool) $is_spammer );
+}
+
+/**
+ * Checks if the user has been marked as deleted.
+ *
+ * @package BuddyPress Core
+ * @param int $user_id int The id for the user.
+ * @return bool True if deleted, False if not.
+ */
+function bp_is_user_deleted( $user_id = 0 ) {
+
+	// No user to check
+	if ( empty( $user_id ) )
+		return false;
+
+	$bp = buddypress();
+
+	// Assume user is not deleted
+	$is_deleted = false;
+
+	// Setup our user
+	$user = false;
+
+	// Get locally-cached data if available
+	switch ( $user_id ) {
+		case bp_loggedin_user_id() :
+			$user = ! empty( $bp->loggedin_user->userdata ) ? $bp->loggedin_user->userdata : false;
+			break;
+
+		case bp_displayed_user_id() :
+			$user = ! empty( $bp->displayed_user->userdata ) ? $bp->displayed_user->userdata : false;
+			break;
+	}
+
+	// Manually get userdata if still empty
+	if ( empty( $user ) ) {
+		$user = get_userdata( $user_id );
+	}
+
+	// No user found
+	if ( empty( $user ) ) {
+		$is_deleted = true;
+
+	// User found
+	} else {
+
+		// Check if deleted
+		if ( !empty( $user->deleted ) )
+			$is_deleted = true;
+
+		if ( 2 == $user->user_status )
+			$is_deleted = true;
+
+	}
+
+	return apply_filters( 'bp_is_user_deleted', (bool) $is_deleted );
+}
+
+/**
+ * Checks if user is active
+ *
+ * @since BuddyPress (1.6)
+ *
+ * @uses is_user_logged_in() To check if user is logged in
+ * @uses bp_loggedin_user_id() To get current user ID
+ * @uses bp_is_user_spammer() To check if user is spammer
+ * @uses bp_is_user_deleted() To check if user is deleted
+ *
+ * @param int $user_id The user ID to check
+ * @return bool True if public, false if not
+ */
+function bp_is_user_active( $user_id = 0 ) {
+
+	// Default to current user
+	if ( empty( $user_id ) && is_user_logged_in() )
+		$user_id = bp_loggedin_user_id();
+
+	// No user to check
+	if ( empty( $user_id ) )
+		return false;
+
+	// Check spam
+	if ( bp_is_user_spammer( $user_id ) )
+		return false;
+
+	// Check deleted
+	if ( bp_is_user_deleted( $user_id ) )
+		return false;
+
+	// Assume true if not spam or deleted
+	return true;
+}
+
+/**
+ * Checks if user is not active.
+ *
+ * @since BuddyPress (1.6)
+ *
+ * @uses is_user_logged_in() To check if user is logged in
+ * @uses bp_get_displayed_user_id() To get current user ID
+ * @uses bp_is_user_active() To check if user is active
+ *
+ * @param int $user_id The user ID to check
+ * @return bool True if inactive, false if active
+ */
+function bp_is_user_inactive( $user_id = 0 ) {
+
+	// Default to current user
+	if ( empty( $user_id ) && is_user_logged_in() )
+		$user_id = bp_loggedin_user_id();
+
+	// No user to check
+	if ( empty( $user_id ) )
+		return false;
+
+	// Return the inverse of active
+	return !bp_is_user_active( $user_id );
+}
+
+/**
+ * Update a user's last activity
+ *
+ * @since BuddyPress (1.9)
+ * @param int $user_id ID of the user being updated
+ * @param string $time Time of last activity, in 'Y-m-d H:i:s' format
+ * @return bool True on success
+ */
+function bp_update_user_last_activity( $user_id = 0, $time = '' ) {
+	// Fall back on current user
+	if ( empty( $user_id ) ) {
+		$user_id = bp_loggedin_user_id();
+	}
+
+	// Bail if the user id is 0, as there's nothing to update
+	if ( empty( $user_id ) ) {
+		return false;
+	}
+
+	// Fall back on current time
+	if ( empty( $time ) ) {
+		$time = bp_core_current_time();
+	}
+
+	return bp_update_user_meta( $user_id, 'last_activity', $time );
+}
+
+/**
+ * Get the last activity for a given user
+ *
+ * @param int $user_id The ID of the user
+ * @return string Time of last activity, in 'Y-m-d H:i:s' format, or an empty
+ *   string if none is found
+ */
+function bp_get_user_last_activity( $user_id = 0 ) {
+	// Fall back on current user
+	if ( empty( $user_id ) ) {
+		$user_id = bp_loggedin_user_id();
+	}
+
+	$activity = bp_get_user_meta( $user_id, 'last_activity', true );
+
+	return apply_filters( 'bp_get_user_last_activity', $activity, $user_id );
+}
+
+/**
+ * Fetch every post that is authored by the given user for the current blog.
+ *
+ * @package BuddyPress Core
+ * @global $wpdb WordPress user data for the current logged in user.
+ * @return array of post ids.
+ */
+function bp_core_get_all_posts_for_user( $user_id = 0 ) {
+	global $wpdb;
+
+	if ( empty( $user_id ) )
+		$user_id = bp_displayed_user_id();
+
+	return apply_filters( 'bp_core_get_all_posts_for_user', $wpdb->get_col( $wpdb->prepare( "SELECT ID FROM {$wpdb->posts} WHERE post_author = %d AND post_status = 'publish' AND post_type = 'post'", $user_id ) ) );
+}
+
+/**
+ * Allows a user to completely remove their account from the system
+ *
+ * @package BuddyPress Core
+ * @uses wpmu_delete_user() Deletes a user from the system on multisite installs.
+ * @uses wp_delete_user() Deletes a user from the system on singlesite installs.
+ */
+function bp_core_delete_account( $user_id = 0 ) {
+
+	// Use logged in user ID if none is passed
+	if ( empty( $user_id ) )
+		$user_id = bp_loggedin_user_id();
+
+	// Bail if account deletion is disabled
+	if ( bp_disable_account_deletion() )
+		return false;
+
+	// Site admins cannot be deleted
+	if ( is_super_admin( $user_id ) )
+		return false;
+
+	// Extra checks if user is not deleting themselves
+	if ( bp_loggedin_user_id() !== absint( $user_id ) ) {
+
+		// Bail if current user cannot delete any users
+		if ( ! bp_current_user_can( 'delete_users' ) ) {
+			return false;
+		}
+
+		// Bail if current user cannot delete this user
+		if ( ! current_user_can_for_blog( bp_get_root_blog_id(), 'delete_user', $user_id ) ) {
+			return false;
+		}
+	}
+
+	do_action( 'bp_core_pre_delete_account', $user_id );
+
+	// Specifically handle multi-site environment
+	if ( is_multisite() ) {
+		require_once( ABSPATH . '/wp-admin/includes/ms.php'   );
+		require_once( ABSPATH . '/wp-admin/includes/user.php' );
+
+		$retval = wpmu_delete_user( $user_id );
+
+	// Single site user deletion
+	} else {
+		require_once( ABSPATH . '/wp-admin/includes/user.php' );
+		$retval = wp_delete_user( $user_id );
+	}
+
+	do_action( 'bp_core_deleted_account', $user_id );
+
+	return $retval;
+}
+
+/**
+ * Delete a user's avatar when the user is deleted.
+ *
+ * @since BuddyPress (1.9.0)
+ *
+ * @param int $user_id ID of the user who is about to be deleted.
+ * @return bool True on success, false on failure.
+ */
+function bp_core_delete_avatar_on_user_delete( $user_id ) {
+	return bp_core_delete_existing_avatar( array(
+		'item_id' => $user_id,
+		'object'  => 'user',
+	) );
+}
+add_action( 'wpmu_delete_user', 'bp_core_delete_avatar_on_user_delete' );
+add_action( 'delete_user', 'bp_core_delete_avatar_on_user_delete' );
+
+/**
+ * Localization safe ucfirst() support.
+ *
+ * @package BuddyPress Core
+ */
+function bp_core_ucfirst( $str ) {
+	if ( function_exists( 'mb_strtoupper' ) && function_exists( 'mb_substr' ) ) {
+		$fc = mb_strtoupper( mb_substr( $str, 0, 1 ) );
+		return $fc.mb_substr( $str, 1 );
+	} else {
+		return ucfirst( $str );
+	}
+}
+
+/**
+ * When a user logs in, check if they have been marked as a spammer. If yes then simply
+ * redirect them to the home page and stop them from logging in.
+ *
+ * @param WP_User|WP_Error $user Either the WP_User object or the WP_Error object
+ * @return WP_User|WP_Error If the user is not a spammer, return the WP_User object. Otherwise a new WP_Error object.
+ *
+ * @since BuddyPress (1.1.2)
+ */
+function bp_core_boot_spammer( $user ) {
+	// check to see if the $user has already failed logging in, if so return $user as-is
+	if ( is_wp_error( $user ) || empty( $user ) )
+		return $user;
+
+	// the user exists; now do a check to see if the user is a spammer
+	// if the user is a spammer, stop them in their tracks!
+	if ( is_a( $user, 'WP_User' ) && ( ( is_multisite() && (int) $user->spam ) || 1 == $user->user_status ) )
+		return new WP_Error( 'invalid_username', __( '<strong>ERROR</strong>: Your account has been marked as a spammer.', 'buddypress' ) );
+
+	// user is good to go!
+	return $user;
+}
+add_filter( 'authenticate', 'bp_core_boot_spammer', 30 );
+
+/**
+ * Deletes usermeta for the user when the user is deleted.
+ *
+ * @package BuddyPress Core
+ * @param int $user_id The user id for the user to delete usermeta for
+ * @uses bp_delete_user_meta() deletes a row from the wp_usermeta table based on meta_key
+ */
+function bp_core_remove_data( $user_id ) {
+
+	// Remove usermeta
+	bp_delete_user_meta( $user_id, 'last_activity' );
+
+	// Flush the cache to remove the user from all cached objects
+	wp_cache_flush();
+}
+add_action( 'wpmu_delete_user',  'bp_core_remove_data' );
+add_action( 'delete_user',       'bp_core_remove_data' );
+add_action( 'bp_make_spam_user', 'bp_core_remove_data' );
+
+function bp_core_can_edit_settings() {
+	if ( bp_is_my_profile() )
+		return true;
+
+	if ( bp_current_user_can( 'bp_moderate' ) || current_user_can( 'edit_users' ) )
+		return true;
+
+	return false;
+}
+
+/** Sign-up *******************************************************************/
+
+/**
+ * Flush illegal names by getting and setting 'illegal_names' site option
+ */
+function bp_core_flush_illegal_names() {
+	$illegal_names = get_site_option( 'illegal_names' );
+	update_site_option( 'illegal_names', $illegal_names );
+}
+
+/**
+ * Filter the illegal_names site option and make sure it includes a few
+ * specific BuddyPress and Multi-site slugs
+ *
+ * @param array|string $value Illegal names from field
+ * @param array|string $oldvalue The value as it is currently
+ * @return array Merged and unique array of illegal names
+ */
+function bp_core_get_illegal_names( $value = '', $oldvalue = '' ) {
+
+	// Make sure $value is array
+	if ( empty( $value ) ) {
+		$db_illegal_names = array();
+	}
+
+	if ( is_array( $value ) ) {
+		$db_illegal_names = $value;
+	} elseif ( is_string( $value ) ) {
+		$db_illegal_names = explode( ' ', $value );
+	}
+
+	// Add the core components' slugs to the banned list even if their components aren't active.
+	$bp_component_slugs = array(
+		'groups',
+		'members',
+		'forums',
+		'blogs',
+		'activity',
+		'profile',
+		'friends',
+		'search',
+		'settings',
+		'notifications',
+		'register',
+		'activate'
+	);
+
+	// Core constants
+	$slug_constants = array(
+		'BP_GROUPS_SLUG',
+		'BP_MEMBERS_SLUG',
+		'BP_FORUMS_SLUG',
+		'BP_BLOGS_SLUG',
+		'BP_ACTIVITY_SLUG',
+		'BP_XPROFILE_SLUG',
+		'BP_FRIENDS_SLUG',
+		'BP_SEARCH_SLUG',
+		'BP_SETTINGS_SLUG',
+		'BP_NOTIFICATIONS_SLUG',
+		'BP_REGISTER_SLUG',
+		'BP_ACTIVATION_SLUG',
+	);
+	foreach( $slug_constants as $constant ) {
+		if ( defined( $constant ) ) {
+			$bp_component_slugs[] = constant( $constant );
+		}
+	}
+
+	// Add our slugs to the array and allow them to be filtered
+	$filtered_illegal_names = apply_filters( 'bp_core_illegal_usernames', array_merge( array( 'www', 'web', 'root', 'admin', 'main', 'invite', 'administrator' ), $bp_component_slugs ) );
+
+	// Merge the arrays together
+	$merged_names           = array_merge( (array) $filtered_illegal_names, (array) $db_illegal_names );
+
+	// Remove duplicates
+	$illegal_names          = array_unique( (array) $merged_names );
+
+	return apply_filters( 'bp_core_illegal_names', $illegal_names );
+}
+add_filter( 'pre_update_site_option_illegal_names', 'bp_core_get_illegal_names', 10, 2 );
+
+/**
+ * Check that an email address is valid for use
+ *
+ * Performs the following checks:
+ *   - Is the email address well-formed?
+ *   - Is the email address already used?
+ *   - If there's an email domain blacklist, is the current domain on it?
+ *   - If there's an email domain whitelest, is the current domain on it?
+ *
+ * @since BuddyPress (1.6.2)
+ *
+ * @param string $user_email The email being checked
+ * @return bool|array True if the address passes all checks; otherwise an array
+ *   of error codes
+ */
+function bp_core_validate_email_address( $user_email ) {
+	$errors = array();
+
+	$user_email = sanitize_email( $user_email );
+
+	// Is the email well-formed?
+	if ( ! is_email( $user_email ) )
+		$errors['invalid'] = 1;
+
+	// Is the email on the Banned Email Domains list?
+	// Note: This check only works on Multisite
+	if ( function_exists( 'is_email_address_unsafe' ) && is_email_address_unsafe( $user_email ) )
+		$errors['domain_banned'] = 1;
+
+	// Is the email on the Limited Email Domains list?
+	// Note: This check only works on Multisite
+	$limited_email_domains = get_site_option( 'limited_email_domains' );
+	if ( is_array( $limited_email_domains ) && empty( $limited_email_domains ) == false ) {
+		$emaildomain = substr( $user_email, 1 + strpos( $user_email, '@' ) );
+		if ( ! in_array( $emaildomain, $limited_email_domains ) ) {
+			$errors['domain_not_allowed'] = 1;
+		}
+	}
+
+	// Is the email alreday in use?
+	if ( email_exists( $user_email ) )
+		$errors['in_use'] = 1;
+
+	$retval = ! empty( $errors ) ? $errors : true;
+
+	return $retval;
+}
+
+/**
+ * Add the appropriate errors to a WP_Error object, given results of a validation test
+ *
+ * Functions like bp_core_validate_email_address() return a structured array
+ * of error codes. bp_core_add_validation_error_messages() takes this array and
+ * parses, adding the appropriate error messages to the WP_Error object.
+ *
+ * @since BuddyPress (1.7)
+ * @see bp_core_validate_email_address()
+ *
+ * @param WP_Error $errors WP_Error object
+ * @param array $validation_results The return value of a validation function
+ *   like bp_core_validate_email_address()
+ */
+function bp_core_add_validation_error_messages( WP_Error $errors, $validation_results ) {
+	if ( ! empty( $validation_results['invalid'] ) )
+		$errors->add( 'user_email', __( 'Please check your email address.', 'buddypress' ) );
+
+	if ( ! empty( $validation_results['domain_banned'] ) )
+		$errors->add( 'user_email',  __( 'Sorry, that email address is not allowed!', 'buddypress' ) );
+
+	if ( ! empty( $validation_results['domain_not_allowed'] ) )
+		$errors->add( 'user_email', __( 'Sorry, that email address is not allowed!', 'buddypress' ) );
+
+	if ( ! empty( $validation_results['in_use'] ) )
+		$errors->add( 'user_email', __( 'Sorry, that email address is already used!', 'buddypress' ) );
+}
+
+/**
+ * Validate a user name and email address when creating a new user.
+ *
+ * @param string $user_name Username to validate
+ * @param string $user_email Email address to validate
+ * @return array Results of user validation including errors, if any
+ */
+function bp_core_validate_user_signup( $user_name, $user_email ) {
+
+	// Make sure illegal names include BuddyPress slugs and values
+	bp_core_flush_illegal_names();
+
+	// WordPress Multisite has its own validation. Use it, so that we
+	// properly mirror restrictions on username, etc.
+	if ( function_exists( 'wpmu_validate_user_signup' ) ) {
+		$result = wpmu_validate_user_signup( $user_name, $user_email );
+
+	// When not running Multisite, we perform our own validation. What
+	// follows reproduces much of the logic of wpmu_validate_user_signup(),
+	// minus the multisite-specific restrictions on user_login
+	} else {
+		$errors = new WP_Error();
+
+		// Apply any user_login filters added by BP or other plugins before validating
+		$user_name = apply_filters( 'pre_user_login', $user_name );
+
+		// User name can't be empty
+		if ( empty( $user_name ) ) {
+			$errors->add( 'user_name', __( 'Please enter a username', 'buddypress' ) );
+		}
+
+		// user name can't be on the blacklist
+		$illegal_names = get_site_option( 'illegal_names' );
+		if ( in_array( $user_name, (array) $illegal_names ) ) {
+			$errors->add( 'user_name', __( 'That username is not allowed', 'buddypress' ) );
+		}
+
+		// User name must pass WP's validity check
+		if ( ! validate_username( $user_name ) ) {
+			$errors->add( 'user_name', __( 'Usernames can contain only letters, numbers, ., -, and @', 'buddypress' ) );
+		}
+
+		// Minimum of 4 characters
+		if ( strlen( $user_name ) < 4 ) {
+			$errors->add( 'user_name',  __( 'Username must be at least 4 characters', 'buddypress' ) );
+		}
+
+		// No underscores. @todo Why not?
+		if ( false !== strpos( ' ' . $user_name, '_' ) ) {
+			$errors->add( 'user_name', __( 'Sorry, usernames may not contain the character "_"!', 'buddypress' ) );
+		}
+
+		// No usernames that are all numeric. @todo Why?
+		$match = array();
+		preg_match( '/[0-9]*/', $user_name, $match );
+		if ( $match[0] == $user_name ) {
+			$errors->add( 'user_name', __( 'Sorry, usernames must have letters too!', 'buddypress' ) );
+		}
+
+		// Check if the username has been used already.
+		if ( username_exists( $user_name ) ) {
+			$errors->add( 'user_name', __( 'Sorry, that username already exists!', 'buddypress' ) );
+		}
+
+		// Validate the email address and process the validation results into
+		// error messages
+		$validate_email = bp_core_validate_email_address( $user_email );
+		bp_core_add_validation_error_messages( $errors, $validate_email );
+
+		// Assemble the return array
+		$result = array(
+			'user_name'  => $user_name,
+			'user_email' => $user_email,
+			'errors'     => $errors,
+		);
+
+		// Apply WPMU legacy filter
+		$result = apply_filters( 'wpmu_validate_user_signup', $result );
+	}
+
+ 	return apply_filters( 'bp_core_validate_user_signup', $result );
+}
+
+function bp_core_validate_blog_signup( $blog_url, $blog_title ) {
+	if ( !is_multisite() || !function_exists( 'wpmu_validate_blog_signup' ) )
+		return false;
+
+	return apply_filters( 'bp_core_validate_blog_signup', wpmu_validate_blog_signup( $blog_url, $blog_title ) );
+}
+
+function bp_core_signup_user( $user_login, $user_password, $user_email, $usermeta ) {
+	global $bp, $wpdb;
+
+	// Multisite installs have their own install procedure
+	if ( is_multisite() ) {
+		wpmu_signup_user( $user_login, $user_email, $usermeta );
+
+		// On multisite, the user id is not created until the user activates the account
+		// but we need to cast $user_id to pass to the filters
+		$user_id = false;
+
+	} else {
+		$errors = new WP_Error();
+
+		$user_id = wp_insert_user( array(
+			'user_login' => $user_login,
+			'user_pass' => $user_password,
+			'display_name' => sanitize_title( $user_login ),
+			'user_email' => $user_email
+		) );
+
+		if ( is_wp_error( $user_id ) || empty( $user_id ) ) {
+			$errors->add( 'registerfail', sprintf( __('<strong>ERROR</strong>: Couldn&#8217;t register you... please contact the <a href="mailto:%s">webmaster</a> !', 'buddypress' ), bp_get_option( 'admin_email' ) ) );
+			return $errors;
+		}
+
+		// Update the user status to '2' which we will use as 'not activated' (0 = active, 1 = spam, 2 = not active)
+		$wpdb->query( $wpdb->prepare( "UPDATE {$wpdb->users} SET user_status = 2 WHERE ID = %d", $user_id ) );
+
+		// Set any profile data
+		if ( bp_is_active( 'xprofile' ) ) {
+			if ( !empty( $usermeta['profile_field_ids'] ) ) {
+				$profile_field_ids = explode( ',', $usermeta['profile_field_ids'] );
+
+				foreach( (array) $profile_field_ids as $field_id ) {
+					if ( empty( $usermeta["field_{$field_id}"] ) )
+						continue;
+
+					$current_field = $usermeta["field_{$field_id}"];
+					xprofile_set_field_data( $field_id, $user_id, $current_field );
+
+					// Save the visibility level
+					$visibility_level = !empty( $usermeta['field_' . $field_id . '_visibility'] ) ? $usermeta['field_' . $field_id . '_visibility'] : 'public';
+					xprofile_set_field_visibility_level( $field_id, $user_id, $visibility_level );
+				}
+			}
+		}
+	}
+	$bp->signup->username = $user_login;
+
+	/***
+	 * Now generate an activation key and send an email to the user so they can activate their
+	 * account and validate their email address. Multisite installs send their own email, so
+	 * this is only for single blog installs.
+	 *
+	 * To disable sending activation emails you can user the filter
+	 * 'bp_core_signup_send_activation_key' and return false. Note that this will only disable
+	 * the email - a key will still be generated, and the account must still be activated
+	 * before use.
+	 */
+	if ( !is_multisite() ) {
+		$activation_key = wp_hash( $user_id );
+		update_user_meta( $user_id, 'activation_key', $activation_key );
+
+		if ( apply_filters( 'bp_core_signup_send_activation_key', true ) ) {
+			bp_core_signup_send_validation_email( $user_id, $user_email, $activation_key );
+		}
+	}
+
+	do_action( 'bp_core_signup_user', $user_id, $user_login, $user_password, $user_email, $usermeta );
+
+	return $user_id;
+}
+
+function bp_core_signup_blog( $blog_domain, $blog_path, $blog_title, $user_name, $user_email, $usermeta ) {
+	if ( !is_multisite() || !function_exists( 'wpmu_signup_blog' ) )
+		return false;
+
+	return apply_filters( 'bp_core_signup_blog', wpmu_signup_blog( $blog_domain, $blog_path, $blog_title, $user_name, $user_email, $usermeta ) );
+}
+
+function bp_core_activate_signup( $key ) {
+	global $wpdb;
+
+	$user = false;
+
+	// Multisite installs have their own activation routine
+	if ( is_multisite() ) {
+		$user = wpmu_activate_signup( $key );
+
+		// If there were errors, add a message and redirect
+		if ( !empty( $user->errors ) ) {
+			return $user;
+		}
+
+		$user_id = $user['user_id'];
+
+		// Set any profile data
+		if ( bp_is_active( 'xprofile' ) ) {
+			if ( !empty( $user['meta']['profile_field_ids'] ) ) {
+				$profile_field_ids = explode( ',', $user['meta']['profile_field_ids'] );
+
+				foreach( (array) $profile_field_ids as $field_id ) {
+					$current_field = isset( $user['meta']["field_{$field_id}"] ) ? $user['meta']["field_{$field_id}"] : false;
+
+					if ( !empty( $current_field ) )
+						xprofile_set_field_data( $field_id, $user_id, $current_field );
+
+					// Save the visibility level
+					$visibility_level = !empty( $user['meta']['field_' . $field_id . '_visibility'] ) ? $user['meta']['field_' . $field_id . '_visibility'] : 'public';
+					xprofile_set_field_visibility_level( $field_id, $user_id, $visibility_level );
+				}
+			}
+		}
+	} else {
+
+		// Get the user_id based on the $key
+		$user_id = $wpdb->get_var( $wpdb->prepare( "SELECT user_id FROM {$wpdb->usermeta} WHERE meta_key = 'activation_key' AND meta_value = %s", $key ) );
+
+		if ( empty( $user_id ) )
+			return new WP_Error( 'invalid_key', __( 'Invalid activation key', 'buddypress' ) );
+
+		// Change the user's status so they become active
+		if ( !$wpdb->query( $wpdb->prepare( "UPDATE {$wpdb->users} SET user_status = 0 WHERE ID = %d", $user_id ) ) )
+			return new WP_Error( 'invalid_key', __( 'Invalid activation key', 'buddypress' ) );
+
+		// Notify the site admin of a new user registration
+		wp_new_user_notification( $user_id );
+
+		// Remove the activation key meta
+		delete_user_meta( $user_id, 'activation_key' );
+	}
+
+	// Update the display_name
+	wp_update_user( array( 'ID' => $user_id, 'display_name' => bp_core_get_user_displayname( $user_id ) ) );
+
+	// Set the password on multisite installs
+	if ( is_multisite() && !empty( $user['meta']['password'] ) )
+		$wpdb->query( $wpdb->prepare( "UPDATE {$wpdb->users} SET user_pass = %s WHERE ID = %d", $user['meta']['password'], $user_id ) );
+
+	do_action( 'bp_core_activated_user', $user_id, $key, $user );
+
+	return $user_id;
+}
+
+function bp_core_new_user_activity( $user ) {
+	if ( empty( $user ) || !bp_is_active( 'activity' ) )
+		return false;
+
+	if ( is_array( $user ) )
+		$user_id = $user['user_id'];
+	else
+		$user_id = $user;
+
+	if ( empty( $user_id ) )
+		return false;
+
+	$userlink = bp_core_get_userlink( $user_id );
+
+	bp_activity_add( array(
+		'user_id'   => $user_id,
+		'action'    => apply_filters( 'bp_core_activity_registered_member_action', sprintf( __( '%s became a registered member', 'buddypress' ), $userlink ), $user_id ),
+		'component' => 'xprofile',
+		'type'      => 'new_member'
+	) );
+}
+add_action( 'bp_core_activated_user', 'bp_core_new_user_activity' );
+
+function bp_core_map_user_registration( $user_id ) {
+
+	// Only map data when the site admin is adding users, not on registration.
+	if ( !is_admin() )
+		return false;
+
+	// Add the user's fullname to Xprofile
+	if ( bp_is_active( 'xprofile' ) ) {
+		$firstname = bp_get_user_meta( $user_id, 'first_name', true );
+		$lastname = ' ' . bp_get_user_meta( $user_id, 'last_name', true );
+		$name = $firstname . $lastname;
+
+		if ( empty( $name ) || ' ' == $name )
+			$name = bp_get_user_meta( $user_id, 'nickname', true );
+
+		xprofile_set_field_data( 1, $user_id, $name );
+	}
+}
+add_action( 'user_register', 'bp_core_map_user_registration' );
+
+function bp_core_signup_avatar_upload_dir() {
+	global $bp;
+
+	if ( !$bp->signup->avatar_dir )
+		return false;
+
+	$path  = bp_core_avatar_upload_path() . '/avatars/signups/' . $bp->signup->avatar_dir;
+	$newbdir = $path;
+
+	if ( !file_exists( $path ) )
+		@wp_mkdir_p( $path );
+
+	$newurl = bp_core_avatar_url() . '/avatars/signups/' . $bp->signup->avatar_dir;
+	$newburl = $newurl;
+	$newsubdir = '/avatars/signups/' . $bp->signup->avatar_dir;
+
+	return apply_filters( 'bp_core_signup_avatar_upload_dir', array( 'path' => $path, 'url' => $newurl, 'subdir' => $newsubdir, 'basedir' => $newbdir, 'baseurl' => $newburl, 'error' => false ) );
+}
+
+function bp_core_signup_send_validation_email( $user_id, $user_email, $key ) {
+	$activate_url = bp_get_activation_page() ."?key=$key";
+	$activate_url = esc_url( $activate_url );
+
+	$message = sprintf( __( "Thanks for registering! To complete the activation of your account please click the following link:\n\n%1\$s\n\n", 'buddypress' ), $activate_url );
+	$subject = bp_get_email_subject( array( 'text' => __( 'Activate Your Account', 'buddypress' ) ) );
+
+	// Send the message
+	$to      = apply_filters( 'bp_core_signup_send_validation_email_to',     $user_email, $user_id                );
+	$subject = apply_filters( 'bp_core_signup_send_validation_email_subject', $subject,    $user_id                );
+	$message = apply_filters( 'bp_core_signup_send_validation_email_message', $message,    $user_id, $activate_url );
+
+	wp_mail( $to, $subject, $message );
+
+	do_action( 'bp_core_sent_user_validation_email', $subject, $message, $user_id, $user_email, $key );
+}
+
+/**
+ * Stop user accounts logging in that have not been activated yet (user_status = 2).
+ *
+ * Note: This is only applicable for single site WordPress installs.
+ * Multisite has their own DB table - 'wp_signups' - dedicated for unactivated users.
+ * See {@link wpmu_signup_user()} and {@link wpmu_validate_user_signup()}.
+ *
+ * @param WP_User|WP_Error $user Either the WP_User object or the WP_Error object
+ * @return WP_User|WP_Error If the user is not a spammer, return the WP_User object. Otherwise a new WP_Error object.
+ *
+ * @since BuddyPress (1.2.2)
+ */
+function bp_core_signup_disable_inactive( $user ) {
+	// check to see if the $user has already failed logging in, if so return $user as-is
+	if ( is_wp_error( $user ) || empty( $user ) )
+		return $user;
+
+	// the user exists; now do a check to see if the user has activated their account or not
+	// NOTE: this is only applicable for single site WordPress installs!
+	// if unactivated, stop the login now!
+	if ( is_a( $user, 'WP_User' ) && 2 == $user->user_status )
+		return new WP_Error( 'bp_account_not_activated', __( '<strong>ERROR</strong>: Your account has not been activated. Check your email for the activation link.', 'buddypress' ) );
+
+	// user has activated their account! all clear!
+	return $user;
+}
+add_filter( 'authenticate', 'bp_core_signup_disable_inactive', 30 );
+
+/**
+ * Kill the wp-signup.php if custom registration signup templates are present
+ */
+function bp_core_wpsignup_redirect() {
+
+	// Bail in admin or if custom signup page is broken
+	if ( is_admin() || ! bp_has_custom_signup_page() )
+		return;
+
+	$action = !empty( $_GET['action'] ) ? $_GET['action'] : '';
+
+	// Not at the WP core signup page and action is not register
+	if ( ! empty( $_SERVER['SCRIPT_NAME'] ) && false === strpos( $_SERVER['SCRIPT_NAME'], 'wp-signup.php' ) && ( 'register' != $action ) )
+		return;
+
+	bp_core_redirect( bp_get_signup_page() );
+}
+add_action( 'bp_init', 'bp_core_wpsignup_redirect' );
+
+/**
+ * Stop a logged-in user who is marked as a spammer.
+ *
+ * When an admin marks a live user as a spammer, that user can still surf
+ * around and cause havoc on the site until that person is logged out.
+ *
+ * This code checks to see if a logged-in user is marked as a spammer.  If so,
+ * we redirect the user back to wp-login.php with the 'reauth' parameter.
+ *
+ * This clears the logged-in spammer's cookies and will ask the spammer to
+ * reauthenticate.
+ *
+ * Note: A spammer cannot log back in - {@see bp_core_boot_spammer()}.
+ *
+ * Runs on 'bp_init' at priority 5 so the members component globals are setup
+ * before we do our spammer checks.
+ *
+ * This is important as the $bp->loggedin_user object is setup at priority 4.
+ *
+ * @since BuddyPress (v1.8)
+ */
+function bp_stop_live_spammer() {
+	// if we're on the login page, stop now to prevent redirect loop
+	$is_login = false;
+	if ( isset( $_GLOBALS['pagenow'] ) && false !== strpos( $GLOBALS['pagenow'], 'wp-login.php' ) ) {
+		$is_login = true;
+	} else if ( isset( $_SERVER['SCRIPT_NAME'] ) && false !== strpos( $_SERVER['SCRIPT_NAME'], 'wp-login.php' ) ) {
+		$is_login = true;
+	}
+
+	if ( $is_login ) {
+		return;
+	}
+
+	// user isn't logged in, so stop!
+	if ( ! is_user_logged_in() ) {
+		return;
+	}
+
+	// if spammer, redirect to wp-login.php and reauthorize
+	if ( bp_is_user_spammer( bp_loggedin_user_id() ) ) {
+		// setup login args
+		$args = array(
+			// custom action used to throw an error message
+			'action' => 'bp-spam',
+
+			// reauthorize user to login
+			'reauth' => 1
+		);
+
+		// setup login URL
+		$login_url = apply_filters( 'bp_live_spammer_redirect', add_query_arg( $args, wp_login_url() ) );
+
+		// redirect user to login page
+		wp_redirect( $login_url );
+		die();
+	}
+}
+add_action( 'bp_init', 'bp_stop_live_spammer', 5 );
+
+/**
+ * Show a custom error message when a logged-in user is marked as a spammer.
+ *
+ * @since BuddyPress (v1.8)
+ */
+function bp_live_spammer_login_error() {
+	global $error;
+
+	$error = __( '<strong>ERROR</strong>: Your account has been marked as a spammer.', 'buddypress' );
+
+	// shake shake shake!
+	add_action( 'login_head', 'wp_shake_js', 12 );
+}
+add_action( 'login_form_bp-spam', 'bp_live_spammer_login_error' );
Index: /tags/1.9/bp-members/bp-members-loader.php
===================================================================
--- /tags/1.9/bp-members/bp-members-loader.php	(revision 7684)
+++ /tags/1.9/bp-members/bp-members-loader.php	(revision 7684)
@@ -0,0 +1,220 @@
+<?php
+/**
+ * BuddyPress Member Loader
+ *
+ * A members component to help contain all of the user specific slugs
+ *
+ * @package BuddyPress
+ * @subpackage Members
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+class BP_Members_Component extends BP_Component {
+
+	/**
+	 * Start the members component creation process
+	 *
+	 * @since BuddyPress (1.5)
+	 */
+	function __construct() {
+		parent::start(
+			'members',
+			__( 'Members', 'buddypress' ),
+			BP_PLUGIN_DIR,
+			array(
+				'adminbar_myaccount_order' => 20
+			)
+		);
+	}
+
+	/**
+	 * Include files
+	 *
+	 * @global BuddyPress $bp The one true BuddyPress instance
+	 */
+	public function includes( $includes = array() ) {
+		$includes = array(
+			'actions',
+			'filters',
+			'screens',
+			'template',
+			'buddybar',
+			'adminbar',
+			'functions',
+			'notifications',
+		);
+		parent::includes( $includes );
+	}
+
+	/**
+	 * Setup globals
+	 *
+	 * The BP_MEMBERS_SLUG constant is deprecated, and only used here for
+	 * backwards compatibility.
+	 *
+	 * @since BuddyPress (1.5)
+	 */
+	public function setup_globals( $args = array() ) {
+		$bp = buddypress();
+
+		// Define a slug, if necessary
+		if ( !defined( 'BP_MEMBERS_SLUG' ) )
+			define( 'BP_MEMBERS_SLUG', $this->id );
+
+		parent::setup_globals( array(
+			'slug'          => BP_MEMBERS_SLUG,
+			'root_slug'     => isset( $bp->pages->members->slug ) ? $bp->pages->members->slug : BP_MEMBERS_SLUG,
+			'has_directory' => true,
+			'search_string' => __( 'Search Members...', 'buddypress' ),
+		) );
+
+		/** Logged in user ****************************************************/
+
+		// Fetch the full name for the logged in user
+		$bp->loggedin_user->fullname       = bp_core_get_user_displayname( bp_loggedin_user_id() );
+
+		// Hits the DB on single WP installs so get this separately
+		$bp->loggedin_user->is_super_admin = $bp->loggedin_user->is_site_admin = is_super_admin( bp_loggedin_user_id() );
+
+		// The domain for the user currently logged in. eg: http://domain.com/members/andy
+		$bp->loggedin_user->domain         = bp_core_get_user_domain( bp_loggedin_user_id() );
+
+		// The core userdata of the user who is currently logged in.
+		$bp->loggedin_user->userdata       = bp_core_get_core_userdata( bp_loggedin_user_id() );
+
+		/** Displayed user ****************************************************/
+
+		// The domain for the user currently being displayed
+		$bp->displayed_user->domain   = bp_core_get_user_domain( bp_displayed_user_id() );
+
+		// The core userdata of the user who is currently being displayed
+		$bp->displayed_user->userdata = bp_core_get_core_userdata( bp_displayed_user_id() );
+
+		// Fetch the full name displayed user
+		$bp->displayed_user->fullname = bp_core_get_user_displayname( bp_displayed_user_id() );
+
+		/** Profiles Fallback *************************************************/
+
+		if ( !bp_is_active( 'xprofile' ) ) {
+			$bp->profile       = new stdClass;
+			$bp->profile->slug = 'profile';
+			$bp->profile->id   = 'profile';
+		}
+
+		/** Default Profile Component *****************************************/
+
+		if ( !defined( 'BP_DEFAULT_COMPONENT' ) ) {
+			if ( bp_is_active( 'activity' ) && isset( $bp->pages->activity ) ) {
+				$bp->default_component = bp_get_activity_slug();
+			} else {
+				$bp->default_component = ( 'xprofile' === $bp->profile->id ) ? 'profile' : $bp->profile->id;
+			}
+
+		} else {
+			$bp->default_component = BP_DEFAULT_COMPONENT;
+		}
+
+		if ( bp_displayed_user_id() ) {
+			$bp->canonical_stack['base_url'] = bp_displayed_user_domain();
+
+			if ( bp_current_component() ) {
+				$bp->canonical_stack['component'] = bp_current_component();
+			}
+
+			if ( bp_current_action() ) {
+				$bp->canonical_stack['action'] = bp_current_action();
+			}
+
+			if ( !empty( $bp->action_variables ) ) {
+				$bp->canonical_stack['action_variables'] = bp_action_variables();
+			}
+
+			if ( !bp_current_component() ) {
+				$bp->current_component = $bp->default_component;
+			} else if ( bp_is_current_component( $bp->default_component ) && !bp_current_action() ) {
+				// The canonical URL will not contain the default component
+				unset( $bp->canonical_stack['component'] );
+			}
+
+			// if we're on a spammer's profile page, only users with the 'bp_moderate' cap
+			// can view subpages on the spammer's profile
+			//
+			// users without the cap trying to access a spammer's subnav page will get
+			// redirected to the root of the spammer's profile page.  this occurs by
+			// by removing the component in the canonical stack.
+			if ( bp_is_user_spammer( bp_displayed_user_id() ) && ! bp_current_user_can( 'bp_moderate' ) ) {
+				unset( $bp->canonical_stack['component'] );
+			}
+		}
+	}
+
+	/**
+	 * Setup BuddyBar navigation
+	 */
+	public function setup_nav( $main_nav = array(), $sub_nav = array() ) {
+		$bp = buddypress();
+
+		// Add 'Profile' to the main navigation
+		if ( !bp_is_active( 'xprofile' ) ) {
+
+			// Don't set up navigation if there's no user
+			if ( !is_user_logged_in() && !bp_is_user() ) {
+				return;
+			}
+
+			$main_nav = array(
+				'name'                => __( 'Profile', 'buddypress' ),
+				'slug'                => $bp->profile->slug,
+				'position'            => 20,
+				'screen_function'     => 'bp_members_screen_display_profile',
+				'default_subnav_slug' => 'public',
+				'item_css_id'         => $bp->profile->id
+			);
+
+			// User links
+			$user_domain  = bp_displayed_user_domain() ? bp_displayed_user_domain() : bp_loggedin_user_domain();
+			$profile_link = trailingslashit( $user_domain . $bp->profile->slug );
+
+			// Add the subnav items to the profile
+			$sub_nav[] = array(
+				'name'            => __( 'View', 'buddypress' ),
+				'slug'            => 'public',
+				'parent_url'      => $profile_link,
+				'parent_slug'     => $bp->profile->slug,
+				'screen_function' => 'bp_members_screen_display_profile',
+				'position'        => 10
+			);
+
+			parent::setup_nav( $main_nav, $sub_nav );
+		}
+	}
+
+	/**
+	 * Sets up the title for pages and <title>
+	 *
+	 * @global BuddyPress $bp The one true BuddyPress instance
+	 */
+	function setup_title() {
+		$bp = buddypress();
+
+		if ( bp_is_my_profile() ) {
+			$bp->bp_options_title = __( 'You', 'buddypress' );
+		} elseif( bp_is_user() ) {
+			$bp->bp_options_avatar = bp_core_fetch_avatar( array(
+				'item_id' => bp_displayed_user_id(),
+				'type'    => 'thumb',
+				'alt'     => sprintf( __( 'Profile picture of %s', 'buddypress' ), bp_get_displayed_user_fullname() )
+			) );
+			$bp->bp_options_title = bp_get_displayed_user_fullname();
+		}
+
+		parent::setup_title();
+	}
+}
+
+function bp_setup_members() {
+	buddypress()->members = new BP_Members_Component();
+}
+add_action( 'bp_setup_components', 'bp_setup_members', 1 );
Index: /tags/1.9/bp-members/bp-members-notifications.php
===================================================================
--- /tags/1.9/bp-members/bp-members-notifications.php	(revision 7684)
+++ /tags/1.9/bp-members/bp-members-notifications.php	(revision 7684)
@@ -0,0 +1,268 @@
+<?php
+
+/**
+ * BuddyPress Member Notifications
+ *
+ * Backwards compatibility functions and filters used for member notifications.
+ * Use bp-notifications instead.
+ *
+ * @package BuddyPress
+ * @subpackage MembersNotifications
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/**
+ * Add a notification for a specific user, from a specific component
+ *
+ * @deprecated Deprecated since BuddyPress 1.9.0. Use
+ *  bp_notifications_add_notification() instead.
+ *
+ * @since BuddyPress (1.0)
+ * @param string $item_id
+ * @param int $user_id
+ * @param string $component_name
+ * @param string $component_action
+ * @param string $secondary_item_id
+ * @param string $date_notified
+ * @param int $is_new
+ * @return boolean True on success, false on fail
+ */
+function bp_core_add_notification( $item_id, $user_id, $component_name, $component_action, $secondary_item_id = 0, $date_notified = false, $is_new = 1 ) {
+
+	// Bail if notifications is not active
+	if ( ! bp_is_active( 'notifications' ) ) {
+		return false;
+	}
+
+	// Trigger the deprecated function notice
+	_deprecated_function( __FUNCTION__, '1.9', 'bp_notifications_add_notification()' );
+
+	// Notifications must always have a time
+	if ( false === $date_notified ) {
+		$date_notified = bp_core_current_time();
+	}
+
+	// Add the notification
+	return bp_notifications_add_notification( array(
+		'item_id'           => $item_id,
+		'user_id'           => $user_id,
+		'component_name'    => $component_name,
+		'component_action'  => $component_action,
+		'secondary_item_id' => $secondary_item_id,
+		'date_notified'     => $date_notified,
+		'is_new'            => $is_new
+	) );
+}
+
+/**
+ * Delete a specific notification by its ID
+ *
+ * @deprecated Deprecated since BuddyPress 1.9.0. Use
+ *  bp_notifications_delete_notification() instead.
+ *
+ * @since BuddyPress (1.0)
+ * @param int $id
+ * @return boolean True on success, false on fail
+ */
+function bp_core_delete_notification( $id ) {
+
+	// Bail if notifications is not active
+	if ( ! bp_is_active( 'notifications' ) ) {
+		return false;
+	}
+
+	// Trigger the deprecated function notice
+	_deprecated_function( __FUNCTION__, '1.9', 'bp_notifications_delete_notification()' );
+
+	return BP_Notifications_Notification::delete_by_id( $id );
+}
+
+/**
+ * Get a specific notification by its ID
+ *
+ * @deprecated Deprecated since BuddyPress 1.9.0. Use
+ *  bp_notifications_get_notification() instead.
+ *
+ * @since BuddyPress (1.0)
+ * @param int $id
+ * @return BP_Core_Notification
+ */
+function bp_core_get_notification( $id ) {
+
+	// Bail if notifications is not active
+	if ( ! bp_is_active( 'notifications' ) ) {
+		return false;
+	}
+
+	// Trigger the deprecated function notice
+	_deprecated_function( __FUNCTION__, '1.9', 'bp_notifications_get_notification()' );
+
+	return bp_notifications_get_notification( $id );
+}
+
+/**
+ * Get notifications for a specific user
+ *
+ * @deprecated Deprecated since BuddyPress 1.9.0. Use
+ *  bp_notifications_get_notifications_for_user() instead.
+ *
+ * @since BuddyPress (1.0)
+ * @global BuddyPress $bp
+ * @param int $user_id
+ * @param string $format
+ * @return boolean Object or array on success, false on fail
+ */
+function bp_core_get_notifications_for_user( $user_id, $format = 'simple' ) {
+
+	// Bail if notifications is not active
+	if ( ! bp_is_active( 'notifications' ) ) {
+		return false;
+	}
+
+	// Trigger the deprecated function notice
+	_deprecated_function( __FUNCTION__, '1.9', 'bp_notifications_get_notifications_for_user()' );
+
+	$renderable = bp_notifications_get_notifications_for_user( $user_id, $format );
+
+	return apply_filters( 'bp_core_get_notifications_for_user', $renderable, $user_id, $format );
+}
+
+/** Delete ********************************************************************/
+
+/**
+ * Delete notifications for a user by type
+ *
+ * Used when clearing out notifications for a specific component when the user
+ * has visited that component.
+ *
+ * @deprecated Deprecated since BuddyPress 1.9.0. Use
+ *  bp_notifications_delete_notifications_by_type() instead.
+ *
+ * @since BuddyPress (1.0)
+ * @param int $user_id
+ * @param string $component_name
+ * @param string $component_action
+ * @return boolean True on success, false on fail
+ */
+function bp_core_delete_notifications_by_type( $user_id, $component_name, $component_action ) {
+
+	// Bail if notifications is not active
+	if ( ! bp_is_active( 'notifications' ) ) {
+		return false;
+	}
+
+	// Trigger the deprecated function notice
+	_deprecated_function( __FUNCTION__, '1.9', 'bp_notifications_delete_notifications_by_type()' );
+
+	return bp_notifications_delete_notifications_by_type( $user_id, $component_name, $component_action );
+}
+
+/**
+ * Delete notifications for an item ID
+ *
+ * Used when clearing out notifications for a specific component when the user
+ * has visited that component.
+ *
+ * @deprecated Deprecated since BuddyPress 1.9.0. Use
+ *  bp_notifications_delete_notifications_by_item_id() instead.
+ *
+ * @since BuddyPress (1.0)
+ * @param int $user_id
+ * @param string $component_name
+ * @param string $component_action
+ * @return boolean True on success, false on fail
+ */
+function bp_core_delete_notifications_by_item_id( $user_id, $item_id, $component_name, $component_action, $secondary_item_id = false ) {
+
+	// Bail if notifications is not active
+	if ( ! bp_is_active( 'notifications' ) ) {
+		return false;
+	}
+
+	// Trigger the deprecated function notice
+	_deprecated_function( __FUNCTION__, '1.9', 'bp_notifications_delete_notifications_by_item_id()' );
+
+	return bp_notifications_delete_notifications_by_item_id( $user_id, $item_id, $component_name, $component_action, $secondary_item_id );
+}
+
+/**
+ * Delete all notifications for by type
+ *
+ * @deprecated Deprecated since BuddyPress 1.9.0. Use
+ *  bp_notifications_delete_all_notifications_by_type() instead.
+ *
+ * @since BuddyPress (1.0)
+ * @param int $user_id
+ * @param string $component_name
+ * @param string $component_action
+ * @return boolean True on success, false on fail
+ */
+function bp_core_delete_all_notifications_by_type( $item_id, $component_name, $component_action = false, $secondary_item_id = false ) {
+
+	// Bail if notifications is not active
+	if ( ! bp_is_active( 'notifications' ) ) {
+		return false;
+	}
+
+	// Trigger the deprecated function notice
+	_deprecated_function( __FUNCTION__, '1.9', 'bp_notifications_delete_all_notifications_by_type()' );
+
+	bp_notifications_delete_all_notifications_by_type( $item_id, $component_name, $component_action, $secondary_item_id );
+}
+
+/**
+ * Delete all notifications for a user
+ *
+ * Used when clearing out all notifications for a user, whene deleted or spammed
+ *
+ * @deprecated Deprecated since BuddyPress 1.9.0. Use
+ *  bp_notifications_delete_notifications_from_user() instead.
+ *
+ * @since BuddyPress (1.0)
+ * @param int $user_id
+ * @param string $component_name
+ * @param string $component_action
+ * @return boolean True on success, false on fail
+ */
+function bp_core_delete_notifications_from_user( $user_id, $component_name, $component_action ) {
+
+	// Bail if notifications is not active
+	if ( ! bp_is_active( 'notifications' ) ) {
+		return false;
+	}
+
+	// Trigger the deprecated function notice
+	_deprecated_function( __FUNCTION__, '1.9', 'bp_notifications_delete_notifications_from_user()' );
+
+	return bp_notifications_delete_notifications_from_user( $user_id, $component_name, $component_action );
+}
+
+/** Helpers *******************************************************************/
+
+/**
+ * Check if a user has access to a specific notification
+ *
+ * Used before deleting a notification for a user
+ *
+ * @deprecated Deprecated since BuddyPress 1.9.0. Use
+ *  bp_notifications_check_notification_access() instead.
+ *
+ * @since BuddyPress (1.0)
+ * @param int $user_id
+ * @param int $notification_id
+ * @return boolean True on success, false on fail
+ */
+function bp_core_check_notification_access( $user_id, $notification_id ) {
+
+	// Bail if notifications is not active
+	if ( ! bp_is_active( 'notifications' ) ) {
+		return false;
+	}
+
+	// Trigger the deprecated function notice
+	_deprecated_function( __FUNCTION__, '1.9', 'bp_notifications_check_notification_access()' );
+
+	return bp_notifications_check_notification_access( $user_id, $notification_id );
+}
Index: /tags/1.9/bp-members/bp-members-screens.php
===================================================================
--- /tags/1.9/bp-members/bp-members-screens.php	(revision 7684)
+++ /tags/1.9/bp-members/bp-members-screens.php	(revision 7684)
@@ -0,0 +1,568 @@
+<?php
+
+/**
+ * BuddyPress Member Screens
+ *
+ * Handlers for member screens that aren't handled elsewhere
+ *
+ * @package BuddyPress
+ * @subpackage MembersScreens
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/**
+ * Handles the display of the profile page by loading the correct template file.
+ *
+ * @package BuddyPress Members
+ * @uses bp_core_load_template() Looks for and loads a template file within the current member theme (folder/filename)
+ */
+function bp_members_screen_display_profile() {
+	do_action( 'bp_members_screen_display_profile' );
+	bp_core_load_template( apply_filters( 'bp_members_screen_display_profile', 'members/single/home' ) );
+}
+
+/**
+ * Handles the display of the members directory index
+ *
+ * @global object $bp
+ *
+ * @uses bp_is_user()
+ * @uses bp_is_current_component()
+ * @uses do_action()
+ * @uses bp_core_load_template()
+ * @uses apply_filters()
+ */
+function bp_members_screen_index() {
+	if ( !bp_is_user() && bp_is_members_component() ) {
+		bp_update_is_directory( true, 'members' );
+
+		do_action( 'bp_members_screen_index' );
+
+		bp_core_load_template( apply_filters( 'bp_members_screen_index', 'members/index' ) );
+	}
+}
+add_action( 'bp_screens', 'bp_members_screen_index' );
+
+
+function bp_core_screen_signup() {
+	global $bp;
+
+	if ( !bp_is_current_component( 'register' ) )
+		return;
+
+	// Not a directory
+	bp_update_is_directory( false, 'register' );
+
+	// If the user is logged in, redirect away from here
+	if ( is_user_logged_in() ) {
+		if ( bp_is_component_front_page( 'register' ) )
+			$redirect_to = trailingslashit( bp_get_root_domain() . '/' . bp_get_members_root_slug() );
+		else
+			$redirect_to = bp_get_root_domain();
+
+		bp_core_redirect( apply_filters( 'bp_loggedin_register_page_redirect_to', $redirect_to ) );
+
+		return;
+	}
+
+	if ( !isset( $bp->signup ) ) {
+		$bp->signup = new stdClass;
+	}
+
+	$bp->signup->step = 'request-details';
+
+ 	if ( !bp_get_signup_allowed() ) {
+		$bp->signup->step = 'registration-disabled';
+
+	// If the signup page is submitted, validate and save
+	} elseif ( isset( $_POST['signup_submit'] ) && bp_verify_nonce_request( 'bp_new_signup' ) ) {
+
+		// Check the base account details for problems
+		$account_details = bp_core_validate_user_signup( $_POST['signup_username'], $_POST['signup_email'] );
+
+		// If there are errors with account details, set them for display
+		if ( !empty( $account_details['errors']->errors['user_name'] ) )
+			$bp->signup->errors['signup_username'] = $account_details['errors']->errors['user_name'][0];
+
+		if ( !empty( $account_details['errors']->errors['user_email'] ) )
+			$bp->signup->errors['signup_email'] = $account_details['errors']->errors['user_email'][0];
+
+		// Check that both password fields are filled in
+		if ( empty( $_POST['signup_password'] ) || empty( $_POST['signup_password_confirm'] ) )
+			$bp->signup->errors['signup_password'] = __( 'Please make sure you enter your password twice', 'buddypress' );
+
+		// Check that the passwords match
+		if ( ( !empty( $_POST['signup_password'] ) && !empty( $_POST['signup_password_confirm'] ) ) && $_POST['signup_password'] != $_POST['signup_password_confirm'] )
+			$bp->signup->errors['signup_password'] = __( 'The passwords you entered do not match.', 'buddypress' );
+
+		$bp->signup->username = $_POST['signup_username'];
+		$bp->signup->email = $_POST['signup_email'];
+
+		// Now we've checked account details, we can check profile information
+		if ( bp_is_active( 'xprofile' ) ) {
+
+			// Make sure hidden field is passed and populated
+			if ( isset( $_POST['signup_profile_field_ids'] ) && !empty( $_POST['signup_profile_field_ids'] ) ) {
+
+				// Let's compact any profile field info into an array
+				$profile_field_ids = explode( ',', $_POST['signup_profile_field_ids'] );
+
+				// Loop through the posted fields formatting any datebox values then validate the field
+				foreach ( (array) $profile_field_ids as $field_id ) {
+					if ( !isset( $_POST['field_' . $field_id] ) ) {
+						if ( !empty( $_POST['field_' . $field_id . '_day'] ) && !empty( $_POST['field_' . $field_id . '_month'] ) && !empty( $_POST['field_' . $field_id . '_year'] ) )
+							$_POST['field_' . $field_id] = date( 'Y-m-d H:i:s', strtotime( $_POST['field_' . $field_id . '_day'] . $_POST['field_' . $field_id . '_month'] . $_POST['field_' . $field_id . '_year'] ) );
+					}
+
+					// Create errors for required fields without values
+					if ( xprofile_check_is_required_field( $field_id ) && empty( $_POST['field_' . $field_id] ) )
+						$bp->signup->errors['field_' . $field_id] = __( 'This is a required field', 'buddypress' );
+				}
+
+			// This situation doesn't naturally occur so bounce to website root
+			} else {
+				bp_core_redirect( bp_get_root_domain() );
+			}
+		}
+
+		// Finally, let's check the blog details, if the user wants a blog and blog creation is enabled
+		if ( isset( $_POST['signup_with_blog'] ) ) {
+			$active_signup = $bp->site_options['registration'];
+
+			if ( 'blog' == $active_signup || 'all' == $active_signup ) {
+				$blog_details = bp_core_validate_blog_signup( $_POST['signup_blog_url'], $_POST['signup_blog_title'] );
+
+				// If there are errors with blog details, set them for display
+				if ( !empty( $blog_details['errors']->errors['blogname'] ) )
+					$bp->signup->errors['signup_blog_url'] = $blog_details['errors']->errors['blogname'][0];
+
+				if ( !empty( $blog_details['errors']->errors['blog_title'] ) )
+					$bp->signup->errors['signup_blog_title'] = $blog_details['errors']->errors['blog_title'][0];
+			}
+		}
+
+		do_action( 'bp_signup_validate' );
+
+		// Add any errors to the action for the field in the template for display.
+		if ( !empty( $bp->signup->errors ) ) {
+			foreach ( (array) $bp->signup->errors as $fieldname => $error_message ) {
+				// addslashes() and stripslashes() to avoid create_function()
+				// syntax errors when the $error_message contains quotes
+				add_action( 'bp_' . $fieldname . '_errors', create_function( '', 'echo apply_filters(\'bp_members_signup_error_message\', "<div class=\"error\">" . stripslashes( \'' . addslashes( $error_message ) . '\' ) . "</div>" );' ) );
+			}
+		} else {
+			$bp->signup->step = 'save-details';
+
+			// No errors! Let's register those deets.
+			$active_signup = !empty( $bp->site_options['registration'] ) ? $bp->site_options['registration'] : '';
+
+			if ( 'none' != $active_signup ) {
+
+				// Make sure the extended profiles module is enabled
+				if ( bp_is_active( 'xprofile' ) ) {
+					// Let's compact any profile field info into usermeta
+					$profile_field_ids = explode( ',', $_POST['signup_profile_field_ids'] );
+
+					// Loop through the posted fields formatting any datebox values then add to usermeta - @todo This logic should be shared with the same in xprofile_screen_edit_profile()
+					foreach ( (array) $profile_field_ids as $field_id ) {
+						if ( ! isset( $_POST['field_' . $field_id] ) ) {
+
+							if ( ! empty( $_POST['field_' . $field_id . '_day'] ) && ! empty( $_POST['field_' . $field_id . '_month'] ) && ! empty( $_POST['field_' . $field_id . '_year'] ) ) {
+								// Concatenate the values
+								$date_value = $_POST['field_' . $field_id . '_day'] . ' ' . $_POST['field_' . $field_id . '_month'] . ' ' . $_POST['field_' . $field_id . '_year'];
+
+								// Turn the concatenated value into a timestamp
+								$_POST['field_' . $field_id] = date( 'Y-m-d H:i:s', strtotime( $date_value ) );
+							}
+						}
+
+						if ( !empty( $_POST['field_' . $field_id] ) )
+							$usermeta['field_' . $field_id] = $_POST['field_' . $field_id];
+
+						if ( !empty( $_POST['field_' . $field_id . '_visibility'] ) )
+							$usermeta['field_' . $field_id . '_visibility'] = $_POST['field_' . $field_id . '_visibility'];
+					}
+
+					// Store the profile field ID's in usermeta
+					$usermeta['profile_field_ids'] = $_POST['signup_profile_field_ids'];
+				}
+
+				// Hash and store the password
+				$usermeta['password'] = wp_hash_password( $_POST['signup_password'] );
+
+				// If the user decided to create a blog, save those details to usermeta
+				if ( 'blog' == $active_signup || 'all' == $active_signup )
+					$usermeta['public'] = ( isset( $_POST['signup_blog_privacy'] ) && 'public' == $_POST['signup_blog_privacy'] ) ? true : false;
+
+				$usermeta = apply_filters( 'bp_signup_usermeta', $usermeta );
+
+				// Finally, sign up the user and/or blog
+				if ( isset( $_POST['signup_with_blog'] ) && is_multisite() )
+					$wp_user_id = bp_core_signup_blog( $blog_details['domain'], $blog_details['path'], $blog_details['blog_title'], $_POST['signup_username'], $_POST['signup_email'], $usermeta );
+				else
+					$wp_user_id = bp_core_signup_user( $_POST['signup_username'], $_POST['signup_password'], $_POST['signup_email'], $usermeta );
+
+				if ( is_wp_error( $wp_user_id ) ) {
+					$bp->signup->step = 'request-details';
+					bp_core_add_message( $wp_user_id->get_error_message(), 'error' );
+				} else {
+					$bp->signup->step = 'completed-confirmation';
+				}
+			}
+
+			do_action( 'bp_complete_signup' );
+		}
+
+	}
+
+	do_action( 'bp_core_screen_signup' );
+	bp_core_load_template( apply_filters( 'bp_core_template_register', array( 'register', 'registration/register' ) ) );
+}
+add_action( 'bp_screens', 'bp_core_screen_signup' );
+
+function bp_core_screen_activation() {
+	global $bp;
+
+	if ( !bp_is_current_component( 'activate' ) )
+		return false;
+
+	// If the user is logged in, redirect away from here
+	if ( is_user_logged_in() ) {
+		if ( bp_is_component_front_page( 'activate' ) ) {
+			$redirect_to = trailingslashit( bp_get_root_domain() . '/' . bp_get_members_root_slug() );
+		} else {
+			$redirect_to = trailingslashit( bp_get_root_domain() );
+		}
+
+		bp_core_redirect( apply_filters( 'bp_loggedin_activate_page_redirect_to', $redirect_to ) );
+
+		return;
+	}
+
+	// Check if an activation key has been passed
+	if ( isset( $_GET['key'] ) ) {
+
+		// Activate the signup
+		$user = apply_filters( 'bp_core_activate_account', bp_core_activate_signup( $_GET['key'] ) );
+
+		// If there were errors, add a message and redirect
+		if ( !empty( $user->errors ) ) {
+			bp_core_add_message( $user->get_error_message(), 'error' );
+			bp_core_redirect( trailingslashit( bp_get_root_domain() . '/' . $bp->pages->activate->slug ) );
+		}
+
+		// Check for an uploaded avatar and move that to the correct user folder
+		if ( is_multisite() )
+			$hashed_key = wp_hash( $_GET['key'] );
+		else
+			$hashed_key = wp_hash( $user );
+
+		// Check if the avatar folder exists. If it does, move rename it, move
+		// it and delete the signup avatar dir
+		if ( file_exists( bp_core_avatar_upload_path() . '/avatars/signups/' . $hashed_key ) )
+			@rename( bp_core_avatar_upload_path() . '/avatars/signups/' . $hashed_key, bp_core_avatar_upload_path() . '/avatars/' . $user );
+
+		bp_core_add_message( __( 'Your account is now active!', 'buddypress' ) );
+
+		$bp->activation_complete = true;
+	}
+
+	bp_core_load_template( apply_filters( 'bp_core_template_activate', array( 'activate', 'registration/activate' ) ) );
+}
+add_action( 'bp_screens', 'bp_core_screen_activation' );
+
+/** Theme Compatability *******************************************************/
+
+/**
+ * The main theme compat class for BuddyPress Members.
+ *
+ * This class sets up the necessary theme compatability actions to safely output
+ * member template parts to the_title and the_content areas of a theme.
+ *
+ * @since BuddyPress (1.7)
+ */
+class BP_Members_Theme_Compat {
+
+	/**
+	 * Setup the members component theme compatibility
+	 *
+	 * @since BuddyPress (1.7)
+	 */
+	public function __construct() {
+		add_action( 'bp_setup_theme_compat', array( $this, 'is_members' ) );
+	}
+
+	/**
+	 * Are we looking at something that needs members theme compatability?
+	 *
+	 * @since BuddyPress (1.7)
+	 */
+	public function is_members() {
+
+		// Bail if not looking at the members component or a user's page
+		if ( ! bp_is_members_component() && ! bp_is_user() )
+			return;
+
+		// Members Directory
+		if ( ! bp_current_action() && ! bp_current_item() ) {
+			bp_update_is_directory( true, 'members' );
+
+			do_action( 'bp_members_screen_index' );
+
+			add_filter( 'bp_get_buddypress_template',                array( $this, 'directory_template_hierarchy' ) );
+			add_action( 'bp_template_include_reset_dummy_post_data', array( $this, 'directory_dummy_post' ) );
+			add_filter( 'bp_replace_the_content',                    array( $this, 'directory_content'    ) );
+
+		// User page
+		} elseif ( bp_is_user() ) {
+			// If we're on a single activity permalink page, we shouldn't use the members
+			// template, so stop here!
+			if ( bp_is_active( 'activity' ) && bp_is_single_activity() )
+				return;
+
+			do_action( 'bp_members_screen_display_profile' );
+
+			add_filter( 'bp_get_buddypress_template',                array( $this, 'single_template_hierarchy' ) );
+			add_action( 'bp_template_include_reset_dummy_post_data', array( $this, 'single_dummy_post'    ) );
+			add_filter( 'bp_replace_the_content',                    array( $this, 'single_dummy_content' ) );
+
+		}
+	}
+
+	/** Directory *************************************************************/
+
+	/**
+	 * Add template hierarchy to theme compat for the members directory page.
+	 *
+	 * This is to mirror how WordPress has {@link https://codex.wordpress.org/Template_Hierarchy template hierarchy}.
+	 *
+	 * @since BuddyPress (1.8)
+	 *
+	 * @param string $templates The templates from bp_get_theme_compat_templates()
+	 * @return array $templates Array of custom templates to look for.
+	 */
+	public function directory_template_hierarchy( $templates = array() ) {
+
+		// Setup our templates based on priority
+		$new_templates = apply_filters( 'bp_template_hierarchy_members_directory', array(
+			'members/index-directory.php'
+		) );
+
+		// Merge new templates with existing stack
+		// @see bp_get_theme_compat_templates()
+		$templates = array_merge( (array) $new_templates, $templates );
+
+		return $templates;
+	}
+
+	/**
+	 * Update the global $post with directory data
+	 *
+	 * @since BuddyPress (1.7)
+	 */
+	public function directory_dummy_post() {
+		bp_theme_compat_reset_post( array(
+			'ID'             => 0,
+			'post_title'     => __( 'Members', 'buddypress' ),
+			'post_author'    => 0,
+			'post_date'      => 0,
+			'post_content'   => '',
+			'post_type'      => 'bp_members',
+			'post_status'    => 'publish',
+			'is_archive'     => true,
+			'comment_status' => 'closed'
+		) );
+	}
+
+	/**
+	 * Filter the_content with the members index template part
+	 *
+	 * @since BuddyPress (1.7)
+	 */
+	public function directory_content() {
+		return bp_buffer_template_part( 'members/index', null, false );
+	}
+
+	/** Single ****************************************************************/
+
+	/**
+	 * Add custom template hierarchy to theme compat for member pages. 
+	 *
+	 * This is to mirror how WordPress has {@link https://codex.wordpress.org/Template_Hierarchy template hierarchy}.
+	 *
+	 * @since BuddyPress (1.8)
+	 *
+	 * @param string $templates The templates from bp_get_theme_compat_templates()
+	 * @return array $templates Array of custom templates to look for.
+	 */
+	public function single_template_hierarchy( $templates ) {
+		// Setup some variables we're going to reference in our custom templates 
+		$user_nicename = buddypress()->displayed_user->userdata->user_nicename; 
+
+		// Setup our templates based on priority
+		$new_templates = apply_filters( 'bp_template_hierarchy_members_single_item', array(
+			'members/single/index-id-'        . sanitize_file_name( bp_displayed_user_id() ) . '.php',
+			'members/single/index-nicename-'  . sanitize_file_name( $user_nicename )         . '.php',
+			'members/single/index-action-'    . sanitize_file_name( bp_current_action() )    . '.php',
+			'members/single/index-component-' . sanitize_file_name( bp_current_component() ) . '.php',
+			'members/single/index.php'
+		) );
+
+		// Merge new templates with existing stack
+		// @see bp_get_theme_compat_templates()
+		$templates = array_merge( (array) $new_templates, $templates );
+
+		return $templates;
+	}
+
+	/**
+	 * Update the global $post with the displayed user's data
+	 *
+	 * @since BuddyPress (1.7)
+	 */
+	public function single_dummy_post() {
+		bp_theme_compat_reset_post( array(
+			'ID'             => 0,
+			'post_title'     => '<a href="' . bp_get_displayed_user_link() . '">' . bp_get_displayed_user_fullname() . '</a>',
+			'post_author'    => 0,
+			'post_date'      => 0,
+			'post_content'   => '',
+			'post_type'      => 'bp_members',
+			'post_status'    => 'publish',
+			'is_archive'     => true,
+			'comment_status' => 'closed'
+		) );
+	}
+
+	/**
+	 * Filter the_content with the members' single home template part
+	 *
+	 * @since BuddyPress (1.7)
+	 */
+	public function single_dummy_content() {
+		return bp_buffer_template_part( 'members/single/home', null, false );
+	}
+}
+new BP_Members_Theme_Compat();
+
+/**
+ * The main theme compat class for BuddyPress Registration.
+ *
+ * This class sets up the necessary theme compatability actions to safely output
+ * registration template parts to the_title and the_content areas of a theme.
+ *
+ * @since BuddyPress (1.7)
+ */
+class BP_Registration_Theme_Compat {
+
+	/**
+	 * Setup the groups component theme compatibility
+	 *
+	 * @since BuddyPress (1.7)
+	 */
+	public function __construct() {
+		add_action( 'bp_setup_theme_compat', array( $this, 'is_registration' ) );
+	}
+
+	/**
+	 * Are we looking at either the registration or activation pages?
+	 *
+	 * @since BuddyPress (1.7)
+	 */
+	public function is_registration() {
+
+		// Bail if not looking at the registration or activation page
+		if ( ! bp_is_register_page() && ! bp_is_activation_page() ) {
+			return;
+		}
+
+		// Not a directory
+		bp_update_is_directory( false, 'register' );
+
+		// Setup actions
+		add_filter( 'bp_get_buddypress_template',                array( $this, 'template_hierarchy' ) );
+		add_action( 'bp_template_include_reset_dummy_post_data', array( $this, 'dummy_post'    ) );
+		add_filter( 'bp_replace_the_content',                    array( $this, 'dummy_content' ) );
+	}
+
+	/** Template ***********************************************************/
+
+	/**
+	 * Add template hierarchy to theme compat for registration / activation pages.
+	 *
+	 * This is to mirror how WordPress has {@link https://codex.wordpress.org/Template_Hierarchy template hierarchy}.
+	 *
+	 * @since BuddyPress (1.8)
+	 *
+	 * @param string $templates The templates from bp_get_theme_compat_templates()
+	 * @return array $templates Array of custom templates to look for.
+	 */
+	public function template_hierarchy( $templates ) {
+		$component = sanitize_file_name( bp_current_component() );
+
+		// Setup our templates based on priority
+		$new_templates = apply_filters( "bp_template_hierarchy_{$component}", array(
+			"members/index-{$component}.php"
+		) );
+
+		// Merge new templates with existing stack
+		// @see bp_get_theme_compat_templates()
+		$templates = array_merge( (array) $new_templates, $templates );
+
+		return $templates;
+	}
+
+	/**
+	 * Update the global $post with dummy data
+	 *
+	 * @since BuddyPress (1.7)
+	 */
+	public function dummy_post() {
+		// Registration page
+		if ( bp_is_register_page() ) {
+			$title = __( 'Create an Account', 'buddypress' );
+
+			if ( 'completed-confirmation' == bp_get_current_signup_step() ) {
+				$title = __( 'Check Your Email To Activate Your Account!', 'buddypress' );
+			}
+
+		// Activation page
+		} else {
+			$title = __( 'Activate your Account', 'buddypress' );
+
+			if ( bp_account_was_activated() ) {
+				$title = __( 'Account Activated', 'buddypress' );
+			}
+		}
+
+		$post_type = bp_is_register_page() ? 'bp_register' : 'bp_activate';
+
+		bp_theme_compat_reset_post( array(
+			'ID'             => 0,
+			'post_title'     => $title,
+			'post_author'    => 0,
+			'post_date'      => 0,
+			'post_content'   => '',
+			'post_type'      => $post_type,
+			'post_status'    => 'publish',
+			'is_archive'     => true,
+			'comment_status' => 'closed'
+		) );
+	}
+
+	/**
+	 * Filter the_content with either the register or activate templates.
+	 *
+	 * @since BuddyPress (1.7)
+	 */
+	public function dummy_content() {
+		if ( bp_is_register_page() ) {
+			return bp_buffer_template_part( 'members/register', null, false );
+		} else {
+			return bp_buffer_template_part( 'members/activate', null, false );
+		}
+	}
+}
+new BP_Registration_Theme_Compat();
Index: /tags/1.9/bp-members/bp-members-template.php
===================================================================
--- /tags/1.9/bp-members/bp-members-template.php	(revision 7684)
+++ /tags/1.9/bp-members/bp-members-template.php	(revision 7684)
@@ -0,0 +1,1255 @@
+<?php
+
+/**
+ * BuddyPress Member Template Tags
+ *
+ * Functions that are safe to use inside your template files and themes
+ *
+ * @package BuddyPress
+ * @subpackage Members
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/**
+ * Output the members component slug
+ *
+ * @package BuddyPress
+ * @subpackage Members Template
+ * @since BuddyPress (1.5)
+ *
+ * @uses bp_get_members_slug()
+ */
+function bp_members_slug() {
+	echo bp_get_members_slug();
+}
+	/**
+	 * Return the members component slug
+	 *
+	 * @package BuddyPress
+	 * @subpackage Members Template
+	 * @since BuddyPress (1.5)
+	 */
+	function bp_get_members_slug() {
+		global $bp;
+		return apply_filters( 'bp_get_members_slug', $bp->members->slug );
+	}
+
+/**
+ * Output the members component root slug
+ *
+ * @package BuddyPress
+ * @subpackage Members Template
+ * @since BuddyPress (1.5)
+ *
+ * @uses bp_get_members_root_slug()
+ */
+function bp_members_root_slug() {
+	echo bp_get_members_root_slug();
+}
+	/**
+	 * Return the members component root slug
+	 *
+	 * @package BuddyPress
+	 * @subpackage Members Template
+	 * @since BuddyPress (1.5)
+	 */
+	function bp_get_members_root_slug() {
+		global $bp;
+		return apply_filters( 'bp_get_members_root_slug', $bp->members->root_slug );
+	}
+
+/**
+ * Output member directory permalink
+ *
+ * @package BuddyPress
+ * @subpackage Members Template
+ * @since BuddyPress (1.5)
+ * @uses bp_get_members_directory_permalink()
+ */
+function bp_members_directory_permalink() {
+	echo bp_get_members_directory_permalink();
+}
+	/**
+	 * Return member directory permalink
+	 *
+	 * @package BuddyPress
+	 * @subpackage Members Template
+	 * @since BuddyPress (1.5)
+	 * @uses apply_filters()
+	 * @uses traisingslashit()
+	 * @uses bp_get_root_domain()
+	 * @uses bp_get_members_root_slug()
+	 * @return string
+	 */
+	function bp_get_members_directory_permalink() {
+		return apply_filters( 'bp_get_members_directory_permalink', trailingslashit( bp_get_root_domain() . '/' . bp_get_members_root_slug() ) );
+	}
+
+/**
+ * Output the sign-up slug
+ *
+ * @package BuddyPress
+ * @subpackage Members Template
+ * @since BuddyPress (1.5)
+ *
+ * @uses bp_get_signup_slug()
+ */
+function bp_signup_slug() {
+	echo bp_get_signup_slug();
+}
+	/**
+	 * Return the sign-up slug
+	 *
+	 * @package BuddyPress
+	 * @subpackage Members Template
+	 * @since BuddyPress (1.5)
+	 */
+	function bp_get_signup_slug() {
+		$bp = buddypress();
+
+		if ( !empty( $bp->pages->register->slug ) )
+			$slug = $bp->pages->register->slug;
+		elseif ( defined( 'BP_REGISTER_SLUG' ) )
+			$slug = BP_REGISTER_SLUG;
+		else
+			$slug = 'register';
+
+		return apply_filters( 'bp_get_signup_slug', $slug );
+	}
+
+/**
+ * Output the activation slug
+ *
+ * @package BuddyPress
+ * @subpackage Members Template
+ * @since BuddyPress (1.5)
+ *
+ * @uses bp_get_activate_slug()
+ */
+function bp_activate_slug() {
+	echo bp_get_activate_slug();
+}
+	/**
+	 * Return the activation slug
+	 *
+	 * @package BuddyPress
+	 * @subpackage Members Template
+	 * @since BuddyPress (1.5)
+	 */
+	function bp_get_activate_slug() {
+		global $bp;
+
+		if ( !empty( $bp->pages->activate->slug ) )
+			$slug = $bp->pages->activate->slug;
+		elseif ( defined( 'BP_ACTIVATION_SLUG' ) )
+			$slug = BP_ACTIVATION_SLUG;
+		else
+			$slug = 'activate';
+
+		return apply_filters( 'bp_get_activate_slug', $slug );
+	}
+
+/***
+ * Members template loop that will allow you to loop all members or friends of a member
+ * if you pass a user_id.
+ */
+
+class BP_Core_Members_Template {
+	var $current_member = -1;
+	var $member_count;
+	var $members;
+	var $member;
+
+	var $in_the_loop;
+
+	var $pag_page;
+	var $pag_num;
+	var $pag_links;
+	var $total_member_count;
+
+	function __construct( $type, $page_number, $per_page, $max, $user_id, $search_terms, $include, $populate_extras, $exclude, $meta_key, $meta_value, $page_arg = 'upage' ) {
+
+		$this->pag_page = !empty( $_REQUEST[$page_arg] ) ? intval( $_REQUEST[$page_arg] ) : (int) $page_number;
+		$this->pag_num  = !empty( $_REQUEST['num'] )   ? intval( $_REQUEST['num'] )   : (int) $per_page;
+		$this->type     = $type;
+
+		if ( !empty( $_REQUEST['letter'] ) )
+			$this->members = BP_Core_User::get_users_by_letter( $_REQUEST['letter'], $this->pag_num, $this->pag_page, $populate_extras, $exclude );
+		else
+			$this->members = bp_core_get_users( array( 'type' => $this->type, 'per_page' => $this->pag_num, 'page' => $this->pag_page, 'user_id' => $user_id, 'include' => $include, 'search_terms' => $search_terms, 'populate_extras' => $populate_extras, 'exclude' => $exclude, 'meta_key' => $meta_key, 'meta_value' => $meta_value ) );
+
+		if ( !$max || $max >= (int) $this->members['total'] )
+			$this->total_member_count = (int) $this->members['total'];
+		else
+			$this->total_member_count = (int) $max;
+
+		$this->members = $this->members['users'];
+
+		if ( $max ) {
+			if ( $max >= count( $this->members ) ) {
+				$this->member_count = count( $this->members );
+			} else {
+				$this->member_count = (int) $max;
+			}
+		} else {
+			$this->member_count = count( $this->members );
+		}
+
+		if ( (int) $this->total_member_count && (int) $this->pag_num ) {
+			$this->pag_links = paginate_links( array(
+				'base'      => add_query_arg( $page_arg, '%#%' ),
+				'format'    => '',
+				'total'     => ceil( (int) $this->total_member_count / (int) $this->pag_num ),
+				'current'   => (int) $this->pag_page,
+				'prev_text' => _x( '&larr;', 'Member pagination previous text', 'buddypress' ),
+				'next_text' => _x( '&rarr;', 'Member pagination next text', 'buddypress' ),
+				'mid_size'   => 1
+			) );
+		}
+	}
+
+	function has_members() {
+		if ( $this->member_count )
+			return true;
+
+		return false;
+	}
+
+	function next_member() {
+		$this->current_member++;
+		$this->member = $this->members[$this->current_member];
+
+		return $this->member;
+	}
+
+	function rewind_members() {
+		$this->current_member = -1;
+		if ( $this->member_count > 0 ) {
+			$this->member = $this->members[0];
+		}
+	}
+
+	function members() {
+		if ( $this->current_member + 1 < $this->member_count ) {
+			return true;
+		} elseif ( $this->current_member + 1 == $this->member_count ) {
+			do_action('member_loop_end');
+			// Do some cleaning up after the loop
+			$this->rewind_members();
+		}
+
+		$this->in_the_loop = false;
+		return false;
+	}
+
+	function the_member() {
+
+		$this->in_the_loop = true;
+		$this->member      = $this->next_member();
+
+		// loop has just started
+		if ( 0 == $this->current_member )
+			do_action( 'member_loop_start' );
+	}
+}
+
+function bp_rewind_members() {
+	global $members_template;
+
+	return $members_template->rewind_members();
+}
+
+function bp_has_members( $args = '' ) {
+	global $members_template;
+
+	/***
+	 * Set the defaults based on the current page. Any of these will be overridden
+	 * if arguments are directly passed into the loop. Custom plugins should always
+	 * pass their parameters directly to the loop.
+	 */
+	$type         = 'active';
+	$user_id      = 0;
+	$page         = 1;
+	$search_terms = null;
+
+	// User filtering
+	if ( bp_is_user_friends() && ! bp_is_user_friend_requests() ) {
+		$user_id = bp_displayed_user_id();
+	}
+
+	// type: active ( default ) | random | newest | popular | online | alphabetical
+	$defaults = array(
+		'type'            => $type,
+		'page'            => $page,
+		'per_page'        => 20,
+		'max'             => false,
+
+		'page_arg'        => 'upage',       // See https://buddypress.trac.wordpress.org/ticket/3679
+
+		'include'         => false,         // Pass a user_id or a list (comma-separated or array) of user_ids to only show these users
+		'exclude'         => false,         // Pass a user_id or a list (comma-separated or array) of user_ids to exclude these users
+
+		'user_id'         => $user_id,      // Pass a user_id to only show friends of this user
+		'search_terms'    => $search_terms, // Pass search_terms to filter users by their profile data
+
+		'meta_key'        => false,	        // Only return users with this usermeta
+		'meta_value'	  => false,	        // Only return users where the usermeta value matches. Requires meta_key
+
+		'populate_extras' => true           // Fetch usermeta? Friend count, last active etc.
+	);
+
+	$r = wp_parse_args( $args, $defaults );
+	extract( $r );
+
+	// Pass a filter if ?s= is set.
+	if ( is_null( $search_terms ) ) {
+		if ( !empty( $_REQUEST['s'] ) )
+			$search_terms = $_REQUEST['s'];
+		else
+			$search_terms = false;
+	}
+
+	// Set per_page to max if max is larger than per_page
+	if ( !empty( $max ) && ( $per_page > $max ) )
+		$per_page = $max;
+
+	$members_template = new BP_Core_Members_Template( $type, $page, $per_page, $max, $user_id, $search_terms, $include, (bool)$populate_extras, $exclude, $meta_key, $meta_value, $page_arg );
+	return apply_filters( 'bp_has_members', $members_template->has_members(), $members_template );
+}
+
+function bp_the_member() {
+	global $members_template;
+	return $members_template->the_member();
+}
+
+function bp_members() {
+	global $members_template;
+	return $members_template->members();
+}
+
+function bp_members_pagination_count() {
+	echo bp_get_members_pagination_count();
+}
+	function bp_get_members_pagination_count() {
+		global $members_template;
+
+		if ( empty( $members_template->type ) )
+			$members_template->type = '';
+
+		$start_num = intval( ( $members_template->pag_page - 1 ) * $members_template->pag_num ) + 1;
+		$from_num  = bp_core_number_format( $start_num );
+		$to_num    = bp_core_number_format( ( $start_num + ( $members_template->pag_num - 1 ) > $members_template->total_member_count ) ? $members_template->total_member_count : $start_num + ( $members_template->pag_num - 1 ) );
+		$total     = bp_core_number_format( $members_template->total_member_count );
+
+		if ( 'active' == $members_template->type )
+			$pag = sprintf( _n( 'Viewing member %1$s to %2$s (of %3$s active member)', 'Viewing member %1$s to %2$s (of %3$s active members)', $total, 'buddypress' ), $from_num, $to_num, $total );
+		else if ( 'popular' == $members_template->type )
+			$pag = sprintf( _n( 'Viewing member %1$s to %2$s (of %3$s member with friends)', 'Viewing member %1$s to %2$s (of %3$s members with friends)', $total, 'buddypress' ), $from_num, $to_num, $total );
+		else if ( 'online' == $members_template->type )
+			$pag = sprintf( _n( 'Viewing member %1$s to %2$s (of %3$s member online)', 'Viewing member %1$s to %2$s (of %3$s members online)', $total, 'buddypress' ), $from_num, $to_num, $total );
+		else
+			$pag = sprintf( _n( 'Viewing member %1$s to %2$s (of %3$s member)', 'Viewing member %1$s to %2$s (of %3$s members)', $total, 'buddypress' ), $from_num, $to_num, $total );
+
+		return apply_filters( 'bp_members_pagination_count', $pag );
+	}
+
+function bp_members_pagination_links() {
+	echo bp_get_members_pagination_links();
+}
+	function bp_get_members_pagination_links() {
+		global $members_template;
+
+		return apply_filters( 'bp_get_members_pagination_links', $members_template->pag_links );
+	}
+
+/**
+ * bp_member_user_id()
+ *
+ * Echo id from bp_get_member_user_id()
+ *
+ * @uses bp_get_member_user_id()
+ */
+function bp_member_user_id() {
+	echo bp_get_member_user_id();
+}
+	/**
+	 * bp_get_member_user_id()
+	 *
+	 * Get the id of the user in a members loop
+	 *
+	 * @global object $members_template
+	 * @return string Members id
+	 */
+	function bp_get_member_user_id() {
+		global $members_template;
+		$member_id = isset( $members_template->member->id ) ? (int) $members_template->member->id : false;
+		return apply_filters( 'bp_get_member_user_id', $member_id );
+	}
+
+/**
+ * Output the row class of a member
+ *
+ * @since BuddyPress (1.7)
+ */
+function bp_member_class() {
+	echo bp_get_member_class();
+}
+	/**
+	 * Return the row class of a member
+	 *
+	 * @global BP_Core_Members_Template $members_template
+	 * @return string Row class of the member
+	 * @since BuddyPress (1.7)
+	 */
+	function bp_get_member_class() {
+		global $members_template;
+
+		$classes      = array();
+		$current_time = bp_core_current_time();
+		$pos_in_loop  = (int) $members_template->current_member;
+
+		// If we've only one group in the loop, don't both with odd and even.
+		if ( $members_template->member_count > 1 )
+			$classes[] = ( $pos_in_loop % 2 ) ? 'even' : 'odd';
+		else
+			$classes[] = 'bp-single-member';
+
+		// Has the user been active recently?
+		if ( ! empty( $members_template->member->last_activity ) ) {
+			if ( strtotime( $current_time ) <= strtotime( '+5 minutes', strtotime( $members_template->member->last_activity ) ) )
+				$classes[] = 'is-online';
+		}
+
+		$classes = apply_filters( 'bp_get_member_class', $classes );
+		$classes = array_merge( $classes, array() );
+		$retval  = 'class="' . join( ' ', $classes ) . '"';
+
+		return $retval;
+	}
+
+/**
+ * bp_member_user_nicename()
+ *
+ * Echo nicename from bp_get_member_user_nicename()
+ *
+ * @uses bp_get_member_user_nicename()
+ */
+function bp_member_user_nicename() {
+	echo bp_get_member_user_nicename();
+}
+	/**
+	 * bp_get_member_user_nicename()
+	 *
+	 * Get the nicename of the user in a members loop
+	 *
+	 * @global object $members_template
+	 * @return string Members nicename
+	 */
+	function bp_get_member_user_nicename() {
+		global $members_template;
+		return apply_filters( 'bp_get_member_user_nicename', $members_template->member->user_nicename );
+	}
+
+/**
+ * bp_member_user_login()
+ *
+ * Echo login from bp_get_member_user_login()
+ *
+ * @uses bp_get_member_user_login()
+ */
+function bp_member_user_login() {
+	echo bp_get_member_user_login();
+}
+	/**
+	 * bp_get_member_user_login()
+	 *
+	 * Get the login of the user in a members loop
+	 *
+	 * @global object $members_template
+	 * @return string Members login
+	 */
+	function bp_get_member_user_login() {
+		global $members_template;
+		return apply_filters( 'bp_get_member_user_login', $members_template->member->user_login );
+	}
+
+/**
+ * bp_member_user_email()
+ *
+ * Echo email address from bp_get_member_user_email()
+ *
+ * @uses bp_get_member_user_email()
+ */
+function bp_member_user_email() {
+	echo bp_get_member_user_email();
+}
+	/**
+	 * bp_get_member_user_email()
+	 *
+	 * Get the email address of the user in a members loop
+	 *
+	 * @global object $members_template
+	 * @return string Members email address
+	 */
+	function bp_get_member_user_email() {
+		global $members_template;
+		return apply_filters( 'bp_get_member_user_email', $members_template->member->user_email );
+	}
+
+function bp_member_is_loggedin_user() {
+	global $members_template;
+	return apply_filters( 'bp_member_is_loggedin_user', bp_loggedin_user_id() == $members_template->member->id ? true : false );
+}
+
+function bp_member_avatar( $args = '' ) {
+	echo apply_filters( 'bp_member_avatar', bp_get_member_avatar( $args ) );
+}
+	function bp_get_member_avatar( $args = '' ) {
+		global $members_template;
+
+		$fullname = !empty( $members_template->member->fullname ) ? $members_template->member->fullname : $members_template->member->display_name;
+
+		$defaults = array(
+			'type'   => 'thumb',
+			'width'  => false,
+			'height' => false,
+			'class'  => 'avatar',
+			'id'     => false,
+			'alt'    => sprintf( __( 'Profile picture of %s', 'buddypress' ), $fullname )
+		);
+
+		$r = wp_parse_args( $args, $defaults );
+		extract( $r, EXTR_SKIP );
+
+		return apply_filters( 'bp_get_member_avatar', bp_core_fetch_avatar( array( 'item_id' => $members_template->member->id, 'type' => $type, 'alt' => $alt, 'css_id' => $id, 'class' => $class, 'width' => $width, 'height' => $height, 'email' => $members_template->member->user_email ) ) );
+	}
+
+function bp_member_permalink() {
+	echo bp_get_member_permalink();
+}
+	function bp_get_member_permalink() {
+		global $members_template;
+
+		return apply_filters( 'bp_get_member_permalink', bp_core_get_user_domain( $members_template->member->id, $members_template->member->user_nicename, $members_template->member->user_login ) );
+	}
+	function bp_member_link() { echo bp_get_member_permalink(); }
+	function bp_get_member_link() { return bp_get_member_permalink(); }
+
+/**
+ * Echoes bp_get_member_name()
+ *
+ * @package BuddyPress
+ */
+function bp_member_name() {
+	echo apply_filters( 'bp_member_name', bp_get_member_name() );
+}
+	/**
+	 * Used inside a bp_has_members() loop, this function returns a user's full name
+	 *
+	 * Full name is, by default, pulled from xprofile's Full Name field. When this field is
+	 * empty, we try to get an alternative name from the WP users table, in the following order
+	 * of preference: display_name, user_nicename, user_login.
+	 *
+	 * @package BuddyPress
+	 *
+	 * @uses apply_filters() Filter bp_get_the_member_name() to alter the function's output
+	 * @return string The user's fullname for display
+	 */
+	function bp_get_member_name() {
+		global $members_template;
+
+		// Generally, this only fires when xprofile is disabled
+		if ( empty( $members_template->member->fullname ) ) {
+			// Our order of preference for alternative fullnames
+			$name_stack = array(
+				'display_name',
+				'user_nicename',
+				'user_login'
+			);
+
+			foreach ( $name_stack as $source ) {
+				if ( !empty( $members_template->member->{$source} ) ) {
+					// When a value is found, set it as fullname and be done
+					// with it
+					$members_template->member->fullname = $members_template->member->{$source};
+					break;
+				}
+			}
+		}
+
+		return apply_filters( 'bp_get_member_name', $members_template->member->fullname );
+	}
+	add_filter( 'bp_get_member_name', 'wp_filter_kses' );
+	add_filter( 'bp_get_member_name', 'stripslashes'   );
+	add_filter( 'bp_get_member_name', 'strip_tags'     );
+	add_filter( 'bp_get_member_name', 'esc_html'       );
+
+function bp_member_last_active() {
+	echo bp_get_member_last_active();
+}
+	function bp_get_member_last_active() {
+		global $members_template;
+
+		if ( isset( $members_template->member->last_activity ) )
+			$last_activity = bp_core_get_last_activity( $members_template->member->last_activity, __( 'active %s', 'buddypress' ) );
+		else
+			$last_activity = __( 'Never active', 'buddypress' );
+
+		return apply_filters( 'bp_member_last_active', $last_activity );
+	}
+
+function bp_member_latest_update( $args = '' ) {
+	echo bp_get_member_latest_update( $args );
+}
+	function bp_get_member_latest_update( $args = '' ) {
+		global $members_template;
+
+		$defaults = array(
+			'length'    => 225,
+			'view_link' => true
+		);
+
+		$r = wp_parse_args( $args, $defaults );
+		extract( $r );
+
+		if ( !bp_is_active( 'activity' ) || empty( $members_template->member->latest_update ) || !$update = maybe_unserialize( $members_template->member->latest_update ) )
+			return false;
+
+		$update_content = apply_filters( 'bp_get_activity_latest_update_excerpt', sprintf( _x( '- &quot;%s &quot;', 'member latest update in member directory', 'buddypress' ), trim( strip_tags( bp_create_excerpt( $update['content'], $length ) ) ) ) );
+
+		// If $view_link is true and the text returned by bp_create_excerpt() is different from the original text (ie it's
+		// been truncated), add the "View" link.
+		if ( $view_link && ( $update_content != $update['content'] ) ) {
+			$view = __( 'View', 'buddypress' );
+
+			$update_content .= '<span class="activity-read-more"><a href="' . bp_activity_get_permalink( $update['id'] ) . '" rel="nofollow">' . $view . '</a></span>';
+		}
+
+		return apply_filters( 'bp_get_member_latest_update', $update_content );
+	}
+
+function bp_member_profile_data( $args = '' ) {
+	echo bp_get_member_profile_data( $args );
+}
+	function bp_get_member_profile_data( $args = '' ) {
+		global $members_template;
+
+		if ( !bp_is_active( 'xprofile' ) )
+			return false;
+
+		// Declare local variables
+		$data    = false;
+		$user_id = 0;
+
+		// Guess at default $user_id
+		if ( !empty( $members_template->member->id ) )
+			$user_id = $members_template->member->id;
+		elseif ( bp_displayed_user_id() )
+			$user_id = bp_displayed_user_id();
+
+		$defaults = array(
+			'field'   => false,   // Field name
+			'user_id' => $user_id
+		);
+
+		$r = wp_parse_args( $args, $defaults );
+		extract( $r, EXTR_SKIP );
+
+		// Populate the user if it hasn't been already.
+		if ( empty( $members_template->member->profile_data ) && method_exists( 'BP_XProfile_ProfileData', 'get_all_for_user' ) )
+			$members_template->member->profile_data = BP_XProfile_ProfileData::get_all_for_user( $user_id );
+
+		// Get the field data if there is data to get
+		if ( ! empty( $members_template->member->profile_data ) && ! empty( $members_template->member->profile_data[$field]['field_type'] ) && ! empty( $members_template->member->profile_data[$field]['field_data'] ) )
+			$data = xprofile_format_profile_field( $members_template->member->profile_data[$field]['field_type'], $members_template->member->profile_data[$field]['field_data'] );
+
+		return apply_filters( 'bp_get_member_profile_data', $data );
+	}
+
+function bp_member_registered() {
+	echo bp_get_member_registered();
+}
+	function bp_get_member_registered() {
+		global $members_template;
+
+		$registered = esc_attr( bp_core_get_last_activity( $members_template->member->user_registered, _x( 'registered %s', 'Records the timestamp that the user registered into the activy stream', 'buddypress' ) ) );
+
+		return apply_filters( 'bp_member_last_active', $registered );
+	}
+
+function bp_member_random_profile_data() {
+	global $members_template;
+
+	if ( bp_is_active( 'xprofile' ) ) { ?>
+		<?php $random_data = xprofile_get_random_profile_data( $members_template->member->id, true ); ?>
+			<strong><?php echo wp_filter_kses( $random_data[0]->name ) ?></strong>
+			<?php echo wp_filter_kses( $random_data[0]->value ) ?>
+	<?php }
+}
+
+function bp_member_hidden_fields() {
+	if ( isset( $_REQUEST['s'] ) )
+		echo '<input type="hidden" id="search_terms" value="' . esc_attr( $_REQUEST['s'] ) . '" name="search_terms" />';
+
+	if ( isset( $_REQUEST['letter'] ) )
+		echo '<input type="hidden" id="selected_letter" value="' . esc_attr( $_REQUEST['letter'] ) . '" name="selected_letter" />';
+
+	if ( isset( $_REQUEST['members_search'] ) )
+		echo '<input type="hidden" id="search_terms" value="' . esc_attr( $_REQUEST['members_search'] ) . '" name="search_terms" />';
+}
+
+function bp_directory_members_search_form() {
+
+	$default_search_value = bp_get_search_default_text( 'members' );
+	$search_value         = !empty( $_REQUEST['s'] ) ? stripslashes( $_REQUEST['s'] ) : $default_search_value;
+
+	$search_form_html = '<form action="" method="get" id="search-members-form">
+		<label><input type="text" name="s" id="members_search" placeholder="'. esc_attr( $search_value ) .'" /></label>
+		<input type="submit" id="members_search_submit" name="members_search_submit" value="' . __( 'Search', 'buddypress' ) . '" />
+	</form>';
+
+	echo apply_filters( 'bp_directory_members_search_form', $search_form_html );
+}
+
+function bp_total_site_member_count() {
+	echo bp_get_total_site_member_count();
+}
+	function bp_get_total_site_member_count() {
+		return apply_filters( 'bp_get_total_site_member_count', bp_core_number_format( bp_core_get_total_member_count() ) );
+	}
+
+/** Navigation and other misc template tags **/
+
+/**
+ * Uses the $bp->bp_nav global to render out the navigation within a BuddyPress install.
+ * Each component adds to this navigation array within its own [component_name]setup_nav() function.
+ *
+ * This navigation array is the top level navigation, so it contains items such as:
+ *      [Blog, Profile, Messages, Groups, Friends] ...
+ *
+ * The function will also analyze the current component the user is in, to determine whether
+ * or not to highlight a particular nav item.
+ *
+ * @package BuddyPress Core
+ * @todo Move to a back-compat file?
+ * @deprecated Does not seem to be called anywhere in the core
+ * @global BuddyPress $bp The one true BuddyPress instance
+ */
+function bp_get_loggedin_user_nav() {
+	global $bp;
+
+	// Loop through each navigation item
+	foreach( (array) $bp->bp_nav as $nav_item ) {
+
+		$selected = '';
+
+		// If the current component matches the nav item id, then add a highlight CSS class.
+		if ( !bp_is_directory() && !empty( $bp->active_components[bp_current_component()] ) && $bp->active_components[bp_current_component()] == $nav_item['css_id'] ) {
+			$selected = ' class="current selected"';
+		}
+
+		// If we are viewing another person (current_userid does not equal
+		// loggedin_user->id then check to see if the two users are friends.
+		// if they are, add a highlight CSS class to the friends nav item
+		// if it exists.
+		if ( !bp_is_my_profile() && bp_displayed_user_id() ) {
+			$selected = '';
+
+			if ( bp_is_active( 'friends' ) ) {
+				if ( $nav_item['css_id'] == $bp->friends->id ) {
+					if ( friends_check_friendship( bp_loggedin_user_id(), bp_displayed_user_id() ) ) {
+						$selected = ' class="current selected"';
+					}
+				}
+			}
+		}
+
+		// echo out the final list item
+		echo apply_filters_ref_array( 'bp_get_loggedin_user_nav_' . $nav_item['css_id'], array( '<li id="li-nav-' . $nav_item['css_id'] . '" ' . $selected . '><a id="my-' . $nav_item['css_id'] . '" href="' . $nav_item['link'] . '">' . $nav_item['name'] . '</a></li>', &$nav_item ) );
+	}
+
+	// Always add a log out list item to the end of the navigation
+	$logout_link = '<li><a id="wp-logout" href="' .  wp_logout_url( bp_get_root_domain() ) . '">' . __( 'Log Out', 'buddypress' ) . '</a></li>';
+
+	echo apply_filters( 'bp_logout_nav_link', $logout_link );
+}
+
+/**
+ * Uses the $bp->bp_nav global to render out the user navigation when viewing another user other than
+ * yourself.
+ *
+ * @package BuddyPress Core
+ * @global BuddyPress $bp The one true BuddyPress instance
+ */
+function bp_get_displayed_user_nav() {
+	global $bp;
+
+	foreach ( (array) $bp->bp_nav as $user_nav_item ) {
+		if ( empty( $user_nav_item['show_for_displayed_user'] ) && !bp_is_my_profile() )
+			continue;
+
+		$selected = '';
+		if ( bp_is_current_component( $user_nav_item['slug'] ) ) {
+			$selected = ' class="current selected"';
+		}
+
+		if ( bp_loggedin_user_domain() ) {
+			$link = str_replace( bp_loggedin_user_domain(), bp_displayed_user_domain(), $user_nav_item['link'] );
+		} else {
+			$link = trailingslashit( bp_displayed_user_domain() . $user_nav_item['link'] );
+		}
+
+		echo apply_filters_ref_array( 'bp_get_displayed_user_nav_' . $user_nav_item['css_id'], array( '<li id="' . $user_nav_item['css_id'] . '-personal-li" ' . $selected . '><a id="user-' . $user_nav_item['css_id'] . '" href="' . $link . '">' . $user_nav_item['name'] . '</a></li>', &$user_nav_item ) );
+	}
+}
+
+/** Avatars *******************************************************************/
+
+function bp_loggedin_user_avatar( $args = '' ) {
+	echo bp_get_loggedin_user_avatar( $args );
+}
+	function bp_get_loggedin_user_avatar( $args = '' ) {
+
+		$defaults = array(
+			'type'   => 'thumb',
+			'width'  => false,
+			'height' => false,
+			'html'   => true,
+			'alt'    => sprintf( __( 'Profile picture of %s', 'buddypress' ), bp_get_loggedin_user_fullname() )
+		);
+
+		$r = wp_parse_args( $args, $defaults );
+		extract( $r, EXTR_SKIP );
+
+		return apply_filters( 'bp_get_loggedin_user_avatar', bp_core_fetch_avatar( array( 'item_id' => bp_loggedin_user_id(), 'type' => $type, 'width' => $width, 'height' => $height, 'html' => $html, 'alt' => $alt ) ) );
+	}
+
+function bp_displayed_user_avatar( $args = '' ) {
+	echo bp_get_displayed_user_avatar( $args );
+}
+	function bp_get_displayed_user_avatar( $args = '' ) {
+
+		$defaults = array(
+			'type'   => 'thumb',
+			'width'  => false,
+			'height' => false,
+			'html'   => true,
+			'alt'    => sprintf( __( 'Profile picture of %s', 'buddypress' ), bp_get_displayed_user_fullname() )
+		);
+
+		$r = wp_parse_args( $args, $defaults );
+		extract( $r, EXTR_SKIP );
+
+		return apply_filters( 'bp_get_displayed_user_avatar', bp_core_fetch_avatar( array( 'item_id' => bp_displayed_user_id(), 'type' => $type, 'width' => $width, 'height' => $height, 'html' => $html, 'alt' => $alt ) ) );
+	}
+
+function bp_displayed_user_email() {
+	echo bp_get_displayed_user_email();
+}
+	function bp_get_displayed_user_email() {
+		global $bp;
+
+		// If displayed user exists, return email address
+		if ( isset( $bp->displayed_user->userdata->user_email ) )
+			$retval = $bp->displayed_user->userdata->user_email;
+		else
+			$retval = '';
+
+		return apply_filters( 'bp_get_displayed_user_email', esc_attr( $retval ) );
+	}
+
+function bp_last_activity( $user_id = 0 ) {
+	echo apply_filters( 'bp_last_activity', bp_get_last_activity( $user_id ) );
+}
+	function bp_get_last_activity( $user_id = 0 ) {
+
+		if ( empty( $user_id ) )
+			$user_id = bp_displayed_user_id();
+
+		$last_activity = bp_core_get_last_activity( bp_get_user_last_activity( $user_id ), __('active %s', 'buddypress') );
+
+		return apply_filters( 'bp_get_last_activity', $last_activity );
+	}
+
+function bp_user_firstname() {
+	echo bp_get_user_firstname();
+}
+	function bp_get_user_firstname( $name = false ) {
+
+		// Try to get displayed user
+		if ( empty( $name ) )
+			$name = bp_get_displayed_user_fullname();
+
+		// Fall back on logged in user
+		if ( empty( $name ) )
+			$name = bp_get_loggedin_user_fullname();
+
+		$fullname = (array) explode( ' ', $name );
+
+		return apply_filters( 'bp_get_user_firstname', $fullname[0], $fullname );
+	}
+
+function bp_loggedin_user_link() {
+	echo bp_get_loggedin_user_link();
+}
+	function bp_get_loggedin_user_link() {
+		return apply_filters( 'bp_get_loggedin_user_link', bp_loggedin_user_domain() );
+	}
+
+function bp_displayed_user_link() {
+	echo bp_get_displayed_user_link();
+}
+	function bp_get_displayed_user_link() {
+		return apply_filters( 'bp_get_displayed_user_link', bp_displayed_user_domain() );
+	}
+	function bp_user_link() { bp_displayed_user_domain(); } // Deprecated.
+
+function bp_current_user_id() { return bp_displayed_user_id(); }
+
+function bp_displayed_user_domain() {
+	global $bp;
+	return apply_filters( 'bp_displayed_user_domain', isset( $bp->displayed_user->domain ) ? $bp->displayed_user->domain : '' );
+}
+
+function bp_loggedin_user_domain() {
+	global $bp;
+	return apply_filters( 'bp_loggedin_user_domain', isset( $bp->loggedin_user->domain ) ? $bp->loggedin_user->domain : '' );
+}
+
+function bp_displayed_user_fullname() {
+	echo bp_get_displayed_user_fullname();
+}
+	function bp_get_displayed_user_fullname() {
+		global $bp;
+		return apply_filters( 'bp_displayed_user_fullname', isset( $bp->displayed_user->fullname ) ? $bp->displayed_user->fullname : '' );
+	}
+	function bp_user_fullname() { echo bp_get_displayed_user_fullname(); }
+
+
+function bp_loggedin_user_fullname() {
+	echo bp_get_loggedin_user_fullname();
+}
+	function bp_get_loggedin_user_fullname() {
+		global $bp;
+		return apply_filters( 'bp_get_loggedin_user_fullname', isset( $bp->loggedin_user->fullname ) ? $bp->loggedin_user->fullname : '' );
+	}
+
+function bp_displayed_user_username() {
+	echo bp_get_displayed_user_username();
+}
+	function bp_get_displayed_user_username() {
+		global $bp;
+
+		if ( bp_displayed_user_id() ) {
+			$username = bp_core_get_username( bp_displayed_user_id(), $bp->displayed_user->userdata->user_nicename, $bp->displayed_user->userdata->user_login );
+		} else {
+			$username = '';
+		}
+
+		return apply_filters( 'bp_get_displayed_user_username', $username );
+	}
+
+function bp_loggedin_user_username() {
+	echo bp_get_loggedin_user_username();
+}
+	function bp_get_loggedin_user_username() {
+		global $bp;
+
+		if ( bp_loggedin_user_id() ) {
+			$username = bp_core_get_username( bp_loggedin_user_id(), $bp->loggedin_user->userdata->user_nicename, $bp->loggedin_user->userdata->user_login );
+		} else {
+			$username = '';
+		}
+
+		return apply_filters( 'bp_get_loggedin_user_username', $username );
+	}
+
+/** Signup Form ***************************************************************/
+
+/**
+ * Do we have a working custom sign up page?
+ *
+ * @since BuddyPress (1.5)
+ *
+ * @uses bp_get_signup_slug() To make sure there is a slug assigned to the page
+ * @uses bp_locate_template() To make sure a template exists to provide output
+ * @return boolean True if page and template exist, false if not
+ */
+function bp_has_custom_signup_page() {
+	static $has_page = false;
+
+	if ( empty( $has_page ) )
+		$has_page = bp_get_signup_slug() && bp_locate_template( array( 'registration/register.php', 'members/register.php', 'register.php' ), false );
+
+	return (bool) $has_page;
+}
+
+/**
+ * Echoes the URL to the signup page
+ */
+function bp_signup_page() {
+	echo bp_get_signup_page();
+}
+	/**
+	 * Returns the URL to the signup page
+	 *
+	 * @return string
+	 */
+	function bp_get_signup_page() {
+		if ( bp_has_custom_signup_page() ) {
+			$page = trailingslashit( bp_get_root_domain() . '/' . bp_get_signup_slug() );
+		} else {
+			$page = bp_get_root_domain() . '/wp-signup.php';
+		}
+
+		return apply_filters( 'bp_get_signup_page', $page );
+	}
+
+/**
+ * Do we have a working custom activation page?
+ *
+ * @since BuddyPress (1.5)
+ *
+ * @uses bp_get_activate_slug() To make sure there is a slug assigned to the page
+ * @uses bp_locate_template() To make sure a template exists to provide output
+ * @return boolean True if page and template exist, false if not
+ */
+function bp_has_custom_activation_page() {
+	static $has_page = false;
+
+	if ( empty( $has_page ) )
+		$has_page = bp_get_activate_slug() && bp_locate_template( array( 'registration/activate.php', 'members/activate.php', 'activate.php' ), false );
+
+	return (bool) $has_page;
+}
+
+function bp_activation_page() {
+	echo bp_get_activation_page();
+}
+	function bp_get_activation_page() {
+		if ( bp_has_custom_activation_page() ) {
+			$page = trailingslashit( bp_get_root_domain() . '/' . bp_get_activate_slug() );
+		} else {
+			$page = trailingslashit( bp_get_root_domain() ) . 'wp-activate.php';
+		}
+
+		return apply_filters( 'bp_get_activation_page', $page );
+	}
+
+function bp_signup_username_value() {
+	echo bp_get_signup_username_value();
+}
+	function bp_get_signup_username_value() {
+		$value = '';
+		if ( isset( $_POST['signup_username'] ) )
+			$value = $_POST['signup_username'];
+
+		return apply_filters( 'bp_get_signup_username_value', $value );
+	}
+
+function bp_signup_email_value() {
+	echo bp_get_signup_email_value();
+}
+	function bp_get_signup_email_value() {
+		$value = '';
+		if ( isset( $_POST['signup_email'] ) )
+			$value = $_POST['signup_email'];
+
+		return apply_filters( 'bp_get_signup_email_value', $value );
+	}
+
+function bp_signup_with_blog_value() {
+	echo bp_get_signup_with_blog_value();
+}
+	function bp_get_signup_with_blog_value() {
+		$value = '';
+		if ( isset( $_POST['signup_with_blog'] ) )
+			$value = $_POST['signup_with_blog'];
+
+		return apply_filters( 'bp_get_signup_with_blog_value', $value );
+	}
+
+function bp_signup_blog_url_value() {
+	echo bp_get_signup_blog_url_value();
+}
+	function bp_get_signup_blog_url_value() {
+		$value = '';
+		if ( isset( $_POST['signup_blog_url'] ) )
+			$value = $_POST['signup_blog_url'];
+
+		return apply_filters( 'bp_get_signup_blog_url_value', $value );
+	}
+
+function bp_signup_blog_title_value() {
+	echo bp_get_signup_blog_title_value();
+}
+	function bp_get_signup_blog_title_value() {
+		$value = '';
+		if ( isset( $_POST['signup_blog_title'] ) )
+			$value = $_POST['signup_blog_title'];
+
+		return apply_filters( 'bp_get_signup_blog_title_value', $value );
+	}
+
+function bp_signup_blog_privacy_value() {
+	echo bp_get_signup_blog_privacy_value();
+}
+	function bp_get_signup_blog_privacy_value() {
+		$value = '';
+		if ( isset( $_POST['signup_blog_privacy'] ) )
+			$value = $_POST['signup_blog_privacy'];
+
+		return apply_filters( 'bp_get_signup_blog_privacy_value', $value );
+	}
+
+function bp_signup_avatar_dir_value() {
+	echo bp_get_signup_avatar_dir_value();
+}
+	function bp_get_signup_avatar_dir_value() {
+		global $bp;
+
+		// Check if signup_avatar_dir is passed
+		if ( !empty( $_POST['signup_avatar_dir'] ) )
+			$signup_avatar_dir = $_POST['signup_avatar_dir'];
+
+		// If not, check if global is set
+		elseif ( !empty( $bp->signup->avatar_dir ) )
+			$signup_avatar_dir = $bp->signup->avatar_dir;
+
+		// If not, set false
+		else
+			$signup_avatar_dir = false;
+
+		return apply_filters( 'bp_get_signup_avatar_dir_value', $bp->signup->avatar_dir );
+	}
+
+function bp_current_signup_step() {
+	echo bp_get_current_signup_step();
+}
+	function bp_get_current_signup_step() {
+		global $bp;
+
+		return $bp->signup->step;
+	}
+
+function bp_signup_avatar( $args = '' ) {
+	echo bp_get_signup_avatar( $args );
+}
+	function bp_get_signup_avatar( $args = '' ) {
+		global $bp;
+
+		$defaults = array(
+			'size' => bp_core_avatar_full_width(),
+			'class' => 'avatar',
+			'alt' => __( 'Your Avatar', 'buddypress' )
+		);
+
+		$r = wp_parse_args( $args, $defaults );
+		extract( $r, EXTR_SKIP );
+
+		// Avatar DIR is found
+		if ( $signup_avatar_dir = bp_get_signup_avatar_dir_value() ) {
+			$gravatar_img = bp_core_fetch_avatar( array(
+				'item_id'    => $signup_avatar_dir,
+				'object'     => 'signup',
+				'avatar_dir' => 'avatars/signups',
+				'type'       => 'full',
+				'width'      => $size,
+				'height'     => $size,
+				'alt'        => $alt,
+				'class'      => $class
+			) );
+
+		// No avatar DIR was found
+		} else {
+
+			// Set default gravatar type
+			if ( empty( $bp->grav_default->user ) )
+				$default_grav = 'wavatar';
+			else if ( 'mystery' == $bp->grav_default->user )
+				$default_grav = BP_PLUGIN_URL . 'bp-core/images/mystery-man.jpg';
+			else
+				$default_grav = $bp->grav_default->user;
+
+			// Create
+			$gravatar_url    = apply_filters( 'bp_gravatar_url', 'http://www.gravatar.com/avatar/' );
+			$md5_lcase_email = md5( strtolower( bp_get_signup_email_value() ) );
+			$gravatar_img    = '<img src="' . $gravatar_url . $md5_lcase_email . '?d=' . $default_grav . '&amp;s=' . $size . '" width="' . $size . '" height="' . $size . '" alt="' . $alt . '" class="' . $class . '" />';
+		}
+
+		return apply_filters( 'bp_get_signup_avatar', $gravatar_img, $args );
+	}
+
+function bp_signup_allowed() {
+	echo bp_get_signup_allowed();
+}
+	function bp_get_signup_allowed() {
+		global $bp;
+
+		$signup_allowed = false;
+
+		if ( is_multisite() ) {
+			if ( in_array( $bp->site_options['registration'], array( 'all', 'user' ) ) ) {
+				$signup_allowed = true;
+			}
+
+		} else {
+			if ( bp_get_option( 'users_can_register') ) {
+				$signup_allowed = true;
+			}
+		}
+
+		return apply_filters( 'bp_get_signup_allowed', $signup_allowed );
+	}
+
+/**
+ * Hook member activity feed to <head>
+ *
+ * @since BuddyPress (1.5)
+ */
+function bp_members_activity_feed() {
+	if ( !bp_is_active( 'activity' ) || !bp_is_user() )
+		return; ?>
+
+	<link rel="alternate" type="application/rss+xml" title="<?php bloginfo( 'name' ) ?> | <?php bp_displayed_user_fullname() ?> | <?php _e( 'Activity RSS Feed', 'buddypress' ) ?>" href="<?php bp_member_activity_feed_link() ?>" />
+
+<?php
+}
+add_action( 'bp_head', 'bp_members_activity_feed' );
+
+
+function bp_members_component_link( $component, $action = '', $query_args = '', $nonce = false ) {
+	echo bp_get_members_component_link( $component, $action, $query_args, $nonce );
+}
+	function bp_get_members_component_link( $component, $action = '', $query_args = '', $nonce = false ) {
+		global $bp;
+
+		// Must be displayed user
+		if ( !bp_displayed_user_id() )
+			return;
+
+		// Append $action to $url if there is no $type
+		if ( !empty( $action ) )
+			$url = bp_displayed_user_domain() . $bp->{$component}->slug . '/' . $action;
+		else
+			$url = bp_displayed_user_domain() . $bp->{$component}->slug;
+
+		// Add a slash at the end of our user url
+		$url = trailingslashit( $url );
+
+		// Add possible query arg
+		if ( !empty( $query_args ) && is_array( $query_args ) )
+			$url = add_query_arg( $query_args, $url );
+
+		// To nonce, or not to nonce...
+		if ( true === $nonce )
+			$url = wp_nonce_url( $url );
+		elseif ( is_string( $nonce ) )
+			$url = wp_nonce_url( $url, $nonce );
+
+		// Return the url, if there is one
+		if ( !empty( $url ) )
+			return $url;
+	}
Index: /tags/1.9/bp-messages/bp-messages-actions.php
===================================================================
--- /tags/1.9/bp-messages/bp-messages-actions.php	(revision 7684)
+++ /tags/1.9/bp-messages/bp-messages-actions.php	(revision 7684)
@@ -0,0 +1,97 @@
+<?php
+
+/**
+ * BuddyPress Messages Actions
+ *
+ * Action functions are exactly the same as screen functions, however they do not
+ * have a template screen associated with them. Usually they will send the user
+ * back to the default screen after execution.
+ *
+ * @package BuddyPress
+ * @subpackage MessagesActions
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+function messages_action_conversation() {
+
+	if ( !bp_is_messages_component() || !bp_is_current_action( 'view' ) )
+		return false;
+
+	$thread_id = (int)bp_action_variable( 0 );
+
+	if ( !$thread_id || !messages_is_valid_thread( $thread_id ) || ( !messages_check_thread_access( $thread_id ) && !bp_current_user_can( 'bp_moderate' ) ) )
+		bp_core_redirect( trailingslashit( bp_displayed_user_domain() . bp_get_messages_slug() ) );
+
+	// Check if a new reply has been submitted
+	if ( isset( $_POST['send'] ) ) {
+
+		// Check the nonce
+		check_admin_referer( 'messages_send_message', 'send_message_nonce' );
+
+		// Send the reply
+		if ( messages_new_message( array( 'thread_id' => $thread_id, 'subject' => ! empty( $_POST['subject'] ) ? $_POST['subject'] : false, 'content' => $_POST['content'] ) ) ) {
+			bp_core_add_message( __( 'Your reply was sent successfully', 'buddypress' ) );
+		} else {
+			bp_core_add_message( __( 'There was a problem sending your reply, please try again', 'buddypress' ), 'error' );
+		}
+
+		bp_core_redirect( bp_displayed_user_domain() . bp_get_messages_slug() . '/view/' . $thread_id . '/' );
+	}
+
+	// Mark message read
+	messages_mark_thread_read( $thread_id );
+
+	do_action( 'messages_action_conversation' );
+}
+add_action( 'bp_actions', 'messages_action_conversation' );
+
+function messages_action_delete_message() {
+
+	if ( !bp_is_messages_component() || bp_is_current_action( 'notices' ) || !bp_is_action_variable( 'delete', 0 ) )
+		return false;
+
+	$thread_id = bp_action_variable( 1 );
+
+	if ( !$thread_id || !is_numeric( $thread_id ) || !messages_check_thread_access( $thread_id ) ) {
+		bp_core_redirect( trailingslashit( bp_displayed_user_domain() . bp_get_messages_slug() . '/' . bp_current_action() ) );
+	} else {
+		if ( !check_admin_referer( 'messages_delete_thread' ) )
+			return false;
+
+		// Delete message
+		if ( !messages_delete_thread( $thread_id ) ) {
+			bp_core_add_message( __('There was an error deleting that message.', 'buddypress'), 'error' );
+		} else {
+			bp_core_add_message( __('Message deleted.', 'buddypress') );
+		}
+		bp_core_redirect( trailingslashit( bp_displayed_user_domain() . bp_get_messages_slug() . '/' . bp_current_action() ) );
+	}
+}
+add_action( 'bp_actions', 'messages_action_delete_message' );
+
+function messages_action_bulk_delete() {
+
+	if ( !bp_is_messages_component() || !bp_is_action_variable( 'bulk-delete', 0 ) )
+		return false;
+
+	$thread_ids = $_POST['thread_ids'];
+
+	if ( !$thread_ids || !messages_check_thread_access( $thread_ids ) ) {
+		bp_core_redirect( trailingslashit( bp_displayed_user_domain() . bp_get_messages_slug() . '/' . bp_current_action() ) );
+	} else {
+		if ( !check_admin_referer( 'messages_delete_thread' ) ) {
+			return false;
+		}
+
+		if ( !messages_delete_thread( $thread_ids ) ) {
+			bp_core_add_message( __('There was an error deleting messages.', 'buddypress'), 'error' );
+		} else {
+			bp_core_add_message( __('Messages deleted.', 'buddypress') );
+		}
+
+		bp_core_redirect( trailingslashit( bp_displayed_user_domain() . bp_get_messages_slug() . '/' . bp_current_action() ) );
+	}
+}
+add_action( 'bp_actions', 'messages_action_bulk_delete' );
Index: /tags/1.9/bp-messages/bp-messages-cache.php
===================================================================
--- /tags/1.9/bp-messages/bp-messages-cache.php	(revision 7684)
+++ /tags/1.9/bp-messages/bp-messages-cache.php	(revision 7684)
@@ -0,0 +1,24 @@
+<?php
+
+/**
+ * BuddyPress Messages Caching
+ *
+ * Caching functions handle the clearing of cached objects and pages on specific
+ * actions throughout BuddyPress.
+ *
+ * @package BuddyPress
+ * @subpackage SettingsLoader
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+// List actions to clear super cached pages on, if super cache is installed
+add_action( 'messages_delete_thread',  'bp_core_clear_cache' );
+add_action( 'messages_send_notice',    'bp_core_clear_cache' );
+add_action( 'messages_message_sent',   'bp_core_clear_cache' );
+
+// Don't cache message inbox/sentbox/compose as it's too problematic
+add_action( 'messages_screen_compose', 'bp_core_clear_cache' );
+add_action( 'messages_screen_sentbox', 'bp_core_clear_cache' );
+add_action( 'messages_screen_inbox',   'bp_core_clear_cache' );
Index: /tags/1.9/bp-messages/bp-messages-classes.php
===================================================================
--- /tags/1.9/bp-messages/bp-messages-classes.php	(revision 7684)
+++ /tags/1.9/bp-messages/bp-messages-classes.php	(revision 7684)
@@ -0,0 +1,554 @@
+<?php
+
+/**
+ * BuddyPress Messages Classes
+ *
+ * @package BuddyPress
+ * @subpackage MessagesClasses
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+class BP_Messages_Thread {
+	public $thread_id;
+	public $messages;
+	public $recipients;
+	public $sender_ids;
+
+	public $unread_count;
+
+	/**
+	 * The content of the last message in this thread
+	 *
+	 * @since BuddyPress (1.2)
+	 * @var string
+	 */
+	public $last_message_content;
+
+	/**
+	 * The date of the last message in this thread
+	 *
+	 * @since BuddyPress (1.2)
+	 * @var string
+	 */
+	public $last_message_date;
+
+	/**
+	 * The ID of the last message in this thread
+	 *
+	 * @since BuddyPress (1.2)
+	 * @var int
+	 */
+	public $last_message_id;
+
+	/**
+	 * The subject of the last message in this thread
+	 *
+	 * @since BuddyPress (1.2)
+	 * @var string
+	 */
+	public $last_message_subject;
+
+	/**
+	 * The user ID of the author of the last message in this thread
+	 *
+	 * @since BuddyPress (1.2)
+	 * @var int
+	 */
+	public $last_sender_id;
+
+	/**
+	 * Sort order of the messages in this thread (ASC or DESC).
+	 *
+	 * @since BuddyPress (1.5)
+	 * @var string
+	 */
+	public $messages_order;
+
+	public function __construct( $thread_id = false, $order = 'ASC' ) {
+		if ( $thread_id )
+			$this->populate( $thread_id, $order );
+	}
+
+	public function populate( $thread_id, $order ) {
+		global $wpdb, $bp;
+
+		if( 'ASC' != $order && 'DESC' != $order )
+			$order= 'ASC';
+
+		$this->messages_order = $order;
+		$this->thread_id      = $thread_id;
+
+		if ( !$this->messages = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM {$bp->messages->table_name_messages} WHERE thread_id = %d ORDER BY date_sent " . $order, $this->thread_id ) ) )
+			return false;
+
+		foreach ( (array) $this->messages as $key => $message )
+			$this->sender_ids[$message->sender_id] = $message->sender_id;
+
+		// Fetch the recipients
+		$this->recipients = $this->get_recipients();
+
+		// Get the unread count for the logged in user
+		if ( isset( $this->recipients[bp_loggedin_user_id()] ) )
+			$this->unread_count = $this->recipients[bp_loggedin_user_id()]->unread_count;
+	}
+
+	public function mark_read() {
+		BP_Messages_Thread::mark_as_read( $this->thread_id );
+	}
+
+	public function mark_unread() {
+		BP_Messages_Thread::mark_as_unread( $this->thread_id );
+	}
+
+	public function get_recipients() {
+		global $wpdb, $bp;
+
+		$recipients = array();
+		$results    = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM {$bp->messages->table_name_recipients} WHERE thread_id = %d", $this->thread_id ) );
+
+		foreach ( (array) $results as $recipient )
+			$recipients[$recipient->user_id] = $recipient;
+
+		return $recipients;
+	}
+
+	/** Static Functions ******************************************************/
+
+	public static function delete( $thread_id ) {
+		global $wpdb, $bp;
+
+		// Mark messages as deleted
+		$wpdb->query( $wpdb->prepare( "UPDATE {$bp->messages->table_name_recipients} SET is_deleted = 1 WHERE thread_id = %d AND user_id = %d", $thread_id, bp_loggedin_user_id() ) );
+
+		// Check to see if any more recipients remain for this message
+		// if not, then delete the message from the database.
+		$recipients = $wpdb->get_results( $wpdb->prepare( "SELECT id FROM {$bp->messages->table_name_recipients} WHERE thread_id = %d AND is_deleted = 0", $thread_id ) );
+
+		if ( empty( $recipients ) ) {
+			// Delete all the messages
+			$wpdb->query( $wpdb->prepare( "DELETE FROM {$bp->messages->table_name_messages} WHERE thread_id = %d", $thread_id ) );
+
+			// Delete all the recipients
+			$wpdb->query( $wpdb->prepare( "DELETE FROM {$bp->messages->table_name_recipients} WHERE thread_id = %d", $thread_id ) );
+		}
+
+		return true;
+	}
+
+	public static function get_current_threads_for_user( $user_id, $box = 'inbox', $type = 'all', $limit = null, $page = null, $search_terms = '' ) {
+		global $wpdb, $bp;
+
+		$pag_sql = $type_sql = $search_sql = '';
+		if ( $limit && $page )
+			$pag_sql = $wpdb->prepare( " LIMIT %d, %d", intval( ( $page - 1 ) * $limit), intval( $limit ) );
+
+		if ( $type == 'unread' )
+			$type_sql = " AND r.unread_count != 0 ";
+		elseif ( $type == 'read' )
+			$type_sql = " AND r.unread_count = 0 ";
+
+		if ( !empty( $search_terms ) ) {
+			$search_terms = like_escape( esc_sql( $search_terms ) );
+			$search_sql   = "AND ( subject LIKE '%%$search_terms%%' OR message LIKE '%%$search_terms%%' )";
+		}
+
+		if ( 'sentbox' == $box ) {
+			$thread_ids    = $wpdb->get_results( $wpdb->prepare( "SELECT m.thread_id, MAX(m.date_sent) AS date_sent FROM {$bp->messages->table_name_recipients} r, {$bp->messages->table_name_messages} m WHERE m.thread_id = r.thread_id AND m.sender_id = r.user_id AND m.sender_id = %d AND r.is_deleted = 0 {$search_sql} GROUP BY m.thread_id ORDER BY date_sent DESC {$pag_sql}", $user_id ) );
+			$total_threads = $wpdb->get_var( $wpdb->prepare( "SELECT COUNT( DISTINCT m.thread_id ) FROM {$bp->messages->table_name_recipients} r, {$bp->messages->table_name_messages} m WHERE m.thread_id = r.thread_id AND m.sender_id = r.user_id AND m.sender_id = %d AND r.is_deleted = 0 {$search_sql} ", $user_id ) );
+		} else {
+			$thread_ids = $wpdb->get_results( $wpdb->prepare( "SELECT m.thread_id, MAX(m.date_sent) AS date_sent FROM {$bp->messages->table_name_recipients} r, {$bp->messages->table_name_messages} m WHERE m.thread_id = r.thread_id AND r.is_deleted = 0 AND r.user_id = %d AND r.sender_only = 0 {$type_sql} {$search_sql} GROUP BY m.thread_id ORDER BY date_sent DESC {$pag_sql}", $user_id ) );
+			$total_threads = $wpdb->get_var( $wpdb->prepare( "SELECT COUNT( DISTINCT m.thread_id ) FROM {$bp->messages->table_name_recipients} r, {$bp->messages->table_name_messages} m WHERE m.thread_id = r.thread_id AND r.is_deleted = 0 AND r.user_id = %d AND r.sender_only = 0 {$type_sql} {$search_sql} ", $user_id ) );
+		}
+
+		if ( empty( $thread_ids ) )
+			return false;
+
+		// Sort threads by date_sent
+		foreach( (array) $thread_ids as $thread )
+			$sorted_threads[$thread->thread_id] = strtotime( $thread->date_sent );
+
+		arsort( $sorted_threads );
+
+		$threads = false;
+		foreach ( (array) $sorted_threads as $thread_id => $date_sent )
+			$threads[] = new BP_Messages_Thread( $thread_id );
+
+		return array( 'threads' => &$threads, 'total' => (int) $total_threads );
+	}
+
+	public static function mark_as_read( $thread_id ) {
+		global $wpdb, $bp;
+
+		$sql = $wpdb->prepare( "UPDATE {$bp->messages->table_name_recipients} SET unread_count = 0 WHERE user_id = %d AND thread_id = %d", bp_loggedin_user_id(), $thread_id );
+		$wpdb->query($sql);
+	}
+
+	public static function mark_as_unread( $thread_id ) {
+		global $wpdb, $bp;
+
+		$sql = $wpdb->prepare( "UPDATE {$bp->messages->table_name_recipients} SET unread_count = 1 WHERE user_id = %d AND thread_id = %d", bp_loggedin_user_id(), $thread_id );
+		$wpdb->query($sql);
+	}
+
+	public static function get_total_threads_for_user( $user_id, $box = 'inbox', $type = 'all' ) {
+		global $wpdb, $bp;
+
+		$exclude_sender = '';
+		if ( $box != 'sentbox' )
+			$exclude_sender = ' AND sender_only != 1';
+
+		if ( $type == 'unread' )
+			$type_sql = " AND unread_count != 0 ";
+		else if ( $type == 'read' )
+			$type_sql = " AND unread_count = 0 ";
+
+		return (int) $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(thread_id) FROM {$bp->messages->table_name_recipients} WHERE user_id = %d AND is_deleted = 0{$exclude_sender} {$type_sql}", $user_id ) );
+	}
+
+	public static function user_is_sender( $thread_id ) {
+		global $wpdb, $bp;
+
+		$sender_ids = $wpdb->get_col( $wpdb->prepare( "SELECT sender_id FROM {$bp->messages->table_name_messages} WHERE thread_id = %d", $thread_id ) );
+
+		if ( !$sender_ids )
+			return false;
+
+		return in_array( bp_loggedin_user_id(), $sender_ids );
+	}
+
+	public static function get_last_sender( $thread_id ) {
+		global $wpdb, $bp;
+
+		if ( !$sender_id = $wpdb->get_var( $wpdb->prepare( "SELECT sender_id FROM {$bp->messages->table_name_messages} WHERE thread_id = %d GROUP BY sender_id ORDER BY date_sent LIMIT 1", $thread_id ) ) )
+			return false;
+
+		return bp_core_get_userlink( $sender_id, true );
+	}
+
+	public static function get_inbox_count( $user_id = 0 ) {
+		global $wpdb, $bp;
+
+		if ( empty( $user_id ) )
+			$user_id = bp_loggedin_user_id();
+
+		$sql = $wpdb->prepare( "SELECT SUM(unread_count) FROM {$bp->messages->table_name_recipients} WHERE user_id = %d AND is_deleted = 0 AND sender_only = 0", $user_id );
+		$unread_count = $wpdb->get_var( $sql );
+
+		if ( empty( $unread_count ) || is_wp_error( $unread_count ) )
+			return 0;
+
+		return (int) $unread_count;
+	}
+
+	public static function check_access( $thread_id, $user_id = 0 ) {
+		global $wpdb, $bp;
+
+		if ( empty( $user_id ) )
+			$user_id = bp_loggedin_user_id();
+
+		return $wpdb->get_var( $wpdb->prepare( "SELECT id FROM {$bp->messages->table_name_recipients} WHERE thread_id = %d AND user_id = %d", $thread_id, $user_id ) );
+	}
+
+	public static function is_valid( $thread_id ) {
+		global $wpdb, $bp;
+
+		return $wpdb->get_var( $wpdb->prepare( "SELECT thread_id FROM {$bp->messages->table_name_messages} WHERE thread_id = %d LIMIT 1", $thread_id ) );
+	}
+
+	public static function get_recipient_links( $recipients ) {
+		if ( count( $recipients ) >= 5 )
+			return sprintf( __( '%s Recipients', 'buddypress' ), number_format_i18n( count( $recipients ) ) );
+
+		$recipient_links = array();
+
+		foreach ( (array) $recipients as $recipient ) {
+			$recipient_link = bp_core_get_userlink( $recipient->user_id );
+
+			if ( empty( $recipient_link ) ) {
+				$recipient_link = __( 'Deleted User', 'buddypress' );
+			}
+
+			$recipient_links[] = $recipient_link;
+		}
+
+		return implode( ', ', (array) $recipient_links );
+	}
+
+	public static function update_tables() {
+		global $wpdb, $bp;
+
+		$bp_prefix = bp_core_get_table_prefix();
+		$errors    = false;
+		$threads   = $wpdb->get_results( "SELECT * FROM {$bp_prefix}bp_messages_threads" );
+
+		// Nothing to update, just return true to remove the table
+		if ( empty( $threads ) )
+			return true;
+
+		foreach( (array) $threads as $thread ) {
+			$message_ids = maybe_unserialize( $thread->message_ids );
+
+			if ( !empty( $message_ids ) ) {
+				$message_ids = implode( ',', $message_ids );
+
+				// Add the thread_id to the messages table
+				if ( !$wpdb->query( $wpdb->prepare( "UPDATE {$bp->messages->table_name_messages} SET thread_id = %d WHERE id IN ({$message_ids})", $thread->id ) ) )
+					$errors = true;
+			}
+		}
+
+		if ( $errors )
+			return false;
+
+		return true;
+	}
+}
+
+class BP_Messages_Message {
+	public $id;
+	public $thread_id;
+	public $sender_id;
+	public $subject;
+	public $message;
+	public $date_sent;
+
+	public $recipients = false;
+
+	public function __construct( $id = null ) {
+		$this->date_sent = bp_core_current_time();
+		$this->sender_id = bp_loggedin_user_id();
+
+		if ( !empty( $id ) ) {
+			$this->populate( $id );
+		}
+	}
+
+	public function populate( $id ) {
+		global $wpdb, $bp;
+
+		if ( $message = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$bp->messages->table_name_messages} WHERE id = %d", $id ) ) ) {
+			$this->id        = $message->id;
+			$this->thread_id = $message->thread_id;
+			$this->sender_id = $message->sender_id;
+			$this->subject   = $message->subject;
+			$this->message   = $message->message;
+			$this->date_sent = $message->date_sent;
+		}
+	}
+
+	public function send() {
+		global $wpdb, $bp;
+
+		$this->sender_id = apply_filters( 'messages_message_sender_id_before_save', $this->sender_id, $this->id );
+		$this->thread_id = apply_filters( 'messages_message_thread_id_before_save', $this->thread_id, $this->id );
+		$this->subject   = apply_filters( 'messages_message_subject_before_save',   $this->subject,   $this->id );
+		$this->message   = apply_filters( 'messages_message_content_before_save',   $this->message,   $this->id );
+		$this->date_sent = apply_filters( 'messages_message_date_sent_before_save', $this->date_sent, $this->id );
+
+		do_action_ref_array( 'messages_message_before_save', array( &$this ) );
+
+		// Make sure we have at least one recipient before sending.
+		if ( empty( $this->recipients ) )
+			return false;
+
+		$new_thread = false;
+
+		// If we have no thread_id then this is the first message of a new thread.
+		if ( empty( $this->thread_id ) ) {
+			$this->thread_id = (int) $wpdb->get_var( "SELECT MAX(thread_id) FROM {$bp->messages->table_name_messages}" ) + 1;
+			$new_thread = true;
+		}
+
+		// First insert the message into the messages table
+		if ( !$wpdb->query( $wpdb->prepare( "INSERT INTO {$bp->messages->table_name_messages} ( thread_id, sender_id, subject, message, date_sent ) VALUES ( %d, %d, %s, %s, %s )", $this->thread_id, $this->sender_id, $this->subject, $this->message, $this->date_sent ) ) )
+			return false;
+
+		$this->id = $wpdb->insert_id;
+
+		$recipient_ids = array();
+
+		if ( $new_thread ) {
+			// Add an recipient entry for all recipients
+			foreach ( (array) $this->recipients as $recipient ) {
+				$wpdb->query( $wpdb->prepare( "INSERT INTO {$bp->messages->table_name_recipients} ( user_id, thread_id, unread_count ) VALUES ( %d, %d, 1 )", $recipient->user_id, $this->thread_id ) );
+				$recipient_ids[] = $recipient->user_id;
+			}
+
+			// Add a sender recipient entry if the sender is not in the list of recipients
+			if ( !in_array( $this->sender_id, $recipient_ids ) )
+				$wpdb->query( $wpdb->prepare( "INSERT INTO {$bp->messages->table_name_recipients} ( user_id, thread_id, sender_only ) VALUES ( %d, %d, 1 )", $this->sender_id, $this->thread_id ) );
+		} else {
+			// Update the unread count for all recipients
+			$wpdb->query( $wpdb->prepare( "UPDATE {$bp->messages->table_name_recipients} SET unread_count = unread_count + 1, sender_only = 0, is_deleted = 0 WHERE thread_id = %d AND user_id != %d", $this->thread_id, $this->sender_id ) );
+		}
+
+		messages_remove_callback_values();
+
+		do_action_ref_array( 'messages_message_after_save', array( &$this ) );
+
+		return $this->id;
+	}
+
+	public function get_recipients() {
+		global $bp, $wpdb;
+		return $wpdb->get_results( $wpdb->prepare( "SELECT user_id FROM {$bp->messages->table_name_recipients} WHERE thread_id = %d", $this->thread_id ) );
+	}
+
+	/** Static Functions ******************************************************/
+
+	public static function get_recipient_ids( $recipient_usernames ) {
+		if ( !$recipient_usernames )
+			return false;
+
+		if ( is_array( $recipient_usernames ) ) {
+			for ( $i = 0, $count = count( $recipient_usernames ); $i < $count; ++$i ) {
+				if ( $rid = bp_core_get_userid( trim($recipient_usernames[$i]) ) ) {
+					$recipient_ids[] = $rid;
+				}
+			}
+		}
+
+		return $recipient_ids;
+	}
+
+	public static function get_last_sent_for_user( $thread_id ) {
+		global $wpdb, $bp;
+		return $wpdb->get_var( $wpdb->prepare( "SELECT id FROM {$bp->messages->table_name_messages} WHERE sender_id = %d AND thread_id = %d ORDER BY date_sent DESC LIMIT 1", bp_loggedin_user_id(), $thread_id ) );
+	}
+
+	public static function is_user_sender( $user_id, $message_id ) {
+		global $wpdb, $bp;
+		return $wpdb->get_var( $wpdb->prepare( "SELECT id FROM {$bp->messages->table_name_messages} WHERE sender_id = %d AND id = %d", $user_id, $message_id ) );
+	}
+
+	public static function get_message_sender( $message_id ) {
+		global $wpdb, $bp;
+		return $wpdb->get_var( $wpdb->prepare( "SELECT sender_id FROM {$bp->messages->table_name_messages} WHERE id = %d", $message_id ) );
+	}
+}
+
+class BP_Messages_Notice {
+	public $id = null;
+	public $subject;
+	public $message;
+	public $date_sent;
+	public $is_active;
+
+	public function __construct( $id = null ) {
+		if ( $id ) {
+			$this->id = $id;
+			$this->populate($id);
+		}
+	}
+
+	public function populate() {
+		global $wpdb, $bp;
+
+		$notice = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$bp->messages->table_name_notices} WHERE id = %d", $this->id ) );
+
+		if ( $notice ) {
+			$this->subject   = $notice->subject;
+			$this->message   = $notice->message;
+			$this->date_sent = $notice->date_sent;
+			$this->is_active = $notice->is_active;
+		}
+	}
+
+	public function save() {
+		global $wpdb, $bp;
+
+		$this->subject = apply_filters( 'messages_notice_subject_before_save', $this->subject, $this->id );
+		$this->message = apply_filters( 'messages_notice_message_before_save', $this->message, $this->id );
+
+		do_action_ref_array( 'messages_notice_before_save', array( &$this ) );
+
+		if ( empty( $this->id ) )
+			$sql = $wpdb->prepare( "INSERT INTO {$bp->messages->table_name_notices} (subject, message, date_sent, is_active) VALUES (%s, %s, %s, %d)", $this->subject, $this->message, $this->date_sent, $this->is_active );
+		else
+			$sql = $wpdb->prepare( "UPDATE {$bp->messages->table_name_notices} SET subject = %s, message = %s, is_active = %d WHERE id = %d", $this->subject, $this->message, $this->is_active, $this->id );
+
+		if ( !$wpdb->query( $sql ) )
+			return false;
+
+		if ( !$id = $this->id )
+			$id = $wpdb->insert_id;
+
+		// Now deactivate all notices apart from the new one.
+		$wpdb->query( $wpdb->prepare( "UPDATE {$bp->messages->table_name_notices} SET is_active = 0 WHERE id != %d", $id ) );
+
+		bp_update_user_last_activity( bp_loggedin_user_id(), bp_core_current_time() );
+
+		do_action_ref_array( 'messages_notice_after_save', array( &$this ) );
+
+		return true;
+	}
+
+	public function activate() {
+		$this->is_active = 1;
+		return (bool) $this->save();
+	}
+
+	public function deactivate() {
+		$this->is_active = 0;
+		return (bool) $this->save();
+	}
+
+	public function delete() {
+		global $wpdb, $bp;
+
+		$sql = $wpdb->prepare( "DELETE FROM {$bp->messages->table_name_notices} WHERE id = %d", $this->id );
+
+		if ( !$wpdb->query( $sql ) )
+			return false;
+
+		return true;
+	}
+
+	/** Static Methods ********************************************************/
+
+	/**
+	 * Pulls up a list of notices
+	 *
+	 * To get all notices, pass a value of -1 to pag_num
+	 *
+	 * @param array $args See $defaults for explanation of accepted arguments
+	 * @return array $notices
+	 */
+	public static function get_notices( $args = array() ) {
+		global $wpdb, $bp;
+
+		$defaults = array(
+			'pag_num'  => 20, // Number of notices per page
+			'pag_page' => 1   // Page number
+		);
+		$r = wp_parse_args( $args, $defaults );
+		extract( $r );
+
+		$limit_sql = '';
+		if ( (int) $pag_num >= 0 ) {
+			$limit_sql = $wpdb->prepare( "LIMIT %d, %d", (int) ( ( $pag_page - 1 ) * $pag_num ), (int) $pag_num );
+		}
+
+		$notices = $wpdb->get_results( "SELECT * FROM {$bp->messages->table_name_notices} ORDER BY date_sent DESC {$limit_sql}" );
+
+		return $notices;
+	}
+
+	public static function get_total_notice_count() {
+		global $wpdb, $bp;
+
+		$notice_count = $wpdb->get_var( "SELECT COUNT(id) FROM " . $bp->messages->table_name_notices );
+
+		return $notice_count;
+	}
+
+	public static function get_active() {
+		global $wpdb, $bp;
+
+		$notice_id = $wpdb->get_var( "SELECT id FROM {$bp->messages->table_name_notices} WHERE is_active = 1" );
+
+		return new BP_Messages_Notice( $notice_id );
+	}
+}
Index: /tags/1.9/bp-messages/bp-messages-cssjs.php
===================================================================
--- /tags/1.9/bp-messages/bp-messages-cssjs.php	(revision 7684)
+++ /tags/1.9/bp-messages/bp-messages-cssjs.php	(revision 7684)
@@ -0,0 +1,56 @@
+<?php
+
+/**
+ * BuddyPress Messages CSS and JS
+ *
+ * Apply WordPress defined filters to private messages
+ *
+ * @package BuddyPress
+ * @subpackage MessagesScripts
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+function messages_add_autocomplete_js() {
+
+	// Include the autocomplete JS for composing a message.
+	if ( bp_is_messages_component() && bp_is_current_action( 'compose' ) ) {
+		add_action( 'wp_head', 'messages_autocomplete_init_jsblock' );
+
+		$min = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min';
+		wp_enqueue_script( 'bp-jquery-autocomplete',    BP_PLUGIN_URL . "bp-messages/js/autocomplete/jquery.autocomplete{$min}.js",   array( 'jquery' ), bp_get_version() );
+		wp_enqueue_script( 'bp-jquery-autocomplete-fb', BP_PLUGIN_URL . "bp-messages/js/autocomplete/jquery.autocompletefb{$min}.js", array(),           bp_get_version() );
+		wp_enqueue_script( 'bp-jquery-bgiframe',        BP_PLUGIN_URL . "bp-messages/js/autocomplete/jquery.bgiframe{$min}.js",       array(),           bp_get_version() );
+		wp_enqueue_script( 'bp-jquery-dimensions',      BP_PLUGIN_URL . "bp-messages/js/autocomplete/jquery.dimensions{$min}.js",     array(),           bp_get_version() );
+	}
+}
+add_action( 'bp_actions', 'messages_add_autocomplete_js' );
+
+function messages_add_autocomplete_css() {
+
+	if ( bp_is_messages_component() && bp_is_current_action( 'compose' ) ) {
+		$min = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min';
+		wp_enqueue_style( 'bp-messages-autocomplete', BP_PLUGIN_URL . "bp-messages/css/autocomplete/jquery.autocompletefb{$min}.css", array(), bp_get_version() );
+
+		wp_print_styles();
+	}
+}
+add_action( 'wp_head', 'messages_add_autocomplete_css' );
+
+function messages_autocomplete_init_jsblock() {
+?>
+
+	<script type="text/javascript">
+		jQuery(document).ready(function() {
+			var acfb = jQuery("ul.first").autoCompletefb({urlLookup: ajaxurl});
+
+			jQuery('#send_message_form').submit( function() {
+				var users = document.getElementById('send-to-usernames').className;
+				document.getElementById('send-to-usernames').value = String(users);
+			});
+		});
+	</script>
+
+<?php
+}
Index: /tags/1.9/bp-messages/bp-messages-filters.php
===================================================================
--- /tags/1.9/bp-messages/bp-messages-filters.php	(revision 7684)
+++ /tags/1.9/bp-messages/bp-messages-filters.php	(revision 7684)
@@ -0,0 +1,68 @@
+<?php
+
+/**
+ * BuddyPress Messages Filters
+ *
+ * Apply WordPress defined filters to private messages
+ *
+ * @package BuddyPress
+ * @subpackage MessagesFilters
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+add_filter( 'bp_get_message_notice_subject',        'wp_filter_kses', 1 );
+add_filter( 'bp_get_message_notice_text',           'wp_filter_kses', 1 );
+add_filter( 'bp_get_message_thread_subject',        'wp_filter_kses', 1 );
+add_filter( 'bp_get_message_thread_excerpt',        'wp_filter_kses', 1 );
+add_filter( 'bp_get_messages_subject_value',        'wp_filter_kses', 1 );
+add_filter( 'bp_get_messages_content_value',        'wp_filter_kses', 1 );
+add_filter( 'bp_get_the_thread_message_content',    'wp_filter_kses', 1 );
+
+add_filter( 'messages_message_content_before_save', 'wp_filter_kses', 1 );
+add_filter( 'messages_message_subject_before_save', 'wp_filter_kses', 1 );
+add_filter( 'messages_notice_message_before_save',  'wp_filter_kses', 1 );
+add_filter( 'messages_notice_subject_before_save',  'wp_filter_kses', 1 );
+
+add_filter( 'bp_get_the_thread_message_content',    'wp_filter_kses', 1 );
+add_filter( 'bp_get_the_thread_subject',            'wp_filter_kses', 1 );
+
+add_filter( 'messages_message_content_before_save', 'force_balance_tags' );
+add_filter( 'messages_message_subject_before_save', 'force_balance_tags' );
+add_filter( 'messages_notice_message_before_save',  'force_balance_tags' );
+add_filter( 'messages_notice_subject_before_save',  'force_balance_tags' );
+
+add_filter( 'bp_get_message_notice_subject',     'wptexturize' );
+add_filter( 'bp_get_message_notice_text',        'wptexturize' );
+add_filter( 'bp_get_message_thread_subject',     'wptexturize' );
+add_filter( 'bp_get_message_thread_excerpt',     'wptexturize' );
+add_filter( 'bp_get_the_thread_message_content', 'wptexturize' );
+
+add_filter( 'bp_get_message_notice_subject',     'convert_smilies', 2 );
+add_filter( 'bp_get_message_notice_text',        'convert_smilies', 2 );
+add_filter( 'bp_get_message_thread_subject',     'convert_smilies', 2 );
+add_filter( 'bp_get_message_thread_excerpt',     'convert_smilies', 2 );
+add_filter( 'bp_get_the_thread_message_content', 'convert_smilies', 2 );
+
+add_filter( 'bp_get_message_notice_subject',     'convert_chars' );
+add_filter( 'bp_get_message_notice_text',        'convert_chars' );
+add_filter( 'bp_get_message_thread_subject',     'convert_chars' );
+add_filter( 'bp_get_message_thread_excerpt',     'convert_chars' );
+add_filter( 'bp_get_the_thread_message_content', 'convert_chars' );
+
+add_filter( 'bp_get_message_notice_text',        'make_clickable', 9 );
+add_filter( 'bp_get_message_thread_excerpt',     'make_clickable', 9 );
+add_filter( 'bp_get_the_thread_message_content', 'make_clickable', 9 );
+
+add_filter( 'bp_get_message_notice_text',        'wpautop' );
+add_filter( 'bp_get_the_thread_message_content', 'wpautop' );
+
+add_filter( 'bp_get_message_notice_subject',     'stripslashes_deep' );
+add_filter( 'bp_get_message_notice_text',        'stripslashes_deep' );
+add_filter( 'bp_get_message_thread_subject',     'stripslashes_deep' );
+add_filter( 'bp_get_message_thread_excerpt',     'stripslashes_deep' );
+add_filter( 'bp_get_messages_subject_value',     'stripslashes_deep' );
+add_filter( 'bp_get_messages_content_value',     'stripslashes_deep' );
+add_filter( 'bp_get_the_thread_message_content', 'stripslashes_deep' );
+add_filter( 'bp_get_the_thread_subject',         'stripslashes_deep' );
Index: /tags/1.9/bp-messages/bp-messages-functions.php
===================================================================
--- /tags/1.9/bp-messages/bp-messages-functions.php	(revision 7684)
+++ /tags/1.9/bp-messages/bp-messages-functions.php	(revision 7684)
@@ -0,0 +1,216 @@
+<?php
+
+/**
+ * BuddyPress Messages Functions
+ *
+ * Business functions are where all the magic happens in BuddyPress. They will
+ * handle the actual saving or manipulation of information. Usually they will
+ * hand off to a database class for data access, then return
+ * true or false on success or failure.
+ *
+ * @package BuddyPress
+ * @subpackage MessagesFunctions
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+function messages_new_message( $args = '' ) {
+
+	$defaults = array (
+		'sender_id'  => bp_loggedin_user_id(),
+		'thread_id'  => false, // false for a new message, thread id for a reply to a thread.
+		'recipients' => false, // Can be an array of usernames, user_ids or mixed.
+		'subject'    => false,
+		'content'    => false,
+		'date_sent'  => bp_core_current_time()
+	);
+
+	$r = wp_parse_args( $args, $defaults );
+	extract( $r, EXTR_SKIP );
+
+	if ( empty( $sender_id ) || empty( $content ) )
+		return false;
+
+	// Create a new message object
+	$message            = new BP_Messages_Message;
+	$message->thread_id = $thread_id;
+	$message->sender_id = $sender_id;
+	$message->subject   = $subject;
+	$message->message   = $content;
+	$message->date_sent = $date_sent;
+
+	// If we have a thread ID, use the existing recipients, otherwise use the recipients passed
+	if ( !empty( $thread_id ) ) {
+		$thread = new BP_Messages_Thread( $thread_id );
+		$message->recipients = $thread->get_recipients();
+
+		// Strip the sender from the recipient list if they exist
+		if ( isset( $message->recipients[$sender_id] ) )
+			unset( $message->recipients[$sender_id] );
+
+		if ( empty( $message->subject ) )
+			$message->subject = sprintf( __( 'Re: %s', 'buddypress' ), $thread->messages[0]->subject );
+
+	// No thread ID, so make some adjustments
+	} else {
+		if ( empty( $recipients ) )
+			return false;
+
+		if ( empty( $message->subject ) )
+			$message->subject = __( 'No Subject', 'buddypress' );
+
+		$recipient_ids 	    = array();
+
+		// Invalid recipients are added to an array, for future enhancements
+		$invalid_recipients = array();
+
+		// Loop the recipients and convert all usernames to user_ids where needed
+		foreach( (array) $recipients as $recipient ) {
+			$recipient = trim( $recipient );
+
+			if ( empty( $recipient ) )
+				continue;
+
+			$recipient_id = false;
+
+			// check user_login / nicename columns first
+			// @see http://buddypress.trac.wordpress.org/ticket/5151
+			if ( bp_is_username_compatibility_mode() ) {
+				$recipient_id = bp_core_get_userid( urldecode( $recipient ) );
+			} else {
+				$recipient_id = bp_core_get_userid_from_nicename( $recipient );
+			}
+
+			// check against user ID column if no match and if passed recipient is numeric
+			if ( ! $recipient_id && is_numeric( $recipient ) ) {
+				if ( bp_core_get_core_userdata( (int) $recipient ) ) {
+					$recipient_id = (int) $recipient;
+				}
+			}
+
+			if ( ! $recipient_id ) {
+				$invalid_recipients[] = $recipient;
+			} else {
+				$recipient_ids[] = (int) $recipient_id;
+			}
+		}
+
+		// Strip the sender from the recipient list if they exist
+		if ( $key = array_search( $sender_id, (array) $recipient_ids ) )
+			unset( $recipient_ids[$key] );
+
+		// Remove duplicates
+		$recipient_ids = array_unique( (array) $recipient_ids );
+
+		if ( empty( $recipient_ids ) )
+			return false;
+
+		// Format this to match existing recipients
+		foreach( (array) $recipient_ids as $i => $recipient_id ) {
+			$message->recipients[$i]          = new stdClass;
+			$message->recipients[$i]->user_id = $recipient_id;
+		}
+	}
+
+	if ( $message->send() ) {
+		do_action_ref_array( 'messages_message_sent', array( &$message ) );
+
+		return $message->thread_id;
+	}
+
+	return false;
+}
+
+
+function messages_send_notice( $subject, $message ) {
+	if ( !bp_current_user_can( 'bp_moderate' ) || empty( $subject ) || empty( $message ) ) {
+		return false;
+
+	// Has access to send notices, lets do it.
+	} else {
+		$notice            = new BP_Messages_Notice;
+		$notice->subject   = $subject;
+		$notice->message   = $message;
+		$notice->date_sent = bp_core_current_time();
+		$notice->is_active = 1;
+		$notice->save(); // send it.
+
+		do_action_ref_array( 'messages_send_notice', array( $subject, $message ) );
+
+		return true;
+	}
+}
+
+function messages_delete_thread( $thread_ids ) {
+	do_action( 'messages_before_delete_thread', $thread_ids );
+
+	if ( is_array( $thread_ids ) ) {
+		$error = 0;
+		for ( $i = 0, $count = count( $thread_ids ); $i < $count; ++$i ) {
+			if ( !$status = BP_Messages_Thread::delete( $thread_ids[$i]) ) {
+				$error = 1;
+			}
+		}
+
+		if ( !empty( $error ) )
+			return false;
+
+		do_action( 'messages_delete_thread', $thread_ids );
+
+		return true;
+	} else {
+		if ( !BP_Messages_Thread::delete( $thread_ids ) )
+			return false;
+
+		do_action( 'messages_delete_thread', $thread_ids );
+
+		return true;
+	}
+}
+
+function messages_check_thread_access( $thread_id, $user_id = 0 ) {
+	if ( empty( $user_id ) )
+		$user_id = bp_loggedin_user_id();
+
+	return BP_Messages_Thread::check_access( $thread_id, $user_id );
+}
+
+function messages_mark_thread_read( $thread_id ) {
+	return BP_Messages_Thread::mark_as_read( $thread_id );
+}
+
+function messages_mark_thread_unread( $thread_id ) {
+	return BP_Messages_Thread::mark_as_unread( $thread_id );
+}
+
+function messages_add_callback_values( $recipients, $subject, $content ) {
+	@setcookie( 'bp_messages_send_to', $recipients, time() + 60 * 60 * 24, COOKIEPATH );
+	@setcookie( 'bp_messages_subject', $subject,    time() + 60 * 60 * 24, COOKIEPATH );
+	@setcookie( 'bp_messages_content', $content,    time() + 60 * 60 * 24, COOKIEPATH );
+}
+
+function messages_remove_callback_values() {
+	@setcookie( 'bp_messages_send_to', false, time() - 1000, COOKIEPATH );
+	@setcookie( 'bp_messages_subject', false, time() - 1000, COOKIEPATH );
+	@setcookie( 'bp_messages_content', false, time() - 1000, COOKIEPATH );
+}
+
+function messages_get_unread_count( $user_id = 0 ) {
+	if ( empty( $user_id ) )
+		$user_id = bp_loggedin_user_id();
+
+	return BP_Messages_Thread::get_inbox_count( $user_id );
+}
+
+function messages_is_user_sender( $user_id, $message_id ) {
+	return BP_Messages_Message::is_user_sender( $user_id, $message_id );
+}
+
+function messages_get_message_sender( $message_id ) {
+	return BP_Messages_Message::get_message_sender( $message_id );
+}
+
+function messages_is_valid_thread( $thread_id ) {
+	return BP_Messages_Thread::is_valid( $thread_id );
+}
Index: /tags/1.9/bp-messages/bp-messages-loader.php
===================================================================
--- /tags/1.9/bp-messages/bp-messages-loader.php	(revision 7684)
+++ /tags/1.9/bp-messages/bp-messages-loader.php	(revision 7684)
@@ -0,0 +1,271 @@
+<?php
+
+/**
+ * BuddyPress Messages Loader
+ *
+ * A private messages component, for users to send messages to each other
+ *
+ * @package BuddyPress
+ * @subpackage MessagesLoader
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+class BP_Messages_Component extends BP_Component {
+	/**
+	 * If this is true, the Message autocomplete will return friends only, unless
+	 * this is set to false, in which any matching users will be returned.
+	 *
+	 * @since BuddyPress (1.5)
+	 * @var bool
+	 */
+	public $autocomplete_all;
+
+	/**
+	 * Start the messages component creation process
+	 *
+	 * @since BuddyPress (1.5)
+	 */
+	function __construct() {
+		parent::start(
+			'messages',
+			__( 'Private Messages', 'buddypress' ),
+			BP_PLUGIN_DIR,
+			array(
+				'adminbar_myaccount_order' => 50
+			)
+		);
+	}
+
+	/**
+	 * Include files
+	 */
+	public function includes( $includes = array() ) {
+
+		// Files to include
+		$includes = array(
+			'cssjs',
+			'cache',
+			'actions',
+			'screens',
+			'classes',
+			'filters',
+			'template',
+			'functions',
+			'notifications',
+			'widgets',
+		);
+
+		parent::includes( $includes );
+	}
+
+	/**
+	 * Setup globals
+	 *
+	 * The BP_MESSAGES_SLUG constant is deprecated, and only used here for
+	 * backwards compatibility.
+	 *
+	 * @since BuddyPress (1.5)
+	 */
+	public function setup_globals( $args = array() ) {
+		$bp = buddypress();
+
+		// Define a slug, if necessary
+		if ( !defined( 'BP_MESSAGES_SLUG' ) )
+			define( 'BP_MESSAGES_SLUG', $this->id );
+
+		// Global tables for messaging component
+		$global_tables = array(
+			'table_name_notices'    => $bp->table_prefix . 'bp_messages_notices',
+			'table_name_messages'   => $bp->table_prefix . 'bp_messages_messages',
+			'table_name_recipients' => $bp->table_prefix . 'bp_messages_recipients'
+		);
+
+		// All globals for messaging component.
+		// Note that global_tables is included in this array.
+		$globals = array(
+			'slug'                  => BP_MESSAGES_SLUG,
+			'has_directory'         => false,
+			'notification_callback' => 'messages_format_notifications',
+			'search_string'         => __( 'Search Messages...', 'buddypress' ),
+			'global_tables'         => $global_tables
+		);
+
+		$this->autocomplete_all = defined( 'BP_MESSAGES_AUTOCOMPLETE_ALL' );
+
+		parent::setup_globals( $globals );
+	}
+
+	/**
+	 * Setup BuddyBar navigation
+	 */
+	public function setup_nav( $main_nav = array(), $sub_nav = array() ) {
+
+		$name = sprintf( __( 'Messages <span>%s</span>', 'buddypress' ), bp_get_total_unread_messages_count() );
+
+		// Add 'Messages' to the main navigation
+		$main_nav = array(
+			'name'                    => $name,
+			'slug'                    => $this->slug,
+			'position'                => 50,
+			'show_for_displayed_user' => false,
+			'screen_function'         => 'messages_screen_inbox',
+			'default_subnav_slug'     => 'inbox',
+			'item_css_id'             => $this->id
+		);
+
+		// Determine user to use
+		if ( bp_displayed_user_domain() ) {
+			$user_domain = bp_displayed_user_domain();
+		} elseif ( bp_loggedin_user_domain() ) {
+			$user_domain = bp_loggedin_user_domain();
+		} else {
+			return;
+		}
+
+		// Link to user messages
+		$messages_link = trailingslashit( $user_domain . $this->slug );
+
+		// Add the subnav items to the profile
+		$sub_nav[] = array(
+			'name'            => __( 'Inbox', 'buddypress' ),
+			'slug'            => 'inbox',
+			'parent_url'      => $messages_link,
+			'parent_slug'     => $this->slug,
+			'screen_function' => 'messages_screen_inbox',
+			'position'        => 10,
+			'user_has_access' => bp_core_can_edit_settings()
+		);
+
+		$sub_nav[] = array(
+			'name'            => __( 'Sent', 'buddypress' ),
+			'slug'            => 'sentbox',
+			'parent_url'      => $messages_link,
+			'parent_slug'     => $this->slug,
+			'screen_function' => 'messages_screen_sentbox',
+			'position'        => 20,
+			'user_has_access' => bp_core_can_edit_settings()
+		);
+
+		$sub_nav[] = array(
+			'name'            => __( 'Compose', 'buddypress' ),
+			'slug'            => 'compose',
+			'parent_url'      => $messages_link,
+			'parent_slug'     => $this->slug,
+			'screen_function' => 'messages_screen_compose',
+			'position'        => 30,
+			'user_has_access' => bp_core_can_edit_settings()
+		);
+
+		if ( bp_current_user_can( 'bp_moderate' ) ) {
+			$sub_nav[] = array(
+				'name'            => __( 'Notices', 'buddypress' ),
+				'slug'            => 'notices',
+				'parent_url'      => $messages_link,
+				'parent_slug'     => $this->slug,
+				'screen_function' => 'messages_screen_notices',
+				'position'        => 90,
+				'user_has_access' => bp_current_user_can( 'bp_moderate' )
+			);
+		}
+
+		parent::setup_nav( $main_nav, $sub_nav );
+	}
+
+	/**
+	 * Set up the Toolbar
+	 */
+	public function setup_admin_bar( $wp_admin_nav = array() ) {
+		$bp = buddypress();
+
+		// Menus for logged in user
+		if ( is_user_logged_in() ) {
+
+			// Setup the logged in user variables
+			$user_domain   = bp_loggedin_user_domain();
+			$messages_link = trailingslashit( $user_domain . $this->slug );
+
+			// Unread message count
+			$count = messages_get_unread_count();
+			if ( !empty( $count ) ) {
+				$title = sprintf( __( 'Messages <span class="count">%s</span>', 'buddypress' ), number_format_i18n( $count ) );
+				$inbox = sprintf( __( 'Inbox <span class="count">%s</span>',    'buddypress' ), number_format_i18n( $count ) );
+			} else {
+				$title = __( 'Messages', 'buddypress' );
+				$inbox = __( 'Inbox',    'buddypress' );
+			}
+
+			// Add main Messages menu
+			$wp_admin_nav[] = array(
+				'parent' => $bp->my_account_menu_id,
+				'id'     => 'my-account-' . $this->id,
+				'title'  => $title,
+				'href'   => trailingslashit( $messages_link )
+			);
+
+			// Inbox
+			$wp_admin_nav[] = array(
+				'parent' => 'my-account-' . $this->id,
+				'id'     => 'my-account-' . $this->id . '-inbox',
+				'title'  => $inbox,
+				'href'   => trailingslashit( $messages_link . 'inbox' )
+			);
+
+			// Sent Messages
+			$wp_admin_nav[] = array(
+				'parent' => 'my-account-' . $this->id,
+				'id'     => 'my-account-' . $this->id . '-sentbox',
+				'title'  => __( 'Sent', 'buddypress' ),
+				'href'   => trailingslashit( $messages_link . 'sentbox' )
+			);
+
+			// Compose Message
+			$wp_admin_nav[] = array(
+				'parent' => 'my-account-' . $this->id,
+				'id'     => 'my-account-' . $this->id . '-compose',
+				'title'  => __( 'Compose', 'buddypress' ),
+				'href'   => trailingslashit( $messages_link . 'compose' )
+			);
+
+			// Site Wide Notices
+			if ( bp_current_user_can( 'bp_moderate' ) ) {
+				$wp_admin_nav[] = array(
+					'parent' => 'my-account-' . $this->id,
+					'id'     => 'my-account-' . $this->id . '-notices',
+					'title'  => __( 'All Member Notices', 'buddypress' ),
+					'href'   => trailingslashit( $messages_link . 'notices' )
+				);
+			}
+		}
+
+		parent::setup_admin_bar( $wp_admin_nav );
+	}
+
+	/**
+	 * Sets up the title for pages and <title>
+	 */
+	function setup_title() {
+		$bp = buddypress();
+
+		if ( bp_is_messages_component() ) {
+			if ( bp_is_my_profile() ) {
+				$bp->bp_options_title = __( 'My Messages', 'buddypress' );
+			} else {
+				$bp->bp_options_avatar = bp_core_fetch_avatar( array(
+					'item_id' => bp_displayed_user_id(),
+					'type'    => 'thumb',
+					'alt'     => sprintf( __( 'Profile picture of %s', 'buddypress' ), bp_get_displayed_user_fullname() )
+				) );
+				$bp->bp_options_title = bp_get_displayed_user_fullname();
+			}
+		}
+
+		parent::setup_title();
+	}
+}
+
+function bp_setup_messages() {
+	buddypress()->messages = new BP_Messages_Component();
+}
+add_action( 'bp_setup_components', 'bp_setup_messages', 6 );
Index: /tags/1.9/bp-messages/bp-messages-notifications.php
===================================================================
--- /tags/1.9/bp-messages/bp-messages-notifications.php	(revision 7684)
+++ /tags/1.9/bp-messages/bp-messages-notifications.php	(revision 7684)
@@ -0,0 +1,191 @@
+<?php
+
+/**
+ * BuddyPress Messages Notifications
+ *
+ * @package BuddyPress
+ * @subpackage MessagesNotifications
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/** Email *********************************************************************/
+
+/**
+ * Email message recipients to alert them of a new unread private message
+ *
+ * @since BuddyPress (1.0)
+ * @param array $raw_args
+ */
+function messages_notification_new_message( $raw_args = array() ) {
+
+	// Cast possible $message object as an array
+	if ( is_object( $raw_args ) ) {
+		$args = (array) $raw_args;
+	} else {
+		$args = $raw_args;
+	}
+
+	// These should be extracted below
+	$recipients    = array();
+	$email_subject = $email_content = '';
+	$sender_id     = 0;
+
+	// Barf
+	extract( $args );
+
+	// Get the sender display name
+	$sender_name = bp_core_get_user_displayname( $sender_id );
+
+	// Bail if no recipients
+	if ( ! empty( $recipients ) ) {
+
+		foreach ( $recipients as $recipient ) {
+
+			if ( $sender_id == $recipient->user_id || 'no' == bp_get_user_meta( $recipient->user_id, 'notification_messages_new_message', true ) ) {
+				continue;
+			}
+
+			// User data and links
+			$ud = get_userdata( $recipient->user_id );
+
+			// Bail if user cannot be found
+			if ( empty( $ud ) ) {
+				continue;
+			}
+
+			$message_link  = bp_core_get_user_domain( $recipient->user_id ) . bp_get_messages_slug() .'/';
+			$settings_slug = function_exists( 'bp_get_settings_slug' ) ? bp_get_settings_slug() : 'settings';
+			$settings_link = bp_core_get_user_domain( $recipient->user_id ) . $settings_slug . '/notifications/';
+
+			// Sender info
+			$sender_name   = stripslashes( $sender_name );
+			$subject       = stripslashes( wp_filter_kses( $subject ) );
+			$content       = stripslashes( wp_filter_kses( $message ) );
+
+			// Set up and send the message
+			$email_to      = $ud->user_email;
+			$email_subject = bp_get_email_subject( array( 'text' => sprintf( __( 'New message from %s', 'buddypress' ), $sender_name ) ) );
+
+			$email_content = sprintf( __(
+'%1$s sent you a new message:
+
+Subject: %2$s
+
+"%3$s"
+
+To view and read your messages please log in and visit: %4$s
+
+---------------------
+', 'buddypress' ), $sender_name, $subject, $content, $message_link );
+
+			// Only show the disable notifications line if the settings component is enabled
+			if ( bp_is_active( 'settings' ) ) {
+				$email_content .= sprintf( __( 'To disable these notifications please log in and go to: %s', 'buddypress' ), $settings_link );
+			}
+
+			// Send the message
+			$email_to      = apply_filters( 'messages_notification_new_message_to',      $email_to );
+			$email_subject = apply_filters( 'messages_notification_new_message_subject', $email_subject, $sender_name );
+			$email_content = apply_filters( 'messages_notification_new_message_message', $email_content, $sender_name, $subject, $content, $message_link, $settings_link );
+
+			wp_mail( $email_to, $email_subject, $email_content );
+		}
+	}
+
+	do_action( 'bp_messages_sent_notification_email', $recipients, $email_subject, $email_content, $args );
+}
+add_action( 'messages_message_sent', 'messages_notification_new_message', 10 );
+
+/** Notifications *************************************************************/
+
+/**
+ * Format the BuddyBar/Toolbar notifications for the Messages component
+ *
+ * @since BuddyPress (1.0)
+ * @param string $action The kind of notification being rendered
+ * @param int $item_id The primary item id
+ * @param int $secondary_item_id The secondary item id
+ * @param int $total_items The total number of messaging-related notifications waiting for the user
+ * @param string $format 'string' for BuddyBar-compatible notifications; 'array' for WP Toolbar
+ */
+function messages_format_notifications( $action, $item_id, $secondary_item_id, $total_items, $format = 'string' ) {
+
+	if ( 'new_message' === $action ) {
+		$link  = trailingslashit( bp_loggedin_user_domain() . bp_get_messages_slug() . '/inbox' );
+		$title = __( 'Inbox', 'buddypress' );
+
+		if ( (int) $total_items > 1 ) {
+			$text   = sprintf( __('You have %d new messages', 'buddypress' ), (int) $total_items );
+			$filter = 'bp_messages_multiple_new_message_notification';
+		} else {
+			if ( !empty( $secondary_item_id ) ) {
+				$text = sprintf( __('You have %d new message from %s', 'buddypress' ), (int) $total_items, bp_core_get_user_displayname( $secondary_item_id ) );
+			} else {
+				$text = sprintf( __('You have %d new message',         'buddypress' ), (int) $total_items );
+			}
+			$filter = 'bp_messages_single_new_message_notification';
+		}
+	}
+
+	if ( 'string' === $format ) {
+		$return = apply_filters( $filter, '<a href="' . esc_url( $link ) . '" title="' . esc_attr( $title ) . '">' . esc_html( $text ) . '</a>', (int) $total_items, $text, $link, $item_id, $secondary_item_id );
+	} else {
+		$return = apply_filters( $filter, array(
+			'text' => $text,
+			'link' => $link
+		), $link, (int) $total_items, $text, $link, $item_id, $secondary_item_id );
+	}
+
+	do_action( 'messages_format_notifications', $action, $item_id, $secondary_item_id, $total_items );
+
+	return $return;
+}
+
+/**
+ * Send notifications to message recipients
+ *
+ * @since BuddyPress (1.9.0)
+ * @param obj $message
+ */
+function bp_messages_message_sent_add_notification( $message ) {
+	if ( bp_is_active( 'notifications' ) && ! empty( $message->recipients ) ) {
+		foreach ( (array) $message->recipients as $recipient ) {
+			bp_notifications_add_notification( array(
+				'user_id'           => $recipient->user_id,
+				'item_id'           => $message->id,
+				'secondary_item_id' => $message->sender_id,
+				'component_name'    => buddypress()->messages->id,
+				'component_action'  => 'new_message',
+				'date_notified'     => bp_core_current_time(),
+				'is_new'            => 1,
+			) );
+		}
+	}
+}
+add_action( 'messages_message_sent', 'bp_messages_message_sent_add_notification', 10 );
+
+/**
+ * Mark new message notifications when member views their inbox.
+ *
+ * @since BuddyPress (1.9.0)
+ */
+function bp_messages_screen_inbox_mark_notifications() {
+	if ( bp_is_active( 'notifications' ) ) {
+		bp_notifications_mark_notifications_by_type( bp_loggedin_user_id(), buddypress()->messages->id, 'new_message' );
+	}
+}
+add_action( 'messages_screen_inbox', 'bp_messages_screen_inbox_mark_notifications', 10 );
+
+/**
+ * Mark new message notification when member reads a message thread directly.
+ *
+ * @since BuddyPress (1.9.0)
+ */
+function bp_messages_screen_conversation_mark_notifications() {
+	if ( bp_is_active( 'notifications' ) ) {
+		bp_notifications_mark_notifications_by_item_id( bp_loggedin_user_id(), (int) bp_action_variable( 0 ), buddypress()->messages->id, 'new_message' );
+	}
+}
+add_action( 'messages_screen_conversation', 'bp_messages_screen_inbox_mark_notifications', 10 );
Index: /tags/1.9/bp-messages/bp-messages-screens.php
===================================================================
--- /tags/1.9/bp-messages/bp-messages-screens.php	(revision 7684)
+++ /tags/1.9/bp-messages/bp-messages-screens.php	(revision 7684)
@@ -0,0 +1,188 @@
+<?php
+
+/**
+ * BuddyPress Messages Screens
+ *
+ * Screen functions are the controllers of BuddyPress. They will execute when their
+ * specific URL is caught. They will first save or manipulate data using business
+ * functions, then pass on the user to a template file.
+ *
+ * @package BuddyPress
+ * @subpackage MessagesScreens
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+function messages_screen_inbox() {
+	if ( bp_action_variables() ) {
+		bp_do_404();
+		return;
+	}
+
+	do_action( 'messages_screen_inbox' );
+	bp_core_load_template( apply_filters( 'messages_template_inbox', 'members/single/home' ) );
+}
+
+function messages_screen_sentbox() {
+	if ( bp_action_variables() ) {
+		bp_do_404();
+		return;
+	}
+
+	do_action( 'messages_screen_sentbox' );
+	bp_core_load_template( apply_filters( 'messages_template_sentbox', 'members/single/home' ) );
+}
+
+function messages_screen_compose() {
+	global $bp;
+
+	if ( bp_action_variables() ) {
+		bp_do_404();
+		return;
+	}
+
+	// Remove any saved message data from a previous session.
+	messages_remove_callback_values();
+
+	// Check if the message form has been submitted
+	if ( isset( $_POST['send'] ) ) {
+
+		// Check the nonce
+		check_admin_referer( 'messages_send_message' );
+
+		// Check we have what we need
+		if ( empty( $_POST['subject'] ) || empty( $_POST['content'] ) ) {
+			bp_core_add_message( __( 'There was an error sending that message, please try again', 'buddypress' ), 'error' );
+		} else {
+			// If this is a notice, send it
+			if ( isset( $_POST['send-notice'] ) ) {
+				if ( messages_send_notice( $_POST['subject'], $_POST['content'] ) ) {
+					bp_core_add_message( __( 'Notice sent successfully!', 'buddypress' ) );
+					bp_core_redirect( bp_loggedin_user_domain() . $bp->messages->slug . '/inbox/' );
+				} else {
+					bp_core_add_message( __( 'There was an error sending that notice, please try again', 'buddypress' ), 'error' );
+				}
+			} else {
+				// Filter recipients into the format we need - array( 'username/userid', 'username/userid' )
+				$autocomplete_recipients = explode( ',', $_POST['send-to-input'] );
+				$typed_recipients        = explode( ' ', $_POST['send_to_usernames'] );
+				$recipients              = array_merge( (array) $autocomplete_recipients, (array) $typed_recipients );
+				$recipients              = apply_filters( 'bp_messages_recipients', $recipients );
+
+				// Send the message
+				if ( $thread_id = messages_new_message( array( 'recipients' => $recipients, 'subject' => $_POST['subject'], 'content' => $_POST['content'] ) ) ) {
+					bp_core_add_message( __( 'Message sent successfully!', 'buddypress' ) );
+					bp_core_redirect( bp_loggedin_user_domain() . $bp->messages->slug . '/view/' . $thread_id . '/' );
+				} else {
+					bp_core_add_message( __( 'There was an error sending that message, please try again', 'buddypress' ), 'error' );
+				}
+			}
+		}
+	}
+
+	do_action( 'messages_screen_compose' );
+
+	bp_core_load_template( apply_filters( 'messages_template_compose', 'members/single/home' ) );
+}
+
+function messages_screen_conversation() {
+
+	// Bail if not viewing a single message
+	if ( !bp_is_messages_component() || !bp_is_current_action( 'view' ) )
+		return false;
+
+	$thread_id = (int) bp_action_variable( 0 );
+
+	if ( empty( $thread_id ) || !messages_is_valid_thread( $thread_id ) || ( !messages_check_thread_access( $thread_id ) && !bp_current_user_can( 'bp_moderate' ) ) )
+		bp_core_redirect( trailingslashit( bp_displayed_user_domain() . bp_get_messages_slug() ) );
+
+	// Load up BuddyPress one time
+	$bp = buddypress();
+
+	// Decrease the unread count in the nav before it's rendered
+	$bp->bp_nav[$bp->messages->slug]['name'] = sprintf( __( 'Messages <span>%s</span>', 'buddypress' ), bp_get_total_unread_messages_count() );
+
+	do_action( 'messages_screen_conversation' );
+
+	bp_core_load_template( apply_filters( 'messages_template_view_message', 'members/single/home' ) );
+}
+add_action( 'bp_screens', 'messages_screen_conversation' );
+
+function messages_screen_notices() {
+	global $notice_id;
+
+	if ( !bp_current_user_can( 'bp_moderate' ) )
+		return false;
+
+	$notice_id = (int)bp_action_variable( 1 );
+
+	if ( !empty( $notice_id ) && is_numeric( $notice_id ) ) {
+		$notice = new BP_Messages_Notice( $notice_id );
+
+		if ( bp_is_action_variable( 'deactivate', 0 ) ) {
+			if ( !$notice->deactivate() ) {
+				bp_core_add_message( __('There was a problem deactivating that notice.', 'buddypress'), 'error' );
+			} else {
+				bp_core_add_message( __('Notice deactivated.', 'buddypress') );
+			}
+		} else if ( bp_is_action_variable( 'activate', 0 ) ) {
+			if ( !$notice->activate() ) {
+				bp_core_add_message( __('There was a problem activating that notice.', 'buddypress'), 'error' );
+			} else {
+				bp_core_add_message( __('Notice activated.', 'buddypress') );
+			}
+		} else if ( bp_is_action_variable( 'delete' ) ) {
+			if ( !$notice->delete() ) {
+				bp_core_add_message( __('There was a problem deleting that notice.', 'buddypress'), 'buddypress' );
+			} else {
+				bp_core_add_message( __('Notice deleted.', 'buddypress') );
+			}
+		}
+		bp_core_redirect( trailingslashit( bp_loggedin_user_domain() . bp_get_messages_slug() . '/notices' ) );
+	}
+
+	if ( bp_action_variables() ) {
+		bp_do_404();
+		return;
+	}
+
+	do_action( 'messages_screen_notices' );
+
+	bp_core_load_template( apply_filters( 'messages_template_notices', 'members/single/home' ) );
+}
+
+function messages_screen_notification_settings() {
+	if ( bp_action_variables() ) {
+		bp_do_404();
+		return;
+	}
+
+	if ( !$new_messages = bp_get_user_meta( bp_displayed_user_id(), 'notification_messages_new_message', true ) )
+		$new_messages = 'yes'; ?>
+
+	<table class="notification-settings" id="messages-notification-settings">
+		<thead>
+			<tr>
+				<th class="icon"></th>
+				<th class="title"><?php _e( 'Messages', 'buddypress' ) ?></th>
+				<th class="yes"><?php _e( 'Yes', 'buddypress' ) ?></th>
+				<th class="no"><?php _e( 'No', 'buddypress' )?></th>
+			</tr>
+		</thead>
+
+		<tbody>
+			<tr id="messages-notification-settings-new-message">
+				<td></td>
+				<td><?php _e( 'A member sends you a new message', 'buddypress' ) ?></td>
+				<td class="yes"><input type="radio" name="notifications[notification_messages_new_message]" value="yes" <?php checked( $new_messages, 'yes', true ) ?>/></td>
+				<td class="no"><input type="radio" name="notifications[notification_messages_new_message]" value="no" <?php checked( $new_messages, 'no', true ) ?>/></td>
+			</tr>
+
+			<?php do_action( 'messages_screen_notification_settings' ) ?>
+		</tbody>
+	</table>
+
+<?php
+}
+add_action( 'bp_notification_settings', 'messages_screen_notification_settings', 2 );
Index: /tags/1.9/bp-messages/bp-messages-template.php
===================================================================
--- /tags/1.9/bp-messages/bp-messages-template.php	(revision 7684)
+++ /tags/1.9/bp-messages/bp-messages-template.php	(revision 7684)
@@ -0,0 +1,1012 @@
+<?php
+
+/**
+ * BuddyPress Messages Template Tags
+ *
+ * @package BuddyPress
+ * @subpackage MessagesTemplate
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/**
+ * Message Box Template Class
+ */
+class BP_Messages_Box_Template {
+	var $current_thread = -1;
+	var $current_thread_count;
+	var $total_thread_count;
+	var $threads;
+	var $thread;
+
+	var $in_the_loop;
+	var $user_id;
+	var $box;
+
+	var $pag_page;
+	var $pag_num;
+	var $pag_links;
+	var $search_terms;
+
+	function __construct( $user_id, $box, $per_page, $max, $type, $search_terms, $page_arg = 'mpage' ) {
+		$this->pag_page = isset( $_GET[$page_arg] ) ? intval( $_GET[$page_arg] ) : 1;
+		$this->pag_num  = isset( $_GET['num'] )   ? intval( $_GET['num'] )   : $per_page;
+
+		$this->user_id      = $user_id;
+		$this->box          = $box;
+		$this->type         = $type;
+		$this->search_terms = $search_terms;
+
+		if ( 'notices' == $this->box ) {
+			$this->threads = BP_Messages_Notice::get_notices( array(
+				'pag_num'  => $this->pag_num,
+				'pag_page' => $this->pag_page
+			) );
+		} else {
+			$threads = BP_Messages_Thread::get_current_threads_for_user( $this->user_id, $this->box, $this->type, $this->pag_num, $this->pag_page, $this->search_terms );
+
+			$this->threads            = $threads['threads'];
+			$this->total_thread_count = $threads['total'];
+		}
+
+		if ( !$this->threads ) {
+			$this->thread_count       = 0;
+			$this->total_thread_count = 0;
+		} else {
+			$total_notice_count = BP_Messages_Notice::get_total_notice_count();
+
+			if ( !$max || $max >= (int) $total_notice_count ) {
+				if ( 'notices' == $this->box ) {
+					$this->total_thread_count = (int) $total_notice_count;
+				}
+			} else {
+				$this->total_thread_count = (int) $max;
+			}
+
+			if ( $max ) {
+				if ( $max >= count( $this->threads ) ) {
+					$this->thread_count = count( $this->threads );
+				} else {
+					$this->thread_count = (int) $max;
+				}
+			} else {
+				$this->thread_count = count( $this->threads );
+			}
+		}
+
+		if ( (int) $this->total_thread_count && (int) $this->pag_num ) {
+			$this->pag_links = paginate_links( array(
+				'base'      => add_query_arg( $page_arg, '%#%' ),
+				'format'    => '',
+				'total'     => ceil( (int) $this->total_thread_count / (int) $this->pag_num ),
+				'current'   => $this->pag_page,
+				'prev_text' => _x( '&larr;', 'Message pagination previous text', 'buddypress' ),
+				'next_text' => _x( '&rarr;', 'Message pagination next text', 'buddypress' ),
+				'mid_size'  => 1
+			) );
+		}
+	}
+
+	function has_threads() {
+		if ( $this->thread_count )
+			return true;
+
+		return false;
+	}
+
+	function next_thread() {
+		$this->current_thread++;
+		$this->thread = $this->threads[$this->current_thread];
+
+		return $this->thread;
+	}
+
+	function rewind_threads() {
+		$this->current_thread = -1;
+		if ( $this->thread_count > 0 ) {
+			$this->thread = $this->threads[0];
+		}
+	}
+
+	function message_threads() {
+		if ( $this->current_thread + 1 < $this->thread_count ) {
+			return true;
+		} elseif ( $this->current_thread + 1 == $this->thread_count ) {
+			do_action('messages_box_loop_end');
+			// Do some cleaning up after the loop
+			$this->rewind_threads();
+		}
+
+		$this->in_the_loop = false;
+		return false;
+	}
+
+	function the_message_thread() {
+
+		$this->in_the_loop = true;
+		$this->thread      = $this->next_thread();
+
+		if ( ! bp_is_current_action( 'notices' ) ) {
+			$last_message_index     = count( $this->thread->messages ) - 1;
+			$this->thread->messages = array_reverse( (array) $this->thread->messages );
+
+			// Set up the last message data
+			if ( count($this->thread->messages) > 1 ) {
+				if ( 'inbox' == $this->box ) {
+					foreach ( (array) $this->thread->messages as $key => $message ) {
+						if ( bp_loggedin_user_id() != $message->sender_id ) {
+							$last_message_index = $key;
+							break;
+						}
+					}
+
+				} elseif ( 'sentbox' == $this->box ) {
+					foreach ( (array) $this->thread->messages as $key => $message ) {
+						if ( bp_loggedin_user_id() == $message->sender_id ) {
+							$last_message_index = $key;
+							break;
+						}
+					}
+				}
+			}
+
+			$this->thread->last_message_id      = $this->thread->messages[$last_message_index]->id;
+			$this->thread->last_message_date    = $this->thread->messages[$last_message_index]->date_sent;
+			$this->thread->last_sender_id       = $this->thread->messages[$last_message_index]->sender_id;
+			$this->thread->last_message_subject = $this->thread->messages[$last_message_index]->subject;
+			$this->thread->last_message_content = $this->thread->messages[$last_message_index]->message;
+		}
+
+		// loop has just started
+		if ( 0 == $this->current_thread ) {
+			do_action('messages_box_loop_start');
+		}
+	}
+}
+
+function bp_has_message_threads( $args = '' ) {
+	global $bp, $messages_template;
+
+	$defaults = array(
+		'user_id'      => bp_loggedin_user_id(),
+		'box'          => 'inbox',
+		'per_page'     => 10,
+		'max'          => false,
+		'type'         => 'all',
+		'search_terms' => isset( $_REQUEST['s'] ) ? stripslashes( $_REQUEST['s'] ) : '',
+		'page_arg'     => 'mpage', // See https://buddypress.trac.wordpress.org/ticket/3679
+	);
+
+	$r = wp_parse_args( $args, $defaults );
+	extract( $r, EXTR_SKIP );
+
+	if ( bp_is_current_action( 'notices' ) && !bp_current_user_can( 'bp_moderate' ) ) {
+		wp_redirect( bp_displayed_user_id() );
+	} else {
+		if ( bp_is_current_action( 'sentbox' ) ) {
+			$box = 'sentbox';
+		}
+
+		if ( bp_is_current_action( 'notices' ) ) {
+			$box = 'notices';
+		}
+
+		$messages_template = new BP_Messages_Box_Template( $user_id, $box, $per_page, $max, $type, $search_terms, $page_arg );
+	}
+
+	return apply_filters( 'bp_has_message_threads', $messages_template->has_threads(), $messages_template );
+}
+
+function bp_message_threads() {
+	global $messages_template;
+	return $messages_template->message_threads();
+}
+
+function bp_message_thread() {
+	global $messages_template;
+	return $messages_template->the_message_thread();
+}
+
+function bp_message_thread_id() {
+	echo bp_get_message_thread_id();
+}
+	function bp_get_message_thread_id() {
+		global $messages_template;
+
+		return apply_filters( 'bp_get_message_thread_id', $messages_template->thread->thread_id );
+	}
+
+function bp_message_thread_subject() {
+	echo bp_get_message_thread_subject();
+}
+	function bp_get_message_thread_subject() {
+		global $messages_template;
+
+		return apply_filters( 'bp_get_message_thread_subject', stripslashes_deep( $messages_template->thread->last_message_subject ) );
+	}
+
+function bp_message_thread_excerpt() {
+	echo bp_get_message_thread_excerpt();
+}
+	function bp_get_message_thread_excerpt() {
+		global $messages_template;
+
+		return apply_filters( 'bp_get_message_thread_excerpt', strip_tags( bp_create_excerpt( $messages_template->thread->last_message_content, 75 ) ) );
+	}
+
+function bp_message_thread_from() {
+	echo bp_get_message_thread_from();
+}
+	function bp_get_message_thread_from() {
+		global $messages_template;
+
+		return apply_filters( 'bp_get_message_thread_from', bp_core_get_userlink( $messages_template->thread->last_sender_id ) );
+	}
+
+function bp_message_thread_to() {
+	echo bp_get_message_thread_to();
+}
+	function bp_get_message_thread_to() {
+		global $messages_template;
+		return apply_filters( 'bp_message_thread_to', BP_Messages_Thread::get_recipient_links($messages_template->thread->recipients ) );
+	}
+
+function bp_message_thread_view_link() {
+	echo bp_get_message_thread_view_link();
+}
+	function bp_get_message_thread_view_link() {
+		global $messages_template, $bp;
+		return apply_filters( 'bp_get_message_thread_view_link', trailingslashit( bp_loggedin_user_domain() . $bp->messages->slug . '/view/' . $messages_template->thread->thread_id ) );
+	}
+
+function bp_message_thread_delete_link() {
+	echo bp_get_message_thread_delete_link();
+}
+	function bp_get_message_thread_delete_link() {
+		global $messages_template, $bp;
+		return apply_filters( 'bp_get_message_thread_delete_link', wp_nonce_url( trailingslashit( bp_loggedin_user_domain() . $bp->messages->slug . '/' . bp_current_action() . '/delete/' . $messages_template->thread->thread_id ), 'messages_delete_thread' ) );
+	}
+
+function bp_message_css_class() {
+	echo bp_get_message_css_class();
+}
+
+	function bp_get_message_css_class() {
+		global $messages_template;
+
+		$class = false;
+
+		if ( $messages_template->current_thread % 2 == 1 )
+			$class .= 'alt';
+
+		return apply_filters( 'bp_get_message_css_class', trim( $class ) );
+	}
+
+function bp_message_thread_has_unread() {
+	global $messages_template;
+
+	if ( $messages_template->thread->unread_count )
+		return true;
+
+	return false;
+}
+
+function bp_message_thread_unread_count() {
+	echo bp_get_message_thread_unread_count();
+}
+	function bp_get_message_thread_unread_count() {
+		global $messages_template;
+
+		if ( (int) $messages_template->thread->unread_count )
+			return apply_filters( 'bp_get_message_thread_unread_count', $messages_template->thread->unread_count );
+
+		return false;
+	}
+
+function bp_message_thread_last_post_date() {
+	echo bp_get_message_thread_last_post_date();
+}
+	function bp_get_message_thread_last_post_date() {
+		global $messages_template;
+
+		return apply_filters( 'bp_get_message_thread_last_post_date', bp_format_time( strtotime( $messages_template->thread->last_message_date ) ) );
+	}
+
+/**
+ * Output the avatar for the last sender in the current message thread.
+ *
+ * @see bp_get_message_thread_avatar() for a description of arguments.
+ *
+ * @param array $args See {@link bp_get_message_thread_avatar()}.
+ */
+function bp_message_thread_avatar( $args = '' ) {
+	echo bp_get_message_thread_avatar( $args );
+}
+	/**
+	 * Return the avatar for the last sender in the current message thread.
+	 *
+	 * @see bp_core_fetch_avatar() For a description of arguments and
+	 *      return values.
+	 *
+	 * @param array $args {
+	 *     Arguments are listed here with an explanation of their defaults.
+	 *     For more information about the arguments, see
+	 *     {@link bp_core_fetch_avatar()}.
+	 *     @type string $type Default: 'thumb'.
+	 *     @type int|bool $width Default: false.
+	 *     @type int|bool $height Default: false.
+	 *     @type string $class Default: 'avatar'.
+	 *     @type string|bool $id Default: false.
+	 *     @type string $alt Default: 'Profile picture of [display name]'.
+	 * }
+	 * @return User avatar string.
+	 */
+	function bp_get_message_thread_avatar( $args = '' ) {
+		global $messages_template;
+
+		$fullname = bp_core_get_user_displayname( $messages_template->thread->last_sender_id );
+
+		$defaults = array(
+			'type'   => 'thumb',
+			'width'  => false,
+			'height' => false,
+			'class'  => 'avatar',
+			'id'     => false,
+			'alt'    => sprintf( __( 'Profile picture of %s', 'buddypress' ), $fullname )
+		);
+
+		$r = wp_parse_args( $args, $defaults );
+
+		return apply_filters( 'bp_get_message_thread_avatar', bp_core_fetch_avatar( array(
+			'item_id' => $messages_template->thread->last_sender_id,
+			'type'    => $r['type'],
+			'alt'     => $r['alt'],
+			'css_id'  => $r['id'],
+			'class'   => $r['class'],
+			'width'   => $r['width'],
+			'height'  => $r['height'],
+		) ) );
+	}
+
+function bp_total_unread_messages_count() {
+	echo bp_get_total_unread_messages_count();
+}
+	function bp_get_total_unread_messages_count() {
+		return apply_filters( 'bp_get_total_unread_messages_count', BP_Messages_Thread::get_inbox_count() );
+	}
+
+function bp_messages_pagination() {
+	echo bp_get_messages_pagination();
+}
+	function bp_get_messages_pagination() {
+		global $messages_template;
+		return apply_filters( 'bp_get_messages_pagination', $messages_template->pag_links );
+	}
+
+function bp_messages_pagination_count() {
+	global $messages_template;
+
+	$start_num = intval( ( $messages_template->pag_page - 1 ) * $messages_template->pag_num ) + 1;
+	$from_num = bp_core_number_format( $start_num );
+	$to_num = bp_core_number_format( ( $start_num + ( $messages_template->pag_num - 1 ) > $messages_template->total_thread_count ) ? $messages_template->total_thread_count : $start_num + ( $messages_template->pag_num - 1 ) );
+	$total = bp_core_number_format( $messages_template->total_thread_count );
+
+	echo sprintf( _n( 'Viewing message %1$s to %2$s (of %3$s message)', 'Viewing message %1$s to %2$s (of %3$s messages)', $total, 'buddypress' ), $from_num, $to_num, number_format_i18n( $total ) ); ?><?php
+}
+
+/**
+ * Output the Private Message search form
+ *
+ * @since BuddyPress (1.6)
+ */
+function bp_message_search_form() {
+
+	$default_search_value = bp_get_search_default_text( 'messages' );
+	$search_value         = !empty( $_REQUEST['s'] ) ? stripslashes( $_REQUEST['s'] ) : $default_search_value; ?>
+
+	<form action="" method="get" id="search-message-form">
+		<label><input type="text" name="s" id="messages_search" <?php if ( $search_value === $default_search_value ) : ?>placeholder="<?php echo esc_html( $search_value ); ?>"<?php endif; ?> <?php if ( $search_value !== $default_search_value ) : ?>value="<?php echo esc_html( $search_value ); ?>"<?php endif; ?> /></label>
+		<input type="submit" id="messages_search_submit" name="messages_search_submit" value="<?php _e( 'Search', 'buddypress' ) ?>" />
+	</form>
+
+<?php
+}
+
+/**
+ * Echoes the form action for Messages HTML forms
+ *
+ * @package BuddyPress
+ */
+function bp_messages_form_action() {
+	echo bp_get_messages_form_action();
+}
+	/**
+	 * Returns the form action for Messages HTML forms
+	 *
+	 * @package BuddyPress
+	 *
+	 * @return string The form action
+	 */
+	function bp_get_messages_form_action() {
+		return apply_filters( 'bp_get_messages_form_action', trailingslashit( bp_loggedin_user_domain() . bp_get_messages_slug() . '/' . bp_current_action() . '/' . bp_action_variable( 0 ) ) );
+	}
+
+function bp_messages_username_value() {
+	echo bp_get_messages_username_value();
+}
+	function bp_get_messages_username_value() {
+		if ( isset( $_COOKIE['bp_messages_send_to'] ) ) {
+			return apply_filters( 'bp_get_messages_username_value', $_COOKIE['bp_messages_send_to'] );
+		} else if ( isset( $_GET['r'] ) && !isset( $_COOKIE['bp_messages_send_to'] ) ) {
+			return apply_filters( 'bp_get_messages_username_value', $_GET['r'] );
+		}
+	}
+
+function bp_messages_subject_value() {
+	echo bp_get_messages_subject_value();
+}
+	function bp_get_messages_subject_value() {
+		$subject = '';
+		if ( !empty( $_POST['subject'] ) )
+			$subject = $_POST['subject'];
+
+		return apply_filters( 'bp_get_messages_subject_value', $subject );
+	}
+
+function bp_messages_content_value() {
+	echo bp_get_messages_content_value();
+}
+	function bp_get_messages_content_value() {
+		$content = '';
+		if ( !empty( $_POST['content'] ) )
+			$content = $_POST['content'];
+
+		return apply_filters( 'bp_get_messages_content_value', $content );
+	}
+
+function bp_messages_options() {
+?>
+
+	<?php _e( 'Select:', 'buddypress' ) ?>
+
+	<select name="message-type-select" id="message-type-select">
+		<option value=""></option>
+		<option value="read"><?php _e('Read', 'buddypress') ?></option>
+		<option value="unread"><?php _e('Unread', 'buddypress') ?></option>
+		<option value="all"><?php _e('All', 'buddypress') ?></option>
+	</select> &nbsp;
+
+	<?php if ( ! bp_is_current_action( 'sentbox' ) && bp_is_current_action( 'notices' ) ) : ?>
+
+		<a href="#" id="mark_as_read"><?php _e('Mark as Read', 'buddypress') ?></a> &nbsp;
+		<a href="#" id="mark_as_unread"><?php _e('Mark as Unread', 'buddypress') ?></a> &nbsp;
+
+	<?php endif; ?>
+
+	<a href="#" id="delete_<?php echo bp_current_action(); ?>_messages"><?php _e( 'Delete Selected', 'buddypress' ); ?></a> &nbsp;
+
+<?php
+}
+
+/**
+ * Return whether or not the notice is currently active
+ *
+ * @since BuddyPress (1.6)
+ * @uses bp_get_messages_is_active_notice()
+ */
+function bp_messages_is_active_notice() {
+	global $messages_template;
+
+	if ( $messages_template->thread->is_active )
+		return true;
+
+	return false;
+}
+
+/**
+ * Output a string for the active notice
+ *
+ * Since 1.6 this function has been deprecated in favor of text in the theme
+ *
+ * @since BuddyPress (1.0)
+ * @deprecated BuddyPress (1.6)
+ * @uses bp_get_message_is_active_notice()
+ */
+function bp_message_is_active_notice() {
+	echo bp_get_message_is_active_notice();
+}
+	/**
+	 * Returns a string for the active notice
+	 *
+	 * Since 1.6 this function has been deprecated in favor of text in the theme
+	 *
+	 * @since BuddyPress (1.0)
+	 * @deprecated BuddyPress (1.6)
+	 * @uses bp_messages_is_active_notice()
+	 */
+	function bp_get_message_is_active_notice() {
+
+		$string = '';
+		if ( bp_messages_is_active_notice() )
+			$string = __( 'Currently Active', 'buddypress' );
+
+		return apply_filters( 'bp_get_message_is_active_notice', $string );
+	}
+
+function bp_message_notice_id() {
+	echo bp_get_message_notice_id();
+}
+	function bp_get_message_notice_id() {
+		global $messages_template;
+		return apply_filters( 'bp_get_message_notice_id', $messages_template->thread->id );
+	}
+
+function bp_message_notice_post_date() {
+	echo bp_get_message_notice_post_date();
+}
+	function bp_get_message_notice_post_date() {
+		global $messages_template;
+		return apply_filters( 'bp_get_message_notice_post_date', bp_format_time( strtotime($messages_template->thread->date_sent) ) );
+	}
+
+function bp_message_notice_subject() {
+	echo bp_get_message_notice_subject();
+}
+	function bp_get_message_notice_subject() {
+		global $messages_template;
+		return apply_filters( 'bp_get_message_notice_subject', $messages_template->thread->subject );
+	}
+
+function bp_message_notice_text() {
+	echo bp_get_message_notice_text();
+}
+	function bp_get_message_notice_text() {
+		global $messages_template;
+		return apply_filters( 'bp_get_message_notice_text', $messages_template->thread->message );
+	}
+
+function bp_message_notice_delete_link() {
+	echo bp_get_message_notice_delete_link();
+}
+	function bp_get_message_notice_delete_link() {
+		global $messages_template, $bp;
+
+		return apply_filters( 'bp_get_message_notice_delete_link', wp_nonce_url( bp_loggedin_user_domain() . $bp->messages->slug . '/notices/delete/' . $messages_template->thread->id, 'messages_delete_thread' ) );
+	}
+
+function bp_message_activate_deactivate_link() {
+	echo bp_get_message_activate_deactivate_link();
+}
+	function bp_get_message_activate_deactivate_link() {
+		global $messages_template, $bp;
+
+		if ( 1 == (int) $messages_template->thread->is_active ) {
+			$link = wp_nonce_url( trailingslashit( bp_loggedin_user_domain() . $bp->messages->slug . '/notices/deactivate/' . $messages_template->thread->id ), 'messages_deactivate_notice' );
+		} else {
+			$link = wp_nonce_url( trailingslashit( bp_loggedin_user_domain() . $bp->messages->slug . '/notices/activate/' . $messages_template->thread->id ), 'messages_activate_notice' );
+		}
+		return apply_filters( 'bp_get_message_activate_deactivate_link', $link );
+	}
+
+function bp_message_activate_deactivate_text() {
+	echo bp_get_message_activate_deactivate_text();
+}
+	function bp_get_message_activate_deactivate_text() {
+		global $messages_template;
+
+		if ( 1 == (int) $messages_template->thread->is_active  ) {
+			$text = __('Deactivate', 'buddypress');
+		} else {
+			$text = __('Activate', 'buddypress');
+		}
+		return apply_filters( 'bp_message_activate_deactivate_text', $text );
+	}
+
+/**
+ * Output the messages component slug
+ *
+ * @package BuddyPress
+ * @subpackage Messages Template
+ * @since BuddyPress (1.5)
+ *
+ * @uses bp_get_messages_slug()
+ */
+function bp_messages_slug() {
+	echo bp_get_messages_slug();
+}
+	/**
+	 * Return the messages component slug
+	 *
+	 * @package BuddyPress
+	 * @subpackage Messages Template
+	 * @since BuddyPress (1.5)
+	 */
+	function bp_get_messages_slug() {
+		global $bp;
+		return apply_filters( 'bp_get_messages_slug', $bp->messages->slug );
+	}
+
+function bp_message_get_notices() {
+	$notice = BP_Messages_Notice::get_active();
+
+	if ( empty( $notice ) )
+		return false;
+
+	$closed_notices = bp_get_user_meta( bp_loggedin_user_id(), 'closed_notices', true );
+
+	if ( !$closed_notices )
+		$closed_notices = array();
+
+	if ( is_array($closed_notices) ) {
+		if ( !in_array( $notice->id, $closed_notices ) && $notice->id ) {
+			?>
+			<div id="message" class="info notice" rel="n-<?php echo $notice->id ?>">
+				<p>
+					<strong><?php echo stripslashes( wp_filter_kses( $notice->subject ) ) ?></strong><br />
+					<?php echo stripslashes( wp_filter_kses( $notice->message) ) ?>
+					<a href="#" id="close-notice"><?php _e( 'Close', 'buddypress' ) ?></a>
+				</p>
+			</div>
+			<?php
+		}
+	}
+}
+
+function bp_send_private_message_link() {
+	echo bp_get_send_private_message_link();
+}
+	function bp_get_send_private_message_link() {
+
+		if ( bp_is_my_profile() || !is_user_logged_in() )
+			return false;
+
+		return apply_filters( 'bp_get_send_private_message_link', wp_nonce_url( bp_loggedin_user_domain() . bp_get_messages_slug() . '/compose/?r=' . bp_core_get_username( bp_displayed_user_id() ) ) );
+	}
+
+/**
+ * bp_send_private_message_button()
+ *
+ * Explicitly named function to avoid confusion with public messages.
+ *
+ * @uses bp_get_send_message_button()
+ * @since BuddyPress (1.2.6)
+ */
+function bp_send_private_message_button() {
+	echo bp_get_send_message_button();
+}
+
+function bp_send_message_button() {
+	echo bp_get_send_message_button();
+}
+	function bp_get_send_message_button() {
+		// Note: 'bp_get_send_message_button' is a legacy filter. Use
+		// 'bp_get_send_message_button_args' instead. See #4536
+		return apply_filters( 'bp_get_send_message_button',
+			bp_get_button( apply_filters( 'bp_get_send_message_button_args', array(
+				'id'                => 'private_message',
+				'component'         => 'messages',
+				'must_be_logged_in' => true,
+				'block_self'        => true,
+				'wrapper_id'        => 'send-private-message',
+				'link_href'         => bp_get_send_private_message_link(),
+				'link_title'        => __( 'Send a private message to this user.', 'buddypress' ),
+				'link_text'         => __( 'Private Message', 'buddypress' ),
+				'link_class'        => 'send-message',
+			) ) )
+		);
+	}
+
+function bp_message_loading_image_src() {
+	echo bp_get_message_loading_image_src();
+}
+	function bp_get_message_loading_image_src() {
+		global $bp;
+		return apply_filters( 'bp_get_message_loading_image_src', $bp->messages->image_base . '/ajax-loader.gif' );
+	}
+
+function bp_message_get_recipient_tabs() {
+	$recipients = explode( ' ', bp_get_message_get_recipient_usernames() );
+
+	foreach ( $recipients as $recipient ) {
+		$user_id = bp_is_username_compatibility_mode() ? bp_core_get_userid( $recipient ) : bp_core_get_userid_from_nicename( $recipient );
+
+		if ( $user_id ) : ?>
+
+			<li id="un-<?php echo esc_attr( $recipient ); ?>" class="friend-tab">
+				<span><?php
+					echo bp_core_fetch_avatar( array( 'item_id' => $user_id, 'type' => 'thumb', 'width' => 15, 'height' => 15 ) );
+					echo bp_core_get_userlink( $user_id );
+				?></span>
+			</li>
+
+		<?php endif;
+	}
+}
+
+function bp_message_get_recipient_usernames() {
+	echo bp_get_message_get_recipient_usernames();
+}
+	function bp_get_message_get_recipient_usernames() {
+		$recipients = isset( $_GET['r'] ) ? stripslashes( $_GET['r'] ) : '';
+
+		return apply_filters( 'bp_get_message_get_recipient_usernames', $recipients );
+	}
+
+
+/*****************************************************************************
+ * Message Thread Template Class
+ **/
+
+class BP_Messages_Thread_Template {
+	var $current_message = -1;
+	var $message_count;
+	var $message;
+
+	var $thread;
+
+	var $in_the_loop;
+
+	var $pag_page;
+	var $pag_num;
+	var $pag_links;
+	var $total_message_count;
+
+	function __construct( $thread_id, $order ) {
+		$this->thread        = new BP_Messages_Thread( $thread_id, $order );
+		$this->message_count = count( $this->thread->messages );
+
+		$last_message_index = $this->message_count - 1;
+		$this->thread->last_message_id = $this->thread->messages[$last_message_index]->id;
+		$this->thread->last_message_date = $this->thread->messages[$last_message_index]->date_sent;
+		$this->thread->last_sender_id = $this->thread->messages[$last_message_index]->sender_id;
+		$this->thread->last_message_subject = $this->thread->messages[$last_message_index]->subject;
+		$this->thread->last_message_content = $this->thread->messages[$last_message_index]->message;
+	}
+
+	function has_messages() {
+		if ( $this->message_count )
+			return true;
+
+		return false;
+	}
+
+	function next_message() {
+		$this->current_message++;
+		$this->message = $this->thread->messages[$this->current_message];
+
+		return $this->message;
+	}
+
+	function rewind_messages() {
+		$this->current_message = -1;
+		if ( $this->message_count > 0 ) {
+			$this->message = $this->thread->messages[0];
+		}
+	}
+
+	function messages() {
+		if ( $this->current_message + 1 < $this->message_count ) {
+			return true;
+		} elseif ( $this->current_message + 1 == $this->message_count ) {
+			do_action('thread_loop_end');
+			// Do some cleaning up after the loop
+			$this->rewind_messages();
+		}
+
+		$this->in_the_loop = false;
+		return false;
+	}
+
+	function the_message() {
+		$this->in_the_loop = true;
+		$this->message     = $this->next_message();
+
+		// loop has just started
+		if ( 0 == $this->current_message )
+			do_action('thread_loop_start');
+	}
+}
+
+function bp_thread_has_messages( $args = '' ) {
+	global $thread_template;
+
+	$defaults = array(
+		'thread_id' => false,
+		'order'     => 'ASC'
+	);
+
+	$r = wp_parse_args( $args, $defaults );
+	extract( $r, EXTR_SKIP );
+
+	if ( empty( $thread_id ) && bp_is_messages_component() && bp_is_current_action( 'view' ) )
+		$thread_id = (int) bp_action_variable( 0 );
+
+	$thread_template = new BP_Messages_Thread_Template( $thread_id, $order );
+	return $thread_template->has_messages();
+}
+
+function bp_thread_messages_order() {
+	echo bp_get_thread_messages_order();
+}
+
+	function bp_get_thread_messages_order() {
+		global $thread_template;
+		return $thread_template->thread->messages_order;
+	}
+
+function bp_thread_messages() {
+	global $thread_template;
+
+	return $thread_template->messages();
+}
+
+function bp_thread_the_message() {
+	global $thread_template;
+
+	return $thread_template->the_message();
+}
+
+function bp_the_thread_id() {
+	echo bp_get_the_thread_id();
+}
+	function bp_get_the_thread_id() {
+		global $thread_template;
+
+		return apply_filters( 'bp_get_the_thread_id', $thread_template->thread->thread_id );
+	}
+
+function bp_the_thread_subject() {
+	echo bp_get_the_thread_subject();
+}
+	function bp_get_the_thread_subject() {
+		global $thread_template;
+
+		return apply_filters( 'bp_get_the_thread_subject', $thread_template->thread->last_message_subject );
+	}
+
+function bp_the_thread_recipients() {
+	echo bp_get_the_thread_recipients();
+}
+	function bp_get_the_thread_recipients() {
+		global $thread_template;
+
+		$recipient_links = array();
+
+		if ( count( $thread_template->thread->recipients ) >= 5 )
+			return apply_filters( 'bp_get_the_thread_recipients', sprintf( __( '%d Recipients', 'buddypress' ), count($thread_template->thread->recipients) ) );
+
+		foreach( (array) $thread_template->thread->recipients as $recipient ) {
+			if ( (int) $recipient->user_id !== bp_loggedin_user_id() ) {
+				$recipient_link = bp_core_get_userlink( $recipient->user_id );
+
+				if ( empty( $recipient_link ) ) {
+					$recipient_link = __( 'Deleted User', 'buddypress' );
+				}
+
+				$recipient_links[] = $recipient_link;
+			}
+		}
+
+		return apply_filters( 'bp_get_the_thread_recipients', implode( ', ', $recipient_links ) );
+	}
+
+/**
+ * Echoes the ID of the current message in the thread
+ *
+ * @since BuddyPress (1.9)
+ */
+function bp_the_thread_message_id() {
+	echo bp_get_the_thread_message_id();
+}
+	/**
+	 * Gets the ID of the current message in the thread
+	 *
+	 * @since BuddyPress (1.9)
+	 * @return int
+	 */
+	function bp_get_the_thread_message_id() {
+		global $thread_template;
+
+		$thread_message_id = isset( $thread_template->message->id ) ? (int) $thread_template->message->id : null;
+		return apply_filters( 'bp_get_the_thread_message_id', $thread_message_id );
+	}
+
+function bp_the_thread_message_alt_class() {
+	echo bp_get_the_thread_message_alt_class();
+}
+	function bp_get_the_thread_message_alt_class() {
+		global $thread_template;
+
+		if ( $thread_template->current_message % 2 == 1 ) {
+			$class = 'even alt';
+		} else {
+			$class = 'odd';
+		}
+
+		return apply_filters( 'bp_get_the_thread_message_alt_class', $class );
+	}
+
+function bp_the_thread_message_sender_avatar( $args = '' ) {
+	echo bp_get_the_thread_message_sender_avatar_thumb( $args );
+}
+	function bp_get_the_thread_message_sender_avatar_thumb( $args = '' ) {
+		global $thread_template;
+
+		$defaults = array(
+			'type'   => 'thumb',
+			'width'  => false,
+			'height' => false,
+		);
+
+		$r = wp_parse_args( $args, $defaults );
+		extract( $r, EXTR_SKIP );
+
+		return apply_filters( 'bp_get_the_thread_message_sender_avatar_thumb', bp_core_fetch_avatar( array( 'item_id' => $thread_template->message->sender_id, 'type' => $type, 'width' => $width, 'height' => $height, 'alt' => bp_core_get_user_displayname( $thread_template->message->sender_id ) ) ) );
+	}
+
+function bp_the_thread_message_sender_link() {
+	echo bp_get_the_thread_message_sender_link();
+}
+	function bp_get_the_thread_message_sender_link() {
+		global $thread_template;
+
+		return apply_filters( 'bp_get_the_thread_message_sender_link', bp_core_get_userlink( $thread_template->message->sender_id, false, true ) );
+	}
+
+function bp_the_thread_message_sender_name() {
+	echo bp_get_the_thread_message_sender_name();
+}
+	function bp_get_the_thread_message_sender_name() {
+		global $thread_template;
+
+		$display_name = bp_core_get_user_displayname( $thread_template->message->sender_id );
+
+		if ( empty( $display_name ) )
+			$display_name = __( 'Deleted User', 'buddypress' );
+
+		return apply_filters( 'bp_get_the_thread_message_sender_name', $display_name );
+	}
+
+function bp_the_thread_delete_link() {
+	echo bp_get_the_thread_delete_link();
+}
+	function bp_get_the_thread_delete_link() {
+		global $bp;
+
+		return apply_filters( 'bp_get_message_thread_delete_link', wp_nonce_url( bp_loggedin_user_domain() . $bp->messages->slug . '/inbox/delete/' . bp_get_the_thread_id(), 'messages_delete_thread' ) );
+	}
+
+function bp_the_thread_message_time_since() {
+	echo bp_get_the_thread_message_time_since();
+}
+	function bp_get_the_thread_message_time_since() {
+		global $thread_template;
+
+		return apply_filters( 'bp_get_the_thread_message_time_since', sprintf( __( 'Sent %s', 'buddypress' ), bp_core_time_since( strtotime( $thread_template->message->date_sent ) ) ) );
+	}
+
+function bp_the_thread_message_content() {
+	echo bp_get_the_thread_message_content();
+}
+	function bp_get_the_thread_message_content() {
+		global $thread_template;
+
+		return apply_filters( 'bp_get_the_thread_message_content', $thread_template->message->message );
+	}
+
+/** Embeds *******************************************************************/
+
+/**
+ * Enable oembed support for Messages.
+ *
+ * There's no caching as BP 1.5 does not have a Messages meta API.
+ *
+ * @see BP_Embed
+ * @since BuddyPress (1.5)
+ * @todo Add Messages meta?
+ */
+function bp_messages_embed() {
+	add_filter( 'embed_post_id', 'bp_get_message_thread_id' );
+}
+add_action( 'messages_box_loop_start', 'bp_messages_embed' );
Index: /tags/1.9/bp-messages/bp-messages-widgets.php
===================================================================
--- /tags/1.9/bp-messages/bp-messages-widgets.php	(revision 7684)
+++ /tags/1.9/bp-messages/bp-messages-widgets.php	(revision 7684)
@@ -0,0 +1,116 @@
+<?php
+/**
+ * BuddyPress Messages Widgets
+ *
+ * @package BuddyPress
+ * @subpackage Messages
+ */
+
+/**
+ * Register widgets for the Messages component.
+ *
+ * @since BuddyPress (1.9.0)
+ */
+function bp_messages_register_widgets() {
+	add_action( 'widgets_init', create_function('', 'return register_widget( "BP_Messages_Sitewide_Notices_Widget" );') );
+}
+add_action( 'bp_register_widgets', 'bp_messages_register_widgets' );
+
+/** Sitewide Notices widget *************************************************/
+
+/**
+ * A widget that displays sitewide notices.
+ *
+ * @since BuddyPress (1.9.0)
+ */
+class BP_Messages_Sitewide_Notices_Widget extends WP_Widget {
+
+	/**
+	 * Constructor method
+	 */
+	function __construct() {
+		parent::__construct(
+			'bp_messages_sitewide_notices_widget',
+			__( '(BuddyPress) Sitewide Notices', 'buddypress' ),
+			array(
+				'classname'   => 'widget_bp_core_sitewide_messages buddypress widget',
+				'description' => __( 'Display Sitewide Notices posted by the site administrator', 'buddypress' ),
+			)
+		);
+	}
+
+	/**
+	 * Render the widget.
+	 *
+	 * @see WP_Widget::widget() for a description of parameters.
+	 *
+	 * @param array $args See {@WP_Widget::widget()}.
+	 * @param array $args See {@WP_Widget::widget()}.
+	 */
+	public function widget( $args, $instance ) {
+
+		if ( ! is_user_logged_in() ) {
+			return;
+		}
+
+		// Don't display the widget if there are no Notices to show
+		$notices = BP_Messages_Notice::get_active();
+		if ( empty( $notices ) ) {
+			return;
+		}
+
+		extract( $args );
+
+		$title = ! empty( $instance['title'] ) ? $instance['title'] : '';
+		$title = apply_filters( 'widget_title', $title, $instance );
+
+		echo $before_widget;
+		echo $before_title . $title . $after_title; ?>
+
+		<div class="bp-site-wide-message">
+			<?php bp_message_get_notices(); ?>
+		</div>
+
+		<?php
+
+		echo $after_widget;
+	}
+
+	/**
+	 * Process the saved settings for the widget.
+	 *
+	 * @see WP_Widget::update() for a description of parameters and
+	 *      return values.
+	 *
+	 * @param array $new_instance See {@WP_Widget::update()}.
+	 * @param array $old_instance See {@WP_Widget::update()}.
+	 * @return array $instance See {@WP_Widget::update()}.
+	 */
+	public function update( $new_instance, $old_instance ) {
+		$instance = $old_instance;
+		$instance['title'] = strip_tags( $new_instance['title'] );
+		return $instance;
+	}
+
+	/**
+	 * Render the settings form for Appearance > Widgets.
+	 *
+	 * @see WP_Widget::form() for a description of parameters.
+	 *
+	 * @param array $instance See {@WP_Widget::form()}.
+	 */
+	public function form( $instance ) {
+		$instance = wp_parse_args( (array) $instance, array(
+			'title' => '',
+		) );
+
+		$title = strip_tags( $instance['title'] ); ?>
+
+		<p>
+			<label for="<?php echo $this->get_field_id( 'title' ); ?>"><?php _e( 'Title:', 'buddypress' ); ?></label>
+			<input class="widefat" id="<?php echo $this->get_field_id( 'title' ); ?>" name="<?php echo $this->get_field_name( 'title' ); ?>" type="text" value="<?php echo esc_attr( $title ); ?>" />
+		</p>
+
+		<?php
+	}
+}
Index: /tags/1.9/bp-messages/css/autocomplete/jquery.autocompletefb.css
===================================================================
--- /tags/1.9/bp-messages/css/autocomplete/jquery.autocompletefb.css	(revision 7684)
+++ /tags/1.9/bp-messages/css/autocomplete/jquery.autocompletefb.css	(revision 7684)
@@ -0,0 +1,85 @@
+.ac_results {
+	padding: 0px;
+	overflow: hidden;
+	z-index: 99999;
+	background: #fff;
+	border: 1px solid #ccc;
+	-moz-border-radius-bottomleft: 3px;
+	-khtml-border-bottom-left-radius: 3px;
+	-webkit-border-bottom-left-radius: 3px;
+	border-bottom-left-radius: 3px;
+	-moz-border-radius-bottomright: 3px;
+	-khtml-border-bottom-right-radius: 3px;
+	-webkit-border-bottom-right-radius: 3px;
+	border-bottom-right-radius: 3px;
+}
+	.ac_results ul {
+		width: 100%;
+		list-style-position: outside;
+		list-style: none;
+		padding: 0;
+		margin: 0;
+	}
+
+	.ac_results li {
+		margin: 0px;
+		padding: 5px 10px;
+		cursor: pointer;
+		display: block;
+		font-size: 1em;
+		line-height: 16px;
+		overflow: hidden;
+	}
+		.ac_results li img {
+			margin-right: 5px;
+		}
+
+.ac_loading {
+	background : url('../../../bp-themes/bp-default/_inc/images/ajax-loader.gif') right center no-repeat;
+}
+
+.ac_odd {
+	background-color: #f0f0f0;
+}
+
+.ac_over {
+	background-color: #888;
+	color: #fff;
+}
+
+ul.acfb-holder {
+	margin  : 0;
+	height  : auto !important;
+	height  : 1%;
+	overflow: hidden;
+	padding: 0;
+	list-style: none;
+}
+	ul.acfb-holder li {
+		float   : left;
+		margin  : 0 5px 4px 0;
+		list-style-type: none;
+	}
+
+	ul.acfb-holder li.friend-tab {
+		border-radius         : 3px;
+		-moz-border-radius    : 3px;
+		-webkit-border-radius : 3px;
+		border     : 1px solid #ffe7c7;
+		padding    : 2px 7px 2px;
+		background : #FFF9DF;
+		font-size: 1em;
+	}
+		li.friend-tab img.avatar {
+			border-width: 2px !important;
+			vertical-align: middle;
+		}
+
+		li.friend-tab span.p {
+			padding-left: 5px;
+			font-size: 0.8em;
+			cursor: pointer;
+		}
+
+input#send-to-input { width: 275px; }
+
Index: /tags/1.9/bp-messages/css/autocomplete/jquery.autocompletefb.min.css
===================================================================
--- /tags/1.9/bp-messages/css/autocomplete/jquery.autocompletefb.min.css	(revision 7684)
+++ /tags/1.9/bp-messages/css/autocomplete/jquery.autocompletefb.min.css	(revision 7684)
@@ -0,0 +1,1 @@
+.ac_results{padding:0;overflow:hidden;z-index:99999;background:#fff;border:1px solid #ccc;-moz-border-radius-bottomleft:3px;-khtml-border-bottom-left-radius:3px;-webkit-border-bottom-left-radius:3px;border-bottom-left-radius:3px;-moz-border-radius-bottomright:3px;-khtml-border-bottom-right-radius:3px;-webkit-border-bottom-right-radius:3px;border-bottom-right-radius:3px}.ac_results ul{width:100%;list-style-position:outside;list-style:none;padding:0;margin:0}.ac_results li{margin:0;padding:5px 10px;cursor:pointer;display:block;font-size:1em;line-height:16px;overflow:hidden}.ac_results li img{margin-right:5px}.ac_loading{background:url('../../../bp-themes/bp-default/_inc/images/ajax-loader.gif') right center no-repeat}.ac_odd{background-color:#f0f0f0}.ac_over{background-color:#888;color:#fff}ul.acfb-holder{margin:0;height:auto!important;height:1%;overflow:hidden;padding:0;list-style:none}ul.acfb-holder li{float:left;margin:0 5px 4px 0;list-style-type:none}ul.acfb-holder li.friend-tab{border-radius:3px;-moz-border-radius:3px;-webkit-border-radius:3px;border:1px solid #ffe7c7;padding:2px 7px 2px;background:#fff9df;font-size:1em}li.friend-tab img.avatar{border-width:2px!important;vertical-align:middle}li.friend-tab span.p{padding-left:5px;font-size:.8em;cursor:pointer}input#send-to-input{width:275px}
Index: /tags/1.9/bp-messages/js/autocomplete/jquery.autocomplete.js
===================================================================
--- /tags/1.9/bp-messages/js/autocomplete/jquery.autocomplete.js	(revision 7684)
+++ /tags/1.9/bp-messages/js/autocomplete/jquery.autocomplete.js	(revision 7684)
@@ -0,0 +1,730 @@
+/*!
+ * Autocomplete - jQuery plugin 1.0 Beta
+ *
+ * Copyright (c) 2007 Dylan Verheul, Dan G. Switzer, Anjesh Tuladhar, Jörn Zaefferer
+ *
+ * Dual licensed under the MIT and GPL licenses:
+ *   http://www.opensource.org/licenses/mit-license.php
+ *   http://www.gnu.org/licenses/gpl.html
+ *
+ * Revision: $Id: jquery.autocomplete.js 4485 2008-01-20 13:52:47Z joern.zaefferer $
+ *
+ */
+
+;(function($) {
+
+$.fn.extend({
+	autocomplete: function(urlOrData, options) {
+		var isUrl = typeof urlOrData == "string";
+		options = $.extend({}, $.Autocompleter.defaults, {
+			url: isUrl ? urlOrData : null,
+			data: isUrl ? null : urlOrData,
+			delay: isUrl ? $.Autocompleter.defaults.delay : 10,
+			max: options && !options.scroll ? 10 : 150
+		}, options);
+
+		// if highlight is set to false, replace it with a do-nothing function
+		options.highlight = options.highlight || function(value) { return value; };
+
+		return this.each(function() {
+			new $.Autocompleter(this, options);
+		});
+	},
+	result: function(handler) {
+		return this.bind("result", handler);
+	},
+	search: function(handler) {
+		return this.trigger("search", [handler]);
+	},
+	flushCache: function() {
+		return this.trigger("flushCache");
+	},
+	setOptions: function(options){
+		return this.trigger("setOptions", [options]);
+	},
+	unautocomplete: function() {
+		return this.trigger("unautocomplete");
+	}
+});
+
+$.Autocompleter = function(input, options) {
+
+	var KEY = {
+		UP: 38,
+		DOWN: 40,
+		DEL: 46,
+		TAB: 9,
+		RETURN: 13,
+		ESC: 27,
+		COMMA: 188,
+		PAGEUP: 33,
+		PAGEDOWN: 34
+	};
+
+	// Create $ object for input element
+	var $input = $(input).attr("autocomplete", "off").addClass(options.inputClass);
+
+	var timeout;
+	var previousValue = "";
+	var cache = $.Autocompleter.Cache(options);
+	var hasFocus = 0;
+	var lastKeyPressCode;
+	var config = {
+		mouseDownOnSelect: false
+	};
+	var select = $.Autocompleter.Select(options, input, selectCurrent, config);
+
+	$input.keydown(function(event) {
+		// track last key pressed
+		lastKeyPressCode = event.keyCode;
+		switch(event.keyCode) {
+
+			case KEY.UP:
+				event.preventDefault();
+				if ( select.visible() ) {
+					select.prev();
+				} else {
+					onChange(0, true);
+				}
+				break;
+
+			case KEY.DOWN:
+				event.preventDefault();
+				if ( select.visible() ) {
+					select.next();
+				} else {
+					onChange(0, true);
+				}
+				break;
+
+			case KEY.PAGEUP:
+				event.preventDefault();
+				if ( select.visible() ) {
+					select.pageUp();
+				} else {
+					onChange(0, true);
+				}
+				break;
+
+			case KEY.PAGEDOWN:
+				event.preventDefault();
+				if ( select.visible() ) {
+					select.pageDown();
+				} else {
+					onChange(0, true);
+				}
+				break;
+
+			// matches also semicolon
+			case options.multiple && $.trim(options.multipleSeparator) == "," && KEY.COMMA:
+			case KEY.TAB:
+			case KEY.RETURN:
+				if( selectCurrent() ){
+					// make sure to blur off the current field
+					if( !options.multiple )
+						$input.blur();
+					event.preventDefault();
+						$input.focus();
+				}
+				break;
+
+			case KEY.ESC:
+				select.hide();
+				break;
+
+			default:
+				clearTimeout(timeout);
+				timeout = setTimeout(onChange, options.delay);
+				break;
+		}
+	}).keypress(function() {
+		// having fun with opera - remove this binding and Opera submits the form when we select an entry via return
+	}).focus(function(){
+		// track whether the field has focus, we shouldn't process any
+		// results if the field no longer has focus
+		hasFocus++;
+	}).blur(function() {
+		hasFocus = 0;
+		if (!config.mouseDownOnSelect) {
+			hideResults();
+		}
+	}).click(function() {
+		// show select when clicking in a focused field
+		if ( hasFocus++ > 1 && !select.visible() ) {
+			onChange(0, true);
+		}
+	}).bind("search", function() {
+		// TODO why not just specifying both arguments?
+		var fn = (arguments.length > 1) ? arguments[1] : null;
+		function findValueCallback(q, data) {
+			var result;
+			if( data && data.length ) {
+				for (var i=0; i < data.length; i++) {
+					if( data[i].result.toLowerCase() == q.toLowerCase() ) {
+						result = data[i];
+						break;
+					}
+				}
+			}
+			if( typeof fn == "function" ) fn(result);
+			else $input.trigger("result", result && [result.data, result.value]);
+		}
+		$.each(trimWords($input.val()), function(i, value) {
+			request(value, findValueCallback, findValueCallback);
+		});
+	}).bind("flushCache", function() {
+		cache.flush();
+	}).bind("setOptions", function() {
+		$.extend(options, arguments[1]);
+		// if we've updated the data, repopulate
+		if ( "data" in arguments[1] )
+			cache.populate();
+	}).bind("unautocomplete", function() {
+		select.unbind();
+		$input.unbind();
+	});
+
+
+	function selectCurrent() {
+		var selected = select.selected();
+		if( !selected )
+			return false;
+
+		var v = selected.result;
+		previousValue = v;
+
+		if ( options.multiple ) {
+			var words = trimWords($input.val());
+			if ( words.length > 1 ) {
+				v = words.slice(0, words.length - 1).join( options.multipleSeparator ) + options.multipleSeparator + v;
+			}
+			v += options.multipleSeparator;
+		}
+
+		$input.val(v);
+		hideResultsNow();
+		$input.trigger("result", [selected.data, selected.value]);
+		return true;
+	}
+
+	function onChange(crap, skipPrevCheck) {
+		if( lastKeyPressCode == KEY.DEL ) {
+			select.hide();
+			return;
+		}
+
+		var currentValue = $input.val();
+
+		if ( !skipPrevCheck && currentValue == previousValue )
+			return;
+
+		previousValue = currentValue;
+
+		currentValue = lastWord(currentValue);
+		if ( currentValue.length >= options.minChars) {
+			$input.addClass(options.loadingClass);
+			jQuery('#send-to-input').addClass('loading');
+			if (!options.matchCase)
+				currentValue = currentValue.toLowerCase();
+			request(currentValue, receiveData, hideResultsNow);
+		} else {
+			stopLoading();
+			select.hide();
+		}
+	};
+
+	function trimWords(value) {
+		if ( !value ) {
+			return [""];
+		}
+		var words = value.split( $.trim( options.multipleSeparator ) );
+		var result = [];
+		$.each(words, function(i, value) {
+			if ( $.trim(value) )
+				result[i] = $.trim(value);
+		});
+		return result;
+	}
+
+	function lastWord(value) {
+		if ( !options.multiple )
+			return value;
+		var words = trimWords(value);
+		return words[words.length - 1];
+	}
+
+	// fills in the input box w/the first match (assumed to be the best match)
+	function autoFill(q, sValue){
+		// autofill in the complete box w/the first match as long as the user hasn't entered in more data
+		// if the last user key pressed was backspace, don't autofill
+		if( options.autoFill && (lastWord($input.val()).toLowerCase() == q.toLowerCase()) && lastKeyPressCode != 8 ) {
+			// fill in the value (keep the case the user has typed)
+			$input.val($input.val() + sValue.substring(lastWord(previousValue).length));
+			// select the portion of the value not typed by the user (so the next character will erase)
+			$.Autocompleter.Selection(input, previousValue.length, previousValue.length + sValue.length);
+		}
+	};
+
+	function hideResults() {
+		clearTimeout(timeout);
+		timeout = setTimeout(hideResultsNow, 200);
+	};
+
+	function hideResultsNow() {
+		select.hide();
+		clearTimeout(timeout);
+		stopLoading();
+		if (options.mustMatch) {
+			// call search and run callback
+			$input.search(
+				function (result){
+					// if no value found, clear the input box
+					if( !result ) $input.val("");
+				}
+			);
+		}
+	};
+
+	function receiveData(q, data) {
+		if ( data && data.length && hasFocus ) {
+			stopLoading();
+			select.display(data, q);
+
+			var newData = data[0].value.split(';');
+			data.value = newData[0];
+
+			autoFill(q, data.value);
+			select.show();
+		} else {
+			hideResultsNow();
+		}
+	};
+
+	function request(term, success, failure) {
+		if (!options.matchCase)
+			term = term.toLowerCase();
+		var data = cache.load(term);
+		// recieve the cached data
+		if (data && data.length) {
+			success(term, data);
+		// if an AJAX url has been supplied, try loading the data now
+		} else if( (typeof options.url == "string") && (options.url.length > 0) ){
+
+			var extraParams = {};
+			$.each(options.extraParams, function(key, param) {
+				extraParams[key] = typeof param == "function" ? param() : param;
+			});
+
+			$.ajax({
+				// try to leverage ajaxQueue plugin to abort previous requests
+				mode: "abort",
+				// limit abortion to this input
+				port: "autocomplete" + input.name,
+				dataType: options.dataType,
+				url: options.url,
+				data: $.extend({
+					q: lastWord(term),
+					limit: options.max,
+					action: 'messages_autocomplete_results',
+					'cookie': encodeURIComponent(document.cookie)
+				}, extraParams),
+				success: function(data) {
+					var parsed = options.parse && options.parse(data) || parse(data);
+					cache.add(term, parsed);
+					success(term, parsed);
+				}
+			});
+		} else {
+			failure(term);
+		}
+	};
+
+	function parse(data) {
+		var parsed = [];
+		var rows = data.split("\n");
+		for (var i=0; i < rows.length; i++) {
+			var row = $.trim(rows[i]);
+			if (row) {
+				row = row.split("|");
+				parsed[parsed.length] = {
+					data: row,
+					value: row[0],
+					result: options.formatResult && options.formatResult(row, row[0]) || row[0]
+				};
+			}
+		}
+		return parsed;
+	};
+
+	function stopLoading() {
+		$input.removeClass(options.loadingClass);
+		jQuery('#send-to-input').removeClass('loading');
+	};
+
+};
+
+$.Autocompleter.defaults = {
+	inputClass: "ac_input",
+	resultsClass: "ac_results",
+	loadingClass: "ac_loading",
+	minChars: 1,
+	delay: 400,
+	matchCase: false,
+	matchSubset: true,
+	matchContains: false,
+	cacheLength: 10,
+	max: 100,
+	mustMatch: false,
+	extraParams: {},
+	selectFirst: true,
+	formatItem: function(row) { return row[0]; },
+	autoFill: false,
+	width: 0,
+	multiple: false,
+	multipleSeparator: ", ",
+	highlight: function(value, term) {
+		return value.replace(new RegExp("(?![^&;]+;)(?!<[^<>]*)(" + term.replace(/([\^\$\(\)\[\]\{\}\*\.\+\?\|\\])/gi, "\\$1") + ")(?![^<>]*>)(?![^&;]+;)", "gi"), "<strong>$1</strong>");
+	},
+    scroll: true,
+    scrollHeight: 250,
+	attachTo: 'body'
+};
+
+$.Autocompleter.Cache = function(options) {
+
+	var data = {};
+	var length = 0;
+
+	function matchSubset(s, sub) {
+		if (!options.matchCase)
+			s = s.toLowerCase();
+		var i = s.indexOf(sub);
+		if (i == -1) return false;
+		return i == 0 || options.matchContains;
+	};
+
+	function add(q, value) {
+		if (length > options.cacheLength){
+			flush();
+		}
+		if (!data[q]){
+			length++;
+		}
+		data[q] = value;
+	}
+
+	function populate(){
+		if( !options.data ) return false;
+		// track the matches
+		var stMatchSets = {},
+			nullData = 0;
+
+		// no url was specified, we need to adjust the cache length to make sure it fits the local data store
+		if( !options.url ) options.cacheLength = 1;
+
+		// track all options for minChars = 0
+		stMatchSets[""] = [];
+
+		// loop through the array and create a lookup structure
+		for ( var i = 0, ol = options.data.length; i < ol; i++ ) {
+			var rawValue = options.data[i];
+			// if rawValue is a string, make an array otherwise just reference the array
+			rawValue = (typeof rawValue == "string") ? [rawValue] : rawValue;
+
+			var value = options.formatItem(rawValue, i+1, options.data.length);
+			if ( value === false )
+				continue;
+
+			var firstChar = value.charAt(0).toLowerCase();
+			// if no lookup array for this character exists, look it up now
+			if( !stMatchSets[firstChar] )
+				stMatchSets[firstChar] = [];
+
+			// if the match is a string
+			var row = {
+				value: value,
+				data: rawValue,
+				result: options.formatResult && options.formatResult(rawValue) || value
+			};
+
+			// push the current match into the set list
+			stMatchSets[firstChar].push(row);
+
+			// keep track of minChars zero items
+			if ( nullData++ < options.max ) {
+				stMatchSets[""].push(row);
+			}
+		};
+
+		// add the data items to the cache
+		$.each(stMatchSets, function(i, value) {
+			// increase the cache size
+			options.cacheLength++;
+			// add to the cache
+			add(i, value);
+		});
+	}
+
+	// populate any existing data
+	setTimeout(populate, 25);
+
+	function flush(){
+		data = {};
+		length = 0;
+	}
+
+	return {
+		flush: flush,
+		add: add,
+		populate: populate,
+		load: function(q) {
+			if (!options.cacheLength || !length)
+				return null;
+			/*
+			 * if dealing w/local data and matchContains than we must make sure
+			 * to loop through all the data collections looking for matches
+			 */
+			if( !options.url && options.matchContains ){
+				// track all matches
+				var csub = [];
+				// loop through all the data grids for matches
+				for( var k in data ){
+					// don't search through the stMatchSets[""] (minChars: 0) cache
+					// this prevents duplicates
+					if( k.length > 0 ){
+						var c = data[k];
+						$.each(c, function(i, x) {
+							// if we've got a match, add it to the array
+							if (matchSubset(x.value, q)) {
+								csub.push(x);
+							}
+						});
+					}
+				}
+				return csub;
+			} else
+			// if the exact item exists, use it
+			if (data[q]){
+				return data[q];
+			} else
+			if (options.matchSubset) {
+				for (var i = q.length - 1; i >= options.minChars; i--) {
+					var c = data[q.substr(0, i)];
+					if (c) {
+						var csub = [];
+						$.each(c, function(i, x) {
+							if (matchSubset(x.value, q)) {
+								csub[csub.length] = x;
+							}
+						});
+						return csub;
+					}
+				}
+			}
+			return null;
+		}
+	};
+};
+
+$.Autocompleter.Select = function (options, input, select, config) {
+	var CLASSES = {
+		ACTIVE: "ac_over"
+	};
+
+	var listItems,
+		active = -1,
+		data,
+		term = "",
+		needsInit = true,
+		element,
+		list;
+
+	// Create results
+	function init() {
+		if (!needsInit)
+			return;
+		element = $("<div/>")
+		.hide()
+		.addClass(options.resultsClass)
+		.css("position", "absolute")
+		.appendTo(options.attachTo);
+
+		list = $("<ul>").appendTo(element).mouseover( function(event) {
+			if(target(event).nodeName && target(event).nodeName.toUpperCase() == 'LI') {
+	            active = $("li", list).removeClass(CLASSES.ACTIVE).index(target(event));
+			    $(target(event)).addClass(CLASSES.ACTIVE);
+	        }
+		}).click(function(event) {
+			$(target(event)).addClass(CLASSES.ACTIVE);
+			select();
+			input.focus();
+			return false;
+		}).mousedown(function() {
+			config.mouseDownOnSelect = true;
+		}).mouseup(function() {
+			config.mouseDownOnSelect = false;
+		});
+
+		if( options.width > 0 )
+			element.css("width", options.width);
+
+		needsInit = false;
+	}
+
+	function target(event) {
+		var element = event.target;
+		while(element && element.tagName != "LI")
+			element = element.parentNode;
+		// more fun with IE, sometimes event.target is empty, just ignore it then
+		if(!element)
+			return [];
+		return element;
+	}
+
+	function moveSelect(step) {
+		listItems.slice(active, active + 1).removeClass();
+		movePosition(step);
+        var activeItem = listItems.slice(active, active + 1).addClass(CLASSES.ACTIVE);
+        if(options.scroll) {
+            var offset = 0;
+            listItems.slice(0, active).each(function() {
+				offset += this.offsetHeight;
+			});
+            if((offset + activeItem[0].offsetHeight - list.scrollTop()) > list[0].clientHeight) {
+                list.scrollTop(offset + activeItem[0].offsetHeight - list.innerHeight());
+            } else if(offset < list.scrollTop()) {
+                list.scrollTop(offset);
+            }
+        }
+	};
+
+	function movePosition(step) {
+		active += step;
+		if (active < 0) {
+			active = listItems.size() - 1;
+		} else if (active >= listItems.size()) {
+			active = 0;
+		}
+	}
+
+	function limitNumberOfItems(available) {
+		return options.max && options.max < available
+			? options.max
+			: available;
+	}
+
+	function fillList() {
+		list.empty();
+		var max = limitNumberOfItems(data.length);
+		for (var i=0; i < max; i++) {
+			if (!data[i])
+				continue;
+			var formatted = options.formatItem(data[i].data, i+1, max, data[i].value, term);
+			if ( formatted === false )
+				continue;
+			var li = $("<li>").html( options.highlight(formatted, term) ).addClass(i%2 == 0 ? "ac_event" : "ac_odd").appendTo(list)[0];
+			$.data(li, "ac_data", data[i]);
+		}
+		listItems = list.find("li");
+		if ( options.selectFirst ) {
+			listItems.slice(0, 1).addClass(CLASSES.ACTIVE);
+			active = 0;
+		}
+		list.bgiframe();
+	}
+
+	return {
+		display: function(d, q) {
+			init();
+			data = d;
+			term = q;
+			fillList();
+		},
+		next: function() {
+			moveSelect(1);
+		},
+		prev: function() {
+			moveSelect(-1);
+		},
+		pageUp: function() {
+			if (active != 0 && active - 8 < 0) {
+				moveSelect( -active );
+			} else {
+				moveSelect(-8);
+			}
+		},
+		pageDown: function() {
+			if (active != listItems.size() - 1 && active + 8 > listItems.size()) {
+				moveSelect( listItems.size() - 1 - active );
+			} else {
+				moveSelect(8);
+			}
+		},
+		hide: function() {
+			element && element.hide();
+			active = -1;
+		},
+		visible : function() {
+			return element && element.is(":visible");
+		},
+		current: function() {
+			return this.visible() && (listItems.filter("." + CLASSES.ACTIVE)[0] || options.selectFirst && listItems[0]);
+		},
+		show: function() {
+			var offset = $(input).offset();
+			element.css({
+				width: typeof options.width == "string" || options.width > 0 ? options.width : $(input).width(),
+				top: offset.top + input.offsetHeight,
+				left: offset.left
+			}).show();
+            if(options.scroll) {
+                list.scrollTop(0);
+                list.css({
+					maxHeight: options.scrollHeight,
+					overflow: 'auto'
+				});
+
+                if($.browser.msie && typeof document.body.style.maxHeight === "undefined") {
+					var listHeight = 0;
+					listItems.each(function() {
+						listHeight += this.offsetHeight;
+					});
+					var scrollbarsVisible = listHeight > options.scrollHeight;
+                    list.css('height', scrollbarsVisible ? options.scrollHeight : listHeight );
+					if (!scrollbarsVisible) {
+						// IE doesn't recalculate width when scrollbar disappears
+						listItems.width( list.width() - parseInt(listItems.css("padding-left")) - parseInt(listItems.css("padding-right")) );
+					}
+                }
+
+            }
+		},
+		selected: function() {
+			var selected = listItems && listItems.filter("." + CLASSES.ACTIVE).removeClass(CLASSES.ACTIVE);
+			return selected && selected.length && $.data(selected[0], "ac_data");
+		},
+		unbind: function() {
+			element && element.remove();
+		}
+	};
+};
+
+$.Autocompleter.Selection = function(field, start, end) {
+	if( field.createTextRange ){
+		var selRange = field.createTextRange();
+		selRange.collapse(true);
+		selRange.moveStart("character", start);
+		selRange.moveEnd("character", end);
+		selRange.select();
+	} else if( field.setSelectionRange ){
+		field.setSelectionRange(start, end);
+	} else {
+		if( field.selectionStart ){
+			field.selectionStart = start;
+			field.selectionEnd = end;
+		}
+	}
+	field.focus();
+};
+
+})(jQuery);
Index: /tags/1.9/bp-messages/js/autocomplete/jquery.autocomplete.min.js
===================================================================
--- /tags/1.9/bp-messages/js/autocomplete/jquery.autocomplete.min.js	(revision 7684)
+++ /tags/1.9/bp-messages/js/autocomplete/jquery.autocomplete.min.js	(revision 7684)
@@ -0,0 +1,13 @@
+/*!
+ * Autocomplete - jQuery plugin 1.0 Beta
+ *
+ * Copyright (c) 2007 Dylan Verheul, Dan G. Switzer, Anjesh Tuladhar, Jörn Zaefferer
+ *
+ * Dual licensed under the MIT and GPL licenses:
+ *   http://www.opensource.org/licenses/mit-license.php
+ *   http://www.gnu.org/licenses/gpl.html
+ *
+ * Revision: $Id: jquery.autocomplete.js 4485 2008-01-20 13:52:47Z joern.zaefferer $
+ *
+ */
+(function(a){a.fn.extend({autocomplete:function(b,c){var d=typeof b=="string";c=a.extend({},a.Autocompleter.defaults,{url:d?b:null,data:d?null:b,delay:d?a.Autocompleter.defaults.delay:10,max:c&&!c.scroll?10:150},c);c.highlight=c.highlight||function(e){return e};return this.each(function(){new a.Autocompleter(this,c)})},result:function(b){return this.bind("result",b)},search:function(b){return this.trigger("search",[b])},flushCache:function(){return this.trigger("flushCache")},setOptions:function(b){return this.trigger("setOptions",[b])},unautocomplete:function(){return this.trigger("unautocomplete")}});a.Autocompleter=function(l,g){var c={UP:38,DOWN:40,DEL:46,TAB:9,RETURN:13,ESC:27,COMMA:188,PAGEUP:33,PAGEDOWN:34};var b=a(l).attr("autocomplete","off").addClass(g.inputClass);var j;var p="";var m=a.Autocompleter.Cache(g);var e=0;var u;var w={mouseDownOnSelect:false};var r=a.Autocompleter.Select(g,l,d,w);b.keydown(function(x){u=x.keyCode;switch(x.keyCode){case c.UP:x.preventDefault();if(r.visible()){r.prev()}else{t(0,true)}break;case c.DOWN:x.preventDefault();if(r.visible()){r.next()}else{t(0,true)}break;case c.PAGEUP:x.preventDefault();if(r.visible()){r.pageUp()}else{t(0,true)}break;case c.PAGEDOWN:x.preventDefault();if(r.visible()){r.pageDown()}else{t(0,true)}break;case g.multiple&&a.trim(g.multipleSeparator)==","&&c.COMMA:case c.TAB:case c.RETURN:if(d()){if(!g.multiple){b.blur()}x.preventDefault();b.focus()}break;case c.ESC:r.hide();break;default:clearTimeout(j);j=setTimeout(t,g.delay);break}}).keypress(function(){}).focus(function(){e++}).blur(function(){e=0;if(!w.mouseDownOnSelect){s()}}).click(function(){if(e++>1&&!r.visible()){t(0,true)}}).bind("search",function(){var x=(arguments.length>1)?arguments[1]:null;function y(C,B){var z;if(B&&B.length){for(var A=0;A<B.length;A++){if(B[A].result.toLowerCase()==C.toLowerCase()){z=B[A];break}}}if(typeof x=="function"){x(z)}else{b.trigger("result",z&&[z.data,z.value])}}a.each(h(b.val()),function(z,A){f(A,y,y)})}).bind("flushCache",function(){m.flush()}).bind("setOptions",function(){a.extend(g,arguments[1]);if("data" in arguments[1]){m.populate()}}).bind("unautocomplete",function(){r.unbind();b.unbind()});function d(){var y=r.selected();if(!y){return false}var x=y.result;p=x;if(g.multiple){var z=h(b.val());if(z.length>1){x=z.slice(0,z.length-1).join(g.multipleSeparator)+g.multipleSeparator+x}x+=g.multipleSeparator}b.val(x);v();b.trigger("result",[y.data,y.value]);return true}function t(z,y){if(u==c.DEL){r.hide();return}var x=b.val();if(!y&&x==p){return}p=x;x=i(x);if(x.length>=g.minChars){b.addClass(g.loadingClass);jQuery("#send-to-input").addClass("loading");if(!g.matchCase){x=x.toLowerCase()}f(x,k,v)}else{n();r.hide()}}function h(y){if(!y){return[""]}var z=y.split(a.trim(g.multipleSeparator));var x=[];a.each(z,function(A,B){if(a.trim(B)){x[A]=a.trim(B)}});return x}function i(x){if(!g.multiple){return x}var y=h(x);return y[y.length-1]}function q(x,y){if(g.autoFill&&(i(b.val()).toLowerCase()==x.toLowerCase())&&u!=8){b.val(b.val()+y.substring(i(p).length));a.Autocompleter.Selection(l,p.length,p.length+y.length)}}function s(){clearTimeout(j);j=setTimeout(v,200)}function v(){r.hide();clearTimeout(j);n();if(g.mustMatch){b.search(function(x){if(!x){b.val("")}})}}function k(z,y){if(y&&y.length&&e){n();r.display(y,z);var x=y[0].value.split(";");y.value=x[0];q(z,y.value);r.show()}else{v()}}function f(y,A,x){if(!g.matchCase){y=y.toLowerCase()}var z=m.load(y);if(z&&z.length){A(y,z)}else{if((typeof g.url=="string")&&(g.url.length>0)){var B={};a.each(g.extraParams,function(C,D){B[C]=typeof D=="function"?D():D});a.ajax({mode:"abort",port:"autocomplete"+l.name,dataType:g.dataType,url:g.url,data:a.extend({q:i(y),limit:g.max,action:"messages_autocomplete_results",cookie:encodeURIComponent(document.cookie)},B),success:function(D){var C=g.parse&&g.parse(D)||o(D);m.add(y,C);A(y,C)}})}else{x(y)}}}function o(A){var x=[];var z=A.split("\n");for(var y=0;y<z.length;y++){var B=a.trim(z[y]);if(B){B=B.split("|");x[x.length]={data:B,value:B[0],result:g.formatResult&&g.formatResult(B,B[0])||B[0]}}}return x}function n(){b.removeClass(g.loadingClass);jQuery("#send-to-input").removeClass("loading")}};a.Autocompleter.defaults={inputClass:"ac_input",resultsClass:"ac_results",loadingClass:"ac_loading",minChars:1,delay:400,matchCase:false,matchSubset:true,matchContains:false,cacheLength:10,max:100,mustMatch:false,extraParams:{},selectFirst:true,formatItem:function(b){return b[0]},autoFill:false,width:0,multiple:false,multipleSeparator:", ",highlight:function(c,b){return c.replace(new RegExp("(?![^&;]+;)(?!<[^<>]*)("+b.replace(/([\^\$\(\)\[\]\{\}\*\.\+\?\|\\])/gi,"\\$1")+")(?![^<>]*>)(?![^&;]+;)","gi"),"<strong>$1</strong>")},scroll:true,scrollHeight:250,attachTo:"body"};a.Autocompleter.Cache=function(c){var f={};var d=0;function h(l,k){if(!c.matchCase){l=l.toLowerCase()}var j=l.indexOf(k);if(j==-1){return false}return j==0||c.matchContains}function g(j,i){if(d>c.cacheLength){b()}if(!f[j]){d++}f[j]=i}function e(){if(!c.data){return false}var k={},j=0;if(!c.url){c.cacheLength=1}k[""]=[];for(var m=0,l=c.data.length;m<l;m++){var p=c.data[m];p=(typeof p=="string")?[p]:p;var o=c.formatItem(p,m+1,c.data.length);if(o===false){continue}var n=o.charAt(0).toLowerCase();if(!k[n]){k[n]=[]}var q={value:o,data:p,result:c.formatResult&&c.formatResult(p)||o};k[n].push(q);if(j++<c.max){k[""].push(q)}}a.each(k,function(r,s){c.cacheLength++;g(r,s)})}setTimeout(e,25);function b(){f={};d=0}return{flush:b,add:g,populate:e,load:function(n){if(!c.cacheLength||!d){return null}if(!c.url&&c.matchContains){var m=[];for(var j in f){if(j.length>0){var o=f[j];a.each(o,function(p,k){if(h(k.value,n)){m.push(k)}})}}return m}else{if(f[n]){return f[n]}else{if(c.matchSubset){for(var l=n.length-1;l>=c.minChars;l--){var o=f[n.substr(0,l)];if(o){var m=[];a.each(o,function(p,k){if(h(k.value,n)){m[m.length]=k}});return m}}}}}return null}}};a.Autocompleter.Select=function(e,j,l,p){var i={ACTIVE:"ac_over"};var k,f=-1,r,m="",s=true,c,o;function n(){if(!s){return}c=a("<div/>").hide().addClass(e.resultsClass).css("position","absolute").appendTo(e.attachTo);o=a("<ul>").appendTo(c).mouseover(function(t){if(q(t).nodeName&&q(t).nodeName.toUpperCase()=="LI"){f=a("li",o).removeClass(i.ACTIVE).index(q(t));a(q(t)).addClass(i.ACTIVE)}}).click(function(t){a(q(t)).addClass(i.ACTIVE);l();j.focus();return false}).mousedown(function(){p.mouseDownOnSelect=true}).mouseup(function(){p.mouseDownOnSelect=false});if(e.width>0){c.css("width",e.width)}s=false}function q(u){var t=u.target;while(t&&t.tagName!="LI"){t=t.parentNode}if(!t){return[]}return t}function h(t){k.slice(f,f+1).removeClass();g(t);var v=k.slice(f,f+1).addClass(i.ACTIVE);if(e.scroll){var u=0;k.slice(0,f).each(function(){u+=this.offsetHeight});if((u+v[0].offsetHeight-o.scrollTop())>o[0].clientHeight){o.scrollTop(u+v[0].offsetHeight-o.innerHeight())}else{if(u<o.scrollTop()){o.scrollTop(u)}}}}function g(t){f+=t;if(f<0){f=k.size()-1}else{if(f>=k.size()){f=0}}}function b(t){return e.max&&e.max<t?e.max:t}function d(){o.empty();var u=b(r.length);for(var v=0;v<u;v++){if(!r[v]){continue}var w=e.formatItem(r[v].data,v+1,u,r[v].value,m);if(w===false){continue}var t=a("<li>").html(e.highlight(w,m)).addClass(v%2==0?"ac_event":"ac_odd").appendTo(o)[0];a.data(t,"ac_data",r[v])}k=o.find("li");if(e.selectFirst){k.slice(0,1).addClass(i.ACTIVE);f=0}o.bgiframe()}return{display:function(u,t){n();r=u;m=t;d()},next:function(){h(1)},prev:function(){h(-1)},pageUp:function(){if(f!=0&&f-8<0){h(-f)}else{h(-8)}},pageDown:function(){if(f!=k.size()-1&&f+8>k.size()){h(k.size()-1-f)}else{h(8)}},hide:function(){c&&c.hide();f=-1},visible:function(){return c&&c.is(":visible")},current:function(){return this.visible()&&(k.filter("."+i.ACTIVE)[0]||e.selectFirst&&k[0])},show:function(){var v=a(j).offset();c.css({width:typeof e.width=="string"||e.width>0?e.width:a(j).width(),top:v.top+j.offsetHeight,left:v.left}).show();if(e.scroll){o.scrollTop(0);o.css({maxHeight:e.scrollHeight,overflow:"auto"});if(a.browser.msie&&typeof document.body.style.maxHeight==="undefined"){var t=0;k.each(function(){t+=this.offsetHeight});var u=t>e.scrollHeight;o.css("height",u?e.scrollHeight:t);if(!u){k.width(o.width()-parseInt(k.css("padding-left"))-parseInt(k.css("padding-right")))}}}},selected:function(){var t=k&&k.filter("."+i.ACTIVE).removeClass(i.ACTIVE);return t&&t.length&&a.data(t[0],"ac_data")},unbind:function(){c&&c.remove()}}};a.Autocompleter.Selection=function(d,e,c){if(d.createTextRange){var b=d.createTextRange();b.collapse(true);b.moveStart("character",e);b.moveEnd("character",c);b.select()}else{if(d.setSelectionRange){d.setSelectionRange(e,c)}else{if(d.selectionStart){d.selectionStart=e;d.selectionEnd=c}}}d.focus()}})(jQuery);
Index: /tags/1.9/bp-messages/js/autocomplete/jquery.autocompletefb.js
===================================================================
--- /tags/1.9/bp-messages/js/autocomplete/jquery.autocompletefb.js	(revision 7684)
+++ /tags/1.9/bp-messages/js/autocomplete/jquery.autocompletefb.js	(revision 7684)
@@ -0,0 +1,76 @@
+/*!
+ * jQuery plugin: autoCompletefb(AutoComplete Facebook)
+ * @requires jQuery v1.2.2 or later
+ * using plugin:jquery.autocomplete.js
+ *
+ * Credits:
+ * - Idea: Facebook
+ * - Guillermo Rauch: Original MooTools script
+ * - InteRiders <http://interiders.com/>
+ *
+ * Copyright (c) 2008 Widi Harsojo <wharsojo@gmail.com>, http://wharsojo.wordpress.com/
+ * Dual licensed under the MIT and GPL licenses:
+ *   http://www.opensource.org/licenses/mit-license.php
+ *   http://www.gnu.org/licenses/gpl.html
+ */
+
+jQuery.fn.autoCompletefb = function(options)
+{
+	var tmp = this;
+	var settings =
+	{
+		ul         : tmp,
+		urlLookup  : [""],
+		acOptions  : {},
+		foundClass : ".friend-tab",
+		inputClass : ".send-to-input"
+	}
+
+	if(options) jQuery.extend(settings, options);
+
+	var acfb =
+	{
+		params  : settings,
+		removeFind : function(o){
+			acfb.removeUsername(o);
+			jQuery(o).unbind('click').parent().remove();
+			jQuery(settings.inputClass,tmp).focus();
+			return tmp.acfb;
+		},
+		removeUsername: function(o){
+			var newID = o.parentNode.id.substr( o.parentNode.id.indexOf('-')+1 );
+			jQuery('#send-to-usernames').removeClass(newID);
+		}
+	}
+
+	jQuery(settings.foundClass+" img.p").click(function(){
+		acfb.removeFind(this);
+	});
+
+	jQuery(settings.inputClass,tmp).autocomplete(settings.urlLookup,settings.acOptions);
+	jQuery(settings.inputClass,tmp).result(function(e,d,f){
+		var f = settings.foundClass.replace(/\./,'');
+		var d = String(d).split(' (');
+		var un = d[1].substr(0, d[1].length-1);
+		
+		/* Don't add the same user multiple times */
+		if( 0 === jQuery(settings.inputClass).siblings('#un-' + un).length ) {		
+			var ln = '#link-' + un;
+			var l = jQuery(ln).attr('href');
+			var v = '<li class="'+f+'" id="un-'+un+'"><span><a href="'+l+'">'+d[0]+'</a></span> <span class="p">X</span></li>';
+			
+			var x = jQuery(settings.inputClass,tmp).before(v);
+			jQuery('#send-to-usernames').addClass(un);
+				
+			jQuery('.p',x[0].previousSibling).click(function(){
+				acfb.removeFind(this);
+			});
+		} 
+			
+		jQuery(settings.inputClass,tmp).val('');
+
+	});
+
+	jQuery(settings.inputClass,tmp).focus();
+	return acfb;
+}
Index: /tags/1.9/bp-messages/js/autocomplete/jquery.autocompletefb.min.js
===================================================================
--- /tags/1.9/bp-messages/js/autocomplete/jquery.autocompletefb.min.js	(revision 7684)
+++ /tags/1.9/bp-messages/js/autocomplete/jquery.autocompletefb.min.js	(revision 7684)
@@ -0,0 +1,16 @@
+/*!
+ * jQuery plugin: autoCompletefb(AutoComplete Facebook)
+ * @requires jQuery v1.2.2 or later
+ * using plugin:jquery.autocomplete.js
+ *
+ * Credits:
+ * - Idea: Facebook
+ * - Guillermo Rauch: Original MooTools script
+ * - InteRiders <http://interiders.com/>
+ *
+ * Copyright (c) 2008 Widi Harsojo <wharsojo@gmail.com>, http://wharsojo.wordpress.com/
+ * Dual licensed under the MIT and GPL licenses:
+ *   http://www.opensource.org/licenses/mit-license.php
+ *   http://www.gnu.org/licenses/gpl.html
+ */
+jQuery.fn.autoCompletefb=function(b){var c=this;var d={ul:c,urlLookup:[""],acOptions:{},foundClass:".friend-tab",inputClass:".send-to-input"};if(b){jQuery.extend(d,b)}var a={params:d,removeFind:function(e){a.removeUsername(e);jQuery(e).unbind("click").parent().remove();jQuery(d.inputClass,c).focus();return c.acfb},removeUsername:function(f){var e=f.parentNode.id.substr(f.parentNode.id.indexOf("-")+1);jQuery("#send-to-usernames").removeClass(e)}};jQuery(d.foundClass+" img.p").click(function(){a.removeFind(this)});jQuery(d.inputClass,c).autocomplete(d.urlLookup,d.acOptions);jQuery(d.inputClass,c).result(function(n,o,m){var m=d.foundClass.replace(/\./,"");var o=String(o).split(" (");var j=o[1].substr(0,o[1].length-1);if(0===jQuery(d.inputClass).siblings("#un-"+j).length){var k="#link-"+j;var h=jQuery(k).attr("href");var i='<li class="'+m+'" id="un-'+j+'"><span><a href="'+h+'">'+o[0]+'</a></span> <span class="p">X</span></li>';var g=jQuery(d.inputClass,c).before(i);jQuery("#send-to-usernames").addClass(j);jQuery(".p",g[0].previousSibling).click(function(){a.removeFind(this)})}jQuery(d.inputClass,c).val("")});jQuery(d.inputClass,c).focus();return a};
Index: /tags/1.9/bp-messages/js/autocomplete/jquery.bgiframe.js
===================================================================
--- /tags/1.9/bp-messages/js/autocomplete/jquery.bgiframe.js	(revision 7684)
+++ /tags/1.9/bp-messages/js/autocomplete/jquery.bgiframe.js	(revision 7684)
@@ -0,0 +1,39 @@
+/*! Copyright (c) 2010 Brandon Aaron (http://brandonaaron.net)
+ * Licensed under the MIT License (license.bgiframe.txt).
+ *
+ * Version 2.1.2
+ */
+
+(function($){
+
+$.fn.bgiframe = ($.browser.msie && /msie 6\.0/i.test(navigator.userAgent) ? function(s) {
+    s = $.extend({
+        top     : 'auto', // auto == .currentStyle.borderTopWidth
+        left    : 'auto', // auto == .currentStyle.borderLeftWidth
+        width   : 'auto', // auto == offsetWidth
+        height  : 'auto', // auto == offsetHeight
+        opacity : true,
+        src     : 'javascript:false;'
+    }, s);
+    var html = '<iframe class="bgiframe"frameborder="0"tabindex="-1"src="'+s.src+'"'+
+                   'style="display:block;position:absolute;z-index:-1;'+
+                       (s.opacity !== false?'filter:Alpha(Opacity=\'0\');':'')+
+                       'top:'+(s.top=='auto'?'expression(((parseInt(this.parentNode.currentStyle.borderTopWidth)||0)*-1)+\'px\')':prop(s.top))+';'+
+                       'left:'+(s.left=='auto'?'expression(((parseInt(this.parentNode.currentStyle.borderLeftWidth)||0)*-1)+\'px\')':prop(s.left))+';'+
+                       'width:'+(s.width=='auto'?'expression(this.parentNode.offsetWidth+\'px\')':prop(s.width))+';'+
+                       'height:'+(s.height=='auto'?'expression(this.parentNode.offsetHeight+\'px\')':prop(s.height))+';'+
+                '"/>';
+    return this.each(function() {
+        if ( $(this).children('iframe.bgiframe').length === 0 )
+            this.insertBefore( document.createElement(html), this.firstChild );
+    });
+} : function() { return this; });
+
+// old alias
+$.fn.bgIframe = $.fn.bgiframe;
+
+function prop(n) {
+    return n && n.constructor === Number ? n + 'px' : n;
+}
+
+})(jQuery);
Index: /tags/1.9/bp-messages/js/autocomplete/jquery.bgiframe.min.js
===================================================================
--- /tags/1.9/bp-messages/js/autocomplete/jquery.bgiframe.min.js	(revision 7684)
+++ /tags/1.9/bp-messages/js/autocomplete/jquery.bgiframe.min.js	(revision 7684)
@@ -0,0 +1,6 @@
+/*! Copyright (c) 2010 Brandon Aaron (http://brandonaaron.net)
+ * Licensed under the MIT License (license.bgiframe.txt).
+ *
+ * Version 2.1.2
+ */
+(function(a){a.fn.bgiframe=(a.browser.msie&&/msie 6\.0/i.test(navigator.userAgent)?function(d){d=a.extend({top:"auto",left:"auto",width:"auto",height:"auto",opacity:true,src:"javascript:false;"},d);var c='<iframe class="bgiframe"frameborder="0"tabindex="-1"src="'+d.src+'"style="display:block;position:absolute;z-index:-1;'+(d.opacity!==false?"filter:Alpha(Opacity='0');":"")+"top:"+(d.top=="auto"?"expression(((parseInt(this.parentNode.currentStyle.borderTopWidth)||0)*-1)+'px')":b(d.top))+";left:"+(d.left=="auto"?"expression(((parseInt(this.parentNode.currentStyle.borderLeftWidth)||0)*-1)+'px')":b(d.left))+";width:"+(d.width=="auto"?"expression(this.parentNode.offsetWidth+'px')":b(d.width))+";height:"+(d.height=="auto"?"expression(this.parentNode.offsetHeight+'px')":b(d.height))+';"/>';return this.each(function(){if(a(this).children("iframe.bgiframe").length===0){this.insertBefore(document.createElement(c),this.firstChild)}})}:function(){return this});a.fn.bgIframe=a.fn.bgiframe;function b(c){return c&&c.constructor===Number?c+"px":c}})(jQuery);
Index: /tags/1.9/bp-messages/js/autocomplete/jquery.dimensions.js
===================================================================
--- /tags/1.9/bp-messages/js/autocomplete/jquery.dimensions.js	(revision 7684)
+++ /tags/1.9/bp-messages/js/autocomplete/jquery.dimensions.js	(revision 7684)
@@ -0,0 +1,117 @@
+/*!
+ * Copyright (c) 2007 Paul Bakaus (paul.bakaus@googlemail.com) and Brandon Aaron (brandon.aaron@gmail.com || http://brandonaaron.net)
+ * Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php)
+ * and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses.
+ *
+ * $LastChangedDate: 2007-09-11 05:38:31 +0300 (Вт, 11 сен 2007) $
+ * $Rev: 3238 $
+ *
+ * Version: @VERSION
+ *
+ * Requires: jQuery 1.2+
+ */
+
+(function($){
+
+$.dimensions = {
+	version: '@VERSION'
+};
+
+// Create innerHeight, innerWidth, outerHeight and outerWidth methods
+$.each( [ 'Height', 'Width' ], function(i, name){
+
+	// innerHeight and innerWidth
+	$.fn[ 'inner' + name ] = function() {
+		if (!this[0]) return;
+
+		var torl = name == 'Height' ? 'Top'    : 'Left',  // top or left
+		    borr = name == 'Height' ? 'Bottom' : 'Right'; // bottom or right
+
+		return this[ name.toLowerCase() ]() + num(this, 'padding' + torl) + num(this, 'padding' + borr);
+	};
+
+	// outerHeight and outerWidth
+	$.fn[ 'outer' + name ] = function(options) {
+		if (!this[0]) return;
+
+		var torl = name == 'Height' ? 'Top'    : 'Left',  // top or left
+		    borr = name == 'Height' ? 'Bottom' : 'Right'; // bottom or right
+
+		options = $.extend({ margin: false }, options || {});
+
+		return this[ name.toLowerCase() ]()
+				+ num(this, 'border' + torl + 'Width') + num(this, 'border' + borr + 'Width')
+				+ num(this, 'padding' + torl) + num(this, 'padding' + borr)
+				+ (options.margin ? (num(this, 'margin' + torl) + num(this, 'margin' + borr)) : 0);
+	};
+});
+
+// Create scrollLeft and scrollTop methods
+$.each( ['Left', 'Top'], function(i, name) {
+	$.fn[ 'scroll' + name ] = function(val) {
+		if (!this[0]) return;
+
+		return val != undefined ?
+
+			// Set the scroll offset
+			this.each(function() {
+				this == window || this == document ?
+					window.scrollTo(
+						name == 'Left' ? val : $(window)[ 'scrollLeft' ](),
+						name == 'Top'  ? val : $(window)[ 'scrollTop'  ]()
+					) :
+					this[ 'scroll' + name ] = val;
+			}) :
+
+			// Return the scroll offset
+			this[0] == window || this[0] == document ?
+				self[ (name == 'Left' ? 'pageXOffset' : 'pageYOffset') ] ||
+					$.boxModel && document.documentElement[ 'scroll' + name ] ||
+					document.body[ 'scroll' + name ] :
+				this[0][ 'scroll' + name ];
+	};
+});
+
+$.fn.extend({
+	position: function() {
+		var left = 0, top = 0, elem = this[0], offset, parentOffset, offsetParent, results;
+
+		if (elem) {
+			// Get *real* offsetParent
+			offsetParent = this.offsetParent();
+
+			// Get correct offsets
+			offset       = this.offset();
+			parentOffset = offsetParent.offset();
+
+			// Subtract element margins
+			offset.top  -= num(elem, 'marginTop');
+			offset.left -= num(elem, 'marginLeft');
+
+			// Add offsetParent borders
+			parentOffset.top  += num(offsetParent, 'borderTopWidth');
+			parentOffset.left += num(offsetParent, 'borderLeftWidth');
+
+			// Subtract the two offsets
+			results = {
+				top:  offset.top  - parentOffset.top,
+				left: offset.left - parentOffset.left
+			};
+		}
+
+		return results;
+	},
+
+	offsetParent: function() {
+		var offsetParent = this[0].offsetParent;
+		while ( offsetParent && (!/^body|html$/i.test(offsetParent.tagName) && $.css(offsetParent, 'position') == 'static') )
+			offsetParent = offsetParent.offsetParent;
+		return $(offsetParent);
+	}
+});
+
+var num = function(el, prop) {
+	return parseInt($.css(el.jquery?el[0]:el,prop))||0;
+};
+
+})(jQuery);
Index: /tags/1.9/bp-messages/js/autocomplete/jquery.dimensions.min.js
===================================================================
--- /tags/1.9/bp-messages/js/autocomplete/jquery.dimensions.min.js	(revision 7684)
+++ /tags/1.9/bp-messages/js/autocomplete/jquery.dimensions.min.js	(revision 7684)
@@ -0,0 +1,13 @@
+/*!
+ * Copyright (c) 2007 Paul Bakaus (paul.bakaus@googlemail.com) and Brandon Aaron (brandon.aaron@gmail.com || http://brandonaaron.net)
+ * Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php)
+ * and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses.
+ *
+ * $LastChangedDate: 2007-09-11 05:38:31 +0300 (Вт, 11 сен 2007) $
+ * $Rev: 3238 $
+ *
+ * Version: @VERSION
+ *
+ * Requires: jQuery 1.2+
+ */
+(function(b){b.dimensions={version:"@VERSION"};b.each(["Height","Width"],function(d,c){b.fn["inner"+c]=function(){if(!this[0]){return}var f=c=="Height"?"Top":"Left",e=c=="Height"?"Bottom":"Right";return this[c.toLowerCase()]()+a(this,"padding"+f)+a(this,"padding"+e)};b.fn["outer"+c]=function(f){if(!this[0]){return}var g=c=="Height"?"Top":"Left",e=c=="Height"?"Bottom":"Right";f=b.extend({margin:false},f||{});return this[c.toLowerCase()]()+a(this,"border"+g+"Width")+a(this,"border"+e+"Width")+a(this,"padding"+g)+a(this,"padding"+e)+(f.margin?(a(this,"margin"+g)+a(this,"margin"+e)):0)}});b.each(["Left","Top"],function(d,c){b.fn["scroll"+c]=function(e){if(!this[0]){return}return e!=undefined?this.each(function(){this==window||this==document?window.scrollTo(c=="Left"?e:b(window)["scrollLeft"](),c=="Top"?e:b(window)["scrollTop"]()):this["scroll"+c]=e}):this[0]==window||this[0]==document?self[(c=="Left"?"pageXOffset":"pageYOffset")]||b.boxModel&&document.documentElement["scroll"+c]||document.body["scroll"+c]:this[0]["scroll"+c]}});b.fn.extend({position:function(){var h=0,g=0,f=this[0],i,c,e,d;if(f){e=this.offsetParent();i=this.offset();c=e.offset();i.top-=a(f,"marginTop");i.left-=a(f,"marginLeft");c.top+=a(e,"borderTopWidth");c.left+=a(e,"borderLeftWidth");d={top:i.top-c.top,left:i.left-c.left}}return d},offsetParent:function(){var c=this[0].offsetParent;while(c&&(!/^body|html$/i.test(c.tagName)&&b.css(c,"position")=="static")){c=c.offsetParent}return b(c)}});var a=function(c,d){return parseInt(b.css(c.jquery?c[0]:c,d))||0}})(jQuery);
Index: /tags/1.9/bp-messages/js/autocomplete/license.bgiframe.txt
===================================================================
--- /tags/1.9/bp-messages/js/autocomplete/license.bgiframe.txt	(revision 7684)
+++ /tags/1.9/bp-messages/js/autocomplete/license.bgiframe.txt	(revision 7684)
@@ -0,0 +1,20 @@
+Copyright 2010, Brandon Aaron (http://brandonaaron.net/)
+ 
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+ 
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+ 
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Index: /tags/1.9/bp-notifications/bp-notifications-actions.php
===================================================================
--- /tags/1.9/bp-notifications/bp-notifications-actions.php	(revision 7684)
+++ /tags/1.9/bp-notifications/bp-notifications-actions.php	(revision 7684)
@@ -0,0 +1,123 @@
+<?php
+
+/**
+ * BuddyPress Notifications Actions
+ *
+ * Action functions are exactly the same as screen functions, however they do not
+ * have a template screen associated with them. Usually they will send the user
+ * back to the default screen after execution.
+ *
+ * @package BuddyPress
+ * @subpackage NotificationsActions
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/**
+ * Handle marking single notifications as read
+ *
+ * @since BuddyPress (1.9.0)
+ *
+ * @return boolean
+ */
+function bp_notifications_action_mark_read() {
+
+	// Bail if not the unread screen
+	if ( ! bp_is_notifications_component() || ! bp_is_current_action( 'unread' ) ) {
+		return false;
+	}
+
+	// Get the action
+	$action = !empty( $_GET['action']          ) ? $_GET['action']          : '';
+	$nonce  = !empty( $_GET['_wpnonce']        ) ? $_GET['_wpnonce']        : '';
+	$id     = !empty( $_GET['notification_id'] ) ? $_GET['notification_id'] : '';
+
+	// Bail if no action or no ID
+	if ( ( 'read' !== $action ) || empty( $id ) || empty( $nonce ) ) {
+		return false;
+	}
+
+	// Check the nonce and mark the notification
+	if ( bp_verify_nonce_request( 'bp_notification_mark_read_' . $id ) && bp_notifications_mark_notification( $id, false ) ) {
+		bp_core_add_message( __( 'Notification successfully marked read.',         'buddypress' )          );
+	} else {
+		bp_core_add_message( __( 'There was a problem marking that notification.', 'buddypress' ), 'error' );
+	}
+
+	// Redirect
+	bp_core_redirect( bp_displayed_user_domain() . bp_get_notifications_slug() . '/unread/' );
+}
+add_action( 'bp_actions', 'bp_notifications_action_mark_read' );
+
+/**
+ * Handle marking single notifications as unread
+ *
+ * @since BuddyPress (1.9.0)
+ *
+ * @return boolean
+ */
+function bp_notifications_action_mark_unread() {
+
+	// Bail if not the unread screen
+	if ( ! bp_is_notifications_component() || ! bp_is_current_action( 'read' ) ) {
+		return false;
+	}
+
+	// Get the action
+	$action = !empty( $_GET['action']          ) ? $_GET['action']          : '';
+	$nonce  = !empty( $_GET['_wpnonce']        ) ? $_GET['_wpnonce']        : '';
+	$id     = !empty( $_GET['notification_id'] ) ? $_GET['notification_id'] : '';
+
+	// Bail if no action or no ID
+	if ( ( 'unread' !== $action ) || empty( $id ) || empty( $nonce ) ) {
+		return false;
+	}
+
+	// Check the nonce and mark the notification
+	if ( bp_verify_nonce_request( 'bp_notification_mark_unread_' . $id ) && bp_notifications_mark_notification( $id, true ) ) {
+		bp_core_add_message( __( 'Notification successfully marked unread.',       'buddypress' )          );
+	} else {
+		bp_core_add_message( __( 'There was a problem marking that notification.', 'buddypress' ), 'error' );
+	}
+
+	// Redirect
+	bp_core_redirect( bp_displayed_user_domain() . bp_get_notifications_slug() . '/read/' );
+}
+add_action( 'bp_actions', 'bp_notifications_action_mark_unread' );
+
+/**
+ * Handle marking single notifications as unread
+ *
+ * @since BuddyPress (1.9.0)
+ *
+ * @return boolean
+ */
+function bp_notifications_action_delete() {
+
+	// Bail if not the unread screen
+	if ( ! bp_is_notifications_component() || ! ( bp_is_current_action( 'read' ) || bp_is_current_action( 'unread' ) ) ) {
+		return false;
+	}
+
+	// Get the action
+	$action = !empty( $_GET['action']          ) ? $_GET['action']          : '';
+	$nonce  = !empty( $_GET['_wpnonce']        ) ? $_GET['_wpnonce']        : '';
+	$id     = !empty( $_GET['notification_id'] ) ? $_GET['notification_id'] : '';
+
+	// Bail if no action or no ID
+	if ( ( 'delete' !== $action ) || empty( $id ) || empty( $nonce ) ) {
+		return false;
+	}
+
+	// Check the nonce and delete the notification
+	if ( bp_verify_nonce_request( 'bp_notification_delete_' . $id ) && bp_notifications_delete_notification( $id ) ) {
+		bp_core_add_message( __( 'Notification successfully deleted.',              'buddypress' )          );
+	} else {
+		bp_core_add_message( __( 'There was a problem deleting that notification.', 'buddypress' ), 'error' );
+	}
+
+	// Redirect
+	bp_core_redirect( bp_displayed_user_domain() . bp_get_notifications_slug() . '/' . bp_current_action() . '/' );
+}
+add_action( 'bp_actions', 'bp_notifications_action_delete' );
Index: /tags/1.9/bp-notifications/bp-notifications-adminbar.php
===================================================================
--- /tags/1.9/bp-notifications/bp-notifications-adminbar.php	(revision 7684)
+++ /tags/1.9/bp-notifications/bp-notifications-adminbar.php	(revision 7684)
@@ -0,0 +1,61 @@
+<?php
+
+/**
+ * BuddyPress Notifications Admin Bar functions.
+ *
+ * Admin Bar functions for the Notifications component.
+ *
+ * @package BuddyPress
+ * @subpackage NotificationsToolbar
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/**
+ * Build the "Notifications" dropdown.
+ *
+ * @since BuddyPress (1.9.0)
+ */
+function bp_notifications_toolbar_menu() {
+	global $wp_admin_bar;
+
+	if ( ! is_user_logged_in() ) {
+		return false;
+	}
+
+	$notifications = bp_notifications_get_notifications_for_user( bp_loggedin_user_id(), 'object' );
+	$count         = ! empty( $notifications ) ? count( $notifications ) : 0;
+	$alert_class   = (int) $count > 0 ? 'pending-count alert' : 'count no-alert';
+	$menu_title    = '<span id="ab-pending-notifications" class="' . $alert_class . '">' . number_format_i18n( $count ) . '</span>';
+	$menu_link     = trailingslashit( bp_loggedin_user_domain() . bp_get_notifications_slug() );
+
+	// Add the top-level Notifications button
+	$wp_admin_bar->add_menu( array(
+		'parent'    => 'top-secondary',
+		'id'        => 'bp-notifications',
+		'title'     => $menu_title,
+		'href'      => $menu_link,
+	) );
+
+	if ( ! empty( $notifications ) ) {
+		foreach ( (array) $notifications as $notification ) {
+			$wp_admin_bar->add_menu( array(
+				'parent' => 'bp-notifications',
+				'id'     => 'notification-' . $notification->id,
+				'title'  => $notification->content,
+				'href'   => $notification->href,
+			) );
+		}
+	} else {
+		$wp_admin_bar->add_menu( array(
+			'parent' => 'bp-notifications',
+			'id'     => 'no-notifications',
+			'title'  => __( 'No new notifications', 'buddypress' ),
+			'href'   => $menu_link,
+		) );
+	}
+
+	return;
+}
+add_action( 'admin_bar_menu', 'bp_members_admin_bar_notifications_menu', 90 );
Index: /tags/1.9/bp-notifications/bp-notifications-buddybar.php
===================================================================
--- /tags/1.9/bp-notifications/bp-notifications-buddybar.php	(revision 7684)
+++ /tags/1.9/bp-notifications/bp-notifications-buddybar.php	(revision 7684)
@@ -0,0 +1,57 @@
+<?php
+
+/**
+ * BuddyPress Notifications Navigational Functions.
+ *
+ * Sets up navigation elements, including BuddyBar functionality, for the
+ * Notifications component.
+ *
+ * @package BuddyPress
+ * @subpackage NotificationsBuddyBar
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/**
+ * Create the Notifications menu for the BuddyBar.
+ *
+ * @since BuddyPress (1.9.0)
+ */
+function bp_notifications_buddybar_menu() {
+
+	if ( ! is_user_logged_in() ) {
+		return false;
+	}
+
+	echo '<li id="bp-adminbar-notifications-menu"><a href="' . esc_url( bp_loggedin_user_domain() ) . '">';
+	_e( 'Notifications', 'buddypress' );
+
+	if ( $notifications = bp_notifications_get_notifications_for_user( bp_loggedin_user_id() ) ) : ?>
+		<span><?php echo number_format_i18n( $notifications ); ?></span>
+	<?php
+	endif;
+
+	echo '</a>';
+	echo '<ul>';
+
+	if ( $notifications ) {
+		$counter = 0;
+		for ( $i = 0, $count = count( $notifications ); $i < $count; ++$i ) {
+			$alt = ( 0 == $counter % 2 ) ? ' class="alt"' : ''; ?>
+
+			<li<?php echo $alt ?>><?php echo $notifications[$i] ?></li>
+
+			<?php $counter++;
+		}
+	} else { ?>
+
+		<li><a href="<?php echo esc_url( bp_loggedin_user_domain() ); ?>"><?php _e( 'No new notifications.', 'buddypress' ); ?></a></li>
+
+	<?php
+	}
+
+	echo '</ul>';
+	echo '</li>';
+}
+add_action( 'bp_adminbar_menus', 'bp_adminbar_notifications_menu', 8 );
Index: /tags/1.9/bp-notifications/bp-notifications-classes.php
===================================================================
--- /tags/1.9/bp-notifications/bp-notifications-classes.php	(revision 7684)
+++ /tags/1.9/bp-notifications/bp-notifications-classes.php	(revision 7684)
@@ -0,0 +1,897 @@
+<?php
+
+/**
+ * BuddyPress Notifications Classes
+ *
+ * Classes used for the Notifications component.
+ *
+ * @package BuddyPress
+ * @subpackage NotificationsClasses
+ *
+ * @since BuddyPress (1.9.0)
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/**
+ * BuddyPress Notification items.
+ *
+ * Use this class to create, access, edit, or delete BuddyPress Notifications.
+ *
+ * @since BuddyPress (1.9.0)
+ */
+class BP_Notifications_Notification {
+
+	/**
+	 * The notification ID.
+	 *
+	 * @var int
+	 */
+	public $id;
+
+	/**
+	 * The ID of the item associated with the notification.
+	 *
+	 * @var int
+	 */
+	public $item_id;
+
+	/**
+	 * The ID of the secondary item associated with the notification.
+	 *
+	 * @var int
+	 */
+	public $secondary_item_id = null;
+
+	/**
+	 * The ID of the user the notification is associated with.
+	 *
+	 * @var int
+	 */
+	public $user_id;
+
+	/**
+	 * The name of the component that the notification is for.
+	 *
+	 * @var string
+	 */
+	public $component_name;
+
+	/**
+	 * The component action which the notification is related to.
+	 *
+	 * @var string
+	 */
+	public $component_action;
+
+	/**
+	 * The date the notification was created.
+	 *
+	 * @var string
+	 */
+	public $date_notified;
+
+	/**
+	 * Is the notification new, or has it already been read.
+	 *
+	 * @var bool
+	 */
+	public $is_new;
+
+	/** Public Methods ****************************************************/
+
+	/**
+	 * Constructor method.
+	 *
+	 * @since BuddyPress (1.9.0)
+	 *
+	 * @param int $id Optional. Provide an ID to access an existing
+	 *        notification item.
+	 */
+	public function __construct( $id = 0 ) {
+		if ( ! empty( $id ) ) {
+			$this->id = $id;
+			$this->populate();
+		}
+	}
+
+	/**
+	 * Update or insert notification details into the database.
+	 *
+	 * @since BuddyPress (1.9.0)
+	 *
+	 * @global wpdb $wpdb WordPress database object.
+	 *
+	 * @return bool True on success, false on failure.
+	 */
+	public function save() {
+
+		// Return value
+		$retval = false;
+
+		// Default data and format
+		$data = array(
+			'user_id'           => $this->user_id,
+			'item_id'           => $this->item_id,
+			'secondary_item_id' => $this->secondary_item_id,
+			'component_name'    => $this->component_name,
+			'component_action'  => $this->component_action,
+			'date_notified'     => $this->date_notified,
+			'is_new'            => $this->is_new,
+		);
+		$data_format = array( '%d', '%d', '%d', '%s', '%s', '%s', '%d' );
+
+		// Update
+		if ( ! empty( $this->id ) ) {
+			$result = self::_update( $data, array( 'ID' => $this->id ), $data_format, array( '%d' ) );
+
+		// Insert
+		} else {
+			$result = self::_insert( $data, $data_format );
+		}
+
+		// Set the notification ID if successful
+		if ( ! empty( $result ) && ! is_wp_error( $result ) ) {
+			global $wpdb;
+
+			$this->id = $wpdb->insert_id;
+			$retval   = $wpdb->insert_id;
+		}
+
+		// Return the result
+		return $retval;
+	}
+
+	/**
+	 * Fetch data for an existing notification from the database.
+	 *
+	 * @since BuddyPress (1.9.0)
+	 *
+	 * @global BuddyPress $bp The one true BuddyPress instance.
+	 * @global wpdb $wpdb WordPress database object.
+	 */
+	public function populate() {
+		global $wpdb;
+
+		$bp = buddypress();
+
+		// Look for a notification
+		$notification = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$bp->notifications->table_name} WHERE id = %d", $this->id ) );
+
+		// Setup the notification data
+		if ( ! empty( $notification ) && ! is_wp_error( $notification ) ) {
+			$this->item_id           = $notification->item_id;
+			$this->secondary_item_id = $notification->secondary_item_id;
+			$this->user_id           = $notification->user_id;
+			$this->component_name    = $notification->component_name;
+			$this->component_action  = $notification->component_action;
+			$this->date_notified     = $notification->date_notified;
+			$this->is_new            = $notification->is_new;
+		}
+	}
+
+	/** Protected Static Methods ******************************************/
+
+	/**
+	 * Create a notification entry.
+	 *
+	 * @since BuddyPress (1.9.0)
+	 *
+	 * @param array $data {
+	 *     Array of notification data, passed to {@link wpdb::insert()}.
+	 *     @type int $user_id ID of the associated user.
+	 *     @type int $item_id ID of the associated item.
+	 *     @type int $secondary_item_id ID of the secondary associated item.
+	 *     @type string $component_name Name of the associated component.
+	 *     @type string $component_action Name of the associated component
+	 *           action.
+	 *     @type string $date_notified Timestamp of the notification.
+	 *     @type bool $is_new True if the notification is unread, otherwise
+	 *           false.
+	 * }
+	 * @param array $data_format See {@link wpdb::insert()}.
+	 * @return int|false The number of rows inserted, or false on error.
+	 */
+	protected static function _insert( $data = array(), $data_format = array() ) {
+		global $wpdb;
+		return $wpdb->insert( buddypress()->notifications->table_name, $data, $data_format );
+	}
+
+	/**
+	 * Update notifications.
+	 *
+	 * @since BuddyPress (1.9.0)
+	 *
+	 * @see wpdb::update() for further description of paramater formats.
+	 *
+	 * @param array $data Array of notification data to update, passed to
+	 *        {@link wpdb::update()}. Accepts any property of a
+	 *        BP_Notification_Notification object.
+	 * @param array $where The WHERE params as passed to wpdb::update().
+	 *        Typically consists of array( 'ID' => $id ) to specify the ID
+	 *        of the item being updated. See {@link wpdb::update()}.
+	 * @param array $data_format See {@link wpdb::insert()}.
+	 * @param array $where_format See {@link wpdb::insert()}.
+	 * @return int|false The number of rows updated, or false on error.
+	 */
+	protected static function _update( $data = array(), $where = array(), $data_format = array(), $where_format = array() ) {
+		global $wpdb;
+		return $wpdb->update( buddypress()->notifications->table_name, $data, $where, $data_format, $where_format );
+	}
+
+	/**
+	 * Delete notifications.
+	 *
+	 * @since BuddyPress (1.9.0)
+	 *
+	 * @see wpdb::update() for further description of paramater formats.
+	 *
+	 * @param array $where Array of WHERE clauses to filter by, passed to
+	 *        {@link wpdb::delete()}. Accepts any property of a
+	 *        BP_Notification_Notification object.
+	 * @param array $where_format See {@link wpdb::insert()}.
+	 * @return int|false The number of rows updated, or false on error.
+	 */
+	protected static function _delete( $where = array(), $where_format = array() ) {
+		global $wpdb;
+		return $wpdb->delete( buddypress()->notifications->table_name, $where, $where_format );
+	}
+
+	/**
+	 * Assemble the WHERE clause of a get() SQL statement.
+	 *
+	 * Used by BP_Notifications_Notification::get() to create its WHERE
+	 * clause.
+	 *
+	 * @since BuddyPress (1.9.0)
+	 *
+	 * @param array $args See {@link BP_Notifications_Notification::get()}
+	 *        for more details.
+	 * @return string WHERE clause.
+	 */
+	protected static function get_where_sql( $args = array() ) {
+		global $wpdb;
+
+		$where_conditions = array();
+		$where            = '';
+
+		// id
+		if ( ! empty( $args['id'] ) ) {
+			$id_in = implode( ',', wp_parse_id_list( $args['id'] ) );
+			$where_conditions['id'] = "id IN ({$id_in})";
+		}
+
+		// user_id
+		if ( ! empty( $args['user_id'] ) ) {
+			$user_id_in = implode( ',', wp_parse_id_list( $args['user_id'] ) );
+			$where_conditions['user_id'] = "user_id IN ({$user_id_in})";
+		}
+
+		// item_id
+		if ( ! empty( $args['item_id'] ) ) {
+			$item_id_in = implode( ',', wp_parse_id_list( $args['item_id'] ) );
+			$where_conditions['item_id'] = "item_id IN ({$item_id_in})";
+		}
+
+		// secondary_item_id
+		if ( ! empty( $args['secondary_item_id'] ) ) {
+			$secondary_item_id_in = implode( ',', wp_parse_id_list( $args['secondary_item_id'] ) );
+			$where_conditions['secondary_item_id'] = "secondary_item_id IN ({$secondary_item_id_in})";
+		}
+
+		// component_name
+		if ( ! empty( $args['component_name'] ) ) {
+			if ( ! is_array( $args['component_name'] ) ) {
+				$component_names = explode( ',', $args['component_name'] );
+			} else {
+				$component_names = $args['component_name'];
+			}
+
+			$cn_clean = array();
+			foreach ( $component_names as $cn ) {
+				$cn_clean[] = $wpdb->prepare( '%s', $cn );
+			}
+
+			$cn_in = implode( ',', $cn_clean );
+			$where_conditions['component_name'] = "component_name IN ({$cn_in})";
+		}
+
+		// component_action
+		if ( ! empty( $args['component_action'] ) ) {
+			if ( ! is_array( $args['component_action'] ) ) {
+				$component_actions = explode( ',', $args['component_action'] );
+			} else {
+				$component_actions = $args['component_action'];
+			}
+
+			$ca_clean = array();
+			foreach ( $component_actions as $ca ) {
+				$ca_clean[] = $wpdb->prepare( '%s', $ca );
+			}
+
+			$ca_in = implode( ',', $ca_clean );
+			$where_conditions['component_action'] = "component_action IN ({$ca_in})";
+		}
+
+		// is_new
+		if ( ! empty( $args['is_new'] ) ) {
+			$where_conditions['is_new'] = "is_new = 1";
+		} elseif ( ( 0 === $args['is_new'] ) || ( false === $args['is_new'] ) ) {
+			$where_conditions['is_new'] = "is_new = 0";
+		}
+
+		// search_terms
+		if ( ! empty( $args['search_terms'] ) ) {
+			$search_terms = like_escape( esc_sql( $args['search_terms'] ) );
+			$where_conditions['search_terms'] = "( component_name LIKE '%%$search_terms%%' OR component_action LIKE '%%$search_terms%%' )";
+		}
+
+		// Custom WHERE
+		if ( ! empty( $where_conditions ) ) {
+			$where = 'WHERE ' . implode( ' AND ', $where_conditions );
+		}
+
+		return $where;
+	}
+
+	/**
+	 * Assemble the ORDER BY clause of a get() SQL statement.
+	 *
+	 * Used by BP_Notifications_Notification::get() to create its ORDER BY
+	 * clause.
+	 *
+	 * @since BuddyPress (1.9.0)
+	 *
+	 * @param array $args See {@link BP_Notifications_Notification::get()}
+	 *        for more details.
+	 * @return string ORDER BY clause.
+	 */
+	protected static function get_order_by_sql( $args = array() ) {
+
+		// Setup local variable
+		$conditions = array();
+		$retval     = '';
+
+		// Order by
+		if ( ! empty( $args['order_by'] ) ) {
+			$order_by               = implode( ', ', (array) $args['order_by'] );
+			$conditions['order_by'] = "{$order_by}";
+		}
+
+		// Sort order direction
+		if ( ! empty( $args['sort_order'] ) && in_array( $args['sort_order'], array( 'ASC', 'DESC' ) ) ) {
+			$sort_order               = $args['sort_order'];
+			$conditions['sort_order'] = "{$sort_order}";
+		}
+
+		// Custom ORDER BY
+		if ( ! empty( $conditions ) ) {
+			$retval = 'ORDER BY ' . implode( ' ', $conditions );
+		}
+
+		return $retval;
+	}
+
+	/**
+	 * Assemble the LIMIT clause of a get() SQL statement.
+	 *
+	 * Used by BP_Notifications_Notification::get() to create its LIMIT clause.
+	 *
+	 * @since BuddyPress (1.9.0)
+	 *
+	 * @param array $args See {@link BP_Notifications_Notification::get()}
+	 *        for more details.
+	 * @return string LIMIT clause.
+	 */
+	protected static function get_paged_sql( $args = array() ) {
+		global $wpdb;
+
+		// Setup local variable
+		$retval = '';
+
+		// Custom LIMIT
+		if ( ! empty( $args['page'] ) && ! empty( $args['per_page'] ) ) {
+			$page     = absint( $args['page']     );
+			$per_page = absint( $args['per_page'] );
+			$offset   = $per_page * ( $page - 1 );
+			$retval   = $wpdb->prepare( "LIMIT %d, %d", $offset, $per_page );
+		}
+
+		return $retval;
+	}
+
+	/**
+	 * Assemble query clauses, based on arrguments, to pass to $wpdb methods.
+	 *
+	 * The insert(), update(), and delete() methods of {@link wpdb} expect
+	 * arguments of the following forms:
+	 *
+	 * - associative arrays whose key/value pairs are column => value, to
+	 *   be used in WHERE, SET, or VALUES clauses
+	 * - arrays of "formats", which tell $wpdb->prepare() which type of
+	 *   value to expect when sanitizing (eg, array( '%s', '%d' ))
+	 *
+	 * This utility method can be used to assemble both kinds of params,
+	 * out of a single set of associative array arguments, such as:
+	 *
+	 *     $args = array(
+	 *         'user_id' => 4,
+	 *         'component_name' => 'groups',
+	 *     );
+	 *
+	 * This will be converted to:
+	 *
+	 *     array(
+	 *         'data' => array(
+	 *             'user_id' => 4,
+	 *             'component_name' => 'groups',
+	 *         ),
+	 *         'format' => array(
+	 *             '%d',
+	 *             '%s',
+	 *         ),
+	 *     )
+	 *
+	 * which can easily be passed as arguments to the $wpdb methods.
+	 *
+	 * @since BuddyPress (1.9.0)
+	 *
+	 * @param $args Associative array of filter arguments.
+	 *        See {@BP_Notifications_Notification::get()} for a breakdown.
+	 * @return array Associative array of 'data' and 'format' args.
+	 */
+	protected static function get_query_clauses( $args = array() ) {
+		$where_clauses = array(
+			'data'   => array(),
+			'format' => array(),
+		);
+
+		// id
+		if ( ! empty( $args['id'] ) ) {
+			$where_clauses['data']['id'] = absint( $args['id'] );
+			$where_clauses['format'][] = '%d';
+		}
+
+		// user_id
+		if ( ! empty( $args['user_id'] ) ) {
+			$where_clauses['data']['user_id'] = absint( $args['user_id'] );
+			$where_clauses['format'][] = '%d';
+		}
+
+		// item_id
+		if ( ! empty( $args['item_id'] ) ) {
+			$where_clauses['data']['item_id'] = absint( $args['item_id'] );
+			$where_clauses['format'][] = '%d';
+		}
+
+		// secondary_item_id
+		if ( ! empty( $args['secondary_item_id'] ) ) {
+			$where_clauses['data']['secondary_item_id'] = absint( $args['secondary_item_id'] );
+			$where_clauses['format'][] = '%d';
+		}
+
+		// component_name
+		if ( ! empty( $args['component_name'] ) ) {
+			$where_clauses['data']['component_name'] = $args['component_name'];
+			$where_clauses['format'][] = '%s';
+		}
+
+		// component_action
+		if ( ! empty( $args['component_action'] ) ) {
+			$where_clauses['data']['component_action'] = $args['component_action'];
+			$where_clauses['format'][] = '%s';
+		}
+
+		// is_new
+		if ( isset( $args['is_new'] ) ) {
+			$where_clauses['data']['is_new'] = ! empty( $args['is_new'] ) ? 1 : 0;
+			$where_clauses['format'][] = '%d';
+		}
+
+		return $where_clauses;
+	}
+
+	/** Public Static Methods *********************************************/
+
+	/**
+	 * Check that a specific notification is for a specific user.
+	 *
+	 * @since BuddyPress (1.9.0)
+	 *
+	 * @param int $user_id ID of the user being checked.
+	 * @param int $notification_id ID of the notification being checked.
+	 * @return bool True if the notification belongs to the user, otherwise
+	 *         false.
+	 */
+	public static function check_access( $user_id, $notification_id ) {
+		global $wpdb;
+
+		$bp = buddypress();
+
+		return $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(id) FROM {$bp->core->table_name_notifications} WHERE id = %d AND user_id = %d", $notification_id, $user_id ) );
+	}
+
+	/**
+	 * Get notifications, based on provided filter parameters.
+	 *
+	 * @since BuddyPress (1.9.0)
+	 *
+	 * @param array $args {
+	 *     Associative array of arguments. All arguments but $page and
+	 *     $per_page can be treated as filter values for get_where_sql()
+	 *     and get_query_clauses(). All items are optional.
+	 *     @type int|array $id ID of notification being updated. Can be an
+	 *           array of IDs.
+	 *     @type int|array $user_id ID of user being queried. Can be an
+	 *           array of user IDs.
+	 *     @type int|array $item_id ID of associated item. Can be an array
+	 *           of multiple item IDs.
+	 *     @type int|array $secondary_item_id ID of secondary associated
+	 *           item. Can be an array of multiple IDs.
+	 *     @type string|array $component_name Name of the component to
+	 *           filter by. Can be an array of component names.
+	 *     @type string|array $component_action Name of the action to
+	 *           filter by. Can be an array of actions.
+	 *     @type bool $is_new Whether to limit the query to is_new (unread)
+	 *           notifications. Default: true.
+	 *     @type string $search_terms Term to match against component_name
+	 *           or component_action fields.
+	 *     @type int $page Number of the current page of results. Default:
+	 *           false (no pagination - all items).
+	 *     @type int $per_page Number of items to show per page. Default:
+	 *           false (no pagination - all items).
+	 * }
+	 * @return array Located notifications.
+	 */
+	public static function get( $args = array() ) {
+		global $wpdb;
+
+		// Parse the arguments
+		$r  = wp_parse_args( $args, array(
+			'id'                => false,
+			'user_id'           => false,
+			'item_id'           => false,
+			'secondary_item_id' => false,
+			'component_name'    => false,
+			'component_action'  => false,
+			'is_new'            => true,
+			'search_terms'      => '',
+			'order_by'          => false,
+			'sort_order'        => false,
+			'page'              => false,
+			'per_page'          => false,
+		) );
+
+		// SELECT
+		$select_sql = "SELECT *";
+
+		// FROM
+		$from_sql   = "FROM " . buddypress()->notifications->table_name;
+
+		// WHERE
+		$where_sql  = self::get_where_sql( array(
+			'id'                => $r['id'],
+			'user_id'           => $r['user_id'],
+			'item_id'           => $r['item_id'],
+			'secondary_item_id' => $r['secondary_item_id'],
+			'component_name'    => $r['component_name'],
+			'component_action'  => $r['component_action'],
+			'is_new'            => $r['is_new'],
+			'search_terms'      => $r['search_terms'],
+		) );
+
+		// ORDER BY
+		$order_sql  = self::get_order_by_sql( array(
+			'order_by'   => $r['order_by'],
+			'sort_order' => $r['sort_order']
+		) );
+
+		// LIMIT %d, %d
+		$pag_sql    = self::get_paged_sql( array(
+			'page'     => $r['page'],
+			'per_page' => $r['per_page'],
+		) );
+
+		$sql = "{$select_sql} {$from_sql} {$where_sql} {$order_sql} {$pag_sql}";
+
+		return $wpdb->get_results( $sql );
+	}
+
+	/**
+	 * Get a count of total notifications matching a set of arguments.
+	 *
+	 * @since BuddyPress (1.9.0)
+	 *
+	 * @see BP_Notifications_Notification::get() for a description of
+	 *      arguments.
+	 *
+	 * @param array $args See {@link BP_Notifications_Notification::get()}.
+	 * @return int Count of located items.
+	 */
+	public static function get_total_count( $args ) {
+		global $wpdb;
+
+		$bp         = buddypress();
+		$select_sql = "SELECT COUNT(*)";
+		$from_sql   = "FROM {$bp->notifications->table_name}";
+		$where_sql  = self::get_where_sql( $args );
+		$sql        = "{$select_sql} {$from_sql} {$where_sql}";
+
+		return $wpdb->get_var( $sql );
+	}
+
+	/**
+	 * Update notifications.
+	 *
+	 * @since BuddyPress (1.9.0)
+	 *
+	 * @see BP_Notifications_Notification::get() for a description of
+	 *      accepted update/where arguments.
+	 *
+	 * @param array $update_args Associative array of fields to update,
+	 *        and the values to update them to. Of the format
+	 *            array( 'user_id' => 4, 'component_name' => 'groups', )
+	 * @param array $where_args Associative array of columns/values, to
+	 *        determine which rows should be updated. Of the format
+	 *            array( 'item_id' => 7, 'component_action' => 'members', )
+	 * @return int|bool Number of rows updated on success, false on failure.
+	 */
+	public static function update( $update_args = array(), $where_args = array() ) {
+		$update = self::get_query_clauses( $update_args );
+		$where  = self::get_query_clauses( $where_args  );
+
+		return self::_update( $update['data'], $where['data'], $update['format'], $where['format'] );
+	}
+
+	/**
+	 * Delete notifications.
+	 *
+	 * @since BuddyPress (1.9.0)
+	 *
+	 * @see BP_Notifications_Notification::get() for a description of
+	 *      accepted update/where arguments.
+	 *
+	 * @param array $args Associative array of columns/values, to determine
+	 *        which rows should be deleted.  Of the format
+	 *            array( 'item_id' => 7, 'component_action' => 'members', )
+	 * @return int|bool Number of rows deleted on success, false on failure.
+	 */
+	public static function delete( $args = array() ) {
+		$where = self::get_query_clauses( $args );
+
+		return self::_delete( $where['data'], $where['format'] );
+	}
+
+	/** Convenience methods ***************************************************/
+
+	/**
+	 * Delete a single notification by ID.
+	 *
+	 * @since BuddyPress (1.9.0)
+	 *
+	 * @see BP_Notifications_Notification::delete() for explanation of
+	 *      return value.
+	 *
+	 * @param int $id ID of the notification item to be deleted.
+	 * @return bool True on success, false on failure.
+	 */
+	public static function delete_by_id( $id ) {
+		return self::delete( array(
+			'id' => $id,
+		) );
+	}
+
+	/**
+	 * Fetch all the notifications in the database for a specific user.
+	 *
+	 * @since BuddyPress (1.9.0)
+	 *
+	 * @param int $user_id ID of the user whose notifications are being
+	 *        fetched.
+	 * @param string $status Optional. Status of notifications to fetch.
+	 *        'is_new' to get only unread items, 'all' to get all.
+	 * @return array Associative array of notification items.
+	 */
+	public static function get_all_for_user( $user_id, $status = 'is_new' ) {
+		return self::get( array(
+			'user_id' => $user_id,
+			'is_new'  => 'is_new' === $status,
+		) );
+	}
+
+	/**
+	 * Fetch all the unread notifications in the database for a specific user.
+	 *
+	 * @since BuddyPress (1.9.0)
+	 *
+	 * @param int $user_id ID of the user whose notifications are being
+	 *        fetched.
+	 * @return array Associative array of unread notification items.
+	 */
+	public static function get_unread_for_user( $user_id = 0 ) {
+		return self::get( array(
+			'user_id' => $user_id,
+			'is_new'  => true,
+		) );
+	}
+
+	/**
+	 * Fetch all the read notifications in the database for a specific user.
+	 *
+	 * @since BuddyPress (1.9.0)
+	 *
+	 * @param int $user_id ID of the user whose notifications are being
+	 *        fetched.
+	 * @return array Associative array of unread notification items.
+	 */
+	public static function get_read_for_user( $user_id = 0 ) {
+		return self::get( array(
+			'user_id' => $user_id,
+			'is_new'  => false,
+		) );
+	}
+
+	/**
+	 * Get unread notifications for a user, in a pagination-friendly format.
+	 *
+	 * @since BuddyPress (1.9.0)
+	 *
+	 * @param array $args {
+	 *     Array of arguments.
+	 *     @type int $user_id ID of the user for whom the notifications are
+	 *           being fetched. Default: logged-in user ID.
+	 *     @type bool $is_new Whether to limit the query to unread
+	 *           notifications. Default: true.
+	 *     @type int $page Number of the page to return. Default: 1.
+	 *     @type int $per_page Number of results to display per page.
+	 *           Default: 10.
+	 *     @type string $search_terms Optional. A term to search against in
+	 *           the 'component_name' and 'component_action' columns.
+	 * }
+	 * @return array {
+	 *     @type array $notifications Array of notification results.
+	 *     @type int $total Count of all located notifications matching
+	 *           the query params.
+	 * }
+	 */
+	public static function get_current_notifications_for_user( $args = array() ) {
+		$r = wp_parse_args( $args, array(
+			'user_id'      => bp_loggedin_user_id(),
+			'is_new'       => true,
+			'page'         => 1,
+			'per_page'     => 25,
+			'search_terms' => '',
+		) );
+
+		$notifications = self::get( $r );
+
+		// Bail if no notifications
+		if ( empty( $notifications ) ) {
+			return false;
+		}
+
+		$total_count = self::get_total_count( $r );
+
+		return array( 'notifications' => &$notifications, 'total' => $total_count );
+	}
+
+	/** Mark ******************************************************************/
+
+	/**
+	 * Mark all user notifications as read.
+	 *
+	 * @since BuddyPress (1.9.0)
+	 *
+	 * @param int $user_id The ID of the user who the notifications
+	 *        are for.
+	 * @param int $is_new Mark as read (1) or unread (0).
+	 */
+	public static function mark_all_for_user( $user_id, $is_new = 0, $item_id = 0, $component_name = '', $component_action = '', $secondary_item_id = 0 ) {
+
+		// Values to be updated
+		$update_args = array(
+			'is_new' => $is_new,
+		);
+
+		// WHERE clauses
+		$where_args = array(
+			'user_id' => $user_id,
+		);
+
+		if ( ! empty( $item_id ) ) {
+			$where_args['item_id'] = $item_id;
+		}
+
+		if ( ! empty( $component_name ) ) {
+			$where_args['component_name'] = $component_name;
+		}
+
+		if ( ! empty( $component_action ) ) {
+			$where_args['component_action'] = $component_action;
+		}
+
+		if ( ! empty( $secondary_item_id ) ) {
+			$where_args['secondary_item_id'] = $secondary_item_id;
+		}
+
+		return self::update( $update_args, $where_args );
+	}
+
+	/**
+	 * Mark all notifications from a user as read.
+	 *
+	 * @since BuddyPress (1.9.0)
+	 *
+	 * @param int $user_id The ID of the user who the notifications are from.
+	 * @param int $is_new Mark as read (1) or unread (0).
+	 */
+	public static function mark_all_from_user( $user_id, $is_new = 0, $component_name = '', $component_action = '', $secondary_item_id = 0 ) {
+
+		// Values to be updated
+		$update_args = array(
+			'is_new' => $is_new,
+		);
+
+		// WHERE clauses
+		$where_args = array(
+			'item_id' => $user_id,
+		);
+
+		if ( ! empty( $component_name ) ) {
+			$where_args['component_name'] = $component_name;
+		}
+
+		if ( ! empty( $component_action ) ) {
+			$where_args['component_action'] = $component_action;
+		}
+
+		if ( ! empty( $secondary_item_id ) ) {
+			$where_args['secondary_item_id'] = $secondary_item_id;
+		}
+
+		return self::update( $update_args, $where_args );
+	}
+
+	/**
+	 * Mark all notifications for all users as read by item id, and optional
+	 * secondary item id, and component name and action.
+	 *
+	 * @since BuddyPress (1.9.0)
+	 *
+	 * @param int $item_id The ID of the item associated with the
+	 *        notifications.
+	 * @param string $component_name The component that the notifications
+	 *        are associated with.
+	 * @param string $component_action The action that the notifications
+	 *        are associated with.
+	 * @param string $secondary_item_id Optional. ID of the secondary
+	 *        associated item.
+	 */
+	public static function mark_all_by_type( $item_id, $is_new = 0, $component_name = '', $component_action = '', $secondary_item_id = 0 ) {
+
+		// Values to be updated
+		$update_args = array(
+			'is_new' => $is_new,
+		);
+
+		// WHERE clauses
+		$where_args = array(
+			'item_id' => $item_id,
+		);
+
+		if ( ! empty( $component_name ) ) {
+			$where_args['component_name'] = $component_name;
+		}
+
+		if ( ! empty( $component_action ) ) {
+			$where_args['component_action'] = $component_action;
+		}
+
+		if ( ! empty( $secondary_item_id ) ) {
+			$where_args['secondary_item_id'] = $secondary_item_id;
+		}
+
+		return self::update( $update_args, $where_args );
+	}
+}
Index: /tags/1.9/bp-notifications/bp-notifications-functions.php
===================================================================
--- /tags/1.9/bp-notifications/bp-notifications-functions.php	(revision 7684)
+++ /tags/1.9/bp-notifications/bp-notifications-functions.php	(revision 7684)
@@ -0,0 +1,510 @@
+<?php
+
+/**
+ * BuddyPress Member Notifications Functions.
+ *
+ * Functions and filters used in the Notifications component.
+ *
+ * @package BuddyPress
+ * @subpackage NotificationsFunctions
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/**
+ * Add a notification for a specific user, from a specific component.
+ *
+ * @since BuddyPress (1.9.0)
+ *
+ * @param array $args {
+ *     Array of arguments describing the notification. All are optional.
+ *     @type int $user_id ID of the user to associate the notificiton with.
+ *     @type int $item_id ID of the item to associate the notification with.
+ *     @type int $secondary_item_id ID of the secondary item to associate the
+ *           notification with.
+ *     @type string $component_name Name of the component to associate the
+ *           notification with.
+ *     @type string $component_action Name of the action to associate the
+ *           notification with.
+ *     @type string $date_notified Timestamp for the notification.
+ * }
+ * @return int|bool ID of the newly created notification on success, false
+ *         on failure.
+ */
+function bp_notifications_add_notification( $args = array() ) {
+
+	$r = wp_parse_args( $args, array(
+		'user_id'           => 0,
+		'item_id'           => 0,
+		'secondary_item_id' => 0,
+		'component_name'    => '',
+		'component_action'  => '',
+		'date_notified'     => bp_core_current_time(),
+		'is_new'            => 1,
+	) );
+
+	// Setup the new notification
+	$notification                    = new BP_Notifications_Notification;
+	$notification->user_id           = $r['user_id'];
+	$notification->item_id           = $r['item_id'];
+	$notification->secondary_item_id = $r['secondary_item_id'];
+	$notification->component_name    = $r['component_name'];
+	$notification->component_action  = $r['component_action'];
+	$notification->date_notified     = $r['date_notified'];
+	$notification->is_new            = $r['is_new'];
+
+	// Save the new notification
+	return $notification->save();
+}
+
+/**
+ * Get a specific notification by its ID.
+ *
+ * @since BuddyPress (1.9.0)
+ *
+ * @param int $id ID of the notification.
+ * @return BP_Notifications_Notification
+ */
+function bp_notifications_get_notification( $id ) {
+	return new BP_Notifications_Notification( $id );
+}
+
+/**
+ * Delete a specific notification by its ID.
+ *
+ * @since BuddyPress (1.9.0)
+ *
+ * @param int $id ID of the notification to delete.
+ * @return bool True on success, false on failure.
+ */
+function bp_notifications_delete_notification( $id ) {
+	if ( ! bp_notifications_check_notification_access( bp_loggedin_user_id(), $id ) ) {
+		return false;
+	}
+
+	return BP_Notifications_Notification::delete( array( 'id' => $id ) );
+}
+
+/**
+ * Mark notification read/unread for a user by ID.
+ *
+ * Used when clearing out notifications for a specific notification item.
+ *
+ * @since BuddyPress (1.9.0)
+ *
+ * @param int $user_id ID of the user whose notifications are being deleted.
+ * @param int $is_new 0 for read, 1 for unread
+ * @return bool True on success, false on failure.
+ */
+function bp_notifications_mark_notification( $id, $is_new = false ) {
+	if ( ! bp_notifications_check_notification_access( bp_loggedin_user_id(), $id ) ) {
+		return false;
+	}
+
+	return BP_Notifications_Notification::update(
+		array( 'is_new' => $is_new ),
+		array( 'id'     => $id     )
+	);
+}
+
+/**
+ * Get notifications for a specific user.
+ *
+ * @since BuddyPress (1.9.0)
+ *
+ * @param int $user_id ID of the user whose notification are being fetched.
+ * @param string $format Format of the returned values. 'simple' returns HTML,
+ *        while 'object' returns a structured object for parsing.
+ * @return mixed Object or array on success, false on failure.
+ */
+function bp_notifications_get_notifications_for_user( $user_id, $format = 'simple' ) {
+
+	// Setup local variables
+	$bp                    = buddypress();
+	$notifications         = BP_Notifications_Notification::get( array(
+		'user_id'        => $user_id,
+		'component_name' => array_keys( $bp->active_components ),
+	) );
+	$grouped_notifications = array(); // Notification groups
+	$renderable            = array(); // Renderable notifications
+
+	// Group notifications by component and component_action and provide totals
+	for ( $i = 0, $count = count( $notifications ); $i < $count; ++$i ) {
+		$notification = $notifications[$i];
+		$grouped_notifications[$notification->component_name][$notification->component_action][] = $notification;
+	}
+
+	// Bail if no notification groups
+	if ( empty( $grouped_notifications ) ) {
+		return false;
+	}
+
+	// Calculate a renderable output for each notification type
+	foreach ( $grouped_notifications as $component_name => $action_arrays ) {
+
+		// Skip if group is empty
+		if ( empty( $action_arrays ) ) {
+			continue;
+		}
+
+		// Loop through each actionable item and try to map it to a component
+		foreach ( (array) $action_arrays as $component_action_name => $component_action_items ) {
+
+			// Get the number of actionable items
+			$action_item_count = count( $component_action_items );
+
+			// Skip if the count is less than 1
+			if ( $action_item_count < 1 ) {
+				continue;
+			}
+
+			// Callback function exists
+			if ( isset( $bp->{$component_name}->notification_callback ) && is_callable( $bp->{$component_name}->notification_callback ) ) {
+
+				// Function should return an object
+				if ( 'object' === $format ) {
+
+					// Retrieve the content of the notification using the callback
+					$content = call_user_func(
+						$bp->{$component_name}->notification_callback,
+						$component_action_name,
+						$component_action_items[0]->item_id,
+						$component_action_items[0]->secondary_item_id,
+						$action_item_count,
+						'array'
+					);
+
+					// Create the object to be returned
+					$notification_object = new stdClass;
+
+					// Minimal backpat with non-compatible notification
+					// callback functions
+					if ( is_string( $content ) ) {
+						$notification_object->content = $content;
+						$notification_object->href    = bp_loggedin_user_domain();
+					} else {
+						$notification_object->content = $content['text'];
+						$notification_object->href    = $content['link'];
+					}
+
+					$notification_object->id = $component_action_items[0]->id;
+					$renderable[]            = $notification_object;
+
+				// Return an array of content strings
+				} else {
+					$content      = call_user_func( $bp->{$component_name}->notification_callback, $component_action_name, $component_action_items[0]->item_id, $component_action_items[0]->secondary_item_id, $action_item_count );
+					$renderable[] = $content;
+				}
+
+			// @deprecated format_notification_function - 1.5
+			} elseif ( isset( $bp->{$component_name}->format_notification_function ) && function_exists( $bp->{$component_name}->format_notification_function ) ) {
+				$renderable[] = call_user_func( $bp->{$component_name}->format_notification_function, $component_action_name, $component_action_items[0]->item_id, $component_action_items[0]->secondary_item_id, $action_item_count );
+
+			// Allow non BuddyPress components to hook in
+			} else {
+
+				// The array to reference with apply_filters_ref_array()
+				$ref_array = array(
+					$component_action_name,
+					$component_action_items[0]->item_id,
+					$component_action_items[0]->secondary_item_id,
+					$action_item_count,
+					$format
+				);
+
+				// Function should return an object
+				if ( 'object' === $format ) {
+
+					// Retrieve the content of the notification using the callback
+					$content = apply_filters_ref_array( 'bp_notifications_get_notifications_for_user', $ref_array );
+
+					// Create the object to be returned
+					$notification_object = new stdClass;
+
+					// Minimal backpat with non-compatible notification
+					// callback functions
+					if ( is_string( $content ) ) {
+						$notification_object->content = $content;
+						$notification_object->href    = bp_loggedin_user_domain();
+					} else {
+						$notification_object->content = $content['text'];
+						$notification_object->href    = $content['link'];
+					}
+
+					$notification_object->id = $component_action_items[0]->id;
+					$renderable[]            = $notification_object;
+
+				// Return an array of content strings
+				} else {
+					$renderable[] = apply_filters_ref_array( 'bp_notifications_get_notifications_for_user', $ref_array );
+				}
+			}
+		}
+	}
+
+	// If renderable is empty array, set to false
+	if ( empty( $renderable ) ) {
+		$renderable = false;
+	}
+
+	// Filter and return
+	return apply_filters( 'bp_core_get_notifications_for_user', $renderable, $user_id, $format );
+}
+
+/** Delete ********************************************************************/
+
+/**
+ * Delete notifications for a user by type.
+ *
+ * Used when clearing out notifications for a specific component when the user
+ * has visited that component.
+ *
+ * @since BuddyPress (1.9.0)
+ *
+ * @param int $user_id ID of the user whose notifications are being deleted.
+ * @param string $component_name Name of the associated component.
+ * @param string $component_action Name of the associated action.
+ * @return bool True on success, false on failure.
+ */
+function bp_notifications_delete_notifications_by_type( $user_id, $component_name, $component_action ) {
+	return BP_Notifications_Notification::delete( array(
+		'user_id'          => $user_id,
+		'component_name'   => $component_name,
+		'component_action' => $component_action,
+	) );
+}
+
+/**
+ * Delete notifications for an item ID.
+ *
+ * Used when clearing out notifications for a specific component when the user
+ * has visited that component.
+ *
+ * @since BuddyPress (1.9.0)
+ *
+ * @param int $user_id ID of the user whose notifications are being deleted.
+ * @param int $item_id ID of the associated item.
+ * @param string $component_name Name of the associated component.
+ * @param string $component_action Name of the associated action.
+ * @param int $secondary_item_id ID of the secondary associated item.
+ * @return bool True on success, false on failure.
+ */
+function bp_notifications_delete_notifications_by_item_id( $user_id, $item_id, $component_name, $component_action, $secondary_item_id = false ) {
+	return BP_Notifications_Notification::delete( array(
+		'user_id'           => $user_id,
+		'item_id'           => $item_id,
+		'secondary_item_id' => $secondary_item_id,
+		'component_name'    => $component_name,
+		'component_action'  => $component_action,
+	) );
+}
+
+/**
+ * Delete all notifications by type.
+ *
+ * Used when clearing out notifications for an entire component.
+ *
+ * @since BuddyPress (1.9.0)
+ *
+ * @param int $user_id ID of the user whose notifications are being deleted.
+ * @param string $component_name Name of the associated component.
+ * @param string $component_action Optional. Name of the associated action.
+ * @param int $secondary_item_id Optional. ID of the secondary associated item.
+ * @return bool True on success, false on failure.
+ */
+function bp_notifications_delete_all_notifications_by_type( $item_id, $component_name, $component_action = false, $secondary_item_id = false ) {
+	return BP_Notifications_Notification::delete( array(
+		'item_id'           => $item_id,
+		'secondary_item_id' => $secondary_item_id,
+		'component_name'    => $component_name,
+		'component_action'  => $component_action,
+	) );
+}
+
+/**
+ * Delete all notifications from a user.
+ *
+ * Used when clearing out all notifications for a user, when deleted or spammed.
+ *
+ * @todo This function assumes that items with the user_id in the item_id slot
+ *       are associated with that user. However, this will only be true with
+ *       certain components (such as Friends). Use with caution!
+ *
+ * @since BuddyPress (1.9.0)
+ *
+ * @param int $user_id ID of the user whose associated items are beind deleted.
+ * @param string $component_name Name of the associated component.
+ * @param string $component_action Name of the associated action.
+ * @return bool True on success, false on failure.
+ */
+function bp_notifications_delete_notifications_from_user( $user_id, $component_name, $component_action ) {
+	return BP_Notifications_Notification::delete( array(
+		'item_id'           => $user_id,
+		'component_name'    => $component_name,
+		'component_action'  => $component_action,
+	) );
+}
+
+/** Mark **********************************************************************/
+
+/**
+ * Mark notifications read/unread for a user by type.
+ *
+ * Used when clearing out notifications for a specific component when the user
+ * has visited that component.
+ *
+ * @since BuddyPress (1.9.0)
+ *
+ * @param int $user_id ID of the user whose notifications are being deleted.
+ * @param string $component_name Name of the associated component.
+ * @param string $component_action Name of the associated action.
+ * @param int $is_new 0 for read, 1 for unread
+ * @return bool True on success, false on failure.
+ */
+function bp_notifications_mark_notifications_by_type( $user_id, $component_name, $component_action, $is_new = false ) {
+	return BP_Notifications_Notification::update(
+		array(
+			'is_new' => $is_new
+		),
+		array(
+			'user_id'          => $user_id,
+			'component_name'   => $component_name,
+			'component_action' => $component_action
+		)
+	);
+}
+
+/**
+ * Mark notifications read/unread for an item ID.
+ *
+ * Used when clearing out notifications for a specific component when the user
+ * has visited that component.
+ *
+ * @since BuddyPress (1.9.0)
+ *
+ * @param int $user_id ID of the user whose notifications are being deleted.
+ * @param int $item_id ID of the associated item.
+ * @param string $component_name Name of the associated component.
+ * @param string $component_action Name of the associated action.
+ * @param int $secondary_item_id ID of the secondary associated item.
+ * @param int $is_new 0 for read, 1 for unread
+ * @return bool True on success, false on failure.
+ */
+function bp_notifications_mark_notifications_by_item_id( $user_id, $item_id, $component_name, $component_action, $secondary_item_id = false, $is_new = false ) {
+	return BP_Notifications_Notification::update(
+		array(
+			'is_new' => $is_new
+		),
+		array(
+			'user_id'           => $user_id,
+			'item_id'           => $item_id,
+			'secondary_item_id' => $secondary_item_id,
+			'component_name'    => $component_name,
+			'component_action'  => $component_action
+		)
+	);
+}
+
+/**
+ * Mark all notifications read/unread by type.
+ *
+ * Used when clearing out notifications for an entire component.
+ *
+ * @since BuddyPress (1.9.0)
+ *
+ * @param int $user_id ID of the user whose notifications are being deleted.
+ * @param int $is_new 0 for read, 1 for unread
+ * @param string $component_name Name of the associated component.
+ * @param string $component_action Optional. Name of the associated action.
+ * @param int $secondary_item_id Optional. ID of the secondary associated item.
+ * @param int $is_new 0 for read, 1 for unread
+ * @return bool True on success, false on failure.
+ */
+function bp_notifications_mark_all_notifications_by_type( $item_id, $component_name, $component_action = false, $secondary_item_id = false, $is_new = false ) {
+	return BP_Notifications_Notification::update(
+		array(
+			'is_new' => $is_new
+		),
+		array(
+			'item_id'           => $item_id,
+			'secondary_item_id' => $secondary_item_id,
+			'component_name'    => $component_name,
+			'component_action'  => $component_action
+		)
+	);
+}
+
+/**
+ * Mark all notifications read/unread from a user.
+ *
+ * Used when clearing out all notifications for a user, when deleted or spammed.
+ *
+ * @todo This function assumes that items with the user_id in the item_id slot
+ *       are associated with that user. However, this will only be true with
+ *       certain components (such as Friends). Use with caution!
+ *
+ * @since BuddyPress (1.9.0)
+ *
+ * @param int $user_id ID of the user whose associated items are beind deleted.
+ * @param int $is_new 0 for read, 1 for unread
+ * @param string $component_name Name of the associated component.
+ * @param string $component_action Name of the associated action.
+ * @param int $is_new 0 for read, 1 for unread
+ * @return bool True on success, false on failure.
+ */
+function bp_notifications_mark_notifications_from_user( $user_id, $component_name, $component_action, $is_new = false ) {
+	return BP_Notifications_Notification::update(
+		array(
+			'is_new' => $is_new
+		),
+		array(
+			'item_id'          => $user_id,
+			'component_name'   => $component_name,
+			'component_action' => $component_action
+		)
+	);
+}
+
+/** Helpers *******************************************************************/
+
+/**
+ * Check if a user has access to a specific notification.
+ *
+ * Used before deleting a notification for a user.
+ *
+ * @since BuddyPress (1.9.0)
+ *
+ * @param int $user_id ID of the user being checked.
+ * @param int $notification_id ID of the notification being checked.
+ * @return bool True if the notification belongs to the user, otherwise false.
+ */
+function bp_notifications_check_notification_access( $user_id, $notification_id ) {
+	return (bool) BP_Notifications_Notification::check_access( $user_id, $notification_id );
+}
+
+/**
+ * Get a count of unread notification items for a user.
+ *
+ * @since BuddyPress (1.9.0)
+ *
+ * @param int $user_id ID of the user whose unread notifications are being
+ *        counted.
+ * @return int Unread notification count.
+ */
+function bp_notifications_get_unread_notification_count( $user_id = 0 ) {
+
+	// Default to displayed user if no ID is passed
+	if ( empty( $user_id ) ) {
+		$user_id = ( bp_displayed_user_id() ) ? bp_displayed_user_id() : bp_loggedin_user_id();
+	}
+
+	// Get the notifications, and count them
+	$notifications = BP_Notifications_Notification::get( array(
+		'user_id' => $user_id,
+	) );
+
+	$count = ! empty( $notifications ) ? count( $notifications ) : 0;
+
+	return apply_filters( 'bp_notifications_get_total_notification_count', $count );
+}
Index: /tags/1.9/bp-notifications/bp-notifications-loader.php
===================================================================
--- /tags/1.9/bp-notifications/bp-notifications-loader.php	(revision 7684)
+++ /tags/1.9/bp-notifications/bp-notifications-loader.php	(revision 7684)
@@ -0,0 +1,245 @@
+<?php
+
+/**
+ * BuddyPress Member Notifications Loader.
+ *
+ * Initializes the Notifications component.
+ *
+ * @package BuddyPress
+ * @subpackage NotificationsLoader
+ * @since BuddyPress (1.9.0)
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+class BP_Notifications_Component extends BP_Component {
+
+	/**
+	 * Start the notifications component creation process.
+	 *
+	 * @since BuddyPress (1.9.0)
+	 */
+	function __construct() {
+		parent::start(
+			'notifications',
+			__( 'Notifications', 'buddypress' ),
+			BP_PLUGIN_DIR,
+			array(
+				'adminbar_myaccount_order' => 30
+			)
+		);
+	}
+
+	/**
+	 * Include notifications component files.
+	 *
+	 * @since BuddyPress (1.9.0)
+	 *
+	 * @see BP_Component::includes() for a description of arguments.
+	 *
+	 * @param array $includes See BP_Component::includes() for a description.
+	 */
+	public function includes( $includes = array() ) {
+		$includes = array(
+			'actions',
+			'classes',
+			'screens',
+			'adminbar',
+			'buddybar',
+			'template',
+			'functions',
+		);
+
+		parent::includes( $includes );
+	}
+
+	/**
+	 * Setup globals
+	 *
+	 * The BP_FRIENDS_SLUG constant is deprecated, and only used here for
+	 * backwards compatibility.
+	 *
+	 * @since BuddyPress (1.9.0)
+	 *
+	 * @see BP_Component::setup_globals() for a description of arguments.
+	 *
+	 * @param array $args See BP_Component::setup_globals() for a description.
+	 */
+	public function setup_globals( $args = array() ) {
+		// Define a slug, if necessary
+		if ( !defined( 'BP_NOTIFICATIONS_SLUG' ) ) {
+			define( 'BP_NOTIFICATIONS_SLUG', $this->id );
+		}
+
+		// Global tables for the notifications component
+		$global_tables = array(
+			'table_name' => bp_core_get_table_prefix() . 'bp_notifications'
+		);
+
+		// All globals for the notifications component.
+		// Note that global_tables is included in this array.
+		$args = array(
+			'slug'          => BP_NOTIFICATIONS_SLUG,
+			'has_directory' => false,
+			'search_string' => __( 'Search Notifications...', 'buddypress' ),
+			'global_tables' => $global_tables,
+		);
+
+		parent::setup_globals( $args );
+	}
+
+	/**
+	 * Set up component navigation.
+	 *
+	 * @since BuddyPress (1.9.0)
+	 *
+	 * @see BP_Component::setup_nav() for a description of arguments.
+	 *
+	 * @param array $main_nav Optional. See BP_Component::setup_nav() for
+	 *        description.
+	 * @param array $sub_nav Optional. See BP_Component::setup_nav() for
+	 *        description.
+	 */
+	public function setup_nav( $main_nav = array(), $sub_nav = array() ) {
+
+		// Add 'Notifications' to the main navigation
+		$count    = bp_notifications_get_unread_notification_count( bp_loggedin_user_id() );
+		$main_nav = array(
+			'name'                    => sprintf( __( 'Notifications <span>%d</span>', 'buddypress' ), number_format_i18n( $count ) ),
+			'slug'                    => $this->slug,
+			'position'                => 30,
+			'show_for_displayed_user' => bp_core_can_edit_settings(),
+			'screen_function'         => 'bp_notifications_screen_unread',
+			'default_subnav_slug'     => 'unread',
+			'item_css_id'             => $this->id,
+		);
+
+		// Determine user to use
+		if ( bp_displayed_user_domain() ) {
+			$user_domain = bp_displayed_user_domain();
+		} elseif ( bp_loggedin_user_domain() ) {
+			$user_domain = bp_loggedin_user_domain();
+		} else {
+			return;
+		}
+
+		$notifications_link = trailingslashit( $user_domain . bp_get_notifications_slug() );
+
+		// Add the subnav items to the notifications nav item
+		$sub_nav[] = array(
+			'name'            => __( 'Unread', 'buddypress' ),
+			'slug'            => 'unread',
+			'parent_url'      => $notifications_link,
+			'parent_slug'     => bp_get_notifications_slug(),
+			'screen_function' => 'bp_notifications_screen_unread',
+			'position'        => 10,
+			'item_css_id'     => 'notifications-my-notifications',
+			'user_has_access' => bp_core_can_edit_settings(),
+		);
+
+		$sub_nav[] = array(
+			'name'            => __( 'Read',   'buddypress' ),
+			'slug'            => 'read',
+			'parent_url'      => $notifications_link,
+			'parent_slug'     => bp_get_notifications_slug(),
+			'screen_function' => 'bp_notifications_screen_read',
+			'position'        => 20,
+			'user_has_access' => bp_core_can_edit_settings(),
+		);
+
+		parent::setup_nav( $main_nav, $sub_nav );
+	}
+
+	/**
+	 * Set up the component entries in the WordPress Admin Bar.
+	 *
+	 * @since BuddyPress (1.9.0)
+	 *
+	 * @see BP_Component::setup_nav() for a description of the $wp_admin_nav
+	 *      parameter array.
+	 *
+	 * @param array $wp_admin_nav See BP_Component::setup_admin_bar() for a
+	 *        description.
+	 */
+	public function setup_admin_bar( $wp_admin_nav = array() ) {
+
+		// Menus for logged in user
+		if ( is_user_logged_in() ) {
+
+			// Setup the logged in user variables
+			$notifications_link = trailingslashit( bp_loggedin_user_domain() . $this->slug );
+
+			// Pending notification requests
+			$count = bp_notifications_get_unread_notification_count( bp_loggedin_user_id() );
+			if ( ! empty( $count ) ) {
+				$title  = sprintf( __( 'Notifications <span class="count">%s</span>', 'buddypress' ), number_format_i18n( $count ) );
+				$unread = sprintf( __( 'Unread <span class="count">%s</span>',        'buddypress' ), number_format_i18n( $count ) );
+			} else {
+				$title  = __( 'Notifications', 'buddypress' );
+				$unread = __( 'Unread',        'buddypress' );
+			}
+
+			// Add the "My Account" sub menus
+			$wp_admin_nav[] = array(
+				'parent' => buddypress()->my_account_menu_id,
+				'id'     => 'my-account-' . $this->id,
+				'title'  => $title,
+				'href'   => trailingslashit( $notifications_link ),
+			);
+
+			// Unread
+			$wp_admin_nav[] = array(
+				'parent' => 'my-account-' . $this->id,
+				'id'     => 'my-account-' . $this->id . '-unread',
+				'title'  => $unread,
+				'href'   => trailingslashit( $notifications_link ),
+			);
+
+			// Read
+			$wp_admin_nav[] = array(
+				'parent' => 'my-account-' . $this->id,
+				'id'     => 'my-account-' . $this->id . '-read',
+				'title'  => __( 'Read', 'buddypress' ),
+				'href'   => trailingslashit( $notifications_link . 'read' ),
+			);
+		}
+
+		parent::setup_admin_bar( $wp_admin_nav );
+	}
+
+	/**
+	 * Set up the title for pages and <title>.
+	 *
+	 * @since BuddyPress (1.9.0)
+	 */
+	function setup_title() {
+		$bp = buddypress();
+
+		// Adjust title
+		if ( bp_is_notifications_component() ) {
+			if ( bp_is_my_profile() ) {
+				$bp->bp_options_title = __( 'Notifications', 'buddypress' );
+			} else {
+				$bp->bp_options_avatar = bp_core_fetch_avatar( array(
+					'item_id' => bp_displayed_user_id(),
+					'type'    => 'thumb',
+					'alt'     => sprintf( __( 'Profile picture of %s', 'buddypress' ), bp_get_displayed_user_fullname() )
+				) );
+				$bp->bp_options_title = bp_get_displayed_user_fullname();
+			}
+		}
+
+		parent::setup_title();
+	}
+}
+
+/**
+ * Bootstrap the Notifications component.
+ *
+ * @since BuddyPress (1.9.0)
+ */
+function bp_setup_notifications() {
+	buddypress()->notifications = new BP_Notifications_Component();
+}
+add_action( 'bp_setup_components', 'bp_setup_notifications', 6 );
Index: /tags/1.9/bp-notifications/bp-notifications-screens.php
===================================================================
--- /tags/1.9/bp-notifications/bp-notifications-screens.php	(revision 7684)
+++ /tags/1.9/bp-notifications/bp-notifications-screens.php	(revision 7684)
@@ -0,0 +1,46 @@
+<?php
+
+/**
+ * BuddyPress Notifications Screen Functions.
+ *
+ * Screen functions are the controllers of BuddyPress. They will execute when
+ * their specific URL is caught. They will first save or manipulate data using
+ * business functions, then pass on the user to a template file.
+ *
+ * @package BuddyPress
+ * @subpackage NotificationsScreens
+ */
+
+// Exit if accessed directly
+if ( ! defined( 'ABSPATH' ) ) exit;
+
+/**
+ * Catch and route the 'unread' notifications screen.
+ *
+ * @since BuddyPress (1.9.0)
+ */
+function bp_notifications_screen_unread() {
+	do_action( 'bp_notifications_screen_unread' );
+
+	bp_core_load_template( apply_filters( 'bp_notifications_template_unread', 'members/single/home' ) );
+}
+
+/**
+ * Catch and route the 'read' notifications screen.
+ *
+ * @since BuddyPress (1.9.0)
+ */
+function bp_notifications_screen_read() {
+	do_action( 'bp_notifications_screen_read' );
+
+	bp_core_load_template( apply_filters( 'bp_notifications_template_read', 'members/single/home' ) );
+}
+
+/**
+ * Catch and route the 'settings' notifications screen.
+ *
+ * @since BuddyPress (1.9.0)
+ */
+function bp_notifications_screen_settings() {
+
+}
Index: /tags/1.9/bp-notifications/bp-notifications-template.php
===================================================================
--- /tags/1.9/bp-notifications/bp-notifications-template.php	(revision 7684)
+++ /tags/1.9/bp-notifications/bp-notifications-template.php	(revision 7684)
@@ -0,0 +1,953 @@
+<?php
+
+/**
+ * BuddyPress Notifications Template Functions
+ *
+ * @package BuddyPress
+ * @subpackage TonificationsTemplate
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/**
+ * Output the notifications component slug.
+ *
+ * @since BuddyPress (1.9.0)
+ */
+function bp_notifications_slug() {
+	echo bp_get_notifications_slug();
+}
+	/**
+	 * Return the notifications component slug.
+	 *
+	 * @since BuddyPress (1.9.0)
+	 *
+	 * @return string Slug of the Notifications component.
+	 */
+	function bp_get_notifications_slug() {
+		return apply_filters( 'bp_get_notifications_slug', buddypress()->notifications->slug );
+	}
+
+/**
+ * Output the notifications permalink.
+ *
+ * @since BuddyPress (1.9.0)
+ */
+function bp_notifications_permalink() {
+	echo bp_get_notifications_permalink();
+}
+	/**
+	 * Return the notifications permalink.
+	 *
+	 * @since BuddyPress (1.9.0)
+	 *
+	 * @return string Notifications permalink
+	 */
+	function bp_get_notifications_permalink() {
+		$retval = trailingslashit( bp_loggedin_user_domain() . bp_get_notifications_slug() );
+		return apply_filters( 'bp_get_notifications_permalink', $retval );
+	}
+
+/**
+ * Output the unread notifications permalink.
+ *
+ * @since BuddyPress (1.9.0)
+ */
+function bp_notifications_unread_permalink() {
+	echo bp_get_notifications_unread_permalink();
+}
+	/**
+	 * Return the unread notifications permalink.
+	 *
+	 * @since BuddyPress (1.9.0)
+	 *
+	 * @return string Unread notifications permalink
+	 */
+	function bp_get_notifications_unread_permalink() {
+		$retval = trailingslashit( bp_loggedin_user_domain() . bp_get_notifications_slug() . '/unread' );
+		return apply_filters( 'bp_get_notifications_unread_permalink', $retval );
+	}
+
+/**
+ * Output the read notifications permalink.
+ *
+ * @since BuddyPress (1.9.0)
+ */
+function bp_notifications_read_permalink() {
+	echo bp_get_notifications_read_permalink();
+}
+	/**
+	 * Return the read notifications permalink.
+	 *
+	 * @since BuddyPress (1.9.0)
+	 *
+	 * @return string Read notifications permalink
+	 */
+	function bp_get_notifications_read_permalink() {
+		$retval = trailingslashit( bp_loggedin_user_domain() . bp_get_notifications_slug() . '/read' );
+		return apply_filters( 'bp_get_notifications_unread_permalink', $retval );
+	}
+
+/** Main Loop *****************************************************************/
+
+/**
+ * The main notifications template loop class.
+ *
+ * Responsible for loading a group of notifications into a loop for display.
+ *
+ * @since BuddyPress (1.9.0)
+ */
+class BP_Notifications_Template {
+
+	/**
+	 * The loop iterator.
+	 *
+	 * @since BuddyPress (1.9.0)
+	 * @access public
+	 * @var int
+	 */
+	public $current_notification = -1;
+
+	/**
+	 * The number of notifications returned by the paged query.
+	 *
+	 * @since BuddyPress (1.9.0)
+	 * @access public
+	 * @var int
+	 */
+	public $current_notification_count;
+
+	/**
+	 * Total number of notifications matching the query.
+	 *
+	 * @since BuddyPress (1.9.0)
+	 * @access public
+	 * @var int
+	 */
+	public $total_notification_count;
+
+	/**
+	 * Array of notifications located by the query.
+	 *
+	 * @since BuddyPress (1.9.0)
+	 * @access public
+	 * @var array
+	 */
+	public $notifications;
+
+	/**
+	 * The notification object currently being iterated on.
+	 *
+	 * @since BuddyPress (1.9.0)
+	 * @access public
+	 * @var object
+	 */
+	public $notification;
+
+	/**
+	 * A flag for whether the loop is currently being iterated.
+	 *
+	 * @since BuddyPress (1.9.0)
+	 * @access public
+	 * @var bool
+	 */
+	public $in_the_loop;
+
+	/**
+	 * The ID of the user to whom the displayed notifications belong.
+	 *
+	 * @since BuddyPress (1.9.0)
+	 * @access public
+	 * @var int
+	 */
+	public $user_id;
+
+	/**
+	 * The page number being requested.
+	 *
+	 * @since BuddyPress (1.9.0)
+	 * @access public
+	 * @var int
+	 */
+	public $pag_page;
+
+	/**
+	 * The number of items to display per page of results.
+	 *
+	 * @since BuddyPress (1.9.0)
+	 * @access public
+	 * @var int
+	 */
+	public $pag_num;
+
+	/**
+	 * An HTML string containing pagination links.
+	 *
+	 * @since BuddyPress (1.9.0)
+	 * @access public
+	 * @var string
+	 */
+	public $pag_links;
+
+	/**
+	 * A string to match against.
+	 *
+	 * @since BuddyPress (1.9.0)
+	 * @access public
+	 * @var string
+	 */
+	public $search_terms;
+
+	/**
+	 * A database column to order the results by.
+	 *
+	 * @since BuddyPress (1.9.0)
+	 * @access public
+	 * @var string
+	 */
+	public $order_by;
+
+	/**
+	 * The direction to sort the results (ASC or DESC)
+	 *
+	 * @since BuddyPress (1.9.0)
+	 * @access public
+	 * @var string
+	 */
+	public $sort_order;
+
+	/**
+	 * Constructor method.
+	 *
+	 * @since BuddyPress (1.9.0)
+	 *
+	 * @param array $args {
+	 *     @type int $user_id ID of the user to whom the displayed
+	 *           notifications belong.
+	 *     @type bool $is_new Whether to limit the query to unread
+	 *           notifications. Default: true.
+	 *     @type int $page Number of the page of results to return.
+	 *           Will be overridden by URL parameter. Default: 1.
+	 *     @type int $per_page Number of results to return per page.
+	 *           Will be overridden by URL parameter. Default: 25.
+	 *     @type int $max Optional. Max results to display.
+	 *     @type string $search_terms Optional. Term to match against
+	 *           component_name and component_action.
+	 *     @type string $page_arg URL argument to use for pagination.
+	 *           Default: 'npage'.
+	 * }
+	 */
+	public function __construct( $args = array() ) {
+
+		// Parse arguments
+		$r = wp_parse_args( $args, array(
+			'user_id'      => 0,
+			'is_new'       => true,
+			'page'         => 1,
+			'per_page'     => 25,
+			'order_by'     => 'date_notified',
+			'sort_order'   => 'DESC',
+			'max'          => null,
+			'search_terms' => '',
+			'page_arg'     => 'npage',
+		) );
+
+		// Overrides
+
+		// Set which pagination page
+		if ( isset( $_GET[ $r['page_arg'] ] ) ) {
+			$pag_page = intval( $_GET[ $r['page_arg'] ] );
+		} else {
+			$pag_page = $r['page'];
+		}
+
+		// Set the number to show per page
+		if ( isset( $_GET['num'] ) ) {
+			$pag_num = intval( $_GET['num'] );
+		} else {
+			$pag_num = intval( $r['per_page'] );
+		}
+
+		// Sort order direction
+		$orders = array( 'ASC', 'DESC' );
+		if ( ! empty( $_GET['sort_order'] ) && in_array( $_GET['sort_order'], $orders ) ) {
+			$sort_order = $_GET['sort_order'];
+		} else {
+			$sort_order = in_array( $r['sort_order'], $orders ) ? $r['sort_order'] : 'DESC';
+		}
+
+		// Setup variables
+		$this->pag_page     = $pag_page;
+		$this->pag_num      = $pag_num;
+		$this->user_id      = $r['user_id'];
+		$this->is_new       = $r['is_new'];
+		$this->search_terms = $r['search_terms'];
+		$this->page_arg     = $r['page_arg'];
+		$this->order_by     = $r['order_by'];
+		$this->sort_order   = $sort_order;
+
+		// Get the notifications
+		$notifications      = BP_Notifications_Notification::get_current_notifications_for_user( array(
+			'user_id'      => $this->user_id,
+			'is_new'       => $this->is_new,
+			'page'         => $this->pag_page,
+			'per_page'     => $this->pag_num,
+			'search_terms' => $this->search_terms,
+			'order_by'     => $this->order_by,
+			'sort_order'   => $this->sort_order,
+		) );
+
+		// Setup the notifications to loop through
+		$this->notifications            = $notifications['notifications'];
+		$this->total_notification_count = $notifications['total'];
+
+		if ( empty( $this->notifications ) ) {
+			$this->notification_count       = 0;
+			$this->total_notification_count = 0;
+
+		} else {
+			if ( ! empty( $max ) ) {
+				if ( $max >= count( $this->notifications ) ) {
+					$this->notification_count = count( $this->notifications );
+				} else {
+					$this->notification_count = (int) $max;
+				}
+			} else {
+				$this->notification_count = count( $this->notifications );
+			}
+		}
+
+		if ( (int) $this->total_notification_count && (int) $this->pag_num ) {
+			$this->pag_links = paginate_links( array(
+				'base'      => add_query_arg( $this->page_arg, '%#%' ),
+				'format'    => '',
+				'total'     => ceil( (int) $this->total_notification_count / (int) $this->pag_num ),
+				'current'   => $this->pag_page,
+				'prev_text' => _x( '&larr;', 'Notifications pagination previous text', 'buddypress' ),
+				'next_text' => _x( '&rarr;', 'Notifications pagination next text',     'buddypress' ),
+				'mid_size'  => 1,
+			) );
+
+			// Remove first page from pagination
+			$this->pag_links = str_replace( '?'      . $r['page_arg'] . '=1', '', $this->pag_links );
+			$this->pag_links = str_replace( '&#038;' . $r['page_arg'] . '=1', '', $this->pag_links );
+		}
+	}
+
+	/**
+	 * Whether there are notifications available in the loop.
+	 *
+	 * @since BuddyPress (1.9.0)
+	 *
+	 * @see bp_has_notifications()
+	 *
+	 * @return bool True if there are items in the loop, otherwise false.
+	 */
+	public function has_notifications() {
+		if ( $this->notification_count ) {
+			return true;
+		}
+
+		return false;
+	}
+
+	/**
+	 * Set up the next notification and iterate index.
+	 *
+	 * @since BuddyPress (1.9.0)
+	 *
+	 * @return object The next notification to iterate over.
+	 */
+	public function next_notification() {
+
+		$this->current_notification++;
+
+		$this->notification = $this->notifications[ $this->current_notification ];
+
+		return $this->notification;
+	}
+
+	/**
+	 * Rewind the blogs and reset blog index.
+	 *
+	 * @since BuddyPress (1.9.0)
+	 */
+	public function rewind_notifications() {
+
+		$this->current_notification = -1;
+
+		if ( $this->notification_count > 0 ) {
+			$this->notification = $this->notifications[0];
+		}
+	}
+
+	/**
+	 * Whether there are notifications left in the loop to iterate over.
+	 *
+	 * This method is used by {@link bp_notifications()} as part of the
+	 * while loop that controls iteration inside the notifications loop, eg:
+	 *     while ( bp_notifications() ) { ...
+	 *
+	 * @since BuddyPress (1.9.0)
+	 *
+	 * @see bp_notifications()
+	 *
+	 * @return bool True if there are more notifications to show,
+	 *         otherwise false.
+	 */
+	public function notifications() {
+
+		if ( $this->current_notification + 1 < $this->notification_count ) {
+			return true;
+
+		} elseif ( $this->current_notification + 1 == $this->notification_count ) {
+			do_action( 'notifications_loop_end');
+
+			$this->rewind_notifications();
+		}
+
+		$this->in_the_loop = false;
+		return false;
+	}
+
+	/**
+	 * Set up the current notification inside the loop.
+	 *
+	 * Used by {@link bp_the_notification()} to set up the current
+	 * notification data while looping, so that template tags used during
+	 * that iteration make reference to the current notification.
+	 *
+	 * @since BuddyPress (1.9.0)
+	 *
+	 * @see bp_the_notification()
+	 */
+	public function the_notification() {
+		$this->in_the_loop  = true;
+		$this->notification = $this->next_notification();
+
+		// loop has just started
+		if ( 0 === $this->current_notification ) {
+			do_action( 'notifications_loop_start' );
+		}
+	}
+}
+
+/** The Loop ******************************************************************/
+
+/**
+ * Initialize the notifications loop.
+ *
+ * Based on the $args passed, bp_has_notifications() populates
+ * buddypress()->notifications->query_loop global, enabling the use of BP
+ * templates and template functions to display a list of notifications.
+ *
+ * @since BuddyPress (1.9.0)
+ *
+ * @param array $args {
+ *     Arguments for limiting the contents of the notifications loop. Can be
+ *     passed as an associative array, or as a URL query string.
+ *     @type int $user_id ID of the user to whom notifications belong. Default:
+ *           ID of the logged-in user.
+ *     @type bool $is_new Whether to limit query to unread notifications.
+ *           Default: when viewing the 'unread' tab, defaults to true; when
+ *           viewing the 'read' tab, defaults to false.
+ *     @type int $page The page of notifications being fetched. Default: 1.
+ *     @type int $per_page Number of items to display on a page. Default: 25.
+ *     @type int $max Optional. Max items to display. Default: false.
+ *     @type string $search_terms Optional. Term to match against
+ *           component_name and component_action.
+ *     @type string $page_arg URL argument to use for pagination.
+ *           Default: 'npage'.
+ * }
+ */
+function bp_has_notifications( $args = '' ) {
+
+	// Get the default is_new argument
+	if ( bp_is_current_action( 'unread' ) ) {
+		$is_new = 1;
+	} elseif ( bp_is_current_action( 'read' ) ) {
+		$is_new = 0;
+	}
+
+	// Get the user ID
+	if ( bp_displayed_user_id() ) {
+		$user_id = bp_displayed_user_id();
+	} else {
+		$user_id = bp_loggedin_user_id();
+	}
+
+	// Parse the args
+	$r = wp_parse_args( $args, array(
+		'user_id'      => $user_id,
+		'is_new'       => $is_new,
+		'page'         => 1,
+		'per_page'     => 25,
+		'max'          => false,
+		'search_terms' => isset( $_REQUEST['s'] ) ? stripslashes( $_REQUEST['s'] ) : '',
+		'page_arg'     => 'npage',
+	) );
+
+	// Get the notifications
+	$query_loop = new BP_Notifications_Template( $r );
+
+	// Setup the global query loop
+	buddypress()->notifications->query_loop = $query_loop;
+
+	return apply_filters( 'bp_has_notificationss', $query_loop->has_notifications(), $query_loop );
+}
+
+/**
+ * Get the notifications returned by the template loop.
+ *
+ * @since BuddyPress (1.9.0)
+ *
+ * @return array List of notifications.
+ */
+function bp_the_notifications() {
+	return buddypress()->notifications->query_loop->notifications();
+}
+
+/**
+ * Get the current notification object in the loop.
+ *
+ * @since BuddyPress (1.9.0)
+ *
+ * @return object The current notification within the loop.
+ */
+function bp_the_notification() {
+	return buddypress()->notifications->query_loop->the_notification();
+}
+
+/** Loop Output ***************************************************************/
+
+/**
+ * Output the ID of the notification currently being iterated on.
+ *
+ * @since BuddyPress (1.9.0)
+ */
+function bp_the_notification_id() {
+	echo bp_get_the_notification_id();
+}
+	/**
+	 * Return the ID of the notification currently being iterated on.
+	 *
+	 * @since BuddyPress (1.9.0)
+	 *
+	 * @return int ID of the current notification.
+	 */
+	function bp_get_the_notification_id() {
+		return apply_filters( 'bp_get_the_notification_id', buddypress()->notifications->query_loop->notification->id );
+	}
+
+/**
+ * Output the associated item ID of the notification currently being iterated on.
+ *
+ * @since BuddyPress (1.9.0)
+ */
+function bp_the_notification_item_id() {
+	echo bp_get_the_notification_item_id();
+}
+	/**
+	 * Return the associated item ID of the notification currently being iterated on.
+	 *
+	 * @since BuddyPress (1.9.0)
+	 *
+	 * @return int ID of the item associated with the current notification.
+	 */
+	function bp_get_the_notification_item_id() {
+		return apply_filters( 'bp_get_the_notification_item_id', buddypress()->notifications->query_loop->notification->item_id );
+	}
+
+/**
+ * Output the secondary associated item ID of the notification currently being iterated on.
+ *
+ * @since BuddyPress (1.9.0)
+ */
+function bp_the_notification_secondary_item_id() {
+	echo bp_get_the_notification_secondary_item_id();
+}
+	/**
+	 * Return the secondary associated item ID of the notification currently being iterated on.
+	 *
+	 * @since BuddyPress (1.9.0)
+	 *
+	 * @return int ID of the secondary item associated with the current notification.
+	 */
+	function bp_get_the_notification_secondary_item_id() {
+		return apply_filters( 'bp_get_the_notification_secondary_item_id', buddypress()->notifications->query_loop->notification->secondary_item_id );
+	}
+
+/**
+ * Output the name of the component associated with the notification currently being iterated on.
+ *
+ * @since BuddyPress (1.9.0)
+ */
+function bp_the_notification_component_name() {
+	echo bp_get_the_notification_component_name();
+}
+	/**
+	 * Return the name of the component associated with the notification currently being iterated on.
+	 *
+	 * @since BuddyPress (1.9.0)
+	 *
+	 * @return int Name of the component associated with the current notification.
+	 */
+	function bp_get_the_notification_component_name() {
+		return apply_filters( 'bp_get_the_notification_component_name', buddypress()->notifications->query_loop->notification->component_name );
+	}
+
+/**
+ * Output the name of the action associated with the notification currently being iterated on.
+ *
+ * @since BuddyPress (1.9.0)
+ */
+function bp_the_notification_component_action() {
+	echo bp_get_the_notification_component_action();
+}
+	/**
+	 * Return the name of the action associated with the notification currently being iterated on.
+	 *
+	 * @since BuddyPress (1.9.0)
+	 *
+	 * @return int Name of the action associated with the current notification.
+	 */
+	function bp_get_the_notification_component_action() {
+		return apply_filters( 'bp_get_the_notification_component_action', buddypress()->notifications->query_loop->notification->component_action );
+	}
+
+/**
+ * Output the timestamp of the current notification.
+ *
+ * @since BuddyPress (1.9.0)
+ */
+function bp_the_notification_date_notified() {
+	echo bp_get_the_notification_date_notified();
+}
+	/**
+	 * Return the timestamp of the current notification.
+	 *
+	 * @since BuddyPress (1.9.0)
+	 *
+	 * @return string Timestamp of the current notification.
+	 */
+	function bp_get_the_notification_date_notified() {
+		return apply_filters( 'bp_get_the_notification_date_notified', buddypress()->notifications->query_loop->notification->date_notified );
+	}
+
+/**
+ * Output the timestamp of the current notification.
+ *
+ * @since BuddyPress (1.9.0)
+ */
+function bp_the_notification_time_since() {
+	echo bp_get_the_notification_time_since();
+}
+	/**
+	 * Return the timestamp of the current notification.
+	 *
+	 * @since BuddyPress (1.9.0)
+	 *
+	 * @return string Timestamp of the current notification.
+	 */
+	function bp_get_the_notification_time_since() {
+
+		// Get the notified date
+		$date_notified = bp_get_the_notification_date_notified();
+
+		// Notified date has legitimate data
+		if ( '0000-00-00 00:00:00' !== $date_notified ) {
+			$retval = bp_core_time_since( $date_notified );
+
+		// Notified date is empty, so return a fun string
+		} else {
+			$retval = __( 'Date not found', 'buddypress' );
+		}
+
+		return apply_filters( 'bp_get_the_notification_time_since', $retval );
+	}
+
+/**
+ * Output full-text description for a specific notification.
+ *
+ * @since BuddyPress (1.9.0)
+ */
+function bp_the_notification_description() {
+	echo bp_get_the_notification_description();
+}
+
+	/**
+	 * Get full-text description for a specific notification.
+	 *
+	 * @since BuddyPress (1.9.0)
+	 *
+	 * @return string
+	 */
+	function bp_get_the_notification_description() {
+
+		// Setup local variables
+		$description  = '';
+		$bp           = buddypress();
+		$notification = $bp->notifications->query_loop->notification;
+
+		// Callback function exists
+		if ( isset( $bp->{ $notification->component_name }->notification_callback ) && is_callable( $bp->{ $notification->component_name }->notification_callback ) ) {
+			$description = call_user_func( $bp->{ $notification->component_name }->notification_callback, $notification->component_action, $notification->item_id, $notification->secondary_item_id, 1 );
+
+		// @deprecated format_notification_function - 1.5
+		} elseif ( isset( $bp->{ $notification->component_name }->format_notification_function ) && function_exists( $bp->{ $notification->component_name }->format_notification_function ) ) {
+			$description = call_user_func( $bp->{ $notification->component_name }->format_notification_function, $notification->component_action, $notification->item_id, $notification->secondary_item_id, 1 );
+
+		// Allow non BuddyPress components to hook in
+		} else {
+			$description = apply_filters_ref_array( 'bp_notifications_get_notifications_for_user', array( $notification->component_action, $notification->item_id, $notification->secondary_item_id, 1 ) );
+		}
+
+		// Filter and return
+		return apply_filters( 'bp_get_the_notification_description', $description );
+	}
+
+/**
+ * Output the mark read link for the current notification.
+ *
+ * @since BuddyPress (1.9.0)
+ *
+ * @uses bp_get_the_notification_mark_read_link()
+ */
+function bp_the_notification_mark_read_link() {
+	echo bp_get_the_notification_mark_read_link();
+}
+	/**
+	 * Return the mark read link for the current notification.
+	 *
+	 * @since BuddyPress (1.9.0)
+	 */
+	function bp_get_the_notification_mark_read_link() {
+
+		// Get the URL with nonce, action, and id
+		$url = wp_nonce_url( add_query_arg( array( 'action' => 'read', 'notification_id' => bp_get_the_notification_id() ), bp_get_notifications_unread_permalink() ), 'bp_notification_mark_read_' . bp_get_the_notification_id() );
+
+		// Start the output buffer
+		ob_start(); ?>
+
+		<a href="<?php echo esc_url( $url ); ?>" class="mark-read primary"><?php _e( 'Read', 'buddypress' ); ?></a>
+
+		<?php $retval = ob_get_clean();
+
+		return apply_filters( 'bp_get_the_notification_mark_read_link', $retval );
+	}
+
+/**
+ * Output the mark read link for the current notification.
+ *
+ * @since BuddyPress (1.9.0)
+ *
+ * @uses bp_get_the_notification_mark_unread_link()
+ */
+function bp_the_notification_mark_unread_link() {
+	echo bp_get_the_notification_mark_unread_link();
+}
+	/**
+	 * Return the mark read link for the current notification.
+	 *
+	 * @since BuddyPress (1.9.0)
+	 */
+	function bp_get_the_notification_mark_unread_link() {
+
+		// Get the URL with nonce, action, and id
+		$url = wp_nonce_url( add_query_arg( array( 'action' => 'unread', 'notification_id' => bp_get_the_notification_id() ), bp_get_notifications_read_permalink() ), 'bp_notification_mark_unread_' . bp_get_the_notification_id() );
+
+		// Start the output buffer
+		ob_start(); ?>
+
+		<a href="<?php echo esc_url( $url ); ?>" class="mark-unread primary"><?php _e( 'Unread', 'buddypress' ); ?></a>
+
+		<?php $retval = ob_get_clean();
+
+		return apply_filters( 'bp_get_the_notification_mark_unread_link', $retval );
+	}
+
+/**
+ * Output the mark link for the current notification.
+ *
+ * @since BuddyPress (1.9.0)
+ *
+ * @uses bp_get_the_notification_mark_unread_link()
+ */
+function bp_the_notification_mark_link() {
+	echo bp_get_the_notification_mark_link();
+}
+	/**
+	 * Return the mark link for the current notification.
+	 *
+	 * @since BuddyPress (1.9.0)
+	 */
+	function bp_get_the_notification_mark_link() {
+
+		if ( bp_is_current_action( 'read' ) ) {
+			$retval = bp_get_the_notification_mark_unread_link();
+		} else {
+			$retval = bp_get_the_notification_mark_read_link();
+		}
+
+		return apply_filters( 'bp_get_the_notification_mark_link', $retval );
+	}
+
+/**
+ * Output the delete link for the current notification.
+ *
+ * @since BuddyPress (1.9.0)
+ *
+ * @uses bp_get_the_notification_delete_link()
+ */
+function bp_the_notification_delete_link() {
+	echo bp_get_the_notification_delete_link();
+}
+	/**
+	 * Return the delete link for the current notification.
+	 *
+	 * @since BuddyPress (1.9.0)
+	 */
+	function bp_get_the_notification_delete_link() {
+
+		// URL to add nonce to
+		if ( bp_is_current_action( 'unread' ) ) {
+			$link = bp_get_notifications_unread_permalink();
+		} elseif ( bp_is_current_action( 'read' ) ) {
+			$link = bp_get_notifications_read_permalink();
+		}
+
+		// Get the URL with nonce, action, and id
+		$url = wp_nonce_url( add_query_arg( array( 'action' => 'delete', 'notification_id' => bp_get_the_notification_id() ), $link ), 'bp_notification_delete_' . bp_get_the_notification_id() );
+
+		// Start the output buffer
+		ob_start(); ?>
+
+		<a href="<?php echo esc_url( $url ); ?>" class="delete secondary confirm"><?php _e( 'Delete', 'buddypress' ); ?></a>
+
+		<?php $retval = ob_get_clean();
+
+		return apply_filters( 'bp_get_the_notification_delete_link', $retval );
+	}
+
+/**
+ * Output the action links for the current notification.
+ *
+ * @since BuddyPress (1.9.0)
+ */
+function bp_the_notification_action_links( $args = '' ) {
+	echo bp_get_the_notification_action_links( $args );
+}
+	/**
+	 * Return the action links for the current notification.
+	 *
+	 * @since BuddyPress (1.9.0)
+	 *
+	 * @param array $args {
+	 *     @type string $before HTML before the links
+	 *     @type string $after HTML after the links
+	 *     @type string $sep HTML between the links
+	 *     @type array $links Array of links to implode by 'sep'
+	 * }
+	 *
+	 * @return string HTML links for actions to take on single notifications.
+	 */
+	function bp_get_the_notification_action_links( $args = '' ) {
+
+		// Parse
+		$r = wp_parse_args( $args, array(
+			'before' => '',
+			'after'  => '',
+			'sep'    => ' | ',
+			'links'  => array(
+				bp_get_the_notification_mark_link(),
+				bp_get_the_notification_delete_link()
+			)
+		) );
+
+		// Build the links
+		$retval = $r['before'] . implode( $r['links'], $r['sep'] ) . $r['after'];
+
+		return apply_filters( 'bp_get_the_notification_action_links', $retval );
+	}
+
+/**
+ * Output the pagination count for the current notification loop.
+ *
+ * @since BuddyPress (1.9.0)
+ */
+function bp_notifications_pagination_count() {
+	echo bp_get_notifications_pagination_count();
+}
+	/**
+	 * Return the pagination count for the current notification loop.
+	 *
+	 * @since BuddyPress (1.9.0)
+	 *
+	 * @return string HTML for the pagination count.
+	 */
+	function bp_get_notifications_pagination_count() {
+		$query_loop = buddypress()->notifications->query_loop;
+		$start_num  = intval( ( $query_loop->pag_page - 1 ) * $query_loop->pag_num ) + 1;
+		$from_num   = bp_core_number_format( $start_num );
+		$to_num     = bp_core_number_format( ( $start_num + ( $query_loop->pag_num - 1 ) > $query_loop->total_notification_count ) ? $query_loop->total_notification_count : $start_num + ( $query_loop->pag_num - 1 ) );
+		$total      = bp_core_number_format( $query_loop->total_notification_count );
+		$pag        = sprintf( _n( 'Viewing %1$s to %2$s (of %3$s notification)', 'Viewing %1$s to %2$s (of %3$s notifications)', $total, 'buddypress' ), $from_num, $to_num, $total );
+
+		return apply_filters( 'bp_notifications_pagination_count', $pag );
+	}
+
+/**
+ * Output the pagination links for the current notification loop.
+ *
+ * @since BuddyPress (1.9.0)
+ */
+function bp_notifications_pagination_links() {
+	echo bp_get_notifications_pagination_links();
+}
+	/**
+	 * Return the pagination links for the current notification loop.
+	 *
+	 * @since BuddyPress (1.9.0)
+	 *
+	 * @return string HTML for the pagination links.
+	 */
+	function bp_get_notifications_pagination_links() {
+		return apply_filters( 'bp_get_notifications_pagination_links', buddypress()->notifications->query_loop->pag_links );
+	}
+
+/** Form Helpers **************************************************************/
+
+/**
+ * Output the form for changing the sort order of notifications
+ *
+ * @since BuddyPress (1.9.0)
+ */
+function bp_notifications_sort_order_form() {
+
+	// Setup local variables
+	$orders   = array( 'DESC', 'ASC' );
+	$selected = 'DESC';
+
+	// Check for a custom sort_order
+	if ( !empty( $_REQUEST['sort_order'] ) ) {
+		if ( in_array( $_REQUEST['sort_order'], $orders ) ) {
+			$selected = $_REQUEST['sort_order'];
+		}
+	} ?>
+
+	<form action="" method="get" id="notifications-sort-order">
+		<label for="notifications-friends"><?php esc_html_e( 'Order By:', 'buddypress' ); ?></label>
+
+		<select id="notifications-sort-order-list" name="sort_order" onchange="this.form.submit();">
+			<option value="DESC" <?php selected( $selected, 'DESC' ); ?>><?php _e( 'Newest First', 'buddypress' ); ?></option>
+			<option value="ASC"  <?php selected( $selected, 'ASC'  ); ?>><?php _e( 'Oldest First', 'buddypress' ); ?></option>
+		</select>
+
+		<noscript>
+			<input id="submit" type="submit" name="form-submit" class="submit" value="<?php _e( 'Go', 'buddypress' ); ?>" />
+		</noscript>
+	</form>
+
+<?php
+}
Index: /tags/1.9/bp-settings/bp-settings-actions.php
===================================================================
--- /tags/1.9/bp-settings/bp-settings-actions.php	(revision 7684)
+++ /tags/1.9/bp-settings/bp-settings-actions.php	(revision 7684)
@@ -0,0 +1,352 @@
+<?php
+
+/**
+ * BuddyPress Settings Actions
+ *
+ * @todo split actions into separate screen functions
+ * @package BuddyPress
+ * @subpackage SettingsActions
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/**
+ * Handles the changing and saving of user email addressos and passwords
+ *
+ * We do quite a bit of logic and error handling here to make sure that users
+ * do not accidentally lock themselves out of their accounts. We also try to
+ * provide as accurate of feedback as possible without exposing anyone else's
+ * inforation to them.
+ *
+ * Special considerations are made for super admins that are able to edit any
+ * users accounts already, without knowing their existing password.
+ *
+ * @global BuddyPress $bp
+ */
+function bp_settings_action_general() {
+
+	// Bail if not a POST action
+	if ( 'POST' !== strtoupper( $_SERVER['REQUEST_METHOD'] ) )
+		return;
+
+	// Bail if no submit action
+	if ( ! isset( $_POST['submit'] ) )
+		return;
+
+	// Bail if not in settings
+	if ( ! bp_is_settings_component() || ! bp_is_current_action( 'general' ) )
+		return;
+
+	// 404 if there are any additional action variables attached
+	if ( bp_action_variables() ) {
+		bp_do_404();
+		return;
+	}
+
+	// Define local defaults
+	$bp            = buddypress(); // The instance
+	$email_error   = false;        // invalid|blocked|taken|empty|nochange
+	$pass_error    = false;        // invalid|mismatch|empty|nochange
+	$pass_changed  = false;        // true if the user changes their password
+	$email_changed = false;        // true if the user changes their email
+	$feedback_type = 'error';      // success|error
+	$feedback      = array();      // array of strings for feedback
+
+	// Nonce check
+	check_admin_referer('bp_settings_general');
+
+	// Validate the user again for the current password when making a big change
+	if ( ( is_super_admin() ) || ( !empty( $_POST['pwd'] ) && wp_check_password( $_POST['pwd'], $bp->displayed_user->userdata->user_pass, bp_displayed_user_id() ) ) ) {
+
+		$update_user = get_userdata( bp_displayed_user_id() );
+
+		/** Email Change Attempt ******************************************/
+
+		if ( !empty( $_POST['email'] ) ) {
+
+			// What is missing from the profile page vs signup - lets double check the goodies
+			$user_email = sanitize_email( esc_html( trim( $_POST['email'] ) ) );
+
+			// User is changing email address
+			if ( $bp->displayed_user->userdata->user_email != $user_email ) {
+
+				// Run some tests on the email address
+				$email_checks = bp_core_validate_email_address( $user_email );
+
+				if ( true !== $email_checks ) {
+					if ( isset( $email_checks['invalid'] ) ) {
+						$email_error = 'invalid';
+					}
+
+					if ( isset( $email_checks['domain_banned'] ) || isset( $email_checks['domain_not_allowed'] ) ) {
+						$email_error = 'blocked';
+					}
+
+					if ( isset( $email_checks['in_use'] ) ) {
+						$email_error = 'taken';
+					}
+				}
+
+				// Yay we made it!
+				if ( false === $email_error ) {
+					$update_user->user_email = $user_email;
+					$email_changed = true;
+				}
+
+			// No change
+			} else {
+				$email_error = false;
+			}
+
+		// Email address cannot be empty
+		} else {
+			$email_error = 'empty';
+		}
+
+		/** Password Change Attempt ***************************************/
+
+		if ( !empty( $_POST['pass1'] ) && !empty( $_POST['pass2'] ) ) {
+
+			// Password change attempt is successful
+			if ( ( $_POST['pass1'] == $_POST['pass2'] ) && !strpos( " " . $_POST['pass1'], "\\" ) ) {
+				$update_user->user_pass = $_POST['pass1'];
+				$pass_changed = true;
+
+			// Password change attempt was unsuccessful
+			} else {
+				$pass_error = 'mismatch';
+			}
+
+		// Both password fields were empty
+		} elseif ( empty( $_POST['pass1'] ) && empty( $_POST['pass2'] ) ) {
+			$pass_error = false;
+
+		// One of the password boxes was left empty
+		} elseif ( ( empty( $_POST['pass1'] ) && !empty( $_POST['pass2'] ) ) || ( !empty( $_POST['pass1'] ) && empty( $_POST['pass2'] ) ) ) {
+			$pass_error = 'empty';
+		}
+
+		// The structure of the $update_user object changed in WP 3.3, but
+		// wp_update_user() still expects the old format
+		if ( isset( $update_user->data ) && is_object( $update_user->data ) ) {
+			$update_user = $update_user->data;
+			$update_user = get_object_vars( $update_user );
+
+			// Unset the password field to prevent it from emptying out the
+			// user's user_pass field in the database.
+			// @see wp_update_user()
+			if ( false === $pass_changed ) {
+				unset( $update_user['user_pass'] );
+			}
+		}
+
+		// Clear cached data, so that the changed settings take effect
+		// on the current page load
+		if ( ( false === $email_error ) && ( false === $pass_error ) && ( wp_update_user( $update_user ) ) ) {
+			wp_cache_delete( 'bp_core_userdata_' . bp_displayed_user_id(), 'bp' );
+			$bp->displayed_user->userdata = bp_core_get_core_userdata( bp_displayed_user_id() );
+		}
+
+	// Password Error
+	} else {
+		$pass_error = 'invalid';
+	}
+
+	// Email feedback
+	switch ( $email_error ) {
+		case 'invalid' :
+			$feedback['email_invalid']  = __( 'That email address is invalid. Check the formatting and try again.', 'buddypress' );
+			break;
+		case 'blocked' :
+			$feedback['email_blocked']  = __( 'That email address is currently unavailable for use.', 'buddypress' );
+			break;
+		case 'taken' :
+			$feedback['email_taken']    = __( 'That email address is already taken.', 'buddypress' );
+			break;
+		case 'empty' :
+			$feedback['email_empty']    = __( 'Email address cannot be empty.', 'buddypress' );
+			break;
+		case false :
+			// No change
+			break;
+	}
+
+	// Password feedback
+	switch ( $pass_error ) {
+		case 'invalid' :
+			$feedback['pass_error']    = __( 'Your current password is invalid.', 'buddypress' );
+			break;
+		case 'mismatch' :
+			$feedback['pass_mismatch'] = __( 'The new password fields did not match.', 'buddypress' );
+			break;
+		case 'empty' :
+			$feedback['pass_empty']    = __( 'One of the password fields was empty.', 'buddypress' );
+			break;
+		case false :
+			// No change
+			break;
+	}
+
+	// No errors so show a simple success message
+	if ( ( ( false === $email_error ) || ( false == $pass_error ) ) && ( ( true === $pass_changed ) || ( true === $email_changed ) ) ) {
+		$feedback[]    = __( 'Your settings have been saved.', 'buddypress' );
+		$feedback_type = 'success';
+
+	// Some kind of errors occurred
+	} elseif ( ( ( false === $email_error ) || ( false === $pass_error ) ) && ( ( false === $pass_changed ) || ( false === $email_changed ) ) ) {
+		if ( bp_is_my_profile() ) {
+			$feedback['nochange'] = __( 'No changes were made to your account.', 'buddypress' );
+		} else {
+			$feedback['nochange'] = __( 'No changes were made to this account.', 'buddypress' );
+		}
+	}
+
+	// Set the feedback
+	bp_core_add_message( implode( '</p><p>', $feedback ), $feedback_type );
+
+	// Execute additional code
+	do_action( 'bp_core_general_settings_after_save' );
+
+	// Redirect to prevent issues with browser back button
+	bp_core_redirect( trailingslashit( bp_displayed_user_domain() . bp_get_settings_slug() . '/general' ) );
+}
+add_action( 'bp_actions', 'bp_settings_action_general' );
+
+/**
+ * Handles the changing and saving of user notification settings
+ */
+function bp_settings_action_notifications() {
+
+	// Bail if not a POST action
+	if ( 'POST' !== strtoupper( $_SERVER['REQUEST_METHOD'] ) )
+		return;
+
+	// Bail if no submit action
+	if ( ! isset( $_POST['submit'] ) )
+		return;
+
+	// Bail if not in settings
+	if ( ! bp_is_settings_component() || ! bp_is_current_action( 'notifications' ) )
+		return false;
+
+	// 404 if there are any additional action variables attached
+	if ( bp_action_variables() ) {
+		bp_do_404();
+		return;
+	}
+
+	check_admin_referer( 'bp_settings_notifications' );
+
+	if ( isset( $_POST['notifications'] ) ) {
+		foreach ( (array) $_POST['notifications'] as $key => $value ) {
+			bp_update_user_meta( (int) bp_displayed_user_id(), $key, $value );
+		}
+	}
+
+	// Switch feedback for super admins
+	if ( bp_is_my_profile() ) {
+		bp_core_add_message( __( 'Your notification settings have been saved.',        'buddypress' ), 'success' );
+	} else {
+		bp_core_add_message( __( "This user's notification settings have been saved.", 'buddypress' ), 'success' );
+	}
+
+	do_action( 'bp_core_notification_settings_after_save' );
+
+	bp_core_redirect( bp_displayed_user_domain() . bp_get_settings_slug() . '/notifications/' );
+}
+add_action( 'bp_actions', 'bp_settings_action_notifications' );
+
+/**
+ * Handles the setting of user capabilities, spamming, hamming, role, etc...
+ */
+function bp_settings_action_capabilities() {
+
+	// Bail if not a POST action
+	if ( 'POST' !== strtoupper( $_SERVER['REQUEST_METHOD'] ) )
+		return;
+
+	// Bail if no submit action
+	if ( ! isset( $_POST['capabilities-submit'] ) )
+		return;
+
+	// Bail if not in settings
+	if ( ! bp_is_settings_component() || ! bp_is_current_action( 'capabilities' ) )
+		return false;
+
+	// 404 if there are any additional action variables attached
+	if ( bp_action_variables() ) {
+		bp_do_404();
+		return;
+	}
+
+	// Only super admins can currently spam users (but they can't spam
+	// themselves)
+	if ( ! is_super_admin() || bp_is_my_profile() ) {
+		return;
+	}
+
+	// Nonce check
+	check_admin_referer( 'capabilities' );
+
+	do_action( 'bp_settings_capabilities_before_save' );
+
+	/** Spam **************************************************************/
+
+	$is_spammer = !empty( $_POST['user-spammer'] ) ? true : false;
+
+	if ( bp_is_user_spammer( bp_displayed_user_id() ) != $is_spammer ) {
+		$status = ( true == $is_spammer ) ? 'spam' : 'ham';
+		bp_core_process_spammer_status( bp_displayed_user_id(), $status );
+		do_action( 'bp_core_action_set_spammer_status', bp_displayed_user_id(), $status );
+	}
+
+	/** Other *************************************************************/
+
+	do_action( 'bp_settings_capabilities_after_save' );
+
+	// Redirect to the root domain
+	bp_core_redirect( bp_displayed_user_domain() . bp_get_settings_slug() . '/capabilities/' );
+}
+add_action( 'bp_actions', 'bp_settings_action_capabilities' );
+
+/**
+ * Handles the deleting of a user
+ */
+function bp_settings_action_delete_account() {
+
+	// Bail if not a POST action
+	if ( 'POST' !== strtoupper( $_SERVER['REQUEST_METHOD'] ) )
+		return;
+
+	// Bail if no submit action
+	if ( ! isset( $_POST['delete-account-understand'] ) )
+		return;
+
+	// Bail if not in settings
+	if ( ! bp_is_settings_component() || ! bp_is_current_action( 'delete-account' ) )
+		return false;
+
+	// 404 if there are any additional action variables attached
+	if ( bp_action_variables() ) {
+		bp_do_404();
+		return;
+	}
+
+	// Nonce check
+	check_admin_referer( 'delete-account' );
+
+	// Get username now because it might be gone soon!
+	$username = bp_get_displayed_user_fullname();
+
+	// delete the users account
+	if ( bp_core_delete_account( bp_displayed_user_id() ) ) {
+
+		// Add feedback ater deleting a user
+		bp_core_add_message( sprintf( __( '%s was successfully deleted.', 'buddypress' ), $username ), 'success' );
+
+		// Redirect to the root domain
+		bp_core_redirect( bp_get_root_domain() );
+	}
+}
+add_action( 'bp_actions', 'bp_settings_action_delete_account' );
Index: /tags/1.9/bp-settings/bp-settings-functions.php
===================================================================
--- /tags/1.9/bp-settings/bp-settings-functions.php	(revision 7684)
+++ /tags/1.9/bp-settings/bp-settings-functions.php	(revision 7684)
@@ -0,0 +1,11 @@
+<?php
+
+/**
+ * BuddyPress Settings Functions
+ *
+ * @package BuddyPress
+ * @subpackage SettingsFunctions
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
Index: /tags/1.9/bp-settings/bp-settings-loader.php
===================================================================
--- /tags/1.9/bp-settings/bp-settings-loader.php	(revision 7684)
+++ /tags/1.9/bp-settings/bp-settings-loader.php	(revision 7684)
@@ -0,0 +1,201 @@
+<?php
+
+/**
+ * BuddyPress Settings Loader
+ *
+ * @package BuddyPress
+ * @subpackage SettingsLoader
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+class BP_Settings_Component extends BP_Component {
+
+	/**
+	 * Start the settings component creation process
+	 *
+	 * @since BuddyPress (1.5)
+	 */
+	public function __construct() {
+		parent::start(
+			'settings',
+			__( 'Settings', 'buddypress' ),
+			BP_PLUGIN_DIR,
+			array(
+				'adminbar_myaccount_order' => 100
+			)
+		);
+	}
+
+	/**
+	 * Include files
+	 *
+	 * @global BuddyPress $bp The one true BuddyPress instance
+	 */
+	public function includes( $includes = array() ) {
+		parent::includes( array(
+			'actions',
+			'screens',
+			'template',
+			'functions',
+		) );
+	}
+
+	/**
+	 * Setup globals
+	 *
+	 * The BP_SETTINGS_SLUG constant is deprecated, and only used here for
+	 * backwards compatibility.
+	 *
+	 * @since BuddyPress (1.5)
+	 */
+	public function setup_globals( $args = array() ) {
+
+		// Define a slug, if necessary
+		if ( !defined( 'BP_SETTINGS_SLUG' ) )
+			define( 'BP_SETTINGS_SLUG', $this->id );
+
+		// All globals for settings component.
+		parent::setup_globals( array(
+			'slug'          => BP_SETTINGS_SLUG,
+			'has_directory' => false,
+		) );
+	}
+
+	/**
+	 * Setup BuddyBar navigation
+	 */
+	public function setup_nav( $main_nav = array(), $sub_nav = array() ) {
+
+		// Add the settings navigation item
+		$main_nav = array(
+			'name'                    => __( 'Settings', 'buddypress' ),
+			'slug'                    => $this->slug,
+			'position'                => 100,
+			'show_for_displayed_user' => bp_core_can_edit_settings(),
+			'screen_function'         => 'bp_settings_screen_general',
+			'default_subnav_slug'     => 'general'
+		);
+
+		// Determine user to use
+		if ( bp_displayed_user_domain() ) {
+			$user_domain = bp_displayed_user_domain();
+		} elseif ( bp_loggedin_user_domain() ) {
+			$user_domain = bp_loggedin_user_domain();
+		} else {
+			return;
+		}
+
+		$settings_link = trailingslashit( $user_domain . $this->slug );
+
+		// Add General Settings nav item
+		$sub_nav[] = array(
+			'name'            => __( 'General', 'buddypress' ),
+			'slug'            => 'general',
+			'parent_url'      => $settings_link,
+			'parent_slug'     => $this->slug,
+			'screen_function' => 'bp_settings_screen_general',
+			'position'        => 10,
+			'user_has_access' => bp_core_can_edit_settings()
+		);
+
+		// Add Email nav item. Formerly called 'Notifications', we
+		// retain the old slug and function names for backward compat
+		$sub_nav[] = array(
+			'name'            => __( 'Email', 'buddypress' ),
+			'slug'            => 'notifications',
+			'parent_url'      => $settings_link,
+			'parent_slug'     => $this->slug,
+			'screen_function' => 'bp_settings_screen_notification',
+			'position'        => 20,
+			'user_has_access' => bp_core_can_edit_settings()
+		);
+
+		// Add Spam Account nav item
+		if ( bp_current_user_can( 'bp_moderate' ) ) {
+			$sub_nav[] = array(
+				'name'            => __( 'Capabilities', 'buddypress' ),
+				'slug'            => 'capabilities',
+				'parent_url'      => $settings_link,
+				'parent_slug'     => $this->slug,
+				'screen_function' => 'bp_settings_screen_capabilities',
+				'position'        => 80,
+				'user_has_access' => ! bp_is_my_profile()
+			);
+		}
+
+		// Add Delete Account nav item
+		if ( ( ! bp_disable_account_deletion() && bp_is_my_profile() ) || bp_current_user_can( 'delete_users' ) ) {
+			$sub_nav[] = array(
+				'name'            => __( 'Delete Account', 'buddypress' ),
+				'slug'            => 'delete-account',
+				'parent_url'      => $settings_link,
+				'parent_slug'     => $this->slug,
+				'screen_function' => 'bp_settings_screen_delete_account',
+				'position'        => 90,
+				'user_has_access' => ! is_super_admin( bp_displayed_user_id() )
+			);
+		}
+
+		parent::setup_nav( $main_nav, $sub_nav );
+	}
+
+	/**
+	 * Set up the Toolbar
+	 */
+	public function setup_admin_bar( $wp_admin_nav = array() ) {
+
+		// The instance
+		$bp = buddypress();
+
+		// Menus for logged in user
+		if ( is_user_logged_in() ) {
+
+			// Setup the logged in user variables
+			$user_domain   = bp_loggedin_user_domain();
+			$settings_link = trailingslashit( $user_domain . $this->slug );
+
+			// Add main Settings menu
+			$wp_admin_nav[] = array(
+				'parent' => $bp->my_account_menu_id,
+				'id'     => 'my-account-' . $this->id,
+				'title'  => __( 'Settings', 'buddypress' ),
+				'href'   => trailingslashit( $settings_link )
+			);
+
+			// General Account
+			$wp_admin_nav[] = array(
+				'parent' => 'my-account-' . $this->id,
+				'id'     => 'my-account-' . $this->id . '-general',
+				'title'  => __( 'General', 'buddypress' ),
+				'href'   => trailingslashit( $settings_link . 'general' )
+			);
+
+			// Notifications
+			$wp_admin_nav[] = array(
+				'parent' => 'my-account-' . $this->id,
+				'id'     => 'my-account-' . $this->id . '-notifications',
+				'title'  => __( 'Email', 'buddypress' ),
+				'href'   => trailingslashit( $settings_link . 'notifications' )
+			);
+
+			// Delete Account
+			if ( !bp_current_user_can( 'bp_moderate' ) && empty( $bp->site_options['bp-disable-account-deletion'] ) ) {
+				$wp_admin_nav[] = array(
+					'parent' => 'my-account-' . $this->id,
+					'id'     => 'my-account-' . $this->id . '-delete-account',
+					'title'  => __( 'Delete Account', 'buddypress' ),
+					'href'   => trailingslashit( $settings_link . 'delete-account' )
+				);
+			}
+		}
+
+		parent::setup_admin_bar( $wp_admin_nav );
+	}
+}
+
+function bp_setup_settings() {
+	buddypress()->settings = new BP_Settings_Component();
+}
+add_action( 'bp_setup_components', 'bp_setup_settings', 6 );
Index: /tags/1.9/bp-settings/bp-settings-screens.php
===================================================================
--- /tags/1.9/bp-settings/bp-settings-screens.php	(revision 7684)
+++ /tags/1.9/bp-settings/bp-settings-screens.php	(revision 7684)
@@ -0,0 +1,73 @@
+<?php
+
+/**
+ * BuddyPress Settings Screens
+ *
+ * @package BuddyPress
+ * @subpackage SettingsScreens
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/**
+ * Show the general settings template
+ *
+ * @since BuddyPress (1.5)
+ */
+function bp_settings_screen_general() {
+
+	if ( bp_action_variables() ) {
+		bp_do_404();
+		return;
+	}
+
+	bp_core_load_template( apply_filters( 'bp_settings_screen_general_settings', 'members/single/settings/general' ) );
+}
+
+/**
+ * Show the notifications settings template
+ *
+ * @since BuddyPress (1.5)
+ */
+function bp_settings_screen_notification() {
+
+	if ( bp_action_variables() ) {
+		bp_do_404();
+		return;
+	}
+
+	bp_core_load_template( apply_filters( 'bp_settings_screen_notification_settings', 'members/single/settings/notifications' ) );
+}
+
+/**
+ * Show the delete-account settings template
+ *
+ * @since BuddyPress (1.5)
+ */
+function bp_settings_screen_delete_account() {
+
+	if ( bp_action_variables() ) {
+		bp_do_404();
+		return;
+	}
+
+	// Load the template
+	bp_core_load_template( apply_filters( 'bp_settings_screen_delete_account', 'members/single/settings/delete-account' ) );
+}
+
+/**
+ * Show the capabilities settings template
+ *
+ * @since BuddyPress (1.6)
+ */
+function bp_settings_screen_capabilities() {
+
+	if ( bp_action_variables() ) {
+		bp_do_404();
+		return;
+	}
+
+	// Load the template
+	bp_core_load_template( apply_filters( 'bp_settings_screen_capabilities', 'members/single/settings/capabilities' ) );
+}
Index: /tags/1.9/bp-settings/bp-settings-template.php
===================================================================
--- /tags/1.9/bp-settings/bp-settings-template.php	(revision 7684)
+++ /tags/1.9/bp-settings/bp-settings-template.php	(revision 7684)
@@ -0,0 +1,57 @@
+<?php
+
+/**
+ * BuddyPress Settings Template Functions
+ *
+ * @package BuddyPress
+ * @subpackage SettingsTemplate
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/**
+ * Output the settings component slug
+ *
+ * @package BuddyPress
+ * @subpackage SettingsTemplate
+ * @since BuddyPress (1.5)
+ *
+ * @uses bp_get_settings_slug()
+ */
+function bp_settings_slug() {
+	echo bp_get_settings_slug();
+}
+	/**
+	 * Return the settings component slug
+	 *
+	 * @package BuddyPress
+	 * @subpackage SettingsTemplate
+	 * @since BuddyPress (1.5)
+	 */
+	function bp_get_settings_slug() {
+		return apply_filters( 'bp_get_settings_slug', buddypress()->settings->slug );
+	}
+
+/**
+ * Output the settings component root slug
+ *
+ * @package BuddyPress
+ * @subpackage SettingsTemplate
+ * @since BuddyPress (1.5)
+ *
+ * @uses bp_get_settings_root_slug()
+ */
+function bp_settings_root_slug() {
+	echo bp_get_settings_root_slug();
+}
+	/**
+	 * Return the settings component root slug
+	 *
+	 * @package BuddyPress
+	 * @subpackage SettingsTemplate
+	 * @since BuddyPress (1.5)
+	 */
+	function bp_get_settings_root_slug() {
+		return apply_filters( 'bp_get_settings_root_slug', buddypress()->settings->root_slug );
+	}
Index: /tags/1.9/bp-templates/bp-legacy/buddypress-functions.php
===================================================================
--- /tags/1.9/bp-templates/bp-legacy/buddypress-functions.php	(revision 7684)
+++ /tags/1.9/bp-templates/bp-legacy/buddypress-functions.php	(revision 7684)
@@ -0,0 +1,1352 @@
+<?php
+
+/**
+ * Functions of BuddyPress's Legacy theme
+ *
+ * @package BuddyPress
+ * @subpackage BP_Theme_Compat
+ * @since BuddyPress (1.7)
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/** Theme Setup ***************************************************************/
+
+if ( !class_exists( 'BP_Legacy' ) ) :
+
+/**
+ * Loads BuddyPress Legacy Theme functionality
+ *
+ * This is not a real theme by WordPress standards, and is instead used as the
+ * fallback for any WordPress theme that does not have BuddyPress templates in it.
+ *
+ * To make your custom theme BuddyPress compatible and customize the templates, you
+ * can copy these files into your theme without needing to merge anything
+ * together; BuddyPress should safely handle the rest.
+ *
+ * See @link BP_Theme_Compat() for more.
+ *
+ * @since BuddyPress (1.7)
+ *
+ * @package BuddyPress
+ * @subpackage BP_Theme_Compat
+ */
+class BP_Legacy extends BP_Theme_Compat {
+
+	/** Functions *************************************************************/
+
+	/**
+	 * The main BuddyPress (Legacy) Loader
+	 *
+	 * @since BuddyPress (1.7)
+	 *
+	 * @uses BP_Legacy::setup_globals()
+	 * @uses BP_Legacy::setup_actions()
+	 */
+	public function __construct() {
+		parent::start();
+	}
+
+	/**
+	 * Component global variables
+	 *
+	 * You'll want to customize the values in here, so they match whatever your
+	 * needs are.
+	 *
+	 * @since BuddyPress (1.7)
+	 * @access private
+	 */
+	protected function setup_globals() {
+		$bp            = buddypress();
+		$this->id      = 'legacy';
+		$this->name    = __( 'BuddyPress Legacy', 'buddypress' );
+		$this->version = bp_get_version();
+		$this->dir     = trailingslashit( $bp->themes_dir . '/bp-legacy' );
+		$this->url     = trailingslashit( $bp->themes_url . '/bp-legacy' );
+	}
+
+	/**
+	 * Setup the theme hooks
+	 *
+	 * @since BuddyPress (1.7)
+	 * @access private
+	 *
+	 * @uses add_filter() To add various filters
+	 * @uses add_action() To add various actions
+	 */
+	protected function setup_actions() {
+
+		// Template Output
+		add_filter( 'bp_get_activity_action_pre_meta', array( $this, 'secondary_avatars' ), 10, 2 );
+
+		/** Scripts ***********************************************************/
+
+		add_action( 'bp_enqueue_scripts', array( $this, 'enqueue_styles'   ) ); // Enqueue theme CSS
+		add_action( 'bp_enqueue_scripts', array( $this, 'enqueue_scripts'  ) ); // Enqueue theme JS
+		add_filter( 'bp_enqueue_scripts', array( $this, 'localize_scripts' ) ); // Enqueue theme script localization
+		add_action( 'bp_head',            array( $this, 'head_scripts'     ) ); // Output some extra JS in the <head>
+
+		/** Body no-js Class ********************************************************/
+		add_filter( 'body_class', array( $this, 'add_nojs_body_class' ), 20, 1 );
+
+		/** Buttons ***********************************************************/
+
+		if ( ! is_admin() || ( defined( 'DOING_AJAX' ) && DOING_AJAX ) ) {
+			// Register buttons for the relevant component templates
+			// Friends button
+			if ( bp_is_active( 'friends' ) )
+				add_action( 'bp_member_header_actions',    'bp_add_friend_button',           5 );
+
+			// Activity button
+			if ( bp_is_active( 'activity' ) && bp_activity_do_mentions() )
+				add_action( 'bp_member_header_actions',    'bp_send_public_message_button',  20 );
+
+			// Messages button
+			if ( bp_is_active( 'messages' ) )
+				add_action( 'bp_member_header_actions',    'bp_send_private_message_button', 20 );
+
+			// Group buttons
+			if ( bp_is_active( 'groups' ) ) {
+				add_action( 'bp_group_header_actions',     'bp_group_join_button',           5 );
+				add_action( 'bp_group_header_actions',     'bp_group_new_topic_button',      20 );
+				add_action( 'bp_directory_groups_actions', 'bp_group_join_button' );
+			}
+
+			// Blog button
+			if ( bp_is_active( 'blogs' ) )
+				add_action( 'bp_directory_blogs_actions',  'bp_blogs_visit_blog_button' );
+
+		}
+
+		/** Notices ***********************************************************/
+
+		// Only hook the 'sitewide_notices' overlay if the Sitewide
+		// Notices widget is not in use (to avoid duplicate content).
+		if ( bp_is_active( 'messages' ) && ! is_active_widget( false, false, 'bp_messages_sitewide_notices_widget', true ) ) {
+			add_action( 'wp_footer', array( $this, 'sitewide_notices' ), 9999 );
+		}
+
+		/** Ajax **************************************************************/
+
+		$actions = array(
+
+			// Directory filters
+			'blogs_filter'    => 'bp_legacy_theme_object_template_loader',
+			'forums_filter'   => 'bp_legacy_theme_object_template_loader',
+			'groups_filter'   => 'bp_legacy_theme_object_template_loader',
+			'members_filter'  => 'bp_legacy_theme_object_template_loader',
+			'messages_filter' => 'bp_legacy_theme_messages_template_loader',
+
+			// Friends
+			'accept_friendship' => 'bp_legacy_theme_ajax_accept_friendship',
+			'addremove_friend'  => 'bp_legacy_theme_ajax_addremove_friend',
+			'reject_friendship' => 'bp_legacy_theme_ajax_reject_friendship',
+
+			// Activity
+			'activity_get_older_updates'  => 'bp_legacy_theme_activity_template_loader',
+			'activity_mark_fav'           => 'bp_legacy_theme_mark_activity_favorite',
+			'activity_mark_unfav'         => 'bp_legacy_theme_unmark_activity_favorite',
+			'activity_widget_filter'      => 'bp_legacy_theme_activity_template_loader',
+			'delete_activity'             => 'bp_legacy_theme_delete_activity',
+			'delete_activity_comment'     => 'bp_legacy_theme_delete_activity_comment',
+			'get_single_activity_content' => 'bp_legacy_theme_get_single_activity_content',
+			'new_activity_comment'        => 'bp_legacy_theme_new_activity_comment',
+			'post_update'                 => 'bp_legacy_theme_post_update',
+			'bp_spam_activity'            => 'bp_legacy_theme_spam_activity',
+			'bp_spam_activity_comment'    => 'bp_legacy_theme_spam_activity',
+
+			// Groups
+			'groups_invite_user' => 'bp_legacy_theme_ajax_invite_user',
+			'joinleave_group'    => 'bp_legacy_theme_ajax_joinleave_group',
+
+			// Messages
+			'messages_autocomplete_results' => 'bp_legacy_theme_ajax_messages_autocomplete_results',
+			'messages_close_notice'         => 'bp_legacy_theme_ajax_close_notice',
+			'messages_delete'               => 'bp_legacy_theme_ajax_messages_delete',
+			'messages_markread'             => 'bp_legacy_theme_ajax_message_markread',
+			'messages_markunread'           => 'bp_legacy_theme_ajax_message_markunread',
+			'messages_send_reply'           => 'bp_legacy_theme_ajax_messages_send_reply',
+		);
+
+		/**
+		 * Register all of these AJAX handlers
+		 *
+		 * The "wp_ajax_" action is used for logged in users, and "wp_ajax_nopriv_"
+		 * executes for users that aren't logged in. This is for backpat with BP <1.6.
+		 */
+		foreach( $actions as $name => $function ) {
+			add_action( 'wp_ajax_'        . $name, $function );
+			add_action( 'wp_ajax_nopriv_' . $name, $function );
+		}
+
+		add_filter( 'bp_ajax_querystring', 'bp_legacy_theme_ajax_querystring', 10, 2 );
+
+		/** Override **********************************************************/
+
+		do_action_ref_array( 'bp_theme_compat_actions', array( &$this ) );
+	}
+
+	/**
+	 * Load the theme CSS
+	 *
+	 * @since BuddyPress (1.7)
+	 *
+	 * @uses wp_enqueue_style() To enqueue the styles
+	 */
+	public function enqueue_styles() {
+
+		// LTR or RTL
+		$file = is_rtl() ? 'buddypress-rtl.css' : 'buddypress.css';
+
+		// Locate the BP stylesheet
+		$asset = $this->locate_asset_in_stack( $file, 'css' );
+
+		// Enqueue BuddyPress-specific styling, if found
+		if ( isset( $asset['location'], $asset['handle'] ) ) {
+			wp_enqueue_style( $asset['handle'], $asset['location'], array(), $this->version, 'screen' );
+		}
+	}
+
+	/**
+	 * Enqueue the required Javascript files
+	 *
+	 * @since BuddyPress (1.7)
+	 */
+	public function enqueue_scripts() {
+
+		$file = 'buddypress.js';
+
+		// Locate the BP JS file
+		$asset = $this->locate_asset_in_stack( $file, 'js' );
+
+		// Enqueue the global JS, if found - AJAX will not work
+		// without it
+		if ( isset( $asset['location'], $asset['handle'] ) ) {
+			wp_enqueue_script( $asset['handle'], $asset['location'], array( 'jquery' ), $this->version );
+		}
+
+		// Add words that we need to use in JS to the end of the page
+		// so they can be translated and still used.
+		$params = array(
+			'accepted'            => __( 'Accepted', 'buddypress' ),
+			'close'               => __( 'Close', 'buddypress' ),
+			'comments'            => __( 'comments', 'buddypress' ),
+			'leave_group_confirm' => __( 'Are you sure you want to leave this group?', 'buddypress' ),
+			'mark_as_fav'	      => __( 'Favorite', 'buddypress' ),
+			'my_favs'             => __( 'My Favorites', 'buddypress' ),
+			'rejected'            => __( 'Rejected', 'buddypress' ),
+			'remove_fav'	      => __( 'Remove Favorite', 'buddypress' ),
+			'show_all'            => __( 'Show all', 'buddypress' ),
+			'show_all_comments'   => __( 'Show all comments for this thread', 'buddypress' ),
+			'show_x_comments'     => __( 'Show all %d comments', 'buddypress' ),
+			'unsaved_changes'     => __( 'Your profile has unsaved changes. If you leave the page, the changes will be lost.', 'buddypress' ),
+			'view'                => __( 'View', 'buddypress' ),
+		);
+		wp_localize_script( $asset['handle'], 'BP_DTheme', $params );
+
+		// Maybe enqueue comment reply JS
+		if ( is_singular() && bp_is_blog_page() && get_option( 'thread_comments' ) ) {
+			wp_enqueue_script( 'comment-reply' );
+		}
+	}
+
+	/**
+	 * Get the URL and handle of a web-accessible CSS or JS asset
+	 *
+	 * We provide two levels of customizability with respect to where CSS
+	 * and JS files can be stored: (1) the child theme/parent theme/theme
+	 * compat hierarchy, and (2) the "template stack" of /buddypress/css/,
+	 * /community/css/, and /css/. In this way, CSS and JS assets can be
+	 * overloaded, and default versions provided, in exactly the same way
+	 * as corresponding PHP templates.
+	 *
+	 * We are duplicating some of the logic that is currently found in
+	 * bp_locate_template() and the _template_stack() functions. Those
+	 * functions were built with PHP templates in mind, and will require
+	 * refactoring in order to provide "stack" functionality for assets
+	 * that must be accessible both using file_exists() (the file path)
+	 * and at a public URI.
+	 *
+	 * This method is marked private, with the understanding that the
+	 * implementation is subject to change or removal in an upcoming
+	 * release, in favor of a unified _template_stack() system. Plugin
+	 * and theme authors should not attempt to use what follows.
+	 *
+	 * @since BuddyPress (1.8)
+	 * @access private
+	 * @param string $file A filename like buddypress.cs
+	 * @param string $type css|js
+	 * @return array An array of data for the wp_enqueue_* function:
+	 *   'handle' (eg 'bp-child-css') and a 'location' (the URI of the
+	 *   asset)
+	 */
+	private function locate_asset_in_stack( $file, $type = 'css' ) {
+		// Child, parent, theme compat
+		$locations = array();
+
+		// No need to check child if template == stylesheet
+		if ( is_child_theme() ) {
+			$locations['bp-child'] = array(
+				'dir' => get_stylesheet_directory(),
+				'uri' => get_stylesheet_directory_uri(),
+			);
+		}
+
+		$locations['bp-parent'] = array(
+			'dir' => get_template_directory(),
+			'uri' => get_template_directory_uri(),
+		);
+
+		$locations['bp-legacy'] = array(
+			'dir' => bp_get_theme_compat_dir(),
+			'uri' => bp_get_theme_compat_url(),
+		);
+
+		// Subdirectories within the top-level $locations directories
+		$subdirs = array(
+			'buddypress/' . $type,
+			'community/' . $type,
+			$type,
+		);
+
+		$retval = array();
+
+		foreach ( $locations as $location_type => $location ) {
+			foreach ( $subdirs as $subdir ) {
+				if ( file_exists( trailingslashit( $location['dir'] ) . trailingslashit( $subdir ) . $file ) ) {
+					$retval['location'] = trailingslashit( $location['uri'] ) . trailingslashit( $subdir ) . $file;
+					$retval['handle']   = $location_type . '-' . $type;
+					break 2;
+				}
+			}
+		}
+
+		return $retval;
+	}
+
+	/**
+	 * Put some scripts in the header, like AJAX url for wp-lists
+	 *
+	 * @since BuddyPress (1.7)
+	 */
+	public function head_scripts() {
+	?>
+
+		<script type="text/javascript" charset="utf-8">
+			/* <![CDATA[ */
+			var ajaxurl = '<?php echo bp_core_ajax_url(); ?>';
+			/* ]]> */
+		</script>
+
+	<?php
+	}
+
+	/**
+	 * Adds the no-js class to the body tag.
+	 *
+	 * This function ensures that the <body> element will have the 'no-js' class by default. If you're
+	 * using JavaScript for some visual functionality in your theme, and you want to provide noscript
+	 * support, apply those styles to body.no-js.
+	 *
+	 * The no-js class is removed by the JavaScript created in buddypress.js.
+	 *
+	 * @since BuddyPress (1.7)
+	 */
+	public function add_nojs_body_class( $classes ) {
+		if ( ! in_array( 'no-js', $classes ) )
+			$classes[] = 'no-js';
+
+		return array_unique( $classes );
+	}
+
+	/**
+	 * Load localizations for topic script
+	 *
+	 * These localizations require information that may not be loaded even by init.
+	 *
+	 * @since BuddyPress (1.7)
+	 */
+	public function localize_scripts() {
+	}
+
+	/**
+	 * Outputs sitewide notices markup in the footer.
+	 *
+	 * @since BuddyPress (1.7)
+	 *
+	 * @see https://buddypress.trac.wordpress.org/ticket/4802
+	 */
+	public function sitewide_notices() {
+		// Do not show notices if user is not logged in
+		if ( ! is_user_logged_in() )
+			return;
+
+		// add a class to determine if the admin bar is on or not
+		$class = did_action( 'admin_bar_menu' ) ? 'admin-bar-on' : 'admin-bar-off';
+
+		echo '<div id="sitewide-notice" class="' . $class . '">';
+		bp_message_get_notices();
+		echo '</div>';
+	}
+
+	/**
+	 * Add secondary avatar image to this activity stream's record, if supported.
+	 *
+	 * @since BuddyPress (1.7)
+	 *
+	 * @param string $action The text of this activity
+	 * @param BP_Activity_Activity $activity Activity object
+	 * @package BuddyPress Theme
+	 * @return string
+	 */
+	function secondary_avatars( $action, $activity ) {
+		switch ( $activity->component ) {
+			case 'groups' :
+			case 'friends' :
+				// Only insert avatar if one exists
+				if ( $secondary_avatar = bp_get_activity_secondary_avatar() ) {
+					$reverse_content = strrev( $action );
+					$position        = strpos( $reverse_content, 'a<' );
+					$action          = substr_replace( $action, $secondary_avatar, -$position - 2, 0 );
+				}
+				break;
+		}
+
+		return $action;
+	}
+}
+new BP_Legacy();
+endif;
+
+/**
+ * This function looks scarier than it actually is. :)
+ * Each object loop (activity/members/groups/blogs/forums) contains default
+ * parameters to show specific information based on the page we are currently
+ * looking at.
+ *
+ * The following function will take into account any cookies set in the JS and
+ * allow us to override the parameters sent. That way we can change the results
+ * returned without reloading the page.
+ *
+ * By using cookies we can also make sure that user settings are retained
+ * across page loads.
+ *
+ * @return string Query string for the component loops
+ * @since BuddyPress (1.2)
+ */
+function bp_legacy_theme_ajax_querystring( $query_string, $object ) {
+	if ( empty( $object ) )
+		return '';
+
+	// Set up the cookies passed on this AJAX request. Store a local var to avoid conflicts
+	if ( ! empty( $_POST['cookie'] ) ) {
+		$_BP_COOKIE = wp_parse_args( str_replace( '; ', '&', urldecode( $_POST['cookie'] ) ) );
+	} else {
+		$_BP_COOKIE = &$_COOKIE;
+	}
+
+	$qs = array();
+
+	/**
+	 * Check if any cookie values are set. If there are then override the
+	 * default params passed to the template loop.
+	 */
+
+	// Activity stream filtering on action
+	if ( ! empty( $_BP_COOKIE['bp-' . $object . '-filter'] ) && '-1' != $_BP_COOKIE['bp-' . $object . '-filter'] ) {
+		$qs[] = 'type='   . $_BP_COOKIE['bp-' . $object . '-filter'];
+		$qs[] = 'action=' . $_BP_COOKIE['bp-' . $object . '-filter'];
+	}
+
+	if ( ! empty( $_BP_COOKIE['bp-' . $object . '-scope'] ) ) {
+		if ( 'personal' == $_BP_COOKIE['bp-' . $object . '-scope'] ) {
+			$user_id = ( bp_displayed_user_id() ) ? bp_displayed_user_id() : bp_loggedin_user_id();
+			$qs[] = 'user_id=' . $user_id;
+		}
+
+		// Activity stream scope only on activity directory.
+		if ( 'all' != $_BP_COOKIE['bp-' . $object . '-scope'] && ! bp_displayed_user_id() && ! bp_is_single_item() )
+			$qs[] = 'scope=' . $_BP_COOKIE['bp-' . $object . '-scope'];
+	}
+
+	// If page and search_terms have been passed via the AJAX post request, use those.
+	if ( ! empty( $_POST['page'] ) && '-1' != $_POST['page'] )
+		$qs[] = 'page=' . absint( $_POST['page'] );
+
+	// exludes activity just posted and avoids duplicate ids
+	if ( ! empty( $_POST['exclude_just_posted'] ) ) {
+		$just_posted = wp_parse_id_list( $_POST['exclude_just_posted'] );
+		$qs[] = 'exclude=' . implode( ',', $just_posted );
+	}
+
+	$object_search_text = bp_get_search_default_text( $object );
+ 	if ( ! empty( $_POST['search_terms'] ) && $object_search_text != $_POST['search_terms'] && 'false' != $_POST['search_terms'] && 'undefined' != $_POST['search_terms'] )
+		$qs[] = 'search_terms=' . $_POST['search_terms'];
+
+	// Now pass the querystring to override default values.
+	$query_string = empty( $qs ) ? '' : join( '&', (array) $qs );
+
+	$object_filter = '';
+	if ( isset( $_BP_COOKIE['bp-' . $object . '-filter'] ) )
+		$object_filter = $_BP_COOKIE['bp-' . $object . '-filter'];
+
+	$object_scope = '';
+	if ( isset( $_BP_COOKIE['bp-' . $object . '-scope'] ) )
+		$object_scope = $_BP_COOKIE['bp-' . $object . '-scope'];
+
+	$object_page = '';
+	if ( isset( $_BP_COOKIE['bp-' . $object . '-page'] ) )
+		$object_page = $_BP_COOKIE['bp-' . $object . '-page'];
+
+	$object_search_terms = '';
+	if ( isset( $_BP_COOKIE['bp-' . $object . '-search-terms'] ) )
+		$object_search_terms = $_BP_COOKIE['bp-' . $object . '-search-terms'];
+
+	$object_extras = '';
+	if ( isset( $_BP_COOKIE['bp-' . $object . '-extras'] ) )
+		$object_extras = $_BP_COOKIE['bp-' . $object . '-extras'];
+
+	return apply_filters( 'bp_legacy_theme_ajax_querystring', $query_string, $object, $object_filter, $object_scope, $object_page, $object_search_terms, $object_extras );
+}
+
+/**
+ * Load the template loop for the current object.
+ *
+ * @return string Prints template loop for the specified object
+ * @since BuddyPress (1.2)
+ */
+function bp_legacy_theme_object_template_loader() {
+	// Bail if not a POST action
+	if ( 'POST' !== strtoupper( $_SERVER['REQUEST_METHOD'] ) )
+		return;
+
+	// Bail if no object passed
+	if ( empty( $_POST['object'] ) )
+		return;
+
+	// Sanitize the object
+	$object = sanitize_title( $_POST['object'] );
+
+	// Bail if object is not an active component to prevent arbitrary file inclusion
+	if ( ! bp_is_active( $object ) )
+		return;
+
+ 	/**
+	 * AJAX requests happen too early to be seen by bp_update_is_directory()
+	 * so we do it manually here to ensure templates load with the correct
+	 * context. Without this check, templates will load the 'single' version
+	 * of themselves rather than the directory version.
+	 */
+	if ( ! bp_current_action() )
+		bp_update_is_directory( true, bp_current_component() );
+
+	// Locate the object template
+	bp_get_template_part( "$object/$object-loop" );
+	exit();
+}
+
+/**
+ * Load messages template loop when searched on the private message page
+ *
+ * @return string Prints template loop for the Messages component
+ * @since BuddyPress (1.6)
+ */
+function bp_legacy_theme_messages_template_loader() {
+	bp_get_template_part( 'members/single/messages/messages-loop' );
+	exit();
+}
+
+/**
+ * Load the activity loop template when activity is requested via AJAX,
+ *
+ * @return string JSON object containing 'contents' (output of the template loop
+ * for the Activity component) and 'feed_url' (URL to the relevant RSS feed).
+ *
+ * @since BuddyPress (1.2)
+ */
+function bp_legacy_theme_activity_template_loader() {
+	// Bail if not a POST action
+	if ( 'POST' !== strtoupper( $_SERVER['REQUEST_METHOD'] ) )
+		return;
+
+	$scope = '';
+	if ( ! empty( $_POST['scope'] ) )
+		$scope = $_POST['scope'];
+
+	// We need to calculate and return the feed URL for each scope
+	switch ( $scope ) {
+		case 'friends':
+			$feed_url = bp_loggedin_user_domain() . bp_get_activity_slug() . '/friends/feed/';
+			break;
+		case 'groups':
+			$feed_url = bp_loggedin_user_domain() . bp_get_activity_slug() . '/groups/feed/';
+			break;
+		case 'favorites':
+			$feed_url = bp_loggedin_user_domain() . bp_get_activity_slug() . '/favorites/feed/';
+			break;
+		case 'mentions':
+			$feed_url = bp_loggedin_user_domain() . bp_get_activity_slug() . '/mentions/feed/';
+			bp_activity_clear_new_mentions( bp_loggedin_user_id() );
+			break;
+		default:
+			$feed_url = home_url( bp_get_activity_root_slug() . '/feed/' );
+			break;
+	}
+
+	// Buffer the loop in the template to a var for JS to spit out.
+	ob_start();
+	bp_get_template_part( 'activity/activity-loop' );
+	$result['contents'] = ob_get_contents();
+	$result['feed_url'] = apply_filters( 'bp_legacy_theme_activity_feed_url', $feed_url, $scope );
+	ob_end_clean();
+
+	exit( json_encode( $result ) );
+}
+
+/**
+ * Processes Activity updates received via a POST request.
+ *
+ * @return string HTML
+ * @since BuddyPress (1.2)
+ */
+function bp_legacy_theme_post_update() {
+	// Bail if not a POST action
+	if ( 'POST' !== strtoupper( $_SERVER['REQUEST_METHOD'] ) )
+		return;
+
+	// Check the nonce
+	check_admin_referer( 'post_update', '_wpnonce_post_update' );
+
+	if ( ! is_user_logged_in() )
+		exit( '-1' );
+
+	if ( empty( $_POST['content'] ) )
+		exit( '-1<div id="message" class="error"><p>' . __( 'Please enter some content to post.', 'buddypress' ) . '</p></div>' );
+
+	$activity_id = 0;
+	if ( empty( $_POST['object'] ) && bp_is_active( 'activity' ) ) {
+		$activity_id = bp_activity_post_update( array( 'content' => $_POST['content'] ) );
+
+	} elseif ( $_POST['object'] == 'groups' ) {
+		if ( ! empty( $_POST['item_id'] ) && bp_is_active( 'groups' ) )
+			$activity_id = groups_post_update( array( 'content' => $_POST['content'], 'group_id' => $_POST['item_id'] ) );
+
+	} else {
+		$activity_id = apply_filters( 'bp_activity_custom_update', $_POST['object'], $_POST['item_id'], $_POST['content'] );
+	}
+
+	if ( empty( $activity_id ) )
+		exit( '-1<div id="message" class="error"><p>' . __( 'There was a problem posting your update, please try again.', 'buddypress' ) . '</p></div>' );
+
+	if ( bp_has_activities ( 'include=' . $activity_id ) ) {
+		while ( bp_activities() ) {
+			bp_the_activity();
+			bp_get_template_part( 'activity/entry' );
+		}
+	}
+
+	exit;
+}
+
+/**
+ * Posts new Activity comments received via a POST request.
+ *
+ * @global BP_Activity_Template $activities_template
+ * @return string HTML
+ * @since BuddyPress (1.2)
+ */
+function bp_legacy_theme_new_activity_comment() {
+	global $activities_template;
+
+	// Bail if not a POST action
+	if ( 'POST' !== strtoupper( $_SERVER['REQUEST_METHOD'] ) )
+		return;
+
+	// Check the nonce
+	check_admin_referer( 'new_activity_comment', '_wpnonce_new_activity_comment' );
+
+	if ( ! is_user_logged_in() )
+		exit( '-1' );
+
+	if ( empty( $_POST['content'] ) )
+		exit( '-1<div id="message" class="error"><p>' . __( 'Please do not leave the comment area blank.', 'buddypress' ) . '</p></div>' );
+
+	if ( empty( $_POST['form_id'] ) || empty( $_POST['comment_id'] ) || ! is_numeric( $_POST['form_id'] ) || ! is_numeric( $_POST['comment_id'] ) )
+		exit( '-1<div id="message" class="error"><p>' . __( 'There was an error posting that reply, please try again.', 'buddypress' ) . '</p></div>' );
+
+	$comment_id = bp_activity_new_comment( array(
+		'activity_id' => $_POST['form_id'],
+		'content'     => $_POST['content'],
+		'parent_id'   => $_POST['comment_id'],
+	) );
+
+	if ( ! $comment_id )
+		exit( '-1<div id="message" class="error"><p>' . __( 'There was an error posting that reply, please try again.', 'buddypress' ) . '</p></div>' );
+
+	// Load the new activity item into the $activities_template global
+	bp_has_activities( 'display_comments=stream&hide_spam=false&include=' . $comment_id );
+
+	// Swap the current comment with the activity item we just loaded
+	if ( isset( $activities_template->activities[0] ) ) {
+		$activities_template->activity = new stdClass();
+		$activities_template->activity->id              = $activities_template->activities[0]->item_id;
+		$activities_template->activity->current_comment = $activities_template->activities[0];
+	}
+
+	// get activity comment template part
+	bp_get_template_part( 'activity/comment' );
+
+	unset( $activities_template );
+	exit;
+}
+
+/**
+ * Deletes an Activity item received via a POST request.
+ *
+ * @return mixed String on error, void on success
+ * @since BuddyPress (1.2)
+ */
+function bp_legacy_theme_delete_activity() {
+	// Bail if not a POST action
+	if ( 'POST' !== strtoupper( $_SERVER['REQUEST_METHOD'] ) )
+		return;
+
+	// Check the nonce
+	check_admin_referer( 'bp_activity_delete_link' );
+
+	if ( ! is_user_logged_in() )
+		exit( '-1' );
+
+	if ( empty( $_POST['id'] ) || ! is_numeric( $_POST['id'] ) )
+		exit( '-1' );
+
+	$activity = new BP_Activity_Activity( (int) $_POST['id'] );
+
+	// Check access
+	if ( ! bp_activity_user_can_delete( $activity ) )
+		exit( '-1' );
+
+	// Call the action before the delete so plugins can still fetch information about it
+	do_action( 'bp_activity_before_action_delete_activity', $activity->id, $activity->user_id );
+
+	if ( ! bp_activity_delete( array( 'id' => $activity->id, 'user_id' => $activity->user_id ) ) )
+		exit( '-1<div id="message" class="error"><p>' . __( 'There was a problem when deleting. Please try again.', 'buddypress' ) . '</p></div>' );
+
+	do_action( 'bp_activity_action_delete_activity', $activity->id, $activity->user_id );
+	exit;
+}
+
+/**
+ * Deletes an Activity comment received via a POST request
+ *
+ * @return mixed String on error, void on success
+ * @since BuddyPress (1.2)
+ */
+function bp_legacy_theme_delete_activity_comment() {
+	// Bail if not a POST action
+	if ( 'POST' !== strtoupper( $_SERVER['REQUEST_METHOD'] ) )
+		return;
+
+	// Check the nonce
+	check_admin_referer( 'bp_activity_delete_link' );
+
+	if ( ! is_user_logged_in() )
+		exit( '-1' );
+
+	$comment = new BP_Activity_Activity( $_POST['id'] );
+
+	// Check access
+	if ( ! bp_current_user_can( 'bp_moderate' ) && $comment->user_id != bp_loggedin_user_id() )
+		exit( '-1' );
+
+	if ( empty( $_POST['id'] ) || ! is_numeric( $_POST['id'] ) )
+		exit( '-1' );
+
+	// Call the action before the delete so plugins can still fetch information about it
+	do_action( 'bp_activity_before_action_delete_activity', $_POST['id'], $comment->user_id );
+
+	if ( ! bp_activity_delete_comment( $comment->item_id, $comment->id ) )
+		exit( '-1<div id="message" class="error"><p>' . __( 'There was a problem when deleting. Please try again.', 'buddypress' ) . '</p></div>' );
+
+	do_action( 'bp_activity_action_delete_activity', $_POST['id'], $comment->user_id );
+	exit;
+}
+
+/**
+ * AJAX spam an activity item or comment
+ *
+ * @return mixed String on error, void on success
+ * @since BuddyPress (1.6)
+ */
+function bp_legacy_theme_spam_activity() {
+	$bp = buddypress();
+
+	// Bail if not a POST action
+	if ( 'POST' !== strtoupper( $_SERVER['REQUEST_METHOD'] ) )
+		return;
+
+	// Check that user is logged in, Activity Streams are enabled, and Akismet is present.
+	if ( ! is_user_logged_in() || ! bp_is_active( 'activity' ) || empty( $bp->activity->akismet ) )
+		exit( '-1' );
+
+	// Check an item ID was passed
+	if ( empty( $_POST['id'] ) || ! is_numeric( $_POST['id'] ) )
+		exit( '-1' );
+
+	// Is the current user allowed to spam items?
+	if ( ! bp_activity_user_can_mark_spam() )
+		exit( '-1' );
+
+	// Load up the activity item
+	$activity = new BP_Activity_Activity( (int) $_POST['id'] );
+	if ( empty( $activity->component ) )
+		exit( '-1' );
+
+	// Check nonce
+	check_admin_referer( 'bp_activity_akismet_spam_' . $activity->id );
+
+	// Call an action before the spamming so plugins can modify things if they want to
+	do_action( 'bp_activity_before_action_spam_activity', $activity->id, $activity );
+
+	// Mark as spam
+	bp_activity_mark_as_spam( $activity );
+	$activity->save();
+
+	do_action( 'bp_activity_action_spam_activity', $activity->id, $activity->user_id );
+	exit;
+}
+
+/**
+ * Mark an activity as a favourite via a POST request.
+ *
+ * @return string HTML
+ * @since BuddyPress (1.2)
+ */
+function bp_legacy_theme_mark_activity_favorite() {
+	// Bail if not a POST action
+	if ( 'POST' !== strtoupper( $_SERVER['REQUEST_METHOD'] ) )
+		return;
+
+	if ( bp_activity_add_user_favorite( $_POST['id'] ) )
+		_e( 'Remove Favorite', 'buddypress' );
+	else
+		_e( 'Favorite', 'buddypress' );
+
+	exit;
+}
+
+/**
+ * Un-favourite an activity via a POST request.
+ *
+ * @return string HTML
+ * @since BuddyPress (1.2)
+ */
+function bp_legacy_theme_unmark_activity_favorite() {
+	// Bail if not a POST action
+	if ( 'POST' !== strtoupper( $_SERVER['REQUEST_METHOD'] ) )
+		return;
+
+	if ( bp_activity_remove_user_favorite( $_POST['id'] ) )
+		_e( 'Favorite', 'buddypress' );
+	else
+		_e( 'Remove Favorite', 'buddypress' );
+
+	exit;
+}
+
+/**
+ * Fetches full an activity's full, non-excerpted content via a POST request.
+ * Used for the 'Read More' link on long activity items.
+ *
+ * @return string HTML
+ * @since BuddyPress (1.5)
+ */
+function bp_legacy_theme_get_single_activity_content() {
+	// Bail if not a POST action
+	if ( 'POST' !== strtoupper( $_SERVER['REQUEST_METHOD'] ) )
+		return;
+
+	$activity_array = bp_activity_get_specific( array(
+		'activity_ids'     => $_POST['activity_id'],
+		'display_comments' => 'stream'
+	) );
+
+	$activity = ! empty( $activity_array['activities'][0] ) ? $activity_array['activities'][0] : false;
+
+	if ( empty( $activity ) )
+		exit; // @todo: error?
+
+	do_action_ref_array( 'bp_legacy_theme_get_single_activity_content', array( &$activity ) );
+
+	// Activity content retrieved through AJAX should run through normal filters, but not be truncated
+	remove_filter( 'bp_get_activity_content_body', 'bp_activity_truncate_entry', 5 );
+	$content = apply_filters( 'bp_get_activity_content_body', $activity->content );
+
+	exit( $content );
+}
+
+/**
+ * Invites a friend to join a group via a POST request.
+ *
+ * @since BuddyPress (1.2)
+ * @todo Audit return types
+ */
+function bp_legacy_theme_ajax_invite_user() {
+	// Bail if not a POST action
+	if ( 'POST' !== strtoupper( $_SERVER['REQUEST_METHOD'] ) )
+		return;
+
+	check_ajax_referer( 'groups_invite_uninvite_user' );
+
+	if ( ! $_POST['friend_id'] || ! $_POST['friend_action'] || ! $_POST['group_id'] )
+		return;
+
+	if ( ! bp_groups_user_can_send_invites( $_POST['group_id'] ) )
+		return;
+
+	if ( ! friends_check_friendship( bp_loggedin_user_id(), $_POST['friend_id'] ) )
+		return;
+
+	$group_id = (int) $_POST['group_id'];
+	$friend_id = (int) $_POST['friend_id'];
+
+	if ( 'invite' == $_POST['friend_action'] ) {
+		$group = groups_get_group( $group_id );
+
+		// Users who have previously requested membership do not need
+		// another invitation created for them
+		if ( BP_Groups_Member::check_for_membership_request( $friend_id, $group_id ) ) {
+			$user_status = 'is_pending';
+
+		// Create the user invitation
+		} else if ( groups_invite_user( array( 'user_id' => $friend_id, 'group_id' => $group_id ) ) ) {
+			$user_status = 'is_invited';
+
+		// Miscellaneous failure
+		} else {
+			return;
+		}
+
+		$user = new BP_Core_User( $friend_id );
+
+		echo '<li id="uid-' . $user->id . '">';
+		echo $user->avatar_thumb;
+		echo '<h4>' . $user->user_link . '</h4>';
+		echo '<span class="activity">' . esc_attr( $user->last_active ) . '</span>';
+		echo '<div class="action">
+				<a class="button remove" href="' . wp_nonce_url( bp_loggedin_user_domain() . bp_get_groups_slug() . '/' . $_POST['group_id'] . '/invites/remove/' . $user->id, 'groups_invite_uninvite_user' ) . '" id="uid-' . esc_attr( $user->id ) . '">' . __( 'Remove Invite', 'buddypress' ) . '</a>
+			  </div>';
+
+		if ( 'is_pending' == $user_status ) {
+			echo '<p class="description">' . sprintf( __( '%s has previously requested to join this group. Sending an invitation will automatically add the member to the group.', 'buddypress' ), $user->user_link ) . '</p>';
+		}
+
+		echo '</li>';
+		exit;
+
+	} elseif ( 'uninvite' == $_POST['friend_action'] ) {
+		// Users who have previously requested membership should not
+		// have their requests deleted on the "uninvite" action
+		if ( BP_Groups_Member::check_for_membership_request( $friend_id, $group_id ) ) {
+			return;
+		}
+
+		// Remove the unsent invitation
+		if ( ! groups_uninvite_user( $friend_id, $group_id ) ) {
+			return;
+		}
+
+		exit;
+
+	} else {
+		return;
+	}
+}
+
+/**
+ * Friend/un-friend a user via a POST request.
+ *
+ * @return string HTML
+ * @since BuddyPress (1.2)
+ */
+function bp_legacy_theme_ajax_addremove_friend() {
+
+	// Bail if not a POST action
+	if ( 'POST' !== strtoupper( $_SERVER['REQUEST_METHOD'] ) )
+		return;
+
+	// Cast fid as an integer
+	$friend_id = (int) $_POST['fid'];
+
+	// Trying to cancel friendship
+	if ( 'is_friend' == BP_Friends_Friendship::check_is_friend( bp_loggedin_user_id(), $friend_id ) ) {
+		check_ajax_referer( 'friends_remove_friend' );
+
+		if ( ! friends_remove_friend( bp_loggedin_user_id(), $friend_id ) ) {
+			echo __( 'Friendship could not be canceled.', 'buddypress' );
+		} else {
+			echo '<a id="friend-' . esc_attr( $friend_id ) . '" class="add" rel="add" title="' . __( 'Add Friend', 'buddypress' ) . '" href="' . wp_nonce_url( bp_loggedin_user_domain() . bp_get_friends_slug() . '/add-friend/' . $friend_id, 'friends_add_friend' ) . '">' . __( 'Add Friend', 'buddypress' ) . '</a>';
+		}
+
+	// Trying to request friendship
+	} elseif ( 'not_friends' == BP_Friends_Friendship::check_is_friend( bp_loggedin_user_id(), $friend_id ) ) {
+		check_ajax_referer( 'friends_add_friend' );
+
+		if ( ! friends_add_friend( bp_loggedin_user_id(), $friend_id ) ) {
+			echo __(' Friendship could not be requested.', 'buddypress' );
+		} else {
+			echo '<a id="friend-' . esc_attr( $friend_id ) . '" class="remove" rel="remove" title="' . __( 'Cancel Friendship Request', 'buddypress' ) . '" href="' . wp_nonce_url( bp_loggedin_user_domain() . bp_get_friends_slug() . '/requests/cancel/' . $friend_id . '/', 'friends_withdraw_friendship' ) . '" class="requested">' . __( 'Cancel Friendship Request', 'buddypress' ) . '</a>';
+		}
+
+	// Trying to cancel pending request
+	} elseif ( 'pending' == BP_Friends_Friendship::check_is_friend( bp_loggedin_user_id(), $friend_id ) ) {
+		check_ajax_referer( 'friends_withdraw_friendship' );
+
+		if ( friends_withdraw_friendship( bp_loggedin_user_id(), $friend_id ) ) {
+			echo '<a id="friend-' . esc_attr( $friend_id ) . '" class="add" rel="add" title="' . __( 'Add Friend', 'buddypress' ) . '" href="' . wp_nonce_url( bp_loggedin_user_domain() . bp_get_friends_slug() . '/add-friend/' . $friend_id, 'friends_add_friend' ) . '">' . __( 'Add Friend', 'buddypress' ) . '</a>';
+		} else {
+			echo __("Friendship request could not be cancelled.", 'buddypress');
+		}
+
+	// Request already pending
+	} else {
+		echo __( 'Request Pending', 'buddypress' );
+	}
+
+	exit;
+}
+
+/**
+ * Accept a user friendship request via a POST request.
+ *
+ * @return mixed String on error, void on success
+ * @since BuddyPress (1.2)
+ */
+function bp_legacy_theme_ajax_accept_friendship() {
+	// Bail if not a POST action
+	if ( 'POST' !== strtoupper( $_SERVER['REQUEST_METHOD'] ) )
+		return;
+
+	check_admin_referer( 'friends_accept_friendship' );
+
+	if ( ! friends_accept_friendship( (int) $_POST['id'] ) )
+		echo "-1<div id='message' class='error'><p>" . __( 'There was a problem accepting that request. Please try again.', 'buddypress' ) . '</p></div>';
+
+	exit;
+}
+
+/**
+ * Reject a user friendship request via a POST request.
+ *
+ * @return mixed String on error, void on success
+ * @since BuddyPress (1.2)
+ */
+function bp_legacy_theme_ajax_reject_friendship() {
+	// Bail if not a POST action
+	if ( 'POST' !== strtoupper( $_SERVER['REQUEST_METHOD'] ) )
+		return;
+
+	check_admin_referer( 'friends_reject_friendship' );
+
+	if ( ! friends_reject_friendship( (int) $_POST['id'] ) )
+		echo "-1<div id='message' class='error'><p>" . __( 'There was a problem rejecting that request. Please try again.', 'buddypress' ) . '</p></div>';
+
+	exit;
+}
+
+/**
+ * Join or leave a group when clicking the "join/leave" button via a POST request.
+ *
+ * @return string HTML
+ * @since BuddyPress (1.2)
+ */
+function bp_legacy_theme_ajax_joinleave_group() {
+	// Bail if not a POST action
+	if ( 'POST' !== strtoupper( $_SERVER['REQUEST_METHOD'] ) )
+		return;
+
+	// Cast gid as integer
+	$group_id = (int) $_POST['gid'];
+
+	if ( groups_is_user_banned( bp_loggedin_user_id(), $group_id ) )
+		return;
+
+	if ( ! $group = groups_get_group( array( 'group_id' => $group_id ) ) )
+		return;
+
+	if ( ! groups_is_user_member( bp_loggedin_user_id(), $group->id ) ) {
+		if ( 'public' == $group->status ) {
+			check_ajax_referer( 'groups_join_group' );
+
+			if ( ! groups_join_group( $group->id ) ) {
+				_e( 'Error joining group', 'buddypress' );
+			} else {
+				echo '<a id="group-' . esc_attr( $group->id ) . '" class="leave-group" rel="leave" title="' . __( 'Leave Group', 'buddypress' ) . '" href="' . wp_nonce_url( bp_get_group_permalink( $group ) . 'leave-group', 'groups_leave_group' ) . '">' . __( 'Leave Group', 'buddypress' ) . '</a>';
+			}
+
+		} elseif ( 'private' == $group->status ) {
+
+			// If the user has already been invited, then this is
+			// an Accept Invitation button
+			if ( groups_check_user_has_invite( bp_loggedin_user_id(), $group->id ) ) {
+				check_ajax_referer( 'groups_accept_invite' );
+
+				if ( ! groups_accept_invite( bp_loggedin_user_id(), $group->id ) ) {
+					_e( 'Error requesting membership', 'buddypress' );
+				} else {
+					echo '<a id="group-' . esc_attr( $group->id ) . '" class="leave-group" rel="leave" title="' . __( 'Leave Group', 'buddypress' ) . '" href="' . wp_nonce_url( bp_get_group_permalink( $group ) . 'leave-group', 'groups_leave_group' ) . '">' . __( 'Leave Group', 'buddypress' ) . '</a>';
+				}
+
+			// Otherwise, it's a Request Membership button
+			} else {
+				check_ajax_referer( 'groups_request_membership' );
+
+				if ( ! groups_send_membership_request( bp_loggedin_user_id(), $group->id ) ) {
+					_e( 'Error requesting membership', 'buddypress' );
+				} else {
+					echo '<a id="group-' . esc_attr( $group->id ) . '" class="membership-requested" rel="membership-requested" title="' . __( 'Membership Requested', 'buddypress' ) . '" href="' . bp_get_group_permalink( $group ) . '">' . __( 'Membership Requested', 'buddypress' ) . '</a>';
+				}
+			}
+		}
+
+	} else {
+		check_ajax_referer( 'groups_leave_group' );
+
+		if ( ! groups_leave_group( $group->id ) ) {
+			_e( 'Error leaving group', 'buddypress' );
+		} elseif ( 'public' == $group->status ) {
+			echo '<a id="group-' . esc_attr( $group->id ) . '" class="join-group" rel="join" title="' . __( 'Join Group', 'buddypress' ) . '" href="' . wp_nonce_url( bp_get_group_permalink( $group ) . 'join', 'groups_join_group' ) . '">' . __( 'Join Group', 'buddypress' ) . '</a>';
+		} elseif ( 'private' == $group->status ) {
+			echo '<a id="group-' . esc_attr( $group->id ) . '" class="request-membership" rel="join" title="' . __( 'Request Membership', 'buddypress' ) . '" href="' . wp_nonce_url( bp_get_group_permalink( $group ) . 'request-membership', 'groups_send_membership_request' ) . '">' . __( 'Request Membership', 'buddypress' ) . '</a>';
+		}
+	}
+
+	exit;
+}
+
+/**
+ * Close and keep closed site wide notices from an admin in the sidebar, via a POST request.
+ *
+ * @return mixed String on error, void on success
+ * @since BuddyPress (1.2)
+ */
+function bp_legacy_theme_ajax_close_notice() {
+	// Bail if not a POST action
+	if ( 'POST' !== strtoupper( $_SERVER['REQUEST_METHOD'] ) )
+		return;
+
+	if ( ! isset( $_POST['notice_id'] ) ) {
+		echo "-1<div id='message' class='error'><p>" . __( 'There was a problem closing the notice.', 'buddypress' ) . '</p></div>';
+
+	} else {
+		$user_id      = get_current_user_id();
+		$notice_ids   = bp_get_user_meta( $user_id, 'closed_notices', true );
+		$notice_ids[] = (int) $_POST['notice_id'];
+
+		bp_update_user_meta( $user_id, 'closed_notices', $notice_ids );
+	}
+
+	exit;
+}
+
+/**
+ * Send a private message reply to a thread via a POST request.
+ *
+ * @return string HTML
+ * @since BuddyPress (1.2)
+ */
+function bp_legacy_theme_ajax_messages_send_reply() {
+	// Bail if not a POST action
+	if ( 'POST' !== strtoupper( $_SERVER['REQUEST_METHOD'] ) )
+		return;
+
+	check_ajax_referer( 'messages_send_message' );
+
+	$result = messages_new_message( array( 'thread_id' => (int) $_REQUEST['thread_id'], 'content' => $_REQUEST['content'] ) );
+
+	if ( !empty( $result ) ) {
+
+		// Get the zebra line classes correct on ajax requests
+		global $thread_template;
+
+		bp_thread_has_messages( array( 'thread_id' => (int) $_REQUEST['thread_id'] ) );
+
+		if ( $thread_template->message_count % 2 == 1 ) {
+			$class = 'odd';
+		} else {
+			$class = 'even alt';
+		} ?>
+
+		<div class="message-box new-message <?php echo $class; ?>">
+			<div class="message-metadata">
+				<?php do_action( 'bp_before_message_meta' ); ?>
+				<?php echo bp_loggedin_user_avatar( 'type=thumb&width=30&height=30' ); ?>
+
+				<strong><a href="<?php echo bp_loggedin_user_domain(); ?>"><?php bp_loggedin_user_fullname(); ?></a> <span class="activity"><?php printf( __( 'Sent %s', 'buddypress' ), bp_core_time_since( bp_core_current_time() ) ); ?></span></strong>
+
+				<?php do_action( 'bp_after_message_meta' ); ?>
+			</div>
+
+			<?php do_action( 'bp_before_message_content' ); ?>
+
+			<div class="message-content">
+				<?php echo stripslashes( apply_filters( 'bp_get_the_thread_message_content', $_REQUEST['content'] ) ); ?>
+			</div>
+
+			<?php do_action( 'bp_after_message_content' ); ?>
+
+			<div class="clear"></div>
+		</div>
+	<?php
+	} else {
+		echo "-1<div id='message' class='error'><p>" . __( 'There was a problem sending that reply. Please try again.', 'buddypress' ) . '</p></div>';
+	}
+
+	exit;
+}
+
+/**
+ * Mark a private message as unread in your inbox via a POST request.
+ *
+ * @return mixed String on error, void on success
+ * @since BuddyPress (1.2)
+ */
+function bp_legacy_theme_ajax_message_markunread() {
+	// Bail if not a POST action
+	if ( 'POST' !== strtoupper( $_SERVER['REQUEST_METHOD'] ) )
+		return;
+
+	if ( ! isset($_POST['thread_ids']) ) {
+		echo "-1<div id='message' class='error'><p>" . __( 'There was a problem marking messages as unread.', 'buddypress' ) . '</p></div>';
+
+	} else {
+		$thread_ids = explode( ',', $_POST['thread_ids'] );
+
+		for ( $i = 0, $count = count( $thread_ids ); $i < $count; ++$i ) {
+			BP_Messages_Thread::mark_as_unread( (int) $thread_ids[$i] );
+		}
+	}
+
+	exit;
+}
+
+/**
+ * Mark a private message as read in your inbox via a POST request.
+ *
+ * @return mixed String on error, void on success
+ * @since BuddyPress (1.2)
+ */
+function bp_legacy_theme_ajax_message_markread() {
+	// Bail if not a POST action
+	if ( 'POST' !== strtoupper( $_SERVER['REQUEST_METHOD'] ) )
+		return;
+
+	if ( ! isset($_POST['thread_ids']) ) {
+		echo "-1<div id='message' class='error'><p>" . __('There was a problem marking messages as read.', 'buddypress' ) . '</p></div>';
+
+	} else {
+		$thread_ids = explode( ',', $_POST['thread_ids'] );
+
+		for ( $i = 0, $count = count( $thread_ids ); $i < $count; ++$i ) {
+			BP_Messages_Thread::mark_as_read( (int) $thread_ids[$i] );
+		}
+	}
+
+	exit;
+}
+
+/**
+ * Delete a private message(s) in your inbox via a POST request.
+ *
+ * @return string HTML
+ * @since BuddyPress (1.2)
+ */
+function bp_legacy_theme_ajax_messages_delete() {
+	// Bail if not a POST action
+	if ( 'POST' !== strtoupper( $_SERVER['REQUEST_METHOD'] ) )
+		return;
+
+	if ( ! isset($_POST['thread_ids']) ) {
+		echo "-1<div id='message' class='error'><p>" . __( 'There was a problem deleting messages.', 'buddypress' ) . '</p></div>';
+
+	} else {
+		$thread_ids = explode( ',', $_POST['thread_ids'] );
+
+		for ( $i = 0, $count = count( $thread_ids ); $i < $count; ++$i ) {
+			BP_Messages_Thread::delete( (int) $thread_ids[$i] );
+		}
+
+		_e( 'Messages deleted.', 'buddypress' );
+	}
+
+	exit;
+}
+
+/**
+ * AJAX handler for autocomplete. Displays friends only, unless BP_MESSAGES_AUTOCOMPLETE_ALL is defined.
+ *
+ * @return string HTML
+ * @since BuddyPress (1.2)
+ */
+function bp_legacy_theme_ajax_messages_autocomplete_results() {
+
+	// Include everyone in the autocomplete, or just friends?
+	if ( bp_is_current_component( bp_get_messages_slug() ) )
+		$autocomplete_all = buddypress()->messages->autocomplete_all;
+
+	$pag_page = 1;
+	$limit    = (int) $_GET['limit'] ? $_GET['limit'] : apply_filters( 'bp_autocomplete_max_results', 10 );
+
+	// Get the user ids based on the search terms
+	if ( ! empty( $autocomplete_all ) ) {
+		$users = BP_Core_User::search_users( $_GET['q'], $limit, $pag_page );
+
+		if ( ! empty( $users['users'] ) ) {
+			// Build an array with the correct format
+			$user_ids = array();
+			foreach( $users['users'] as $user ) {
+				if ( $user->id != bp_loggedin_user_id() ) {
+					$user_ids[] = $user->id;
+				}
+			}
+
+			$user_ids = apply_filters( 'bp_core_autocomplete_ids', $user_ids, $_GET['q'], $limit );
+		}
+
+	} else {
+		if ( bp_is_active( 'friends' ) ) {
+			$users = friends_search_friends( $_GET['q'], bp_loggedin_user_id(), $limit, 1 );
+
+			// Keeping the bp_friends_autocomplete_list filter for backward compatibility
+			$users = apply_filters( 'bp_friends_autocomplete_list', $users, $_GET['q'], $limit );
+
+			if ( ! empty( $users['friends'] ) ) {
+				$user_ids = apply_filters( 'bp_friends_autocomplete_ids', $users['friends'], $_GET['q'], $limit );
+			}
+		}
+	}
+
+	if ( ! empty( $user_ids ) ) {
+		foreach ( $user_ids as $user_id ) {
+			$ud = get_userdata( $user_id );
+			if ( ! $ud ) {
+				continue;
+			}
+
+			if ( bp_is_username_compatibility_mode() ) {
+				// Sanitize for spaces. Use urlencode() rather
+				// than rawurlencode() because %20 breaks JS
+				$username = urlencode( $ud->user_login );
+			} else {
+				$username = $ud->user_nicename;
+			}
+
+			// Note that the final line break acts as a delimiter for the
+			// autocomplete javascript and thus should not be removed
+			echo '<span id="link-' . esc_attr( $username ) . '" href="' . bp_core_get_user_domain( $user_id ) . '"></span>' . bp_core_fetch_avatar( array( 'item_id' => $user_id, 'type' => 'thumb', 'width' => 15, 'height' => 15, 'alt' => $ud->display_name ) ) . ' &nbsp;' . bp_core_get_user_displayname( $user_id ) . ' (' . esc_html( $username ) . ')' . "\n";
+		}
+	}
+
+	exit;
+}
Index: /tags/1.9/bp-templates/bp-legacy/buddypress/activity/activity-loop.php
===================================================================
--- /tags/1.9/bp-templates/bp-legacy/buddypress/activity/activity-loop.php	(revision 7684)
+++ /tags/1.9/bp-templates/bp-legacy/buddypress/activity/activity-loop.php	(revision 7684)
@@ -0,0 +1,53 @@
+<?php do_action( 'bp_before_activity_loop' ); ?>
+
+<?php if ( bp_has_activities( bp_ajax_querystring( 'activity' ) ) ) : ?>
+
+	<?php /* Show pagination if JS is not enabled, since the "Load More" link will do nothing */ ?>
+	<noscript>
+		<div class="pagination">
+			<div class="pag-count"><?php bp_activity_pagination_count(); ?></div>
+			<div class="pagination-links"><?php bp_activity_pagination_links(); ?></div>
+		</div>
+	</noscript>
+
+	<?php if ( empty( $_POST['page'] ) ) : ?>
+
+		<ul id="activity-stream" class="activity-list item-list">
+
+	<?php endif; ?>
+
+	<?php while ( bp_activities() ) : bp_the_activity(); ?>
+
+		<?php bp_get_template_part( 'activity/entry' ); ?>
+
+	<?php endwhile; ?>
+
+	<?php if ( bp_activity_has_more_items() ) : ?>
+
+		<li class="load-more">
+			<a href="#more"><?php _e( 'Load More', 'buddypress' ); ?></a>
+		</li>
+
+	<?php endif; ?>
+
+	<?php if ( empty( $_POST['page'] ) ) : ?>
+
+		</ul>
+
+	<?php endif; ?>
+
+<?php else : ?>
+
+	<div id="message" class="info">
+		<p><?php _e( 'Sorry, there was no activity found. Please try a different filter.', 'buddypress' ); ?></p>
+	</div>
+
+<?php endif; ?>
+
+<?php do_action( 'bp_after_activity_loop' ); ?>
+
+<form action="" name="activity-loop-form" id="activity-loop-form" method="post">
+
+	<?php wp_nonce_field( 'activity_filter', '_wpnonce_activity_filter' ); ?>
+
+</form>
Index: /tags/1.9/bp-templates/bp-legacy/buddypress/activity/comment.php
===================================================================
--- /tags/1.9/bp-templates/bp-legacy/buddypress/activity/comment.php	(revision 7684)
+++ /tags/1.9/bp-templates/bp-legacy/buddypress/activity/comment.php	(revision 7684)
@@ -0,0 +1,54 @@
+<?php
+
+/**
+ * BuddyPress - Activity Stream Comment
+ *
+ * This template is used by bp_activity_comments() functions to show
+ * each activity.
+ *
+ * @package BuddyPress
+ * @subpackage bp-legacy
+ */
+
+?>
+
+<?php do_action( 'bp_before_activity_comment' ); ?>
+
+<li id="acomment-<?php bp_activity_comment_id(); ?>">
+	<div class="acomment-avatar">
+		<a href="<?php bp_activity_comment_user_link(); ?>">
+			<?php bp_activity_avatar( 'type=thumb&user_id=' . bp_get_activity_comment_user_id() ); ?>
+		</a>
+	</div>
+
+	<div class="acomment-meta">
+		<?php
+		/* translators: 1: user profile link, 2: user name, 3: activity permalink, 4: activity timestamp */
+		printf( __( '<a href="%1$s">%2$s</a> replied <a href="%3$s" class="activity-time-since"><span class="time-since">%4$s</span></a>', 'buddypress' ), bp_get_activity_comment_user_link(), bp_get_activity_comment_name(), bp_get_activity_comment_permalink(), bp_get_activity_comment_date_recorded() );
+		?>
+	</div>
+
+	<div class="acomment-content"><?php bp_activity_comment_content(); ?></div>
+
+	<div class="acomment-options">
+
+		<?php if ( is_user_logged_in() && bp_activity_can_comment_reply( bp_activity_current_comment() ) ) : ?>
+
+			<a href="#acomment-<?php bp_activity_comment_id(); ?>" class="acomment-reply bp-primary-action" id="acomment-reply-<?php bp_activity_id(); ?>-from-<?php bp_activity_comment_id(); ?>"><?php _e( 'Reply', 'buddypress' ); ?></a>
+
+		<?php endif; ?>
+
+		<?php if ( bp_activity_user_can_delete() ) : ?>
+
+			<a href="<?php bp_activity_comment_delete_link(); ?>" class="delete acomment-delete confirm bp-secondary-action" rel="nofollow"><?php _e( 'Delete', 'buddypress' ); ?></a>
+
+		<?php endif; ?>
+
+		<?php do_action( 'bp_activity_comment_options' ); ?>
+
+	</div>
+
+	<?php bp_activity_recurse_comments( bp_activity_current_comment() ); ?>
+</li>
+
+<?php do_action( 'bp_after_activity_comment' ); ?>
Index: /tags/1.9/bp-templates/bp-legacy/buddypress/activity/entry.php
===================================================================
--- /tags/1.9/bp-templates/bp-legacy/buddypress/activity/entry.php	(revision 7684)
+++ /tags/1.9/bp-templates/bp-legacy/buddypress/activity/entry.php	(revision 7684)
@@ -0,0 +1,122 @@
+<?php
+
+/**
+ * BuddyPress - Activity Stream (Single Item)
+ *
+ * This template is used by activity-loop.php and AJAX functions to show
+ * each activity.
+ *
+ * @package BuddyPress
+ * @subpackage bp-legacy
+ */
+
+?>
+
+<?php do_action( 'bp_before_activity_entry' ); ?>
+
+<li class="<?php bp_activity_css_class(); ?>" id="activity-<?php bp_activity_id(); ?>">
+	<div class="activity-avatar">
+		<a href="<?php bp_activity_user_link(); ?>">
+
+			<?php bp_activity_avatar(); ?>
+
+		</a>
+	</div>
+
+	<div class="activity-content">
+
+		<div class="activity-header">
+
+			<?php bp_activity_action(); ?>
+
+		</div>
+
+		<?php if ( bp_activity_has_content() ) : ?>
+
+			<div class="activity-inner">
+
+				<?php bp_activity_content_body(); ?>
+
+			</div>
+
+		<?php endif; ?>
+
+		<?php do_action( 'bp_activity_entry_content' ); ?>
+
+		<div class="activity-meta">
+
+			<?php if ( bp_get_activity_type() == 'activity_comment' ) : ?>
+
+				<a href="<?php bp_activity_thread_permalink(); ?>" class="button view bp-secondary-action" title="<?php _e( 'View Conversation', 'buddypress' ); ?>"><?php _e( 'View Conversation', 'buddypress' ); ?></a>
+
+			<?php endif; ?>
+
+			<?php if ( is_user_logged_in() ) : ?>
+
+				<?php if ( bp_activity_can_comment() ) : ?>
+
+					<a href="<?php bp_activity_comment_link(); ?>" class="button acomment-reply bp-primary-action" id="acomment-comment-<?php bp_activity_id(); ?>"><?php printf( __( 'Comment <span>%s</span>', 'buddypress' ), bp_activity_get_comment_count() ); ?></a>
+
+				<?php endif; ?>
+
+				<?php if ( bp_activity_can_favorite() ) : ?>
+
+					<?php if ( !bp_get_activity_is_favorite() ) : ?>
+
+						<a href="<?php bp_activity_favorite_link(); ?>" class="button fav bp-secondary-action" title="<?php esc_attr_e( 'Mark as Favorite', 'buddypress' ); ?>"><?php _e( 'Favorite', 'buddypress' ); ?></a>
+
+					<?php else : ?>
+
+						<a href="<?php bp_activity_unfavorite_link(); ?>" class="button unfav bp-secondary-action" title="<?php esc_attr_e( 'Remove Favorite', 'buddypress' ); ?>"><?php _e( 'Remove Favorite', 'buddypress' ); ?></a>
+
+					<?php endif; ?>
+
+				<?php endif; ?>
+
+				<?php if ( bp_activity_user_can_delete() ) bp_activity_delete_link(); ?>
+
+				<?php do_action( 'bp_activity_entry_meta' ); ?>
+
+			<?php endif; ?>
+
+		</div>
+
+	</div>
+
+	<?php do_action( 'bp_before_activity_entry_comments' ); ?>
+
+	<?php if ( ( is_user_logged_in() && bp_activity_can_comment() ) || bp_is_single_activity() ) : ?>
+
+		<div class="activity-comments">
+
+			<?php bp_activity_comments(); ?>
+
+			<?php if ( is_user_logged_in() ) : ?>
+
+				<form action="<?php bp_activity_comment_form_action(); ?>" method="post" id="ac-form-<?php bp_activity_id(); ?>" class="ac-form"<?php bp_activity_comment_form_nojs_display(); ?>>
+					<div class="ac-reply-avatar"><?php bp_loggedin_user_avatar( 'width=' . BP_AVATAR_THUMB_WIDTH . '&height=' . BP_AVATAR_THUMB_HEIGHT ); ?></div>
+					<div class="ac-reply-content">
+						<div class="ac-textarea">
+							<textarea id="ac-input-<?php bp_activity_id(); ?>" class="ac-input" name="ac_input_<?php bp_activity_id(); ?>"></textarea>
+						</div>
+						<input type="submit" name="ac_form_submit" value="<?php _e( 'Post', 'buddypress' ); ?>" /> &nbsp; <a href="#" class="ac-reply-cancel"><?php _e( 'Cancel', 'buddypress' ); ?></a>
+						<input type="hidden" name="comment_form_id" value="<?php bp_activity_id(); ?>" />
+					</div>
+
+					<?php do_action( 'bp_activity_entry_comments' ); ?>
+
+					<?php wp_nonce_field( 'new_activity_comment', '_wpnonce_new_activity_comment' ); ?>
+
+				</form>
+
+			<?php endif; ?>
+
+		</div>
+
+	<?php endif; ?>
+
+	<?php do_action( 'bp_after_activity_entry_comments' ); ?>
+
+</li>
+
+<?php do_action( 'bp_after_activity_entry' ); ?>
Index: /tags/1.9/bp-templates/bp-legacy/buddypress/activity/index.php
===================================================================
--- /tags/1.9/bp-templates/bp-legacy/buddypress/activity/index.php	(revision 7684)
+++ /tags/1.9/bp-templates/bp-legacy/buddypress/activity/index.php	(revision 7684)
@@ -0,0 +1,133 @@
+<?php do_action( 'bp_before_directory_activity' ); ?>
+
+<div id="buddypress">
+
+	<?php do_action( 'bp_before_directory_activity_content' ); ?>
+
+	<?php if ( is_user_logged_in() ) : ?>
+
+		<?php bp_get_template_part( 'activity/post-form' ); ?>
+
+	<?php endif; ?>
+
+	<?php do_action( 'template_notices' ); ?>
+
+	<div class="item-list-tabs activity-type-tabs" role="navigation">
+		<ul>
+			<?php do_action( 'bp_before_activity_type_tab_all' ); ?>
+
+			<li class="selected" id="activity-all"><a href="<?php bp_activity_directory_permalink(); ?>" title="<?php _e( 'The public activity for everyone on this site.', 'buddypress' ); ?>"><?php printf( __( 'All Members <span>%s</span>', 'buddypress' ), bp_get_total_member_count() ); ?></a></li>
+
+			<?php if ( is_user_logged_in() ) : ?>
+
+				<?php do_action( 'bp_before_activity_type_tab_friends' ); ?>
+
+				<?php if ( bp_is_active( 'friends' ) ) : ?>
+
+					<?php if ( bp_get_total_friend_count( bp_loggedin_user_id() ) ) : ?>
+
+						<li id="activity-friends"><a href="<?php echo bp_loggedin_user_domain() . bp_get_activity_slug() . '/' . bp_get_friends_slug() . '/'; ?>" title="<?php _e( 'The activity of my friends only.', 'buddypress' ); ?>"><?php printf( __( 'My Friends <span>%s</span>', 'buddypress' ), bp_get_total_friend_count( bp_loggedin_user_id() ) ); ?></a></li>
+
+					<?php endif; ?>
+
+				<?php endif; ?>
+
+				<?php do_action( 'bp_before_activity_type_tab_groups' ); ?>
+
+				<?php if ( bp_is_active( 'groups' ) ) : ?>
+
+					<?php if ( bp_get_total_group_count_for_user( bp_loggedin_user_id() ) ) : ?>
+
+						<li id="activity-groups"><a href="<?php echo bp_loggedin_user_domain() . bp_get_activity_slug() . '/' . bp_get_groups_slug() . '/'; ?>" title="<?php _e( 'The activity of groups I am a member of.', 'buddypress' ); ?>"><?php printf( __( 'My Groups <span>%s</span>', 'buddypress' ), bp_get_total_group_count_for_user( bp_loggedin_user_id() ) ); ?></a></li>
+
+					<?php endif; ?>
+
+				<?php endif; ?>
+
+				<?php do_action( 'bp_before_activity_type_tab_favorites' ); ?>
+
+				<?php if ( bp_get_total_favorite_count_for_user( bp_loggedin_user_id() ) ) : ?>
+
+					<li id="activity-favorites"><a href="<?php echo bp_loggedin_user_domain() . bp_get_activity_slug() . '/favorites/'; ?>" title="<?php _e( "The activity I've marked as a favorite.", 'buddypress' ); ?>"><?php printf( __( 'My Favorites <span>%s</span>', 'buddypress' ), bp_get_total_favorite_count_for_user( bp_loggedin_user_id() ) ); ?></a></li>
+
+				<?php endif; ?>
+
+				<?php if ( bp_activity_do_mentions() ) : ?>
+
+					<?php do_action( 'bp_before_activity_type_tab_mentions' ); ?>
+
+					<li id="activity-mentions"><a href="<?php echo bp_loggedin_user_domain() . bp_get_activity_slug() . '/mentions/'; ?>" title="<?php _e( 'Activity that I have been mentioned in.', 'buddypress' ); ?>"><?php _e( 'Mentions', 'buddypress' ); ?><?php if ( bp_get_total_mention_count_for_user( bp_loggedin_user_id() ) ) : ?> <strong><span><?php printf( _nx( '%s new', '%s new', bp_get_total_mention_count_for_user( bp_loggedin_user_id() ), 'Number of new activity mentions', 'buddypress' ), bp_get_total_mention_count_for_user( bp_loggedin_user_id() ) ); ?></span></strong><?php endif; ?></a></li>
+
+				<?php endif; ?>
+
+			<?php endif; ?>
+
+			<?php do_action( 'bp_activity_type_tabs' ); ?>
+		</ul>
+	</div><!-- .item-list-tabs -->
+
+	<div class="item-list-tabs no-ajax" id="subnav" role="navigation">
+		<ul>
+			<li class="feed"><a href="<?php bp_sitewide_activity_feed_link(); ?>" title="<?php _e( 'RSS Feed', 'buddypress' ); ?>"><?php _e( 'RSS', 'buddypress' ); ?></a></li>
+
+			<?php do_action( 'bp_activity_syndication_options' ); ?>
+
+			<li id="activity-filter-select" class="last">
+				<label for="activity-filter-by"><?php _e( 'Show:', 'buddypress' ); ?></label>
+				<select id="activity-filter-by">
+					<option value="-1"><?php _e( 'Everything', 'buddypress' ); ?></option>
+					<option value="activity_update"><?php _e( 'Updates', 'buddypress' ); ?></option>
+
+					<?php if ( bp_is_active( 'blogs' ) ) : ?>
+
+						<option value="new_blog_post"><?php _e( 'Posts', 'buddypress' ); ?></option>
+						<option value="new_blog_comment"><?php _e( 'Comments', 'buddypress' ); ?></option>
+
+					<?php endif; ?>
+
+					<?php if ( bp_is_active( 'forums' ) ) : ?>
+
+						<option value="new_forum_topic"><?php _e( 'Forum Topics', 'buddypress' ); ?></option>
+						<option value="new_forum_post"><?php _e( 'Forum Replies', 'buddypress' ); ?></option>
+
+					<?php endif; ?>
+
+					<?php if ( bp_is_active( 'groups' ) ) : ?>
+
+						<option value="created_group"><?php _e( 'New Groups', 'buddypress' ); ?></option>
+						<option value="joined_group"><?php _e( 'Group Memberships', 'buddypress' ); ?></option>
+
+					<?php endif; ?>
+
+					<?php if ( bp_is_active( 'friends' ) ) : ?>
+
+						<option value="friendship_accepted,friendship_created"><?php _e( 'Friendships', 'buddypress' ); ?></option>
+
+					<?php endif; ?>
+
+					<option value="new_member"><?php _e( 'New Members', 'buddypress' ); ?></option>
+
+					<?php do_action( 'bp_activity_filter_options' ); ?>
+
+				</select>
+			</li>
+		</ul>
+	</div><!-- .item-list-tabs -->
+
+	<?php do_action( 'bp_before_directory_activity_list' ); ?>
+
+	<div class="activity" role="main">
+
+		<?php bp_get_template_part( 'activity/activity-loop' ); ?>
+
+	</div><!-- .activity -->
+
+	<?php do_action( 'bp_after_directory_activity_list' ); ?>
+
+	<?php do_action( 'bp_directory_activity_content' ); ?>
+
+	<?php do_action( 'bp_after_directory_activity_content' ); ?>
+
+	<?php do_action( 'bp_after_directory_activity' ); ?>
+
+</div>
Index: /tags/1.9/bp-templates/bp-legacy/buddypress/activity/post-form.php
===================================================================
--- /tags/1.9/bp-templates/bp-legacy/buddypress/activity/post-form.php	(revision 7684)
+++ /tags/1.9/bp-templates/bp-legacy/buddypress/activity/post-form.php	(revision 7684)
@@ -0,0 +1,74 @@
+<?php
+
+/**
+ * BuddyPress - Activity Post Form
+ *
+ * @package BuddyPress
+ * @subpackage bp-legacy
+ */
+
+?>
+
+<form action="<?php bp_activity_post_form_action(); ?>" method="post" id="whats-new-form" name="whats-new-form" role="complementary">
+
+	<?php do_action( 'bp_before_activity_post_form' ); ?>
+
+	<div id="whats-new-avatar">
+		<a href="<?php echo bp_loggedin_user_domain(); ?>">
+			<?php bp_loggedin_user_avatar( 'width=' . bp_core_avatar_thumb_width() . '&height=' . bp_core_avatar_thumb_height() ); ?>
+		</a>
+	</div>
+	
+	<p class="activity-greeting"><?php if ( bp_is_group() )
+		printf( __( "What's new in %s, %s?", 'buddypress' ), bp_get_group_name(), bp_get_user_firstname() );
+	else
+		printf( __( "What's new, %s?", 'buddypress' ), bp_get_user_firstname() );
+	?></p>
+
+	<div id="whats-new-content">
+		<div id="whats-new-textarea">
+			<textarea name="whats-new" id="whats-new" cols="50" rows="10"><?php if ( isset( $_GET['r'] ) ) : ?>@<?php echo esc_attr( $_GET['r'] ); ?> <?php endif; ?></textarea>
+		</div>
+
+		<div id="whats-new-options">
+			<div id="whats-new-submit">
+				<input type="submit" name="aw-whats-new-submit" id="aw-whats-new-submit" value="<?php _e( 'Post Update', 'buddypress' ); ?>" />
+			</div>
+
+			<?php if ( bp_is_active( 'groups' ) && !bp_is_my_profile() && !bp_is_group() ) : ?>
+
+				<div id="whats-new-post-in-box">
+
+					<?php _e( 'Post in', 'buddypress' ); ?>:
+
+					<select id="whats-new-post-in" name="whats-new-post-in">
+						<option selected="selected" value="0"><?php _e( 'My Profile', 'buddypress' ); ?></option>
+
+						<?php if ( bp_has_groups( 'user_id=' . bp_loggedin_user_id() . '&type=alphabetical&max=100&per_page=100&populate_extras=0' ) ) :
+							while ( bp_groups() ) : bp_the_group(); ?>
+
+								<option value="<?php bp_group_id(); ?>"><?php bp_group_name(); ?></option>
+
+							<?php endwhile;
+						endif; ?>
+
+					</select>
+				</div>
+				<input type="hidden" id="whats-new-post-object" name="whats-new-post-object" value="groups" />
+
+			<?php elseif ( bp_is_group_home() ) : ?>
+
+				<input type="hidden" id="whats-new-post-object" name="whats-new-post-object" value="groups" />
+				<input type="hidden" id="whats-new-post-in" name="whats-new-post-in" value="<?php bp_group_id(); ?>" />
+
+			<?php endif; ?>
+
+			<?php do_action( 'bp_activity_post_form_options' ); ?>
+
+		</div><!-- #whats-new-options -->
+	</div><!-- #whats-new-content -->
+
+	<?php wp_nonce_field( 'post_update', '_wpnonce_post_update' ); ?>
+	<?php do_action( 'bp_after_activity_post_form' ); ?>
+
+</form><!-- #whats-new-form -->
Index: /tags/1.9/bp-templates/bp-legacy/buddypress/activity/single/home.php
===================================================================
--- /tags/1.9/bp-templates/bp-legacy/buddypress/activity/single/home.php	(revision 7684)
+++ /tags/1.9/bp-templates/bp-legacy/buddypress/activity/single/home.php	(revision 7684)
@@ -0,0 +1,17 @@
+<div id="buddypress">
+	<?php do_action( 'template_notices' ); ?>
+
+	<div class="activity no-ajax" role="main">
+		<?php if ( bp_has_activities( 'display_comments=threaded&show_hidden=true&include=' . bp_current_action() ) ) : ?>
+
+			<ul id="activity-stream" class="activity-list item-list">
+			<?php while ( bp_activities() ) : bp_the_activity(); ?>
+
+				<?php bp_get_template_part( 'activity/entry' ); ?>
+
+			<?php endwhile; ?>
+			</ul>
+
+		<?php endif; ?>
+	</div>
+</div>
Index: /tags/1.9/bp-templates/bp-legacy/buddypress/blogs/blogs-loop.php
===================================================================
--- /tags/1.9/bp-templates/bp-legacy/buddypress/blogs/blogs-loop.php	(revision 7684)
+++ /tags/1.9/bp-templates/bp-legacy/buddypress/blogs/blogs-loop.php	(revision 7684)
@@ -0,0 +1,95 @@
+<?php
+
+/**
+ * BuddyPress - Blogs Loop
+ *
+ * Querystring is set via AJAX in _inc/ajax.php - bp_legacy_theme_object_filter()
+ *
+ * @package BuddyPress
+ * @subpackage bp-legacy
+ */
+
+?>
+
+<?php do_action( 'bp_before_blogs_loop' ); ?>
+
+<?php if ( bp_has_blogs( bp_ajax_querystring( 'blogs' ) ) ) : ?>
+
+	<div id="pag-top" class="pagination">
+
+		<div class="pag-count" id="blog-dir-count-top">
+			<?php bp_blogs_pagination_count(); ?>
+		</div>
+
+		<div class="pagination-links" id="blog-dir-pag-top">
+			<?php bp_blogs_pagination_links(); ?>
+		</div>
+
+	</div>
+
+	<?php do_action( 'bp_before_directory_blogs_list' ); ?>
+
+	<ul id="blogs-list" class="item-list" role="main">
+
+	<?php while ( bp_blogs() ) : bp_the_blog(); ?>
+
+		<li>
+			<div class="item-avatar">
+				<a href="<?php bp_blog_permalink(); ?>"><?php bp_blog_avatar( 'type=thumb' ); ?></a>
+			</div>
+
+			<div class="item">
+				<div class="item-title"><a href="<?php bp_blog_permalink(); ?>"><?php bp_blog_name(); ?></a></div>
+				<div class="item-meta"><span class="activity"><?php bp_blog_last_active(); ?></span></div>
+
+				<?php do_action( 'bp_directory_blogs_item' ); ?>
+			</div>
+
+			<div class="action">
+
+				<?php do_action( 'bp_directory_blogs_actions' ); ?>
+
+				<div class="meta">
+
+					<?php bp_blog_latest_post(); ?>
+
+				</div>
+
+			</div>
+
+			<div class="clear"></div>
+		</li>
+
+	<?php endwhile; ?>
+
+	</ul>
+
+	<?php do_action( 'bp_after_directory_blogs_list' ); ?>
+
+	<?php bp_blog_hidden_fields(); ?>
+
+	<div id="pag-bottom" class="pagination">
+
+		<div class="pag-count" id="blog-dir-count-bottom">
+
+			<?php bp_blogs_pagination_count(); ?>
+
+		</div>
+
+		<div class="pagination-links" id="blog-dir-pag-bottom">
+
+			<?php bp_blogs_pagination_links(); ?>
+
+		</div>
+
+	</div>
+
+<?php else: ?>
+
+	<div id="message" class="info">
+		<p><?php _e( 'Sorry, there were no sites found.', 'buddypress' ); ?></p>
+	</div>
+
+<?php endif; ?>
+
+<?php do_action( 'bp_after_blogs_loop' ); ?>
Index: /tags/1.9/bp-templates/bp-legacy/buddypress/blogs/create.php
===================================================================
--- /tags/1.9/bp-templates/bp-legacy/buddypress/blogs/create.php	(revision 7684)
+++ /tags/1.9/bp-templates/bp-legacy/buddypress/blogs/create.php	(revision 7684)
@@ -0,0 +1,21 @@
+<?php do_action( 'bp_before_create_blog_content_template' ); ?>
+
+<?php do_action( 'template_notices' ); ?>
+
+<?php do_action( 'bp_before_create_blog_content' ); ?>
+
+<?php if ( bp_blog_signup_enabled() ) : ?>
+
+	<?php bp_show_blog_signup_form(); ?>
+
+<?php else: ?>
+
+	<div id="message" class="info">
+		<p><?php _e( 'Site registration is currently disabled', 'buddypress' ); ?></p>
+	</div>
+
+<?php endif; ?>
+
+<?php do_action( 'bp_after_create_blog_content' ); ?>
+
+<?php do_action( 'bp_after_create_blog_content_template' ); ?>
Index: /tags/1.9/bp-templates/bp-legacy/buddypress/blogs/index.php
===================================================================
--- /tags/1.9/bp-templates/bp-legacy/buddypress/blogs/index.php	(revision 7684)
+++ /tags/1.9/bp-templates/bp-legacy/buddypress/blogs/index.php	(revision 7684)
@@ -0,0 +1,65 @@
+<?php do_action( 'bp_before_directory_blogs' ); ?>
+
+<div id="buddypress">
+	<form action="" method="post" id="blogs-directory-form" class="dir-form">
+
+		<?php do_action( 'bp_before_directory_blogs_content' ); ?>
+
+		<div id="blog-dir-search" class="dir-search" role="search">
+
+			<?php bp_directory_blogs_search_form(); ?>
+
+		</div><!-- #blog-dir-search -->
+
+		<div class="item-list-tabs" role="navigation">
+			<ul>
+				<li class="selected" id="blogs-all"><a href="<?php bp_root_domain(); ?>/<?php bp_blogs_root_slug(); ?>"><?php printf( __( 'All Sites <span>%s</span>', 'buddypress' ), bp_get_total_blog_count() ); ?></a></li>
+
+				<?php if ( is_user_logged_in() && bp_get_total_blog_count_for_user( bp_loggedin_user_id() ) ) : ?>
+
+					<li id="blogs-personal"><a href="<?php echo bp_loggedin_user_domain() . bp_get_blogs_slug(); ?>"><?php printf( __( 'My Sites <span>%s</span>', 'buddypress' ), bp_get_total_blog_count_for_user( bp_loggedin_user_id() ) ); ?></a></li>
+
+				<?php endif; ?>
+
+				<?php do_action( 'bp_blogs_directory_blog_types' ); ?>
+
+			</ul>
+		</div><!-- .item-list-tabs -->
+
+		<div class="item-list-tabs" id="subnav" role="navigation">
+			<ul>
+
+				<?php do_action( 'bp_blogs_directory_blog_sub_types' ); ?>
+
+				<li id="blogs-order-select" class="last filter">
+
+					<label for="blogs-order-by"><?php _e( 'Order By:', 'buddypress' ); ?></label>
+					<select id="blogs-order-by">
+						<option value="active"><?php _e( 'Last Active', 'buddypress' ); ?></option>
+						<option value="newest"><?php _e( 'Newest', 'buddypress' ); ?></option>
+						<option value="alphabetical"><?php _e( 'Alphabetical', 'buddypress' ); ?></option>
+
+						<?php do_action( 'bp_blogs_directory_order_options' ); ?>
+
+					</select>
+				</li>
+			</ul>
+		</div>
+
+		<div id="blogs-dir-list" class="blogs dir-list">
+
+			<?php bp_get_template_part( 'blogs/blogs-loop' ); ?>
+
+		</div><!-- #blogs-dir-list -->
+
+		<?php do_action( 'bp_directory_blogs_content' ); ?>
+
+		<?php wp_nonce_field( 'directory_blogs', '_wpnonce-blogs-filter' ); ?>
+
+		<?php do_action( 'bp_after_directory_blogs_content' ); ?>
+
+	</form><!-- #blogs-directory-form -->
+
+	<?php do_action( 'bp_after_directory_blogs' ); ?>
+
+</div>
Index: /tags/1.9/bp-templates/bp-legacy/buddypress/forums/forums-loop.php
===================================================================
--- /tags/1.9/bp-templates/bp-legacy/buddypress/forums/forums-loop.php	(revision 7684)
+++ /tags/1.9/bp-templates/bp-legacy/buddypress/forums/forums-loop.php	(revision 7684)
@@ -0,0 +1,127 @@
+<?php
+
+/**
+ * BuddyPress - Forums Loop
+ *
+ * Querystring is set via AJAX in _inc/ajax.php - bp_legacy_theme_object_filter()
+ *
+ * @package BuddyPress
+ * @subpackage bp-legacy
+ */
+
+?>
+
+<?php do_action( 'bp_before_forums_loop' ); ?>
+
+<?php if ( bp_has_forum_topics( bp_ajax_querystring( 'forums' ) ) ) : ?>
+
+	<div id="pag-top" class="pagination">
+
+		<div class="pag-count" id="topic-count-top">
+
+			<?php bp_forum_pagination_count(); ?>
+
+		</div>
+
+		<div class="pagination-links" id="topic-pag-top">
+
+			<?php bp_forum_pagination(); ?>
+
+		</div>
+
+	</div>
+
+	<?php do_action( 'bp_before_directory_forums_list' ); ?>
+
+	<table class="forum">
+		<thead>
+			<tr>
+				<th id="th-title"><?php _e( 'Topic', 'buddypress' ); ?></th>
+				<th id="th-postcount"><?php _e( 'Posts', 'buddypress' ); ?></th>
+				<th id="th-freshness"><?php _e( 'Freshness', 'buddypress' ); ?></th>
+
+				<?php do_action( 'bp_directory_forums_extra_cell_head' ); ?>
+
+			</tr>
+		</thead>
+
+		<tbody>
+
+			<?php while ( bp_forum_topics() ) : bp_the_forum_topic(); ?>
+
+			<tr class="<?php bp_the_topic_css_class(); ?>">
+				<td class="td-title">
+					<a class="topic-title" href="<?php bp_the_topic_permalink(); ?>" title="<?php _e( 'Permanent link to this post', 'buddypress' ); ?>">
+
+						<?php bp_the_topic_title(); ?>
+
+					</a>
+
+					<p class="topic-meta">
+						<span class="topic-by"><?php /* translators: "started by [poster] in [forum]" */ printf( __( 'Started by %1$s', 'buddypress' ), bp_get_the_topic_poster_avatar( 'height=20&width=20') . bp_get_the_topic_poster_name() ); ?></span>
+
+						<?php if ( !bp_is_group_forum() ) : ?>
+
+							<span class="topic-in">
+
+								<?php
+									$topic_in = '<a href="' . bp_get_the_topic_object_permalink() . '">' . bp_get_the_topic_object_avatar( 'type=thumb&width=20&height=20' ) . '</a>' .
+													'<a href="' . bp_get_the_topic_object_permalink() . '" title="' . bp_get_the_topic_object_name() . '">' . bp_get_the_topic_object_name() .'</a>';
+
+									/* translators: "started by [poster] in [forum]" */
+									printf( __( 'in %1$s', 'buddypress' ), $topic_in );
+								?>
+
+							</span>
+
+						<?php endif; ?>
+
+					</p>
+				</td>
+				<td class="td-postcount">
+					<?php bp_the_topic_total_posts(); ?>
+				</td>
+				<td class="td-freshness">
+					<span class="time-since"><?php bp_the_topic_time_since_last_post(); ?></span>
+					<p class="topic-meta">
+						<span class="freshness-author">
+							<a href="<?php bp_the_topic_permalink(); ?>"><?php bp_the_topic_last_poster_avatar( 'type=thumb&width=20&height=20' ); ?></a>
+							<?php bp_the_topic_last_poster_name(); ?>
+						</span>
+					</p>
+				</td>
+
+				<?php do_action( 'bp_directory_forums_extra_cell' ); ?>
+
+			</tr>
+
+			<?php do_action( 'bp_directory_forums_extra_row' ); ?>
+
+			<?php endwhile; ?>
+
+		</tbody>
+	</table>
+
+	<?php do_action( 'bp_after_directory_forums_list' ); ?>
+
+	<div id="pag-bottom" class="pagination">
+
+		<div class="pag-count" id="topic-count-bottom">
+			<?php bp_forum_pagination_count(); ?>
+		</div>
+
+		<div class="pagination-links" id="topic-pag-bottom">
+			<?php bp_forum_pagination(); ?>
+		</div>
+
+	</div>
+
+<?php else: ?>
+
+	<div id="message" class="info">
+		<p><?php _e( 'Sorry, there were no forum topics found.', 'buddypress' ); ?></p>
+	</div>
+
+<?php endif; ?>
+
+<?php do_action( 'bp_after_forums_loop' ); ?>
Index: /tags/1.9/bp-templates/bp-legacy/buddypress/forums/index.php
===================================================================
--- /tags/1.9/bp-templates/bp-legacy/buddypress/forums/index.php	(revision 7684)
+++ /tags/1.9/bp-templates/bp-legacy/buddypress/forums/index.php	(revision 7684)
@@ -0,0 +1,140 @@
+<div id="buddypress">
+	
+	<?php do_action( 'bp_before_directory_forums' ); ?>
+
+	<form action="" method="post" id="forums-search-form" class="dir-form">
+
+		<?php do_action( 'bp_before_directory_forums_content' ); ?>
+
+		<div id="forums-dir-search" class="dir-search" role="search">
+
+			<?php bp_directory_forums_search_form(); ?>
+
+		</div>
+	</form>
+
+	<?php do_action( 'bp_before_topics' ); ?>
+
+	<form action="" method="post" id="forums-directory-form" class="dir-form">
+
+		<div class="item-list-tabs" role="navigation">
+			<ul>
+				<li class="selected" id="forums-all"><a href="<?php echo trailingslashit( bp_get_root_domain() . '/' . bp_get_forums_root_slug() ); ?>"><?php printf( __( 'All Topics <span>%s</span>', 'buddypress' ), bp_get_forum_topic_count() ); ?></a></li>
+
+				<?php if ( is_user_logged_in() && bp_get_forum_topic_count_for_user( bp_loggedin_user_id() ) ) : ?>
+
+					<li id="forums-personal"><a href="<?php echo trailingslashit( bp_loggedin_user_domain() . bp_get_forums_slug() . '/topics' ); ?>"><?php printf( __( 'My Topics <span>%s</span>', 'buddypress' ), bp_get_forum_topic_count_for_user( bp_loggedin_user_id() ) ); ?></a></li>
+
+				<?php endif; ?>
+
+				<?php do_action( 'bp_forums_directory_group_types' ); ?>
+
+			</ul>
+		</div>
+
+		<div class="item-list-tabs" id="subnav" role="navigation">
+			<ul>
+
+				<?php do_action( 'bp_forums_directory_group_sub_types' ); ?>
+
+				<li id="forums-order-select" class="last filter">
+
+					<label for="forums-order-by"><?php _e( 'Order By:', 'buddypress' ); ?></label>
+					<select id="forums-order-by">
+						<option value="active"><?php _e( 'Last Active', 'buddypress' ); ?></option>
+						<option value="popular"><?php _e( 'Most Posts', 'buddypress' ); ?></option>
+						<option value="unreplied"><?php _e( 'Unreplied', 'buddypress' ); ?></option>
+
+						<?php do_action( 'bp_forums_directory_order_options' ); ?>
+
+					</select>
+				</li>
+			</ul>
+		</div>
+
+		<div id="forums-dir-list" class="forums dir-list" role="main">
+
+			<?php bp_get_template_part( 'forums/forums-loop' ); ?>
+
+		</div>
+
+		<?php do_action( 'bp_directory_forums_content' ); ?>
+
+		<?php wp_nonce_field( 'directory_forums', '_wpnonce-forums-filter' ); ?>
+
+	</form>
+
+	<?php do_action( 'bp_after_directory_forums' ); ?>
+
+	<?php do_action( 'bp_before_new_topic_form' ); ?>
+
+	<div id="new-topic-post">
+
+		<?php if ( is_user_logged_in() ) : ?>
+
+			<?php if ( bp_is_active( 'groups' ) && bp_has_groups( 'user_id=' . bp_loggedin_user_id() . '&type=alphabetical&max=100&per_page=100' ) ) : ?>
+
+				<form action="" method="post" id="forum-topic-form" class="standard-form">
+
+					<?php do_action( 'groups_forum_new_topic_before' ); ?>
+
+					<a name="post-new"></a>
+					<h5><?php _e( 'Create New Topic:', 'buddypress' ); ?></h5>
+
+					<?php do_action( 'template_notices' ); ?>
+
+					<label><?php _e( 'Title:', 'buddypress' ); ?></label>
+					<input type="text" name="topic_title" id="topic_title" value="" maxlength="100" />
+
+					<label><?php _e( 'Content:', 'buddypress' ); ?></label>
+					<textarea name="topic_text" id="topic_text"></textarea>
+
+					<label><?php _e( 'Tags (comma separated):', 'buddypress' ); ?></label>
+					<input type="text" name="topic_tags" id="topic_tags" value="" />
+
+					<label><?php _e( 'Post In Group Forum:', 'buddypress' ); ?></label>
+					<select id="topic_group_id" name="topic_group_id">
+
+						<option value=""><?php /* translators: no option picked in select box */ _e( '----', 'buddypress' ); ?></option>
+
+						<?php while ( bp_groups() ) : bp_the_group(); ?>
+
+							<?php if ( bp_group_is_forum_enabled() && ( bp_current_user_can( 'bp_moderate' ) || 'public' == bp_get_group_status() || bp_group_is_member() ) ) : ?>
+
+								<option value="<?php bp_group_id(); ?>"><?php bp_group_name(); ?></option>
+
+							<?php endif; ?>
+
+						<?php endwhile; ?>
+
+					</select><!-- #topic_group_id -->
+
+					<?php do_action( 'groups_forum_new_topic_after' ); ?>
+
+					<div class="submit">
+						<input type="submit" name="submit_topic" id="submit" value="<?php _e( 'Post Topic', 'buddypress' ); ?>" />
+						<input type="button" name="submit_topic_cancel" id="submit_topic_cancel" value="<?php _e( 'Cancel', 'buddypress' ); ?>" />
+					</div>
+
+					<?php wp_nonce_field( 'bp_forums_new_topic' ); ?>
+
+				</form><!-- #forum-topic-form -->
+
+			<?php elseif ( bp_is_active( 'groups' ) ) : ?>
+
+				<div id="message" class="info">
+
+					<p><?php printf( __( "You are not a member of any groups so you don't have any group forums you can post in. To start posting, first find a group that matches the topic subject you'd like to start. If this group does not exist, why not <a href='%s'>create a new group</a>? Once you have joined or created the group you can post your topic in that group's forum.", 'buddypress' ), site_url( bp_get_groups_root_slug() . '/create/' ) ); ?></p>
+
+				</div>
+
+			<?php endif; ?>
+
+		<?php endif; ?>
+	</div><!-- #new-topic-post -->
+
+	<?php do_action( 'bp_after_new_topic_form' ); ?>
+
+	<?php do_action( 'bp_after_directory_forums_content' ); ?>
+	
+</div>
Index: /tags/1.9/bp-templates/bp-legacy/buddypress/groups/create.php
===================================================================
--- /tags/1.9/bp-templates/bp-legacy/buddypress/groups/create.php	(revision 7684)
+++ /tags/1.9/bp-templates/bp-legacy/buddypress/groups/create.php	(revision 7684)
@@ -0,0 +1,306 @@
+<?php do_action( 'bp_before_create_group_page' ); ?>
+
+<div id="buddypress">
+
+	<?php do_action( 'bp_before_create_group_content_template' ); ?>
+
+	<form action="<?php bp_group_creation_form_action(); ?>" method="post" id="create-group-form" class="standard-form" enctype="multipart/form-data">
+
+		<?php do_action( 'bp_before_create_group' ); ?>
+
+		<div class="item-list-tabs no-ajax" id="group-create-tabs" role="navigation">
+			<ul>
+
+				<?php bp_group_creation_tabs(); ?>
+
+			</ul>
+		</div>
+
+		<?php do_action( 'template_notices' ); ?>
+
+		<div class="item-body" id="group-create-body">
+
+			<?php /* Group creation step 1: Basic group details */ ?>
+			<?php if ( bp_is_group_creation_step( 'group-details' ) ) : ?>
+
+				<?php do_action( 'bp_before_group_details_creation_step' ); ?>
+
+				<div>
+					<label for="group-name"><?php _e( 'Group Name (required)', 'buddypress' ); ?></label>
+					<input type="text" name="group-name" id="group-name" aria-required="true" value="<?php bp_new_group_name(); ?>" />
+				</div>
+
+				<div>
+					<label for="group-desc"><?php _e( 'Group Description (required)', 'buddypress' ); ?></label>
+					<textarea name="group-desc" id="group-desc" aria-required="true"><?php bp_new_group_description(); ?></textarea>
+				</div>
+
+				<?php
+				do_action( 'bp_after_group_details_creation_step' );
+				do_action( 'groups_custom_group_fields_editable' ); // @Deprecated
+
+				wp_nonce_field( 'groups_create_save_group-details' ); ?>
+
+			<?php endif; ?>
+
+			<?php /* Group creation step 2: Group settings */ ?>
+			<?php if ( bp_is_group_creation_step( 'group-settings' ) ) : ?>
+
+				<?php do_action( 'bp_before_group_settings_creation_step' ); ?>
+
+				<h4><?php _e( 'Privacy Options', 'buddypress' ); ?></h4>
+
+				<div class="radio">
+					<label><input type="radio" name="group-status" value="public"<?php if ( 'public' == bp_get_new_group_status() || !bp_get_new_group_status() ) { ?> checked="checked"<?php } ?> />
+						<strong><?php _e( 'This is a public group', 'buddypress' ); ?></strong>
+						<ul>
+							<li><?php _e( 'Any site member can join this group.', 'buddypress' ); ?></li>
+							<li><?php _e( 'This group will be listed in the groups directory and in search results.', 'buddypress' ); ?></li>
+							<li><?php _e( 'Group content and activity will be visible to any site member.', 'buddypress' ); ?></li>
+						</ul>
+					</label>
+
+					<label><input type="radio" name="group-status" value="private"<?php if ( 'private' == bp_get_new_group_status() ) { ?> checked="checked"<?php } ?> />
+						<strong><?php _e( 'This is a private group', 'buddypress' ); ?></strong>
+						<ul>
+							<li><?php _e( 'Only users who request membership and are accepted can join the group.', 'buddypress' ); ?></li>
+							<li><?php _e( 'This group will be listed in the groups directory and in search results.', 'buddypress' ); ?></li>
+							<li><?php _e( 'Group content and activity will only be visible to members of the group.', 'buddypress' ); ?></li>
+						</ul>
+					</label>
+
+					<label><input type="radio" name="group-status" value="hidden"<?php if ( 'hidden' == bp_get_new_group_status() ) { ?> checked="checked"<?php } ?> />
+						<strong><?php _e('This is a hidden group', 'buddypress' ); ?></strong>
+						<ul>
+							<li><?php _e( 'Only users who are invited can join the group.', 'buddypress' ); ?></li>
+							<li><?php _e( 'This group will not be listed in the groups directory or search results.', 'buddypress' ); ?></li>
+							<li><?php _e( 'Group content and activity will only be visible to members of the group.', 'buddypress' ); ?></li>
+						</ul>
+					</label>
+				</div>
+
+				<h4><?php _e( 'Group Invitations', 'buddypress' ); ?></h4>
+
+				<p><?php _e( 'Which members of this group are allowed to invite others?', 'buddypress' ); ?></p>
+
+				<div class="radio">
+					<label>
+						<input type="radio" name="group-invite-status" value="members"<?php bp_group_show_invite_status_setting( 'members' ); ?> />
+						<strong><?php _e( 'All group members', 'buddypress' ); ?></strong>
+					</label>
+
+					<label>
+						<input type="radio" name="group-invite-status" value="mods"<?php bp_group_show_invite_status_setting( 'mods' ); ?> />
+						<strong><?php _e( 'Group admins and mods only', 'buddypress' ); ?></strong>
+					</label>
+
+					<label>
+						<input type="radio" name="group-invite-status" value="admins"<?php bp_group_show_invite_status_setting( 'admins' ); ?> />
+						<strong><?php _e( 'Group admins only', 'buddypress' ); ?></strong>
+					</label>
+				</div>
+
+				<?php if ( bp_is_active( 'forums' ) ) : ?>
+
+					<h4><?php _e( 'Group Forums', 'buddypress' ); ?></h4>
+
+					<?php if ( bp_forums_is_installed_correctly() ) : ?>
+
+						<p><?php _e( 'Should this group have a forum?', 'buddypress' ); ?></p>
+
+						<div class="checkbox">
+							<label><input type="checkbox" name="group-show-forum" id="group-show-forum" value="1"<?php checked( bp_get_new_group_enable_forum(), true, true ); ?> /> <?php _e( 'Enable discussion forum', 'buddypress' ); ?></label>
+						</div>
+					<?php elseif ( is_super_admin() ) : ?>
+
+						<p><?php printf( __( '<strong>Attention Site Admin:</strong> Group forums require the <a href="%s">correct setup and configuration</a> of a bbPress installation.', 'buddypress' ), bp_core_do_network_admin() ? network_admin_url( 'settings.php?page=bb-forums-setup' ) :  admin_url( 'admin.php?page=bb-forums-setup' ) ); ?></p>
+
+					<?php endif; ?>
+
+				<?php endif; ?>
+
+				<?php do_action( 'bp_after_group_settings_creation_step' ); ?>
+
+				<?php wp_nonce_field( 'groups_create_save_group-settings' ); ?>
+
+			<?php endif; ?>
+
+			<?php /* Group creation step 3: Avatar Uploads */ ?>
+			<?php if ( bp_is_group_creation_step( 'group-avatar' ) ) : ?>
+
+				<?php do_action( 'bp_before_group_avatar_creation_step' ); ?>
+
+				<?php if ( 'upload-image' == bp_get_avatar_admin_step() ) : ?>
+
+					<div class="left-menu">
+
+						<?php bp_new_group_avatar(); ?>
+
+					</div><!-- .left-menu -->
+
+					<div class="main-column">
+						<p><?php _e( "Upload an image to use as an avatar for this group. The image will be shown on the main group page, and in search results.", 'buddypress' ); ?></p>
+
+						<p>
+							<input type="file" name="file" id="file" />
+							<input type="submit" name="upload" id="upload" value="<?php _e( 'Upload Image', 'buddypress' ); ?>" />
+							<input type="hidden" name="action" id="action" value="bp_avatar_upload" />
+						</p>
+
+						<p><?php _e( 'To skip the avatar upload process, hit the "Next Step" button.', 'buddypress' ); ?></p>
+					</div><!-- .main-column -->
+
+				<?php endif; ?>
+
+				<?php if ( 'crop-image' == bp_get_avatar_admin_step() ) : ?>
+
+					<h4><?php _e( 'Crop Group Avatar', 'buddypress' ); ?></h4>
+
+					<img src="<?php bp_avatar_to_crop(); ?>" id="avatar-to-crop" class="avatar" alt="<?php _e( 'Avatar to crop', 'buddypress' ); ?>" />
+
+					<div id="avatar-crop-pane">
+						<img src="<?php bp_avatar_to_crop(); ?>" id="avatar-crop-preview" class="avatar" alt="<?php _e( 'Avatar preview', 'buddypress' ); ?>" />
+					</div>
+
+					<input type="submit" name="avatar-crop-submit" id="avatar-crop-submit" value="<?php _e( 'Crop Image', 'buddypress' ); ?>" />
+
+					<input type="hidden" name="image_src" id="image_src" value="<?php bp_avatar_to_crop_src(); ?>" />
+					<input type="hidden" name="upload" id="upload" />
+					<input type="hidden" id="x" name="x" />
+					<input type="hidden" id="y" name="y" />
+					<input type="hidden" id="w" name="w" />
+					<input type="hidden" id="h" name="h" />
+
+				<?php endif; ?>
+
+				<?php do_action( 'bp_after_group_avatar_creation_step' ); ?>
+
+				<?php wp_nonce_field( 'groups_create_save_group-avatar' ); ?>
+
+			<?php endif; ?>
+
+			<?php /* Group creation step 4: Invite friends to group */ ?>
+			<?php if ( bp_is_group_creation_step( 'group-invites' ) ) : ?>
+
+				<?php do_action( 'bp_before_group_invites_creation_step' ); ?>
+
+				<?php if ( bp_is_active( 'friends' ) && bp_get_total_friend_count( bp_loggedin_user_id() ) ) : ?>
+
+					<div class="left-menu">
+
+						<div id="invite-list">
+							<ul>
+								<?php bp_new_group_invite_friend_list(); ?>
+							</ul>
+
+							<?php wp_nonce_field( 'groups_invite_uninvite_user', '_wpnonce_invite_uninvite_user' ); ?>
+						</div>
+
+					</div><!-- .left-menu -->
+
+					<div class="main-column">
+
+						<div id="message" class="info">
+							<p><?php _e('Select people to invite from your friends list.', 'buddypress' ); ?></p>
+						</div>
+
+						<?php /* The ID 'friend-list' is important for AJAX support. */ ?>
+						<ul id="friend-list" class="item-list" role="main">
+
+						<?php if ( bp_group_has_invites() ) : ?>
+
+							<?php while ( bp_group_invites() ) : bp_group_the_invite(); ?>
+
+								<li id="<?php bp_group_invite_item_id(); ?>">
+
+									<?php bp_group_invite_user_avatar(); ?>
+
+									<h4><?php bp_group_invite_user_link(); ?></h4>
+									<span class="activity"><?php bp_group_invite_user_last_active(); ?></span>
+
+									<div class="action">
+										<a class="remove" href="<?php bp_group_invite_user_remove_invite_url(); ?>" id="<?php bp_group_invite_item_id(); ?>"><?php _e( 'Remove Invite', 'buddypress' ); ?></a>
+									</div>
+								</li>
+
+							<?php endwhile; ?>
+
+							<?php wp_nonce_field( 'groups_send_invites', '_wpnonce_send_invites' ); ?>
+
+						<?php endif; ?>
+
+						</ul>
+
+					</div><!-- .main-column -->
+
+				<?php else : ?>
+
+					<div id="message" class="info">
+						<p><?php _e( 'Once you have built up friend connections you will be able to invite others to your group.', 'buddypress' ); ?></p>
+					</div>
+
+				<?php endif; ?>
+
+				<?php wp_nonce_field( 'groups_create_save_group-invites' ); ?>
+
+				<?php do_action( 'bp_after_group_invites_creation_step' ); ?>
+
+			<?php endif; ?>
+
+			<?php do_action( 'groups_custom_create_steps' ); // Allow plugins to add custom group creation steps ?>
+
+			<?php do_action( 'bp_before_group_creation_step_buttons' ); ?>
+
+			<?php if ( 'crop-image' != bp_get_avatar_admin_step() ) : ?>
+
+				<div class="submit" id="previous-next">
+
+					<?php /* Previous Button */ ?>
+					<?php if ( !bp_is_first_group_creation_step() ) : ?>
+
+						<input type="button" value="<?php _e( 'Back to Previous Step', 'buddypress' ); ?>" id="group-creation-previous" name="previous" onclick="location.href='<?php bp_group_creation_previous_link(); ?>'" />
+
+					<?php endif; ?>
+
+					<?php /* Next Button */ ?>
+					<?php if ( !bp_is_last_group_creation_step() && !bp_is_first_group_creation_step() ) : ?>
+
+						<input type="submit" value="<?php _e( 'Next Step', 'buddypress' ); ?>" id="group-creation-next" name="save" />
+
+					<?php endif;?>
+
+					<?php /* Create Button */ ?>
+					<?php if ( bp_is_first_group_creation_step() ) : ?>
+
+						<input type="submit" value="<?php _e( 'Create Group and Continue', 'buddypress' ); ?>" id="group-creation-create" name="save" />
+
+					<?php endif; ?>
+
+					<?php /* Finish Button */ ?>
+					<?php if ( bp_is_last_group_creation_step() ) : ?>
+
+						<input type="submit" value="<?php _e( 'Finish', 'buddypress' ); ?>" id="group-creation-finish" name="save" />
+
+					<?php endif; ?>
+				</div>
+
+			<?php endif;?>
+
+			<?php do_action( 'bp_after_group_creation_step_buttons' ); ?>
+
+			<?php /* Don't leave out this hidden field */ ?>
+			<input type="hidden" name="group_id" id="group_id" value="<?php bp_new_group_id(); ?>" />
+
+			<?php do_action( 'bp_directory_groups_content' ); ?>
+
+		</div><!-- .item-body -->
+
+		<?php do_action( 'bp_after_create_group' ); ?>
+
+	</form>
+
+	<?php do_action( 'bp_after_create_group_content_template' ); ?>
+
+</div>
+
+<?php do_action( 'bp_after_create_group_page' ); ?>
Index: /tags/1.9/bp-templates/bp-legacy/buddypress/groups/groups-loop.php
===================================================================
--- /tags/1.9/bp-templates/bp-legacy/buddypress/groups/groups-loop.php	(revision 7684)
+++ /tags/1.9/bp-templates/bp-legacy/buddypress/groups/groups-loop.php	(revision 7684)
@@ -0,0 +1,100 @@
+<?php
+
+/**
+ * BuddyPress - Groups Loop
+ *
+ * Querystring is set via AJAX in _inc/ajax.php - bp_legacy_theme_object_filter()
+ *
+ * @package BuddyPress
+ * @subpackage bp-legacy
+ */
+
+?>
+
+<?php do_action( 'bp_before_groups_loop' ); ?>
+
+<?php if ( bp_has_groups( bp_ajax_querystring( 'groups' ) ) ) : ?>
+
+	<div id="pag-top" class="pagination">
+
+		<div class="pag-count" id="group-dir-count-top">
+
+			<?php bp_groups_pagination_count(); ?>
+
+		</div>
+
+		<div class="pagination-links" id="group-dir-pag-top">
+
+			<?php bp_groups_pagination_links(); ?>
+
+		</div>
+
+	</div>
+
+	<?php do_action( 'bp_before_directory_groups_list' ); ?>
+
+	<ul id="groups-list" class="item-list" role="main">
+
+	<?php while ( bp_groups() ) : bp_the_group(); ?>
+
+		<li <?php bp_group_class(); ?>>
+			<div class="item-avatar">
+				<a href="<?php bp_group_permalink(); ?>"><?php bp_group_avatar( 'type=thumb&width=50&height=50' ); ?></a>
+			</div>
+
+			<div class="item">
+				<div class="item-title"><a href="<?php bp_group_permalink(); ?>"><?php bp_group_name(); ?></a></div>
+				<div class="item-meta"><span class="activity"><?php printf( __( 'active %s', 'buddypress' ), bp_get_group_last_active() ); ?></span></div>
+
+				<div class="item-desc"><?php bp_group_description_excerpt(); ?></div>
+
+				<?php do_action( 'bp_directory_groups_item' ); ?>
+
+			</div>
+
+			<div class="action">
+
+				<?php do_action( 'bp_directory_groups_actions' ); ?>
+
+				<div class="meta">
+
+					<?php bp_group_type(); ?> / <?php bp_group_member_count(); ?>
+
+				</div>
+
+			</div>
+
+			<div class="clear"></div>
+		</li>
+
+	<?php endwhile; ?>
+
+	</ul>
+
+	<?php do_action( 'bp_after_directory_groups_list' ); ?>
+
+	<div id="pag-bottom" class="pagination">
+
+		<div class="pag-count" id="group-dir-count-bottom">
+
+			<?php bp_groups_pagination_count(); ?>
+
+		</div>
+
+		<div class="pagination-links" id="group-dir-pag-bottom">
+
+			<?php bp_groups_pagination_links(); ?>
+
+		</div>
+
+	</div>
+
+<?php else: ?>
+
+	<div id="message" class="info">
+		<p><?php _e( 'There were no groups found.', 'buddypress' ); ?></p>
+	</div>
+
+<?php endif; ?>
+
+<?php do_action( 'bp_after_groups_loop' ); ?>
Index: /tags/1.9/bp-templates/bp-legacy/buddypress/groups/index.php
===================================================================
--- /tags/1.9/bp-templates/bp-legacy/buddypress/groups/index.php	(revision 7684)
+++ /tags/1.9/bp-templates/bp-legacy/buddypress/groups/index.php	(revision 7684)
@@ -0,0 +1,66 @@
+<?php do_action( 'bp_before_directory_groups_page' ); ?>
+
+<div id="buddypress">
+
+	<?php do_action( 'bp_before_directory_groups' ); ?>
+
+	<?php do_action( 'bp_before_directory_groups_content' ); ?>
+
+	<div id="group-dir-search" class="dir-search" role="search">
+		<?php bp_directory_groups_search_form(); ?>
+	</div><!-- #group-dir-search -->
+
+	<form action="" method="post" id="groups-directory-form" class="dir-form">
+
+		<?php do_action( 'template_notices' ); ?>
+
+		<div class="item-list-tabs" role="navigation">
+			<ul>
+				<li class="selected" id="groups-all"><a href="<?php bp_groups_directory_permalink(); ?>"><?php printf( __( 'All Groups <span>%s</span>', 'buddypress' ), bp_get_total_group_count() ); ?></a></li>
+
+				<?php if ( is_user_logged_in() && bp_get_total_group_count_for_user( bp_loggedin_user_id() ) ) : ?>
+					<li id="groups-personal"><a href="<?php echo bp_loggedin_user_domain() . bp_get_groups_slug() . '/my-groups/'; ?>"><?php printf( __( 'My Groups <span>%s</span>', 'buddypress' ), bp_get_total_group_count_for_user( bp_loggedin_user_id() ) ); ?></a></li>
+				<?php endif; ?>
+
+				<?php do_action( 'bp_groups_directory_group_filter' ); ?>
+
+			</ul>
+		</div><!-- .item-list-tabs -->
+
+		<div class="item-list-tabs" id="subnav" role="navigation">
+			<ul>
+				<?php do_action( 'bp_groups_directory_group_types' ); ?>
+
+				<li id="groups-order-select" class="last filter">
+
+					<label for="groups-order-by"><?php _e( 'Order By:', 'buddypress' ); ?></label>
+
+					<select id="groups-order-by">
+						<option value="active"><?php _e( 'Last Active', 'buddypress' ); ?></option>
+						<option value="popular"><?php _e( 'Most Members', 'buddypress' ); ?></option>
+						<option value="newest"><?php _e( 'Newly Created', 'buddypress' ); ?></option>
+						<option value="alphabetical"><?php _e( 'Alphabetical', 'buddypress' ); ?></option>
+
+						<?php do_action( 'bp_groups_directory_order_options' ); ?>
+					</select>
+				</li>
+			</ul>
+		</div>
+
+		<div id="groups-dir-list" class="groups dir-list">
+			<?php bp_get_template_part( 'groups/groups-loop' ); ?>
+		</div><!-- #groups-dir-list -->
+
+		<?php do_action( 'bp_directory_groups_content' ); ?>
+
+		<?php wp_nonce_field( 'directory_groups', '_wpnonce-groups-filter' ); ?>
+
+		<?php do_action( 'bp_after_directory_groups_content' ); ?>
+
+	</form><!-- #groups-directory-form -->
+
+	<?php do_action( 'bp_after_directory_groups' ); ?>
+
+</div><!-- #buddypress -->
+
+<?php do_action( 'bp_after_directory_groups_page' ); ?>
Index: /tags/1.9/bp-templates/bp-legacy/buddypress/groups/single/activity.php
===================================================================
--- /tags/1.9/bp-templates/bp-legacy/buddypress/groups/single/activity.php	(revision 7684)
+++ /tags/1.9/bp-templates/bp-legacy/buddypress/groups/single/activity.php	(revision 7684)
@@ -0,0 +1,43 @@
+<div class="item-list-tabs no-ajax" id="subnav" role="navigation">
+	<ul>
+		<li class="feed"><a href="<?php bp_group_activity_feed_link(); ?>" title="<?php _e( 'RSS Feed', 'buddypress' ); ?>"><?php _e( 'RSS', 'buddypress' ); ?></a></li>
+
+		<?php do_action( 'bp_group_activity_syndication_options' ); ?>
+
+		<li id="activity-filter-select" class="last">
+			<label for="activity-filter-by"><?php _e( 'Show:', 'buddypress' ); ?></label> 
+			<select id="activity-filter-by">
+				<option value="-1"><?php _e( 'Everything', 'buddypress' ); ?></option>
+				<option value="activity_update"><?php _e( 'Updates', 'buddypress' ); ?></option>
+
+				<?php if ( bp_is_active( 'forums' ) ) : ?>
+					<option value="new_forum_topic"><?php _e( 'Forum Topics', 'buddypress' ); ?></option>
+					<option value="new_forum_post"><?php _e( 'Forum Replies', 'buddypress' ); ?></option>
+				<?php endif; ?>
+
+				<option value="joined_group"><?php _e( 'Group Memberships', 'buddypress' ); ?></option>
+
+				<?php do_action( 'bp_group_activity_filter_options' ); ?>
+			</select>
+		</li>
+	</ul>
+</div><!-- .item-list-tabs -->
+
+<?php do_action( 'bp_before_group_activity_post_form' ); ?>
+
+<?php if ( is_user_logged_in() && bp_group_is_member() ) : ?>
+
+	<?php bp_get_template_part( 'activity/post-form' ); ?>
+
+<?php endif; ?>
+
+<?php do_action( 'bp_after_group_activity_post_form' ); ?>
+<?php do_action( 'bp_before_group_activity_content' ); ?>
+
+<div class="activity single-group" role="main">
+
+	<?php bp_get_template_part( 'activity/activity-loop' ); ?>
+
+</div><!-- .activity.single-group -->
+
+<?php do_action( 'bp_after_group_activity_content' ); ?>
Index: /tags/1.9/bp-templates/bp-legacy/buddypress/groups/single/admin.php
===================================================================
--- /tags/1.9/bp-templates/bp-legacy/buddypress/groups/single/admin.php	(revision 7684)
+++ /tags/1.9/bp-templates/bp-legacy/buddypress/groups/single/admin.php	(revision 7684)
@@ -0,0 +1,373 @@
+<div class="item-list-tabs no-ajax" id="subnav" role="navigation">
+	<ul>
+		<?php bp_group_admin_tabs(); ?>
+	</ul>
+</div><!-- .item-list-tabs -->
+
+<form action="<?php bp_group_admin_form_action(); ?>" name="group-settings-form" id="group-settings-form" class="standard-form" method="post" enctype="multipart/form-data" role="main">
+
+<?php do_action( 'bp_before_group_admin_content' ); ?>
+
+<?php /* Edit Group Details */ ?>
+<?php if ( bp_is_group_admin_screen( 'edit-details' ) ) : ?>
+
+	<?php do_action( 'bp_before_group_details_admin' ); ?>
+
+	<label for="group-name"><?php _e( 'Group Name (required)', 'buddypress' ); ?></label>
+	<input type="text" name="group-name" id="group-name" value="<?php bp_group_name(); ?>" aria-required="true" />
+
+	<label for="group-desc"><?php _e( 'Group Description (required)', 'buddypress' ); ?></label>
+	<textarea name="group-desc" id="group-desc" aria-required="true"><?php bp_group_description_editable(); ?></textarea>
+
+	<?php do_action( 'groups_custom_group_fields_editable' ); ?>
+
+	<p>
+		<label for="group-notifiy-members">
+			<input type="checkbox" name="group-notify-members" value="1" /> <?php _e( 'Notify group members of these changes via email', 'buddypress' ); ?>
+		</label>
+	</p>
+
+	<?php do_action( 'bp_after_group_details_admin' ); ?>
+
+	<p><input type="submit" value="<?php _e( 'Save Changes', 'buddypress' ); ?>" id="save" name="save" /></p>
+	<?php wp_nonce_field( 'groups_edit_group_details' ); ?>
+
+<?php endif; ?>
+
+<?php /* Manage Group Settings */ ?>
+<?php if ( bp_is_group_admin_screen( 'group-settings' ) ) : ?>
+
+	<?php do_action( 'bp_before_group_settings_admin' ); ?>
+
+	<?php if ( bp_is_active( 'forums' ) ) : ?>
+
+		<?php if ( bp_forums_is_installed_correctly() ) : ?>
+
+			<div class="checkbox">
+				<label><input type="checkbox" name="group-show-forum" id="group-show-forum" value="1"<?php bp_group_show_forum_setting(); ?> /> <?php _e( 'Enable discussion forum', 'buddypress' ); ?></label>
+			</div>
+
+			<hr />
+
+		<?php endif; ?>
+
+	<?php endif; ?>
+
+	<h4><?php _e( 'Privacy Options', 'buddypress' ); ?></h4>
+
+	<div class="radio">
+		<label>
+			<input type="radio" name="group-status" value="public"<?php bp_group_show_status_setting( 'public' ); ?> />
+			<strong><?php _e( 'This is a public group', 'buddypress' ); ?></strong>
+			<ul>
+				<li><?php _e( 'Any site member can join this group.', 'buddypress' ); ?></li>
+				<li><?php _e( 'This group will be listed in the groups directory and in search results.', 'buddypress' ); ?></li>
+				<li><?php _e( 'Group content and activity will be visible to any site member.', 'buddypress' ); ?></li>
+			</ul>
+		</label>
+
+		<label>
+			<input type="radio" name="group-status" value="private"<?php bp_group_show_status_setting( 'private' ); ?> />
+			<strong><?php _e( 'This is a private group', 'buddypress' ); ?></strong>
+			<ul>
+				<li><?php _e( 'Only users who request membership and are accepted can join the group.', 'buddypress' ); ?></li>
+				<li><?php _e( 'This group will be listed in the groups directory and in search results.', 'buddypress' ); ?></li>
+				<li><?php _e( 'Group content and activity will only be visible to members of the group.', 'buddypress' ); ?></li>
+			</ul>
+		</label>
+
+		<label>
+			<input type="radio" name="group-status" value="hidden"<?php bp_group_show_status_setting( 'hidden' ); ?> />
+			<strong><?php _e( 'This is a hidden group', 'buddypress' ); ?></strong>
+			<ul>
+				<li><?php _e( 'Only users who are invited can join the group.', 'buddypress' ); ?></li>
+				<li><?php _e( 'This group will not be listed in the groups directory or search results.', 'buddypress' ); ?></li>
+				<li><?php _e( 'Group content and activity will only be visible to members of the group.', 'buddypress' ); ?></li>
+			</ul>
+		</label>
+	</div>
+
+	<hr />
+
+	<h4><?php _e( 'Group Invitations', 'buddypress' ); ?></h4>
+
+	<p><?php _e( 'Which members of this group are allowed to invite others?', 'buddypress' ); ?></p>
+
+	<div class="radio">
+		<label>
+			<input type="radio" name="group-invite-status" value="members"<?php bp_group_show_invite_status_setting( 'members' ); ?> />
+			<strong><?php _e( 'All group members', 'buddypress' ); ?></strong>
+		</label>
+
+		<label>
+			<input type="radio" name="group-invite-status" value="mods"<?php bp_group_show_invite_status_setting( 'mods' ); ?> />
+			<strong><?php _e( 'Group admins and mods only', 'buddypress' ); ?></strong>
+		</label>
+
+		<label>
+			<input type="radio" name="group-invite-status" value="admins"<?php bp_group_show_invite_status_setting( 'admins' ); ?> />
+			<strong><?php _e( 'Group admins only', 'buddypress' ); ?></strong>
+		</label>
+ 	</div>
+
+	<hr />
+
+	<?php do_action( 'bp_after_group_settings_admin' ); ?>
+
+	<p><input type="submit" value="<?php _e( 'Save Changes', 'buddypress' ); ?>" id="save" name="save" /></p>
+	<?php wp_nonce_field( 'groups_edit_group_settings' ); ?>
+
+<?php endif; ?>
+
+<?php /* Group Avatar Settings */ ?>
+<?php if ( bp_is_group_admin_screen( 'group-avatar' ) ) : ?>
+
+	<?php if ( 'upload-image' == bp_get_avatar_admin_step() ) : ?>
+
+			<p><?php _e("Upload an image to use as an avatar for this group. The image will be shown on the main group page, and in search results.", 'buddypress' ); ?></p>
+
+			<p>
+				<input type="file" name="file" id="file" />
+				<input type="submit" name="upload" id="upload" value="<?php _e( 'Upload Image', 'buddypress' ); ?>" />
+				<input type="hidden" name="action" id="action" value="bp_avatar_upload" />
+			</p>
+
+			<?php if ( bp_get_group_has_avatar() ) : ?>
+
+				<p><?php _e( "If you'd like to remove the existing avatar but not upload a new one, please use the delete avatar button.", 'buddypress' ); ?></p>
+
+				<?php bp_button( array( 'id' => 'delete_group_avatar', 'component' => 'groups', 'wrapper_id' => 'delete-group-avatar-button', 'link_class' => 'edit', 'link_href' => bp_get_group_avatar_delete_link(), 'link_title' => __( 'Delete Avatar', 'buddypress' ), 'link_text' => __( 'Delete Avatar', 'buddypress' ) ) ); ?>
+
+			<?php endif; ?>
+
+			<?php wp_nonce_field( 'bp_avatar_upload' ); ?>
+
+	<?php endif; ?>
+
+	<?php if ( 'crop-image' == bp_get_avatar_admin_step() ) : ?>
+
+		<h4><?php _e( 'Crop Avatar', 'buddypress' ); ?></h4>
+
+		<img src="<?php bp_avatar_to_crop(); ?>" id="avatar-to-crop" class="avatar" alt="<?php _e( 'Avatar to crop', 'buddypress' ); ?>" />
+
+		<div id="avatar-crop-pane">
+			<img src="<?php bp_avatar_to_crop(); ?>" id="avatar-crop-preview" class="avatar" alt="<?php _e( 'Avatar preview', 'buddypress' ); ?>" />
+		</div>
+
+		<input type="submit" name="avatar-crop-submit" id="avatar-crop-submit" value="<?php _e( 'Crop Image', 'buddypress' ); ?>" />
+
+		<input type="hidden" name="image_src" id="image_src" value="<?php bp_avatar_to_crop_src(); ?>" />
+		<input type="hidden" id="x" name="x" />
+		<input type="hidden" id="y" name="y" />
+		<input type="hidden" id="w" name="w" />
+		<input type="hidden" id="h" name="h" />
+
+		<?php wp_nonce_field( 'bp_avatar_cropstore' ); ?>
+
+	<?php endif; ?>
+
+<?php endif; ?>
+
+<?php /* Manage Group Members */ ?>
+<?php if ( bp_is_group_admin_screen( 'manage-members' ) ) : ?>
+
+	<?php do_action( 'bp_before_group_manage_members_admin' ); ?>
+
+	<div class="bp-widget">
+		<h4><?php _e( 'Administrators', 'buddypress' ); ?></h4>
+
+		<?php if ( bp_has_members( '&include='. bp_group_admin_ids() ) ) : ?>
+
+		<ul id="admins-list" class="item-list single-line">
+
+			<?php while ( bp_members() ) : bp_the_member(); ?>
+			<li>
+				<?php echo bp_core_fetch_avatar( array( 'item_id' => bp_get_member_user_id(), 'type' => 'thumb', 'width' => 30, 'height' => 30, 'alt' => sprintf( __( 'Profile picture of %s', 'buddypress' ), bp_get_member_name() ) ) ); ?>
+				<h5>
+					<a href="<?php bp_member_permalink(); ?>"> <?php bp_member_name(); ?></a>
+					<?php if ( count( bp_group_admin_ids( false, 'array' ) ) > 1 ) : ?>
+					<span class="small">
+						<a class="button confirm admin-demote-to-member" href="<?php bp_group_member_demote_link( bp_get_member_user_id() ); ?>"><?php _e( 'Demote to Member', 'buddypress' ); ?></a>
+					</span>
+					<?php endif; ?>
+				</h5>
+			</li>
+			<?php endwhile; ?>
+
+		</ul>
+
+		<?php endif; ?>
+
+	</div>
+
+	<?php if ( bp_group_has_moderators() ) : ?>
+		<div class="bp-widget">
+			<h4><?php _e( 'Moderators', 'buddypress' ); ?></h4>
+
+			<?php if ( bp_has_members( '&include=' . bp_group_mod_ids() ) ) : ?>
+				<ul id="mods-list" class="item-list single-line">
+
+					<?php while ( bp_members() ) : bp_the_member(); ?>
+					<li>
+						<?php echo bp_core_fetch_avatar( array( 'item_id' => bp_get_member_user_id(), 'type' => 'thumb', 'width' => 30, 'height' => 30, 'alt' => sprintf( __( 'Profile picture of %s', 'buddypress' ), bp_get_member_name() ) ) ); ?>
+						<h5>
+							<a href="<?php bp_member_permalink(); ?>"> <?php bp_member_name(); ?></a>
+							<span class="small">
+								<a href="<?php bp_group_member_promote_admin_link( array( 'user_id' => bp_get_member_user_id() ) ); ?>" class="button confirm mod-promote-to-admin" title="<?php _e( 'Promote to Admin', 'buddypress' ); ?>"><?php _e( 'Promote to Admin', 'buddypress' ); ?></a>
+								<a class="button confirm mod-demote-to-member" href="<?php bp_group_member_demote_link( bp_get_member_user_id() ); ?>"><?php _e( 'Demote to Member', 'buddypress' ); ?></a>
+							</span>
+						</h5>
+					</li>
+					<?php endwhile; ?>
+
+				</ul>
+
+			<?php endif; ?>
+		</div>
+	<?php endif ?>
+
+
+	<div class="bp-widget">
+		<h4><?php _e("Members", "buddypress"); ?></h4>
+
+		<?php if ( bp_group_has_members( 'per_page=15&exclude_banned=false' ) ) : ?>
+
+			<?php if ( bp_group_member_needs_pagination() ) : ?>
+
+				<div class="pagination no-ajax">
+
+					<div id="member-count" class="pag-count">
+						<?php bp_group_member_pagination_count(); ?>
+					</div>
+
+					<div id="member-admin-pagination" class="pagination-links">
+						<?php bp_group_member_admin_pagination(); ?>
+					</div>
+
+				</div>
+
+			<?php endif; ?>
+
+			<ul id="members-list" class="item-list single-line">
+				<?php while ( bp_group_members() ) : bp_group_the_member(); ?>
+
+					<li class="<?php bp_group_member_css_class(); ?>">
+						<?php bp_group_member_avatar_mini(); ?>
+
+						<h5>
+							<?php bp_group_member_link(); ?>
+
+							<?php if ( bp_get_group_member_is_banned() ) _e( '(banned)', 'buddypress' ); ?>
+
+							<span class="small">
+
+							<?php if ( bp_get_group_member_is_banned() ) : ?>
+
+								<a href="<?php bp_group_member_unban_link(); ?>" class="button confirm member-unban" title="<?php _e( 'Unban this member', 'buddypress' ); ?>"><?php _e( 'Remove Ban', 'buddypress' ); ?></a>
+
+							<?php else : ?>
+
+								<a href="<?php bp_group_member_ban_link(); ?>" class="button confirm member-ban" title="<?php _e( 'Kick and ban this member', 'buddypress' ); ?>"><?php _e( 'Kick &amp; Ban', 'buddypress' ); ?></a>
+								<a href="<?php bp_group_member_promote_mod_link(); ?>" class="button confirm member-promote-to-mod" title="<?php _e( 'Promote to Mod', 'buddypress' ); ?>"><?php _e( 'Promote to Mod', 'buddypress' ); ?></a>
+								<a href="<?php bp_group_member_promote_admin_link(); ?>" class="button confirm member-promote-to-admin" title="<?php _e( 'Promote to Admin', 'buddypress' ); ?>"><?php _e( 'Promote to Admin', 'buddypress' ); ?></a>
+
+							<?php endif; ?>
+
+								<a href="<?php bp_group_member_remove_link(); ?>" class="button confirm" title="<?php _e( 'Remove this member', 'buddypress' ); ?>"><?php _e( 'Remove from group', 'buddypress' ); ?></a>
+
+								<?php do_action( 'bp_group_manage_members_admin_item' ); ?>
+
+							</span>
+						</h5>
+					</li>
+
+				<?php endwhile; ?>
+			</ul>
+
+		<?php else: ?>
+
+			<div id="message" class="info">
+				<p><?php _e( 'This group has no members.', 'buddypress' ); ?></p>
+			</div>
+
+		<?php endif; ?>
+
+	</div>
+
+	<?php do_action( 'bp_after_group_manage_members_admin' ); ?>
+
+<?php endif; ?>
+
+<?php /* Manage Membership Requests */ ?>
+<?php if ( bp_is_group_admin_screen( 'membership-requests' ) ) : ?>
+
+	<?php do_action( 'bp_before_group_membership_requests_admin' ); ?>
+
+	<?php if ( bp_group_has_membership_requests() ) : ?>
+
+		<ul id="request-list" class="item-list">
+			<?php while ( bp_group_membership_requests() ) : bp_group_the_membership_request(); ?>
+
+				<li>
+					<?php bp_group_request_user_avatar_thumb(); ?>
+					<h4><?php bp_group_request_user_link(); ?> <span class="comments"><?php bp_group_request_comment(); ?></span></h4>
+					<span class="activity"><?php bp_group_request_time_since_requested(); ?></span>
+
+					<?php do_action( 'bp_group_membership_requests_admin_item' ); ?>
+
+					<div class="action">
+
+						<?php bp_button( array( 'id' => 'group_membership_accept', 'component' => 'groups', 'wrapper_class' => 'accept', 'link_href' => bp_get_group_request_accept_link(), 'link_title' => __( 'Accept', 'buddypress' ), 'link_text' => __( 'Accept', 'buddypress' ) ) ); ?>
+
+						<?php bp_button( array( 'id' => 'group_membership_reject', 'component' => 'groups', 'wrapper_class' => 'reject', 'link_href' => bp_get_group_request_reject_link(), 'link_title' => __( 'Reject', 'buddypress' ), 'link_text' => __( 'Reject', 'buddypress' ) ) ); ?>
+
+						<?php do_action( 'bp_group_membership_requests_admin_item_action' ); ?>
+
+					</div>
+				</li>
+
+			<?php endwhile; ?>
+		</ul>
+
+	<?php else: ?>
+
+		<div id="message" class="info">
+			<p><?php _e( 'There are no pending membership requests.', 'buddypress' ); ?></p>
+		</div>
+
+	<?php endif; ?>
+
+	<?php do_action( 'bp_after_group_membership_requests_admin' ); ?>
+
+<?php endif; ?>
+
+<?php do_action( 'groups_custom_edit_steps' ) // Allow plugins to add custom group edit screens ?>
+
+<?php /* Delete Group Option */ ?>
+<?php if ( bp_is_group_admin_screen( 'delete-group' ) ) : ?>
+
+	<?php do_action( 'bp_before_group_delete_admin' ); ?>
+
+	<div id="message" class="info">
+		<p><?php _e( 'WARNING: Deleting this group will completely remove ALL content associated with it. There is no way back, please be careful with this option.', 'buddypress' ); ?></p>
+	</div>
+
+	<label><input type="checkbox" name="delete-group-understand" id="delete-group-understand" value="1" onclick="if(this.checked) { document.getElementById('delete-group-button').disabled = ''; } else { document.getElementById('delete-group-button').disabled = 'disabled'; }" /> <?php _e( 'I understand the consequences of deleting this group.', 'buddypress' ); ?></label>
+
+	<?php do_action( 'bp_after_group_delete_admin' ); ?>
+
+	<div class="submit">
+		<input type="submit" disabled="disabled" value="<?php _e( 'Delete Group', 'buddypress' ); ?>" id="delete-group-button" name="delete-group-button" />
+	</div>
+
+	<?php wp_nonce_field( 'groups_delete_group' ); ?>
+
+<?php endif; ?>
+
+<?php /* This is important, don't forget it */ ?>
+	<input type="hidden" name="group-id" id="group-id" value="<?php bp_group_id(); ?>" />
+
+<?php do_action( 'bp_after_group_admin_content' ); ?>
+
+</form><!-- #group-settings-form -->
+
Index: /tags/1.9/bp-templates/bp-legacy/buddypress/groups/single/forum.php
===================================================================
--- /tags/1.9/bp-templates/bp-legacy/buddypress/groups/single/forum.php	(revision 7684)
+++ /tags/1.9/bp-templates/bp-legacy/buddypress/groups/single/forum.php	(revision 7684)
@@ -0,0 +1,97 @@
+<?php
+
+do_action( 'bp_before_group_forum_content' );
+
+if ( bp_is_group_forum_topic_edit() ) :
+	bp_get_template_part( 'groups/single/forum/edit' );
+
+elseif ( bp_is_group_forum_topic() ) :
+	bp_get_template_part( 'groups/single/forum/topic' );
+
+else : ?>
+
+	<div class="item-list-tabs no-ajax" id="subnav" role="navigation">
+		<ul>
+
+			<?php if ( is_user_logged_in() ) : ?>
+
+				<li>
+					<a href="#post-new" class="show-hide-new"><?php _e( 'New Topic', 'buddypress' ); ?></a>
+				</li>
+
+			<?php endif; ?>
+
+			<?php if ( bp_forums_has_directory() ) : ?>
+
+				<li>
+					<a href="<?php bp_forums_directory_permalink(); ?>"><?php _e( 'Forum Directory', 'buddypress' ); ?></a>
+				</li>
+
+			<?php endif; ?>
+
+			<?php do_action( 'bp_forums_directory_group_sub_types' ); ?>
+
+			<li id="forums-order-select" class="last filter">
+
+				<label for="forums-order-by"><?php _e( 'Order By:', 'buddypress' ); ?></label>
+				<select id="forums-order-by">
+					<option value="active"><?php _e( 'Last Active', 'buddypress' ); ?></option>
+					<option value="popular"><?php _e( 'Most Posts', 'buddypress' ); ?></option>
+					<option value="unreplied"><?php _e( 'Unreplied', 'buddypress' ); ?></option>
+
+					<?php do_action( 'bp_forums_directory_order_options' ); ?>
+
+				</select>
+			</li>
+		</ul>
+	</div>
+
+	<div class="forums single-forum" role="main">
+
+		<?php bp_get_template_part( 'forums/forums-loop' ) ?>
+
+	</div><!-- .forums.single-forum -->
+
+<?php endif; ?>
+
+<?php do_action( 'bp_after_group_forum_content' ); ?>
+
+<?php if ( !bp_is_group_forum_topic_edit() && !bp_is_group_forum_topic() ) : ?>
+
+	<?php if ( !bp_group_is_user_banned() && ( ( is_user_logged_in() && 'public' == bp_get_group_status() ) || bp_group_is_member() ) ) : ?>
+
+		<form action="" method="post" id="forum-topic-form" class="standard-form">
+			<div id="new-topic-post">
+
+				<?php do_action( 'bp_before_group_forum_post_new' ); ?>
+
+				<?php if ( bp_groups_auto_join() && !bp_group_is_member() ) : ?>
+					<p><?php _e( 'You will auto join this group when you start a new topic.', 'buddypress' ); ?></p>
+				<?php endif; ?>
+
+				<p id="post-new"></p>
+				<h4><?php _e( 'Post a New Topic:', 'buddypress' ); ?></h4>
+
+				<label><?php _e( 'Title:', 'buddypress' ); ?></label>
+				<input type="text" name="topic_title" id="topic_title" value="" maxlength="100" />
+
+				<label><?php _e( 'Content:', 'buddypress' ); ?></label>
+				<textarea name="topic_text" id="topic_text"></textarea>
+
+				<label><?php _e( 'Tags (comma separated):', 'buddypress' ); ?></label>
+				<input type="text" name="topic_tags" id="topic_tags" value="" />
+
+				<?php do_action( 'bp_after_group_forum_post_new' ); ?>
+
+				<div class="submit">
+					<input type="submit" name="submit_topic" id="submit" value="<?php _e( 'Post Topic', 'buddypress' ); ?>" />
+				</div>
+
+				<?php wp_nonce_field( 'bp_forums_new_topic' ); ?>
+			</div><!-- #new-topic-post -->
+		</form><!-- #forum-topic-form -->
+
+	<?php endif; ?>
+
+<?php endif; ?>
+
Index: /tags/1.9/bp-templates/bp-legacy/buddypress/groups/single/forum/edit.php
===================================================================
--- /tags/1.9/bp-templates/bp-legacy/buddypress/groups/single/forum/edit.php	(revision 7684)
+++ /tags/1.9/bp-templates/bp-legacy/buddypress/groups/single/forum/edit.php	(revision 7684)
@@ -0,0 +1,92 @@
+<?php do_action( 'bp_before_group_forum_edit_form' ); ?>
+
+<?php if ( bp_has_forum_topic_posts() ) : ?>
+
+	<form action="<?php bp_forum_topic_action(); ?>" method="post" id="forum-topic-form" class="standard-form">
+
+		<div class="item-list-tabs" id="subnav" role="navigation">
+			<ul>
+				<li>
+					<a href="#post-topic-reply"><?php _e( 'Reply', 'buddypress' ); ?></a>
+				</li>
+
+				<?php if ( bp_forums_has_directory() ) : ?>
+
+					<li>
+						<a href="<?php bp_forums_directory_permalink(); ?>"><?php _e( 'Forum Directory', 'buddypress' ); ?></a>
+					</li>
+
+				<?php endif; ?>
+
+			</ul>
+		</div>
+
+		<div id="topic-meta">
+			<h3><?php _e( 'Edit:', 'buddypress' ); ?> <?php bp_the_topic_title(); ?> (<?php bp_the_topic_total_post_count(); ?>)</h3>
+
+			<?php if ( bp_group_is_admin() || bp_group_is_mod() || bp_get_the_topic_is_mine() ) : ?>
+
+				<div class="last admin-links">
+
+					<?php bp_the_topic_admin_links(); ?>
+
+				</div>
+
+			<?php endif; ?>
+
+			<?php do_action( 'bp_group_forum_topic_meta' ); ?>
+
+		</div>
+
+		<?php if ( bp_is_edit_topic() ) : ?>
+
+			<div id="edit-topic">
+
+				<?php do_action( 'bp_group_before_edit_forum_topic' ); ?>
+
+				<label for="topic_title"><?php _e( 'Title:', 'buddypress' ); ?></label>
+				<input type="text" name="topic_title" id="topic_title" value="<?php bp_the_topic_title(); ?>" maxlength="100" />
+
+				<label for="topic_text"><?php _e( 'Content:', 'buddypress' ); ?></label>
+				<textarea name="topic_text" id="topic_text"><?php bp_the_topic_text(); ?></textarea>
+
+				<label><?php _e( 'Tags (comma separated):', 'buddypress' ); ?></label>
+				<input type="text" name="topic_tags" id="topic_tags" value="<?php bp_forum_topic_tag_list(); ?>" />
+
+				<?php do_action( 'bp_group_after_edit_forum_topic' ); ?>
+
+				<p class="submit"><input type="submit" name="save_changes" id="save_changes" value="<?php _e( 'Save Changes', 'buddypress' ); ?>" /></p>
+
+				<?php wp_nonce_field( 'bp_forums_edit_topic' ); ?>
+
+			</div>
+
+		<?php else : ?>
+
+			<div id="edit-post">
+
+				<?php do_action( 'bp_group_before_edit_forum_post' ); ?>
+
+				<textarea name="post_text" id="post_text"><?php bp_the_topic_post_edit_text(); ?></textarea>
+
+				<?php do_action( 'bp_group_after_edit_forum_post' ); ?>
+
+				<p class="submit"><input type="submit" name="save_changes" id="save_changes" value="<?php _e( 'Save Changes', 'buddypress' ); ?>" /></p>
+
+				<?php wp_nonce_field( 'bp_forums_edit_post' ); ?>
+
+			</div>
+
+		<?php endif; ?>
+
+	</form><!-- #forum-topic-form -->
+
+<?php else: ?>
+
+	<div id="message" class="info">
+		<p><?php _e( 'This topic does not exist.', 'buddypress' ); ?></p>
+	</div>
+
+<?php endif;?>
+
+<?php do_action( 'bp_after_group_forum_edit_form' ); ?>
Index: /tags/1.9/bp-templates/bp-legacy/buddypress/groups/single/forum/topic.php
===================================================================
--- /tags/1.9/bp-templates/bp-legacy/buddypress/groups/single/forum/topic.php	(revision 7684)
+++ /tags/1.9/bp-templates/bp-legacy/buddypress/groups/single/forum/topic.php	(revision 7684)
@@ -0,0 +1,166 @@
+<?php do_action( 'bp_before_group_forum_topic' ); ?>
+
+<form action="<?php bp_forum_topic_action(); ?>" method="post" id="forum-topic-form" class="standard-form">
+	<div class="item-list-tabs no-ajax" id="subnav" role="navigation">
+		<ul>
+			<?php if ( is_user_logged_in() ) : ?>
+	
+				<li>
+					<a href="<?php bp_forum_topic_new_reply_link(); ?>" class="new-reply-link"><?php _e( 'New Reply', 'buddypress' ); ?></a>
+				</li>
+	
+			<?php endif; ?>
+	
+			<?php if ( bp_forums_has_directory() ) : ?>
+	
+				<li>
+					<a href="<?php bp_forums_directory_permalink(); ?>"><?php _e( 'Forum Directory', 'buddypress' ); ?></a>
+				</li>
+	
+			<?php endif; ?>
+	
+		</ul>
+	</div>
+	
+	<div id="topic-meta">
+		<h3><?php bp_the_topic_title(); ?> (<?php bp_the_topic_total_post_count(); ?>)</h3>
+	
+		<?php if ( bp_forum_topic_has_tags() ) : ?>
+	
+			<div class="topic-tags">
+	
+				<?php _e( 'Topic tags:', 'buddypress' ); ?> <?php bp_forum_topic_tag_list(); ?>
+	
+			</div>
+	
+		<?php endif; ?>
+	
+		<?php if ( bp_group_is_admin() || bp_group_is_mod() || bp_get_the_topic_is_mine() ) : ?>
+	
+			<div class="last admin-links">
+	
+				<?php bp_the_topic_admin_links(); ?>
+	
+			</div>
+	
+		<?php endif; ?>
+	
+		<?php do_action( 'bp_group_forum_topic_meta' ); ?>
+	
+	</div>
+
+
+	<?php if ( bp_has_forum_topic_posts() ) : ?>
+
+		<div class="pagination no-ajax">
+
+			<div id="post-count-top" class="pag-count">
+
+				<?php bp_the_topic_pagination_count(); ?>
+
+			</div>
+
+			<div class="pagination-links" id="topic-pag-top">
+
+				<?php bp_the_topic_pagination(); ?>
+
+			</div>
+
+		</div>
+
+		<?php do_action( 'bp_before_group_forum_topic_posts' ); ?>
+
+		<ul id="topic-post-list" class="item-list" role="main">
+			<?php while ( bp_forum_topic_posts() ) : bp_the_forum_topic_post(); ?>
+
+				<li id="post-<?php bp_the_topic_post_id(); ?>" class="<?php bp_the_topic_post_css_class(); ?>">
+					<div class="poster-meta">
+						<a href="<?php bp_the_topic_post_poster_link(); ?>">
+							<?php bp_the_topic_post_poster_avatar( 'width=40&height=40' ); ?>
+						</a>
+						<?php echo sprintf( __( '%1$s said %2$s:', 'buddypress' ), bp_get_the_topic_post_poster_name(), bp_get_the_topic_post_time_since() ); ?>
+					</div>
+
+					<div class="post-content">
+						<?php bp_the_topic_post_content(); ?>
+					</div>
+
+					<div class="admin-links">
+						<?php if ( bp_group_is_admin() || bp_group_is_mod() || bp_get_the_topic_post_is_mine() ) : ?>
+							<?php bp_the_topic_post_admin_links(); ?>
+						<?php endif; ?>
+
+						<?php do_action( 'bp_group_forum_post_meta' ); ?>
+
+						<a href="#post-<?php bp_the_topic_post_id(); ?>" title="<?php _e( 'Permanent link to this post', 'buddypress' ); ?>">#</a>
+					</div>
+				</li>
+
+			<?php endwhile; ?>
+		</ul><!-- #topic-post-list -->
+
+		<?php do_action( 'bp_after_group_forum_topic_posts' ); ?>
+
+		<div class="pagination no-ajax">
+
+			<div id="post-count-bottom" class="pag-count">
+				<?php bp_the_topic_pagination_count(); ?>
+			</div>
+
+			<div class="pagination-links" id="topic-pag-bottom">
+				<?php bp_the_topic_pagination(); ?>
+			</div>
+
+		</div>
+
+	<?php else: ?>
+	
+		<div id="message" class="info">
+			<p><?php _e( 'There are no posts for this topic.', 'buddypress' ); ?></p>
+		</div>
+	
+	<?php endif;?>
+
+	<?php if ( ( is_user_logged_in() && 'public' == bp_get_group_status() ) || bp_group_is_member() ) : ?>
+
+		<?php if ( bp_get_the_topic_is_last_page() ) : ?>
+
+			<?php if ( bp_get_the_topic_is_topic_open() && !bp_group_is_user_banned() ) : ?>
+
+				<div id="post-topic-reply">
+					<p id="post-reply"></p>
+
+					<?php if ( bp_groups_auto_join() && !bp_group_is_member() ) : ?>
+						<p><?php _e( 'You will auto join this group when you reply to this topic.', 'buddypress' ); ?></p>
+					<?php endif; ?>
+
+					<?php do_action( 'groups_forum_new_reply_before' ); ?>
+
+					<h4><?php _e( 'Add a reply:', 'buddypress' ); ?></h4>
+
+					<textarea name="reply_text" id="reply_text"></textarea>
+
+					<div class="submit">
+						<input type="submit" name="submit_reply" id="submit" value="<?php _e( 'Post Reply', 'buddypress' ); ?>" />
+					</div>
+
+					<?php do_action( 'groups_forum_new_reply_after' ); ?>
+
+					<?php wp_nonce_field( 'bp_forums_new_reply' ); ?>
+				</div>
+
+			<?php elseif ( !bp_group_is_user_banned() ) : ?>
+
+				<div id="message" class="info">
+					<p><?php _e( 'This topic is closed, replies are no longer accepted.', 'buddypress' ); ?></p>
+				</div>
+
+			<?php endif; ?>
+
+		<?php endif; ?>
+
+	<?php endif; ?>
+
+</form><!-- #forum-topic-form -->
+
+<?php do_action( 'bp_after_group_forum_topic' ); ?>
Index: /tags/1.9/bp-templates/bp-legacy/buddypress/groups/single/group-header.php
===================================================================
--- /tags/1.9/bp-templates/bp-legacy/buddypress/groups/single/group-header.php	(revision 7684)
+++ /tags/1.9/bp-templates/bp-legacy/buddypress/groups/single/group-header.php	(revision 7684)
@@ -0,0 +1,64 @@
+<?php
+
+do_action( 'bp_before_group_header' );
+
+?>
+
+<div id="item-actions">
+
+	<?php if ( bp_group_is_visible() ) : ?>
+
+		<h3><?php _e( 'Group Admins', 'buddypress' ); ?></h3>
+
+		<?php bp_group_list_admins();
+
+		do_action( 'bp_after_group_menu_admins' );
+
+		if ( bp_group_has_moderators() ) :
+			do_action( 'bp_before_group_menu_mods' ); ?>
+
+			<h3><?php _e( 'Group Mods' , 'buddypress' ); ?></h3>
+
+			<?php bp_group_list_mods();
+
+			do_action( 'bp_after_group_menu_mods' );
+
+		endif;
+
+	endif; ?>
+
+</div><!-- #item-actions -->
+
+<div id="item-header-avatar">
+	<a href="<?php bp_group_permalink(); ?>" title="<?php bp_group_name(); ?>">
+
+		<?php bp_group_avatar(); ?>
+
+	</a>
+</div><!-- #item-header-avatar -->
+
+<div id="item-header-content">
+	<span class="highlight"><?php bp_group_type(); ?></span>
+	<span class="activity"><?php printf( __( 'active %s', 'buddypress' ), bp_get_group_last_active() ); ?></span>
+
+	<?php do_action( 'bp_before_group_header_meta' ); ?>
+
+	<div id="item-meta">
+
+		<?php bp_group_description(); ?>
+
+		<div id="item-buttons">
+
+			<?php do_action( 'bp_group_header_actions' ); ?>
+
+		</div><!-- #item-buttons -->
+
+		<?php do_action( 'bp_group_header_meta' ); ?>
+
+	</div>
+</div><!-- #item-header-content -->
+
+<?php
+do_action( 'bp_after_group_header' );
+do_action( 'template_notices' );
+?>
Index: /tags/1.9/bp-templates/bp-legacy/buddypress/groups/single/home.php
===================================================================
--- /tags/1.9/bp-templates/bp-legacy/buddypress/groups/single/home.php	(revision 7684)
+++ /tags/1.9/bp-templates/bp-legacy/buddypress/groups/single/home.php	(revision 7684)
@@ -0,0 +1,107 @@
+<div id="buddypress">
+
+	<?php if ( bp_has_groups() ) : while ( bp_groups() ) : bp_the_group(); ?>
+
+	<?php do_action( 'bp_before_group_home_content' ); ?>
+
+	<div id="item-header" role="complementary">
+
+		<?php bp_get_template_part( 'groups/single/group-header' ); ?>
+
+	</div><!-- #item-header -->
+
+	<div id="item-nav">
+		<div class="item-list-tabs no-ajax" id="object-nav" role="navigation">
+			<ul>
+
+				<?php bp_get_options_nav(); ?>
+
+				<?php do_action( 'bp_group_options_nav' ); ?>
+
+			</ul>
+		</div>
+	</div><!-- #item-nav -->
+
+	<div id="item-body">
+
+		<?php do_action( 'bp_before_group_body' );
+
+		/**
+		 * Does this next bit look familiar? If not, go check out WordPress's
+		 * /wp-includes/template-loader.php file.
+		 *
+		 * @todo A real template hierarchy? Gasp!
+		 */
+
+		// Group is visible
+		if ( bp_group_is_visible() ) : 
+
+			// Looking at home location
+			if ( bp_is_group_home() ) :
+
+				// Use custom front if one exists
+				$custom_front = bp_locate_template( array( 'groups/single/front.php' ), false, true );
+				if     ( ! empty( $custom_front   ) ) : load_template( $custom_front, true );
+
+				// Default to activity
+				elseif ( bp_is_active( 'activity' ) ) : bp_get_template_part( 'groups/single/activity' );
+
+				// Otherwise show members
+				elseif ( bp_is_active( 'members'  ) ) : bp_get_template_part( 'groups/single/members'  );
+
+				endif;
+				
+			// Not looking at home
+			else :
+
+				// Group Admin
+				if     ( bp_is_group_admin_page() ) : bp_get_template_part( 'groups/single/admin'        );
+
+				// Group Activity
+				elseif ( bp_is_group_activity()   ) : bp_get_template_part( 'groups/single/activity'     );
+
+				// Group Members
+				elseif ( bp_is_group_members()    ) : bp_get_template_part( 'groups/single/members'      );
+
+				// Group Invitations
+				elseif ( bp_is_group_invites()    ) : bp_get_template_part( 'groups/single/send-invites' );
+
+				// Old group forums
+				elseif ( bp_is_group_forum()      ) : bp_get_template_part( 'groups/single/forum'        );
+
+				// Anything else (plugins mostly)
+				else                                : bp_get_template_part( 'groups/single/plugins'      );
+
+				endif;
+			endif;
+
+		// Group is not visible
+		elseif ( ! bp_group_is_visible() ) :
+
+			// Membership request
+			if ( bp_is_group_membership_request() ) :
+				bp_get_template_part( 'groups/single/request-membership' );
+
+			// The group is not visible, show the status message
+			else :
+
+				do_action( 'bp_before_group_status_message' ); ?>
+
+				<div id="message" class="info">
+					<p><?php bp_group_status_message(); ?></p>
+				</div>
+
+				<?php do_action( 'bp_after_group_status_message' );
+
+			endif;
+		endif;
+
+		do_action( 'bp_after_group_body' ); ?>
+
+	</div><!-- #item-body -->
+
+	<?php do_action( 'bp_after_group_home_content' ); ?>
+
+	<?php endwhile; endif; ?>
+
+</div><!-- #buddypress -->
Index: /tags/1.9/bp-templates/bp-legacy/buddypress/groups/single/members.php
===================================================================
--- /tags/1.9/bp-templates/bp-legacy/buddypress/groups/single/members.php	(revision 7684)
+++ /tags/1.9/bp-templates/bp-legacy/buddypress/groups/single/members.php	(revision 7684)
@@ -0,0 +1,90 @@
+<?php if ( bp_group_has_members( 'exclude_admins_mods=0' ) ) : ?>
+
+	<?php do_action( 'bp_before_group_members_content' ); ?>
+
+	<div class="item-list-tabs" id="subnav" role="navigation">
+		<ul>
+
+			<?php do_action( 'bp_members_directory_member_sub_types' ); ?>
+
+		</ul>
+	</div>
+
+	<div id="pag-top" class="pagination no-ajax">
+
+		<div class="pag-count" id="member-count-top">
+
+			<?php bp_members_pagination_count(); ?>
+
+		</div>
+
+		<div class="pagination-links" id="member-pag-top">
+
+			<?php bp_members_pagination_links(); ?>
+
+		</div>
+
+	</div>
+
+	<?php do_action( 'bp_before_group_members_list' ); ?>
+
+	<ul id="member-list" class="item-list" role="main">
+
+		<?php while ( bp_group_members() ) : bp_group_the_member(); ?>
+
+			<li>
+				<a href="<?php bp_group_member_domain(); ?>">
+
+					<?php bp_group_member_avatar_thumb(); ?>
+
+				</a>
+
+				<h5><?php bp_group_member_link(); ?></h5>
+				<span class="activity"><?php bp_group_member_joined_since(); ?></span>
+
+				<?php do_action( 'bp_group_members_list_item' ); ?>
+
+				<?php if ( bp_is_active( 'friends' ) ) : ?>
+
+					<div class="action">
+
+						<?php bp_add_friend_button( bp_get_group_member_id(), bp_get_group_member_is_friend() ); ?>
+
+						<?php do_action( 'bp_group_members_list_item_action' ); ?>
+
+					</div>
+
+				<?php endif; ?>
+			</li>
+
+		<?php endwhile; ?>
+
+	</ul>
+
+	<?php do_action( 'bp_after_group_members_list' ); ?>
+
+	<div id="pag-bottom" class="pagination no-ajax">
+
+		<div class="pag-count" id="member-count-bottom">
+
+			<?php bp_members_pagination_count(); ?>
+
+		</div>
+
+		<div class="pagination-links" id="member-pag-bottom">
+
+			<?php bp_members_pagination_links(); ?>
+
+		</div>
+
+	</div>
+
+	<?php do_action( 'bp_after_group_members_content' ); ?>
+
+<?php else: ?>
+
+	<div id="message" class="info">
+		<p><?php _e( 'This group has no members.', 'buddypress' ); ?></p>
+	</div>
+
+<?php endif; ?>
Index: /tags/1.9/bp-templates/bp-legacy/buddypress/groups/single/plugins.php
===================================================================
--- /tags/1.9/bp-templates/bp-legacy/buddypress/groups/single/plugins.php	(revision 7684)
+++ /tags/1.9/bp-templates/bp-legacy/buddypress/groups/single/plugins.php	(revision 7684)
@@ -0,0 +1,5 @@
+<?php do_action( 'bp_before_group_plugin_template' ); ?>
+
+<?php do_action( 'bp_template_content' ); ?>
+
+<?php do_action( 'bp_after_group_plugin_template' );
Index: /tags/1.9/bp-templates/bp-legacy/buddypress/groups/single/request-membership.php
===================================================================
--- /tags/1.9/bp-templates/bp-legacy/buddypress/groups/single/request-membership.php	(revision 7684)
+++ /tags/1.9/bp-templates/bp-legacy/buddypress/groups/single/request-membership.php	(revision 7684)
@@ -0,0 +1,18 @@
+<?php do_action( 'bp_before_group_request_membership_content' ); ?>
+
+<?php if ( !bp_group_has_requested_membership() ) : ?>
+	<p><?php printf( __( "You are requesting to become a member of the group '%s'.", "buddypress" ), bp_get_group_name( false ) ); ?></p>
+
+	<form action="<?php bp_group_form_action('request-membership' ); ?>" method="post" name="request-membership-form" id="request-membership-form" class="standard-form">
+		<label for="group-request-membership-comments"><?php _e( 'Comments (optional)', 'buddypress' ); ?></label>
+		<textarea name="group-request-membership-comments" id="group-request-membership-comments"></textarea>
+
+		<?php do_action( 'bp_group_request_membership_content' ); ?>
+
+		<p><input type="submit" name="group-request-send" id="group-request-send" value="<?php _e( 'Send Request', 'buddypress' ); ?>" />
+
+		<?php wp_nonce_field( 'groups_request_membership' ); ?>
+	</form><!-- #request-membership-form -->
+<?php endif; ?>
+
+<?php do_action( 'bp_after_group_request_membership_content' ); ?>
Index: /tags/1.9/bp-templates/bp-legacy/buddypress/groups/single/send-invites.php
===================================================================
--- /tags/1.9/bp-templates/bp-legacy/buddypress/groups/single/send-invites.php	(revision 7684)
+++ /tags/1.9/bp-templates/bp-legacy/buddypress/groups/single/send-invites.php	(revision 7684)
@@ -0,0 +1,78 @@
+<?php do_action( 'bp_before_group_send_invites_content' ); ?>
+
+<?php if ( bp_get_total_friend_count( bp_loggedin_user_id() ) ) : ?>
+
+	<form action="<?php bp_group_send_invite_form_action(); ?>" method="post" id="send-invite-form" class="standard-form" role="main">
+
+		<div class="left-menu">
+
+			<div id="invite-list">
+				<ul>
+					<?php bp_new_group_invite_friend_list(); ?>
+				</ul>
+
+				<?php wp_nonce_field( 'groups_invite_uninvite_user', '_wpnonce_invite_uninvite_user' ); ?>
+			</div>
+
+		</div><!-- .left-menu -->
+
+		<div class="main-column">
+
+			<div id="message" class="info">
+				<p><?php _e('Select people to invite from your friends list.', 'buddypress' ); ?></p>
+			</div>
+
+			<?php do_action( 'bp_before_group_send_invites_list' ); ?>
+
+			<?php /* The ID 'friend-list' is important for AJAX support. */ ?>
+			<ul id="friend-list" class="item-list">
+			<?php if ( bp_group_has_invites() ) : ?>
+
+				<?php while ( bp_group_invites() ) : bp_group_the_invite(); ?>
+
+					<li id="<?php bp_group_invite_item_id(); ?>">
+						<?php bp_group_invite_user_avatar(); ?>
+
+						<h4><?php bp_group_invite_user_link(); ?></h4>
+						<span class="activity"><?php bp_group_invite_user_last_active(); ?></span>
+
+						<?php do_action( 'bp_group_send_invites_item' ); ?>
+
+						<div class="action">
+							<a class="button remove" href="<?php bp_group_invite_user_remove_invite_url(); ?>" id="<?php bp_group_invite_item_id(); ?>"><?php _e( 'Remove Invite', 'buddypress' ); ?></a>
+
+							<?php do_action( 'bp_group_send_invites_item_action' ); ?>
+						</div>
+					</li>
+
+				<?php endwhile; ?>
+
+			<?php endif; ?>
+			</ul><!-- #friend-list -->
+
+			<?php do_action( 'bp_after_group_send_invites_list' ); ?>
+
+		</div><!-- .main-column -->
+
+		<div class="clear"></div>
+
+		<div class="submit">
+			<input type="submit" name="submit" id="submit" value="<?php _e( 'Send Invites', 'buddypress' ); ?>" />
+		</div>
+
+		<?php wp_nonce_field( 'groups_send_invites', '_wpnonce_send_invites' ); ?>
+
+		<?php /* This is important, don't forget it */ ?>
+		<input type="hidden" name="group_id" id="group_id" value="<?php bp_group_id(); ?>" />
+
+	</form><!-- #send-invite-form -->
+
+<?php else : ?>
+
+	<div id="message" class="info" role="main">
+		<p><?php _e( 'Once you have built up friend connections you will be able to invite others to your group.', 'buddypress' ); ?></p>
+	</div>
+
+<?php endif; ?>
+
+<?php do_action( 'bp_after_group_send_invites_content' ); ?>
Index: /tags/1.9/bp-templates/bp-legacy/buddypress/members/activate.php
===================================================================
--- /tags/1.9/bp-templates/bp-legacy/buddypress/members/activate.php	(revision 7684)
+++ /tags/1.9/bp-templates/bp-legacy/buddypress/members/activate.php	(revision 7684)
@@ -0,0 +1,42 @@
+<div id="buddypress">
+
+	<?php do_action( 'bp_before_activation_page' ); ?>
+
+	<div class="page" id="activate-page">
+
+		<?php do_action( 'template_notices' ); ?>
+
+		<?php do_action( 'bp_before_activate_content' ); ?>
+
+		<?php if ( bp_account_was_activated() ) : ?>
+
+			<?php if ( isset( $_GET['e'] ) ) : ?>
+				<p><?php _e( 'Your account was activated successfully! Your account details have been sent to you in a separate email.', 'buddypress' ); ?></p>
+			<?php else : ?>
+				<p><?php printf( __( 'Your account was activated successfully! You can now <a href="%s">log in</a> with the username and password you provided when you signed up.', 'buddypress' ), wp_login_url( bp_get_root_domain() ) ); ?></p>
+			<?php endif; ?>
+
+		<?php else : ?>
+
+			<p><?php _e( 'Please provide a valid activation key.', 'buddypress' ); ?></p>
+
+			<form action="" method="get" class="standard-form" id="activation-form">
+
+				<label for="key"><?php _e( 'Activation Key:', 'buddypress' ); ?></label>
+				<input type="text" name="key" id="key" value="" />
+
+				<p class="submit">
+					<input type="submit" name="submit" value="<?php _e( 'Activate', 'buddypress' ); ?>" />
+				</p>
+
+			</form>
+
+		<?php endif; ?>
+
+		<?php do_action( 'bp_after_activate_content' ); ?>
+
+	</div><!-- .page -->
+
+	<?php do_action( 'bp_after_activation_page' ); ?>
+
+</div><!-- #buddypress -->
Index: /tags/1.9/bp-templates/bp-legacy/buddypress/members/index.php
===================================================================
--- /tags/1.9/bp-templates/bp-legacy/buddypress/members/index.php	(revision 7684)
+++ /tags/1.9/bp-templates/bp-legacy/buddypress/members/index.php	(revision 7684)
@@ -0,0 +1,66 @@
+<?php do_action( 'bp_before_directory_members_page' ); ?>
+
+<div id="buddypress">
+
+	<?php do_action( 'bp_before_directory_members' ); ?>
+
+	<?php do_action( 'bp_before_directory_members_content' ); ?>
+
+	<div id="members-dir-search" class="dir-search" role="search">
+		<?php bp_directory_members_search_form(); ?>
+	</div><!-- #members-dir-search -->
+
+	<?php do_action( 'bp_before_directory_members_tabs' ); ?>
+
+	<form action="" method="post" id="members-directory-form" class="dir-form">
+
+		<div class="item-list-tabs" role="navigation">
+			<ul>
+				<li class="selected" id="members-all"><a href="<?php bp_members_directory_permalink(); ?>"><?php printf( __( 'All Members <span>%s</span>', 'buddypress' ), bp_get_total_member_count() ); ?></a></li>
+
+				<?php if ( is_user_logged_in() && bp_is_active( 'friends' ) && bp_get_total_friend_count( bp_loggedin_user_id() ) ) : ?>
+					<li id="members-personal"><a href="<?php echo bp_loggedin_user_domain() . bp_get_friends_slug() . '/my-friends/'; ?>"><?php printf( __( 'My Friends <span>%s</span>', 'buddypress' ), bp_get_total_friend_count( bp_loggedin_user_id() ) ); ?></a></li>
+				<?php endif; ?>
+
+				<?php do_action( 'bp_members_directory_member_types' ); ?>
+
+			</ul>
+		</div><!-- .item-list-tabs -->
+
+		<div class="item-list-tabs" id="subnav" role="navigation">
+			<ul>
+				<?php do_action( 'bp_members_directory_member_sub_types' ); ?>
+
+				<li id="members-order-select" class="last filter">
+					<label for="members-order-by"><?php _e( 'Order By:', 'buddypress' ); ?></label>
+					<select id="members-order-by">
+						<option value="active"><?php _e( 'Last Active', 'buddypress' ); ?></option>
+						<option value="newest"><?php _e( 'Newest Registered', 'buddypress' ); ?></option>
+
+						<?php if ( bp_is_active( 'xprofile' ) ) : ?>
+							<option value="alphabetical"><?php _e( 'Alphabetical', 'buddypress' ); ?></option>
+						<?php endif; ?>
+
+						<?php do_action( 'bp_members_directory_order_options' ); ?>
+					</select>
+				</li>
+			</ul>
+		</div>
+
+		<div id="members-dir-list" class="members dir-list">
+			<?php bp_get_template_part( 'members/members-loop' ); ?>
+		</div><!-- #members-dir-list -->
+
+		<?php do_action( 'bp_directory_members_content' ); ?>
+
+		<?php wp_nonce_field( 'directory_members', '_wpnonce-member-filter' ); ?>
+
+		<?php do_action( 'bp_after_directory_members_content' ); ?>
+
+	</form><!-- #members-directory-form -->
+
+	<?php do_action( 'bp_after_directory_members' ); ?>
+
+</div><!-- #buddypress -->
+
+<?php do_action( 'bp_after_directory_members_page' ); ?>
Index: /tags/1.9/bp-templates/bp-legacy/buddypress/members/members-loop.php
===================================================================
--- /tags/1.9/bp-templates/bp-legacy/buddypress/members/members-loop.php	(revision 7684)
+++ /tags/1.9/bp-templates/bp-legacy/buddypress/members/members-loop.php	(revision 7684)
@@ -0,0 +1,113 @@
+<?php
+
+/**
+ * BuddyPress - Members Loop
+ *
+ * Querystring is set via AJAX in _inc/ajax.php - bp_legacy_theme_object_filter()
+ *
+ * @package BuddyPress
+ * @subpackage bp-legacy
+ */
+
+?>
+
+<?php do_action( 'bp_before_members_loop' ); ?>
+
+<?php if ( bp_has_members( bp_ajax_querystring( 'members' ) ) ) : ?>
+
+	<div id="pag-top" class="pagination">
+
+		<div class="pag-count" id="member-dir-count-top">
+
+			<?php bp_members_pagination_count(); ?>
+
+		</div>
+
+		<div class="pagination-links" id="member-dir-pag-top">
+
+			<?php bp_members_pagination_links(); ?>
+
+		</div>
+
+	</div>
+
+	<?php do_action( 'bp_before_directory_members_list' ); ?>
+
+	<ul id="members-list" class="item-list" role="main">
+
+	<?php while ( bp_members() ) : bp_the_member(); ?>
+
+		<li>
+			<div class="item-avatar">
+				<a href="<?php bp_member_permalink(); ?>"><?php bp_member_avatar(); ?></a>
+			</div>
+
+			<div class="item">
+				<div class="item-title">
+					<a href="<?php bp_member_permalink(); ?>"><?php bp_member_name(); ?></a>
+
+					<?php if ( bp_get_member_latest_update() ) : ?>
+
+						<span class="update"> <?php bp_member_latest_update(); ?></span>
+
+					<?php endif; ?>
+
+				</div>
+
+				<div class="item-meta"><span class="activity"><?php bp_member_last_active(); ?></span></div>
+
+				<?php do_action( 'bp_directory_members_item' ); ?>
+
+				<?php
+				 /***
+				  * If you want to show specific profile fields here you can,
+				  * but it'll add an extra query for each member in the loop
+				  * (only one regardless of the number of fields you show):
+				  *
+				  * bp_member_profile_data( 'field=the field name' );
+				  */
+				?>
+			</div>
+
+			<div class="action">
+
+				<?php do_action( 'bp_directory_members_actions' ); ?>
+
+			</div>
+
+			<div class="clear"></div>
+		</li>
+
+	<?php endwhile; ?>
+
+	</ul>
+
+	<?php do_action( 'bp_after_directory_members_list' ); ?>
+
+	<?php bp_member_hidden_fields(); ?>
+
+	<div id="pag-bottom" class="pagination">
+
+		<div class="pag-count" id="member-dir-count-bottom">
+
+			<?php bp_members_pagination_count(); ?>
+
+		</div>
+
+		<div class="pagination-links" id="member-dir-pag-bottom">
+
+			<?php bp_members_pagination_links(); ?>
+
+		</div>
+
+	</div>
+
+<?php else: ?>
+
+	<div id="message" class="info">
+		<p><?php _e( "Sorry, no members were found.", 'buddypress' ); ?></p>
+	</div>
+
+<?php endif; ?>
+
+<?php do_action( 'bp_after_members_loop' ); ?>
Index: /tags/1.9/bp-templates/bp-legacy/buddypress/members/register.php
===================================================================
--- /tags/1.9/bp-templates/bp-legacy/buddypress/members/register.php	(revision 7684)
+++ /tags/1.9/bp-templates/bp-legacy/buddypress/members/register.php	(revision 7684)
@@ -0,0 +1,275 @@
+<div id="buddypress">
+
+	<?php do_action( 'bp_before_register_page' ); ?>
+
+	<div class="page" id="register-page">
+
+		<form action="" name="signup_form" id="signup_form" class="standard-form" method="post" enctype="multipart/form-data">
+
+		<?php if ( 'registration-disabled' == bp_get_current_signup_step() ) : ?>
+			<?php do_action( 'template_notices' ); ?>
+			<?php do_action( 'bp_before_registration_disabled' ); ?>
+
+				<p><?php _e( 'User registration is currently not allowed.', 'buddypress' ); ?></p>
+
+			<?php do_action( 'bp_after_registration_disabled' ); ?>
+		<?php endif; // registration-disabled signup setp ?>
+
+		<?php if ( 'request-details' == bp_get_current_signup_step() ) : ?>
+
+			<?php do_action( 'template_notices' ); ?>
+
+			<p><?php _e( 'Registering for this site is easy. Just fill in the fields below, and we\'ll get a new account set up for you in no time.', 'buddypress' ); ?></p>
+
+			<?php do_action( 'bp_before_account_details_fields' ); ?>
+
+			<div class="register-section" id="basic-details-section">
+
+				<?php /***** Basic Account Details ******/ ?>
+
+				<h4><?php _e( 'Account Details', 'buddypress' ); ?></h4>
+
+				<label for="signup_username"><?php _e( 'Username', 'buddypress' ); ?> <?php _e( '(required)', 'buddypress' ); ?></label>
+				<?php do_action( 'bp_signup_username_errors' ); ?>
+				<input type="text" name="signup_username" id="signup_username" value="<?php bp_signup_username_value(); ?>" />
+
+				<label for="signup_email"><?php _e( 'Email Address', 'buddypress' ); ?> <?php _e( '(required)', 'buddypress' ); ?></label>
+				<?php do_action( 'bp_signup_email_errors' ); ?>
+				<input type="text" name="signup_email" id="signup_email" value="<?php bp_signup_email_value(); ?>" />
+
+				<label for="signup_password"><?php _e( 'Choose a Password', 'buddypress' ); ?> <?php _e( '(required)', 'buddypress' ); ?></label>
+				<?php do_action( 'bp_signup_password_errors' ); ?>
+				<input type="password" name="signup_password" id="signup_password" value="" />
+
+				<label for="signup_password_confirm"><?php _e( 'Confirm Password', 'buddypress' ); ?> <?php _e( '(required)', 'buddypress' ); ?></label>
+				<?php do_action( 'bp_signup_password_confirm_errors' ); ?>
+				<input type="password" name="signup_password_confirm" id="signup_password_confirm" value="" />
+
+				<?php do_action( 'bp_account_details_fields' ); ?>
+
+			</div><!-- #basic-details-section -->
+
+			<?php do_action( 'bp_after_account_details_fields' ); ?>
+
+			<?php /***** Extra Profile Details ******/ ?>
+
+			<?php if ( bp_is_active( 'xprofile' ) ) : ?>
+
+				<?php do_action( 'bp_before_signup_profile_fields' ); ?>
+
+				<div class="register-section" id="profile-details-section">
+
+					<h4><?php _e( 'Profile Details', 'buddypress' ); ?></h4>
+
+					<?php /* Use the profile field loop to render input fields for the 'base' profile field group */ ?>
+					<?php if ( bp_is_active( 'xprofile' ) ) : if ( bp_has_profile( array( 'profile_group_id' => 1, 'fetch_field_data' => false ) ) ) : while ( bp_profile_groups() ) : bp_the_profile_group(); ?>
+
+					<?php while ( bp_profile_fields() ) : bp_the_profile_field(); ?>
+
+						<div class="editfield">
+
+							<?php if ( 'textbox' == bp_get_the_profile_field_type() ) : ?>
+
+								<label for="<?php bp_the_profile_field_input_name(); ?>"><?php bp_the_profile_field_name(); ?> <?php if ( bp_get_the_profile_field_is_required() ) : ?><?php _e( '(required)', 'buddypress' ); ?><?php endif; ?></label>
+								<?php do_action( bp_get_the_profile_field_errors_action() ); ?>
+								<input type="text" name="<?php bp_the_profile_field_input_name(); ?>" id="<?php bp_the_profile_field_input_name(); ?>" value="<?php bp_the_profile_field_edit_value(); ?>" />
+
+							<?php endif; ?>
+
+							<?php if ( 'textarea' == bp_get_the_profile_field_type() ) : ?>
+
+								<label for="<?php bp_the_profile_field_input_name(); ?>"><?php bp_the_profile_field_name(); ?> <?php if ( bp_get_the_profile_field_is_required() ) : ?><?php _e( '(required)', 'buddypress' ); ?><?php endif; ?></label>
+								<?php do_action( bp_get_the_profile_field_errors_action() ); ?>
+								<textarea rows="5" cols="40" name="<?php bp_the_profile_field_input_name(); ?>" id="<?php bp_the_profile_field_input_name(); ?>"><?php bp_the_profile_field_edit_value(); ?></textarea>
+
+							<?php endif; ?>
+
+							<?php if ( 'selectbox' == bp_get_the_profile_field_type() ) : ?>
+
+								<label for="<?php bp_the_profile_field_input_name(); ?>"><?php bp_the_profile_field_name(); ?> <?php if ( bp_get_the_profile_field_is_required() ) : ?><?php _e( '(required)', 'buddypress' ); ?><?php endif; ?></label>
+								<?php do_action( bp_get_the_profile_field_errors_action() ); ?>
+								<select name="<?php bp_the_profile_field_input_name(); ?>" id="<?php bp_the_profile_field_input_name(); ?>">
+									<?php bp_the_profile_field_options(); ?>
+								</select>
+
+							<?php endif; ?>
+
+							<?php if ( 'multiselectbox' == bp_get_the_profile_field_type() ) : ?>
+
+								<label for="<?php bp_the_profile_field_input_name(); ?>"><?php bp_the_profile_field_name(); ?> <?php if ( bp_get_the_profile_field_is_required() ) : ?><?php _e( '(required)', 'buddypress' ); ?><?php endif; ?></label>
+								<?php do_action( bp_get_the_profile_field_errors_action() ); ?>
+								<select name="<?php bp_the_profile_field_input_name(); ?>" id="<?php bp_the_profile_field_input_name(); ?>" multiple="multiple">
+									<?php bp_the_profile_field_options(); ?>
+								</select>
+
+							<?php endif; ?>
+
+							<?php if ( 'radio' == bp_get_the_profile_field_type() ) : ?>
+
+								<div class="radio">
+									<span class="label"><?php bp_the_profile_field_name(); ?> <?php if ( bp_get_the_profile_field_is_required() ) : ?><?php _e( '(required)', 'buddypress' ); ?><?php endif; ?></span>
+
+									<?php do_action( bp_get_the_profile_field_errors_action() ); ?>
+									<?php bp_the_profile_field_options(); ?>
+
+									<?php if ( !bp_get_the_profile_field_is_required() ) : ?>
+										<a class="clear-value" href="javascript:clear( '<?php bp_the_profile_field_input_name(); ?>' );"><?php _e( 'Clear', 'buddypress' ); ?></a>
+									<?php endif; ?>
+								</div>
+
+							<?php endif; ?>
+
+							<?php if ( 'checkbox' == bp_get_the_profile_field_type() ) : ?>
+
+								<div class="checkbox">
+									<span class="label"><?php bp_the_profile_field_name(); ?> <?php if ( bp_get_the_profile_field_is_required() ) : ?><?php _e( '(required)', 'buddypress' ); ?><?php endif; ?></span>
+
+									<?php do_action( bp_get_the_profile_field_errors_action() ); ?>
+									<?php bp_the_profile_field_options(); ?>
+								</div>
+
+							<?php endif; ?>
+
+							<?php if ( 'datebox' == bp_get_the_profile_field_type() ) : ?>
+
+								<div class="datebox">
+									<label for="<?php bp_the_profile_field_input_name(); ?>_day"><?php bp_the_profile_field_name(); ?> <?php if ( bp_get_the_profile_field_is_required() ) : ?><?php _e( '(required)', 'buddypress' ); ?><?php endif; ?></label>
+									<?php do_action( bp_get_the_profile_field_errors_action() ); ?>
+
+									<select name="<?php bp_the_profile_field_input_name(); ?>_day" id="<?php bp_the_profile_field_input_name(); ?>_day">
+										<?php bp_the_profile_field_options( 'type=day' ); ?>
+									</select>
+
+									<select name="<?php bp_the_profile_field_input_name(); ?>_month" id="<?php bp_the_profile_field_input_name(); ?>_month">
+										<?php bp_the_profile_field_options( 'type=month' ); ?>
+									</select>
+
+									<select name="<?php bp_the_profile_field_input_name(); ?>_year" id="<?php bp_the_profile_field_input_name(); ?>_year">
+										<?php bp_the_profile_field_options( 'type=year' ); ?>
+									</select>
+								</div>
+
+							<?php endif; ?>
+
+							<?php do_action( 'bp_custom_profile_edit_fields_pre_visibility' ); ?>
+
+							<?php if ( bp_current_user_can( 'bp_xprofile_change_field_visibility' ) ) : ?>
+								<p class="field-visibility-settings-toggle" id="field-visibility-settings-toggle-<?php bp_the_profile_field_id() ?>">
+									<?php printf( __( 'This field can be seen by: <span class="current-visibility-level">%s</span>', 'buddypress' ), bp_get_the_profile_field_visibility_level_label() ) ?> <a href="#" class="visibility-toggle-link"><?php _ex( 'Change', 'Change profile field visibility level', 'buddypress' ); ?></a>
+								</p>
+
+								<div class="field-visibility-settings" id="field-visibility-settings-<?php bp_the_profile_field_id() ?>">
+									<fieldset>
+										<legend><?php _e( 'Who can see this field?', 'buddypress' ) ?></legend>
+
+										<?php bp_profile_visibility_radio_buttons() ?>
+
+									</fieldset>
+									<a class="field-visibility-settings-close" href="#"><?php _e( 'Close', 'buddypress' ) ?></a>
+
+								</div>
+							<?php else : ?>
+								<p class="field-visibility-settings-notoggle" id="field-visibility-settings-toggle-<?php bp_the_profile_field_id() ?>">
+									<?php printf( __( 'This field can be seen by: <span class="current-visibility-level">%s</span>', 'buddypress' ), bp_get_the_profile_field_visibility_level_label() ) ?>
+								</p>
+							<?php endif ?>
+
+							<?php do_action( 'bp_custom_profile_edit_fields' ); ?>
+
+							<p class="description"><?php bp_the_profile_field_description(); ?></p>
+
+						</div>
+
+					<?php endwhile; ?>
+
+					<input type="hidden" name="signup_profile_field_ids" id="signup_profile_field_ids" value="<?php bp_the_profile_group_field_ids(); ?>" />
+
+					<?php endwhile; endif; endif; ?>
+
+					<?php do_action( 'bp_signup_profile_fields' ); ?>
+
+				</div><!-- #profile-details-section -->
+
+				<?php do_action( 'bp_after_signup_profile_fields' ); ?>
+
+			<?php endif; ?>
+
+			<?php if ( bp_get_blog_signup_allowed() ) : ?>
+
+				<?php do_action( 'bp_before_blog_details_fields' ); ?>
+
+				<?php /***** Blog Creation Details ******/ ?>
+
+				<div class="register-section" id="blog-details-section">
+
+					<h4><?php _e( 'Blog Details', 'buddypress' ); ?></h4>
+
+					<p><input type="checkbox" name="signup_with_blog" id="signup_with_blog" value="1"<?php if ( (int) bp_get_signup_with_blog_value() ) : ?> checked="checked"<?php endif; ?> /> <?php _e( 'Yes, I\'d like to create a new site', 'buddypress' ); ?></p>
+
+					<div id="blog-details"<?php if ( (int) bp_get_signup_with_blog_value() ) : ?>class="show"<?php endif; ?>>
+
+						<label for="signup_blog_url"><?php _e( 'Blog URL', 'buddypress' ); ?> <?php _e( '(required)', 'buddypress' ); ?></label>
+						<?php do_action( 'bp_signup_blog_url_errors' ); ?>
+
+						<?php if ( is_subdomain_install() ) : ?>
+							http:// <input type="text" name="signup_blog_url" id="signup_blog_url" value="<?php bp_signup_blog_url_value(); ?>" /> .<?php bp_blogs_subdomain_base(); ?>
+						<?php else : ?>
+							<?php echo home_url( '/' ); ?> <input type="text" name="signup_blog_url" id="signup_blog_url" value="<?php bp_signup_blog_url_value(); ?>" />
+						<?php endif; ?>
+
+						<label for="signup_blog_title"><?php _e( 'Site Title', 'buddypress' ); ?> <?php _e( '(required)', 'buddypress' ); ?></label>
+						<?php do_action( 'bp_signup_blog_title_errors' ); ?>
+						<input type="text" name="signup_blog_title" id="signup_blog_title" value="<?php bp_signup_blog_title_value(); ?>" />
+
+						<span class="label"><?php _e( 'I would like my site to appear in search engines, and in public listings around this network.', 'buddypress' ); ?>:</span>
+						<?php do_action( 'bp_signup_blog_privacy_errors' ); ?>
+
+						<label><input type="radio" name="signup_blog_privacy" id="signup_blog_privacy_public" value="public"<?php if ( 'public' == bp_get_signup_blog_privacy_value() || !bp_get_signup_blog_privacy_value() ) : ?> checked="checked"<?php endif; ?> /> <?php _e( 'Yes', 'buddypress' ); ?></label>
+						<label><input type="radio" name="signup_blog_privacy" id="signup_blog_privacy_private" value="private"<?php if ( 'private' == bp_get_signup_blog_privacy_value() ) : ?> checked="checked"<?php endif; ?> /> <?php _e( 'No', 'buddypress' ); ?></label>
+
+						<?php do_action( 'bp_blog_details_fields' ); ?>
+
+					</div>
+
+				</div><!-- #blog-details-section -->
+
+				<?php do_action( 'bp_after_blog_details_fields' ); ?>
+
+			<?php endif; ?>
+
+			<?php do_action( 'bp_before_registration_submit_buttons' ); ?>
+
+			<div class="submit">
+				<input type="submit" name="signup_submit" id="signup_submit" value="<?php _e( 'Complete Sign Up', 'buddypress' ); ?>" />
+			</div>
+
+			<?php do_action( 'bp_after_registration_submit_buttons' ); ?>
+
+			<?php wp_nonce_field( 'bp_new_signup' ); ?>
+
+		<?php endif; // request-details signup step ?>
+
+		<?php if ( 'completed-confirmation' == bp_get_current_signup_step() ) : ?>
+
+			<?php do_action( 'template_notices' ); ?>
+			<?php do_action( 'bp_before_registration_confirmed' ); ?>
+
+			<?php if ( bp_registration_needs_activation() ) : ?>
+				<p><?php _e( 'You have successfully created your account! To begin using this site you will need to activate your account via the email we have just sent to your address.', 'buddypress' ); ?></p>
+			<?php else : ?>
+				<p><?php _e( 'You have successfully created your account! Please log in using the username and password you have just created.', 'buddypress' ); ?></p>
+			<?php endif; ?>
+
+			<?php do_action( 'bp_after_registration_confirmed' ); ?>
+
+		<?php endif; // completed-confirmation signup step ?>
+
+		<?php do_action( 'bp_custom_signup_steps' ); ?>
+
+		</form>
+
+	</div>
+
+	<?php do_action( 'bp_after_register_page' ); ?>
+
+</div><!-- #buddypress -->
Index: /tags/1.9/bp-templates/bp-legacy/buddypress/members/single/activity.php
===================================================================
--- /tags/1.9/bp-templates/bp-legacy/buddypress/members/single/activity.php	(revision 7684)
+++ /tags/1.9/bp-templates/bp-legacy/buddypress/members/single/activity.php	(revision 7684)
@@ -0,0 +1,77 @@
+<?php
+
+/**
+ * BuddyPress - Users Activity
+ *
+ * @package BuddyPress
+ * @subpackage bp-legacy
+ */
+
+?>
+
+<div class="item-list-tabs no-ajax" id="subnav" role="navigation">
+	<ul>
+
+		<?php bp_get_options_nav(); ?>
+
+		<li id="activity-filter-select" class="last">
+			<label for="activity-filter-by"><?php _e( 'Show:', 'buddypress' ); ?></label>
+			<select id="activity-filter-by">
+				<option value="-1"><?php _e( 'Everything', 'buddypress' ); ?></option>
+				<option value="activity_update"><?php _e( 'Updates', 'buddypress' ); ?></option>
+
+				<?php
+				if ( !bp_is_current_action( 'groups' ) ) :
+					if ( bp_is_active( 'blogs' ) ) : ?>
+
+						<option value="new_blog_post"><?php _e( 'Posts', 'buddypress' ); ?></option>
+						<option value="new_blog_comment"><?php _e( 'Comments', 'buddypress' ); ?></option>
+
+					<?php
+					endif;
+
+					if ( bp_is_active( 'friends' ) ) : ?>
+
+						<option value="friendship_accepted,friendship_created"><?php _e( 'Friendships', 'buddypress' ); ?></option>
+
+					<?php endif;
+
+				endif;
+
+				if ( bp_is_active( 'forums' ) ) : ?>
+
+					<option value="new_forum_topic"><?php _e( 'Forum Topics', 'buddypress' ); ?></option>
+					<option value="new_forum_post"><?php _e( 'Forum Replies', 'buddypress' ); ?></option>
+
+				<?php endif;
+
+				if ( bp_is_active( 'groups' ) ) : ?>
+
+					<option value="created_group"><?php _e( 'New Groups', 'buddypress' ); ?></option>
+					<option value="joined_group"><?php _e( 'Group Memberships', 'buddypress' ); ?></option>
+
+				<?php endif;
+
+				do_action( 'bp_member_activity_filter_options' ); ?>
+
+			</select>
+		</li>
+	</ul>
+</div><!-- .item-list-tabs -->
+
+<?php do_action( 'bp_before_member_activity_post_form' ); ?>
+
+<?php
+if ( is_user_logged_in() && bp_is_my_profile() && ( !bp_current_action() || bp_is_current_action( 'just-me' ) ) )
+	bp_get_template_part( 'activity/post-form' );
+
+do_action( 'bp_after_member_activity_post_form' );
+do_action( 'bp_before_member_activity_content' ); ?>
+
+<div class="activity" role="main">
+
+	<?php bp_get_template_part( 'activity/activity-loop' ) ?>
+
+</div><!-- .activity -->
+
+<?php do_action( 'bp_after_member_activity_content' ); ?>
Index: /tags/1.9/bp-templates/bp-legacy/buddypress/members/single/blogs.php
===================================================================
--- /tags/1.9/bp-templates/bp-legacy/buddypress/members/single/blogs.php	(revision 7684)
+++ /tags/1.9/bp-templates/bp-legacy/buddypress/members/single/blogs.php	(revision 7684)
@@ -0,0 +1,52 @@
+<?php
+
+/**
+ * BuddyPress - Users Blogs
+ *
+ * @package BuddyPress
+ * @subpackage bp-legacy
+ */
+
+?>
+
+<div class="item-list-tabs" id="subnav" role="navigation">
+	<ul>
+
+		<?php bp_get_options_nav(); ?>
+
+		<li id="blogs-order-select" class="last filter">
+
+			<label for="blogs-all"><?php _e( 'Order By:', 'buddypress' ); ?></label>
+			<select id="blogs-all">
+				<option value="active"><?php _e( 'Last Active', 'buddypress' ); ?></option>
+				<option value="newest"><?php _e( 'Newest', 'buddypress' ); ?></option>
+				<option value="alphabetical"><?php _e( 'Alphabetical', 'buddypress' ); ?></option>
+
+				<?php do_action( 'bp_member_blog_order_options' ); ?>
+
+			</select>
+		</li>
+	</ul>
+</div><!-- .item-list-tabs -->
+
+<?php
+switch ( bp_current_action() ) :
+
+	// Home/My Blogs
+	case 'my-sites' :
+		do_action( 'bp_before_member_blogs_content' ); ?>
+
+		<div class="blogs myblogs" role="main">
+
+			<?php bp_get_template_part( 'blogs/blogs-loop' ) ?>
+
+		</div><!-- .blogs.myblogs -->
+
+		<?php do_action( 'bp_after_member_blogs_content' );
+		break;
+
+	// Any other
+	default :
+		bp_get_template_part( 'members/single/plugins' );
+		break;
+endswitch;
Index: /tags/1.9/bp-templates/bp-legacy/buddypress/members/single/forums.php
===================================================================
--- /tags/1.9/bp-templates/bp-legacy/buddypress/members/single/forums.php	(revision 7684)
+++ /tags/1.9/bp-templates/bp-legacy/buddypress/members/single/forums.php	(revision 7684)
@@ -0,0 +1,47 @@
+<?php
+
+/**
+ * BuddyPress - Users Forums
+ *
+ * @package BuddyPress
+ * @subpackage bp-legacy
+ */
+
+?>
+
+<div class="item-list-tabs no-ajax" id="subnav" role="navigation">
+	<ul>
+		<?php bp_get_options_nav(); ?>
+
+		<li id="forums-order-select" class="last filter">
+
+			<label for="forums-order-by"><?php _e( 'Order By:', 'buddypress' ); ?></label>
+			<select id="forums-order-by">
+				<option value="active"><?php _e( 'Last Active', 'buddypress' ); ?></option>
+				<option value="popular"><?php _e( 'Most Posts', 'buddypress' ); ?></option>
+				<option value="unreplied"><?php _e( 'Unreplied', 'buddypress' ); ?></option>
+
+				<?php do_action( 'bp_forums_directory_order_options' ); ?>
+
+			</select>
+		</li>
+	</ul>
+</div><!-- .item-list-tabs -->
+
+<?php
+
+if ( bp_is_current_action( 'favorites' ) ) :
+	bp_get_template_part( 'members/single/forums/topics' );
+
+else :
+	do_action( 'bp_before_member_forums_content' ); ?>
+
+	<div class="forums myforums">
+
+		<?php bp_get_template_part( 'forums/forums-loop' ) ?>
+
+	</div>
+
+	<?php do_action( 'bp_after_member_forums_content' ); ?>
+
+<?php endif; ?>
Index: /tags/1.9/bp-templates/bp-legacy/buddypress/members/single/forums/topics.php
===================================================================
--- /tags/1.9/bp-templates/bp-legacy/buddypress/members/single/forums/topics.php	(revision 7684)
+++ /tags/1.9/bp-templates/bp-legacy/buddypress/members/single/forums/topics.php	(revision 7684)
@@ -0,0 +1,7 @@
+<?php
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+?>
Index: /tags/1.9/bp-templates/bp-legacy/buddypress/members/single/friends.php
===================================================================
--- /tags/1.9/bp-templates/bp-legacy/buddypress/members/single/friends.php	(revision 7684)
+++ /tags/1.9/bp-templates/bp-legacy/buddypress/members/single/friends.php	(revision 7684)
@@ -0,0 +1,60 @@
+<?php
+
+/**
+ * BuddyPress - Users Friends
+ *
+ * @package BuddyPress
+ * @subpackage bp-legacy
+ */
+
+?>
+
+<div class="item-list-tabs no-ajax" id="subnav" role="navigation">
+	<ul>
+		<?php if ( bp_is_my_profile() ) bp_get_options_nav(); ?>
+
+		<?php if ( !bp_is_current_action( 'requests' ) ) : ?>
+
+			<li id="members-order-select" class="last filter">
+
+				<label for="members-friends"><?php _e( 'Order By:', 'buddypress' ); ?></label>
+				<select id="members-friends">
+					<option value="active"><?php _e( 'Last Active', 'buddypress' ); ?></option>
+					<option value="newest"><?php _e( 'Newest Registered', 'buddypress' ); ?></option>
+					<option value="alphabetical"><?php _e( 'Alphabetical', 'buddypress' ); ?></option>
+
+					<?php do_action( 'bp_member_blog_order_options' ); ?>
+
+				</select>
+			</li>
+
+		<?php endif; ?>
+
+	</ul>
+</div>
+
+<?php
+switch ( bp_current_action() ) :
+
+	// Home/My Friends
+	case 'my-friends' :
+		do_action( 'bp_before_member_friends_content' ); ?>
+
+		<div class="members friends">
+
+			<?php bp_get_template_part( 'members/members-loop' ) ?>
+
+		</div><!-- .members.friends -->
+
+		<?php do_action( 'bp_after_member_friends_content' );
+		break;
+
+	case 'requests' :
+		bp_get_template_part( 'members/single/friends/requests' );
+		break;
+
+	// Any other
+	default :
+		bp_get_template_part( 'members/single/plugins' );
+		break;
+endswitch;
Index: /tags/1.9/bp-templates/bp-legacy/buddypress/members/single/friends/requests.php
===================================================================
--- /tags/1.9/bp-templates/bp-legacy/buddypress/members/single/friends/requests.php	(revision 7684)
+++ /tags/1.9/bp-templates/bp-legacy/buddypress/members/single/friends/requests.php	(revision 7684)
@@ -0,0 +1,73 @@
+<?php do_action( 'bp_before_member_friend_requests_content' ); ?>
+
+<?php if ( bp_has_members( 'type=alphabetical&include=' . bp_get_friendship_requests() ) ) : ?>
+
+	<div id="pag-top" class="pagination no-ajax">
+
+		<div class="pag-count" id="member-dir-count-top">
+
+			<?php bp_members_pagination_count(); ?>
+
+		</div>
+
+		<div class="pagination-links" id="member-dir-pag-top">
+
+			<?php bp_members_pagination_links(); ?>
+
+		</div>
+
+	</div>
+
+	<ul id="friend-list" class="item-list" role="main">
+		<?php while ( bp_members() ) : bp_the_member(); ?>
+
+			<li id="friendship-<?php bp_friend_friendship_id(); ?>">
+				<div class="item-avatar">
+					<a href="<?php bp_member_link(); ?>"><?php bp_member_avatar(); ?></a>
+				</div>
+
+				<div class="item">
+					<div class="item-title"><a href="<?php bp_member_link(); ?>"><?php bp_member_name(); ?></a></div>
+					<div class="item-meta"><span class="activity"><?php bp_member_last_active(); ?></span></div>
+				</div>
+
+				<?php do_action( 'bp_friend_requests_item' ); ?>
+
+				<div class="action">
+					<a class="button accept" href="<?php bp_friend_accept_request_link(); ?>"><?php _e( 'Accept', 'buddypress' ); ?></a> &nbsp;
+					<a class="button reject" href="<?php bp_friend_reject_request_link(); ?>"><?php _e( 'Reject', 'buddypress' ); ?></a>
+
+					<?php do_action( 'bp_friend_requests_item_action' ); ?>
+				</div>
+			</li>
+
+		<?php endwhile; ?>
+	</ul>
+
+	<?php do_action( 'bp_friend_requests_content' ); ?>
+
+	<div id="pag-bottom" class="pagination no-ajax">
+
+		<div class="pag-count" id="member-dir-count-bottom">
+
+			<?php bp_members_pagination_count(); ?>
+
+		</div>
+
+		<div class="pagination-links" id="member-dir-pag-bottom">
+
+			<?php bp_members_pagination_links(); ?>
+
+		</div>
+
+	</div>
+
+<?php else: ?>
+
+	<div id="message" class="info">
+		<p><?php _e( 'You have no pending friendship requests.', 'buddypress' ); ?></p>
+	</div>
+
+<?php endif;?>
+
+<?php do_action( 'bp_after_member_friend_requests_content' ); ?>
Index: /tags/1.9/bp-templates/bp-legacy/buddypress/members/single/groups.php
===================================================================
--- /tags/1.9/bp-templates/bp-legacy/buddypress/members/single/groups.php	(revision 7684)
+++ /tags/1.9/bp-templates/bp-legacy/buddypress/members/single/groups.php	(revision 7684)
@@ -0,0 +1,63 @@
+<?php
+
+/**
+ * BuddyPress - Users Groups
+ *
+ * @package BuddyPress
+ * @subpackage bp-legacy
+ */
+
+?>
+
+<div class="item-list-tabs no-ajax" id="subnav" role="navigation">
+	<ul>
+		<?php if ( bp_is_my_profile() ) bp_get_options_nav(); ?>
+
+		<?php if ( !bp_is_current_action( 'invites' ) ) : ?>
+
+			<li id="groups-order-select" class="last filter">
+
+				<label for="groups-sort-by"><?php _e( 'Order By:', 'buddypress' ); ?></label>
+				<select id="groups-sort-by">
+					<option value="active"><?php _e( 'Last Active', 'buddypress' ); ?></option>
+					<option value="popular"><?php _e( 'Most Members', 'buddypress' ); ?></option>
+					<option value="newest"><?php _e( 'Newly Created', 'buddypress' ); ?></option>
+					<option value="alphabetical"><?php _e( 'Alphabetical', 'buddypress' ); ?></option>
+
+					<?php do_action( 'bp_member_group_order_options' ); ?>
+
+				</select>
+			</li>
+
+		<?php endif; ?>
+
+	</ul>
+</div><!-- .item-list-tabs -->
+
+<?php
+
+switch ( bp_current_action() ) :
+
+	// Home/My Groups
+	case 'my-groups' :
+		do_action( 'bp_before_member_groups_content' ); ?>
+
+		<div class="groups mygroups">
+
+			<?php bp_get_template_part( 'groups/groups-loop' ); ?>
+
+		</div>
+
+		<?php do_action( 'bp_after_member_groups_content' );
+		break;
+
+	// Group Invitations
+	case 'invites' :
+		bp_get_template_part( 'members/single/groups/invites' );
+		break;
+
+	// Any other
+	default :
+		bp_get_template_part( 'members/single/plugins' );
+		break;
+endswitch;
Index: /tags/1.9/bp-templates/bp-legacy/buddypress/members/single/groups/invites.php
===================================================================
--- /tags/1.9/bp-templates/bp-legacy/buddypress/members/single/groups/invites.php	(revision 7684)
+++ /tags/1.9/bp-templates/bp-legacy/buddypress/members/single/groups/invites.php	(revision 7684)
@@ -0,0 +1,42 @@
+<?php do_action( 'bp_before_group_invites_content' ); ?>
+
+<?php if ( bp_has_groups( 'type=invites&user_id=' . bp_loggedin_user_id() ) ) : ?>
+
+	<ul id="group-list" class="invites item-list" role="main">
+
+		<?php while ( bp_groups() ) : bp_the_group(); ?>
+
+			<li>
+				<div class="item-avatar">
+					<a href="<?php bp_group_permalink(); ?>"><?php bp_group_avatar( 'type=thumb&width=50&height=50' ); ?></a>
+				</div>
+
+				<h4><a href="<?php bp_group_permalink(); ?>"><?php bp_group_name(); ?></a><span class="small"> - <?php printf( _n( '1 member', '%d members', bp_get_group_total_members( false ), 'buddypress' ), bp_get_group_total_members( false )  ); ?></span></h4>
+
+				<p class="desc">
+					<?php bp_group_description_excerpt(); ?>
+				</p>
+
+				<?php do_action( 'bp_group_invites_item' ); ?>
+
+				<div class="action">
+					<a class="button accept" href="<?php bp_group_accept_invite_link(); ?>"><?php _e( 'Accept', 'buddypress' ); ?></a> &nbsp;
+					<a class="button reject confirm" href="<?php bp_group_reject_invite_link(); ?>"><?php _e( 'Reject', 'buddypress' ); ?></a>
+
+					<?php do_action( 'bp_group_invites_item_action' ); ?>
+
+				</div>
+			</li>
+
+		<?php endwhile; ?>
+	</ul>
+
+<?php else: ?>
+
+	<div id="message" class="info" role="main">
+		<p><?php _e( 'You have no outstanding group invites.', 'buddypress' ); ?></p>
+	</div>
+
+<?php endif;?>
+
+<?php do_action( 'bp_after_group_invites_content' ); ?>
Index: /tags/1.9/bp-templates/bp-legacy/buddypress/members/single/home.php
===================================================================
--- /tags/1.9/bp-templates/bp-legacy/buddypress/members/single/home.php	(revision 7684)
+++ /tags/1.9/bp-templates/bp-legacy/buddypress/members/single/home.php	(revision 7684)
@@ -0,0 +1,66 @@
+<div id="buddypress">
+
+	<?php do_action( 'bp_before_member_home_content' ); ?>
+
+	<div id="item-header" role="complementary">
+
+		<?php bp_get_template_part( 'members/single/member-header' ) ?>
+
+	</div><!-- #item-header -->
+
+	<div id="item-nav">
+		<div class="item-list-tabs no-ajax" id="object-nav" role="navigation">
+			<ul>
+
+				<?php bp_get_displayed_user_nav(); ?>
+
+				<?php do_action( 'bp_member_options_nav' ); ?>
+
+			</ul>
+		</div>
+	</div><!-- #item-nav -->
+
+	<div id="item-body" role="main">
+
+		<?php do_action( 'bp_before_member_body' );
+
+		if ( bp_is_user_activity() || !bp_current_component() ) :
+			bp_get_template_part( 'members/single/activity' );
+
+		elseif ( bp_is_user_blogs() ) :
+			bp_get_template_part( 'members/single/blogs'    );
+
+		elseif ( bp_is_user_friends() ) :
+			bp_get_template_part( 'members/single/friends'  );
+
+		elseif ( bp_is_user_groups() ) :
+			bp_get_template_part( 'members/single/groups'   );
+
+		elseif ( bp_is_user_messages() ) :
+			bp_get_template_part( 'members/single/messages' );
+
+		elseif ( bp_is_user_profile() ) :
+			bp_get_template_part( 'members/single/profile'  );
+
+		elseif ( bp_is_user_forums() ) :
+			bp_get_template_part( 'members/single/forums'   );
+
+		elseif ( bp_is_user_notifications() ) :
+			bp_get_template_part( 'members/single/notifications' );
+
+		elseif ( bp_is_user_settings() ) :
+			bp_get_template_part( 'members/single/settings' );
+
+		// If nothing sticks, load a generic template
+		else :
+			bp_get_template_part( 'members/single/plugins'  );
+
+		endif;
+
+		do_action( 'bp_after_member_body' ); ?>
+
+	</div><!-- #item-body -->
+
+	<?php do_action( 'bp_after_member_home_content' ); ?>
+
+</div><!-- #buddypress -->
Index: /tags/1.9/bp-templates/bp-legacy/buddypress/members/single/member-header.php
===================================================================
--- /tags/1.9/bp-templates/bp-legacy/buddypress/members/single/member-header.php	(revision 7684)
+++ /tags/1.9/bp-templates/bp-legacy/buddypress/members/single/member-header.php	(revision 7684)
@@ -0,0 +1,65 @@
+<?php
+
+/**
+ * BuddyPress - Users Header
+ *
+ * @package BuddyPress
+ * @subpackage bp-legacy
+ */
+
+?>
+
+<?php do_action( 'bp_before_member_header' ); ?>
+
+<div id="item-header-avatar">
+	<a href="<?php bp_displayed_user_link(); ?>">
+
+		<?php bp_displayed_user_avatar( 'type=full' ); ?>
+
+	</a>
+</div><!-- #item-header-avatar -->
+
+<div id="item-header-content">
+
+	<?php if ( bp_is_active( 'activity' ) && bp_activity_do_mentions() ) : ?>
+		<h2 class="user-nicename">@<?php bp_displayed_user_mentionname(); ?></h2>
+	<?php endif; ?>
+
+	<span class="activity"><?php bp_last_activity( bp_displayed_user_id() ); ?></span>
+
+	<?php do_action( 'bp_before_member_header_meta' ); ?>
+
+	<div id="item-meta">
+
+		<?php if ( bp_is_active( 'activity' ) ) : ?>
+
+			<div id="latest-update">
+
+				<?php bp_activity_latest_update( bp_displayed_user_id() ); ?>
+
+			</div>
+
+		<?php endif; ?>
+
+		<div id="item-buttons">
+
+			<?php do_action( 'bp_member_header_actions' ); ?>
+
+		</div><!-- #item-buttons -->
+
+		<?php
+		/***
+		 * If you'd like to show specific profile fields here use:
+		 * bp_member_profile_data( 'field=About Me' ); -- Pass the name of the field
+		 */
+		 do_action( 'bp_profile_header_meta' );
+
+		 ?>
+
+	</div><!-- #item-meta -->
+
+</div><!-- #item-header-content -->
+
+<?php do_action( 'bp_after_member_header' ); ?>
+
+<?php do_action( 'template_notices' ); ?>
Index: /tags/1.9/bp-templates/bp-legacy/buddypress/members/single/messages.php
===================================================================
--- /tags/1.9/bp-templates/bp-legacy/buddypress/members/single/messages.php	(revision 7684)
+++ /tags/1.9/bp-templates/bp-legacy/buddypress/members/single/messages.php	(revision 7684)
@@ -0,0 +1,67 @@
+<?php
+
+/**
+ * BuddyPress - Users Messages
+ *
+ * @package BuddyPress
+ * @subpackage bp-legacy
+ */
+
+?>
+
+<div class="item-list-tabs no-ajax" id="subnav" role="navigation">
+	<ul>
+
+		<?php bp_get_options_nav(); ?>
+
+	</ul>
+	
+	<?php if ( bp_is_messages_inbox() || bp_is_messages_sentbox() ) : ?>
+
+		<div class="message-search"><?php bp_message_search_form(); ?></div>
+
+	<?php endif; ?>
+
+</div><!-- .item-list-tabs -->
+
+<?php
+switch ( bp_current_action() ) :
+
+	// Inbox/Sentbox
+	case 'inbox'   :
+	case 'sentbox' :
+		do_action( 'bp_before_member_messages_content' ); ?>
+
+		<div class="messages" role="main">
+			<?php bp_get_template_part( 'members/single/messages/messages-loop' ); ?>
+		</div><!-- .messages -->
+
+		<?php do_action( 'bp_after_member_messages_content' );
+		break;
+
+	// Single Message View
+	case 'view' :
+		bp_get_template_part( 'members/single/messages/single' );
+		break;
+
+	// Compose
+	case 'compose' :
+		bp_get_template_part( 'members/single/messages/compose' );
+		break;
+
+	// Sitewide Notices
+	case 'notices' :
+		do_action( 'bp_before_member_messages_content' ); ?>
+
+		<div class="messages" role="main">
+			<?php bp_get_template_part( 'members/single/messages/notices-loop' );; ?>
+		</div><!-- .messages -->
+
+		<?php do_action( 'bp_after_member_messages_content' );
+		break;
+
+	// Any other
+	default :
+		bp_get_template_part( 'members/single/plugins' );
+		break;
+endswitch;
Index: /tags/1.9/bp-templates/bp-legacy/buddypress/members/single/messages/compose.php
===================================================================
--- /tags/1.9/bp-templates/bp-legacy/buddypress/members/single/messages/compose.php	(revision 7684)
+++ /tags/1.9/bp-templates/bp-legacy/buddypress/members/single/messages/compose.php	(revision 7684)
@@ -0,0 +1,37 @@
+<form action="<?php bp_messages_form_action('compose' ); ?>" method="post" id="send_message_form" class="standard-form" role="main" enctype="multipart/form-data">
+
+	<?php do_action( 'bp_before_messages_compose_content' ); ?>
+
+	<label for="send-to-input"><?php _e("Send To (Username or Friend's Name)", 'buddypress' ); ?></label>
+	<ul class="first acfb-holder">
+		<li>
+			<?php bp_message_get_recipient_tabs(); ?>
+			<input type="text" name="send-to-input" class="send-to-input" id="send-to-input" />
+		</li>
+	</ul>
+
+	<?php if ( bp_current_user_can( 'bp_moderate' ) ) : ?>
+		<input type="checkbox" id="send-notice" name="send-notice" value="1" /> <?php _e( "This is a notice to all users.", "buddypress" ); ?>
+	<?php endif; ?>
+
+	<label for="subject"><?php _e( 'Subject', 'buddypress' ); ?></label>
+	<input type="text" name="subject" id="subject" value="<?php bp_messages_subject_value(); ?>" />
+
+	<label for="content"><?php _e( 'Message', 'buddypress' ); ?></label>
+	<textarea name="content" id="message_content" rows="15" cols="40"><?php bp_messages_content_value(); ?></textarea>
+
+	<input type="hidden" name="send_to_usernames" id="send-to-usernames" value="<?php bp_message_get_recipient_usernames(); ?>" class="<?php bp_message_get_recipient_usernames(); ?>" />
+
+	<?php do_action( 'bp_after_messages_compose_content' ); ?>
+
+	<div class="submit">
+		<input type="submit" value="<?php _e( "Send Message", 'buddypress' ); ?>" name="send" id="send" />
+	</div>
+
+	<?php wp_nonce_field( 'messages_send_message' ); ?>
+</form>
+
+<script type="text/javascript">
+	document.getElementById("send-to-input").focus();
+</script>
+
Index: /tags/1.9/bp-templates/bp-legacy/buddypress/members/single/messages/messages-loop.php
===================================================================
--- /tags/1.9/bp-templates/bp-legacy/buddypress/members/single/messages/messages-loop.php	(revision 7684)
+++ /tags/1.9/bp-templates/bp-legacy/buddypress/members/single/messages/messages-loop.php	(revision 7684)
@@ -0,0 +1,74 @@
+<?php do_action( 'bp_before_member_messages_loop' ); ?>
+
+<?php if ( bp_has_message_threads( bp_ajax_querystring( 'messages' ) ) ) : ?>
+
+	<div class="pagination no-ajax" id="user-pag">
+
+		<div class="pag-count" id="messages-dir-count">
+			<?php bp_messages_pagination_count(); ?>
+		</div>
+
+		<div class="pagination-links" id="messages-dir-pag">
+			<?php bp_messages_pagination(); ?>
+		</div>
+
+	</div><!-- .pagination -->
+
+	<?php do_action( 'bp_after_member_messages_pagination' ); ?>
+
+	<?php do_action( 'bp_before_member_messages_threads'   ); ?>
+
+	<table id="message-threads" class="messages-notices">
+		<?php while ( bp_message_threads() ) : bp_message_thread(); ?>
+
+			<tr id="m-<?php bp_message_thread_id(); ?>" class="<?php bp_message_css_class(); ?><?php if ( bp_message_thread_has_unread() ) : ?> unread<?php else: ?> read<?php endif; ?>">
+				<td width="1%" class="thread-count">
+					<span class="unread-count"><?php bp_message_thread_unread_count(); ?></span>
+				</td>
+				<td width="1%" class="thread-avatar"><?php bp_message_thread_avatar(); ?></td>
+
+				<?php if ( 'sentbox' != bp_current_action() ) : ?>
+					<td width="30%" class="thread-from">
+						<?php _e( 'From:', 'buddypress' ); ?> <?php bp_message_thread_from(); ?><br />
+						<span class="activity"><?php bp_message_thread_last_post_date(); ?></span>
+					</td>
+				<?php else: ?>
+					<td width="30%" class="thread-from">
+						<?php _e( 'To:', 'buddypress' ); ?> <?php bp_message_thread_to(); ?><br />
+						<span class="activity"><?php bp_message_thread_last_post_date(); ?></span>
+					</td>
+				<?php endif; ?>
+
+				<td width="50%" class="thread-info">
+					<p><a href="<?php bp_message_thread_view_link(); ?>" title="<?php _e( "View Message", "buddypress" ); ?>"><?php bp_message_thread_subject(); ?></a></p>
+					<p class="thread-excerpt"><?php bp_message_thread_excerpt(); ?></p>
+				</td>
+
+				<?php do_action( 'bp_messages_inbox_list_item' ); ?>
+
+				<td width="13%" class="thread-options">
+					<input type="checkbox" name="message_ids[]" value="<?php bp_message_thread_id(); ?>" />
+					<a class="button confirm" href="<?php bp_message_thread_delete_link(); ?>" title="<?php _e( "Delete Message", "buddypress" ); ?>"><?php _e( 'Delete', 'buddypress' ); ?></a> &nbsp;
+				</td>
+			</tr>
+
+		<?php endwhile; ?>
+	</table><!-- #message-threads -->
+
+	<div class="messages-options-nav">
+		<?php bp_messages_options(); ?>
+	</div><!-- .messages-options-nav -->
+
+	<?php do_action( 'bp_after_member_messages_threads' ); ?>
+
+	<?php do_action( 'bp_after_member_messages_options' ); ?>
+
+<?php else: ?>
+
+	<div id="message" class="info">
+		<p><?php _e( 'Sorry, no messages were found.', 'buddypress' ); ?></p>
+	</div>
+
+<?php endif;?>
+
+<?php do_action( 'bp_after_member_messages_loop' ); ?>
Index: /tags/1.9/bp-templates/bp-legacy/buddypress/members/single/messages/notices-loop.php
===================================================================
--- /tags/1.9/bp-templates/bp-legacy/buddypress/members/single/messages/notices-loop.php	(revision 7684)
+++ /tags/1.9/bp-templates/bp-legacy/buddypress/members/single/messages/notices-loop.php	(revision 7684)
@@ -0,0 +1,59 @@
+<?php do_action( 'bp_before_notices_loop' ); ?>
+
+<?php if ( bp_has_message_threads() ) : ?>
+
+	<div class="pagination no-ajax" id="user-pag">
+
+		<div class="pag-count" id="messages-dir-count">
+			<?php bp_messages_pagination_count(); ?>
+		</div>
+
+		<div class="pagination-links" id="messages-dir-pag">
+			<?php bp_messages_pagination(); ?>
+		</div>
+
+	</div><!-- .pagination -->
+
+	<?php do_action( 'bp_after_notices_pagination' ); ?>
+	<?php do_action( 'bp_before_notices' ); ?>
+
+	<table id="message-threads" class="messages-notices">
+		<?php while ( bp_message_threads() ) : bp_message_thread(); ?>
+			<tr id="notice-<?php bp_message_notice_id(); ?>" class="<?php bp_message_css_class(); ?>">
+				<td width="1%"></td>
+				<td width="38%">
+					<strong><?php bp_message_notice_subject(); ?></strong>
+					<?php bp_message_notice_text(); ?>
+				</td>
+				<td width="21%">
+
+					<?php if ( bp_messages_is_active_notice() ) : ?>
+
+						<strong><?php bp_messages_is_active_notice(); ?></strong>
+
+					<?php endif; ?>
+
+					<span class="activity"><?php _e( 'Sent:', 'buddypress' ); ?> <?php bp_message_notice_post_date(); ?></span>
+				</td>
+
+				<?php do_action( 'bp_notices_list_item' ); ?>
+
+				<td width="10%">
+					<a class="button" href="<?php bp_message_activate_deactivate_link(); ?>" class="confirm"><?php bp_message_activate_deactivate_text(); ?></a>
+					<a class="button" href="<?php bp_message_notice_delete_link(); ?>" class="confirm" title="<?php _e( "Delete Message", "buddypress" ); ?>">x</a>
+				</td>
+			</tr>
+		<?php endwhile; ?>
+	</table><!-- #message-threads -->
+
+	<?php do_action( 'bp_after_notices' ); ?>
+
+<?php else: ?>
+
+	<div id="message" class="info">
+		<p><?php _e( 'Sorry, no notices were found.', 'buddypress' ); ?></p>
+	</div>
+
+<?php endif;?>
+
+<?php do_action( 'bp_after_notices_loop' ); ?>
Index: /tags/1.9/bp-templates/bp-legacy/buddypress/members/single/messages/single.php
===================================================================
--- /tags/1.9/bp-templates/bp-legacy/buddypress/members/single/messages/single.php	(revision 7684)
+++ /tags/1.9/bp-templates/bp-legacy/buddypress/members/single/messages/single.php	(revision 7684)
@@ -0,0 +1,121 @@
+<div id="message-thread" role="main">
+
+	<?php do_action( 'bp_before_message_thread_content' ); ?>
+
+	<?php if ( bp_thread_has_messages() ) : ?>
+
+		<h3 id="message-subject"><?php bp_the_thread_subject(); ?></h3>
+
+		<p id="message-recipients">
+			<span class="highlight">
+
+				<?php if ( !bp_get_the_thread_recipients() ) : ?>
+
+					<?php _e( 'You are alone in this conversation.', 'buddypress' ); ?>
+
+				<?php else : ?>
+
+					<?php printf( __( 'Conversation between %s and you.', 'buddypress' ), bp_get_the_thread_recipients() ); ?>
+
+				<?php endif; ?>
+
+			</span>
+
+			<a class="button confirm" href="<?php bp_the_thread_delete_link(); ?>" title="<?php _e( "Delete Message", "buddypress" ); ?>"><?php _e( 'Delete', 'buddypress' ); ?></a> &nbsp;
+		</p>
+
+		<?php do_action( 'bp_before_message_thread_list' ); ?>
+
+		<?php while ( bp_thread_messages() ) : bp_thread_the_message(); ?>
+
+			<div class="message-box <?php bp_the_thread_message_alt_class(); ?>">
+
+				<div class="message-metadata">
+
+					<?php do_action( 'bp_before_message_meta' ); ?>
+
+					<?php bp_the_thread_message_sender_avatar( 'type=thumb&width=30&height=30' ); ?>
+
+					<?php if ( bp_get_the_thread_message_sender_link() ) : ?>
+
+						<strong><a href="<?php bp_the_thread_message_sender_link(); ?>" title="<?php bp_the_thread_message_sender_name(); ?>"><?php bp_the_thread_message_sender_name(); ?></a></strong>
+
+					<?php else : ?>
+
+						<strong><?php bp_the_thread_message_sender_name(); ?></strong>
+
+					<?php endif; ?>
+
+					<span class="activity"><?php bp_the_thread_message_time_since(); ?></span>
+
+					<?php do_action( 'bp_after_message_meta' ); ?>
+
+				</div><!-- .message-metadata -->
+
+				<?php do_action( 'bp_before_message_content' ); ?>
+
+				<div class="message-content">
+
+					<?php bp_the_thread_message_content(); ?>
+
+				</div><!-- .message-content -->
+
+				<?php do_action( 'bp_after_message_content' ); ?>
+
+				<div class="clear"></div>
+
+			</div><!-- .message-box -->
+
+		<?php endwhile; ?>
+
+		<?php do_action( 'bp_after_message_thread_list' ); ?>
+
+		<?php do_action( 'bp_before_message_thread_reply' ); ?>
+
+		<form id="send-reply" action="<?php bp_messages_form_action(); ?>" method="post" class="standard-form">
+
+			<div class="message-box">
+
+				<div class="message-metadata">
+
+					<?php do_action( 'bp_before_message_meta' ); ?>
+
+					<div class="avatar-box">
+						<?php bp_loggedin_user_avatar( 'type=thumb&height=30&width=30' ); ?>
+
+						<strong><?php _e( 'Send a Reply', 'buddypress' ); ?></strong>
+					</div>
+
+					<?php do_action( 'bp_after_message_meta' ); ?>
+
+				</div><!-- .message-metadata -->
+
+				<div class="message-content">
+
+					<?php do_action( 'bp_before_message_reply_box' ); ?>
+
+					<textarea name="content" id="message_content" rows="15" cols="40"></textarea>
+
+					<?php do_action( 'bp_after_message_reply_box' ); ?>
+
+					<div class="submit">
+						<input type="submit" name="send" value="<?php _e( 'Send Reply', 'buddypress' ); ?>" id="send_reply_button"/>
+					</div>
+
+					<input type="hidden" id="thread_id" name="thread_id" value="<?php bp_the_thread_id(); ?>" />
+					<input type="hidden" id="messages_order" name="messages_order" value="<?php bp_thread_messages_order(); ?>" />
+					<?php wp_nonce_field( 'messages_send_message', 'send_message_nonce' ); ?>
+
+				</div><!-- .message-content -->
+
+			</div><!-- .message-box -->
+
+		</form><!-- #send-reply -->
+
+		<?php do_action( 'bp_after_message_thread_reply' ); ?>
+
+	<?php endif; ?>
+
+	<?php do_action( 'bp_after_message_thread_content' ); ?>
+
+</div>
Index: /tags/1.9/bp-templates/bp-legacy/buddypress/members/single/notifications.php
===================================================================
--- /tags/1.9/bp-templates/bp-legacy/buddypress/members/single/notifications.php	(revision 7684)
+++ /tags/1.9/bp-templates/bp-legacy/buddypress/members/single/notifications.php	(revision 7684)
@@ -0,0 +1,39 @@
+<?php
+
+/**
+ * BuddyPress - Users Notifications
+ *
+ * @package BuddyPress
+ * @subpackage bp-legacy
+ */
+
+?>
+
+<div class="item-list-tabs no-ajax" id="subnav" role="navigation">
+	<ul>
+		<?php bp_get_options_nav(); ?>
+
+		<li id="members-order-select" class="last filter">
+			<?php bp_notifications_sort_order_form(); ?>
+		</li>
+	</ul>
+</div>
+
+<?php
+switch ( bp_current_action() ) :
+
+	// Unread
+	case 'unread' :
+		bp_get_template_part( 'members/single/notifications/unread' );
+		break;
+
+	// Read
+	case 'read' :
+		bp_get_template_part( 'members/single/notifications/read' );
+		break;
+
+	// Any other
+	default :
+		bp_get_template_part( 'members/single/plugins' );
+		break;
+endswitch;
Index: /tags/1.9/bp-templates/bp-legacy/buddypress/members/single/notifications/feedback-no-notifications.php
===================================================================
--- /tags/1.9/bp-templates/bp-legacy/buddypress/members/single/notifications/feedback-no-notifications.php	(revision 7684)
+++ /tags/1.9/bp-templates/bp-legacy/buddypress/members/single/notifications/feedback-no-notifications.php	(revision 7684)
@@ -0,0 +1,29 @@
+<div id="message" class="info">
+
+	<?php if ( bp_is_current_action( 'unread' ) ) : ?>
+
+		<?php if ( bp_is_my_profile() ) : ?>
+
+			<p><?php _e( 'You have no unread notifications.', 'buddypress' ); ?></p>
+
+		<?php else : ?>
+
+			<p><?php _e( 'This member has no unread notifications.', 'buddypress' ); ?></p>
+
+		<?php endif; ?>
+			
+	<?php else : ?>
+			
+		<?php if ( bp_is_my_profile() ) : ?>
+
+			<p><?php _e( 'You have no notifications.', 'buddypress' ); ?></p>
+
+		<?php else : ?>
+
+			<p><?php _e( 'This member has no notifications.', 'buddypress' ); ?></p>
+
+		<?php endif; ?>
+
+	<?php endif; ?>
+
+</div>
Index: /tags/1.9/bp-templates/bp-legacy/buddypress/members/single/notifications/notifications-loop.php
===================================================================
--- /tags/1.9/bp-templates/bp-legacy/buddypress/members/single/notifications/notifications-loop.php	(revision 7684)
+++ /tags/1.9/bp-templates/bp-legacy/buddypress/members/single/notifications/notifications-loop.php	(revision 7684)
@@ -0,0 +1,25 @@
+<table class="notifications">
+	<thead>
+		<tr>
+			<th class="icon"></th>
+			<th class="title"><?php _e( 'Notification', 'buddypress' ); ?></th>
+			<th class="date"><?php _e( 'Date Received', 'buddypress' ); ?></th>
+			<th class="actions"><?php _e( 'Actions',    'buddypress' ); ?></th>
+		</tr>
+	</thead>
+
+	<tbody>
+
+		<?php while ( bp_the_notifications() ) : bp_the_notification(); ?>
+
+			<tr>
+				<td></td>
+				<td><?php bp_the_notification_description();  ?></td>
+				<td><?php bp_the_notification_time_since();   ?></td>
+				<td><?php bp_the_notification_action_links(); ?></td>
+			</tr>
+
+		<?php endwhile; ?>
+
+	</tbody>
+</table>
Index: /tags/1.9/bp-templates/bp-legacy/buddypress/members/single/notifications/read.php
===================================================================
--- /tags/1.9/bp-templates/bp-legacy/buddypress/members/single/notifications/read.php	(revision 7684)
+++ /tags/1.9/bp-templates/bp-legacy/buddypress/members/single/notifications/read.php	(revision 7684)
@@ -0,0 +1,29 @@
+<?php if ( bp_has_notifications() ) : ?>
+
+	<div id="pag-top" class="pagination no-ajax">
+		<div class="pag-count" id="notifications-count-top">
+			<?php bp_notifications_pagination_count(); ?>
+		</div>
+
+		<div class="pagination-links" id="notifications-pag-top">
+			<?php bp_notifications_pagination_links(); ?>
+		</div>
+	</div>
+
+	<?php bp_get_template_part( 'members/single/notifications/notifications-loop' ); ?>
+
+	<div id="pag-bottom" class="pagination no-ajax">
+		<div class="pag-count" id="notifications-count-bottom">
+			<?php bp_notifications_pagination_count(); ?>
+		</div>
+
+		<div class="pagination-links" id="notifications-pag-bottom">
+			<?php bp_notifications_pagination_links(); ?>
+		</div>
+	</div>
+
+<?php else : ?>
+
+	<?php bp_get_template_part( 'members/single/notifications/feedback-no-notifications' ); ?>
+
+<?php endif;
Index: /tags/1.9/bp-templates/bp-legacy/buddypress/members/single/notifications/unread.php
===================================================================
--- /tags/1.9/bp-templates/bp-legacy/buddypress/members/single/notifications/unread.php	(revision 7684)
+++ /tags/1.9/bp-templates/bp-legacy/buddypress/members/single/notifications/unread.php	(revision 7684)
@@ -0,0 +1,29 @@
+<?php if ( bp_has_notifications() ) : ?>
+
+	<div id="pag-top" class="pagination no-ajax">
+		<div class="pag-count" id="notifications-count-top">
+			<?php bp_notifications_pagination_count(); ?>
+		</div>
+
+		<div class="pagination-links" id="notifications-pag-top">
+			<?php bp_notifications_pagination_links(); ?>
+		</div>
+	</div>
+
+	<?php bp_get_template_part( 'members/single/notifications/notifications-loop' ); ?>
+
+	<div id="pag-bottom" class="pagination no-ajax">
+		<div class="pag-count" id="notifications-count-bottom">
+			<?php bp_notifications_pagination_count(); ?>
+		</div>
+
+		<div class="pagination-links" id="notifications-pag-bottom">
+			<?php bp_notifications_pagination_links(); ?>
+		</div>
+	</div>
+
+<?php else : ?>
+
+	<?php bp_get_template_part( 'members/single/notifications/feedback-no-notifications' ); ?>
+
+<?php endif;
Index: /tags/1.9/bp-templates/bp-legacy/buddypress/members/single/plugins.php
===================================================================
--- /tags/1.9/bp-templates/bp-legacy/buddypress/members/single/plugins.php	(revision 7684)
+++ /tags/1.9/bp-templates/bp-legacy/buddypress/members/single/plugins.php	(revision 7684)
@@ -0,0 +1,31 @@
+<?php
+/**
+ * BuddyPress - Users Plugins Template
+ *
+ * 3rd-party plugins should use this template to easily add template
+ * support to their plugins for the members component.
+ *
+ * @package BuddyPress
+ * @subpackage bp-legacy
+ */
+?>
+
+		<?php do_action( 'bp_before_member_plugin_template' ); ?>
+
+		<?php if ( ! bp_is_current_component_core() ) : ?>
+
+		<div class="item-list-tabs no-ajax" id="subnav">
+			<ul>
+				<?php bp_get_options_nav(); ?>
+
+				<?php do_action( 'bp_member_plugin_options_nav' ); ?>
+			</ul>
+		</div><!-- .item-list-tabs -->
+
+		<?php endif; ?>
+
+		<h3><?php do_action( 'bp_template_title' ); ?></h3>
+
+		<?php do_action( 'bp_template_content' ); ?>
+
+		<?php do_action( 'bp_after_member_plugin_template' ); ?>
Index: /tags/1.9/bp-templates/bp-legacy/buddypress/members/single/profile.php
===================================================================
--- /tags/1.9/bp-templates/bp-legacy/buddypress/members/single/profile.php	(revision 7684)
+++ /tags/1.9/bp-templates/bp-legacy/buddypress/members/single/profile.php	(revision 7684)
@@ -0,0 +1,54 @@
+<?php
+
+/**
+ * BuddyPress - Users Profile
+ *
+ * @package BuddyPress
+ * @subpackage bp-legacy
+ */
+
+?>
+
+<div class="item-list-tabs no-ajax" id="subnav" role="navigation">
+	<ul>
+		<?php bp_get_options_nav(); ?>
+	</ul>
+</div><!-- .item-list-tabs -->
+
+<?php do_action( 'bp_before_profile_content' ); ?>
+
+<div class="profile" role="main">
+
+<?php switch ( bp_current_action() ) :
+
+	// Edit
+	case 'edit'   :
+		bp_get_template_part( 'members/single/profile/edit' );
+		break;
+
+	// Change Avatar
+	case 'change-avatar' :
+		bp_get_template_part( 'members/single/profile/change-avatar' );
+		break;
+
+	// Compose
+	case 'public' :
+
+		// Display XProfile
+		if ( bp_is_active( 'xprofile' ) )
+			bp_get_template_part( 'members/single/profile/profile-loop' );
+
+		// Display WordPress profile (fallback)
+		else
+			bp_get_template_part( 'members/single/profile/profile-wp' );
+
+		break;
+
+	// Any other
+	default :
+		bp_get_template_part( 'members/single/plugins' );
+		break;
+endswitch; ?>
+</div><!-- .profile -->
+
+<?php do_action( 'bp_after_profile_content' ); ?>
Index: /tags/1.9/bp-templates/bp-legacy/buddypress/members/single/profile/change-avatar.php
===================================================================
--- /tags/1.9/bp-templates/bp-legacy/buddypress/members/single/profile/change-avatar.php	(revision 7684)
+++ /tags/1.9/bp-templates/bp-legacy/buddypress/members/single/profile/change-avatar.php	(revision 7684)
@@ -0,0 +1,59 @@
+<h4><?php _e( 'Change Avatar', 'buddypress' ); ?></h4>
+
+<?php do_action( 'bp_before_profile_avatar_upload_content' ); ?>
+
+<?php if ( !(int)bp_get_option( 'bp-disable-avatar-uploads' ) ) : ?>
+
+	<p><?php _e( 'Your avatar will be used on your profile and throughout the site. If there is a <a href="http://gravatar.com">Gravatar</a> associated with your account email we will use that, or you can upload an image from your computer.', 'buddypress' ); ?></p>
+
+	<form action="" method="post" id="avatar-upload-form" class="standard-form" enctype="multipart/form-data">
+
+		<?php if ( 'upload-image' == bp_get_avatar_admin_step() ) : ?>
+
+			<?php wp_nonce_field( 'bp_avatar_upload' ); ?>
+			<p><?php _e( 'Click below to select a JPG, GIF or PNG format photo from your computer and then click \'Upload Image\' to proceed.', 'buddypress' ); ?></p>
+
+			<p id="avatar-upload">
+				<input type="file" name="file" id="file" />
+				<input type="submit" name="upload" id="upload" value="<?php _e( 'Upload Image', 'buddypress' ); ?>" />
+				<input type="hidden" name="action" id="action" value="bp_avatar_upload" />
+			</p>
+
+			<?php if ( bp_get_user_has_avatar() ) : ?>
+				<p><?php _e( "If you'd like to delete your current avatar but not upload a new one, please use the delete avatar button.", 'buddypress' ); ?></p>
+				<p><a class="button edit" href="<?php bp_avatar_delete_link(); ?>" title="<?php _e( 'Delete Avatar', 'buddypress' ); ?>"><?php _e( 'Delete My Avatar', 'buddypress' ); ?></a></p>
+			<?php endif; ?>
+
+		<?php endif; ?>
+
+		<?php if ( 'crop-image' == bp_get_avatar_admin_step() ) : ?>
+
+			<h5><?php _e( 'Crop Your New Avatar', 'buddypress' ); ?></h5>
+
+			<img src="<?php bp_avatar_to_crop(); ?>" id="avatar-to-crop" class="avatar" alt="<?php _e( 'Avatar to crop', 'buddypress' ); ?>" />
+
+			<div id="avatar-crop-pane">
+				<img src="<?php bp_avatar_to_crop(); ?>" id="avatar-crop-preview" class="avatar" alt="<?php _e( 'Avatar preview', 'buddypress' ); ?>" />
+			</div>
+
+			<input type="submit" name="avatar-crop-submit" id="avatar-crop-submit" value="<?php _e( 'Crop Image', 'buddypress' ); ?>" />
+
+			<input type="hidden" name="image_src" id="image_src" value="<?php bp_avatar_to_crop_src(); ?>" />
+			<input type="hidden" id="x" name="x" />
+			<input type="hidden" id="y" name="y" />
+			<input type="hidden" id="w" name="w" />
+			<input type="hidden" id="h" name="h" />
+
+			<?php wp_nonce_field( 'bp_avatar_cropstore' ); ?>
+
+		<?php endif; ?>
+
+	</form>
+
+<?php else : ?>
+
+	<p><?php _e( 'Your avatar will be used on your profile and throughout the site. To change your avatar, please create an account with <a href="http://gravatar.com">Gravatar</a> using the same email address as you used to register with this site.', 'buddypress' ); ?></p>
+
+<?php endif; ?>
+
+<?php do_action( 'bp_after_profile_avatar_upload_content' ); ?>
Index: /tags/1.9/bp-templates/bp-legacy/buddypress/members/single/profile/edit.php
===================================================================
--- /tags/1.9/bp-templates/bp-legacy/buddypress/members/single/profile/edit.php	(revision 7684)
+++ /tags/1.9/bp-templates/bp-legacy/buddypress/members/single/profile/edit.php	(revision 7684)
@@ -0,0 +1,159 @@
+<?php do_action( 'bp_before_profile_edit_content' );
+
+if ( bp_has_profile( 'profile_group_id=' . bp_get_current_profile_group_id() ) ) :
+	while ( bp_profile_groups() ) : bp_the_profile_group(); ?>
+
+<form action="<?php bp_the_profile_group_edit_form_action(); ?>" method="post" id="profile-edit-form" class="standard-form <?php bp_the_profile_group_slug(); ?>">
+
+	<?php do_action( 'bp_before_profile_field_content' ); ?>
+
+		<h4><?php printf( __( "Editing '%s' Profile Group", "buddypress" ), bp_get_the_profile_group_name() ); ?></h4>
+
+		<ul class="button-nav">
+
+			<?php bp_profile_group_tabs(); ?>
+
+		</ul>
+
+		<div class="clear"></div>
+
+		<?php while ( bp_profile_fields() ) : bp_the_profile_field(); ?>
+
+			<div<?php bp_field_css_class( 'editfield' ); ?>>
+
+				<?php if ( 'textbox' == bp_get_the_profile_field_type() ) : ?>
+
+					<label for="<?php bp_the_profile_field_input_name(); ?>"><?php bp_the_profile_field_name(); ?> <?php if ( bp_get_the_profile_field_is_required() ) : ?><?php _e( '(required)', 'buddypress' ); ?><?php endif; ?></label>
+					<input type="text" name="<?php bp_the_profile_field_input_name(); ?>" id="<?php bp_the_profile_field_input_name(); ?>" value="<?php bp_the_profile_field_edit_value(); ?>" <?php if ( bp_get_the_profile_field_is_required() ) : ?>aria-required="true"<?php endif; ?>/>
+
+				<?php endif; ?>
+
+				<?php if ( 'textarea' == bp_get_the_profile_field_type() ) : ?>
+
+					<label for="<?php bp_the_profile_field_input_name(); ?>"><?php bp_the_profile_field_name(); ?> <?php if ( bp_get_the_profile_field_is_required() ) : ?><?php _e( '(required)', 'buddypress' ); ?><?php endif; ?></label>
+					<textarea rows="5" cols="40" name="<?php bp_the_profile_field_input_name(); ?>" id="<?php bp_the_profile_field_input_name(); ?>" <?php if ( bp_get_the_profile_field_is_required() ) : ?>aria-required="true"<?php endif; ?>><?php bp_the_profile_field_edit_value(); ?></textarea>
+
+				<?php endif; ?>
+
+				<?php if ( 'selectbox' == bp_get_the_profile_field_type() ) : ?>
+
+					<label for="<?php bp_the_profile_field_input_name(); ?>"><?php bp_the_profile_field_name(); ?> <?php if ( bp_get_the_profile_field_is_required() ) : ?><?php _e( '(required)', 'buddypress' ); ?><?php endif; ?></label>
+					<select name="<?php bp_the_profile_field_input_name(); ?>" id="<?php bp_the_profile_field_input_name(); ?>" <?php if ( bp_get_the_profile_field_is_required() ) : ?>aria-required="true"<?php endif; ?>>
+						<?php bp_the_profile_field_options(); ?>
+					</select>
+
+				<?php endif; ?>
+
+				<?php if ( 'multiselectbox' == bp_get_the_profile_field_type() ) : ?>
+
+					<label for="<?php bp_the_profile_field_input_name(); ?>"><?php bp_the_profile_field_name(); ?> <?php if ( bp_get_the_profile_field_is_required() ) : ?><?php _e( '(required)', 'buddypress' ); ?><?php endif; ?></label>
+					<select name="<?php bp_the_profile_field_input_name(); ?>" id="<?php bp_the_profile_field_input_name(); ?>" multiple="multiple" <?php if ( bp_get_the_profile_field_is_required() ) : ?>aria-required="true"<?php endif; ?>>
+
+						<?php bp_the_profile_field_options(); ?>
+
+					</select>
+
+					<?php if ( !bp_get_the_profile_field_is_required() ) : ?>
+
+						<a class="clear-value" href="javascript:clear( '<?php bp_the_profile_field_input_name(); ?>' );"><?php _e( 'Clear', 'buddypress' ); ?></a>
+
+					<?php endif; ?>
+
+				<?php endif; ?>
+
+				<?php if ( 'radio' == bp_get_the_profile_field_type() ) : ?>
+
+					<div class="radio">
+						<span class="label"><?php bp_the_profile_field_name(); ?> <?php if ( bp_get_the_profile_field_is_required() ) : ?><?php _e( '(required)', 'buddypress' ); ?><?php endif; ?></span>
+
+						<?php bp_the_profile_field_options(); ?>
+
+						<?php if ( !bp_get_the_profile_field_is_required() ) : ?>
+
+							<a class="clear-value" href="javascript:clear( '<?php bp_the_profile_field_input_name(); ?>' );"><?php _e( 'Clear', 'buddypress' ); ?></a>
+
+						<?php endif; ?>
+					</div>
+
+				<?php endif; ?>
+
+				<?php if ( 'checkbox' == bp_get_the_profile_field_type() ) : ?>
+
+					<div class="checkbox">
+						<span class="label"><?php bp_the_profile_field_name(); ?> <?php if ( bp_get_the_profile_field_is_required() ) : ?><?php _e( '(required)', 'buddypress' ); ?><?php endif; ?></span>
+
+						<?php bp_the_profile_field_options(); ?>
+					</div>
+
+				<?php endif; ?>
+
+				<?php if ( 'datebox' == bp_get_the_profile_field_type() ) : ?>
+
+					<div class="datebox">
+						<label for="<?php bp_the_profile_field_input_name(); ?>_day"><?php bp_the_profile_field_name(); ?> <?php if ( bp_get_the_profile_field_is_required() ) : ?><?php _e( '(required)', 'buddypress' ); ?><?php endif; ?></label>
+
+						<select name="<?php bp_the_profile_field_input_name(); ?>_day" id="<?php bp_the_profile_field_input_name(); ?>_day" <?php if ( bp_get_the_profile_field_is_required() ) : ?>aria-required="true"<?php endif; ?>>
+
+							<?php bp_the_profile_field_options( 'type=day' ); ?>
+
+						</select>
+
+						<select name="<?php bp_the_profile_field_input_name(); ?>_month" id="<?php bp_the_profile_field_input_name(); ?>_month" <?php if ( bp_get_the_profile_field_is_required() ) : ?>aria-required="true"<?php endif; ?>>
+
+							<?php bp_the_profile_field_options( 'type=month' ); ?>
+
+						</select>
+
+						<select name="<?php bp_the_profile_field_input_name(); ?>_year" id="<?php bp_the_profile_field_input_name(); ?>_year" <?php if ( bp_get_the_profile_field_is_required() ) : ?>aria-required="true"<?php endif; ?>>
+
+							<?php bp_the_profile_field_options( 'type=year' ); ?>
+
+						</select>
+					</div>
+
+				<?php endif; ?>
+
+				<?php do_action( 'bp_custom_profile_edit_fields_pre_visibility' ); ?>
+
+				<?php if ( bp_current_user_can( 'bp_xprofile_change_field_visibility' ) ) : ?>
+					<p class="field-visibility-settings-toggle" id="field-visibility-settings-toggle-<?php bp_the_profile_field_id() ?>">
+						<?php printf( __( 'This field can be seen by: <span class="current-visibility-level">%s</span>', 'buddypress' ), bp_get_the_profile_field_visibility_level_label() ) ?> <a href="#" class="visibility-toggle-link"><?php _e( 'Change', 'buddypress' ); ?></a>
+					</p>
+
+					<div class="field-visibility-settings" id="field-visibility-settings-<?php bp_the_profile_field_id() ?>">
+						<fieldset>
+							<legend><?php _e( 'Who can see this field?', 'buddypress' ) ?></legend>
+
+							<?php bp_profile_visibility_radio_buttons() ?>
+
+						</fieldset>
+						<a class="field-visibility-settings-close" href="#"><?php _e( 'Close', 'buddypress' ) ?></a>
+					</div>
+				<?php else : ?>
+					<div class="field-visibility-settings-notoggle" id="field-visibility-settings-toggle-<?php bp_the_profile_field_id() ?>">
+						<?php printf( __( 'This field can be seen by: <span class="current-visibility-level">%s</span>', 'buddypress' ), bp_get_the_profile_field_visibility_level_label() ) ?>
+					</div>
+				<?php endif ?>
+
+				<?php do_action( 'bp_custom_profile_edit_fields' ); ?>
+
+				<p class="description"><?php bp_the_profile_field_description(); ?></p>
+			</div>
+
+		<?php endwhile; ?>
+
+	<?php do_action( 'bp_after_profile_field_content' ); ?>
+
+	<div class="submit">
+		<input type="submit" name="profile-group-edit-submit" id="profile-group-edit-submit" value="<?php _e( 'Save Changes', 'buddypress' ); ?> " />
+	</div>
+
+	<input type="hidden" name="field_ids" id="field_ids" value="<?php bp_the_profile_group_field_ids(); ?>" />
+
+	<?php wp_nonce_field( 'bp_xprofile_edit' ); ?>
+
+</form>
+
+<?php endwhile; endif; ?>
+
+<?php do_action( 'bp_after_profile_edit_content' ); ?>
Index: /tags/1.9/bp-templates/bp-legacy/buddypress/members/single/profile/profile-loop.php
===================================================================
--- /tags/1.9/bp-templates/bp-legacy/buddypress/members/single/profile/profile-loop.php	(revision 7684)
+++ /tags/1.9/bp-templates/bp-legacy/buddypress/members/single/profile/profile-loop.php	(revision 7684)
@@ -0,0 +1,48 @@
+<?php do_action( 'bp_before_profile_loop_content' ); ?>
+
+<?php if ( bp_has_profile() ) : ?>
+
+	<?php while ( bp_profile_groups() ) : bp_the_profile_group(); ?>
+
+		<?php if ( bp_profile_group_has_fields() ) : ?>
+
+			<?php do_action( 'bp_before_profile_field_content' ); ?>
+
+			<div class="bp-widget <?php bp_the_profile_group_slug(); ?>">
+
+				<h4><?php bp_the_profile_group_name(); ?></h4>
+
+				<table class="profile-fields">
+
+					<?php while ( bp_profile_fields() ) : bp_the_profile_field(); ?>
+
+						<?php if ( bp_field_has_data() ) : ?>
+
+							<tr<?php bp_field_css_class(); ?>>
+
+								<td class="label"><?php bp_the_profile_field_name(); ?></td>
+
+								<td class="data"><?php bp_the_profile_field_value(); ?></td>
+
+							</tr>
+
+						<?php endif; ?>
+
+						<?php do_action( 'bp_profile_field_item' ); ?>
+
+					<?php endwhile; ?>
+
+				</table>
+			</div>
+
+			<?php do_action( 'bp_after_profile_field_content' ); ?>
+
+		<?php endif; ?>
+
+	<?php endwhile; ?>
+
+	<?php do_action( 'bp_profile_field_buttons' ); ?>
+
+<?php endif; ?>
+
+<?php do_action( 'bp_after_profile_loop_content' ); ?>
Index: /tags/1.9/bp-templates/bp-legacy/buddypress/members/single/profile/profile-wp.php
===================================================================
--- /tags/1.9/bp-templates/bp-legacy/buddypress/members/single/profile/profile-wp.php	(revision 7684)
+++ /tags/1.9/bp-templates/bp-legacy/buddypress/members/single/profile/profile-wp.php	(revision 7684)
@@ -0,0 +1,73 @@
+<?php do_action( 'bp_before_profile_loop_content' ); ?>
+
+<?php $ud = get_userdata( bp_displayed_user_id() ); ?>
+
+<?php do_action( 'bp_before_profile_field_content' ); ?>
+
+	<div class="bp-widget wp-profile">
+		<h4><?php bp_is_my_profile() ? _e( 'My Profile', 'buddypress' ) : printf( __( "%s's Profile", 'buddypress' ), bp_get_displayed_user_fullname() ); ?></h4>
+
+		<table class="wp-profile-fields">
+
+			<?php if ( $ud->display_name ) : ?>
+
+				<tr id="wp_displayname">
+					<td class="label"><?php _e( 'Name', 'buddypress' ); ?></td>
+					<td class="data"><?php echo $ud->display_name; ?></td>
+				</tr>
+
+			<?php endif; ?>
+
+			<?php if ( $ud->user_description ) : ?>
+
+				<tr id="wp_desc">
+					<td class="label"><?php _e( 'About Me', 'buddypress' ); ?></td>
+					<td class="data"><?php echo $ud->user_description; ?></td>
+				</tr>
+
+			<?php endif; ?>
+
+			<?php if ( $ud->user_url ) : ?>
+
+				<tr id="wp_website">
+					<td class="label"><?php _e( 'Website', 'buddypress' ); ?></td>
+					<td class="data"><?php echo make_clickable( $ud->user_url ); ?></td>
+				</tr>
+
+			<?php endif; ?>
+
+			<?php if ( $ud->jabber ) : ?>
+
+				<tr id="wp_jabber">
+					<td class="label"><?php _e( 'Jabber', 'buddypress' ); ?></td>
+					<td class="data"><?php echo $ud->jabber; ?></td>
+				</tr>
+
+			<?php endif; ?>
+
+			<?php if ( $ud->aim ) : ?>
+
+				<tr id="wp_aim">
+					<td class="label"><?php _e( 'AOL Messenger', 'buddypress' ); ?></td>
+					<td class="data"><?php echo $ud->aim; ?></td>
+				</tr>
+
+			<?php endif; ?>
+
+			<?php if ( $ud->yim ) : ?>
+
+				<tr id="wp_yim">
+					<td class="label"><?php _e( 'Yahoo Messenger', 'buddypress' ); ?></td>
+					<td class="data"><?php echo $ud->yim; ?></td>
+				</tr>
+
+			<?php endif; ?>
+
+		</table>
+	</div>
+
+<?php do_action( 'bp_after_profile_field_content' ); ?>
+
+<?php do_action( 'bp_profile_field_buttons' ); ?>
+
+<?php do_action( 'bp_after_profile_loop_content' ); ?>
Index: /tags/1.9/bp-templates/bp-legacy/buddypress/members/single/settings.php
===================================================================
--- /tags/1.9/bp-templates/bp-legacy/buddypress/members/single/settings.php	(revision 7684)
+++ /tags/1.9/bp-templates/bp-legacy/buddypress/members/single/settings.php	(revision 7684)
@@ -0,0 +1,40 @@
+<?php
+
+/**
+ * BuddyPress - Users Settings
+ *
+ * @package BuddyPress
+ * @subpackage bp-legacy
+ */
+
+?>
+
+<div class="item-list-tabs no-ajax" id="subnav" role="navigation">
+	<ul>
+		<?php if ( bp_core_can_edit_settings() ) : ?>
+
+			<?php bp_get_options_nav(); ?>
+
+		<?php endif; ?>
+	</ul>
+</div>
+
+<?php
+
+switch ( bp_current_action() ) :
+	case 'notifications'  :
+		bp_get_template_part( 'members/single/settings/notifications'  );
+		break;
+	case 'capabilities'   :
+		bp_get_template_part( 'members/single/settings/capabilities'   );
+		break;
+	case 'delete-account' :
+		bp_get_template_part( 'members/single/settings/delete-account' );
+		break;
+	case 'general'        :
+		bp_get_template_part( 'members/single/settings/general'        );
+		break;
+	default:
+		bp_get_template_part( 'members/single/plugins'                 );
+		break;
+endswitch;
Index: /tags/1.9/bp-templates/bp-legacy/buddypress/members/single/settings/capabilities.php
===================================================================
--- /tags/1.9/bp-templates/bp-legacy/buddypress/members/single/settings/capabilities.php	(revision 7684)
+++ /tags/1.9/bp-templates/bp-legacy/buddypress/members/single/settings/capabilities.php	(revision 7684)
@@ -0,0 +1,22 @@
+<?php do_action( 'bp_before_member_settings_template' ); ?>
+
+<form action="<?php echo bp_displayed_user_domain() . bp_get_settings_slug() . '/capabilities/'; ?>" name="account-capabilities-form" id="account-capabilities-form" class="standard-form" method="post">
+
+	<?php do_action( 'bp_members_capabilities_account_before_submit' ); ?>
+
+	<label>
+		<input type="checkbox" name="user-spammer" id="user-spammer" value="1" <?php checked( bp_is_user_spammer( bp_displayed_user_id() ) ); ?> />
+		 <?php _e( 'This user is a spammer.', 'buddypress' ); ?>
+	</label>
+
+	<div class="submit">
+		<input type="submit" value="<?php _e( 'Save', 'buddypress' ); ?>" id="capabilities-submit" name="capabilities-submit" />
+	</div>
+
+	<?php do_action( 'bp_members_capabilities_account_after_submit' ); ?>
+
+	<?php wp_nonce_field( 'capabilities' ); ?>
+
+</form>
+
+<?php do_action( 'bp_after_member_settings_template' ); ?>
Index: /tags/1.9/bp-templates/bp-legacy/buddypress/members/single/settings/delete-account.php
===================================================================
--- /tags/1.9/bp-templates/bp-legacy/buddypress/members/single/settings/delete-account.php	(revision 7684)
+++ /tags/1.9/bp-templates/bp-legacy/buddypress/members/single/settings/delete-account.php	(revision 7684)
@@ -0,0 +1,36 @@
+<?php do_action( 'bp_before_member_settings_template' ); ?>
+
+<div id="message" class="info">
+
+	<?php if ( bp_is_my_profile() ) : ?>
+
+		<p><?php _e( 'Deleting your account will delete all of the content you have created. It will be completely irrecoverable.', 'buddypress' ); ?></p>
+
+	<?php else : ?>
+
+		<p><?php _e( 'Deleting this account will delete all of the content it has created. It will be completely irrecoverable.', 'buddypress' ); ?></p>
+
+	<?php endif; ?>
+
+</div>
+
+<form action="<?php echo bp_displayed_user_domain() . bp_get_settings_slug() . '/delete-account'; ?>" name="account-delete-form" id="account-delete-form" class="standard-form" method="post">
+
+	<?php do_action( 'bp_members_delete_account_before_submit' ); ?>
+
+	<label>
+		<input type="checkbox" name="delete-account-understand" id="delete-account-understand" value="1" onclick="if(this.checked) { document.getElementById('delete-account-button').disabled = ''; } else { document.getElementById('delete-account-button').disabled = 'disabled'; }" />
+		 <?php _e( 'I understand the consequences.', 'buddypress' ); ?>
+	</label>
+
+	<div class="submit">
+		<input type="submit" disabled="disabled" value="<?php _e( 'Delete Account', 'buddypress' ); ?>" id="delete-account-button" name="delete-account-button" />
+	</div>
+
+	<?php do_action( 'bp_members_delete_account_after_submit' ); ?>
+
+	<?php wp_nonce_field( 'delete-account' ); ?>
+
+</form>
+
+<?php do_action( 'bp_after_member_settings_template' ); ?>
Index: /tags/1.9/bp-templates/bp-legacy/buddypress/members/single/settings/general.php
===================================================================
--- /tags/1.9/bp-templates/bp-legacy/buddypress/members/single/settings/general.php	(revision 7684)
+++ /tags/1.9/bp-templates/bp-legacy/buddypress/members/single/settings/general.php	(revision 7684)
@@ -0,0 +1,31 @@
+<?php do_action( 'bp_before_member_settings_template' ); ?>
+
+<form action="<?php echo bp_displayed_user_domain() . bp_get_settings_slug() . '/general'; ?>" method="post" class="standard-form" id="settings-form">
+
+	<?php if ( !is_super_admin() ) : ?>
+
+		<label for="pwd"><?php _e( 'Current Password <span>(required to update email or change current password)</span>', 'buddypress' ); ?></label>
+		<input type="password" name="pwd" id="pwd" size="16" value="" class="settings-input small" /> &nbsp;<a href="<?php echo wp_lostpassword_url(); ?>" title="<?php _e( 'Password Lost and Found', 'buddypress' ); ?>"><?php _e( 'Lost your password?', 'buddypress' ); ?></a>
+
+	<?php endif; ?>
+
+	<label for="email"><?php _e( 'Account Email', 'buddypress' ); ?></label>
+	<input type="text" name="email" id="email" value="<?php echo bp_get_displayed_user_email(); ?>" class="settings-input" />
+
+	<label for="pass1"><?php _e( 'Change Password <span>(leave blank for no change)</span>', 'buddypress' ); ?></label>
+	<input type="password" name="pass1" id="pass1" size="16" value="" class="settings-input small" /> &nbsp;<?php _e( 'New Password', 'buddypress' ); ?><br />
+	<input type="password" name="pass2" id="pass2" size="16" value="" class="settings-input small" /> &nbsp;<?php _e( 'Repeat New Password', 'buddypress' ); ?>
+
+	<?php do_action( 'bp_core_general_settings_before_submit' ); ?>
+
+	<div class="submit">
+		<input type="submit" name="submit" value="<?php _e( 'Save Changes', 'buddypress' ); ?>" id="submit" class="auto" />
+	</div>
+
+	<?php do_action( 'bp_core_general_settings_after_submit' ); ?>
+
+	<?php wp_nonce_field( 'bp_settings_general' ); ?>
+
+</form>
+
+<?php do_action( 'bp_after_member_settings_template' ); ?>
Index: /tags/1.9/bp-templates/bp-legacy/buddypress/members/single/settings/notifications.php
===================================================================
--- /tags/1.9/bp-templates/bp-legacy/buddypress/members/single/settings/notifications.php	(revision 7684)
+++ /tags/1.9/bp-templates/bp-legacy/buddypress/members/single/settings/notifications.php	(revision 7684)
@@ -0,0 +1,20 @@
+<?php do_action( 'bp_before_member_settings_template' ); ?>
+
+<form action="<?php echo bp_displayed_user_domain() . bp_get_settings_slug() . '/notifications'; ?>" method="post" class="standard-form" id="settings-form">
+	<p><?php _e( 'Send an email notice when:', 'buddypress' ); ?></p>
+
+	<?php do_action( 'bp_notification_settings' ); ?>
+
+	<?php do_action( 'bp_members_notification_settings_before_submit' ); ?>
+
+	<div class="submit">
+		<input type="submit" name="submit" value="<?php _e( 'Save Changes', 'buddypress' ); ?>" id="submit" class="auto" />
+	</div>
+
+	<?php do_action( 'bp_members_notification_settings_after_submit' ); ?>
+
+	<?php wp_nonce_field('bp_settings_notifications' ); ?>
+
+</form>
+
+<?php do_action( 'bp_after_member_settings_template' ); ?>
Index: /tags/1.9/bp-templates/bp-legacy/css/buddypress-rtl.css
===================================================================
--- /tags/1.9/bp-templates/bp-legacy/css/buddypress-rtl.css	(revision 7684)
+++ /tags/1.9/bp-templates/bp-legacy/css/buddypress-rtl.css	(revision 7684)
@@ -0,0 +1,1530 @@
+/*--------------------------------------------------------------
+Hello, this is the BuddyPress Legacy stylesheet.
+
+----------------------------------------------------------------
+>>> TABLE OF CONTENTS:
+----------------------------------------------------------------
+1.0 - Navigation
+	1.1 - Pagination
+2.0 - WordPress
+	2.1 - Images
+3.0 - BuddyPress
+	3.1 - Activity
+		3.1.1 - Activity Listing
+		3.1.2 - Activity Comments
+	3.2 - Toolbar
+	3.3 - Directories - Members, Groups, Blogs, Forums
+	3.4 - Error / Success Messages
+	3.5 - Forms
+	3.6 - Ajax Loading
+	3.7 - Topics and Tables - Forums and General
+	3.8 - Headers, Lists and Tabs - Activity, Groups, Blogs, Forums
+	3.9 - Private Messaging Threads
+	3.10 - Extended Profiles
+	3.11 - Widgets
+4.0 - Media Queries
+	4.1 - Smartphones Landscape
+	4.2 - Smartphones Portrait
+	4.3 - Smartphones - smaller screen sizes
+--------------------------------------------------------------*/
+
+/*--------------------------------------------------------------
+1 - Navigation
+--------------------------------------------------------------*/
+/*--------------------------------------------------------------
+1.1 - Pagination
+--------------------------------------------------------------*/
+#buddypress div.pagination {
+	background: transparent;
+	border: none;
+	color: #888;
+	font-size: 90%;
+	margin: 0;
+	position: relative;
+	display: block;
+	float: right;
+	width: 100%;
+	padding: 10px 0;
+}
+#buddypress div.pagination .pag-count {
+	float: right;
+	margin-right: 10px;
+}
+#buddypress div.pagination .pagination-links {
+	float: left;
+	margin-left: 10px;
+}
+#buddypress div.pagination .pagination-links span,
+#buddypress div.pagination .pagination-links a {
+	font-size: 90%;
+	padding: 0 5px;
+}
+#buddypress div.pagination .pagination-links a:hover {
+	font-weight: bold;
+}
+#buddypress noscript div.pagination {
+	margin-bottom: 15px;
+}
+#buddypress #nav-above {
+	display: none;
+}
+#buddypress .paged #nav-above {
+	display: block;
+}
+/*--------------------------------------------------------------
+2 - WordPress
+--------------------------------------------------------------*/
+/*--------------------------------------------------------------
+2.1 - Images
+--------------------------------------------------------------*/
+#buddypress img.wp-smiley {
+	border: none !important;
+	clear: none !important;
+	float: none !important;
+	margin: 0 !important;
+	padding: 0 !important;
+}
+
+/*--------------------------------------------------------------
+3.0 - BuddyPress
+--------------------------------------------------------------*/
+/*--------------------------------------------------------------
+3.1 - Activity
+--------------------------------------------------------------*/
+#buddypress #activity-stream {
+	margin-top: -5px;
+}
+
+#buddypress #activity-stream p {
+	margin: 5px 0;
+}
+
+#buddypress #item-body form#whats-new-form {
+	margin: 0;
+	padding: 0;
+}
+#buddypress .home-page form#whats-new-form {
+	border-bottom: none;
+	padding-bottom: 0;
+}
+#buddypress form#whats-new-form #whats-new-avatar {
+	float: right;
+}
+#buddypress form#whats-new-form #whats-new-content {
+	margin-right: 55px;
+	padding: 0 0 20px 20px;
+}
+#buddypress form#whats-new-form p.activity-greeting {
+	line-height: 0.5em;
+	margin-bottom: 15px;
+	margin-right: 75px;
+}
+#buddypress form#whats-new-form textarea {
+	background: #fff;
+	color: #555;
+	font-family: inherit;
+	font-size: 90%;
+	height: 20px;
+	padding: 6px;
+	width: 98%;
+}
+body.no-js #buddypress form#whats-new-form textarea {
+	height: 50px;
+}
+#buddypress form#whats-new-form #whats-new-options select {
+	max-width: 200px;
+	margin-top: 12px;
+}
+#buddypress form#whats-new-form #whats-new-submit {
+	float: left;
+	margin-top: 12px;
+}
+#buddypress #whats-new-options {
+	overflow: auto;
+	height: 0;
+}
+body.no-js #buddypress #whats-new-options {
+	height: auto;
+}
+#buddypress #whats-new:focus {
+	border-color: rgba(31, 179, 221, 0.9) !important;
+	outline-color: rgba(31, 179, 221, 0.9);
+}
+
+/*--------------------------------------------------------------
+3.1.1 - Activity Listing
+--------------------------------------------------------------*/
+#buddypress ul.activity-list li {
+	overflow: hidden;
+	padding: 15px 0 0;
+	list-style: none;
+}
+#buddypress .activity-list .activity-avatar {
+	float: right;
+}
+#buddypress ul.item-list.activity-list li.has-comments {
+	padding-bottom: 15px;
+}
+body.activity-permalink #buddypress ul.activity-list li.has-comments {
+	padding-bottom: 0;
+}
+#buddypress .activity-list li.mini {
+	font-size: 80%;
+	position: relative;
+}
+#buddypress .activity-list li.mini .activity-avatar img.avatar,
+#buddypress .activity-list li.mini .activity-avatar img.FB_profile_pic {
+	height: 20px;
+	margin-right: 30px;
+	width: 20px;
+}
+#buddypress .activity-permalink .activity-list li.mini .activity-avatar img.avatar,
+#buddypress .activity-permalink .activity-list li.mini .activity-avatar img.FB_profile_pic {
+	height: auto;
+	margin-right: 0;
+	width: auto;
+}
+body.activity-permalink #buddypress .activity-list > li:first-child {
+	padding-top: 0;
+}
+#buddypress .activity-list li .activity-content {
+	position: relative;
+}
+#buddypress .activity-list li.mini .activity-content p {
+	margin: 0;
+}
+#buddypress .activity-list li.mini .activity-comments {
+	clear: both;
+	font-size: 120%;
+}
+body.activity-permalink #buddypress li.mini .activity-meta {
+	margin-top: 4px;
+}
+#buddypress .activity-list li .activity-inreplyto {
+	color: #888;
+	font-size: 80%;
+}
+#buddypress .activity-list li .activity-inreplyto > p {
+	margin: 0;
+	display: inline;
+}
+#buddypress .activity-list li .activity-inreplyto blockquote,
+#buddypress .activity-list li .activity-inreplyto div.activity-inner {
+	background: none;
+	border: none;
+	display: inline;
+	margin: 0;
+	overflow: hidden;
+	padding: 0;
+}
+#buddypress .activity-list .activity-content {
+	margin: 0 70px 0 0;
+}
+body.activity-permalink #buddypress .activity-list li .activity-content {
+	border: none;
+	font-size: 100%;
+	line-height: 150%;
+	margin-right: 170px;
+	margin-left: 0;
+	padding: 0;
+}
+body.activity-permalink #buddypress .activity-list li .activity-header > p {
+	margin: 0;
+	padding: 5px 0 0 0;
+}
+#buddypress .activity-list .activity-content .activity-header,
+#buddypress .activity-list .activity-content .comment-header {
+	color: #888;
+	line-height: 220%;
+}
+#buddypress .activity-header {
+	margin-left: 20px;
+}
+#buddypress .activity-header a,
+#buddypress .comment-meta a,
+#buddypress .acomment-meta a {
+	text-decoration: none;
+}
+#buddypress .activity-list .activity-content .activity-header img.avatar {
+	float: none !important;
+	margin: 0 0 -8px 5px !important;
+}
+#buddypress a.bp-secondary-action,
+#buddypress span.highlight {
+	font-size: 80%;
+	padding: 0;
+	margin-left: 5px;
+	text-decoration: none;
+}
+#buddypress .activity-list .activity-content .activity-inner,
+#buddypress .activity-list .activity-content blockquote {
+	margin: 10px 0 5px 10px;
+	overflow: hidden;
+}
+#buddypress .activity-list li.new_forum_post .activity-content .activity-inner,
+#buddypress .activity-list li.new_forum_topic .activity-content .activity-inner {
+	border-right: 2px solid #EAEAEA;
+	margin-right: 5px;
+	padding-right: 10px;
+}
+body.activity-permalink #buddypress .activity-content .activity-inner,
+body.activity-permalink #buddypress .activity-content blockquote {
+	margin-right: 0;
+	margin-top: 5px;
+}
+#buddypress .activity-inner > p {
+	word-wrap: break-word;
+}
+#buddypress .activity-inner > .activity-inner {
+	margin: 0;
+}
+#buddypress .activity-inner > blockquote {
+	margin: 0;
+}
+#buddypress .activity-list .activity-content img.thumbnail {
+	border: 2px solid #eee;
+	float: right;
+	margin: 0 0 5px 10px;
+}
+#buddypress .activity-read-more {
+	margin-right: 1em;
+	white-space: nowrap;
+}
+#buddypress .activity-list li.load-more {
+	background: #f0f0f0;
+	font-size: 110%;
+	margin: 15px 0;
+	padding: 10px 15px;
+	text-align: center;
+}
+#buddypress .activity-list li.load-more a {
+	color: #4D4D4D;
+}
+
+
+/*--------------------------------------------------------------
+3.1.2 - Activity Comments
+--------------------------------------------------------------*/
+#buddypress div.activity-meta {
+	margin: 18px 0 0;
+}
+body.activity-permalink #buddypress div.activity-meta {
+	margin-bottom: 6px;
+}
+#buddypress div.activity-meta a {
+	padding: 4px 8px;
+}
+#buddypress a.activity-time-since {
+	color: #aaa;
+	text-decoration: none;
+}
+#buddypress a.activity-time-since:hover {
+	color: #888;
+	text-decoration: underline;
+}
+#buddypress a.bp-primary-action,
+#buddypress #reply-title small a {
+	font-size: 80%;
+	margin-left: 5px;
+	text-decoration: none;
+}
+#buddypress a.bp-primary-action span,
+#buddypress #reply-title small a span {
+	background: #999;
+	color: #fff;
+	font-size: 90%;
+	margin-right: 2px;
+	padding: 0 5px;
+}
+#buddypress a.bp-primary-action:hover span,
+#buddypress #reply-title small a:hover span {
+	background: #555;
+	color: #fff;
+}
+#buddypress div.activity-comments {
+	margin: 0 70px 0 0;
+	overflow: hidden; /* IE fix */
+	position: relative;
+	width: auto;
+	clear: both;
+}
+body.activity-permalink #buddypress div.activity-comments {
+	background: none;
+	margin-right: 170px;
+	width: auto;
+}
+#buddypress div.activity-comments > ul {
+	padding: 0 10px 0 0;
+}
+#buddypress div.activity-comments ul,
+#buddypress div.activity-comments ul li {
+	border: none;
+	list-style: none;
+}
+#buddypress div.activity-comments ul {
+	clear: both;
+	margin: 0;
+}
+#buddypress div.activity-comments ul li {
+	border-top: 1px solid #eee;
+	padding: 10px 0 0;
+}
+body.activity-permalink #buddypress .activity-list li.mini .activity-comments {
+	clear: none;
+	margin-top: 0;
+}
+body.activity-permalink #buddypress div.activity-comments ul li {
+	border-width: 1px;
+	padding: 10px 0 0 0;
+}
+#buddypress div.activity-comments > ul > li:first-child {
+	border-top: none;
+}
+#buddypress div.activity-comments ul li:last-child {
+	margin-bottom: 0;
+}
+#buddypress div.activity-comments ul li > ul {
+	margin-right: 30px;
+	margin-top: 0;
+	padding-right: 10px;
+}
+body.activity-permalink #buddypress div.activity-comments ul li > ul {
+	margin-top: 10px;
+}
+body.activity-permalink #buddypress div.activity-comments > ul {
+	padding: 0 15px 0 10px;
+}
+#buddypress div.activity-comments div.acomment-avatar img {
+	border-width: 1px;
+	float: right;
+	height: 25px;
+	margin-left: 10px;
+	width: 25px;
+}
+#buddypress div.activity-comments div.acomment-content {
+	font-size: 80%;
+	margin: 5px 40px 0 0;
+}
+#buddypress div.acomment-content .time-since,
+#buddypress div.acomment-content .activity-delete-link,
+#buddypress div.acomment-content .comment-header {
+	display: none;
+}
+body.activity-permalink #buddypress div.activity-comments div.acomment-content {
+	font-size: 90%;
+}
+#buddypress div.activity-comments div.acomment-meta {
+	color: #888;
+	font-size: 80%;
+}
+#buddypress div.activity-comments form.ac-form {
+	display: none;
+	padding: 10px;
+}
+#buddypress div.activity-comments li form.ac-form {
+	margin-left: 15px;
+	clear: both;
+}
+#buddypress div.activity-comments form.root {
+	margin-right: 0;
+}
+#buddypress div.activity-comments div#message {
+	margin-top: 15px;
+	margin-bottom: 0;
+}
+#buddypress div.activity-comments form .ac-textarea {
+	background: #fff;
+	border: 1px inset #ccc;
+	margin-bottom: 10px;
+	padding: 8px;
+}
+#buddypress div.activity-comments form textarea {
+	border: none;
+	background: transparent;
+	box-shadow: none;
+	outline: none;
+	color: #555;
+	font-family: inherit;
+	font-size: 100%;
+	height: 60px;
+	padding: 0;
+	margin: 0;
+	width: 100%;
+}
+#buddypress div.activity-comments form input {
+	margin-top: 5px;
+}
+#buddypress div.activity-comments form div.ac-reply-avatar {
+	float: right;
+}
+#buddypress div.ac-reply-avatar img {
+	border: 1px solid #eee;
+}
+#buddypress div.activity-comments form div.ac-reply-content {
+	color: #888;
+	margin-right: 50px;
+	padding-right: 15px;
+}
+#buddypress div.activity-comments form div.ac-reply-content a {
+	text-decoration: none;
+}
+#buddypress .acomment-options {
+	float: right;
+	margin: 5px 40px 5px 0;
+}
+#buddypress .acomment-options a {
+	color: #999;
+}
+#buddypress .acomment-options a:hover {
+	color: inherit;
+}
+
+/*--------------------------------------------------------------
+3.3 - Directories - Members, Groups, Blogs, Forums
+--------------------------------------------------------------*/
+#buddypress div.dir-search {
+	float: left;
+	margin: -39px 0 0 0;
+}
+#buddypress div.dir-search input[type=text] {
+	font-size: 90%;
+	padding: 1px 3px;
+}
+
+#buddypress .dir-form {
+	clear: both;
+}
+
+/*--------------------------------------------------------------
+3.4 - Errors / Success Messages
+--------------------------------------------------------------*/
+#buddypress div#message {
+	margin: 0 0 15px;
+}
+#buddypress #message.info {
+	margin-bottom: 0;
+}
+#buddypress div#message.updated {
+	clear: both;
+}
+#buddypress div#message p,
+#sitewide-notice p {
+	font-size: 90%;
+	display: block;
+	padding: 10px 15px;
+}
+#buddypress div#message.error p {
+	background-color: #ffa;
+	border: 1px solid #960;
+	clear: right;
+	color: #960;
+}
+#buddypress div#message.updated p {
+	background-color: #efc;
+	border: 1px solid #591;
+	color: #591;
+}
+#buddypress .standard-form#signup_form div div.error {
+	background: #faa;
+	color: #a00;
+	margin: 0 0 10px 0;
+	padding: 6px;
+	width: 90%;
+}
+#buddypress div.accept,
+#buddypress div.reject {
+	float: right;
+	margin-right: 10px;
+}
+#buddypress ul.button-nav li {
+	float: right;
+	margin: 0 0 10px 10px;
+	list-style: none;
+}
+#buddypress ul.button-nav li.current a {
+	font-weight: bold;
+}
+#sitewide-notice #message {
+	right: 2%;
+	position: fixed;
+	top: 1em;
+	width: 96%;
+	z-index: 9999;
+}
+#sitewide-notice.admin-bar-on #message {
+	top: 3.3em;
+}
+#sitewide-notice strong {
+	display: block;
+	margin-bottom: -1em;
+}
+
+/*--------------------------------------------------------------
+3.5 - Forms
+--------------------------------------------------------------*/
+#buddypress .standard-form textarea,
+#buddypress .standard-form input[type=text],
+#buddypress .standard-form input[type=text],
+#buddypress .standard-form input[type=color],
+#buddypress .standard-form input[type=date],
+#buddypress .standard-form input[type=datetime],
+#buddypress .standard-form input[type=datetime-local],
+#buddypress .standard-form input[type=email],
+#buddypress .standard-form input[type=month],
+#buddypress .standard-form input[type=number],
+#buddypress .standard-form input[type=range],
+#buddypress .standard-form input[type=search],
+#buddypress .standard-form input[type=tel],
+#buddypress .standard-form input[type=time],
+#buddypress .standard-form input[type=url],
+#buddypress .standard-form input[type=week],
+#buddypress .standard-form select,
+#buddypress .standard-form input[type=password],
+#buddypress .dir-search input[type=search],
+#buddypress .dir-search input[type=text] {
+	border: 1px solid #ccc;
+	background: #fafafa;
+	border-radius: 0;
+	color: #888;
+	font: inherit;
+	font-size: 100%;
+	padding: 6px;
+}
+#buddypress .standard-form select {
+	padding: 3px;
+}
+#buddypress .standard-form input[type=password] {
+	margin-bottom: 5px;
+}
+#buddypress .standard-form label,
+#buddypress .standard-form span.label {
+	display: block;
+	font-weight: bold;
+	margin: 15px 0 5px 0;
+}
+#buddypress .standard-form div.checkbox label,
+#buddypress .standard-form div.radio label {
+	color: #888;
+	font-size: 100%;
+	font-weight: normal;
+	margin: 5px 0 0 0;
+}
+#buddypress .standard-form#sidebar-login-form label {
+	margin-top: 5px;
+}
+#buddypress .standard-form input[type=text] {
+	width: 75%;
+}
+#buddypress .standard-form#sidebar-login-form input[type=text],
+#buddypress .standard-form#sidebar-login-form input[type=password] {
+	padding: 4px;
+	width: 95%;
+}
+#buddypress .standard-form #basic-details-section input[type=password],
+#buddypress .standard-form #blog-details-section input#signup_blog_url {
+	width: 35%;
+}
+#buddypress .standard-form#signup_form input[type=text],
+#buddypress .standard-form#signup_form textarea,
+#buddypress .form-allowed-tags,
+#buddypress #commentform input[type=text],
+#buddypress #commentform textarea {
+	width: 90%;
+}
+#buddypress .standard-form#signup_form div.submit {
+	float: left;
+}
+#buddypress div#signup-avatar img {
+	margin: 0 0 10px 15px;
+}
+#buddypress .standard-form textarea {
+	width: 75%;
+	height: 120px;
+}
+#buddypress .standard-form textarea#message_content {
+	height: 200px;
+}
+#buddypress .standard-form#send-reply textarea {
+	width: 97.5%;
+}
+#buddypress .standard-form p.description {
+	color: #888;
+	font-size: 80%;
+	margin: 5px 0;
+}
+#buddypress .standard-form div.submit {
+	clear: both;
+	padding: 15px 0 0 0;
+}
+#buddypress .standard-form p.submit {
+	margin-bottom: 0;
+	padding: 15px 0 0 0;
+}
+#buddypress .standard-form div.submit input {
+	margin-left: 15px;
+}
+#buddypress .standard-form div.radio ul {
+	margin: 10px 38px 15px 0;
+	list-style: disc;
+}
+#buddypress .standard-form div.radio ul li {
+	margin-bottom: 5px;
+}
+#buddypress .standard-form a.clear-value {
+	display: block;
+	margin-top: 5px;
+	outline: none;
+}
+#buddypress .standard-form #basic-details-section,
+#buddypress .standard-form #blog-details-section,
+#buddypress .standard-form #profile-details-section {
+	float: right;
+	width: 48%;
+}
+#buddypress .standard-form #profile-details-section {
+	float: left;
+}
+#buddypress .standard-form #blog-details-section {
+	clear: right;
+}
+#buddypress .standard-form input:focus,
+#buddypress .standard-form textarea:focus,
+#buddypress .standard-form select:focus {
+	background: #fafafa;
+	color: #555;
+}
+#buddypress form#send-invite-form {
+	margin-top: 20px;
+}
+#buddypress div#invite-list {
+	background: #f5f5f5;
+	height: 400px;
+	margin: 0 0 10px;
+	overflow: auto;
+	padding: 5px;
+	width: 160px;
+}
+#buddypress button,
+#buddypress a.button,
+#buddypress input[type=submit],
+#buddypress input[type=button],
+#buddypress input[type=reset],
+#buddypress ul.button-nav li a,
+#buddypress div.generic-button a,
+#buddypress .comment-reply-link,
+a.bp-title-button {
+	background: #fff; /* Old browsers */
+	border: 1px solid #ccc;
+	color: #777;
+	font-size: .8rem;
+	cursor: pointer;
+	outline: none;
+	padding: 4px 10px;
+	text-align: center;
+	text-decoration: none;
+}
+#buddypress button:hover,
+#buddypress a.button:hover,
+#buddypress a.button:focus,
+#buddypress input[type=submit]:hover,
+#buddypress input[type=button]:hover,
+#buddypress input[type=reset]:hover,
+#buddypress ul.button-nav li a:hover,
+#buddypress ul.button-nav li.current a,
+#buddypress div.generic-button a:hover,
+#buddypress .comment-reply-link:hover {
+	background: #ededed;
+	border: 1px solid #bbb;
+	color: #555;
+	outline: none;
+	text-decoration: none;
+}
+
+#buddypress form.standard-form .right-menu {
+	float: right;
+}
+
+#buddypress form.standard-form .right-menu #invite-list ul{
+	margin: 1%;
+	list-style: none;
+}
+
+#buddypress form.standard-form .right-menu #invite-list ul li {
+	margin: 0 1% 0 0;
+}
+
+#buddypress form.standard-form .main-column {
+	margin-right: 190px;
+}
+
+#buddypress form.standard-form .main-column ul#friend-list {
+	clear:none;
+}
+
+#buddypress form.standard-form .main-column ul#friend-list h4 {
+	clear:none;
+}
+
+/*--------------------------------------------------------------
+3.6 - Ajax Loading
+--------------------------------------------------------------*/
+#buddypress a.loading,
+#buddypress input.loading {
+	-webkit-animation: loader-pulsate .5s infinite ease-in-out alternate;
+	-moz-animation: loader-pulsate .5s infinite ease-in-out alternate;
+	border-color: #aaa;
+}
+@-webkit-keyframes loader-pulsate {
+	from {
+		border-color: #aaa;
+		-webkit-box-shadow: 0 0 6px #ccc;
+		box-shadow: 0 0 6px #ccc;
+	}
+	to {
+		border-color: #ccc;
+		-webkit-box-shadow: 0 0 6px #f8f8f8;
+		box-shadow: 0 0 6px #f8f8f8;
+	}
+}
+@-moz-keyframes loader-pulsate {
+	from {
+		border-color: #aaa;
+		-moz-box-shadow: 0 0 6px #ccc;
+		box-shadow: 0 0 6px #ccc;
+	}
+	to {
+		border-color: #ccc;
+		-moz-box-shadow: 0 0 6px #f8f8f8;
+		box-shadow: 0 0 6px #f8f8f8;
+	}
+}
+
+#buddypress a.loading:hover,
+#buddypress input.loading:hover {
+    color: #777;
+}
+#buddypress input[type="submit"].pending,
+#buddypress input[type="button"].pending,
+#buddypress input[type="reset"].pending,
+#buddypress input[type="submit"].disabled,
+#buddypress input[type="button"].disabled,
+#buddypress input[type="reset"].disabled,
+#buddypress button.pending,
+#buddypress button.disabled,
+#buddypress div.pending a,
+#buddypress a.disabled {
+    border-color: #eee;
+    color: #bbb;
+    cursor: default;
+}
+#buddypress input[type="submit"]:hover.pending,
+#buddypress input[type="button"]:hover.pending,
+#buddypress input[type="reset"]:hover.pending,
+#buddypress input[type="submit"]:hover.disabled,
+#buddypress input[type="button"]:hover.disabled,
+#buddypress input[type="reset"]:hover.disabled,
+#buddypress button.pending:hover,
+#buddypress button.disabled:hover,
+#buddypress div.pending a:hover,
+#buddypress a.disabled:hover {
+	border-color: #eee;
+    color: #bbb;
+}
+
+/*--------------------------------------------------------------
+3.7 - Forums, Tables and Topics
+--------------------------------------------------------------*/
+#buddypress ul#topic-post-list {
+	margin: 0;
+	width: auto;
+}
+#buddypress ul#topic-post-list li {
+	padding: 15px;
+	position: relative;
+}
+#buddypress ul#topic-post-list li.alt {
+	background: #f5f5f5;
+}
+#buddypress ul#topic-post-list li div.poster-meta {
+	color: #888;
+	margin-bottom: 10px;
+}
+#buddypress ul#topic-post-list li div.post-content {
+	margin-right: 54px;
+}
+#buddypress div.topic-tags {
+	font-size: 80%;
+}
+#buddypress div.admin-links {
+	color: #888;
+	font-size: 80%;
+	position: absolute;
+	top: 15px;
+	left: 25px;
+}
+#buddypress div#topic-meta {
+	margin: 0;
+	padding: 5px 19px 30px;
+	position: relative;
+}
+#buddypress div#topic-meta div.admin-links {
+	left: 19px;
+	top: -36px;
+}
+#buddypress div#topic-meta h3 {
+	margin: 5px 0;
+}
+#buddypress div#new-topic-post {
+	display: none;
+	margin: 20px 0 0 0;
+	padding: 1px 0 0 0;
+}
+#buddypress table {
+	width: 100%;
+}
+#buddypress table thead tr {
+	background: #eaeaea;
+}
+#buddypress table#message-threads {
+	clear: both;
+	margin: 0;
+	width: auto;
+}
+#buddypress table.profile-fields {
+	margin-bottom: 20px;
+}
+#buddypress table.profile-fields:last-child {
+	margin-bottom: 0;
+}
+#buddypress table.profile-fields p {
+	margin: 0;
+}
+#buddypress table.profile-fields p:last-child {
+	margin-top: 0;
+}
+#buddypress table tr td,
+#buddypress table tr th {
+	padding: 8px;
+	vertical-align: middle;
+}
+#buddypress table tr td.label {
+	border-left: 1px solid #eaeaea;
+	font-weight: bold;
+	width: 25%;
+}
+#buddypress table tr td.thread-info p {
+	margin: 0;
+}
+#buddypress table tr td.thread-info p.thread-excerpt {
+	color: #888;
+	font-size: 80%;
+	margin-top: 3px;
+}
+#buddypress table.forum td {
+	text-align: center;
+}
+#buddypress table tr.alt td {
+	background: #f5f5f5;
+}
+#buddypress table.notification-settings {
+	margin-bottom: 20px;
+	text-align: right;
+}
+#buddypress #groups-notification-settings {
+	margin-bottom: 0;
+}
+#buddypress table.notification-settings th.icon,
+#buddypress table.notification-settings td:first-child {
+	display: none;
+}
+#buddypress table.notification-settings th.title {
+	width: 80%;
+}
+#buddypress table.notification-settings .yes,
+#buddypress table.notification-settings .no {
+	text-align: center;
+	width: 40px;
+}
+#buddypress table.forum {
+	margin: 0;
+	width: auto;
+	clear: both;
+}
+#buddypress table.forum tr.sticky td {
+	font-size: 110%;
+	background: #fff9db;
+	border-top: 1px solid #ffe8c4;
+	border-bottom: 1px solid #ffe8c4;
+}
+#buddypress table.forum tr.closed td.td-title {
+	padding-right: 35px;
+}
+#buddypress table.forum td p.topic-text {
+	color: #888;
+	font-size: 100%;
+}
+#buddypress table.forum tr > td:first-child,
+#buddypress table.forum tr > th:first-child {
+	padding-right: 15px;
+}
+#buddypress table.forum tr > td:last-child,
+#buddypress table.forum tr > th:last-child {
+	padding-left: 15px;
+}
+#buddypress table.forum tr th#th-title,
+#buddypress table.forum tr th#th-poster,
+#buddypress table.forum tr th#th-group,
+#buddypress table.forum td.td-poster,
+#buddypress table.forum td.td-group,
+#buddypress table.forum td.td-title {
+	text-align: right;
+}
+#buddypress table.forum tr td.td-title a.topic-title {
+	font-size: 110%;
+}
+#buddypress table.forum td.td-freshness {
+	white-space: nowrap;
+}
+#buddypress table.forum td.td-freshness span.time-since {
+	font-size: 80%;
+	color: #888;
+}
+#buddypress table.forum td img.avatar {
+	float: none;
+	margin: 0 0 -8px 5px;
+}
+#buddypress table.forum td.td-poster,
+#buddypress table.forum td.td-group {
+	min-width: 140px;
+}
+#buddypress table.forum th#th-title {
+	width: 80%;
+}
+#buddypress table.forum th#th-freshness {
+	width: 25%;
+}
+#buddypress table.forum th#th-postcount {
+	width: 15%;
+}
+#buddypress table.forum p.topic-meta {
+	font-size: 80%;
+	margin: 5px 0 0 0;
+}
+
+/*-------------------------------------------------------------------------
+3.8 - Headers, Lists and Tabs - Activity, Groups, Blogs, Forums, Profiles
+-------------------------------------------------------------------------*/
+#buddypress .item-body {
+	margin: 20px 0;
+}
+#buddypress span.activity {
+	display: inline-block;
+	font-size: 80%;
+	opacity: 0.8;
+	padding: 0;
+}
+#buddypress span.user-nicename {
+	color: #777;
+	display: inline-block;
+	font-size: 120%;
+	font-weight: bold;
+}
+#buddypress div#message p,
+#sitewide-notice p {
+	font-weight: normal;
+	margin-top: 3px;
+	text-decoration: none;
+	background: #ffff00;
+}
+#buddypress div#item-header {
+	overflow: hidden;
+}
+#buddypress div#item-header div#item-header-content {
+	float: right;
+	margin-right: 0;
+}
+#buddypress div#item-header h2 {
+	line-height: 120%;
+	margin: 0 0 15px 0;
+}
+#buddypress div#item-header h2 a {
+	color: #777;
+	text-decoration: none;
+}
+#buddypress div#item-header img.avatar {
+	float: right;
+	margin: 0 0 19px 15px;
+}
+#buddypress div#item-header h2 {
+	margin-bottom: 5px;
+}
+#buddypress div#item-header h2 span.highlight {
+	font-size: 60%;
+	font-weight: normal;
+	line-height: 170%;
+	vertical-align: middle;
+	display: inline-block;
+}
+#buddypress div#item-header h2 span.highlight span {
+	background: #a1dcfa;
+	color: #fff;
+	cursor: pointer;
+	font-weight: bold;
+	font-size: 80%;
+	margin-bottom: 2px;
+	padding: 1px 4px;
+	position: relative;
+	left: -2px;
+	top: -2px;
+	vertical-align: middle;
+}
+#buddypress div#item-header div#item-meta {
+	font-size: 80%;
+	color: #aaa;
+	overflow: hidden;
+	margin: 15px 0 5px 0;
+	padding-bottom: 10px;
+}
+#buddypress div#item-header div#item-actions {
+	float: left;
+	margin: 0 15px 15px 0;
+	text-align: left;
+	width: 20%;
+}
+#buddypress div#item-header div#item-actions h3 {
+	margin: 0 0 5px 0;
+}
+#buddypress div#item-header ul {
+	margin-bottom: 15px;
+	overflow: hidden;
+}
+#buddypress div#item-header ul h5,
+#buddypress div#item-header ul span,
+#buddypress div#item-header ul hr {
+	display: none;
+}
+#buddypress div#item-header ul li {
+	float: left;
+	list-style: none;
+}
+#buddypress div#item-header ul img.avatar,
+#buddypress div#item-header ul.avatars img.avatar {
+	height: 30px;
+	margin: 2px;
+	width: 30px;
+}
+#buddypress div#item-header div.generic-button,
+#buddypress div#item-header a.button {
+	float: right;
+	margin: 10px 0 0 10px;
+}
+#buddypress div#item-header div#message.info {
+	line-height: 80%;
+}
+#buddypress ul.item-list {
+	border-top: 1px solid #eaeaea;
+	width: 100%;
+	list-style: none;
+	clear: both;
+	margin: 0;
+	padding: 0;
+}
+body.activity-permalink #buddypress ul.item-list,
+body.activity-permalink #buddypress ul.item-list li.activity-item {
+	border: none;
+}
+#buddypress ul.item-list li {
+	border-bottom: 1px solid #eaeaea;
+	padding: 15px 0;
+	margin: 0;
+	position: relative;
+	list-style: none;
+}
+#buddypress ul.single-line li {
+	border: none;
+}
+#buddypress ul.item-list li img.avatar {
+	float: right;
+	margin: 0 0 0 10px;
+}
+#buddypress ul.item-list li div.item-title,
+#buddypress ul.item-list li h4 {
+	font-weight: normal;
+	font-size: 90%;
+	margin: 0;
+	width: 75%;
+}
+#buddypress ul.item-list li div.item-title span {
+	color: #999;
+	font-size: 80%;
+}
+#buddypress ul.item-list li div.item-desc {
+	color: #888;
+	font-size: 80%;
+	margin: 10px 60px 0 0;
+	width: 50%;
+}
+#buddypress ul.item-list li div.action {
+	position: absolute;
+	top: 15px;
+	left: 0;
+	text-align: left;
+}
+#buddypress ul.item-list li div.meta {
+	color: #888;
+	font-size: 80%;
+	margin-top: 10px;
+}
+#buddypress ul.item-list li h5 span.small {
+	float: left;
+	font-size: 80%;
+	font-weight: normal;
+}
+#buddypress div.item-list-tabs {
+	background: transparent;
+	clear: right;
+	overflow: hidden;
+}
+
+#buddypress div.item-list-tabs ul {
+	margin: 0;
+	padding: 0;
+}
+#buddypress div.item-list-tabs ul li {
+	float: right;
+	margin: 0;
+	list-style: none;
+}
+#buddypress div.item-list-tabs#subnav ul li {
+	margin-top: 0;
+}
+#buddypress div.item-list-tabs ul li.last {
+	float: left;
+	margin: 7px 0 0;
+}
+#buddypress div.item-list-tabs#subnav ul li.last {
+	margin-top: 4px;
+}
+#buddypress div.item-list-tabs ul li.last select {
+	max-width: 175px;
+}
+#buddypress div.item-list-tabs ul li a,
+#buddypress div.item-list-tabs ul li span {
+	display: block;
+	padding: 5px 10px;
+	text-decoration: none;
+}
+#buddypress div.item-list-tabs ul li a span {
+	background: #eee;
+	border-radius: 50%;
+	border: 1px solid #ccc;
+	color: #999;
+	display: inline;
+	font-size: 70%;
+	margin-right: 2px;
+	padding: 3px 6px;
+	text-align: center;
+	vertical-align: middle;
+}
+#buddypress div.item-list-tabs ul li.selected a,
+#buddypress div.item-list-tabs ul li.current a {
+	background-color: #eee;
+	color: #555;
+	opacity: .8;
+	font-weight: bold;
+}
+#buddypress div.item-list-tabs ul li.selected a span,
+#buddypress div.item-list-tabs ul li.current a span,
+#buddypress div.item-list-tabs ul li a:hover span {
+	background-color: #eee;
+}
+#buddypress div.item-list-tabs ul li.selected a span,
+#buddypress div.item-list-tabs ul li.current a span {
+	background-color: #fff;
+}
+#buddypress div#item-nav ul li.loading a {
+	background-position: 88% 50%;
+}
+#buddypress div.item-list-tabs#object-nav {
+	margin-top: 0;
+}
+#buddypress div.item-list-tabs#subnav {
+	background: transparent;
+	margin: 10px 0 10px;
+	overflow: hidden;
+}
+#buddypress #admins-list li,
+#buddypress #mods-list li,
+#buddypress #members-list li {
+	overflow: auto;
+	list-style: none;
+}
+
+
+/*--------------------------------------------------------------
+3.9 - Private Messaging Threads
+--------------------------------------------------------------*/
+#buddypress table#message-threads tr.unread td {
+	background: #fff9db;
+	border-top: 1px solid #ffe8c4;
+	border-bottom: 1px solid #ffe8c4;
+	font-weight: bold;
+}
+#buddypress li span.unread-count,
+#buddypress tr.unread span.unread-count {
+	background: #dd0000;
+	color: #fff;
+	font-weight: bold;
+	padding: 2px 8px;
+}
+#buddypress div.item-list-tabs ul li a span.unread-count {
+	padding: 1px 6px;
+	color: #fff;
+}
+#buddypress div.messages-options-nav {
+	background: #eee;
+	font-size: 80%;
+	margin: 0;
+	padding: 5px 15px;
+	text-align: left;
+}
+#buddypress div#message-thread div.message-box {
+	margin: 0;
+	padding: 15px;
+}
+#buddypress div#message-thread div.alt {
+	background: #f4f4f4;
+}
+#buddypress div#message-thread p#message-recipients {
+	margin: 10px 0 20px 0;
+}
+#buddypress div#message-thread img.avatar {
+	float: right;
+	margin: 0 10px 0 0;
+	vertical-align: middle;
+}
+#buddypress div#message-thread strong {
+	font-size: 100%;
+	margin: 0;
+}
+#buddypress div#message-thread strong a {
+	text-decoration: none;
+}
+#buddypress div#message-thread strong span.activity {
+	margin-top: 4px;
+}
+#buddypress div#message-thread div.message-metadata {
+	overflow: hidden;
+}
+#buddypress div#message-thread div.message-content {
+	margin-right: 45px;
+}
+#buddypress div#message-thread div.message-options {
+	text-align: left;
+}
+#buddypress #message-threads img.avatar {
+	max-width: none;
+}
+#buddypress div.message-search {
+	float: left;
+	margin: 0 20px;
+}
+
+/*--------------------------------------------------------------
+3.10 - Extended Profiles
+--------------------------------------------------------------*/
+
+#buddypress div.profile h4 {
+	margin-bottom: auto;
+	margin-top: 15px;
+}
+#buddypress #profile-edit-form ul.button-nav {
+	margin-top: 15px;
+}
+body.no-js #buddypress .field-visibility-settings-toggle,
+body.no-js #buddypress .field-visibility-settings-close {
+	display: none;
+}
+#buddypress .field-visibility-settings {
+	display: none;
+	margin-top: 10px;
+}
+	body.no-js #buddypress .field-visibility-settings {
+		display: block;
+	}
+#buddypress .current-visibility-level {
+	font-weight: bold;
+	font-style: normal;
+}
+#buddypress .field-visibility-settings,
+#buddypress .field-visibility-settings-toggle,
+#buddypress .field-visibility-settings-notoggle {
+	color: #888;
+}
+#buddypress .field-visibility-settings-toggle a,
+#buddypress .field-visibility-settings a {
+	font-size: 80%;
+}
+body.register #buddypress div.page ul {
+	list-style: none;
+}
+#buddypress .standard-form .field-visibility-settings label {
+	margin: 0;
+	font-weight: normal;
+}
+#buddypress .field-visibility-settings legend,
+#buddypress .field-visibility-settings-toggle {
+	font-style: italic;
+}
+
+/*--------------------------------------------------------------
+3.11 - Widgets
+--------------------------------------------------------------*/
+
+.widget.buddypress div.item-avatar img.avatar {
+	float: right;
+	margin: 0 0 15px 10px;
+}
+
+.widget.buddypress span.activity {
+	display: inline-block;
+	font-size: 80%;
+	opacity: 0.8;
+	padding: 0;
+}
+
+.widget.buddypress div.item-options {
+	font-size: 90%;
+	margin: 0 0 1em 0;
+	padding: 1em 0;
+}
+
+.widget.buddypress div.item{
+	margin:0 0 1em 0;
+}
+
+.widget.buddypress div.item-meta,
+.widget.buddypress div.item-content {
+	font-size: 11px;
+	margin-right: 38px;
+}
+
+.widget.buddypress ul.item-list img.avatar {
+	height: 20px;
+	margin-left: 10px;
+	width: 20px;
+}
+.widget.buddypress div.item-avatar img {
+	height: 40px;
+	margin: 1px;
+	width: 40px;
+}
+
+.widget.buddypress div.avatar-block{
+	overflow: hidden;
+}
+
+/*--------------------------------------------------------------
+4.0 - Media Queries
+--------------------------------------------------------------*/
+/*--------------------------------------------------------------
+4.1 - Smartphones - landscape
+--------------------------------------------------------------*/
+@media screen and (max-device-width: 480px), screen and (-webkit-min-device-pixel-ratio: 2) {
+	-webkit-text-size-adjust: none;
+}
+@media only screen and (max-width: 480px ){
+	#buddypress div.dir-search {
+		float: left;
+		margin-top: -50px;
+		text-align: left;
+	}
+	#buddypress div.dir-search input[type="text"] {
+		margin-bottom: 1em;
+		width: 50%;
+	}
+	a.bp-title-button {
+		margin-right: 10px;
+	}
+	#buddypress form.standard-form .main-column div.action{
+		position: relative;
+		margin-bottom:1em;
+	}
+	#buddypress form.standard-form .main-column ul#friend-list h4{
+		width:100%;
+	}
+}
+
+/*--------------------------------------------------------------
+4.2 - Smartphones - portrait
+--------------------------------------------------------------*/
+@media only screen and (max-width: 320px) {
+	#buddypress div.dir-search {
+		clear: right;
+		float: right;
+		margin-top: 0;
+		text-align: right;
+	}
+	#buddypress li#groups-order-select {
+		clear: right;
+		float: right;
+	}
+	#buddypress ul.item-list li div.action {
+		clear: right;
+		float: right;
+		margin-top: 0;
+		margin-right: 70px;
+		position: relative;
+		top: 0;
+		left: 0;
+		text-align: right;
+	}
+	#buddypress ul.item-list li div.item-desc {
+		clear: right;
+		float: right;
+		margin: 10px 0 0;
+		width: auto;
+	}
+	#buddypress li div.item {
+		margin-right: 70px;
+		width: auto;
+	}
+	#buddypress ul.item-list li div.meta {
+		margin-top: 0;
+	}
+	#buddypress .item-desc p {
+		margin: 0 0 10px;
+	}
+	#buddypress div.pagination .pag-count {
+		margin-right: 0;
+	}
+}
+
+/*--------------------------------------------------------------
+4.2 - Smartphones - smaller screen sizes
+--------------------------------------------------------------*/
+@media only screen and (max-width: 240px) {
+	#buddypress div.dir-search {
+		float: right;
+		margin: 0;
+	}
+	#buddypress div.dir-search input[type="text"] {
+		width: 50%;
+	}
+	#buddypress li#groups-order-select {
+		float: right;
+	}
+	#buddypress ul.item-list li img.avatar {
+		width: 30px;
+		height: auto;
+	}
+	#buddypress ul.item-list li div.action,
+	#buddypress li div.item{
+		margin-right: 45px;
+	}
+	h1 a.bp-title-button {
+		clear: right;
+		float: right;
+		margin: 10px 0 20px;
+	}
+}
Index: /tags/1.9/bp-templates/bp-legacy/css/buddypress.css
===================================================================
--- /tags/1.9/bp-templates/bp-legacy/css/buddypress.css	(revision 7684)
+++ /tags/1.9/bp-templates/bp-legacy/css/buddypress.css	(revision 7684)
@@ -0,0 +1,1599 @@
+/*--------------------------------------------------------------
+Hello, this is the BuddyPress Legacy stylesheet.
+
+----------------------------------------------------------------
+>>> TABLE OF CONTENTS:
+----------------------------------------------------------------
+1.0 - Navigation
+	1.1 - Pagination
+2.0 - WordPress
+	2.1 - Images
+3.0 - BuddyPress
+	3.1 - Activity
+		3.1.1 - Activity Listing
+		3.1.2 - Activity Comments
+	3.2 - Toolbar
+	3.3 - Directories - Members, Groups, Blogs, Forums
+	3.4 - Error / Success Messages
+	3.5 - Forms
+	3.6 - Ajax Loading
+	3.7 - Topics and Tables - Forums and General
+	3.8 - Headers, Lists and Tabs - Activity, Groups, Blogs, Forums
+	3.9 - Private Messaging Threads
+	3.10 - Extended Profiles
+	3.11 - Widgets
+4.0 - Media Queries
+	4.1 - Smartphones Landscape
+	4.2 - Smartphones Portrait
+	4.3 - Smartphones - smaller screen sizes
+--------------------------------------------------------------*/
+
+/*--------------------------------------------------------------
+1 - Navigation
+--------------------------------------------------------------*/
+/*--------------------------------------------------------------
+1.1 - Pagination
+--------------------------------------------------------------*/
+#buddypress div.pagination {
+	background: transparent;
+	border: none;
+	color: #888;
+	font-size: 90%;
+	margin: 0;
+	position: relative;
+	display: block;
+	float: left;
+	width: 100%;
+	padding: 10px 0;
+}
+#buddypress div.pagination .pag-count {
+	float: left;
+	margin-left: 10px;
+}
+#buddypress div.pagination .pagination-links {
+	float: right;
+	margin-right: 10px;
+}
+#buddypress div.pagination .pagination-links span,
+#buddypress div.pagination .pagination-links a {
+	font-size: 90%;
+	padding: 0 5px;
+}
+#buddypress div.pagination .pagination-links a:hover {
+	font-weight: bold;
+}
+#buddypress noscript div.pagination {
+	margin-bottom: 15px;
+}
+#buddypress #nav-above {
+	display: none;
+}
+#buddypress .paged #nav-above {
+	display: block;
+}
+/*--------------------------------------------------------------
+2 - WordPress
+--------------------------------------------------------------*/
+/*--------------------------------------------------------------
+2.1 - Images
+--------------------------------------------------------------*/
+#buddypress img.wp-smiley {
+	border: none !important;
+	clear: none !important;
+	float: none !important;
+	margin: 0 !important;
+	padding: 0 !important;
+}
+
+/*--------------------------------------------------------------
+3.0 - BuddyPress
+--------------------------------------------------------------*/
+/*--------------------------------------------------------------
+3.1 - Activity
+--------------------------------------------------------------*/
+#buddypress #activity-stream {
+	margin-top: -5px;
+}
+
+#buddypress #activity-stream p {
+	margin: 5px 0;
+}
+
+#buddypress #item-body form#whats-new-form {
+	margin: 0;
+	padding: 0;
+}
+#buddypress .home-page form#whats-new-form {
+	border-bottom: none;
+	padding-bottom: 0;
+}
+#buddypress form#whats-new-form #whats-new-avatar {
+	float: left;
+}
+#buddypress form#whats-new-form #whats-new-content {
+	margin-left: 55px;
+	padding: 0 0 20px 20px;
+}
+#buddypress form#whats-new-form p.activity-greeting {
+	line-height: 0.5em;
+	margin-bottom: 15px;
+	margin-left: 75px;
+}
+#buddypress form#whats-new-form textarea {
+	background: #fff;
+	color: #555;
+	font-family: inherit;
+	font-size: 90%;
+	height: 20px;
+	padding: 6px;
+	width: 98%;
+}
+body.no-js #buddypress form#whats-new-form textarea {
+	height: 50px;
+}
+#buddypress form#whats-new-form #whats-new-options select {
+	max-width: 200px;
+	margin-top: 12px;
+}
+#buddypress form#whats-new-form #whats-new-submit {
+	float: right;
+	margin-top: 12px;
+}
+#buddypress #whats-new-options {
+	overflow: auto;
+	height: 0;
+}
+body.no-js #buddypress #whats-new-options {
+	height: auto;
+}
+#buddypress #whats-new:focus {
+	border-color: rgba(31, 179, 221, 0.9) !important;
+	outline-color: rgba(31, 179, 221, 0.9);
+}
+
+/*--------------------------------------------------------------
+3.1.1 - Activity Listing
+--------------------------------------------------------------*/
+#buddypress ul.activity-list li {
+	overflow: hidden;
+	padding: 15px 0 0;
+	list-style: none;
+}
+#buddypress .activity-list .activity-avatar {
+	float: left;
+}
+#buddypress ul.item-list.activity-list li.has-comments {
+	padding-bottom: 15px;
+}
+body.activity-permalink #buddypress ul.activity-list li.has-comments {
+	padding-bottom: 0;
+}
+#buddypress .activity-list li.mini {
+	font-size: 80%;
+	position: relative;
+}
+#buddypress .activity-list li.mini .activity-avatar img.avatar,
+#buddypress .activity-list li.mini .activity-avatar img.FB_profile_pic {
+	height: 20px;
+	margin-left: 30px;
+	width: 20px;
+}
+#buddypress .activity-permalink .activity-list li.mini .activity-avatar img.avatar,
+#buddypress .activity-permalink .activity-list li.mini .activity-avatar img.FB_profile_pic {
+	height: auto;
+	margin-left: 0;
+	width: auto;
+}
+body.activity-permalink #buddypress .activity-list > li:first-child {
+	padding-top: 0;
+}
+#buddypress .activity-list li .activity-content {
+	position: relative;
+}
+#buddypress .activity-list li.mini .activity-content p {
+	margin: 0;
+}
+#buddypress .activity-list li.mini .activity-comments {
+	clear: both;
+	font-size: 120%;
+}
+body.activity-permalink #buddypress li.mini .activity-meta {
+	margin-top: 4px;
+}
+#buddypress .activity-list li .activity-inreplyto {
+	color: #888;
+	font-size: 80%;
+}
+#buddypress .activity-list li .activity-inreplyto > p {
+	margin: 0;
+	display: inline;
+}
+#buddypress .activity-list li .activity-inreplyto blockquote,
+#buddypress .activity-list li .activity-inreplyto div.activity-inner {
+	background: none;
+	border: none;
+	display: inline;
+	margin: 0;
+	overflow: hidden;
+	padding: 0;
+}
+#buddypress .activity-list .activity-content {
+	margin: 0 0 0 70px;
+}
+body.activity-permalink #buddypress .activity-list li .activity-content {
+	border: none;
+	font-size: 100%;
+	line-height: 150%;
+	margin-left: 170px;
+	margin-right: 0;
+	padding: 0;
+}
+body.activity-permalink #buddypress .activity-list li .activity-header > p {
+	margin: 0;
+	padding: 5px 0 0 0;
+}
+#buddypress .activity-list .activity-content .activity-header,
+#buddypress .activity-list .activity-content .comment-header {
+	color: #888;
+	line-height: 220%;
+}
+#buddypress .activity-header {
+	margin-right: 20px;
+}
+#buddypress .activity-header a,
+#buddypress .comment-meta a,
+#buddypress .acomment-meta a {
+	text-decoration: none;
+}
+#buddypress .activity-list .activity-content .activity-header img.avatar {
+	float: none !important;
+	margin: 0 5px -8px 0 !important;
+}
+#buddypress a.bp-secondary-action,
+#buddypress span.highlight {
+	font-size: 80%;
+	padding: 0;
+	margin-right: 5px;
+	text-decoration: none;
+}
+#buddypress .activity-list .activity-content .activity-inner,
+#buddypress .activity-list .activity-content blockquote {
+	margin: 10px 10px 5px 0;
+	overflow: hidden;
+}
+#buddypress .activity-list li.new_forum_post .activity-content .activity-inner,
+#buddypress .activity-list li.new_forum_topic .activity-content .activity-inner {
+	border-left: 2px solid #EAEAEA;
+	margin-left: 5px;
+	padding-left: 10px;
+}
+body.activity-permalink #buddypress .activity-content .activity-inner,
+body.activity-permalink #buddypress .activity-content blockquote {
+	margin-left: 0;
+	margin-top: 5px;
+}
+#buddypress .activity-inner > p {
+	word-wrap: break-word;
+}
+#buddypress .activity-inner > .activity-inner {
+	margin: 0;
+}
+#buddypress .activity-inner > blockquote {
+	margin: 0;
+}
+#buddypress .activity-list .activity-content img.thumbnail {
+	border: 2px solid #eee;
+	float: left;
+	margin: 0 10px 5px 0;
+}
+#buddypress .activity-read-more {
+	margin-left: 1em;
+	white-space: nowrap;
+}
+#buddypress .activity-list li.load-more {
+	background: #f0f0f0;
+	font-size: 110%;
+	margin: 15px 0;
+	padding: 10px 15px;
+	text-align: center;
+}
+#buddypress .activity-list li.load-more a {
+	color: #4D4D4D;
+}
+
+
+/*--------------------------------------------------------------
+3.1.2 - Activity Comments
+--------------------------------------------------------------*/
+#buddypress div.activity-meta {
+	margin: 18px 0 0;
+}
+body.activity-permalink #buddypress div.activity-meta {
+	margin-bottom: 6px;
+}
+#buddypress div.activity-meta a {
+	padding: 4px 8px;
+}
+#buddypress a.activity-time-since {
+	color: #aaa;
+	text-decoration: none;
+}
+#buddypress a.activity-time-since:hover {
+	color: #888;
+	text-decoration: underline;
+}
+#buddypress a.bp-primary-action,
+#buddypress #reply-title small a {
+	font-size: 80%;
+	margin-right: 5px;
+	text-decoration: none;
+}
+#buddypress a.bp-primary-action span,
+#buddypress #reply-title small a span {
+	background: #999;
+	color: #fff;
+	font-size: 90%;
+	margin-left: 2px;
+	padding: 0 5px;
+}
+#buddypress a.bp-primary-action:hover span,
+#buddypress #reply-title small a:hover span {
+	background: #555;
+	color: #fff;
+}
+#buddypress div.activity-comments {
+	margin: 0 0 0 70px;
+	overflow: hidden; /* IE fix */
+	position: relative;
+	width: auto;
+	clear: both;
+}
+body.activity-permalink #buddypress div.activity-comments {
+	background: none;
+	margin-left: 170px;
+	width: auto;
+}
+#buddypress div.activity-comments > ul {
+	padding: 0 0 0 10px;
+}
+#buddypress div.activity-comments ul,
+#buddypress div.activity-comments ul li {
+	border: none;
+	list-style: none;
+}
+#buddypress div.activity-comments ul {
+	clear: both;
+	margin: 0;
+}
+#buddypress div.activity-comments ul li {
+	border-top: 1px solid #eee;
+	padding: 10px 0 0;
+}
+body.activity-permalink #buddypress .activity-list li.mini .activity-comments {
+	clear: none;
+	margin-top: 0;
+}
+body.activity-permalink #buddypress div.activity-comments ul li {
+	border-width: 1px;
+	padding: 10px 0 0 0;
+}
+#buddypress div.activity-comments > ul > li:first-child {
+	border-top: none;
+}
+#buddypress div.activity-comments ul li:last-child {
+	margin-bottom: 0;
+}
+#buddypress div.activity-comments ul li > ul {
+	margin-left: 30px;
+	margin-top: 0;
+	padding-left: 10px;
+}
+body.activity-permalink #buddypress div.activity-comments ul li > ul {
+	margin-top: 10px;
+}
+body.activity-permalink #buddypress div.activity-comments > ul {
+	padding: 0 10px 0 15px;
+}
+#buddypress div.activity-comments div.acomment-avatar img {
+	border-width: 1px;
+	float: left;
+	height: 25px;
+	margin-right: 10px;
+	width: 25px;
+}
+#buddypress div.activity-comments div.acomment-content {
+	font-size: 80%;
+	margin: 5px 0 0 40px;
+}
+#buddypress div.acomment-content .time-since,
+#buddypress div.acomment-content .activity-delete-link,
+#buddypress div.acomment-content .comment-header {
+	display: none;
+}
+body.activity-permalink #buddypress div.activity-comments div.acomment-content {
+	font-size: 90%;
+}
+#buddypress div.activity-comments div.acomment-meta {
+	color: #888;
+	font-size: 80%;
+}
+#buddypress div.activity-comments form.ac-form {
+	display: none;
+	padding: 10px;
+}
+#buddypress div.activity-comments li form.ac-form {
+	margin-right: 15px;
+	clear: both;
+}
+#buddypress div.activity-comments form.root {
+	margin-left: 0;
+}
+#buddypress div.activity-comments div#message {
+	margin-top: 15px;
+	margin-bottom: 0;
+}
+#buddypress div.activity-comments form .ac-textarea {
+	background: #fff;
+	border: 1px inset #ccc;
+	margin-bottom: 10px;
+	padding: 8px;
+}
+#buddypress div.activity-comments form textarea {
+	border: none;
+	background: transparent;
+	box-shadow: none;
+	outline: none;
+	color: #555;
+	font-family: inherit;
+	font-size: 100%;
+	height: 60px;
+	padding: 0;
+	margin: 0;
+	width: 100%;
+}
+#buddypress div.activity-comments form input {
+	margin-top: 5px;
+}
+#buddypress div.activity-comments form div.ac-reply-avatar {
+	float: left;
+}
+#buddypress div.ac-reply-avatar img {
+	border: 1px solid #eee;
+}
+#buddypress div.activity-comments form div.ac-reply-content {
+	color: #888;
+	margin-left: 50px;
+	padding-left: 15px;
+}
+#buddypress div.activity-comments form div.ac-reply-content a {
+	text-decoration: none;
+}
+#buddypress .acomment-options {
+	float: left;
+	margin: 5px 0 5px 40px;
+}
+#buddypress .acomment-options a {
+	color: #999;
+}
+#buddypress .acomment-options a:hover {
+	color: inherit;
+}
+
+/*--------------------------------------------------------------
+3.3 - Directories - Members, Groups, Blogs, Forums
+--------------------------------------------------------------*/
+#buddypress div.dir-search {
+	float: right;
+	margin: -39px 0 0 0;
+}
+#buddypress div.dir-search input[type=text] {
+	font-size: 90%;
+	padding: 1px 3px;
+}
+
+#buddypress .dir-form {
+	clear: both;
+}
+
+/*--------------------------------------------------------------
+3.4 - Errors / Success Messages
+--------------------------------------------------------------*/
+#buddypress div#message {
+	margin: 0 0 15px;
+}
+#buddypress #message.info {
+	margin-bottom: 0;
+}
+#buddypress div#message.updated {
+	clear: both;
+}
+#buddypress div#message p,
+#sitewide-notice p {
+	font-size: 90%;
+	display: block;
+	padding: 10px 15px;
+}
+#buddypress div#message.error p {
+	background-color: #fdc;
+	border: 1px solid #a00;
+	clear: left;
+	color: #800;
+}
+#buddypress div#message.updated p {
+	background-color: #efc;
+	border: 1px solid #591;
+	color: #250;
+}
+#buddypress .standard-form#signup_form div div.error {
+	background: #faa;
+	color: #a00;
+	margin: 0 0 10px 0;
+	padding: 6px;
+	width: 90%;
+}
+#buddypress div.accept,
+#buddypress div.reject {
+	float: left;
+	margin-left: 10px;
+}
+#buddypress ul.button-nav li {
+	float: left;
+	margin: 0 10px 10px 0;
+	list-style: none;
+}
+#buddypress ul.button-nav li.current a {
+	font-weight: bold;
+}
+#sitewide-notice #message {
+	left: 2%;
+	position: fixed;
+	top: 1em;
+	width: 96%;
+	z-index: 9999;
+}
+#sitewide-notice.admin-bar-on #message {
+	top: 3.3em;
+}
+#sitewide-notice strong {
+	display: block;
+	margin-bottom: -1em;
+}
+
+/*--------------------------------------------------------------
+3.5 - Forms
+--------------------------------------------------------------*/
+#buddypress .standard-form textarea,
+#buddypress .standard-form input[type=text],
+#buddypress .standard-form input[type=text],
+#buddypress .standard-form input[type=color],
+#buddypress .standard-form input[type=date],
+#buddypress .standard-form input[type=datetime],
+#buddypress .standard-form input[type=datetime-local],
+#buddypress .standard-form input[type=email],
+#buddypress .standard-form input[type=month],
+#buddypress .standard-form input[type=number],
+#buddypress .standard-form input[type=range],
+#buddypress .standard-form input[type=search],
+#buddypress .standard-form input[type=tel],
+#buddypress .standard-form input[type=time],
+#buddypress .standard-form input[type=url],
+#buddypress .standard-form input[type=week],
+#buddypress .standard-form select,
+#buddypress .standard-form input[type=password],
+#buddypress .dir-search input[type=search],
+#buddypress .dir-search input[type=text] {
+	border: 1px solid #ccc;
+	background: #fafafa;
+	border-radius: 0;
+	color: #888;
+	font: inherit;
+	font-size: 100%;
+	padding: 6px;
+}
+#buddypress .standard-form select {
+	padding: 3px;
+}
+#buddypress .standard-form input[type=password] {
+	margin-bottom: 5px;
+}
+#buddypress .standard-form label,
+#buddypress .standard-form span.label {
+	display: block;
+	font-weight: bold;
+	margin: 15px 0 5px 0;
+}
+#buddypress .standard-form div.checkbox label,
+#buddypress .standard-form div.radio label {
+	color: #888;
+	font-size: 100%;
+	font-weight: normal;
+	margin: 5px 0 0 0;
+}
+#buddypress .standard-form#sidebar-login-form label {
+	margin-top: 5px;
+}
+#buddypress .standard-form input[type=text] {
+	width: 75%;
+}
+#buddypress .standard-form#sidebar-login-form input[type=text],
+#buddypress .standard-form#sidebar-login-form input[type=password] {
+	padding: 4px;
+	width: 95%;
+}
+#buddypress .standard-form #basic-details-section input[type=password],
+#buddypress .standard-form #blog-details-section input#signup_blog_url {
+	width: 35%;
+}
+#buddypress .standard-form#signup_form input[type=text],
+#buddypress .standard-form#signup_form textarea,
+#buddypress .form-allowed-tags,
+#buddypress #commentform input[type=text],
+#buddypress #commentform textarea {
+	width: 90%;
+}
+#buddypress .standard-form#signup_form div.submit {
+	float: right;
+}
+#buddypress div#signup-avatar img {
+	margin: 0 15px 10px 0;
+}
+#buddypress .standard-form textarea {
+	width: 75%;
+	height: 120px;
+}
+#buddypress .standard-form textarea#message_content {
+	height: 200px;
+}
+#buddypress .standard-form#send-reply textarea {
+	width: 97.5%;
+}
+#buddypress .standard-form p.description {
+	color: #888;
+	font-size: 80%;
+	margin: 5px 0;
+}
+#buddypress .standard-form div.submit {
+	clear: both;
+	padding: 15px 0 0 0;
+}
+#buddypress .standard-form p.submit {
+	margin-bottom: 0;
+	padding: 15px 0 0 0;
+}
+#buddypress .standard-form div.submit input {
+	margin-right: 15px;
+}
+#buddypress .standard-form div.radio ul {
+	margin: 10px 0 15px 38px;
+	list-style: disc;
+}
+#buddypress .standard-form div.radio ul li {
+	margin-bottom: 5px;
+}
+#buddypress .standard-form a.clear-value {
+	display: block;
+	margin-top: 5px;
+	outline: none;
+}
+#buddypress .standard-form #basic-details-section,
+#buddypress .standard-form #blog-details-section,
+#buddypress .standard-form #profile-details-section {
+	float: left;
+	width: 48%;
+}
+#buddypress .standard-form #profile-details-section {
+	float: right;
+}
+#buddypress .standard-form #blog-details-section {
+	clear: left;
+}
+#buddypress .standard-form input:focus,
+#buddypress .standard-form textarea:focus,
+#buddypress .standard-form select:focus {
+	background: #fafafa;
+	color: #555;
+}
+#buddypress form#send-invite-form {
+	margin-top: 20px;
+}
+#buddypress div#invite-list {
+	background: #f5f5f5;
+	height: 400px;
+	margin: 0 0 10px;
+	overflow: auto;
+	padding: 5px;
+	width: 160px;
+}
+#buddypress button,
+#buddypress a.button,
+#buddypress input[type=submit],
+#buddypress input[type=button],
+#buddypress input[type=reset],
+#buddypress ul.button-nav li a,
+#buddypress div.generic-button a,
+#buddypress .comment-reply-link,
+a.bp-title-button {
+	background: #fff; /* Old browsers */
+	border: 1px solid #ccc;
+	color: #777;
+	font-size: .8rem;
+	cursor: pointer;
+	outline: none;
+	padding: 4px 10px;
+	text-align: center;
+	text-decoration: none;
+}
+#buddypress button:hover,
+#buddypress a.button:hover,
+#buddypress a.button:focus,
+#buddypress input[type=submit]:hover,
+#buddypress input[type=button]:hover,
+#buddypress input[type=reset]:hover,
+#buddypress ul.button-nav li a:hover,
+#buddypress ul.button-nav li.current a,
+#buddypress div.generic-button a:hover,
+#buddypress .comment-reply-link:hover {
+	background: #ededed;
+	border: 1px solid #bbb;
+	color: #555;
+	outline: none;
+	text-decoration: none;
+}
+
+#buddypress form.standard-form .left-menu {
+	float: left;
+}
+
+#buddypress form.standard-form .left-menu #invite-list ul{
+	margin:1%;
+	list-style: none;
+}
+
+#buddypress form.standard-form .left-menu #invite-list ul li {
+	margin:0 0 0 1%;
+}
+
+#buddypress form.standard-form .main-column {
+	margin-left: 190px;
+}
+
+#buddypress form.standard-form .main-column ul#friend-list {
+	clear:none;
+}
+
+#buddypress form.standard-form .main-column ul#friend-list h4 {
+	clear:none;
+}
+
+/* Overrides for embedded WP editors */
+#buddypress .wp-editor-wrap a.button,
+#buddypress .wp-editor-wrap button,
+#buddypress .wp-editor-wrap input[type=submit],
+#buddypress .wp-editor-wrap input[type=button],
+#buddypress .wp-editor-wrap input[type=reset] {
+	padding: 0 10px 1px;
+}
+/*--------------------------------------------------------------
+3.6 - Ajax Loading
+--------------------------------------------------------------*/
+#buddypress a.loading,
+#buddypress input.loading {
+	-webkit-animation: loader-pulsate .5s infinite ease-in-out alternate;
+	-moz-animation: loader-pulsate .5s infinite ease-in-out alternate;
+	border-color: #aaa;
+}
+@-webkit-keyframes loader-pulsate {
+	from {
+		border-color: #aaa;
+		-webkit-box-shadow: 0 0 6px #ccc;
+		box-shadow: 0 0 6px #ccc;
+	}
+	to {
+		border-color: #ccc;
+		-webkit-box-shadow: 0 0 6px #f8f8f8;
+		box-shadow: 0 0 6px #f8f8f8;
+	}
+}
+@-moz-keyframes loader-pulsate {
+	from {
+		border-color: #aaa;
+		-moz-box-shadow: 0 0 6px #ccc;
+		box-shadow: 0 0 6px #ccc;
+	}
+	to {
+		border-color: #ccc;
+		-moz-box-shadow: 0 0 6px #f8f8f8;
+		box-shadow: 0 0 6px #f8f8f8;
+	}
+}
+
+#buddypress a.loading:hover,
+#buddypress input.loading:hover {
+    color: #777;
+}
+#buddypress input[type="submit"].pending,
+#buddypress input[type="button"].pending,
+#buddypress input[type="reset"].pending,
+#buddypress input[type="submit"].disabled,
+#buddypress input[type="button"].disabled,
+#buddypress input[type="reset"].disabled,
+#buddypress button.pending,
+#buddypress button.disabled,
+#buddypress div.pending a,
+#buddypress a.disabled {
+    border-color: #eee;
+    color: #bbb;
+    cursor: default;
+}
+#buddypress input[type="submit"]:hover.pending,
+#buddypress input[type="button"]:hover.pending,
+#buddypress input[type="reset"]:hover.pending,
+#buddypress input[type="submit"]:hover.disabled,
+#buddypress input[type="button"]:hover.disabled,
+#buddypress input[type="reset"]:hover.disabled,
+#buddypress button.pending:hover,
+#buddypress button.disabled:hover,
+#buddypress div.pending a:hover,
+#buddypress a.disabled:hover {
+	border-color: #eee;
+    color: #bbb;
+}
+
+/*--------------------------------------------------------------
+3.7 - Forums, Tables and Topics
+--------------------------------------------------------------*/
+#buddypress ul#topic-post-list {
+	margin: 0;
+	width: auto;
+}
+#buddypress ul#topic-post-list li {
+	padding: 15px;
+	position: relative;
+}
+#buddypress ul#topic-post-list li.alt {
+	background: #f5f5f5;
+}
+#buddypress ul#topic-post-list li div.poster-meta {
+	color: #888;
+	margin-bottom: 10px;
+}
+#buddypress ul#topic-post-list li div.post-content {
+	margin-left: 54px;
+}
+#buddypress div.topic-tags {
+	font-size: 80%;
+}
+#buddypress div.admin-links {
+	color: #888;
+	font-size: 80%;
+	position: absolute;
+	top: 15px;
+	right: 25px;
+}
+#buddypress div#topic-meta {
+	margin: 0;
+	padding: 5px 19px 30px;
+	position: relative;
+}
+#buddypress div#topic-meta div.admin-links {
+	right: 19px;
+	top: -36px;
+}
+#buddypress div#topic-meta h3 {
+	margin: 5px 0;
+}
+#buddypress div#new-topic-post {
+	display: none;
+	margin: 20px 0 0 0;
+	padding: 1px 0 0 0;
+}
+#buddypress table.notifications,
+#buddypress table.notifications-settings,
+#buddypress table.profile-fields,
+#buddypress table.wp-profile-fields,
+#buddypress table.messages-notices,
+#buddypress table.forum {
+	width: 100%;
+}
+#buddypress table.notifications thead tr,
+#buddypress table.notifications-settings thead tr,
+#buddypress table.profile-fields thead tr,
+#buddypress table.wp-profile-fields thead tr,
+#buddypress table.messages-notices thead tr,
+#buddypress table.forum thead tr {
+	background: #eaeaea;
+}
+#buddypress table#message-threads {
+	clear: both;
+	margin: 0;
+	width: auto;
+}
+#buddypress table.profile-fields {
+	margin-bottom: 20px;
+}
+#buddypress table.profile-fields:last-child {
+	margin-bottom: 0;
+}
+#buddypress table.profile-fields p {
+	margin: 0;
+}
+#buddypress table.profile-fields p:last-child {
+	margin-top: 0;
+}
+#buddypress table.notifications tr td,
+#buddypress table.notifications-settings tr td,
+#buddypress table.profile-fields tr td,
+#buddypress table.wp-profile-fields tr td,
+#buddypress table.messages-notices tr td,
+#buddypress table.forum tr td,
+#buddypress table.notifications tr th,
+#buddypress table.notifications-settings tr th,
+#buddypress table.profile-fields tr th,
+#buddypress table.wp-profile-fields tr th,
+#buddypress table.messages-notices tr th,
+#buddypress table.forum tr th {
+	padding: 8px;
+	vertical-align: middle;
+}
+#buddypress table.notifications tr td.label,
+#buddypress table.notifications-settings tr td.label,
+#buddypress table.profile-fields tr td.label,
+#buddypress table.wp-profile-fields tr td.label,
+#buddypress table.messages-notices tr td.label,
+#buddypress table.forum tr td.label {
+	border-right: 1px solid #eaeaea;
+	font-weight: bold;
+	width: 25%;
+}
+#buddypress table tr td.thread-info p {
+	margin: 0;
+}
+#buddypress table tr td.thread-info p.thread-excerpt {
+	color: #888;
+	font-size: 80%;
+	margin-top: 3px;
+}
+#buddypress table.forum td {
+	text-align: center;
+}
+#buddypress table.notifications tr.alt td,
+#buddypress table.notifications-settings tr.alt td,
+#buddypress table.profile-fields tr.alt td,
+#buddypress table.wp-profile-fields tr.alt td,
+#buddypress table.messages-notices tr.alt td,
+#buddypress table.forum tr.alt td {
+	background: #f5f5f5;
+}
+#buddypress table.notification-settings {
+	margin-bottom: 20px;
+	text-align: left;
+}
+#buddypress #groups-notification-settings {
+	margin-bottom: 0;
+}
+#buddypress table.notifications th.icon,
+#buddypress table.notifications td:first-child,
+#buddypress table.notification-settings th.icon,
+#buddypress table.notification-settings td:first-child {
+	display: none;
+}
+#buddypress table.notification-settings th.title {
+	width: 80%;
+}
+#buddypress table.notification-settings .yes,
+#buddypress table.notification-settings .no {
+	text-align: center;
+	width: 40px;
+}
+#buddypress table.forum {
+	margin: 0;
+	width: auto;
+	clear: both;
+}
+#buddypress table.forum tr.sticky td {
+	font-size: 110%;
+	background: #fff9db;
+	border-top: 1px solid #ffe8c4;
+	border-bottom: 1px solid #ffe8c4;
+}
+#buddypress table.forum tr.closed td.td-title {
+	padding-left: 35px;
+}
+#buddypress table.forum td p.topic-text {
+	color: #888;
+	font-size: 100%;
+}
+#buddypress table.forum tr > td:first-child,
+#buddypress table.forum tr > th:first-child {
+	padding-left: 15px;
+}
+#buddypress table.forum tr > td:last-child,
+#buddypress table.forum tr > th:last-child {
+	padding-right: 15px;
+}
+#buddypress table.forum tr th#th-title,
+#buddypress table.forum tr th#th-poster,
+#buddypress table.forum tr th#th-group,
+#buddypress table.forum td.td-poster,
+#buddypress table.forum td.td-group,
+#buddypress table.forum td.td-title {
+	text-align: left;
+}
+#buddypress table.forum tr td.td-title a.topic-title {
+	font-size: 110%;
+}
+#buddypress table.forum td.td-freshness {
+	white-space: nowrap;
+}
+#buddypress table.forum td.td-freshness span.time-since {
+	font-size: 80%;
+	color: #888;
+}
+#buddypress table.forum td img.avatar {
+	float: none;
+	margin: 0 5px -8px 0;
+}
+#buddypress table.forum td.td-poster,
+#buddypress table.forum td.td-group {
+	min-width: 140px;
+}
+#buddypress table.forum th#th-title {
+	width: 80%;
+}
+#buddypress table.forum th#th-freshness {
+	width: 25%;
+}
+#buddypress table.forum th#th-postcount {
+	width: 15%;
+}
+#buddypress table.forum p.topic-meta {
+	font-size: 80%;
+	margin: 5px 0 0 0;
+}
+
+/*-------------------------------------------------------------------------
+3.8 - Headers, Lists and Tabs - Activity, Groups, Blogs, Forums, Profiles
+-------------------------------------------------------------------------*/
+#buddypress .item-body {
+	margin: 20px 0;
+}
+#buddypress span.activity {
+	display: inline-block;
+	font-size: 80%;
+	opacity: 0.8;
+	padding: 0;
+}
+#buddypress span.user-nicename {
+	color: #777;
+	display: inline-block;
+	font-size: 120%;
+	font-weight: bold;
+}
+#buddypress div#message p,
+#sitewide-notice p {
+	font-weight: normal;
+	margin-top: 3px;
+	text-decoration: none;
+	background-color: #ffd;
+	border: 1px solid #cb2;
+	color: #440;
+	
+}
+#buddypress div#item-header {
+	overflow: hidden;
+}
+#buddypress div#item-header div#item-header-content {
+	float: left;
+	margin-left: 0;
+}
+#buddypress div#item-header h2 {
+	line-height: 120%;
+	margin: 0 0 15px 0;
+}
+#buddypress div#item-header h2 a {
+	color: #777;
+	text-decoration: none;
+}
+#buddypress div#item-header img.avatar {
+	float: left;
+	margin: 0 15px 19px 0;
+}
+#buddypress div#item-header h2 {
+	margin-bottom: 5px;
+}
+#buddypress div#item-header h2 span.highlight {
+	font-size: 60%;
+	font-weight: normal;
+	line-height: 170%;
+	vertical-align: middle;
+	display: inline-block;
+}
+#buddypress div#item-header h2 span.highlight span {
+	background: #a1dcfa;
+	color: #fff;
+	cursor: pointer;
+	font-weight: bold;
+	font-size: 80%;
+	margin-bottom: 2px;
+	padding: 1px 4px;
+	position: relative;
+	right: -2px;
+	top: -2px;
+	vertical-align: middle;
+}
+#buddypress div#item-header div#item-meta {
+	font-size: 80%;
+	color: #aaa;
+	overflow: hidden;
+	margin: 15px 0 5px 0;
+	padding-bottom: 10px;
+}
+#buddypress div#item-header div#item-actions {
+	float: right;
+	margin: 0 0 15px 15px;
+	text-align: right;
+	width: 20%;
+}
+#buddypress div#item-header div#item-actions h3 {
+	margin: 0 0 5px 0;
+}
+#buddypress div#item-header ul {
+	margin-bottom: 15px;
+	overflow: hidden;
+}
+#buddypress div#item-header ul h5,
+#buddypress div#item-header ul span,
+#buddypress div#item-header ul hr {
+	display: none;
+}
+#buddypress div#item-header ul li {
+	float: right;
+	list-style: none;
+}
+#buddypress div#item-header ul img.avatar,
+#buddypress div#item-header ul.avatars img.avatar {
+	height: 30px;
+	margin: 2px;
+	width: 30px;
+}
+#buddypress div#item-header div.generic-button,
+#buddypress div#item-header a.button {
+	float: left;
+	margin: 10px 10px 0 0;
+}
+#buddypress div#item-header div#message.info {
+	line-height: 80%;
+}
+#buddypress ul.item-list {
+	border-top: 1px solid #eaeaea;
+	width: 100%;
+	list-style: none;
+	clear: both;
+	margin: 0;
+	padding: 0;
+}
+body.activity-permalink #buddypress ul.item-list,
+body.activity-permalink #buddypress ul.item-list li.activity-item {
+	border: none;
+}
+#buddypress ul.item-list li {
+	border-bottom: 1px solid #eaeaea;
+	padding: 15px 0;
+	margin: 0;
+	position: relative;
+	list-style: none;
+}
+#buddypress ul.single-line li {
+	border: none;
+}
+#buddypress ul.item-list li img.avatar {
+	float: left;
+	margin: 0 10px 0 0;
+}
+#buddypress ul.item-list li div.item-title,
+#buddypress ul.item-list li h4 {
+	font-weight: normal;
+	font-size: 90%;
+	margin: 0;
+	width: 75%;
+}
+#buddypress ul.item-list li div.item-title span {
+	color: #999;
+	font-size: 80%;
+}
+#buddypress ul.item-list li div.item-desc {
+	color: #888;
+	font-size: 80%;
+	margin: 10px 0 0 60px;
+	width: 50%;
+}
+#buddypress ul.item-list li div.action {
+	position: absolute;
+	top: 15px;
+	right: 0;
+	text-align: right;
+}
+#buddypress ul.item-list li div.meta {
+	color: #888;
+	font-size: 80%;
+	margin-top: 10px;
+}
+#buddypress ul.item-list li h5 span.small {
+	float: right;
+	font-size: 80%;
+	font-weight: normal;
+}
+#buddypress div.item-list-tabs {
+	background: transparent;
+	clear: left;
+	overflow: hidden;
+}
+
+#buddypress div.item-list-tabs ul {
+	margin: 0;
+	padding: 0;
+}
+#buddypress div.item-list-tabs ul li {
+	float: left;
+	margin: 0;
+	list-style: none;
+}
+#buddypress div.item-list-tabs#subnav ul li {
+	margin-top: 0;
+}
+#buddypress div.item-list-tabs ul li.last {
+	float: right;
+	margin: 7px 0 0;
+}
+#buddypress div.item-list-tabs#subnav ul li.last {
+	margin-top: 4px;
+}
+#buddypress div.item-list-tabs ul li.last select {
+	max-width: 175px;
+}
+#buddypress div.item-list-tabs ul li a,
+#buddypress div.item-list-tabs ul li span {
+	display: block;
+	padding: 5px 10px;
+	text-decoration: none;
+}
+#buddypress div.item-list-tabs ul li a span {
+	background: #eee;
+	border-radius: 50%;
+	border: 1px solid #ccc;
+	color: #999;
+	display: inline;
+	font-size: 70%;
+	margin-left: 2px;
+	padding: 3px 6px;
+	text-align: center;
+	vertical-align: middle;
+}
+#buddypress div.item-list-tabs ul li.selected a,
+#buddypress div.item-list-tabs ul li.current a {
+	background-color: #eee;
+	color: #555;
+	opacity: .8;
+	font-weight: bold;
+}
+#buddypress div.item-list-tabs ul li.selected a span,
+#buddypress div.item-list-tabs ul li.current a span,
+#buddypress div.item-list-tabs ul li a:hover span {
+	background-color: #eee;
+}
+#buddypress div.item-list-tabs ul li.selected a span,
+#buddypress div.item-list-tabs ul li.current a span {
+	background-color: #fff;
+}
+#buddypress div#item-nav ul li.loading a {
+	background-position: 88% 50%;
+}
+#buddypress div.item-list-tabs#object-nav {
+	margin-top: 0;
+}
+#buddypress div.item-list-tabs#subnav {
+	background: transparent;
+	margin: 10px 0 10px;
+	overflow: hidden;
+}
+#buddypress #admins-list li,
+#buddypress #mods-list li,
+#buddypress #members-list li {
+	overflow: auto;
+	list-style: none;
+}
+
+
+/*--------------------------------------------------------------
+3.9 - Private Messaging Threads
+--------------------------------------------------------------*/
+#buddypress table#message-threads tr.unread td {
+	background: #fff9db;
+	border-top: 1px solid #ffe8c4;
+	border-bottom: 1px solid #ffe8c4;
+	font-weight: bold;
+}
+#buddypress li span.unread-count,
+#buddypress tr.unread span.unread-count {
+	background: #dd0000;
+	color: #fff;
+	font-weight: bold;
+	padding: 2px 8px;
+}
+#buddypress div.item-list-tabs ul li a span.unread-count {
+	padding: 1px 6px;
+	color: #fff;
+}
+#buddypress div.messages-options-nav {
+	background: #eee;
+	font-size: 80%;
+	margin: 0;
+	padding: 5px 15px;
+	text-align: right;
+}
+#buddypress div#message-thread div.message-box {
+	margin: 0;
+	padding: 15px;
+}
+#buddypress div#message-thread div.alt {
+	background: #f4f4f4;
+}
+#buddypress div#message-thread p#message-recipients {
+	margin: 10px 0 20px 0;
+}
+#buddypress div#message-thread img.avatar {
+	float: left;
+	margin: 0 10px 0 0;
+	vertical-align: middle;
+}
+#buddypress div#message-thread strong {
+	font-size: 100%;
+	margin: 0;
+}
+#buddypress div#message-thread strong a {
+	text-decoration: none;
+}
+#buddypress div#message-thread strong span.activity {
+	margin-top: 4px;
+}
+#buddypress div#message-thread div.message-metadata {
+	overflow: hidden;
+}
+#buddypress div#message-thread div.message-content {
+	margin-left: 45px;
+}
+#buddypress div#message-thread div.message-options {
+	text-align: right;
+}
+#buddypress #message-threads img.avatar {
+	max-width: none;
+}
+#buddypress div.message-search {
+	float: right;
+	margin: 0 20px;
+}
+
+/*--------------------------------------------------------------
+3.10 - Extended Profiles
+--------------------------------------------------------------*/
+
+#buddypress div.profile h4 {
+	margin-bottom: auto;
+	margin-top: 15px;
+}
+#buddypress #profile-edit-form ul.button-nav {
+	margin-top: 15px;
+}
+body.no-js #buddypress .field-visibility-settings-toggle,
+body.no-js #buddypress .field-visibility-settings-close {
+	display: none;
+}
+#buddypress .field-visibility-settings {
+	display: none;
+	margin-top: 10px;
+}
+	body.no-js #buddypress .field-visibility-settings {
+		display: block;
+	}
+#buddypress .current-visibility-level {
+	font-weight: bold;
+	font-style: normal;
+}
+#buddypress .field-visibility-settings,
+#buddypress .field-visibility-settings-toggle,
+#buddypress .field-visibility-settings-notoggle {
+	color: #888;
+}
+#buddypress .field-visibility-settings-toggle a,
+#buddypress .field-visibility-settings a {
+	font-size: 80%;
+}
+body.register #buddypress div.page ul {
+	list-style: none;
+}
+#buddypress .standard-form .field-visibility-settings label {
+	margin: 0;
+	font-weight: normal;
+}
+#buddypress .field-visibility-settings legend,
+#buddypress .field-visibility-settings-toggle {
+	font-style: italic;
+}
+
+/*--------------------------------------------------------------
+3.11 - Widgets
+--------------------------------------------------------------*/
+
+.widget.buddypress div.item-avatar img.avatar {
+	float: left;
+	margin: 0 10px 15px 0;
+}
+
+.widget.buddypress span.activity {
+	display: inline-block;
+	font-size: 80%;
+	opacity: 0.8;
+	padding: 0;
+}
+
+.widget.buddypress div.item-options {
+	font-size: 90%;
+	margin: 0 0 1em 0;
+	padding: 1em 0;
+}
+
+.widget.buddypress div.item{
+	margin:0 0 1em 0;
+}
+
+.widget.buddypress div.item-meta,
+.widget.buddypress div.item-content {
+	font-size: 11px;
+	margin-left: 38px;
+}
+
+.widget.buddypress ul.item-list img.avatar {
+	height: 20px;
+	margin-right: 10px;
+	width: 20px;
+}
+.widget.buddypress div.item-avatar img {
+	height: 40px;
+	margin: 1px;
+	width: 40px;
+}
+
+.widget.buddypress div.avatar-block{
+	overflow: hidden;
+}
+
+.widget.buddypress #bp-login-widget-form label {
+	display: block;
+	margin: 1rem 0 .5rem;
+}
+
+.widget.buddypress #bp-login-widget-form #bp-login-widget-submit {
+	margin-right: 10px;
+}
+
+.widget.buddypress .bp-login-widget-user-avatar {
+	float: left;
+	width: 60px;
+}
+
+.widget.buddypress .bp-login-widget-user-links > div {
+	padding-left: 60px;
+}
+
+.widget.buddypress .bp-login-widget-user-links > div {
+	margin-bottom: .5rem;
+}
+
+.widget.buddypress .bp-login-widget-user-links > div.bp-login-widget-user-link a {
+	font-weight: bold;
+}
+
+/*--------------------------------------------------------------
+4.0 - Media Queries
+--------------------------------------------------------------*/
+/*--------------------------------------------------------------
+4.1 - Smartphones - landscape
+--------------------------------------------------------------*/
+@media screen and (max-device-width: 480px), screen and (-webkit-min-device-pixel-ratio: 2) {
+	-webkit-text-size-adjust: none;
+}
+@media only screen and (max-width: 480px ){
+	#buddypress div.dir-search {
+		float: right;
+		margin-top: -50px;
+		text-align: right;
+	}
+	#buddypress div.dir-search input[type="text"] {
+		margin-bottom: 1em;
+		width: 50%;
+	}
+	a.bp-title-button {
+		margin-left: 10px;
+	}
+	#buddypress form.standard-form .main-column div.action{
+		position: relative;
+		margin-bottom:1em;
+	}
+	#buddypress form.standard-form .main-column ul#friend-list h4{
+		width:100%;
+	}
+}
+
+/*--------------------------------------------------------------
+4.2 - Smartphones - portrait
+--------------------------------------------------------------*/
+@media only screen and (max-width: 320px) {
+	#buddypress div.dir-search {
+		clear: left;
+		float: left;
+		margin-top: 0;
+		text-align: left;
+	}
+	#buddypress li#groups-order-select {
+		clear: left;
+		float: left;
+	}
+	#buddypress ul.item-list li div.action {
+		clear: left;
+		float: left;
+		margin-top: 0;
+		margin-left: 70px;
+		position: relative;
+		top: 0;
+		right: 0;
+		text-align: left;
+	}
+	#buddypress ul.item-list li div.item-desc {
+		clear: left;
+		float: left;
+		margin: 10px 0 0;
+		width: auto;
+	}
+	#buddypress li div.item {
+		margin-left: 70px;
+		width: auto;
+	}
+	#buddypress ul.item-list li div.meta {
+		margin-top: 0;
+	}
+	#buddypress .item-desc p {
+		margin: 0 0 10px;
+	}
+	#buddypress div.pagination .pag-count {
+		margin-left: 0;
+	}
+}
+
+/*--------------------------------------------------------------
+4.2 - Smartphones - smaller screen sizes
+--------------------------------------------------------------*/
+@media only screen and (max-width: 240px) {
+	#buddypress div.dir-search {
+		float: left;
+		margin: 0;
+	}
+	#buddypress div.dir-search input[type="text"] {
+		width: 50%;
+	}
+	#buddypress li#groups-order-select {
+		float: left;
+	}
+	#buddypress ul.item-list li img.avatar {
+		width: 30px;
+		height: auto;
+	}
+	#buddypress ul.item-list li div.action,
+	#buddypress li div.item{
+		margin-left: 45px;
+	}
+	h1 a.bp-title-button {
+		clear: left;
+		float: left;
+		margin: 10px 0 20px;
+	}
+}
Index: /tags/1.9/bp-templates/bp-legacy/js/buddypress.js
===================================================================
--- /tags/1.9/bp-templates/bp-legacy/js/buddypress.js	(revision 7684)
+++ /tags/1.9/bp-templates/bp-legacy/js/buddypress.js	(revision 7684)
@@ -0,0 +1,1613 @@
+// AJAX Functions
+var jq = jQuery;
+
+// Global variable to prevent multiple AJAX requests
+var bp_ajax_request = null;
+
+jq(document).ready( function() {
+	/**** Page Load Actions *******************************************************/
+
+	/* Hide Forums Post Form */
+	if ( '-1' == window.location.search.indexOf('new') && jq('div.forums').length )
+		jq('#new-topic-post').hide();
+	else
+		jq('#new-topic-post').show();
+
+	/* Activity filter and scope set */
+	bp_init_activity();
+
+	/* Object filter and scope set. */
+	var objects = [ 'members', 'groups', 'blogs', 'forums' ];
+	bp_init_objects( objects );
+
+	/* @mention Compose Scrolling */
+	var $whats_new = jq('#whats-new');
+	if ( jq.query.get('r') && $whats_new.length ) {
+		jq('#whats-new-options').animate({
+			height:'40px'
+		});
+		jq("#whats-new-form textarea").animate({
+			height:'50px'
+		});
+		jq.scrollTo( $whats_new, 500, {
+			offset:-125,
+			easing:'easeOutQuad'
+		} );
+		var whats_new_content = $whats_new.val();
+		$whats_new.val('').focus().val(whats_new_content);
+	}
+
+	/**** Activity Posting ********************************************************/
+
+	/* Textarea focus */
+	$whats_new.focus( function(){
+		jq("#whats-new-options").animate({
+			height:'40px'
+		});
+		jq("#whats-new-form textarea").animate({
+			height:'50px'
+		});
+		jq("#aw-whats-new-submit").prop("disabled", false);
+		
+		var $whats_new_form = jq("form#whats-new-form");
+		if ( $whats_new_form.hasClass("submitted") ) {
+			$whats_new_form.removeClass("submitted");	
+		}
+	});
+
+	/* On blur, shrink if it's empty */
+	$whats_new.blur( function(){
+		if (!this.value.match(/\S+/)) {
+			this.value = "";
+			jq("#whats-new-options").animate({
+				height:'40px'
+			});
+			jq("form#whats-new-form textarea").animate({
+				height:'20px'
+			});
+			jq("#aw-whats-new-submit").prop("disabled", true);
+		}
+	});
+
+	/* New posts */
+	jq("#aw-whats-new-submit").on( 'click', function() {
+		var button = jq(this);
+		var form = button.closest("form#whats-new-form");
+
+		form.children().each( function() {
+			if ( jq.nodeName(this, "textarea") || jq.nodeName(this, "input") )
+				jq(this).prop( 'disabled', true );
+		});
+
+		/* Remove any errors */
+		jq('div.error').remove();
+		button.addClass('loading');
+		button.prop('disabled', true);
+		form.addClass("submitted");
+
+		/* Default POST values */
+		var object = '';
+		var item_id = jq("#whats-new-post-in").val();
+		var content = jq("#whats-new").val();
+
+		/* Set object for non-profile posts */
+		if ( item_id > 0 ) {
+			object = jq("#whats-new-post-object").val();
+		}
+
+		jq.post( ajaxurl, {
+			action: 'post_update',
+			'cookie': bp_get_cookies(),
+			'_wpnonce_post_update': jq("#_wpnonce_post_update").val(),
+			'content': content,
+			'object': object,
+			'item_id': item_id,
+			'_bp_as_nonce': jq('#_bp_as_nonce').val() || ''
+		},
+		function(response) {
+
+			form.children().each( function() {
+				if ( jq.nodeName(this, "textarea") || jq.nodeName(this, "input") ) {
+					jq(this).prop( 'disabled', false );
+				}
+			});
+
+			/* Check for errors and append if found. */
+			if ( response[0] + response[1] == '-1' ) {
+				form.prepend( response.substr( 2, response.length ) );
+				jq( '#' + form.attr('id') + ' div.error').hide().fadeIn( 200 );
+			} else {
+				if ( 0 == jq("ul.activity-list").length ) {
+					jq("div.error").slideUp(100).remove();
+					jq("#message").slideUp(100).remove();
+					jq("div.activity").append( '<ul id="activity-stream" class="activity-list item-list">' );
+				}
+
+				jq("#activity-stream").prepend(response);
+				jq("#activity-stream li:first").addClass('new-update just-posted');
+
+				if ( 0 != jq("#latest-update").length ) {
+					var l = jq("#activity-stream li.new-update .activity-content .activity-inner p").html();
+					var v = jq("#activity-stream li.new-update .activity-content .activity-header p a.view").attr('href');
+
+					var ltext = jq("#activity-stream li.new-update .activity-content .activity-inner p").text();
+
+					var u = '';
+					if ( ltext != '' )
+						u = l + ' ';
+
+					u += '<a href="' + v + '" rel="nofollow">' + BP_DTheme.view + '</a>';
+
+					jq("#latest-update").slideUp(300,function(){
+						jq("#latest-update").html( u );
+						jq("#latest-update").slideDown(300);
+					});
+				}
+
+				jq("li.new-update").hide().slideDown( 300 );
+				jq("li.new-update").removeClass( 'new-update' );
+				jq("#whats-new").val('');
+			}
+
+			jq("#whats-new-options").animate({
+				height:'0px'
+			});
+			jq("#whats-new-form textarea").animate({
+				height:'20px'
+			});
+			jq("#aw-whats-new-submit").prop("disabled", true).removeClass('loading');
+		});
+
+		return false;
+	});
+
+	/* List tabs event delegation */
+	jq('div.activity-type-tabs').on( 'click', function(event) {
+		var target = jq(event.target).parent();
+
+		if ( event.target.nodeName == 'STRONG' || event.target.nodeName == 'SPAN' )
+			target = target.parent();
+		else if ( event.target.nodeName != 'A' )
+			return false;
+
+		/* Reset the page */
+		jq.cookie( 'bp-activity-oldestpage', 1, {
+			path: '/'
+		} );
+
+		/* Activity Stream Tabs */
+		var scope = target.attr('id').substr( 9, target.attr('id').length );
+		var filter = jq("#activity-filter-select select").val();
+
+		if ( scope == 'mentions' )
+			jq( '#' + target.attr('id') + ' a strong' ).remove();
+
+		bp_activity_request(scope, filter);
+
+		return false;
+	});
+
+	/* Activity filter select */
+	jq('#activity-filter-select select').change( function() {
+		var selected_tab = jq( 'div.activity-type-tabs li.selected' );
+
+		if ( !selected_tab.length )
+			var scope = null;
+		else
+			var scope = selected_tab.attr('id').substr( 9, selected_tab.attr('id').length );
+
+		var filter = jq(this).val();
+
+		bp_activity_request(scope, filter);
+
+		return false;
+	});
+
+	/* Stream event delegation */
+	jq('div.activity').on( 'click', function(event) {
+		var target = jq(event.target);
+
+		/* Favoriting activity stream items */
+		if ( target.hasClass('fav') || target.hasClass('unfav') ) {
+			var type = target.hasClass('fav') ? 'fav' : 'unfav';
+			var parent = target.closest('.activity-item');
+			var parent_id = parent.attr('id').substr( 9, parent.attr('id').length );
+
+			target.addClass('loading');
+
+			jq.post( ajaxurl, {
+				action: 'activity_mark_' + type,
+				'cookie': bp_get_cookies(),
+				'id': parent_id
+			},
+			function(response) {
+				target.removeClass('loading');
+
+				target.fadeOut( 200, function() {
+					jq(this).html(response);
+					jq(this).attr('title', 'fav' == type ? BP_DTheme.remove_fav : BP_DTheme.mark_as_fav);
+					jq(this).fadeIn(200);
+				});
+
+				if ( 'fav' == type ) {
+					if ( !jq('.item-list-tabs #activity-favs-personal-li').length ) {
+						if ( !jq('.item-list-tabs #activity-favorites').length )
+							jq('.item-list-tabs ul #activity-mentions').before( '<li id="activity-favorites"><a href="#">' + BP_DTheme.my_favs + ' <span>0</span></a></li>');
+
+						jq('.item-list-tabs ul #activity-favorites span').html( Number( jq('.item-list-tabs ul #activity-favorites span').html() ) + 1 );
+					}
+
+					target.removeClass('fav');
+					target.addClass('unfav');
+
+				} else {
+					target.removeClass('unfav');
+					target.addClass('fav');
+
+					jq('.item-list-tabs ul #activity-favorites span').html( Number( jq('.item-list-tabs ul #activity-favorites span').html() ) - 1 );
+
+					if ( !Number( jq('.item-list-tabs ul #activity-favorites span').html() ) ) {
+						if ( jq('.item-list-tabs ul #activity-favorites').hasClass('selected') )
+							bp_activity_request( null, null );
+
+						jq('.item-list-tabs ul #activity-favorites').remove();
+					}
+				}
+
+				if ( 'activity-favorites' == jq( '.item-list-tabs li.selected').attr('id') )
+					target.parent().parent().parent().slideUp(100);
+			});
+
+			return false;
+		}
+
+		/* Delete activity stream items */
+		if ( target.hasClass('delete-activity') ) {
+			var li        = target.parents('div.activity ul li');
+			var id        = li.attr('id').substr( 9, li.attr('id').length );
+			var link_href = target.attr('href');
+			var nonce     = link_href.split('_wpnonce=');
+
+			nonce = nonce[1];
+
+			target.addClass('loading');
+
+			jq.post( ajaxurl, {
+				action: 'delete_activity',
+				'cookie': bp_get_cookies(),
+				'id': id,
+				'_wpnonce': nonce
+			},
+			function(response) {
+
+				if ( response[0] + response[1] == '-1' ) {
+					li.prepend( response.substr( 2, response.length ) );
+					li.children('#message').hide().fadeIn(300);
+				} else {
+					li.slideUp(300);
+				}
+			});
+
+			return false;
+		}
+
+		// Spam activity stream items
+		if ( target.hasClass( 'spam-activity' ) ) {
+			var li = target.parents( 'div.activity ul li' );
+			target.addClass( 'loading' );
+
+			jq.post( ajaxurl, {
+				action: 'bp_spam_activity',
+				'cookie': encodeURIComponent( document.cookie ),
+				'id': li.attr( 'id' ).substr( 9, li.attr( 'id' ).length ),
+				'_wpnonce': target.attr( 'href' ).split( '_wpnonce=' )[1]
+			},
+
+			function(response) {
+				if ( response[0] + response[1] === '-1' ) {
+					li.prepend( response.substr( 2, response.length ) );
+					li.children( '#message' ).hide().fadeIn(300);
+				} else {
+					li.slideUp( 300 );
+				}
+			});
+
+			return false;
+		}
+
+		/* Load more updates at the end of the page */
+		if ( target.parent().hasClass('load-more') ) {
+			jq("#buddypress li.load-more").addClass('loading');
+
+			if ( null == jq.cookie('bp-activity-oldestpage') )
+				jq.cookie('bp-activity-oldestpage', 1, {
+					path: '/'
+				} );
+
+			var oldest_page = ( jq.cookie('bp-activity-oldestpage') * 1 ) + 1;
+
+			var just_posted = [];
+			
+			jq('.activity-list li.just-posted').each( function(){
+				just_posted.push( jq(this).attr('id').replace( 'activity-','' ) );
+			});
+
+			jq.post( ajaxurl, {
+				action: 'activity_get_older_updates',
+				'cookie': bp_get_cookies(),
+				'page': oldest_page,
+				'exclude_just_posted': just_posted.join(',')
+			},
+			function(response)
+			{
+				jq("#buddypress li.load-more").removeClass('loading');
+				jq.cookie( 'bp-activity-oldestpage', oldest_page, {
+					path: '/'
+				} );
+				jq("#buddypress ul.activity-list").append(response.contents);
+
+				target.parent().hide();
+			}, 'json' );
+
+			return false;
+		}
+	});
+
+	// Activity "Read More" links
+	jq('div.activity').on('click', '.activity-read-more a', function(event) {
+		var target = jq(event.target);
+		var link_id = target.parent().attr('id').split('-');
+		var a_id = link_id[3];
+		var type = link_id[0]; /* activity or acomment */
+
+		var inner_class = type == 'acomment' ? 'acomment-content' : 'activity-inner';
+		var a_inner = jq('#' + type + '-' + a_id + ' .' + inner_class + ':first' );
+		jq(target).addClass('loading');
+
+		jq.post( ajaxurl, {
+			action: 'get_single_activity_content',
+			'activity_id': a_id
+		},
+		function(response) {
+			jq(a_inner).slideUp(300).html(response).slideDown(300);
+		});
+
+		return false;
+	});
+
+	/**** Activity Comments *******************************************************/
+
+	/* Hide all activity comment forms */
+	jq('form.ac-form').hide();
+
+	/* Hide excess comments */
+	if ( jq('.activity-comments').length )
+		bp_legacy_theme_hide_comments();
+
+	/* Activity list event delegation */
+	jq('div.activity').on( 'click', function(event) {
+		var target = jq(event.target);
+
+		/* Comment / comment reply links */
+		if ( target.hasClass('acomment-reply') || target.parent().hasClass('acomment-reply') ) {
+			if ( target.parent().hasClass('acomment-reply') )
+				target = target.parent();
+
+			var id = target.attr('id');
+			ids = id.split('-');
+
+			var a_id = ids[2]
+			var c_id = target.attr('href').substr( 10, target.attr('href').length );
+			var form = jq( '#ac-form-' + a_id );
+
+			form.css( 'display', 'none' );
+			form.removeClass('root');
+			jq('.ac-form').hide();
+
+			/* Hide any error messages */
+			form.children('div').each( function() {
+				if ( jq(this).hasClass( 'error' ) )
+					jq(this).hide();
+			});
+
+			if ( ids[1] != 'comment' ) {
+				jq('#acomment-' + c_id).append( form );
+			} else {
+				jq('#activity-' + a_id + ' .activity-comments').append( form );
+			}
+
+			if ( form.parent().hasClass( 'activity-comments' ) )
+				form.addClass('root');
+
+			form.slideDown( 200 );
+			jq.scrollTo( form, 500, {
+				offset:-100,
+				easing:'easeOutQuad'
+			} );
+			jq('#ac-form-' + ids[2] + ' textarea').focus();
+
+			return false;
+		}
+
+		/* Activity comment posting */
+		if ( target.attr('name') == 'ac_form_submit' ) {
+			var form = target.parents( 'form' );
+			var form_parent = form.parent();
+			var form_id = form.attr('id').split('-');
+
+			if ( !form_parent.hasClass('activity-comments') ) {
+				var tmp_id = form_parent.attr('id').split('-');
+				var comment_id = tmp_id[1];
+			} else {
+				var comment_id = form_id[2];
+			}
+
+			var content = jq( '#' + form.attr('id') + ' textarea' );
+
+			/* Hide any error messages */
+			jq( '#' + form.attr('id') + ' div.error').hide();
+			target.addClass('loading').prop('disabled', true);
+			content.addClass('loading').prop('disabled', true);
+
+			var ajaxdata = {
+				action: 'new_activity_comment',
+				'cookie': bp_get_cookies(),
+				'_wpnonce_new_activity_comment': jq("#_wpnonce_new_activity_comment").val(),
+				'comment_id': comment_id,
+				'form_id': form_id[2],
+				'content': content.val()
+			};
+
+			// Akismet
+			var ak_nonce = jq('#_bp_as_nonce_' + comment_id).val();
+			if ( ak_nonce ) {
+				ajaxdata['_bp_as_nonce_' + comment_id] = ak_nonce;
+			}
+
+			jq.post( ajaxurl, ajaxdata, function(response) {
+				target.removeClass('loading');
+				content.removeClass('loading');
+
+				/* Check for errors and append if found. */
+				if ( response[0] + response[1] == '-1' ) {
+					form.append( jq( response.substr( 2, response.length ) ).hide().fadeIn( 200 ) );
+				} else {
+					var activity_comments = form.parent();
+					form.fadeOut( 200, function() {
+						if ( 0 == activity_comments.children('ul').length ) {
+							if ( activity_comments.hasClass('activity-comments') ) {
+								activity_comments.prepend('<ul></ul>');
+							} else {
+								activity_comments.append('<ul></ul>');
+							}
+						}
+
+						/* Preceeding whitespace breaks output with jQuery 1.9.0 */
+						var the_comment = jq.trim( response );
+
+						activity_comments.children('ul').append( jq( the_comment ).hide().fadeIn( 200 ) );
+						form.children('textarea').val('');
+						activity_comments.parent().addClass('has-comments');
+					} );
+					jq( '#' + form.attr('id') + ' textarea').val('');
+
+					/* Increase the "Reply (X)" button count */
+					jq('#activity-' + form_id[2] + ' a.acomment-reply span').html( Number( jq('#activity-' + form_id[2] + ' a.acomment-reply span').html() ) + 1 );
+
+					// Increment the 'Show all x comments' string, if present
+					var show_all_a = activity_comments.find('.show-all').find('a');
+					if ( show_all_a ) {
+						var new_count = jq('li#activity-' + form_id[2] + ' a.acomment-reply span').html();
+						show_all_a.html( BP_DTheme.show_x_comments.replace( '%d', new_count ) );
+					}
+				}
+
+				jq(target).prop("disabled", false);
+				jq(content).prop("disabled", false);
+			});
+
+			return false;
+		}
+
+		/* Deleting an activity comment */
+		if ( target.hasClass('acomment-delete') ) {
+			var link_href = target.attr('href');
+			var comment_li = target.parent().parent();
+			var form = comment_li.parents('div.activity-comments').children('form');
+
+			var nonce = link_href.split('_wpnonce=');
+			nonce = nonce[1];
+
+			var comment_id = link_href.split('cid=');
+			comment_id = comment_id[1].split('&');
+			comment_id = comment_id[0];
+
+			target.addClass('loading');
+
+			/* Remove any error messages */
+			jq('.activity-comments ul .error').remove();
+
+			/* Reset the form position */
+			comment_li.parents('.activity-comments').append(form);
+
+			jq.post( ajaxurl, {
+				action: 'delete_activity_comment',
+				'cookie': bp_get_cookies(),
+				'_wpnonce': nonce,
+				'id': comment_id
+			},
+			function(response) {
+				/* Check for errors and append if found. */
+				if ( response[0] + response[1] == '-1' ) {
+					comment_li.prepend( jq( response.substr( 2, response.length ) ).hide().fadeIn( 200 ) );
+				} else {
+					var children = jq( '#' + comment_li.attr('id') + ' ul' ).children('li');
+					var child_count = 0;
+					jq(children).each( function() {
+						if ( !jq(this).is(':hidden') )
+							child_count++;
+					});
+					comment_li.fadeOut(200, function() {
+						comment_li.remove();
+					});
+
+					/* Decrease the "Reply (X)" button count */
+					var count_span = jq('#' + comment_li.parents('#activity-stream > li').attr('id') + ' a.acomment-reply span');
+					var new_count = count_span.html() - ( 1 + child_count );
+					count_span.html(new_count);
+					
+					// Change the 'Show all x comments' text
+					var show_all_a = comment_li.siblings('.show-all').find('a');
+					if ( show_all_a ) {
+						show_all_a.html( BP_DTheme.show_x_comments.replace( '%d', new_count ) );
+					}
+
+					/* If that was the last comment for the item, remove the has-comments class to clean up the styling */
+					if ( 0 == new_count ) {
+						jq(comment_li.parents('#activity-stream > li')).removeClass('has-comments');
+					}
+				}
+			});
+
+			return false;
+		}
+
+		// Spam an activity stream comment
+		if ( target.hasClass( 'spam-activity-comment' ) ) {
+			var link_href  = target.attr( 'href' );
+			var comment_li = target.parent().parent();
+
+			target.addClass('loading');
+
+			// Remove any error messages
+			jq( '.activity-comments ul div.error' ).remove();
+
+			// Reset the form position
+			comment_li.parents( '.activity-comments' ).append( comment_li.parents( '.activity-comments' ).children( 'form' ) );
+
+			jq.post( ajaxurl, {
+				action: 'bp_spam_activity_comment',
+				'cookie': encodeURIComponent( document.cookie ),
+				'_wpnonce': link_href.split( '_wpnonce=' )[1],
+				'id': link_href.split( 'cid=' )[1].split( '&' )[0]
+			},
+
+			function ( response ) {
+				// Check for errors and append if found.
+				if ( response[0] + response[1] == '-1' ) {
+					comment_li.prepend( jq( response.substr( 2, response.length ) ).hide().fadeIn( 200 ) );
+
+				} else {
+					var children = jq( '#' + comment_li.attr( 'id' ) + ' ul' ).children( 'li' );
+					var child_count = 0;
+					jq(children).each( function() {
+						if ( !jq( this ).is( ':hidden' ) ) {
+							child_count++;
+						}
+					});
+					comment_li.fadeOut( 200 );
+
+					// Decrease the "Reply (X)" button count
+					var parent_li = comment_li.parents( '#activity-stream > li' );
+					jq( '#' + parent_li.attr( 'id' ) + ' a.acomment-reply span' ).html( jq( '#' + parent_li.attr( 'id' ) + ' a.acomment-reply span' ).html() - ( 1 + child_count ) );
+				}
+			});
+
+			return false;
+		}
+
+		/* Showing hidden comments - pause for half a second */
+		if ( target.parent().hasClass('show-all') ) {
+			target.parent().addClass('loading');
+
+			setTimeout( function() {
+				target.parent().parent().children('li').fadeIn(200, function() {
+					target.parent().remove();
+				});
+			}, 600 );
+
+			return false;
+		}
+
+		// Canceling an activity comment	
+		if ( target.hasClass( 'ac-reply-cancel' ) ) {
+			jq(target).closest('.ac-form').slideUp( 200 );
+			return false;
+		};
+	});
+
+	/* Escape Key Press for cancelling comment forms */
+	jq(document).keydown( function(e) {
+		e = e || window.event;
+		if (e.target)
+			element = e.target;
+		else if (e.srcElement)
+			element = e.srcElement;
+
+		if( element.nodeType == 3)
+			element = element.parentNode;
+
+		if( e.ctrlKey == true || e.altKey == true || e.metaKey == true )
+			return;
+
+		var keyCode = (e.keyCode) ? e.keyCode : e.which;
+
+		if ( keyCode == 27 ) {
+			if (element.tagName == 'TEXTAREA') {
+				if ( jq(element).hasClass('ac-input') )
+					jq(element).parent().parent().parent().slideUp( 200 );
+			}
+		}
+	});
+
+	/**** Directory Search ****************************************************/
+
+	/* The search form on all directory pages */
+	jq('.dir-search').on( 'click', function(event) {
+		if ( jq(this).hasClass('no-ajax') )
+			return;
+
+		var target = jq(event.target);
+
+		if ( target.attr('type') == 'submit' ) {
+			var css_id = jq('.item-list-tabs li.selected').attr('id').split( '-' );
+			var object = css_id[0];
+
+			bp_filter_request( object, jq.cookie('bp-' + object + '-filter'), jq.cookie('bp-' + object + '-scope') , 'div.' + object, target.parent().children('label').children('input').val(), 1, jq.cookie('bp-' + object + '-extras') );
+
+			return false;
+		}
+	});
+
+	/**** Tabs and Filters ****************************************************/
+
+	/* When a navigation tab is clicked - e.g. | All Groups | My Groups | */
+	jq('div.item-list-tabs').on( 'click', function(event) {
+		if ( jq(this).hasClass('no-ajax') )
+			return;
+
+		var targetElem = ( event.target.nodeName == 'SPAN' ) ? event.target.parentNode : event.target;
+		var target     = jq( targetElem ).parent();
+		if ( 'LI' == target[0].nodeName && !target.hasClass( 'last' ) ) {
+			var css_id = target.attr('id').split( '-' );
+			var object = css_id[0];
+
+			if ( 'activity' == object )
+				return false;
+
+			var scope = css_id[1];
+			var filter = jq("#" + object + "-order-select select").val();
+			var search_terms = jq("#" + object + "_search").val();
+
+			bp_filter_request( object, filter, scope, 'div.' + object, search_terms, 1, jq.cookie('bp-' + object + '-extras') );
+
+			return false;
+		}
+	});
+
+	/* When the filter select box is changed re-query */
+	jq('li.filter select').change( function() {
+		if ( jq('.item-list-tabs li.selected').length )
+			var el = jq('.item-list-tabs li.selected');
+		else
+			var el = jq(this);
+
+		var css_id = el.attr('id').split('-');
+		var object = css_id[0];
+		var scope = css_id[1];
+		var filter = jq(this).val();
+		var search_terms = false;
+
+		if ( jq('.dir-search input').length )
+			search_terms = jq('.dir-search input').val();
+
+		if ( 'friends' == object )
+			object = 'members';
+
+		bp_filter_request( object, filter, scope, 'div.' + object, search_terms, 1, jq.cookie('bp-' + object + '-extras') );
+
+		return false;
+	});
+
+	/* All pagination links run through this function */
+	jq('#buddypress').on( 'click', function(event) {
+		var target = jq(event.target);
+
+		if ( target.hasClass('button') )
+			return true;
+
+		if ( target.parent().parent().hasClass('pagination') && !target.parent().parent().hasClass('no-ajax') ) {
+			if ( target.hasClass('dots') || target.hasClass('current') )
+				return false;
+
+			if ( jq('.item-list-tabs li.selected').length )
+				var el = jq('.item-list-tabs li.selected');
+			else
+				var el = jq('li.filter select');
+
+			var page_number = 1;
+			var css_id = el.attr('id').split( '-' );
+			var object = css_id[0];
+			var search_terms = false;
+			var pagination_id = jq(target).closest('.pagination-links').attr('id');
+
+			if ( jq('div.dir-search input').length )
+				search_terms = jq('.dir-search input').val();
+
+			if ( jq(target).hasClass('next') )
+				var page_number = Number( jq('.pagination span.current').html() ) + 1;
+			else if ( jq(target).hasClass('prev') )
+				var page_number = Number( jq('.pagination span.current').html() ) - 1;
+			else
+				var page_number = Number( jq(target).html() );
+			
+			if ( pagination_id.indexOf( 'pag-bottom' ) !== -1 ) {
+				var caller = 'pag-bottom';
+			} else {
+				var caller = null;
+			}
+
+			bp_filter_request( object, jq.cookie('bp-' + object + '-filter'), jq.cookie('bp-' + object + '-scope'), 'div.' + object, search_terms, page_number, jq.cookie('bp-' + object + '-extras'), caller );
+
+			return false;
+		}
+
+	});
+
+	/**** New Forum Directory Post **************************************/
+
+	/* Hit the "New Topic" button on the forums directory page */
+	jq('a.show-hide-new').on( 'click', function() {
+		if ( !jq('#new-topic-post').length )
+			return false;
+
+		if ( jq('#new-topic-post').is(":visible") )
+			jq('#new-topic-post').slideUp(200);
+		else
+			jq('#new-topic-post').slideDown(200, function() {
+				jq('#topic_title').focus();
+			} );
+
+		return false;
+	});
+
+	/* Cancel the posting of a new forum topic */
+	jq('#submit_topic_cancel').on( 'click', function() {
+		if ( !jq('#new-topic-post').length )
+			return false;
+
+		jq('#new-topic-post').slideUp(200);
+		return false;
+	});
+
+	/* Clicking a forum tag */
+	jq('#forum-directory-tags a').on( 'click', function() {
+		bp_filter_request( 'forums', 'tags', jq.cookie('bp-forums-scope'), 'div.forums', jq(this).html().replace( /&nbsp;/g, '-' ), 1, jq.cookie('bp-forums-extras') );
+		return false;
+	});
+
+	/** Invite Friends Interface ****************************************/
+
+	/* Select a user from the list of friends and add them to the invite list */
+	jq("#invite-list input").on( 'click', function() {
+		jq('.ajax-loader').toggle();
+
+		var friend_id = jq(this).val();
+
+		if ( jq(this).prop('checked') == true )
+			var friend_action = 'invite';
+		else
+			var friend_action = 'uninvite';
+
+		jq('.item-list-tabs li.selected').addClass('loading');
+
+		jq.post( ajaxurl, {
+			action: 'groups_invite_user',
+			'friend_action': friend_action,
+			'cookie': bp_get_cookies(),
+			'_wpnonce': jq("#_wpnonce_invite_uninvite_user").val(),
+			'friend_id': friend_id,
+			'group_id': jq("#group_id").val()
+		},
+		function(response)
+		{
+			if ( jq("#message") )
+				jq("#message").hide();
+
+			jq('.ajax-loader').toggle();
+
+			if ( friend_action == 'invite' ) {
+				jq('#friend-list').append(response);
+			} else if ( friend_action == 'uninvite' ) {
+				jq('#friend-list li#uid-' + friend_id).remove();
+			}
+
+			jq('.item-list-tabs li.selected').removeClass('loading');
+		});
+	});
+
+	/* Remove a user from the list of users to invite to a group */
+	jq("#friend-list").on('click', 'li a.remove', function() {
+		jq('.ajax-loader').toggle();
+
+		var friend_id = jq(this).attr('id');
+		friend_id = friend_id.split('-');
+		friend_id = friend_id[1];
+
+		jq.post( ajaxurl, {
+			action: 'groups_invite_user',
+			'friend_action': 'uninvite',
+			'cookie': bp_get_cookies(),
+			'_wpnonce': jq("#_wpnonce_invite_uninvite_user").val(),
+			'friend_id': friend_id,
+			'group_id': jq("#group_id").val()
+		},
+		function(response)
+		{
+			jq('.ajax-loader').toggle();
+			jq('#friend-list #uid-' + friend_id).remove();
+			jq('#invite-list #f-' + friend_id).prop('checked', false);
+		});
+
+		return false;
+	});
+
+	/** Profile Visibility Settings *********************************/
+	jq('.field-visibility-settings').hide();
+	jq('.visibility-toggle-link').on( 'click', function() {
+		var toggle_div = jq(this).parent();
+
+		jq(toggle_div).fadeOut( 600, function(){
+			jq(toggle_div).siblings('.field-visibility-settings').slideDown(400);
+		});
+
+		return false;
+	} );
+
+	jq('.field-visibility-settings-close').on( 'click', function() {
+		var settings_div = jq(this).parent();
+		var vis_setting_text = settings_div.find('input:checked').parent().text();
+
+		settings_div.slideUp( 400, function() {
+			settings_div.siblings('.field-visibility-settings-toggle').fadeIn(800);
+			settings_div.siblings('.field-visibility-settings-toggle').children('.current-visibility-level').html(vis_setting_text);
+		} );
+
+		return false;
+	} );
+
+	jq("#profile-edit-form input:not(:submit), #profile-edit-form textarea, #profile-edit-form select, #signup_form input:not(:submit), #signup_form textarea, #signup_form select").change( function() {
+		var shouldconfirm = true;
+
+		jq('#profile-edit-form input:submit, #signup_form input:submit').on( 'click', function() {
+			shouldconfirm = false;
+		});
+		
+		window.onbeforeunload = function(e) {
+			if ( shouldconfirm ) {
+				return BP_DTheme.unsaved_changes;
+			}
+		};
+	});
+
+	/** Friendship Requests **************************************/
+
+	/* Accept and Reject friendship request buttons */
+	jq("#friend-list a.accept, #friend-list a.reject").on( 'click', function() {
+		var button = jq(this);
+		var li = jq(this).parents('#friend-list li');
+		var action_div = jq(this).parents('li div.action');
+
+		var id = li.attr('id').substr( 11, li.attr('id').length );
+		var link_href = button.attr('href');
+
+		var nonce = link_href.split('_wpnonce=');
+		nonce = nonce[1];
+
+		if ( jq(this).hasClass('accepted') || jq(this).hasClass('rejected') )
+			return false;
+
+		if ( jq(this).hasClass('accept') ) {
+			var action = 'accept_friendship';
+			action_div.children('a.reject').css( 'visibility', 'hidden' );
+		} else {
+			var action = 'reject_friendship';
+			action_div.children('a.accept').css( 'visibility', 'hidden' );
+		}
+
+		button.addClass('loading');
+
+		jq.post( ajaxurl, {
+			action: action,
+			'cookie': bp_get_cookies(),
+			'id': id,
+			'_wpnonce': nonce
+		},
+		function(response) {
+			button.removeClass('loading');
+
+			if ( response[0] + response[1] == '-1' ) {
+				li.prepend( response.substr( 2, response.length ) );
+				li.children('#message').hide().fadeIn(200);
+			} else {
+				button.fadeOut( 100, function() {
+					if ( jq(this).hasClass('accept') ) {
+						action_div.children('a.reject').hide();
+						jq(this).html( BP_DTheme.accepted ).contents().unwrap();
+					} else {
+						action_div.children('a.accept').hide();
+						jq(this).html( BP_DTheme.rejected ).contents().unwrap();
+					}
+				});
+			}
+		});
+
+		return false;
+	});
+
+	/* Add / Remove friendship buttons */
+	jq('#members-dir-list').on('click', '.friendship-button a', function() {
+		jq(this).parent().addClass('loading');
+		var fid = jq(this).attr('id');
+		fid = fid.split('-');
+		fid = fid[1];
+
+		var nonce = jq(this).attr('href');
+		nonce = nonce.split('?_wpnonce=');
+		nonce = nonce[1].split('&');
+		nonce = nonce[0];
+
+		var thelink = jq(this);
+
+		jq.post( ajaxurl, {
+			action: 'addremove_friend',
+			'cookie': bp_get_cookies(),
+			'fid': fid,
+			'_wpnonce': nonce
+		},
+		function(response)
+		{
+			var action = thelink.attr('rel');
+			var parentdiv = thelink.parent();
+
+			if ( action == 'add' ) {
+				jq(parentdiv).fadeOut(200,
+					function() {
+						parentdiv.removeClass('add_friend');
+						parentdiv.removeClass('loading');
+						parentdiv.addClass('pending_friend');
+						parentdiv.fadeIn(200).html(response);
+					}
+					);
+
+			} else if ( action == 'remove' ) {
+				jq(parentdiv).fadeOut(200,
+					function() {
+						parentdiv.removeClass('remove_friend');
+						parentdiv.removeClass('loading');
+						parentdiv.addClass('add');
+						parentdiv.fadeIn(200).html(response);
+					}
+					);
+			}
+		});
+		return false;
+	} );
+
+	/** Group Join / Leave Buttons **************************************/
+
+	// Confirmation when clicking Leave Group in group headers
+	jq('#buddypress').on('click', '.group-button .leave-group', function() {
+		if ( false == confirm( BP_DTheme.leave_group_confirm ) ) {
+			return false;
+		}
+	});
+
+	jq('#groups-dir-list').on('click', '.group-button a', function() {
+		var gid = jq(this).parent().attr('id');
+		gid = gid.split('-');
+		gid = gid[1];
+
+		var nonce = jq(this).attr('href');
+		nonce = nonce.split('?_wpnonce=');
+		nonce = nonce[1].split('&');
+		nonce = nonce[0];
+
+		var thelink = jq(this);
+
+		// Leave Group confirmation within directories - must intercept
+		// AJAX request
+		if ( thelink.hasClass( 'leave-group' ) && false == confirm( BP_DTheme.leave_group_confirm ) ) {
+			return false;
+		}
+
+		jq.post( ajaxurl, {
+			action: 'joinleave_group',
+			'cookie': bp_get_cookies(),
+			'gid': gid,
+			'_wpnonce': nonce
+		},
+		function(response)
+		{
+			var parentdiv = thelink.parent();
+
+			// user groups page
+			if ( ! jq('body.directory').length ) {
+				location.href = location.href;
+
+			// groups directory
+			} else {
+				jq(parentdiv).fadeOut(200,
+					function() {
+						parentdiv.fadeIn(200).html(response);
+
+						var mygroups = jq('#groups-personal span');
+						var add      = 1;
+
+						if( thelink.hasClass( 'leave-group' ) ) {
+							// hidden groups slide up
+							if ( parentdiv.hasClass( 'hidden' ) ) {
+								parentdiv.closest('li').slideUp( 200 );
+							}
+
+							add = 0;
+						} else if ( thelink.hasClass( 'request-membership' ) ) {
+							add = false;
+						}
+
+						// change the "My Groups" value
+						if ( mygroups.length && add !== false ) {
+							if ( add ) {
+								mygroups.text( ( mygroups.text() >> 0 ) + 1 );
+							} else {
+								mygroups.text( ( mygroups.text() >> 0 ) - 1 );
+							}
+						}
+
+					}
+				);
+			}
+		});
+		return false;
+	} );
+
+	/** Button disabling ************************************************/
+
+	jq('#buddypress').on( 'click', '.pending', function() {
+		return false;
+	});
+
+	/** Private Messaging ******************************************/
+
+	/** Message search*/
+	jq('.message-search').on( 'click', function(event) {
+		if ( jq(this).hasClass('no-ajax') )
+			return;
+
+		var target = jq(event.target);
+
+		if ( target.attr('type') == 'submit' ) {
+			//var css_id = jq('.item-list-tabs li.selected').attr('id').split( '-' );
+			var object = 'messages';
+
+			bp_filter_request( object, jq.cookie('bp-' + object + '-filter'), jq.cookie('bp-' + object + '-scope') , 'div.' + object, target.parent().children('label').children('input').val(), 1, jq.cookie('bp-' + object + '-extras') );
+
+			return false;
+		}
+	});
+
+	/* AJAX send reply functionality */
+	jq("#send_reply_button").click(
+		function() {
+			var order = jq('#messages_order').val() || 'ASC',
+			offset = jq('#message-recipients').offset();
+
+			var button = jq("#send_reply_button");
+			jq(button).addClass('loading');
+
+			jq.post( ajaxurl, {
+				action: 'messages_send_reply',
+				'cookie': bp_get_cookies(),
+				'_wpnonce': jq("#send_message_nonce").val(),
+
+				'content': jq("#message_content").val(),
+				'send_to': jq("#send_to").val(),
+				'subject': jq("#subject").val(),
+				'thread_id': jq("#thread_id").val()
+			},
+			function(response)
+			{
+				if ( response[0] + response[1] == "-1" ) {
+					jq('#send-reply').prepend( response.substr( 2, response.length ) );
+				} else {
+					jq('#send-reply #message').remove();
+					jq("#message_content").val('');
+
+					if ( 'ASC' == order ) {
+						jq('#send-reply').before( response );
+					} else {
+						jq('#message-recipients').after( response );
+						jq(window).scrollTop(offset.top);
+					}
+
+					jq(".new-message").hide().slideDown( 200, function() {
+						jq('.new-message').removeClass('new-message');
+					});
+				}
+				jq(button).removeClass('loading');
+			});
+
+			return false;
+		}
+	);
+
+	/* Marking private messages as read and unread */
+	jq("#mark_as_read, #mark_as_unread").click(function() {
+		var checkboxes_tosend = '';
+		var checkboxes = jq("#message-threads tr td input[type='checkbox']");
+
+		if ( 'mark_as_unread' == jq(this).attr('id') ) {
+			var currentClass = 'read'
+			var newClass = 'unread'
+			var unreadCount = 1;
+			var inboxCount = 0;
+			var unreadCountDisplay = 'inline';
+			var action = 'messages_markunread';
+		} else {
+			var currentClass = 'unread'
+			var newClass = 'read'
+			var unreadCount = 0;
+			var inboxCount = 1;
+			var unreadCountDisplay = 'none';
+			var action = 'messages_markread';
+		}
+
+		checkboxes.each( function(i) {
+			if(jq(this).is(':checked')) {
+				if ( jq('#m-' + jq(this).attr('value')).hasClass(currentClass) ) {
+					checkboxes_tosend += jq(this).attr('value');
+					jq('#m-' + jq(this).attr('value')).removeClass(currentClass);
+					jq('#m-' + jq(this).attr('value')).addClass(newClass);
+					var thread_count = jq('#m-' + jq(this).attr('value') + ' td span.unread-count').html();
+
+					jq('#m-' + jq(this).attr('value') + ' td span.unread-count').html(unreadCount);
+					jq('#m-' + jq(this).attr('value') + ' td span.unread-count').css('display', unreadCountDisplay);
+
+					var inboxcount = jq('tr.unread').length;
+
+					jq('#user-messages span').html( inboxcount );
+
+					if ( i != checkboxes.length - 1 ) {
+						checkboxes_tosend += ','
+					}
+				}
+			}
+		});
+		jq.post( ajaxurl, {
+			action: action,
+			'thread_ids': checkboxes_tosend
+		});
+		return false;
+	});
+
+	/* Selecting unread and read messages in inbox */
+	jq( 'body.messages #item-body div.messages' ).on( 'change', '#message-type-select', function() {
+		var selection = this.value;
+		var checkboxes = jq( "td input[type='checkbox']" );
+
+		checkboxes.each( function(i) {
+			checkboxes[i].checked = "";
+		});
+
+		var checked_value = "checked";
+		switch ( selection ) {
+			case 'unread' :
+				checkboxes = jq("tr.unread td input[type='checkbox']");
+				break;
+			case 'read' :
+				checkboxes = jq("tr.read td input[type='checkbox']");
+				break;
+			case '' :
+				checked_value = "";
+				break;
+		}
+
+		checkboxes.each( function(i) {
+			checkboxes[i].checked = checked_value;
+		});
+	});
+	
+	/* Bulk delete messages */
+	jq( 'body.messages #item-body div.messages' ).on( 'click', '.messages-options-nav a', function() {
+		if ( -1 == jq.inArray( this.id ), Array( 'delete_sentbox_messages', 'delete_inbox_messages' ) ) {
+			return;
+		}
+		
+		checkboxes_tosend = '';
+		checkboxes = jq("#message-threads tr td input[type='checkbox']");
+
+		jq('#message').remove();
+		jq(this).addClass('loading');
+
+		jq(checkboxes).each( function(i) {
+			if( jq(this).is(':checked') )
+				checkboxes_tosend += jq(this).attr('value') + ',';
+		});
+
+		if ( '' == checkboxes_tosend ) {
+			jq(this).removeClass('loading');
+			return false;
+		}
+		
+		jq.post( ajaxurl, {
+			action: 'messages_delete',
+			'thread_ids': checkboxes_tosend
+		}, function(response) {
+			if ( response[0] + response[1] == "-1" ) {
+				jq('#message-threads').prepend( response.substr( 2, response.length ) );
+			} else {
+				jq('#message-threads').before( '<div id="message" class="updated"><p>' + response + '</p></div>' );
+
+				jq(checkboxes).each( function(i) {
+					if( jq(this).is(':checked') ) {
+						// We need to uncheck because message is only hidden
+						// Otherwise, AJAX will be fired again with same data 
+						jq(this).attr( 'checked', false );
+						jq(this).parent().parent().fadeOut(150);
+					}
+				});
+			}
+
+			jq('#message').hide().slideDown(150);
+			jq("#delete_inbox_messages, #delete_sentbox_messages").removeClass('loading');
+		});
+
+		return false;
+	});
+
+	/* Close site wide notices in the sidebar */
+	jq("#close-notice").on( 'click', function() {
+		jq(this).addClass('loading');
+		jq('#sidebar div.error').remove();
+
+		jq.post( ajaxurl, {
+			action: 'messages_close_notice',
+			'notice_id': jq('.notice').attr('rel').substr( 2, jq('.notice').attr('rel').length )
+		},
+		function(response) {
+			jq("#close-notice").removeClass('loading');
+
+			if ( response[0] + response[1] == '-1' ) {
+				jq('.notice').prepend( response.substr( 2, response.length ) );
+				jq( '#sidebar div.error').hide().fadeIn( 200 );
+			} else {
+				jq('.notice').slideUp( 100 );
+			}
+		});
+		return false;
+	});
+
+	/* Toolbar & wp_list_pages Javascript IE6 hover class */
+	jq("#wp-admin-bar ul.main-nav li, #nav li").mouseover( function() {
+		jq(this).addClass('sfhover');
+	});
+
+	jq("#wp-admin-bar ul.main-nav li, #nav li").mouseout( function() {
+		jq(this).removeClass('sfhover');
+	});
+
+	/* Clear BP cookies on logout */
+	jq('a.logout').on( 'click', function() {
+		jq.cookie('bp-activity-scope', null, {
+			path: '/'
+		});
+		jq.cookie('bp-activity-filter', null, {
+			path: '/'
+		});
+		jq.cookie('bp-activity-oldestpage', null, {
+			path: '/'
+		});
+
+		var objects = [ 'members', 'groups', 'blogs', 'forums' ];
+		jq(objects).each( function(i) {
+			jq.cookie('bp-' + objects[i] + '-scope', null, {
+				path: '/'
+			} );
+			jq.cookie('bp-' + objects[i] + '-filter', null, {
+				path: '/'
+			} );
+			jq.cookie('bp-' + objects[i] + '-extras', null, {
+				path: '/'
+			} );
+		});
+	});
+	
+	/* if js is enabled then replace the no-js class by a js one */
+	if( jq('body').hasClass('no-js') )
+		jq('body').attr('class', jq('body').attr('class').replace( /no-js/,'js' ) );
+		
+});
+
+/* Setup activity scope and filter based on the current cookie settings. */
+function bp_init_activity() {
+	/* Reset the page */
+	jq.cookie( 'bp-activity-oldestpage', 1, {
+		path: '/'
+	} );
+
+	if ( null != jq.cookie('bp-activity-filter') && jq('#activity-filter-select').length )
+		jq('#activity-filter-select select option[value="' + jq.cookie('bp-activity-filter') + '"]').prop( 'selected', true );
+
+	/* Activity Tab Set */
+	if ( null != jq.cookie('bp-activity-scope') && jq('.activity-type-tabs').length ) {
+		jq('.activity-type-tabs li').each( function() {
+			jq(this).removeClass('selected');
+		});
+		jq('#activity-' + jq.cookie('bp-activity-scope') + ', .item-list-tabs li.current').addClass('selected');
+	}
+}
+
+/* Setup object scope and filter based on the current cookie settings for the object. */
+function bp_init_objects(objects) {
+	jq(objects).each( function(i) {
+		if ( null != jq.cookie('bp-' + objects[i] + '-filter') && jq('#' + objects[i] + '-order-select select').length )
+			jq('#' + objects[i] + '-order-select select option[value="' + jq.cookie('bp-' + objects[i] + '-filter') + '"]').prop( 'selected', true );
+
+		if ( null != jq.cookie('bp-' + objects[i] + '-scope') && jq('div.' + objects[i]).length ) {
+			jq('.item-list-tabs li').each( function() {
+				jq(this).removeClass('selected');
+			});
+			jq('#' + objects[i] + '-' + jq.cookie('bp-' + objects[i] + '-scope') + ', #object-nav li.current').addClass('selected');
+		}
+	});
+}
+
+/* Filter the current content list (groups/members/blogs/topics) */
+function bp_filter_request( object, filter, scope, target, search_terms, page, extras, caller ) {
+	if ( 'activity' == object )
+		return false;
+
+	if ( jq.query.get('s') && !search_terms )
+		search_terms = jq.query.get('s');
+
+	if ( null == scope )
+		scope = 'all';
+
+	/* Save the settings we want to remain persistent to a cookie */
+	jq.cookie( 'bp-' + object + '-scope', scope, {
+		path: '/'
+	} );
+	jq.cookie( 'bp-' + object + '-filter', filter, {
+		path: '/'
+	} );
+	jq.cookie( 'bp-' + object + '-extras', extras, {
+		path: '/'
+	} );
+
+	/* Set the correct selected nav and filter */
+	jq('.item-list-tabs li').each( function() {
+		jq(this).removeClass('selected');
+	});
+	jq('#' + object + '-' + scope + ', #object-nav li.current').addClass('selected');
+	jq('.item-list-tabs li.selected').addClass('loading');
+	jq('.item-list-tabs select option[value="' + filter + '"]').prop( 'selected', true );
+
+	if ( 'friends' == object )
+		object = 'members';
+
+	if ( bp_ajax_request )
+		bp_ajax_request.abort();
+
+	bp_ajax_request = jq.post( ajaxurl, {
+		action: object + '_filter',
+		'cookie': bp_get_cookies(),
+		'object': object,
+		'filter': filter,
+		'search_terms': search_terms,
+		'scope': scope,
+		'page': page,
+		'extras': extras
+	},
+	function(response)
+	{
+		/* animate to top if called from bottom pagination */
+		if ( caller == 'pag-bottom' && jq('#subnav').length ) {
+			var top = jq('#subnav').parent();
+			jq('html,body').animate({scrollTop: top.offset().top}, 'slow', function() {
+				jq(target).fadeOut( 100, function() {
+					jq(this).html(response);
+					jq(this).fadeIn(100);
+			 	});
+			});	
+
+		} else {
+			jq(target).fadeOut( 100, function() {
+				jq(this).html(response);
+				jq(this).fadeIn(100);
+		 	});
+		}
+
+		jq('.item-list-tabs li.selected').removeClass('loading');
+	});
+}
+
+/* Activity Loop Requesting */
+function bp_activity_request(scope, filter) {
+	/* Save the type and filter to a session cookie */
+	jq.cookie( 'bp-activity-scope', scope, {
+		path: '/'
+	} );
+	jq.cookie( 'bp-activity-filter', filter, {
+		path: '/'
+	} );
+	jq.cookie( 'bp-activity-oldestpage', 1, {
+		path: '/'
+	} );
+
+	/* Remove selected and loading classes from tabs */
+	jq('.item-list-tabs li').each( function() {
+		jq(this).removeClass('selected loading');
+	});
+	/* Set the correct selected nav and filter */
+	jq('#activity-' + scope + ', .item-list-tabs li.current').addClass('selected');
+	jq('#object-nav.item-list-tabs li.selected, div.activity-type-tabs li.selected').addClass('loading');
+	jq('#activity-filter-select select option[value="' + filter + '"]').prop( 'selected', true );
+
+	/* Reload the activity stream based on the selection */
+	jq('.widget_bp_activity_widget h2 span.ajax-loader').show();
+
+	if ( bp_ajax_request )
+		bp_ajax_request.abort();
+
+	bp_ajax_request = jq.post( ajaxurl, {
+		action: 'activity_widget_filter',
+		'cookie': bp_get_cookies(),
+		'_wpnonce_activity_filter': jq("#_wpnonce_activity_filter").val(),
+		'scope': scope,
+		'filter': filter
+	},
+	function(response)
+	{
+		jq('.widget_bp_activity_widget h2 span.ajax-loader').hide();
+
+		jq('div.activity').fadeOut( 100, function() {
+			jq(this).html(response.contents);
+			jq(this).fadeIn(100);
+
+			/* Selectively hide comments */
+			bp_legacy_theme_hide_comments();
+		});
+
+		/* Update the feed link */
+		if ( null != response.feed_url )
+			jq('.directory #subnav li.feed a, .home-page #subnav li.feed a').attr('href', response.feed_url);
+
+		jq('.item-list-tabs li.selected').removeClass('loading');
+
+	}, 'json' );
+}
+
+/* Hide long lists of activity comments, only show the latest five root comments. */
+function bp_legacy_theme_hide_comments() {
+	var comments_divs = jq('div.activity-comments');
+
+	if ( !comments_divs.length )
+		return false;
+
+	comments_divs.each( function() {
+		if ( jq(this).children('ul').children('li').length < 5 ) return;
+
+		var comments_div = jq(this);
+		var parent_li = comments_div.parents('#activity-stream > li');
+		var comment_lis = jq(this).children('ul').children('li');
+		var comment_count = ' ';
+
+		if ( jq('#' + parent_li.attr('id') + ' a.acomment-reply span').length )
+			var comment_count = jq('#' + parent_li.attr('id') + ' a.acomment-reply span').html();
+
+		comment_lis.each( function(i) {
+			/* Show the latest 5 root comments */
+			if ( i < comment_lis.length - 5 ) {
+				jq(this).addClass('hidden');
+				jq(this).toggle();
+
+				if ( !i ) 
+					jq(this).before( '<li class="show-all"><a href="#' + parent_li.attr('id') + '/show-all/" title="' + BP_DTheme.show_all_comments + '">' + BP_DTheme.show_x_comments.replace( '%d', comment_count ) + '</a></li>' );
+			}
+		});
+
+	});
+}
+
+/* Helper Functions */
+
+function checkAll() {
+	var checkboxes = document.getElementsByTagName("input");
+	for(var i=0; i<checkboxes.length; i++) {
+		if(checkboxes[i].type == "checkbox") {
+			if($("check_all").checked == "") {
+				checkboxes[i].checked = "";
+			}
+			else {
+				checkboxes[i].checked = "checked";
+			}
+		}
+	}
+}
+
+function clear(container) {
+	if( !document.getElementById(container) ) return;
+
+	var container = document.getElementById(container);
+
+	if ( radioButtons = container.getElementsByTagName('INPUT') ) {
+		for(var i=0; i<radioButtons.length; i++) {
+			radioButtons[i].checked = '';
+		}
+	}
+
+	if ( options = container.getElementsByTagName('OPTION') ) {
+		for(var i=0; i<options.length; i++) {
+			options[i].selected = false;
+		}
+	}
+
+	return;
+}
+
+/* Returns a querystring of BP cookies (cookies beginning with 'bp-') */
+function bp_get_cookies() {
+	// get all cookies and split into an array
+	var allCookies   = document.cookie.split(";");
+
+	var bpCookies    = {};
+	var cookiePrefix = 'bp-';
+
+	// loop through cookies
+	for (var i = 0; i < allCookies.length; i++) {
+		var cookie    = allCookies[i];
+		var delimiter = cookie.indexOf("=");
+		var name      = jq.trim( unescape( cookie.slice(0, delimiter) ) );
+		var value     = unescape( cookie.slice(delimiter + 1) );
+
+		// if BP cookie, store it
+		if ( name.indexOf(cookiePrefix) == 0 ) {
+			bpCookies[name] = value;
+		}
+	}
+
+	// returns BP cookies as querystring
+	return encodeURIComponent( jq.param(bpCookies) );
+}
+
+/* ScrollTo plugin - just inline and minified */
+;(function($){var h=$.scrollTo=function(a,b,c){$(window).scrollTo(a,b,c)};h.defaults={axis:'xy',duration:parseFloat($.fn.jquery)>=1.3?0:1,limit:true};h.window=function(a){return $(window)._scrollable()};$.fn._scrollable=function(){return this.map(function(){var a=this,isWin=!a.nodeName||$.inArray(a.nodeName.toLowerCase(),['iframe','#document','html','body'])!=-1;if(!isWin)return a;var b=(a.contentWindow||a).document||a.ownerDocument||a;return/webkit/i.test(navigator.userAgent)||b.compatMode=='BackCompat'?b.body:b.documentElement})};$.fn.scrollTo=function(e,f,g){if(typeof f=='object'){g=f;f=0}if(typeof g=='function')g={onAfter:g};if(e=='max')e=9e9;g=$.extend({},h.defaults,g);f=f||g.duration;g.queue=g.queue&&g.axis.length>1;if(g.queue)f/=2;g.offset=both(g.offset);g.over=both(g.over);return this._scrollable().each(function(){if(e==null)return;var d=this,$elem=$(d),targ=e,toff,attr={},win=$elem.is('html,body');switch(typeof targ){case'number':case'string':if(/^([+-]=?)?\d+(\.\d+)?(px|%)?$/.test(targ)){targ=both(targ);break}targ=$(targ,this);if(!targ.length)return;case'object':if(targ.is||targ.style)toff=(targ=$(targ)).offset()}$.each(g.axis.split(''),function(i,a){var b=a=='x'?'Left':'Top',pos=b.toLowerCase(),key='scroll'+b,old=d[key],max=h.max(d,a);if(toff){attr[key]=toff[pos]+(win?0:old-$elem.offset()[pos]);if(g.margin){attr[key]-=parseInt(targ.css('margin'+b))||0;attr[key]-=parseInt(targ.css('border'+b+'Width'))||0}attr[key]+=g.offset[pos]||0;if(g.over[pos])attr[key]+=targ[a=='x'?'width':'height']()*g.over[pos]}else{var c=targ[pos];attr[key]=c.slice&&c.slice(-1)=='%'?parseFloat(c)/100*max:c}if(g.limit&&/^\d+$/.test(attr[key]))attr[key]=attr[key]<=0?0:Math.min(attr[key],max);if(!i&&g.queue){if(old!=attr[key])animate(g.onAfterFirst);delete attr[key]}});animate(g.onAfter);function animate(a){$elem.animate(attr,f,g.easing,a&&function(){a.call(this,e,g)})}}).end()};h.max=function(a,b){var c=b=='x'?'Width':'Height',scroll='scroll'+c;if(!$(a).is('html,body'))return a[scroll]-$(a)[c.toLowerCase()]();var d='client'+c,html=a.ownerDocument.documentElement,body=a.ownerDocument.body;return Math.max(html[scroll],body[scroll])-Math.min(html[d],body[d])};function both(a){return typeof a=='object'?a:{top:a,left:a}}})(jQuery);
+
+/* jQuery Easing Plugin, v1.3 - http://gsgd.co.uk/sandbox/jquery/easing/ */
+jQuery.easing.jswing=jQuery.easing.swing;jQuery.extend(jQuery.easing,{def:"easeOutQuad",swing:function(e,f,a,h,g){return jQuery.easing[jQuery.easing.def](e,f,a,h,g)},easeInQuad:function(e,f,a,h,g){return h*(f/=g)*f+a},easeOutQuad:function(e,f,a,h,g){return -h*(f/=g)*(f-2)+a},easeInOutQuad:function(e,f,a,h,g){if((f/=g/2)<1){return h/2*f*f+a}return -h/2*((--f)*(f-2)-1)+a},easeInCubic:function(e,f,a,h,g){return h*(f/=g)*f*f+a},easeOutCubic:function(e,f,a,h,g){return h*((f=f/g-1)*f*f+1)+a},easeInOutCubic:function(e,f,a,h,g){if((f/=g/2)<1){return h/2*f*f*f+a}return h/2*((f-=2)*f*f+2)+a},easeInQuart:function(e,f,a,h,g){return h*(f/=g)*f*f*f+a},easeOutQuart:function(e,f,a,h,g){return -h*((f=f/g-1)*f*f*f-1)+a},easeInOutQuart:function(e,f,a,h,g){if((f/=g/2)<1){return h/2*f*f*f*f+a}return -h/2*((f-=2)*f*f*f-2)+a},easeInQuint:function(e,f,a,h,g){return h*(f/=g)*f*f*f*f+a},easeOutQuint:function(e,f,a,h,g){return h*((f=f/g-1)*f*f*f*f+1)+a},easeInOutQuint:function(e,f,a,h,g){if((f/=g/2)<1){return h/2*f*f*f*f*f+a}return h/2*((f-=2)*f*f*f*f+2)+a},easeInSine:function(e,f,a,h,g){return -h*Math.cos(f/g*(Math.PI/2))+h+a},easeOutSine:function(e,f,a,h,g){return h*Math.sin(f/g*(Math.PI/2))+a},easeInOutSine:function(e,f,a,h,g){return -h/2*(Math.cos(Math.PI*f/g)-1)+a},easeInExpo:function(e,f,a,h,g){return(f==0)?a:h*Math.pow(2,10*(f/g-1))+a},easeOutExpo:function(e,f,a,h,g){return(f==g)?a+h:h*(-Math.pow(2,-10*f/g)+1)+a},easeInOutExpo:function(e,f,a,h,g){if(f==0){return a}if(f==g){return a+h}if((f/=g/2)<1){return h/2*Math.pow(2,10*(f-1))+a}return h/2*(-Math.pow(2,-10*--f)+2)+a},easeInCirc:function(e,f,a,h,g){return -h*(Math.sqrt(1-(f/=g)*f)-1)+a},easeOutCirc:function(e,f,a,h,g){return h*Math.sqrt(1-(f=f/g-1)*f)+a},easeInOutCirc:function(e,f,a,h,g){if((f/=g/2)<1){return -h/2*(Math.sqrt(1-f*f)-1)+a}return h/2*(Math.sqrt(1-(f-=2)*f)+1)+a},easeInElastic:function(f,h,e,l,k){var i=1.70158;var j=0;var g=l;if(h==0){return e}if((h/=k)==1){return e+l}if(!j){j=k*0.3}if(g<Math.abs(l)){g=l;var i=j/4}else{var i=j/(2*Math.PI)*Math.asin(l/g)}return -(g*Math.pow(2,10*(h-=1))*Math.sin((h*k-i)*(2*Math.PI)/j))+e},easeOutElastic:function(f,h,e,l,k){var i=1.70158;var j=0;var g=l;if(h==0){return e}if((h/=k)==1){return e+l}if(!j){j=k*0.3}if(g<Math.abs(l)){g=l;var i=j/4}else{var i=j/(2*Math.PI)*Math.asin(l/g)}return g*Math.pow(2,-10*h)*Math.sin((h*k-i)*(2*Math.PI)/j)+l+e},easeInOutElastic:function(f,h,e,l,k){var i=1.70158;var j=0;var g=l;if(h==0){return e}if((h/=k/2)==2){return e+l}if(!j){j=k*(0.3*1.5)}if(g<Math.abs(l)){g=l;var i=j/4}else{var i=j/(2*Math.PI)*Math.asin(l/g)}if(h<1){return -0.5*(g*Math.pow(2,10*(h-=1))*Math.sin((h*k-i)*(2*Math.PI)/j))+e}return g*Math.pow(2,-10*(h-=1))*Math.sin((h*k-i)*(2*Math.PI)/j)*0.5+l+e},easeInBack:function(e,f,a,i,h,g){if(g==undefined){g=1.70158}return i*(f/=h)*f*((g+1)*f-g)+a},easeOutBack:function(e,f,a,i,h,g){if(g==undefined){g=1.70158}return i*((f=f/h-1)*f*((g+1)*f+g)+1)+a},easeInOutBack:function(e,f,a,i,h,g){if(g==undefined){g=1.70158}if((f/=h/2)<1){return i/2*(f*f*(((g*=(1.525))+1)*f-g))+a}return i/2*((f-=2)*f*(((g*=(1.525))+1)*f+g)+2)+a},easeInBounce:function(e,f,a,h,g){return h-jQuery.easing.easeOutBounce(e,g-f,0,h,g)+a},easeOutBounce:function(e,f,a,h,g){if((f/=g)<(1/2.75)){return h*(7.5625*f*f)+a}else{if(f<(2/2.75)){return h*(7.5625*(f-=(1.5/2.75))*f+0.75)+a}else{if(f<(2.5/2.75)){return h*(7.5625*(f-=(2.25/2.75))*f+0.9375)+a}else{return h*(7.5625*(f-=(2.625/2.75))*f+0.984375)+a}}}},easeInOutBounce:function(e,f,a,h,g){if(f<g/2){return jQuery.easing.easeInBounce(e,f*2,0,h,g)*0.5+a}return jQuery.easing.easeOutBounce(e,f*2-g,0,h,g)*0.5+h*0.5+a}});
+
+/* jQuery Cookie plugin */
+jQuery.cookie=function(name,value,options){if(typeof value!='undefined'){options=options||{};if(value===null){value='';options.expires=-1;}var expires='';if(options.expires&&(typeof options.expires=='number'||options.expires.toUTCString)){var date;if(typeof options.expires=='number'){date=new Date();date.setTime(date.getTime()+(options.expires*24*60*60*1000));}else{date=options.expires;}expires='; expires='+date.toUTCString();}var path=options.path?'; path='+(options.path):'';var domain=options.domain?'; domain='+(options.domain):'';var secure=options.secure?'; secure':'';document.cookie=[name,'=',encodeURIComponent(value),expires,path,domain,secure].join('');}else{var cookieValue=null;if(document.cookie&&document.cookie!=''){var cookies=document.cookie.split(';');for(var i=0;i<cookies.length;i++){var cookie=jQuery.trim(cookies[i]);if(cookie.substring(0,name.length+1)==(name+'=')){cookieValue=decodeURIComponent(cookie.substring(name.length+1));break;}}}return cookieValue;}};
+
+/* jQuery querystring plugin */
+eval(function(p,a,c,k,e,d){e=function(c){return(c<a?'':e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--){d[e(c)]=k[c]||e(c)}k=[function(e){return d[e]}];e=function(){return'\\w+'};c=1};while(c--){if(k[c]){p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c])}}return p}('M 6(A){4 $11=A.11||\'&\';4 $V=A.V===r?r:j;4 $1p=A.1p===r?\'\':\'[]\';4 $13=A.13===r?r:j;4 $D=$13?A.D===j?"#":"?":"";4 $15=A.15===r?r:j;v.1o=M 6(){4 f=6(o,t){8 o!=1v&&o!==x&&(!!t?o.1t==t:j)};4 14=6(1m){4 m,1l=/\\[([^[]*)\\]/g,T=/^([^[]+)(\\[.*\\])?$/.1r(1m),k=T[1],e=[];19(m=1l.1r(T[2]))e.u(m[1]);8[k,e]};4 w=6(3,e,7){4 o,y=e.1b();b(I 3!=\'X\')3=x;b(y===""){b(!3)3=[];b(f(3,L)){3.u(e.h==0?7:w(x,e.z(0),7))}n b(f(3,1a)){4 i=0;19(3[i++]!=x);3[--i]=e.h==0?7:w(3[i],e.z(0),7)}n{3=[];3.u(e.h==0?7:w(x,e.z(0),7))}}n b(y&&y.T(/^\\s*[0-9]+\\s*$/)){4 H=1c(y,10);b(!3)3=[];3[H]=e.h==0?7:w(3[H],e.z(0),7)}n b(y){4 H=y.B(/^\\s*|\\s*$/g,"");b(!3)3={};b(f(3,L)){4 18={};1w(4 i=0;i<3.h;++i){18[i]=3[i]}3=18}3[H]=e.h==0?7:w(3[H],e.z(0),7)}n{8 7}8 3};4 C=6(a){4 p=d;p.l={};b(a.C){v.J(a.Z(),6(5,c){p.O(5,c)})}n{v.J(1u,6(){4 q=""+d;q=q.B(/^[?#]/,\'\');q=q.B(/[;&]$/,\'\');b($V)q=q.B(/[+]/g,\' \');v.J(q.Y(/[&;]/),6(){4 5=1e(d.Y(\'=\')[0]||"");4 c=1e(d.Y(\'=\')[1]||"");b(!5)8;b($15){b(/^[+-]?[0-9]+\\.[0-9]*$/.1d(c))c=1A(c);n b(/^[+-]?[0-9]+$/.1d(c))c=1c(c,10)}c=(!c&&c!==0)?j:c;b(c!==r&&c!==j&&I c!=\'1g\')c=c;p.O(5,c)})})}8 p};C.1H={C:j,1G:6(5,1f){4 7=d.Z(5);8 f(7,1f)},1h:6(5){b(!f(5))8 d.l;4 K=14(5),k=K[0],e=K[1];4 3=d.l[k];19(3!=x&&e.h!=0){3=3[e.1b()]}8 I 3==\'1g\'?3:3||""},Z:6(5){4 3=d.1h(5);b(f(3,1a))8 v.1E(j,{},3);n b(f(3,L))8 3.z(0);8 3},O:6(5,c){4 7=!f(c)?x:c;4 K=14(5),k=K[0],e=K[1];4 3=d.l[k];d.l[k]=w(3,e.z(0),7);8 d},w:6(5,c){8 d.N().O(5,c)},1s:6(5){8 d.O(5,x).17()},1z:6(5){8 d.N().1s(5)},1j:6(){4 p=d;v.J(p.l,6(5,7){1y p.l[5]});8 p},1F:6(Q){4 D=Q.B(/^.*?[#](.+?)(?:\\?.+)?$/,"$1");4 S=Q.B(/^.*?[?](.+?)(?:#.+)?$/,"$1");8 M C(Q.h==S.h?\'\':S,Q.h==D.h?\'\':D)},1x:6(){8 d.N().1j()},N:6(){8 M C(d)},17:6(){6 F(G){4 R=I G=="X"?f(G,L)?[]:{}:G;b(I G==\'X\'){6 1k(o,5,7){b(f(o,L))o.u(7);n o[5]=7}v.J(G,6(5,7){b(!f(7))8 j;1k(R,5,F(7))})}8 R}d.l=F(d.l);8 d},1B:6(){8 d.N().17()},1D:6(){4 i=0,U=[],W=[],p=d;4 16=6(E){E=E+"";b($V)E=E.B(/ /g,"+");8 1C(E)};4 1n=6(1i,5,7){b(!f(7)||7===r)8;4 o=[16(5)];b(7!==j){o.u("=");o.u(16(7))}1i.u(o.P(""))};4 F=6(R,k){4 12=6(5){8!k||k==""?[5].P(""):[k,"[",5,"]"].P("")};v.J(R,6(5,7){b(I 7==\'X\')F(7,12(5));n 1n(W,12(5),7)})};F(d.l);b(W.h>0)U.u($D);U.u(W.P($11));8 U.P("")}};8 M C(1q.S,1q.D)}}(v.1o||{});',62,106,'|||target|var|key|function|value|return|||if|val|this|tokens|is||length||true|base|keys||else||self||false|||push|jQuery|set|null|token|slice|settings|replace|queryObject|hash|str|build|orig|index|typeof|each|parsed|Array|new|copy|SET|join|url|obj|search|match|queryString|spaces|chunks|object|split|get||separator|newKey|prefix|parse|numbers|encode|COMPACT|temp|while|Object|shift|parseInt|test|decodeURIComponent|type|number|GET|arr|EMPTY|add|rx|path|addFields|query|suffix|location|exec|REMOVE|constructor|arguments|undefined|for|empty|delete|remove|parseFloat|compact|encodeURIComponent|toString|extend|load|has|prototype'.split('|'),0,{}))
Index: /tags/1.9/bp-themes/bp-default/404.php
===================================================================
--- /tags/1.9/bp-themes/bp-default/404.php	(revision 7684)
+++ /tags/1.9/bp-themes/bp-default/404.php	(revision 7684)
@@ -0,0 +1,19 @@
+<?php get_header(); ?>
+
+	<div id="content">
+		<div class="padder one-column">
+			<?php do_action( 'bp_before_404' ); ?>
+			<div id="post-0" class="post page-404 error404 not-found" role="main">
+				<h2 class="posttitle"><?php _e( "Page not found", 'buddypress' ); ?></h2>
+
+				<p><?php _e( "We're sorry, but we can't find the page that you're looking for. Perhaps searching will help.", 'buddypress' ); ?></p>
+				<?php get_search_form(); ?>
+
+				<?php do_action( 'bp_404' ); ?>
+			</div>
+
+			<?php do_action( 'bp_after_404' ); ?>
+		</div><!-- .padder -->
+	</div><!-- #content -->
+
+<?php get_footer(); ?>
Index: /tags/1.9/bp-themes/bp-default/_inc/ajax.php
===================================================================
--- /tags/1.9/bp-themes/bp-default/_inc/ajax.php	(revision 7684)
+++ /tags/1.9/bp-themes/bp-default/_inc/ajax.php	(revision 7684)
@@ -0,0 +1,998 @@
+<?php
+/**
+ * AJAX Functions
+ *
+ * All of these functions enhance the responsiveness of the user interface in
+ * the default theme by adding AJAX functionality.
+ *
+ * For more information on how the custom AJAX functions work, see
+ * http://codex.wordpress.org/AJAX_in_Plugins.
+ *
+ * @package BuddyPress
+ * @since BuddyPress (1.2)
+ * @subpackage BP-Default
+ */
+
+// Exit if accessed directly
+if ( ! defined( 'ABSPATH' ) ) exit;
+
+/**
+ * Register AJAX handlers for BP Default theme functionality.
+ *
+ * This function is registered to the after_setup_theme hook with priority 20 as
+ * this file is included in a function hooked to after_setup_theme at priority 10.
+ *
+ * @since BuddyPress (1.6)
+ */
+function bp_dtheme_register_actions() {
+	$actions = array(
+		// Directory filters
+		'blogs_filter'    => 'bp_dtheme_object_template_loader',
+		'forums_filter'   => 'bp_dtheme_object_template_loader',
+		'groups_filter'   => 'bp_dtheme_object_template_loader',
+		'members_filter'  => 'bp_dtheme_object_template_loader',
+		'messages_filter' => 'bp_dtheme_messages_template_loader',
+
+		// Friends
+		'accept_friendship' => 'bp_dtheme_ajax_accept_friendship',
+		'addremove_friend'  => 'bp_dtheme_ajax_addremove_friend',
+		'reject_friendship' => 'bp_dtheme_ajax_reject_friendship',
+
+		// Activity
+		'activity_get_older_updates'  => 'bp_dtheme_activity_template_loader',
+		'activity_mark_fav'           => 'bp_dtheme_mark_activity_favorite',
+		'activity_mark_unfav'         => 'bp_dtheme_unmark_activity_favorite',
+		'activity_widget_filter'      => 'bp_dtheme_activity_template_loader',
+		'delete_activity'             => 'bp_dtheme_delete_activity',
+		'delete_activity_comment'     => 'bp_dtheme_delete_activity_comment',
+		'get_single_activity_content' => 'bp_dtheme_get_single_activity_content',
+		'new_activity_comment'        => 'bp_dtheme_new_activity_comment',
+		'post_update'                 => 'bp_dtheme_post_update',
+		'bp_spam_activity'            => 'bp_dtheme_spam_activity',
+		'bp_spam_activity_comment'    => 'bp_dtheme_spam_activity',
+
+		// Groups
+		'groups_invite_user' => 'bp_dtheme_ajax_invite_user',
+		'joinleave_group'    => 'bp_dtheme_ajax_joinleave_group',
+
+		// Messages
+		'messages_autocomplete_results' => 'bp_dtheme_ajax_messages_autocomplete_results',
+		'messages_close_notice'         => 'bp_dtheme_ajax_close_notice',
+		'messages_delete'               => 'bp_dtheme_ajax_messages_delete',
+		'messages_markread'             => 'bp_dtheme_ajax_message_markread',
+		'messages_markunread'           => 'bp_dtheme_ajax_message_markunread',
+		'messages_send_reply'           => 'bp_dtheme_ajax_messages_send_reply',
+	);
+
+	/**
+	 * Register all of these AJAX handlers
+	 *
+	 * The "wp_ajax_" action is used for logged in users, and "wp_ajax_nopriv_"
+	 * executes for users that aren't logged in. This is for backpat with BP <1.6.
+	 */
+	foreach( $actions as $name => $function ) {
+		add_action( 'wp_ajax_'        . $name, $function );
+		add_action( 'wp_ajax_nopriv_' . $name, $function );
+	}
+}
+add_action( 'after_setup_theme', 'bp_dtheme_register_actions', 20 );
+
+/**
+ * This function looks scarier than it actually is. :)
+ * Each object loop (activity/members/groups/blogs/forums) contains default parameters to
+ * show specific information based on the page we are currently looking at.
+ * The following function will take into account any cookies set in the JS and allow us
+ * to override the parameters sent. That way we can change the results returned without reloading the page.
+ * By using cookies we can also make sure that user settings are retained across page loads.
+ *
+ * @return string Query string for the activity/members/groups/blogs/forums loops
+ * @since BuddyPress (1.2)
+ */
+function bp_dtheme_ajax_querystring( $query_string, $object ) {
+	if ( empty( $object ) )
+		return '';
+
+	// Set up the cookies passed on this AJAX request. Store a local var to avoid conflicts
+	if ( ! empty( $_POST['cookie'] ) )
+		$_BP_COOKIE = wp_parse_args( str_replace( '; ', '&', urldecode( $_POST['cookie'] ) ) );
+	else
+		$_BP_COOKIE = &$_COOKIE;
+
+	$qs = array();
+
+	/**
+	 * Check if any cookie values are set. If there are then override the default params passed to the
+	 * template loop
+	 */
+
+	// Activity stream filtering on action
+	if ( ! empty( $_BP_COOKIE['bp-' . $object . '-filter'] ) && '-1' != $_BP_COOKIE['bp-' . $object . '-filter'] ) {
+		$qs[] = 'type='   . $_BP_COOKIE['bp-' . $object . '-filter'];
+		$qs[] = 'action=' . $_BP_COOKIE['bp-' . $object . '-filter'];
+	}
+
+	if ( ! empty( $_BP_COOKIE['bp-' . $object . '-scope'] ) ) {
+		if ( 'personal' == $_BP_COOKIE['bp-' . $object . '-scope'] ) {
+			$user_id = ( bp_displayed_user_id() ) ? bp_displayed_user_id() : bp_loggedin_user_id();
+			$qs[] = 'user_id=' . $user_id;
+		}
+
+		// Activity stream scope only on activity directory.
+		if ( 'all' != $_BP_COOKIE['bp-' . $object . '-scope'] && ! bp_displayed_user_id() && ! bp_is_single_item() )
+			$qs[] = 'scope=' . $_BP_COOKIE['bp-' . $object . '-scope'];
+	}
+
+	// If page and search_terms have been passed via the AJAX post request, use those.
+	if ( ! empty( $_POST['page'] ) && '-1' != $_POST['page'] )
+		$qs[] = 'page=' . absint( $_POST['page'] );
+
+	// exludes activity just posted and avoids duplicate ids
+	if ( ! empty( $_POST['exclude_just_posted'] ) ) {
+		$just_posted = wp_parse_id_list( $_POST['exclude_just_posted'] );
+		$qs[] = 'exclude=' . implode( ',', $just_posted );
+	}
+
+	$object_search_text = bp_get_search_default_text( $object );
+ 	if ( ! empty( $_POST['search_terms'] ) && $object_search_text != $_POST['search_terms'] && 'false' != $_POST['search_terms'] && 'undefined' != $_POST['search_terms'] )
+		$qs[] = 'search_terms=' . $_POST['search_terms'];
+
+	// Now pass the querystring to override default values.
+	$query_string = empty( $qs ) ? '' : join( '&', (array) $qs );
+
+	$object_filter = '';
+	if ( isset( $_BP_COOKIE['bp-' . $object . '-filter'] ) )
+		$object_filter = $_BP_COOKIE['bp-' . $object . '-filter'];
+
+	$object_scope = '';
+	if ( isset( $_BP_COOKIE['bp-' . $object . '-scope'] ) )
+		$object_scope = $_BP_COOKIE['bp-' . $object . '-scope'];
+
+	$object_page = '';
+	if ( isset( $_BP_COOKIE['bp-' . $object . '-page'] ) )
+		$object_page = $_BP_COOKIE['bp-' . $object . '-page'];
+
+	$object_search_terms = '';
+	if ( isset( $_BP_COOKIE['bp-' . $object . '-search-terms'] ) )
+		$object_search_terms = $_BP_COOKIE['bp-' . $object . '-search-terms'];
+
+	$object_extras = '';
+	if ( isset( $_BP_COOKIE['bp-' . $object . '-extras'] ) )
+		$object_extras = $_BP_COOKIE['bp-' . $object . '-extras'];
+
+	return apply_filters( 'bp_dtheme_ajax_querystring', $query_string, $object, $object_filter, $object_scope, $object_page, $object_search_terms, $object_extras );
+}
+add_filter( 'bp_ajax_querystring', 'bp_dtheme_ajax_querystring', 10, 2 );
+
+/**
+ * Load the template loop for the current object.
+ *
+ * @return string Prints template loop for the specified object
+ * @since BuddyPress (1.2)
+ */
+function bp_dtheme_object_template_loader() {
+	// Bail if not a POST action
+	if ( 'POST' !== strtoupper( $_SERVER['REQUEST_METHOD'] ) )
+		return;
+
+	// Bail if no object passed
+	if ( empty( $_POST['object'] ) )
+		return;
+
+	// Sanitize the object
+	$object = sanitize_title( $_POST['object'] );
+
+	// Bail if object is not an active component
+	if ( ! bp_is_active( $object ) )
+		return;
+
+ 	/**
+	 * AJAX requests happen too early to be seen by bp_update_is_directory()
+	 * so we do it manually here to ensure templates load with the correct
+	 * context. Without this check, templates will load the 'single' version
+	 * of themselves rather than the directory version.
+	 */
+	if ( ! bp_current_action() )
+		bp_update_is_directory( true, bp_current_component() );
+
+	// Locate the object template
+	locate_template( array( "$object/$object-loop.php" ), true );
+	exit;
+}
+
+/**
+ * Load messages template loop when searched on the private message page
+ *
+ * @return string Prints template loop for the Messages component
+ * @since BuddyPress (1.6)
+ */
+function bp_dtheme_messages_template_loader(){
+	locate_template( array( 'members/single/messages/messages-loop.php' ), true );
+	exit;
+}
+
+/**
+ * Load the activity loop template when activity is requested via AJAX,
+ *
+ * @return string JSON object containing 'contents' (output of the template loop for the Activity component) and 'feed_url' (URL to the relevant RSS feed).
+ * @since BuddyPress (1.2)
+ */
+function bp_dtheme_activity_template_loader() {
+	// Bail if not a POST action
+	if ( 'POST' !== strtoupper( $_SERVER['REQUEST_METHOD'] ) )
+		return;
+
+	$scope = '';
+	if ( ! empty( $_POST['scope'] ) )
+		$scope = $_POST['scope'];
+
+	// We need to calculate and return the feed URL for each scope
+	switch ( $scope ) {
+		case 'friends':
+			$feed_url = bp_loggedin_user_domain() . bp_get_activity_slug() . '/friends/feed/';
+			break;
+		case 'groups':
+			$feed_url = bp_loggedin_user_domain() . bp_get_activity_slug() . '/groups/feed/';
+			break;
+		case 'favorites':
+			$feed_url = bp_loggedin_user_domain() . bp_get_activity_slug() . '/favorites/feed/';
+			break;
+		case 'mentions':
+			$feed_url = bp_loggedin_user_domain() . bp_get_activity_slug() . '/mentions/feed/';
+			bp_activity_clear_new_mentions( bp_loggedin_user_id() );
+			break;
+		default:
+			$feed_url = home_url( bp_get_activity_root_slug() . '/feed/' );
+			break;
+	}
+
+	// Buffer the loop in the template to a var for JS to spit out.
+	ob_start();
+	locate_template( array( 'activity/activity-loop.php' ), true );
+	$result['contents'] = ob_get_contents();
+	$result['feed_url'] = apply_filters( 'bp_dtheme_activity_feed_url', $feed_url, $scope );
+	ob_end_clean();
+
+	exit( json_encode( $result ) );
+}
+
+/**
+ * Processes Activity updates received via a POST request.
+ *
+ * @return string HTML
+ * @since BuddyPress (1.2)
+ */
+function bp_dtheme_post_update() {
+	// Bail if not a POST action
+	if ( 'POST' !== strtoupper( $_SERVER['REQUEST_METHOD'] ) )
+		return;
+
+	// Check the nonce
+	check_admin_referer( 'post_update', '_wpnonce_post_update' );
+
+	if ( ! is_user_logged_in() )
+		exit( '-1' );
+
+	if ( empty( $_POST['content'] ) )
+		exit( '-1<div id="message" class="error"><p>' . __( 'Please enter some content to post.', 'buddypress' ) . '</p></div>' );
+
+	$activity_id = 0;
+	if ( empty( $_POST['object'] ) && bp_is_active( 'activity' ) ) {
+		$activity_id = bp_activity_post_update( array( 'content' => $_POST['content'] ) );
+
+	} elseif ( $_POST['object'] == 'groups' ) {
+		if ( ! empty( $_POST['item_id'] ) && bp_is_active( 'groups' ) )
+			$activity_id = groups_post_update( array( 'content' => $_POST['content'], 'group_id' => $_POST['item_id'] ) );
+
+	} else {
+		$activity_id = apply_filters( 'bp_activity_custom_update', $_POST['object'], $_POST['item_id'], $_POST['content'] );
+	}
+
+	if ( empty( $activity_id ) )
+		exit( '-1<div id="message" class="error"><p>' . __( 'There was a problem posting your update, please try again.', 'buddypress' ) . '</p></div>' );
+
+	if ( bp_has_activities ( 'include=' . $activity_id ) ) {
+		while ( bp_activities() ) {
+			bp_the_activity();
+			locate_template( array( 'activity/entry.php' ), true );
+		}
+	}
+
+	exit;
+}
+
+/**
+ * Posts new Activity comments received via a POST request.
+ *
+ * @global BP_Activity_Template $activities_template
+ * @return string HTML
+ * @since BuddyPress (1.2)
+ */
+function bp_dtheme_new_activity_comment() {
+	global $activities_template;
+
+	// Bail if not a POST action
+	if ( 'POST' !== strtoupper( $_SERVER['REQUEST_METHOD'] ) )
+		return;
+
+	// Check the nonce
+	check_admin_referer( 'new_activity_comment', '_wpnonce_new_activity_comment' );
+
+	if ( ! is_user_logged_in() )
+		exit( '-1' );
+
+	if ( empty( $_POST['content'] ) )
+		exit( '-1<div id="message" class="error"><p>' . __( 'Please do not leave the comment area blank.', 'buddypress' ) . '</p></div>' );
+
+	if ( empty( $_POST['form_id'] ) || empty( $_POST['comment_id'] ) || ! is_numeric( $_POST['form_id'] ) || ! is_numeric( $_POST['comment_id'] ) )
+		exit( '-1<div id="message" class="error"><p>' . __( 'There was an error posting that reply, please try again.', 'buddypress' ) . '</p></div>' );
+
+	$comment_id = bp_activity_new_comment( array(
+		'activity_id' => $_POST['form_id'],
+		'content'     => $_POST['content'],
+		'parent_id'   => $_POST['comment_id'],
+	) );
+
+	if ( ! $comment_id )
+		exit( '-1<div id="message" class="error"><p>' . __( 'There was an error posting that reply, please try again.', 'buddypress' ) . '</p></div>' );
+
+	// Load the new activity item into the $activities_template global
+	bp_has_activities( 'display_comments=stream&hide_spam=false&include=' . $comment_id );
+
+	// Swap the current comment with the activity item we just loaded
+	$activities_template->activity                  = new stdClass;
+	$activities_template->activity->id              = $activities_template->activities[0]->item_id;
+	$activities_template->activity->current_comment = $activities_template->activities[0];
+
+	$template = locate_template( 'activity/comment.php', false, false );
+
+	/**
+	 * Backward compatibility. In older versions of BP, the markup was
+	 * generated in the PHP instead of a template. This ensures that
+	 * older themes (which are not children of bp-default and won't
+	 * have the new template) will still work.
+	 */
+	if ( empty( $template ) )
+		$template = BP_PLUGIN_DIR . '/bp-themes/bp-default/activity/comment.php';
+
+	load_template( $template, false );
+
+	unset( $activities_template );
+	exit;
+}
+
+/**
+ * Deletes an Activity item received via a POST request.
+ *
+ * @return mixed String on error, void on success
+ * @since BuddyPress (1.2)
+ */
+function bp_dtheme_delete_activity() {
+	// Bail if not a POST action
+	if ( 'POST' !== strtoupper( $_SERVER['REQUEST_METHOD'] ) )
+		return;
+
+	// Check the nonce
+	check_admin_referer( 'bp_activity_delete_link' );
+
+	if ( ! is_user_logged_in() )
+		exit( '-1' );
+
+	if ( empty( $_POST['id'] ) || ! is_numeric( $_POST['id'] ) )
+		exit( '-1' );
+
+	$activity = new BP_Activity_Activity( (int) $_POST['id'] );
+
+	// Check access
+	if ( ! bp_activity_user_can_delete( $activity ) )
+		exit( '-1' );
+
+	// Call the action before the delete so plugins can still fetch information about it
+	do_action( 'bp_activity_before_action_delete_activity', $activity->id, $activity->user_id );
+
+	if ( ! bp_activity_delete( array( 'id' => $activity->id, 'user_id' => $activity->user_id ) ) )
+		exit( '-1<div id="message" class="error"><p>' . __( 'There was a problem when deleting. Please try again.', 'buddypress' ) . '</p></div>' );
+
+	do_action( 'bp_activity_action_delete_activity', $activity->id, $activity->user_id );
+	exit;
+}
+
+/**
+ * Deletes an Activity comment received via a POST request
+ *
+ * @return mixed String on error, void on success
+ * @since BuddyPress (1.2)
+ */
+function bp_dtheme_delete_activity_comment() {
+	// Bail if not a POST action
+	if ( 'POST' !== strtoupper( $_SERVER['REQUEST_METHOD'] ) )
+		return;
+
+	// Check the nonce
+	check_admin_referer( 'bp_activity_delete_link' );
+
+	if ( ! is_user_logged_in() )
+		exit( '-1' );
+
+	$comment = new BP_Activity_Activity( $_POST['id'] );
+
+	// Check access
+	if ( ! bp_current_user_can( 'bp_moderate' ) && $comment->user_id != bp_loggedin_user_id() )
+		exit( '-1' );
+
+	if ( empty( $_POST['id'] ) || ! is_numeric( $_POST['id'] ) )
+		exit( '-1' );
+
+	// Call the action before the delete so plugins can still fetch information about it
+	do_action( 'bp_activity_before_action_delete_activity', $_POST['id'], $comment->user_id );
+
+	if ( ! bp_activity_delete_comment( $comment->item_id, $comment->id ) )
+		exit( '-1<div id="message" class="error"><p>' . __( 'There was a problem when deleting. Please try again.', 'buddypress' ) . '</p></div>' );
+
+	do_action( 'bp_activity_action_delete_activity', $_POST['id'], $comment->user_id );
+	exit;
+}
+
+/**
+ * AJAX spam an activity item or comment
+ *
+ * @global BuddyPress $bp The one true BuddyPress instance
+ * @return mixed String on error, void on success
+ * @since BuddyPress (1.6)
+ */
+function bp_dtheme_spam_activity() {
+	global $bp;
+
+	// Bail if not a POST action
+	if ( 'POST' !== strtoupper( $_SERVER['REQUEST_METHOD'] ) )
+		return;
+
+	// Check that user is logged in, Activity Streams are enabled, and Akismet is present.
+	if ( ! is_user_logged_in() || ! bp_is_active( 'activity' ) || empty( $bp->activity->akismet ) )
+		exit( '-1' );
+
+	// Check an item ID was passed
+	if ( empty( $_POST['id'] ) || ! is_numeric( $_POST['id'] ) )
+		exit( '-1' );
+
+	// Is the current user allowed to spam items?
+	if ( ! bp_activity_user_can_mark_spam() )
+		exit( '-1' );
+
+	// Load up the activity item
+	$activity = new BP_Activity_Activity( (int) $_POST['id'] );
+	if ( empty( $activity->component ) )
+		exit( '-1' );
+
+	// Check nonce
+	check_admin_referer( 'bp_activity_akismet_spam_' . $activity->id );
+
+	// Call an action before the spamming so plugins can modify things if they want to
+	do_action( 'bp_activity_before_action_spam_activity', $activity->id, $activity );
+
+	// Mark as spam
+	bp_activity_mark_as_spam( $activity );
+	$activity->save();
+
+	do_action( 'bp_activity_action_spam_activity', $activity->id, $activity->user_id );
+	exit;
+}
+
+/**
+ * Mark an activity as a favourite via a POST request.
+ *
+ * @return string HTML
+ * @since BuddyPress (1.2)
+ */
+function bp_dtheme_mark_activity_favorite() {
+	// Bail if not a POST action
+	if ( 'POST' !== strtoupper( $_SERVER['REQUEST_METHOD'] ) )
+		return;
+
+	if ( bp_activity_add_user_favorite( $_POST['id'] ) )
+		_e( 'Remove Favorite', 'buddypress' );
+	else
+		_e( 'Favorite', 'buddypress' );
+
+	exit;
+}
+
+/**
+ * Un-favourite an activity via a POST request.
+ *
+ * @return string HTML
+ * @since BuddyPress (1.2)
+ */
+function bp_dtheme_unmark_activity_favorite() {
+	// Bail if not a POST action
+	if ( 'POST' !== strtoupper( $_SERVER['REQUEST_METHOD'] ) )
+		return;
+
+	if ( bp_activity_remove_user_favorite( $_POST['id'] ) )
+		_e( 'Favorite', 'buddypress' );
+	else
+		_e( 'Remove Favorite', 'buddypress' );
+
+	exit;
+}
+
+/**
+ * Fetches full an activity's full, non-excerpted content via a POST request.
+ * Used for the 'Read More' link on long activity items.
+ *
+ * @return string HTML
+ * @since BuddyPress (1.5)
+ */
+function bp_dtheme_get_single_activity_content() {
+	// Bail if not a POST action
+	if ( 'POST' !== strtoupper( $_SERVER['REQUEST_METHOD'] ) )
+		return;
+
+	$activity_array = bp_activity_get_specific( array(
+		'activity_ids'     => $_POST['activity_id'],
+		'display_comments' => 'stream'
+	) );
+
+	$activity = ! empty( $activity_array['activities'][0] ) ? $activity_array['activities'][0] : false;
+
+	if ( empty( $activity ) )
+		exit; // @todo: error?
+
+	do_action_ref_array( 'bp_dtheme_get_single_activity_content', array( &$activity ) );
+
+	// Activity content retrieved through AJAX should run through normal filters, but not be truncated
+	remove_filter( 'bp_get_activity_content_body', 'bp_activity_truncate_entry', 5 );
+	$content = apply_filters( 'bp_get_activity_content_body', $activity->content );
+
+	exit( $content );
+}
+
+/**
+ * Invites a friend to join a group via a POST request.
+ *
+ * @since BuddyPress (1.2)
+ * @todo Audit return types
+ */
+function bp_dtheme_ajax_invite_user() {
+	// Bail if not a POST action
+	if ( 'POST' !== strtoupper( $_SERVER['REQUEST_METHOD'] ) )
+		return;
+
+	check_ajax_referer( 'groups_invite_uninvite_user' );
+
+	if ( ! $_POST['friend_id'] || ! $_POST['friend_action'] || ! $_POST['group_id'] )
+		return;
+
+	if ( ! bp_groups_user_can_send_invites( $_POST['group_id'] ) )
+		return;
+
+	if ( ! friends_check_friendship( bp_loggedin_user_id(), $_POST['friend_id'] ) )
+		return;
+
+	$group_id = (int) $_POST['group_id'];
+	$friend_id = (int) $_POST['friend_id'];
+
+	if ( 'invite' == $_POST['friend_action'] ) {
+		$group = groups_get_group( $group_id );
+
+		// Users who have previously requested membership do not need
+		// another invitation created for them
+		if ( BP_Groups_Member::check_for_membership_request( $friend_id, $group_id ) ) {
+			$user_status = 'is_pending';
+
+		// Create the user invitation
+		} else if ( groups_invite_user( array( 'user_id' => $friend_id, 'group_id' => $group_id ) ) ) {
+			$user_status = 'is_invited';
+
+		// Miscellaneous failure
+		} else {
+			return;
+		}
+
+		$user = new BP_Core_User( $_POST['friend_id'] );
+
+		echo '<li id="uid-' . $user->id . '">';
+		echo $user->avatar_thumb;
+		echo '<h4>' . $user->user_link . '</h4>';
+		echo '<span class="activity">' . esc_attr( $user->last_active ) . '</span>';
+		echo '<div class="action">
+				<a class="button remove" href="' . wp_nonce_url( bp_loggedin_user_domain() . bp_get_groups_slug() . '/' . $_POST['group_id'] . '/invites/remove/' . $user->id, 'groups_invite_uninvite_user' ) . '" id="uid-' . esc_attr( $user->id ) . '">' . __( 'Remove Invite', 'buddypress' ) . '</a>
+			  </div>';
+
+		if ( 'is_pending' == $user_status ) {
+			echo '<p class="description">' . sprintf( __( '%s has previously requested to join this group. Sending an invitation will automatically add the member to the group.', 'buddypress' ), $user->user_link ) . '</p>';
+		}
+
+		echo '</li>';
+		exit;
+
+	} elseif ( 'uninvite' == $_POST['friend_action'] ) {
+		// Users who have previously requested membership should not
+		// have their requests deleted on the "uninvite" action
+		if ( BP_Groups_Member::check_for_membership_request( $friend_id, $group_id ) ) {
+			return;
+		}
+
+		// Remove the unsent invitation
+		if ( ! groups_uninvite_user( $friend_id, $group_id ) ) {
+			return;
+		}
+
+		exit;
+
+	} else {
+		return;
+	}
+}
+
+/**
+ * Friend/un-friend a user via a POST request.
+ *
+ * @return string HTML
+ * @since BuddyPress (1.2)
+ */
+function bp_dtheme_ajax_addremove_friend() {
+	// Bail if not a POST action
+	if ( 'POST' !== strtoupper( $_SERVER['REQUEST_METHOD'] ) )
+		return;
+
+	// Cast fid as an integer
+	$friend_id = (int) $_POST['fid'];
+
+	// Trying to cancel friendship
+	if ( 'is_friend' == BP_Friends_Friendship::check_is_friend( bp_loggedin_user_id(), $friend_id ) ) {
+		check_ajax_referer( 'friends_remove_friend' );
+
+		if ( ! friends_remove_friend( bp_loggedin_user_id(), $friend_id ) ) {
+			echo __( 'Friendship could not be canceled.', 'buddypress' );
+		} else {
+			echo '<a id="friend-' . esc_attr( $friend_id ) . '" class="add" rel="add" title="' . __( 'Add Friend', 'buddypress' ) . '" href="' . wp_nonce_url( bp_loggedin_user_domain() . bp_get_friends_slug() . '/add-friend/' . $friend_id, 'friends_add_friend' ) . '">' . __( 'Add Friend', 'buddypress' ) . '</a>';
+		}
+
+	// Trying to request friendship
+	} elseif ( 'not_friends' == BP_Friends_Friendship::check_is_friend( bp_loggedin_user_id(), $friend_id ) ) {
+		check_ajax_referer( 'friends_add_friend' );
+
+		if ( ! friends_add_friend( bp_loggedin_user_id(), $friend_id ) ) {
+			echo __(' Friendship could not be requested.', 'buddypress' );
+		} else {
+			echo '<a id="friend-' . esc_attr( $friend_id ) . '" class="remove" rel="remove" title="' . __( 'Cancel Friendship Request', 'buddypress' ) . '" href="' . wp_nonce_url( bp_loggedin_user_domain() . bp_get_friends_slug() . '/requests/cancel/' . $friend_id . '/', 'friends_withdraw_friendship' ) . '" class="requested">' . __( 'Cancel Friendship Request', 'buddypress' ) . '</a>';
+		}
+
+	// Trying to cancel pending request
+	} elseif ( 'pending' == BP_Friends_Friendship::check_is_friend( bp_loggedin_user_id(), $friend_id ) ) {
+		check_ajax_referer( 'friends_withdraw_friendship' );
+
+		if ( friends_withdraw_friendship( bp_loggedin_user_id(), $friend_id ) ) {
+			echo '<a id="friend-' . esc_attr( $friend_id ) . '" class="add" rel="add" title="' . __( 'Add Friend', 'buddypress' ) . '" href="' . wp_nonce_url( bp_loggedin_user_domain() . bp_get_friends_slug() . '/add-friend/' . $friend_id, 'friends_add_friend' ) . '">' . __( 'Add Friend', 'buddypress' ) . '</a>';
+		} else {
+			echo __("Friendship request could not be cancelled.", 'buddypress');
+		}
+
+	// Request already pending
+	} else {
+		echo __( 'Request Pending', 'buddypress' );
+	}
+
+	exit;
+}
+
+/**
+ * Accept a user friendship request via a POST request.
+ *
+ * @return mixed String on error, void on success
+ * @since BuddyPress (1.2)
+ */
+function bp_dtheme_ajax_accept_friendship() {
+	// Bail if not a POST action
+	if ( 'POST' !== strtoupper( $_SERVER['REQUEST_METHOD'] ) )
+		return;
+
+	check_admin_referer( 'friends_accept_friendship' );
+
+	if ( ! friends_accept_friendship( (int) $_POST['id'] ) )
+		echo "-1<div id='message' class='error'><p>" . __( 'There was a problem accepting that request. Please try again.', 'buddypress' ) . '</p></div>';
+
+	exit;
+}
+
+/**
+ * Reject a user friendship request via a POST request.
+ *
+ * @return mixed String on error, void on success
+ * @since BuddyPress (1.2)
+ */
+function bp_dtheme_ajax_reject_friendship() {
+	// Bail if not a POST action
+	if ( 'POST' !== strtoupper( $_SERVER['REQUEST_METHOD'] ) )
+		return;
+
+	check_admin_referer( 'friends_reject_friendship' );
+
+	if ( ! friends_reject_friendship( (int) $_POST['id'] ) )
+		echo "-1<div id='message' class='error'><p>" . __( 'There was a problem rejecting that request. Please try again.', 'buddypress' ) . '</p></div>';
+
+	exit;
+}
+
+/**
+ * Join or leave a group when clicking the "join/leave" button via a POST request.
+ *
+ * @return string HTML
+ * @since BuddyPress (1.2)
+ */
+function bp_dtheme_ajax_joinleave_group() {
+	// Bail if not a POST action
+	if ( 'POST' !== strtoupper( $_SERVER['REQUEST_METHOD'] ) )
+		return;
+
+	// Cast gid as integer
+	$group_id = (int) $_POST['gid'];
+
+	if ( groups_is_user_banned( bp_loggedin_user_id(), $group_id ) )
+		return;
+
+	if ( ! $group = groups_get_group( array( 'group_id' => $group_id ) ) )
+		return;
+
+	if ( ! groups_is_user_member( bp_loggedin_user_id(), $group->id ) ) {
+		if ( 'public' == $group->status ) {
+			check_ajax_referer( 'groups_join_group' );
+
+			if ( ! groups_join_group( $group->id ) ) {
+				_e( 'Error joining group', 'buddypress' );
+			} else {
+				echo '<a id="group-' . esc_attr( $group->id ) . '" class="leave-group" rel="leave" title="' . __( 'Leave Group', 'buddypress' ) . '" href="' . wp_nonce_url( bp_get_group_permalink( $group ) . 'leave-group', 'groups_leave_group' ) . '">' . __( 'Leave Group', 'buddypress' ) . '</a>';
+			}
+
+		} elseif ( 'private' == $group->status ) {
+
+			// If the user has already been invited, then this is
+			// an Accept Invitation button
+			if ( groups_check_user_has_invite( bp_loggedin_user_id(), $group->id ) ) {
+				check_ajax_referer( 'groups_accept_invite' );
+
+				if ( ! groups_accept_invite( bp_loggedin_user_id(), $group->id ) ) {
+					_e( 'Error requesting membership', 'buddypress' );
+				} else {
+					echo '<a id="group-' . esc_attr( $group->id ) . '" class="leave-group" rel="leave" title="' . __( 'Leave Group', 'buddypress' ) . '" href="' . wp_nonce_url( bp_get_group_permalink( $group ) . 'leave-group', 'groups_leave_group' ) . '">' . __( 'Leave Group', 'buddypress' ) . '</a>';
+				}
+
+			// Otherwise, it's a Request Membership button
+			} else {
+				check_ajax_referer( 'groups_request_membership' );
+
+				if ( ! groups_send_membership_request( bp_loggedin_user_id(), $group->id ) ) {
+					_e( 'Error requesting membership', 'buddypress' );
+				} else {
+					echo '<a id="group-' . esc_attr( $group->id ) . '" class="membership-requested" rel="membership-requested" title="' . __( 'Membership Requested', 'buddypress' ) . '" href="' . bp_get_group_permalink( $group ) . '">' . __( 'Membership Requested', 'buddypress' ) . '</a>';
+				}
+			}
+		}
+
+	} else {
+		check_ajax_referer( 'groups_leave_group' );
+
+		if ( ! groups_leave_group( $group->id ) ) {
+			_e( 'Error leaving group', 'buddypress' );
+		} elseif ( 'public' == $group->status ) {
+			echo '<a id="group-' . esc_attr( $group->id ) . '" class="join-group" rel="join" title="' . __( 'Join Group', 'buddypress' ) . '" href="' . wp_nonce_url( bp_get_group_permalink( $group ) . 'join', 'groups_join_group' ) . '">' . __( 'Join Group', 'buddypress' ) . '</a>';
+		} elseif ( 'private' == $group->status ) {
+			echo '<a id="group-' . esc_attr( $group->id ) . '" class="request-membership" rel="join" title="' . __( 'Request Membership', 'buddypress' ) . '" href="' . wp_nonce_url( bp_get_group_permalink( $group ) . 'request-membership', 'groups_send_membership_request' ) . '">' . __( 'Request Membership', 'buddypress' ) . '</a>';
+		}
+	}
+
+	exit;
+}
+
+/**
+ * Close and keep closed site wide notices from an admin in the sidebar, via a POST request.
+ *
+ * @return mixed String on error, void on success
+ * @since BuddyPress (1.2)
+ */
+function bp_dtheme_ajax_close_notice() {
+	// Bail if not a POST action
+	if ( 'POST' !== strtoupper( $_SERVER['REQUEST_METHOD'] ) )
+		return;
+
+	if ( ! isset( $_POST['notice_id'] ) ) {
+		echo "-1<div id='message' class='error'><p>" . __( 'There was a problem closing the notice.', 'buddypress' ) . '</p></div>';
+
+	} else {
+		$user_id      = get_current_user_id();
+		$notice_ids   = bp_get_user_meta( $user_id, 'closed_notices', true );
+		$notice_ids[] = (int) $_POST['notice_id'];
+
+		bp_update_user_meta( $user_id, 'closed_notices', $notice_ids );
+	}
+
+	exit;
+}
+
+/**
+ * Send a private message reply to a thread via a POST request.
+ *
+ * @return string HTML
+ * @since BuddyPress (1.2)
+ */
+function bp_dtheme_ajax_messages_send_reply() {
+	// Bail if not a POST action
+	if ( 'POST' !== strtoupper( $_SERVER['REQUEST_METHOD'] ) )
+		return;
+
+	check_ajax_referer( 'messages_send_message' );
+
+	$result = messages_new_message( array( 'thread_id' => (int) $_REQUEST['thread_id'], 'content' => $_REQUEST['content'] ) );
+
+	if ( $result ) { ?>
+		<div class="message-box new-message">
+			<div class="message-metadata">
+				<?php do_action( 'bp_before_message_meta' ); ?>
+				<?php echo bp_loggedin_user_avatar( 'type=thumb&width=30&height=30' ); ?>
+
+				<strong><a href="<?php echo bp_loggedin_user_domain(); ?>"><?php bp_loggedin_user_fullname(); ?></a> <span class="activity"><?php printf( __( 'Sent %s', 'buddypress' ), bp_core_time_since( bp_core_current_time() ) ); ?></span></strong>
+
+				<?php do_action( 'bp_after_message_meta' ); ?>
+			</div>
+
+			<?php do_action( 'bp_before_message_content' ); ?>
+
+			<div class="message-content">
+				<?php echo stripslashes( apply_filters( 'bp_get_the_thread_message_content', $_REQUEST['content'] ) ); ?>
+			</div>
+
+			<?php do_action( 'bp_after_message_content' ); ?>
+
+			<div class="clear"></div>
+		</div>
+	<?php
+	} else {
+		echo "-1<div id='message' class='error'><p>" . __( 'There was a problem sending that reply. Please try again.', 'buddypress' ) . '</p></div>';
+	}
+
+	exit;
+}
+
+/**
+ * Mark a private message as unread in your inbox via a POST request.
+ *
+ * @return mixed String on error, void on success
+ * @since BuddyPress (1.2)
+ */
+function bp_dtheme_ajax_message_markunread() {
+	// Bail if not a POST action
+	if ( 'POST' !== strtoupper( $_SERVER['REQUEST_METHOD'] ) )
+		return;
+
+	if ( ! isset($_POST['thread_ids']) ) {
+		echo "-1<div id='message' class='error'><p>" . __( 'There was a problem marking messages as unread.', 'buddypress' ) . '</p></div>';
+
+	} else {
+		$thread_ids = explode( ',', $_POST['thread_ids'] );
+
+		for ( $i = 0, $count = count( $thread_ids ); $i < $count; ++$i ) {
+			BP_Messages_Thread::mark_as_unread( (int) $thread_ids[$i] );
+		}
+	}
+
+	exit;
+}
+
+/**
+ * Mark a private message as read in your inbox via a POST request.
+ *
+ * @return mixed String on error, void on success
+ * @since BuddyPress (1.2)
+ */
+function bp_dtheme_ajax_message_markread() {
+	// Bail if not a POST action
+	if ( 'POST' !== strtoupper( $_SERVER['REQUEST_METHOD'] ) )
+		return;
+
+	if ( ! isset($_POST['thread_ids']) ) {
+		echo "-1<div id='message' class='error'><p>" . __('There was a problem marking messages as read.', 'buddypress' ) . '</p></div>';
+
+	} else {
+		$thread_ids = explode( ',', $_POST['thread_ids'] );
+
+		for ( $i = 0, $count = count( $thread_ids ); $i < $count; ++$i ) {
+			BP_Messages_Thread::mark_as_read( (int) $thread_ids[$i] );
+		}
+	}
+
+	exit;
+}
+
+/**
+ * Delete a private message(s) in your inbox via a POST request.
+ *
+ * @return string HTML
+ * @since BuddyPress (1.2)
+ */
+function bp_dtheme_ajax_messages_delete() {
+	// Bail if not a POST action
+	if ( 'POST' !== strtoupper( $_SERVER['REQUEST_METHOD'] ) )
+		return;
+
+	if ( ! isset($_POST['thread_ids']) ) {
+		echo "-1<div id='message' class='error'><p>" . __( 'There was a problem deleting messages.', 'buddypress' ) . '</p></div>';
+
+	} else {
+		$thread_ids = explode( ',', $_POST['thread_ids'] );
+
+		for ( $i = 0, $count = count( $thread_ids ); $i < $count; ++$i ) {
+			BP_Messages_Thread::delete( (int) $thread_ids[$i] );
+		}
+
+		_e( 'Messages deleted.', 'buddypress' );
+	}
+
+	exit;
+}
+
+/**
+ * AJAX handler for autocomplete. Displays friends only, unless BP_MESSAGES_AUTOCOMPLETE_ALL is defined.
+ *
+ * @return string HTML
+ * @since BuddyPress (1.2)
+ */
+function bp_dtheme_ajax_messages_autocomplete_results() {
+
+	// Include everyone in the autocomplete, or just friends?
+	if ( bp_is_current_component( bp_get_messages_slug() ) )
+		$autocomplete_all = buddypress()->messages->autocomplete_all;
+
+	$pag_page = 1;
+	$limit    = (int) $_GET['limit'] ? $_GET['limit'] : apply_filters( 'bp_autocomplete_max_results', 10 );
+
+	// Get the user ids based on the search terms
+	if ( ! empty( $autocomplete_all ) ) {
+		$users = BP_Core_User::search_users( $_GET['q'], $limit, $pag_page );
+
+		if ( ! empty( $users['users'] ) ) {
+			// Build an array with the correct format
+			$user_ids = array();
+			foreach( $users['users'] as $user ) {
+				if ( $user->id != bp_loggedin_user_id() ) {
+					$user_ids[] = $user->id;
+				}
+			}
+
+			$user_ids = apply_filters( 'bp_core_autocomplete_ids', $user_ids, $_GET['q'], $limit );
+		}
+
+	} else {
+		if ( bp_is_active( 'friends' ) ) {
+			$users = friends_search_friends( $_GET['q'], bp_loggedin_user_id(), $limit, 1 );
+
+			// Keeping the bp_friends_autocomplete_list filter for backward compatibility
+			$users = apply_filters( 'bp_friends_autocomplete_list', $users, $_GET['q'], $limit );
+
+			if ( ! empty( $users['friends'] ) ) {
+				$user_ids = apply_filters( 'bp_friends_autocomplete_ids', $users['friends'], $_GET['q'], $limit );
+			}
+		}
+	}
+
+	if ( ! empty( $user_ids ) ) {
+		foreach ( $user_ids as $user_id ) {
+			$ud = get_userdata( $user_id );
+			if ( ! $ud ) {
+				continue;
+			}
+
+			if ( bp_is_username_compatibility_mode() ) {
+				// Sanitize for spaces
+				$username = urlencode( $ud->user_login );
+			} else {
+				$username = $ud->user_nicename;
+			}
+
+			// Note that the final line break acts as a delimiter for the
+			// autocomplete javascript and thus should not be removed
+			echo '<span id="link-' . esc_attr( $username ) . '" href="' . bp_core_get_user_domain( $user_id ) . '"></span>' . bp_core_fetch_avatar( array( 'item_id' => $user_id, 'type' => 'thumb', 'width' => 15, 'height' => 15, 'alt' => $ud->display_name ) ) . ' &nbsp;' . bp_core_get_user_displayname( $user_id ) . ' (' . esc_html( $username ) . ')' . "\n";
+		}
+	}
+
+	exit;
+}
Index: /tags/1.9/bp-themes/bp-default/_inc/css/default-rtl.css
===================================================================
--- /tags/1.9/bp-themes/bp-default/_inc/css/default-rtl.css	(revision 7684)
+++ /tags/1.9/bp-themes/bp-default/_inc/css/default-rtl.css	(revision 7684)
@@ -0,0 +1,766 @@
+/*--------------------------------------------------------------
+Hello, this is the BuddyPress Default rtl stylesheet.
+Right to left styles. This will transform the theme to read from
+right to left for languages that support this method.
+
+----------------------------------------------------------------
+>>> TABLE OF CONTENTS:
+----------------------------------------------------------------
+1.0 - Structural
+	1.1 - Content
+	1.2 - Header
+	1.3 - Footer
+	1.4 - Sidebar
+2.0 - Non-structural
+	2.1 - Text
+	2.2 - Headers
+	2.3 - Lists
+3.0 - Navigation
+	3.1 - Pagination
+4.0 - WordPress
+	4.1 - Alignments
+	4.2 - Comments
+	4.3 - Gallery
+	4.4 - Images
+	4.5 - Posts
+5.0 - BuddyPress
+	5.1 - Activity
+		5.1.1 - Activity Listing
+		5.1.2 - Activity Comments
+	5.2 - Toolbar
+	5.3 - Ajax Loading
+	5.4 - Directories - Members, Groups, Blogs, Forums
+	5.5 - Error / Success Messages
+	5.6 - Forms
+	5.7 - Topics and Tables - Forums and General
+	5.8 - Headers, Lists and Tabs - Activity, Groups, Blogs, Forums
+	5.9 - Private Messaging Threads
+--------------------------------------------------------------*/
+/*--------------------------------------------------------------
+1.0 - Structure
+--------------------------------------------------------------*/
+body {
+	direction: rtl;
+	unicode-bidi: embed;
+}
+body {
+	background: #eaeaea url( ../images/background.gif ) top right repeat-x;
+}
+
+
+/*--------------------------------------------------------------
+1.1 - Content
+--------------------------------------------------------------*/
+div#container {
+	border-left: 1px solid #e0e0e0;
+	border-right: 0;
+}
+div#content {
+	float: right;
+	-moz-border-radius-topleft: 0;
+	-moz-border-radius-topright: 6px;
+	-webkit-border-top-right-radius: 6px;
+	-webkit-border-top-left-radius: 0;
+	-moz-border-radius-bottomleft: 0;
+	-moz-border-radius-bottomright: 6px;
+	-webkit-border-bottom-right-radius: 6px;
+	-webkit-border-bottom-left-radius: 0;
+}
+div#content .padder {
+	margin-left: 225px;
+	margin-right: 0;
+	border-left: 1px solid #e4e4e4;
+	border-right: 0;
+	-moz-border-radius-topright: 6px;
+	-moz-border-radius-topleft: 0;
+	-webkit-border-top-right-radius: 6px;
+	-webkit-border-top-left-radius: 0;
+	-moz-border-radius-bottomright: 6px;
+	-moz-border-radius-bottomleft: 0;
+	-webkit-border-bottom-right-radius: 6px;
+	-webkit-border-bottom-left-radius: 0;
+}
+div#content .left-menu {
+	float: right;
+}
+div#content .main-column {
+	margin-right: 190px;
+	margin-left: 0;
+}
+
+
+/*--------------------------------------------------------------
+1.2 - Header
+--------------------------------------------------------------*/
+#header #search-bar {
+	left: 0;
+	right: auto;
+	text-align: left;
+}
+#header #search-bar input[type=text] {
+	margin-left: 4px;
+	margin-right: 0;
+}
+#header #search-bar input[type=submit] {
+	margin-right: 4px;
+	margin-left: 0;
+}
+#header h1 {
+	float: right;
+	left: auto;
+	right: 20px;
+}
+
+
+/*--------------------------------------------------------------
+1.3 - Footer
+--------------------------------------------------------------*/
+#footer-widget-area div.widget-area > ul {
+	float: right;
+	margin-left: 19px;
+	margin-right: 0;
+}
+#footer-widget-area ul.item-list li img.avatar {
+	margin-right: 15px; /* border is 4px */
+	margin-left: 0;
+}
+
+
+/*--------------------------------------------------------------
+1.4 - Sidebar
+--------------------------------------------------------------*/
+div#sidebar {
+	float: right;
+	margin-right: -226px;
+	margin-left: 0;
+	border-right: 1px solid #e4e4e4;
+	border-left: 0;
+	-moz-border-radius-topleft: 3px;
+	-webkit-border-top-left-radius: 3px;
+	-moz-border-radius-topright: 0;
+	-webkit-border-top-right-radius: 0;
+}
+div#sidebar div#sidebar-me img.avatar {
+	float: right;
+	margin: 0 0 15px 10px;
+}
+div#sidebar ul#bp-nav {
+	clear: right;
+}
+#footer-widget-area h3.widgettitle,
+div#sidebar h3.widgettitle {
+	margin: 25px -19px 10px -20px;
+	clear: right;
+}
+#footer-widget-area ul.item-list img.avatar,
+div#sidebar ul.item-list img.avatar {
+	margin-left: 10px;
+	margin-right: 0;
+}
+#footer-widget-area div.item-options,
+div#sidebar div.item-options {
+	margin: -10px -19px 0 -20px;
+}
+#footer-widget-area div.item-meta,
+#footer-widget-area div.item-content,
+div#sidebar div.item-meta,
+div#sidebar div.item-content {
+	margin-right: 38px;
+	margin-left: 0;
+}
+
+
+/*--------------------------------------------------------------
+2.0 - Non-structural
+--------------------------------------------------------------*/
+p.postmetadata {
+	clear: right;
+}
+
+
+/*--------------------------------------------------------------
+2.1 - Text
+--------------------------------------------------------------*/
+code {
+	font-family: "Monaco", courier, sans-serif;
+}
+blockquote {
+	font-family: sans-serif;
+}
+table th {
+	text-align: right;
+}
+div.author-box,
+div.comment-avatar-box {
+	float: right;
+	margin: 0 0 15px 15px;
+	font-family: sans-serif;
+}
+div.post-content {
+	margin-right: 105px;
+	margin-left: 0;
+}
+p.date,
+p.postmetadata,
+div.comment-meta,
+div.comment-options {
+	font-family: sans-serif;
+}
+
+
+/*--------------------------------------------------------------
+2.2 - Headers
+--------------------------------------------------------------*/
+/*--------------------------------------------------------------
+2.3 - Lists
+--------------------------------------------------------------*/
+div.page ul,
+div.page ol,
+div.page dl,
+div.post ul,
+div.post ol,
+div.post dl {
+	margin: 0 1.5em 18px 0;
+}
+dl {
+	margin-right: 0;
+}
+
+
+/*--------------------------------------------------------------
+3.0 - Navigation
+--------------------------------------------------------------*/
+#navigation {
+	text-align: left;
+}
+#nav {
+	margin: 40px 0 0 20px;
+}
+#nav li {
+	margin-left: auto;
+	margin-right: 5px;
+}
+#nav li a {
+	text-align: right;
+}
+#nav li li {
+	margin-left: auto;
+	margin-right: 0;
+}
+#nav .sfhover ul .sfhover > ul,
+#nav :hover ul :hover > ul {
+	left: auto;
+	right: 125px;
+}
+.navigation,
+.paged-navigation,
+.comment-navigation {
+	font-family: sans-serif;
+}
+#nav .sfhover ul li a,
+#nav :hover ul li a {
+	padding-left: 0;
+	padding-right: 10px;
+}
+
+
+/*--------------------------------------------------------------
+3.1 - Pagination
+--------------------------------------------------------------*/
+div.pagination .pag-count {
+	float: right;
+}
+div.pagination .pagination-links {
+	float: left;
+}
+
+
+/*--------------------------------------------------------------
+4.0 - WordPress
+--------------------------------------------------------------*/
+/*--------------------------------------------------------------
+4.1 - Alignments
+--------------------------------------------------------------*/
+.alignright {
+	float: left;
+}
+.alignleft {
+	float: right;
+}
+.clear {
+	clear: right;
+}
+img.avatar {
+	float: right;
+}
+.accessibly-hidden {
+	left: auto;
+	right: -999em;
+}
+
+
+/*--------------------------------------------------------------
+4.2 - Comments
+--------------------------------------------------------------*/
+.comments {
+	float: left;
+}
+ol.commentlist li.comment {
+	clear: right;
+}
+.commentlist ul.children {
+	margin: 15px 70px 15px 0;
+}
+.commentlist ul.children ul {
+	margin: 0 25px 0 0;
+	padding-left: 0;
+}
+ol.commentlist #respond {
+	clear: right;
+	margin-left: auto;
+	margin-right: 70px;
+}
+.commentlist ul.children #respond {
+	margin-left: 20px;
+	margin-right: 35px;
+}
+ol.commentlist div.comment-avatar-box {
+	float: right;
+	margin: 15px 0 0 15px;
+}
+.commentlist ul.children div.comment-avatar-box {
+	float: right;
+	margin: 0 0 0 10px;
+}
+#comments ol.commentlist ol {
+	margin: 0 2.5em 18px 0;
+}
+#reply-title small {
+	float: left;
+}
+#reply-title small a {
+	margin-right: auto;
+	margin-left: 0;
+}
+#respond .comment-avatar-box {
+	float: right;
+	margin: 0 0 0 15px;
+}
+.acomment-options {
+	float: right;
+	margin-right: 40px;
+	margin-left: auto;
+}
+.comment-options .comment-reply-link,
+.comment-options .comment-edit-link {
+	margin-left: 5px;
+	margin-right: auto;
+}
+
+
+/*--------------------------------------------------------------
+4.3 - Gallery
+--------------------------------------------------------------*/
+dd.wp-caption p.wp-caption-text,
+.wp-caption p.wp-caption-text {
+	padding: 0 0 5px 4px;
+}
+
+
+/*--------------------------------------------------------------
+4.4 - Images
+--------------------------------------------------------------*/
+/*--------------------------------------------------------------
+4.5 - Posts
+--------------------------------------------------------------*/
+.page .tags,
+.post .tags {
+	float: right;
+}
+
+
+/*--------------------------------------------------------------
+5.0 - BuddyPress
+--------------------------------------------------------------*/
+/*--------------------------------------------------------------
+5.1 - Activity
+--------------------------------------------------------------*/
+form#whats-new-form h5 {
+	margin-right: 76px;
+	margin-left: 0;
+}
+form#whats-new-form #whats-new-avatar {
+	float: right;
+}
+form#whats-new-form #whats-new-content {
+	margin-right: 54px;
+	padding-right: 22px;
+}
+form#whats-new-form #whats-new-submit {
+	float: left;
+}
+
+
+/*--------------------------------------------------------------
+5.1.1 - Activity Listing
+--------------------------------------------------------------*/
+.activity-header {
+	margin-left: 20px;
+	margin-right: auto;
+}
+.activity-list .activity-avatar {
+	float: right;
+}
+.activity-list li.mini .activity-avatar img.avatar,
+.activity-list li.mini .activity-avatar img.FB_profile_pic {
+	margin-right: 30px;
+	margin-left: 0;
+}
+body.activity-permalink .activity-list li .activity-header > p {
+	margin-left: auto;
+	margin-right: -35px;
+	padding: 5px 35px 0 0;
+}
+.activity-list li.mini .activity-content p {
+	float: right;
+}
+.activity-list li.mini .activity-meta {
+	left: 0;
+	right: auto;
+}
+body.activity-permalink .activity-list li.mini .activity-meta {
+	left: 15px;
+	right: auto;
+}
+.activity-list li.mini .activity-comments {
+	clear: right;
+}
+.activity-list li .activity-inreplyto {
+	margin-right: 5px;
+	margin-left: 0;
+	padding-right: 25px;
+	padding-left: 0;
+	background-position: 100% 0;
+}
+.activity-list .activity-content {
+	margin-right: 70px;
+	margin-left: 0;
+}
+.activity-list li.new_forum_post .activity-content .activity-inner,
+.activity-list li.new_forum_topic .activity-content .activity-inner {
+	border-left: none;
+	margin-left: 0;
+	padding-left: 0;
+	border-right: 2px solid #EAEAEA;
+	margin-right: 5px;
+	padding-right: 10px;
+}
+body.activity-permalink .activity-list li .activity-content {
+	margin-right: 185px;
+	margin-left: 0;
+}
+body.activity-permalink .activity-list li .activity-content > p {
+	background-position: top right;
+	margin-right: -35px;
+	margin-left: 0;
+	padding: 5px 38px 0 0;
+}
+.activity-list .activity-content > p > a:first-child,
+span.highlight,
+.activity-list .activity-content > .comment-header > a:first-child {
+	margin-left: 3px;
+	margin-right: 0;
+}
+.activity-list .activity-content img.thumbnail {
+	float: right;
+	margin: 0 0 5px 10px;
+}
+.activity-list li.load-more {
+	border-left: 1px solid #ddd;
+	border-right: 0;
+}
+a.bp-secondary-action,
+span.highlight {
+	margin-left: 5px;
+	margin-right: auto;
+}
+.activity-list .activity-content .activity-inner,
+.activity-list .activity-content blockquote {
+	margin-left: 10px;
+	margin-right: 0;
+}
+
+
+/*--------------------------------------------------------------
+5.1.2 - Activity Comments
+--------------------------------------------------------------*/
+div.activity-comments {
+	margin: 0 70px 0 0;
+}
+body.activity-permalink div.activity-comments {
+	margin-right: 185px;
+	margin-left: 0;
+}
+div.activity-comments ul {
+	clear: right;
+}
+div.activity-comments > ul {
+	padding: 0 10px 0 0;
+}
+div.activity-comments ul li > ul {
+	margin-left: 0;
+	margin-right: 30px;
+	padding-left: 0;
+	padding-right: 10px;
+}
+div.activity-comments div.acomment-avatar img {
+	float: right;
+	margin-left: 10px;
+	margin-right: 0;
+}
+div.activity-comments div.acomment-content {
+	margin-left: 0;
+	margin-right: 40px;
+}
+div.activity-comments form.ac-form {
+	margin: 10px 33px 10px 0;
+	border-left: 1px solid #ddd;
+	border-right: 0;
+}
+div.activity-comments li form.ac-form {
+	margin-left: 15px;
+	margin-right: 0;
+}
+div.activity-comments form.root {
+	margin-right: 0;
+}
+div.activity-comments form.loading {
+	background-position: 88% 95%;
+}
+div.activity-comments form div.ac-reply-avatar {
+	float: right;
+}
+div.activity-comments form div.ac-reply-content {
+	margin-right: 50px;
+	margin-left: 0;
+	padding-right: 15px;
+	padding-left: 0;
+}
+body.activity-permalink div.activity-comments > ul {
+	padding: 0 15px 0 10px;
+}
+
+
+/*--------------------------------------------------------------
+5.2 - Toolbar
+--------------------------------------------------------------*/
+/*--------------------------------------------------------------
+5.3 - Ajax Loading
+--------------------------------------------------------------*/
+a.loading {
+	background-position: 5% 50% !important;
+	padding-left: 25px !important;
+	padding-right: 0 !important;
+}
+
+
+/*--------------------------------------------------------------
+5.4 - Directories - Members, Groups, Blogs, Forums
+--------------------------------------------------------------*/
+div.dir-search {
+	float: left;
+}
+
+
+/*--------------------------------------------------------------
+5.5 - Error / Success Messages
+--------------------------------------------------------------*/
+span.activity,
+div#message p {
+	border-left: 1px solid #FFE8C4;
+	border-right: 0;
+}
+
+
+/*--------------------------------------------------------------
+5.6 - Forms
+--------------------------------------------------------------*/
+.standard-form#signup_form div.submit {
+	float: left;
+}
+.standard-form#signup_form div.signup-avatar {
+	margin-left: 15px;
+	margin-right: 0;
+}
+.standard-form div.submit input {
+	margin-left: 15px;
+	margin-right: 0;
+}
+.standard-form div.radio ul {
+	margin: 10px 38px 15px 0;
+}
+.standard-form #basic-details-section,
+.standard-form #blog-details-section,
+.standard-form #profile-details-section {
+	float: right;
+}
+.standard-form #profile-details-section {
+	float: left;
+}
+.standard-form #blog-details-section {
+	clear: right;
+}
+a.button,
+input[type=submit],
+input[type=button],
+ul.button-nav li a,
+div.generic-button a {
+	background-position: right top;
+}
+div.accept, div.reject {
+	float: right;
+	margin-left: 0;
+	margin-right: 10px;
+}
+ul.button-nav li {
+	float: right;
+	margin: 0 0 10px 10px;
+}
+
+
+/*--------------------------------------------------------------
+5.7 - Topics and Tables - Forums and General
+--------------------------------------------------------------*/
+table tr td.label {
+	border-left: 1px solid #eaeaea;
+	border-right: 0;
+}
+table.forum tr.closed td.td-title {
+	padding-right: 35px;
+	padding-left: 0;
+	background-position: 5% 50%;
+}
+table.forum tr > td:first-child,
+table.forum tr > th:first-child {
+	padding-right: 15px;
+	padding-left: 0;
+}
+table.forum tr > td:last-child,
+table.forum tr > th:last-child {
+	padding-left: 15px;
+	padding-right: 0;
+}
+table.forum tr th#th-title,
+table.forum tr th#th-poster,
+table.forum tr th#th-group,
+table.forum td.td-poster,
+table.forum td.td-group,
+table.forum td.td-title {
+	text-align: right;
+}
+table.forum td img.avatar {
+	margin-left: 5px;
+	margin-right: 0;
+}
+ul#topic-post-list li div.post-content {
+	margin-right: 54px;
+	margin-left: 0;
+}
+div.admin-links {
+	left: 25px;
+	right: auto
+}
+div#topic-meta div.admin-links {
+	left: 0;
+	right: auto;
+}
+
+
+/*--------------------------------------------------------------
+5.8 - Headers, Lists and Tabs - Activity, Groups, Blogs, Forums
+--------------------------------------------------------------*/
+div#item-header img.avatar {
+	float: right;
+	margin: 0 0 25px 15px;
+}
+div#item-header span.activity {
+	margin: 0 4px 5px 0;
+}
+div#item-header div#item-actions {
+	float: left;
+	margin: 0 15px 15px 0;
+	text-align: left;
+}
+div#item-header ul li {
+	float: left;
+}
+div#item-header div.generic-button,
+div#item-header a.button {
+	float: right;
+	margin: 10px 0 0 10px;
+}
+ul.item-list li img.avatar {
+	float: right;
+	margin: 0 0 0 10px;
+}
+ul.item-list li div.item-desc {
+	margin: 10px 64px 0 0;
+}
+ul.item-list li div.action {
+	left: 0;
+	right: auto;
+	text-align: left;
+}
+div.item-list-tabs {
+	clear: right;
+}
+div.item-list-tabs ul li {
+	float: right;
+	margin: 5px 5px 0 0;
+}
+div.item-list-tabs ul li:first-child {
+	margin-left: 0;
+	margin-right: 20px;
+}
+div.item-list-tabs ul li.last {
+	float: left;
+	margin: 7px 0 0 20px;
+}
+ul li.loading a {
+	background-position: 8% 50%;
+	padding-left: 30px !important;
+	padding-right: 0 !important;
+}
+div#item-nav ul li.loading a {
+	background-position: 12% 50%;
+}
+div.item-list-tabs ul li.feed a {
+	background-position: right center;
+	padding-right: 20px;
+	padding-left: 0;
+}
+
+
+/*--------------------------------------------------------------
+5.9 - Private Messaging Threads
+--------------------------------------------------------------*/
+div.messages-options-nav {
+	text-align: left;
+}
+div#message-thread img.avatar {
+	float: right;
+	margin: 0 0 0 10px;
+}
+div#message-thread strong span.activity {
+	margin: 4px 10px 0 0;
+}
+div#message-thread div.message-content {
+	margin-right: 45px;
+	margin-left: 0;
+}
+div#message-thread div.message-options {
+	text-align: left;
+}
+div.message-search {
+	float: left;
+}
Index: /tags/1.9/bp-themes/bp-default/_inc/css/default.css
===================================================================
--- /tags/1.9/bp-themes/bp-default/_inc/css/default.css	(revision 7684)
+++ /tags/1.9/bp-themes/bp-default/_inc/css/default.css	(revision 7684)
@@ -0,0 +1,2437 @@
+/*--------------------------------------------------------------
+Hello, this is the BuddyPress Default theme stylesheet.
+
+----------------------------------------------------------------
+>>> TABLE OF CONTENTS:
+----------------------------------------------------------------
+1.0 - Reset - Based on work by Eric Meyer
+2.0 - Structural
+	2.1 - Content
+	2.2 - Header
+	2.3 - Footer
+	2.4 - Sidebar
+3.0 - Non-structural
+	3.1 - Text
+	3.2 - Headers
+	3.3 - Lists
+4.0 - Navigation
+	4.1 - Pagination
+5.0 - WordPress
+	5.1 - Alignments
+	5.2 - Comments
+	5.3 - Gallery
+	5.4 - Images
+	5.5 - Posts
+6.0 - BuddyPress
+	6.1 - Activity
+		6.1.1 - Activity Listing
+		6.1.2 - Activity Comments
+	6.2 - Toolbar
+	6.3 - Directories - Members, Groups, Blogs, Forums
+	6.4 - Error / Success Messages
+	6.5 - Forms
+	6.6 - Ajax Loading
+	6.7 - Topics and Tables - Forums and General
+	6.8 - Headers, Lists and Tabs - Activity, Groups, Blogs, Forums
+	6.9 - Private Messaging Threads
+	6.10 - Extended Profiles
+--------------------------------------------------------------*/
+
+/*--------------------------------------------------------------
+1.0 - Reset - Reset default browser CSS. Based on work by Eric
+Meyer: v1.0  http://meyerweb.com/eric/tools/css/reset/index.html
+--------------------------------------------------------------*/
+html,body,div,span,applet,object,iframe,
+h1,h2,h3,h4,h5,h6,p,blockquote,pre,
+a,abbr,acronym,address,big,cite,code,
+del,dfn,em,font,img,ins,kbd,q,s,samp,
+small,strike,strong,sub,sup,tt,var,
+b,u,i,center,
+dl,dt,dd,ol,ul,li,
+fieldset,form,label,legend,
+table,caption,tbody,tfoot,thead,tr,th,td{margin:0;padding:0;border:0;outline:0;font-size:100%;vertical-align:baseline;background:transparent;}
+body{background:#fff;line-height:1;}
+ol,ul{list-style:none;}
+blockquote,q{quotes:none;}
+blockquote:before,blockquote:after,
+q:before,q:after{content:'';content:none;}
+:focus{outline:0;}
+ins{text-decoration:none;}
+del{text-decoration:line-through;}
+table{border-collapse:collapse;border-spacing:0;}
+a img{border:none;}
+
+
+/*--------------------------------------------------------------
+2.0 - Structural
+--------------------------------------------------------------*/
+body {
+	background-color: #eaeaea;
+	background-image: url( ../images/background.gif );
+	background-repeat: repeat-x;
+	background-position: top left;
+	color: #555;
+	font-size: 12px;
+	font-family: Arial, Tahoma, Verdana, sans-serif;
+	line-height: 170%;
+	max-width: 1250px;
+	margin: 0 auto;
+	width: 95%;
+}
+.padder {
+	padding: 19px;
+}
+div#container {
+	background: #fff;
+	border-right: 1px solid #e0e0e0;
+	border-bottom: 1px solid #e0e0e0;
+	-moz-border-radius: 6px;
+	-webkit-border-radius: 6px;
+	border-radius: 6px;
+	overflow: hidden;
+	position: relative;
+	width: 100%;
+}
+body.activity-permalink div#container {
+	background: none;
+	border: none;
+}
+
+
+/*--------------------------------------------------------------
+2.1 - Content
+--------------------------------------------------------------*/
+div#content {
+	-moz-border-radius-topleft: 6px;
+	-webkit-border-top-left-radius: 6px;
+	-moz-border-radius-bottomleft: 6px;
+	-webkit-border-bottom-left-radius: 6px;
+	border-top-left-radius: 6px;
+	border-top-right-radius: 6px;
+	float: left;
+	width: 100%;
+}
+div#content .padder {
+	border-right: 1px solid #ddd;
+	-moz-border-radius-topleft: 6px;
+	-webkit-border-top-left-radius: 6px;
+	-moz-border-radius-bottomleft: 6px;
+	-webkit-border-bottom-left-radius: 6px;
+	border-top-left-radius: 6px;
+	border-bottom-left-radius: 6px;
+	margin-right: 225px;
+}
+div#content .one-column {
+	border-right: 0 none;
+	margin-right: 0;
+}
+div#content .left-menu {
+	float: left;
+	width: 170px;
+}
+div#content .main-column {
+	margin-left: 190px;
+}
+textarea {
+	overflow: auto;
+}
+
+
+/*--------------------------------------------------------------
+2.2 - Header
+--------------------------------------------------------------*/
+#header {
+	background: #1fb3dd; /* Old browsers */
+	background: -moz-linear-gradient(top, #1fb3dd 0%, #1fb3dd 15%, #394c79 100%); /* FF3.6+ */
+	background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#1fb3dd), color-stop(15%,#1fb3dd), color-stop(100%,#394c79)); /* Chrome,Safari4+ */
+	background: -webkit-linear-gradient(top, #1fb3dd 0%,#1fb3dd 15%,#394c79 100%); /* Chrome10+,Safari5.1+ */
+	background: -o-linear-gradient(top, #1fb3dd 0%,#1fb3dd 15%,#394c79 100%); /* Opera11.10+ */
+	background: -ms-linear-gradient(top, #1fb3dd 0%,#1fb3dd 15%,#394c79 100%); /* IE10+ */
+	background: linear-gradient(top, #1fb3dd 0%,#1fb3dd 15%,#394c79 100%); /* W3C */
+	-moz-border-radius-bottomleft: 6px;
+	-webkit-border-bottom-left-radius: 6px;
+	border-bottom-left-radius: 6px;
+	-moz-border-radius-bottomright: 6px;
+	-webkit-border-bottom-right-radius: 6px;
+	border-bottom-right-radius: 6px;
+	color: #fff;
+	height: auto;
+	margin-bottom: 20px;
+	padding-top: 25px;
+	position: relative;
+	z-index: 1000;
+}
+#header #search-bar {
+	margin-top: 5px;
+	text-align: right;
+	width: 100%;
+}
+#header #search-bar .padder {
+	padding: 10px 15px 0 20px;
+	height: auto;
+}
+#header #search-bar input[type=text] {
+	border: 1px inset #888;
+	-moz-border-radius: 3px;
+	-webkit-border-radius: 3px;
+	border-radius: 3px;
+	margin-right: 4px;
+	padding: 2px;
+}
+#header #search-bar input[type=submit] {
+	font-size: 11px;
+	padding: 1px 4px;
+	margin-left: 4px;
+}
+#header h1 {
+	float: left;
+	margin-bottom: 0;
+	margin-top: 0;
+}
+#header h1 a {
+	color: #fff;
+	font-size: 26px;
+	text-decoration: none;
+}
+
+
+/*--------------------------------------------------------------
+2.3 - Footer
+--------------------------------------------------------------*/
+#footer {
+	margin: 20px 0;
+}
+#footer-widgets {
+	background: #fff;
+	border-bottom: 1px solid #e0e0e0;
+	border-right: 1px solid #e0e0e0;
+	-moz-border-radius: 6px;
+	-webkit-border-radius: 6px;
+	border-radius: 6px;
+	padding: 19px;
+}
+#site-generator {
+	color: #4D4D4D;
+	margin: 20px 20px;
+	text-align: center;
+	text-shadow: #fafafa 1px 1px 0;
+}
+#footer-widget-area {
+	margin-top: -19px;
+	overflow: hidden;
+}
+#footer-widget-area div.widget-area > ul {
+	float: left;
+	margin-right: 2.5%;
+	width: 23%;
+}
+#footer-widget-area div.widget-area > ul > li {
+	margin-top: 19px;
+}
+#footer-widget-area h3.widgettitle {
+	background: #eaeaea;
+	clear: left;
+	padding: 5px 15px;
+	font-size: 12px;
+	margin: 0 0 10px 0;
+}
+#footer-widget-area div div.item-options {
+	margin-left: 0;
+	margin-right: 0;
+}
+#footer-widget-area ul.item-list li img.avatar {
+	margin-left: 15px; /* border is 4px */
+}
+div#fourth ul.xoxo { margin-right: 0; }
+
+
+/*--------------------------------------------------------------
+2.4 - Sidebar
+--------------------------------------------------------------*/
+div#sidebar {
+	border-left: 1px solid #ddd;
+	-moz-border-radius-topright: 3px;
+	-webkit-border-top-right-radius: 3px;
+	border-top-right-radius: 3px;
+	float: left;
+	margin-left: -226px;
+	margin-top: 1px;
+	width: 224px;
+}
+div#sidebar div#sidebar-me {
+	margin-bottom: 15px;
+}
+div#sidebar div#sidebar-me img.avatar {
+	float: left;
+	margin: 0 10px 15px 0;
+}
+div#sidebar div#sidebar-me h4 {
+	font-size: 16px;
+	margin: 0 0 8px 0;
+	font-weight: normal;
+}
+div#sidebar ul#bp-nav {
+	clear: left;
+	margin: 15px -16px;
+}
+div#sidebar ul#bp-nav li {
+	padding: 10px 15px;
+}
+div#sidebar h3.widgettitle {
+	background: #eaeaea;
+	clear: left;
+	font-size: 12px;
+	margin: 25px -20px 10px -19px;
+	padding: 5px 15px;
+}
+#footer-widget-area .widget_search,
+div#sidebar .widget_search {
+	margin-top: 20px;
+}
+#footer-widget-area .widget_search input[type=text],
+div#sidebar .widget_search input[type=text] {
+	padding: 2px;
+	width: 110px;
+}
+#footer-widget-area ul.item-list img.avatar,
+div#sidebar ul.item-list img.avatar {
+	height: 20px;
+	margin-right: 10px;
+	width: 20px;
+}
+#footer-widget-area div.item-avatar img,
+div#sidebar div.item-avatar img {
+	height: 40px;
+	margin: 1px;
+	width: 40px;
+}
+#footer-widget-area .avatar-block,
+div#sidebar .avatar-block {
+	overflow: hidden;
+}
+#footer-widget-area ul.item-list div.item-title,
+div#sidebar ul.item-list div.item-title {
+	font-size: 12px;
+}
+#footer-widget-area div.item-options,
+div#sidebar div.item-options {
+	background: #f5f5f5;
+	font-size: 11px;
+	margin: -10px -20px 0 -19px;
+	padding: 5px 15px;
+}
+#footer-widget-area div.item-content {
+	margin-left: 38px;
+}
+#footer-widget-area div.item-meta,
+div#sidebar div.item-meta,
+div#sidebar div.item-content {
+	font-size: 11px;
+	margin-left: 38px;
+}
+#footer-widget-area div.tags div#tag-text,
+div#sidebar div.tags div#tag-text {
+	font-size: 1.4em;
+	line-height: 140%;
+	padding: 10px 0 15px;
+}
+
+
+/*--------------------------------------------------------------
+3.0 - Non-structural
+--------------------------------------------------------------*/
+p {
+	margin-bottom: 15px;
+}
+p:last-child {
+	margin-bottom: 0;
+}
+.accessibly-hidden {
+	left: -999em;
+	position: absolute;
+}
+hr {
+	background-color: #e7e7e7;
+	border: 0 none;
+	clear: both;
+	height: 1px;
+	margin: 20px 0;
+}
+textarea {
+	resize: vertical;
+}
+
+
+/*--------------------------------------------------------------
+3.1 - Text
+--------------------------------------------------------------*/
+big {
+	font-size: 18px;
+}
+del {
+	text-decoration: line-through;
+}
+ins {
+	background: #fff9db;
+	text-decoration: none;
+}
+sub {
+	top: .5ex;
+}
+sup {
+	bottom: 1ex;
+}
+sub,
+sup {
+	height: 0;
+	line-height: 1;
+	position: relative;
+	vertical-align: baseline;
+}
+pre, blockquote {
+	margin-bottom: 20px;
+}
+pre,
+code p {
+	background: #f4f4f4;
+	-moz-border-radius: 3px;
+	-webkit-border-radius: 3px;
+	border-radius: 3px;
+	padding: 15px;
+	overflow: auto;
+}
+code {
+	font-family: "Monaco", courier, sans-serif;
+}
+blockquote {
+	font-family: georgia, times, serif;
+	font-size: 16px;
+	font-style: italic;
+	line-height: 150%;
+	padding: 0 3em;
+	quotes: none;
+}
+blockquote p {
+	margin-bottom: 15px !important;
+}
+
+
+/*--------------------------------------------------------------
+3.2 - Headers
+--------------------------------------------------------------*/
+h1,
+h2,
+h3,
+h4,
+h5,
+h6 {
+	margin: 5px 0 15px 0;
+}
+h1 {
+	font-size: 28px;
+	margin-bottom: 25px;
+}
+h2 {
+	font-size: 24px;
+	margin-bottom: 20px;
+}
+h3 {
+	font-size: 20px;
+}
+h4 {
+	font-size: 16px;
+	margin-bottom: 15px;
+}
+h5 {
+	font-size: 14px;
+	margin-bottom: 0;
+}
+h6 {
+	font-size: 12px;
+	margin-bottom: 0;
+}
+
+
+/*--------------------------------------------------------------
+3.3 - Lists
+--------------------------------------------------------------*/
+div.page ul,
+div.page ol,
+div.page dl,
+div.post ul,
+div.post ol,
+div.post dl {
+	margin: 0 0 18px 1.5em;
+}
+div.page ul,
+div.post ul {
+	list-style: square;
+}
+div.page ol,
+div.post ol {
+	list-style: decimal;
+}
+div.page ol ol,
+div.post ol ol {
+	list-style: lower-alpha;
+}
+div.page ol ol ol,
+div.post ol ol ol {
+	list-style: lower-roman;
+}
+dl {
+	margin-left: 0;
+}
+dt {
+	font-size: 14px;
+	font-weight: bold;
+}
+dd {
+	margin: 0 0 15px 0;
+}
+div.post ul ul,
+div.post ol ol,
+div.post ol ul,
+div.post ul ol,
+div.page ul ul,
+div.page ol ol,
+div.page ol ul,
+div.page ul ol {
+	margin-bottom: 0px;
+}
+
+
+/*--------------------------------------------------------------
+4.0 - Navigation
+--------------------------------------------------------------*/
+a {
+	color: #1fb3dd;
+}
+a:hover,
+a:active {
+	color: #888;
+}
+a:focus {
+	outline: 1px dotted #ccc;
+}
+#navigation {
+	position: relative;
+	width: 100%;
+}
+#navigation:after {
+	content: ".";
+	display: block;
+	height: 0;
+	clear: both;
+	visibility: hidden;
+}
+#nav {
+	margin: 40px 20px 0 0;
+	list-style: none;
+	padding: 0;
+	float: right;
+}
+#nav li a {
+	background: url( ../images/60pc_black.png );
+	color: #fff;
+	display: block;
+	padding: 5px 15px;
+	text-decoration: none;
+	text-align: left;
+}
+#nav li {
+	margin-left: 5px;
+	display: inline-block;
+	float: left;
+}
+#nav li li {
+	margin-left: 0;
+}
+#nav > li > a {
+	-moz-border-radius-topleft: 3px;
+	-webkit-border-top-left-radius: 3px;
+	-moz-border-radius-topright: 3px;
+	-webkit-border-top-right-radius: 3px;
+	border-top-left-radius: 3px;
+	border-top-right-radius: 3px;
+}
+#nav li.selected a,
+#nav > li.current-menu-item a,
+#nav > li.current_page_item a,
+#nav > li.current_page_ancestor a {
+	background: #f5f5f5;
+	color: #4D4D4D;
+}
+#nav > li > ul {
+	border-top-width: 0;
+}
+#nav > ul li.sfhover a,
+#nav > ul li:hover a {
+	background: #333;
+	color: #fff;
+}
+#nav li.sfhover,
+#nav li:hover {
+	position: relative;
+	z-index: 1000;
+}
+#nav ul {
+	border: 1px solid #222;
+	-moz-border-radius: 3px;
+	-webkit-border-radius: 3px;
+	-moz-border-radius-topleft: 0;
+	-moz-border-radius-topright: 0;
+	-webkit-border-top-left-radius: 0;
+	-webkit-border-top-right-radius: 0;
+	border-top-left-radius: 0;
+	border-top-right-radius: 0;
+	-moz-box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
+	-webkit-box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
+	box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
+}
+#nav ul li ul {
+	-moz-border-radius: 3px;
+	-webkit-border-radius: 3px;
+	border-radius: 3px;
+}
+#nav ul,
+#nav .sfhover ul ul,
+#nav :hover ul ul {
+	display: none;
+	position: absolute;
+}
+#nav .sfhover ul,
+#nav :hover ul {
+	display: block;
+	top: 100%;
+	width: 128px;
+}
+#nav .sfhover ul li > a,
+#nav :hover ul li > a {
+	background: #333;
+	color: #fff;
+}
+#nav .sfhover ul .sfhover > ul,
+#nav :hover ul :hover > ul {
+	left: 125px;
+	top: -1px;
+	width: 128px;
+	display: block;
+}
+#nav ul li.sfhover > a,
+#nav ul li:hover > a {
+	background-color: #222;
+	color: #fff;
+}
+#nav .sfhover ul li,
+#nav :hover ul li {
+	min-height: 30px;
+	line-height: 20px;
+	width: 128px;
+}
+#nav .sfhover ul li a,
+#nav :hover ul li a {
+	padding: 5px 5px 5px 10px;
+}
+
+
+/*--------------------------------------------------------------
+4.1 - Pagination
+--------------------------------------------------------------*/
+div.pagination {
+	background: #f4f4f4;
+	border: none;
+	color: #888;
+	font-size: 11px;
+	height: 19px;
+	margin: -20px -19px 0px -19px;
+	padding: 8px 20px;
+	position: relative;
+}
+div.pagination .pag-count {
+	float: left;
+}
+div.pagination .pagination-links {
+	float: right;
+}
+div.pagination .pagination-links span,
+div.pagination .pagination-links a {
+	font-size: 12px;
+	padding: 0 5px;
+}
+div.pagination .pagination-links a:hover {
+	font-weight: bold;
+}
+noscript div.pagination {
+	margin-bottom: 15px;
+}
+div#pag-bottom {
+	margin-top: -1px;
+}
+#nav-above {
+	display: none;
+}
+.paged #nav-above {
+	display: block;
+}
+
+
+/*--------------------------------------------------------------
+5.0 - WordPress
+--------------------------------------------------------------*/
+/*--------------------------------------------------------------
+5.1 - Alignments
+--------------------------------------------------------------*/
+.alignright {
+	float: right;
+	margin-left: 15px;
+}
+.alignleft {
+	float: left;
+	margin-right: 15px;
+}
+.aligncenter {
+	display: block;
+	margin-left: auto;
+	margin-right: auto;
+}
+.clear {
+	clear: left;
+}
+
+
+/*--------------------------------------------------------------
+5.2 - Comments
+--------------------------------------------------------------*/
+.navigation,
+.paged-navigation,
+.comment-navigation {
+	overflow: hidden;
+	font-family: georgia, times, serif;
+	font-size: 14px;
+	font-style: italic;
+	margin: 5px 0 25px 0;
+	padding: 5px 0;
+}
+.comments {
+	float: right;
+}
+#trackbacks {
+	margin-top: 30px;
+}
+.commentlist .bypostauthor {
+}
+#comments {
+	margin-top: 30px;
+}
+#comments ol.commentlist {
+	border-bottom: 1px solid #e4e4e4;
+	margin: 0 0 30px 0;
+}
+#comments ol.commentlist ol {
+	list-style-type: decimal;
+	margin: 0 0 18px 2.5em;
+}
+#comments ol.commentlist ol ol {
+	list-style: lower-alpha;
+	margin-bottom: 0px;
+}
+#comments ol.commentlist ol ol ol {
+	list-style: lower-roman;
+}
+ol.commentlist li.comment {
+	border-top: 1px solid #e4e4e4;
+	clear: left;
+	list-style: none;
+	margin-bottom: 15px;
+}
+ol.commentlist ul.children li {
+	margin-bottom: 0;
+}
+ol.commentlist div.comment-avatar-box {
+	float: left;
+	margin: 15px 15px 0 0;
+}
+.commentlist ul.children div.comment-avatar-box {
+	float: left;
+	margin: 0 10px 0 0;
+}
+div.comment-avatar-box img {
+	border: 2px solid #eee;
+}
+div.comment-content {
+	overflow: hidden;
+}
+ul.children .comment-entry {
+	margin-bottom: 10px;
+}
+div.comment-meta {
+	color: #888;
+	font-size: 11px;
+	margin: 15px 0;
+	width: 100%;
+}
+div.comment-meta em {
+	font-style: normal;
+}
+#reply-title {
+	margin-top: 0;
+}
+#reply-title small {
+	float: right;
+	font-size: 11px;
+	font-weight: normal;
+}
+#reply-title small a {
+	margin-right: 0;
+}
+.commentlist ul.children {
+	background: #f5f5f5;
+	-moz-border-radius: 4px;
+	-webkit-border-radius: 4px;
+	border-radius: 4px;
+	margin: 15px 0 15px 70px;
+	padding: 0 10px;
+}
+.commentlist ul.children ul {
+	margin: 0 0 0 25px;
+	padding-right: 0;
+}
+.commentlist ul.children img.avatar {
+	border-style: none;
+	height: 25px;
+	margin: 0;
+	width: 25px;
+}
+.commentlist ul.children div.comment-meta {
+	font-size: 11px;
+	margin: 0 0 10px 0;
+}
+.commentlist ul.children li {
+	border-top: 2px solid #fffeff;
+	padding-top: 10px;
+}
+.commentlist ul.children li:first-child {
+	border-top: none;
+}
+.commentlist ul.children ul li:first-child {
+	border-top: 2px solid #fffeff;
+}
+#respond {
+	background-color: #fafafa;
+	border: 1px solid #e5e5e5;
+	-moz-border-radius: 4px;
+	-webkit-border-radius: 4px;
+	border-radius: 4px;
+	padding: 15px;
+}
+#respond .avb img {
+	float: inherit;
+}
+#respond .comment-avatar-box {
+	float: left;
+	margin: 0 15px 0 0;
+}
+#respond .form-submit {
+	margin-bottom: 0;
+}
+ol.commentlist #respond {
+	clear: left;
+	margin-left: 70px;
+}
+.commentlist ul.children #respond {
+	margin-bottom: 10px;
+	margin-left: 35px;
+	margin-right: 20px;
+}
+h3#reply .comments-header {
+	font-size: 14px;
+}
+#respond div.comment-content {
+	border-style: none;
+}
+#nav-below {
+	margin: 0 0;
+	padding: 0 0;
+}
+#nav-above {
+	margin: 0 0 15px;
+	padding: 0;
+}
+.comment-options {
+	margin: 10px 0 2px;
+}
+.comment-options .comment-reply-link,
+.comment-options .comment-edit-link {
+	font: normal 11px/20px Arial, Tahoma, Verdana, sans-serif;
+	margin-right: 5px;
+	padding: 4px 8px;
+}
+.commentlist ul.children div.comment-options {
+	margin-bottom: 10px;
+}
+
+
+/*--------------------------------------------------------------
+5.3 - Gallery
+--------------------------------------------------------------*/
+.wp-caption {
+	background-color: #f3f3f3;
+	border: 1px solid #ddd;
+	-moz-border-radius: 3px;
+	-webkit-border-radius: 3px;
+	border-radius: 3px;
+	margin-bottom: 15px;
+	padding-top: 4px;
+	text-align: center;
+
+}
+.wp-caption img {
+	border: 0 none;
+	margin: 0;
+	padding: 0;
+
+}
+dd.wp-caption p.wp-caption-text,
+.wp-caption p.wp-caption-text {
+	font-size: 0.9em;
+	line-height: 17px;
+	margin: 0;
+	padding: 5px 4px 5px 0;
+}
+#content .gallery {
+	margin: 0 auto 15px;
+}
+#content .gallery .gallery-item {
+	margin-bottom: 0;
+	margin-left: 0;
+}
+.gallery-item img {
+	margin-bottom: 15px;
+}
+.gallery .gallery-caption {
+	color: #555;
+}
+
+
+/*--------------------------------------------------------------
+5.4 - Images
+--------------------------------------------------------------*/
+img.avatar {
+	border: 2px solid #eee;
+	float: left;
+}
+img.wp-smiley {
+	border: none !important;
+	clear: none !important;
+	float: none !important;
+	margin: 0 !important;
+	padding: 0 !important;
+}
+img.centered,
+img.aligncenter {
+	display: block;
+	margin-left: auto;
+	margin-right: auto;
+}
+img.alignright {
+	display: inline;
+	margin: 0 0 2px 7px;
+	padding: 4px;
+}
+img.alignleft {
+	display: inline;
+	margin: 0 7px 2px 0;
+	padding: 4px;
+}
+
+
+/*--------------------------------------------------------------
+5.5 - Posts
+--------------------------------------------------------------*/
+div.page,
+div.post,
+div.attachment {
+	margin: 0 0 15px 0;
+	overflow: hidden;
+}
+div.page:last-child,
+div.post:last-child,
+#item-body:last-child,
+#trackbacklist {
+	margin-bottom: 0;
+}
+h2.posttitle {
+	line-height: 120%;
+	margin: 0;
+}
+h2.pagetitle {
+	line-height: 120%;
+}
+h2.pagetitle a,
+h2.posttitle a {
+	color: #666;
+	text-decoration: none;
+}
+.edit-link,
+.page-link {
+	clear: both;
+	font-weight: bold;
+}
+div.post table,
+div.page table {
+	border: 1px solid #eee;
+	border-collapse: collapse;
+	border-spacing: 0;
+	margin-bottom: 15px;
+}
+div.post table th,
+div.page table th {
+	border-top: 1px solid #eee;
+	text-align: left;
+}
+div.post table td,
+div.page table td {
+	border-top: 1px solid #eee;
+}
+div.author-box {
+	background: #f0f0f0;
+	-moz-border-radius: 3px;
+	-webkit-border-radius: 3px;
+	border-radius: 3px;
+	float: left;
+	font-family: georgia, times, serif;
+	font-style: italic;
+	margin: 0 15px 15px 0;
+	padding: 10px;
+	text-align: center;
+	width: 70px;
+}
+div.author-box p {
+	word-wrap: break-word;
+}
+div.author-box p,
+div.comment-avatar-box p {
+	margin: 5px 0 0;
+}
+div.author-box a,
+div.comment-avatar-box a {
+	text-decoration: none;
+}
+div.author-box img {
+	float: none;
+	border: 4px solid #fff;
+	margin: 0;
+}
+div.post-content {
+	margin-left: 105px;
+}
+p.date span:first-child {
+	font-style: italic;
+}
+div.post .entry {
+	margin-bottom: 15px;
+}
+p.date,
+p.postmetadata {
+	border-bottom: 1px solid #e4e4e4;
+	border-top: 1px solid #e4e4e4;
+	color: #888;
+	font-family: Georgia, times, serif;
+	font-size: 12px;
+	margin: 10px 0;
+	padding: 3px 0;
+}
+p.postmetadata {
+	clear: left;
+	overflow: hidden;
+}
+.page .tags,
+.post .tags {
+	float: left;
+}
+span.sticky-post {
+	font-style: normal;
+}
+
+
+/*--------------------------------------------------------------
+6.0 - BuddyPress
+--------------------------------------------------------------*/
+/*--------------------------------------------------------------
+6.1 - Activity
+--------------------------------------------------------------*/
+#activity-stream {
+	margin-top: -5px;
+}
+#item-body form#whats-new-form {
+	border-bottom: 1px solid #ddd;
+	margin: 20px 0 10px;
+	padding-bottom: 20px;
+}
+.home-page form#whats-new-form {
+	border-bottom: none;
+	padding-bottom: 0;
+}
+form#whats-new-form h5 {
+	font-weight: normal;
+	font-size: 12px;
+	color: #888;
+	margin: 0;
+	margin-left: 76px;
+	padding: 0 0 3px 0;
+}
+form#whats-new-form #whats-new-avatar {
+	float: left;
+}
+form#whats-new-form #whats-new-content {
+	margin-left: 54px;
+	padding-left: 22px;
+}
+form#whats-new-form textarea {
+	background: #fff;
+	border: 1px inset #ccc;
+	-moz-border-radius: 3px;
+	-webkit-border-radius: 3px;
+	border-radius: 3px;
+	color: #555;
+	font-family: inherit;
+	font-size: 14px;
+	height: 20px;
+	padding: 6px;
+	width: 98%;
+}
+body.no-js form#whats-new-form textarea {
+	height: 50px;
+}
+form#whats-new-form #whats-new-options select {
+	max-width: 200px;
+	margin-top: 12px;
+}
+form#whats-new-form #whats-new-submit {
+	float: right;
+	margin-top: 12px;
+}
+#whats-new-options {
+	overflow: auto;
+	height: 0;
+}
+body.no-js #whats-new-options {
+	height: auto;
+}
+#whats-new:focus {
+	border-color: rgba(31, 179, 221, 0.9) !important;
+	outline-color: rgba(31, 179, 221, 0.9);
+	box-shadow: 0 0 7px         rgba(31, 179, 221, 0.7);
+	-moz-box-shadow: 0 0 7px    rgba(31, 179, 221, 0.7);
+	-webkit-box-shadow: 0 0 7px rgba(31, 179, 221, 0.7);
+}
+
+/*--------------------------------------------------------------
+6.1.1 - Activity Listing
+--------------------------------------------------------------*/
+ul.activity-list li {
+	overflow: hidden;
+	padding: 15px 0 0;
+}
+.activity-list .activity-avatar {
+	float: left;
+}
+ul.activity-list > li:first-child {
+	padding-top: 5px;
+}
+ul.item-list.activity-list li.has-comments {
+	padding-bottom: 15px;
+}
+body.activity-permalink ul.activity-list li.has-comments {
+	padding-bottom: 0;
+}
+.activity-list li.mini {
+	font-size: 11px;
+	min-height: 35px;
+	padding: 15px 0 0 0;
+	position: relative;
+}
+.activity-list li.mini .activity-avatar img.avatar,
+.activity-list li.mini .activity-avatar img.FB_profile_pic {
+	height: 20px;
+	margin-left: 30px;
+	width: 20px;
+}
+.activity-permalink .activity-list li.mini .activity-avatar img.avatar,
+.activity-permalink .activity-list li.mini .activity-avatar img.FB_profile_pic {
+	height: auto;
+	margin-left: 0;
+	width: auto;
+}
+body.activity-permalink .activity-list > li:first-child {
+	padding-top: 0;
+}
+.activity-list li .activity-content {
+	position: relative;
+}
+.activity-list li.mini .activity-content p {
+	margin: 0;
+}
+.activity-list li.mini .activity-comments {
+	clear: both;
+	font-size: 12px;
+}
+body.activity-permalink li.mini .activity-meta {
+	margin-top: 4px;
+}
+.activity-list li .activity-inreplyto {
+	background: url( ../images/replyto_arrow.gif ) 7px 0 no-repeat;
+	color: #888;
+	font-size: 11px;
+	margin-left: 5px;
+	margin-top: 5px;
+	padding-left: 25px;
+}
+.activity-list li .activity-inreplyto > p {
+	margin: 0;
+	display: inline;
+}
+.activity-list li .activity-inreplyto blockquote,
+.activity-list li .activity-inreplyto div.activity-inner {
+	background: none;
+	border: none;
+	display: inline;
+	margin: 0;
+	overflow: hidden;
+	padding: 0;
+}
+.activity-list .activity-content {
+	margin-left: 70px;
+	margin-bottom: 15px;
+}
+body.activity-permalink .activity-list li .activity-content {
+	background: #fff;
+	border-bottom: 1px solid #ddd;
+	border-right: 1px solid #ddd;
+	-moz-border-radius: 4px;
+	-webkit-border-radius: 4px;
+	border-radius: 4px;
+	font-size: 16px;
+	line-height: 150%;
+	min-height: 35px;
+	margin-left: 185px;
+	margin-right: 0;
+	padding: 15px;
+}
+body.activity-permalink .activity-list li .activity-header > p {
+	background: url( ../images/activity_arrow.gif ) top left no-repeat;
+	height: 35px;
+	margin-bottom: 0;
+	margin-left: -35px;
+	padding: 5px 0 0 35px;
+}
+.activity-list .activity-content .activity-header,
+.activity-list .activity-content .comment-header {
+	color: #888;
+	font-size: 11px;
+	line-height: 220%;
+}
+.activity-header {
+	margin-right: 20px;
+}
+.activity-header a,
+.comment-meta a,
+.acomment-meta a {
+	text-decoration: none;
+}
+.activity-list .activity-content .activity-header img.avatar {
+	float: none !important;
+	margin: 0 5px -8px 0 !important;
+}
+a.bp-secondary-action,
+span.highlight {
+	font-size: 11px;
+	padding: 0;
+	margin-right: 5px;
+	text-decoration: none;
+}
+.activity-list .activity-content .activity-inner,
+.activity-list .activity-content blockquote {
+	margin: 10px 10px 5px 0;
+	overflow: hidden;
+}
+.activity-list li.new_forum_post .activity-content .activity-inner,
+.activity-list li.new_forum_topic .activity-content .activity-inner {
+	border-left: 2px solid #EAEAEA;
+	margin-left: 5px;
+	padding-left: 10px;
+}
+body.activity-permalink .activity-content .activity-inner,
+body.activity-permalink .activity-content blockquote {
+	margin-left: 0;
+	margin-top: 5px;
+}
+.activity-inner > p {
+	word-wrap: break-word;
+}
+.activity-inner > .activity-inner {
+	margin: 0 !important;
+}
+.activity-inner > blockquote {
+	margin: 0 !important;
+}
+.activity-list .activity-content img.thumbnail {
+	border: 2px solid #eee;
+	float: left;
+	margin: 0 10px 5px 0;
+}
+.activity-read-more {
+	margin-left: 1em;
+	white-space: nowrap;
+}
+.activity-list li.load-more {
+	background: #f0f0f0 !important;
+	border-right: 1px solid #ddd;
+	border-bottom: 1px solid #ddd;
+	-moz-border-radius: 4px;
+	-webkit-border-radius: 4px;
+	border-radius: 4px;
+	font-size: 1.2em;
+	margin: 15px 0 !important;
+	padding: 10px 15px !important;
+	text-align: center;
+}
+.activity-list li.load-more a {
+	color: #4D4D4D;
+}
+
+
+/*--------------------------------------------------------------
+6.1.2 - Activity Comments
+--------------------------------------------------------------*/
+div.activity-meta {
+	margin: 18px 0;
+}
+body.activity-permalink div.activity-meta {
+	margin-bottom: 6px;
+}
+div.activity-meta a {
+	font: normal 11px/20px Arial, Tahoma, Verdana, sans-serif;
+	padding: 4px 8px;
+}
+a.activity-time-since {
+	color: #aaa;
+	text-decoration: none;
+}
+a.activity-time-since:hover {
+	color: #888;
+	text-decoration: underline;
+}
+a.bp-primary-action,
+#reply-title small a {
+	font-size: 11px;
+	margin-right: 5px;
+	text-decoration: none;
+}
+a.bp-primary-action span,
+#reply-title small a span {
+	background: #999;
+	-moz-border-radius: 3px;
+	-webkit-border-radius: 3px;
+	border-radius: 3px;
+	color: #fff;
+	font-size: 90%;
+	margin-left: 2px;
+	padding: 0 5px;
+}
+a.bp-primary-action:hover span,
+#reply-title small a:hover span {
+	background: #555;
+	color: #fff;
+}
+div.activity-comments {
+	margin: 0 0 0 70px;
+	overflow: hidden; /* IE fix */
+	position: relative;
+	width: auto;
+	clear: both;
+}
+body.activity-permalink div.activity-comments {
+	background: none;
+	margin-left: 185px;
+	width: auto;
+}
+div.activity-comments > ul {
+	background: #f5f5f5;
+	-moz-border-radius: 4px;
+	-webkit-border-radius: 4px;
+	border-radius: 4px;
+	padding: 0 0 0 10px;
+}
+div.activity-comments ul,
+div.activity-comments ul li {
+	border: none;
+	list-style: none;
+}
+div.activity-comments ul {
+	clear: both;
+}
+div.activity-comments ul li {
+	border-top: 2px solid #fff;
+	padding: 10px 0 0;
+}
+body.activity-permalink .activity-list li.mini .activity-comments {
+	clear: none;
+	margin-top: 0;
+}
+body.activity-permalink div.activity-comments ul li {
+	border-width: 1px;
+	padding: 10px 0 0 0;
+}
+div.activity-comments > ul > li:first-child {
+	border-top: none;
+}
+div.activity-comments ul li:last-child {
+	margin-bottom: 0;
+}
+div.activity-comments ul li > ul {
+	margin-left: 30px;
+	margin-top: 0;
+	padding-left: 10px;
+}
+body.activity-permalink div.activity-comments ul li > ul {
+	margin-top: 10px;
+}
+body.activity-permalink div.activity-comments > ul {
+	padding: 0 10px 0 15px;
+}
+div.activity-comments div.acomment-avatar img {
+	border-width: 2px !important;
+	float: left;
+	height: 25px;
+	margin-right: 10px;
+	width: 25px;
+}
+div.activity-comments div.acomment-content {
+	font-size: 11px;
+	margin: 5px 0 0 40px;
+}
+div.acomment-content .time-since,
+div.acomment-content .activity-delete-link,
+div.acomment-content .comment-header {
+	display: none;
+}
+body.activity-permalink div.activity-comments div.acomment-content {
+	font-size: 14px;
+}
+div.activity-comments div.acomment-meta {
+	color: #888;
+	font-size: 11px;
+}
+div.activity-comments form.ac-form {
+	background: #fafafa;
+	border: 1px solid #ddd;
+	-moz-border-radius: 4px;
+	-webkit-border-radius: 4px;
+	border-radius: 4px;
+	display: none;
+	margin: 0 0 15px 33px;
+	padding: 8px;
+}
+div.activity-comments li form.ac-form {
+	margin-right: 15px;
+	clear: both;
+}
+div.activity-comments form.root {
+	margin-left: 0;
+}
+div.activity-comments div#message {
+	margin-top: 15px;
+	margin-bottom: 0;
+}
+div.activity-comments form.loading {
+	background-image: url( ../images/ajax-loader.gif );
+	background-position: 2% 95%;
+	background-repeat: no-repeat;
+}
+div.activity-comments form .ac-textarea {
+	background: #fff;
+	border: 1px inset #ccc;
+	-moz-border-radius: 3px;
+	-webkit-border-radius: 3px;
+	border-radius: 3px;
+	margin-bottom: 10px;
+	padding: 8px;
+}
+div.activity-comments form textarea {
+	border: none;
+	color: #555;
+	font-family: inherit;
+	font-size: 11px;
+	height: 60px;
+	padding: 0;
+	width: 100%;
+}
+div.activity-comments form input {
+	margin-top: 5px;
+}
+div.activity-comments form div.ac-reply-avatar {
+	float: left;
+}
+div.ac-reply-avatar img {
+	border: 2px solid #fff !important;
+}
+div.activity-comments form div.ac-reply-content {
+	color: #888;
+	font-size: 11px;
+	margin-left: 50px;
+	padding-left: 15px;
+}
+.acomment-options {
+	float: left;
+	margin: 5px 0 5px 40px;
+}
+.acomment-options a {
+	color: #999;
+}
+.acomment-options a:hover {
+	color: inherit;
+}
+
+
+/*--------------------------------------------------------------
+6.2 - Toolbar
+--------------------------------------------------------------*/
+#wp-admin-bar .padder {
+	width: 95% !important; /* Line up the Toolbar with the content body in this theme */
+}
+
+
+/*--------------------------------------------------------------
+6.3 - Directories - Members, Groups, Blogs, Forums
+--------------------------------------------------------------*/
+div.dir-search {
+	float: right;
+	margin: -39px 0 0 0;
+}
+div.dir-search input[type=text] {
+	font-size: 12px;
+	padding: 1px 3px;
+}
+
+
+/*--------------------------------------------------------------
+6.4 - Errors / Success Messages
+--------------------------------------------------------------*/
+div#message {
+	margin: 0 0 15px;
+}
+#message.info {
+	margin-bottom: 0;
+}
+div#message.updated {
+	clear: both;
+}
+div#message p {
+	font-size: 12px;
+	display: block;
+	padding: 10px 15px;
+}
+div#message.error p {
+	background-color: #db1717;
+	border-color: #a71a1a;
+	clear: left;
+	color: #fff;
+}
+div#message.updated p {
+	background-color: #8ff57a;
+	border-color: #80cf70;
+	color: #1a6a00;
+}
+.standard-form#signup_form div div.error {
+	background: #e41717;
+	-moz-border-radius: 3px;
+	-webkit-border-radius: 3px;
+	border-radius: 3px;
+	color: #fff;
+	margin: 0 0 10px 0;
+	padding: 6px;
+	width: 90%;
+}
+div.accept,
+div.reject {
+	float: left;
+	margin-left: 10px;
+}
+ul.button-nav li {
+	float: left;
+	margin: 0 10px 10px 0;
+}
+ul.button-nav li.current a {
+	font-weight: bold;
+}
+
+
+/*--------------------------------------------------------------
+6.5 - Forms
+--------------------------------------------------------------*/
+.standard-form textarea,
+.standard-form input[type=text],
+.standard-form input[type=color],
+.standard-form input[type=date],
+.standard-form input[type=datetime],
+.standard-form input[type=datetime-local],
+.standard-form input[type=email],
+.standard-form input[type=month],
+.standard-form input[type=number],
+.standard-form input[type=range],
+.standard-form input[type=search],
+.standard-form input[type=tel],
+.standard-form input[type=time],
+.standard-form input[type=url],
+.standard-form input[type=week],
+.standard-form select,
+.standard-form input[type=password],
+.dir-search input[type=search]
+.dir-search input[type=text] {
+	border: 1px inset #ccc;
+	-moz-border-radius: 3px;
+	-webkit-border-radius: 3px;
+	border-radius: 3px;
+	color: #888;
+	font: inherit;
+	font-size: 14px;
+	padding: 6px;
+}
+.standard-form select {
+	padding: 3px;
+}
+.standard-form input[type=password] {
+	margin-bottom: 5px;
+}
+.standard-form label,
+.standard-form span.label {
+	display: block;
+	font-weight: bold;
+	margin: 15px 0 5px 0;
+}
+.standard-form div.checkbox label,
+.standard-form div.radio label {
+	color: #888;
+	font-size: 14px;
+	font-weight: normal;
+	margin: 5px 0 0 0;
+}
+.standard-form#sidebar-login-form label {
+	margin-top: 5px;
+}
+.standard-form input[type=text] {
+	width: 75%;
+}
+.standard-form#sidebar-login-form input[type=text],
+.standard-form#sidebar-login-form input[type=password] {
+	padding: 4px;
+	width: 95%;
+}
+.standard-form #basic-details-section input[type=password],
+.standard-form #blog-details-section input#signup_blog_url {
+	width: 35%;
+}
+.standard-form#signup_form input[type=text],
+.standard-form#signup_form textarea,
+.form-allowed-tags,
+#commentform input[type=text],
+#commentform textarea {
+	width: 90%;
+}
+.standard-form#signup_form div.submit {
+	float: right;
+}
+div#signup-avatar img {
+	margin: 0 15px 10px 0;
+}
+.standard-form textarea {
+	width: 75%;
+	height: 120px;
+}
+.standard-form textarea#message_content {
+	height: 200px;
+}
+.standard-form#send-reply textarea {
+	width: 97.5%;
+}
+.standard-form p.description {
+	color: #888;
+	font-size: 11px;
+	margin: 5px 0;
+}
+.standard-form div.submit {
+	clear: both;
+	padding: 15px 0 0 0;
+}
+.standard-form p.submit {
+	margin-bottom: 0;
+	padding: 15px 0 0 0;
+}
+.standard-form div.submit input {
+	margin-right: 15px;
+}
+.standard-form div.radio ul {
+	margin: 10px 0 15px 38px;
+	list-style: disc;
+}
+.standard-form div.radio ul li {
+	margin-bottom: 5px;
+}
+.standard-form a.clear-value {
+	display: block;
+	margin-top: 5px;
+	outline: none;
+}
+.standard-form #basic-details-section,
+.standard-form #blog-details-section,
+.standard-form #profile-details-section {
+	float: left;
+	width: 48%;
+}
+.standard-form #profile-details-section {
+	float: right;
+}
+.standard-form #blog-details-section {
+	clear: left;
+}
+.standard-form input:focus,
+.standard-form textarea:focus,
+.standard-form select:focus {
+	background: #fafafa;
+	color: #555;
+}
+form#send-invite-form {
+	margin-top: 20px;
+}
+div#invite-list {
+	background: #f5f5f5;
+	border: 1px solid #e4e4e4;
+	-moz-border-radius: 3px;
+	-webkit-border-radius: 3px;
+	border-radius: 3px;
+	height: 400px;
+	margin: 0 0 10px;
+	overflow: auto;
+	padding: 5px;
+	width: 160px;
+}
+button,
+a.button,
+input[type=submit],
+input[type=button],
+input[type=reset],
+ul.button-nav li a,
+div.generic-button a,
+.comment-reply-link {
+	background: #fff; /* Old browsers */
+	background: -moz-linear-gradient(top, #ffffff 0%, #ededed 100%); /* FF3.6+ */
+	background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#ffffff), color-stop(100%,#ededed)); /* Chrome,Safari4+ */
+	background: -webkit-linear-gradient(top, #ffffff 0%,#ededed 100%); /* Chrome10+,Safari5.1+ */
+	background: -o-linear-gradient(top, #ffffff 0%,#ededed 100%); /* Opera11.10+ */
+	background: -ms-linear-gradient(top, #ffffff 0%,#ededed 100%); /* IE10+ */
+	filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#ffffff', endColorstr='#ededed',GradientType=0 ); /* IE6-9 */
+	background: linear-gradient(top, #ffffff 0%,#ededed 100%); /* W3C */
+	border: 1px solid #ccc;
+	-moz-border-radius: 3px;
+	-webkit-border-radius: 3px;
+	border-radius: 3px;
+	color: #777;
+	cursor: pointer;
+	font: normal 12px/20px Arial, Tahoma, Verdana, sans-serif;
+	outline: none;
+	padding: 4px 10px;
+	text-align: center;
+	text-decoration: none;
+	line-height: 14px;
+}
+button:hover,
+a.button:hover,
+a.button:focus,
+input[type=submit]:hover,
+input[type=button]:hover,
+input[type=reset]:hover,
+ul.button-nav li a:hover,
+ul.button-nav li.current a,
+div.generic-button a:hover,
+.comment-reply-link:hover {
+	background: #ededed;
+	background: -moz-linear-gradient(top, #ffffff 0%, #e0e0e0 100%); /* FF3.6+ */
+	background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#ffffff), color-stop(100%,#e0e0e0)); /* Chrome,Safari4+ */
+	background: -webkit-linear-gradient(top, #ffffff 0%,#e0e0e0 100%); /* Chrome10+,Safari5.1+ */
+	background: -o-linear-gradient(top, #ffffff 0%,#e0e0e0 100%); /* Opera11.10+ */
+	background: -ms-linear-gradient(top, #ffffff 0%,#e0e0e0 100%); /* IE10+ */
+	filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#ffffff', endColorstr='#e0e0e0',GradientType=0 ); /* IE6-9 */
+	background: linear-gradient(top, #ffffff 0%,#e0e0e0 100%); /* W3C */
+	border: 1px solid #bbb;
+	color: #555;
+	outline: none;
+	text-decoration: none;
+}
+
+/*--------------------------------------------------------------
+6.6 - Ajax Loading
+--------------------------------------------------------------*/
+a.loading,
+input.loading {
+    background-image: url( ../images/ajax-loader.gif );
+    background-position: 95% 50%;
+    background-repeat: no-repeat;
+    padding-right: 25px;
+}
+a.loading:hover,
+input.loading:hover {
+    background-image: url( ../images/ajax-loader.gif );
+    background-position: 95% 50%;
+    background-repeat: no-repeat;
+    padding-right: 25px;
+    color: #777;
+}
+a.button.loading,
+input[type="submit"].loading,
+input[type="button"].loading,
+input[type="reset"].loading {
+	background-image: url( ../images/ajax-loader.gif ), -moz-linear-gradient(top, #ffffff 0%, #e0e0e0 100%); /* FF3.6+ */
+	background-image: url( ../images/ajax-loader.gif ), -webkit-gradient(linear, left top, left bottom, color-stop(0%,#ffffff), color-stop(100%,#e0e0e0)); /* Chrome,Safari4+ */
+	background-image: url( ../images/ajax-loader.gif ), -webkit-linear-gradient(top, #ffffff 0%,#e0e0e0 100%); /* Chrome10+,Safari5.1+ */
+	background-image: url( ../images/ajax-loader.gif ), -o-linear-gradient(top, #ffffff 0%,#e0e0e0 100%); /* Opera11.10+ */
+	background-image: url( ../images/ajax-loader.gif ), -ms-linear-gradient(top, #ffffff 0%,#e0e0e0 100%); /* IE10+ */
+	filter: progid:DXImageTransform.Microsoft.gradient( enabled=0 ); /* IE6-9 */
+	background-image: url( ../images/ajax-loader.gif ), linear-gradient(top, #ffffff 0%,#e0e0e0 100%); /* W3C */
+	background-position: 95% 50%;
+	background-repeat: no-repeat;
+	padding-right: 25px;
+}
+a.button.loading:hover,
+input[type="submit"].loading:hover,
+input[type="button"].loading:hover,
+input[type="reset"].loading:hover {
+  	background-image: url( ../images/ajax-loader.gif ), -moz-linear-gradient(top, #ffffff 0%, #e0e0e0 100%); /* FF3.6+ */
+	background-image: url( ../images/ajax-loader.gif ), -webkit-gradient(linear, left top, left bottom, color-stop(0%,#ffffff), color-stop(100%,#e0e0e0)); /* Chrome,Safari4+ */
+	background-image: url( ../images/ajax-loader.gif ), -webkit-linear-gradient(top, #ffffff 0%,#e0e0e0 100%); /* Chrome10+,Safari5.1+ */
+	background-image: url( ../images/ajax-loader.gif ), -o-linear-gradient(top, #ffffff 0%,#e0e0e0 100%); /* Opera11.10+ */
+	background-image: url( ../images/ajax-loader.gif ), -ms-linear-gradient(top, #ffffff 0%,#e0e0e0 100%); /* IE10+ */
+	filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#ffffff', endColorstr='#e0e0e0',GradientType=0 ); /* IE6-9 */
+	background-image: url( ../images/ajax-loader.gif ), linear-gradient(top, #ffffff 0%,#e0e0e0 100%); /* W3C */
+	border: 1px solid #ccc;
+	padding-right: 25px;
+}
+input[type="submit"].pending,
+input[type="button"].pending,
+input[type="reset"].pending,
+input[type="submit"].disabled,
+input[type="button"].disabled,
+input[type="reset"].disabled,
+button.pending,
+button.disabled,
+div.pending a,
+a.disabled {
+    border-color: #eee;
+    color: #bbb;
+    cursor: default;
+}
+input[type="submit"]:hover.pending,
+input[type="button"]:hover.pending,
+input[type="reset"]:hover.pending,
+input[type="submit"]:hover.disabled,
+input[type="button"]:hover.disabled,
+input[type="reset"]:hover.disabled,
+button.pending:hover,
+button.disabled:hover,
+div.pending a:hover,
+a.disabled:hover {
+	background: -moz-linear-gradient(top, #ffffff 0%, #ededed 100%); /* FF3.6+ */
+	background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#ffffff), color-stop(100%,#ededed)); /* Chrome,Safari4+ */
+	background: -webkit-linear-gradient(top, #ffffff 0%,#ededed 100%); /* Chrome10+,Safari5.1+ */
+	background: -o-linear-gradient(top, #ffffff 0%,#ededed 100%); /* Opera11.10+ */
+	background: -ms-linear-gradient(top, #ffffff 0%,#ededed 100%); /* IE10+ */
+	filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#ffffff', endColorstr='#ededed',GradientType=0 ); /* IE6-9 */
+	background: linear-gradient(top, #ffffff 0%,#ededed 100%); /* W3C */
+    border-color: #eee;
+    color: #bbb;
+}
+
+
+/*--------------------------------------------------------------
+6.7 - Forums, Tables and Topics
+--------------------------------------------------------------*/
+ul#topic-post-list {
+	margin: 0px -19px 15px;
+	width: auto;
+}
+ul#topic-post-list li {
+	padding: 15px;
+	position: relative;
+}
+ul#topic-post-list li.alt {
+	background: #f5f5f5;
+}
+ul#topic-post-list li div.poster-meta {
+	color: #888;
+	margin-bottom: 10px;
+}
+ul#topic-post-list li div.post-content {
+	margin-left: 54px;
+}
+div.topic-tags {
+	font-size: 11px;
+}
+div.admin-links {
+	color: #888;
+	font-size: 11px;
+	position: absolute;
+	top: 15px;
+	right: 25px;
+}
+div#topic-meta {
+	margin: -10px -19px;
+	padding: 5px 19px 30px;
+	position: relative;
+}
+div#topic-meta div.admin-links {
+	right: 19px;
+	top: -36px;
+}
+div#topic-meta h3 {
+	font-size: 20px;
+	margin: 5px 0;
+}
+div#new-topic-post {
+	display: none;
+	margin: 20px 0 0 0;
+	padding: 1px 0 0 0;
+}
+table {
+	width: 100%;
+}
+table thead tr {
+	background: #eaeaea;
+}
+table#message-threads {
+	margin: 0 -19px;
+	width: auto;
+}
+table.profile-fields {
+	margin-bottom: 20px;
+}
+table.profile-fields:last-child {
+	margin-bottom: 0;
+}
+table.profile-fields p {
+	margin-top: 15px;
+}
+table.profile-fields p:last-child {
+	margin-top: 0;
+}
+div#sidebar table {
+	margin: 0 -16px;
+	width: 117%;
+}
+table tr td,
+table tr th {
+	padding: 8px;
+	vertical-align: middle;
+}
+table tr td.label {
+	border-right: 1px solid #eaeaea;
+	font-weight: bold;
+	width: 25%;
+}
+table tr td.thread-info p {
+	margin: 0;
+}
+table tr td.thread-info p.thread-excerpt {
+	color: #888;
+	font-size: 11px;
+	margin-top: 3px;
+}
+div#sidebar table td,
+table.forum td {
+	text-align: center;
+}
+table tr.alt td {
+	background: #f5f5f5;
+}
+table.notification-settings {
+	margin-bottom: 20px;
+	text-align: left;
+}
+#groups-notification-settings {
+	margin-bottom: 0;
+}
+table.notification-settings th.icon,
+table.notification-settings td:first-child {
+	display: none;
+}
+table.notification-settings th.title {
+	width: 80%;
+}
+table.notification-settings .yes,
+table.notification-settings .no {
+	text-align: center;
+	width: 40px;
+}
+table.forum {
+	margin: 0 -19px;
+	width: auto;
+}
+table.forum tr.sticky td {
+	font-size: 1.2em;
+	background: #fff9db;
+	border-top: 1px solid #ffe8c4;
+	border-bottom: 1px solid #ffe8c4;
+}
+table.forum tr.closed td.td-title {
+	background-image: url( ../images/closed.png );
+	background-position: 15px 50%;
+	background-repeat: no-repeat;
+	padding-left: 35px;
+}
+table.forum td p.topic-text {
+	color: #888;
+	font-size: 13px;
+}
+table.forum tr > td:first-child,
+table.forum tr > th:first-child {
+	padding-left: 15px;
+}
+table.forum tr > td:last-child,
+table.forum tr > th:last-child {
+	padding-right: 15px;
+}
+table.forum tr th#th-title,
+table.forum tr th#th-poster,
+table.forum tr th#th-group,
+table.forum td.td-poster,
+table.forum td.td-group,
+table.forum td.td-title {
+	text-align: left;
+}
+table.forum tr td.td-title a.topic-title {
+	font-size: 1.2em;
+}
+table.forum td.td-freshness {
+	white-space: nowrap;
+}
+table.forum td.td-freshness span.time-since {
+	font-size: 0.9em;
+	color: #888;
+}
+table.forum td img.avatar {
+	float: none;
+	margin: 0 5px -8px 0;
+}
+table.forum td.td-poster,
+table.forum td.td-group {
+	min-width: 140px;
+}
+table.forum th#th-title {
+	width: 80%;
+}
+table.forum th#th-freshness {
+	width: 25%;
+}
+table.forum th#th-postcount {
+	width: 15%;
+}
+table.forum p.topic-meta {
+	font-size: 0.9em;
+	margin: 5px 0 0 0;
+}
+
+/*-------------------------------------------------------------------------
+6.8 - Headers, Lists and Tabs - Activity, Groups, Blogs, Forums, Profiles
+-------------------------------------------------------------------------*/
+.item-body {
+	margin: 20px 0;
+}
+span.activity {
+	display: inline-block;
+	font-size: 11px;
+	opacity: 0.8;
+	padding: 1px 8px;
+}
+span.user-nicename {
+	color: #777;
+	display: inline-block;
+	font-size: 16px;
+	font-weight: bold;
+}
+span.activity,
+div#message p {
+	border: 1px solid #e1ca82;
+	-moz-border-radius: 3px;
+	-webkit-border-radius: 3px;
+	border-radius: 3px;
+	font-weight: normal;
+	margin-top: 3px;
+	text-decoration: none;
+	background: #ffeaa6;
+	background-image: -webkit-linear-gradient(rgba(255, 255, 255, .5), rgba(255, 255, 255, 0));
+	background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%,rgba(255, 255, 255, .5)), color-stop(100%,rgba(255, 255, 255, 0))); /* Chrome,Safari4+ */
+	background-image: -moz-linear-gradient(rgba(255, 255, 255, .5), rgba(255, 255, 255, 0));
+	background-image: -ms-linear-gradient(rgba(255, 255, 255, .5), rgba(255, 255, 255, 0));
+	background-image: -o-linear-gradient(rgba(255, 255, 255, .5), rgba(255, 255, 255, 0));
+	background-image: linear-gradient(rgba(255, 255, 255, .5), rgba(255, 255, 255, 0));
+}
+div#item-header {
+	overflow: hidden;
+}
+div#item-header div#item-header-content {
+	margin-left: 170px;
+}
+div#item-header h2 {
+	font-size: 28px;
+	line-height: 120%;
+	margin: 0 0 15px 0;
+}
+div#item-header h2 a {
+	color: #777;
+	text-decoration: none;
+}
+div#item-header img.avatar {
+	float: left;
+	margin: 0 15px 19px 0;
+}
+div#item-header h2 {
+	margin-bottom: 5px;
+}
+div#item-header span.activity,
+div#item-header h2 span.highlight {
+	font-size: 11px;
+	font-weight: normal;
+	line-height: 170%;
+	margin-bottom: 7px;
+	vertical-align: middle;
+}
+div#item-header h2 span.highlight {
+	font-size: 16px;
+}
+div#item-header h2 span.highlight span {
+	background: #a1dcfa;
+	-moz-border-radius: 3px;
+	-webkit-border-radius: 3px;
+	border-radius: 3px;
+	color: #fff;
+	cursor: pointer;
+	font-weight: bold;
+	font-size: 11px;
+	margin-bottom: 2px;
+	padding: 1px 4px;
+	position: relative;
+	right: -2px;
+	top: -2px;
+	vertical-align: middle;
+}
+div#item-header div#item-meta {
+	font-size: 14px;
+	color: #aaa;
+	overflow: hidden;
+	margin: 15px 0 5px 0;
+	padding-bottom: 10px;
+}
+div#item-header div#item-actions {
+	float: right;
+	margin: 0 0 15px 15px;
+	text-align: right;
+	width: 20%;
+}
+div#item-header div#item-actions h3 {
+	font-size: 12px;
+	margin: 0 0 5px 0;
+}
+div#item-header ul {
+	margin-bottom: 15px;
+	overflow: hidden;
+}
+div#item-header ul h5,
+div#item-header ul span,
+div#item-header ul hr {
+	display: none;
+}
+div#item-header ul li {
+	float: right;
+}
+div#item-header ul img.avatar,
+div#item-header ul.avatars img.avatar {
+	height: 30px;
+	margin: 2px;
+	width: 30px;
+}
+div#item-header div.generic-button,
+div#item-header a.button {
+	float: left;
+	margin: 10px 10px 0 0;
+}
+div#item-header div#message.info {
+	line-height: 80%;
+}
+ul.item-list {
+	width: 100%;
+}
+ul.item-list li {
+	border-bottom: 1px solid #eaeaea;
+	padding: 15px 0;
+	position: relative;
+}
+ul.item-list.activity-list li {
+	padding-bottom: 0;
+}
+ul.single-line li {
+	border: none;
+}
+ul.item-list li img.avatar {
+	float: left;
+	margin: 0 10px 0 0;
+}
+ul.item-list li div.item-title,
+ul.item-list li h4 {
+	font-weight: normal;
+	font-size: 14px;
+	margin: 0;
+	width: 75%;
+}
+ul.item-list li div.item-title span {
+	color: #999;
+	font-size: 12px;
+}
+ul.item-list li div.item-desc {
+	color: #888;
+	font-size: 11px;
+	margin: 10px 0 0 64px;
+	width: 50%;
+}
+ul.item-list li div.action {
+	position: absolute;
+	top: 15px;
+	right: 0;
+	text-align: right;
+}
+ul.item-list li div.meta {
+	color: #888;
+	font-size: 11px;
+	margin-top: 10px;
+}
+ul.item-list li h5 span.small {
+	float: right;
+	font-size: 11px;
+	font-weight: normal;
+}
+div.item-list-tabs {
+	background: #eaeaea;
+	clear: left;
+	margin: 25px -19px 20px -19px;
+	overflow: hidden;
+}
+div.item-list-tabs ul li a {
+	text-decoration: none;
+	height: 20px;
+}
+div.item-list-tabs ul {
+	width: 100%;
+}
+div.item-list-tabs ul li {
+	float: left;
+	margin: 5px 0 0 5px;
+}
+div.item-list-tabs#subnav ul li {
+	margin-top: 0;
+}
+div.item-list-tabs ul li:first-child {
+	margin-left: 20px;
+}
+div.item-list-tabs ul li.last {
+	float: right;
+	margin: 7px 20px 0 0;
+}
+div.item-list-tabs#subnav ul li.last {
+	margin-top: 4px;
+}
+div.item-list-tabs ul li.last select {
+	max-width: 175px;
+}
+div.item-list-tabs ul li a,
+div.item-list-tabs ul li span {
+	display: block;
+	padding: 5px 10px;
+	text-decoration: none;
+}
+div.item-list-tabs ul li a span {
+	background: #1fb3dd;
+	-moz-border-radius: 3px;
+	-webkit-border-radius: 3px;
+	border-radius: 3px;
+	color: #fff;
+	display: inline;
+	font-size: 90%;
+	margin-left: 2px;
+	padding: 1px 6px;
+}
+div.item-list-tabs ul li.selected a,
+div.item-list-tabs ul li.current a {
+	background-color: #fff;
+	-moz-border-radius-topleft: 3px;
+	-webkit-border-top-left-radius: 3px;
+	-moz-border-radius-topright: 3px;
+	-webkit-border-top-right-radius: 3px;
+	border-top-left-radius: 3px;
+	border-top-right-radius: 3px;
+	color: #555;
+	font-weight: bold;
+}
+div.item-list-tabs ul li.selected a span,
+div.item-list-tabs ul li.current a span,
+div.item-list-tabs ul li a:hover span {
+	background-color: #999;
+}
+div.item-list-tabs ul li.selected a span,
+div.item-list-tabs ul li.current a span {
+	background-color: #555;
+}
+ul li.loading a {
+	background-image: url( ../images/ajax-loader.gif );
+	background-position: 92% 50%;
+	background-repeat: no-repeat;
+	padding-right: 30px !important;
+}
+div#item-nav ul li.loading a {
+	background-position: 88% 50%;
+}
+div.item-list-tabs#object-nav {
+	margin-top: 0;
+}
+div.item-list-tabs#subnav {
+	background: #fff;
+	border-bottom: 1px solid #eaeaea;
+	margin: -15px -19px 15px -19px;
+	min-height: 35px;
+	overflow: hidden;
+}
+div.item-list-tabs ul li.feed a {
+	background: url( ../images/rss.png ) center left no-repeat;
+	padding-left: 20px;
+}
+#admins-list li,
+#mods-list li,
+#members-list li {
+	overflow: auto;
+}
+
+
+/*--------------------------------------------------------------
+6.9 - Private Messaging Threads
+--------------------------------------------------------------*/
+table#message-threads tr.unread td {
+	background: #fff9db;
+	border-top: 1px solid #ffe8c4;
+	border-bottom: 1px solid #ffe8c4;
+	font-weight: bold;
+}
+li span.unread-count,
+tr.unread span.unread-count {
+	background: #dd0000;
+	-moz-border-radius: 3px;
+	-webkit-border-radius: 3px;
+	border-radius: 3px;
+	color: #fff;
+	font-weight: bold;
+	padding: 2px 8px;
+}
+div.item-list-tabs ul li a span.unread-count {
+	padding: 1px 6px;
+	color: #fff;
+}
+div.messages-options-nav {
+	background: #eee;
+	font-size: 11px;
+	margin: 0 -19px;
+	padding: 5px 15px;
+	text-align: right;
+}
+div#message-thread div.message-box {
+	margin: 0 -19px;
+	padding: 15px;
+}
+div#message-thread div.alt {
+	background: #f4f4f4;
+}
+div#message-thread p#message-recipients {
+	margin: 10px 0 20px 0;
+}
+div#message-thread img.avatar {
+	float: left;
+	margin: 0 10px 0 0;
+	vertical-align: middle;
+}
+div#message-thread strong {
+	font-size: 16px;
+	margin: 0;
+}
+div#message-thread strong a {
+	text-decoration: none;
+}
+div#message-thread strong span.activity {
+	margin: 4px 0 0 10px;
+}
+div#message-thread div.message-metadata {
+	overflow: hidden;
+}
+div#message-thread div.message-content {
+	margin-left: 45px;
+}
+div#message-thread div.message-options {
+	text-align: right;
+}
+
+div.message-search {
+	float: right;
+	margin: 0 20px;
+}
+
+/*--------------------------------------------------------------
+6.9 - Extended Profiles
+--------------------------------------------------------------*/
+
+div.profile h4 {
+	margin-bottom: auto;
+	margin-top: 15px;
+}
+#profile-edit-form ul.button-nav {
+	margin-top: 15px;
+}
+body.no-js .field-visibility-settings-toggle,
+body.no-js .field-visibility-settings-close {
+	display: none;
+}
+.field-visibility-settings {
+	display: none;
+	margin-top: 10px;
+}
+	body.no-js .field-visibility-settings {
+		display: block;
+	}
+.current-visibility-level {
+	font-weight: bold;
+	font-style: normal;
+}
+.field-visibility-settings,
+.field-visibility-settings-toggle,
+.field-visibility-settings-notoggle {
+	color: #888;
+}
+.field-visibility-settings-toggle a,
+.field-visibility-settings a {
+	font-size: .9em;
+}
+body.register div.page ul {
+	list-style: none;
+}
+.standard-form .field-visibility-settings label {
+	margin: 0;
+	font-weight: normal;
+}
+.field-visibility-settings legend,
+.field-visibility-settings-toggle {
+	font-style: italic;
+}
Index: /tags/1.9/bp-themes/bp-default/_inc/css/responsive-rtl.css
===================================================================
--- /tags/1.9/bp-themes/bp-default/_inc/css/responsive-rtl.css	(revision 7684)
+++ /tags/1.9/bp-themes/bp-default/_inc/css/responsive-rtl.css	(revision 7684)
@@ -0,0 +1,54 @@
+/*--------------------------------------------------------------
+Hello, this is the BuddyPress Reponsive theme rtl stylesheet.
+Right to left styles. This will transform the theme to read from
+right to left for languages that support this method.
+
+----------------------------------------------------------------
+>>> TABLE OF CONTENTS:
+----------------------------------------------------------------
+1.0 - iPad
+	1.1 - Landscape
+	1.2 - Portrait
+2.0 - iPhone
+--------------------------------------------------------------*/
+
+/*--------------------------------------------------------------
+1.1 - iPad Landscape
+--------------------------------------------------------------*/
+@media only screen and (max-width: 768px) {
+	div#content .padder {
+		margin-left: 0;
+		margin-right: auto;
+	}
+	ul#nav li {
+		margin-left: 0;
+		margin-right: auto;
+	}
+	ul#nav li:nth-child(even) {
+		margin-left: 0;
+		margin-right: 3%;
+	}
+}
+
+
+/*--------------------------------------------------------------
+1.2 - iPad Portrait
+--------------------------------------------------------------*/
+@media only screen and (max-width: 640px) {
+	ul.item-list li div.action {
+		padding-left: auto;
+		padding-right: 64px;
+	}
+}
+
+
+/*--------------------------------------------------------------
+2.0 - iPhone
+--------------------------------------------------------------*/
+@media only screen and (max-width: 320px) {
+	div.post div.post-content,
+	div.comment-content {
+		margin-left: auto;
+		margin-right: 0px;
+	}
+}
Index: /tags/1.9/bp-themes/bp-default/_inc/css/responsive.css
===================================================================
--- /tags/1.9/bp-themes/bp-default/_inc/css/responsive.css	(revision 7684)
+++ /tags/1.9/bp-themes/bp-default/_inc/css/responsive.css	(revision 7684)
@@ -0,0 +1,283 @@
+/*--------------------------------------------------------------
+Hello, this is the BuddyPress Responsive theme stylesheet
+
+----------------------------------------------------------------
+>>> TABLE OF CONTENTS:
+----------------------------------------------------------------
+1.0 - iPad
+	1.1 - Landscape
+	1.2 - Portrait
+2.0 - Smartphone
+3.0 - iPhone
+--------------------------------------------------------------*/
+
+/*--------------------------------------------------------------
+1.1 - iPad Landscape
+--------------------------------------------------------------*/
+@media only screen and (max-width: 768px) {
+	html {
+		background-color: #eaeaea;
+	}
+	body {
+		margin-top: -28px !important;
+		background: #eaeaea;
+	}
+	#wpadminbar {
+		display: none;
+	}
+	div#content .padder {
+		margin-right: 0;
+		width: auto;
+		float: none;
+		border: none;
+	}
+	div#sidebar {
+		width: auto;
+		float: none;
+		margin: 2em 0 0 0;
+		border: none;
+	}
+	ul#nav {
+		padding-bottom: 1em;
+	}
+	ul#nav li {
+		width: 46%;
+		margin-bottom: 1em;
+		margin-right: 0;
+	}
+	ul#nav li:nth-child(even) {
+		margin-left: 3%;
+		margin-right: 0;
+	}
+	ul#nav li a {
+		-moz-border-radius: 0.25em;
+		-webkit-border-radius: 0.25em;
+		border-radius: 0.25em;
+		margin-bottom: 0;
+	}
+	.wp-caption {
+		width: 99% !important;
+	}
+	.entry {
+		width: 100%;
+	}
+	.entry img {
+		max-width: 100%;
+		height: auto;
+	}
+	.wp-caption img {
+		max-width: 99%;
+		height: auto;
+	}
+	#footer-widgets {
+		padding: 19px 10px;
+	}
+}
+
+
+/*--------------------------------------------------------------
+1.2 - iPad Portrait
+--------------------------------------------------------------*/
+@media only screen and (max-width: 640px) {
+	div.dir-search {
+		float: none;
+		margin: 1.25em 0 0;
+	}
+	ul.item-list li div.action {
+		padding-left: 64px;
+		position: relative;
+		right: auto;
+		text-align: left;
+		top: 1em;
+		margin-bottom: 1.25em;
+	}
+	.wp-caption {
+		width: 99% !important;
+	}
+	.entry {
+		width: 100%;
+	}
+	.entry img {
+		max-width: 100%;
+		height: auto;
+	}
+	.wp-caption img {
+		max-width: 99%;
+		height: auto;
+	}
+	#footer-widget-area div.widget-area > ul {
+		float: left;
+		width: 100%;
+	}
+	#footer-widgets {
+		padding: 19px 10px;
+	}
+}
+
+
+/*--------------------------------------------------------------
+2.0 - Smartphone (any)
+--------------------------------------------------------------*/
+@media screen and (max-device-width: 480px), screen and (-webkit-min-device-pixel-ratio: 2) {
+	-webkit-text-size-adjust: none;
+}
+
+@media only screen and (max-width: 480px) {
+	body {
+		width: 100%;
+		margin: 0;
+	}
+	#container {
+		border: none;
+	}
+	div.item-list-tabs ul li {
+		float: none;
+		margin: 0.3em 0.6em;
+		background:none;
+	}
+	div.item-list-tabs ul li.last {
+		float: none;
+		margin: 0.3em 0.6em;
+	}
+	div#subnav.item-list-tabs ul li.last {
+		margin-top: 1em;
+	}
+	div.item-list-tabs ul li.selected,
+	div.item-list-tabs ul li.current {
+		margin: 0.3em 0.6em;
+	}
+	div.item-list-tabs ul li.selected a,
+	div.item-list-tabs ul li.current a {
+		background: #eee;
+		font-weight: bold;
+	}
+	div.item-list-tabs {
+		background: none;
+	}
+	div.item-list-tabs ul li:first-child {
+		margin: 0.6em 0.6em 0.5em 0.6em;
+	}
+	div.item-list-tabs ul li a,
+	div.item-list-tabs ul li span {
+		padding: 0.3em;
+	}
+	div#subnav ul {
+		padding-top: 0.6em;
+	}
+	div.pagination {
+		padding: 0.6em;
+	}
+	div.item-list-tabs ul {
+		border-top: 1px solid #EAEAEA;
+		padding-top: 0;
+	}
+	div.item-list-tabs ul li {
+		margin-top: 0;
+	}
+	form.standard-form #basic-details-section,
+	form.standard-form #blog-details-section,
+	form.standard-form #profile-details-section {
+		float: none;
+		width: 100%;
+	}
+ 	.wp-caption {
+		width: 99% !important;
+ 	}
+ 	.entry {
+		width: 100%;
+ 	}
+ 	.entry img {
+		max-width: 100%;
+		height: auto;
+ 	}
+ 	.wp-caption img {
+		max-width: 99%;
+		height: auto;
+ 	}
+	#footer-widget-area div.widget-area > ul {
+		float: left;
+		width: 100%;
+	}
+	#footer-widgets {
+		padding: 19px 10px;
+	}
+}
+
+
+/*--------------------------------------------------------------
+3.0 - iPhone
+--------------------------------------------------------------*/
+@media only screen and (max-width: 320px) {
+	ul#nav li {
+		float: none;
+		width: 100%;
+		margin-bottom: 0.6em;
+		margin-right: 0;
+		margin-left: 0;
+	}
+	ul#nav li:nth-child(even) {
+		margin-left: 0;
+		margin-right: 0;
+	}
+	ul#nav li a {
+		-moz-border-radius: 0.25em;
+		-webkit-border-radius: 0.25em;
+		border-radius: 0.25em;
+		margin-bottom: 0;
+	}
+	form#groups-directory-form h3 a {
+		display: block;
+		margin-top: 0.6em;
+	}
+	div.post div.author-box,
+	div.comment-avatar-box {
+		display: none;
+	}
+	div.post div.post-content,
+	div.comment-content {
+		margin-left: 0px;
+	}
+	form#whats-new-form div#whats-new-avatar {
+		display:none;
+	}
+	form#whats-new-form h5 {
+		margin: 0 0 0 0px;
+	}
+	form#whats-new-form #whats-new-content {
+		margin-left: 0px;
+		padding-left: 0px;
+	}
+	ul#activity-stream.item-list li div.activity-avatar {
+		display: none;
+	}
+	body.activity-permalink .activity-list li .activity-content {
+		margin-left: 0;
+	}
+	body.activity-permalink .activity-list li.mini .activity-meta {
+		left: 0;
+	}
+ 	div.post .entry {
+		width: 100%;
+ 	}
+ 	.wp-caption {
+		width: 99%!important;
+ 	}
+ 	.entry {
+		width: 100%;
+ 	}
+ 	.entry img {
+		width: 100%;
+		height: auto;
+ 	}
+ 	.wp-caption img {
+		width: 99%;
+		height: auto;
+ 	}
+ 	#footer-widget-area div.widget-area > ul {
+		float: left;
+		width: 100%;
+ 	}
+ 	#footer-widgets {
+		padding: 19px 10px;
+	}
+}
Index: /tags/1.9/bp-themes/bp-default/_inc/global.js
===================================================================
--- /tags/1.9/bp-themes/bp-default/_inc/global.js	(revision 7684)
+++ /tags/1.9/bp-themes/bp-default/_inc/global.js	(revision 7684)
@@ -0,0 +1,1579 @@
+// AJAX Functions
+var jq = jQuery;
+
+// Global variable to prevent multiple AJAX requests
+var bp_ajax_request = null;
+
+jq(document).ready( function() {
+	/**** Page Load Actions *******************************************************/
+
+	/* Hide Forums Post Form */
+	if ( '-1' == window.location.search.indexOf('new') && jq('div.forums').length )
+		jq('#new-topic-post').hide();
+	else
+		jq('#new-topic-post').show();
+
+	/* Activity filter and scope set */
+	bp_init_activity();
+
+	/* Object filter and scope set. */
+	var objects = [ 'members', 'groups', 'blogs', 'forums' ];
+	bp_init_objects( objects );
+
+	/* @mention Compose Scrolling */
+	if ( jq.query.get('r') && jq('textarea#whats-new').length ) {
+		jq('#whats-new-options').animate({
+			height:'40px'
+		});
+		jq("form#whats-new-form textarea").animate({
+			height:'50px'
+		});
+		jq.scrollTo( jq('textarea#whats-new'), 500, {
+			offset:-125,
+			easing:'easeOutQuad'
+		} );
+		jq('textarea#whats-new').focus();
+	}
+
+	/**** Activity Posting ********************************************************/
+
+	/* Textarea focus */
+	jq('#whats-new').focus( function(){
+		jq("#whats-new-options").animate({
+			height:'40px'
+		});
+		jq("form#whats-new-form textarea").animate({
+			height:'50px'
+		});
+		jq("#aw-whats-new-submit").prop("disabled", false);
+
+		var $whats_new_form = jq("form#whats-new-form");
+		if ( $whats_new_form.hasClass("submitted") ) {
+			$whats_new_form.removeClass("submitted");	
+		}
+	});
+
+	/* On blur, shrink if it's empty */
+	jq('#whats-new').blur( function(){
+		if (!this.value.match(/\S+/)) {
+			this.value = "";
+			jq("#whats-new-options").animate({
+				height:'40px'
+			});
+			jq("form#whats-new-form textarea").animate({
+				height:'20px'
+			});
+			jq("#aw-whats-new-submit").prop("disabled", true);
+		}
+	});
+
+	/* New posts */
+	jq("input#aw-whats-new-submit").click( function() {
+		var button = jq(this);
+		var form = button.closest("form#whats-new-form");
+
+		form.children().each( function() {
+			if ( jq.nodeName(this, "textarea") || jq.nodeName(this, "input") )
+				jq(this).prop( 'disabled', true );
+		});
+
+		/* Remove any errors */
+		jq('div.error').remove();
+		button.addClass('loading');
+		button.prop('disabled', true);
+		form.addClass("submitted");
+
+		/* Default POST values */
+		var object = '';
+		var item_id = jq("#whats-new-post-in").val();
+		var content = jq("textarea#whats-new").val();
+
+		/* Set object for non-profile posts */
+		if ( item_id > 0 ) {
+			object = jq("#whats-new-post-object").val();
+		}
+
+		jq.post( ajaxurl, {
+			action: 'post_update',
+			'cookie': bp_get_cookies(),
+			'_wpnonce_post_update': jq("input#_wpnonce_post_update").val(),
+			'content': content,
+			'object': object,
+			'item_id': item_id,
+			'_bp_as_nonce': jq('#_bp_as_nonce').val() || ''
+		},
+		function(response) {
+
+			form.children().each( function() {
+				if ( jq.nodeName(this, "textarea") || jq.nodeName(this, "input") ) {
+					jq(this).prop( 'disabled', false );
+				}
+			});
+
+			/* Check for errors and append if found. */
+			if ( response[0] + response[1] == '-1' ) {
+				form.prepend( response.substr( 2, response.length ) );
+				jq( 'form#' + form.attr('id') + ' div.error').hide().fadeIn( 200 );
+			} else {
+				if ( 0 == jq("ul.activity-list").length ) {
+					jq("div.error").slideUp(100).remove();
+					jq("div#message").slideUp(100).remove();
+					jq("div.activity").append( '<ul id="activity-stream" class="activity-list item-list">' );
+				}
+
+				jq("ul#activity-stream").prepend(response);
+				jq("ul#activity-stream li:first").addClass('new-update just-posted');
+
+				if ( 0 != jq("#latest-update").length ) {
+					var l = jq("ul#activity-stream li.new-update .activity-content .activity-inner p").html();
+					var v = jq("ul#activity-stream li.new-update .activity-content .activity-header p a.view").attr('href');
+
+					var ltext = jq("ul#activity-stream li.new-update .activity-content .activity-inner p").text();
+
+					var u = '';
+					if ( ltext != '' )
+						u = l + ' ';
+
+					u += '<a href="' + v + '" rel="nofollow">' + BP_DTheme.view + '</a>';
+
+					jq("#latest-update").slideUp(300,function(){
+						jq("#latest-update").html( u );
+						jq("#latest-update").slideDown(300);
+					});
+				}
+
+				jq("li.new-update").hide().slideDown( 300 );
+				jq("li.new-update").removeClass( 'new-update' );
+				jq("textarea#whats-new").val('');
+			}
+
+			jq("#whats-new-options").animate({
+				height:'0px'
+			});
+			jq("form#whats-new-form textarea").animate({
+				height:'20px'
+			});
+			jq("#aw-whats-new-submit").prop("disabled", true).removeClass('loading');
+		});
+
+		return false;
+	});
+
+	/* List tabs event delegation */
+	jq('div.activity-type-tabs').click( function(event) {
+		var target = jq(event.target).parent();
+
+		if ( event.target.nodeName == 'STRONG' || event.target.nodeName == 'SPAN' )
+			target = target.parent();
+		else if ( event.target.nodeName != 'A' )
+			return false;
+
+		/* Reset the page */
+		jq.cookie( 'bp-activity-oldestpage', 1, {
+			path: '/'
+		} );
+
+		/* Activity Stream Tabs */
+		var scope = target.attr('id').substr( 9, target.attr('id').length );
+		var filter = jq("#activity-filter-select select").val();
+
+		if ( scope == 'mentions' )
+			jq( 'li#' + target.attr('id') + ' a strong' ).remove();
+
+		bp_activity_request(scope, filter);
+
+		return false;
+	});
+
+	/* Activity filter select */
+	jq('#activity-filter-select select').change( function() {
+		var selected_tab = jq( 'div.activity-type-tabs li.selected' );
+
+		if ( !selected_tab.length )
+			var scope = null;
+		else
+			var scope = selected_tab.attr('id').substr( 9, selected_tab.attr('id').length );
+
+		var filter = jq(this).val();
+
+		bp_activity_request(scope, filter);
+
+		return false;
+	});
+
+	/* Stream event delegation */
+	jq('div.activity').click( function(event) {
+		var target = jq(event.target);
+
+		/* Favoriting activity stream items */
+		if ( target.hasClass('fav') || target.hasClass('unfav') ) {
+			var type = target.hasClass('fav') ? 'fav' : 'unfav';
+			var parent = target.closest('.activity-item');
+			var parent_id = parent.attr('id').substr( 9, parent.attr('id').length );
+
+			target.addClass('loading');
+
+			jq.post( ajaxurl, {
+				action: 'activity_mark_' + type,
+				'cookie': bp_get_cookies(),
+				'id': parent_id
+			},
+			function(response) {
+				target.removeClass('loading');
+
+				target.fadeOut( 100, function() {
+					jq(this).html(response);
+					jq(this).attr('title', 'fav' == type ? BP_DTheme.remove_fav : BP_DTheme.mark_as_fav);
+					jq(this).fadeIn(100);
+				});
+
+				if ( 'fav' == type ) {
+					if ( !jq('.item-list-tabs li#activity-favorites').length )
+						jq('.item-list-tabs ul li#activity-mentions').before( '<li id="activity-favorites"><a href="#">' + BP_DTheme.my_favs + ' <span>0</span></a></li>');
+
+					target.removeClass('fav');
+					target.addClass('unfav');
+
+					jq('.item-list-tabs ul li#activity-favorites span').html( Number( jq('.item-list-tabs ul li#activity-favorites span').html() ) + 1 );
+				} else {
+					target.removeClass('unfav');
+					target.addClass('fav');
+
+					jq('.item-list-tabs ul li#activity-favorites span').html( Number( jq('.item-list-tabs ul li#activity-favorites span').html() ) - 1 );
+
+					if ( !Number( jq('.item-list-tabs ul li#activity-favorites span').html() ) ) {
+						if ( jq('.item-list-tabs ul li#activity-favorites').hasClass('selected') )
+							bp_activity_request( null, null );
+
+						jq('.item-list-tabs ul li#activity-favorites').remove();
+					}
+				}
+
+				if ( 'activity-favorites' == jq( '.item-list-tabs li.selected').attr('id') )
+					target.parent().parent().parent().slideUp(100);
+			});
+
+			return false;
+		}
+
+		/* Delete activity stream items */
+		if ( target.hasClass('delete-activity') ) {
+			var li        = target.parents('div.activity ul li');
+			var id        = li.attr('id').substr( 9, li.attr('id').length );
+			var link_href = target.attr('href');
+			var nonce     = link_href.split('_wpnonce=');
+
+			nonce = nonce[1];
+
+			target.addClass('loading');
+
+			jq.post( ajaxurl, {
+				action: 'delete_activity',
+				'cookie': bp_get_cookies(),
+				'id': id,
+				'_wpnonce': nonce
+			},
+			function(response) {
+
+				if ( response[0] + response[1] == '-1' ) {
+					li.prepend( response.substr( 2, response.length ) );
+					li.children('div#message').hide().fadeIn(300);
+				} else {
+					li.slideUp(300);
+				}
+			});
+
+			return false;
+		}
+
+		// Spam activity stream items
+		if ( target.hasClass( 'spam-activity' ) ) {
+			var li = target.parents( 'div.activity ul li' );
+			target.addClass( 'loading' );
+
+			jq.post( ajaxurl, {
+				action: 'bp_spam_activity',
+				'cookie': encodeURIComponent( document.cookie ),
+				'id': li.attr( 'id' ).substr( 9, li.attr( 'id' ).length ),
+				'_wpnonce': target.attr( 'href' ).split( '_wpnonce=' )[1]
+			},
+
+			function(response) {
+				if ( response[0] + response[1] === '-1' ) {
+					li.prepend( response.substr( 2, response.length ) );
+					li.children( 'div#message' ).hide().fadeIn(300);
+				} else {
+					li.slideUp( 300 );
+				}
+			});
+
+			return false;
+		}
+
+		/* Load more updates at the end of the page */
+		if ( target.parent().hasClass('load-more') ) {
+			jq("#content li.load-more").addClass('loading');
+
+			if ( null == jq.cookie('bp-activity-oldestpage') )
+				jq.cookie('bp-activity-oldestpage', 1, {
+					path: '/'
+				} );
+
+			var oldest_page = ( jq.cookie('bp-activity-oldestpage') * 1 ) + 1;
+
+			var just_posted = [];
+			
+			jq('.activity-list li.just-posted').each( function(){
+				just_posted.push( jq(this).attr('id').replace( 'activity-','' ) );
+			});
+
+			jq.post( ajaxurl, {
+				action: 'activity_get_older_updates',
+				'cookie': bp_get_cookies(),
+				'page': oldest_page,
+				'exclude_just_posted': just_posted.join(',')
+			},
+			function(response)
+			{
+				jq("#content li.load-more").removeClass('loading');
+				jq.cookie( 'bp-activity-oldestpage', oldest_page, {
+					path: '/'
+				} );
+				jq("#content ul.activity-list").append(response.contents);
+
+				target.parent().hide();
+			}, 'json' );
+
+			return false;
+		}
+	});
+
+	// Activity "Read More" links
+	jq('div.activity').on('click', '.activity-read-more a', function(event) {
+		var target = jq(event.target);
+		var link_id = target.parent().attr('id').split('-');
+		var a_id = link_id[3];
+		var type = link_id[0]; /* activity or acomment */
+
+		var inner_class = type == 'acomment' ? 'acomment-content' : 'activity-inner';
+		var a_inner = jq('li#' + type + '-' + a_id + ' .' + inner_class + ':first' );
+		jq(target).addClass('loading');
+
+		jq.post( ajaxurl, {
+			action: 'get_single_activity_content',
+			'activity_id': a_id
+		},
+		function(response) {
+			jq(a_inner).slideUp(300).html(response).slideDown(300);
+		});
+
+		return false;
+	});
+
+	/**** Activity Comments *******************************************************/
+
+	/* Hide all activity comment forms */
+	jq('form.ac-form').hide();
+
+	/* Hide excess comments */
+	if ( jq('.activity-comments').length )
+		bp_dtheme_hide_comments();
+
+	/* Activity list event delegation */
+	jq('div.activity').click( function(event) {
+		var target = jq(event.target);
+
+		/* Comment / comment reply links */
+		if ( target.hasClass('acomment-reply') || target.parent().hasClass('acomment-reply') ) {
+			if ( target.parent().hasClass('acomment-reply') )
+				target = target.parent();
+
+			var id = target.attr('id');
+			ids = id.split('-');
+
+			var a_id = ids[2]
+			var c_id = target.attr('href').substr( 10, target.attr('href').length );
+			var form = jq( '#ac-form-' + a_id );
+
+			form.css( 'display', 'none' );
+			form.removeClass('root');
+			jq('.ac-form').hide();
+
+			/* Hide any error messages */
+			form.children('div').each( function() {
+				if ( jq(this).hasClass( 'error' ) )
+					jq(this).hide();
+			});
+
+			if ( ids[1] != 'comment' ) {
+				jq('.activity-comments li#acomment-' + c_id).append( form );
+			} else {
+				jq('li#activity-' + a_id + ' .activity-comments').append( form );
+			}
+
+			if ( form.parent().hasClass( 'activity-comments' ) )
+				form.addClass('root');
+
+			form.slideDown( 200 );
+			jq.scrollTo( form, 500, {
+				offset:-100,
+				easing:'easeOutQuad'
+			} );
+			jq('#ac-form-' + ids[2] + ' textarea').focus();
+
+			return false;
+		}
+
+		/* Activity comment posting */
+		if ( target.attr('name') == 'ac_form_submit' ) {
+			var form        = target.parents( 'form' );
+			var form_parent = form.parent();
+			var form_id     = form.attr('id').split('-');
+
+			if ( !form_parent.hasClass('activity-comments') ) {
+				var tmp_id = form_parent.attr('id').split('-');
+				var comment_id = tmp_id[1];
+			} else {
+				var comment_id = form_id[2];
+			}
+
+			/* Hide any error messages */
+			jq( 'form#' + form.attr('id') + ' div.error').hide();
+			target.addClass('loading').prop('disabled', true);
+
+			var ajaxdata = {
+				action: 'new_activity_comment',
+				'cookie': bp_get_cookies(),
+				'_wpnonce_new_activity_comment': jq("input#_wpnonce_new_activity_comment").val(),
+				'comment_id': comment_id,
+				'form_id': form_id[2],
+				'content': jq('form#' + form.attr('id') + ' textarea').val()
+			};
+
+			// Akismet
+			var ak_nonce = jq('#_bp_as_nonce_' + comment_id).val();
+			if ( ak_nonce ) {
+				ajaxdata['_bp_as_nonce_' + comment_id] = ak_nonce;
+			}
+
+			jq.post( ajaxurl, ajaxdata, function(response) {
+				target.removeClass('loading');
+
+				/* Check for errors and append if found. */
+				if ( response[0] + response[1] == '-1' ) {
+					form.append( jq( response.substr( 2, response.length ) ).hide().fadeIn( 200 ) );
+				} else {
+					var activity_comments = form.parent();
+					form.fadeOut( 200, function() {
+						if ( 0 == activity_comments.children('ul').length ) {
+							if ( activity_comments.hasClass('activity-comments') ) {
+								activity_comments.prepend('<ul></ul>');
+							} else {
+								activity_comments.append('<ul></ul>');
+							}
+						}
+
+						/* Preceeding whitespace breaks output with jQuery 1.9.0 */
+						var the_comment = jq.trim( response );
+
+						activity_comments.children('ul').append( jq( the_comment ).hide().fadeIn( 200 ) );
+						form.children('textarea').val('');
+						activity_comments.parent().addClass('has-comments');
+					} );
+
+					jq( 'form#' + form.attr('id') + ' textarea').val('');
+
+					/* Increase the "Reply (X)" button count */
+					jq('li#activity-' + form_id[2] + ' a.acomment-reply span').html( Number( jq('li#activity-' + form_id[2] + ' a.acomment-reply span').html() ) + 1 );
+
+					// Increment the 'Show all x comments' string, if present
+					var show_all_a = activity_comments.find('.show-all').find('a');
+					if ( show_all_a ) {
+						var new_count = jq('li#activity-' + form_id[2] + ' a.acomment-reply span').html();
+						show_all_a.html( BP_DTheme.show_x_comments.replace( '%d', new_count ) );
+					}
+				}
+
+				jq(target).prop("disabled", false);
+			});
+
+			return false;
+		}
+
+		/* Deleting an activity comment */
+		if ( target.hasClass('acomment-delete') ) {
+			var link_href = target.attr('href');
+			var comment_li = target.parent().parent();
+			var form = comment_li.parents('div.activity-comments').children('form');
+
+			var nonce = link_href.split('_wpnonce=');
+			nonce = nonce[1];
+
+			var comment_id = link_href.split('cid=');
+			comment_id = comment_id[1].split('&');
+			comment_id = comment_id[0];
+
+			target.addClass('loading');
+
+			/* Remove any error messages */
+			jq('.activity-comments ul .error').remove();
+
+			/* Reset the form position */
+			comment_li.parents('.activity-comments').append(form);
+
+			jq.post( ajaxurl, {
+				action: 'delete_activity_comment',
+				'cookie': bp_get_cookies(),
+				'_wpnonce': nonce,
+				'id': comment_id
+			},
+			function(response)
+			{
+				/* Check for errors and append if found. */
+				if ( response[0] + response[1] == '-1' ) {
+					comment_li.prepend( jq( response.substr( 2, response.length ) ).hide().fadeIn( 200 ) );
+				} else {
+					var children = jq( 'li#' + comment_li.attr('id') + ' ul' ).children('li');
+					var child_count = 0;
+					jq(children).each( function() {
+						if ( !jq(this).is(':hidden') )
+							child_count++;
+					});
+					comment_li.fadeOut(200, function() {
+						comment_li.remove();
+					});
+
+					/* Decrease the "Reply (X)" button count */
+					var count_span = jq('li#' + comment_li.parents('ul#activity-stream > li').attr('id') + ' a.acomment-reply span');
+					var new_count = count_span.html() - ( 1 + child_count );
+					count_span.html(new_count);
+	
+					// Change the 'Show all x comments' text
+					var show_all_a = comment_li.siblings('.show-all').find('a');
+					if ( show_all_a ) {
+						show_all_a.html( BP_DTheme.show_x_comments.replace( '%d', new_count ) );
+					}
+
+					/* If that was the last comment for the item, remove the has-comments class to clean up the styling */
+					if ( 0 == new_count ) {
+						jq(comment_li.parents('ul#activity-stream > li')).removeClass('has-comments');
+					}
+				}
+			});
+
+			return false;
+		}
+
+		// Spam an activity stream comment
+		if ( target.hasClass( 'spam-activity-comment' ) ) {
+			var link_href  = target.attr( 'href' );
+			var comment_li = target.parent().parent();
+
+			target.addClass('loading');
+
+			// Remove any error messages
+			jq( '.activity-comments ul div.error' ).remove();
+
+			// Reset the form position
+			comment_li.parents( '.activity-comments' ).append( comment_li.parents( '.activity-comments' ).children( 'form' ) );
+
+			jq.post( ajaxurl, {
+				action: 'bp_spam_activity_comment',
+				'cookie': encodeURIComponent( document.cookie ),
+				'_wpnonce': link_href.split( '_wpnonce=' )[1],
+				'id': link_href.split( 'cid=' )[1].split( '&' )[0]
+			},
+
+			function ( response ) {
+				// Check for errors and append if found.
+				if ( response[0] + response[1] == '-1' ) {
+					comment_li.prepend( jq( response.substr( 2, response.length ) ).hide().fadeIn( 200 ) );
+
+				} else {
+					var children = jq( 'li#' + comment_li.attr( 'id' ) + ' ul' ).children( 'li' );
+					var child_count = 0;
+					jq(children).each( function() {
+						if ( !jq( this ).is( ':hidden' ) ) {
+							child_count++;
+						}
+					});
+					comment_li.fadeOut( 200 );
+
+					// Decrease the "Reply (X)" button count
+					var parent_li = comment_li.parents( 'ul#activity-stream > li' );
+					jq( 'li#' + parent_li.attr( 'id' ) + ' a.acomment-reply span' ).html( jq( 'li#' + parent_li.attr( 'id' ) + ' a.acomment-reply span' ).html() - ( 1 + child_count ) );
+				}
+			});
+
+			return false;
+		}
+
+		/* Showing hidden comments - pause for half a second */
+		if ( target.parent().hasClass('show-all') ) {
+			target.parent().addClass('loading');
+
+			setTimeout( function() {
+				target.parent().parent().children('li').fadeIn(200, function() {
+					target.parent().remove();
+				});
+			}, 600 );
+
+			return false;
+		}
+	});
+
+	/* Escape Key Press for cancelling comment forms */
+	jq(document).keydown( function(e) {
+		e = e || window.event;
+		if (e.target)
+			element = e.target;
+		else if (e.srcElement)
+			element = e.srcElement;
+
+		if( element.nodeType == 3)
+			element = element.parentNode;
+
+		if( e.ctrlKey == true || e.altKey == true || e.metaKey == true )
+			return;
+
+		var keyCode = (e.keyCode) ? e.keyCode : e.which;
+
+		if ( keyCode == 27 ) {
+			if (element.tagName == 'TEXTAREA') {
+				if ( jq(element).hasClass('ac-input') )
+					jq(element).parent().parent().parent().slideUp( 200 );
+			}
+		}
+	});
+
+	/**** Directory Search ****************************************************/
+
+	/* The search form on all directory pages */
+	jq('.dir-search').click( function(event) {
+		if ( jq(this).hasClass('no-ajax') )
+			return;
+
+		var target = jq(event.target);
+
+		if ( target.attr('type') == 'submit' ) {
+			var css_id = jq('.item-list-tabs li.selected').attr('id').split( '-' );
+			var object = css_id[0];
+
+			bp_filter_request( object, jq.cookie('bp-' + object + '-filter'), jq.cookie('bp-' + object + '-scope') , 'div.' + object, target.parent().children('label').children('input').val(), 1, jq.cookie('bp-' + object + '-extras') );
+
+			return false;
+		}
+	});
+
+	/**** Tabs and Filters ****************************************************/
+
+	/* When a navigation tab is clicked - e.g. | All Groups | My Groups | */
+	jq('div.item-list-tabs').click( function(event) {
+		if ( jq(this).hasClass('no-ajax') )
+			return;
+
+		var targetElem = ( event.target.nodeName == 'SPAN' ) ? event.target.parentNode : event.target;
+		var target     = jq( targetElem ).parent();
+		if ( 'LI' == target[0].nodeName && !target.hasClass('last') ) {
+			var css_id = target.attr('id').split( '-' );
+			var object = css_id[0];
+
+			if ( 'activity' == object )
+				return false;
+
+			var scope = css_id[1];
+			var filter = jq("#" + object + "-order-select select").val();
+			var search_terms = jq("#" + object + "_search").val();
+
+			bp_filter_request( object, filter, scope, 'div.' + object, search_terms, 1, jq.cookie('bp-' + object + '-extras') );
+
+			return false;
+		}
+	});
+
+	/* When the filter select box is changed re-query */
+	jq('li.filter select').change( function() {
+		if ( jq('.item-list-tabs li.selected').length )
+			var el = jq('.item-list-tabs li.selected');
+		else
+			var el = jq(this);
+
+		var css_id = el.attr('id').split('-');
+		var object = css_id[0];
+		var scope = css_id[1];
+		var filter = jq(this).val();
+		var search_terms = false;
+
+		if ( jq('.dir-search input').length )
+			search_terms = jq('.dir-search input').val();
+
+		if ( 'friends' == object )
+			object = 'members';
+
+		bp_filter_request( object, filter, scope, 'div.' + object, search_terms, 1, jq.cookie('bp-' + object + '-extras') );
+
+		return false;
+	});
+
+	/* All pagination links run through this function */
+	jq('div#content').click( function(event) {
+		var target = jq(event.target);
+
+		if ( target.hasClass('button') )
+			return true;
+
+		if ( target.parent().parent().hasClass('pagination') && !target.parent().parent().hasClass('no-ajax') ) {
+			if ( target.hasClass('dots') || target.hasClass('current') )
+				return false;
+
+			if ( jq('.item-list-tabs li.selected').length )
+				var el = jq('.item-list-tabs li.selected');
+			else
+				var el = jq('li.filter select');
+
+			var page_number = 1;
+			var css_id = el.attr('id').split( '-' );
+			var object = css_id[0];
+			var search_terms = false;
+			var pagination_id = jq(target).closest('.pagination-links').attr('id');
+
+			if ( jq('div.dir-search input').length )
+				search_terms = jq('.dir-search input').val();
+
+			if ( jq(target).hasClass('next') )
+				var page_number = Number( jq('.pagination span.current').html() ) + 1;
+			else if ( jq(target).hasClass('prev') )
+				var page_number = Number( jq('.pagination span.current').html() ) - 1;
+			else
+				var page_number = Number( jq(target).html() );
+			
+			if ( pagination_id.indexOf( 'pag-bottom' ) !== -1 ) {
+				var caller = 'pag-bottom';
+			} else {
+				var caller = null;
+			}
+
+			bp_filter_request( object, jq.cookie('bp-' + object + '-filter'), jq.cookie('bp-' + object + '-scope'), 'div.' + object, search_terms, page_number, jq.cookie('bp-' + object + '-extras'), caller );
+
+			return false;
+		}
+
+	});
+
+	/**** New Forum Directory Post **************************************/
+
+	/* Hit the "New Topic" button on the forums directory page */
+	jq('a.show-hide-new').click( function() {
+		if ( !jq('#new-topic-post').length )
+			return false;
+
+		if ( jq('#new-topic-post').is(":visible") )
+			jq('#new-topic-post').slideUp(200);
+		else
+			jq('#new-topic-post').slideDown(200, function() {
+				jq('#topic_title').focus();
+			} );
+
+		return false;
+	});
+
+	/* Cancel the posting of a new forum topic */
+	jq('input#submit_topic_cancel').click( function() {
+		if ( !jq('#new-topic-post').length )
+			return false;
+
+		jq('#new-topic-post').slideUp(200);
+		return false;
+	});
+
+	/* Clicking a forum tag */
+	jq('#forum-directory-tags a').click( function() {
+		bp_filter_request( 'forums', 'tags', jq.cookie('bp-forums-scope'), 'div.forums', jq(this).html().replace( /&nbsp;/g, '-' ), 1, jq.cookie('bp-forums-extras') );
+		return false;
+	});
+
+	/** Invite Friends Interface ****************************************/
+
+	/* Select a user from the list of friends and add them to the invite list */
+	jq("div#invite-list input").click( function() {
+		jq('.ajax-loader').toggle();
+
+		var friend_id = jq(this).val();
+
+		if ( jq(this).prop('checked') == true )
+			var friend_action = 'invite';
+		else
+			var friend_action = 'uninvite';
+
+		jq('.item-list-tabs li.selected').addClass('loading');
+
+		jq.post( ajaxurl, {
+			action: 'groups_invite_user',
+			'friend_action': friend_action,
+			'cookie': bp_get_cookies(),
+			'_wpnonce': jq("input#_wpnonce_invite_uninvite_user").val(),
+			'friend_id': friend_id,
+			'group_id': jq("input#group_id").val()
+		},
+		function(response)
+		{
+			if ( jq("#message") )
+				jq("#message").hide();
+
+			jq('.ajax-loader').toggle();
+
+			if ( friend_action == 'invite' ) {
+				jq('#friend-list').append(response);
+			} else if ( friend_action == 'uninvite' ) {
+				jq('#friend-list li#uid-' + friend_id).remove();
+			}
+
+			jq('.item-list-tabs li.selected').removeClass('loading');
+		});
+	});
+
+	/* Remove a user from the list of users to invite to a group */
+	jq("#friend-list").on('click', 'li a.remove', function() {
+		jq('.ajax-loader').toggle();
+
+		var friend_id = jq(this).attr('id');
+		friend_id = friend_id.split('-');
+		friend_id = friend_id[1];
+
+		jq.post( ajaxurl, {
+			action: 'groups_invite_user',
+			'friend_action': 'uninvite',
+			'cookie': bp_get_cookies(),
+			'_wpnonce': jq("input#_wpnonce_invite_uninvite_user").val(),
+			'friend_id': friend_id,
+			'group_id': jq("input#group_id").val()
+		},
+		function(response)
+		{
+			jq('.ajax-loader').toggle();
+			jq('#friend-list li#uid-' + friend_id).remove();
+			jq('#invite-list input#f-' + friend_id).prop('checked', false);
+		});
+
+		return false;
+	});
+
+	/** Profile Visibility Settings *********************************/
+	jq('.field-visibility-settings').hide();
+	jq('.visibility-toggle-link').on( 'click', function() {
+		var toggle_div = jq(this).parent();
+
+		jq(toggle_div).fadeOut( 600, function(){
+			jq(toggle_div).siblings('.field-visibility-settings').slideDown(400);
+		});
+
+		return false;
+	} );
+
+	jq('.field-visibility-settings-close').on( 'click', function() {
+		var settings_div = jq(this).parent();
+
+		jq(settings_div).slideUp( 400, function(){
+			jq(settings_div).siblings('.field-visibility-settings-toggle').fadeIn(800);
+		});
+
+		return false;
+	} );
+
+	jq("#profile-edit-form input:not(:submit), #profile-edit-form textarea, #profile-edit-form select, #signup_form input:not(:submit), #signup_form textarea, #signup_form select").change( function() {
+		var shouldconfirm = true;
+
+		jq('#profile-edit-form input:submit, #signup_form input:submit').on( 'click', function() {
+			shouldconfirm = false;
+		});
+		
+		window.onbeforeunload = function(e) {
+			if ( shouldconfirm ) {
+				return BP_DTheme.unsaved_changes;
+			}
+		};
+	});
+
+	/** Friendship Requests **************************************/
+
+	/* Accept and Reject friendship request buttons */
+	jq("ul#friend-list a.accept, ul#friend-list a.reject").click( function() {
+		var button = jq(this);
+		var li = jq(this).parents('ul#friend-list li');
+		var action_div = jq(this).parents('li div.action');
+
+		var id = li.attr('id').substr( 11, li.attr('id').length );
+		var link_href = button.attr('href');
+
+		var nonce = link_href.split('_wpnonce=');
+		nonce = nonce[1];
+
+		if ( jq(this).hasClass('accepted') || jq(this).hasClass('rejected') )
+			return false;
+
+		if ( jq(this).hasClass('accept') ) {
+			var action = 'accept_friendship';
+			action_div.children('a.reject').css( 'visibility', 'hidden' );
+		} else {
+			var action = 'reject_friendship';
+			action_div.children('a.accept').css( 'visibility', 'hidden' );
+		}
+
+		button.addClass('loading');
+
+		jq.post( ajaxurl, {
+			action: action,
+			'cookie': bp_get_cookies(),
+			'id': id,
+			'_wpnonce': nonce
+		},
+		function(response) {
+			button.removeClass('loading');
+
+			if ( response[0] + response[1] == '-1' ) {
+				li.prepend( response.substr( 2, response.length ) );
+				li.children('div#message').hide().fadeIn(200);
+			} else {
+				button.fadeOut( 100, function() {
+					if ( jq(this).hasClass('accept') ) {
+						action_div.children('a.reject').hide();
+						jq(this).html( BP_DTheme.accepted ).contents().unwrap();
+					} else {
+						action_div.children('a.accept').hide();
+						jq(this).html( BP_DTheme.rejected ).contents().unwrap();
+					}
+				});
+			}
+		});
+
+		return false;
+	});
+
+	/* Add / Remove friendship buttons */
+	jq('#members-dir-list').on('click', '.friendship-button a', function() {
+		jq(this).parent().addClass('loading');
+		var fid = jq(this).attr('id');
+		fid = fid.split('-');
+		fid = fid[1];
+
+		var nonce = jq(this).attr('href');
+		nonce = nonce.split('?_wpnonce=');
+		nonce = nonce[1].split('&');
+		nonce = nonce[0];
+
+		var thelink = jq(this);
+
+		jq.post( ajaxurl, {
+			action: 'addremove_friend',
+			'cookie': bp_get_cookies(),
+			'fid': fid,
+			'_wpnonce': nonce
+		},
+		function(response)
+		{
+			var action = thelink.attr('rel');
+			var parentdiv = thelink.parent();
+
+			if ( action == 'add' ) {
+				jq(parentdiv).fadeOut(200,
+					function() {
+						parentdiv.removeClass('add_friend');
+						parentdiv.removeClass('loading');
+						parentdiv.addClass('pending_friend');
+						parentdiv.fadeIn(200).html(response);
+					}
+					);
+
+			} else if ( action == 'remove' ) {
+				jq(parentdiv).fadeOut(200,
+					function() {
+						parentdiv.removeClass('remove_friend');
+						parentdiv.removeClass('loading');
+						parentdiv.addClass('add');
+						parentdiv.fadeIn(200).html(response);
+					}
+					);
+			}
+		});
+		return false;
+	} );
+
+	/** Group Join / Leave Buttons **************************************/
+
+	jq('#groups-dir-list').on('click', '.group-button a', function() {
+		var gid = jq(this).parent().attr('id');
+		gid = gid.split('-');
+		gid = gid[1];
+
+		var nonce = jq(this).attr('href');
+		nonce = nonce.split('?_wpnonce=');
+		nonce = nonce[1].split('&');
+		nonce = nonce[0];
+
+		var thelink = jq(this);
+
+		jq.post( ajaxurl, {
+			action: 'joinleave_group',
+			'cookie': bp_get_cookies(),
+			'gid': gid,
+			'_wpnonce': nonce
+		},
+		function(response)
+		{
+			var parentdiv = thelink.parent();
+
+			// user groups page
+			if ( ! jq('body.directory').length ) {
+				location.href = location.href;
+
+			// groups directory
+			} else {
+				jq(parentdiv).fadeOut(200,
+					function() {
+						parentdiv.fadeIn(200).html(response);
+
+						var mygroups = jq('#groups-personal span');
+						var add      = 1;
+
+						if( thelink.hasClass( 'leave-group' ) ) {
+							// hidden groups slide up
+							if ( parentdiv.hasClass( 'hidden' ) ) {
+								parentdiv.closest('li').slideUp( 200 );
+							}
+
+							add = 0;
+						} else if ( thelink.hasClass( 'request-membership' ) ) {
+							add = false;
+						}
+
+						// change the "My Groups" value
+						if ( add !== false && mygroups.length ) {
+							if ( add ) {
+								mygroups.text( ( mygroups.text() >> 0 ) + 1 );
+							} else {
+								mygroups.text( ( mygroups.text() >> 0 ) - 1 );
+							}
+						}
+
+					}
+				);
+			}
+		});
+		return false;
+	} );
+
+	/** Button disabling ************************************************/
+
+	jq('.pending').click(function() {
+		return false;
+	});
+
+	/** Private Messaging ******************************************/
+
+	/** Message search*/
+	jq('.message-search').click( function(event) {
+		if ( jq(this).hasClass('no-ajax') )
+			return;
+
+		var target = jq(event.target);
+
+		if ( target.attr('type') == 'submit' ) {
+			//var css_id = jq('.item-list-tabs li.selected').attr('id').split( '-' );
+			var object = 'messages';
+
+			bp_filter_request( object, jq.cookie('bp-' + object + '-filter'), jq.cookie('bp-' + object + '-scope') , 'div.' + object, target.parent().children('label').children('input').val(), 1, jq.cookie('bp-' + object + '-extras') );
+
+			return false;
+		}
+	});
+
+	/* AJAX send reply functionality */
+	jq("input#send_reply_button").click(
+		function() {
+			var order = jq('#messages_order').val() || 'ASC',
+			offset = jq('#message-recipients').offset();
+
+			var button = jq("input#send_reply_button");
+			jq(button).addClass('loading');
+
+			jq.post( ajaxurl, {
+				action: 'messages_send_reply',
+				'cookie': bp_get_cookies(),
+				'_wpnonce': jq("input#send_message_nonce").val(),
+
+				'content': jq("#message_content").val(),
+				'send_to': jq("input#send_to").val(),
+				'subject': jq("input#subject").val(),
+				'thread_id': jq("input#thread_id").val()
+			},
+			function(response)
+			{
+				if ( response[0] + response[1] == "-1" ) {
+					jq('form#send-reply').prepend( response.substr( 2, response.length ) );
+				} else {
+					jq('form#send-reply div#message').remove();
+					jq("#message_content").val('');
+
+					if ( 'ASC' == order ) {
+						jq('form#send-reply').before( response );
+					} else {
+						jq('#message-recipients').after( response );
+						jq(window).scrollTop(offset.top);
+					}
+
+					jq(".new-message").hide().slideDown( 200, function() {
+						jq('.new-message').removeClass('new-message');
+					});
+				}
+				jq(button).removeClass('loading');
+			});
+
+			return false;
+		}
+	);
+
+	/* Marking private messages as read and unread */
+	jq("a#mark_as_read, a#mark_as_unread").click(function() {
+		var checkboxes_tosend = '';
+		var checkboxes = jq("#message-threads tr td input[type='checkbox']");
+
+		if ( 'mark_as_unread' == jq(this).attr('id') ) {
+			var currentClass = 'read'
+			var newClass = 'unread'
+			var unreadCount = 1;
+			var inboxCount = 0;
+			var unreadCountDisplay = 'inline';
+			var action = 'messages_markunread';
+		} else {
+			var currentClass = 'unread'
+			var newClass = 'read'
+			var unreadCount = 0;
+			var inboxCount = 1;
+			var unreadCountDisplay = 'none';
+			var action = 'messages_markread';
+		}
+
+		checkboxes.each( function(i) {
+			if(jq(this).is(':checked')) {
+				if ( jq('tr#m-' + jq(this).attr('value')).hasClass(currentClass) ) {
+					checkboxes_tosend += jq(this).attr('value');
+					jq('tr#m-' + jq(this).attr('value')).removeClass(currentClass);
+					jq('tr#m-' + jq(this).attr('value')).addClass(newClass);
+					var thread_count = jq('tr#m-' + jq(this).attr('value') + ' td span.unread-count').html();
+
+					jq('tr#m-' + jq(this).attr('value') + ' td span.unread-count').html(unreadCount);
+					jq('tr#m-' + jq(this).attr('value') + ' td span.unread-count').css('display', unreadCountDisplay);
+
+					var inboxcount = jq('tr.unread').length;
+
+					jq('a#user-messages span').html( inboxcount );
+
+					if ( i != checkboxes.length - 1 ) {
+						checkboxes_tosend += ','
+					}
+				}
+			}
+		});
+		jq.post( ajaxurl, {
+			action: action,
+			'thread_ids': checkboxes_tosend
+		});
+		return false;
+	});
+
+	/* Selecting unread and read messages in inbox */
+	jq( 'body.messages #item-body div.messages' ).on( 'change', '#message-type-select', function() {
+		var selection = this.value;
+		var checkboxes = jq( "td input[type='checkbox']" );
+
+		checkboxes.each( function(i) {
+			checkboxes[i].checked = "";
+		});
+
+		var checked_value = "checked";
+		switch ( selection ) {
+			case 'unread' :
+				checkboxes = jq("tr.unread td input[type='checkbox']");
+				break;
+			case 'read' :
+				checkboxes = jq("tr.read td input[type='checkbox']");
+				break;
+			case '' :
+				checked_value = "";
+				break;
+		}
+
+		checkboxes.each( function(i) {
+			checkboxes[i].checked = checked_value;
+		});
+	});
+	
+	/* Bulk delete messages */
+	jq( 'body.messages #item-body div.messages' ).on( 'click', '.messages-options-nav a', function() {
+		if ( -1 == jq.inArray( this.id ), Array( 'delete_sentbox_messages', 'delete_inbox_messages' ) ) {
+			return;
+		}
+		
+		checkboxes_tosend = '';
+		checkboxes = jq("#message-threads tr td input[type='checkbox']");
+
+		jq('#message').remove();
+		jq(this).addClass('loading');
+
+		jq(checkboxes).each( function(i) {
+			if( jq(this).is(':checked') )
+				checkboxes_tosend += jq(this).attr('value') + ',';
+		});
+
+		if ( '' == checkboxes_tosend ) {
+			jq(this).removeClass('loading');
+			return false;
+		}
+		
+		jq.post( ajaxurl, {
+			action: 'messages_delete',
+			'thread_ids': checkboxes_tosend
+		}, function(response) {
+			if ( response[0] + response[1] == "-1" ) {
+				jq('#message-threads').prepend( response.substr( 2, response.length ) );
+			} else {
+				jq('#message-threads').before( '<div id="message" class="updated"><p>' + response + '</p></div>' );
+
+				jq(checkboxes).each( function(i) {
+					if( jq(this).is(':checked') ) {
+						// We need to uncheck because message is only hidden
+						// Otherwise, AJAX will be fired again with same data 
+						jq(this).attr( 'checked', false );
+						jq(this).parent().parent().fadeOut(150);
+					}
+				});
+			}
+
+			jq('#message').hide().slideDown(150);
+			jq("#delete_inbox_messages, #delete_sentbox_messages").removeClass('loading');
+		});
+
+		return false;
+	});
+
+	/* Close site wide notices in the sidebar */
+	jq("a#close-notice").click( function() {
+		jq(this).addClass('loading');
+		jq('div#sidebar div.error').remove();
+
+		jq.post( ajaxurl, {
+			action: 'messages_close_notice',
+			'notice_id': jq('.notice').attr('rel').substr( 2, jq('.notice').attr('rel').length )
+		},
+		function(response) {
+			jq("a#close-notice").removeClass('loading');
+
+			if ( response[0] + response[1] == '-1' ) {
+				jq('.notice').prepend( response.substr( 2, response.length ) );
+				jq( 'div#sidebar div.error').hide().fadeIn( 200 );
+			} else {
+				jq('.notice').slideUp( 100 );
+			}
+		});
+		return false;
+	});
+
+	/* Toolbar & wp_list_pages Javascript IE6 hover class */
+	jq("#wp-admin-bar ul.main-nav li, #nav li").mouseover( function() {
+		jq(this).addClass('sfhover');
+	});
+
+	jq("#wp-admin-bar ul.main-nav li, #nav li").mouseout( function() {
+		jq(this).removeClass('sfhover');
+	});
+
+	/* Clear BP cookies on logout */
+	jq('a.logout').click( function() {
+		jq.cookie('bp-activity-scope', null, {
+			path: '/'
+		});
+		jq.cookie('bp-activity-filter', null, {
+			path: '/'
+		});
+		jq.cookie('bp-activity-oldestpage', null, {
+			path: '/'
+		});
+
+		var objects = [ 'members', 'groups', 'blogs', 'forums' ];
+		jq(objects).each( function(i) {
+			jq.cookie('bp-' + objects[i] + '-scope', null, {
+				path: '/'
+			} );
+			jq.cookie('bp-' + objects[i] + '-filter', null, {
+				path: '/'
+			} );
+			jq.cookie('bp-' + objects[i] + '-extras', null, {
+				path: '/'
+			} );
+		});
+	});
+});
+
+/* Setup activity scope and filter based on the current cookie settings. */
+function bp_init_activity() {
+	/* Reset the page */
+	jq.cookie( 'bp-activity-oldestpage', 1, {
+		path: '/'
+	} );
+
+	if ( null != jq.cookie('bp-activity-filter') && jq('#activity-filter-select').length )
+		jq('#activity-filter-select select option[value="' + jq.cookie('bp-activity-filter') + '"]').prop( 'selected', true );
+
+	/* Activity Tab Set */
+	if ( null != jq.cookie('bp-activity-scope') && jq('.activity-type-tabs').length ) {
+		jq('.activity-type-tabs li').each( function() {
+			jq(this).removeClass('selected');
+		});
+		jq('li#activity-' + jq.cookie('bp-activity-scope') + ', .item-list-tabs li.current').addClass('selected');
+	}
+}
+
+/* Setup object scope and filter based on the current cookie settings for the object. */
+function bp_init_objects(objects) {
+	jq(objects).each( function(i) {
+		if ( null != jq.cookie('bp-' + objects[i] + '-filter') && jq('li#' + objects[i] + '-order-select select').length )
+			jq('li#' + objects[i] + '-order-select select option[value="' + jq.cookie('bp-' + objects[i] + '-filter') + '"]').prop( 'selected', true );
+
+		if ( null != jq.cookie('bp-' + objects[i] + '-scope') && jq('div.' + objects[i]).length ) {
+			jq('.item-list-tabs li').each( function() {
+				jq(this).removeClass('selected');
+			});
+			jq('.item-list-tabs li#' + objects[i] + '-' + jq.cookie('bp-' + objects[i] + '-scope') + ', div.item-list-tabs#object-nav li.current').addClass('selected');
+		}
+	});
+}
+
+/* Filter the current content list (groups/members/blogs/topics) */
+function bp_filter_request( object, filter, scope, target, search_terms, page, extras, caller ) {
+	if ( 'activity' == object )
+		return false;
+
+	if ( jq.query.get('s') && !search_terms )
+		search_terms = jq.query.get('s');
+
+	if ( null == scope )
+		scope = 'all';
+
+	/* Save the settings we want to remain persistent to a cookie */
+	jq.cookie( 'bp-' + object + '-scope', scope, {
+		path: '/'
+	} );
+	jq.cookie( 'bp-' + object + '-filter', filter, {
+		path: '/'
+	} );
+	jq.cookie( 'bp-' + object + '-extras', extras, {
+		path: '/'
+	} );
+
+	/* Set the correct selected nav and filter */
+	jq('.item-list-tabs li').each( function() {
+		jq(this).removeClass('selected');
+	});
+	jq('.item-list-tabs li#' + object + '-' + scope + ', .item-list-tabs#object-nav li.current').addClass('selected');
+	jq('.item-list-tabs li.selected').addClass('loading');
+	jq('.item-list-tabs select option[value="' + filter + '"]').prop( 'selected', true );
+
+	if ( 'friends' == object )
+		object = 'members';
+
+	if ( bp_ajax_request )
+		bp_ajax_request.abort();
+
+	bp_ajax_request = jq.post( ajaxurl, {
+		action: object + '_filter',
+		'cookie': bp_get_cookies(),
+		'object': object,
+		'filter': filter,
+		'search_terms': search_terms,
+		'scope': scope,
+		'page': page,
+		'extras': extras
+	},
+	function(response)
+	{
+		/* animate to top if called from bottom pagination */
+		if ( caller == 'pag-bottom' && jq('#subnav').length ) {
+			var top = jq('#subnav').parent();
+			jq('html,body').animate({scrollTop: top.offset().top}, 'slow', function() {
+				jq(target).fadeOut( 100, function() {
+					jq(this).html(response);
+					jq(this).fadeIn(100);
+			 	});
+			});	
+
+		} else {
+			jq(target).fadeOut( 100, function() {
+				jq(this).html(response);
+				jq(this).fadeIn(100);
+		 	});
+		}
+
+		jq('.item-list-tabs li.selected').removeClass('loading');
+	});
+}
+
+/* Activity Loop Requesting */
+function bp_activity_request(scope, filter) {
+	/* Save the type and filter to a session cookie */
+	jq.cookie( 'bp-activity-scope', scope, {
+		path: '/'
+	} );
+	jq.cookie( 'bp-activity-filter', filter, {
+		path: '/'
+	} );
+	jq.cookie( 'bp-activity-oldestpage', 1, {
+		path: '/'
+	} );
+
+	/* Remove selected and loading classes from tabs */
+	jq('.item-list-tabs li').each( function() {
+		jq(this).removeClass('selected loading');
+	});
+	/* Set the correct selected nav and filter */
+	jq('li#activity-' + scope + ', .item-list-tabs li.current').addClass('selected');
+	jq('#object-nav.item-list-tabs li.selected, div.activity-type-tabs li.selected').addClass('loading');
+	jq('#activity-filter-select select option[value="' + filter + '"]').prop( 'selected', true );
+
+	/* Reload the activity stream based on the selection */
+	jq('.widget_bp_activity_widget h2 span.ajax-loader').show();
+
+	if ( bp_ajax_request )
+		bp_ajax_request.abort();
+
+	bp_ajax_request = jq.post( ajaxurl, {
+		action: 'activity_widget_filter',
+		'cookie': bp_get_cookies(),
+		'_wpnonce_activity_filter': jq("input#_wpnonce_activity_filter").val(),
+		'scope': scope,
+		'filter': filter
+	},
+	function(response)
+	{
+		jq('.widget_bp_activity_widget h2 span.ajax-loader').hide();
+
+		jq('div.activity').fadeOut( 100, function() {
+			jq(this).html(response.contents);
+			jq(this).fadeIn(100);
+
+			/* Selectively hide comments */
+			bp_dtheme_hide_comments();
+		});
+
+		/* Update the feed link */
+		if ( null != response.feed_url )
+			jq('.directory #subnav li.feed a, .home-page #subnav li.feed a').attr('href', response.feed_url);
+
+		jq('.item-list-tabs li.selected').removeClass('loading');
+
+	}, 'json' );
+}
+
+/* Hide long lists of activity comments, only show the latest five root comments. */
+function bp_dtheme_hide_comments() {
+	var comments_divs = jq('div.activity-comments');
+
+	if ( !comments_divs.length )
+		return false;
+
+	comments_divs.each( function() {
+		if ( jq(this).children('ul').children('li').length < 5 ) return;
+
+		var comments_div = jq(this);
+		var parent_li = comments_div.parents('ul#activity-stream > li');
+		var comment_lis = jq(this).children('ul').children('li');
+		var comment_count = ' ';
+
+		if ( jq('li#' + parent_li.attr('id') + ' a.acomment-reply span').length )
+			var comment_count = jq('li#' + parent_li.attr('id') + ' a.acomment-reply span').html();
+
+		comment_lis.each( function(i) {
+			/* Show the latest 5 root comments */
+			if ( i < comment_lis.length - 5 ) {
+				jq(this).addClass('hidden');
+				jq(this).toggle();
+
+				if ( !i )
+					jq(this).before( '<li class="show-all"><a href="#' + parent_li.attr('id') + '/show-all/" title="' + BP_DTheme.show_all_comments + '">' + BP_DTheme.show_x_comments.replace( '%d', comment_count ) + '</a></li>' );
+			}
+		});
+
+	});
+}
+
+/* Helper Functions */
+
+function checkAll() {
+	var checkboxes = document.getElementsByTagName("input");
+	for(var i=0; i<checkboxes.length; i++) {
+		if(checkboxes[i].type == "checkbox") {
+			if($("check_all").checked == "") {
+				checkboxes[i].checked = "";
+			}
+			else {
+				checkboxes[i].checked = "checked";
+			}
+		}
+	}
+}
+
+function clear(container) {
+	if( !document.getElementById(container) ) return;
+
+	var container = document.getElementById(container);
+
+	if ( radioButtons = container.getElementsByTagName('INPUT') ) {
+		for(var i=0; i<radioButtons.length; i++) {
+			radioButtons[i].checked = '';
+		}
+	}
+
+	if ( options = container.getElementsByTagName('OPTION') ) {
+		for(var i=0; i<options.length; i++) {
+			options[i].selected = false;
+		}
+	}
+
+	return;
+}
+
+/* Returns a querystring of BP cookies (cookies beginning with 'bp-') */
+function bp_get_cookies() {
+	// get all cookies and split into an array
+	var allCookies   = document.cookie.split(";");
+
+	var bpCookies    = {};
+	var cookiePrefix = 'bp-';
+
+	// loop through cookies
+	for (var i = 0; i < allCookies.length; i++) {
+		var cookie    = allCookies[i];
+		var delimiter = cookie.indexOf("=");
+		var name      = jq.trim( unescape( cookie.slice(0, delimiter) ) );
+		var value     = unescape( cookie.slice(delimiter + 1) );
+
+		// if BP cookie, store it
+		if ( name.indexOf(cookiePrefix) == 0 ) {
+			bpCookies[name] = value;
+		}
+	}
+
+	// returns BP cookies as querystring
+	return encodeURIComponent( jq.param(bpCookies) );
+}
+
+/* ScrollTo plugin - just inline and minified */
+;(function($){var h=$.scrollTo=function(a,b,c){$(window).scrollTo(a,b,c)};h.defaults={axis:'xy',duration:parseFloat($.fn.jquery)>=1.3?0:1,limit:true};h.window=function(a){return $(window)._scrollable()};$.fn._scrollable=function(){return this.map(function(){var a=this,isWin=!a.nodeName||$.inArray(a.nodeName.toLowerCase(),['iframe','#document','html','body'])!=-1;if(!isWin)return a;var b=(a.contentWindow||a).document||a.ownerDocument||a;return/webkit/i.test(navigator.userAgent)||b.compatMode=='BackCompat'?b.body:b.documentElement})};$.fn.scrollTo=function(e,f,g){if(typeof f=='object'){g=f;f=0}if(typeof g=='function')g={onAfter:g};if(e=='max')e=9e9;g=$.extend({},h.defaults,g);f=f||g.duration;g.queue=g.queue&&g.axis.length>1;if(g.queue)f/=2;g.offset=both(g.offset);g.over=both(g.over);return this._scrollable().each(function(){if(e==null)return;var d=this,$elem=$(d),targ=e,toff,attr={},win=$elem.is('html,body');switch(typeof targ){case'number':case'string':if(/^([+-]=?)?\d+(\.\d+)?(px|%)?$/.test(targ)){targ=both(targ);break}targ=$(targ,this);if(!targ.length)return;case'object':if(targ.is||targ.style)toff=(targ=$(targ)).offset()}$.each(g.axis.split(''),function(i,a){var b=a=='x'?'Left':'Top',pos=b.toLowerCase(),key='scroll'+b,old=d[key],max=h.max(d,a);if(toff){attr[key]=toff[pos]+(win?0:old-$elem.offset()[pos]);if(g.margin){attr[key]-=parseInt(targ.css('margin'+b))||0;attr[key]-=parseInt(targ.css('border'+b+'Width'))||0}attr[key]+=g.offset[pos]||0;if(g.over[pos])attr[key]+=targ[a=='x'?'width':'height']()*g.over[pos]}else{var c=targ[pos];attr[key]=c.slice&&c.slice(-1)=='%'?parseFloat(c)/100*max:c}if(g.limit&&/^\d+$/.test(attr[key]))attr[key]=attr[key]<=0?0:Math.min(attr[key],max);if(!i&&g.queue){if(old!=attr[key])animate(g.onAfterFirst);delete attr[key]}});animate(g.onAfter);function animate(a){$elem.animate(attr,f,g.easing,a&&function(){a.call(this,e,g)})}}).end()};h.max=function(a,b){var c=b=='x'?'Width':'Height',scroll='scroll'+c;if(!$(a).is('html,body'))return a[scroll]-$(a)[c.toLowerCase()]();var d='client'+c,html=a.ownerDocument.documentElement,body=a.ownerDocument.body;return Math.max(html[scroll],body[scroll])-Math.min(html[d],body[d])};function both(a){return typeof a=='object'?a:{top:a,left:a}}})(jQuery);
+
+/* jQuery Easing Plugin, v1.3 - http://gsgd.co.uk/sandbox/jquery/easing/ */
+jQuery.easing.jswing=jQuery.easing.swing;jQuery.extend(jQuery.easing,{def:"easeOutQuad",swing:function(e,f,a,h,g){return jQuery.easing[jQuery.easing.def](e,f,a,h,g)},easeInQuad:function(e,f,a,h,g){return h*(f/=g)*f+a},easeOutQuad:function(e,f,a,h,g){return -h*(f/=g)*(f-2)+a},easeInOutQuad:function(e,f,a,h,g){if((f/=g/2)<1){return h/2*f*f+a}return -h/2*((--f)*(f-2)-1)+a},easeInCubic:function(e,f,a,h,g){return h*(f/=g)*f*f+a},easeOutCubic:function(e,f,a,h,g){return h*((f=f/g-1)*f*f+1)+a},easeInOutCubic:function(e,f,a,h,g){if((f/=g/2)<1){return h/2*f*f*f+a}return h/2*((f-=2)*f*f+2)+a},easeInQuart:function(e,f,a,h,g){return h*(f/=g)*f*f*f+a},easeOutQuart:function(e,f,a,h,g){return -h*((f=f/g-1)*f*f*f-1)+a},easeInOutQuart:function(e,f,a,h,g){if((f/=g/2)<1){return h/2*f*f*f*f+a}return -h/2*((f-=2)*f*f*f-2)+a},easeInQuint:function(e,f,a,h,g){return h*(f/=g)*f*f*f*f+a},easeOutQuint:function(e,f,a,h,g){return h*((f=f/g-1)*f*f*f*f+1)+a},easeInOutQuint:function(e,f,a,h,g){if((f/=g/2)<1){return h/2*f*f*f*f*f+a}return h/2*((f-=2)*f*f*f*f+2)+a},easeInSine:function(e,f,a,h,g){return -h*Math.cos(f/g*(Math.PI/2))+h+a},easeOutSine:function(e,f,a,h,g){return h*Math.sin(f/g*(Math.PI/2))+a},easeInOutSine:function(e,f,a,h,g){return -h/2*(Math.cos(Math.PI*f/g)-1)+a},easeInExpo:function(e,f,a,h,g){return(f==0)?a:h*Math.pow(2,10*(f/g-1))+a},easeOutExpo:function(e,f,a,h,g){return(f==g)?a+h:h*(-Math.pow(2,-10*f/g)+1)+a},easeInOutExpo:function(e,f,a,h,g){if(f==0){return a}if(f==g){return a+h}if((f/=g/2)<1){return h/2*Math.pow(2,10*(f-1))+a}return h/2*(-Math.pow(2,-10*--f)+2)+a},easeInCirc:function(e,f,a,h,g){return -h*(Math.sqrt(1-(f/=g)*f)-1)+a},easeOutCirc:function(e,f,a,h,g){return h*Math.sqrt(1-(f=f/g-1)*f)+a},easeInOutCirc:function(e,f,a,h,g){if((f/=g/2)<1){return -h/2*(Math.sqrt(1-f*f)-1)+a}return h/2*(Math.sqrt(1-(f-=2)*f)+1)+a},easeInElastic:function(f,h,e,l,k){var i=1.70158;var j=0;var g=l;if(h==0){return e}if((h/=k)==1){return e+l}if(!j){j=k*0.3}if(g<Math.abs(l)){g=l;var i=j/4}else{var i=j/(2*Math.PI)*Math.asin(l/g)}return -(g*Math.pow(2,10*(h-=1))*Math.sin((h*k-i)*(2*Math.PI)/j))+e},easeOutElastic:function(f,h,e,l,k){var i=1.70158;var j=0;var g=l;if(h==0){return e}if((h/=k)==1){return e+l}if(!j){j=k*0.3}if(g<Math.abs(l)){g=l;var i=j/4}else{var i=j/(2*Math.PI)*Math.asin(l/g)}return g*Math.pow(2,-10*h)*Math.sin((h*k-i)*(2*Math.PI)/j)+l+e},easeInOutElastic:function(f,h,e,l,k){var i=1.70158;var j=0;var g=l;if(h==0){return e}if((h/=k/2)==2){return e+l}if(!j){j=k*(0.3*1.5)}if(g<Math.abs(l)){g=l;var i=j/4}else{var i=j/(2*Math.PI)*Math.asin(l/g)}if(h<1){return -0.5*(g*Math.pow(2,10*(h-=1))*Math.sin((h*k-i)*(2*Math.PI)/j))+e}return g*Math.pow(2,-10*(h-=1))*Math.sin((h*k-i)*(2*Math.PI)/j)*0.5+l+e},easeInBack:function(e,f,a,i,h,g){if(g==undefined){g=1.70158}return i*(f/=h)*f*((g+1)*f-g)+a},easeOutBack:function(e,f,a,i,h,g){if(g==undefined){g=1.70158}return i*((f=f/h-1)*f*((g+1)*f+g)+1)+a},easeInOutBack:function(e,f,a,i,h,g){if(g==undefined){g=1.70158}if((f/=h/2)<1){return i/2*(f*f*(((g*=(1.525))+1)*f-g))+a}return i/2*((f-=2)*f*(((g*=(1.525))+1)*f+g)+2)+a},easeInBounce:function(e,f,a,h,g){return h-jQuery.easing.easeOutBounce(e,g-f,0,h,g)+a},easeOutBounce:function(e,f,a,h,g){if((f/=g)<(1/2.75)){return h*(7.5625*f*f)+a}else{if(f<(2/2.75)){return h*(7.5625*(f-=(1.5/2.75))*f+0.75)+a}else{if(f<(2.5/2.75)){return h*(7.5625*(f-=(2.25/2.75))*f+0.9375)+a}else{return h*(7.5625*(f-=(2.625/2.75))*f+0.984375)+a}}}},easeInOutBounce:function(e,f,a,h,g){if(f<g/2){return jQuery.easing.easeInBounce(e,f*2,0,h,g)*0.5+a}return jQuery.easing.easeOutBounce(e,f*2-g,0,h,g)*0.5+h*0.5+a}});
+
+/* jQuery Cookie plugin */
+jQuery.cookie=function(name,value,options){if(typeof value!='undefined'){options=options||{};if(value===null){value='';options.expires=-1;}var expires='';if(options.expires&&(typeof options.expires=='number'||options.expires.toUTCString)){var date;if(typeof options.expires=='number'){date=new Date();date.setTime(date.getTime()+(options.expires*24*60*60*1000));}else{date=options.expires;}expires='; expires='+date.toUTCString();}var path=options.path?'; path='+(options.path):'';var domain=options.domain?'; domain='+(options.domain):'';var secure=options.secure?'; secure':'';document.cookie=[name,'=',encodeURIComponent(value),expires,path,domain,secure].join('');}else{var cookieValue=null;if(document.cookie&&document.cookie!=''){var cookies=document.cookie.split(';');for(var i=0;i<cookies.length;i++){var cookie=jQuery.trim(cookies[i]);if(cookie.substring(0,name.length+1)==(name+'=')){cookieValue=decodeURIComponent(cookie.substring(name.length+1));break;}}}return cookieValue;}};
+
+/* jQuery querystring plugin */
+eval(function(p,a,c,k,e,d){e=function(c){return(c<a?'':e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--){d[e(c)]=k[c]||e(c)}k=[function(e){return d[e]}];e=function(){return'\\w+'};c=1};while(c--){if(k[c]){p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c])}}return p}('M 6(A){4 $11=A.11||\'&\';4 $V=A.V===r?r:j;4 $1p=A.1p===r?\'\':\'[]\';4 $13=A.13===r?r:j;4 $D=$13?A.D===j?"#":"?":"";4 $15=A.15===r?r:j;v.1o=M 6(){4 f=6(o,t){8 o!=1v&&o!==x&&(!!t?o.1t==t:j)};4 14=6(1m){4 m,1l=/\\[([^[]*)\\]/g,T=/^([^[]+)(\\[.*\\])?$/.1r(1m),k=T[1],e=[];19(m=1l.1r(T[2]))e.u(m[1]);8[k,e]};4 w=6(3,e,7){4 o,y=e.1b();b(I 3!=\'X\')3=x;b(y===""){b(!3)3=[];b(f(3,L)){3.u(e.h==0?7:w(x,e.z(0),7))}n b(f(3,1a)){4 i=0;19(3[i++]!=x);3[--i]=e.h==0?7:w(3[i],e.z(0),7)}n{3=[];3.u(e.h==0?7:w(x,e.z(0),7))}}n b(y&&y.T(/^\\s*[0-9]+\\s*$/)){4 H=1c(y,10);b(!3)3=[];3[H]=e.h==0?7:w(3[H],e.z(0),7)}n b(y){4 H=y.B(/^\\s*|\\s*$/g,"");b(!3)3={};b(f(3,L)){4 18={};1w(4 i=0;i<3.h;++i){18[i]=3[i]}3=18}3[H]=e.h==0?7:w(3[H],e.z(0),7)}n{8 7}8 3};4 C=6(a){4 p=d;p.l={};b(a.C){v.J(a.Z(),6(5,c){p.O(5,c)})}n{v.J(1u,6(){4 q=""+d;q=q.B(/^[?#]/,\'\');q=q.B(/[;&]$/,\'\');b($V)q=q.B(/[+]/g,\' \');v.J(q.Y(/[&;]/),6(){4 5=1e(d.Y(\'=\')[0]||"");4 c=1e(d.Y(\'=\')[1]||"");b(!5)8;b($15){b(/^[+-]?[0-9]+\\.[0-9]*$/.1d(c))c=1A(c);n b(/^[+-]?[0-9]+$/.1d(c))c=1c(c,10)}c=(!c&&c!==0)?j:c;b(c!==r&&c!==j&&I c!=\'1g\')c=c;p.O(5,c)})})}8 p};C.1H={C:j,1G:6(5,1f){4 7=d.Z(5);8 f(7,1f)},1h:6(5){b(!f(5))8 d.l;4 K=14(5),k=K[0],e=K[1];4 3=d.l[k];19(3!=x&&e.h!=0){3=3[e.1b()]}8 I 3==\'1g\'?3:3||""},Z:6(5){4 3=d.1h(5);b(f(3,1a))8 v.1E(j,{},3);n b(f(3,L))8 3.z(0);8 3},O:6(5,c){4 7=!f(c)?x:c;4 K=14(5),k=K[0],e=K[1];4 3=d.l[k];d.l[k]=w(3,e.z(0),7);8 d},w:6(5,c){8 d.N().O(5,c)},1s:6(5){8 d.O(5,x).17()},1z:6(5){8 d.N().1s(5)},1j:6(){4 p=d;v.J(p.l,6(5,7){1y p.l[5]});8 p},1F:6(Q){4 D=Q.B(/^.*?[#](.+?)(?:\\?.+)?$/,"$1");4 S=Q.B(/^.*?[?](.+?)(?:#.+)?$/,"$1");8 M C(Q.h==S.h?\'\':S,Q.h==D.h?\'\':D)},1x:6(){8 d.N().1j()},N:6(){8 M C(d)},17:6(){6 F(G){4 R=I G=="X"?f(G,L)?[]:{}:G;b(I G==\'X\'){6 1k(o,5,7){b(f(o,L))o.u(7);n o[5]=7}v.J(G,6(5,7){b(!f(7))8 j;1k(R,5,F(7))})}8 R}d.l=F(d.l);8 d},1B:6(){8 d.N().17()},1D:6(){4 i=0,U=[],W=[],p=d;4 16=6(E){E=E+"";b($V)E=E.B(/ /g,"+");8 1C(E)};4 1n=6(1i,5,7){b(!f(7)||7===r)8;4 o=[16(5)];b(7!==j){o.u("=");o.u(16(7))}1i.u(o.P(""))};4 F=6(R,k){4 12=6(5){8!k||k==""?[5].P(""):[k,"[",5,"]"].P("")};v.J(R,6(5,7){b(I 7==\'X\')F(7,12(5));n 1n(W,12(5),7)})};F(d.l);b(W.h>0)U.u($D);U.u(W.P($11));8 U.P("")}};8 M C(1q.S,1q.D)}}(v.1o||{});',62,106,'|||target|var|key|function|value|return|||if|val|this|tokens|is||length||true|base|keys||else||self||false|||push|jQuery|set|null|token|slice|settings|replace|queryObject|hash|str|build|orig|index|typeof|each|parsed|Array|new|copy|SET|join|url|obj|search|match|queryString|spaces|chunks|object|split|get||separator|newKey|prefix|parse|numbers|encode|COMPACT|temp|while|Object|shift|parseInt|test|decodeURIComponent|type|number|GET|arr|EMPTY|add|rx|path|addFields|query|suffix|location|exec|REMOVE|constructor|arguments|undefined|for|empty|delete|remove|parseFloat|compact|encodeURIComponent|toString|extend|load|has|prototype'.split('|'),0,{}))
Index: /tags/1.9/bp-themes/bp-default/activity/activity-loop.php
===================================================================
--- /tags/1.9/bp-themes/bp-default/activity/activity-loop.php	(revision 7684)
+++ /tags/1.9/bp-themes/bp-default/activity/activity-loop.php	(revision 7684)
@@ -0,0 +1,66 @@
+<?php
+
+/**
+ * BuddyPress - Activity Loop
+ *
+ * Querystring is set via AJAX in _inc/ajax.php - bp_dtheme_object_filter()
+ *
+ * @package BuddyPress
+ * @subpackage bp-default
+ */
+
+?>
+
+<?php do_action( 'bp_before_activity_loop' ); ?>
+
+<?php if ( bp_has_activities( bp_ajax_querystring( 'activity' ) ) ) : ?>
+
+	<?php /* Show pagination if JS is not enabled, since the "Load More" link will do nothing */ ?>
+	<noscript>
+		<div class="pagination">
+			<div class="pag-count"><?php bp_activity_pagination_count(); ?></div>
+			<div class="pagination-links"><?php bp_activity_pagination_links(); ?></div>
+		</div>
+	</noscript>
+
+	<?php if ( empty( $_POST['page'] ) ) : ?>
+
+		<ul id="activity-stream" class="activity-list item-list">
+
+	<?php endif; ?>
+
+	<?php while ( bp_activities() ) : bp_the_activity(); ?>
+
+		<?php locate_template( array( 'activity/entry.php' ), true, false ); ?>
+
+	<?php endwhile; ?>
+
+	<?php if ( bp_activity_has_more_items() ) : ?>
+
+		<li class="load-more">
+			<a href="#more"><?php _e( 'Load More', 'buddypress' ); ?></a>
+		</li>
+
+	<?php endif; ?>
+
+	<?php if ( empty( $_POST['page'] ) ) : ?>
+
+		</ul>
+
+	<?php endif; ?>
+
+<?php else : ?>
+
+	<div id="message" class="info">
+		<p><?php _e( 'Sorry, there was no activity found. Please try a different filter.', 'buddypress' ); ?></p>
+	</div>
+
+<?php endif; ?>
+
+<?php do_action( 'bp_after_activity_loop' ); ?>
+
+<form action="" name="activity-loop-form" id="activity-loop-form" method="post">
+
+	<?php wp_nonce_field( 'activity_filter', '_wpnonce_activity_filter' ); ?>
+
+</form>
Index: /tags/1.9/bp-themes/bp-default/activity/comment.php
===================================================================
--- /tags/1.9/bp-themes/bp-default/activity/comment.php	(revision 7684)
+++ /tags/1.9/bp-themes/bp-default/activity/comment.php	(revision 7684)
@@ -0,0 +1,57 @@
+<?php
+
+/**
+ * BuddyPress - Activity Stream Comment
+ *
+ * This template is used by bp_activity_comments() functions to show
+ * each activity.
+ *
+ * @package BuddyPress
+ * @subpackage bp-default
+ */
+
+?>
+
+<?php do_action( 'bp_before_activity_comment' ); ?>
+
+<li id="acomment-<?php bp_activity_comment_id(); ?>">
+	<div class="acomment-avatar">
+		<a href="<?php bp_activity_comment_user_link(); ?>">
+			<?php bp_activity_avatar( array(
+				'type'    => 'thumb',
+				'user_id' => bp_get_activity_comment_user_id()
+			) ); ?>
+		</a>
+	</div>
+
+	<div class="acomment-meta">
+		<?php
+		/* translators: 1: user profile link, 2: user name, 3: activity permalink, 4: activity timestamp */
+		printf( __( '<a href="%1$s">%2$s</a> replied <a href="%3$s" class="activity-time-since"><span class="time-since">%4$s</span></a>', 'buddypress' ), bp_get_activity_comment_user_link(), bp_get_activity_comment_name(), bp_get_activity_comment_permalink(), bp_get_activity_comment_date_recorded() );
+		?>
+	</div>
+
+	<div class="acomment-content"><?php bp_activity_comment_content(); ?></div>
+
+	<div class="acomment-options">
+
+		<?php if ( is_user_logged_in() && bp_activity_can_comment_reply( bp_activity_current_comment() ) ) : ?>
+
+			<a href="#acomment-<?php bp_activity_comment_id(); ?>" class="acomment-reply bp-primary-action" id="acomment-reply-<?php bp_activity_id(); ?>-from-<?php bp_activity_comment_id(); ?>"><?php _e( 'Reply', 'buddypress' ); ?></a>
+
+		<?php endif; ?>
+
+		<?php if ( bp_activity_user_can_delete() ) : ?>
+
+			<a href="<?php bp_activity_comment_delete_link(); ?>" class="delete acomment-delete confirm bp-secondary-action" rel="nofollow"><?php _e( 'Delete', 'buddypress' ); ?></a>
+
+		<?php endif; ?>
+
+		<?php do_action( 'bp_activity_comment_options' ); ?>
+
+	</div>
+
+	<?php bp_activity_recurse_comments( bp_activity_current_comment() ); ?>
+</li>
+
+<?php do_action( 'bp_after_activity_comment' ); ?>
Index: /tags/1.9/bp-themes/bp-default/activity/entry.php
===================================================================
--- /tags/1.9/bp-themes/bp-default/activity/entry.php	(revision 7684)
+++ /tags/1.9/bp-themes/bp-default/activity/entry.php	(revision 7684)
@@ -0,0 +1,124 @@
+<?php
+
+/**
+ * BuddyPress - Activity Stream (Single Item)
+ *
+ * This template is used by activity-loop.php and AJAX functions to show
+ * each activity.
+ *
+ * @package BuddyPress
+ * @subpackage bp-default
+ */
+
+?>
+
+<?php do_action( 'bp_before_activity_entry' ); ?>
+
+<li class="<?php bp_activity_css_class(); ?>" id="activity-<?php bp_activity_id(); ?>">
+	<div class="activity-avatar">
+		<a href="<?php bp_activity_user_link(); ?>">
+
+			<?php bp_activity_avatar(); ?>
+
+		</a>
+	</div>
+
+	<div class="activity-content">
+
+		<div class="activity-header">
+
+			<?php bp_activity_action(); ?>
+
+		</div>
+
+		<?php if ( 'activity_comment' == bp_get_activity_type() ) : ?>
+
+			<div class="activity-inreplyto">
+				<strong><?php _e( 'In reply to: ', 'buddypress' ); ?></strong><?php bp_activity_parent_content(); ?> <a href="<?php bp_activity_thread_permalink(); ?>" class="view" title="<?php _e( 'View Thread / Permalink', 'buddypress' ); ?>"><?php _e( 'View', 'buddypress' ); ?></a>
+			</div>
+
+		<?php endif; ?>
+
+		<?php if ( bp_activity_has_content() ) : ?>
+
+			<div class="activity-inner">
+
+				<?php bp_activity_content_body(); ?>
+
+			</div>
+
+		<?php endif; ?>
+
+		<?php do_action( 'bp_activity_entry_content' ); ?>
+
+		<?php if ( is_user_logged_in() ) : ?>
+
+			<div class="activity-meta">
+
+				<?php if ( bp_activity_can_comment() ) : ?>
+
+					<a href="<?php bp_activity_comment_link(); ?>" class="button acomment-reply bp-primary-action" id="acomment-comment-<?php bp_activity_id(); ?>"><?php printf( __( 'Comment <span>%s</span>', 'buddypress' ), bp_activity_get_comment_count() ); ?></a>
+
+				<?php endif; ?>
+
+				<?php if ( bp_activity_can_favorite() ) : ?>
+
+					<?php if ( !bp_get_activity_is_favorite() ) : ?>
+
+						<a href="<?php bp_activity_favorite_link(); ?>" class="button fav bp-secondary-action" title="<?php esc_attr_e( 'Mark as Favorite', 'buddypress' ); ?>"><?php _e( 'Favorite', 'buddypress' ); ?></a>
+
+					<?php else : ?>
+
+						<a href="<?php bp_activity_unfavorite_link(); ?>" class="button unfav bp-secondary-action" title="<?php esc_attr_e( 'Remove Favorite', 'buddypress' ); ?>"><?php _e( 'Remove Favorite', 'buddypress' ); ?></a>
+
+					<?php endif; ?>
+
+				<?php endif; ?>
+
+				<?php if ( bp_activity_user_can_delete() ) bp_activity_delete_link(); ?>
+
+				<?php do_action( 'bp_activity_entry_meta' ); ?>
+
+			</div>
+
+		<?php endif; ?>
+
+	</div>
+
+	<?php do_action( 'bp_before_activity_entry_comments' ); ?>
+
+	<?php if ( ( is_user_logged_in() && bp_activity_can_comment() ) || bp_is_single_activity() ) : ?>
+
+		<div class="activity-comments">
+
+			<?php bp_activity_comments(); ?>
+
+			<?php if ( is_user_logged_in() ) : ?>
+
+				<form action="<?php bp_activity_comment_form_action(); ?>" method="post" id="ac-form-<?php bp_activity_id(); ?>" class="ac-form"<?php bp_activity_comment_form_nojs_display(); ?>>
+					<div class="ac-reply-avatar"><?php bp_loggedin_user_avatar( 'width=' . BP_AVATAR_THUMB_WIDTH . '&height=' . BP_AVATAR_THUMB_HEIGHT ); ?></div>
+					<div class="ac-reply-content">
+						<div class="ac-textarea">
+							<textarea id="ac-input-<?php bp_activity_id(); ?>" class="ac-input" name="ac_input_<?php bp_activity_id(); ?>"></textarea>
+						</div>
+						<input type="submit" name="ac_form_submit" value="<?php _e( 'Post', 'buddypress' ); ?>" /> &nbsp; <?php _e( 'or press esc to cancel.', 'buddypress' ); ?>
+						<input type="hidden" name="comment_form_id" value="<?php bp_activity_id(); ?>" />
+					</div>
+
+					<?php do_action( 'bp_activity_entry_comments' ); ?>
+
+					<?php wp_nonce_field( 'new_activity_comment', '_wpnonce_new_activity_comment' ); ?>
+
+				</form>
+
+			<?php endif; ?>
+
+		</div>
+
+	<?php endif; ?>
+
+	<?php do_action( 'bp_after_activity_entry_comments' ); ?>
+
+</li>
+
+<?php do_action( 'bp_after_activity_entry' ); ?>
Index: /tags/1.9/bp-themes/bp-default/activity/index.php
===================================================================
--- /tags/1.9/bp-themes/bp-default/activity/index.php	(revision 7684)
+++ /tags/1.9/bp-themes/bp-default/activity/index.php	(revision 7684)
@@ -0,0 +1,159 @@
+<?php
+
+/**
+ * Template Name: BuddyPress - Activity Directory
+ *
+ * @package BuddyPress
+ * @subpackage Theme
+ */
+
+get_header( 'buddypress' ); ?>
+
+	<?php do_action( 'bp_before_directory_activity_page' ); ?>
+
+	<div id="content">
+		<div class="padder">
+
+			<?php do_action( 'bp_before_directory_activity' ); ?>
+
+			<?php if ( !is_user_logged_in() ) : ?>
+
+				<h3><?php _e( 'Site Activity', 'buddypress' ); ?></h3>
+
+			<?php endif; ?>
+
+			<?php do_action( 'bp_before_directory_activity_content' ); ?>
+
+			<?php if ( is_user_logged_in() ) : ?>
+
+				<?php locate_template( array( 'activity/post-form.php'), true ); ?>
+
+			<?php endif; ?>
+
+			<?php do_action( 'template_notices' ); ?>
+
+			<div class="item-list-tabs activity-type-tabs" role="navigation">
+				<ul>
+					<?php do_action( 'bp_before_activity_type_tab_all' ); ?>
+
+					<li class="selected" id="activity-all"><a href="<?php bp_activity_directory_permalink(); ?>" title="<?php _e( 'The public activity for everyone on this site.', 'buddypress' ); ?>"><?php printf( __( 'All Members <span>%s</span>', 'buddypress' ), bp_get_total_member_count() ); ?></a></li>
+
+					<?php if ( is_user_logged_in() ) : ?>
+
+						<?php do_action( 'bp_before_activity_type_tab_friends' ); ?>
+
+						<?php if ( bp_is_active( 'friends' ) ) : ?>
+
+							<?php if ( bp_get_total_friend_count( bp_loggedin_user_id() ) ) : ?>
+
+								<li id="activity-friends"><a href="<?php echo bp_loggedin_user_domain() . bp_get_activity_slug() . '/' . bp_get_friends_slug() . '/'; ?>" title="<?php _e( 'The activity of my friends only.', 'buddypress' ); ?>"><?php printf( __( 'My Friends <span>%s</span>', 'buddypress' ), bp_get_total_friend_count( bp_loggedin_user_id() ) ); ?></a></li>
+
+							<?php endif; ?>
+
+						<?php endif; ?>
+
+						<?php do_action( 'bp_before_activity_type_tab_groups' ); ?>
+
+						<?php if ( bp_is_active( 'groups' ) ) : ?>
+
+							<?php if ( bp_get_total_group_count_for_user( bp_loggedin_user_id() ) ) : ?>
+
+								<li id="activity-groups"><a href="<?php echo bp_loggedin_user_domain() . bp_get_activity_slug() . '/' . bp_get_groups_slug() . '/'; ?>" title="<?php _e( 'The activity of groups I am a member of.', 'buddypress' ); ?>"><?php printf( __( 'My Groups <span>%s</span>', 'buddypress' ), bp_get_total_group_count_for_user( bp_loggedin_user_id() ) ); ?></a></li>
+
+							<?php endif; ?>
+
+						<?php endif; ?>
+
+						<?php do_action( 'bp_before_activity_type_tab_favorites' ); ?>
+
+						<?php if ( bp_get_total_favorite_count_for_user( bp_loggedin_user_id() ) ) : ?>
+
+							<li id="activity-favorites"><a href="<?php echo bp_loggedin_user_domain() . bp_get_activity_slug() . '/favorites/'; ?>" title="<?php _e( "The activity I've marked as a favorite.", 'buddypress' ); ?>"><?php printf( __( 'My Favorites <span>%s</span>', 'buddypress' ), bp_get_total_favorite_count_for_user( bp_loggedin_user_id() ) ); ?></a></li>
+
+						<?php endif; ?>
+
+						<?php if ( bp_activity_do_mentions() ) : ?>
+
+							<?php do_action( 'bp_before_activity_type_tab_mentions' ); ?>
+
+							<li id="activity-mentions"><a href="<?php echo bp_loggedin_user_domain() . bp_get_activity_slug() . '/mentions/'; ?>" title="<?php _e( 'Activity that I have been mentioned in.', 'buddypress' ); ?>"><?php _e( 'Mentions', 'buddypress' ); ?><?php if ( bp_get_total_mention_count_for_user( bp_loggedin_user_id() ) ) : ?> <strong><span><?php printf( _nx( '%s new', '%s new', bp_get_total_mention_count_for_user( bp_loggedin_user_id() ), 'Number of new activity mentions', 'buddypress' ), bp_get_total_mention_count_for_user( bp_loggedin_user_id() ) ); ?></span></strong><?php endif; ?></a></li>
+
+						<?php endif; ?>
+
+					<?php endif; ?>
+
+					<?php do_action( 'bp_activity_type_tabs' ); ?>
+				</ul>
+			</div><!-- .item-list-tabs -->
+
+			<div class="item-list-tabs no-ajax" id="subnav" role="navigation">
+				<ul>
+					<li class="feed"><a href="<?php bp_sitewide_activity_feed_link(); ?>" title="<?php _e( 'RSS Feed', 'buddypress' ); ?>"><?php _e( 'RSS', 'buddypress' ); ?></a></li>
+
+					<?php do_action( 'bp_activity_syndication_options' ); ?>
+
+					<li id="activity-filter-select" class="last">
+						<label for="activity-filter-by"><?php _e( 'Show:', 'buddypress' ); ?></label>
+						<select id="activity-filter-by">
+							<option value="-1"><?php _e( 'Everything', 'buddypress' ); ?></option>
+							<option value="activity_update"><?php _e( 'Updates', 'buddypress' ); ?></option>
+
+							<?php if ( bp_is_active( 'blogs' ) ) : ?>
+
+								<option value="new_blog_post"><?php _e( 'Posts', 'buddypress' ); ?></option>
+								<option value="new_blog_comment"><?php _e( 'Comments', 'buddypress' ); ?></option>
+
+							<?php endif; ?>
+
+							<?php if ( bp_is_active( 'forums' ) ) : ?>
+
+								<option value="new_forum_topic"><?php _e( 'Forum Topics', 'buddypress' ); ?></option>
+								<option value="new_forum_post"><?php _e( 'Forum Replies', 'buddypress' ); ?></option>
+
+							<?php endif; ?>
+
+							<?php if ( bp_is_active( 'groups' ) ) : ?>
+
+								<option value="created_group"><?php _e( 'New Groups', 'buddypress' ); ?></option>
+								<option value="joined_group"><?php _e( 'Group Memberships', 'buddypress' ); ?></option>
+
+							<?php endif; ?>
+
+							<?php if ( bp_is_active( 'friends' ) ) : ?>
+
+								<option value="friendship_accepted,friendship_created"><?php _e( 'Friendships', 'buddypress' ); ?></option>
+
+							<?php endif; ?>
+
+							<option value="new_member"><?php _e( 'New Members', 'buddypress' ); ?></option>
+
+							<?php do_action( 'bp_activity_filter_options' ); ?>
+
+						</select>
+					</li>
+				</ul>
+			</div><!-- .item-list-tabs -->
+
+			<?php do_action( 'bp_before_directory_activity_list' ); ?>
+
+			<div class="activity" role="main">
+
+				<?php locate_template( array( 'activity/activity-loop.php' ), true ); ?>
+
+			</div><!-- .activity -->
+
+			<?php do_action( 'bp_after_directory_activity_list' ); ?>
+
+			<?php do_action( 'bp_directory_activity_content' ); ?>
+
+			<?php do_action( 'bp_after_directory_activity_content' ); ?>
+
+			<?php do_action( 'bp_after_directory_activity' ); ?>
+
+		</div><!-- .padder -->
+	</div><!-- #content -->
+
+	<?php do_action( 'bp_after_directory_activity_page' ); ?>
+
+<?php get_sidebar( 'buddypress' ); ?>
+<?php get_footer( 'buddypress' ); ?>
Index: /tags/1.9/bp-themes/bp-default/activity/post-form.php
===================================================================
--- /tags/1.9/bp-themes/bp-default/activity/post-form.php	(revision 7684)
+++ /tags/1.9/bp-themes/bp-default/activity/post-form.php	(revision 7684)
@@ -0,0 +1,74 @@
+<?php
+
+/**
+ * BuddyPress - Activity Post Form
+ *
+ * @package BuddyPress
+ * @subpackage bp-default
+ */
+
+?>
+
+<form action="<?php bp_activity_post_form_action(); ?>" method="post" id="whats-new-form" name="whats-new-form" role="complementary">
+
+	<?php do_action( 'bp_before_activity_post_form' ); ?>
+
+	<div id="whats-new-avatar">
+		<a href="<?php echo bp_loggedin_user_domain(); ?>">
+			<?php bp_loggedin_user_avatar( 'width=' . bp_core_avatar_thumb_width() . '&height=' . bp_core_avatar_thumb_height() ); ?>
+		</a>
+	</div>
+
+	<h5><?php if ( bp_is_group() )
+			printf( __( "What's new in %s, %s?", 'buddypress' ), bp_get_group_name(), bp_get_user_firstname() );
+		else
+			printf( __( "What's new, %s?", 'buddypress' ), bp_get_user_firstname() );
+	?></h5>
+
+	<div id="whats-new-content">
+		<div id="whats-new-textarea">
+			<textarea name="whats-new" id="whats-new" cols="50" rows="10"><?php if ( isset( $_GET['r'] ) ) : ?>@<?php echo esc_attr( $_GET['r'] ); ?> <?php endif; ?></textarea>
+		</div>
+
+		<div id="whats-new-options">
+			<div id="whats-new-submit">
+				<input type="submit" name="aw-whats-new-submit" id="aw-whats-new-submit" value="<?php _e( 'Post Update', 'buddypress' ); ?>" />
+			</div>
+
+			<?php if ( bp_is_active( 'groups' ) && !bp_is_my_profile() && !bp_is_group() ) : ?>
+
+				<div id="whats-new-post-in-box">
+
+					<?php _e( 'Post in', 'buddypress' ); ?>:
+
+					<select id="whats-new-post-in" name="whats-new-post-in">
+						<option selected="selected" value="0"><?php _e( 'My Profile', 'buddypress' ); ?></option>
+
+						<?php if ( bp_has_groups( 'user_id=' . bp_loggedin_user_id() . '&type=alphabetical&max=100&per_page=100&populate_extras=0' ) ) :
+							while ( bp_groups() ) : bp_the_group(); ?>
+
+								<option value="<?php bp_group_id(); ?>"><?php bp_group_name(); ?></option>
+
+							<?php endwhile;
+						endif; ?>
+
+					</select>
+				</div>
+				<input type="hidden" id="whats-new-post-object" name="whats-new-post-object" value="groups" />
+
+			<?php elseif ( bp_is_group_home() ) : ?>
+
+				<input type="hidden" id="whats-new-post-object" name="whats-new-post-object" value="groups" />
+				<input type="hidden" id="whats-new-post-in" name="whats-new-post-in" value="<?php bp_group_id(); ?>" />
+
+			<?php endif; ?>
+
+			<?php do_action( 'bp_activity_post_form_options' ); ?>
+
+		</div><!-- #whats-new-options -->
+	</div><!-- #whats-new-content -->
+
+	<?php wp_nonce_field( 'post_update', '_wpnonce_post_update' ); ?>
+	<?php do_action( 'bp_after_activity_post_form' ); ?>
+
+</form><!-- #whats-new-form -->
Index: /tags/1.9/bp-themes/bp-default/archive.php
===================================================================
--- /tags/1.9/bp-themes/bp-default/archive.php	(revision 7684)
+++ /tags/1.9/bp-themes/bp-default/archive.php	(revision 7684)
@@ -0,0 +1,64 @@
+<?php get_header(); ?>
+
+	<div id="content">
+		<div class="padder">
+
+		<?php do_action( 'bp_before_archive' ); ?>
+
+		<div class="page" id="blog-archives" role="main">
+
+			<h3 class="pagetitle"><?php printf( __( 'You are browsing the archive for %1$s.', 'buddypress' ), wp_title( false, false ) ); ?></h3>
+
+			<?php if ( have_posts() ) : ?>
+
+				<?php bp_dtheme_content_nav( 'nav-above' ); ?>
+
+				<?php while (have_posts()) : the_post(); ?>
+
+					<?php do_action( 'bp_before_blog_post' ); ?>
+
+					<div id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
+
+						<div class="author-box">
+							<?php echo get_avatar( get_the_author_meta( 'user_email' ), '50' ); ?>
+							<p><?php printf( _x( 'by %s', 'Post written by...', 'buddypress' ), bp_core_get_userlink( $post->post_author ) ); ?></p>
+						</div>
+
+						<div class="post-content">
+							<h2 class="posttitle"><a href="<?php the_permalink(); ?>" rel="bookmark" title="<?php _e( 'Permanent Link to', 'buddypress' ); ?> <?php the_title_attribute(); ?>"><?php the_title(); ?></a></h2>
+
+							<p class="date"><?php printf( __( '%1$s <span>in %2$s</span>', 'buddypress' ), get_the_date(), get_the_category_list( ', ' ) ); ?></p>
+
+							<div class="entry">
+								<?php the_content( __( 'Read the rest of this entry &rarr;', 'buddypress' ) ); ?>
+								<?php wp_link_pages( array( 'before' => '<div class="page-link"><p>' . __( 'Pages: ', 'buddypress' ), 'after' => '</p></div>', 'next_or_number' => 'number' ) ); ?>
+							</div>
+
+							<p class="postmetadata"><?php the_tags( '<span class="tags">' . __( 'Tags: ', 'buddypress' ), ', ', '</span>' ); ?> <span class="comments"><?php comments_popup_link( __( 'No Comments &#187;', 'buddypress' ), __( '1 Comment &#187;', 'buddypress' ), __( '% Comments &#187;', 'buddypress' ) ); ?></span></p>
+						</div>
+
+					</div>
+
+					<?php do_action( 'bp_after_blog_post' ); ?>
+
+				<?php endwhile; ?>
+
+				<?php bp_dtheme_content_nav( 'nav-below' ); ?>
+
+			<?php else : ?>
+
+				<h2 class="center"><?php _e( 'Not Found', 'buddypress' ); ?></h2>
+				<?php get_search_form(); ?>
+
+			<?php endif; ?>
+
+		</div>
+
+		<?php do_action( 'bp_after_archive' ); ?>
+
+		</div><!-- .padder -->
+	</div><!-- #content -->
+
+	<?php get_sidebar(); ?>
+
+<?php get_footer(); ?>
Index: /tags/1.9/bp-themes/bp-default/attachment.php
===================================================================
--- /tags/1.9/bp-themes/bp-default/attachment.php	(revision 7684)
+++ /tags/1.9/bp-themes/bp-default/attachment.php	(revision 7684)
@@ -0,0 +1,75 @@
+<?php get_header(); ?>
+
+	<div id="content">
+		<div class="padder">
+
+			<?php do_action( 'bp_before_attachment' ); ?>
+
+			<div class="page" id="attachments-page" role="main">
+
+				<?php if (have_posts()) : while (have_posts()) : the_post(); ?>
+
+					<?php do_action( 'bp_before_blog_post' ); ?>
+
+					<div id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
+
+						<div class="author-box">
+							<?php echo get_avatar( get_the_author_meta( 'user_email' ), '50' ); ?>
+							<p><?php printf( _x( 'by %s', 'Post written by...', 'buddypress' ), str_replace( '<a href=', '<a rel="author" href=', bp_core_get_userlink( $post->post_author ) ) ); ?></p>
+						</div>
+
+						<div class="post-content">
+							<h2 class="posttitle"><a href="<?php the_permalink(); ?>" rel="bookmark" title="<?php _e( 'Permanent Link to', 'buddypress' ); ?> <?php the_title_attribute(); ?>"><?php the_title(); ?></a></h2>
+
+							<p class="date">
+								<?php the_date(); ?>
+								<span class="post-utility alignright"><?php edit_post_link( __( 'Edit this entry', 'buddypress' ) ); ?></span>
+							</p>
+
+							<div class="entry">
+								<?php echo wp_get_attachment_image( $post->ID, 'large', false, array( 'class' => 'size-large aligncenter' ) ); ?>
+
+								<div class="entry-caption"><?php if ( !empty( $post->post_excerpt ) ) the_excerpt(); ?></div>
+								<?php the_content(); ?>
+							</div>
+
+							<p class="postmetadata">
+								<?php
+									if ( wp_attachment_is_image() ) :
+										$metadata = wp_get_attachment_metadata();
+										printf( __( 'Full size is %s pixels', 'buddypress' ),
+											sprintf( '<a href="%1$s" title="%2$s">%3$s &times; %4$s</a>',
+												wp_get_attachment_url(),
+												esc_attr( __( 'Link to full size image', 'buddypress' ) ),
+												$metadata['width'],
+												$metadata['height']
+											)
+										);
+									endif;
+								?>
+								&nbsp;
+							</p>
+						</div>
+
+					</div>
+
+					<?php do_action( 'bp_after_blog_post' ); ?>
+
+					<?php comments_template(); ?>
+
+				<?php endwhile; else: ?>
+
+					<p><?php _e( 'Sorry, no attachments matched your criteria.', 'buddypress' ); ?></p>
+
+				<?php endif; ?>
+
+			</div>
+
+		<?php do_action( 'bp_after_attachment' ); ?>
+
+		</div><!-- .padder -->
+	</div><!-- #content -->
+
+	<?php get_sidebar(); ?>
+
+<?php get_footer(); ?>
Index: /tags/1.9/bp-themes/bp-default/blogs/blogs-loop.php
===================================================================
--- /tags/1.9/bp-themes/bp-default/blogs/blogs-loop.php	(revision 7684)
+++ /tags/1.9/bp-themes/bp-default/blogs/blogs-loop.php	(revision 7684)
@@ -0,0 +1,95 @@
+<?php
+
+/**
+ * BuddyPress - Blogs Loop
+ *
+ * Querystring is set via AJAX in _inc/ajax.php - bp_dtheme_object_filter()
+ *
+ * @package BuddyPress
+ * @subpackage bp-default
+ */
+
+?>
+
+<?php do_action( 'bp_before_blogs_loop' ); ?>
+
+<?php if ( bp_has_blogs( bp_ajax_querystring( 'blogs' ) ) ) : ?>
+
+	<div id="pag-top" class="pagination">
+
+		<div class="pag-count" id="blog-dir-count-top">
+			<?php bp_blogs_pagination_count(); ?>
+		</div>
+
+		<div class="pagination-links" id="blog-dir-pag-top">
+			<?php bp_blogs_pagination_links(); ?>
+		</div>
+
+	</div>
+
+	<?php do_action( 'bp_before_directory_blogs_list' ); ?>
+
+	<ul id="blogs-list" class="item-list" role="main">
+
+	<?php while ( bp_blogs() ) : bp_the_blog(); ?>
+
+		<li>
+			<div class="item-avatar">
+				<a href="<?php bp_blog_permalink(); ?>"><?php bp_blog_avatar( 'type=thumb' ); ?></a>
+			</div>
+
+			<div class="item">
+				<div class="item-title"><a href="<?php bp_blog_permalink(); ?>"><?php bp_blog_name(); ?></a></div>
+				<div class="item-meta"><span class="activity"><?php bp_blog_last_active(); ?></span></div>
+
+				<?php do_action( 'bp_directory_blogs_item' ); ?>
+			</div>
+
+			<div class="action">
+
+				<?php do_action( 'bp_directory_blogs_actions' ); ?>
+
+				<div class="meta">
+
+					<?php bp_blog_latest_post(); ?>
+
+				</div>
+
+			</div>
+
+			<div class="clear"></div>
+		</li>
+
+	<?php endwhile; ?>
+
+	</ul>
+
+	<?php do_action( 'bp_after_directory_blogs_list' ); ?>
+
+	<?php bp_blog_hidden_fields(); ?>
+
+	<div id="pag-bottom" class="pagination">
+
+		<div class="pag-count" id="blog-dir-count-bottom">
+
+			<?php bp_blogs_pagination_count(); ?>
+
+		</div>
+
+		<div class="pagination-links" id="blog-dir-pag-bottom">
+
+			<?php bp_blogs_pagination_links(); ?>
+
+		</div>
+
+	</div>
+
+<?php else: ?>
+
+	<div id="message" class="info">
+		<p><?php _e( 'Sorry, there were no sites found.', 'buddypress' ); ?></p>
+	</div>
+
+<?php endif; ?>
+
+<?php do_action( 'bp_after_blogs_loop' ); ?>
Index: /tags/1.9/bp-themes/bp-default/blogs/create.php
===================================================================
--- /tags/1.9/bp-themes/bp-default/blogs/create.php	(revision 7684)
+++ /tags/1.9/bp-themes/bp-default/blogs/create.php	(revision 7684)
@@ -0,0 +1,48 @@
+<?php
+
+/**
+ * BuddyPress - Create Blog
+ *
+ * @package BuddyPress
+ * @subpackage bp-default
+ */
+
+get_header( 'buddypress' ); ?>
+
+	<?php do_action( 'bp_before_directory_blogs_content' ); ?>
+
+	<div id="content">
+		<div class="padder" role="main">
+		
+		<?php do_action( 'bp_before_create_blog_content_template' ); ?>
+
+		<?php do_action( 'template_notices' ); ?>
+
+			<h3><?php _e( 'Create a Site', 'buddypress' ); ?> &nbsp;<a class="button" href="<?php echo trailingslashit( bp_get_root_domain() . '/' . bp_get_blogs_root_slug() ); ?>"><?php _e( 'Site Directory', 'buddypress' ); ?></a></h3>
+
+		<?php do_action( 'bp_before_create_blog_content' ); ?>
+
+		<?php if ( bp_blog_signup_enabled() ) : ?>
+
+			<?php bp_show_blog_signup_form(); ?>
+
+		<?php else: ?>
+
+			<div id="message" class="info">
+				<p><?php _e( 'Site registration is currently disabled', 'buddypress' ); ?></p>
+			</div>
+
+		<?php endif; ?>
+
+		<?php do_action( 'bp_after_create_blog_content' ); ?>
+		
+		<?php do_action( 'bp_after_create_blog_content_template' ); ?>
+
+		</div><!-- .padder -->
+	</div><!-- #content -->
+
+	<?php do_action( 'bp_after_directory_blogs_content' ); ?>
+
+<?php get_sidebar( 'buddypress' ); ?>
+<?php get_footer( 'buddypress' ); ?>
+
Index: /tags/1.9/bp-themes/bp-default/blogs/index.php
===================================================================
--- /tags/1.9/bp-themes/bp-default/blogs/index.php	(revision 7684)
+++ /tags/1.9/bp-themes/bp-default/blogs/index.php	(revision 7684)
@@ -0,0 +1,88 @@
+<?php
+
+/**
+ * BuddyPress - Blogs Directory
+ *
+ * @package BuddyPress
+ * @subpackage bp-default
+ */
+
+get_header( 'buddypress' ); ?>
+
+	<?php do_action( 'bp_before_directory_blogs_page' ); ?>
+
+	<div id="content">
+		<div class="padder">
+
+		<?php do_action( 'bp_before_directory_blogs' ); ?>
+
+		<form action="" method="post" id="blogs-directory-form" class="dir-form">
+
+			<h3><?php _e( 'Site Directory', 'buddypress' ); ?><?php if ( is_user_logged_in() && bp_blog_signup_enabled() ) : ?> &nbsp;<a class="button" href="<?php echo bp_get_root_domain() . '/' . bp_get_blogs_root_slug() . '/create/' ?>"><?php _e( 'Create a Site', 'buddypress' ); ?></a><?php endif; ?></h3>
+
+			<?php do_action( 'bp_before_directory_blogs_content' ); ?>
+
+			<div id="blog-dir-search" class="dir-search" role="search">
+
+				<?php bp_directory_blogs_search_form(); ?>
+
+			</div><!-- #blog-dir-search -->
+
+			<div class="item-list-tabs" role="navigation">
+				<ul>
+					<li class="selected" id="blogs-all"><a href="<?php bp_root_domain(); ?>/<?php bp_blogs_root_slug(); ?>"><?php printf( __( 'All Sites <span>%s</span>', 'buddypress' ), bp_get_total_blog_count() ); ?></a></li>
+
+					<?php if ( is_user_logged_in() && bp_get_total_blog_count_for_user( bp_loggedin_user_id() ) ) : ?>
+
+						<li id="blogs-personal"><a href="<?php echo bp_loggedin_user_domain() . bp_get_blogs_slug(); ?>"><?php printf( __( 'My Sites <span>%s</span>', 'buddypress' ), bp_get_total_blog_count_for_user( bp_loggedin_user_id() ) ); ?></a></li>
+
+					<?php endif; ?>
+
+					<?php do_action( 'bp_blogs_directory_blog_types' ); ?>
+
+				</ul>
+			</div><!-- .item-list-tabs -->
+
+			<div class="item-list-tabs" id="subnav" role="navigation">
+				<ul>
+
+					<?php do_action( 'bp_blogs_directory_blog_sub_types' ); ?>
+
+					<li id="blogs-order-select" class="last filter">
+
+						<label for="blogs-order-by"><?php _e( 'Order By:', 'buddypress' ); ?></label>
+						<select id="blogs-order-by">
+							<option value="active"><?php _e( 'Last Active', 'buddypress' ); ?></option>
+							<option value="newest"><?php _e( 'Newest', 'buddypress' ); ?></option>
+							<option value="alphabetical"><?php _e( 'Alphabetical', 'buddypress' ); ?></option>
+
+							<?php do_action( 'bp_blogs_directory_order_options' ); ?>
+
+						</select>
+					</li>
+				</ul>
+			</div>
+
+			<div id="blogs-dir-list" class="blogs dir-list">
+
+				<?php locate_template( array( 'blogs/blogs-loop.php' ), true ); ?>
+
+			</div><!-- #blogs-dir-list -->
+
+			<?php do_action( 'bp_directory_blogs_content' ); ?>
+
+			<?php wp_nonce_field( 'directory_blogs', '_wpnonce-blogs-filter' ); ?>
+
+			<?php do_action( 'bp_after_directory_blogs_content' ); ?>
+
+		</form><!-- #blogs-directory-form -->
+
+		<?php do_action( 'bp_after_directory_blogs' ); ?>
+
+		</div><!-- .padder -->
+	</div><!-- #content -->
+
+	<?php do_action( 'bp_after_directory_blogs_page' ); ?>
+
+<?php get_sidebar( 'buddypress' ); ?>
+<?php get_footer( 'buddypress' ); ?>
Index: /tags/1.9/bp-themes/bp-default/comments.php
===================================================================
--- /tags/1.9/bp-themes/bp-default/comments.php	(revision 7684)
+++ /tags/1.9/bp-themes/bp-default/comments.php	(revision 7684)
@@ -0,0 +1,86 @@
+<?php
+
+	// Bail if post type doesn't support comments
+	if ( ! post_type_supports( get_post_type(), 'comments' ) )
+		return;
+
+	// Bail if is a page, and comments are not open
+	if ( is_page() && ! have_comments() && ! comments_open() && ! pings_open() )
+		return;
+
+	if ( post_password_required() ) {
+		echo '<h3 class="comments-header">' . __( 'Password Protected', 'buddypress' ) . '</h3>';
+		echo '<p class="alert password-protected">' . __( 'Enter the password to view comments.', 'buddypress' ) . '</p>';
+		return;
+	}
+
+	if ( have_comments() ) :
+		$num_comments   = 0;
+		$num_trackbacks = 0;
+		foreach ( (array) $comments as $comment ) {
+			if ( 'comment' != get_comment_type() ) {
+				$num_trackbacks++;
+			} else {
+				$num_comments++;
+			}
+		}
+?>
+	<div id="comments">
+
+		<h3>
+			<?php printf( _n( '1 response to %2$s', '%1$s responses to %2$s', $num_comments, 'buddypress' ), number_format_i18n( $num_comments ), '<em>' . get_the_title() . '</em>' ); ?>
+		</h3>
+
+		<?php do_action( 'bp_before_blog_comment_list' ); ?>
+
+		<ol class="commentlist">
+			<?php wp_list_comments( array( 'callback' => 'bp_dtheme_blog_comments', 'type' => 'comment' ) ); ?>
+		</ol><!-- .comment-list -->
+
+		<?php do_action( 'bp_after_blog_comment_list' ); ?>
+
+		<?php if ( get_option( 'page_comments' ) ) : ?>
+			<div class="comment-navigation paged-navigation">
+				<?php paginate_comments_links(); ?>
+			</div>
+		<?php endif; ?>
+
+	</div><!-- #comments -->
+
+<?php else : ?>
+
+	<?php if ( ! comments_open() ) : ?>
+		<?php if ( pings_open() ) : ?>
+			<p class="comments-closed pings-open">
+				<?php printf( __( 'Comments are closed, but <a href="%1$s" title="Trackback URL for this post">trackbacks</a> and pingbacks are open.', 'buddypress' ), get_trackback_url() ); ?>
+			</p>
+		<?php else : ?>
+			<p class="comments-closed">
+				<?php _e( 'Comments are closed.', 'buddypress' ); ?>
+			</p>
+		<?php endif; ?>
+	<?php endif; ?>
+
+<?php endif; ?>
+
+<?php if ( comments_open() ) comment_form(); ?>
+
+<?php if ( !empty( $num_trackbacks ) ) : ?>
+	<div id="trackbacks">
+		<h3><?php printf( _n( '1 trackback', '%d trackbacks', $num_trackbacks, 'buddypress' ), number_format_i18n( $num_trackbacks ) ); ?></h3>
+
+		<ul id="trackbacklist">
+			<?php foreach ( (array) $comments as $comment ) : ?>
+
+				<?php if ( 'comment' != get_comment_type() ) : ?>
+					<li>
+						<h5><?php comment_author_link(); ?></h5>
+						<em>on <?php comment_date(); ?></em>
+					</li>
+ 				<?php endif; ?>
+
+			<?php endforeach; ?>
+		</ul>
+
+	</div>
+<?php endif; ?>
Index: /tags/1.9/bp-themes/bp-default/editor-style-rtl.css
===================================================================
--- /tags/1.9/bp-themes/bp-default/editor-style-rtl.css	(revision 7684)
+++ /tags/1.9/bp-themes/bp-default/editor-style-rtl.css	(revision 7684)
@@ -0,0 +1,43 @@
+/*
+Theme Name: BuddyPress Default
+Description: Used to style the TinyMCE editor (RTL version).
+*/
+
+html .mceContentBody .alignright {
+	float: left;
+	margin-left: auto;
+	margin-right: 15px;
+}
+html .mceContentBody .alignleft {
+	float: right;
+	margin-left: 15px;
+	margin-right: auto;
+}
+dl {
+	margin-left: auto;
+	margin-right: 0;
+}
+html .mceContentBody img.alignright {
+	margin: 0 7px 2px 0;
+}
+html .mceContentBody img.alignleft {
+	margin: 0 0 2px 7px;
+}
+dd.wp-caption p.wp-caption-text,
+.wp-caption p.wp-caption-text {
+	padding: 0 0 5px 4px;
+}
+html .mceContentBody ul,
+html .mceContentBody ol,
+html .mceContentBody dl {
+	margin: 0 1.5em 18px 0;
+}
+
+html .mceContentBody table th:first {
+	border-left: 1px solid #eaeaea;
+	border-right: 0;
+}
+html .mceContentBody table tr td.label {
+	border-left: 1px solid #eaeaea;
+	border-right: 0;
+}
Index: /tags/1.9/bp-themes/bp-default/editor-style.css
===================================================================
--- /tags/1.9/bp-themes/bp-default/editor-style.css	(revision 7684)
+++ /tags/1.9/bp-themes/bp-default/editor-style.css	(revision 7684)
@@ -0,0 +1,272 @@
+/*
+Theme Name: BuddyPress Default
+Description: Used to style the TinyMCE editor.
+*/
+
+html .mceContentBody {
+	font-family: Arial, Tahoma, Verdana, sans-serif;
+	font-size: 12px;
+	color: #555;
+}
+ul,
+ol {
+	margin: 0;
+	padding: 0;
+}
+h1,
+h2,
+h3,
+h4,
+h5,
+h6 {
+	margin: 5px 0 15px 0;
+}
+h1 {
+	font-size: 28px;
+	margin-bottom: 25px;
+}
+h2 {
+	font-size: 24px;
+	margin-bottom: 20px;
+}
+h3 {
+	font-size: 20px;
+}
+h4 {
+	font-size: 16px;
+	margin-bottom: 15px;
+}
+h5 {
+	font-size: 14px;
+	margin-bottom: 0;
+}
+h6 {
+	font-size: 12px;
+	margin-bottom: 0;
+}
+a {
+	color: #1fb3dd;
+}
+a:hover,
+a:active {
+	color: #888;
+}
+a:focus {
+	outline: 1px dotted #ccc;
+}
+p {
+	margin-bottom: 15px;
+}
+p:last-child {
+	margin-bottom: 0;
+}
+hr {
+	background-color: #e7e7e7;
+	border: 0 none;
+	clear: both;
+	height: 1px;
+	margin: 20px 0;
+}
+big {
+	font-size: 18px;
+}
+acronym {
+	border-bottom: 0;
+	cursor: normal;
+}
+acronym:hover {
+	cursor: normal;
+}
+del {
+	text-decoration: line-through;
+	color: #555;
+}
+ins {
+	background: #fff9db;
+	border: 0;
+	color: #555;
+	text-decoration: none;
+}
+sub {
+	top: .5ex;
+}
+sup {
+	bottom: 1ex;
+}
+sub,
+sup {
+	height: 0;
+	line-height: 1;
+	vertical-align: baseline;
+	position: relative;
+}
+html .mceContentBody .alignright {
+	float: right;
+	margin-left: 15px;
+}
+html .mceContentBody .alignleft {
+	float: left;
+	margin-right: 15px;
+}
+p {
+	margin: 0 0 20px 0;
+}
+dl {
+	margin-left: 0;
+}
+dt {
+	font-size: 14px;
+	font-weight: bold;
+}
+dd {
+	margin: 0 0 15px 0;
+}
+pre,
+code p {
+	padding: 15px;
+	background: #f4f4f4;
+	-moz-border-radius: 3px;
+	-webkit-border-radius: 3px;
+	border-radius: 3px;
+}
+code {
+	font-family: "Monaco", courier, sans-serif;
+}
+cite {
+	border: 0;
+}
+blockquote {
+	quotes: none;
+	font-style: italic;
+	margin: 0 0;
+	padding: 0 3em;
+	font-family: georgia, times, serif;
+	font-size: 16px;
+	line-height: 150%;
+}
+blockquote p {
+	margin-bottom: 15px !important;
+}
+p.date {
+	color: #888;
+	font-size: 12px;
+	font-family: Georgia, times, serif;
+	padding: 3px 0;
+	margin: 10px 0;
+	border-bottom: 1px solid #e4e4e4;
+	border-top: 1px solid #e4e4e4;
+}
+img.wp-smiley {
+	padding: 0 !important;
+	margin: 0 !important;
+	border: none !important;
+	float: none !important;
+	clear: none !important;
+}
+html .mceContentBody img.centered,
+html .mceContentBody img.aligncenter {
+	display: block;
+	margin-left: auto;
+	margin-right: auto;
+}
+html .mceContentBody img.alignright {
+	padding: 4px;
+	margin: 0 0 2px 7px;
+	display: inline;
+}
+html .mceContentBody img.alignleft {
+	padding: 4px;
+	margin: 0 7px 2px 0;
+	display: inline;
+}
+html .mceContentBody .aligncenter {
+	display: block;
+	margin-left: auto;
+	margin-right: auto;
+}
+.wp-caption {
+	border: 1px solid #ddd;
+	text-align: center;
+	background-color: #f3f3f3;
+	padding-top: 4px;
+	-moz-border-radius: 3px;
+	-webkit-border-radius: 3px;
+	border-radius: 3px;
+}
+.wp-caption img {
+	margin: 0;
+	padding: 0;
+	border: 0 none;
+}
+dd.wp-caption p.wp-caption-text,
+.wp-caption p.wp-caption-text {
+	font-size: 0.9em;
+	line-height: 17px;
+	padding: 0 4px 5px 0;
+	margin: 0;
+}
+.gallery .gallery-caption {
+	color: #555;
+}
+table {
+	width: 100%;
+}
+table thead tr {
+	background: #eaeaea;
+}
+td {
+	color: #555;
+	font-size: 12px;
+}
+table tr td,
+table tr th {
+	padding: 8px;
+	vertical-align: middle;
+}
+table tr.alt td {
+	background: #f5f5f5;
+}
+html .mceContentBody ul,
+html .mceContentBody ol,
+html .mceContentBody dl {
+	margin: 0 0 18px 1.5em;
+}
+html .mceContentBody ul {
+	list-style: square;
+}
+html .mceContentBody ol {
+	list-style: decimal;
+}
+html .mceContentBody ol ol {
+	list-style: upper-alpha;
+}
+html .mceContentBody table {
+	border-collapse: collapse;
+	border-spacing: 0;
+	border: 1px solid #eee;
+}
+html .mceContentBody table th {
+	border-top: 1px solid #eee;
+	border-left: 0 none;
+	border-right: 0 none;
+	font-size: 12px;
+	text-align: left;
+}
+html .mceContentBody table th:first {
+	border-right: 1px solid #eaeaea;
+}
+html .mceContentBody table td {
+	border-top: 1px solid #eee;
+}
+html .mceContentBody img {
+	margin-bottom: 15px;
+}
+html .mceContentBody table tr td {
+	border-left: 0 none;
+	border-right: 0 none;
+}
+html .mceContentBody table tr td.label {
+	border-right: 1px solid #eaeaea;
+	font-weight: bold;
+	width: 25%;
+}
Index: /tags/1.9/bp-themes/bp-default/footer.php
===================================================================
--- /tags/1.9/bp-themes/bp-default/footer.php	(revision 7684)
+++ /tags/1.9/bp-themes/bp-default/footer.php	(revision 7684)
@@ -0,0 +1,28 @@
+		</div> <!-- #container -->
+
+		<?php do_action( 'bp_after_container' ); ?>
+		<?php do_action( 'bp_before_footer'   ); ?>
+
+		<div id="footer">
+			<?php if ( is_active_sidebar( 'first-footer-widget-area' ) || is_active_sidebar( 'second-footer-widget-area' ) || is_active_sidebar( 'third-footer-widget-area' ) || is_active_sidebar( 'fourth-footer-widget-area' ) ) : ?>
+				<div id="footer-widgets">
+					<?php get_sidebar( 'footer' ); ?>
+				</div>
+			<?php endif; ?>
+
+			<div id="site-generator" role="contentinfo">
+				<?php do_action( 'bp_dtheme_credits' ); ?>
+				<p><?php printf( __( 'Proudly powered by <a href="%1$s">WordPress</a> and <a href="%2$s">BuddyPress</a>.', 'buddypress' ), 'http://wordpress.org', 'http://buddypress.org' ); ?></p>
+			</div>
+
+			<?php do_action( 'bp_footer' ); ?>
+
+		</div><!-- #footer -->
+
+		<?php do_action( 'bp_after_footer' ); ?>
+
+		<?php wp_footer(); ?>
+
+	</body>
+
+</html>
Index: /tags/1.9/bp-themes/bp-default/forums/forums-loop.php
===================================================================
--- /tags/1.9/bp-themes/bp-default/forums/forums-loop.php	(revision 7684)
+++ /tags/1.9/bp-themes/bp-default/forums/forums-loop.php	(revision 7684)
@@ -0,0 +1,127 @@
+<?php
+
+/**
+ * BuddyPress - Forums Loop
+ *
+ * Querystring is set via AJAX in _inc/ajax.php - bp_dtheme_object_filter()
+ *
+ * @package BuddyPress
+ * @subpackage bp-default
+ */
+
+?>
+
+<?php do_action( 'bp_before_forums_loop' ); ?>
+
+<?php if ( bp_has_forum_topics( bp_ajax_querystring( 'forums' ) ) ) : ?>
+
+	<div id="pag-top" class="pagination">
+
+		<div class="pag-count" id="topic-count-top">
+
+			<?php bp_forum_pagination_count(); ?>
+
+		</div>
+
+		<div class="pagination-links" id="topic-pag-top">
+
+			<?php bp_forum_pagination(); ?>
+
+		</div>
+
+	</div>
+
+	<?php do_action( 'bp_before_directory_forums_list' ); ?>
+
+	<table class="forum">
+		<thead>
+			<tr>
+				<th id="th-title"><?php _e( 'Topic', 'buddypress' ); ?></th>
+				<th id="th-postcount"><?php _e( 'Posts', 'buddypress' ); ?></th>
+				<th id="th-freshness"><?php _e( 'Freshness', 'buddypress' ); ?></th>
+
+				<?php do_action( 'bp_directory_forums_extra_cell_head' ); ?>
+
+			</tr>
+		</thead>
+
+		<tbody>
+
+			<?php while ( bp_forum_topics() ) : bp_the_forum_topic(); ?>
+
+			<tr class="<?php bp_the_topic_css_class(); ?>">
+				<td class="td-title">
+					<a class="topic-title" href="<?php bp_the_topic_permalink(); ?>" title="<?php _e( 'Permanent link to this post', 'buddypress' ); ?>">
+
+						<?php bp_the_topic_title(); ?>
+
+					</a>
+
+					<p class="topic-meta">
+						<span class="topic-by"><?php /* translators: "started by [poster] in [forum]" */ printf( __( 'Started by %1$s', 'buddypress' ), bp_get_the_topic_poster_avatar( 'height=20&width=20') . bp_get_the_topic_poster_name() ); ?></span>
+
+						<?php if ( !bp_is_group_forum() ) : ?>
+
+							<span class="topic-in">
+
+								<?php
+									$topic_in = '<a href="' . bp_get_the_topic_object_permalink() . '">' . bp_get_the_topic_object_avatar( 'type=thumb&width=20&height=20' ) . '</a>' .
+													'<a href="' . bp_get_the_topic_object_permalink() . '" title="' . bp_get_the_topic_object_name() . '">' . bp_get_the_topic_object_name() .'</a>';
+
+									/* translators: "started by [poster] in [forum]" */
+									printf( __( 'in %1$s', 'buddypress' ), $topic_in );
+								?>
+
+							</span>
+
+						<?php endif; ?>
+
+					</p>
+				</td>
+				<td class="td-postcount">
+					<?php bp_the_topic_total_posts(); ?>
+				</td>
+				<td class="td-freshness">
+					<span class="time-since"><?php bp_the_topic_time_since_last_post(); ?></span>
+					<p class="topic-meta">
+						<span class="freshness-author">
+							<a href="<?php bp_the_topic_permalink(); ?>"><?php bp_the_topic_last_poster_avatar( 'type=thumb&width=20&height=20' ); ?></a>
+							<?php bp_the_topic_last_poster_name(); ?>
+						</span>
+					</p>
+				</td>
+
+				<?php do_action( 'bp_directory_forums_extra_cell' ); ?>
+
+			</tr>
+
+			<?php do_action( 'bp_directory_forums_extra_row' ); ?>
+
+			<?php endwhile; ?>
+
+		</tbody>
+	</table>
+
+	<?php do_action( 'bp_after_directory_forums_list' ); ?>
+
+	<div id="pag-bottom" class="pagination">
+
+		<div class="pag-count" id="topic-count-bottom">
+			<?php bp_forum_pagination_count(); ?>
+		</div>
+
+		<div class="pagination-links" id="topic-pag-bottom">
+			<?php bp_forum_pagination(); ?>
+		</div>
+
+	</div>
+
+<?php else: ?>
+
+	<div id="message" class="info">
+		<p><?php _e( 'Sorry, there were no forum topics found.', 'buddypress' ); ?></p>
+	</div>
+
+<?php endif; ?>
+
+<?php do_action( 'bp_after_forums_loop' ); ?>
Index: /tags/1.9/bp-themes/bp-default/forums/index.php
===================================================================
--- /tags/1.9/bp-themes/bp-default/forums/index.php	(revision 7684)
+++ /tags/1.9/bp-themes/bp-default/forums/index.php	(revision 7684)
@@ -0,0 +1,164 @@
+<?php
+
+/**
+ * BuddyPress - Forums Directory
+ *
+ * @package BuddyPress
+ * @subpackage bp-default
+ */
+
+?>
+
+<?php get_header( 'buddypress' ); ?>
+
+	<?php do_action( 'bp_before_directory_forums_page' ); ?>
+
+	<div id="content">
+		<div class="padder">
+
+			<?php do_action( 'bp_before_directory_forums' ); ?>
+
+			<form action="" method="post" id="forums-search-form" class="dir-form">
+
+				<h3><?php _e( 'Forums Directory', 'buddypress' ); ?><?php if ( is_user_logged_in() ) : ?> &nbsp;<a class="button show-hide-new" href="#new-topic" id="new-topic-button"><?php _e( 'New Topic', 'buddypress' ); ?></a><?php endif; ?></h3>
+
+				<?php do_action( 'bp_before_directory_forums_content' ); ?>
+
+				<div id="forums-dir-search" class="dir-search" role="search">
+
+					<?php bp_directory_forums_search_form(); ?>
+
+				</div>
+			</form>
+
+			<?php do_action( 'bp_before_topics' ); ?>
+
+			<form action="" method="post" id="forums-directory-form" class="dir-form">
+
+				<div class="item-list-tabs" role="navigation">
+					<ul>
+						<li class="selected" id="forums-all"><a href="<?php echo trailingslashit( bp_get_root_domain() . '/' . bp_get_forums_root_slug() ); ?>"><?php printf( __( 'All Topics <span>%s</span>', 'buddypress' ), bp_get_forum_topic_count() ); ?></a></li>
+
+						<?php if ( is_user_logged_in() && bp_get_forum_topic_count_for_user( bp_loggedin_user_id() ) ) : ?>
+
+							<li id="forums-personal"><a href="<?php echo trailingslashit( bp_loggedin_user_domain() . bp_get_forums_slug() . '/topics' ); ?>"><?php printf( __( 'My Topics <span>%s</span>', 'buddypress' ), bp_get_forum_topic_count_for_user( bp_loggedin_user_id() ) ); ?></a></li>
+
+						<?php endif; ?>
+
+						<?php do_action( 'bp_forums_directory_group_types' ); ?>
+
+					</ul>
+				</div>
+
+				<div class="item-list-tabs" id="subnav" role="navigation">
+					<ul>
+
+						<?php do_action( 'bp_forums_directory_group_sub_types' ); ?>
+
+						<li id="forums-order-select" class="last filter">
+
+							<label for="forums-order-by"><?php _e( 'Order By:', 'buddypress' ); ?></label>
+							<select id="forums-order-by">
+								<option value="active"><?php _e( 'Last Active', 'buddypress' ); ?></option>
+								<option value="popular"><?php _e( 'Most Posts', 'buddypress' ); ?></option>
+								<option value="unreplied"><?php _e( 'Unreplied', 'buddypress' ); ?></option>
+
+								<?php do_action( 'bp_forums_directory_order_options' ); ?>
+
+							</select>
+						</li>
+					</ul>
+				</div>
+
+				<div id="forums-dir-list" class="forums dir-list" role="main">
+
+					<?php locate_template( array( 'forums/forums-loop.php' ), true ); ?>
+
+				</div>
+
+				<?php do_action( 'bp_directory_forums_content' ); ?>
+
+				<?php wp_nonce_field( 'directory_forums', '_wpnonce-forums-filter' ); ?>
+
+			</form>
+
+			<?php do_action( 'bp_after_directory_forums' ); ?>
+
+			<?php do_action( 'bp_before_new_topic_form' ); ?>
+
+			<div id="new-topic-post">
+
+				<?php if ( is_user_logged_in() ) : ?>
+
+					<?php if ( bp_is_active( 'groups' ) && bp_has_groups( 'user_id=' . bp_loggedin_user_id() . '&type=alphabetical&max=100&per_page=100' ) ) : ?>
+
+						<form action="" method="post" id="forum-topic-form" class="standard-form">
+
+							<?php do_action( 'groups_forum_new_topic_before' ); ?>
+
+							<a name="post-new"></a>
+							<h5><?php _e( 'Create New Topic:', 'buddypress' ); ?></h5>
+
+							<?php do_action( 'template_notices' ); ?>
+
+							<label><?php _e( 'Title:', 'buddypress' ); ?></label>
+							<input type="text" name="topic_title" id="topic_title" value="" maxlength="100" />
+
+							<label><?php _e( 'Content:', 'buddypress' ); ?></label>
+							<textarea name="topic_text" id="topic_text"></textarea>
+
+							<label><?php _e( 'Tags (comma separated):', 'buddypress' ); ?></label>
+							<input type="text" name="topic_tags" id="topic_tags" value="" />
+
+							<label><?php _e( 'Post In Group Forum:', 'buddypress' ); ?></label>
+							<select id="topic_group_id" name="topic_group_id">
+
+								<option value=""><?php /* translators: no option picked in select box */ _e( '----', 'buddypress' ); ?></option>
+
+								<?php while ( bp_groups() ) : bp_the_group(); ?>
+
+									<?php if ( bp_group_is_forum_enabled() && ( bp_current_user_can( 'bp_moderate' ) || 'public' == bp_get_group_status() || bp_group_is_member() ) ) : ?>
+
+										<option value="<?php bp_group_id(); ?>"><?php bp_group_name(); ?></option>
+
+									<?php endif; ?>
+
+								<?php endwhile; ?>
+
+							</select><!-- #topic_group_id -->
+
+							<?php do_action( 'groups_forum_new_topic_after' ); ?>
+
+							<div class="submit">
+								<input type="submit" name="submit_topic" id="submit" value="<?php _e( 'Post Topic', 'buddypress' ); ?>" />
+								<input type="button" name="submit_topic_cancel" id="submit_topic_cancel" value="<?php _e( 'Cancel', 'buddypress' ); ?>" />
+							</div>
+
+							<?php wp_nonce_field( 'bp_forums_new_topic' ); ?>
+
+						</form><!-- #forum-topic-form -->
+
+					<?php elseif ( bp_is_active( 'groups' ) ) : ?>
+
+						<div id="message" class="info">
+
+							<p><?php printf( __( "You are not a member of any groups so you don't have any group forums you can post in. To start posting, first find a group that matches the topic subject you'd like to start. If this group does not exist, why not <a href='%s'>create a new group</a>? Once you have joined or created the group you can post your topic in that group's forum.", 'buddypress' ), site_url( bp_get_groups_root_slug() . '/create/' ) ); ?></p>
+
+						</div>
+
+					<?php endif; ?>
+
+				<?php endif; ?>
+			</div><!-- #new-topic-post -->
+
+			<?php do_action( 'bp_after_new_topic_form' ); ?>
+
+			<?php do_action( 'bp_after_directory_forums_content' ); ?>
+
+		</div><!-- .padder -->
+	</div><!-- #content -->
+
+	<?php do_action( 'bp_after_directory_forums_page' ); ?>
+
+<?php get_sidebar( 'buddypress' ); ?>
+<?php get_footer( 'buddypress' ); ?>
Index: /tags/1.9/bp-themes/bp-default/functions.php
===================================================================
--- /tags/1.9/bp-themes/bp-default/functions.php	(revision 7684)
+++ /tags/1.9/bp-themes/bp-default/functions.php	(revision 7684)
@@ -0,0 +1,793 @@
+<?php
+/**
+ * BP-Default theme functions and definitions
+ *
+ * Sets up the theme and provides some helper functions. Some helper functions
+ * are used in the theme as custom template tags. Others are attached to action and
+ * filter hooks in WordPress and BuddyPress to change core functionality.
+ *
+ * The first function, bp_dtheme_setup(), sets up the theme by registering support
+ * for various features in WordPress, such as post thumbnails and navigation menus, and
+ * for BuddyPress, action buttons and javascript localisation.
+ *
+ * When using a child theme (see http://codex.wordpress.org/Theme_Development, http://codex.wordpress.org/Child_Themes
+ * and http://codex.buddypress.org/theme-development/building-a-buddypress-child-theme/), you can override
+ * certain functions (those wrapped in a function_exists() call) by defining them first in your
+ * child theme's functions.php file. The child theme's functions.php file is included before the
+ * parent theme's file, so the child theme functions would be used.
+ *
+ * Functions that are not pluggable (not wrapped in function_exists()) are instead attached
+ * to a filter or action hook. The hook can be removed by using remove_action() or
+ * remove_filter() and you can attach your own function to the hook.
+ *
+ * For more information on hooks, actions, and filters, see http://codex.wordpress.org/Plugin_API.
+ *
+ * @package BuddyPress
+ * @subpackage BP-Default
+ * @since BuddyPress (1.2)
+ */
+
+// Exit if accessed directly
+if ( ! defined( 'ABSPATH' ) ) exit;
+
+// If BuddyPress is not activated, switch back to the default WP theme and bail out
+if ( ! function_exists( 'bp_is_active' ) ) {
+	switch_theme( WP_DEFAULT_THEME, WP_DEFAULT_THEME );
+	return;
+}
+
+/**
+ * Set the content width based on the theme's design and stylesheet.
+ *
+ * Used to set the width of images and content. Should be equal to the width the theme
+ * is designed for, generally via the style.css stylesheet.
+ */
+if ( ! isset( $content_width ) )
+	$content_width = 591;
+
+if ( ! function_exists( 'bp_dtheme_setup' ) ) :
+/**
+ * Sets up theme defaults and registers support for various WordPress and BuddyPress features.
+ *
+ * Note that this function is hooked into the after_setup_theme hook, which runs
+ * before the init hook. The init hook is too late for some features, such as indicating
+ * support post thumbnails.
+ *
+ * To override bp_dtheme_setup() in a child theme, add your own bp_dtheme_setup to your child theme's
+ * functions.php file.
+ *
+ * @global BuddyPress $bp The one true BuddyPress instance
+ * @since BuddyPress (1.5)
+ */
+function bp_dtheme_setup() {
+
+	// Load the AJAX functions for the theme
+	require( get_template_directory() . '/_inc/ajax.php' );
+
+	// This theme styles the visual editor with editor-style.css to match the theme style.
+	add_editor_style();
+
+	// This theme comes with all the BuddyPress goodies
+	add_theme_support( 'buddypress' );
+
+	// This theme uses post thumbnails
+	add_theme_support( 'post-thumbnails' );
+
+	// Add default posts and comments RSS feed links to head
+	add_theme_support( 'automatic-feed-links' );
+
+	// Add responsive layout support to bp-default without forcing child
+	// themes to inherit it if they don't want to
+	add_theme_support( 'bp-default-responsive' );
+
+	// This theme uses wp_nav_menu() in one location.
+	register_nav_menus( array(
+		'primary' => __( 'Primary Navigation', 'buddypress' ),
+	) );
+
+	// This theme allows users to set a custom background
+	$custom_background_args = array(
+		'wp-head-callback' => 'bp_dtheme_custom_background_style'
+	);
+	add_theme_support( 'custom-background', $custom_background_args );
+
+	// Add custom header support if allowed
+	if ( !defined( 'BP_DTHEME_DISABLE_CUSTOM_HEADER' ) ) {
+		define( 'HEADER_TEXTCOLOR', 'FFFFFF' );
+
+		// The height and width of your custom header. You can hook into the theme's own filters to change these values.
+		// Add a filter to bp_dtheme_header_image_width and bp_dtheme_header_image_height to change these values.
+		define( 'HEADER_IMAGE_WIDTH',  apply_filters( 'bp_dtheme_header_image_width',  1250 ) );
+		define( 'HEADER_IMAGE_HEIGHT', apply_filters( 'bp_dtheme_header_image_height', 133  ) );
+
+		// We'll be using post thumbnails for custom header images on posts and pages. We want them to be 1250 pixels wide by 133 pixels tall.
+		// Larger images will be auto-cropped to fit, smaller ones will be ignored.
+		set_post_thumbnail_size( HEADER_IMAGE_WIDTH, HEADER_IMAGE_HEIGHT, true );
+
+		// Add a way for the custom header to be styled in the admin panel that controls custom headers.
+		$custom_header_args = array(
+			'wp-head-callback' => 'bp_dtheme_header_style',
+			'admin-head-callback' => 'bp_dtheme_admin_header_style'
+		);
+		add_theme_support( 'custom-header', $custom_header_args );
+	}
+
+	if ( ! is_admin() || ( defined( 'DOING_AJAX' ) && DOING_AJAX ) ) {
+		// Register buttons for the relevant component templates
+		// Friends button
+		if ( bp_is_active( 'friends' ) )
+			add_action( 'bp_member_header_actions',    'bp_add_friend_button',           5 );
+
+		// Activity button
+		if ( bp_is_active( 'activity' ) && bp_activity_do_mentions() )
+			add_action( 'bp_member_header_actions',    'bp_send_public_message_button',  20 );
+
+		// Messages button
+		if ( bp_is_active( 'messages' ) )
+			add_action( 'bp_member_header_actions',    'bp_send_private_message_button', 20 );
+
+		// Group buttons
+		if ( bp_is_active( 'groups' ) ) {
+			add_action( 'bp_group_header_actions',     'bp_group_join_button',           5 );
+			add_action( 'bp_group_header_actions',     'bp_group_new_topic_button',      20 );
+			add_action( 'bp_directory_groups_actions', 'bp_group_join_button' );
+		}
+
+		// Blog button
+		if ( bp_is_active( 'blogs' ) )
+			add_action( 'bp_directory_blogs_actions',  'bp_blogs_visit_blog_button' );
+	}
+}
+add_action( 'after_setup_theme', 'bp_dtheme_setup' );
+endif;
+
+if ( !function_exists( 'bp_dtheme_enqueue_scripts' ) ) :
+/**
+ * Enqueue theme javascript safely
+ *
+ * @see http://codex.wordpress.org/Function_Reference/wp_enqueue_script
+ * @since BuddyPress (1.5)
+ */
+function bp_dtheme_enqueue_scripts() {
+
+	// Enqueue the global JS - Ajax will not work without it
+	wp_enqueue_script( 'dtheme-ajax-js', get_template_directory_uri() . '/_inc/global.js', array( 'jquery' ), bp_get_version() );
+
+	// Add words that we need to use in JS to the end of the page so they can be translated and still used.
+	$params = array(
+		'my_favs'           => __( 'My Favorites', 'buddypress' ),
+		'accepted'          => __( 'Accepted', 'buddypress' ),
+		'rejected'          => __( 'Rejected', 'buddypress' ),
+		'show_all_comments' => __( 'Show all comments for this thread', 'buddypress' ),
+		'show_x_comments'   => __( 'Show all %d comments', 'buddypress' ),
+		'show_all'          => __( 'Show all', 'buddypress' ),
+		'comments'          => __( 'comments', 'buddypress' ),
+		'close'             => __( 'Close', 'buddypress' ),
+		'view'              => __( 'View', 'buddypress' ),
+		'mark_as_fav'	    => __( 'Favorite', 'buddypress' ),
+		'remove_fav'	    => __( 'Remove Favorite', 'buddypress' ),
+		'unsaved_changes'   => __( 'Your profile has unsaved changes. If you leave the page, the changes will be lost.', 'buddypress' ),
+	);
+	wp_localize_script( 'dtheme-ajax-js', 'BP_DTheme', $params );
+
+	// Maybe enqueue comment reply JS
+	if ( is_singular() && bp_is_blog_page() && get_option( 'thread_comments' ) )
+		wp_enqueue_script( 'comment-reply' );
+}
+add_action( 'wp_enqueue_scripts', 'bp_dtheme_enqueue_scripts' );
+endif;
+
+if ( !function_exists( 'bp_dtheme_enqueue_styles' ) ) :
+/**
+ * Enqueue theme CSS safely
+ *
+ * For maximum flexibility, BuddyPress Default's stylesheet is enqueued, using wp_enqueue_style().
+ * If you're building a child theme of bp-default, your stylesheet will also be enqueued,
+ * automatically, as dependent on bp-default's CSS. For this reason, bp-default child themes are
+ * not recommended to include bp-default's stylesheet using @import.
+ *
+ * If you would prefer to use @import, or would like to change the way in which stylesheets are
+ * enqueued, you can override bp_dtheme_enqueue_styles() in your theme's functions.php file.
+ *
+ * @see http://codex.wordpress.org/Function_Reference/wp_enqueue_style
+ * @see http://codex.buddypress.org/releases/1-5-developer-and-designer-information/
+ * @since BuddyPress (1.5)
+ */
+function bp_dtheme_enqueue_styles() {
+
+	// Register our main stylesheet
+	wp_register_style( 'bp-default-main', get_template_directory_uri() . '/_inc/css/default.css', array(), bp_get_version() );
+
+	// If the current theme is a child of bp-default, enqueue its stylesheet
+	if ( is_child_theme() && 'bp-default' == get_template() ) {
+		wp_enqueue_style( get_stylesheet(), get_stylesheet_uri(), array( 'bp-default-main' ), bp_get_version() );
+	}
+
+	// Enqueue the main stylesheet
+	wp_enqueue_style( 'bp-default-main' );
+
+	// Default CSS RTL
+	if ( is_rtl() )
+		wp_enqueue_style( 'bp-default-main-rtl',  get_template_directory_uri() . '/_inc/css/default-rtl.css', array( 'bp-default-main' ), bp_get_version() );
+
+	// Responsive layout
+	if ( current_theme_supports( 'bp-default-responsive' ) ) {
+		wp_enqueue_style( 'bp-default-responsive', get_template_directory_uri() . '/_inc/css/responsive.css', array( 'bp-default-main' ), bp_get_version() );
+
+		if ( is_rtl() ) {
+			wp_enqueue_style( 'bp-default-responsive-rtl', get_template_directory_uri() . '/_inc/css/responsive-rtl.css', array( 'bp-default-responsive' ), bp_get_version() );
+		}
+	}
+}
+add_action( 'wp_enqueue_scripts', 'bp_dtheme_enqueue_styles' );
+endif;
+
+if ( !function_exists( 'bp_dtheme_admin_header_style' ) ) :
+/**
+ * Styles the header image displayed on the Appearance > Header admin panel.
+ *
+ * Referenced via add_custom_image_header() in bp_dtheme_setup().
+ *
+ * @since BuddyPress (1.2)
+ */
+function bp_dtheme_admin_header_style() {
+?>
+	<style type="text/css">
+		#headimg {
+			position: relative;
+			color: #fff;
+			background: url(<?php header_image(); ?>);
+			-moz-border-radius-bottomleft: 6px;
+			-webkit-border-bottom-left-radius: 6px;
+			-moz-border-radius-bottomright: 6px;
+			-webkit-border-bottom-right-radius: 6px;
+			margin-bottom: 20px;
+			height: 133px;
+		}
+
+		#headimg h1{
+			position: absolute;
+			bottom: 15px;
+			left: 15px;
+			width: 44%;
+			margin: 0;
+			font-family: Arial, Tahoma, sans-serif;
+		}
+		#headimg h1 a{
+			color:#<?php header_textcolor(); ?>;
+			text-decoration: none;
+			border-bottom: none;
+		}
+		#headimg #desc{
+			color:#<?php header_textcolor(); ?>;
+			font-size:1em;
+			margin-top:-0.5em;
+		}
+
+		#desc {
+			display: none;
+		}
+
+		<?php if ( 'blank' == get_header_textcolor() ) { ?>
+		#headimg h1, #headimg #desc {
+			display: none;
+		}
+		#headimg h1 a, #headimg #desc {
+			color:#<?php echo HEADER_TEXTCOLOR; ?>;
+		}
+		<?php } ?>
+	</style>
+<?php
+}
+endif;
+
+if ( !function_exists( 'bp_dtheme_custom_background_style' ) ) :
+/**
+ * The style for the custom background image or colour.
+ *
+ * Referenced via add_custom_background() in bp_dtheme_setup().
+ *
+ * @see _custom_background_cb()
+ * @since BuddyPress (1.5)
+ */
+function bp_dtheme_custom_background_style() {
+	$background = get_background_image();
+	$color = get_background_color();
+	if ( ! $background && ! $color )
+		return;
+
+	$style = $color ? "background-color: #$color;" : '';
+
+	if ( $style && !$background ) {
+		$style .= ' background-image: none;';
+
+	} elseif ( $background ) {
+		$image = " background-image: url('$background');";
+
+		$repeat = get_theme_mod( 'background_repeat', 'repeat' );
+		if ( ! in_array( $repeat, array( 'no-repeat', 'repeat-x', 'repeat-y', 'repeat' ) ) )
+			$repeat = 'repeat';
+		$repeat = " background-repeat: $repeat;";
+
+		$position = get_theme_mod( 'background_position_x', 'left' );
+		if ( ! in_array( $position, array( 'center', 'right', 'left' ) ) )
+			$position = 'left';
+		$position = " background-position: top $position;";
+
+		$attachment = get_theme_mod( 'background_attachment', 'scroll' );
+		if ( ! in_array( $attachment, array( 'fixed', 'scroll' ) ) )
+			$attachment = 'scroll';
+		$attachment = " background-attachment: $attachment;";
+
+		$style .= $image . $repeat . $position . $attachment;
+	}
+?>
+	<style type="text/css">
+		body { <?php echo trim( $style ); ?> }
+	</style>
+<?php
+}
+endif;
+
+if ( !function_exists( 'bp_dtheme_header_style' ) ) :
+/**
+ * The styles for the post thumbnails / custom page headers.
+ *
+ * Referenced via add_custom_image_header() in bp_dtheme_setup().
+ *
+ * @global WP_Query $post The current WP_Query object for the current post or page
+ * @since BuddyPress (1.2)
+ */
+function bp_dtheme_header_style() {
+	global $post;
+
+	$header_image = '';
+
+	if ( is_singular() && current_theme_supports( 'post-thumbnails' ) && has_post_thumbnail( $post->ID ) ) {
+		$image = wp_get_attachment_image_src( get_post_thumbnail_id( $post->ID ), 'post-thumbnail' );
+
+		// $src, $width, $height
+		if ( !empty( $image ) && $image[1] >= HEADER_IMAGE_WIDTH )
+			$header_image = $image[0];
+		else
+			$header_image = get_header_image();
+
+	} else {
+		$header_image = get_header_image();
+	}
+?>
+
+	<style type="text/css">
+		<?php if ( !empty( $header_image ) ) : ?>
+			#header { background-image: url(<?php echo $header_image ?>); }
+		<?php endif; ?>
+
+		<?php if ( 'blank' == get_header_textcolor() ) { ?>
+		#header h1, #header #desc { display: none; }
+		<?php } else { ?>
+		#header h1 a, #desc { color:#<?php header_textcolor(); ?>; }
+		<?php } ?>
+	</style>
+
+<?php
+}
+endif;
+
+if ( !function_exists( 'bp_dtheme_widgets_init' ) ) :
+/**
+ * Register widgetised areas, including one sidebar and four widget-ready columns in the footer.
+ *
+ * To override bp_dtheme_widgets_init() in a child theme, remove the action hook and add your own
+ * function tied to the init hook.
+ *
+ * @since BuddyPress (1.5)
+ */
+function bp_dtheme_widgets_init() {
+
+	// Area 1, located in the sidebar. Empty by default.
+	register_sidebar( array(
+		'name'          => 'Sidebar',
+		'id'            => 'sidebar-1',
+		'description'   => __( 'The sidebar widget area', 'buddypress' ),
+		'before_widget' => '<div id="%1$s" class="widget %2$s">',
+		'after_widget'  => '</div>',
+		'before_title'  => '<h3 class="widgettitle">',
+		'after_title'   => '</h3>'
+	) );
+
+	// Area 2, located in the footer. Empty by default.
+	register_sidebar( array(
+		'name' => __( 'First Footer Widget Area', 'buddypress' ),
+		'id' => 'first-footer-widget-area',
+		'description' => __( 'The first footer widget area', 'buddypress' ),
+		'before_widget' => '<li id="%1$s" class="widget %2$s">',
+		'after_widget' => '</li>',
+		'before_title' => '<h3 class="widgettitle">',
+		'after_title' => '</h3>',
+	) );
+
+	// Area 3, located in the footer. Empty by default.
+	register_sidebar( array(
+		'name' => __( 'Second Footer Widget Area', 'buddypress' ),
+		'id' => 'second-footer-widget-area',
+		'description' => __( 'The second footer widget area', 'buddypress' ),
+		'before_widget' => '<li id="%1$s" class="widget %2$s">',
+		'after_widget' => '</li>',
+		'before_title' => '<h3 class="widgettitle">',
+		'after_title' => '</h3>',
+	) );
+
+	// Area 4, located in the footer. Empty by default.
+	register_sidebar( array(
+		'name' => __( 'Third Footer Widget Area', 'buddypress' ),
+		'id' => 'third-footer-widget-area',
+		'description' => __( 'The third footer widget area', 'buddypress' ),
+		'before_widget' => '<li id="%1$s" class="widget %2$s">',
+		'after_widget' => '</li>',
+		'before_title' => '<h3 class="widgettitle">',
+		'after_title' => '</h3>',
+	) );
+
+	// Area 5, located in the footer. Empty by default.
+	register_sidebar( array(
+		'name' => __( 'Fourth Footer Widget Area', 'buddypress' ),
+		'id' => 'fourth-footer-widget-area',
+		'description' => __( 'The fourth footer widget area', 'buddypress' ),
+		'before_widget' => '<li id="%1$s" class="widget %2$s">',
+		'after_widget' => '</li>',
+		'before_title' => '<h3 class="widgettitle">',
+		'after_title' => '</h3>',
+	) );
+}
+add_action( 'widgets_init', 'bp_dtheme_widgets_init' );
+endif;
+
+if ( !function_exists( 'bp_dtheme_blog_comments' ) ) :
+/**
+ * Template for comments and pingbacks.
+ *
+ * To override this walker in a child theme without modifying the comments template
+ * simply create your own bp_dtheme_blog_comments(), and that function will be used instead.
+ *
+ * Used as a callback by wp_list_comments() for displaying the comments.
+ *
+ * @param mixed $comment Comment record from database
+ * @param array $args Arguments from wp_list_comments() call
+ * @param int $depth Comment nesting level
+ * @see wp_list_comments()
+ * @since BuddyPress (1.2)
+ */
+function bp_dtheme_blog_comments( $comment, $args, $depth ) {
+	$GLOBALS['comment'] = $comment;
+
+	if ( 'pingback' == $comment->comment_type )
+		return false;
+
+	if ( 1 == $depth )
+		$avatar_size = 50;
+	else
+		$avatar_size = 25;
+	?>
+
+	<li <?php comment_class(); ?> id="comment-<?php comment_ID(); ?>">
+		<div class="comment-avatar-box">
+			<div class="avb">
+				<a href="<?php echo get_comment_author_url(); ?>" rel="nofollow">
+					<?php if ( $comment->user_id ) : ?>
+						<?php echo bp_core_fetch_avatar( array( 'item_id' => $comment->user_id, 'width' => $avatar_size, 'height' => $avatar_size, 'email' => $comment->comment_author_email ) ); ?>
+					<?php else : ?>
+						<?php echo get_avatar( $comment, $avatar_size ); ?>
+					<?php endif; ?>
+				</a>
+			</div>
+		</div>
+
+		<div class="comment-content">
+			<div class="comment-meta">
+				<p>
+					<?php
+						/* translators: 1: comment author url, 2: comment author name, 3: comment permalink, 4: comment date/timestamp*/
+						printf( __( '<a href="%1$s" rel="nofollow">%2$s</a> said on <a href="%3$s"><span class="time-since">%4$s</span></a>', 'buddypress' ), get_comment_author_url(), get_comment_author(), get_comment_link(), get_comment_date() );
+					?>
+				</p>
+			</div>
+
+			<div class="comment-entry">
+				<?php if ( $comment->comment_approved == '0' ) : ?>
+				 	<em class="moderate"><?php _e( 'Your comment is awaiting moderation.', 'buddypress' ); ?></em>
+				<?php endif; ?>
+
+				<?php comment_text(); ?>
+			</div>
+
+			<div class="comment-options">
+					<?php if ( comments_open() ) : ?>
+						<?php comment_reply_link( array( 'depth' => $depth, 'max_depth' => $args['max_depth'] ) ); ?>
+					<?php endif; ?>
+
+					<?php if ( current_user_can( 'edit_comment', $comment->comment_ID ) ) : ?>
+						<?php printf( '<a class="button comment-edit-link bp-secondary-action" href="%1$s" title="%2$s">%3$s</a> ', get_edit_comment_link( $comment->comment_ID ), esc_attr__( 'Edit comment', 'buddypress' ), __( 'Edit', 'buddypress' ) ); ?>
+					<?php endif; ?>
+
+			</div>
+
+		</div>
+
+<?php
+}
+endif;
+
+if ( !function_exists( 'bp_dtheme_page_on_front' ) ) :
+/**
+ * Return the ID of a page set as the home page.
+ *
+ * @return int|bool ID of page set as the home page
+ * @since BuddyPress (1.2)
+ */
+function bp_dtheme_page_on_front() {
+	if ( 'page' != get_option( 'show_on_front' ) )
+		return false;
+
+	return apply_filters( 'bp_dtheme_page_on_front', get_option( 'page_on_front' ) );
+}
+endif;
+
+if ( !function_exists( 'bp_dtheme_activity_secondary_avatars' ) ) :
+/**
+ * Add secondary avatar image to this activity stream's record, if supported.
+ *
+ * @param string $action The text of this activity
+ * @param BP_Activity_Activity $activity Activity object
+ * @package BuddyPress Theme
+ * @return string
+ * @since BuddyPress (1.2.6)
+ */
+function bp_dtheme_activity_secondary_avatars( $action, $activity ) {
+	switch ( $activity->component ) {
+		case 'groups' :
+		case 'friends' :
+			// Only insert avatar if one exists
+			if ( $secondary_avatar = bp_get_activity_secondary_avatar() ) {
+				$reverse_content = strrev( $action );
+				$position        = strpos( $reverse_content, 'a<' );
+				$action          = substr_replace( $action, $secondary_avatar, -$position - 2, 0 );
+			}
+			break;
+	}
+
+	return $action;
+}
+add_filter( 'bp_get_activity_action_pre_meta', 'bp_dtheme_activity_secondary_avatars', 10, 2 );
+endif;
+
+if ( !function_exists( 'bp_dtheme_show_notice' ) ) :
+/**
+ * Show a notice when the theme is activated - workaround by Ozh (http://old.nabble.com/Activation-hook-exist-for-themes--td25211004.html)
+ *
+ * @since BuddyPress (1.2)
+ */
+function bp_dtheme_show_notice() {
+	global $pagenow;
+
+	// Bail if bp-default theme was not just activated
+	if ( empty( $_GET['activated'] ) || ( 'themes.php' != $pagenow ) || !is_admin() )
+		return;
+
+	?>
+
+	<div id="message" class="updated fade">
+		<p><?php printf( __( 'Theme activated! This theme contains <a href="%s">custom header image</a> support and <a href="%s">sidebar widgets</a>.', 'buddypress' ), admin_url( 'themes.php?page=custom-header' ), admin_url( 'widgets.php' ) ); ?></p>
+	</div>
+
+	<style type="text/css">#message2, #message0 { display: none; }</style>
+
+	<?php
+}
+add_action( 'admin_notices', 'bp_dtheme_show_notice' );
+endif;
+
+if ( !function_exists( 'bp_dtheme_main_nav' ) ) :
+/**
+ * wp_nav_menu() callback from the main navigation in header.php
+ *
+ * Used when the custom menus haven't been configured.
+ *
+ * @param array Menu arguments from wp_nav_menu()
+ * @see wp_nav_menu()
+ * @since BuddyPress (1.5)
+ */
+function bp_dtheme_main_nav( $args ) {
+	$pages_args = array(
+		'depth'      => 0,
+		'echo'       => false,
+		'exclude'    => '',
+		'title_li'   => ''
+	);
+	$menu = wp_page_menu( $pages_args );
+	$menu = str_replace( array( '<div class="menu"><ul>', '</ul></div>' ), array( '<ul id="nav">', '</ul><!-- #nav -->' ), $menu );
+	echo $menu;
+
+	do_action( 'bp_nav_items' );
+}
+endif;
+
+if ( !function_exists( 'bp_dtheme_page_menu_args' ) ) :
+/**
+ * Get our wp_nav_menu() fallback, bp_dtheme_main_nav(), to show a home link.
+ *
+ * @param array $args Default values for wp_page_menu()
+ * @see wp_page_menu()
+ * @since BuddyPress (1.5)
+ */
+function bp_dtheme_page_menu_args( $args ) {
+	$args['show_home'] = true;
+	return $args;
+}
+add_filter( 'wp_page_menu_args', 'bp_dtheme_page_menu_args' );
+endif;
+
+if ( !function_exists( 'bp_dtheme_comment_form' ) ) :
+/**
+ * Applies BuddyPress customisations to the post comment form.
+ *
+ * @param array $default_labels The default options for strings, fields etc in the form
+ * @see comment_form()
+ * @since BuddyPress (1.5)
+ */
+function bp_dtheme_comment_form( $default_labels ) {
+
+	$commenter = wp_get_current_commenter();
+	$req       = get_option( 'require_name_email' );
+	$aria_req  = ( $req ? " aria-required='true'" : '' );
+	$fields    =  array(
+		'author' => '<p class="comment-form-author">' . '<label for="author">' . __( 'Name', 'buddypress' ) . ( $req ? '<span class="required"> *</span>' : '' ) . '</label> ' .
+		            '<input id="author" name="author" type="text" value="' . esc_attr( $commenter['comment_author'] ) . '" size="30"' . $aria_req . ' /></p>',
+		'email'  => '<p class="comment-form-email"><label for="email">' . __( 'Email', 'buddypress' ) . ( $req ? '<span class="required"> *</span>' : '' ) . '</label> ' .
+		            '<input id="email" name="email" type="text" value="' . esc_attr(  $commenter['comment_author_email'] ) . '" size="30"' . $aria_req . ' /></p>',
+		'url'    => '<p class="comment-form-url"><label for="url">' . __( 'Website', 'buddypress' ) . '</label>' .
+		            '<input id="url" name="url" type="text" value="' . esc_attr( $commenter['comment_author_url'] ) . '" size="30" /></p>',
+	);
+
+	$new_labels = array(
+		'comment_field'  => '<p class="form-textarea"><textarea name="comment" id="comment" cols="60" rows="10" aria-required="true"></textarea></p>',
+		'fields'         => apply_filters( 'comment_form_default_fields', $fields ),
+		'logged_in_as'   => '',
+		'must_log_in'    => '<p class="alert">' . sprintf( __( 'You must be <a href="%1$s">logged in</a> to post a comment.', 'buddypress' ), wp_login_url( get_permalink() ) )	. '</p>',
+		'title_reply'    => __( 'Leave a reply', 'buddypress' )
+	);
+
+	return apply_filters( 'bp_dtheme_comment_form', array_merge( $default_labels, $new_labels ) );
+}
+add_filter( 'comment_form_defaults', 'bp_dtheme_comment_form', 10 );
+endif;
+
+if ( !function_exists( 'bp_dtheme_before_comment_form' ) ) :
+/**
+ * Adds the user's avatar before the comment form box.
+ *
+ * The 'comment_form_top' action is used to insert our HTML within <div id="reply">
+ * so that the nested comments comment-reply javascript moves the entirety of the comment reply area.
+ *
+ * @see comment_form()
+ * @since BuddyPress (1.5)
+ */
+function bp_dtheme_before_comment_form() {
+?>
+	<div class="comment-avatar-box">
+		<div class="avb">
+			<?php if ( bp_loggedin_user_id() ) : ?>
+				<a href="<?php echo bp_loggedin_user_domain(); ?>">
+					<?php echo get_avatar( bp_loggedin_user_id(), 50 ); ?>
+				</a>
+			<?php else : ?>
+				<?php echo get_avatar( 0, 50 ); ?>
+			<?php endif; ?>
+		</div>
+	</div>
+
+	<div class="comment-content standard-form">
+<?php
+}
+add_action( 'comment_form_top', 'bp_dtheme_before_comment_form' );
+endif;
+
+if ( !function_exists( 'bp_dtheme_after_comment_form' ) ) :
+/**
+ * Closes tags opened in bp_dtheme_before_comment_form().
+ *
+ * @see bp_dtheme_before_comment_form()
+ * @see comment_form()
+ * @since BuddyPress (1.5)
+ */
+function bp_dtheme_after_comment_form() {
+?>
+
+	</div><!-- .comment-content standard-form -->
+
+<?php
+}
+add_action( 'comment_form', 'bp_dtheme_after_comment_form' );
+endif;
+
+if ( !function_exists( 'bp_dtheme_sidebar_login_redirect_to' ) ) :
+/**
+ * Adds a hidden "redirect_to" input field to the sidebar login form.
+ *
+ * @since BuddyPress (1.5)
+ */
+function bp_dtheme_sidebar_login_redirect_to() {
+	$redirect_to = !empty( $_REQUEST['redirect_to'] ) ? $_REQUEST['redirect_to'] : '';
+	$redirect_to = apply_filters( 'bp_no_access_redirect', $redirect_to ); ?>
+
+	<input type="hidden" name="redirect_to" value="<?php echo esc_url( $redirect_to ); ?>" />
+
+<?php
+}
+add_action( 'bp_sidebar_login_form', 'bp_dtheme_sidebar_login_redirect_to' );
+endif;
+
+if ( !function_exists( 'bp_dtheme_content_nav' ) ) :
+/**
+ * Display navigation to next/previous pages when applicable
+ *
+ * @global WP_Query $wp_query
+ * @param string $nav_id DOM ID for this navigation
+ * @since BuddyPress (1.5)
+ */
+function bp_dtheme_content_nav( $nav_id ) {
+	global $wp_query;
+
+	if ( !empty( $wp_query->max_num_pages ) && $wp_query->max_num_pages > 1 ) : ?>
+
+		<div id="<?php echo $nav_id; ?>" class="navigation">
+			<div class="alignleft"><?php next_posts_link( __( '&larr; Previous Entries', 'buddypress' ) ); ?></div>
+			<div class="alignright"><?php previous_posts_link( __( 'Next Entries &rarr;', 'buddypress' ) ); ?></div>
+		</div><!-- #<?php echo $nav_id; ?> -->
+
+	<?php endif;
+}
+endif;
+
+/**
+ * Adds the no-js class to the body tag.
+ *
+ * This function ensures that the <body> element will have the 'no-js' class by default. If you're
+ * using JavaScript for some visual functionality in your theme, and you want to provide noscript
+ * support, apply those styles to body.no-js.
+ *
+ * The no-js class is removed by the JavaScript created in bp_dtheme_remove_nojs_body_class().
+ *
+ * @package BuddyPress
+ * @since BuddyPress (1.5).1
+ * @see bp_dtheme_remove_nojs_body_class()
+ */
+function bp_dtheme_add_nojs_body_class( $classes ) {
+	$classes[] = 'no-js';
+	return array_unique( $classes );
+}
+add_filter( 'bp_get_the_body_class', 'bp_dtheme_add_nojs_body_class' );
+
+/**
+ * Dynamically removes the no-js class from the <body> element.
+ *
+ * By default, the no-js class is added to the body (see bp_dtheme_add_no_js_body_class()). The
+ * JavaScript in this function is loaded into the <body> element immediately after the <body> tag
+ * (note that it's hooked to bp_before_header), and uses JavaScript to switch the 'no-js' body class
+ * to 'js'. If your theme has styles that should only apply for JavaScript-enabled users, apply them
+ * to body.js.
+ *
+ * This technique is borrowed from WordPress, wp-admin/admin-header.php.
+ *
+ * @package BuddyPress
+ * @since BuddyPress (1.5).1
+ * @see bp_dtheme_add_nojs_body_class()
+ */
+function bp_dtheme_remove_nojs_body_class() {
+?><script type="text/javascript">//<![CDATA[
+(function(){var c=document.body.className;c=c.replace(/no-js/,'js');document.body.className=c;})();
+//]]></script>
+<?php
+}
+add_action( 'bp_before_header', 'bp_dtheme_remove_nojs_body_class' );
+
+?>
Index: /tags/1.9/bp-themes/bp-default/groups/create.php
===================================================================
--- /tags/1.9/bp-themes/bp-default/groups/create.php	(revision 7684)
+++ /tags/1.9/bp-themes/bp-default/groups/create.php	(revision 7684)
@@ -0,0 +1,315 @@
+<?php
+
+/**
+ * BuddyPress - Create Group
+ *
+ * @package BuddyPress
+ * @subpackage bp-default
+ */
+
+get_header( 'buddypress' ); ?>
+
+	<div id="content">
+		<div class="padder">
+		
+		<?php do_action( 'bp_before_create_group_content_template' ); ?>
+
+		<form action="<?php bp_group_creation_form_action(); ?>" method="post" id="create-group-form" class="standard-form" enctype="multipart/form-data">
+			<h3><?php _e( 'Create a Group', 'buddypress' ); ?> &nbsp;<a class="button" href="<?php echo trailingslashit( bp_get_root_domain() . '/' . bp_get_groups_root_slug() ); ?>"><?php _e( 'Groups Directory', 'buddypress' ); ?></a></h3>
+
+			<?php do_action( 'bp_before_create_group' ); ?>
+
+			<div class="item-list-tabs no-ajax" id="group-create-tabs" role="navigation">
+				<ul>
+
+					<?php bp_group_creation_tabs(); ?>
+
+				</ul>
+			</div>
+
+			<?php do_action( 'template_notices' ); ?>
+
+			<div class="item-body" id="group-create-body">
+
+				<?php /* Group creation step 1: Basic group details */ ?>
+				<?php if ( bp_is_group_creation_step( 'group-details' ) ) : ?>
+
+					<?php do_action( 'bp_before_group_details_creation_step' ); ?>
+
+					<label for="group-name"><?php _e( 'Group Name (required)', 'buddypress' ); ?></label>
+					<input type="text" name="group-name" id="group-name" aria-required="true" value="<?php bp_new_group_name(); ?>" />
+
+					<label for="group-desc"><?php _e( 'Group Description (required)', 'buddypress' ); ?></label>
+					<textarea name="group-desc" id="group-desc" aria-required="true"><?php bp_new_group_description(); ?></textarea>
+
+					<?php
+					do_action( 'bp_after_group_details_creation_step' );
+					do_action( 'groups_custom_group_fields_editable' ); // @Deprecated
+
+					wp_nonce_field( 'groups_create_save_group-details' ); ?>
+
+				<?php endif; ?>
+
+				<?php /* Group creation step 2: Group settings */ ?>
+				<?php if ( bp_is_group_creation_step( 'group-settings' ) ) : ?>
+
+					<?php do_action( 'bp_before_group_settings_creation_step' ); ?>
+
+					<h4><?php _e( 'Privacy Options', 'buddypress' ); ?></h4>
+
+					<div class="radio">
+						<label><input type="radio" name="group-status" value="public"<?php if ( 'public' == bp_get_new_group_status() || !bp_get_new_group_status() ) { ?> checked="checked"<?php } ?> />
+							<strong><?php _e( 'This is a public group', 'buddypress' ); ?></strong>
+							<ul>
+								<li><?php _e( 'Any site member can join this group.', 'buddypress' ); ?></li>
+								<li><?php _e( 'This group will be listed in the groups directory and in search results.', 'buddypress' ); ?></li>
+								<li><?php _e( 'Group content and activity will be visible to any site member.', 'buddypress' ); ?></li>
+							</ul>
+						</label>
+
+						<label><input type="radio" name="group-status" value="private"<?php if ( 'private' == bp_get_new_group_status() ) { ?> checked="checked"<?php } ?> />
+							<strong><?php _e( 'This is a private group', 'buddypress' ); ?></strong>
+							<ul>
+								<li><?php _e( 'Only users who request membership and are accepted can join the group.', 'buddypress' ); ?></li>
+								<li><?php _e( 'This group will be listed in the groups directory and in search results.', 'buddypress' ); ?></li>
+								<li><?php _e( 'Group content and activity will only be visible to members of the group.', 'buddypress' ); ?></li>
+							</ul>
+						</label>
+
+						<label><input type="radio" name="group-status" value="hidden"<?php if ( 'hidden' == bp_get_new_group_status() ) { ?> checked="checked"<?php } ?> />
+							<strong><?php _e('This is a hidden group', 'buddypress'); ?></strong>
+							<ul>
+								<li><?php _e( 'Only users who are invited can join the group.', 'buddypress' ); ?></li>
+								<li><?php _e( 'This group will not be listed in the groups directory or search results.', 'buddypress' ); ?></li>
+								<li><?php _e( 'Group content and activity will only be visible to members of the group.', 'buddypress' ); ?></li>
+							</ul>
+						</label>
+					</div>
+
+					<h4><?php _e( 'Group Invitations', 'buddypress' ); ?></h4>
+
+					<p><?php _e( 'Which members of this group are allowed to invite others?', 'buddypress' ); ?></p>
+
+					<div class="radio">
+						<label>
+							<input type="radio" name="group-invite-status" value="members"<?php bp_group_show_invite_status_setting( 'members' ); ?> />
+							<strong><?php _e( 'All group members', 'buddypress' ); ?></strong>
+						</label>
+
+						<label>
+							<input type="radio" name="group-invite-status" value="mods"<?php bp_group_show_invite_status_setting( 'mods' ); ?> />
+							<strong><?php _e( 'Group admins and mods only', 'buddypress' ); ?></strong>
+						</label>
+
+						<label>
+							<input type="radio" name="group-invite-status" value="admins"<?php bp_group_show_invite_status_setting( 'admins' ); ?> />
+							<strong><?php _e( 'Group admins only', 'buddypress' ); ?></strong>
+						</label>
+					</div>
+
+					<?php if ( bp_is_active( 'forums' ) ) : ?>
+
+						<h4><?php _e( 'Group Forums', 'buddypress' ); ?></h4>
+
+						<?php if ( bp_forums_is_installed_correctly() ) : ?>
+
+							<p><?php _e( 'Should this group have a forum?', 'buddypress' ); ?></p>
+
+							<div class="checkbox">
+								<label><input type="checkbox" name="group-show-forum" id="group-show-forum" value="1"<?php checked( bp_get_new_group_enable_forum(), true, true ); ?> /> <?php _e( 'Enable discussion forum', 'buddypress' ); ?></label>
+							</div>
+						<?php elseif ( is_super_admin() ) : ?>
+
+							<p><?php printf( __( '<strong>Attention Site Admin:</strong> Group forums require the <a href="%s">correct setup and configuration</a> of a bbPress installation.', 'buddypress' ), bp_core_do_network_admin() ? network_admin_url( 'settings.php?page=bb-forums-setup' ) :  admin_url( 'admin.php?page=bb-forums-setup' ) ); ?></p>
+
+						<?php endif; ?>
+
+					<?php endif; ?>
+
+					<?php do_action( 'bp_after_group_settings_creation_step' ); ?>
+
+					<?php wp_nonce_field( 'groups_create_save_group-settings' ); ?>
+
+				<?php endif; ?>
+
+				<?php /* Group creation step 3: Avatar Uploads */ ?>
+				<?php if ( bp_is_group_creation_step( 'group-avatar' ) ) : ?>
+
+					<?php do_action( 'bp_before_group_avatar_creation_step' ); ?>
+
+					<?php if ( 'upload-image' == bp_get_avatar_admin_step() ) : ?>
+
+						<div class="left-menu">
+
+							<?php bp_new_group_avatar(); ?>
+
+						</div><!-- .left-menu -->
+
+						<div class="main-column">
+							<p><?php _e( "Upload an image to use as an avatar for this group. The image will be shown on the main group page, and in search results.", 'buddypress' ); ?></p>
+
+							<p>
+								<input type="file" name="file" id="file" />
+								<input type="submit" name="upload" id="upload" value="<?php _e( 'Upload Image', 'buddypress' ); ?>" />
+								<input type="hidden" name="action" id="action" value="bp_avatar_upload" />
+							</p>
+
+							<p><?php _e( 'To skip the avatar upload process, hit the "Next Step" button.', 'buddypress' ); ?></p>
+						</div><!-- .main-column -->
+
+					<?php endif; ?>
+
+					<?php if ( 'crop-image' == bp_get_avatar_admin_step() ) : ?>
+
+						<h3><?php _e( 'Crop Group Avatar', 'buddypress' ); ?></h3>
+
+						<img src="<?php bp_avatar_to_crop(); ?>" id="avatar-to-crop" class="avatar" alt="<?php _e( 'Avatar to crop', 'buddypress' ); ?>" />
+
+						<div id="avatar-crop-pane">
+							<img src="<?php bp_avatar_to_crop(); ?>" id="avatar-crop-preview" class="avatar" alt="<?php _e( 'Avatar preview', 'buddypress' ); ?>" />
+						</div>
+
+						<input type="submit" name="avatar-crop-submit" id="avatar-crop-submit" value="<?php _e( 'Crop Image', 'buddypress' ); ?>" />
+
+						<input type="hidden" name="image_src" id="image_src" value="<?php bp_avatar_to_crop_src(); ?>" />
+						<input type="hidden" name="upload" id="upload" />
+						<input type="hidden" id="x" name="x" />
+						<input type="hidden" id="y" name="y" />
+						<input type="hidden" id="w" name="w" />
+						<input type="hidden" id="h" name="h" />
+
+					<?php endif; ?>
+
+					<?php do_action( 'bp_after_group_avatar_creation_step' ); ?>
+
+					<?php wp_nonce_field( 'groups_create_save_group-avatar' ); ?>
+
+				<?php endif; ?>
+
+				<?php /* Group creation step 4: Invite friends to group */ ?>
+				<?php if ( bp_is_group_creation_step( 'group-invites' ) ) : ?>
+
+					<?php do_action( 'bp_before_group_invites_creation_step' ); ?>
+
+					<?php if ( bp_is_active( 'friends' ) && bp_get_total_friend_count( bp_loggedin_user_id() ) ) : ?>
+
+						<div class="left-menu">
+
+							<div id="invite-list">
+								<ul>
+									<?php bp_new_group_invite_friend_list(); ?>
+								</ul>
+
+								<?php wp_nonce_field( 'groups_invite_uninvite_user', '_wpnonce_invite_uninvite_user' ); ?>
+							</div>
+
+						</div><!-- .left-menu -->
+
+						<div class="main-column">
+
+							<div id="message" class="info">
+								<p><?php _e('Select people to invite from your friends list.', 'buddypress'); ?></p>
+							</div>
+
+							<?php /* The ID 'friend-list' is important for AJAX support. */ ?>
+							<ul id="friend-list" class="item-list" role="main">
+
+							<?php if ( bp_group_has_invites() ) : ?>
+
+								<?php while ( bp_group_invites() ) : bp_group_the_invite(); ?>
+
+									<li id="<?php bp_group_invite_item_id(); ?>">
+
+										<?php bp_group_invite_user_avatar(); ?>
+
+										<h4><?php bp_group_invite_user_link(); ?></h4>
+										<span class="activity"><?php bp_group_invite_user_last_active(); ?></span>
+
+										<div class="action">
+											<a class="remove" href="<?php bp_group_invite_user_remove_invite_url(); ?>" id="<?php bp_group_invite_item_id(); ?>"><?php _e( 'Remove Invite', 'buddypress' ); ?></a>
+										</div>
+									</li>
+
+								<?php endwhile; ?>
+
+								<?php wp_nonce_field( 'groups_send_invites', '_wpnonce_send_invites' ); ?>
+
+							<?php endif; ?>
+
+							</ul>
+
+						</div><!-- .main-column -->
+
+					<?php else : ?>
+
+						<div id="message" class="info">
+							<p><?php _e( 'Once you have built up friend connections you will be able to invite others to your group.', 'buddypress' ); ?></p>
+						</div>
+
+					<?php endif; ?>
+
+					<?php wp_nonce_field( 'groups_create_save_group-invites' ); ?>
+
+					<?php do_action( 'bp_after_group_invites_creation_step' ); ?>
+
+				<?php endif; ?>
+
+				<?php do_action( 'groups_custom_create_steps' ); // Allow plugins to add custom group creation steps ?>
+
+				<?php do_action( 'bp_before_group_creation_step_buttons' ); ?>
+
+				<?php if ( 'crop-image' != bp_get_avatar_admin_step() ) : ?>
+
+					<div class="submit" id="previous-next">
+
+						<?php /* Previous Button */ ?>
+						<?php if ( !bp_is_first_group_creation_step() ) : ?>
+
+							<input type="button" value="<?php _e( 'Back to Previous Step', 'buddypress' ); ?>" id="group-creation-previous" name="previous" onclick="location.href='<?php bp_group_creation_previous_link(); ?>'" />
+
+						<?php endif; ?>
+
+						<?php /* Next Button */ ?>
+						<?php if ( !bp_is_last_group_creation_step() && !bp_is_first_group_creation_step() ) : ?>
+
+							<input type="submit" value="<?php _e( 'Next Step', 'buddypress' ); ?>" id="group-creation-next" name="save" />
+
+						<?php endif;?>
+
+						<?php /* Create Button */ ?>
+						<?php if ( bp_is_first_group_creation_step() ) : ?>
+
+							<input type="submit" value="<?php _e( 'Create Group and Continue', 'buddypress' ); ?>" id="group-creation-create" name="save" />
+
+						<?php endif; ?>
+
+						<?php /* Finish Button */ ?>
+						<?php if ( bp_is_last_group_creation_step() ) : ?>
+
+							<input type="submit" value="<?php _e( 'Finish', 'buddypress' ); ?>" id="group-creation-finish" name="save" />
+
+						<?php endif; ?>
+					</div>
+
+				<?php endif;?>
+
+				<?php do_action( 'bp_after_group_creation_step_buttons' ); ?>
+
+				<?php /* Don't leave out this hidden field */ ?>
+				<input type="hidden" name="group_id" id="group_id" value="<?php bp_new_group_id(); ?>" />
+
+				<?php do_action( 'bp_directory_groups_content' ); ?>
+
+			</div><!-- .item-body -->
+
+			<?php do_action( 'bp_after_create_group' ); ?>
+
+		</form>
+		
+		<?php do_action( 'bp_after_create_group_content_template' ); ?>
+
+		</div><!-- .padder -->
+	</div><!-- #content -->
+
+<?php get_sidebar( 'buddypress' ); ?>
+<?php get_footer( 'buddypress' ); ?>
Index: /tags/1.9/bp-themes/bp-default/groups/groups-loop.php
===================================================================
--- /tags/1.9/bp-themes/bp-default/groups/groups-loop.php	(revision 7684)
+++ /tags/1.9/bp-themes/bp-default/groups/groups-loop.php	(revision 7684)
@@ -0,0 +1,100 @@
+<?php
+
+/**
+ * BuddyPress - Groups Loop
+ *
+ * Querystring is set via AJAX in _inc/ajax.php - bp_dtheme_object_filter()
+ *
+ * @package BuddyPress
+ * @subpackage bp-default
+ */
+
+?>
+
+<?php do_action( 'bp_before_groups_loop' ); ?>
+
+<?php if ( bp_has_groups( bp_ajax_querystring( 'groups' ) ) ) : ?>
+
+	<div id="pag-top" class="pagination">
+
+		<div class="pag-count" id="group-dir-count-top">
+
+			<?php bp_groups_pagination_count(); ?>
+
+		</div>
+
+		<div class="pagination-links" id="group-dir-pag-top">
+
+			<?php bp_groups_pagination_links(); ?>
+
+		</div>
+
+	</div>
+
+	<?php do_action( 'bp_before_directory_groups_list' ); ?>
+
+	<ul id="groups-list" class="item-list" role="main">
+
+	<?php while ( bp_groups() ) : bp_the_group(); ?>
+
+		<li <?php bp_group_class(); ?>>
+			<div class="item-avatar">
+				<a href="<?php bp_group_permalink(); ?>"><?php bp_group_avatar( 'type=thumb&width=50&height=50' ); ?></a>
+			</div>
+
+			<div class="item">
+				<div class="item-title"><a href="<?php bp_group_permalink(); ?>"><?php bp_group_name(); ?></a></div>
+				<div class="item-meta"><span class="activity"><?php printf( __( 'active %s', 'buddypress' ), bp_get_group_last_active() ); ?></span></div>
+
+				<div class="item-desc"><?php bp_group_description_excerpt(); ?></div>
+
+				<?php do_action( 'bp_directory_groups_item' ); ?>
+
+			</div>
+
+			<div class="action">
+
+				<?php do_action( 'bp_directory_groups_actions' ); ?>
+
+				<div class="meta">
+
+					<?php bp_group_type(); ?> / <?php bp_group_member_count(); ?>
+
+				</div>
+
+			</div>
+
+			<div class="clear"></div>
+		</li>
+
+	<?php endwhile; ?>
+
+	</ul>
+
+	<?php do_action( 'bp_after_directory_groups_list' ); ?>
+
+	<div id="pag-bottom" class="pagination">
+
+		<div class="pag-count" id="group-dir-count-bottom">
+
+			<?php bp_groups_pagination_count(); ?>
+
+		</div>
+
+		<div class="pagination-links" id="group-dir-pag-bottom">
+
+			<?php bp_groups_pagination_links(); ?>
+
+		</div>
+
+	</div>
+
+<?php else: ?>
+
+	<div id="message" class="info">
+		<p><?php _e( 'There were no groups found.', 'buddypress' ); ?></p>
+	</div>
+
+<?php endif; ?>
+
+<?php do_action( 'bp_after_groups_loop' ); ?>
Index: /tags/1.9/bp-themes/bp-default/groups/index.php
===================================================================
--- /tags/1.9/bp-themes/bp-default/groups/index.php	(revision 7684)
+++ /tags/1.9/bp-themes/bp-default/groups/index.php	(revision 7684)
@@ -0,0 +1,92 @@
+<?php
+
+/**
+ * BuddyPress - Groups Directory
+ *
+ * @package BuddyPress
+ * @subpackage bp-default
+ */
+
+get_header( 'buddypress' ); ?>
+
+	<?php do_action( 'bp_before_directory_groups_page' ); ?>
+
+	<div id="content">
+		<div class="padder">
+
+		<?php do_action( 'bp_before_directory_groups' ); ?>
+
+		<form action="" method="post" id="groups-directory-form" class="dir-form">
+
+			<h3><?php _e( 'Groups Directory', 'buddypress' ); ?><?php if ( is_user_logged_in() && bp_user_can_create_groups() ) : ?> &nbsp;<a class="button" href="<?php echo trailingslashit( bp_get_root_domain() . '/' . bp_get_groups_root_slug() . '/create' ); ?>"><?php _e( 'Create a Group', 'buddypress' ); ?></a><?php endif; ?></h3>
+
+			<?php do_action( 'bp_before_directory_groups_content' ); ?>
+
+			<div id="group-dir-search" class="dir-search" role="search">
+
+				<?php bp_directory_groups_search_form(); ?>
+
+			</div><!-- #group-dir-search -->
+
+			<?php do_action( 'template_notices' ); ?>
+
+			<div class="item-list-tabs" role="navigation">
+				<ul>
+					<li class="selected" id="groups-all"><a href="<?php echo trailingslashit( bp_get_root_domain() . '/' . bp_get_groups_root_slug() ); ?>"><?php printf( __( 'All Groups <span>%s</span>', 'buddypress' ), bp_get_total_group_count() ); ?></a></li>
+
+					<?php if ( is_user_logged_in() && bp_get_total_group_count_for_user( bp_loggedin_user_id() ) ) : ?>
+
+						<li id="groups-personal"><a href="<?php echo trailingslashit( bp_loggedin_user_domain() . bp_get_groups_slug() . '/my-groups' ); ?>"><?php printf( __( 'My Groups <span>%s</span>', 'buddypress' ), bp_get_total_group_count_for_user( bp_loggedin_user_id() ) ); ?></a></li>
+
+					<?php endif; ?>
+
+					<?php do_action( 'bp_groups_directory_group_filter' ); ?>
+
+				</ul>
+			</div><!-- .item-list-tabs -->
+
+			<div class="item-list-tabs" id="subnav" role="navigation">
+				<ul>
+
+					<?php do_action( 'bp_groups_directory_group_types' ); ?>
+
+					<li id="groups-order-select" class="last filter">
+
+						<label for="groups-order-by"><?php _e( 'Order By:', 'buddypress' ); ?></label>
+						<select id="groups-order-by">
+							<option value="active"><?php _e( 'Last Active', 'buddypress' ); ?></option>
+							<option value="popular"><?php _e( 'Most Members', 'buddypress' ); ?></option>
+							<option value="newest"><?php _e( 'Newly Created', 'buddypress' ); ?></option>
+							<option value="alphabetical"><?php _e( 'Alphabetical', 'buddypress' ); ?></option>
+
+							<?php do_action( 'bp_groups_directory_order_options' ); ?>
+
+						</select>
+					</li>
+				</ul>
+			</div>
+
+			<div id="groups-dir-list" class="groups dir-list">
+
+				<?php locate_template( array( 'groups/groups-loop.php' ), true ); ?>
+
+			</div><!-- #groups-dir-list -->
+
+			<?php do_action( 'bp_directory_groups_content' ); ?>
+
+			<?php wp_nonce_field( 'directory_groups', '_wpnonce-groups-filter' ); ?>
+
+			<?php do_action( 'bp_after_directory_groups_content' ); ?>
+
+		</form><!-- #groups-directory-form -->
+
+		<?php do_action( 'bp_after_directory_groups' ); ?>
+
+		</div><!-- .padder -->
+	</div><!-- #content -->
+
+	<?php do_action( 'bp_after_directory_groups_page' ); ?>
+
+<?php get_sidebar( 'buddypress' ); ?>
+<?php get_footer( 'buddypress' ); ?>
+
Index: /tags/1.9/bp-themes/bp-default/groups/single/activity.php
===================================================================
--- /tags/1.9/bp-themes/bp-default/groups/single/activity.php	(revision 7684)
+++ /tags/1.9/bp-themes/bp-default/groups/single/activity.php	(revision 7684)
@@ -0,0 +1,39 @@
+<div class="item-list-tabs no-ajax" id="subnav" role="navigation">
+	<ul>
+		<li class="feed"><a href="<?php bp_group_activity_feed_link(); ?>" title="<?php _e( 'RSS Feed', 'buddypress' ); ?>"><?php _e( 'RSS', 'buddypress' ); ?></a></li>
+
+		<?php do_action( 'bp_group_activity_syndication_options' ); ?>
+
+		<li id="activity-filter-select" class="last">
+			<label for="activity-filter-by"><?php _e( 'Show:', 'buddypress' ); ?></label> 
+			<select id="activity-filter-by">
+				<option value="-1"><?php _e( 'Everything', 'buddypress' ); ?></option>
+				<option value="activity_update"><?php _e( 'Updates', 'buddypress' ); ?></option>
+
+				<?php if ( bp_is_active( 'forums' ) ) : ?>
+					<option value="new_forum_topic"><?php _e( 'Forum Topics', 'buddypress' ); ?></option>
+					<option value="new_forum_post"><?php _e( 'Forum Replies', 'buddypress' ); ?></option>
+				<?php endif; ?>
+
+				<option value="joined_group"><?php _e( 'Group Memberships', 'buddypress' ); ?></option>
+
+				<?php do_action( 'bp_group_activity_filter_options' ); ?>
+			</select>
+		</li>
+	</ul>
+</div><!-- .item-list-tabs -->
+
+<?php do_action( 'bp_before_group_activity_post_form' ); ?>
+
+<?php if ( is_user_logged_in() && bp_group_is_member() ) : ?>
+	<?php locate_template( array( 'activity/post-form.php'), true ); ?>
+<?php endif; ?>
+
+<?php do_action( 'bp_after_group_activity_post_form' ); ?>
+<?php do_action( 'bp_before_group_activity_content' ); ?>
+
+<div class="activity single-group" role="main">
+	<?php locate_template( array( 'activity/activity-loop.php' ), true ); ?>
+</div><!-- .activity.single-group -->
+
+<?php do_action( 'bp_after_group_activity_content' ); ?>
Index: /tags/1.9/bp-themes/bp-default/groups/single/admin.php
===================================================================
--- /tags/1.9/bp-themes/bp-default/groups/single/admin.php	(revision 7684)
+++ /tags/1.9/bp-themes/bp-default/groups/single/admin.php	(revision 7684)
@@ -0,0 +1,373 @@
+<div class="item-list-tabs no-ajax" id="subnav" role="navigation">
+	<ul>
+		<?php bp_group_admin_tabs(); ?>
+	</ul>
+</div><!-- .item-list-tabs -->
+
+<form action="<?php bp_group_admin_form_action(); ?>" name="group-settings-form" id="group-settings-form" class="standard-form" method="post" enctype="multipart/form-data" role="main">
+
+<?php do_action( 'bp_before_group_admin_content' ); ?>
+
+<?php /* Edit Group Details */ ?>
+<?php if ( bp_is_group_admin_screen( 'edit-details' ) ) : ?>
+
+	<?php do_action( 'bp_before_group_details_admin' ); ?>
+
+	<label for="group-name"><?php _e( 'Group Name (required)', 'buddypress' ); ?></label>
+	<input type="text" name="group-name" id="group-name" value="<?php bp_group_name(); ?>" aria-required="true" />
+
+	<label for="group-desc"><?php _e( 'Group Description (required)', 'buddypress' ); ?></label>
+	<textarea name="group-desc" id="group-desc" aria-required="true"><?php bp_group_description_editable(); ?></textarea>
+
+	<?php do_action( 'groups_custom_group_fields_editable' ); ?>
+
+	<p>
+		<label for="group-notifiy-members">
+			<input type="checkbox" name="group-notify-members" value="1" /> <?php _e( 'Notify group members of these changes via email', 'buddypress' ); ?>
+		</label>
+	</p>
+
+	<?php do_action( 'bp_after_group_details_admin' ); ?>
+
+	<p><input type="submit" value="<?php _e( 'Save Changes', 'buddypress' ); ?>" id="save" name="save" /></p>
+	<?php wp_nonce_field( 'groups_edit_group_details' ); ?>
+
+<?php endif; ?>
+
+<?php /* Manage Group Settings */ ?>
+<?php if ( bp_is_group_admin_screen( 'group-settings' ) ) : ?>
+
+	<?php do_action( 'bp_before_group_settings_admin' ); ?>
+
+	<?php if ( bp_is_active( 'forums' ) ) : ?>
+
+		<?php if ( bp_forums_is_installed_correctly() ) : ?>
+
+			<div class="checkbox">
+				<label><input type="checkbox" name="group-show-forum" id="group-show-forum" value="1"<?php bp_group_show_forum_setting(); ?> /> <?php _e( 'Enable discussion forum', 'buddypress' ); ?></label>
+			</div>
+
+			<hr />
+
+		<?php endif; ?>
+
+	<?php endif; ?>
+
+	<h4><?php _e( 'Privacy Options', 'buddypress' ); ?></h4>
+
+	<div class="radio">
+		<label>
+			<input type="radio" name="group-status" value="public"<?php bp_group_show_status_setting( 'public' ); ?> />
+			<strong><?php _e( 'This is a public group', 'buddypress' ); ?></strong>
+			<ul>
+				<li><?php _e( 'Any site member can join this group.', 'buddypress' ); ?></li>
+				<li><?php _e( 'This group will be listed in the groups directory and in search results.', 'buddypress' ); ?></li>
+				<li><?php _e( 'Group content and activity will be visible to any site member.', 'buddypress' ); ?></li>
+			</ul>
+		</label>
+
+		<label>
+			<input type="radio" name="group-status" value="private"<?php bp_group_show_status_setting( 'private' ); ?> />
+			<strong><?php _e( 'This is a private group', 'buddypress' ); ?></strong>
+			<ul>
+				<li><?php _e( 'Only users who request membership and are accepted can join the group.', 'buddypress' ); ?></li>
+				<li><?php _e( 'This group will be listed in the groups directory and in search results.', 'buddypress' ); ?></li>
+				<li><?php _e( 'Group content and activity will only be visible to members of the group.', 'buddypress' ); ?></li>
+			</ul>
+		</label>
+
+		<label>
+			<input type="radio" name="group-status" value="hidden"<?php bp_group_show_status_setting( 'hidden' ); ?> />
+			<strong><?php _e( 'This is a hidden group', 'buddypress' ); ?></strong>
+			<ul>
+				<li><?php _e( 'Only users who are invited can join the group.', 'buddypress' ); ?></li>
+				<li><?php _e( 'This group will not be listed in the groups directory or search results.', 'buddypress' ); ?></li>
+				<li><?php _e( 'Group content and activity will only be visible to members of the group.', 'buddypress' ); ?></li>
+			</ul>
+		</label>
+	</div>
+
+	<hr />
+
+	<h4><?php _e( 'Group Invitations', 'buddypress' ); ?></h4>
+
+	<p><?php _e( 'Which members of this group are allowed to invite others?', 'buddypress' ); ?></p>
+
+	<div class="radio">
+		<label>
+			<input type="radio" name="group-invite-status" value="members"<?php bp_group_show_invite_status_setting( 'members' ); ?> />
+			<strong><?php _e( 'All group members', 'buddypress' ); ?></strong>
+		</label>
+
+		<label>
+			<input type="radio" name="group-invite-status" value="mods"<?php bp_group_show_invite_status_setting( 'mods' ); ?> />
+			<strong><?php _e( 'Group admins and mods only', 'buddypress' ); ?></strong>
+		</label>
+
+		<label>
+			<input type="radio" name="group-invite-status" value="admins"<?php bp_group_show_invite_status_setting( 'admins' ); ?> />
+			<strong><?php _e( 'Group admins only', 'buddypress' ); ?></strong>
+		</label>
+ 	</div>
+
+	<hr />
+
+	<?php do_action( 'bp_after_group_settings_admin' ); ?>
+
+	<p><input type="submit" value="<?php _e( 'Save Changes', 'buddypress' ); ?>" id="save" name="save" /></p>
+	<?php wp_nonce_field( 'groups_edit_group_settings' ); ?>
+
+<?php endif; ?>
+
+<?php /* Group Avatar Settings */ ?>
+<?php if ( bp_is_group_admin_screen( 'group-avatar' ) ) : ?>
+
+	<?php if ( 'upload-image' == bp_get_avatar_admin_step() ) : ?>
+
+			<p><?php _e("Upload an image to use as an avatar for this group. The image will be shown on the main group page, and in search results.", 'buddypress'); ?></p>
+
+			<p>
+				<input type="file" name="file" id="file" />
+				<input type="submit" name="upload" id="upload" value="<?php _e( 'Upload Image', 'buddypress' ); ?>" />
+				<input type="hidden" name="action" id="action" value="bp_avatar_upload" />
+			</p>
+
+			<?php if ( bp_get_group_has_avatar() ) : ?>
+
+				<p><?php _e( "If you'd like to remove the existing avatar but not upload a new one, please use the delete avatar button.", 'buddypress' ); ?></p>
+
+				<?php bp_button( array( 'id' => 'delete_group_avatar', 'component' => 'groups', 'wrapper_id' => 'delete-group-avatar-button', 'link_class' => 'edit', 'link_href' => bp_get_group_avatar_delete_link(), 'link_title' => __( 'Delete Avatar', 'buddypress' ), 'link_text' => __( 'Delete Avatar', 'buddypress' ) ) ); ?>
+
+			<?php endif; ?>
+
+			<?php wp_nonce_field( 'bp_avatar_upload' ); ?>
+
+	<?php endif; ?>
+
+	<?php if ( 'crop-image' == bp_get_avatar_admin_step() ) : ?>
+
+		<h3><?php _e( 'Crop Avatar', 'buddypress' ); ?></h3>
+
+		<img src="<?php bp_avatar_to_crop(); ?>" id="avatar-to-crop" class="avatar" alt="<?php _e( 'Avatar to crop', 'buddypress' ); ?>" />
+
+		<div id="avatar-crop-pane">
+			<img src="<?php bp_avatar_to_crop(); ?>" id="avatar-crop-preview" class="avatar" alt="<?php _e( 'Avatar preview', 'buddypress' ); ?>" />
+		</div>
+
+		<input type="submit" name="avatar-crop-submit" id="avatar-crop-submit" value="<?php _e( 'Crop Image', 'buddypress' ); ?>" />
+
+		<input type="hidden" name="image_src" id="image_src" value="<?php bp_avatar_to_crop_src(); ?>" />
+		<input type="hidden" id="x" name="x" />
+		<input type="hidden" id="y" name="y" />
+		<input type="hidden" id="w" name="w" />
+		<input type="hidden" id="h" name="h" />
+
+		<?php wp_nonce_field( 'bp_avatar_cropstore' ); ?>
+
+	<?php endif; ?>
+
+<?php endif; ?>
+
+<?php /* Manage Group Members */ ?>
+<?php if ( bp_is_group_admin_screen( 'manage-members' ) ) : ?>
+
+	<?php do_action( 'bp_before_group_manage_members_admin' ); ?>
+
+	<div class="bp-widget">
+		<h4><?php _e( 'Administrators', 'buddypress' ); ?></h4>
+
+		<?php if ( bp_has_members( '&include='. bp_group_admin_ids() ) ) : ?>
+
+		<ul id="admins-list" class="item-list single-line">
+
+			<?php while ( bp_members() ) : bp_the_member(); ?>
+			<li>
+				<?php echo bp_core_fetch_avatar( array( 'item_id' => bp_get_member_user_id(), 'type' => 'thumb', 'width' => 30, 'height' => 30, 'alt' => sprintf( __( 'Profile picture of %s', 'buddypress' ), bp_get_member_name() ) ) ); ?>
+				<h5>
+					<a href="<?php bp_member_permalink(); ?>"> <?php bp_member_name(); ?></a>
+					<?php if ( count( bp_group_admin_ids( false, 'array' ) ) > 1 ) : ?>
+					<span class="small">
+						<a class="button confirm admin-demote-to-member" href="<?php bp_group_member_demote_link( bp_get_member_user_id() ); ?>"><?php _e( 'Demote to Member', 'buddypress' ); ?></a>
+					</span>
+					<?php endif; ?>
+				</h5>
+			</li>
+			<?php endwhile; ?>
+
+		</ul>
+
+		<?php endif; ?>
+
+	</div>
+
+	<?php if ( bp_group_has_moderators() ) : ?>
+		<div class="bp-widget">
+			<h4><?php _e( 'Moderators', 'buddypress' ); ?></h4>
+
+			<?php if ( bp_has_members( '&include=' . bp_group_mod_ids() ) ) : ?>
+				<ul id="mods-list" class="item-list single-line">
+
+					<?php while ( bp_members() ) : bp_the_member(); ?>
+					<li>
+						<?php echo bp_core_fetch_avatar( array( 'item_id' => bp_get_member_user_id(), 'type' => 'thumb', 'width' => 30, 'height' => 30, 'alt' => sprintf( __( 'Profile picture of %s', 'buddypress' ), bp_get_member_name() ) ) ); ?>
+						<h5>
+							<a href="<?php bp_member_permalink(); ?>"> <?php bp_member_name(); ?></a>
+							<span class="small">
+								<a href="<?php bp_group_member_promote_admin_link( array( 'user_id' => bp_get_member_user_id() ) ); ?>" class="button confirm mod-promote-to-admin" title="<?php _e( 'Promote to Admin', 'buddypress' ); ?>"><?php _e( 'Promote to Admin', 'buddypress' ); ?></a>
+								<a class="button confirm mod-demote-to-member" href="<?php bp_group_member_demote_link( bp_get_member_user_id() ); ?>"><?php _e( 'Demote to Member', 'buddypress' ); ?></a>
+							</span>
+						</h5>
+					</li>
+					<?php endwhile; ?>
+
+				</ul>
+
+			<?php endif; ?>
+		</div>
+	<?php endif ?>
+
+
+	<div class="bp-widget">
+		<h4><?php _e("Members", "buddypress"); ?></h4>
+
+		<?php if ( bp_group_has_members( 'per_page=15&exclude_banned=false' ) ) : ?>
+
+			<?php if ( bp_group_member_needs_pagination() ) : ?>
+
+				<div class="pagination no-ajax">
+
+					<div id="member-count" class="pag-count">
+						<?php bp_group_member_pagination_count(); ?>
+					</div>
+
+					<div id="member-admin-pagination" class="pagination-links">
+						<?php bp_group_member_admin_pagination(); ?>
+					</div>
+
+				</div>
+
+			<?php endif; ?>
+
+			<ul id="members-list" class="item-list single-line">
+				<?php while ( bp_group_members() ) : bp_group_the_member(); ?>
+
+					<li class="<?php bp_group_member_css_class(); ?>">
+						<?php bp_group_member_avatar_mini(); ?>
+
+						<h5>
+							<?php bp_group_member_link(); ?>
+
+							<?php if ( bp_get_group_member_is_banned() ) _e( '(banned)', 'buddypress'); ?>
+
+							<span class="small">
+
+							<?php if ( bp_get_group_member_is_banned() ) : ?>
+
+								<a href="<?php bp_group_member_unban_link(); ?>" class="button confirm member-unban" title="<?php _e( 'Unban this member', 'buddypress' ); ?>"><?php _e( 'Remove Ban', 'buddypress' ); ?></a>
+
+							<?php else : ?>
+
+								<a href="<?php bp_group_member_ban_link(); ?>" class="button confirm member-ban" title="<?php _e( 'Kick and ban this member', 'buddypress' ); ?>"><?php _e( 'Kick &amp; Ban', 'buddypress' ); ?></a>
+								<a href="<?php bp_group_member_promote_mod_link(); ?>" class="button confirm member-promote-to-mod" title="<?php _e( 'Promote to Mod', 'buddypress' ); ?>"><?php _e( 'Promote to Mod', 'buddypress' ); ?></a>
+								<a href="<?php bp_group_member_promote_admin_link(); ?>" class="button confirm member-promote-to-admin" title="<?php _e( 'Promote to Admin', 'buddypress' ); ?>"><?php _e( 'Promote to Admin', 'buddypress' ); ?></a>
+
+							<?php endif; ?>
+
+								<a href="<?php bp_group_member_remove_link(); ?>" class="button confirm" title="<?php _e( 'Remove this member', 'buddypress' ); ?>"><?php _e( 'Remove from group', 'buddypress' ); ?></a>
+
+								<?php do_action( 'bp_group_manage_members_admin_item' ); ?>
+
+							</span>
+						</h5>
+					</li>
+
+				<?php endwhile; ?>
+			</ul>
+
+		<?php else: ?>
+
+			<div id="message" class="info">
+				<p><?php _e( 'This group has no members.', 'buddypress' ); ?></p>
+			</div>
+
+		<?php endif; ?>
+
+	</div>
+
+	<?php do_action( 'bp_after_group_manage_members_admin' ); ?>
+
+<?php endif; ?>
+
+<?php /* Manage Membership Requests */ ?>
+<?php if ( bp_is_group_admin_screen( 'membership-requests' ) ) : ?>
+
+	<?php do_action( 'bp_before_group_membership_requests_admin' ); ?>
+
+	<?php if ( bp_group_has_membership_requests() ) : ?>
+
+		<ul id="request-list" class="item-list">
+			<?php while ( bp_group_membership_requests() ) : bp_group_the_membership_request(); ?>
+
+				<li>
+					<?php bp_group_request_user_avatar_thumb(); ?>
+					<h4><?php bp_group_request_user_link(); ?> <span class="comments"><?php bp_group_request_comment(); ?></span></h4>
+					<span class="activity"><?php bp_group_request_time_since_requested(); ?></span>
+
+					<?php do_action( 'bp_group_membership_requests_admin_item' ); ?>
+
+					<div class="action">
+
+						<?php bp_button( array( 'id' => 'group_membership_accept', 'component' => 'groups', 'wrapper_class' => 'accept', 'link_href' => bp_get_group_request_accept_link(), 'link_title' => __( 'Accept', 'buddypress' ), 'link_text' => __( 'Accept', 'buddypress' ) ) ); ?>
+
+						<?php bp_button( array( 'id' => 'group_membership_reject', 'component' => 'groups', 'wrapper_class' => 'reject', 'link_href' => bp_get_group_request_reject_link(), 'link_title' => __( 'Reject', 'buddypress' ), 'link_text' => __( 'Reject', 'buddypress' ) ) ); ?>
+
+						<?php do_action( 'bp_group_membership_requests_admin_item_action' ); ?>
+
+					</div>
+				</li>
+
+			<?php endwhile; ?>
+		</ul>
+
+	<?php else: ?>
+
+		<div id="message" class="info">
+			<p><?php _e( 'There are no pending membership requests.', 'buddypress' ); ?></p>
+		</div>
+
+	<?php endif; ?>
+
+	<?php do_action( 'bp_after_group_membership_requests_admin' ); ?>
+
+<?php endif; ?>
+
+<?php do_action( 'groups_custom_edit_steps' ) // Allow plugins to add custom group edit screens ?>
+
+<?php /* Delete Group Option */ ?>
+<?php if ( bp_is_group_admin_screen( 'delete-group' ) ) : ?>
+
+	<?php do_action( 'bp_before_group_delete_admin' ); ?>
+
+	<div id="message" class="info">
+		<p><?php _e( 'WARNING: Deleting this group will completely remove ALL content associated with it. There is no way back, please be careful with this option.', 'buddypress' ); ?></p>
+	</div>
+
+	<label><input type="checkbox" name="delete-group-understand" id="delete-group-understand" value="1" onclick="if(this.checked) { document.getElementById('delete-group-button').disabled = ''; } else { document.getElementById('delete-group-button').disabled = 'disabled'; }" /> <?php _e( 'I understand the consequences of deleting this group.', 'buddypress' ); ?></label>
+
+	<?php do_action( 'bp_after_group_delete_admin' ); ?>
+
+	<div class="submit">
+		<input type="submit" disabled="disabled" value="<?php _e( 'Delete Group', 'buddypress' ); ?>" id="delete-group-button" name="delete-group-button" />
+	</div>
+
+	<?php wp_nonce_field( 'groups_delete_group' ); ?>
+
+<?php endif; ?>
+
+<?php /* This is important, don't forget it */ ?>
+	<input type="hidden" name="group-id" id="group-id" value="<?php bp_group_id(); ?>" />
+
+<?php do_action( 'bp_after_group_admin_content' ); ?>
+
+</form><!-- #group-settings-form -->
+
Index: /tags/1.9/bp-themes/bp-default/groups/single/forum.php
===================================================================
--- /tags/1.9/bp-themes/bp-default/groups/single/forum.php	(revision 7684)
+++ /tags/1.9/bp-themes/bp-default/groups/single/forum.php	(revision 7684)
@@ -0,0 +1,97 @@
+<?php
+
+do_action( 'bp_before_group_forum_content' );
+
+if ( bp_is_group_forum_topic_edit() ) :
+	locate_template( array( 'groups/single/forum/edit.php' ), true );
+
+elseif ( bp_is_group_forum_topic() ) :
+	locate_template( array( 'groups/single/forum/topic.php' ), true );
+
+else : ?>
+
+	<div class="item-list-tabs no-ajax" id="subnav" role="navigation">
+		<ul>
+
+			<?php if ( is_user_logged_in() ) : ?>
+
+				<li>
+					<a href="#post-new" class="show-hide-new"><?php _e( 'New Topic', 'buddypress' ); ?></a>
+				</li>
+
+			<?php endif; ?>
+
+			<?php if ( bp_forums_has_directory() ) : ?>
+
+				<li>
+					<a href="<?php bp_forums_directory_permalink(); ?>"><?php _e( 'Forum Directory', 'buddypress'); ?></a>
+				</li>
+
+			<?php endif; ?>
+
+			<?php do_action( 'bp_forums_directory_group_sub_types' ); ?>
+
+			<li id="forums-order-select" class="last filter">
+
+				<label for="forums-order-by"><?php _e( 'Order By:', 'buddypress' ); ?></label>
+				<select id="forums-order-by">
+					<option value="active"><?php _e( 'Last Active', 'buddypress' ); ?></option>
+					<option value="popular"><?php _e( 'Most Posts', 'buddypress' ); ?></option>
+					<option value="unreplied"><?php _e( 'Unreplied', 'buddypress' ); ?></option>
+
+					<?php do_action( 'bp_forums_directory_order_options' ); ?>
+
+				</select>
+			</li>
+		</ul>
+	</div>
+
+	<div class="forums single-forum" role="main">
+
+		<?php locate_template( array( 'forums/forums-loop.php' ), true ); ?>
+
+	</div><!-- .forums.single-forum -->
+
+<?php endif; ?>
+
+<?php do_action( 'bp_after_group_forum_content' ); ?>
+
+<?php if ( !bp_is_group_forum_topic_edit() && !bp_is_group_forum_topic() ) : ?>
+
+	<?php if ( !bp_group_is_user_banned() && ( ( is_user_logged_in() && 'public' == bp_get_group_status() ) || bp_group_is_member() ) ) : ?>
+
+		<form action="" method="post" id="forum-topic-form" class="standard-form">
+			<div id="new-topic-post">
+
+				<?php do_action( 'bp_before_group_forum_post_new' ); ?>
+
+				<?php if ( bp_groups_auto_join() && !bp_group_is_member() ) : ?>
+					<p><?php _e( 'You will auto join this group when you start a new topic.', 'buddypress' ); ?></p>
+				<?php endif; ?>
+
+				<p id="post-new"></p>
+				<h4><?php _e( 'Post a New Topic:', 'buddypress' ); ?></h4>
+
+				<label><?php _e( 'Title:', 'buddypress' ); ?></label>
+				<input type="text" name="topic_title" id="topic_title" value="" maxlength="100" />
+
+				<label><?php _e( 'Content:', 'buddypress' ); ?></label>
+				<textarea name="topic_text" id="topic_text"></textarea>
+
+				<label><?php _e( 'Tags (comma separated):', 'buddypress' ); ?></label>
+				<input type="text" name="topic_tags" id="topic_tags" value="" />
+
+				<?php do_action( 'bp_after_group_forum_post_new' ); ?>
+
+				<div class="submit">
+					<input type="submit" name="submit_topic" id="submit" value="<?php _e( 'Post Topic', 'buddypress' ); ?>" />
+				</div>
+
+				<?php wp_nonce_field( 'bp_forums_new_topic' ); ?>
+			</div><!-- #new-topic-post -->
+		</form><!-- #forum-topic-form -->
+
+	<?php endif; ?>
+
+<?php endif; ?>
+
Index: /tags/1.9/bp-themes/bp-default/groups/single/forum/edit.php
===================================================================
--- /tags/1.9/bp-themes/bp-default/groups/single/forum/edit.php	(revision 7684)
+++ /tags/1.9/bp-themes/bp-default/groups/single/forum/edit.php	(revision 7684)
@@ -0,0 +1,92 @@
+<?php do_action( 'bp_before_group_forum_edit_form' ); ?>
+
+<?php if ( bp_has_forum_topic_posts() ) : ?>
+
+	<form action="<?php bp_forum_topic_action(); ?>" method="post" id="forum-topic-form" class="standard-form">
+
+		<div class="item-list-tabs" id="subnav" role="navigation">
+			<ul>
+				<li>
+					<a href="#post-topic-reply"><?php _e( 'Reply', 'buddypress' ); ?></a>
+				</li>
+
+				<?php if ( bp_forums_has_directory() ) : ?>
+
+					<li>
+						<a href="<?php bp_forums_directory_permalink(); ?>"><?php _e( 'Forum Directory', 'buddypress'); ?></a>
+					</li>
+
+				<?php endif; ?>
+
+			</ul>
+		</div>
+
+		<div id="topic-meta">
+			<h3><?php _e( 'Edit:', 'buddypress' ); ?> <?php bp_the_topic_title(); ?> (<?php bp_the_topic_total_post_count(); ?>)</h3>
+
+			<?php if ( bp_group_is_admin() || bp_group_is_mod() || bp_get_the_topic_is_mine() ) : ?>
+
+				<div class="last admin-links">
+
+					<?php bp_the_topic_admin_links(); ?>
+
+				</div>
+
+			<?php endif; ?>
+
+			<?php do_action( 'bp_group_forum_topic_meta' ); ?>
+
+		</div>
+
+		<?php if ( bp_is_edit_topic() ) : ?>
+
+			<div id="edit-topic">
+
+				<?php do_action( 'bp_group_before_edit_forum_topic' ); ?>
+
+				<label for="topic_title"><?php _e( 'Title:', 'buddypress' ); ?></label>
+				<input type="text" name="topic_title" id="topic_title" value="<?php bp_the_topic_title(); ?>" maxlength="100" />
+
+				<label for="topic_text"><?php _e( 'Content:', 'buddypress' ); ?></label>
+				<textarea name="topic_text" id="topic_text"><?php bp_the_topic_text(); ?></textarea>
+
+				<label><?php _e( 'Tags (comma separated):', 'buddypress' ); ?></label>
+				<input type="text" name="topic_tags" id="topic_tags" value="<?php bp_forum_topic_tag_list(); ?>" />
+
+				<?php do_action( 'bp_group_after_edit_forum_topic' ); ?>
+
+				<p class="submit"><input type="submit" name="save_changes" id="save_changes" value="<?php _e( 'Save Changes', 'buddypress' ); ?>" /></p>
+
+				<?php wp_nonce_field( 'bp_forums_edit_topic' ); ?>
+
+			</div>
+
+		<?php else : ?>
+
+			<div id="edit-post">
+
+				<?php do_action( 'bp_group_before_edit_forum_post' ); ?>
+
+				<textarea name="post_text" id="post_text"><?php bp_the_topic_post_edit_text(); ?></textarea>
+
+				<?php do_action( 'bp_group_after_edit_forum_post' ); ?>
+
+				<p class="submit"><input type="submit" name="save_changes" id="save_changes" value="<?php _e( 'Save Changes', 'buddypress' ); ?>" /></p>
+
+				<?php wp_nonce_field( 'bp_forums_edit_post' ); ?>
+
+			</div>
+
+		<?php endif; ?>
+
+	</form><!-- #forum-topic-form -->
+
+<?php else: ?>
+
+	<div id="message" class="info">
+		<p><?php _e( 'This topic does not exist.', 'buddypress' ); ?></p>
+	</div>
+
+<?php endif;?>
+
+<?php do_action( 'bp_after_group_forum_edit_form' ); ?>
Index: /tags/1.9/bp-themes/bp-default/groups/single/forum/topic.php
===================================================================
--- /tags/1.9/bp-themes/bp-default/groups/single/forum/topic.php	(revision 7684)
+++ /tags/1.9/bp-themes/bp-default/groups/single/forum/topic.php	(revision 7684)
@@ -0,0 +1,166 @@
+<?php do_action( 'bp_before_group_forum_topic' ); ?>
+
+<form action="<?php bp_forum_topic_action(); ?>" method="post" id="forum-topic-form" class="standard-form">
+	<div class="item-list-tabs no-ajax" id="subnav" role="navigation">
+		<ul>
+			<?php if ( is_user_logged_in() ) : ?>
+	
+				<li>
+					<a href="<?php bp_forum_topic_new_reply_link(); ?>" class="new-reply-link"><?php _e( 'New Reply', 'buddypress' ); ?></a>
+				</li>
+	
+			<?php endif; ?>
+	
+			<?php if ( bp_forums_has_directory() ) : ?>
+	
+				<li>
+					<a href="<?php bp_forums_directory_permalink(); ?>"><?php _e( 'Forum Directory', 'buddypress'); ?></a>
+				</li>
+	
+			<?php endif; ?>
+	
+		</ul>
+	</div>
+	
+	<div id="topic-meta">
+		<h3><?php bp_the_topic_title(); ?> (<?php bp_the_topic_total_post_count(); ?>)</h3>
+	
+		<?php if ( bp_forum_topic_has_tags() ) : ?>
+	
+			<div class="topic-tags">
+	
+				<?php _e( 'Topic tags:', 'buddypress' ); ?> <?php bp_forum_topic_tag_list(); ?>
+	
+			</div>
+	
+		<?php endif; ?>
+	
+		<?php if ( bp_group_is_admin() || bp_group_is_mod() || bp_get_the_topic_is_mine() ) : ?>
+	
+			<div class="last admin-links">
+	
+				<?php bp_the_topic_admin_links(); ?>
+	
+			</div>
+	
+		<?php endif; ?>
+	
+		<?php do_action( 'bp_group_forum_topic_meta' ); ?>
+	
+	</div>
+
+
+	<?php if ( bp_has_forum_topic_posts() ) : ?>
+
+		<div class="pagination no-ajax">
+
+			<div id="post-count-top" class="pag-count">
+
+				<?php bp_the_topic_pagination_count(); ?>
+
+			</div>
+
+			<div class="pagination-links" id="topic-pag-top">
+
+				<?php bp_the_topic_pagination(); ?>
+
+			</div>
+
+		</div>
+
+		<?php do_action( 'bp_before_group_forum_topic_posts' ); ?>
+
+		<ul id="topic-post-list" class="item-list" role="main">
+			<?php while ( bp_forum_topic_posts() ) : bp_the_forum_topic_post(); ?>
+
+				<li id="post-<?php bp_the_topic_post_id(); ?>" class="<?php bp_the_topic_post_css_class(); ?>">
+					<div class="poster-meta">
+						<a href="<?php bp_the_topic_post_poster_link(); ?>">
+							<?php bp_the_topic_post_poster_avatar( 'width=40&height=40' ); ?>
+						</a>
+						<?php echo sprintf( __( '%1$s said %2$s:', 'buddypress' ), bp_get_the_topic_post_poster_name(), bp_get_the_topic_post_time_since() ); ?>
+					</div>
+
+					<div class="post-content">
+						<?php bp_the_topic_post_content(); ?>
+					</div>
+
+					<div class="admin-links">
+						<?php if ( bp_group_is_admin() || bp_group_is_mod() || bp_get_the_topic_post_is_mine() ) : ?>
+							<?php bp_the_topic_post_admin_links(); ?>
+						<?php endif; ?>
+
+						<?php do_action( 'bp_group_forum_post_meta' ); ?>
+
+						<a href="#post-<?php bp_the_topic_post_id(); ?>" title="<?php _e( 'Permanent link to this post', 'buddypress' ); ?>">#</a>
+					</div>
+				</li>
+
+			<?php endwhile; ?>
+		</ul><!-- #topic-post-list -->
+
+		<?php do_action( 'bp_after_group_forum_topic_posts' ); ?>
+
+		<div class="pagination no-ajax">
+
+			<div id="post-count-bottom" class="pag-count">
+				<?php bp_the_topic_pagination_count(); ?>
+			</div>
+
+			<div class="pagination-links" id="topic-pag-bottom">
+				<?php bp_the_topic_pagination(); ?>
+			</div>
+
+		</div>
+
+	<?php else: ?>
+	
+		<div id="message" class="info">
+			<p><?php _e( 'There are no posts for this topic.', 'buddypress' ); ?></p>
+		</div>
+	
+	<?php endif;?>
+
+	<?php if ( ( is_user_logged_in() && 'public' == bp_get_group_status() ) || bp_group_is_member() ) : ?>
+
+		<?php if ( bp_get_the_topic_is_last_page() ) : ?>
+
+			<?php if ( bp_get_the_topic_is_topic_open() && !bp_group_is_user_banned() ) : ?>
+
+				<div id="post-topic-reply">
+					<p id="post-reply"></p>
+
+					<?php if ( bp_groups_auto_join() && !bp_group_is_member() ) : ?>
+						<p><?php _e( 'You will auto join this group when you reply to this topic.', 'buddypress' ); ?></p>
+					<?php endif; ?>
+
+					<?php do_action( 'groups_forum_new_reply_before' ); ?>
+
+					<h4><?php _e( 'Add a reply:', 'buddypress' ); ?></h4>
+
+					<textarea name="reply_text" id="reply_text"></textarea>
+
+					<div class="submit">
+						<input type="submit" name="submit_reply" id="submit" value="<?php _e( 'Post Reply', 'buddypress' ); ?>" />
+					</div>
+
+					<?php do_action( 'groups_forum_new_reply_after' ); ?>
+
+					<?php wp_nonce_field( 'bp_forums_new_reply' ); ?>
+				</div>
+
+			<?php elseif ( !bp_group_is_user_banned() ) : ?>
+
+				<div id="message" class="info">
+					<p><?php _e( 'This topic is closed, replies are no longer accepted.', 'buddypress' ); ?></p>
+				</div>
+
+			<?php endif; ?>
+
+		<?php endif; ?>
+
+	<?php endif; ?>
+
+</form><!-- #forum-topic-form -->
+
+<?php do_action( 'bp_after_group_forum_topic' ); ?>
Index: /tags/1.9/bp-themes/bp-default/groups/single/group-header.php
===================================================================
--- /tags/1.9/bp-themes/bp-default/groups/single/group-header.php	(revision 7684)
+++ /tags/1.9/bp-themes/bp-default/groups/single/group-header.php	(revision 7684)
@@ -0,0 +1,64 @@
+<?php
+
+do_action( 'bp_before_group_header' );
+
+?>
+
+<div id="item-actions">
+
+	<?php if ( bp_group_is_visible() ) : ?>
+
+		<h3><?php _e( 'Group Admins', 'buddypress' ); ?></h3>
+
+		<?php bp_group_list_admins();
+
+		do_action( 'bp_after_group_menu_admins' );
+
+		if ( bp_group_has_moderators() ) :
+			do_action( 'bp_before_group_menu_mods' ); ?>
+
+			<h3><?php _e( 'Group Mods' , 'buddypress' ); ?></h3>
+
+			<?php bp_group_list_mods();
+
+			do_action( 'bp_after_group_menu_mods' );
+
+		endif;
+
+	endif; ?>
+
+</div><!-- #item-actions -->
+
+<div id="item-header-avatar">
+	<a href="<?php bp_group_permalink(); ?>" title="<?php bp_group_name(); ?>">
+
+		<?php bp_group_avatar(); ?>
+
+	</a>
+</div><!-- #item-header-avatar -->
+
+<div id="item-header-content">
+	<h2><a href="<?php bp_group_permalink(); ?>" title="<?php bp_group_name(); ?>"><?php bp_group_name(); ?></a></h2>
+	<span class="highlight"><?php bp_group_type(); ?></span> <span class="activity"><?php printf( __( 'active %s', 'buddypress' ), bp_get_group_last_active() ); ?></span>
+
+	<?php do_action( 'bp_before_group_header_meta' ); ?>
+
+	<div id="item-meta">
+
+		<?php bp_group_description(); ?>
+
+		<div id="item-buttons">
+
+			<?php do_action( 'bp_group_header_actions' ); ?>
+
+		</div><!-- #item-buttons -->
+
+		<?php do_action( 'bp_group_header_meta' ); ?>
+
+	</div>
+</div><!-- #item-header-content -->
+
+<?php
+do_action( 'bp_after_group_header' );
+do_action( 'template_notices' );
+?>
Index: /tags/1.9/bp-themes/bp-default/groups/single/home.php
===================================================================
--- /tags/1.9/bp-themes/bp-default/groups/single/home.php	(revision 7684)
+++ /tags/1.9/bp-themes/bp-default/groups/single/home.php	(revision 7684)
@@ -0,0 +1,113 @@
+<?php get_header( 'buddypress' ); ?>
+
+	<div id="content">
+		<div class="padder">
+
+			<?php if ( bp_has_groups() ) : while ( bp_groups() ) : bp_the_group(); ?>
+
+			<?php do_action( 'bp_before_group_home_content' ); ?>
+
+			<div id="item-header" role="complementary">
+
+				<?php locate_template( array( 'groups/single/group-header.php' ), true ); ?>
+
+			</div><!-- #item-header -->
+
+			<div id="item-nav">
+				<div class="item-list-tabs no-ajax" id="object-nav" role="navigation">
+					<ul>
+
+						<?php bp_get_options_nav(); ?>
+
+						<?php do_action( 'bp_group_options_nav' ); ?>
+
+					</ul>
+				</div>
+			</div><!-- #item-nav -->
+
+			<div id="item-body">
+
+				<?php do_action( 'bp_before_group_body' );
+
+				/**
+				 * Does this next bit look familiar? If not, go check out WordPress's
+				 * /wp-includes/template-loader.php file.
+				 *
+				 * @todo A real template hierarchy? Gasp!
+				 */
+
+				// Group is visible
+				if ( bp_group_is_visible() ) :
+
+					// Looking at home location
+					if ( bp_is_group_home() ) :
+
+						// Use custom front if one exists
+						$custom_front = locate_template( array( 'groups/single/front.php' ) );
+						if     ( ! empty( $custom_front   ) ) : load_template( $custom_front, true );
+
+						// Default to activity
+						elseif ( bp_is_active( 'activity' ) ) : locate_template( array( 'groups/single/activity.php' ), true );
+
+						// Otherwise show members
+						elseif ( bp_is_active( 'members'  ) ) : locate_template( array( 'groups/single/members.php'  ), true );
+
+						endif;
+
+					// Not looking at home
+					else :
+
+						// Group Admin
+						if     ( bp_is_group_admin_page() ) : locate_template( array( 'groups/single/admin.php'        ), true );
+
+						// Group Activity
+						elseif ( bp_is_group_activity()   ) : locate_template( array( 'groups/single/activity.php'     ), true );
+
+						// Group Members
+						elseif ( bp_is_group_members()    ) : locate_template( array( 'groups/single/members.php'      ), true );
+
+						// Group Invitations
+						elseif ( bp_is_group_invites()    ) : locate_template( array( 'groups/single/send-invites.php' ), true );
+
+						// Old group forums
+						elseif ( bp_is_group_forum()      ) : locate_template( array( 'groups/single/forum.php'        ), true );
+
+						// Anything else (plugins mostly)
+						else                                : locate_template( array( 'groups/single/plugins.php'      ), true );
+
+						endif;
+					endif;
+
+				// Group is not visible
+				elseif ( ! bp_group_is_visible() ) :
+					// Membership request
+					if ( bp_is_group_membership_request() ) :
+						locate_template( array( 'groups/single/request-membership.php' ), true );
+
+					// The group is not visible, show the status message
+					else :
+
+						do_action( 'bp_before_group_status_message' ); ?>
+
+						<div id="message" class="info">
+							<p><?php bp_group_status_message(); ?></p>
+						</div>
+
+						<?php do_action( 'bp_after_group_status_message' );
+
+					endif;
+				endif;
+
+				do_action( 'bp_after_group_body' ); ?>
+
+			</div><!-- #item-body -->
+
+			<?php do_action( 'bp_after_group_home_content' ); ?>
+
+			<?php endwhile; endif; ?>
+
+		</div><!-- .padder -->
+	</div><!-- #content -->
+
+<?php get_sidebar( 'buddypress' ); ?>
+<?php get_footer( 'buddypress' ); ?>
Index: /tags/1.9/bp-themes/bp-default/groups/single/members.php
===================================================================
--- /tags/1.9/bp-themes/bp-default/groups/single/members.php	(revision 7684)
+++ /tags/1.9/bp-themes/bp-default/groups/single/members.php	(revision 7684)
@@ -0,0 +1,90 @@
+<?php if ( bp_group_has_members( 'exclude_admins_mods=0' ) ) : ?>
+
+	<?php do_action( 'bp_before_group_members_content' ); ?>
+
+	<div class="item-list-tabs" id="subnav" role="navigation">
+		<ul>
+
+			<?php do_action( 'bp_members_directory_member_sub_types' ); ?>
+
+		</ul>
+	</div>
+
+	<div id="pag-top" class="pagination no-ajax">
+
+		<div class="pag-count" id="member-count-top">
+
+			<?php bp_members_pagination_count(); ?>
+
+		</div>
+
+		<div class="pagination-links" id="member-pag-top">
+
+			<?php bp_members_pagination_links(); ?>
+
+		</div>
+
+	</div>
+
+	<?php do_action( 'bp_before_group_members_list' ); ?>
+
+	<ul id="member-list" class="item-list" role="main">
+
+		<?php while ( bp_group_members() ) : bp_group_the_member(); ?>
+
+			<li>
+				<a href="<?php bp_group_member_domain(); ?>">
+
+					<?php bp_group_member_avatar_thumb(); ?>
+
+				</a>
+
+				<h5><?php bp_group_member_link(); ?></h5>
+				<span class="activity"><?php bp_group_member_joined_since(); ?></span>
+
+				<?php do_action( 'bp_group_members_list_item' ); ?>
+
+				<?php if ( bp_is_active( 'friends' ) ) : ?>
+
+					<div class="action">
+
+						<?php bp_add_friend_button( bp_get_group_member_id(), bp_get_group_member_is_friend() ); ?>
+
+						<?php do_action( 'bp_group_members_list_item_action' ); ?>
+
+					</div>
+
+				<?php endif; ?>
+			</li>
+
+		<?php endwhile; ?>
+
+	</ul>
+
+	<?php do_action( 'bp_after_group_members_list' ); ?>
+
+	<div id="pag-bottom" class="pagination no-ajax">
+
+		<div class="pag-count" id="member-count-bottom">
+
+			<?php bp_members_pagination_count(); ?>
+
+		</div>
+
+		<div class="pagination-links" id="member-pag-bottom">
+
+			<?php bp_members_pagination_links(); ?>
+
+		</div>
+
+	</div>
+
+	<?php do_action( 'bp_after_group_members_content' ); ?>
+
+<?php else: ?>
+
+	<div id="message" class="info">
+		<p><?php _e( 'This group has no members.', 'buddypress' ); ?></p>
+	</div>
+
+<?php endif; ?>
Index: /tags/1.9/bp-themes/bp-default/groups/single/plugins.php
===================================================================
--- /tags/1.9/bp-themes/bp-default/groups/single/plugins.php	(revision 7684)
+++ /tags/1.9/bp-themes/bp-default/groups/single/plugins.php	(revision 7684)
@@ -0,0 +1,41 @@
+<?php get_header( 'buddypress' ); ?>
+
+	<div id="content">
+		<div class="padder">
+			<?php if ( bp_has_groups() ) : while ( bp_groups() ) : bp_the_group(); ?>
+
+			<?php do_action( 'bp_before_group_plugin_template' ); ?>
+
+			<div id="item-header">
+				<?php locate_template( array( 'groups/single/group-header.php' ), true ); ?>
+			</div><!-- #item-header -->
+
+			<div id="item-nav">
+				<div class="item-list-tabs no-ajax" id="object-nav" role="navigation">
+					<ul>
+						<?php bp_get_options_nav(); ?>
+
+						<?php do_action( 'bp_group_plugin_options_nav' ); ?>
+					</ul>
+				</div>
+			</div><!-- #item-nav -->
+
+			<div id="item-body">
+
+				<?php do_action( 'bp_before_group_body' ); ?>
+
+				<?php do_action( 'bp_template_content' ); ?>
+
+				<?php do_action( 'bp_after_group_body' ); ?>
+			</div><!-- #item-body -->
+
+			<?php do_action( 'bp_after_group_plugin_template' ); ?>
+
+			<?php endwhile; endif; ?>
+
+		</div><!-- .padder -->
+	</div><!-- #content -->
+
+	<?php get_sidebar( 'buddypress' ); ?>
+
+<?php get_footer( 'buddypress' ); ?>
Index: /tags/1.9/bp-themes/bp-default/groups/single/request-membership.php
===================================================================
--- /tags/1.9/bp-themes/bp-default/groups/single/request-membership.php	(revision 7684)
+++ /tags/1.9/bp-themes/bp-default/groups/single/request-membership.php	(revision 7684)
@@ -0,0 +1,18 @@
+<?php do_action( 'bp_before_group_request_membership_content' ); ?>
+
+<?php if ( !bp_group_has_requested_membership() ) : ?>
+	<p><?php printf( __( "You are requesting to become a member of the group '%s'.", "buddypress" ), bp_get_group_name( false ) ); ?></p>
+
+	<form action="<?php bp_group_form_action('request-membership'); ?>" method="post" name="request-membership-form" id="request-membership-form" class="standard-form">
+		<label for="group-request-membership-comments"><?php _e( 'Comments (optional)', 'buddypress' ); ?></label>
+		<textarea name="group-request-membership-comments" id="group-request-membership-comments"></textarea>
+
+		<?php do_action( 'bp_group_request_membership_content' ); ?>
+
+		<p><input type="submit" name="group-request-send" id="group-request-send" value="<?php _e( 'Send Request', 'buddypress' ); ?>" />
+
+		<?php wp_nonce_field( 'groups_request_membership' ); ?>
+	</form><!-- #request-membership-form -->
+<?php endif; ?>
+
+<?php do_action( 'bp_after_group_request_membership_content' ); ?>
Index: /tags/1.9/bp-themes/bp-default/groups/single/send-invites.php
===================================================================
--- /tags/1.9/bp-themes/bp-default/groups/single/send-invites.php	(revision 7684)
+++ /tags/1.9/bp-themes/bp-default/groups/single/send-invites.php	(revision 7684)
@@ -0,0 +1,78 @@
+<?php do_action( 'bp_before_group_send_invites_content' ); ?>
+
+<?php if ( bp_get_total_friend_count( bp_loggedin_user_id() ) ) : ?>
+
+	<form action="<?php bp_group_send_invite_form_action(); ?>" method="post" id="send-invite-form" class="standard-form" role="main">
+
+		<div class="left-menu">
+
+			<div id="invite-list">
+				<ul>
+					<?php bp_new_group_invite_friend_list(); ?>
+				</ul>
+
+				<?php wp_nonce_field( 'groups_invite_uninvite_user', '_wpnonce_invite_uninvite_user' ); ?>
+			</div>
+
+		</div><!-- .left-menu -->
+
+		<div class="main-column">
+
+			<div id="message" class="info">
+				<p><?php _e('Select people to invite from your friends list.', 'buddypress'); ?></p>
+			</div>
+
+			<?php do_action( 'bp_before_group_send_invites_list' ); ?>
+
+			<?php /* The ID 'friend-list' is important for AJAX support. */ ?>
+			<ul id="friend-list" class="item-list">
+			<?php if ( bp_group_has_invites() ) : ?>
+
+				<?php while ( bp_group_invites() ) : bp_group_the_invite(); ?>
+
+					<li id="<?php bp_group_invite_item_id(); ?>">
+						<?php bp_group_invite_user_avatar(); ?>
+
+						<h4><?php bp_group_invite_user_link(); ?></h4>
+						<span class="activity"><?php bp_group_invite_user_last_active(); ?></span>
+
+						<?php do_action( 'bp_group_send_invites_item' ); ?>
+
+						<div class="action">
+							<a class="button remove" href="<?php bp_group_invite_user_remove_invite_url(); ?>" id="<?php bp_group_invite_item_id(); ?>"><?php _e( 'Remove Invite', 'buddypress' ); ?></a>
+
+							<?php do_action( 'bp_group_send_invites_item_action' ); ?>
+						</div>
+					</li>
+
+				<?php endwhile; ?>
+
+			<?php endif; ?>
+			</ul><!-- #friend-list -->
+
+			<?php do_action( 'bp_after_group_send_invites_list' ); ?>
+
+		</div><!-- .main-column -->
+
+		<div class="clear"></div>
+
+		<div class="submit">
+			<input type="submit" name="submit" id="submit" value="<?php _e( 'Send Invites', 'buddypress' ); ?>" />
+		</div>
+
+		<?php wp_nonce_field( 'groups_send_invites', '_wpnonce_send_invites'); ?>
+
+		<?php /* This is important, don't forget it */ ?>
+		<input type="hidden" name="group_id" id="group_id" value="<?php bp_group_id(); ?>" />
+
+	</form><!-- #send-invite-form -->
+
+<?php else : ?>
+
+	<div id="message" class="info" role="main">
+		<p><?php _e( 'Once you have built up friend connections you will be able to invite others to your group.', 'buddypress' ); ?></p>
+	</div>
+
+<?php endif; ?>
+
+<?php do_action( 'bp_after_group_send_invites_content' ); ?>
Index: /tags/1.9/bp-themes/bp-default/header.php
===================================================================
--- /tags/1.9/bp-themes/bp-default/header.php	(revision 7684)
+++ /tags/1.9/bp-themes/bp-default/header.php	(revision 7684)
@@ -0,0 +1,52 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+
+<html xmlns="http://www.w3.org/1999/xhtml" <?php language_attributes(); ?>>
+	<head profile="http://gmpg.org/xfn/11">
+		<meta http-equiv="Content-Type" content="<?php bloginfo( 'html_type' ); ?>; charset=<?php bloginfo( 'charset' ); ?>" />
+		<?php if ( current_theme_supports( 'bp-default-responsive' ) ) : ?><meta name="viewport" content="width=device-width, initial-scale=1.0" /><?php endif; ?>
+		<title><?php wp_title( '|', true, 'right' ); bloginfo( 'name' ); ?></title>
+		<link rel="pingback" href="<?php bloginfo( 'pingback_url' ); ?>" />
+
+		<?php bp_head(); ?>
+		<?php wp_head(); ?>
+
+	</head>
+
+	<body <?php body_class(); ?> id="bp-default">
+
+		<?php do_action( 'bp_before_header' ); ?>
+
+		<div id="header">
+			<div id="search-bar" role="search">
+				<div class="padder">
+					<h1 id="logo" role="banner"><a href="<?php echo home_url(); ?>" title="<?php _ex( 'Home', 'Home page banner link title', 'buddypress' ); ?>"><?php bp_site_name(); ?></a></h1>
+
+						<form action="<?php echo bp_search_form_action(); ?>" method="post" id="search-form">
+							<label for="search-terms" class="accessibly-hidden"><?php _e( 'Search for:', 'buddypress' ); ?></label>
+							<input type="text" id="search-terms" name="search-terms" value="<?php echo isset( $_REQUEST['s'] ) ? esc_attr( $_REQUEST['s'] ) : ''; ?>" />
+
+							<?php echo bp_search_form_type_select(); ?>
+
+							<input type="submit" name="search-submit" id="search-submit" value="<?php _e( 'Search', 'buddypress' ); ?>" />
+
+							<?php wp_nonce_field( 'bp_search_form' ); ?>
+
+						</form><!-- #search-form -->
+
+				<?php do_action( 'bp_search_login_bar' ); ?>
+
+				</div><!-- .padder -->
+			</div><!-- #search-bar -->
+
+			<div id="navigation" role="navigation">
+				<?php wp_nav_menu( array( 'container' => false, 'menu_id' => 'nav', 'theme_location' => 'primary', 'fallback_cb' => 'bp_dtheme_main_nav' ) ); ?>
+			</div>
+
+			<?php do_action( 'bp_header' ); ?>
+
+		</div><!-- #header -->
+
+		<?php do_action( 'bp_after_header'     ); ?>
+		<?php do_action( 'bp_before_container' ); ?>
+
+		<div id="container">
Index: /tags/1.9/bp-themes/bp-default/index.php
===================================================================
--- /tags/1.9/bp-themes/bp-default/index.php	(revision 7684)
+++ /tags/1.9/bp-themes/bp-default/index.php	(revision 7684)
@@ -0,0 +1,69 @@
+<?php get_header(); ?>
+
+	<div id="content">
+		<div class="padder">
+
+		<?php do_action( 'bp_before_blog_home' ); ?>
+
+		<?php do_action( 'template_notices' ); ?>
+
+		<div class="page" id="blog-latest" role="main">
+
+			<?php if ( have_posts() ) : ?>
+
+				<?php bp_dtheme_content_nav( 'nav-above' ); ?>
+
+				<?php while (have_posts()) : the_post(); ?>
+
+					<?php do_action( 'bp_before_blog_post' ); ?>
+
+					<div id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
+
+						<div class="author-box">
+							<?php echo get_avatar( get_the_author_meta( 'user_email' ), '50' ); ?>
+							<p><?php printf( _x( 'by %s', 'Post written by...', 'buddypress' ), bp_core_get_userlink( $post->post_author ) ); ?></p>
+
+							<?php if ( is_sticky() ) : ?>
+								<span class="activity sticky-post"><?php _ex( 'Featured', 'Sticky post', 'buddypress' ); ?></span>
+							<?php endif; ?>
+						</div>
+
+						<div class="post-content">
+							<h2 class="posttitle"><a href="<?php the_permalink(); ?>" rel="bookmark" title="<?php _e( 'Permanent Link to', 'buddypress' ); ?> <?php the_title_attribute(); ?>"><?php the_title(); ?></a></h2>
+
+							<p class="date"><?php printf( __( '%1$s <span>in %2$s</span>', 'buddypress' ), get_the_date(), get_the_category_list( ', ' ) ); ?></p>
+
+							<div class="entry">
+								<?php the_content( __( 'Read the rest of this entry &rarr;', 'buddypress' ) ); ?>
+								<?php wp_link_pages( array( 'before' => '<div class="page-link"><p>' . __( 'Pages: ', 'buddypress' ), 'after' => '</p></div>', 'next_or_number' => 'number' ) ); ?>
+							</div>
+
+							<p class="postmetadata"><?php the_tags( '<span class="tags">' . __( 'Tags: ', 'buddypress' ), ', ', '</span>' ); ?> <span class="comments"><?php comments_popup_link( __( 'No Comments &#187;', 'buddypress' ), __( '1 Comment &#187;', 'buddypress' ), __( '% Comments &#187;', 'buddypress' ) ); ?></span></p>
+						</div>
+
+					</div>
+
+					<?php do_action( 'bp_after_blog_post' ); ?>
+
+				<?php endwhile; ?>
+
+				<?php bp_dtheme_content_nav( 'nav-below' ); ?>
+
+			<?php else : ?>
+
+				<h2 class="center"><?php _e( 'Not Found', 'buddypress' ); ?></h2>
+				<p class="center"><?php _e( 'Sorry, but you are looking for something that isn\'t here.', 'buddypress' ); ?></p>
+
+				<?php get_search_form(); ?>
+
+			<?php endif; ?>
+		</div>
+
+		<?php do_action( 'bp_after_blog_home' ); ?>
+
+		</div><!-- .padder -->
+	</div><!-- #content -->
+
+	<?php get_sidebar(); ?>
+
+<?php get_footer(); ?>
Index: /tags/1.9/bp-themes/bp-default/license.txt
===================================================================
--- /tags/1.9/bp-themes/bp-default/license.txt	(revision 7684)
+++ /tags/1.9/bp-themes/bp-default/license.txt	(revision 7684)
@@ -0,0 +1,280 @@
+		    GNU GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+                          675 Mass Ave, Cambridge, MA 02139, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+		    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+			    NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
Index: /tags/1.9/bp-themes/bp-default/links.php
===================================================================
--- /tags/1.9/bp-themes/bp-default/links.php	(revision 7684)
+++ /tags/1.9/bp-themes/bp-default/links.php	(revision 7684)
@@ -0,0 +1,29 @@
+<?php
+/*
+Template Name: Links
+*/
+?>
+
+<?php get_header(); ?>
+
+	<div id="content">
+		<div class="padder">
+
+		<?php do_action( 'bp_before_blog_links' ); ?>
+
+		<div class="page" id="blog-latest" role="main">
+
+			<h2 class="pagetitle"><?php _e( 'Links', 'buddypress' ); ?></h2>
+
+			<ul id="links-list">
+				<?php wp_list_bookmarks(); ?>
+			</ul>
+
+		</div>
+
+		<?php do_action( 'bp_after_blog_links' ); ?>
+
+		</div>
+	</div>
+
+<?php get_footer(); ?>
Index: /tags/1.9/bp-themes/bp-default/members/index.php
===================================================================
--- /tags/1.9/bp-themes/bp-default/members/index.php	(revision 7684)
+++ /tags/1.9/bp-themes/bp-default/members/index.php	(revision 7684)
@@ -0,0 +1,95 @@
+<?php
+
+/**
+ * BuddyPress - Members Directory
+ *
+ * @package BuddyPress
+ * @subpackage bp-default
+ */
+
+get_header( 'buddypress' ); ?>
+
+	<?php do_action( 'bp_before_directory_members_page' ); ?>
+
+	<div id="content">
+		<div class="padder">
+
+		<?php do_action( 'bp_before_directory_members' ); ?>
+
+		<form action="" method="post" id="members-directory-form" class="dir-form">
+
+			<h3><?php _e( 'Members Directory', 'buddypress' ); ?></h3>
+
+			<?php do_action( 'bp_before_directory_members_content' ); ?>
+
+			<div id="members-dir-search" class="dir-search" role="search">
+
+				<?php bp_directory_members_search_form(); ?>
+
+			</div><!-- #members-dir-search -->
+
+			<?php do_action( 'bp_before_directory_members_tabs' ); ?>
+
+			<div class="item-list-tabs" role="navigation">
+				<ul>
+					<li class="selected" id="members-all"><a href="<?php echo trailingslashit( bp_get_root_domain() . '/' . bp_get_members_root_slug() ); ?>"><?php printf( __( 'All Members <span>%s</span>', 'buddypress' ), bp_get_total_member_count() ); ?></a></li>
+
+					<?php if ( is_user_logged_in() && bp_is_active( 'friends' ) && bp_get_total_friend_count( bp_loggedin_user_id() ) ) : ?>
+
+						<li id="members-personal"><a href="<?php echo bp_loggedin_user_domain() . bp_get_friends_slug() . '/my-friends/' ?>"><?php printf( __( 'My Friends <span>%s</span>', 'buddypress' ), bp_get_total_friend_count( bp_loggedin_user_id() ) ); ?></a></li>
+
+					<?php endif; ?>
+
+					<?php do_action( 'bp_members_directory_member_types' ); ?>
+
+				</ul>
+			</div><!-- .item-list-tabs -->
+
+			<div class="item-list-tabs" id="subnav" role="navigation">
+				<ul>
+
+					<?php do_action( 'bp_members_directory_member_sub_types' ); ?>
+
+					<li id="members-order-select" class="last filter">
+
+						<label for="members-order-by"><?php _e( 'Order By:', 'buddypress' ); ?></label>
+						<select id="members-order-by">
+							<option value="active"><?php _e( 'Last Active', 'buddypress' ); ?></option>
+							<option value="newest"><?php _e( 'Newest Registered', 'buddypress' ); ?></option>
+
+							<?php if ( bp_is_active( 'xprofile' ) ) : ?>
+
+								<option value="alphabetical"><?php _e( 'Alphabetical', 'buddypress' ); ?></option>
+
+							<?php endif; ?>
+
+							<?php do_action( 'bp_members_directory_order_options' ); ?>
+
+						</select>
+					</li>
+				</ul>
+			</div>
+
+			<div id="members-dir-list" class="members dir-list">
+
+				<?php locate_template( array( 'members/members-loop.php' ), true ); ?>
+
+			</div><!-- #members-dir-list -->
+
+			<?php do_action( 'bp_directory_members_content' ); ?>
+
+			<?php wp_nonce_field( 'directory_members', '_wpnonce-member-filter' ); ?>
+
+			<?php do_action( 'bp_after_directory_members_content' ); ?>
+
+		</form><!-- #members-directory-form -->
+
+		<?php do_action( 'bp_after_directory_members' ); ?>
+
+		</div><!-- .padder -->
+	</div><!-- #content -->
+
+	<?php do_action( 'bp_after_directory_members_page' ); ?>
+
+<?php get_sidebar( 'buddypress' ); ?>
+<?php get_footer( 'buddypress' ); ?>
Index: /tags/1.9/bp-themes/bp-default/members/members-loop.php
===================================================================
--- /tags/1.9/bp-themes/bp-default/members/members-loop.php	(revision 7684)
+++ /tags/1.9/bp-themes/bp-default/members/members-loop.php	(revision 7684)
@@ -0,0 +1,113 @@
+<?php
+
+/**
+ * BuddyPress - Members Loop
+ *
+ * Querystring is set via AJAX in _inc/ajax.php - bp_dtheme_object_filter()
+ *
+ * @package BuddyPress
+ * @subpackage bp-default
+ */
+
+?>
+
+<?php do_action( 'bp_before_members_loop' ); ?>
+
+<?php if ( bp_has_members( bp_ajax_querystring( 'members' ) ) ) : ?>
+
+	<div id="pag-top" class="pagination">
+
+		<div class="pag-count" id="member-dir-count-top">
+
+			<?php bp_members_pagination_count(); ?>
+
+		</div>
+
+		<div class="pagination-links" id="member-dir-pag-top">
+
+			<?php bp_members_pagination_links(); ?>
+
+		</div>
+
+	</div>
+
+	<?php do_action( 'bp_before_directory_members_list' ); ?>
+
+	<ul id="members-list" class="item-list" role="main">
+
+	<?php while ( bp_members() ) : bp_the_member(); ?>
+
+		<li>
+			<div class="item-avatar">
+				<a href="<?php bp_member_permalink(); ?>"><?php bp_member_avatar(); ?></a>
+			</div>
+
+			<div class="item">
+				<div class="item-title">
+					<a href="<?php bp_member_permalink(); ?>"><?php bp_member_name(); ?></a>
+
+					<?php if ( bp_get_member_latest_update() ) : ?>
+
+						<span class="update"> <?php bp_member_latest_update(); ?></span>
+
+					<?php endif; ?>
+
+				</div>
+
+				<div class="item-meta"><span class="activity"><?php bp_member_last_active(); ?></span></div>
+
+				<?php do_action( 'bp_directory_members_item' ); ?>
+
+				<?php
+				 /***
+				  * If you want to show specific profile fields here you can,
+				  * but it'll add an extra query for each member in the loop
+				  * (only one regardless of the number of fields you show):
+				  *
+				  * bp_member_profile_data( 'field=the field name' );
+				  */
+				?>
+			</div>
+
+			<div class="action">
+
+				<?php do_action( 'bp_directory_members_actions' ); ?>
+
+			</div>
+
+			<div class="clear"></div>
+		</li>
+
+	<?php endwhile; ?>
+
+	</ul>
+
+	<?php do_action( 'bp_after_directory_members_list' ); ?>
+
+	<?php bp_member_hidden_fields(); ?>
+
+	<div id="pag-bottom" class="pagination">
+
+		<div class="pag-count" id="member-dir-count-bottom">
+
+			<?php bp_members_pagination_count(); ?>
+
+		</div>
+
+		<div class="pagination-links" id="member-dir-pag-bottom">
+
+			<?php bp_members_pagination_links(); ?>
+
+		</div>
+
+	</div>
+
+<?php else: ?>
+
+	<div id="message" class="info">
+		<p><?php _e( "Sorry, no members were found.", 'buddypress' ); ?></p>
+	</div>
+
+<?php endif; ?>
+
+<?php do_action( 'bp_after_members_loop' ); ?>
Index: /tags/1.9/bp-themes/bp-default/members/single/activity.php
===================================================================
--- /tags/1.9/bp-themes/bp-default/members/single/activity.php	(revision 7684)
+++ /tags/1.9/bp-themes/bp-default/members/single/activity.php	(revision 7684)
@@ -0,0 +1,77 @@
+<?php
+
+/**
+ * BuddyPress - Users Activity
+ *
+ * @package BuddyPress
+ * @subpackage bp-default
+ */
+
+?>
+
+<div class="item-list-tabs no-ajax" id="subnav" role="navigation">
+	<ul>
+
+		<?php bp_get_options_nav(); ?>
+
+		<li id="activity-filter-select" class="last">
+			<label for="activity-filter-by"><?php _e( 'Show:', 'buddypress' ); ?></label>
+			<select id="activity-filter-by">
+				<option value="-1"><?php _e( 'Everything', 'buddypress' ); ?></option>
+				<option value="activity_update"><?php _e( 'Updates', 'buddypress' ); ?></option>
+
+				<?php
+				if ( !bp_is_current_action( 'groups' ) ) :
+					if ( bp_is_active( 'blogs' ) ) : ?>
+
+						<option value="new_blog_post"><?php _e( 'Posts', 'buddypress' ); ?></option>
+						<option value="new_blog_comment"><?php _e( 'Comments', 'buddypress' ); ?></option>
+
+					<?php
+					endif;
+
+					if ( bp_is_active( 'friends' ) ) : ?>
+
+						<option value="friendship_accepted,friendship_created"><?php _e( 'Friendships', 'buddypress' ); ?></option>
+
+					<?php endif;
+
+				endif;
+
+				if ( bp_is_active( 'forums' ) ) : ?>
+
+					<option value="new_forum_topic"><?php _e( 'Forum Topics', 'buddypress' ); ?></option>
+					<option value="new_forum_post"><?php _e( 'Forum Replies', 'buddypress' ); ?></option>
+
+				<?php endif;
+
+				if ( bp_is_active( 'groups' ) ) : ?>
+
+					<option value="created_group"><?php _e( 'New Groups', 'buddypress' ); ?></option>
+					<option value="joined_group"><?php _e( 'Group Memberships', 'buddypress' ); ?></option>
+
+				<?php endif;
+
+				do_action( 'bp_member_activity_filter_options' ); ?>
+
+			</select>
+		</li>
+	</ul>
+</div><!-- .item-list-tabs -->
+
+<?php do_action( 'bp_before_member_activity_post_form' ); ?>
+
+<?php
+if ( is_user_logged_in() && bp_is_my_profile() && ( !bp_current_action() || bp_is_current_action( 'just-me' ) ) )
+	locate_template( array( 'activity/post-form.php'), true );
+
+do_action( 'bp_after_member_activity_post_form' );
+do_action( 'bp_before_member_activity_content' ); ?>
+
+<div class="activity" role="main">
+
+	<?php locate_template( array( 'activity/activity-loop.php' ), true ); ?>
+
+</div><!-- .activity -->
+
+<?php do_action( 'bp_after_member_activity_content' ); ?>
Index: /tags/1.9/bp-themes/bp-default/members/single/activity/permalink.php
===================================================================
--- /tags/1.9/bp-themes/bp-default/members/single/activity/permalink.php	(revision 7684)
+++ /tags/1.9/bp-themes/bp-default/members/single/activity/permalink.php	(revision 7684)
@@ -0,0 +1,19 @@
+<?php get_header( 'buddypress' ); ?>
+
+<?php do_action( 'template_notices' ); ?>
+
+<div class="activity no-ajax" role="main">
+	<?php if ( bp_has_activities( 'display_comments=threaded&show_hidden=true&include=' . bp_current_action() ) ) : ?>
+
+		<ul id="activity-stream" class="activity-list item-list">
+		<?php while ( bp_activities() ) : bp_the_activity(); ?>
+
+			<?php locate_template( array( 'activity/entry.php' ), true ); ?>
+
+		<?php endwhile; ?>
+		</ul>
+
+	<?php endif; ?>
+</div>
+
+<?php get_footer( 'buddypress' ); ?>
Index: /tags/1.9/bp-themes/bp-default/members/single/blogs.php
===================================================================
--- /tags/1.9/bp-themes/bp-default/members/single/blogs.php	(revision 7684)
+++ /tags/1.9/bp-themes/bp-default/members/single/blogs.php	(revision 7684)
@@ -0,0 +1,40 @@
+<?php
+
+/**
+ * BuddyPress - Users Blogs
+ *
+ * @package BuddyPress
+ * @subpackage bp-default
+ */
+
+?>
+
+<div class="item-list-tabs" id="subnav" role="navigation">
+	<ul>
+
+		<?php bp_get_options_nav(); ?>
+
+		<li id="blogs-order-select" class="last filter">
+
+			<label for="blogs-all"><?php _e( 'Order By:', 'buddypress' ); ?></label>
+			<select id="blogs-all">
+				<option value="active"><?php _e( 'Last Active', 'buddypress' ); ?></option>
+				<option value="newest"><?php _e( 'Newest', 'buddypress' ); ?></option>
+				<option value="alphabetical"><?php _e( 'Alphabetical', 'buddypress' ); ?></option>
+
+				<?php do_action( 'bp_member_blog_order_options' ); ?>
+
+			</select>
+		</li>
+	</ul>
+</div><!-- .item-list-tabs -->
+
+<?php do_action( 'bp_before_member_blogs_content' ); ?>
+
+<div class="blogs myblogs" role="main">
+
+	<?php locate_template( array( 'blogs/blogs-loop.php' ), true ); ?>
+
+</div><!-- .blogs.myblogs -->
+
+<?php do_action( 'bp_after_member_blogs_content' ); ?>
Index: /tags/1.9/bp-themes/bp-default/members/single/forums.php
===================================================================
--- /tags/1.9/bp-themes/bp-default/members/single/forums.php	(revision 7684)
+++ /tags/1.9/bp-themes/bp-default/members/single/forums.php	(revision 7684)
@@ -0,0 +1,47 @@
+<?php
+
+/**
+ * BuddyPress - Users Forums
+ *
+ * @package BuddyPress
+ * @subpackage bp-default
+ */
+
+?>
+
+<div class="item-list-tabs no-ajax" id="subnav" role="navigation">
+	<ul>
+		<?php bp_get_options_nav(); ?>
+
+		<li id="forums-order-select" class="last filter">
+
+			<label for="forums-order-by"><?php _e( 'Order By:', 'buddypress' ); ?></label>
+			<select id="forums-order-by">
+				<option value="active"><?php _e( 'Last Active', 'buddypress' ); ?></option>
+				<option value="popular"><?php _e( 'Most Posts', 'buddypress' ); ?></option>
+				<option value="unreplied"><?php _e( 'Unreplied', 'buddypress' ); ?></option>
+
+				<?php do_action( 'bp_forums_directory_order_options' ); ?>
+
+			</select>
+		</li>
+	</ul>
+</div><!-- .item-list-tabs -->
+
+<?php
+
+if ( bp_is_current_action( 'favorites' ) ) :
+	locate_template( array( 'members/single/forums/topics.php' ), true );
+
+else :
+	do_action( 'bp_before_member_forums_content' ); ?>
+
+	<div class="forums myforums">
+
+		<?php locate_template( array( 'forums/forums-loop.php' ), true ); ?>
+
+	</div>
+
+	<?php do_action( 'bp_after_member_forums_content' ); ?>
+
+<?php endif; ?>
Index: /tags/1.9/bp-themes/bp-default/members/single/forums/topics.php
===================================================================
--- /tags/1.9/bp-themes/bp-default/members/single/forums/topics.php	(revision 7684)
+++ /tags/1.9/bp-themes/bp-default/members/single/forums/topics.php	(revision 7684)
@@ -0,0 +1,7 @@
+<?php
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+?>
Index: /tags/1.9/bp-themes/bp-default/members/single/friends.php
===================================================================
--- /tags/1.9/bp-themes/bp-default/members/single/friends.php	(revision 7684)
+++ /tags/1.9/bp-themes/bp-default/members/single/friends.php	(revision 7684)
@@ -0,0 +1,52 @@
+<?php
+
+/**
+ * BuddyPress - Users Friends
+ *
+ * @package BuddyPress
+ * @subpackage bp-default
+ */
+
+?>
+
+<div class="item-list-tabs no-ajax" id="subnav" role="navigation">
+	<ul>
+		<?php if ( bp_is_my_profile() ) bp_get_options_nav(); ?>
+
+		<?php if ( !bp_is_current_action( 'requests' ) ) : ?>
+
+			<li id="members-order-select" class="last filter">
+
+				<label for="members-friends"><?php _e( 'Order By:', 'buddypress' ); ?></label>
+				<select id="members-friends">
+					<option value="active"><?php _e( 'Last Active', 'buddypress' ); ?></option>
+					<option value="newest"><?php _e( 'Newest Registered', 'buddypress' ); ?></option>
+					<option value="alphabetical"><?php _e( 'Alphabetical', 'buddypress' ); ?></option>
+
+					<?php do_action( 'bp_member_blog_order_options' ); ?>
+
+				</select>
+			</li>
+
+		<?php endif; ?>
+
+	</ul>
+</div>
+
+<?php
+
+if ( bp_is_current_action( 'requests' ) ) :
+	 locate_template( array( 'members/single/friends/requests.php' ), true );
+
+else :
+	do_action( 'bp_before_member_friends_content' ); ?>
+
+	<div class="members friends">
+
+		<?php locate_template( array( 'members/members-loop.php' ), true ); ?>
+
+	</div><!-- .members.friends -->
+
+	<?php do_action( 'bp_after_member_friends_content' ); ?>
+
+<?php endif; ?>
Index: /tags/1.9/bp-themes/bp-default/members/single/friends/requests.php
===================================================================
--- /tags/1.9/bp-themes/bp-default/members/single/friends/requests.php	(revision 7684)
+++ /tags/1.9/bp-themes/bp-default/members/single/friends/requests.php	(revision 7684)
@@ -0,0 +1,73 @@
+<?php do_action( 'bp_before_member_friend_requests_content' ); ?>
+
+<?php if ( bp_has_members( 'type=alphabetical&include=' . bp_get_friendship_requests() ) ) : ?>
+
+	<div id="pag-top" class="pagination no-ajax">
+
+		<div class="pag-count" id="member-dir-count-top">
+
+			<?php bp_members_pagination_count(); ?>
+
+		</div>
+
+		<div class="pagination-links" id="member-dir-pag-top">
+
+			<?php bp_members_pagination_links(); ?>
+
+		</div>
+
+	</div>
+
+	<ul id="friend-list" class="item-list" role="main">
+		<?php while ( bp_members() ) : bp_the_member(); ?>
+
+			<li id="friendship-<?php bp_friend_friendship_id(); ?>">
+				<div class="item-avatar">
+					<a href="<?php bp_member_link(); ?>"><?php bp_member_avatar(); ?></a>
+				</div>
+
+				<div class="item">
+					<div class="item-title"><a href="<?php bp_member_link(); ?>"><?php bp_member_name(); ?></a></div>
+					<div class="item-meta"><span class="activity"><?php bp_member_last_active(); ?></span></div>
+				</div>
+
+				<?php do_action( 'bp_friend_requests_item' ); ?>
+
+				<div class="action">
+					<a class="button accept" href="<?php bp_friend_accept_request_link(); ?>"><?php _e( 'Accept', 'buddypress' ); ?></a> &nbsp;
+					<a class="button reject" href="<?php bp_friend_reject_request_link(); ?>"><?php _e( 'Reject', 'buddypress' ); ?></a>
+
+					<?php do_action( 'bp_friend_requests_item_action' ); ?>
+				</div>
+			</li>
+
+		<?php endwhile; ?>
+	</ul>
+
+	<?php do_action( 'bp_friend_requests_content' ); ?>
+
+	<div id="pag-bottom" class="pagination no-ajax">
+
+		<div class="pag-count" id="member-dir-count-bottom">
+
+			<?php bp_members_pagination_count(); ?>
+
+		</div>
+
+		<div class="pagination-links" id="member-dir-pag-bottom">
+
+			<?php bp_members_pagination_links(); ?>
+
+		</div>
+
+	</div>
+
+<?php else: ?>
+
+	<div id="message" class="info">
+		<p><?php _e( 'You have no pending friendship requests.', 'buddypress' ); ?></p>
+	</div>
+
+<?php endif;?>
+
+<?php do_action( 'bp_after_member_friend_requests_content' ); ?>
Index: /tags/1.9/bp-themes/bp-default/members/single/groups.php
===================================================================
--- /tags/1.9/bp-themes/bp-default/members/single/groups.php	(revision 7684)
+++ /tags/1.9/bp-themes/bp-default/members/single/groups.php	(revision 7684)
@@ -0,0 +1,53 @@
+<?php
+
+/**
+ * BuddyPress - Users Groups
+ *
+ * @package BuddyPress
+ * @subpackage bp-default
+ */
+
+?>
+
+<div class="item-list-tabs no-ajax" id="subnav" role="navigation">
+	<ul>
+		<?php if ( bp_is_my_profile() ) bp_get_options_nav(); ?>
+
+		<?php if ( !bp_is_current_action( 'invites' ) ) : ?>
+
+			<li id="groups-order-select" class="last filter">
+
+				<label for="groups-sort-by"><?php _e( 'Order By:', 'buddypress' ); ?></label>
+				<select id="groups-sort-by">
+					<option value="active"><?php _e( 'Last Active', 'buddypress' ); ?></option>
+					<option value="popular"><?php _e( 'Most Members', 'buddypress' ); ?></option>
+					<option value="newest"><?php _e( 'Newly Created', 'buddypress' ); ?></option>
+					<option value="alphabetical"><?php _e( 'Alphabetical', 'buddypress' ); ?></option>
+
+					<?php do_action( 'bp_member_group_order_options' ); ?>
+
+				</select>
+			</li>
+
+		<?php endif; ?>
+
+	</ul>
+</div><!-- .item-list-tabs -->
+
+<?php
+
+if ( bp_is_current_action( 'invites' ) ) :
+	locate_template( array( 'members/single/groups/invites.php' ), true );
+
+else :
+	do_action( 'bp_before_member_groups_content' ); ?>
+
+	<div class="groups mygroups">
+
+		<?php locate_template( array( 'groups/groups-loop.php' ), true ); ?>
+
+	</div>
+
+	<?php do_action( 'bp_after_member_groups_content' ); ?>
+
+<?php endif; ?>
Index: /tags/1.9/bp-themes/bp-default/members/single/groups/invites.php
===================================================================
--- /tags/1.9/bp-themes/bp-default/members/single/groups/invites.php	(revision 7684)
+++ /tags/1.9/bp-themes/bp-default/members/single/groups/invites.php	(revision 7684)
@@ -0,0 +1,42 @@
+<?php do_action( 'bp_before_group_invites_content' ); ?>
+
+<?php if ( bp_has_groups( 'type=invites&user_id=' . bp_loggedin_user_id() ) ) : ?>
+
+	<ul id="group-list" class="invites item-list" role="main">
+
+		<?php while ( bp_groups() ) : bp_the_group(); ?>
+
+			<li>
+				<div class="item-avatar">
+					<a href="<?php bp_group_permalink(); ?>"><?php bp_group_avatar( 'type=thumb&width=50&height=50' ); ?></a>
+				</div>
+
+				<h4><a href="<?php bp_group_permalink(); ?>"><?php bp_group_name(); ?></a><span class="small"> - <?php printf( _n( '1 member', '%d members', bp_get_group_total_members( false ), 'buddypress' )  ); ?></span></h4>
+
+				<p class="desc">
+					<?php bp_group_description_excerpt(); ?>
+				</p>
+
+				<?php do_action( 'bp_group_invites_item' ); ?>
+
+				<div class="action">
+					<a class="button accept" href="<?php bp_group_accept_invite_link(); ?>"><?php _e( 'Accept', 'buddypress' ); ?></a> &nbsp;
+					<a class="button reject confirm" href="<?php bp_group_reject_invite_link(); ?>"><?php _e( 'Reject', 'buddypress' ); ?></a>
+
+					<?php do_action( 'bp_group_invites_item_action' ); ?>
+
+				</div>
+			</li>
+
+		<?php endwhile; ?>
+	</ul>
+
+<?php else: ?>
+
+	<div id="message" class="info" role="main">
+		<p><?php _e( 'You have no outstanding group invites.', 'buddypress' ); ?></p>
+	</div>
+
+<?php endif;?>
+
+<?php do_action( 'bp_after_group_invites_content' ); ?>
Index: /tags/1.9/bp-themes/bp-default/members/single/home.php
===================================================================
--- /tags/1.9/bp-themes/bp-default/members/single/home.php	(revision 7684)
+++ /tags/1.9/bp-themes/bp-default/members/single/home.php	(revision 7684)
@@ -0,0 +1,79 @@
+<?php
+
+/**
+ * BuddyPress - Users Home
+ *
+ * @package BuddyPress
+ * @subpackage bp-default
+ */
+
+get_header( 'buddypress' ); ?>
+
+	<div id="content">
+		<div class="padder">
+
+			<?php do_action( 'bp_before_member_home_content' ); ?>
+
+			<div id="item-header" role="complementary">
+
+				<?php locate_template( array( 'members/single/member-header.php' ), true ); ?>
+
+			</div><!-- #item-header -->
+
+			<div id="item-nav">
+				<div class="item-list-tabs no-ajax" id="object-nav" role="navigation">
+					<ul>
+
+						<?php bp_get_displayed_user_nav(); ?>
+
+						<?php do_action( 'bp_member_options_nav' ); ?>
+
+					</ul>
+				</div>
+			</div><!-- #item-nav -->
+
+			<div id="item-body">
+
+				<?php do_action( 'bp_before_member_body' );
+
+				if ( bp_is_user_activity() || !bp_current_component() ) :
+					locate_template( array( 'members/single/activity.php'  ), true );
+
+				 elseif ( bp_is_user_blogs() ) :
+					locate_template( array( 'members/single/blogs.php'     ), true );
+
+				elseif ( bp_is_user_friends() ) :
+					locate_template( array( 'members/single/friends.php'   ), true );
+
+				elseif ( bp_is_user_groups() ) :
+					locate_template( array( 'members/single/groups.php'    ), true );
+
+				elseif ( bp_is_user_messages() ) :
+					locate_template( array( 'members/single/messages.php'  ), true );
+
+				elseif ( bp_is_user_profile() ) :
+					locate_template( array( 'members/single/profile.php'   ), true );
+
+				elseif ( bp_is_user_forums() ) :
+					locate_template( array( 'members/single/forums.php'    ), true );
+
+				elseif ( bp_is_user_settings() ) :
+					locate_template( array( 'members/single/settings.php'  ), true );
+
+				// If nothing sticks, load a generic template
+				else :
+					locate_template( array( 'members/single/plugins.php'   ), true );
+
+				endif;
+
+				do_action( 'bp_after_member_body' ); ?>
+
+			</div><!-- #item-body -->
+
+			<?php do_action( 'bp_after_member_home_content' ); ?>
+
+		</div><!-- .padder -->
+	</div><!-- #content -->
+
+<?php get_sidebar( 'buddypress' ); ?>
+<?php get_footer( 'buddypress' ); ?>
Index: /tags/1.9/bp-themes/bp-default/members/single/member-header.php
===================================================================
--- /tags/1.9/bp-themes/bp-default/members/single/member-header.php	(revision 7684)
+++ /tags/1.9/bp-themes/bp-default/members/single/member-header.php	(revision 7684)
@@ -0,0 +1,69 @@
+<?php
+
+/**
+ * BuddyPress - Users Header
+ *
+ * @package BuddyPress
+ * @subpackage bp-default
+ */
+
+?>
+
+<?php do_action( 'bp_before_member_header' ); ?>
+
+<div id="item-header-avatar">
+	<a href="<?php bp_displayed_user_link(); ?>">
+
+		<?php bp_displayed_user_avatar( 'type=full' ); ?>
+
+	</a>
+</div><!-- #item-header-avatar -->
+
+<div id="item-header-content">
+
+	<h2>
+		<a href="<?php bp_displayed_user_link(); ?>"><?php bp_displayed_user_fullname(); ?></a>
+	</h2>
+
+	<?php if ( bp_is_active( 'activity' ) && bp_activity_do_mentions() ) : ?>
+		<span class="user-nicename">@<?php bp_displayed_user_mentionname(); ?></span>
+	<?php endif; ?>
+
+	<span class="activity"><?php bp_last_activity( bp_displayed_user_id() ); ?></span>
+
+	<?php do_action( 'bp_before_member_header_meta' ); ?>
+
+	<div id="item-meta">
+
+		<?php if ( bp_is_active( 'activity' ) ) : ?>
+
+			<div id="latest-update">
+
+				<?php bp_activity_latest_update( bp_displayed_user_id() ); ?>
+
+			</div>
+
+		<?php endif; ?>
+
+		<div id="item-buttons">
+
+			<?php do_action( 'bp_member_header_actions' ); ?>
+
+		</div><!-- #item-buttons -->
+
+		<?php
+		/***
+		 * If you'd like to show specific profile fields here use:
+		 * bp_member_profile_data( 'field=About Me' ); -- Pass the name of the field
+		 */
+		 do_action( 'bp_profile_header_meta' );
+
+		 ?>
+
+	</div><!-- #item-meta -->
+
+</div><!-- #item-header-content -->
+
+<?php do_action( 'bp_after_member_header' ); ?>
+
+<?php do_action( 'template_notices' ); ?>
Index: /tags/1.9/bp-themes/bp-default/members/single/messages.php
===================================================================
--- /tags/1.9/bp-themes/bp-default/members/single/messages.php	(revision 7684)
+++ /tags/1.9/bp-themes/bp-default/members/single/messages.php	(revision 7684)
@@ -0,0 +1,51 @@
+<?php
+
+/**
+ * BuddyPress - Users Messages
+ *
+ * @package BuddyPress
+ * @subpackage bp-default
+ */
+
+?>
+
+<div class="item-list-tabs no-ajax" id="subnav" role="navigation">
+	<ul>
+
+		<?php bp_get_options_nav(); ?>
+
+	</ul>
+	
+	<?php if ( bp_is_messages_inbox() || bp_is_messages_sentbox() ) : ?>
+
+		<div class="message-search"><?php bp_message_search_form(); ?></div>
+
+	<?php endif; ?>
+
+</div><!-- .item-list-tabs -->
+
+<?php
+
+	if ( bp_is_current_action( 'compose' ) ) :
+		locate_template( array( 'members/single/messages/compose.php' ), true );
+
+	elseif ( bp_is_current_action( 'view' ) ) :
+		locate_template( array( 'members/single/messages/single.php' ), true );
+
+	else :
+		do_action( 'bp_before_member_messages_content' ); ?>
+
+	<div class="messages" role="main">
+
+		<?php
+			if ( bp_is_current_action( 'notices' ) )
+				locate_template( array( 'members/single/messages/notices-loop.php' ), true );
+			else
+				locate_template( array( 'members/single/messages/messages-loop.php' ), true );
+		?>
+
+	</div><!-- .messages -->
+
+	<?php do_action( 'bp_after_member_messages_content' ); ?>
+
+<?php endif; ?>
Index: /tags/1.9/bp-themes/bp-default/members/single/messages/compose.php
===================================================================
--- /tags/1.9/bp-themes/bp-default/members/single/messages/compose.php	(revision 7684)
+++ /tags/1.9/bp-themes/bp-default/members/single/messages/compose.php	(revision 7684)
@@ -0,0 +1,37 @@
+<form action="<?php bp_messages_form_action('compose'); ?>" method="post" id="send_message_form" class="standard-form" role="main" enctype="multipart/form-data">
+
+	<?php do_action( 'bp_before_messages_compose_content' ); ?>
+
+	<label for="send-to-input"><?php _e("Send To (Username or Friend's Name)", 'buddypress'); ?></label>
+	<ul class="first acfb-holder">
+		<li>
+			<?php bp_message_get_recipient_tabs(); ?>
+			<input type="text" name="send-to-input" class="send-to-input" id="send-to-input" />
+		</li>
+	</ul>
+
+	<?php if ( bp_current_user_can( 'bp_moderate' ) ) : ?>
+		<input type="checkbox" id="send-notice" name="send-notice" value="1" /> <?php _e( "This is a notice to all users.", "buddypress" ); ?>
+	<?php endif; ?>
+
+	<label for="subject"><?php _e( 'Subject', 'buddypress'); ?></label>
+	<input type="text" name="subject" id="subject" value="<?php bp_messages_subject_value(); ?>" />
+
+	<label for="content"><?php _e( 'Message', 'buddypress'); ?></label>
+	<textarea name="content" id="message_content" rows="15" cols="40"><?php bp_messages_content_value(); ?></textarea>
+
+	<input type="hidden" name="send_to_usernames" id="send-to-usernames" value="<?php bp_message_get_recipient_usernames(); ?>" class="<?php bp_message_get_recipient_usernames(); ?>" />
+
+	<?php do_action( 'bp_after_messages_compose_content' ); ?>
+
+	<div class="submit">
+		<input type="submit" value="<?php _e( "Send Message", 'buddypress' ); ?>" name="send" id="send" />
+	</div>
+
+	<?php wp_nonce_field( 'messages_send_message' ); ?>
+</form>
+
+<script type="text/javascript">
+	document.getElementById("send-to-input").focus();
+</script>
+
Index: /tags/1.9/bp-themes/bp-default/members/single/messages/messages-loop.php
===================================================================
--- /tags/1.9/bp-themes/bp-default/members/single/messages/messages-loop.php	(revision 7684)
+++ /tags/1.9/bp-themes/bp-default/members/single/messages/messages-loop.php	(revision 7684)
@@ -0,0 +1,74 @@
+<?php do_action( 'bp_before_member_messages_loop' ); ?>
+
+<?php if ( bp_has_message_threads( bp_ajax_querystring( 'messages' ) ) ) : ?>
+
+	<div class="pagination no-ajax" id="user-pag">
+
+		<div class="pag-count" id="messages-dir-count">
+			<?php bp_messages_pagination_count(); ?>
+		</div>
+
+		<div class="pagination-links" id="messages-dir-pag">
+			<?php bp_messages_pagination(); ?>
+		</div>
+
+	</div><!-- .pagination -->
+
+	<?php do_action( 'bp_after_member_messages_pagination' ); ?>
+
+	<?php do_action( 'bp_before_member_messages_threads'   ); ?>
+
+	<table id="message-threads" class="messages-notices">
+		<?php while ( bp_message_threads() ) : bp_message_thread(); ?>
+
+			<tr id="m-<?php bp_message_thread_id(); ?>" class="<?php bp_message_css_class(); ?><?php if ( bp_message_thread_has_unread() ) : ?> unread<?php else: ?> read<?php endif; ?>">
+				<td width="1%" class="thread-count">
+					<span class="unread-count"><?php bp_message_thread_unread_count(); ?></span>
+				</td>
+				<td width="1%" class="thread-avatar"><?php bp_message_thread_avatar(); ?></td>
+
+				<?php if ( 'sentbox' != bp_current_action() ) : ?>
+					<td width="30%" class="thread-from">
+						<?php _e( 'From:', 'buddypress' ); ?> <?php bp_message_thread_from(); ?><br />
+						<span class="activity"><?php bp_message_thread_last_post_date(); ?></span>
+					</td>
+				<?php else: ?>
+					<td width="30%" class="thread-from">
+						<?php _e( 'To:', 'buddypress' ); ?> <?php bp_message_thread_to(); ?><br />
+						<span class="activity"><?php bp_message_thread_last_post_date(); ?></span>
+					</td>
+				<?php endif; ?>
+
+				<td width="50%" class="thread-info">
+					<p><a href="<?php bp_message_thread_view_link(); ?>" title="<?php _e( "View Message", "buddypress" ); ?>"><?php bp_message_thread_subject(); ?></a></p>
+					<p class="thread-excerpt"><?php bp_message_thread_excerpt(); ?></p>
+				</td>
+
+				<?php do_action( 'bp_messages_inbox_list_item' ); ?>
+
+				<td width="13%" class="thread-options">
+					<input type="checkbox" name="message_ids[]" value="<?php bp_message_thread_id(); ?>" />
+					<a class="button confirm" href="<?php bp_message_thread_delete_link(); ?>" title="<?php _e( "Delete Message", "buddypress" ); ?>"><?php _e( 'Delete', 'buddypress' ); ?></a> &nbsp;
+				</td>
+			</tr>
+
+		<?php endwhile; ?>
+	</table><!-- #message-threads -->
+
+	<div class="messages-options-nav">
+		<?php bp_messages_options(); ?>
+	</div><!-- .messages-options-nav -->
+
+	<?php do_action( 'bp_after_member_messages_threads' ); ?>
+
+	<?php do_action( 'bp_after_member_messages_options' ); ?>
+
+<?php else: ?>
+
+	<div id="message" class="info">
+		<p><?php _e( 'Sorry, no messages were found.', 'buddypress' ); ?></p>
+	</div>
+
+<?php endif;?>
+
+<?php do_action( 'bp_after_member_messages_loop' ); ?>
Index: /tags/1.9/bp-themes/bp-default/members/single/messages/notices-loop.php
===================================================================
--- /tags/1.9/bp-themes/bp-default/members/single/messages/notices-loop.php	(revision 7684)
+++ /tags/1.9/bp-themes/bp-default/members/single/messages/notices-loop.php	(revision 7684)
@@ -0,0 +1,59 @@
+<?php do_action( 'bp_before_notices_loop' ); ?>
+
+<?php if ( bp_has_message_threads() ) : ?>
+
+	<div class="pagination no-ajax" id="user-pag">
+
+		<div class="pag-count" id="messages-dir-count">
+			<?php bp_messages_pagination_count(); ?>
+		</div>
+
+		<div class="pagination-links" id="messages-dir-pag">
+			<?php bp_messages_pagination(); ?>
+		</div>
+
+	</div><!-- .pagination -->
+
+	<?php do_action( 'bp_after_notices_pagination' ); ?>
+	<?php do_action( 'bp_before_notices' ); ?>
+
+	<table id="message-threads" class="messages-notices">
+		<?php while ( bp_message_threads() ) : bp_message_thread(); ?>
+			<tr id="notice-<?php bp_message_notice_id(); ?>" class="<?php bp_message_css_class(); ?>">
+				<td width="1%"></td>
+				<td width="38%">
+					<strong><?php bp_message_notice_subject(); ?></strong>
+					<?php bp_message_notice_text(); ?>
+				</td>
+				<td width="21%">
+
+					<?php if ( bp_messages_is_active_notice() ) : ?>
+
+						<strong><?php bp_messages_is_active_notice(); ?></strong>
+
+					<?php endif; ?>
+
+					<span class="activity"><?php _e( 'Sent:', 'buddypress' ); ?> <?php bp_message_notice_post_date(); ?></span>
+				</td>
+
+				<?php do_action( 'bp_notices_list_item' ); ?>
+
+				<td width="10%">
+					<a class="button" href="<?php bp_message_activate_deactivate_link(); ?>" class="confirm"><?php bp_message_activate_deactivate_text(); ?></a>
+					<a class="button" href="<?php bp_message_notice_delete_link(); ?>" class="confirm" title="<?php _e( "Delete Message", "buddypress" ); ?>">x</a>
+				</td>
+			</tr>
+		<?php endwhile; ?>
+	</table><!-- #message-threads -->
+
+	<?php do_action( 'bp_after_notices' ); ?>
+
+<?php else: ?>
+
+	<div id="message" class="info">
+		<p><?php _e( 'Sorry, no notices were found.', 'buddypress' ); ?></p>
+	</div>
+
+<?php endif;?>
+
+<?php do_action( 'bp_after_notices_loop' ); ?>
Index: /tags/1.9/bp-themes/bp-default/members/single/messages/single.php
===================================================================
--- /tags/1.9/bp-themes/bp-default/members/single/messages/single.php	(revision 7684)
+++ /tags/1.9/bp-themes/bp-default/members/single/messages/single.php	(revision 7684)
@@ -0,0 +1,110 @@
+<div id="message-thread" role="main">
+
+	<?php do_action( 'bp_before_message_thread_content' ); ?>
+
+	<?php if ( bp_thread_has_messages() ) : ?>
+
+		<h3 id="message-subject"><?php bp_the_thread_subject(); ?></h3>
+
+		<p id="message-recipients">
+			<span class="highlight">
+
+				<?php if ( !bp_get_the_thread_recipients() ) : ?>
+
+					<?php _e( 'You are alone in this conversation.', 'buddypress' ); ?>
+
+				<?php else : ?>
+
+					<?php printf( __( 'Conversation between %s and you.', 'buddypress' ), bp_get_the_thread_recipients() ); ?>
+
+				<?php endif; ?>
+
+			</span>
+
+			<a class="button confirm" href="<?php bp_the_thread_delete_link(); ?>" title="<?php _e( "Delete Message", "buddypress" ); ?>"><?php _e( 'Delete', 'buddypress' ); ?></a> &nbsp;
+		</p>
+
+		<?php do_action( 'bp_before_message_thread_list' ); ?>
+
+		<?php while ( bp_thread_messages() ) : bp_thread_the_message(); ?>
+
+			<div class="message-box <?php bp_the_thread_message_alt_class(); ?>">
+
+				<div class="message-metadata">
+
+					<?php do_action( 'bp_before_message_meta' ); ?>
+
+					<?php bp_the_thread_message_sender_avatar( 'type=thumb&width=30&height=30' ); ?>
+					<strong><a href="<?php bp_the_thread_message_sender_link(); ?>" title="<?php bp_the_thread_message_sender_name(); ?>"><?php bp_the_thread_message_sender_name(); ?></a> <span class="activity"><?php bp_the_thread_message_time_since(); ?></span></strong>
+
+					<?php do_action( 'bp_after_message_meta' ); ?>
+
+				</div><!-- .message-metadata -->
+
+				<?php do_action( 'bp_before_message_content' ); ?>
+
+				<div class="message-content">
+
+					<?php bp_the_thread_message_content(); ?>
+
+				</div><!-- .message-content -->
+
+				<?php do_action( 'bp_after_message_content' ); ?>
+
+				<div class="clear"></div>
+
+			</div><!-- .message-box -->
+
+		<?php endwhile; ?>
+
+		<?php do_action( 'bp_after_message_thread_list' ); ?>
+
+		<?php do_action( 'bp_before_message_thread_reply' ); ?>
+
+		<form id="send-reply" action="<?php bp_messages_form_action(); ?>" method="post" class="standard-form">
+
+			<div class="message-box">
+
+				<div class="message-metadata">
+
+					<?php do_action( 'bp_before_message_meta' ); ?>
+
+					<div class="avatar-box">
+						<?php bp_loggedin_user_avatar( 'type=thumb&height=30&width=30' ); ?>
+
+						<strong><?php _e( 'Send a Reply', 'buddypress' ); ?></strong>
+					</div>
+
+					<?php do_action( 'bp_after_message_meta' ); ?>
+
+				</div><!-- .message-metadata -->
+
+				<div class="message-content">
+
+					<?php do_action( 'bp_before_message_reply_box' ); ?>
+
+					<textarea name="content" id="message_content" rows="15" cols="40"></textarea>
+
+					<?php do_action( 'bp_after_message_reply_box' ); ?>
+
+					<div class="submit">
+						<input type="submit" name="send" value="<?php _e( 'Send Reply', 'buddypress' ); ?>" id="send_reply_button"/>
+					</div>
+
+					<input type="hidden" id="thread_id" name="thread_id" value="<?php bp_the_thread_id(); ?>" />
+					<input type="hidden" id="messages_order" name="messages_order" value="<?php bp_thread_messages_order(); ?>" />
+					<?php wp_nonce_field( 'messages_send_message', 'send_message_nonce' ); ?>
+
+				</div><!-- .message-content -->
+
+			</div><!-- .message-box -->
+
+		</form><!-- #send-reply -->
+
+		<?php do_action( 'bp_after_message_thread_reply' ); ?>
+
+	<?php endif; ?>
+
+	<?php do_action( 'bp_after_message_thread_content' ); ?>
+
+</div>
Index: /tags/1.9/bp-themes/bp-default/members/single/plugins.php
===================================================================
--- /tags/1.9/bp-themes/bp-default/members/single/plugins.php	(revision 7684)
+++ /tags/1.9/bp-themes/bp-default/members/single/plugins.php	(revision 7684)
@@ -0,0 +1,69 @@
+<?php
+
+/**
+ * BuddyPress - Users Plugins
+ *
+ * This is a fallback file that external plugins can use if the template they
+ * need is not installed in the current theme. Use the actions in this template
+ * to output everything your plugin needs.
+ *
+ * @package BuddyPress
+ * @subpackage bp-default
+ */
+
+?>
+
+<?php get_header( 'buddypress' ); ?>
+
+	<div id="content">
+		<div class="padder">
+
+			<?php do_action( 'bp_before_member_plugin_template' ); ?>
+
+			<div id="item-header">
+
+				<?php locate_template( array( 'members/single/member-header.php' ), true ); ?>
+
+			</div><!-- #item-header -->
+
+			<div id="item-nav">
+				<div class="item-list-tabs no-ajax" id="object-nav" role="navigation">
+					<ul>
+
+						<?php bp_get_displayed_user_nav(); ?>
+
+						<?php do_action( 'bp_member_options_nav' ); ?>
+
+					</ul>
+				</div>
+			</div><!-- #item-nav -->
+
+			<div id="item-body" role="main">
+
+				<?php do_action( 'bp_before_member_body' ); ?>
+
+				<div class="item-list-tabs no-ajax" id="subnav">
+					<ul>
+
+						<?php bp_get_options_nav(); ?>
+
+						<?php do_action( 'bp_member_plugin_options_nav' ); ?>
+
+					</ul>
+				</div><!-- .item-list-tabs -->
+
+				<h3><?php do_action( 'bp_template_title' ); ?></h3>
+
+				<?php do_action( 'bp_template_content' ); ?>
+
+				<?php do_action( 'bp_after_member_body' ); ?>
+
+			</div><!-- #item-body -->
+
+			<?php do_action( 'bp_after_member_plugin_template' ); ?>
+
+		</div><!-- .padder -->
+	</div><!-- #content -->
+
+<?php get_sidebar( 'buddypress' ); ?>
+<?php get_footer( 'buddypress' ); ?>
Index: /tags/1.9/bp-themes/bp-default/members/single/profile.php
===================================================================
--- /tags/1.9/bp-themes/bp-default/members/single/profile.php	(revision 7684)
+++ /tags/1.9/bp-themes/bp-default/members/single/profile.php	(revision 7684)
@@ -0,0 +1,42 @@
+<?php
+
+/**
+ * BuddyPress - Users Profile
+ *
+ * @package BuddyPress
+ * @subpackage bp-default
+ */
+
+?>
+
+<div class="item-list-tabs no-ajax" id="subnav" role="navigation">
+	<ul>
+		<?php bp_get_options_nav(); ?>
+	</ul>
+</div><!-- .item-list-tabs -->
+
+<?php do_action( 'bp_before_profile_content' ); ?>
+
+<div class="profile" role="main">
+
+	<?php
+		// Profile Edit
+		if ( bp_is_current_action( 'edit' ) )
+			locate_template( array( 'members/single/profile/edit.php' ), true );
+
+		// Change Avatar
+		elseif ( bp_is_current_action( 'change-avatar' ) )
+			locate_template( array( 'members/single/profile/change-avatar.php' ), true );
+
+		// Display XProfile
+		elseif ( bp_is_active( 'xprofile' ) )
+			locate_template( array( 'members/single/profile/profile-loop.php' ), true );
+
+		// Display WordPress profile (fallback)
+		else
+			locate_template( array( 'members/single/profile/profile-wp.php' ), true );
+	?>
+
+</div><!-- .profile -->
+
+<?php do_action( 'bp_after_profile_content' ); ?>
Index: /tags/1.9/bp-themes/bp-default/members/single/profile/change-avatar.php
===================================================================
--- /tags/1.9/bp-themes/bp-default/members/single/profile/change-avatar.php	(revision 7684)
+++ /tags/1.9/bp-themes/bp-default/members/single/profile/change-avatar.php	(revision 7684)
@@ -0,0 +1,59 @@
+<h4><?php _e( 'Change Avatar', 'buddypress' ); ?></h4>
+
+<?php do_action( 'bp_before_profile_avatar_upload_content' ); ?>
+
+<?php if ( !(int)bp_get_option( 'bp-disable-avatar-uploads' ) ) : ?>
+
+	<p><?php _e( 'Your avatar will be used on your profile and throughout the site. If there is a <a href="http://gravatar.com">Gravatar</a> associated with your account email we will use that, or you can upload an image from your computer.', 'buddypress'); ?></p>
+
+	<form action="" method="post" id="avatar-upload-form" class="standard-form" enctype="multipart/form-data">
+
+		<?php if ( 'upload-image' == bp_get_avatar_admin_step() ) : ?>
+
+			<?php wp_nonce_field( 'bp_avatar_upload' ); ?>
+			<p><?php _e( 'Click below to select a JPG, GIF or PNG format photo from your computer and then click \'Upload Image\' to proceed.', 'buddypress' ); ?></p>
+
+			<p id="avatar-upload">
+				<input type="file" name="file" id="file" />
+				<input type="submit" name="upload" id="upload" value="<?php _e( 'Upload Image', 'buddypress' ); ?>" />
+				<input type="hidden" name="action" id="action" value="bp_avatar_upload" />
+			</p>
+
+			<?php if ( bp_get_user_has_avatar() ) : ?>
+				<p><?php _e( "If you'd like to delete your current avatar but not upload a new one, please use the delete avatar button.", 'buddypress' ); ?></p>
+				<p><a class="button edit" href="<?php bp_avatar_delete_link(); ?>" title="<?php _e( 'Delete Avatar', 'buddypress' ); ?>"><?php _e( 'Delete My Avatar', 'buddypress' ); ?></a></p>
+			<?php endif; ?>
+
+		<?php endif; ?>
+
+		<?php if ( 'crop-image' == bp_get_avatar_admin_step() ) : ?>
+
+			<h5><?php _e( 'Crop Your New Avatar', 'buddypress' ); ?></h5>
+
+			<img src="<?php bp_avatar_to_crop(); ?>" id="avatar-to-crop" class="avatar" alt="<?php _e( 'Avatar to crop', 'buddypress' ); ?>" />
+
+			<div id="avatar-crop-pane">
+				<img src="<?php bp_avatar_to_crop(); ?>" id="avatar-crop-preview" class="avatar" alt="<?php _e( 'Avatar preview', 'buddypress' ); ?>" />
+			</div>
+
+			<input type="submit" name="avatar-crop-submit" id="avatar-crop-submit" value="<?php _e( 'Crop Image', 'buddypress' ); ?>" />
+
+			<input type="hidden" name="image_src" id="image_src" value="<?php bp_avatar_to_crop_src(); ?>" />
+			<input type="hidden" id="x" name="x" />
+			<input type="hidden" id="y" name="y" />
+			<input type="hidden" id="w" name="w" />
+			<input type="hidden" id="h" name="h" />
+
+			<?php wp_nonce_field( 'bp_avatar_cropstore' ); ?>
+
+		<?php endif; ?>
+
+	</form>
+
+<?php else : ?>
+
+	<p><?php _e( 'Your avatar will be used on your profile and throughout the site. To change your avatar, please create an account with <a href="http://gravatar.com">Gravatar</a> using the same email address as you used to register with this site.', 'buddypress' ); ?></p>
+
+<?php endif; ?>
+
+<?php do_action( 'bp_after_profile_avatar_upload_content' ); ?>
Index: /tags/1.9/bp-themes/bp-default/members/single/profile/edit.php
===================================================================
--- /tags/1.9/bp-themes/bp-default/members/single/profile/edit.php	(revision 7684)
+++ /tags/1.9/bp-themes/bp-default/members/single/profile/edit.php	(revision 7684)
@@ -0,0 +1,159 @@
+<?php do_action( 'bp_before_profile_edit_content' );
+
+if ( bp_has_profile( 'profile_group_id=' . bp_get_current_profile_group_id() ) ) :
+	while ( bp_profile_groups() ) : bp_the_profile_group(); ?>
+
+<form action="<?php bp_the_profile_group_edit_form_action(); ?>" method="post" id="profile-edit-form" class="standard-form <?php bp_the_profile_group_slug(); ?>">
+
+	<?php do_action( 'bp_before_profile_field_content' ); ?>
+
+		<h4><?php printf( __( "Editing '%s' Profile Group", "buddypress" ), bp_get_the_profile_group_name() ); ?></h4>
+
+		<ul class="button-nav">
+
+			<?php bp_profile_group_tabs(); ?>
+
+		</ul>
+
+		<div class="clear"></div>
+
+		<?php while ( bp_profile_fields() ) : bp_the_profile_field(); ?>
+
+			<div<?php bp_field_css_class( 'editfield' ); ?>>
+
+				<?php if ( 'textbox' == bp_get_the_profile_field_type() ) : ?>
+
+					<label for="<?php bp_the_profile_field_input_name(); ?>"><?php bp_the_profile_field_name(); ?> <?php if ( bp_get_the_profile_field_is_required() ) : ?><?php _e( '(required)', 'buddypress' ); ?><?php endif; ?></label>
+					<input type="text" name="<?php bp_the_profile_field_input_name(); ?>" id="<?php bp_the_profile_field_input_name(); ?>" value="<?php bp_the_profile_field_edit_value(); ?>" <?php if ( bp_get_the_profile_field_is_required() ) : ?>aria-required="true"<?php endif; ?>/>
+
+				<?php endif; ?>
+
+				<?php if ( 'textarea' == bp_get_the_profile_field_type() ) : ?>
+
+					<label for="<?php bp_the_profile_field_input_name(); ?>"><?php bp_the_profile_field_name(); ?> <?php if ( bp_get_the_profile_field_is_required() ) : ?><?php _e( '(required)', 'buddypress' ); ?><?php endif; ?></label>
+					<textarea rows="5" cols="40" name="<?php bp_the_profile_field_input_name(); ?>" id="<?php bp_the_profile_field_input_name(); ?>" <?php if ( bp_get_the_profile_field_is_required() ) : ?>aria-required="true"<?php endif; ?>><?php bp_the_profile_field_edit_value(); ?></textarea>
+
+				<?php endif; ?>
+
+				<?php if ( 'selectbox' == bp_get_the_profile_field_type() ) : ?>
+
+					<label for="<?php bp_the_profile_field_input_name(); ?>"><?php bp_the_profile_field_name(); ?> <?php if ( bp_get_the_profile_field_is_required() ) : ?><?php _e( '(required)', 'buddypress' ); ?><?php endif; ?></label>
+					<select name="<?php bp_the_profile_field_input_name(); ?>" id="<?php bp_the_profile_field_input_name(); ?>" <?php if ( bp_get_the_profile_field_is_required() ) : ?>aria-required="true"<?php endif; ?>>
+						<?php bp_the_profile_field_options(); ?>
+					</select>
+
+				<?php endif; ?>
+
+				<?php if ( 'multiselectbox' == bp_get_the_profile_field_type() ) : ?>
+
+					<label for="<?php bp_the_profile_field_input_name(); ?>"><?php bp_the_profile_field_name(); ?> <?php if ( bp_get_the_profile_field_is_required() ) : ?><?php _e( '(required)', 'buddypress' ); ?><?php endif; ?></label>
+					<select name="<?php bp_the_profile_field_input_name(); ?>" id="<?php bp_the_profile_field_input_name(); ?>" multiple="multiple" <?php if ( bp_get_the_profile_field_is_required() ) : ?>aria-required="true"<?php endif; ?>>
+
+						<?php bp_the_profile_field_options(); ?>
+
+					</select>
+
+					<?php if ( !bp_get_the_profile_field_is_required() ) : ?>
+
+						<a class="clear-value" href="javascript:clear( '<?php bp_the_profile_field_input_name(); ?>' );"><?php _e( 'Clear', 'buddypress' ); ?></a>
+
+					<?php endif; ?>
+
+				<?php endif; ?>
+
+				<?php if ( 'radio' == bp_get_the_profile_field_type() ) : ?>
+
+					<div class="radio">
+						<span class="label"><?php bp_the_profile_field_name(); ?> <?php if ( bp_get_the_profile_field_is_required() ) : ?><?php _e( '(required)', 'buddypress' ); ?><?php endif; ?></span>
+
+						<?php bp_the_profile_field_options(); ?>
+
+						<?php if ( !bp_get_the_profile_field_is_required() ) : ?>
+
+							<a class="clear-value" href="javascript:clear( '<?php bp_the_profile_field_input_name(); ?>' );"><?php _e( 'Clear', 'buddypress' ); ?></a>
+
+						<?php endif; ?>
+					</div>
+
+				<?php endif; ?>
+
+				<?php if ( 'checkbox' == bp_get_the_profile_field_type() ) : ?>
+
+					<div class="checkbox">
+						<span class="label"><?php bp_the_profile_field_name(); ?> <?php if ( bp_get_the_profile_field_is_required() ) : ?><?php _e( '(required)', 'buddypress' ); ?><?php endif; ?></span>
+
+						<?php bp_the_profile_field_options(); ?>
+					</div>
+
+				<?php endif; ?>
+
+				<?php if ( 'datebox' == bp_get_the_profile_field_type() ) : ?>
+
+					<div class="datebox">
+						<label for="<?php bp_the_profile_field_input_name(); ?>_day"><?php bp_the_profile_field_name(); ?> <?php if ( bp_get_the_profile_field_is_required() ) : ?><?php _e( '(required)', 'buddypress' ); ?><?php endif; ?></label>
+
+						<select name="<?php bp_the_profile_field_input_name(); ?>_day" id="<?php bp_the_profile_field_input_name(); ?>_day" <?php if ( bp_get_the_profile_field_is_required() ) : ?>aria-required="true"<?php endif; ?>>
+
+							<?php bp_the_profile_field_options( 'type=day' ); ?>
+
+						</select>
+
+						<select name="<?php bp_the_profile_field_input_name(); ?>_month" id="<?php bp_the_profile_field_input_name(); ?>_month" <?php if ( bp_get_the_profile_field_is_required() ) : ?>aria-required="true"<?php endif; ?>>
+
+							<?php bp_the_profile_field_options( 'type=month' ); ?>
+
+						</select>
+
+						<select name="<?php bp_the_profile_field_input_name(); ?>_year" id="<?php bp_the_profile_field_input_name(); ?>_year" <?php if ( bp_get_the_profile_field_is_required() ) : ?>aria-required="true"<?php endif; ?>>
+
+							<?php bp_the_profile_field_options( 'type=year' ); ?>
+
+						</select>
+					</div>
+
+				<?php endif; ?>
+
+				<?php do_action( 'bp_custom_profile_edit_fields_pre_visibility' ); ?>
+
+				<?php if ( bp_current_user_can( 'bp_xprofile_change_field_visibility' ) ) : ?>
+					<p class="field-visibility-settings-toggle" id="field-visibility-settings-toggle-<?php bp_the_profile_field_id() ?>">
+						<?php printf( __( 'This field can be seen by: <span class="current-visibility-level">%s</span>', 'buddypress' ), bp_get_the_profile_field_visibility_level_label() ) ?> <a href="#" class="visibility-toggle-link"><?php _e( 'Change', 'buddypress' ); ?></a>
+					</p>
+
+					<div class="field-visibility-settings" id="field-visibility-settings-<?php bp_the_profile_field_id() ?>">
+						<fieldset>
+							<legend><?php _e( 'Who can see this field?', 'buddypress' ) ?></legend>
+
+							<?php bp_profile_visibility_radio_buttons() ?>
+
+						</fieldset>
+						<a class="field-visibility-settings-close" href="#"><?php _e( 'Close', 'buddypress' ) ?></a>
+					</div>
+				<?php else : ?>
+					<div class="field-visibility-settings-notoggle" id="field-visibility-settings-toggle-<?php bp_the_profile_field_id() ?>">
+						<?php printf( __( 'This field can be seen by: <span class="current-visibility-level">%s</span>', 'buddypress' ), bp_get_the_profile_field_visibility_level_label() ) ?>
+					</div>
+				<?php endif ?>
+
+				<?php do_action( 'bp_custom_profile_edit_fields' ); ?>
+
+				<p class="description"><?php bp_the_profile_field_description(); ?></p>
+			</div>
+
+		<?php endwhile; ?>
+
+	<?php do_action( 'bp_after_profile_field_content' ); ?>
+
+	<div class="submit">
+		<input type="submit" name="profile-group-edit-submit" id="profile-group-edit-submit" value="<?php _e( 'Save Changes', 'buddypress' ); ?> " />
+	</div>
+
+	<input type="hidden" name="field_ids" id="field_ids" value="<?php bp_the_profile_group_field_ids(); ?>" />
+
+	<?php wp_nonce_field( 'bp_xprofile_edit' ); ?>
+
+</form>
+
+<?php endwhile; endif; ?>
+
+<?php do_action( 'bp_after_profile_edit_content' ); ?>
Index: /tags/1.9/bp-themes/bp-default/members/single/profile/profile-loop.php
===================================================================
--- /tags/1.9/bp-themes/bp-default/members/single/profile/profile-loop.php	(revision 7684)
+++ /tags/1.9/bp-themes/bp-default/members/single/profile/profile-loop.php	(revision 7684)
@@ -0,0 +1,48 @@
+<?php do_action( 'bp_before_profile_loop_content' ); ?>
+
+<?php if ( bp_has_profile() ) : ?>
+
+	<?php while ( bp_profile_groups() ) : bp_the_profile_group(); ?>
+
+		<?php if ( bp_profile_group_has_fields() ) : ?>
+
+			<?php do_action( 'bp_before_profile_field_content' ); ?>
+
+			<div class="bp-widget <?php bp_the_profile_group_slug(); ?>">
+
+				<h4><?php bp_the_profile_group_name(); ?></h4>
+
+				<table class="profile-fields">
+
+					<?php while ( bp_profile_fields() ) : bp_the_profile_field(); ?>
+
+						<?php if ( bp_field_has_data() ) : ?>
+
+							<tr<?php bp_field_css_class(); ?>>
+
+								<td class="label"><?php bp_the_profile_field_name(); ?></td>
+
+								<td class="data"><?php bp_the_profile_field_value(); ?></td>
+
+							</tr>
+
+						<?php endif; ?>
+
+						<?php do_action( 'bp_profile_field_item' ); ?>
+
+					<?php endwhile; ?>
+
+				</table>
+			</div>
+
+			<?php do_action( 'bp_after_profile_field_content' ); ?>
+
+		<?php endif; ?>
+
+	<?php endwhile; ?>
+
+	<?php do_action( 'bp_profile_field_buttons' ); ?>
+
+<?php endif; ?>
+
+<?php do_action( 'bp_after_profile_loop_content' ); ?>
Index: /tags/1.9/bp-themes/bp-default/members/single/profile/profile-wp.php
===================================================================
--- /tags/1.9/bp-themes/bp-default/members/single/profile/profile-wp.php	(revision 7684)
+++ /tags/1.9/bp-themes/bp-default/members/single/profile/profile-wp.php	(revision 7684)
@@ -0,0 +1,73 @@
+<?php do_action( 'bp_before_profile_loop_content' ); ?>
+
+<?php $ud = get_userdata( bp_displayed_user_id() ); ?>
+
+<?php do_action( 'bp_before_profile_field_content' ); ?>
+
+	<div class="bp-widget wp-profile">
+		<h4><?php bp_is_my_profile() ? _e( 'My Profile', 'buddypress' ) : printf( __( "%s's Profile", 'buddypress' ), bp_get_displayed_user_fullname() ); ?></h4>
+
+		<table class="wp-profile-fields">
+
+			<?php if ( $ud->display_name ) : ?>
+
+				<tr id="wp_displayname">
+					<td class="label"><?php _e( 'Name', 'buddypress' ); ?></td>
+					<td class="data"><?php echo $ud->display_name; ?></td>
+				</tr>
+
+			<?php endif; ?>
+
+			<?php if ( $ud->user_description ) : ?>
+
+				<tr id="wp_desc">
+					<td class="label"><?php _e( 'About Me', 'buddypress' ); ?></td>
+					<td class="data"><?php echo $ud->user_description; ?></td>
+				</tr>
+
+			<?php endif; ?>
+
+			<?php if ( $ud->user_url ) : ?>
+
+				<tr id="wp_website">
+					<td class="label"><?php _e( 'Website', 'buddypress' ); ?></td>
+					<td class="data"><?php echo make_clickable( $ud->user_url ); ?></td>
+				</tr>
+
+			<?php endif; ?>
+
+			<?php if ( $ud->jabber ) : ?>
+
+				<tr id="wp_jabber">
+					<td class="label"><?php _e( 'Jabber', 'buddypress' ); ?></td>
+					<td class="data"><?php echo $ud->jabber; ?></td>
+				</tr>
+
+			<?php endif; ?>
+
+			<?php if ( $ud->aim ) : ?>
+
+				<tr id="wp_aim">
+					<td class="label"><?php _e( 'AOL Messenger', 'buddypress' ); ?></td>
+					<td class="data"><?php echo $ud->aim; ?></td>
+				</tr>
+
+			<?php endif; ?>
+
+			<?php if ( $ud->yim ) : ?>
+
+				<tr id="wp_yim">
+					<td class="label"><?php _e( 'Yahoo Messenger', 'buddypress' ); ?></td>
+					<td class="data"><?php echo $ud->yim; ?></td>
+				</tr>
+
+			<?php endif; ?>
+
+		</table>
+	</div>
+
+<?php do_action( 'bp_after_profile_field_content' ); ?>
+
+<?php do_action( 'bp_profile_field_buttons' ); ?>
+
+<?php do_action( 'bp_after_profile_loop_content' ); ?>
Index: /tags/1.9/bp-themes/bp-default/members/single/settings.php
===================================================================
--- /tags/1.9/bp-themes/bp-default/members/single/settings.php	(revision 7684)
+++ /tags/1.9/bp-themes/bp-default/members/single/settings.php	(revision 7684)
@@ -0,0 +1,38 @@
+<?php
+
+/**
+ * BuddyPress - Users Settings
+ *
+ * @package BuddyPress
+ * @subpackage bp-default
+ */
+
+?>
+
+<div class="item-list-tabs no-ajax" id="subnav" role="navigation">
+	<ul>
+		<?php if ( bp_core_can_edit_settings() ) : ?>
+		
+			<?php bp_get_options_nav(); ?>
+		
+		<?php endif; ?>
+	</ul>
+</div>
+
+<?php
+
+if ( bp_is_current_action( 'notifications' ) ) :
+	 locate_template( array( 'members/single/settings/notifications.php' ), true );
+
+elseif ( bp_is_current_action( 'delete-account' ) ) :
+	 locate_template( array( 'members/single/settings/delete-account.php' ), true );
+
+elseif ( bp_is_current_action( 'general' ) ) :
+	locate_template( array( 'members/single/settings/general.php' ), true );
+
+else :
+	locate_template( array( 'members/single/plugins.php' ), true );
+
+endif;
+
+?>
Index: /tags/1.9/bp-themes/bp-default/members/single/settings/capabilities.php
===================================================================
--- /tags/1.9/bp-themes/bp-default/members/single/settings/capabilities.php	(revision 7684)
+++ /tags/1.9/bp-themes/bp-default/members/single/settings/capabilities.php	(revision 7684)
@@ -0,0 +1,81 @@
+<?php
+
+/**
+ * BuddyPress Delete Account
+ *
+ * @package BuddyPress
+ * @subpackage bp-default
+ */
+
+get_header( 'buddypress' ); ?>
+
+	<div id="content">
+		<div class="padder">
+
+			<?php do_action( 'bp_before_member_settings_template' ); ?>
+
+			<div id="item-header">
+
+				<?php locate_template( array( 'members/single/member-header.php' ), true ); ?>
+
+			</div><!-- #item-header -->
+
+			<div id="item-nav">
+				<div class="item-list-tabs no-ajax" id="object-nav" role="navigation">
+					<ul>
+
+						<?php bp_get_displayed_user_nav(); ?>
+
+						<?php do_action( 'bp_member_options_nav' ); ?>
+
+					</ul>
+				</div>
+			</div><!-- #item-nav -->
+
+			<div id="item-body" role="main">
+
+				<?php do_action( 'bp_before_member_body' ); ?>
+
+				<div class="item-list-tabs no-ajax" id="subnav">
+					<ul>
+
+						<?php bp_get_options_nav(); ?>
+
+						<?php do_action( 'bp_member_plugin_options_nav' ); ?>
+
+					</ul>
+				</div><!-- .item-list-tabs -->
+
+				<h3><?php _e( 'Capabilities', 'buddypress' ); ?></h3>
+
+				<form action="<?php echo bp_displayed_user_domain() . bp_get_settings_slug() . '/capabilities/'; ?>" name="account-capabilities-form" id="account-capabilities-form" class="standard-form" method="post">
+
+					<?php do_action( 'bp_members_capabilities_account_before_submit' ); ?>
+
+					<label>
+						<input type="checkbox" name="user-spammer" id="user-spammer" value="1" <?php checked( bp_is_user_spammer( bp_displayed_user_id() ) ); ?> />
+						 <?php _e( 'This user is a spammer.', 'buddypress' ); ?>
+					</label>
+
+					<div class="submit">
+						<input type="submit" value="<?php _e( 'Save', 'buddypress' ); ?>" id="capabilities-submit" name="capabilities-submit" />
+					</div>
+
+					<?php do_action( 'bp_members_capabilities_account_after_submit' ); ?>
+
+					<?php wp_nonce_field( 'capabilities' ); ?>
+
+				</form>
+
+				<?php do_action( 'bp_after_member_body' ); ?>
+
+			</div><!-- #item-body -->
+
+			<?php do_action( 'bp_after_member_settings_template' ); ?>
+
+		</div><!-- .padder -->
+	</div><!-- #content -->
+
+<?php get_sidebar( 'buddypress' ); ?>
+
+<?php get_footer( 'buddypress' ); ?>
Index: /tags/1.9/bp-themes/bp-default/members/single/settings/delete-account.php
===================================================================
--- /tags/1.9/bp-themes/bp-default/members/single/settings/delete-account.php	(revision 7684)
+++ /tags/1.9/bp-themes/bp-default/members/single/settings/delete-account.php	(revision 7684)
@@ -0,0 +1,96 @@
+<?php
+
+/**
+ * BuddyPress Delete Account
+ *
+ * @package BuddyPress
+ * @subpackage bp-default
+ */
+?>
+
+<?php get_header( 'buddypress' ); ?>
+
+	<div id="content">
+		<div class="padder">
+
+			<?php do_action( 'bp_before_member_settings_template' ); ?>
+
+			<div id="item-header">
+
+				<?php locate_template( array( 'members/single/member-header.php' ), true ); ?>
+
+			</div><!-- #item-header -->
+
+			<div id="item-nav">
+				<div class="item-list-tabs no-ajax" id="object-nav" role="navigation">
+					<ul>
+
+						<?php bp_get_displayed_user_nav(); ?>
+
+						<?php do_action( 'bp_member_options_nav' ); ?>
+
+					</ul>
+				</div>
+			</div><!-- #item-nav -->
+
+			<div id="item-body" role="main">
+
+				<?php do_action( 'bp_before_member_body' ); ?>
+
+				<div class="item-list-tabs no-ajax" id="subnav">
+					<ul>
+
+						<?php bp_get_options_nav(); ?>
+
+						<?php do_action( 'bp_member_plugin_options_nav' ); ?>
+
+					</ul>
+				</div><!-- .item-list-tabs -->
+
+				<h3><?php _e( 'Delete Account', 'buddypress' ); ?></h3>
+
+				<div id="message" class="info">
+					
+					<?php if ( bp_is_my_profile() ) : ?>
+
+						<p><?php _e( 'Deleting your account will delete all of the content you have created. It will be completely irrecoverable.', 'buddypress' ); ?></p>
+						
+					<?php else : ?>
+
+						<p><?php _e( 'Deleting this account will delete all of the content it has created. It will be completely irrecoverable.', 'buddypress' ); ?></p>
+
+					<?php endif; ?>
+
+				</div>
+
+				<form action="<?php echo bp_displayed_user_domain() . bp_get_settings_slug() . '/delete-account'; ?>" name="account-delete-form" id="account-delete-form" class="standard-form" method="post">
+
+					<?php do_action( 'bp_members_delete_account_before_submit' ); ?>
+
+					<label>
+						<input type="checkbox" name="delete-account-understand" id="delete-account-understand" value="1" onclick="if(this.checked) { document.getElementById('delete-account-button').disabled = ''; } else { document.getElementById('delete-account-button').disabled = 'disabled'; }" />
+						 <?php _e( 'I understand the consequences.', 'buddypress' ); ?>
+					</label>
+
+					<div class="submit">
+						<input type="submit" disabled="disabled" value="<?php _e( 'Delete Account', 'buddypress' ); ?>" id="delete-account-button" name="delete-account-button" />
+					</div>
+
+					<?php do_action( 'bp_members_delete_account_after_submit' ); ?>
+
+					<?php wp_nonce_field( 'delete-account' ); ?>
+
+				</form>
+
+				<?php do_action( 'bp_after_member_body' ); ?>
+
+			</div><!-- #item-body -->
+
+			<?php do_action( 'bp_after_member_settings_template' ); ?>
+
+		</div><!-- .padder -->
+	</div><!-- #content -->
+
+<?php get_sidebar( 'buddypress' ); ?>
+
+<?php get_footer( 'buddypress' ); ?>
Index: /tags/1.9/bp-themes/bp-default/members/single/settings/general.php
===================================================================
--- /tags/1.9/bp-themes/bp-default/members/single/settings/general.php	(revision 7684)
+++ /tags/1.9/bp-themes/bp-default/members/single/settings/general.php	(revision 7684)
@@ -0,0 +1,92 @@
+<?php
+
+/**
+ * BuddyPress Member Settings
+ *
+ * @package BuddyPress
+ * @subpackage bp-default
+ */
+
+get_header( 'buddypress' ); ?>
+
+	<div id="content">
+		<div class="padder">
+
+			<?php do_action( 'bp_before_member_settings_template' ); ?>
+
+			<div id="item-header">
+
+				<?php locate_template( array( 'members/single/member-header.php' ), true ); ?>
+
+			</div><!-- #item-header -->
+
+			<div id="item-nav">
+				<div class="item-list-tabs no-ajax" id="object-nav" role="navigation">
+					<ul>
+
+						<?php bp_get_displayed_user_nav(); ?>
+
+						<?php do_action( 'bp_member_options_nav' ); ?>
+
+					</ul>
+				</div>
+			</div><!-- #item-nav -->
+
+			<div id="item-body" role="main">
+
+				<?php do_action( 'bp_before_member_body' ); ?>
+
+				<div class="item-list-tabs no-ajax" id="subnav">
+					<ul>
+
+						<?php bp_get_options_nav(); ?>
+
+						<?php do_action( 'bp_member_plugin_options_nav' ); ?>
+
+					</ul>
+				</div><!-- .item-list-tabs -->
+
+				<h3><?php _e( 'General Settings', 'buddypress' ); ?></h3>
+
+				<?php do_action( 'bp_template_content' ); ?>
+
+				<form action="<?php echo bp_displayed_user_domain() . bp_get_settings_slug() . '/general'; ?>" method="post" class="standard-form" id="settings-form">
+
+					<?php if ( !is_super_admin() ) : ?>
+
+						<label for="pwd"><?php _e( 'Current Password <span>(required to update email or change current password)</span>', 'buddypress' ); ?></label>
+						<input type="password" name="pwd" id="pwd" size="16" value="" class="settings-input small" /> &nbsp;<a href="<?php echo wp_lostpassword_url(); ?>" title="<?php _e( 'Password Lost and Found', 'buddypress' ); ?>"><?php _e( 'Lost your password?', 'buddypress' ); ?></a>
+
+					<?php endif; ?>
+
+					<label for="email"><?php _e( 'Account Email', 'buddypress' ); ?></label>
+					<input type="text" name="email" id="email" value="<?php echo bp_get_displayed_user_email(); ?>" class="settings-input" />
+
+					<label for="pass1"><?php _e( 'Change Password <span>(leave blank for no change)</span>', 'buddypress' ); ?></label>
+					<input type="password" name="pass1" id="pass1" size="16" value="" class="settings-input small" /> &nbsp;<?php _e( 'New Password', 'buddypress' ); ?><br />
+					<input type="password" name="pass2" id="pass2" size="16" value="" class="settings-input small" /> &nbsp;<?php _e( 'Repeat New Password', 'buddypress' ); ?>
+
+					<?php do_action( 'bp_core_general_settings_before_submit' ); ?>
+
+					<div class="submit">
+						<input type="submit" name="submit" value="<?php _e( 'Save Changes', 'buddypress' ); ?>" id="submit" class="auto" />
+					</div>
+
+					<?php do_action( 'bp_core_general_settings_after_submit' ); ?>
+
+					<?php wp_nonce_field( 'bp_settings_general' ); ?>
+
+				</form>
+
+				<?php do_action( 'bp_after_member_body' ); ?>
+
+			</div><!-- #item-body -->
+
+			<?php do_action( 'bp_after_member_settings_template' ); ?>
+
+		</div><!-- .padder -->
+	</div><!-- #content -->
+
+<?php get_sidebar( 'buddypress' ); ?>
+
+<?php get_footer( 'buddypress' ); ?>
Index: /tags/1.9/bp-themes/bp-default/members/single/settings/notifications.php
===================================================================
--- /tags/1.9/bp-themes/bp-default/members/single/settings/notifications.php	(revision 7684)
+++ /tags/1.9/bp-themes/bp-default/members/single/settings/notifications.php	(revision 7684)
@@ -0,0 +1,81 @@
+<?php
+
+/**
+ * BuddyPress Notification Settings
+ *
+ * @package BuddyPress
+ * @subpackage bp-default
+ */
+
+get_header( 'buddypress' ); ?>
+
+	<div id="content">
+		<div class="padder">
+
+			<?php do_action( 'bp_before_member_settings_template' ); ?>
+
+			<div id="item-header">
+
+				<?php locate_template( array( 'members/single/member-header.php' ), true ); ?>
+
+			</div><!-- #item-header -->
+
+			<div id="item-nav">
+				<div class="item-list-tabs no-ajax" id="object-nav" role="navigation">
+					<ul>
+
+						<?php bp_get_displayed_user_nav(); ?>
+
+						<?php do_action( 'bp_member_options_nav' ); ?>
+
+					</ul>
+				</div>
+			</div><!-- #item-nav -->
+
+			<div id="item-body" role="main">
+
+				<?php do_action( 'bp_before_member_body' ); ?>
+
+				<div class="item-list-tabs no-ajax" id="subnav">
+					<ul>
+
+						<?php bp_get_options_nav(); ?>
+
+						<?php do_action( 'bp_member_plugin_options_nav' ); ?>
+
+					</ul>
+				</div><!-- .item-list-tabs -->
+
+				<h3><?php _e( 'Email Notification', 'buddypress' ); ?></h3>
+
+				<?php do_action( 'bp_template_content' ); ?>
+
+				<form action="<?php echo bp_displayed_user_domain() . bp_get_settings_slug() . '/notifications'; ?>" method="post" class="standard-form" id="settings-form">
+					<p><?php _e( 'Send an email notice when:', 'buddypress' ); ?></p>
+
+					<?php do_action( 'bp_notification_settings' ); ?>
+
+					<?php do_action( 'bp_members_notification_settings_before_submit' ); ?>
+
+					<div class="submit">
+						<input type="submit" name="submit" value="<?php _e( 'Save Changes', 'buddypress' ); ?>" id="submit" class="auto" />
+					</div>
+
+					<?php do_action( 'bp_members_notification_settings_after_submit' ); ?>
+
+					<?php wp_nonce_field('bp_settings_notifications'); ?>
+
+				</form>
+
+				<?php do_action( 'bp_after_member_body' ); ?>
+
+			</div><!-- #item-body -->
+
+			<?php do_action( 'bp_after_member_settings_template' ); ?>
+
+		</div><!-- .padder -->
+	</div><!-- #content -->
+
+<?php get_sidebar( 'buddypress' ); ?>
+
+<?php get_footer( 'buddypress' ); ?>
Index: /tags/1.9/bp-themes/bp-default/onecolumn-page.php
===================================================================
--- /tags/1.9/bp-themes/bp-default/onecolumn-page.php	(revision 7684)
+++ /tags/1.9/bp-themes/bp-default/onecolumn-page.php	(revision 7684)
@@ -0,0 +1,49 @@
+<?php
+/*
+ * Template Name: One column, no sidebar
+ *
+ * A custom page template without sidebar.
+ *
+ * @package BuddyPress
+ * @subpackage BP_Default
+ * @since BuddyPress (1.5)
+ */
+
+get_header(); ?>
+
+	<div id="content">
+		<div class="padder one-column">
+
+		<?php do_action( 'bp_before_blog_page' ); ?>
+
+		<div class="page" id="blog-page" role="main">
+
+			<?php if (have_posts()) : while (have_posts()) : the_post(); ?>
+
+				<h2 class="pagetitle"><?php the_title(); ?></h2>
+
+				<div id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
+
+					<div class="entry">
+
+						<?php the_content( __( '<p class="serif">Read the rest of this page &rarr;</p>', 'buddypress' ) ); ?>
+
+						<?php wp_link_pages( array( 'before' => '<div class="page-link"><p>' . __( 'Pages: ', 'buddypress' ), 'after' => '</p></div>', 'next_or_number' => 'number' ) ); ?>
+						<?php edit_post_link( __( 'Edit this page.', 'buddypress' ), '<p class="edit-link">', '</p>'); ?>
+
+					</div>
+
+				</div>
+
+			<?php comments_template(); ?>
+
+			<?php endwhile; endif; ?>
+
+		</div><!-- .page -->
+
+		<?php do_action( 'bp_after_blog_page' ); ?>
+
+		</div><!-- .padder -->
+	</div><!-- #content -->
+
+<?php get_footer(); ?>
Index: /tags/1.9/bp-themes/bp-default/page.php
===================================================================
--- /tags/1.9/bp-themes/bp-default/page.php	(revision 7684)
+++ /tags/1.9/bp-themes/bp-default/page.php	(revision 7684)
@@ -0,0 +1,40 @@
+<?php get_header(); ?>
+
+	<div id="content">
+		<div class="padder">
+
+		<?php do_action( 'bp_before_blog_page' ); ?>
+
+		<div class="page" id="blog-page" role="main">
+
+			<?php if (have_posts()) : while (have_posts()) : the_post(); ?>
+
+				<h2 class="pagetitle"><?php the_title(); ?></h2>
+
+				<div id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
+
+					<div class="entry">
+
+						<?php the_content( __( '<p class="serif">Read the rest of this page &rarr;</p>', 'buddypress' ) ); ?>
+
+						<?php wp_link_pages( array( 'before' => '<div class="page-link"><p>' . __( 'Pages: ', 'buddypress' ), 'after' => '</p></div>', 'next_or_number' => 'number' ) ); ?>
+						<?php edit_post_link( __( 'Edit this page.', 'buddypress' ), '<p class="edit-link">', '</p>'); ?>
+
+					</div>
+
+				</div>
+
+			<?php comments_template(); ?>
+
+			<?php endwhile; endif; ?>
+
+		</div><!-- .page -->
+
+		<?php do_action( 'bp_after_blog_page' ); ?>
+
+		</div><!-- .padder -->
+	</div><!-- #content -->
+
+	<?php get_sidebar(); ?>
+
+<?php get_footer(); ?>
Index: /tags/1.9/bp-themes/bp-default/readme.txt
===================================================================
--- /tags/1.9/bp-themes/bp-default/readme.txt	(revision 7684)
+++ /tags/1.9/bp-themes/bp-default/readme.txt	(revision 7684)
@@ -0,0 +1,22 @@
+--- BuddyPress Default ---
+Clean and stylish, BuddyPress Default lets you build a social network straight out of the box. Make it yours with a custom menu, header image, and background. Along with five widgetized areas (one in the sidebar, four in the footer), BP-Default supports featured images (as custom header images on posts and pages) and is furnished with an optional one-column page template that removes the sidebar, and a stylesheet for the admin Visual Editor.
+
+
+--- Installation ---
+The theme is bundled with BuddyPress. After activating the plugin, BuddyPress Default will be added to the "Appearance > Themes" menu in your WordPress admin area.
+
+
+--- About BuddyPress ---
+Social networking in a box. Build a social network for your company, school, sports team or niche community all based on the power and flexibility of WordPress. BuddyPress will let users register on your site and start creating profiles, posting messages, making connections, creating and interacting in groups and much more.
+
+For help with BuddyPress Default, or for more information about BuddyPress, please visit http://buddypress.org/.
+
+
+--- Building a BuddyPress theme ---
+If you want to make a custom theme based on BuddyPress Default, DO NOT copy and edit it. By doing this you will make updates and maintenance much harder for yourself. Instead, please review this codex page for instructions on how to build a BuddyPress child theme:
+
+http://codex.buddypress.org/how-to-guides/building-a-buddypress-child-theme/
+
+
+--- Changelog ---
+A list of changes is available at http://codex.buddypress.org/theme-development/bp-default-theme-changelog/.
Index: /tags/1.9/bp-themes/bp-default/registration/activate.php
===================================================================
--- /tags/1.9/bp-themes/bp-default/registration/activate.php	(revision 7684)
+++ /tags/1.9/bp-themes/bp-default/registration/activate.php	(revision 7684)
@@ -0,0 +1,56 @@
+<?php get_header( 'buddypress' ); ?>
+
+	<div id="content">
+		<div class="padder">
+
+		<?php do_action( 'bp_before_activation_page' ); ?>
+
+		<div class="page" id="activate-page">
+
+			<h3><?php if ( bp_account_was_activated() ) :
+				_e( 'Account Activated', 'buddypress' );
+			else :
+				_e( 'Activate your Account', 'buddypress' );
+			endif; ?></h3>
+
+			<?php do_action( 'template_notices' ); ?>
+
+			<?php do_action( 'bp_before_activate_content' ); ?>
+
+			<?php if ( bp_account_was_activated() ) : ?>
+
+				<?php if ( isset( $_GET['e'] ) ) : ?>
+					<p><?php _e( 'Your account was activated successfully! Your account details have been sent to you in a separate email.', 'buddypress' ); ?></p>
+				<?php else : ?>
+					<p><?php printf( __( 'Your account was activated successfully! You can now <a href="%s">log in</a> with the username and password you provided when you signed up.', 'buddypress' ), wp_login_url( bp_get_root_domain() ) ); ?></p>
+				<?php endif; ?>
+
+			<?php else : ?>
+
+				<p><?php _e( 'Please provide a valid activation key.', 'buddypress' ); ?></p>
+
+				<form action="" method="get" class="standard-form" id="activation-form">
+
+					<label for="key"><?php _e( 'Activation Key:', 'buddypress' ); ?></label>
+					<input type="text" name="key" id="key" value="" />
+
+					<p class="submit">
+						<input type="submit" name="submit" value="<?php _e( 'Activate', 'buddypress' ); ?>" />
+					</p>
+
+				</form>
+
+			<?php endif; ?>
+
+			<?php do_action( 'bp_after_activate_content' ); ?>
+
+		</div><!-- .page -->
+
+		<?php do_action( 'bp_after_activation_page' ); ?>
+
+		</div><!-- .padder -->
+	</div><!-- #content -->
+
+	<?php get_sidebar( 'buddypress' ); ?>
+
+<?php get_footer( 'buddypress' ); ?>
Index: /tags/1.9/bp-themes/bp-default/registration/register.php
===================================================================
--- /tags/1.9/bp-themes/bp-default/registration/register.php	(revision 7684)
+++ /tags/1.9/bp-themes/bp-default/registration/register.php	(revision 7684)
@@ -0,0 +1,298 @@
+<?php get_header( 'buddypress' ); ?>
+
+	<div id="content">
+		<div class="padder">
+
+		<?php do_action( 'bp_before_register_page' ); ?>
+
+		<div class="page" id="register-page">
+
+			<form action="" name="signup_form" id="signup_form" class="standard-form" method="post" enctype="multipart/form-data">
+
+			<?php if ( 'registration-disabled' == bp_get_current_signup_step() ) : ?>
+				<?php do_action( 'template_notices' ); ?>
+				<?php do_action( 'bp_before_registration_disabled' ); ?>
+
+					<p><?php _e( 'User registration is currently not allowed.', 'buddypress' ); ?></p>
+
+				<?php do_action( 'bp_after_registration_disabled' ); ?>
+			<?php endif; // registration-disabled signup setp ?>
+
+			<?php if ( 'request-details' == bp_get_current_signup_step() ) : ?>
+
+				<h2><?php _e( 'Create an Account', 'buddypress' ); ?></h2>
+
+				<?php do_action( 'template_notices' ); ?>
+
+				<p><?php _e( 'Registering for this site is easy, just fill in the fields below and we\'ll get a new account set up for you in no time.', 'buddypress' ); ?></p>
+
+				<?php do_action( 'bp_before_account_details_fields' ); ?>
+
+				<div class="register-section" id="basic-details-section">
+
+					<?php /***** Basic Account Details ******/ ?>
+
+					<h4><?php _e( 'Account Details', 'buddypress' ); ?></h4>
+
+					<label for="signup_username"><?php _e( 'Username', 'buddypress' ); ?> <?php _e( '(required)', 'buddypress' ); ?></label>
+					<?php do_action( 'bp_signup_username_errors' ); ?>
+					<input type="text" name="signup_username" id="signup_username" value="<?php bp_signup_username_value(); ?>" />
+
+					<label for="signup_email"><?php _e( 'Email Address', 'buddypress' ); ?> <?php _e( '(required)', 'buddypress' ); ?></label>
+					<?php do_action( 'bp_signup_email_errors' ); ?>
+					<input type="text" name="signup_email" id="signup_email" value="<?php bp_signup_email_value(); ?>" />
+
+					<label for="signup_password"><?php _e( 'Choose a Password', 'buddypress' ); ?> <?php _e( '(required)', 'buddypress' ); ?></label>
+					<?php do_action( 'bp_signup_password_errors' ); ?>
+					<input type="password" name="signup_password" id="signup_password" value="" />
+
+					<label for="signup_password_confirm"><?php _e( 'Confirm Password', 'buddypress' ); ?> <?php _e( '(required)', 'buddypress' ); ?></label>
+					<?php do_action( 'bp_signup_password_confirm_errors' ); ?>
+					<input type="password" name="signup_password_confirm" id="signup_password_confirm" value="" />
+
+					<?php do_action( 'bp_account_details_fields' ); ?>
+
+				</div><!-- #basic-details-section -->
+
+				<?php do_action( 'bp_after_account_details_fields' ); ?>
+
+				<?php /***** Extra Profile Details ******/ ?>
+
+				<?php if ( bp_is_active( 'xprofile' ) ) : ?>
+
+					<?php do_action( 'bp_before_signup_profile_fields' ); ?>
+
+					<div class="register-section" id="profile-details-section">
+
+						<h4><?php _e( 'Profile Details', 'buddypress' ); ?></h4>
+
+						<?php /* Use the profile field loop to render input fields for the 'base' profile field group */ ?>
+						<?php if ( bp_is_active( 'xprofile' ) ) : if ( bp_has_profile( array( 'profile_group_id' => 1, 'fetch_field_data' => false ) ) ) : while ( bp_profile_groups() ) : bp_the_profile_group(); ?>
+
+						<?php while ( bp_profile_fields() ) : bp_the_profile_field(); ?>
+
+							<div class="editfield">
+
+								<?php if ( 'textbox' == bp_get_the_profile_field_type() ) : ?>
+
+									<label for="<?php bp_the_profile_field_input_name(); ?>"><?php bp_the_profile_field_name(); ?> <?php if ( bp_get_the_profile_field_is_required() ) : ?><?php _e( '(required)', 'buddypress' ); ?><?php endif; ?></label>
+									<?php do_action( bp_get_the_profile_field_errors_action() ); ?>
+									<input type="text" name="<?php bp_the_profile_field_input_name(); ?>" id="<?php bp_the_profile_field_input_name(); ?>" value="<?php bp_the_profile_field_edit_value(); ?>" />
+
+								<?php endif; ?>
+
+								<?php if ( 'textarea' == bp_get_the_profile_field_type() ) : ?>
+
+									<label for="<?php bp_the_profile_field_input_name(); ?>"><?php bp_the_profile_field_name(); ?> <?php if ( bp_get_the_profile_field_is_required() ) : ?><?php _e( '(required)', 'buddypress' ); ?><?php endif; ?></label>
+									<?php do_action( bp_get_the_profile_field_errors_action() ); ?>
+									<textarea rows="5" cols="40" name="<?php bp_the_profile_field_input_name(); ?>" id="<?php bp_the_profile_field_input_name(); ?>"><?php bp_the_profile_field_edit_value(); ?></textarea>
+
+								<?php endif; ?>
+
+								<?php if ( 'selectbox' == bp_get_the_profile_field_type() ) : ?>
+
+									<label for="<?php bp_the_profile_field_input_name(); ?>"><?php bp_the_profile_field_name(); ?> <?php if ( bp_get_the_profile_field_is_required() ) : ?><?php _e( '(required)', 'buddypress' ); ?><?php endif; ?></label>
+									<?php do_action( bp_get_the_profile_field_errors_action() ); ?>
+									<select name="<?php bp_the_profile_field_input_name(); ?>" id="<?php bp_the_profile_field_input_name(); ?>">
+										<?php bp_the_profile_field_options(); ?>
+									</select>
+
+								<?php endif; ?>
+
+								<?php if ( 'multiselectbox' == bp_get_the_profile_field_type() ) : ?>
+
+									<label for="<?php bp_the_profile_field_input_name(); ?>"><?php bp_the_profile_field_name(); ?> <?php if ( bp_get_the_profile_field_is_required() ) : ?><?php _e( '(required)', 'buddypress' ); ?><?php endif; ?></label>
+									<?php do_action( bp_get_the_profile_field_errors_action() ); ?>
+									<select name="<?php bp_the_profile_field_input_name(); ?>" id="<?php bp_the_profile_field_input_name(); ?>" multiple="multiple">
+										<?php bp_the_profile_field_options(); ?>
+									</select>
+
+								<?php endif; ?>
+
+								<?php if ( 'radio' == bp_get_the_profile_field_type() ) : ?>
+
+									<div class="radio">
+										<span class="label"><?php bp_the_profile_field_name(); ?> <?php if ( bp_get_the_profile_field_is_required() ) : ?><?php _e( '(required)', 'buddypress' ); ?><?php endif; ?></span>
+
+										<?php do_action( bp_get_the_profile_field_errors_action() ); ?>
+										<?php bp_the_profile_field_options(); ?>
+
+										<?php if ( !bp_get_the_profile_field_is_required() ) : ?>
+											<a class="clear-value" href="javascript:clear( '<?php bp_the_profile_field_input_name(); ?>' );"><?php _e( 'Clear', 'buddypress' ); ?></a>
+										<?php endif; ?>
+									</div>
+
+								<?php endif; ?>
+
+								<?php if ( 'checkbox' == bp_get_the_profile_field_type() ) : ?>
+
+									<div class="checkbox">
+										<span class="label"><?php bp_the_profile_field_name(); ?> <?php if ( bp_get_the_profile_field_is_required() ) : ?><?php _e( '(required)', 'buddypress' ); ?><?php endif; ?></span>
+
+										<?php do_action( bp_get_the_profile_field_errors_action() ); ?>
+										<?php bp_the_profile_field_options(); ?>
+									</div>
+
+								<?php endif; ?>
+
+								<?php if ( 'datebox' == bp_get_the_profile_field_type() ) : ?>
+
+									<div class="datebox">
+										<label for="<?php bp_the_profile_field_input_name(); ?>_day"><?php bp_the_profile_field_name(); ?> <?php if ( bp_get_the_profile_field_is_required() ) : ?><?php _e( '(required)', 'buddypress' ); ?><?php endif; ?></label>
+										<?php do_action( bp_get_the_profile_field_errors_action() ); ?>
+
+										<select name="<?php bp_the_profile_field_input_name(); ?>_day" id="<?php bp_the_profile_field_input_name(); ?>_day">
+											<?php bp_the_profile_field_options( 'type=day' ); ?>
+										</select>
+
+										<select name="<?php bp_the_profile_field_input_name(); ?>_month" id="<?php bp_the_profile_field_input_name(); ?>_month">
+											<?php bp_the_profile_field_options( 'type=month' ); ?>
+										</select>
+
+										<select name="<?php bp_the_profile_field_input_name(); ?>_year" id="<?php bp_the_profile_field_input_name(); ?>_year">
+											<?php bp_the_profile_field_options( 'type=year' ); ?>
+										</select>
+									</div>
+
+								<?php endif; ?>
+
+								<?php do_action( 'bp_custom_profile_edit_fields_pre_visibility' ); ?>
+
+								<?php if ( bp_current_user_can( 'bp_xprofile_change_field_visibility' ) ) : ?>
+									<p class="field-visibility-settings-toggle" id="field-visibility-settings-toggle-<?php bp_the_profile_field_id() ?>">
+										<?php printf( __( 'This field can be seen by: <span class="current-visibility-level">%s</span>', 'buddypress' ), bp_get_the_profile_field_visibility_level_label() ) ?> <a href="#" class="visibility-toggle-link"><?php _ex( 'Change', 'Change profile field visibility level', 'buddypress' ); ?></a>
+									</p>
+
+									<div class="field-visibility-settings" id="field-visibility-settings-<?php bp_the_profile_field_id() ?>">
+										<fieldset>
+											<legend><?php _e( 'Who can see this field?', 'buddypress' ) ?></legend>
+
+											<?php bp_profile_visibility_radio_buttons() ?>
+
+										</fieldset>
+										<a class="field-visibility-settings-close" href="#"><?php _e( 'Close', 'buddypress' ) ?></a>
+
+									</div>
+								<?php else : ?>
+									<p class="field-visibility-settings-notoggle" id="field-visibility-settings-toggle-<?php bp_the_profile_field_id() ?>">
+										<?php printf( __( 'This field can be seen by: <span class="current-visibility-level">%s</span>', 'buddypress' ), bp_get_the_profile_field_visibility_level_label() ) ?>
+									</p>
+								<?php endif ?>
+
+								<?php do_action( 'bp_custom_profile_edit_fields' ); ?>
+
+								<p class="description"><?php bp_the_profile_field_description(); ?></p>
+
+							</div>
+
+						<?php endwhile; ?>
+
+						<input type="hidden" name="signup_profile_field_ids" id="signup_profile_field_ids" value="<?php bp_the_profile_group_field_ids(); ?>" />
+
+						<?php endwhile; endif; endif; ?>
+
+						<?php do_action( 'bp_signup_profile_fields' ); ?>
+
+					</div><!-- #profile-details-section -->
+
+					<?php do_action( 'bp_after_signup_profile_fields' ); ?>
+
+				<?php endif; ?>
+
+				<?php if ( bp_get_blog_signup_allowed() ) : ?>
+
+					<?php do_action( 'bp_before_blog_details_fields' ); ?>
+
+					<?php /***** Blog Creation Details ******/ ?>
+
+					<div class="register-section" id="blog-details-section">
+
+						<h4><?php _e( 'Blog Details', 'buddypress' ); ?></h4>
+
+						<p><input type="checkbox" name="signup_with_blog" id="signup_with_blog" value="1"<?php if ( (int) bp_get_signup_with_blog_value() ) : ?> checked="checked"<?php endif; ?> /> <?php _e( 'Yes, I\'d like to create a new site', 'buddypress' ); ?></p>
+
+						<div id="blog-details"<?php if ( (int) bp_get_signup_with_blog_value() ) : ?>class="show"<?php endif; ?>>
+
+							<label for="signup_blog_url"><?php _e( 'Blog URL', 'buddypress' ); ?> <?php _e( '(required)', 'buddypress' ); ?></label>
+							<?php do_action( 'bp_signup_blog_url_errors' ); ?>
+
+							<?php if ( is_subdomain_install() ) : ?>
+								http:// <input type="text" name="signup_blog_url" id="signup_blog_url" value="<?php bp_signup_blog_url_value(); ?>" /> .<?php bp_blogs_subdomain_base(); ?>
+							<?php else : ?>
+								<?php echo home_url( '/' ); ?> <input type="text" name="signup_blog_url" id="signup_blog_url" value="<?php bp_signup_blog_url_value(); ?>" />
+							<?php endif; ?>
+
+							<label for="signup_blog_title"><?php _e( 'Site Title', 'buddypress' ); ?> <?php _e( '(required)', 'buddypress' ); ?></label>
+							<?php do_action( 'bp_signup_blog_title_errors' ); ?>
+							<input type="text" name="signup_blog_title" id="signup_blog_title" value="<?php bp_signup_blog_title_value(); ?>" />
+
+							<span class="label"><?php _e( 'I would like my site to appear in search engines, and in public listings around this network.', 'buddypress' ); ?>:</span>
+							<?php do_action( 'bp_signup_blog_privacy_errors' ); ?>
+
+							<label><input type="radio" name="signup_blog_privacy" id="signup_blog_privacy_public" value="public"<?php if ( 'public' == bp_get_signup_blog_privacy_value() || !bp_get_signup_blog_privacy_value() ) : ?> checked="checked"<?php endif; ?> /> <?php _e( 'Yes', 'buddypress' ); ?></label>
+							<label><input type="radio" name="signup_blog_privacy" id="signup_blog_privacy_private" value="private"<?php if ( 'private' == bp_get_signup_blog_privacy_value() ) : ?> checked="checked"<?php endif; ?> /> <?php _e( 'No', 'buddypress' ); ?></label>
+
+							<?php do_action( 'bp_blog_details_fields' ); ?>
+
+						</div>
+
+					</div><!-- #blog-details-section -->
+
+					<?php do_action( 'bp_after_blog_details_fields' ); ?>
+
+				<?php endif; ?>
+
+				<?php do_action( 'bp_before_registration_submit_buttons' ); ?>
+
+				<div class="submit">
+					<input type="submit" name="signup_submit" id="signup_submit" value="<?php _e( 'Complete Sign Up', 'buddypress' ); ?>" />
+				</div>
+
+				<?php do_action( 'bp_after_registration_submit_buttons' ); ?>
+
+				<?php wp_nonce_field( 'bp_new_signup' ); ?>
+
+			<?php endif; // request-details signup step ?>
+
+			<?php if ( 'completed-confirmation' == bp_get_current_signup_step() ) : ?>
+
+				<h2><?php _e( 'Check Your Email To Activate Your Account!', 'buddypress' ); ?></h2>
+
+				<?php do_action( 'template_notices' ); ?>
+				<?php do_action( 'bp_before_registration_confirmed' ); ?>
+
+				<?php if ( bp_registration_needs_activation() ) : ?>
+					<p><?php _e( 'You have successfully created your account! To begin using this site you will need to activate your account via the email we have just sent to your address.', 'buddypress' ); ?></p>
+				<?php else : ?>
+					<p><?php _e( 'You have successfully created your account! Please log in using the username and password you have just created.', 'buddypress' ); ?></p>
+				<?php endif; ?>
+
+				<?php do_action( 'bp_after_registration_confirmed' ); ?>
+
+			<?php endif; // completed-confirmation signup step ?>
+
+			<?php do_action( 'bp_custom_signup_steps' ); ?>
+
+			</form>
+
+		</div>
+
+		<?php do_action( 'bp_after_register_page' ); ?>
+
+		</div><!-- .padder -->
+	</div><!-- #content -->
+
+	<?php get_sidebar( 'buddypress' ); ?>
+
+	<script type="text/javascript">
+		jQuery(document).ready( function() {
+			if ( jQuery('div#blog-details').length && !jQuery('div#blog-details').hasClass('show') )
+				jQuery('div#blog-details').toggle();
+
+			jQuery( 'input#signup_with_blog' ).click( function() {
+				jQuery('div#blog-details').fadeOut().toggle();
+			});
+		});
+	</script>
+
+<?php get_footer( 'buddypress' ); ?>
Index: /tags/1.9/bp-themes/bp-default/rtl.css
===================================================================
--- /tags/1.9/bp-themes/bp-default/rtl.css	(revision 7684)
+++ /tags/1.9/bp-themes/bp-default/rtl.css	(revision 7684)
@@ -0,0 +1,24 @@
+/**
+ * Theme Name: BuddyPress Default
+ * Theme URI: http://buddypress.org/extend/themes/
+ * Description: Clean and stylish, BuddyPress Default lets you build a social network straight out of the box. Make it yours with a custom menu, header image, and background. Along with five widgetized areas (one in the sidebar, four in the footer), BP-Default supports featured images (as custom header images on posts and pages) and is furnished with an optional one-column page template that removes the sidebar, and a stylesheet for the admin Visual Editor.
+ * Version: 1.9
+ * Author: the BuddyPress team
+ * Author URI: http://buddypress.org
+ * License: GNU General Public License
+ * License URI: license.txt
+ * Tags: blue, buddypress, custom-background, custom-header, custom-menu, editor-style, featured-image-header, featured-images, fixed-width, light, right-sidebar, rtl-language-support, sticky-post, threaded-comments, translation-ready, two-columns, white
+ *
+ *** IMPORTANT - DO NOT COPY THIS THEME **
+ *
+ * If you want to make a custom theme based on this theme, DO NOT copy and edit it. By
+ * doing this you will make updates and maintainence much harder for yourself.
+ * Instead, please read this codex page on how to build a BuddyPress child theme:
+ *
+ * http://codex.buddypress.org/how-to-guides/building-a-buddypress-child-theme/
+ *
+ ***
+ *
+ * This file intentionally left blank. CSS is enqueued in functions.php
+ *
+ */
Index: /tags/1.9/bp-themes/bp-default/search.php
===================================================================
--- /tags/1.9/bp-themes/bp-default/search.php	(revision 7684)
+++ /tags/1.9/bp-themes/bp-default/search.php	(revision 7684)
@@ -0,0 +1,65 @@
+<?php get_header(); ?>
+
+	<div id="content">
+		<div class="padder">
+
+		<?php do_action( 'bp_before_blog_search' ); ?>
+
+		<div class="page" id="blog-search" role="main">
+
+			<h2 class="pagetitle"><?php _e( 'Site', 'buddypress' ); ?></h2>
+
+			<?php if (have_posts()) : ?>
+
+				<h3 class="pagetitle"><?php _e( 'Search Results', 'buddypress' ); ?></h3>
+
+				<?php bp_dtheme_content_nav( 'nav-above' ); ?>
+
+				<?php while (have_posts()) : the_post(); ?>
+
+					<?php do_action( 'bp_before_blog_post' ); ?>
+
+					<div id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
+
+						<div class="author-box">
+							<?php echo get_avatar( get_the_author_meta( 'email' ), '50' ); ?>
+							<p><?php printf( _x( 'by %s', 'Post written by...', 'buddypress' ), bp_core_get_userlink( $post->post_author ) ); ?></p>
+						</div>
+
+						<div class="post-content">
+							<h2 class="posttitle"><a href="<?php the_permalink(); ?>" rel="bookmark" title="<?php _e( 'Permanent Link to', 'buddypress' ); ?> <?php the_title_attribute(); ?>"><?php the_title(); ?></a></h2>
+
+							<p class="date"><?php printf( __( '%1$s <span>in %2$s</span>', 'buddypress' ), get_the_date(), get_the_category_list( ', ' ) ); ?></p>
+
+							<div class="entry">
+								<?php the_content( __( 'Read the rest of this entry &rarr;', 'buddypress' ) ); ?>
+							</div>
+
+							<p class="postmetadata"><?php the_tags( '<span class="tags">' . __( 'Tags: ', 'buddypress' ), ', ', '</span>' ); ?> <span class="comments"><?php comments_popup_link( __( 'No Comments &#187;', 'buddypress' ), __( '1 Comment &#187;', 'buddypress' ), __( '% Comments &#187;', 'buddypress' ) ); ?></span></p>
+						</div>
+
+					</div>
+
+					<?php do_action( 'bp_after_blog_post' ); ?>
+
+				<?php endwhile; ?>
+
+				<?php bp_dtheme_content_nav( 'nav-below' ); ?>
+
+			<?php else : ?>
+
+				<h2 class="center"><?php _e( 'No posts found. Try a different search?', 'buddypress' ); ?></h2>
+				<?php get_search_form(); ?>
+
+			<?php endif; ?>
+
+		</div>
+
+		<?php do_action( 'bp_after_blog_search' ); ?>
+
+		</div><!-- .padder -->
+	</div><!-- #content -->
+
+	<?php get_sidebar(); ?>
+
+<?php get_footer(); ?>
Index: /tags/1.9/bp-themes/bp-default/searchform.php
===================================================================
--- /tags/1.9/bp-themes/bp-default/searchform.php	(revision 7684)
+++ /tags/1.9/bp-themes/bp-default/searchform.php	(revision 7684)
@@ -0,0 +1,10 @@
+<?php do_action( 'bp_before_blog_search_form' ); ?>
+
+<form role="search" method="get" id="searchform" action="<?php echo home_url(); ?>/">
+	<input type="text" value="<?php the_search_query(); ?>" name="s" id="s" />
+	<input type="submit" id="searchsubmit" value="<?php _e( 'Search', 'buddypress' ); ?>" />
+
+	<?php do_action( 'bp_blog_search_form' ); ?>
+</form>
+
+<?php do_action( 'bp_after_blog_search_form' ); ?>
Index: /tags/1.9/bp-themes/bp-default/sidebar-footer.php
===================================================================
--- /tags/1.9/bp-themes/bp-default/sidebar-footer.php	(revision 7684)
+++ /tags/1.9/bp-themes/bp-default/sidebar-footer.php	(revision 7684)
@@ -0,0 +1,57 @@
+<?php
+	/**
+	 * The footer widget area is triggered if any of the areas
+	 * have widgets.
+	 *
+	 * If none of the sidebars have widgets, bail early.
+	 */
+	if (   ! is_active_sidebar( 'first-footer-widget-area'  )
+		&& ! is_active_sidebar( 'second-footer-widget-area' )
+		&& ! is_active_sidebar( 'third-footer-widget-area'  )
+		&& ! is_active_sidebar( 'fourth-footer-widget-area' )
+	)
+	return; ?>
+
+			<div id="footer-widget-area" role="complementary">
+
+				<?php if ( is_active_sidebar( 'first-footer-widget-area' ) ) : ?>
+
+					<div id="first" class="widget-area">
+						<ul class="xoxo">
+							<?php dynamic_sidebar( 'first-footer-widget-area' ); ?>
+						</ul>
+					</div><!-- #first .widget-area -->
+
+				<?php endif; ?>
+
+				<?php if ( is_active_sidebar( 'second-footer-widget-area' ) ) : ?>
+
+					<div id="second" class="widget-area">
+						<ul class="xoxo">
+							<?php dynamic_sidebar( 'second-footer-widget-area' ); ?>
+						</ul>
+					</div><!-- #second .widget-area -->
+
+				<?php endif; ?>
+
+				<?php if ( is_active_sidebar( 'third-footer-widget-area' ) ) : ?>
+
+					<div id="third" class="widget-area">
+						<ul class="xoxo">
+							<?php dynamic_sidebar( 'third-footer-widget-area' ); ?>
+						</ul>
+					</div><!-- #third .widget-area -->
+
+				<?php endif; ?>
+
+				<?php if ( is_active_sidebar( 'fourth-footer-widget-area' ) ) : ?>
+
+					<div id="fourth" class="widget-area">
+						<ul class="xoxo">
+							<?php dynamic_sidebar( 'fourth-footer-widget-area' ); ?>
+						</ul>
+					</div><!-- #fourth .widget-area -->
+
+				<?php endif; ?>
+
+			</div><!-- #footer-widget-area -->
Index: /tags/1.9/bp-themes/bp-default/sidebar.php
===================================================================
--- /tags/1.9/bp-themes/bp-default/sidebar.php	(revision 7684)
+++ /tags/1.9/bp-themes/bp-default/sidebar.php	(revision 7684)
@@ -0,0 +1,79 @@
+<?php do_action( 'bp_before_sidebar' ); ?>
+
+<div id="sidebar" role="complementary">
+	<div class="padder">
+
+	<?php do_action( 'bp_inside_before_sidebar' ); ?>
+
+	<?php if ( is_user_logged_in() ) : ?>
+
+		<?php do_action( 'bp_before_sidebar_me' ); ?>
+
+		<div id="sidebar-me">
+			<a href="<?php echo bp_loggedin_user_domain(); ?>">
+				<?php bp_loggedin_user_avatar( 'type=thumb&width=40&height=40' ); ?>
+			</a>
+
+			<h4><?php echo bp_core_get_userlink( bp_loggedin_user_id() ); ?></h4>
+			<a class="button logout" href="<?php echo wp_logout_url( wp_guess_url() ); ?>"><?php _e( 'Log Out', 'buddypress' ); ?></a>
+
+			<?php do_action( 'bp_sidebar_me' ); ?>
+		</div>
+
+		<?php do_action( 'bp_after_sidebar_me' ); ?>
+
+		<?php if ( bp_is_active( 'messages' ) ) : ?>
+			<?php bp_message_get_notices(); /* Site wide notices to all users */ ?>
+		<?php endif; ?>
+
+	<?php else : ?>
+
+		<?php do_action( 'bp_before_sidebar_login_form' ); ?>
+
+		<?php if ( bp_get_signup_allowed() ) : ?>
+		
+			<p id="login-text">
+
+				<?php printf( __( 'Please <a href="%s" title="Create an account">create an account</a> to get started.', 'buddypress' ), bp_get_signup_page() ); ?>
+
+			</p>
+
+		<?php endif; ?>
+
+		<form name="login-form" id="sidebar-login-form" class="standard-form" action="<?php echo site_url( 'wp-login.php', 'login_post' ); ?>" method="post">
+			<label><?php _e( 'Username', 'buddypress' ); ?><br />
+			<input type="text" name="log" id="sidebar-user-login" class="input" value="<?php if ( isset( $user_login) ) echo esc_attr(stripslashes($user_login)); ?>" tabindex="97" /></label>
+
+			<label><?php _e( 'Password', 'buddypress' ); ?><br />
+			<input type="password" name="pwd" id="sidebar-user-pass" class="input" value="" tabindex="98" /></label>
+
+			<p class="forgetmenot"><label><input name="rememberme" type="checkbox" id="sidebar-rememberme" value="forever" tabindex="99" /> <?php _e( 'Remember Me', 'buddypress' ); ?></label></p>
+
+			<input type="submit" name="wp-submit" id="sidebar-wp-submit" value="<?php _e( 'Log In', 'buddypress' ); ?>" tabindex="100" />
+
+			<?php do_action( 'bp_sidebar_login_form' ); ?>
+
+		</form>
+
+		<?php do_action( 'bp_after_sidebar_login_form' ); ?>
+
+	<?php endif; ?>
+
+	<?php /* Show forum tags on the forums directory */
+	if ( bp_is_active( 'forums' ) && bp_is_forums_component() && bp_is_directory() ) : ?>
+		<div id="forum-directory-tags" class="widget tags">
+			<h3 class="widgettitle"><?php _e( 'Forum Topic Tags', 'buddypress' ); ?></h3>
+			<div id="tag-text"><?php bp_forums_tag_heat_map(); ?></div>
+		</div>
+	<?php endif; ?>
+
+	<?php dynamic_sidebar( 'sidebar-1' ); ?>
+
+	<?php do_action( 'bp_inside_after_sidebar' ); ?>
+
+	<?php wp_meta(); ?>
+
+	</div><!-- .padder -->
+</div><!-- #sidebar -->
+
+<?php do_action( 'bp_after_sidebar' ); ?>
Index: /tags/1.9/bp-themes/bp-default/single.php
===================================================================
--- /tags/1.9/bp-themes/bp-default/single.php	(revision 7684)
+++ /tags/1.9/bp-themes/bp-default/single.php	(revision 7684)
@@ -0,0 +1,58 @@
+<?php get_header(); ?>
+
+	<div id="content">
+		<div class="padder">
+
+			<?php do_action( 'bp_before_blog_single_post' ); ?>
+
+			<div class="page" id="blog-single" role="main">
+
+			<?php if (have_posts()) : while (have_posts()) : the_post(); ?>
+
+				<div id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
+
+					<div class="author-box">
+						<?php echo get_avatar( get_the_author_meta( 'user_email' ), '50' ); ?>
+						<p><?php printf( _x( 'by %s', 'Post written by...', 'buddypress' ), str_replace( '<a href=', '<a rel="author" href=', bp_core_get_userlink( $post->post_author ) ) ); ?></p>
+					</div>
+
+					<div class="post-content">
+						<h2 class="posttitle"><?php the_title(); ?></h2>
+
+						<p class="date">
+							<?php printf( __( '%1$s <span>in %2$s</span>', 'buddypress' ), get_the_date(), get_the_category_list( ', ' ) ); ?>
+							<span class="post-utility alignright"><?php edit_post_link( __( 'Edit this entry', 'buddypress' ) ); ?></span>
+						</p>
+
+						<div class="entry">
+							<?php the_content( __( 'Read the rest of this entry &rarr;', 'buddypress' ) ); ?>
+
+							<?php wp_link_pages( array( 'before' => '<div class="page-link"><p>' . __( 'Pages: ', 'buddypress' ), 'after' => '</p></div>', 'next_or_number' => 'number' ) ); ?>
+						</div>
+
+						<p class="postmetadata"><?php the_tags( '<span class="tags">' . __( 'Tags: ', 'buddypress' ), ', ', '</span>' ); ?>&nbsp;</p>
+
+						<div class="alignleft"><?php previous_post_link( '%link', '<span class="meta-nav">' . _x( '&larr;', 'Previous post link', 'buddypress' ) . '</span> %title' ); ?></div>
+						<div class="alignright"><?php next_post_link( '%link', '%title <span class="meta-nav">' . _x( '&rarr;', 'Next post link', 'buddypress' ) . '</span>' ); ?></div>
+					</div>
+
+				</div>
+
+			<?php comments_template(); ?>
+
+			<?php endwhile; else: ?>
+
+				<p><?php _e( 'Sorry, no posts matched your criteria.', 'buddypress' ); ?></p>
+
+			<?php endif; ?>
+
+		</div>
+
+		<?php do_action( 'bp_after_blog_single_post' ); ?>
+
+		</div><!-- .padder -->
+	</div><!-- #content -->
+
+	<?php get_sidebar(); ?>
+
+<?php get_footer(); ?>
Index: /tags/1.9/bp-themes/bp-default/style.css
===================================================================
--- /tags/1.9/bp-themes/bp-default/style.css	(revision 7684)
+++ /tags/1.9/bp-themes/bp-default/style.css	(revision 7684)
@@ -0,0 +1,26 @@
+/**
+ * Theme Name: BuddyPress Default
+ * Theme URI: http://buddypress.org/extend/themes/
+ * Description: [NOTE: except for security issues, BuddyPress Default is no longer being actively maintained by the BuddyPress team.] Clean and stylish, BuddyPress Default lets you build a social network straight out of the box. Make it yours with a custom menu, header image, and background. Along with five widgetized areas (one in the sidebar, four in the footer), BP-Default supports featured images (as custom header images on posts and pages) and is furnished with an optional one-column page template that removes the sidebar, and a stylesheet for the admin Visual Editor.
+ * Version: 1.9
+ * Author: the BuddyPress team
+ * Author URI: http://buddypress.org
+ * License: GNU General Public License
+ * License URI: license.txt
+ * Tags: blue, buddypress, custom-background, custom-header, custom-menu, editor-style, featured-image-header, featured-images, fixed-width, light, right-sidebar, rtl-language-support, sticky-post, threaded-comments, translation-ready, two-columns, white
+ *
+ *** IMPORTANT ***
+ *
+ * BuddyPress Default is no longer being actively developed by the BuddyPress team.
+ *
+ * If you want to make a custom theme based on this theme, DO NOT copy and edit it. By
+ * doing this you will make updates and maintainence much harder for yourself.
+ * Instead, please read this codex page on how to build a BuddyPress child theme:
+ *
+ * http://codex.buddypress.org/how-to-guides/building-a-buddypress-child-theme/
+ *
+ ***
+ *
+ * This file intentionally left blank. CSS is enqueued in functions.php
+ *
+ */
Index: /tags/1.9/bp-themes/index.php
===================================================================
--- /tags/1.9/bp-themes/index.php	(revision 7684)
+++ /tags/1.9/bp-themes/index.php	(revision 7684)
@@ -0,0 +1,5 @@
+<?php
+
+/**
+ * @todo move bp-default to WordPress.org theme repo
+ */
Index: /tags/1.9/bp-xprofile/admin/css/admin.css
===================================================================
--- /tags/1.9/bp-xprofile/admin/css/admin.css	(revision 7684)
+++ /tags/1.9/bp-xprofile/admin/css/admin.css	(revision 7684)
@@ -0,0 +1,249 @@
+/* Profile field group main admin page */
+#tabs-bottom {
+	background: #f9f9f9;
+	height: 32px;
+	border: 1px solid #dfdfdf;
+	border-radius: 0 0 3px 3px;
+}
+
+#tabs {
+	position: relative;
+	}
+	p.nofields {
+		margin-top: 20px;
+	}
+
+	/* Field group tabs */
+	ul#field-group-tabs {
+		float: left;
+		padding: 0 0 0 15px;
+		margin: 0;
+		display: none;
+	}
+		ul#field-group-tabs li {
+			float: left;
+			margin-bottom: -1px;
+			background-color: transparent;
+			margin-right: 8px;
+		}
+		ul#field-group-tabs li.ui-state-hover a {
+			background-color: #fafafa;
+		}
+		ul#field-group-tabs li.ui-state-hover a.ui-tab {
+			border-color: #dfdfdf #dfdfdf #f9f9f9 #dfdfdf;
+			color: #d54e21;
+		}
+		ul#field-group-tabs li.ui-state-acceptable a.ui-tab {
+			border-color: #5a5 #5a5 #ccc #5a5;
+			color: #8a8;
+			background-color: #efe;
+		}
+			ul#field-group-tabs li.ui-state-active.ui-state-acceptable a.ui-tab {
+				background-color: #f9f9f9;
+			}
+		ul#field-group-tabs li.drop-candidate a.ui-tab {
+			background-color: #ffc;
+			border-color: #aa5 #aa5 #ccc #aa5;
+			color: #aa8;
+		}
+		ul#field-group-tabs li a.ui-tab {
+			font-family: Georgia, "Times New Roman", "Bitstream Charter", Times, serif;
+			font-size: 14px;
+			display: block;
+			margin-top: 3px;
+			padding: 5px 10px 5px;
+			border: 1px solid #dfdfdf;
+			border-bottom: none;
+			border-radius: 3px 3px 0 0;
+			text-decoration: none;
+			color: #aaa;
+		}
+
+		/* Selected tab */
+		ul#field-group-tabs li.ui-state-active a.ui-tab {
+			background-color: #f9f9f9;
+			margin-top: -1px;
+			padding: 7px 10px 7px;
+			border: 1px solid #dfdfdf;
+			border-bottom: 1px solid transparent;
+			color: #000;
+		}
+
+	/* Toolbar */
+	.tab-toolbar {
+		background: #f9f9f9;
+		border-width: 1px 1px 0;
+		border-radius: 3px 3px 0 0;
+		margin: -20px -21px 20px -21px;
+		clear: left;
+		padding: 10px;
+		border: 1px solid #dfdfdf;
+	}
+
+	.field-wrapper a.deletion,
+	.tab-toolbar a.deletion {
+		color: #f00;
+		border-bottom: 1px solid #f00;
+		font-size: 12px;
+		text-decoration: none;
+		padding: 0;
+		margin: -2px 0 0 5px;
+	}
+		
+	div.tab-toolbar a.button-primary {
+		color: #fff !important; /* Overriding a WP !important */
+	}
+
+	div.tab-wrapper {
+		background-color: #fff;
+		clear: left;
+		padding: 20px;
+		border-left: 1px solid #ccc;
+		border-right: 1px solid #ccc;
+		border-radius: 3px 3px 0 0;
+	}
+
+	.tab-wrapper fieldset {
+		position: relative;
+		cursor: default !important;
+		background: inherit;
+		}
+		.tab-wrapper fieldset legend {
+			padding-bottom: 15px;
+			font-weight: bold;
+		}
+	.tab-wrapper .xprofile-field {
+		position: relative;
+	}
+	.tab-wrapper fieldset fieldset {
+		position: relative;
+		border: 1px solid #ddd;
+		border-radius: 3px;
+		margin: 10px 0 0 0;
+		cursor: move !important;
+		background: #f9f9f9;
+	}
+	.tab-wrapper fieldset fieldset legend {
+		position: absolute !important;
+		top: 0;
+		left: 0;
+		width: 80%;
+		padding: 30px;
+	}
+	.tab-wrapper fieldset fieldset legend span {
+		position: absolute;
+		top: 6px;
+		left: 10px;
+		font-weight: bold;
+		width: 100%;
+	}
+		.field-group fieldset:hover {
+			background-color: #fafafa;
+			border-color: #ccc;
+		}
+		fieldset div.field-wrapper {
+			padding: 40px 10px 10px;
+		}
+	fieldset.radio div div label,
+	fieldset.checkbox div label {
+		margin-right: 20px;
+	}
+
+	fieldset.clear-value {
+		margin-left: 10px;
+	}
+	.field-group div.actions {
+		float: none;
+		border-top: 1px solid #ddd;
+		margin: 20px 0 0;
+		padding-top: 10px;
+	}
+	.field-group div.actions a,
+	.field-group div.actions button,
+	.field-group div.actions input {
+		float: none;
+	}
+	.field-group fieldset:hover div.actions {
+		display: block;
+	}
+	.field-group fieldset.ui-sortable-placeholder {
+		border: 1px dashed #999;
+		background-color: #eee;
+		visibility: visible !important;
+	}
+
+	ul.forTab {
+		list-style: none;
+		padding: 0;
+		margin: 0 0 0 1em;
+	}
+		ul.forTab li {
+			margin: 0 0 1em 0;
+		}
+
+			ul.forTab li label {
+				display: block;
+			}
+
+			ul.forTab li input {
+				font-size: 1.4em;
+			}
+
+	p.success { background: green;}
+	p.err {
+		border-top: 2px solid red;
+		border-bottom: 2px solid red;
+		color: red;
+		padding: 5px 0;
+		width: 40%;
+	}
+
+	span.desc, span.signup-description {
+		display: block;
+		font-size: 11px;
+		color: #555;
+	}
+
+	select.multi-select {
+		width:90%;
+		height:10em !important;
+	}
+
+ul.multi-checkbox {
+	margin: 0 5px 0 0;
+	padding: .5em .9em;
+	height: 10em;
+	overflow: auto;
+	list-style: none;
+	border: solid 1px #ccc;
+	width: 90%;
+}
+
+ul.multi-checkbox li {
+	padding: 0;
+	margin: 0;
+}
+
+div.options-box {
+	margin-left: 20px !important;
+	margin-right: 10px !important;
+	border-left: 4px solid #EAF3FA;
+	padding-left: 15px;
+}
+
+th a {
+	background: #fff;
+	padding: 2px 5px;
+	-moz-border-radius: 3px;
+	-khtml-border-radius: 3px;
+	-webkit-border-radius: 3px;
+	border-radius: 3px;
+	top: -2px;
+}
+
+textarea#description,
+textarea#group_description {
+	border: 1px solid #ddd;
+	width: 100%;
+}
+
Index: /tags/1.9/bp-xprofile/admin/css/admin.min.css
===================================================================
--- /tags/1.9/bp-xprofile/admin/css/admin.min.css	(revision 7684)
+++ /tags/1.9/bp-xprofile/admin/css/admin.min.css	(revision 7684)
@@ -0,0 +1,1 @@
+#tabs-bottom{background:#f9f9f9;height:32px;border:1px solid #dfdfdf;border-radius:0 0 3px 3px}#tabs{position:relative}p.nofields{margin-top:20px}ul#field-group-tabs{float:left;padding:0 0 0 15px;margin:0;display:none}ul#field-group-tabs li{float:left;margin-bottom:-1px;background-color:transparent;margin-right:8px}ul#field-group-tabs li.ui-state-hover a{background-color:#fafafa}ul#field-group-tabs li.ui-state-hover a.ui-tab{border-color:#dfdfdf #dfdfdf #f9f9f9 #dfdfdf;color:#d54e21}ul#field-group-tabs li.ui-state-acceptable a.ui-tab{border-color:#5a5 #5a5 #ccc #5a5;color:#8a8;background-color:#efe}ul#field-group-tabs li.ui-state-active.ui-state-acceptable a.ui-tab{background-color:#f9f9f9}ul#field-group-tabs li.drop-candidate a.ui-tab{background-color:#ffc;border-color:#aa5 #aa5 #ccc #aa5;color:#aa8}ul#field-group-tabs li a.ui-tab{font-family:Georgia,"Times New Roman","Bitstream Charter",Times,serif;font-size:14px;display:block;margin-top:3px;padding:5px 10px 5px;border:1px solid #dfdfdf;border-bottom:0;border-radius:3px 3px 0 0;text-decoration:none;color:#aaa}ul#field-group-tabs li.ui-state-active a.ui-tab{background-color:#f9f9f9;margin-top:-1px;padding:7px 10px 7px;border:1px solid #dfdfdf;border-bottom:1px solid transparent;color:#000}.tab-toolbar{background:#f9f9f9;border-width:1px 1px 0;border-radius:3px 3px 0 0;margin:-20px -21px 20px -21px;clear:left;padding:10px;border:1px solid #dfdfdf}.field-wrapper a.deletion,.tab-toolbar a.deletion{color:#f00;border-bottom:1px solid #f00;font-size:12px;text-decoration:none;padding:0;margin:-2px 0 0 5px}div.tab-toolbar a.button-primary{color:#fff!important}div.tab-wrapper{background-color:#fff;clear:left;padding:20px;border-left:1px solid #ccc;border-right:1px solid #ccc;border-radius:3px 3px 0 0}.tab-wrapper fieldset{position:relative;cursor:default!important;background:inherit}.tab-wrapper fieldset legend{padding-bottom:15px;font-weight:bold}.tab-wrapper .xprofile-field{position:relative}.tab-wrapper fieldset fieldset{position:relative;border:1px solid #ddd;border-radius:3px;margin:10px 0 0 0;cursor:move!important;background:#f9f9f9}.tab-wrapper fieldset fieldset legend{position:absolute!important;top:0;left:0;width:80%;padding:30px}.tab-wrapper fieldset fieldset legend span{position:absolute;top:6px;left:10px;font-weight:bold;width:100%}.field-group fieldset:hover{background-color:#fafafa;border-color:#ccc}fieldset div.field-wrapper{padding:40px 10px 10px}fieldset.radio div div label,fieldset.checkbox div label{margin-right:20px}fieldset.clear-value{margin-left:10px}.field-group div.actions{float:none;border-top:1px solid #ddd;margin:20px 0 0;padding-top:10px}.field-group div.actions a,.field-group div.actions button,.field-group div.actions input{float:none}.field-group fieldset:hover div.actions{display:block}.field-group fieldset.ui-sortable-placeholder{border:1px dashed #999;background-color:#eee;visibility:visible!important}ul.forTab{list-style:none;padding:0;margin:0 0 0 1em}ul.forTab li{margin:0 0 1em 0}ul.forTab li label{display:block}ul.forTab li input{font-size:1.4em}p.success{background:green}p.err{border-top:2px solid red;border-bottom:2px solid red;color:red;padding:5px 0;width:40%}span.desc,span.signup-description{display:block;font-size:11px;color:#555}select.multi-select{width:90%;height:10em!important}ul.multi-checkbox{margin:0 5px 0 0;padding:.5em .9em;height:10em;overflow:auto;list-style:none;border:solid 1px #ccc;width:90%}ul.multi-checkbox li{padding:0;margin:0}div.options-box{margin-left:20px!important;margin-right:10px!important;border-left:4px solid #eaf3fa;padding-left:15px}th a{background:#fff;padding:2px 5px;-moz-border-radius:3px;-khtml-border-radius:3px;-webkit-border-radius:3px;border-radius:3px;top:-2px}textarea#description,textarea#group_description{border:1px solid #ddd;width:100%}
Index: /tags/1.9/bp-xprofile/admin/js/admin.js
===================================================================
--- /tags/1.9/bp-xprofile/admin/js/admin.js	(revision 7684)
+++ /tags/1.9/bp-xprofile/admin/js/admin.js	(revision 7684)
@@ -0,0 +1,244 @@
+function add_option(forWhat) {
+	var holder    = document.getElementById(forWhat + "_more");
+	var theId     = document.getElementById(forWhat + '_option_number').value;
+	var newDiv    = document.createElement('p');
+	var newOption = document.createElement('input');
+	var span      = document.createElement( 'span' );
+	var txt       = document.createTextNode( "\u00A0\u039E\u00A0" );
+	var isDefault = document.createElement( 'input' );
+	var span1     = document.createElement( 'span' );
+	var txt1      = document.createTextNode( " Default Value " );
+
+	newDiv.setAttribute('id', forWhat + '_div' + theId);
+	newDiv.setAttribute('class', 'sortable');
+
+	newOption.setAttribute( 'type', 'text' );
+	newOption.setAttribute( 'name', forWhat + '_option[' + theId + ']' );
+	newOption.setAttribute( 'id', forWhat + '_option' + theId );
+
+	span.appendChild( txt );
+
+	if ( forWhat == 'checkbox' || forWhat == 'multiselectbox' ) {
+		isDefault.setAttribute( 'type', 'checkbox' );
+		isDefault.setAttribute( 'name', 'isDefault_' + forWhat + '_option[' + theId + ']' );
+	} else {
+		isDefault.setAttribute( 'type', 'radio' );
+		isDefault.setAttribute( 'name', 'isDefault_' + forWhat + '_option' );
+	}
+
+	isDefault.setAttribute( 'value', theId );
+
+	span1.appendChild( txt1 );
+
+	var toDelete     = document.createElement( 'a' );
+	var toDeleteText = document.createTextNode( '[x]' );
+
+	toDelete.setAttribute( 'href', "javascript:hide('" + forWhat + '_div' + theId + "')" );
+	toDelete.setAttribute( 'class', 'delete' );
+	toDelete.appendChild( toDeleteText );
+
+	newDiv.appendChild( span );
+	newDiv.appendChild( newOption );
+	newDiv.appendChild( document.createTextNode( " " ) );
+	newDiv.appendChild( isDefault );
+	newDiv.appendChild( span1 );
+	newDiv.appendChild( toDelete );
+	holder.appendChild( newDiv );
+
+	// re-initialize the sorable ui
+	enableSortableFieldOptions( forWhat );
+
+	// set focus on newly created element
+	document.getElementById(forWhat + "_option" + theId).focus();
+
+	theId++;
+
+	document.getElementById(forWhat + "_option_number").value = theId;
+}
+
+function show_options(forWhat) {
+	document.getElementById( 'radio'          ).style.display = 'none';
+	document.getElementById( 'selectbox'      ).style.display = 'none';
+	document.getElementById( 'multiselectbox' ).style.display = 'none';
+	document.getElementById( 'checkbox'       ).style.display = 'none';
+
+	if ( forWhat == 'radio' )
+		document.getElementById( 'radio' ).style.display = "";
+
+	if ( forWhat == 'selectbox' )
+		document.getElementById( 'selectbox' ).style.display = "";
+
+	if ( forWhat == 'multiselectbox' )
+		document.getElementById( 'multiselectbox' ).style.display = "";
+
+	if ( forWhat == 'checkbox' )
+		document.getElementById( 'checkbox' ).style.display = "";
+}
+
+function hide( id ) {
+	if ( !document.getElementById( id ) ) return false;
+
+	document.getElementById( id ).style.display = "none";
+	document.getElementById( id ).value = '';
+}
+
+var fixHelper = function(e, ui) {
+	ui.children().each(function() {
+		jQuery(this).width( jQuery(this).width() );
+	});
+	return ui;
+};
+
+function enableSortableFieldOptions( forWhat ) {
+	if ( jQuery( '#' + forWhat + ' p.sortable' ).length > 1 ) {
+		jQuery( '.bp-options-box' ).sortable( {
+			items: 'p.sortable',
+			tolerance: 'pointer',
+			axis: 'y',
+			handle: 'span'
+		});
+
+		jQuery( '.sortable span' ).css( 'cursor', 'move' );
+	}
+}
+
+function destroySortableFieldOptions() {
+	jQuery( '.bp-options-box' ).sortable( 'destroy' );
+	jQuery( '.sortable span' ).css( 'cursor', 'default' );
+}
+
+jQuery( document ).ready( function() {
+
+	// Set focus in Field Title, if we're on the right page
+	jQuery( '#bp-xprofile-add-field #title' ).focus();
+	
+	// Set up deleting options ajax
+	jQuery( 'a.ajax-option-delete' ).on( 'click', function() {
+		var theId = this.id.split( '-' );
+		theId = theId[1];
+
+		jQuery.post( ajaxurl, {
+			action: 'xprofile_delete_option',
+			'cookie': encodeURIComponent( document.cookie ),
+			'_wpnonce': jQuery('input#_wpnonce').val(),
+			'option_id': theId
+		},
+		function( response ) {} );
+	} );
+
+	//
+	jQuery( '[id^="sort_order_"]' ).change(function() {
+		if ( jQuery( this ).val() != 'custom' ) {
+			destroySortableFieldOptions();
+		} else {
+			enableSortableFieldOptions( jQuery('#fieldtype :selected').val() );
+		}
+	});
+
+	// Show object if JS is enabled
+	jQuery( 'ul#field-group-tabs' ).show();
+
+	// Allow reordering of field group tabs
+	jQuery( 'ul#field-group-tabs' ).sortable( {
+		cursor: 'move',
+		axis: 'x',
+		opacity: 0.6,
+		items: 'li',
+		tolerance: 'pointer',
+
+		update: function() {
+			jQuery.post( ajaxurl, {
+				action: 'xprofile_reorder_groups',
+				'cookie': encodeURIComponent( document.cookie ),
+				'_wpnonce_reorder_groups': jQuery( 'input#_wpnonce_reorder_groups' ).val(),
+				'group_order': jQuery( this ).sortable( 'serialize' )
+			},
+			function( response ) {} );
+		}
+	}).disableSelection();
+
+	// Allow reordering of fields within groups
+	jQuery( 'fieldset.field-group' ).sortable({
+		cursor: 'move',
+		opacity: 0.3,
+		items: 'fieldset',
+		tolerance: 'pointer',
+
+		update: function() {
+			jQuery.post( ajaxurl, {
+				action: 'xprofile_reorder_fields',
+				'cookie': encodeURIComponent(document.cookie),
+				'_wpnonce_reorder_fields': jQuery( 'input#_wpnonce_reorder_fields' ).val(),
+				'field_order': jQuery(this).sortable( 'serialize' ),
+				'field_group_id': jQuery(this).attr( 'id' )
+			},
+			function( response ) {} );
+		}
+	})
+
+	// Disallow text selection
+	.disableSelection()
+
+	// Change cursor to move if JS is enabled
+	.css( 'cursor', 'move' );
+
+	// Allow reordering of field options
+	enableSortableFieldOptions( jQuery('#fieldtype :selected').val() );
+
+	// tabs init with a custom tab template and an "add" callback filling in the content
+	var $tab_items;
+	var $tabs = jQuery( '#tabs' ).tabs();
+	set_tab_items( $tabs );
+
+	function set_tab_items( $tabs ) {
+		$tab_items = jQuery( 'ul:first li', $tabs ).droppable({
+			accept: '.connectedSortable fieldset',
+			hoverClass: 'ui-state-hover',
+			activeClass: 'ui-state-acceptable',
+			touch: 'pointer',
+			tolerance: 'pointer',
+
+			// When field is dropped on tab
+			drop: function( ev, ui ) {
+				// The tab
+				var $item = jQuery(this);
+
+				// The tab body
+				var $list = jQuery( $item.find( 'a' ).attr( 'href' ) ).find( '.connectedSortable' );
+
+				// Remove helper class
+				jQuery($item).removeClass( 'drop-candidate' );
+
+				// Hide field, change selected tab, and show new placement
+				ui.draggable.hide( 'slow', function() {
+
+					// Select new tab as current
+					$tabs.tabs( 'option', 'active', $tab_items.index( $item ) );
+
+					// Show new placement
+					jQuery(this).appendTo($list).show( 'slow' ).animate( {opacity: "1"}, 500 );
+
+					// Refresh $list variable
+					$list = jQuery( $item.find( 'a' ).attr( 'href' ) ).find( '.connectedSortable' );
+					jQuery($list).find( 'p.nofields' ).hide( 'slow' );
+
+					// Ajax update field locations and orders
+					jQuery.post( ajaxurl, {
+						action: 'xprofile_reorder_fields',
+						'cookie': encodeURIComponent(document.cookie),
+						'_wpnonce_reorder_fields': jQuery( "input#_wpnonce_reorder_fields" ).val(),
+						'field_order': jQuery( $list ).sortable( 'serialize' ),
+						'field_group_id': jQuery( $list ).attr( 'id' )
+					},
+					function( response ) {} );
+				});
+			},
+			over: function( event, ui ) {
+				jQuery(this).addClass( 'drop-candidate' );
+			},
+			out: function( event, ui ) {
+				jQuery(this).removeClass( 'drop-candidate' );
+			}
+		});
+	}
+});
Index: /tags/1.9/bp-xprofile/admin/js/admin.min.js
===================================================================
--- /tags/1.9/bp-xprofile/admin/js/admin.min.js	(revision 7684)
+++ /tags/1.9/bp-xprofile/admin/js/admin.min.js	(revision 7684)
@@ -0,0 +1,1 @@
+function add_option(g){var j=document.getElementById(g+"_more");var l=document.getElementById(g+"_option_number").value;var a=document.createElement("p");var h=document.createElement("input");var k=document.createElement("span");var e=document.createTextNode("\u00A0\u039E\u00A0");var b=document.createElement("input");var f=document.createElement("span");var d=document.createTextNode(" Default Value ");a.setAttribute("id",g+"_div"+l);a.setAttribute("class","sortable");h.setAttribute("type","text");h.setAttribute("name",g+"_option["+l+"]");h.setAttribute("id",g+"_option"+l);k.appendChild(e);if(g=="checkbox"||g=="multiselectbox"){b.setAttribute("type","checkbox");b.setAttribute("name","isDefault_"+g+"_option["+l+"]")}else{b.setAttribute("type","radio");b.setAttribute("name","isDefault_"+g+"_option")}b.setAttribute("value",l);f.appendChild(d);var c=document.createElement("a");var i=document.createTextNode("[x]");c.setAttribute("href","javascript:hide('"+g+"_div"+l+"')");c.setAttribute("class","delete");c.appendChild(i);a.appendChild(k);a.appendChild(h);a.appendChild(document.createTextNode(" "));a.appendChild(b);a.appendChild(f);a.appendChild(c);j.appendChild(a);enableSortableFieldOptions(g);document.getElementById(g+"_option"+l).focus();l++;document.getElementById(g+"_option_number").value=l}function show_options(a){document.getElementById("radio").style.display="none";document.getElementById("selectbox").style.display="none";document.getElementById("multiselectbox").style.display="none";document.getElementById("checkbox").style.display="none";if(a=="radio"){document.getElementById("radio").style.display=""}if(a=="selectbox"){document.getElementById("selectbox").style.display=""}if(a=="multiselectbox"){document.getElementById("multiselectbox").style.display=""}if(a=="checkbox"){document.getElementById("checkbox").style.display=""}}function hide(a){if(!document.getElementById(a)){return false}document.getElementById(a).style.display="none";document.getElementById(a).value=""}var fixHelper=function(b,a){a.children().each(function(){jQuery(this).width(jQuery(this).width())});return a};function enableSortableFieldOptions(a){if(jQuery("#"+a+" p.sortable").length>1){jQuery(".bp-options-box").sortable({items:"p.sortable",tolerance:"pointer",axis:"y",handle:"span"});jQuery(".sortable span").css("cursor","move")}}function destroySortableFieldOptions(){jQuery(".bp-options-box").sortable("destroy");jQuery(".sortable span").css("cursor","default")}jQuery(document).ready(function(){jQuery("#bp-xprofile-add-field #title").focus();jQuery("a.ajax-option-delete").on("click",function(){var d=this.id.split("-");d=d[1];jQuery.post(ajaxurl,{action:"xprofile_delete_option",cookie:encodeURIComponent(document.cookie),_wpnonce:jQuery("input#_wpnonce").val(),option_id:d},function(e){})});jQuery('[id^="sort_order_"]').change(function(){if(jQuery(this).val()!="custom"){destroySortableFieldOptions()}else{enableSortableFieldOptions(jQuery("#fieldtype :selected").val())}});jQuery("ul#field-group-tabs").show();jQuery("ul#field-group-tabs").sortable({cursor:"move",axis:"x",opacity:0.6,items:"li",tolerance:"pointer",update:function(){jQuery.post(ajaxurl,{action:"xprofile_reorder_groups",cookie:encodeURIComponent(document.cookie),_wpnonce_reorder_groups:jQuery("input#_wpnonce_reorder_groups").val(),group_order:jQuery(this).sortable("serialize")},function(d){})}}).disableSelection();jQuery("fieldset.field-group").sortable({cursor:"move",opacity:0.3,items:"fieldset",tolerance:"pointer",update:function(){jQuery.post(ajaxurl,{action:"xprofile_reorder_fields",cookie:encodeURIComponent(document.cookie),_wpnonce_reorder_fields:jQuery("input#_wpnonce_reorder_fields").val(),field_order:jQuery(this).sortable("serialize"),field_group_id:jQuery(this).attr("id")},function(d){})}}).disableSelection().css("cursor","move");enableSortableFieldOptions(jQuery("#fieldtype :selected").val());var b;var a=jQuery("#tabs").tabs();c(a);function c(d){b=jQuery("ul:first li",d).droppable({accept:".connectedSortable fieldset",hoverClass:"ui-state-hover",activeClass:"ui-state-acceptable",touch:"pointer",tolerance:"pointer",drop:function(g,h){var e=jQuery(this);var f=jQuery(e.find("a").attr("href")).find(".connectedSortable");jQuery(e).removeClass("drop-candidate");h.draggable.hide("slow",function(){d.tabs("option","active",b.index(e));jQuery(this).appendTo(f).show("slow").animate({opacity:"1"},500);f=jQuery(e.find("a").attr("href")).find(".connectedSortable");jQuery(f).find("p.nofields").hide("slow");jQuery.post(ajaxurl,{action:"xprofile_reorder_fields",cookie:encodeURIComponent(document.cookie),_wpnonce_reorder_fields:jQuery("input#_wpnonce_reorder_fields").val(),field_order:jQuery(f).sortable("serialize"),field_group_id:jQuery(f).attr("id")},function(i){})})},over:function(e,f){jQuery(this).addClass("drop-candidate")},out:function(e,f){jQuery(this).removeClass("drop-candidate")}})}});
Index: /tags/1.9/bp-xprofile/bp-xprofile-actions.php
===================================================================
--- /tags/1.9/bp-xprofile/bp-xprofile-actions.php	(revision 7684)
+++ /tags/1.9/bp-xprofile/bp-xprofile-actions.php	(revision 7684)
@@ -0,0 +1,45 @@
+<?php
+
+/**
+ * BuddyPress XProfile Actions
+ *
+ * Action functions are exactly the same as screen functions, however they do not
+ * have a template screen associated with them. Usually they will send the user
+ * back to the default screen after execution.
+ *
+ * @package BuddyPress
+ * @subpackage XProfileActions
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/**
+ * This function runs when an action is set for a screen:
+ * example.com/members/andy/profile/change-avatar/ [delete-avatar]
+ *
+ * The function will delete the active avatar for a user.
+ *
+ * @package BuddyPress Xprofile
+ * @uses bp_core_delete_avatar() Deletes the active avatar for the logged in user.
+ * @uses add_action() Runs a specific function for an action when it fires.
+ */
+function xprofile_action_delete_avatar() {
+
+	if ( !bp_is_user_change_avatar() || !bp_is_action_variable( 'delete-avatar', 0 ) )
+		return false;
+
+	// Check the nonce
+	check_admin_referer( 'bp_delete_avatar_link' );
+
+	if ( !bp_is_my_profile() && !bp_current_user_can( 'bp_moderate' ) )
+		return false;
+
+	if ( bp_core_delete_existing_avatar( array( 'item_id' => bp_displayed_user_id() ) ) )
+		bp_core_add_message( __( 'Your avatar was deleted successfully!', 'buddypress' ) );
+	else
+		bp_core_add_message( __( 'There was a problem deleting that avatar, please try again.', 'buddypress' ), 'error' );
+
+	bp_core_redirect( wp_get_referer() );
+}
+add_action( 'bp_actions', 'xprofile_action_delete_avatar' );
Index: /tags/1.9/bp-xprofile/bp-xprofile-activity.php
===================================================================
--- /tags/1.9/bp-xprofile/bp-xprofile-activity.php	(revision 7684)
+++ /tags/1.9/bp-xprofile/bp-xprofile-activity.php	(revision 7684)
@@ -0,0 +1,134 @@
+<?php
+
+/**
+ * BuddyPress XProfile Activity & Notification Functions
+ *
+ * These functions handle the recording, deleting and formatting of activity items and
+ * notifications for the user and for this specific component.
+ *
+ * @package BuddyPress
+ * @subpackage XProfileActivity
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+function xprofile_register_activity_actions() {
+	global $bp;
+
+	// Register the activity stream actions for this component
+	bp_activity_set_action( $bp->profile->id, 'new_avatar',      __( 'Member changed profile picture', 'buddypress' ) );
+	bp_activity_set_action( $bp->profile->id, 'new_member',      __( 'New member registered', 'buddypress' ) );
+	bp_activity_set_action( $bp->profile->id, 'updated_profile', __( 'Updated Profile', 'buddypress' ) );
+
+	do_action( 'xprofile_register_activity_actions' );
+}
+add_action( 'bp_register_activity_actions', 'xprofile_register_activity_actions' );
+
+/**
+ * Records activity for the logged in user within the profile component so that
+ * it will show in the users activity stream (if installed)
+ *
+ * @package BuddyPress
+ * @subpackage XProfileActivity
+ * @param string $args String containing all variables used after extract() call
+ * @global $bp The global BuddyPress settings variable created in bp_core_current_times()
+ * @uses bp_activity_add() Adds an entry to the activity component tables for a specific activity
+ */
+function xprofile_record_activity( $args = '' ) {
+
+	if ( !bp_is_active( 'activity' ) )
+		return false;
+
+	global $bp;
+
+	$defaults = array (
+		'user_id'           => bp_loggedin_user_id(),
+		'action'            => '',
+		'content'           => '',
+		'primary_link'      => '',
+		'component'         => $bp->profile->id,
+		'type'              => false,
+		'item_id'           => false,
+		'secondary_item_id' => false,
+		'recorded_time'     => bp_core_current_time(),
+		'hide_sitewide'     => false
+	);
+
+	$r = wp_parse_args( $args, $defaults );
+	extract( $r, EXTR_SKIP );
+
+	return bp_activity_add( array(
+		'user_id'           => $user_id,
+		'action'            => $action,
+		'content'           => $content,
+		'primary_link'      => $primary_link,
+		'component'         => $component,
+		'type'              => $type,
+		'item_id'           => $item_id,
+		'secondary_item_id' => $secondary_item_id,
+		'recorded_time'     => $recorded_time,
+		'hide_sitewide'     => $hide_sitewide
+	) );
+}
+
+/**
+ * Deletes activity for a user within the profile component so that
+ * it will be removed from the users activity stream and sitewide stream (if installed)
+ *
+ * @package BuddyPress XProfile
+ * @param string $args Containing all variables used after extract() call
+ * @global BuddyPress $bp The one true BuddyPress instance
+ * @uses bp_activity_delete() Deletes an entry to the activity component tables for a specific activity
+ */
+function xprofile_delete_activity( $args = '' ) {
+
+	if ( ! bp_is_active( 'activity' ) )
+		return false;
+
+	global $bp;
+
+	extract( $args );
+
+	bp_activity_delete_by_item_id( array(
+		'item_id'           => $item_id,
+		'component'         => $bp->profile->id,
+		'type'              => $type,
+		'user_id'           => $user_id,
+		'secondary_item_id' => $secondary_item_id
+	) );
+}
+
+function xprofile_register_activity_action( $key, $value ) {
+	global $bp;
+
+	if ( !bp_is_active( 'activity' ) )
+		return false;
+
+	return apply_filters( 'xprofile_register_activity_action', bp_activity_set_action( $bp->profile->id, $key, $value ), $key, $value );
+}
+
+/**
+ * Adds an activity stream item when a user has uploaded a new avatar.
+ *
+ * @package BuddyPress XProfile
+ * @global BuddyPress $bp The one true BuddyPress instance
+ * @uses bp_activity_add() Adds an entry to the activity component tables for a specific activity
+ */
+function bp_xprofile_new_avatar_activity() {
+
+	if ( !bp_is_active( 'activity' ) )
+		return false;
+
+	$user_id = apply_filters( 'bp_xprofile_new_avatar_user_id', bp_displayed_user_id() );
+
+	$userlink = bp_core_get_userlink( $user_id );
+
+	bp_activity_add( array(
+		'user_id' => $user_id,
+		'action' => apply_filters( 'bp_xprofile_new_avatar_action', sprintf( __( '%s changed their profile picture', 'buddypress' ), $userlink ), $user_id ),
+		'component' => 'profile',
+		'type' => 'new_avatar'
+	) );
+}
+add_action( 'xprofile_avatar_uploaded', 'bp_xprofile_new_avatar_activity' );
Index: /tags/1.9/bp-xprofile/bp-xprofile-admin.php
===================================================================
--- /tags/1.9/bp-xprofile/bp-xprofile-admin.php	(revision 7684)
+++ /tags/1.9/bp-xprofile/bp-xprofile-admin.php	(revision 7684)
@@ -0,0 +1,468 @@
+<?php
+
+/**
+ * BuddyPress XProfile Admin
+ *
+ * @package BuddyPress
+ * @subpackage XProfileAdmin
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/**
+ * Creates the administration interface menus and checks to see if the DB
+ * tables are set up.
+ *
+ * @package BuddyPress XProfile
+ * @uses bp_current_user_can() returns true if the current user is a site admin, false if not
+ * @uses add_users_page() Adds a submenu tab to a top level tab in the admin area
+ * @return
+ */
+function xprofile_add_admin_menu() {
+
+	if ( !bp_current_user_can( 'bp_moderate' ) )
+		return false;
+
+	add_users_page( __( 'Profile Fields', 'buddypress' ), __( 'Profile Fields', 'buddypress' ), 'manage_options', 'bp-profile-setup', 'xprofile_admin' );
+}
+add_action( bp_core_admin_hook(), 'xprofile_add_admin_menu' );
+
+/**
+ * Handles all actions for the admin area for creating, editing and deleting
+ * profile groups and fields.
+ */
+function xprofile_admin( $message = '', $type = 'error' ) {
+
+	$type = preg_replace( '|[^a-z]|i', '', $type );
+
+	$groups = BP_XProfile_Group::get( array(
+		'fetch_fields' => true
+	) );
+
+	if ( isset( $_GET['mode'] ) && isset( $_GET['group_id'] ) && 'add_field' == $_GET['mode'] )
+		xprofile_admin_manage_field( $_GET['group_id'] );
+
+	else if ( isset( $_GET['mode'] ) && isset( $_GET['group_id'] ) && isset( $_GET['field_id'] ) && 'edit_field' == $_GET['mode'] )
+		xprofile_admin_manage_field( $_GET['group_id'], $_GET['field_id'] );
+
+	else if ( isset( $_GET['mode'] ) && isset( $_GET['field_id'] ) && 'delete_field' == $_GET['mode'] )
+		xprofile_admin_delete_field( $_GET['field_id'], 'field');
+
+	else if ( isset( $_GET['mode'] ) && isset( $_GET['option_id'] ) && 'delete_option' == $_GET['mode'] )
+		xprofile_admin_delete_field( $_GET['option_id'], 'option' );
+
+	else if ( isset( $_GET['mode'] ) && 'add_group' == $_GET['mode'] )
+		xprofile_admin_manage_group();
+
+	else if ( isset( $_GET['mode'] ) && isset( $_GET['group_id'] ) && 'delete_group' == $_GET['mode'] )
+		xprofile_admin_delete_group( $_GET['group_id'] );
+
+	else if ( isset( $_GET['mode'] ) && isset( $_GET['group_id'] ) && 'edit_group' == $_GET['mode'] )
+		xprofile_admin_manage_group( $_GET['group_id'] );
+
+	else { ?>
+
+	<div class="wrap">
+
+		<?php screen_icon( 'users' ); ?>
+
+		<h2>
+			<?php _e( 'Profile Fields', 'buddypress'); ?>
+			<a id="add_group" class="add-new-h2" href="users.php?page=bp-profile-setup&amp;mode=add_group"><?php _e( 'Add New Field Group', 'buddypress' ); ?></a>
+		</h2>
+
+		<p><?php echo sprintf( __( 'Fields in the "%s" group will appear on the signup page.', 'buddypress' ), esc_html( stripslashes( bp_get_option( 'bp-xprofile-base-group-name' ) ) ) ) ?></p>
+
+		<form action="" id="profile-field-form" method="post">
+
+			<?php
+
+			wp_nonce_field( 'bp_reorder_fields', '_wpnonce_reorder_fields'        );
+			wp_nonce_field( 'bp_reorder_groups', '_wpnonce_reorder_groups', false );
+
+			if ( !empty( $message ) ) :
+				$type = ( $type == 'error' ) ? 'error' : 'updated'; ?>
+
+				<div id="message" class="<?php echo $type; ?> fade">
+					<p><?php echo esc_html( esc_attr( $message ) ); ?></p>
+				</div>
+
+			<?php endif; ?>
+
+			<div id="tabs">
+				<ul id="field-group-tabs">
+
+					<?php if ( !empty( $groups ) ) : foreach ( $groups as $group ) : ?>
+
+						<li id="group_<?php echo $group->id; ?>"><a href="#tabs-<?php echo $group->id; ?>" class="ui-tab"><?php echo esc_attr( $group->name ); ?><?php if ( !$group->can_delete ) : ?> <?php _e( '(Primary)', 'buddypress'); endif; ?></a></li>
+
+					<?php endforeach; endif; ?>
+
+				</ul>
+
+				<?php if ( !empty( $groups ) ) : foreach ( $groups as $group ) : ?>
+
+					<noscript>
+						<h3><?php echo esc_attr( $group->name ); ?></h3>
+					</noscript>
+
+					<div id="tabs-<?php echo $group->id; ?>" class="tab-wrapper">
+						<div class="tab-toolbar">
+							<div class="tab-toolbar-left">
+								<a class="button-primary" href="users.php?page=bp-profile-setup&amp;group_id=<?php echo esc_attr( $group->id ); ?>&amp;mode=add_field"><?php _e( 'Add New Field', 'buddypress' ); ?></a>
+								<a class="button edit" href="users.php?page=bp-profile-setup&amp;mode=edit_group&amp;group_id=<?php echo esc_attr( $group->id ); ?>"><?php _e( 'Edit Group', 'buddypress' ); ?></a>
+
+								<?php if ( $group->can_delete ) : ?>
+
+									<a class="confirm submitdelete deletion ajax-option-delete" href="users.php?page=bp-profile-setup&amp;mode=delete_group&amp;group_id=<?php echo esc_attr( $group->id ); ?>"><?php _e( 'Delete Group', 'buddypress' ); ?></a>
+
+								<?php endif; ?>
+
+							</div>
+						</div>
+
+						<fieldset id="<?php echo $group->id; ?>" class="connectedSortable field-group">
+
+							<?php if ( $group->description ) : ?>
+
+								<legend><?php echo esc_attr( $group->description ) ?></legend>
+
+							<?php endif;
+
+							if ( !empty( $group->fields ) ) :
+								foreach ( $group->fields as $field ) {
+
+									// Load the field
+									$field = new BP_XProfile_Field( $field->id );
+
+									$class = '';
+									if ( !$field->can_delete )
+										$class = ' core nodrag';
+
+									/* This function handles the WYSIWYG profile field
+									* display for the xprofile admin setup screen
+									*/
+									xprofile_admin_field( $field, $group, $class );
+
+								} // end for
+
+							else : // !$group->fields ?>
+
+								<p class="nodrag nofields"><?php _e( 'There are no fields in this group.', 'buddypress' ); ?></p>
+
+							<?php endif; // end $group->fields ?>
+
+						</fieldset>
+					</div>
+
+				<?php endforeach; else : ?>
+
+					<div id="message" class="error"><p><?php _e( 'You have no groups.', 'buddypress' ); ?></p></div>
+					<p><a href="users.php?page=bp-profile-setup&amp;mode=add_group"><?php _e( 'Add New Group', 'buddypress' ); ?></a></p>
+
+				<?php endif; ?>
+
+				<div id="tabs-bottom">&nbsp;</div>
+			</div>
+		</form>
+	</div>
+
+<?php
+	}
+}
+
+/**
+ * Handles the adding or editing of groups.
+ */
+function xprofile_admin_manage_group( $group_id = null ) {
+	global $message, $type;
+
+	$group = new BP_XProfile_Group( $group_id );
+
+	if ( isset( $_POST['save_group'] ) ) {
+		if ( BP_XProfile_Group::admin_validate( $_POST ) ) {
+			$group->name		= wp_filter_kses( $_POST['group_name'] );
+			$group->description	= !empty( $_POST['group_description'] ) ? wp_filter_kses( $_POST['group_description'] ) : '';
+
+			if ( !$group->save() ) {
+				$message = __( 'There was an error saving the group. Please try again', 'buddypress' );
+				$type    = 'error';
+			} else {
+				$message = __( 'The group was saved successfully.', 'buddypress' );
+				$type    = 'success';
+
+				if ( 1 == $group_id )
+					bp_update_option( 'bp-xprofile-base-group-name', $group->name );
+
+				do_action( 'xprofile_groups_saved_group', $group );
+			}
+
+			unset( $_GET['mode'] );
+			xprofile_admin( $message, $type );
+
+		} else {
+			$group->render_admin_form( $message );
+		}
+	} else {
+		$group->render_admin_form();
+	}
+}
+
+/**
+ * Handles the deletion of profile data groups.
+ */
+function xprofile_admin_delete_group( $group_id ) {
+	global $message, $type;
+
+	$group = new BP_XProfile_Group( $group_id );
+
+	if ( !$group->delete() ) {
+		$message = __( 'There was an error deleting the group. Please try again', 'buddypress' );
+		$type    = 'error';
+	} else {
+		$message = __( 'The group was deleted successfully.', 'buddypress' );
+		$type    = 'success';
+
+		do_action( 'xprofile_groups_deleted_group', $group );
+	}
+
+	unset( $_GET['mode'] );
+	xprofile_admin( $message, $type );
+}
+
+/**
+ * Handles the adding or editing of profile field data for a user.
+ */
+function xprofile_admin_manage_field( $group_id, $field_id = null ) {
+	global $bp, $wpdb, $message, $groups;
+
+	$field           = new BP_XProfile_Field( $field_id );
+	$field->group_id = $group_id;
+
+	if ( isset( $_POST['saveField'] ) ) {
+		if ( BP_XProfile_Field::admin_validate() ) {
+			$field->name        = wp_filter_kses( $_POST['title'] );
+			$field->description = !empty( $_POST['description'] ) ? wp_filter_kses( $_POST['description'] ) : '';
+			$field->is_required = wp_filter_kses( $_POST['required'] );
+			$field->type        = wp_filter_kses( $_POST['fieldtype'] );
+
+			if ( !empty( $_POST["sort_order_{$field->type}"] ) )
+				$field->order_by = wp_filter_kses( $_POST["sort_order_{$field->type}"] );
+
+			$field->field_order = $wpdb->get_var( $wpdb->prepare( "SELECT field_order FROM {$bp->profile->table_name_fields} WHERE id = %d", $field_id ) );
+
+			if ( !$field->field_order ) {
+				$field->field_order = (int) $wpdb->get_var( $wpdb->prepare( "SELECT max(field_order) FROM {$bp->profile->table_name_fields} WHERE group_id = %d", $group_id ) );
+				$field->field_order++;
+			}
+
+			// For new profile fields, set the $field_id. For existing profile fields,
+			// this will overwrite $field_id with the same value.
+			$field_id = $field->save();
+
+			if ( !$field_id ) {
+				$message = __( 'There was an error saving the field. Please try again', 'buddypress' );
+				$type = 'error';
+
+				unset( $_GET['mode'] );
+
+				xprofile_admin( $message, $type );
+			} else {
+				$message = __( 'The field was saved successfully.', 'buddypress' );
+				$type = 'success';
+
+				if ( 1 == $field_id )
+					bp_update_option( 'bp-xprofile-fullname-field-name', $field->name );
+
+				if ( !empty( $_POST['default-visibility'] ) ) {
+					bp_xprofile_update_field_meta( $field_id, 'default_visibility', $_POST['default-visibility'] );
+				}
+
+				if ( !empty( $_POST['allow-custom-visibility'] ) ) {
+					bp_xprofile_update_field_meta( $field_id, 'allow_custom_visibility', $_POST['allow-custom-visibility'] );
+				}
+
+				unset( $_GET['mode'] );
+
+				do_action( 'xprofile_fields_saved_field', $field );
+
+				$groups = BP_XProfile_Group::get();
+				xprofile_admin( $message, $type );
+			}
+		} else {
+			$field->render_admin_form( $message );
+		}
+	} else {
+		$field->render_admin_form();
+	}
+}
+
+/**
+ * Handles the deletion of a profile field (or field option)
+ *
+ * @since BuddyPress (1.0)
+ * @global string $message The feedback message to show
+ * @global $type The type of feedback message to show
+ * @param int $field_id The field to delete
+ * @param string $field_type The type of field being deleted
+ * @param bool $delete_data Should the field data be deleted too?
+ */
+function xprofile_admin_delete_field( $field_id, $field_type = 'field', $delete_data = false ) {
+	global $message, $type;
+
+	// Switch type to 'option' if type is not 'field'
+	// @todo trust this param
+	$field_type  = ( 'field' == $field_type ) ? __( 'field', 'buddypress' ) : __( 'option', 'buddypress' );
+	$field       = new BP_XProfile_Field( $field_id );
+
+	if ( !$field->delete( (bool) $delete_data ) ) {
+		$message = sprintf( __( 'There was an error deleting the %s. Please try again', 'buddypress' ), $field_type );
+		$type    = 'error';
+	} else {
+		$message = sprintf( __( 'The %s was deleted successfully!', 'buddypress' ), $field_type );
+		$type    = 'success';
+
+		do_action( 'xprofile_fields_deleted_field', $field );
+	}
+
+	unset( $_GET['mode'] );
+	xprofile_admin( $message, $type );
+}
+
+/**
+ * Handles the ajax reordering of fields within a group
+ */
+function xprofile_ajax_reorder_fields() {
+
+	// Check the nonce
+	check_admin_referer( 'bp_reorder_fields', '_wpnonce_reorder_fields' );
+
+	if ( empty( $_POST['field_order'] ) )
+		return false;
+
+	parse_str( $_POST['field_order'], $order );
+
+	$field_group_id = $_POST['field_group_id'];
+
+	foreach ( (array) $order['field'] as $position => $field_id ) {
+		xprofile_update_field_position( (int) $field_id, (int) $position, (int) $field_group_id );
+	}
+}
+add_action( 'wp_ajax_xprofile_reorder_fields', 'xprofile_ajax_reorder_fields' );
+
+/**
+ * Handles the reordering of field groups
+ */
+function xprofile_ajax_reorder_field_groups() {
+
+	// Check the nonce
+	check_admin_referer( 'bp_reorder_groups', '_wpnonce_reorder_groups' );
+
+	if ( empty( $_POST['group_order'] ) )
+		return false;
+
+	parse_str( $_POST['group_order'], $order );
+
+	foreach ( (array) $order['group'] as $position => $field_group_id ) {
+		xprofile_update_field_group_position( (int) $field_group_id, (int) $position );
+	}
+}
+add_action( 'wp_ajax_xprofile_reorder_groups', 'xprofile_ajax_reorder_field_groups' );
+
+/**
+ * Handles the WYSIWYG display of each profile field on the edit screen
+ */
+function xprofile_admin_field( $admin_field, $admin_group, $class = '' ) {
+	global $field;
+
+	$field = $admin_field; ?>
+
+	<fieldset id="field_<?php echo esc_attr( $field->id ); ?>" class="sortable<?php echo ' ' . $field->type; if ( !empty( $class ) ) echo ' ' . $class; ?>">
+		<legend><span><?php bp_the_profile_field_name(); ?> <?php if( !$field->can_delete ) : ?> <?php _e( '(Primary)', 'buddypress' ); endif; ?> <?php if ( bp_get_the_profile_field_is_required() ) : ?><?php _e( '(Required)', 'buddypress' ) ?><?php endif; ?></span></legend>
+		<div class="field-wrapper">
+
+			<?php switch ( $field->type ) : case 'textbox' : ?>
+
+				<input type="text" name="<?php bp_the_profile_field_input_name() ?>" id="<?php bp_the_profile_field_input_name() ?>" value="" />
+
+			<?php break; case 'textarea' : ?>
+
+				<textarea rows="5" cols="40" name="<?php bp_the_profile_field_input_name() ?>" id="<?php bp_the_profile_field_input_name() ?>"></textarea>
+
+			<?php break; case 'selectbox' : ?>
+
+				<select name="<?php bp_the_profile_field_input_name() ?>" id="<?php bp_the_profile_field_input_name() ?>">
+
+					<?php bp_the_profile_field_options() ?>
+
+				</select>
+
+			<?php break; case 'multiselectbox' : ?>
+
+				<select name="<?php bp_the_profile_field_input_name() ?>" id="<?php bp_the_profile_field_input_name() ?>" multiple="multiple">
+
+					<?php bp_the_profile_field_options() ?>
+
+				</select>
+
+			<?php break; case 'radio' : ?>
+
+				<?php bp_the_profile_field_options() ?>
+
+				<?php if ( !bp_get_the_profile_field_is_required() ) : ?>
+
+					<a class="clear-value" href="javascript:clear( '<?php bp_the_profile_field_input_name() ?>' );"><?php _e( 'Clear', 'buddypress' ) ?></a>
+
+				<?php endif; ?>
+
+			<?php break; case 'checkbox' : ?>
+
+				<?php bp_the_profile_field_options(); ?>
+
+			<?php break; case 'datebox' : ?>
+
+				<select name="<?php bp_the_profile_field_input_name(); ?>_day" id="<?php bp_the_profile_field_input_name(); ?>_day">
+
+					<?php bp_the_profile_field_options( 'type=day' ); ?>
+
+				</select>
+
+				<select name="<?php bp_the_profile_field_input_name(); ?>_month" id="<?php bp_the_profile_field_input_name(); ?>_month">
+
+					<?php bp_the_profile_field_options( 'type=month' ); ?>
+
+				</select>
+
+				<select name="<?php bp_the_profile_field_input_name(); ?>_year" id="<?php bp_the_profile_field_input_name(); ?>_year">
+
+					<?php bp_the_profile_field_options( 'type=year' ); ?>
+
+				</select>
+
+			<?php break; default : ?>
+
+			<?php do_action( 'xprofile_admin_field', $field, 1 ); ?>
+
+			<?php endswitch; ?>
+
+			<?php if ( $field->description ) : ?>
+
+				<p class="description"><?php echo esc_attr( $field->description ); ?></p>
+
+			<?php endif; ?>
+
+			<div class="actions">
+				<a class="button edit" href="users.php?page=bp-profile-setup&amp;group_id=<?php echo esc_attr( $admin_group->id ); ?>&amp;field_id=<?php echo esc_attr( $field->id ); ?>&amp;mode=edit_field"><?php _e( 'Edit', 'buddypress' ); ?></a>
+
+				<?php if ( $field->can_delete ) : ?>
+
+					<a class="confirm submit-delete deletion" href="users.php?page=bp-profile-setup&amp;field_id=<?php echo esc_attr( $field->id ); ?>&amp;mode=delete_field"><?php _e( 'Delete', 'buddypress' ); ?></a>
+
+				<?php endif; ?>
+			</div>
+		</div>
+	</fieldset>
+
+<?php
+}
Index: /tags/1.9/bp-xprofile/bp-xprofile-buddybar.php
===================================================================
--- /tags/1.9/bp-xprofile/bp-xprofile-buddybar.php	(revision 7684)
+++ /tags/1.9/bp-xprofile/bp-xprofile-buddybar.php	(revision 7684)
@@ -0,0 +1,4 @@
+<?php
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
Index: /tags/1.9/bp-xprofile/bp-xprofile-cache.php
===================================================================
--- /tags/1.9/bp-xprofile/bp-xprofile-cache.php	(revision 7684)
+++ /tags/1.9/bp-xprofile/bp-xprofile-cache.php	(revision 7684)
@@ -0,0 +1,31 @@
+<?php
+
+/**
+ * BuddyPress XProfile Template Tags
+ *
+ * Caching functions handle the clearing of cached objects and pages on specific
+ * actions throughout BuddyPress.
+ *
+ * @package BuddyPress
+ * @subpackage XProfileTemplate
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+function xprofile_clear_profile_groups_object_cache( $group_obj ) {
+	wp_cache_delete( 'xprofile_groups_inc_empty',        'bp' );
+	wp_cache_delete( 'xprofile_group_' . $group_obj->id, 'bp' );
+}
+
+function xprofile_clear_profile_data_object_cache( $group_id ) {
+	wp_cache_delete( 'bp_user_fullname_' . bp_loggedin_user_id(), 'bp' );
+}
+
+// List actions to clear object caches on
+add_action( 'xprofile_groups_deleted_group', 'xprofile_clear_profile_groups_object_cache' );
+add_action( 'xprofile_groups_saved_group',   'xprofile_clear_profile_groups_object_cache' );
+add_action( 'xprofile_updated_profile',      'xprofile_clear_profile_data_object_cache'   );
+
+// List actions to clear super cached pages on, if super cache is installed
+add_action( 'xprofile_updated_profile', 'bp_core_clear_cache' );
Index: /tags/1.9/bp-xprofile/bp-xprofile-caps.php
===================================================================
--- /tags/1.9/bp-xprofile/bp-xprofile-caps.php	(revision 7684)
+++ /tags/1.9/bp-xprofile/bp-xprofile-caps.php	(revision 7684)
@@ -0,0 +1,60 @@
+<?php
+
+/**
+ * Roles and capabilities logic for the XProfile component
+ *
+ * @package BuddyPress
+ * @since BuddyPress (1.6)
+ */
+
+// Exit if accessed directly
+if ( ! defined( 'ABSPATH' ) ) exit;
+
+/**
+ * Maps XProfile caps to built in WordPress caps
+ *
+ * @since BuddyPress (1.6)
+ *
+ * @param array $caps Capabilities for meta capability
+ * @param string $cap Capability name
+ * @param int $user_id User id
+ * @param mixed $args Arguments
+ * @uses get_post() To get the post
+ * @uses get_post_type_object() To get the post type object
+ * @uses apply_filters() Calls 'bp_map_meta_caps' with caps, cap, user id and
+ *                        args
+ * @return array Actual capabilities for meta capability
+ */
+function bp_xprofile_map_meta_caps( $caps, $cap, $user_id, $args ) {
+	switch ( $cap ) {
+		case 'bp_xprofile_change_field_visibility' :
+			$caps = array( 'exist' ); // Must allow for logged-out users during registration
+
+			// You may pass args manually: $field_id, $profile_user_id
+			$field_id        = isset( $args[0] ) ? (int)$args[0] : bp_get_the_profile_field_id();
+			$profile_user_id = isset( $args[1] ) ? (int)$args[1] : bp_displayed_user_id();
+
+			// Visibility on the fullname field is not editable
+			if ( 1 == $field_id ) {
+				$caps[] = 'do_not_allow';
+				break;
+			}
+
+			// Has the admin disabled visibility modification for this field?
+			if ( 'disabled' == bp_xprofile_get_meta( $field_id, 'field', 'allow_custom_visibility' ) ) {
+				$caps[] = 'do_not_allow';
+				break;
+			}
+
+			// Friends don't let friends edit each other's visibility
+			if ( $profile_user_id != bp_displayed_user_id() && !bp_current_user_can( 'bp_moderate' ) ) {
+				$caps[] = 'do_not_allow';
+				break;
+			}
+
+			break;
+	}
+
+	return apply_filters( 'bp_xprofile_map_meta_caps', $caps, $cap, $user_id, $args );
+}
+add_filter( 'bp_map_meta_caps', 'bp_xprofile_map_meta_caps', 10, 4 );
Index: /tags/1.9/bp-xprofile/bp-xprofile-classes.php
===================================================================
--- /tags/1.9/bp-xprofile/bp-xprofile-classes.php	(revision 7684)
+++ /tags/1.9/bp-xprofile/bp-xprofile-classes.php	(revision 7684)
@@ -0,0 +1,1283 @@
+<?php
+
+/**
+ * BuddyPress XProfile Classes
+ *
+ * @package BuddyPress
+ * @subpackage XProfileClasses
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+class BP_XProfile_Group {
+	public $id = null;
+	public $name;
+	public $description;
+	public $can_delete;
+	public $group_order;
+	public $fields;
+
+	public function __construct( $id = null ) {
+		if ( !empty( $id ) )
+			$this->populate( $id );
+	}
+
+	public function populate( $id ) {
+		global $wpdb, $bp;
+
+		$sql = $wpdb->prepare( "SELECT * FROM {$bp->profile->table_name_groups} WHERE id = %d", $id );
+
+		if ( !$group = $wpdb->get_row( $sql ) )
+			return false;
+
+		$this->id          = $group->id;
+		$this->name        = stripslashes( $group->name );
+		$this->description = stripslashes( $group->description );
+		$this->can_delete  = $group->can_delete;
+		$this->group_order = $group->group_order;
+	}
+
+	public function save() {
+		global $wpdb, $bp;
+
+		$this->name        = apply_filters( 'xprofile_group_name_before_save',        $this->name,        $this->id );
+		$this->description = apply_filters( 'xprofile_group_description_before_save', $this->description, $this->id );
+
+		do_action_ref_array( 'xprofile_group_before_save', array( &$this ) );
+
+		if ( $this->id )
+			$sql = $wpdb->prepare( "UPDATE {$bp->profile->table_name_groups} SET name = %s, description = %s WHERE id = %d", $this->name, $this->description, $this->id );
+		else
+			$sql = $wpdb->prepare( "INSERT INTO {$bp->profile->table_name_groups} (name, description, can_delete) VALUES (%s, %s, 1)", $this->name, $this->description );
+
+		if ( is_wp_error( $wpdb->query( $sql ) ) )
+			return false;
+
+		// If not set, update the ID in the group object
+		if ( ! $this->id )
+			$this->id = $wpdb->insert_id;
+
+		do_action_ref_array( 'xprofile_group_after_save', array( &$this ) );
+
+		return $this->id;
+	}
+
+	public function delete() {
+		global $wpdb, $bp;
+
+		if ( empty( $this->can_delete ) )
+			return false;
+
+		// Delete field group
+		if ( !$wpdb->query( $wpdb->prepare( "DELETE FROM {$bp->profile->table_name_groups} WHERE id = %d", $this->id ) ) ) {
+			return false;
+		} else {
+
+			// Remove the group's fields.
+			if ( BP_XProfile_Field::delete_for_group( $this->id ) ) {
+
+				// Remove profile data for the groups fields
+				for ( $i = 0, $count = count( $this->fields ); $i < $count; ++$i ) {
+					BP_XProfile_ProfileData::delete_for_field( $this->fields[$i]->id );
+				}
+			}
+
+			return true;
+		}
+	}
+
+	/** Static Methods ********************************************************/
+
+	/**
+	 * get()
+	 *
+	 * Populates the BP_XProfile_Group object with profile field groups, fields, and field data
+	 *
+	 * @package BuddyPress XProfile
+	 *
+	 * @global $wpdb WordPress DB access object.
+	 * @global BuddyPress $bp The one true BuddyPress instance
+	 *
+	 * @param array $args Takes an array of parameters:
+	 *		'profile_group_id' - Limit results to a single profile group
+	 *		'user_id' - Required if you want to load a specific user's data
+	 *		'hide_empty_groups' - Hide groups without any fields
+	 *		'hide_empty_fields' - Hide fields where the user has not provided data
+	 *		'fetch_fields' - Load each group's fields
+	 *		'fetch_field_data' - Load each field's data. Requires a user_id
+	 *		'exclude_groups' - Comma-separated list of groups to exclude
+	 *		'exclude_fields' - Comma-separated list of fields to exclude
+	 *
+	 * @return array $groups
+	 */
+	public static function get( $args = array() ) {
+		global $wpdb, $bp;
+
+		$defaults = array(
+			'profile_group_id'       => false,
+			'user_id'                => bp_displayed_user_id(),
+			'hide_empty_groups'      => false,
+			'hide_empty_fields'      => false,
+			'fetch_fields'           => false,
+			'fetch_field_data'       => false,
+			'fetch_visibility_level' => false,
+			'exclude_groups'         => false,
+			'exclude_fields'         => false
+		);
+
+		$r = wp_parse_args( $args, $defaults );
+		extract( $r, EXTR_SKIP );
+		$where_sql = '';
+
+		if ( !empty( $profile_group_id ) )
+			$where_sql = $wpdb->prepare( 'WHERE g.id = %d', $profile_group_id );
+		elseif ( $exclude_groups )
+			$where_sql = $wpdb->prepare( "WHERE g.id NOT IN ({$exclude_groups})");
+
+		if ( !empty( $hide_empty_groups ) )
+			$groups = $wpdb->get_results( "SELECT DISTINCT g.* FROM {$bp->profile->table_name_groups} g INNER JOIN {$bp->profile->table_name_fields} f ON g.id = f.group_id {$where_sql} ORDER BY g.group_order ASC" );
+		else
+			$groups = $wpdb->get_results( "SELECT DISTINCT g.* FROM {$bp->profile->table_name_groups} g {$where_sql} ORDER BY g.group_order ASC" );
+
+		if ( empty( $fetch_fields ) )
+			return $groups;
+
+		// Get the group ids
+		$group_ids = array();
+		foreach( (array) $groups as $group ) {
+			$group_ids[] = $group->id;
+		}
+
+		$group_ids = implode( ',', (array) $group_ids );
+
+		if ( empty( $group_ids ) )
+			return $groups;
+
+		// Support arrays and comma-separated strings
+		$exclude_fields_cs = wp_parse_id_list( $exclude_fields );
+
+		// Visibility - Handled here so as not to be overridden by sloppy use of the
+		// exclude_fields parameter. See bp_xprofile_get_hidden_fields_for_user()
+		$exclude_fields_cs = array_merge( $exclude_fields_cs, bp_xprofile_get_hidden_fields_for_user( $user_id ) );
+		$exclude_fields_cs = implode( ',', $exclude_fields_cs );
+
+		if ( !empty( $exclude_fields_cs ) ) {
+			$exclude_fields_sql = "AND id NOT IN ({$exclude_fields_cs})";
+		} else {
+			$exclude_fields_sql = '';
+		}
+
+		// Fetch the fields
+		$fields = $wpdb->get_results( "SELECT id, name, description, type, group_id, is_required FROM {$bp->profile->table_name_fields} WHERE group_id IN ( {$group_ids} ) AND parent_id = 0 {$exclude_fields_sql} ORDER BY field_order" );
+
+		if ( empty( $fields ) )
+			return $groups;
+
+		// Maybe fetch field data
+		if ( ! empty( $fetch_field_data ) ) {
+
+			// Fetch the field data for the user.
+			foreach( (array) $fields as $field ) {
+				$field_ids[] = $field->id;
+			}
+
+			$field_ids_sql = implode( ',', (array) $field_ids );
+
+			if ( ! empty( $field_ids ) && ! empty( $user_id ) ) {
+				$field_data = $wpdb->get_results( $wpdb->prepare( "SELECT id, field_id, value FROM {$bp->profile->table_name_data} WHERE field_id IN ( {$field_ids_sql} ) AND user_id = %d", $user_id ) );
+			}
+
+			// Remove data-less fields, if necessary
+			if ( !empty( $hide_empty_fields ) && ! empty( $field_ids ) && ! empty( $field_data ) ) {
+
+				// Loop through the results and find the fields that have data.
+				foreach( (array) $field_data as $data ) {
+
+					// Empty fields may contain a serialized empty array
+					$maybe_value = maybe_unserialize( $data->value );
+					if ( !empty( $maybe_value ) && false !== $key = array_search( $data->field_id, $field_ids ) ) {
+						// Fields that have data get removed from the list
+						unset( $field_ids[$key] );
+					}
+				}
+
+				// The remaining members of $field_ids are empty. Remove them.
+				foreach( $fields as $field_key => $field ) {
+					if ( in_array( $field->id, $field_ids ) ) {
+						unset( $fields[$field_key] );
+					}
+				}
+
+				// Reset indexes
+				$fields = array_values( $fields );
+			}
+
+			// Field data was found
+			if ( ! empty( $fields ) && !empty( $field_data ) && !is_wp_error( $field_data ) ) {
+
+				// Loop through fields
+				foreach( (array) $fields as $field_key => $field ) {
+
+					// Loop throught the data in each field
+					foreach( (array) $field_data as $data ) {
+
+						// Assign correct data value to the field
+						if ( $field->id == $data->field_id ) {
+							$fields[$field_key]->data        = new stdClass;
+							$fields[$field_key]->data->value = $data->value;
+							$fields[$field_key]->data->id    = $data->id;
+						}
+					}
+				}
+			}
+		}
+
+		// Maybe fetch visibility levels
+		if ( !empty( $fetch_visibility_level ) ) {
+			$fields = self::fetch_visibility_level( $user_id, $fields );
+		}
+
+		// Merge the field array back in with the group array
+		foreach( (array) $groups as $group ) {
+
+			// Indexes may have been shifted after previous deletions, so we get a
+			// fresh one each time through the loop
+			$index = array_search( $group, $groups );
+
+			foreach( (array) $fields as $field ) {
+				if ( $group->id == $field->group_id ) {
+					$groups[$index]->fields[] = $field;
+				}
+			}
+
+			// When we unset fields above, we may have created empty groups.
+			// Remove them, if necessary.
+			if ( empty( $group->fields ) && $hide_empty_groups ) {
+				unset( $groups[$index] );
+			}
+
+			// Reset indexes
+			$groups = array_values( $groups );
+		}
+
+		return $groups;
+	}
+
+	public static function admin_validate() {
+		global $message;
+
+		/* Validate Form */
+		if ( empty( $_POST['group_name'] ) ) {
+			$message = __( 'Please make sure you give the group a name.', 'buddypress' );
+			return false;
+		} else {
+			return true;
+		}
+	}
+
+	public static function update_position( $field_group_id, $position ) {
+		global $wpdb, $bp;
+
+		if ( !is_numeric( $position ) )
+			return false;
+
+		return $wpdb->query( $wpdb->prepare( "UPDATE {$bp->profile->table_name_groups} SET group_order = %d WHERE id = %d", $position, $field_group_id ) );
+	}
+
+	/**
+	 * Fetch the field visibility level for the fields returned by the query
+	 *
+	 * @since BuddyPress (1.6)
+	 *
+	 * @param int $user_id The profile owner's user_id
+	 * @param array $fields The database results returned by the get() query
+	 * @return array $fields The database results, with field_visibility added
+	 */
+	public static function fetch_visibility_level( $user_id = 0, $fields = array() ) {
+
+		// Get the user's visibility level preferences
+		$visibility_levels = bp_get_user_meta( $user_id, 'bp_xprofile_visibility_levels', true );
+
+		// Get the admin-set preferences
+		$admin_set_levels  = self::fetch_default_visibility_levels();
+
+		foreach( (array) $fields as $key => $field ) {
+
+			// Does the admin allow this field to be customized?
+			$allow_custom = empty( $admin_set_levels[$field->id]['allow_custom'] ) || 'allowed' == $admin_set_levels[$field->id]['allow_custom'];
+
+			// Look to see if the user has set the visibility for this field
+			if ( $allow_custom && isset( $visibility_levels[$field->id] ) ) {
+				$field_visibility = $visibility_levels[$field->id];
+
+			// If no admin-set default is saved, fall back on a global default
+			} else {
+				$field_visibility = !empty( $admin_set_levels[$field->id]['default'] ) ? $admin_set_levels[$field->id]['default'] : apply_filters( 'bp_xprofile_default_visibility_level', 'public' );
+			}
+
+			$fields[$key]->visibility_level = $field_visibility;
+		}
+
+		return $fields;
+	}
+
+	/**
+	 * Fetch the admin-set preferences for all fields
+	 *
+	 * @since BuddyPress (1.6)
+	 *
+	 * @return array $default_visibility_levels An array, keyed by field_id, of default
+	 *   visibility level + allow_custom (whether the admin allows this field to be set by user)
+	 */
+	public static function fetch_default_visibility_levels() {
+		global $wpdb, $bp;
+
+		$levels = $wpdb->get_results( "SELECT object_id, meta_key, meta_value FROM {$bp->profile->table_name_meta} WHERE object_type = 'field' AND ( meta_key = 'default_visibility' OR meta_key = 'allow_custom_visibility' )" );
+
+		// Arrange so that the field id is the key and the visibility level the value
+		$default_visibility_levels = array();
+		foreach( $levels as $level ) {
+			if ( 'default_visibility' == $level->meta_key ) {
+				$default_visibility_levels[$level->object_id]['default'] = $level->meta_value;
+			} else if ( 'allow_custom_visibility' == $level->meta_key ) {
+				$default_visibility_levels[$level->object_id]['allow_custom'] = $level->meta_value;
+			}
+		}
+
+		return $default_visibility_levels;
+	}
+
+	public function render_admin_form() {
+		global $message;
+
+		if ( empty( $this->id ) ) {
+			$title	= __( 'Add New Field Group', 'buddypress' );
+			$action	= "users.php?page=bp-profile-setup&amp;mode=add_group";
+			$button	= __( 'Create Field Group', 'buddypress' );
+		} else {
+			$title  = __( 'Edit Field Group', 'buddypress' );
+			$action = "users.php?page=bp-profile-setup&amp;mode=edit_group&amp;group_id=" . $this->id;
+			$button	= __( 'Save Changes', 'buddypress' );
+		} ?>
+
+		<div class="wrap">
+
+			<?php screen_icon( 'users' ); ?>
+
+			<h2><?php echo esc_html( $title ); ?></h2>
+
+			<?php if ( !empty( $message ) ) :
+					$type = ( 'error' == $type ) ? 'error' : 'updated'; ?>
+
+				<div id="message" class="<?php echo esc_attr( $type ); ?> fade">
+					<p><?php echo esc_html( $message ); ?></p>
+				</div>
+
+			<?php endif; ?>
+
+			<form action="<?php echo esc_url( $action ); ?>" method="post">
+				<div id="poststuff">
+					<div id="post-body" class="metabox-holder columns-2">
+						<div id="post-body-content">
+							<div id="titlediv">
+								<div id="titlewrap">
+									<label class="screen-reader-text" id="title-prompt-text" for=​"title">​<?php _e( 'Field Group Title', 'buddypress') ?></label>
+									<input type="text" name="group_name" id="title" value="<?php echo esc_attr( $this->name ); ?>" placeholder="<?php esc_attr_e( 'Field Group Title', 'buddypress' ); ?>" />
+								</div>
+							</div>
+
+							<div id="postdiv">
+								<div class="postbox">
+									<div id="titlediv"><h3 class="hndle"><?php _e( 'Group Description', 'buddypress' ); ?></h3></div>
+									<div class="inside">
+										<textarea name="group_description" id="group_description" rows="8" cols="60"><?php echo esc_textarea( $this->description ); ?></textarea>
+									</div>
+								</div>
+							</div>
+						</div>
+						<div id="postbox-container-1" class="postbox-container">
+							<div id="side-sortables" class="meta-box-sortables ui-sortable">
+								<div id="submitdiv" class="postbox">
+									<div id="handlediv"><h3 class="hndle"><?php _e( 'Save', 'buddypress' ); ?></h3></div>
+									<div class="inside">
+										<div id="submitcomment" class="submitbox">
+											<div id="major-publishing-actions">
+												<div id="delete-action">
+													<a href="users.php?page=bp-profile-setup" class="submitdelete deletion"><?php _e( 'Cancel', 'buddypress' ); ?></a>
+												</div>
+												<div id="publishing-action">
+													<input type="submit" name="save_group" value="<?php echo esc_attr( $button ); ?>" class="button-primary"/>
+												</div>
+												<input type="hidden" name="group_order" id="group_order" value="<?php echo esc_attr( $this->group_order ); ?>" />
+												<div class="clear"></div>
+											</div>
+										</div>
+									</div>
+								</div>
+							</div>
+						</div>
+					</div>
+				</div>
+			</form>
+		</div>
+
+<?php
+	}
+}
+
+class BP_XProfile_Field {
+	public $id;
+	public $group_id;
+	public $parent_id;
+	public $type;
+	public $name;
+	public $description;
+	public $is_required;
+	public $can_delete = '1';
+	public $field_order;
+	public $option_order;
+	public $order_by;
+	public $is_default_option;
+	public $default_visibility = 'public';
+	public $allow_custom_visibility = 'allowed';
+
+	public $data;
+	public $message = null;
+	public $message_type = 'err';
+
+	public function __construct( $id = null, $user_id = null, $get_data = true ) {
+		if ( !empty( $id ) )
+			$this->populate( $id, $user_id, $get_data );
+	}
+
+	public function populate( $id, $user_id, $get_data ) {
+		global $wpdb, $userdata, $bp;
+
+		if ( empty( $user_id ) ) {
+			$user_id = isset( $userdata->ID ) ? $userdata->ID : 0;
+		}
+
+		$sql = $wpdb->prepare( "SELECT * FROM {$bp->profile->table_name_fields} WHERE id = %d", $id );
+
+		if ( $field = $wpdb->get_row( $sql ) ) {
+			$this->id               = $field->id;
+			$this->group_id          = $field->group_id;
+			$this->parent_id         = $field->parent_id;
+			$this->type              = $field->type;
+			$this->name              = stripslashes( $field->name );
+			$this->description       = stripslashes( $field->description );
+			$this->is_required       = $field->is_required;
+			$this->can_delete        = $field->can_delete;
+			$this->field_order       = $field->field_order;
+			$this->option_order      = $field->option_order;
+			$this->order_by          = $field->order_by;
+			$this->is_default_option = $field->is_default_option;
+
+			if ( $get_data && $user_id ) {
+				$this->data          = $this->get_field_data( $user_id );
+			}
+
+			$this->default_visibility = bp_xprofile_get_meta( $id, 'field', 'default_visibility' );
+
+			if ( empty( $this->default_visibility ) ) {
+				$this->default_visibility = 'public';
+			}
+
+			$this->allow_custom_visibility = 'disabled' == bp_xprofile_get_meta( $id, 'field', 'allow_custom_visibility' ) ? 'disabled' : 'allowed';
+		}
+	}
+
+	public function delete( $delete_data = false ) {
+		global $wpdb, $bp;
+
+		// Prevent deletion if no ID is present
+		// Prevent deletion by url when can_delete is false.
+		// Prevent deletion of option 1 since this invalidates fields with options.
+		if ( empty( $this->id ) || empty( $this->can_delete ) || ( $this->parent_id && $this->option_order == 1 ) )
+			return false;
+
+		if ( !$wpdb->query( $wpdb->prepare( "DELETE FROM {$bp->profile->table_name_fields} WHERE id = %d OR parent_id = %d", $this->id, $this->id ) ) )
+			return false;
+
+		// delete the data in the DB for this field
+		if ( true === $delete_data )
+			BP_XProfile_ProfileData::delete_for_field( $this->id );
+
+		return true;
+	}
+
+	public function save() {
+		global $wpdb, $bp;
+
+		$this->group_id    = apply_filters( 'xprofile_field_group_id_before_save',    $this->group_id,    $this->id );
+		$this->parent_id   = apply_filters( 'xprofile_field_parent_id_before_save',   $this->parent_id,   $this->id );
+		$this->type        = apply_filters( 'xprofile_field_type_before_save',        $this->type,        $this->id );
+		$this->name        = apply_filters( 'xprofile_field_name_before_save',        $this->name,        $this->id );
+		$this->description = apply_filters( 'xprofile_field_description_before_save', $this->description, $this->id );
+		$this->is_required = apply_filters( 'xprofile_field_is_required_before_save', $this->is_required, $this->id );
+		$this->order_by	   = apply_filters( 'xprofile_field_order_by_before_save',    $this->order_by,    $this->id );
+		$this->field_order = apply_filters( 'xprofile_field_field_order_before_save', $this->field_order, $this->id );
+		$this->can_delete  = apply_filters( 'xprofile_field_can_delete_before_save',  $this->can_delete,  $this->id );
+
+		do_action_ref_array( 'xprofile_field_before_save', array( $this ) );
+
+		if ( $this->id != null ) {
+			$sql = $wpdb->prepare( "UPDATE {$bp->profile->table_name_fields} SET group_id = %d, parent_id = 0, type = %s, name = %s, description = %s, is_required = %d, order_by = %s, field_order = %d, can_delete = %d WHERE id = %d", $this->group_id, $this->type, $this->name, $this->description, $this->is_required, $this->order_by, $this->field_order, $this->can_delete, $this->id );
+		} else {
+			$sql = $wpdb->prepare( "INSERT INTO {$bp->profile->table_name_fields} (group_id, parent_id, type, name, description, is_required, order_by, field_order, can_delete ) VALUES (%d, %d, %s, %s, %s, %d, %s, %d, %d )", $this->group_id, $this->parent_id, $this->type, $this->name, $this->description, $this->is_required, $this->order_by, $this->field_order, $this->can_delete );
+		}
+
+		/**
+		 * Check for null so field options can be changed without changing any other part of the field.
+		 * The described situation will return 0 here.
+		 */
+		if ( $wpdb->query( $sql ) !== null ) {
+
+			if ( !empty( $this->id ) ) {
+				$field_id = $this->id;
+			} else {
+				$field_id = $wpdb->insert_id;
+			}
+
+			// Only do this if we are editing an existing field
+			if ( $this->id != null ) {
+
+				/**
+				 * Remove any radio or dropdown options for this
+				 * field. They will be re-added if needed.
+				 * This stops orphan options if the user changes a
+				 * field from a radio button field to a text box.
+				 */
+				$this->delete_children();
+			}
+
+			/**
+			 * Check to see if this is a field with child options.
+			 * We need to add the options to the db, if it is.
+			 */
+			if ( 'radio' == $this->type || 'selectbox' == $this->type || 'checkbox' == $this->type || 'multiselectbox' == $this->type ) {
+
+				if ( !empty( $this->id ) ) {
+					$parent_id = $this->id;
+				} else {
+					$parent_id = $wpdb->insert_id;
+				}
+
+				if ( 'radio' == $this->type ) {
+					$post_option  = !empty( $_POST['radio_option']           ) ? $_POST['radio_option']           : '';
+					$post_default = !empty( $_POST['isDefault_radio_option'] ) ? $_POST['isDefault_radio_option'] : '';
+
+					$options	= apply_filters( 'xprofile_field_options_before_save', $post_option,  'radio' );
+					$defaults	= apply_filters( 'xprofile_field_default_before_save', $post_default, 'radio' );
+
+				} elseif ( 'selectbox' == $this->type ) {
+					$post_option  = !empty( $_POST['selectbox_option']           ) ? $_POST['selectbox_option']           : '';
+					$post_default = !empty( $_POST['isDefault_selectbox_option'] ) ? $_POST['isDefault_selectbox_option'] : '';
+
+					$options	= apply_filters( 'xprofile_field_options_before_save', $post_option, 'selectbox' );
+					$defaults	= apply_filters( 'xprofile_field_default_before_save', $post_default, 'selectbox' );
+
+				} elseif ( 'multiselectbox' == $this->type ) {
+					$post_option  = !empty( $_POST['multiselectbox_option']           ) ? $_POST['multiselectbox_option']           : '';
+					$post_default = !empty( $_POST['isDefault_multiselectbox_option'] ) ? $_POST['isDefault_multiselectbox_option'] : '';
+
+					$options	= apply_filters( 'xprofile_field_options_before_save', $post_option, 'multiselectbox' );
+					$defaults	= apply_filters( 'xprofile_field_default_before_save', $post_default, 'multiselectbox' );
+
+				} elseif ( 'checkbox' == $this->type ) {
+					$post_option  = !empty( $_POST['checkbox_option']           ) ? $_POST['checkbox_option']           : '';
+					$post_default = !empty( $_POST['isDefault_checkbox_option'] ) ? $_POST['isDefault_checkbox_option'] : '';
+
+					$options	= apply_filters( 'xprofile_field_options_before_save', $post_option, 'checkbox' );
+					$defaults	= apply_filters( 'xprofile_field_default_before_save', $post_default, 'checkbox' );
+				}
+
+				$counter = 1;
+				if ( !empty( $options ) ) {
+					foreach ( (array) $options as $option_key => $option_value ) {
+						$is_default = 0;
+
+						if ( is_array( $defaults ) ) {
+							if ( isset( $defaults[$option_key] ) )
+								$is_default = 1;
+						} else {
+							if ( (int) $defaults == $option_key )
+								$is_default = 1;
+						}
+
+						if ( '' != $option_value ) {
+							if ( !$wpdb->query( $wpdb->prepare( "INSERT INTO {$bp->profile->table_name_fields} (group_id, parent_id, type, name, description, is_required, option_order, is_default_option) VALUES (%d, %d, 'option', %s, '', 0, %d, %d)", $this->group_id, $parent_id, $option_value, $counter, $is_default ) ) ) {
+								return false;
+							}
+						}
+
+						$counter++;
+					}
+				}
+			}
+
+			do_action_ref_array( 'xprofile_field_after_save', array( $this ) );
+
+			return $field_id;
+		} else {
+			return false;
+		}
+	}
+
+	public function get_field_data( $user_id ) {
+		return new BP_XProfile_ProfileData( $this->id, $user_id );
+	}
+
+	public function get_children( $for_editing = false ) {
+		global $wpdb, $bp;
+
+		// This is done here so we don't have problems with sql injection
+		if ( 'asc' == $this->order_by && empty( $for_editing ) ) {
+			$sort_sql = 'ORDER BY name ASC';
+		} elseif ( 'desc' == $this->order_by && empty( $for_editing ) ) {
+			$sort_sql = 'ORDER BY name DESC';
+		} else {
+			$sort_sql = 'ORDER BY option_order ASC';
+		}
+
+		// This eliminates a problem with getting all fields when there is no id for the object
+		if ( empty( $this->id ) ) {
+			$parent_id = -1;
+		} else {
+			$parent_id = $this->id;
+		}
+
+		$sql = $wpdb->prepare( "SELECT * FROM {$bp->profile->table_name_fields} WHERE parent_id = %d AND group_id = %d $sort_sql", $parent_id, $this->group_id );
+
+		if ( !$children = $wpdb->get_results( $sql ) )
+			return false;
+
+		return apply_filters( 'bp_xprofile_field_get_children', $children );
+	}
+
+	public function delete_children() {
+		global $wpdb, $bp;
+
+		$sql = $wpdb->prepare( "DELETE FROM {$bp->profile->table_name_fields} WHERE parent_id = %d", $this->id );
+
+		$wpdb->query( $sql );
+	}
+
+	/** Static Methods ********************************************************/
+
+	public static function get_type( $field_id ) {
+		global $wpdb, $bp;
+
+		if ( !empty( $field_id ) ) {
+			$sql = $wpdb->prepare( "SELECT type FROM {$bp->profile->table_name_fields} WHERE id = %d", $field_id );
+
+			if ( !$field_type = $wpdb->get_var( $sql ) ) {
+				return false;
+			}
+
+			return $field_type;
+		}
+
+		return false;
+	}
+
+	public static function delete_for_group( $group_id ) {
+		global $wpdb, $bp;
+
+		if ( !empty( $group_id ) ) {
+			$sql = $wpdb->prepare( "DELETE FROM {$bp->profile->table_name_fields} WHERE group_id = %d", $group_id );
+
+			if ( $wpdb->get_var( $sql ) === false ) {
+				return false;
+			}
+
+			return true;
+		}
+
+		return false;
+	}
+
+	public static function get_id_from_name( $field_name ) {
+		global $wpdb, $bp;
+
+		if ( empty( $bp->profile->table_name_fields ) || !isset( $field_name ) )
+			return false;
+
+		return $wpdb->get_var( $wpdb->prepare( "SELECT id FROM {$bp->profile->table_name_fields} WHERE name = %s", $field_name ) );
+	}
+
+	public static function update_position( $field_id, $position, $field_group_id ) {
+		global $wpdb, $bp;
+
+		if ( !is_numeric( $position ) || !is_numeric( $field_group_id ) )
+			return false;
+
+		// Update $field_id with new $position and $field_group_id
+		if ( $parent = $wpdb->query( $wpdb->prepare( "UPDATE {$bp->profile->table_name_fields} SET field_order = %d, group_id = %d WHERE id = %d", $position, $field_group_id, $field_id ) ) ) {;
+
+			// Update any children of this $field_id
+			$children = $wpdb->query( $wpdb->prepare( "UPDATE {$bp->profile->table_name_fields} SET group_id = %d WHERE parent_id = %d", $field_group_id, $field_id ) );
+
+			return $parent;
+		}
+
+		return false;
+	}
+
+	/* ADMIN AREA HTML.
+	* TODO: Get this out of here and replace with standard template loops
+	*/
+
+	/* This function populates the items for radio buttons checkboxes and drop down boxes */
+	public function render_admin_form_children() {
+		$input_types = array( 'checkbox', 'selectbox', 'multiselectbox', 'radio' );
+
+		foreach ( $input_types as $type ) {
+			$default_name = '';
+
+			if ( ( 'multiselectbox' == $type ) || ( 'checkbox' == $type ) ) {
+				$default_input = 'checkbox';
+			} else {
+				$default_input = 'radio';
+			}
+
+			$class = $this->type != $type ? 'display: none;' : '';
+
+			if ( empty( $this->default_visibility ) ) {
+				$this->default_visibility = 'public';
+			}
+
+			?>
+
+			<div id="<?php echo esc_attr( $type ); ?>" class="postbox bp-options-box" style="<?php echo esc_attr( $class ); ?> margin-top: 15px;">
+				<h3><?php _e( 'Please enter options for this Field:', 'buddypress' ); ?></h3>
+				<div class="inside">
+					<p>
+						<label for="sort_order_<?php echo esc_attr( $type ); ?>"><?php _e( 'Sort Order:', 'buddypress' ); ?></label>
+						<select name="sort_order_<?php echo esc_attr( $type ); ?>" id="sort_order_<?php echo esc_attr( $type ); ?>" >
+							<option value="custom" <?php selected( 'custom', $this->order_by ); ?>><?php _e( 'Custom',     'buddypress' ); ?></option>
+							<option value="asc"    <?php selected( 'asc',    $this->order_by ); ?>><?php _e( 'Ascending',  'buddypress' ); ?></option>
+							<option value="desc"   <?php selected( 'desc',   $this->order_by ); ?>><?php _e( 'Descending', 'buddypress' ); ?></option>
+						</select>
+					</p>
+
+					<?php if ( !$options = $this->get_children( true ) ) {
+
+						$i = 1;
+						while ( isset( $_POST[$type . '_option'][$i] ) ) {
+							(array) $options[] = (object) array(
+								'id'                => -1,
+								'name'              => $_POST[$type . '_option'][$i],
+								'is_default_option' => ( ( 'multiselectbox' != $type ) && ( 'checkbox' != $type ) && ( $_POST["isDefault_{$type}_option"] == $i ) ) ? 1 : $_POST["isDefault_{$type}_option"][$i]
+							);
+
+							++$i;
+						}
+					}
+
+					if ( !empty( $options ) ) {
+						for ( $i = 0, $count = count( $options ); $i < $count; ++$i ) {
+							$j = $i + 1;
+
+							if ( 'multiselectbox' == $type || 'checkbox' == $type )
+								$default_name = '[' . $j . ']'; ?>
+
+							<p class="sortable">
+								<span>&nbsp;&Xi;&nbsp;</span>
+								<input type="text" name="<?php echo esc_attr( $type ); ?>_option[<?php echo esc_attr( $j ); ?>]" id="<?php echo esc_attr( $type ); ?>_option<?php echo esc_attr( $j ); ?>" value="<?php echo stripslashes( esc_attr( $options[$i]->name ) ); ?>" />
+								<input type="<?php echo $default_input; ?>" name="isDefault_<?php echo esc_attr( $type ); ?>_option<?php echo esc_attr( $default_name ); ?>" <?php checked( (int) $options[$i]->is_default_option, true ); ?> value="<?php echo esc_attr( $j ); ?>" />
+								<span><?php _e( 'Default Value', 'buddypress' ); ?></span>
+								<a href="<?php echo esc_url( 'users.php?page=bp-profile-setup&amp;mode=delete_option&amp;option_id=' . $options[$i]->id ); ?>" class="ajax-option-delete" id="delete-<?php echo esc_attr( $options[$i]->id ); ?>">[x]</a>
+							</p>
+
+						<?php } /* end for */ ?>
+
+						<input type="hidden" name="<?php echo esc_attr( $type ); ?>_option_number" id="<?php echo esc_attr( $type ); ?>_option_number" value="<?php echo esc_attr( (int) $j + 1 ); ?>" />
+
+					<?php } else {
+
+						if ( 'multiselectbox' == $type || 'checkbox' == $type )
+							$default_name = '[1]'; ?>
+
+						<p class="sortable">
+							<span>&nbsp;&Xi;&nbsp;</span>
+							<input type="text" name="<?php echo esc_attr( $type ); ?>_option[1]" id="<?php echo esc_attr( $type ); ?>_option1" />
+							<input type="<?php echo esc_attr( $default_input ); ?>" name="isDefault_<?php echo esc_attr( $type ); ?>_option<?php echo esc_attr( $default_name ); ?>" id="isDefault_<?php echo esc_attr( $type ); ?>_option" value="1" />
+							<span><?php _e( 'Default Value', 'buddypress' ); ?></span>
+							<input type="hidden" name="<?php echo esc_attr( $type ); ?>_option_number" id="<?php echo esc_attr( $type ); ?>_option_number" value="2" />
+						</p>
+
+					<?php } /* end if */ ?>
+
+					<div id="<?php echo esc_attr( $type ); ?>_more"></div>
+					<p><a href="javascript:add_option('<?php echo esc_attr( $type ); ?>')"><?php _e( 'Add Another Option', 'buddypress' ); ?></a></p>
+				</div>
+			</div>
+
+		<?php }
+	}
+
+	public function render_admin_form( $message = '' ) {
+		if ( empty( $this->id ) ) {
+			$title  = __( 'Add Field', 'buddypress' );
+			$action	= "users.php?page=bp-profile-setup&amp;group_id=" . $this->group_id . "&amp;mode=add_field#tabs-" . $this->group_id;
+
+			if ( !empty( $_POST['saveField'] ) ) {
+				$this->name        = $_POST['title'];
+				$this->description = $_POST['description'];
+				$this->is_required = $_POST['required'];
+				$this->type        = $_POST['fieldtype'];
+				$this->order_by    = $_POST["sort_order_{$this->type}"];
+				$this->field_order = $_POST['field_order'];
+			}
+		} else {
+			$title  = __( 'Edit Field', 'buddypress' );
+			$action = "users.php?page=bp-profile-setup&amp;mode=edit_field&amp;group_id=" . $this->group_id . "&amp;field_id=" . $this->id . "#tabs-" . $this->group_id;
+		} ?>
+
+		<div class="wrap">
+			<div id="icon-users" class="icon32"><br /></div>
+			<h2><?php echo esc_html( $title ); ?></h2>
+
+			<?php if ( !empty( $message ) ) : ?>
+
+				<div id="message" class="error fade">
+					<p><?php echo esc_html( $message ); ?></p>
+				</div>
+
+			<?php endif; ?>
+
+			<form id="bp-xprofile-add-field" action="<?php echo esc_url( $action ); ?>" method="post">
+				<div id="poststuff">
+					<div id="post-body" class="metabox-holder columns-<?php echo ( 1 == get_current_screen()->get_columns() ) ? '1' : '2'; ?>">
+						<div id="post-body-content">
+							<div id="titlediv">
+								<input type="text" name="title" id="title" value="<?php echo esc_attr( $this->name ); ?>" />
+							</div>
+							<div class="postbox">
+								<h3><?php _e( 'Field Description', 'buddypress' ); ?></h3>
+								<div class="inside">
+									<textarea name="description" id="description" rows="8" cols="60"><?php echo esc_attr( $this->description ); ?></textarea>
+								</div>
+							</div>
+						</div><!-- #post-body-content -->
+
+						<div id="postbox-container-1" class="postbox-container">
+							<div id="submitdiv" class="postbox">
+								<h3><?php _e( 'Submit', 'buddypress' ); ?></h3>
+								<div class="inside">
+									<div id="submitcomment" class="submitbox">
+										<div id="major-publishing-actions">
+											<input type="hidden" name="field_order" id="field_order" value="<?php echo esc_attr( $this->field_order ); ?>" />
+											<div id="publishing-action">
+												<input type="submit" value="<?php _e( 'Save', 'buddypress' ); ?>" name="saveField" id="saveField" style="font-weight: bold" class="button-primary" />
+											</div>
+											<div id="delete-action">
+												<a href="users.php?page=bp-profile-setup" class="deletion"><?php _e( 'Cancel', 'buddypress' ); ?></a>
+											</div>
+											<?php wp_nonce_field( 'xprofile_delete_option' ); ?>
+											<div class="clear"></div>
+										</div>
+									</div>
+								</div>
+							</div>
+
+							<?php /* Field 1 is the fullname field, which cannot have custom visibility */ ?>
+							<?php if ( 1 != $this->id ) : ?>
+
+								<div class="postbox">
+									<h3><label for="default-visibility"><?php _e( 'Default Visibility', 'buddypress' ); ?></label></h3>
+									<div class="inside">
+										<ul>
+
+											<?php foreach( bp_xprofile_get_visibility_levels() as $level ) : ?>
+
+												<li>
+													<input type="radio" id="default-visibility[<?php echo esc_attr( $level['id'] ) ?>]" name="default-visibility" value="<?php echo esc_attr( $level['id'] ) ?>" <?php checked( $this->default_visibility, $level['id'] ); ?> />
+													<label for="default-visibility[<?php echo esc_attr( $level['id'] ) ?>]"><?php echo esc_html( $level['label'] ) ?></label>
+												</li>
+
+											<?php endforeach ?>
+
+										</ul>
+									</div>
+								</div>
+
+								<div class="postbox">
+									<h3><label for="allow-custom-visibility"><?php _e( 'Per-Member Visibility', 'buddypress' ); ?></label></h3>
+									<div class="inside">
+										<ul>
+											<li>
+												<input type="radio" id="allow-custom-visibility-allowed" name="allow-custom-visibility" value="allowed" <?php checked( $this->allow_custom_visibility, 'allowed' ); ?> />
+												<label for="allow-custom-visibility-allowed"><?php _e( "Let members change this field's visibility", 'buddypress' ); ?></label>
+											</li>
+											<li>
+												<input type="radio" id="allow-custom-visibility-disabled" name="allow-custom-visibility" value="disabled" <?php checked( $this->allow_custom_visibility, 'disabled' ); ?> />
+												<label for="allow-custom-visibility-disabled"><?php _e( 'Enforce the default visibility for all members', 'buddypress' ); ?></label>
+											</li>
+										</ul>
+									</div>
+								</div>
+
+							<?php endif ?>
+						</div>
+
+						<div id="postbox-container-2" class="postbox-container">
+
+							<?php /* Field 1 is the fullname field, which cannot be altered */ ?>
+							<?php if ( 1 != $this->id ) : ?>
+
+								<div class="postbox">
+									<h3><label for="required"><?php _e( "Field Requirement", 'buddypress' ); ?></label></h3>
+									<div class="inside">
+										<select name="required" id="required" style="width: 30%">
+											<option value="0"<?php selected( $this->is_required, '0' ); ?>><?php _e( 'Not Required', 'buddypress' ); ?></option>
+											<option value="1"<?php selected( $this->is_required, '1' ); ?>><?php _e( 'Required',     'buddypress' ); ?></option>
+										</select>
+									</div>
+								</div>
+
+								<div class="postbox">
+									<h3><label for="fieldtype"><?php _e( 'Field Type', 'buddypress'); ?></label></h3>
+									<div class="inside">
+										<select name="fieldtype" id="fieldtype" onchange="show_options(this.value)" style="width: 30%">
+											<optgroup label="<?php _e( 'Single Fields', 'buddypress' ); ?>">
+												<option value="textbox"        <?php selected( $this->type, 'textbox'        ); ?>><?php _e( 'Text Box',             'buddypress' ); ?></option>
+												<option value="textarea"       <?php selected( $this->type, 'textarea'       ); ?>><?php _e( 'Multi-line Text Area', 'buddypress' ); ?></option>
+												<option value="datebox"        <?php selected( $this->type, 'datebox'        ); ?>><?php _e( 'Date Selector',        'buddypress' ); ?></option>
+											</optgroup>
+											<optgroup label="<?php _e( 'Multi Fields', 'buddypress' ); ?>">
+												<option value="radio"          <?php selected( $this->type, 'radio'          ); ?>><?php _e( 'Radio Buttons',        'buddypress' ); ?></option>
+												<option value="selectbox"      <?php selected( $this->type, 'selectbox'      ); ?>><?php _e( 'Drop Down Select Box', 'buddypress' ); ?></option>
+												<option value="multiselectbox" <?php selected( $this->type, 'multiselectbox' ); ?>><?php _e( 'Multi Select Box',     'buddypress' ); ?></option>
+												<option value="checkbox"       <?php selected( $this->type, 'checkbox'       ); ?>><?php _e( 'Checkboxes',           'buddypress' ); ?></option>
+											</optgroup>
+										</select>
+
+										<?php do_action_ref_array( 'xprofile_field_additional_options', array( $this ) ); ?>
+
+										<?php $this->render_admin_form_children(); ?>
+
+									</div>
+								</div>
+
+							<?php else : ?>
+
+								<input type="hidden" name="required"  id="required"  value="1"       />
+								<input type="hidden" name="fieldtype" id="fieldtype" value="textbox" />
+
+							<?php endif; ?>
+
+						</div>
+					</div><!-- #post-body -->
+
+				</div><!-- #poststuff -->
+
+			</form>
+		</div>
+
+<?php
+	}
+
+	public static function admin_validate() {
+		global $message;
+
+		// Validate Form
+		if ( '' == $_POST['title'] || '' == $_POST['required'] || '' == $_POST['fieldtype'] ) {
+			$message = __( 'Please make sure you fill out all required fields.', 'buddypress' );
+			return false;
+		} else if ( empty( $_POST['field_file'] ) && $_POST['fieldtype'] == 'radio' && empty( $_POST['radio_option'][1] ) ) {
+			$message = __( 'Radio button field types require at least one option. Please add options below.', 'buddypress' );
+			return false;
+		} else if ( empty( $_POST['field_file'] ) && $_POST['fieldtype'] == 'selectbox' && empty( $_POST['selectbox_option'][1] ) ) {
+			$message = __( 'Select box field types require at least one option. Please add options below.', 'buddypress' );
+			return false;
+		} else if ( empty( $_POST['field_file'] ) && $_POST['fieldtype'] == 'multiselectbox' && empty( $_POST['multiselectbox_option'][1] ) ) {
+			$message = __( 'Select box field types require at least one option. Please add options below.', 'buddypress' );
+			return false;
+		} else if ( empty( $_POST['field_file'] ) && $_POST['fieldtype'] == 'checkbox' && empty( $_POST['checkbox_option'][1] ) ) {
+			$message = __( 'Checkbox field types require at least one option. Please add options below.', 'buddypress' );
+			return false;
+		} else {
+			return true;
+		}
+	}
+}
+
+
+class BP_XProfile_ProfileData {
+	public $id;
+	public $user_id;
+	public $field_id;
+	public $value;
+	public $last_updated;
+
+	public function __construct( $field_id = null, $user_id = null ) {
+		if ( !empty( $field_id ) ) {
+			$this->populate( $field_id, $user_id );
+		}
+	}
+
+	public function populate( $field_id, $user_id )  {
+		global $wpdb, $bp;
+
+		$sql = $wpdb->prepare( "SELECT * FROM {$bp->profile->table_name_data} WHERE field_id = %d AND user_id = %d", $field_id, $user_id );
+
+		if ( $profiledata = $wpdb->get_row( $sql ) ) {
+			$this->id           = $profiledata->id;
+			$this->user_id      = $profiledata->user_id;
+			$this->field_id     = $profiledata->field_id;
+			$this->value        = stripslashes( $profiledata->value );
+			$this->last_updated = $profiledata->last_updated;
+		} else {
+			// When no row is found, we'll need to set these properties manually
+			$this->field_id	    = $field_id;
+			$this->user_id	    = $user_id;
+		}
+	}
+
+	/**
+	 * Check if there is data already for the user.
+	 *
+	 * @global object $wpdb
+	 * @global array $bp
+	 * @return bool
+	 */
+	public function exists() {
+		global $wpdb, $bp;
+
+		$retval = $wpdb->get_row( $wpdb->prepare( "SELECT id FROM {$bp->profile->table_name_data} WHERE user_id = %d AND field_id = %d", $this->user_id, $this->field_id ) );
+
+		return apply_filters_ref_array( 'xprofile_data_exists', array( (bool)$retval, $this ) );
+	}
+
+	/**
+	 * Check if this data is for a valid field.
+	 *
+	 * @global object $wpdb
+	 * @global array $bp
+	 * @return bool
+	 */
+	public function is_valid_field() {
+		global $wpdb, $bp;
+
+		$retval = $wpdb->get_row( $wpdb->prepare( "SELECT id FROM {$bp->profile->table_name_fields} WHERE id = %d", $this->field_id ) );
+
+		return apply_filters_ref_array( 'xprofile_data_is_valid_field', array( (bool)$retval, $this ) );
+	}
+
+	public function save() {
+		global $wpdb, $bp;
+
+		$this->user_id      = apply_filters( 'xprofile_data_user_id_before_save',      $this->user_id,         $this->id );
+		$this->field_id     = apply_filters( 'xprofile_data_field_id_before_save',     $this->field_id,        $this->id );
+		$this->value        = apply_filters( 'xprofile_data_value_before_save',        $this->value,           $this->id );
+		$this->last_updated = apply_filters( 'xprofile_data_last_updated_before_save', bp_core_current_time(), $this->id );
+
+		do_action_ref_array( 'xprofile_data_before_save', array( $this ) );
+
+		if ( $this->is_valid_field() ) {
+			if ( $this->exists() && !empty( $this->value ) && strlen( trim( $this->value ) ) ) {
+				$result   = $wpdb->query( $wpdb->prepare( "UPDATE {$bp->profile->table_name_data} SET value = %s, last_updated = %s WHERE user_id = %d AND field_id = %d", $this->value, $this->last_updated, $this->user_id, $this->field_id ) );
+
+			} else if ( $this->exists() && empty( $this->value ) ) {
+				// Data removed, delete the entry.
+				$result   = $this->delete();
+
+			} else {
+				$result   = $wpdb->query( $wpdb->prepare("INSERT INTO {$bp->profile->table_name_data} (user_id, field_id, value, last_updated) VALUES (%d, %d, %s, %s)", $this->user_id, $this->field_id, $this->value, $this->last_updated ) );
+				$this->id = $wpdb->insert_id;
+			}
+
+			if ( false === $result )
+				return false;
+
+			do_action_ref_array( 'xprofile_data_after_save', array( $this ) );
+
+			return true;
+		}
+
+		return false;
+	}
+
+	/**
+	 * Delete specific XProfile field data
+	 *
+	 * @global object $wpdb
+	 * @return boolean
+	 */
+	public function delete() {
+		global $wpdb;
+
+		$bp = buddypress();
+
+		do_action_ref_array( 'xprofile_data_before_delete', array( $this ) );
+
+		if ( !$wpdb->query( $wpdb->prepare( "DELETE FROM {$bp->profile->table_name_data} WHERE field_id = %d AND user_id = %d", $this->field_id, $this->user_id ) ) )
+			return false;
+
+		do_action_ref_array( 'xprofile_data_after_delete', array( $this ) );
+
+		return true;
+	}
+
+	/** Static Methods ********************************************************/
+
+	/**
+	 * BP_XProfile_ProfileData::get_all_for_user()
+	 *
+	 * Get all of the profile information for a specific user.
+	 */
+	public static function get_all_for_user( $user_id ) {
+		global $wpdb, $bp;
+
+		$results      = $wpdb->get_results( $wpdb->prepare( "SELECT g.id as field_group_id, g.name as field_group_name, f.id as field_id, f.name as field_name, f.type as field_type, d.value as field_data, u.user_login, u.user_nicename, u.user_email FROM {$bp->profile->table_name_groups} g LEFT JOIN {$bp->profile->table_name_fields} f ON g.id = f.group_id INNER JOIN {$bp->profile->table_name_data} d ON f.id = d.field_id LEFT JOIN {$wpdb->users} u ON d.user_id = u.ID WHERE d.user_id = %d AND d.value != ''", $user_id ) );
+		$profile_data = array();
+
+		if ( !empty( $results ) ) {
+			$profile_data['user_login']    = $results[0]->user_login;
+			$profile_data['user_nicename'] = $results[0]->user_nicename;
+			$profile_data['user_email']    = $results[0]->user_email;
+
+			foreach( (array) $results as $field ) {
+				$profile_data[$field->field_name] = array(
+					'field_group_id'   => $field->field_group_id,
+					'field_group_name' => $field->field_group_name,
+					'field_id'         => $field->field_id,
+					'field_type'       => $field->field_type,
+					'field_data'       => $field->field_data
+				);
+			}
+		}
+
+		return $profile_data;
+	}
+
+	/**
+	 * Get the user's field data id by the id of the xprofile field
+	 *
+	 * @param int $field_id
+	 * @param int $user_id
+	 * @return int $fielddata_id
+	 */
+	public static function get_fielddataid_byid( $field_id, $user_id ) {
+		global $wpdb, $bp;
+
+		if ( empty( $field_id ) || empty( $user_id ) ) {
+			$fielddata_id = 0;
+		} else {
+			$fielddata_id = $wpdb->get_var( $wpdb->prepare( "SELECT id FROM {$bp->profile->table_name_data} WHERE field_id = %d AND user_id = %d", $field_id, $user_id ) );
+		}
+
+		return $fielddata_id;
+	}
+
+	public static function get_value_byid( $field_id, $user_ids = null ) {
+		global $wpdb, $bp;
+
+		if ( empty( $user_ids ) )
+			$user_ids = bp_displayed_user_id();
+
+		if ( is_array( $user_ids ) ) {
+			$user_ids = implode( ',', wp_parse_id_list( $user_ids ) );
+			$data = $wpdb->get_results( $wpdb->prepare( "SELECT user_id, value FROM {$bp->profile->table_name_data} WHERE field_id = %d AND user_id IN ({$user_ids})", $field_id ) );
+		} else {
+			$data = $wpdb->get_var( $wpdb->prepare( "SELECT value FROM {$bp->profile->table_name_data} WHERE field_id = %d AND user_id = %d", $field_id, $user_ids ) );
+		}
+
+		return $data;
+	}
+
+	public static function get_value_byfieldname( $fields, $user_id = null ) {
+		global $bp, $wpdb;
+
+		if ( empty( $fields ) )
+			return false;
+
+		if ( empty( $user_id ) )
+			$user_id = bp_displayed_user_id();
+
+		$field_sql = '';
+
+		if ( is_array( $fields ) ) {
+			for ( $i = 0, $count = count( $fields ); $i < $count; ++$i ) {
+				if ( $i == 0 ) {
+					$field_sql .= $wpdb->prepare( "AND ( f.name = %s ", $fields[$i] );
+				} else {
+					$field_sql .= $wpdb->prepare( "OR f.name = %s ", $fields[$i] );
+				}
+			}
+
+			$field_sql .= ')';
+		} else {
+			$field_sql .= $wpdb->prepare( "AND f.name = %s", $fields );
+		}
+
+		$sql = $wpdb->prepare( "SELECT d.value, f.name FROM {$bp->profile->table_name_data} d, {$bp->profile->table_name_fields} f WHERE d.field_id = f.id AND d.user_id = %d AND f.parent_id = 0 $field_sql", $user_id );
+
+		if ( !$values = $wpdb->get_results( $sql ) )
+			return false;
+
+		$new_values = array();
+
+		if ( is_array( $fields ) ) {
+			for ( $i = 0, $count = count( $values ); $i < $count; ++$i ) {
+				for ( $j = 0; $j < count( $fields ); $j++ ) {
+					if ( $values[$i]->name == $fields[$j] ) {
+						$new_values[$fields[$j]] = $values[$i]->value;
+					} else if ( !array_key_exists( $fields[$j], $new_values ) ) {
+						$new_values[$fields[$j]] = NULL;
+					}
+				}
+			}
+		} else {
+			$new_values = $values[0]->value;
+		}
+
+		return $new_values;
+	}
+
+	public static function delete_for_field( $field_id ) {
+		global $wpdb, $bp;
+
+		if ( !$wpdb->query( $wpdb->prepare( "DELETE FROM {$bp->profile->table_name_data} WHERE field_id = %d", $field_id ) ) )
+			return false;
+
+		return true;
+	}
+
+	public static function get_last_updated( $user_id ) {
+		global $wpdb, $bp;
+
+		$last_updated = $wpdb->get_var( $wpdb->prepare( "SELECT last_updated FROM {$bp->profile->table_name_data} WHERE user_id = %d ORDER BY last_updated LIMIT 1", $user_id ) );
+
+		return $last_updated;
+	}
+
+	public static function delete_data_for_user( $user_id ) {
+		global $wpdb, $bp;
+
+		return $wpdb->query( $wpdb->prepare( "DELETE FROM {$bp->profile->table_name_data} WHERE user_id = %d", $user_id ) );
+	}
+
+	public static function get_random( $user_id, $exclude_fullname ) {
+		global $wpdb, $bp;
+
+		if ( !empty( $exclude_fullname ) )
+			$exclude_sql = $wpdb->prepare( " AND pf.id != 1" );
+
+		return $wpdb->get_results( $wpdb->prepare( "SELECT pf.type, pf.name, pd.value FROM {$bp->profile->table_name_data} pd INNER JOIN {$bp->profile->table_name_fields} pf ON pd.field_id = pf.id AND pd.user_id = %d {$exclude_sql} ORDER BY RAND() LIMIT 1", $user_id ) );
+	}
+
+	public static function get_fullname( $user_id = 0 ) {
+
+		if ( empty( $user_id ) )
+			$user_id = bp_displayed_user_id();
+
+		$field_name = bp_xprofile_fullname_field_name();
+		$data       = xprofile_get_field_data( $field_name, $user_id );
+
+		return $data[$field_name];
+	}
+}
Index: /tags/1.9/bp-xprofile/bp-xprofile-cssjs.php
===================================================================
--- /tags/1.9/bp-xprofile/bp-xprofile-cssjs.php	(revision 7684)
+++ /tags/1.9/bp-xprofile/bp-xprofile-cssjs.php	(revision 7684)
@@ -0,0 +1,44 @@
+<?php
+
+/**
+ * BuddyPress XProfile CSS and JS
+ *
+ * @package BuddyPress
+ * @subpackage XProfileScripts
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/**
+ * Enqueue the CSS for XProfile admin styling
+ *
+ * @since BuddyPress (1.1)
+ */
+function xprofile_add_admin_css() {
+	if ( !empty( $_GET['page'] ) && strpos( $_GET['page'], 'bp-profile-setup' ) !== false ) {
+		$min = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min';
+		wp_enqueue_style( 'xprofile-admin-css', BP_PLUGIN_URL . "bp-xprofile/admin/css/admin{$min}.css", array(), bp_get_version() );
+	}
+}
+add_action( 'admin_enqueue_scripts', 'xprofile_add_admin_css' );
+
+/**
+ * Enqueue the jQuery libraries for handling drag/drop/sort
+ *
+ * @since BuddyPress (1.5)
+ */
+function xprofile_add_admin_js() {
+	if ( !empty( $_GET['page'] ) && strpos( $_GET['page'], 'bp-profile-setup' ) !== false ) {
+		wp_enqueue_script( 'jquery-ui-core'      );
+		wp_enqueue_script( 'jquery-ui-tabs'      );
+		wp_enqueue_script( 'jquery-ui-mouse'     );
+		wp_enqueue_script( 'jquery-ui-draggable' );
+		wp_enqueue_script( 'jquery-ui-droppable' );
+		wp_enqueue_script( 'jquery-ui-sortable'  );
+
+		$min = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min';
+		wp_enqueue_script( 'xprofile-admin-js', BP_PLUGIN_URL . "bp-xprofile/admin/js/admin{$min}.js", array( 'jquery', 'jquery-ui-sortable' ), bp_get_version() );
+	}
+}
+add_action( 'admin_enqueue_scripts', 'xprofile_add_admin_js', 1 );
Index: /tags/1.9/bp-xprofile/bp-xprofile-filters.php
===================================================================
--- /tags/1.9/bp-xprofile/bp-xprofile-filters.php	(revision 7684)
+++ /tags/1.9/bp-xprofile/bp-xprofile-filters.php	(revision 7684)
@@ -0,0 +1,262 @@
+<?php
+
+/**
+ * BuddyPress XProfile Filters
+ *
+ * Apply WordPress defined filters
+ *
+ * @package BuddyPress
+ * @subpackage XProfileFilters
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+add_filter( 'bp_get_the_profile_group_name',            'wp_filter_kses',       1 );
+add_filter( 'bp_get_the_profile_group_description',     'wp_filter_kses',       1 );
+add_filter( 'bp_get_the_profile_field_value',           'xprofile_filter_kses', 1 );
+add_filter( 'bp_get_the_profile_field_name',            'wp_filter_kses',       1 );
+add_filter( 'bp_get_the_profile_field_edit_value',      'wp_filter_kses',       1 );
+add_filter( 'bp_get_the_profile_field_description',     'wp_filter_kses',       1 );
+
+add_filter( 'bp_get_the_profile_field_value',           'wptexturize'        );
+add_filter( 'bp_get_the_profile_field_value',           'convert_chars'      );
+add_filter( 'bp_get_the_profile_field_value',           'wpautop'            );
+add_filter( 'bp_get_the_profile_field_value',           'force_balance_tags' );
+add_filter( 'bp_get_the_profile_field_value',           'make_clickable'     );
+add_filter( 'bp_get_the_profile_field_value',           'esc_html',        8 );
+add_filter( 'bp_get_the_profile_field_value',           'convert_smilies', 9 );
+
+add_filter( 'bp_get_the_profile_field_edit_value',      'force_balance_tags' );
+add_filter( 'bp_get_the_profile_field_edit_value',      'esc_html'           );
+
+add_filter( 'bp_get_the_profile_group_name',            'stripslashes' );
+add_filter( 'bp_get_the_profile_group_description',     'stripslashes' );
+add_filter( 'bp_get_the_profile_field_value',           'stripslashes' );
+add_filter( 'bp_get_the_profile_field_edit_value',      'stripslashes' );
+add_filter( 'bp_get_the_profile_field_name',            'stripslashes' );
+add_filter( 'bp_get_the_profile_field_description',     'stripslashes' );
+
+add_filter( 'xprofile_get_field_data',                  'wp_filter_kses', 1 );
+add_filter( 'xprofile_field_name_before_save',          'wp_filter_kses', 1 );
+add_filter( 'xprofile_field_description_before_save',   'wp_filter_kses', 1 );
+
+add_filter( 'xprofile_get_field_data',                  'force_balance_tags' );
+add_filter( 'xprofile_field_name_before_save',          'force_balance_tags' );
+add_filter( 'xprofile_field_description_before_save',   'force_balance_tags' );
+
+add_filter( 'xprofile_get_field_data',                  'stripslashes' );
+
+add_filter( 'bp_get_the_profile_field_value',           'xprofile_filter_format_field_value', 1, 2 );
+add_filter( 'bp_get_the_site_member_profile_data',      'xprofile_filter_format_field_value', 1, 2 );
+add_filter( 'bp_get_the_profile_field_value',           'xprofile_filter_link_profile_data',  9, 2 );
+
+add_filter( 'xprofile_data_value_before_save',          'xprofile_sanitize_data_value_before_save', 1, 2 );
+add_filter( 'xprofile_filtered_data_value_before_save', 'trim', 2 );
+
+/**
+ * xprofile_filter_kses ( $content )
+ *
+ * Run profile field values through kses with filterable allowed tags.
+ *
+ * @param string $content
+ * @return string $content
+ */
+function xprofile_filter_kses( $content ) {
+	global $allowedtags;
+
+	$xprofile_allowedtags             = $allowedtags;
+	$xprofile_allowedtags['a']['rel'] = array();
+
+	$xprofile_allowedtags = apply_filters( 'xprofile_allowed_tags', $xprofile_allowedtags );
+	return wp_kses( $content, $xprofile_allowedtags );
+}
+
+/**
+ * xprofile_sanitize_data_value_before_save ( $field_value, $field_id )
+ *
+ * Safely runs profile field data through kses and force_balance_tags.
+ *
+ * @param string $field_value
+ * @param int $field_id
+ * @param bool $reserialize Whether to reserialize arrays before returning. Defaults to true
+ * @return string
+ */
+function xprofile_sanitize_data_value_before_save ( $field_value, $field_id, $reserialize = true ) {
+
+	// Return if empty
+	if ( empty( $field_value ) )
+		return;
+
+	// Value might be serialized
+	$field_value = maybe_unserialize( $field_value );
+
+	// Filter single value
+	if ( !is_array( $field_value ) ) {
+		$kses_field_value     = xprofile_filter_kses( $field_value );
+		$filtered_field_value = wp_rel_nofollow( force_balance_tags( $kses_field_value ) );
+		$filtered_field_value = apply_filters( 'xprofile_filtered_data_value_before_save', $filtered_field_value, $field_value );
+
+	// Filter each array item independently
+	} else {
+		$filtered_values = array();
+		foreach ( (array) $field_value as $value ) {
+			$kses_field_value       = xprofile_filter_kses( $value );
+			$filtered_value 	= wp_rel_nofollow( force_balance_tags( $kses_field_value ) );
+			$filtered_values[] = apply_filters( 'xprofile_filtered_data_value_before_save', $filtered_value, $value );
+
+		}
+
+		if ( !empty( $reserialize ) )
+			$filtered_field_value = serialize( $filtered_values );
+		else
+			$filtered_field_value = $filtered_values;
+	}
+
+	return $filtered_field_value;
+}
+
+/**
+ * xprofile_filter_format_field_value()
+ *
+ * Runs stripslashes on XProfile fields. If is field_type is 'datebox'
+ * then the date will be formatted by bp_format_time().
+ *
+ * @since BuddyPress (1.0)
+ *
+ * @param string $field_value XProfile field_value to be filtered.
+ * @param string $field_type XProfile field_type to be filtered.
+ *
+ * @uses bp_format_time()
+ *
+ * @return string $field_value Filtered XProfile field_value. False on failure.
+ */
+function xprofile_filter_format_field_value( $field_value, $field_type = '' ) {
+	if ( !isset( $field_value ) || empty( $field_value ) )
+		return false;
+
+	if ( 'datebox' == $field_type ) {
+
+		// If Unix timestamp
+		if ( is_numeric( $field_value ) ) {
+			$field_value = bp_format_time( $field_value, true, false );
+
+		// If MySQL timestamp
+		} else {
+			$field_value = bp_format_time( strtotime( $field_value ), true, false );
+		}
+
+	} else {
+		$field_value = str_replace(']]>', ']]&gt;', $field_value );
+	}
+
+	return stripslashes( $field_value );
+}
+
+function xprofile_filter_link_profile_data( $field_value, $field_type = 'textbox' ) {
+	if ( 'datebox' == $field_type )
+		return $field_value;
+
+	if ( !strpos( $field_value, ',' ) && ( count( explode( ' ', $field_value ) ) > 5 ) )
+		return $field_value;
+
+	$values = explode( ',', $field_value );
+
+	if ( !empty( $values ) ) {
+		foreach ( (array) $values as $value ) {
+			$value = trim( $value );
+
+			// If the value is a URL, skip it and just make it clickable.
+			if ( preg_match( '@(https?://([-\w\.]+)+(:\d+)?(/([\w/_\.]*(\?\S+)?)?)?)@', $value ) ) {
+				$new_values[] = make_clickable( $value );
+
+			// Is not clickable
+			} else {
+
+				// More than 5 spaces
+				if ( count( explode( ' ', $value ) ) > 5 ) {
+					$new_values[] = $value;
+
+				// Less than 5 spaces
+				} else {
+					$search_url   = add_query_arg( array( 's' => urlencode( $value ) ), bp_get_members_directory_permalink() );
+					$new_values[] = '<a href="' . $search_url . '" rel="nofollow">' . $value . '</a>';
+				}
+			}
+		}
+
+		$values = implode( ', ', $new_values );
+	}
+
+	return $values;
+}
+
+/**
+ * Ensures that BP data appears in comments array
+ *
+ * This filter loops through the comments return by a normal WordPress request
+ * and swaps out user data with BP xprofile data, where available
+ *
+ * @param array $comments
+ * @param int $post_id
+ * @return array $comments
+ */
+function xprofile_filter_comments( $comments, $post_id ) {
+	// Locate comment authors with WP accounts
+	foreach( (array) $comments as $comment ) {
+		if ( $comment->user_id ) {
+			$user_ids[] = $comment->user_id;
+		}
+	}
+
+	// If none are found, just return the comments array
+	if ( empty( $user_ids ) ) {
+		return $comments;
+	}
+
+	// Pull up the xprofile fullname of each commenter
+	if ( $fullnames = BP_XProfile_ProfileData::get_value_byid( 1, $user_ids ) ) {
+		foreach( (array) $fullnames as $user ) {
+			$users[ $user->user_id ] = trim( stripslashes( $user->value ) );
+		}
+	}
+
+	// Loop through and match xprofile fullname with commenters
+	foreach( (array) $comments as $i => $comment ) {
+		if ( ! empty( $comment->user_id ) ) {
+			if ( ! empty( $users[ $comment->user_id ] ) ) {
+				$comments[ $i ]->comment_author = $users[ $comment->user_id ];
+			}
+		}
+	}
+
+	return $comments;
+}
+add_filter( 'comments_array', 'xprofile_filter_comments', 10, 2 );
+
+/**
+ * Filter BP_User_Query::populate_extras to override each queries users fullname
+ *
+ * @since BuddyPress (1.7)
+ *
+ * @global BuddyPress $bp
+ * @global WPDB $wpdb
+ * @param BP_User_Query $user_query
+ * @param string $user_ids_sql
+ */
+function bp_xprofile_filter_user_query_populate_extras( BP_User_Query $user_query, $user_ids_sql ) {
+	global $bp, $wpdb;
+
+	if ( bp_is_active( 'xprofile' ) ) {
+		$fullname_field_id = $wpdb->get_var( $wpdb->prepare( "SELECT id FROM {$bp->profile->table_name_fields} WHERE name = %s", bp_xprofile_fullname_field_name() ) );
+		$user_id_names     = $wpdb->get_results( $wpdb->prepare( "SELECT user_id, value as fullname FROM {$bp->profile->table_name_data} WHERE user_id IN ({$user_ids_sql}) AND field_id = %d", $fullname_field_id ) );
+
+		// Loop through names and override each user's fullname
+		foreach ( $user_id_names as $user ) {
+			if ( isset( $user_query->results[ $user->user_id ] ) ) {
+				$user_query->results[ $user->user_id ]->fullname = $user->fullname;
+			}
+		}
+	}
+}
+add_filter( 'bp_user_query_populate_extras', 'bp_xprofile_filter_user_query_populate_extras', 2, 2 );
Index: /tags/1.9/bp-xprofile/bp-xprofile-functions.php
===================================================================
--- /tags/1.9/bp-xprofile/bp-xprofile-functions.php	(revision 7684)
+++ /tags/1.9/bp-xprofile/bp-xprofile-functions.php	(revision 7684)
@@ -0,0 +1,774 @@
+<?php
+
+/**
+ * BuddyPress XProfile Filters
+ *
+ * Business functions are where all the magic happens in BuddyPress. They will
+ * handle the actual saving or manipulation of information. Usually they will
+ * hand off to a database class for data access, then return
+ * true or false on success or failure.
+ *
+ * @package BuddyPress
+ * @subpackage XProfileFilters
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/*** Field Group Management **************************************************/
+
+function xprofile_insert_field_group( $args = '' ) {
+	$defaults = array(
+		'field_group_id' => false,
+		'name'           => false,
+		'description'    => '',
+		'can_delete'     => true
+	);
+
+	$r = wp_parse_args( $args, $defaults );
+	extract( $r, EXTR_SKIP );
+
+	if ( empty( $name ) )
+		return false;
+
+	$field_group              = new BP_XProfile_Group( $field_group_id );
+	$field_group->name        = $name;
+	$field_group->description = $description;
+	$field_group->can_delete  = $can_delete;
+
+	return $field_group->save();
+}
+
+function xprofile_get_field_group( $field_group_id ) {
+	$field_group = new BP_XProfile_Group( $field_group_id );
+
+	if ( empty( $field_group->id ) )
+		return false;
+
+	return $field_group;
+}
+
+function xprofile_delete_field_group( $field_group_id ) {
+	$field_group = new BP_XProfile_Group( $field_group_id );
+	return $field_group->delete();
+}
+
+function xprofile_update_field_group_position( $field_group_id, $position ) {
+	return BP_XProfile_Group::update_position( $field_group_id, $position );
+}
+
+
+/*** Field Management *********************************************************/
+
+function xprofile_insert_field( $args = '' ) {
+	global $bp;
+
+	extract( $args );
+
+	/**
+	 * Possible parameters (pass as assoc array):
+	 *	'field_id'
+	 *	'field_group_id'
+	 *	'parent_id'
+	 *	'type'
+	 *	'name'
+	 *	'description'
+	 *	'is_required'
+	 *	'can_delete'
+	 *	'field_order'
+	 *	'order_by'
+	 *	'is_default_option'
+	 *	'option_order'
+	 */
+
+	// Check we have the minimum details
+	if ( empty( $field_group_id ) )
+		return false;
+
+	// Check this is a valid field type
+	if ( !in_array( $type, (array) $bp->profile->field_types ) )
+		return false;
+
+	// Instantiate a new field object
+	if ( !empty( $field_id ) )
+		$field = new BP_XProfile_Field( $field_id );
+	else
+		$field = new BP_XProfile_Field;
+
+	$field->group_id = $field_group_id;
+
+	if ( !empty( $parent_id ) )
+		$field->parent_id = $parent_id;
+
+	if ( !empty( $type ) )
+		$field->type = $type;
+
+	if ( !empty( $name ) )
+		$field->name = $name;
+
+	if ( !empty( $description ) )
+		$field->description = $description;
+
+	if ( !empty( $is_required ) )
+		$field->is_required = $is_required;
+
+	if ( !empty( $can_delete ) )
+		$field->can_delete = $can_delete;
+
+	if ( !empty( $field_order ) )
+		$field->field_order = $field_order;
+
+	if ( !empty( $order_by ) )
+		$field->order_by = $order_by;
+
+	if ( !empty( $is_default_option ) )
+		$field->is_default_option = $is_default_option;
+
+	if ( !empty( $option_order ) )
+		$field->option_order = $option_order;
+
+	return $field->save();
+}
+
+function xprofile_get_field( $field_id ) {
+	return new BP_XProfile_Field( $field_id );
+}
+
+function xprofile_delete_field( $field_id ) {
+	$field = new BP_XProfile_Field( $field_id );
+	return $field->delete();
+}
+
+
+/*** Field Data Management *****************************************************/
+
+/**
+ * Fetches profile data for a specific field for the user.
+ *
+ * When the field value is serialized, this function unserializes and filters each item in the array
+ * that results.
+ *
+ * @package BuddyPress Core
+ * @param mixed $field The ID of the field, or the $name of the field.
+ * @param int $user_id The ID of the user
+ * @param string $multi_format How should array data be returned? 'comma' if you want a
+ *   comma-separated string; 'array' if you want an array
+ * @uses BP_XProfile_ProfileData::get_value_byid() Fetches the value based on the params passed.
+ * @return mixed The profile field data.
+ */
+function xprofile_get_field_data( $field, $user_id = 0, $multi_format = 'array' ) {
+
+	if ( empty( $user_id ) )
+		$user_id = bp_displayed_user_id();
+
+	if ( empty( $user_id ) )
+		return false;
+
+	if ( is_numeric( $field ) )
+		$field_id = $field;
+	else
+		$field_id = xprofile_get_field_id_from_name( $field );
+
+	if ( empty( $field_id ) )
+		return false;
+
+	$values = maybe_unserialize( BP_XProfile_ProfileData::get_value_byid( $field_id, $user_id ) );
+
+	if ( is_array( $values ) ) {
+		$data = array();
+		foreach( (array) $values as $value ) {
+			$data[] = apply_filters( 'xprofile_get_field_data', $value, $field_id, $user_id );
+		}
+
+		if ( 'comma' == $multi_format ) {
+			$data = implode( ', ', $data );
+		}
+	} else {
+		$data = apply_filters( 'xprofile_get_field_data', $values, $field_id, $user_id );
+	}
+
+	return $data;
+}
+
+/**
+ * A simple function to set profile data for a specific field for a specific user.
+ *
+ * @package BuddyPress Core
+ * @param int|string $field The ID of the field, or the $name of the field.
+ * @param int|$user_id The ID of the user
+ * @param mixed The value for the field you want to set for the user.
+ * @global BuddyPress $bp The one true BuddyPress instance
+ * @uses xprofile_get_field_id_from_name() Gets the ID for the field based on the name.
+ * @return bool True on success, false on failure.
+ */
+function xprofile_set_field_data( $field, $user_id, $value, $is_required = false ) {
+
+	if ( is_numeric( $field ) )
+		$field_id = $field;
+	else
+		$field_id = xprofile_get_field_id_from_name( $field );
+
+	if ( empty( $field_id ) )
+		return false;
+
+	if ( $is_required && ( empty( $value ) || !is_array( $value ) && !strlen( trim( $value ) ) ) )
+		return false;
+
+	$field = new BP_XProfile_Field( $field_id );
+
+	// If the value is empty, then delete any field data that exists, unless the field is of a
+	// type where null values are semantically meaningful
+	if ( empty( $value ) && 'checkbox' != $field->type && 'multiselectbox' != $field->type ) {
+		xprofile_delete_field_data( $field_id, $user_id );
+		return true;
+	}
+
+	$possible_values = array();
+
+	// Check the value is an acceptable value
+	if ( 'checkbox' == $field->type || 'radio' == $field->type || 'selectbox' == $field->type || 'multiselectbox' == $field->type ) {
+		$options = $field->get_children();
+
+		foreach( $options as $option )
+			$possible_values[] = $option->name;
+
+		if ( is_array( $value ) ) {
+			foreach( $value as $i => $single ) {
+				if ( !in_array( $single, $possible_values ) ) {
+					unset( $value[$i] );
+				}
+			}
+
+			// Reset the keys by merging with an empty array
+			$value = array_merge( array(), $value );
+		} else {
+			if ( !in_array( $value, $possible_values ) ) {
+				return false;
+			}
+		}
+	}
+
+	$field           = new BP_XProfile_ProfileData();
+	$field->field_id = $field_id;
+	$field->user_id  = $user_id;
+	$field->value    = maybe_serialize( $value );
+
+	return $field->save();
+}
+
+/**
+ * Set the visibility level for this field
+ *
+ * @param int $field_id The ID of the xprofile field
+ * @param int $user_id The ID of the user to whom the data belongs
+ * @param string $visibility_level
+ * @return bool True on success
+ */
+function xprofile_set_field_visibility_level( $field_id = 0, $user_id = 0, $visibility_level = '' ) {
+	if ( empty( $field_id ) || empty( $user_id ) || empty( $visibility_level ) ) {
+		return false;
+	}
+
+	// Check against a whitelist
+	$allowed_values = bp_xprofile_get_visibility_levels();
+	if ( !array_key_exists( $visibility_level, $allowed_values ) ) {
+		return false;
+	}
+
+	// Stored in an array in usermeta
+	$current_visibility_levels = bp_get_user_meta( $user_id, 'bp_xprofile_visibility_levels', true );
+
+	if ( !$current_visibility_levels ) {
+		$current_visibility_levels = array();
+	}
+
+	$current_visibility_levels[$field_id] = $visibility_level;
+
+	return bp_update_user_meta( $user_id, 'bp_xprofile_visibility_levels', $current_visibility_levels );
+}
+
+function xprofile_delete_field_data( $field, $user_id ) {
+	if ( is_numeric( $field ) )
+		$field_id = $field;
+	else
+		$field_id = xprofile_get_field_id_from_name( $field );
+
+	if ( empty( $field_id ) || empty( $user_id ) )
+		return false;
+
+	$field = new BP_XProfile_ProfileData( $field_id, $user_id );
+	return $field->delete();
+}
+
+function xprofile_check_is_required_field( $field_id ) {
+	$field = new BP_Xprofile_Field( $field_id );
+
+	// Define locale variable(s)
+	$retval = false;
+
+	// Super admins can skip required check
+	if ( bp_current_user_can( 'bp_moderate' ) && !is_admin() )
+		$retval = false;
+
+	// All other users will use the field's setting
+	elseif ( isset( $field->is_required ) )
+		$retval = $field->is_required;
+
+	return (bool) $retval;
+}
+
+/**
+ * Returns the ID for the field based on the field name.
+ *
+ * @package BuddyPress Core
+ * @param string $field_name The name of the field to get the ID for.
+ * @return int $field_id on success, false on failure.
+ */
+function xprofile_get_field_id_from_name( $field_name ) {
+	return BP_Xprofile_Field::get_id_from_name( $field_name );
+}
+
+/**
+ * Fetches a random piece of profile data for the user.
+ *
+ * @package BuddyPress Core
+ * @param int $user_id User ID of the user to get random data for
+ * @param bool $exclude_fullname Optional; whether or not to exclude the full name field as random data. Defaults to true.
+ * @global BuddyPress $bp The one true BuddyPress instance
+ * @global $wpdb WordPress DB access object.
+ * @global $current_user WordPress global variable containing current logged in user information
+ * @uses xprofile_format_profile_field() Formats profile field data so it is suitable for display.
+ * @return string|bool The fetched random data for the user, or false if no data or no match.
+ */
+function xprofile_get_random_profile_data( $user_id, $exclude_fullname = true ) {
+	$field_data = BP_XProfile_ProfileData::get_random( $user_id, $exclude_fullname );
+
+	if ( empty( $field_data ) )
+		return false;
+
+	$field_data[0]->value = xprofile_format_profile_field( $field_data[0]->type, $field_data[0]->value );
+
+	if ( empty( $field_data[0]->value ) )
+		return false;
+
+	return apply_filters( 'xprofile_get_random_profile_data', $field_data );
+}
+
+/**
+ * Formats a profile field according to its type. [ TODO: Should really be moved to filters ]
+ *
+ * @package BuddyPress Core
+ * @param string $field_type The type of field: datebox, selectbox, textbox etc
+ * @param string $field_value The actual value
+ * @uses bp_format_time() Formats a time value based on the WordPress date format setting
+ * @return string|bool The formatted value, or false if value is empty
+ */
+function xprofile_format_profile_field( $field_type, $field_value ) {
+	if ( !isset( $field_value ) || empty( $field_value ) )
+		return false;
+
+	$field_value = bp_unserialize_profile_field( $field_value );
+
+	if ( 'datebox' == $field_type ) {
+		$field_value = bp_format_time( $field_value, true );
+	} else {
+		$content = $field_value;
+		$field_value = str_replace( ']]>', ']]&gt;', $content );
+	}
+
+	return stripslashes_deep( $field_value );
+}
+
+function xprofile_update_field_position( $field_id, $position, $field_group_id ) {
+	return BP_XProfile_Field::update_position( $field_id, $position, $field_group_id );
+}
+
+/**
+ * Setup the avatar upload directory for a user.
+ *
+ * @package BuddyPress Core
+ * @param string $directory The root directory name. Optional.
+ * @param int $user_id The user ID. Optional.
+ * @return array() containing the path and URL plus some other settings.
+ */
+function xprofile_avatar_upload_dir( $directory = false, $user_id = 0 ) {
+
+	if ( empty( $user_id ) )
+		$user_id = bp_displayed_user_id();
+
+	if ( empty( $directory ) )
+		$directory = 'avatars';
+
+	$path    = bp_core_avatar_upload_path() . '/avatars/' . $user_id;
+	$newbdir = $path;
+
+	if ( !file_exists( $path ) )
+		@wp_mkdir_p( $path );
+
+	$newurl    = bp_core_avatar_url() . '/avatars/' . $user_id;
+	$newburl   = $newurl;
+	$newsubdir = '/avatars/' . $user_id;
+
+	return apply_filters( 'xprofile_avatar_upload_dir', array(
+		'path'    => $path,
+		'url'     => $newurl,
+		'subdir'  => $newsubdir,
+		'basedir' => $newbdir,
+		'baseurl' => $newburl,
+		'error'   => false
+	) );
+}
+
+/**
+ * Syncs Xprofile data to the standard built in WordPress profile data.
+ *
+ * @package BuddyPress Core
+ */
+function xprofile_sync_wp_profile( $user_id = 0 ) {
+
+	$bp = buddypress();
+
+	if ( !empty( $bp->site_options['bp-disable-profile-sync'] ) && (int) $bp->site_options['bp-disable-profile-sync'] )
+		return true;
+
+	if ( empty( $user_id ) )
+		$user_id = bp_loggedin_user_id();
+
+	if ( empty( $user_id ) )
+		return false;
+
+	$fullname = xprofile_get_field_data( bp_xprofile_fullname_field_name(), $user_id );
+	$space    = strpos( $fullname, ' ' );
+
+	if ( false === $space ) {
+		$firstname = $fullname;
+		$lastname = '';
+	} else {
+		$firstname = substr( $fullname, 0, $space );
+		$lastname = trim( substr( $fullname, $space, strlen( $fullname ) ) );
+	}
+
+	bp_update_user_meta( $user_id, 'nickname',   $fullname  );
+	bp_update_user_meta( $user_id, 'first_name', $firstname );
+	bp_update_user_meta( $user_id, 'last_name',  $lastname  );
+
+	global $wpdb;
+
+	$wpdb->query( $wpdb->prepare( "UPDATE {$wpdb->users} SET display_name = %s WHERE ID = %d", $fullname, $user_id ) );
+}
+add_action( 'xprofile_updated_profile', 'xprofile_sync_wp_profile' );
+add_action( 'bp_core_signup_user',      'xprofile_sync_wp_profile' );
+add_action( 'bp_core_activated_user',   'xprofile_sync_wp_profile' );
+
+
+/**
+ * Syncs the standard built in WordPress profile data to XProfile.
+ *
+ * @since BuddyPress (1.2.4)
+ * @package BuddyPress Core
+ */
+function xprofile_sync_bp_profile( &$errors, $update, &$user ) {
+	global $bp;
+
+	if ( ( !empty( $bp->site_options['bp-disable-profile-sync'] ) && (int) $bp->site_options['bp-disable-profile-sync'] ) || !$update || $errors->get_error_codes() )
+		return;
+
+	xprofile_set_field_data( bp_xprofile_fullname_field_name(), $user->ID, $user->display_name );
+}
+add_action( 'user_profile_update_errors', 'xprofile_sync_bp_profile', 10, 3 );
+
+
+/**
+ * When a user is deleted, we need to clean up the database and remove all the
+ * profile data from each table. Also we need to clean anything up in the
+ * usermeta table that this component uses.
+ *
+ * @package BuddyPress XProfile
+ * @param int $user_id The ID of the deleted user
+ */
+function xprofile_remove_data( $user_id ) {
+	BP_XProfile_ProfileData::delete_data_for_user( $user_id );
+}
+add_action( 'wpmu_delete_user',  'xprofile_remove_data' );
+add_action( 'delete_user',       'xprofile_remove_data' );
+add_action( 'bp_make_spam_user', 'xprofile_remove_data' );
+
+/*** XProfile Meta ****************************************************/
+
+function bp_xprofile_delete_meta( $object_id, $object_type, $meta_key = false, $meta_value = false ) {
+	global $wpdb, $bp;
+
+	$object_id = (int) $object_id;
+
+	if ( !$object_id )
+		return false;
+
+	if ( !isset( $object_type ) )
+		return false;
+
+	if ( !in_array( $object_type, array( 'group', 'field', 'data' ) ) )
+		return false;
+
+	$meta_key = preg_replace( '|[^a-z0-9_]|i', '', $meta_key );
+
+	if ( is_array( $meta_value ) || is_object( $meta_value ) ) {
+		$meta_value = serialize( $meta_value );
+	}
+
+	$meta_value = trim( $meta_value );
+
+	if ( empty( $meta_key ) ) {
+		$wpdb->query( $wpdb->prepare( "DELETE FROM {$bp->profile->table_name_meta} WHERE object_id = %d AND object_type = %s", $object_id, $object_type ) );
+	} elseif ( !empty( $meta_value ) ) {
+		$wpdb->query( $wpdb->prepare( "DELETE FROM {$bp->profile->table_name_meta} WHERE object_id = %d AND object_type = %s AND meta_key = %s AND meta_value = %s", $object_id, $object_type, $meta_key, $meta_value ) );
+	} else {
+		$wpdb->query( $wpdb->prepare( "DELETE FROM {$bp->profile->table_name_meta} WHERE object_id = %d AND object_type = %s AND meta_key = %s", $object_id, $object_type, $meta_key ) );
+	}
+
+	// Delete the cached object
+	wp_cache_delete( 'bp_xprofile_meta_' . $object_type . '_' . $object_id . '_' . $meta_key, 'bp' );
+
+	return true;
+}
+
+function bp_xprofile_get_meta( $object_id, $object_type, $meta_key = '') {
+	global $wpdb, $bp;
+
+	$object_id = (int) $object_id;
+
+	if ( !$object_id )
+		return false;
+
+	if ( !isset( $object_type ) )
+		return false;
+
+	if ( !in_array( $object_type, array( 'group', 'field', 'data' ) ) )
+		return false;
+
+	if ( !empty( $meta_key ) ) {
+		$meta_key = preg_replace( '|[^a-z0-9_]|i', '', $meta_key );
+
+		if ( !$metas = wp_cache_get( 'bp_xprofile_meta_' . $object_type . '_' . $object_id . '_' . $meta_key, 'bp' ) ) {
+			$metas = $wpdb->get_col( $wpdb->prepare( "SELECT meta_value FROM {$bp->profile->table_name_meta} WHERE object_id = %d AND object_type = %s AND meta_key = %s", $object_id, $object_type, $meta_key ) );
+			wp_cache_set( 'bp_xprofile_meta_' . $object_type . '_' . $object_id . '_' . $meta_key, $metas, 'bp' );
+		}
+	} else {
+		$metas = $wpdb->get_col( $wpdb->prepare( "SELECT meta_value FROM {$bp->profile->table_name_meta} WHERE object_id = %d AND object_type = %s", $object_id, $object_type ) );
+	}
+
+	if ( empty( $metas ) ) {
+		if ( empty( $meta_key ) ) {
+			return array();
+		} else {
+			return '';
+		}
+	}
+
+	$metas = array_map( 'maybe_unserialize', (array) $metas );
+
+	if ( 1 == count( $metas ) )
+		return $metas[0];
+	else
+		return $metas;
+}
+
+function bp_xprofile_update_meta( $object_id, $object_type, $meta_key, $meta_value ) {
+	global $wpdb, $bp;
+
+	$object_id = (int) $object_id;
+
+	if ( empty( $object_id ) )
+		return false;
+
+	if ( !isset( $object_type ) )
+		return false;
+
+	if ( !in_array( $object_type, array( 'group', 'field', 'data' ) ) )
+		return false;
+
+	$meta_key = preg_replace( '|[^a-z0-9_]|i', '', $meta_key );
+
+	if ( is_string( $meta_value ) ) {
+		$meta_value = stripslashes( $meta_value );
+	}
+
+	$meta_value = maybe_serialize( $meta_value );
+
+	if ( empty( $meta_value ) )
+		return bp_xprofile_delete_meta( $object_id, $object_type, $meta_key );
+
+	$cur = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$bp->profile->table_name_meta} WHERE object_id = %d AND object_type = %s AND meta_key = %s", $object_id, $object_type, $meta_key ) );
+
+	if ( empty( $cur ) )
+		$wpdb->query( $wpdb->prepare( "INSERT INTO {$bp->profile->table_name_meta} ( object_id, object_type, meta_key, meta_value ) VALUES ( %d, %s, %s, %s )", $object_id, $object_type,  $meta_key, $meta_value ) );
+	else if ( $cur->meta_value != $meta_value )
+		$wpdb->query( $wpdb->prepare( "UPDATE {$bp->profile->table_name_meta} SET meta_value = %s WHERE object_id = %d AND object_type = %s AND meta_key = %s", $meta_value, $object_id, $object_type, $meta_key ) );
+	else
+		return false;
+
+	// Update the cached object and recache
+	wp_cache_set( 'bp_xprofile_meta_' . $object_type . '_' . $object_id . '_' . $meta_key, $meta_value, 'bp' );
+
+	return true;
+}
+
+function bp_xprofile_update_fieldgroup_meta( $field_group_id, $meta_key, $meta_value ) {
+	return bp_xprofile_update_meta( $field_group_id, 'group', $meta_key, $meta_value );
+}
+
+function bp_xprofile_update_field_meta( $field_id, $meta_key, $meta_value ) {
+	return bp_xprofile_update_meta( $field_id, 'field', $meta_key, $meta_value );
+}
+
+function bp_xprofile_update_fielddata_meta( $field_data_id, $meta_key, $meta_value ) {
+	return bp_xprofile_update_meta( $field_data_id, 'data', $meta_key, $meta_value );
+}
+
+/**
+ * Return the field name for the Full Name xprofile field
+ *
+ * @package BuddyPress
+ * @since BuddyPress (1.5)
+ *
+ * @return string The field name
+ */
+function bp_xprofile_fullname_field_name() {
+	return apply_filters( 'bp_xprofile_fullname_field_name', BP_XPROFILE_FULLNAME_FIELD_NAME );
+}
+
+/**
+ * Get visibility levels out of the $bp global
+ *
+ * @return array
+ */
+function bp_xprofile_get_visibility_levels() {
+	global $bp;
+
+	return apply_filters( 'bp_xprofile_get_visibility_levels', $bp->profile->visibility_levels );
+}
+
+/**
+ * Get the ids of fields that are hidden for this displayed/loggedin user pair
+ *
+ * This is the function primarily responsible for profile field visibility. It works by determining
+ * the relationship between the displayed_user (ie the profile owner) and the current_user (ie the
+ * profile viewer). Then, based on that relationship, we query for the set of fields that should
+ * be excluded from the profile loop.
+ *
+ * @since BuddyPress (1.6)
+ * @see BP_XProfile_Group::get()
+ * @uses apply_filters() Filter bp_xprofile_get_hidden_fields_for_user to modify visibility levels,
+ *   or if you have added your own custom levels
+ *
+ * @param int $displayed_user_id The id of the user the profile fields belong to
+ * @param int $current_user_id The id of the user viewing the profile
+ * @return array An array of field ids that should be excluded from the profile query
+ */
+function bp_xprofile_get_hidden_fields_for_user( $displayed_user_id = 0, $current_user_id = 0 ) {
+	if ( !$displayed_user_id ) {
+		$displayed_user_id = bp_displayed_user_id();
+	}
+
+	if ( !$displayed_user_id ) {
+		return array();
+	}
+
+	if ( !$current_user_id ) {
+		$current_user_id = bp_loggedin_user_id();
+	}
+
+	// @todo - This is where you'd swap out for current_user_can() checks
+	$hidden_levels = bp_xprofile_get_hidden_field_types_for_user( $displayed_user_id, $current_user_id );
+	$hidden_fields = bp_xprofile_get_fields_by_visibility_levels( $displayed_user_id, $hidden_levels );
+
+	return apply_filters( 'bp_xprofile_get_hidden_fields_for_user', $hidden_fields, $displayed_user_id, $current_user_id );
+}
+
+/**
+ * Get the visibility levels that should be hidden for this user pair
+ *
+ * Field visibility is determined based on the relationship between the
+ * logged-in user, the displayed user, and the visibility setting for the
+ * current field. (See bp_xprofile_get_hidden_fields_for_user().) This
+ * utility function speeds up this matching by fetching the visibility levels
+ * that should be hidden for the current user pair.
+ *
+ * @since BuddyPress (1.8.2)
+ * @see bp_xprofile_get_hidden_fields_for_user()
+ *
+ * @param int $displayed_user_id The id of the user the profile fields belong to
+ * @param int $current_user_id The id of the user viewing the profile
+ * @return array An array of visibility levels hidden to the current user
+ */
+function bp_xprofile_get_hidden_field_types_for_user( $displayed_user_id = 0, $current_user_id = 0 ) {
+
+	// Current user is logged in
+	if ( ! empty( $current_user_id ) ) {
+
+		// Nothing's private when viewing your own profile, or when the
+		// current user is an admin
+		if ( $displayed_user_id == $current_user_id || bp_current_user_can( 'bp_moderate' ) ) {
+			$hidden_levels = array();
+
+		// If the current user and displayed user are friends, show all
+		} elseif ( bp_is_active( 'friends' ) && friends_check_friendship( $displayed_user_id, $current_user_id ) ) {
+			$hidden_levels = array( 'adminsonly', );
+
+		// current user is logged in but not friends, so exclude friends-only
+		} else {
+			$hidden_levels = array( 'friends', 'adminsonly', );
+		}
+
+	// Current user is not logged in, so exclude friends-only, loggedin, and adminsonly.
+	} else {
+		$hidden_levels = array( 'friends', 'loggedin', 'adminsonly', );
+	}
+
+	return $hidden_levels;
+}
+
+/**
+ * Fetch an array of the xprofile fields that a given user has marked with certain visibility levels
+ *
+ * @since BuddyPress (1.6)
+ * @see bp_xprofile_get_hidden_fields_for_user()
+ *
+ * @param int $user_id The id of the profile owner
+ * @param array $levels An array of visibility levels ('public', 'friends', 'loggedin', 'adminsonly' etc) to be
+ *    checked against
+ * @return array $field_ids The fields that match the requested visibility levels for the given user
+ */
+function bp_xprofile_get_fields_by_visibility_levels( $user_id, $levels = array() ) {
+	if ( !is_array( $levels ) ) {
+		$levels = (array)$levels;
+	}
+
+	$user_visibility_levels = bp_get_user_meta( $user_id, 'bp_xprofile_visibility_levels', true );
+
+	// Parse the user-provided visibility levels with the default levels, which may take
+	// precedence
+	$default_visibility_levels = BP_XProfile_Group::fetch_default_visibility_levels();
+
+	foreach( (array) $default_visibility_levels as $d_field_id => $defaults ) {
+		// If the admin has forbidden custom visibility levels for this field, replace
+		// the user-provided setting with the default specified by the admin
+		if ( isset( $defaults['allow_custom'] ) && isset( $defaults['default'] ) && 'disabled' == $defaults['allow_custom'] ) {
+			$user_visibility_levels[$d_field_id] = $defaults['default'];
+		}
+	}
+
+	$field_ids = array();
+	foreach( (array) $user_visibility_levels as $field_id => $field_visibility ) {
+		if ( in_array( $field_visibility, $levels ) ) {
+			$field_ids[] = $field_id;
+		}
+	}
+
+	// Never allow the fullname field to be excluded
+	if ( in_array( 1, $field_ids ) ) {
+		$key = array_search( 1, $field_ids );
+		unset( $field_ids[$key] );
+	}
+
+	return $field_ids;
+}
Index: /tags/1.9/bp-xprofile/bp-xprofile-loader.php
===================================================================
--- /tags/1.9/bp-xprofile/bp-xprofile-loader.php	(revision 7684)
+++ /tags/1.9/bp-xprofile/bp-xprofile-loader.php	(revision 7684)
@@ -0,0 +1,297 @@
+<?php
+
+/**
+ * BuddyPress XProfile Loader
+ *
+ * An extended profile component for users. This allows site admins to create
+ * groups of fields for users to enter information about themselves.
+ *
+ * @package BuddyPress
+ * @subpackage XProfileLoader
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+class BP_XProfile_Component extends BP_Component {
+	/**
+	 * Profile field types
+	 *
+	 * @since BuddyPress (1.5)
+	 * @var array
+	 */
+	public $field_types;
+
+	/**
+	 * The acceptable visibility levels for xprofile fields.
+	 *
+	 * @see bp_xprofile_get_visibility_levels()
+	 * @since BuddyPress (1.6)
+	 */
+	var $visibility_levels = array();
+
+	/**
+	 * Start the xprofile component creation process
+	 *
+	 * @since BuddyPress (1.5)
+	 */
+	function __construct() {
+		parent::start(
+			'xprofile',
+			__( 'Extended Profiles', 'buddypress' ),
+			BP_PLUGIN_DIR,
+			array(
+				'adminbar_myaccount_order' => 20
+			)
+		);
+	}
+
+	/**
+	 * Include files
+	 */
+	public function includes( $includes = array() ) {
+		$includes = array(
+			'cssjs',
+			'cache',
+			'actions',
+			'activity',
+			'screens',
+			'caps',
+			'classes',
+			'filters',
+			'template',
+			'buddybar',
+			'functions',
+		);
+
+		if ( is_admin() )
+			$includes[] = 'admin';
+
+		parent::includes( $includes );
+	}
+
+	/**
+	 * Setup globals
+	 *
+	 * The BP_XPROFILE_SLUG constant is deprecated, and only used here for
+	 * backwards compatibility.
+	 *
+	 * @since BuddyPress (1.5)
+	 */
+	public function setup_globals( $args = array() ) {
+		$bp = buddypress();
+
+		// Define a slug, if necessary
+		if ( !defined( 'BP_XPROFILE_SLUG' ) )
+			define( 'BP_XPROFILE_SLUG', 'profile' );
+
+		// Assign the base group and fullname field names to constants
+		// to use in SQL statements.
+		// Defined conditionally to accommodate unit tests
+		if ( ! defined( 'BP_XPROFILE_BASE_GROUP_NAME' ) ) {
+			define( 'BP_XPROFILE_BASE_GROUP_NAME', stripslashes( $bp->site_options['bp-xprofile-base-group-name'] ) );
+		}
+
+		if ( ! defined( 'BP_XPROFILE_FULLNAME_FIELD_NAME' ) ) {
+			define( 'BP_XPROFILE_FULLNAME_FIELD_NAME', stripslashes( $bp->site_options['bp-xprofile-fullname-field-name'] ) );
+		}
+
+		// Set the support field type ids
+		$this->field_types = apply_filters( 'xprofile_field_types', array(
+			'textbox',
+			'textarea',
+			'radio',
+			'checkbox',
+			'selectbox',
+			'multiselectbox',
+			'datebox'
+		) );
+
+		// Register the visibility levels. See bp_xprofile_get_visibility_levels() to filter
+		$this->visibility_levels = array(
+			'public' => array(
+				'id'	  => 'public',
+				'label' => __( 'Everyone', 'buddypress' )
+			),
+			'adminsonly' => array(
+				'id'	  => 'adminsonly',
+				'label' => __( 'Only Me', 'buddypress' )
+			),
+			'loggedin' => array(
+				'id'	  => 'loggedin',
+				'label' => __( 'All Members', 'buddypress' )
+			)
+		);
+
+		if ( bp_is_active( 'friends' ) ) {
+			$this->visibility_levels['friends'] = array(
+				'id'	=> 'friends',
+				'label'	=> __( 'My Friends', 'buddypress' )
+			);
+		}
+
+		// Tables
+		$global_tables = array(
+			'table_name_data'   => $bp->table_prefix . 'bp_xprofile_data',
+			'table_name_groups' => $bp->table_prefix . 'bp_xprofile_groups',
+			'table_name_fields' => $bp->table_prefix . 'bp_xprofile_fields',
+			'table_name_meta'   => $bp->table_prefix . 'bp_xprofile_meta',
+		);
+
+		$globals = array(
+			'slug'                  => BP_XPROFILE_SLUG,
+			'has_directory'         => false,
+			'notification_callback' => 'xprofile_format_notifications',
+			'global_tables'         => $global_tables
+		);
+
+		parent::setup_globals( $globals );
+	}
+
+	/**
+	 * Setup BuddyBar navigation
+	 *
+	 * @global BuddyPress $bp The one true BuddyPress instance
+	 */
+	public function setup_nav( $main_nav = array(), $sub_nav = array() ) {
+
+		$sub_nav = array();
+
+		// Add 'Profile' to the main navigation
+		$main_nav = array(
+			'name'                => __( 'Profile', 'buddypress' ),
+			'slug'                => $this->slug,
+			'position'            => 20,
+			'screen_function'     => 'xprofile_screen_display_profile',
+			'default_subnav_slug' => 'public',
+			'item_css_id'         => $this->id
+		);
+
+		// Determine user to use
+		if ( bp_displayed_user_domain() ) {
+			$user_domain = bp_displayed_user_domain();
+		} elseif ( bp_loggedin_user_domain() ) {
+			$user_domain = bp_loggedin_user_domain();
+		} else {
+			return;
+		}
+
+		$profile_link = trailingslashit( $user_domain . $this->slug );
+
+		// Add the subnav items to the profile
+		$sub_nav[] = array(
+			'name'            => __( 'View', 'buddypress' ),
+			'slug'            => 'public',
+			'parent_url'      => $profile_link,
+			'parent_slug'     => $this->slug,
+			'screen_function' => 'xprofile_screen_display_profile',
+			'position'        => 10
+		);
+
+		// Edit Profile
+		$sub_nav[] = array(
+			'name'            => __( 'Edit', 'buddypress' ),
+			'slug'            => 'edit',
+			'parent_url'      => $profile_link,
+			'parent_slug'     => $this->slug,
+			'screen_function' => 'xprofile_screen_edit_profile',
+			'position'        => 20,
+			'user_has_access' => bp_core_can_edit_settings()
+		);
+
+		// Change Avatar
+		$sub_nav[] = array(
+			'name'            => __( 'Change Avatar', 'buddypress' ),
+			'slug'            => 'change-avatar',
+			'parent_url'      => $profile_link,
+			'parent_slug'     => $this->slug,
+			'screen_function' => 'xprofile_screen_change_avatar',
+			'position'        => 30,
+			'user_has_access' => bp_core_can_edit_settings()
+		);
+
+		parent::setup_nav( $main_nav, $sub_nav );
+	}
+
+	/**
+	 * Set up the Toolbar
+	 */
+	public function setup_admin_bar( $wp_admin_nav = array() ) {
+		$bp = buddypress();
+
+		// Prevent debug notices
+		$wp_admin_nav = array();
+
+		// Menus for logged in user
+		if ( is_user_logged_in() ) {
+
+			// Profile link
+			$profile_link = trailingslashit( bp_loggedin_user_domain() . $this->slug );
+
+			// Add the "Profile" sub menu
+			$wp_admin_nav[] = array(
+				'parent' => $bp->my_account_menu_id,
+				'id'     => 'my-account-' . $this->id,
+				'title'  => __( 'Profile', 'buddypress' ),
+				'href'   => trailingslashit( $profile_link )
+			);
+
+			// View Profile
+			$wp_admin_nav[] = array(
+				'parent' => 'my-account-' . $this->id,
+				'id'     => 'my-account-' . $this->id . '-public',
+				'title'  => __( 'View', 'buddypress' ),
+				'href'   => trailingslashit( $profile_link . 'public' )
+			);
+
+			// Edit Profile
+			$wp_admin_nav[] = array(
+				'parent' => 'my-account-' . $this->id,
+				'id'     => 'my-account-' . $this->id . '-edit',
+				'title'  => __( 'Edit', 'buddypress' ),
+				'href'   => trailingslashit( $profile_link . 'edit' )
+			);
+
+			// Edit Profile
+			$wp_admin_nav[] = array(
+				'parent' => 'my-account-' . $this->id,
+				'id'     => 'my-account-' . $this->id . '-change-avatar',
+				'title'  => __( 'Change Avatar', 'buddypress' ),
+				'href'   => trailingslashit( $profile_link . 'change-avatar' )
+			);
+
+		}
+
+		parent::setup_admin_bar( $wp_admin_nav );
+	}
+
+	/**
+	 * Sets up the title for pages and <title>
+	 */
+	function setup_title() {
+		$bp = buddypress();
+
+		if ( bp_is_profile_component() ) {
+			if ( bp_is_my_profile() ) {
+				$bp->bp_options_title = __( 'My Profile', 'buddypress' );
+			} else {
+				$bp->bp_options_avatar = bp_core_fetch_avatar( array(
+					'item_id' => bp_displayed_user_id(),
+					'type'    => 'thumb',
+					'alt'	  => sprintf( __( 'Profile picture of %s', 'buddypress' ), bp_get_displayed_user_fullname() )
+				) );
+				$bp->bp_options_title = bp_get_displayed_user_fullname();
+			}
+		}
+
+		parent::setup_title();
+	}
+}
+
+function bp_setup_xprofile() {
+	$bp = buddypress();
+
+	if ( !isset( $bp->profile->id ) )
+		$bp->profile = new BP_XProfile_Component();
+}
+add_action( 'bp_setup_components', 'bp_setup_xprofile', 6 );
Index: /tags/1.9/bp-xprofile/bp-xprofile-screens.php
===================================================================
--- /tags/1.9/bp-xprofile/bp-xprofile-screens.php	(revision 7684)
+++ /tags/1.9/bp-xprofile/bp-xprofile-screens.php	(revision 7684)
@@ -0,0 +1,210 @@
+<?php
+
+/**
+ * BuddyPress XProfile Screens
+ *
+ * Screen functions are the controllers of BuddyPress. They will execute when
+ * their specific URL is caught. They will first save or manipulate data using
+ * business functions, then pass on the user to a template file.
+ *
+ * @package BuddyPress
+ * @subpackage XProfileScreens
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+/**
+ * Handles the display of the profile page by loading the correct template file.
+ *
+ * @package BuddyPress XProfile
+ * @uses bp_core_load_template() Looks for and loads a template file within the current member theme (folder/filename)
+ */
+function xprofile_screen_display_profile() {
+	$new = isset( $_GET['new'] ) ? $_GET['new'] : '';
+
+	do_action( 'xprofile_screen_display_profile', $new );
+	bp_core_load_template( apply_filters( 'xprofile_template_display_profile', 'members/single/home' ) );
+}
+
+/**
+ * Handles the display of the profile edit page by loading the correct template file.
+ * Also checks to make sure this can only be accessed for the logged in users profile.
+ *
+ * @package BuddyPress XProfile
+ * @uses bp_is_my_profile() Checks to make sure the current user being viewed equals the logged in user
+ * @uses bp_core_load_template() Looks for and loads a template file within the current member theme (folder/filename)
+ */
+function xprofile_screen_edit_profile() {
+
+	if ( !bp_is_my_profile() && !bp_current_user_can( 'bp_moderate' ) )
+		return false;
+
+	$bp = buddypress();
+
+	// Make sure a group is set.
+	if ( !bp_action_variable( 1 ) )
+		bp_core_redirect( trailingslashit( bp_displayed_user_domain() . $bp->profile->slug . '/edit/group/1' ) );
+
+	// Check the field group exists
+	if ( !bp_is_action_variable( 'group' ) || !xprofile_get_field_group( bp_action_variable( 1 ) ) ) {
+		bp_do_404();
+		return;
+	}
+
+	// No errors
+	$errors = false;
+
+	// Check to see if any new information has been submitted
+	if ( isset( $_POST['field_ids'] ) ) {
+
+		// Check the nonce
+		check_admin_referer( 'bp_xprofile_edit' );
+
+		// Check we have field ID's
+		if ( empty( $_POST['field_ids'] ) )
+			bp_core_redirect( trailingslashit( bp_displayed_user_domain() . $bp->profile->slug . '/edit/group/' . bp_action_variable( 1 ) ) );
+
+		// Explode the posted field IDs into an array so we know which
+		// fields have been submitted
+		$posted_field_ids = explode( ',', $_POST['field_ids'] );
+		$is_required      = array();
+
+		// Loop through the posted fields formatting any datebox values
+		// then validate the field
+		foreach ( (array) $posted_field_ids as $field_id ) {
+			if ( !isset( $_POST['field_' . $field_id] ) ) {
+
+				if ( !empty( $_POST['field_' . $field_id . '_day'] ) && !empty( $_POST['field_' . $field_id . '_month'] ) && !empty( $_POST['field_' . $field_id . '_year'] ) ) {
+					// Concatenate the values
+					$date_value =   $_POST['field_' . $field_id . '_day'] . ' ' . $_POST['field_' . $field_id . '_month'] . ' ' . $_POST['field_' . $field_id . '_year'];
+
+					// Turn the concatenated value into a timestamp
+					$_POST['field_' . $field_id] = date( 'Y-m-d H:i:s', strtotime( $date_value ) );
+				}
+
+			}
+
+			$is_required[$field_id] = xprofile_check_is_required_field( $field_id );
+			if ( $is_required[$field_id] && empty( $_POST['field_' . $field_id] ) ) {
+				$errors = true;
+			}
+		}
+
+		// There are errors
+		if ( !empty( $errors ) ) {
+			bp_core_add_message( __( 'Please make sure you fill in all required fields in this profile field group before saving.', 'buddypress' ), 'error' );
+
+		// No errors
+		} else {
+
+			// Reset the errors var
+			$errors = false;
+
+			// Now we've checked for required fields, lets save the values.
+			foreach ( (array) $posted_field_ids as $field_id ) {
+
+				// Certain types of fields (checkboxes, multiselects) may come through empty. Save them as an empty array so that they don't get overwritten by the default on the next edit.
+				if ( empty( $_POST['field_' . $field_id] ) ) {
+					$value = array();
+				} else {
+					$value = $_POST['field_' . $field_id];
+				}
+
+				if ( !xprofile_set_field_data( $field_id, bp_displayed_user_id(), $value, $is_required[$field_id] ) ) {
+					$errors = true;
+				} else {
+					do_action( 'xprofile_profile_field_data_updated', $field_id, $value );
+				}
+
+				// Save the visibility level
+				$visibility_level = !empty( $_POST['field_' . $field_id . '_visibility'] ) ? $_POST['field_' . $field_id . '_visibility'] : 'public';
+				xprofile_set_field_visibility_level( $field_id, bp_displayed_user_id(), $visibility_level );
+			}
+
+			do_action( 'xprofile_updated_profile', bp_displayed_user_id(), $posted_field_ids, $errors );
+
+			// Set the feedback messages
+			if ( !empty( $errors ) ) {
+				bp_core_add_message( __( 'There was a problem updating some of your profile information, please try again.', 'buddypress' ), 'error' );
+			} else {
+				bp_core_add_message( __( 'Changes saved.', 'buddypress' ) );
+			}
+
+			// Redirect back to the edit screen to display the updates and message
+			bp_core_redirect( trailingslashit( bp_displayed_user_domain() . $bp->profile->slug . '/edit/group/' . bp_action_variable( 1 ) ) );
+		}
+	}
+
+	do_action( 'xprofile_screen_edit_profile' );
+	bp_core_load_template( apply_filters( 'xprofile_template_edit_profile', 'members/single/home' ) );
+}
+
+/**
+ * Handles the uploading and cropping of a user avatar. Displays the change avatar page.
+ *
+ * @package BuddyPress XProfile
+ * @uses bp_is_my_profile() Checks to make sure the current user being viewed equals the logged in user
+ * @uses bp_core_load_template() Looks for and loads a template file within the current member theme (folder/filename)
+ */
+function xprofile_screen_change_avatar() {
+
+	// Bail if not the correct screen
+	if ( !bp_is_my_profile() && !bp_current_user_can( 'bp_moderate' ) )
+		return false;
+
+	// Bail if there are action variables
+	if ( bp_action_variables() ) {
+		bp_do_404();
+		return;
+	}
+
+	$bp = buddypress();
+
+	if ( ! isset( $bp->avatar_admin ) )
+		$bp->avatar_admin = new stdClass();
+
+	$bp->avatar_admin->step = 'upload-image';
+
+	if ( !empty( $_FILES ) ) {
+
+		// Check the nonce
+		check_admin_referer( 'bp_avatar_upload' );
+
+		// Pass the file to the avatar upload handler
+		if ( bp_core_avatar_handle_upload( $_FILES, 'xprofile_avatar_upload_dir' ) ) {
+			$bp->avatar_admin->step = 'crop-image';
+
+			// Make sure we include the jQuery jCrop file for image cropping
+			add_action( 'wp_print_scripts', 'bp_core_add_jquery_cropper' );
+		}
+	}
+
+	// If the image cropping is done, crop the image and save a full/thumb version
+	if ( isset( $_POST['avatar-crop-submit'] ) ) {
+
+		// Check the nonce
+		check_admin_referer( 'bp_avatar_cropstore' );
+
+		$args = array(
+			'item_id'       => bp_displayed_user_id(),
+			'original_file' => $_POST['image_src'],
+			'crop_x'        => $_POST['x'],
+			'crop_y'        => $_POST['y'],
+			'crop_w'        => $_POST['w'],
+			'crop_h'        => $_POST['h']
+		);
+
+		if ( ! bp_core_avatar_handle_crop( $args ) ) {
+			bp_core_add_message( __( 'There was a problem cropping your avatar.', 'buddypress' ), 'error' );
+		} else {
+			do_action( 'xprofile_avatar_uploaded' );
+			bp_core_add_message( __( 'Your new avatar was uploaded successfully.', 'buddypress' ) );
+			bp_core_redirect( bp_loggedin_user_domain() );
+		}
+	}
+
+	do_action( 'xprofile_screen_change_avatar' );
+
+	bp_core_load_template( apply_filters( 'xprofile_template_change_avatar', 'members/single/home' ) );
+}
Index: /tags/1.9/bp-xprofile/bp-xprofile-template.php
===================================================================
--- /tags/1.9/bp-xprofile/bp-xprofile-template.php	(revision 7684)
+++ /tags/1.9/bp-xprofile/bp-xprofile-template.php	(revision 7684)
@@ -0,0 +1,951 @@
+<?php
+
+/**
+ * BuddyPress XProfile Template Tags
+ *
+ * @package BuddyPress
+ * @subpackage XProfileTemplate
+ */
+
+// Exit if accessed directly
+if ( !defined( 'ABSPATH' ) ) exit;
+
+class BP_XProfile_Data_Template {
+	var $current_group = -1;
+	var $group_count;
+	var $groups;
+	var $group;
+
+	var $current_field = -1;
+	var $field_count;
+	var $field_has_data;
+	var $field;
+
+	var $in_the_loop;
+	var $user_id;
+
+	function __construct( $user_id, $profile_group_id, $hide_empty_groups = false, $fetch_fields = false, $fetch_field_data = false, $exclude_groups = false, $exclude_fields = false, $hide_empty_fields = false, $fetch_visibility_level = false ) {
+		$this->groups = BP_XProfile_Group::get( array(
+			'profile_group_id'    => $profile_group_id,
+			'user_id'             => $user_id,
+			'hide_empty_groups'   => $hide_empty_groups,
+			'hide_empty_fields'   => $hide_empty_fields,
+			'fetch_fields'        => $fetch_fields,
+			'fetch_field_data'    => $fetch_field_data,
+			'fetch_visibility_level' => $fetch_visibility_level,
+			'exclude_groups'      => $exclude_groups,
+			'exclude_fields'      => $exclude_fields
+		) );
+
+		$this->group_count = count($this->groups);
+		$this->user_id = $user_id;
+	}
+
+	function has_groups() {
+		if ( $this->group_count )
+			return true;
+
+		return false;
+	}
+
+	function next_group() {
+		$this->current_group++;
+
+		$this->group         = $this->groups[$this->current_group];
+		$this->group->fields = apply_filters( 'xprofile_group_fields', $this->group->fields, $this->group->id );
+		$this->field_count   = count( $this->group->fields );
+
+		return $this->group;
+	}
+
+	function rewind_groups() {
+		$this->current_group = -1;
+		if ( $this->group_count > 0 ) {
+			$this->group = $this->groups[0];
+		}
+	}
+
+	function profile_groups() {
+		if ( $this->current_group + 1 < $this->group_count ) {
+			return true;
+		} elseif ( $this->current_group + 1 == $this->group_count ) {
+			do_action('xprofile_template_loop_end');
+			// Do some cleaning up after the loop
+			$this->rewind_groups();
+		}
+
+		$this->in_the_loop = false;
+		return false;
+	}
+
+	function the_profile_group() {
+		global $group;
+
+		$this->in_the_loop = true;
+		$group = $this->next_group();
+
+		if ( 0 == $this->current_group ) // loop has just started
+			do_action('xprofile_template_loop_start');
+	}
+
+	/**** FIELDS ****/
+
+	function next_field() {
+		$this->current_field++;
+
+		$this->field = $this->group->fields[$this->current_field];
+		return $this->field;
+	}
+
+	function rewind_fields() {
+		$this->current_field = -1;
+		if ( $this->field_count > 0 ) {
+			$this->field = $this->group->fields[0];
+		}
+	}
+
+	function has_fields() {
+		$has_data = false;
+
+		for ( $i = 0, $count = count( $this->group->fields ); $i < $count; ++$i ) {
+			$field = &$this->group->fields[$i];
+
+			if ( !empty( $field->data ) && $field->data->value != null ) {
+				$has_data = true;
+			}
+		}
+
+		if ( $has_data )
+			return true;
+
+		return false;
+	}
+
+	function profile_fields() {
+		if ( $this->current_field + 1 < $this->field_count ) {
+			return true;
+		} elseif ( $this->current_field + 1 == $this->field_count ) {
+			// Do some cleaning up after the loop
+			$this->rewind_fields();
+		}
+
+		return false;
+	}
+
+	function the_profile_field() {
+		global $field;
+
+		$field = $this->next_field();
+
+		$value = !empty( $field->data ) && !empty( $field->data->value ) ? maybe_unserialize( $field->data->value ) : false;
+
+		if ( !empty( $value ) ) {
+			$this->field_has_data = true;
+		} else {
+			$this->field_has_data = false;
+		}
+	}
+}
+
+function bp_has_profile( $args = '' ) {
+	global $profile_template;
+
+	// Only show empty fields if we're on the Dashboard, or we're on a user's profile edit page,
+	// or this is a registration page
+	$hide_empty_fields_default = ( !is_network_admin() && !is_admin() && !bp_is_user_profile_edit() && !bp_is_register_page() );
+
+	// We only need to fetch visibility levels when viewing your own profile
+	if ( bp_is_my_profile() || bp_current_user_can( 'bp_moderate' ) || bp_is_register_page() ) {
+		$fetch_visibility_level_default = true;
+	} else {
+		$fetch_visibility_level_default = false;
+	}
+
+	$defaults = array(
+		'user_id'             => bp_displayed_user_id(),
+		'profile_group_id'    => false,
+		'hide_empty_groups'   => true,
+		'hide_empty_fields'   => $hide_empty_fields_default,
+		'fetch_fields'        => true,
+		'fetch_field_data'    => true,
+		'fetch_visibility_level' => $fetch_visibility_level_default,
+		'exclude_groups'      => false, // Comma-separated list of profile field group IDs to exclude
+		'exclude_fields'      => false  // Comma-separated list of profile field IDs to exclude
+	);
+
+	$r = wp_parse_args( $args, $defaults );
+	extract( $r, EXTR_SKIP );
+
+	$profile_template = new BP_XProfile_Data_Template( $user_id, $profile_group_id, $hide_empty_groups, $fetch_fields, $fetch_field_data, $exclude_groups, $exclude_fields, $hide_empty_fields, $fetch_visibility_level );
+	return apply_filters( 'bp_has_profile', $profile_template->has_groups(), $profile_template );
+}
+
+function bp_profile_groups() {
+	global $profile_template;
+	return $profile_template->profile_groups();
+}
+
+function bp_the_profile_group() {
+	global $profile_template;
+	return $profile_template->the_profile_group();
+}
+
+function bp_profile_group_has_fields() {
+	global $profile_template;
+	return $profile_template->has_fields();
+}
+
+function bp_field_css_class( $class = false ) {
+	echo bp_get_field_css_class( $class );
+}
+	function bp_get_field_css_class( $class = false ) {
+		global $profile_template;
+
+		$css_classes = array();
+
+		if ( $class )
+			$css_classes[] = sanitize_title( esc_attr( $class ) );
+
+		// Set a class with the field ID
+		$css_classes[] = 'field_' . $profile_template->field->id;
+
+		// Set a class with the field name (sanitized)
+		$css_classes[] = 'field_' . sanitize_title( $profile_template->field->name );
+
+		if ( $profile_template->current_field % 2 == 1 )
+			$css_classes[] = 'alt';
+
+		$css_classes = apply_filters_ref_array( 'bp_field_css_classes', array( &$css_classes ) );
+
+		return apply_filters( 'bp_get_field_css_class', ' class="' . implode( ' ', $css_classes ) . '"' );
+	}
+
+function bp_field_has_data() {
+	global $profile_template;
+	return $profile_template->field_has_data;
+}
+
+function bp_field_has_public_data() {
+	global $profile_template;
+
+	if ( $profile_template->field_has_data )
+		return true;
+
+	return false;
+}
+
+function bp_the_profile_group_id() {
+	echo bp_get_the_profile_group_id();
+}
+	function bp_get_the_profile_group_id() {
+		global $group;
+		return apply_filters( 'bp_get_the_profile_group_id', $group->id );
+	}
+
+function bp_the_profile_group_name() {
+	echo bp_get_the_profile_group_name();
+}
+	function bp_get_the_profile_group_name() {
+		global $group;
+		return apply_filters( 'bp_get_the_profile_group_name', $group->name );
+	}
+
+function bp_the_profile_group_slug() {
+	echo bp_get_the_profile_group_slug();
+}
+	function bp_get_the_profile_group_slug() {
+		global $group;
+		return apply_filters( 'bp_get_the_profile_group_slug', sanitize_title( $group->name ) );
+	}
+
+function bp_the_profile_group_description() {
+	echo bp_get_the_profile_group_description();
+}
+	function bp_get_the_profile_group_description() {
+		global $group;
+		echo apply_filters( 'bp_get_the_profile_group_description', $group->description );
+	}
+
+function bp_the_profile_group_edit_form_action() {
+	echo bp_get_the_profile_group_edit_form_action();
+}
+	function bp_get_the_profile_group_edit_form_action() {
+		global $bp, $group;
+
+		return apply_filters( 'bp_get_the_profile_group_edit_form_action', trailingslashit( bp_displayed_user_domain() . $bp->profile->slug . '/edit/group/' . $group->id ) );
+	}
+
+function bp_the_profile_group_field_ids() {
+	echo bp_get_the_profile_group_field_ids();
+}
+	function bp_get_the_profile_group_field_ids() {
+		global $group;
+
+		$field_ids = '';
+		foreach ( (array) $group->fields as $field )
+			$field_ids .= $field->id . ',';
+
+		return substr( $field_ids, 0, -1 );
+	}
+
+function bp_profile_fields() {
+	global $profile_template;
+	return $profile_template->profile_fields();
+}
+
+function bp_the_profile_field() {
+	global $profile_template;
+	return $profile_template->the_profile_field();
+}
+
+function bp_the_profile_field_id() {
+	echo bp_get_the_profile_field_id();
+}
+	function bp_get_the_profile_field_id() {
+		global $field;
+		return apply_filters( 'bp_get_the_profile_field_id', $field->id );
+	}
+
+function bp_the_profile_field_name() {
+	echo bp_get_the_profile_field_name();
+}
+	function bp_get_the_profile_field_name() {
+		global $field;
+
+		return apply_filters( 'bp_get_the_profile_field_name', $field->name );
+	}
+
+function bp_the_profile_field_value() {
+	echo bp_get_the_profile_field_value();
+}
+	function bp_get_the_profile_field_value() {
+		global $field;
+
+		$field->data->value = bp_unserialize_profile_field( $field->data->value );
+
+		return apply_filters( 'bp_get_the_profile_field_value', $field->data->value, $field->type, $field->id );
+	}
+
+function bp_the_profile_field_edit_value() {
+	echo bp_get_the_profile_field_edit_value();
+}
+	function bp_get_the_profile_field_edit_value() {
+		global $field;
+
+		/**
+		 * Check to see if the posted value is different, if it is re-display this
+		 * value as long as it's not empty and a required field.
+		 */
+		if ( !isset( $field->data ) ) {
+			$field->data = new stdClass;
+		}
+
+		if ( !isset( $field->data->value ) ) {
+			$field->data->value = '';
+		}
+
+		if ( isset( $_POST['field_' . $field->id] ) && $field->data->value != $_POST['field_' . $field->id] ) {
+			if ( !empty( $_POST['field_' . $field->id] ) )
+				$field->data->value = $_POST['field_' . $field->id];
+			else
+				$field->data->value = '';
+		}
+
+		$field_value = isset( $field->data->value ) ? bp_unserialize_profile_field( $field->data->value ) : '';
+
+		return apply_filters( 'bp_get_the_profile_field_edit_value', $field_value, $field->type, $field->id );
+	}
+
+function bp_the_profile_field_type() {
+	echo bp_get_the_profile_field_type();
+}
+	function bp_get_the_profile_field_type() {
+		global $field;
+
+		return apply_filters( 'bp_the_profile_field_type', $field->type );
+	}
+
+function bp_the_profile_field_description() {
+	echo bp_get_the_profile_field_description();
+}
+	function bp_get_the_profile_field_description() {
+		global $field;
+
+		return apply_filters( 'bp_get_the_profile_field_description', $field->description );
+	}
+
+function bp_the_profile_field_input_name() {
+	echo bp_get_the_profile_field_input_name();
+}
+	function bp_get_the_profile_field_input_name() {
+		global $field;
+
+		$array_box = false;
+		if ( 'multiselectbox' == $field->type )
+			$array_box = '[]';
+
+		return apply_filters( 'bp_get_the_profile_field_input_name', 'field_' . $field->id . $array_box );
+	}
+
+/**
+ * Returns the action name for any signup errors related to this profile field
+ *
+ * In the registration templates, signup errors are pulled from the global
+ * object and rendered at actions that look like 'bp_field_12_errors'. This
+ * function allows the action name to be easily concatenated and called in the
+ * following fashion:
+ *   do_action( bp_get_the_profile_field_errors_action() );
+ *
+ * @since BuddyPress (1.8)
+ * @return string The _errors action name corresponding to this profile field
+ */
+function bp_get_the_profile_field_errors_action() {
+	global $field;
+	return 'bp_field_' . $field->id . '_errors';
+}
+
+/**
+ * bp_the_profile_field_options()
+ *
+ * Displays field options HTML for field types of 'selectbox', 'multiselectbox',
+ * 'radio', 'checkbox', and 'datebox'.
+ *
+ * @package BuddyPress Xprofile
+ * @since BuddyPress (1.1)
+ *
+ * @uses bp_get_the_profile_field_options()
+ *
+ * @param array $args Specify type for datebox. Allowed 'day', 'month', 'year'.
+ */
+function bp_the_profile_field_options( $args = '' ) {
+	echo bp_get_the_profile_field_options( $args );
+}
+	/**
+	 * bp_get_the_profile_field_options()
+	 *
+	 * Retrieves field options HTML for field types of 'selectbox', 'multiselectbox',
+	 * 'radio', 'checkbox', and 'datebox'.
+	 *
+	 * @package BuddyPress Xprofile
+	 * @since BuddyPress (1.1)
+	 *
+	 * @uses BP_XProfile_Field::get_children()
+	 * @uses BP_XProfile_ProfileData::get_value_byid()
+	 *
+	 * @param array $args Specify type for datebox. Allowed 'day', 'month', 'year'.
+	 */
+	function bp_get_the_profile_field_options( $args = '' ) {
+		global $field;
+
+		$defaults = array(
+			'type' => false,
+		);
+
+		$r = wp_parse_args( $args, $defaults );
+		extract( $r, EXTR_SKIP );
+
+		// In some cases, the $field global is not an instantiation of the BP_XProfile_Field
+		// class. However, we have to make sure that all data originally in $field gets
+		// merged back in, after reinstantiation.
+		if ( !method_exists( $field, 'get_children' ) ) {
+			$field_obj = new BP_XProfile_Field( $field->id );
+
+			foreach( $field as $field_prop => $field_prop_value ) {
+				if ( !isset( $field_obj->{$field_prop} ) ) {
+					$field_obj->{$field_prop} = $field_prop_value;
+				}
+			}
+
+			$field = $field_obj;
+		}
+
+		$options = $field->get_children();
+
+		// Setup some defaults
+		$html     = '';
+		$selected = '';
+
+		switch ( $field->type ) {
+			case 'selectbox':
+
+				$html .= '<option value="">' . /* translators: no option picked in select box */ __( '----', 'buddypress' ) . '</option>';
+
+				$original_option_values = '';
+				$original_option_values = maybe_unserialize( BP_XProfile_ProfileData::get_value_byid( $field->id ) );
+
+				if ( empty( $original_option_values ) && !empty( $_POST['field_' . $field->id] ) ) {
+					$original_option_values = $_POST['field_' . $field->id];
+				}
+
+				$option_values = (array) $original_option_values;
+
+				for ( $k = 0, $count = count( $options ); $k < $count; ++$k ) {
+
+					// Check for updated posted values, but errors preventing them from being saved first time
+					foreach( $option_values as $i => $option_value ) {
+						if ( isset( $_POST['field_' . $field->id] ) && $_POST['field_' . $field->id] != $option_value ) {
+							if ( !empty( $_POST['field_' . $field->id] ) ) {
+								$option_values[$i] = $_POST['field_' . $field->id];
+							}
+						}
+					}
+
+					$selected = '';
+
+					// Run the allowed option name through the before_save filter, so we'll be sure to get a match
+					$allowed_options = xprofile_sanitize_data_value_before_save( $options[$k]->name, false, false );
+
+					// First, check to see whether the user-entered value matches
+					if ( in_array( $allowed_options, (array) $option_values ) ) {
+						$selected = ' selected="selected"';
+					}
+
+					// Then, if the user has not provided a value, check for defaults
+					if ( !is_array( $original_option_values ) && empty( $option_values ) && $options[$k]->is_default_option ) {
+						$selected = ' selected="selected"';
+					}
+
+					$html .= apply_filters( 'bp_get_the_profile_field_options_select', '<option' . $selected . ' value="' . esc_attr( stripslashes( $options[$k]->name ) ) . '">' . esc_attr( stripslashes( $options[$k]->name ) ) . '</option>', $options[$k], $field->id, $selected, $k );
+				}
+				break;
+
+			case 'multiselectbox':
+				$original_option_values = '';
+				$original_option_values = maybe_unserialize( BP_XProfile_ProfileData::get_value_byid( $field->id ) );
+
+				if ( empty( $original_option_values ) && !empty( $_POST['field_' . $field->id] ) ) {
+					$original_option_values = $_POST['field_' . $field->id];
+				}
+
+				$option_values = (array) $original_option_values;
+
+				for ( $k = 0, $count = count( $options ); $k < $count; ++$k ) {
+
+					// Check for updated posted values, but errors preventing them from being saved first time
+					foreach( $option_values as $i => $option_value ) {
+						if ( isset( $_POST['field_' . $field->id] ) && $_POST['field_' . $field->id][$i] != $option_value ) {
+							if ( !empty( $_POST['field_' . $field->id][$i] ) ) {
+								$option_values[] = $_POST['field_' . $field->id][$i];
+							}
+						}
+					}
+					$selected = '';
+
+					// Run the allowed option name through the before_save filter, so we'll be sure to get a match
+					$allowed_options = xprofile_sanitize_data_value_before_save( $options[$k]->name, false, false );
+
+					// First, check to see whether the user-entered value matches
+					if ( in_array( $allowed_options, (array) $option_values ) ) {
+						$selected = ' selected="selected"';
+					}
+
+					// Then, if the user has not provided a value, check for defaults
+					if ( !is_array( $original_option_values ) && empty( $option_values ) && !empty( $options[$k]->is_default_option ) ) {
+						$selected = ' selected="selected"';
+					}
+
+					$html .= apply_filters( 'bp_get_the_profile_field_options_multiselect', '<option' . $selected . ' value="' . esc_attr( stripslashes( $options[$k]->name ) ) . '">' . esc_attr( stripslashes( $options[$k]->name ) ) . '</option>', $options[$k], $field->id, $selected, $k );
+				}
+				break;
+
+			case 'radio':
+				$html .= '<div id="field_' . $field->id . '">';
+				$option_value = BP_XProfile_ProfileData::get_value_byid( $field->id );
+
+				for ( $k = 0, $count = count( $options ); $k < $count; ++$k ) {
+
+					// Check for updated posted values, but errors preventing them from being saved first time
+					if ( isset( $_POST['field_' . $field->id] ) && $option_value != $_POST['field_' . $field->id] ) {
+						if ( !empty( $_POST['field_' . $field->id] ) ) {
+							$option_value = $_POST['field_' . $field->id];
+						}
+					}
+
+					// Run the allowed option name through the before_save
+					// filter, so we'll be sure to get a match
+					$allowed_options = xprofile_sanitize_data_value_before_save( $options[$k]->name, false, false );
+					$selected        = '';
+
+					// @todo $value is never created
+					if ( $option_value == $allowed_options || !empty( $value ) && $value == $allowed_options || ( empty( $option_value ) && !empty( $options[$k]->is_default_option ) ) )
+						$selected = ' checked="checked"';
+
+					$html .= apply_filters( 'bp_get_the_profile_field_options_radio', '<label><input' . $selected . ' type="radio" name="field_' . $field->id . '" id="option_' . $options[$k]->id . '" value="' . esc_attr( stripslashes( $options[$k]->name ) ) . '"> ' . esc_attr( stripslashes( $options[$k]->name ) ) . '</label>', $options[$k], $field->id, $selected, $k );
+				}
+
+				$html .= '</div>';
+				break;
+
+			case 'checkbox':
+				$option_values = BP_XProfile_ProfileData::get_value_byid( $field->id );
+				$option_values = (array) maybe_unserialize( $option_values );
+
+				// Check for updated posted values, but errors preventing them from being saved first time
+				if ( isset( $_POST['field_' . $field->id] ) && $option_values != maybe_serialize( $_POST['field_' . $field->id] ) ) {
+					if ( !empty( $_POST['field_' . $field->id] ) )
+						$option_values = $_POST['field_' . $field->id];
+				}
+
+				for ( $k = 0, $count = count( $options ); $k < $count; ++$k ) {
+					$selected = '';
+
+					// First, check to see whether the user's saved values
+					// match the option
+					for ( $j = 0, $count_values = count( $option_values ); $j < $count_values; ++$j ) {
+
+						// Run the allowed option name through the
+						// before_save filter, so we'll be sure to get a match
+						$allowed_options = xprofile_sanitize_data_value_before_save( $options[$k]->name, false, false );
+
+						// @todo $value is never created
+						if ( $option_values[$j] == $allowed_options || @in_array( $allowed_options, $option_values ) ) {
+							$selected = ' checked="checked"';
+							break;
+						}
+					}
+
+					// If the user has not yet supplied a value for this field,
+					// check to see whether there is a default value available
+					if ( !is_array( $option_values ) && empty( $option_values ) && empty( $selected ) && !empty( $options[$k]->is_default_option ) ) {
+						$selected = ' checked="checked"';
+					}
+
+					$html .= apply_filters( 'bp_get_the_profile_field_options_checkbox', '<label><input' . $selected . ' type="checkbox" name="field_' . $field->id . '[]" id="field_' . $options[$k]->id . '_' . $k . '" value="' . esc_attr( stripslashes( $options[$k]->name ) ) . '"> ' . esc_attr( stripslashes( $options[$k]->name ) ) . '</label>', $options[$k], $field->id, $selected, $k );
+				}
+				break;
+
+			case 'datebox':
+				$date = BP_XProfile_ProfileData::get_value_byid( $field->id );
+
+				// Set day, month, year defaults
+				$day   = '';
+				$month = '';
+				$year  = '';
+
+				if ( !empty( $date ) ) {
+
+					// If Unix timestamp
+					if ( is_numeric( $date ) ) {
+						$day   = date( 'j', $date );
+						$month = date( 'F', $date );
+						$year  = date( 'Y', $date );
+
+					// If MySQL timestamp
+					} else {
+						$day   = mysql2date( 'j', $date );
+						$month = mysql2date( 'F', $date, false ); // Not localized, so that selected() works below
+						$year  = mysql2date( 'Y', $date );
+					}
+				}
+
+				// Check for updated posted values, and errors preventing
+				// them from being saved first time.
+				if ( !empty( $_POST['field_' . $field->id . '_day'] ) ) {
+					if ( $day != $_POST['field_' . $field->id . '_day'] ) {
+						$day = $_POST['field_' . $field->id . '_day'];
+					}
+				}
+
+				if ( !empty( $_POST['field_' . $field->id . '_month'] ) ) {
+					if ( $month != $_POST['field_' . $field->id . '_month'] ) {
+						$month = $_POST['field_' . $field->id . '_month'];
+					}
+				}
+
+				if ( !empty( $_POST['field_' . $field->id . '_year'] ) ) {
+					if ( $year != date( "j", $_POST['field_' . $field->id . '_year'] ) ) {
+						$year = $_POST['field_' . $field->id . '_year'];
+					}
+				}
+
+				// $type will be passed by calling function when needed
+				switch ( $type ) {
+					case 'day':
+						$html .= '<option value=""' . selected( $day, '', false ) . '>--</option>';
+
+						for ( $i = 1; $i < 32; ++$i ) {
+							$html .= '<option value="' . $i .'"' . selected( $day, $i, false ) . '>' . $i . '</option>';
+						}
+						break;
+
+					case 'month':
+						$eng_months = array( 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December' );
+
+						$months = array(
+							__( 'January', 'buddypress' ),
+							__( 'February', 'buddypress' ),
+							__( 'March', 'buddypress' ),
+							__( 'April', 'buddypress' ),
+							__( 'May', 'buddypress' ),
+							__( 'June', 'buddypress' ),
+							__( 'July', 'buddypress' ),
+							__( 'August', 'buddypress' ),
+							__( 'September', 'buddypress' ),
+							__( 'October', 'buddypress' ),
+							__( 'November', 'buddypress' ),
+							__( 'December', 'buddypress' )
+						);
+
+						$html .= '<option value=""' . selected( $month, '', false ) . '>------</option>';
+
+						for ( $i = 0; $i < 12; ++$i ) {
+							$html .= '<option value="' . $eng_months[$i] . '"' . selected( $month, $eng_months[$i], false ) . '>' . $months[$i] . '</option>';
+						}
+						break;
+
+					case 'year':
+						$html .= '<option value=""' . selected( $year, '', false ) . '>----</option>';
+
+						for ( $i = 2037; $i > 1901; $i-- ) {
+							$html .= '<option value="' . $i .'"' . selected( $year, $i, false ) . '>' . $i . '</option>';
+						}
+						break;
+				}
+
+				$html = apply_filters( 'bp_get_the_profile_field_datebox', $html, $type, $day, $month, $year, $field->id, $date );
+
+				break;
+		}
+
+		return $html;
+	}
+
+function bp_the_profile_field_is_required() {
+	echo bp_get_the_profile_field_is_required();
+}
+	function bp_get_the_profile_field_is_required() {
+		global $field;
+
+		// Define locale variable(s)
+		$retval = false;
+
+		// Super admins can skip required check
+		if ( bp_current_user_can( 'bp_moderate' ) && !is_admin() )
+			$retval = false;
+
+		// All other users will use the field's setting
+		elseif ( isset( $field->is_required ) )
+			$retval = $field->is_required;
+
+		return apply_filters( 'bp_get_the_profile_field_is_required', (bool) $retval );
+	}
+
+/**
+ * Echo the visibility level of this field
+ */
+function bp_the_profile_field_visibility_level() {
+	echo bp_get_the_profile_field_visibility_level();
+}
+	/**
+	 * Return the visibility level of this field
+	 */
+	function bp_get_the_profile_field_visibility_level() {
+		global $field;
+
+		// On the registration page, values stored in POST should take
+		// precedence over default visibility, so that submitted values
+		// are not lost on failure
+		if ( bp_is_register_page() && ! empty( $_POST['field_' . $field->id . '_visibility'] ) ) {
+			$retval = esc_attr( $_POST['field_' . $field->id . '_visibility'] );
+		} else {
+			$retval = ! empty( $field->visibility_level ) ? $field->visibility_level : 'public';
+		}
+
+		return apply_filters( 'bp_get_the_profile_field_visibility_level', $retval );
+	}
+
+/**
+ * Echo the visibility level label of this field
+ */
+function bp_the_profile_field_visibility_level_label() {
+	echo bp_get_the_profile_field_visibility_level_label();
+}
+	/**
+	 * Return the visibility level label of this field
+	 */
+	function bp_get_the_profile_field_visibility_level_label() {
+		global $field;
+
+		// On the registration page, values stored in POST should take
+		// precedence over default visibility, so that submitted values
+		// are not lost on failure
+		if ( bp_is_register_page() && ! empty( $_POST['field_' . $field->id . '_visibility'] ) ) {
+			$level = esc_html( $_POST['field_' . $field->id . '_visibility'] );
+		} else {
+			$level = ! empty( $field->visibility_level ) ? $field->visibility_level : 'public';
+		}
+
+		$fields = bp_xprofile_get_visibility_levels();
+
+		return apply_filters( 'bp_get_the_profile_field_visibility_level_label', $fields[$level]['label'] );
+	}
+
+
+function bp_unserialize_profile_field( $value ) {
+	if ( is_serialized($value) ) {
+		$field_value = maybe_unserialize($value);
+		$field_value = implode( ', ', $field_value );
+		return $field_value;
+	}
+
+	return $value;
+}
+
+function bp_profile_field_data( $args = '' ) {
+	echo bp_get_profile_field_data( $args );
+}
+	function bp_get_profile_field_data( $args = '' ) {
+
+		$defaults = array(
+			'field'   => false, // Field name or ID.
+			'user_id' => bp_displayed_user_id()
+		);
+
+		$r = wp_parse_args( $args, $defaults );
+		extract( $r, EXTR_SKIP );
+
+		return apply_filters( 'bp_get_profile_field_data', xprofile_get_field_data( $field, $user_id ) );
+	}
+
+function bp_profile_group_tabs() {
+	global $bp, $group_name;
+
+	if ( !$groups = wp_cache_get( 'xprofile_groups_inc_empty', 'bp' ) ) {
+		$groups = BP_XProfile_Group::get( array( 'fetch_fields' => true ) );
+		wp_cache_set( 'xprofile_groups_inc_empty', $groups, 'bp' );
+	}
+
+	if ( empty( $group_name ) )
+		$group_name = bp_profile_group_name(false);
+
+	$tabs = array();
+	for ( $i = 0, $count = count( $groups ); $i < $count; ++$i ) {
+		if ( $group_name == $groups[$i]->name )
+			$selected = ' class="current"';
+		else
+			$selected = '';
+
+		if ( !empty( $groups[$i]->fields ) ) {
+			$link = trailingslashit( bp_displayed_user_domain() . $bp->profile->slug . '/edit/group/' . $groups[$i]->id );
+			$tabs[] = sprintf( '<li %1$s><a href="%2$s">%3$s</a></li>', $selected, $link, esc_html( $groups[$i]->name ) );
+		}
+	}
+
+	$tabs = apply_filters( 'xprofile_filter_profile_group_tabs', $tabs, $groups, $group_name );
+	foreach ( (array) $tabs as $tab )
+		echo $tab;
+
+	do_action( 'xprofile_profile_group_tabs' );
+}
+
+function bp_profile_group_name( $deprecated = true ) {
+	if ( !$deprecated ) {
+		return bp_get_profile_group_name();
+	} else {
+		echo bp_get_profile_group_name();
+	}
+}
+	function bp_get_profile_group_name() {
+		if ( !$group_id = bp_action_variable( 1 ) )
+			$group_id = 1;
+
+		if ( !is_numeric( $group_id ) )
+			$group_id = 1;
+
+		if ( !$group = wp_cache_get( 'xprofile_group_' . $group_id, 'bp' ) ) {
+			$group = new BP_XProfile_Group($group_id);
+			wp_cache_set( 'xprofile_group_' . $group_id, $group, 'bp' );
+		}
+
+		return apply_filters( 'bp_get_profile_group_name', $group->name );
+	}
+
+function bp_avatar_upload_form() {
+	global $bp;
+
+	if ( !(int) $bp->site_options['bp-disable-avatar-uploads'] )
+		bp_core_avatar_admin( null, bp_loggedin_user_domain() . $bp->profile->slug . '/change-avatar/', bp_loggedin_user_domain() . $bp->profile->slug . '/delete-avatar/' );
+	else
+		_e( 'Avatar uploads are currently disabled. Why not use a <a href="http://gravatar.com" target="_blank">gravatar</a> instead?', 'buddypress' );
+}
+
+function bp_profile_last_updated() {
+
+	$last_updated = bp_get_profile_last_updated();
+
+	if ( !$last_updated ) {
+		_e( 'Profile not recently updated', 'buddypress' ) . '.';
+	} else {
+		echo $last_updated;
+	}
+}
+	function bp_get_profile_last_updated() {
+
+		$last_updated = bp_get_user_meta( bp_displayed_user_id(), 'profile_last_updated', true );
+
+		if ( $last_updated )
+			return apply_filters( 'bp_get_profile_last_updated', sprintf( __('Profile updated %s', 'buddypress'), bp_core_time_since( strtotime( $last_updated ) ) ) );
+
+		return false;
+	}
+
+function bp_current_profile_group_id() {
+	echo bp_get_current_profile_group_id();
+}
+	function bp_get_current_profile_group_id() {
+		if ( !$profile_group_id = bp_action_variable( 1 ) )
+			$profile_group_id = 1;
+
+		return apply_filters( 'bp_get_current_profile_group_id', $profile_group_id ); // admin/profile/edit/[group-id]
+	}
+
+function bp_avatar_delete_link() {
+	echo bp_get_avatar_delete_link();
+}
+	function bp_get_avatar_delete_link() {
+		global $bp;
+
+		return apply_filters( 'bp_get_avatar_delete_link', wp_nonce_url( bp_displayed_user_domain() . $bp->profile->slug . '/change-avatar/delete-avatar/', 'bp_delete_avatar_link' ) );
+	}
+
+function bp_edit_profile_button() {
+	global $bp;
+
+	bp_button( array (
+		'id'                => 'edit_profile',
+		'component'         => 'xprofile',
+		'must_be_logged_in' => true,
+		'block_self'        => true,
+		'link_href'         => trailingslashit( bp_displayed_user_domain() . $bp->profile->slug . '/edit' ),
+		'link_class'        => 'edit',
+		'link_text'         => __( 'Edit Profile', 'buddypress' ),
+		'link_title'        => __( 'Edit Profile', 'buddypress' ),
+	) );
+}
+
+/**
+ * Echo the field visibility radio buttons
+ */
+function bp_profile_visibility_radio_buttons() {
+	echo bp_profile_get_visibility_radio_buttons();
+}
+	/**
+	 * Return the field visibility radio buttons
+	 */
+	function bp_profile_get_visibility_radio_buttons() {
+		$html = '<ul class="radio">';
+
+		foreach( bp_xprofile_get_visibility_levels() as $level ) {
+			$checked = $level['id'] == bp_get_the_profile_field_visibility_level() ? ' checked="checked" ' : '';
+
+			// Only sanitize once
+			$field_id = bp_get_the_profile_field_id();
+			$level_id = esc_attr( $level['id'] );
+
+			$html .= '<li><label for="see-field_' . $field_id . '_' . $level_id . '"><input type="radio" id="see-field_' . $field_id . '_' . $level_id . '" name="field_' . $field_id . '_visibility" value="' . $level_id . '"' . $checked . ' /> ' . esc_html( $level['label'] ) . '</label></li>';
+		}
+
+		$html .= '</ul>';
+
+		return apply_filters( 'bp_profile_get_visibility_radio_buttons', $html );
+	}
Index: /tags/1.9/humans.txt
===================================================================
--- /tags/1.9/humans.txt	(revision 7684)
+++ /tags/1.9/humans.txt	(revision 7684)
@@ -0,0 +1,59 @@
+               .$$$$$$$Z$.
+          .~$$7...........$$$.
+        .$$...?$$$$$$$$$$Z....$Z.
+      .Z$..Z$$$$$$$$$$$$$$$$Z:..$$.
+     ,$..$$$$$$$$$$$$$7...$$$$$?..$.
+   .$Z .$$$$$$$$$$..?$$.....$$$$$..Z:
+  .$$.$$$$$$$$$........$$....Z$$$$..Z,
+  :$.7$$$$$$$$..........$$....$$$$$..$.
+ .$. $$$$$$$$$...........$....$$$$$$..$.
+.$$.$$$$$$$$$$...........$...$$$$$$$$.$.
+.$. $$$$$$$$$$ ..........Z..$$$$$$$$$.$$.
+.$.,$$$$$$$$$$$.........$$$$Z$$$$$$$$..$.
+.Z $$$$$$$$$$$$$$....+$$$$$,,,,~$$$$$..$.
+.$.=$$$$$$Z,,,,,?$$$$$,,,,,Z$,,,,$$$$..$.
+.$..$$$$$$,,,,,,,,Z$$,,,,,,,,$:,,~$$$.:$.
+.$$.$$$$$,,,,,,,,,,,,,,,,,,,,:$,,:$$$.Z.
+ .$..$$$$,,,,,,,,,,,,,,,,,,,,:$,,,$$..$.
+ .$$.$$$:,,,,,,,,,,,,,,,,,,,,,Z$$$$+.$.
+  .$= $$~,,,,,,:::,:,,:,,::,:,$$$$Z.$Z.
+   .$+.$$$$$$$$$$$$$$$$$$$$$$$$$$:.$$.
+    .$$..Z$$$$$$$$$$$$$$$$$$$$$Z..$7.
+      .$...$$$$$$$$$$$$$$$$$$$..Z$.
+        .Z$=..?Z$$$$$$$$$$$Z...$$.
+          .$$7.............Z$$.
+             .7Z$$$$$$$$$$~
+
+   We are the humans behind BuddyPress
+
+/* TEAM */
+Name: Andy Peatling
+Title: Founding Developer
+Twitter: apeatling
+
+Name: John James Jacoby
+Title: Project Lead
+Twitter: jjj
+Favorite Food: Truffle Lasagna
+
+Name: Boone B. Gorges
+Title: Lead Developer
+Twitter: boone
+Favorite Pudgy Pie Filling: Cherry
+
+Name: Paul Gibbs
+Title: Lead Developer
+Twitter: pgibbs
+Favourite Food: Pizza
+
+Name: Ray
+Title: Core Developer
+Twitter: r-a-y
+Favourite Food: tbd
+
+/* THANKS */
+hnla, mercime, modemlooper, cnorris23, karmatosed, photomatt
+
+/* META */
+Updated: 2012/10/22
+See: http://humanstxt.org/
Index: /tags/1.9/license.txt
===================================================================
--- /tags/1.9/license.txt	(revision 7684)
+++ /tags/1.9/license.txt	(revision 7684)
@@ -0,0 +1,280 @@
+		    GNU GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+                          675 Mass Ave, Cambridge, MA 02139, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+		    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+			    NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
Index: /tags/1.9/readme.txt
===================================================================
--- /tags/1.9/readme.txt	(revision 7684)
+++ /tags/1.9/readme.txt	(revision 7684)
@@ -0,0 +1,152 @@
+=== BuddyPress ===
+Contributors: johnjamesjacoby, DJPaul, boonebgorges, r-a-y
+Tags: social networking, activity, profiles, messaging, friends, groups, forums, notifications, settings, twitter, facebook, social, community, networks, networking, cms
+Requires at least: 3.5
+Tested up to: 3.6
+Stable tag: 1.9
+License: GPLv2 or later
+License URI: http://www.gnu.org/licenses/gpl-2.0.html
+
+Social networking in a box. Build a social network for your company, school, sports team, or niche community.
+
+== Description ==
+
+BuddyPress lets users sign-up and start creating profiles, posting messages, making connections, creating and interacting in groups, and much more. A social network in a box, BuddyPress lets you easily build a community for your company, school, sports team, or other niche community.
+
+<h4>Who's Using BuddyPress?</h4>
+
+Take a look at some of the best sites on the <a href="http://buddypress.org/showcase/">BuddyPress Showcase</a>.
+
+<h4>Plugins: Adding So Much More</h4>
+
+BuddyPress boasts an ever growing array of new features developed by an awesome plugin development community. There are more than 330 BuddyPress plugins available, and the list is growing every day. Check out our list of <a href="http://buddypress.org/extend/recommended-plugins/">popular and recommended plugins</a>; for a full list of plugins, please visit the <a href="http://buddypress.org/extend/plugins/">BuddyPress.org plugins page</a>. You can install any of these plugins automatically, using the plugin installer on your WordPress Dashboard.
+
+<h4>More Information</h4>
+
+Visit the <a href="http://buddypress.org/">BuddyPress website</a> for more information about BuddyPress.
+
+== Installation ==
+
+You can download and install BuddyPress using the built in WordPress plugin installer. If you download BuddyPress manually, make sure it is uploaded to "/wp-content/plugins/buddypress/".
+
+Activate BuddyPress in the "Plugins" admin panel using the "Activate" link. If you're using WordPress Multisite, you can optionally activate BuddyPress Network Wide, allowing its toolbar integration to appear on all of your sites, and optionally turning on post and comment aggregation to the Activity Stream too!
+
+= Discussion Forums =
+
+Try <a href="http://wordpress.org/plugins/bbpress/">bbPress</a>. It's designed to work cohesively with BuddyPress Groups, Profiles, and Notifications. Each group on your site can choose to have its own forum, and each user's topics, replies, favorites, and subscriptions appear in their profiles.
+
+== Frequently Asked Questions ==
+
+= Can I use my existing WordPress theme? =
+
+Of course! BuddyPress works out-of-the-box with nearly every WordPress theme.
+
+= Will this work on WordPress multisite? =
+
+Yes! If your WordPress installation has multisite enabled, BuddyPress will support the global tracking of blogs, posts and comments.
+
+= Where can I get support? =
+
+The support forums can be found at <a href="http://buddypress.org/forums/">http://buddypress.org/forums/</a>.
+
+= Where can I find documentation? =
+
+The documentation codex can be found at <a href="http://codex.buddypress.org/">http://codex.buddypress.org/</a>.
+
+= Where can I report a bug? =
+
+Report bugs and participate in development at <a href="http://buddypress.trac.wordpress.org/">http://buddypress.trac.wordpress.org</a>.
+
+= Where can I get the bleeding edge version of BuddyPress? =
+
+Check out the development trunk of BuddyPress via Subversion, from <a href="http://buddypress.svn.wordpress.org/trunk/">http://buddypress.svn.wordpress.org/trunk/</a>
+
+== Screenshots ==
+
+1. **Activity Streams** - Global, personal, and group activity streams with threaded commenting, direct posting, favoriting and @mentions. All with full RSS feeds and email notification support.
+2. **Extended Profiles** - Fully editable profile fields allow you to define the fields users can fill in to describe themselves. Tailor profile fields to suit your audience.
+3. **User Settings** - Give your users complete control over profile and notification settings. Settings are fully integrated into your theme, and can be disabled by the administrator.
+4. **Extensible Groups** - Powerful public, private or hidden groups allow your users to break the discussion down into specific topics. Extend groups with your own custom features using the group extension API.
+5. **Friend Connections** - Let your users make connections so they can track the activity of others, or filter to show only those users they care about the most.
+6. **Private Messaging** - Private messaging will allow your users to talk to each other directly and in private. Not just limited to one-on-one discussions, your users can send messages to multiple recipients.
+7. **Blogging Network** - Allow your users to start their own blogs using WordPress's Multisite feature, and track posts and comments from across your blog network in the activity stream.
+
+== Languages ==
+
+BuddyPress is available in more than 20 languages. For more information, check out the <a href="http://codex.buddypress.org/getting-started/translations/">translation page</a> on the BuddyPress Codex.
+
+== Upgrade Notice ==
+
+= 1.9 =
+See: http://codex.buddypress.org/releases/version-1-9/
+
+= 1.8.1 =
+See: http://codex.buddypress.org/releases/version-1-8-1/
+
+= 1.8 =
+See: http://codex.buddypress.org/releases/version-1-8/
+
+= 1.7.3 =
+See: http://codex.buddypress.org/releases/version-1-7-3/
+
+= 1.7.2 =
+See: http://codex.buddypress.org/releases/version-1-7-2/
+
+= 1.7.1 =
+See: http://codex.buddypress.org/releases/version-1-7-1/
+
+= 1.7 =
+See: http://codex.buddypress.org/releases/version-1-7/
+
+= 1.6.5 =
+See: http://codex.buddypress.org/releases/version-1-6-5/
+
+= 1.6.4 =
+See: http://codex.buddypress.org/releases/version-1-6-4/
+
+= 1.6.3 =
+See: http://codex.buddypress.org/releases/version-1-6-3/
+
+= 1.6.2 =
+Compatibility with WordPress 3.5
+
+= 1.6.1 =
+Fixes 4 bugs
+
+= 1.6 =
+See: http://codex.buddypress.org/releases/version-1-6/
+
+= 1.5 =
+See: http://codex.buddypress.org/releases/version-1-5/
+
+= 1.2.9 =
+Compatibility with WordPress 3.2
+
+= 1.2.8 =
+Compatibility with WordPress 3.1
+
+= 1.2.7 =
+Fixes over 10 bugs.
+
+== Changelog ==
+
+= 1.9 =
+See: http://codex.buddypress.org/releases/version-1-9/
+
+= 1.8.1 =
+See: http://codex.buddypress.org/releases/version-1-8-1/
+
+= 1.8 =
+See: http://codex.buddypress.org/releases/version-1-8/
+
+= 1.7 =
+See: http://codex.buddypress.org/releases/version-1-7/
+
+= 1.6 =
+See: http://codex.buddypress.org/releases/version-1-6/
+
+= 1.5 =
+See: http://codex.buddypress.org/releases/version-1-5/
+
+= Older =
+See: http://buddypress.org/about/release-history/
Index: /tags/1.9/tests/assets/group-extensions.php
===================================================================
--- /tags/1.9/tests/assets/group-extensions.php	(revision 7684)
+++ /tags/1.9/tests/assets/group-extensions.php	(revision 7684)
@@ -0,0 +1,148 @@
+<?php
+
+/**
+ * The following implementations of BP_Group_Extension act as dummy plugins
+ * for our unit tests
+ */
+
+class BPTest_Group_Extension_Parse_Legacy_Properties extends BP_Group_Extension {
+	function __construct() {
+		$class_name = get_class( $this );
+		$this->name = $class_name;
+		$this->slug = sanitize_title( $class_name );
+		$this->admin_name = $this->name . ' Edit';
+		$this->admin_slug = $this->slug . '-edit';
+		$this->create_name = $this->name . ' Create';
+		$this->create_slug = $this->slug . '-create';
+		$this->visibility = 'private';
+		$this->create_step_position = 58;
+		$this->nav_item_position = 63;
+		$this->admin_metabox_context = 'high';
+		$this->admin_metabox_priority = 'side';
+		$this->enable_create_step = false;
+		$this->enable_nav_item = true;
+		$this->enable_edit_item = false;
+		$this->enable_admin_item = true;
+		$this->nav_item_name = $this->name . ' Nav';
+		$this->display_hook = 'foo_hook';
+		$this->template_file = 'foo_template';
+	}
+
+	/**
+	 * Provides access to protected method unneeded in BP
+	 */
+	function _parse_legacy_properties() {
+		return $this->parse_legacy_properties();
+	}
+
+	/**
+	 * Provides access to protected property unneeded in BP
+	 */
+	function _get_legacy_properties_converted() {
+		return $this->legacy_properties_converted;
+	}
+}
+
+class BPTest_Group_Extension_Setup_Screens_Use_Global_Fallbacks extends BP_Group_Extension {
+	function __construct() {
+		$class_name = get_class( $this );
+		$this->slug = sanitize_title( $class_name );
+		$this->name = $class_name;
+	}
+
+	/**
+	 * Provides access to protected method unneeded in BP
+	 */
+	function _get_default_screens() {
+		return $this->get_default_screens();
+	}
+
+	/**
+	 * Provides access to protected method unneeded in BP
+	 */
+	function _setup_class_info() {
+		return $this->setup_class_info();
+	}
+
+	function settings_screen( $group_id = null ) {}
+	function settings_screen_save( $group_id = null ) {}
+}
+
+class BPTest_Group_Extension_Setup_Screens_Define_Edit_Screens_Locally extends BP_Group_Extension {
+	function __construct() {
+		$class_name = get_class( $this );
+		$this->slug = sanitize_title( $class_name );
+		$this->name = $class_name;
+	}
+
+	function edit_screen( $group_id = null ) {}
+	function edit_screen_save( $group_id = null ) {}
+	function settings_screen( $group_id = null ) {}
+	function settings_screen_save( $group_id = null ) {}
+
+	/**
+	 * Provides access to protected method unneeded in BP
+	 */
+	function _get_default_screens() {
+		return $this->get_default_screens();
+	}
+
+	/**
+	 * Provides access to protected method unneeded in BP
+	 */
+	function _setup_class_info() {
+		return $this->setup_class_info();
+	}
+
+}
+
+class BPTest_Group_Extension_Access_Root_Property extends BP_Group_Extension {
+	function __construct() {
+		$class_name = get_class( $this );
+
+		$args = array(
+			'slug' => sanitize_title( $class_name ),
+			'name' => $class_name,
+			'nav_item_position' => 39,
+		);
+
+		parent::init( $args );
+	}
+}
+
+class BPTest_Group_Extension_Access_Init_Property_Using_Legacy_Location extends BP_Group_Extension {
+	function __construct() {
+		$class_name = get_class( $this );
+
+		$args = array(
+			'slug' => sanitize_title( $class_name ),
+			'name' => $class_name,
+			'screens' => array(
+				'create' => array(
+					'position' => 18,
+				),
+			),
+		);
+
+		parent::init( $args );
+	}
+}
+
+class BPTest_Group_Extension_Get_Screen_Callback_Fallbacks extends BP_Group_Extension {
+	function __construct() {
+		$class_name = get_class( $this );
+
+		$args = array(
+			'slug' => sanitize_title( $class_name ),
+			'name' => $class_name,
+		);
+
+		parent::init( $args );
+	}
+
+	function settings_screen( $group_id = null ) {}
+	function settings_screen_save( $group_id = null ) {}
+
+	function edit_screen( $group_id = null ) {}
+	function edit_screen_save( $group_id = null ) {}
+}
Index: /tags/1.9/tests/bootstrap.php
===================================================================
--- /tags/1.9/tests/bootstrap.php	(revision 7684)
+++ /tags/1.9/tests/bootstrap.php	(revision 7684)
@@ -0,0 +1,19 @@
+<?php
+
+require( dirname( __FILE__ ) . '/includes/define-constants.php' );
+
+if ( ! file_exists( WP_TESTS_DIR . '/includes/functions.php' ) ) {
+	die( "The WordPress PHPUnit test suite could not be found.\n" );
+}
+
+require_once WP_TESTS_DIR . '/includes/functions.php';
+
+function _install_and_load_buddypress() {
+	require BP_TESTS_DIR . '/includes/loader.php';
+}
+tests_add_filter( 'muplugins_loaded', '_install_and_load_buddypress' );
+
+require WP_TESTS_DIR . '/includes/bootstrap.php';
+
+// Load the BP-specific testing tools
+require BP_TESTS_DIR . '/includes/testcase.php';
Index: /tags/1.9/tests/includes/define-constants.php
===================================================================
--- /tags/1.9/tests/includes/define-constants.php	(revision 7684)
+++ /tags/1.9/tests/includes/define-constants.php	(revision 7684)
@@ -0,0 +1,43 @@
+<?php
+
+/**
+ * Define constants needed by test suite.
+ */
+
+define( 'BP_PLUGIN_DIR', dirname( dirname( dirname( __FILE__ ) ) ) . '/' );
+
+if ( ! defined( 'BP_TESTS_DIR' ) ) {
+	define( 'BP_TESTS_DIR', dirname( dirname( __FILE__ ) ) . '/' );
+}
+
+/**
+ * In the pre-develop.svn WP development environment, an environmental bash
+ * variable would be set to run PHP Unit tests. However, this has been done
+ * away with in a post-develop.svn world. We'll still check if this variable
+ * is set for backwards compat.
+ */
+if ( getenv( 'WP_TESTS_DIR' ) ) {
+	define( 'WP_TESTS_DIR', getenv( 'WP_TESTS_DIR' ) );
+	define( 'WP_ROOT_DIR', WP_TESTS_DIR );
+} else {
+	define( 'WP_ROOT_DIR', dirname( dirname( dirname( dirname( dirname( dirname( __DIR__ ) ) ) ) ) ) );
+	define( 'WP_TESTS_DIR', WP_ROOT_DIR . '/tests/phpunit' );
+}
+
+// Based on the tests directory, look for a config file
+if ( file_exists( WP_ROOT_DIR . '/wp-tests-config.php' ) ) {
+	// Standard develop.svn.wordpress.org setup
+	define( 'WP_TESTS_CONFIG_PATH', WP_ROOT_DIR . '/wp-tests-config.php' );
+
+} else if ( file_exists( WP_TESTS_DIR . '/wp-tests-config.php' ) ) {
+	// Legacy unit-test.svn.wordpress.org setup
+	define( 'WP_TESTS_CONFIG_PATH', WP_TESTS_DIR . '/wp-tests-config.php' );
+
+} else if ( file_exists( dirname( dirname( WP_TESTS_DIR ) ) . '/wp-tests-config.php' ) ) {
+	// Environment variable exists and points to tests/phpunit of
+	// develop.svn.wordpress.org setup
+	define( 'WP_TESTS_CONFIG_PATH', dirname( dirname( WP_TESTS_DIR ) ) . '/wp-tests-config.php' );
+
+} else {
+	die( "wp-tests-config.php could not be found.\n" );
+}
Index: /tags/1.9/tests/includes/factory.php
===================================================================
--- /tags/1.9/tests/includes/factory.php	(revision 7684)
+++ /tags/1.9/tests/includes/factory.php	(revision 7684)
@@ -0,0 +1,165 @@
+<?php
+class BP_UnitTest_Factory extends WP_UnitTest_Factory {
+	public $activity = null;
+
+	function __construct() {
+		parent::__construct();
+
+		$this->activity = new BP_UnitTest_Factory_For_Activity( $this );
+		$this->group = new BP_UnitTest_Factory_For_Group( $this );
+		$this->xprofile_group = new BP_UnitTest_Factory_For_XProfileGroup( $this );
+		$this->xprofile_field = new BP_UnitTest_Factory_For_XProfileField( $this );
+		$this->notification = new BP_UnitTest_Factory_For_Notification( $this );
+	}
+}
+
+class BP_UnitTest_Factory_For_Activity extends WP_UnitTest_Factory_For_Thing {
+
+	function __construct( $factory = null ) {
+		parent::__construct( $factory );
+
+		$this->default_generation_definitions = array(
+			'action'       => new WP_UnitTest_Generator_Sequence( 'Activity action %s' ),
+			'component'    => buddypress()->activity->id,
+			'content'      => new WP_UnitTest_Generator_Sequence( 'Activity content %s' ),
+			'primary_link' => 'http://example.com',
+			'type'         => 'activity_update',
+			'recorded_time' => bp_core_current_time(),
+		);
+	}
+
+	function create_object( $args ) {
+		if ( ! isset( $args['user_id'] ) )
+			$args['user_id'] = get_current_user_id();
+
+		return bp_activity_add( $args );
+	}
+
+	function update_object( $activity_id, $fields ) {
+		$activity = new BP_Activity_Activity( $activity_id );
+
+		foreach ( $fields as $field_name => $value ) {
+			if ( isset( $activity->$field_name ) )
+				$activity->$field_name = $value;
+		}
+
+		$activity->save();
+		return $activity;
+	}
+
+	function get_object_by_id( $user_id ) {
+		return new BP_Activity_Activity( $user_id );
+	}
+}
+
+class BP_UnitTest_Factory_For_Group extends WP_UnitTest_Factory_For_Thing {
+
+	function __construct( $factory = null ) {
+		parent::__construct( $factory );
+
+		$this->default_generation_definitions = array(
+			'name'         => new WP_UnitTest_Generator_Sequence( 'Group %s' ),
+			'description'  => new WP_UnitTest_Generator_Sequence( 'Group description %s' ),
+			'slug'         => new WP_UnitTest_Generator_Sequence( 'group-slug-%s' ),
+			'status'       => 'public',
+			'enable_forum' => true,
+			'date_created' => bp_core_current_time(),
+		);
+	}
+
+	function create_object( $args ) {
+		if ( ! isset( $args['creator_id'] ) ) {
+			$args['creator_id'] = get_current_user_id();
+		}
+
+		$group_id = groups_create_group( $args );
+
+		groups_update_groupmeta( $group_id, 'total_member_count', 1 );
+
+		$last_activity = isset( $args['last_activity'] ) ? $args['last_activity'] : bp_core_current_time();
+		groups_update_groupmeta( $group_id, 'last_activity', $last_activity );
+
+		return $group_id;
+	}
+
+	function update_object( $group_id, $fields ) {
+		$group = new BP_Groups_Group( $group_id );
+
+		foreach ( $fields as $field_name => $value ) {
+			if ( isset( $group->field_name ) )
+				$group->field_name = $value;
+		}
+
+		$group->save();
+		return $group;
+	}
+
+	function get_object_by_id( $group_id ) {
+		return new BP_Groups_Group( $group_id );
+	}
+}
+
+class BP_UnitTest_Factory_For_XProfileGroup extends WP_UnitTest_Factory_For_Thing {
+
+	function __construct( $factory = null ) {
+		parent::__construct( $factory );
+
+		$this->default_generation_definitions = array(
+			'name'         => new WP_UnitTest_Generator_Sequence( 'XProfile group %s' ),
+			'description'  => new WP_UnitTest_Generator_Sequence( 'XProfile group description %s' ),
+			'slug'         => new WP_UnitTest_Generator_Sequence( 'xprofile-group-slug-%s' ),
+		);
+	}
+
+	function create_object( $args ) {
+		$group_id = xprofile_insert_field_group( $args );
+		return $this->get_object_by_id( $group_id );
+	}
+
+	function update_object( $group_id, $fields ) {
+	}
+
+	function get_object_by_id( $group_id ) {
+		return new BP_XProfile_Group( $group_id );
+	}
+}
+
+class BP_UnitTest_Factory_For_XProfileField extends WP_UnitTest_Factory_For_Thing {
+
+	function __construct( $factory = null ) {
+		parent::__construct( $factory );
+
+		$this->default_generation_definitions = array(
+			'name'         => new WP_UnitTest_Generator_Sequence( 'XProfile field %s' ),
+			'description'  => new WP_UnitTest_Generator_Sequence( 'XProfile field description %s' ),
+		);
+	}
+
+	function create_object( $args ) {
+		$field_id = xprofile_insert_field( $args );
+		return $this->get_object_by_id( $field_id );
+	}
+
+	function update_object( $field_id, $fields ) {
+	}
+
+	function get_object_by_id( $field_id ) {
+		return new BP_XProfile_Field( $field_id );
+	}
+}
+
+class BP_UnitTest_Factory_For_Notification extends WP_UnitTest_Factory_For_Thing {
+	public function __construct( $factory = null ) {
+		parent::__construct( $factory );
+	}
+
+	public function create_object( $args ) {
+		return bp_notifications_add_notification( $args );
+	}
+
+	public function update_object( $id, $fields ) {}
+
+	public function get_object_by_id( $id ) {
+		return new BP_Notifications_Notification( $id );
+	}
+}
Index: /tags/1.9/tests/includes/install.php
===================================================================
--- /tags/1.9/tests/includes/install.php	(revision 7684)
+++ /tags/1.9/tests/includes/install.php	(revision 7684)
@@ -0,0 +1,74 @@
+<?php
+/**
+ * Installs BuddyPress for the purpose of the unit-tests
+ *
+ * @todo Reuse the init/load code in init.php
+ * @todo Support MULTIBLOG
+ */
+error_reporting( E_ALL & ~E_DEPRECATED & ~E_STRICT );
+
+$config_file_path = $argv[1];
+$tests_dir_path = $argv[2];
+$multisite = ! empty( $argv[3] );
+
+require_once $config_file_path;
+require_once $tests_dir_path . '/includes/functions.php';
+
+function _load_buddypress() {
+	require dirname( dirname( dirname( __FILE__ ) ) ) . '/bp-loader.php';
+}
+tests_add_filter( 'muplugins_loaded', '_load_buddypress' );
+
+define( 'BP_PLUGIN_DIR', dirname( dirname( dirname( __FILE__ ) ) ) . '/' );
+define( 'BP_ROOT_BLOG', 1 );
+
+// Always load admin bar
+tests_add_filter( 'show_admin_bar', '__return_true' );
+
+function wp_test_bp_install( $value ) {
+	return array( 'activity' => 1, 'blogs' => 1, 'friends' => 1, 'groups' => 1, 'members' => 1, 'messages' => 1, 'notifications' => 1, 'settings' => 1, 'xprofile' => 1, );
+}
+tests_add_filter( 'bp_new_install_default_components', 'wp_test_bp_install' );
+
+$_SERVER['SERVER_PROTOCOL'] = 'HTTP/1.1';
+$_SERVER['HTTP_HOST'] = WP_TESTS_DOMAIN;
+$PHP_SELF = $GLOBALS['PHP_SELF'] = $_SERVER['PHP_SELF'] = '/index.php';
+
+require_once ABSPATH . '/wp-settings.php';
+define( 'BP_TESTS_DB_VERSION_FILE', ABSPATH . '.bp-tests-version' );
+
+// Check if BuddyPress has already been installed
+$db_version = buddypress()->db_version;
+$hash = $db_version . ' ' . (int) $multisite . ' ' . sha1_file( $config_file_path );
+
+if ( $db_version && file_exists( BP_TESTS_DB_VERSION_FILE ) ) {
+	$version_file = file_get_contents( BP_TESTS_DB_VERSION_FILE );
+
+	if ( $hash === $version_file ) {
+		return;
+	}
+}
+
+echo "Installing BuddyPress...\n";
+
+// Make sure that BP has been cleaned from all blogs before reinstalling
+$blogs = is_multisite() ? $wpdb->get_col( "SELECT blog_id FROM {$wpdb->blogs}" ) : array( 1 );
+foreach ( $blogs as $blog ) {
+	if ( is_multisite() ) {
+		switch_to_blog( $blog );
+	}
+
+	$wpdb->query( "DELETE FROM {$wpdb->options} WHERE option_name LIKE '%bp%'" );
+
+	if ( is_multisite() ) {
+		restore_current_blog();
+	}
+}
+
+$wpdb->query( 'SET storage_engine = INNODB' );
+$wpdb->select( DB_NAME, $wpdb->dbh );
+
+// Install BuddyPress
+bp_version_updater();
+
+file_put_contents( BP_TESTS_DB_VERSION_FILE, $hash );
Index: /tags/1.9/tests/includes/loader.php
===================================================================
--- /tags/1.9/tests/includes/loader.php	(revision 7684)
+++ /tags/1.9/tests/includes/loader.php	(revision 7684)
@@ -0,0 +1,9 @@
+<?php
+
+require_once( dirname( __FILE__ ) . '/define-constants.php' );
+
+$multisite = (int) ( defined( 'WP_TESTS_MULTISITE') && WP_TESTS_MULTISITE );
+system( WP_PHP_BINARY . ' ' . escapeshellarg( dirname( __FILE__ ) . '/install.php' ) . ' ' . escapeshellarg( WP_TESTS_CONFIG_PATH ) . ' ' . escapeshellarg( WP_TESTS_DIR ) . ' ' . $multisite );
+
+// Bootstrap BP
+require dirname( __FILE__ ) . '/../../bp-loader.php';
Index: /tags/1.9/tests/includes/testcase.php
===================================================================
--- /tags/1.9/tests/includes/testcase.php	(revision 7684)
+++ /tags/1.9/tests/includes/testcase.php	(revision 7684)
@@ -0,0 +1,337 @@
+<?php
+
+/**
+ * WP's test suite wipes out BP's directory page mappings with _delete_all_posts()
+ * We must reestablish them before our tests can be successfully run
+ */
+bp_core_add_page_mappings( bp_get_option( 'bp-active-components' ), 'delete' );
+
+require_once dirname( __FILE__ ) . '/factory.php';
+
+class BP_UnitTestCase extends WP_UnitTestCase {
+
+	protected $temp_has_bp_moderate = array();
+	protected $cached_SERVER_NAME = null;
+
+	public function setUp() {
+		parent::setUp();
+
+		// Make sure all users are deleted
+		// There's a bug in the multisite tests that causes the
+		// transaction rollback to fail for the first user created,
+		// which busts every other attempt to create users. This is a
+		// hack workaround
+		global $wpdb;
+		$wpdb->query( "TRUNCATE TABLE {$wpdb->users}" );
+
+		// Fake WP mail globals, to avoid errors
+		add_filter( 'wp_mail', array( $this, 'setUp_wp_mail' ) );
+		add_filter( 'wp_mail_from', array( $this, 'tearDown_wp_mail' ) );
+
+		$this->factory = new BP_UnitTest_Factory;
+	}
+
+	function clean_up_global_scope() {
+		buddypress()->bp_nav                = buddypress()->bp_options_nav = buddypress()->action_variables = buddypress()->canonical_stack = buddypress()->unfiltered_uri = $GLOBALS['bp_unfiltered_uri'] = array();
+		buddypress()->current_component     = buddypress()->current_item = buddypress()->current_action = '';
+		buddypress()->unfiltered_uri_offset = 0;
+		buddypress()->is_single_item        = false;
+		buddypress()->current_user          = new stdClass();
+		buddypress()->displayed_user        = new stdClass();
+		buddypress()->loggedin_user         = new stdClass();
+		buddypress()->avatar                = new stdClass();
+
+		parent::clean_up_global_scope();
+	}
+
+	function assertPreConditions() {
+		parent::assertPreConditions();
+
+		// Reinit some of the globals that might have been cleared by BP_UnitTestCase::clean_up_global_scope().
+		// This is here because it didn't work in clean_up_global_scope(); I don't know why.
+		do_action( 'bp_setup_globals' );
+	}
+
+	function go_to( $url ) {
+		// note: the WP and WP_Query classes like to silently fetch parameters
+		// from all over the place (globals, GET, etc), which makes it tricky
+		// to run them more than once without very carefully clearing everything
+		$_GET = $_POST = array();
+		foreach (array('query_string', 'id', 'postdata', 'authordata', 'day', 'currentmonth', 'page', 'pages', 'multipage', 'more', 'numpages', 'pagenow') as $v) {
+			if ( isset( $GLOBALS[$v] ) ) unset( $GLOBALS[$v] );
+		}
+		$parts = parse_url($url);
+		if (isset($parts['scheme'])) {
+			// set the HTTP_HOST
+			$GLOBALS['_SERVER']['HTTP_HOST'] = $parts['host'];
+
+			$req = $parts['path'];
+			if (isset($parts['query'])) {
+				$req .= '?' . $parts['query'];
+				// parse the url query vars into $_GET
+				parse_str($parts['query'], $_GET);
+			}
+		} else {
+			$req = $url;
+		}
+		if ( ! isset( $parts['query'] ) ) {
+			$parts['query'] = '';
+		}
+
+		// Scheme
+		if ( 0 === strpos( $req, '/wp-admin' ) && force_ssl_admin() ) {
+			$_SERVER['HTTPS'] = 'on';
+		} else {
+			unset( $_SERVER['HTTPS'] );
+		}
+
+		// Set this for bp_core_set_uri_globals()
+		$GLOBALS['_SERVER']['REQUEST_URI'] = $req;
+		unset($_SERVER['PATH_INFO']);
+
+		// setup $current_site and $current_blog globals for multisite based on
+		// REQUEST_URI; mostly copied from /wp-includes/ms-settings.php
+		if ( is_multisite() ) {
+			$domain = addslashes( $_SERVER['HTTP_HOST'] );
+			if ( false !== strpos( $domain, ':' ) ) {
+				if ( substr( $domain, -3 ) == ':80' ) {
+					$domain = substr( $domain, 0, -3 );
+					$_SERVER['HTTP_HOST'] = substr( $_SERVER['HTTP_HOST'], 0, -3 );
+				} elseif ( substr( $domain, -4 ) == ':443' ) {
+					$domain = substr( $domain, 0, -4 );
+					$_SERVER['HTTP_HOST'] = substr( $_SERVER['HTTP_HOST'], 0, -4 );
+				}
+			}
+
+			$domain = rtrim( $domain, '.' );
+			$cookie_domain = $domain;
+			if ( substr( $cookie_domain, 0, 4 ) == 'www.' )
+				$cookie_domain = substr( $cookie_domain, 4 );
+
+			$path = preg_replace( '|([a-z0-9-]+.php.*)|', '', $GLOBALS['_SERVER']['REQUEST_URI'] );
+			$path = str_replace ( '/wp-admin/', '/', $path );
+			$path = preg_replace( '|(/[a-z0-9-]+?/).*|', '$1', $path );
+
+			$GLOBALS['current_site'] = wpmu_current_site();
+			if ( ! isset( $GLOBALS['current_site']->blog_id ) )
+				$GLOBALS['current_site']->blog_id = $wpdb->get_var( $wpdb->prepare( "SELECT blog_id FROM $wpdb->blogs WHERE domain = %s AND path = %s", $GLOBALS['current_site']->domain, $GLOBALS['current_site']->path ) );
+
+			// unit tests only support subdirectory install at the moment
+			// removed object cache references
+			if ( ! is_subdomain_install() ) {
+				$blogname = htmlspecialchars( substr( $GLOBALS['_SERVER']['REQUEST_URI'], strlen( $path ) ) );
+				if ( false !== strpos( $blogname, '/' ) )
+					$blogname = substr( $blogname, 0, strpos( $blogname, '/' ) );
+				if ( false !== strpos( $blogname, '?' ) )
+					$blogname = substr( $blogname, 0, strpos( $blogname, '?' ) );
+				$reserved_blognames = array( 'page', 'comments', 'blog', 'wp-admin', 'wp-includes', 'wp-content', 'files', 'feed' );
+				if ( $blogname != '' && ! in_array( $blogname, $reserved_blognames ) && ! is_file( $blogname ) )
+					$path .= $blogname . '/';
+
+				$GLOBALS['current_blog'] = get_blog_details( array( 'domain' => $domain, 'path' => $path ), false );
+
+				unset($reserved_blognames);
+			}
+
+			$GLOBALS['blog_id'] = $GLOBALS['current_blog']->blog_id;
+		}
+
+		unset($GLOBALS['wp_query'], $GLOBALS['wp_the_query']);
+		$GLOBALS['wp_the_query'] = new WP_Query();
+		$GLOBALS['wp_query'] = $GLOBALS['wp_the_query'];
+		$GLOBALS['wp'] = new WP();
+
+		// clean out globals to stop them polluting wp and wp_query
+		foreach ($GLOBALS['wp']->public_query_vars as $v) {
+			unset($GLOBALS[$v]);
+		}
+		foreach ($GLOBALS['wp']->private_query_vars as $v) {
+			unset($GLOBALS[$v]);
+		}
+
+		$GLOBALS['wp']->main($parts['query']);
+
+		// For BuddyPress, James.
+		$GLOBALS['bp']->loggedin_user = NULL;
+		do_action( 'bp_init' );
+	}
+
+	protected function checkRequirements() {
+		if ( WP_TESTS_FORCE_KNOWN_BUGS )
+			return;
+
+		parent::checkRequirements();
+
+		$tickets = PHPUnit_Util_Test::getTickets( get_class( $this ), $this->getName( false ) );
+		foreach ( $tickets as $ticket ) {
+			if ( 'BP' == substr( $ticket, 0, 2 ) ) {
+				$ticket = substr( $ticket, 2 );
+				if ( $ticket && is_numeric( $ticket ) )
+					$this->knownBPBug( $ticket );
+			}
+		}
+	}
+
+	/**
+	 * Skips the current test if there is an open BuddyPress ticket with id $ticket_id
+	 */
+	function knownBPBug( $ticket_id ) {
+		if ( WP_TESTS_FORCE_KNOWN_BUGS || in_array( $ticket_id, self::$forced_tickets ) )
+			return;
+
+		if ( ! TracTickets::isTracTicketClosed( 'http://buddypress.trac.wordpress.org', $ticket_id ) )
+			$this->markTestSkipped( sprintf( 'BuddyPress Ticket #%d is not fixed', $ticket_id ) );
+	}
+
+	/**
+	 * WP's core tests use wp_set_current_user() to change the current
+	 * user during tests. BP caches the current user differently, so we
+	 * have to do a bit more work to change it
+	 *
+	 * @global BuddyPres $bp
+	 */
+	function set_current_user( $user_id ) {
+		global $bp;
+		$bp->loggedin_user->id = $user_id;
+		$bp->loggedin_user->fullname       = bp_core_get_user_displayname( $user_id );
+		$bp->loggedin_user->is_super_admin = $bp->loggedin_user->is_site_admin = is_super_admin( $user_id );
+		$bp->loggedin_user->domain         = bp_core_get_user_domain( $user_id );
+		$bp->loggedin_user->userdata       = bp_core_get_core_userdata( $user_id );
+
+		wp_set_current_user( $user_id );
+	}
+
+	/**
+	 * When creating a new user, it's almost always necessary to have the
+	 * last_activity usermeta set right away, so that the user shows up in
+	 * directory queries. This is a shorthand wrapper for the user factory
+	 * create() method.
+	 *
+	 * Also set a display name
+	 */
+	function create_user( $args = array() ) {
+		$r = wp_parse_args( $args, array(
+			'role' => 'subscriber',
+			'last_activity' => bp_core_current_time() - 60*60*24*365,
+		) );
+
+		$last_activity = $r['last_activity'];
+		unset( $r['last_activity'] );
+
+		$user_id = $this->factory->user->create( $args );
+
+		bp_update_user_last_activity( $user_id, $last_activity );
+
+		if ( bp_is_active( 'xprofile' ) ) {
+			$user = new WP_User( $user_id );
+			xprofile_set_field_data( 1, $user_id, $user->display_name );
+		}
+
+		return $user_id;
+	}
+
+	public static function add_user_to_group( $user_id, $group_id, $args = array() ) {
+		$r = wp_parse_args( $args, array(
+			'date_modified' => bp_core_current_time(),
+			'is_confirmed' => 1,
+		) );
+
+		$new_member                = new BP_Groups_Member;
+		$new_member->group_id      = $group_id;
+		$new_member->user_id       = $user_id;
+		$new_member->inviter_id    = 0;
+		$new_member->is_admin      = 0;
+		$new_member->user_title    = '';
+		$new_member->date_modified = $r['date_modified'];
+		$new_member->is_confirmed  = $r['is_confirmed'];
+
+		$new_member->save();
+		return $new_member->id;
+	}
+
+	/**
+	 * We can't use grant_super_admin() because we will need to modify
+	 * the list more than once, and grant_super_admin() can only be run
+	 * once because of its global check
+	 */
+	public function grant_super_admin( $user_id ) {
+		global $super_admins;
+		if ( ! is_multisite() ) {
+			return;
+		}
+
+		$user = get_userdata( $user_id );
+		$super_admins[] = $user->user_login;
+	}
+
+	public function restore_admins() {
+		// We assume that the global can be wiped out
+		// @see grant_super_admin()
+		unset( $GLOBALS['super_admins'] );
+	}
+
+	public function grant_bp_moderate( $user_id ) {
+		if ( ! isset( $this->temp_has_bp_moderate[ $user_id ] ) ) {
+			$this->temp_has_bp_moderate[ $user_id ] = 1;
+		}
+		add_filter( 'bp_current_user_can', array( $this, 'grant_bp_moderate_cb' ), 10, 2 );
+	}
+
+	public function revoke_bp_moderate( $user_id ) {
+		if ( isset( $this->temp_has_bp_moderate[ $user_id ] ) ) {
+			unset( $this->temp_has_bp_moderate[ $user_id ] );
+		}
+		remove_filter( 'bp_current_user_can', array( $this, 'grant_bp_moderate_cb' ), 10, 2 );
+	}
+
+	public function grant_bp_moderate_cb( $retval, $capability ) {
+		$current_user = bp_loggedin_user_id();
+		if ( ! isset( $this->temp_has_bp_moderate[ $current_user ] ) ) {
+			return $retval;
+		}
+
+		if ( 'bp_moderate' == $capability ) {
+			$retval = true;
+		}
+
+		return $retval;
+	}
+
+	/**
+	 * Go to the root blog. This helps reset globals after moving between
+	 * blogs.
+	 */
+	public function go_to_root() {
+		$blog_1_url = get_blog_option( 1, 'home' );
+		$this->go_to( str_replace( $blog_1_url, '', trailingslashit( bp_get_root_domain() ) ) );
+	}
+
+	/**
+	 * Set up globals necessary to avoid errors when using wp_mail()
+	 */
+	public function setUp_wp_mail( $args ) {
+		if ( isset( $_SERVER['SERVER_NAME'] ) ) {
+			$this->cached_SERVER_NAME = $_SERVER['SERVER_NAME'];
+		}
+
+		$_SERVER['SERVER_NAME'] = 'example.com';
+
+		// passthrough
+		return $args;
+	}
+
+	/**
+	 * Tear down globals set up in setUp_wp_mail()
+	 */
+	public function tearDown_wp_mail( $args ) {
+		if ( ! empty( $this->cached_SERVER_NAME ) ) {
+			$_SERVER['SERVER_NAME'] = $this->cached_SERVER_NAME;
+			unset( $this->cached_SERVER_NAME );
+		} else {
+			unset( $_SERVER['SERVER_NAME'] );
+		}
+
+		// passthrough
+		return $args;
+	}
+}
Index: /tags/1.9/tests/multisite.xml
===================================================================
--- /tags/1.9/tests/multisite.xml	(revision 7684)
+++ /tags/1.9/tests/multisite.xml	(revision 7684)
@@ -0,0 +1,17 @@
+<phpunit
+	bootstrap="bootstrap.php"
+	backupGlobals="false"
+	colors="true"
+	convertErrorsToExceptions="true"
+	convertNoticesToExceptions="true"
+	convertWarningsToExceptions="true"
+	>
+	<php>
+		<const name="WP_TESTS_MULTISITE" value="1" />
+	</php>
+	<testsuites>
+		<testsuite>
+			<directory suffix=".php">./testcases/</directory>
+		</testsuite>
+	</testsuites>
+</phpunit>
Index: /tags/1.9/tests/phpunit.xml
===================================================================
--- /tags/1.9/tests/phpunit.xml	(revision 7684)
+++ /tags/1.9/tests/phpunit.xml	(revision 7684)
@@ -0,0 +1,14 @@
+<phpunit
+	bootstrap="bootstrap.php"
+	backupGlobals="false"
+	colors="true"
+	convertErrorsToExceptions="true"
+	convertNoticesToExceptions="true"
+	convertWarningsToExceptions="true"
+	>
+	<testsuites>
+		<testsuite>
+			<directory suffix=".php">./testcases/</directory>
+		</testsuite>
+	</testsuites>
+</phpunit>
Index: /tags/1.9/tests/testcases/activity/class.BP_Activity_Activity.php
===================================================================
--- /tags/1.9/tests/testcases/activity/class.BP_Activity_Activity.php	(revision 7684)
+++ /tags/1.9/tests/testcases/activity/class.BP_Activity_Activity.php	(revision 7684)
@@ -0,0 +1,308 @@
+<?php
+/**
+ * @group activity
+ */
+class BP_Tests_Activity_Class extends BP_UnitTestCase {
+	protected $old_current_user = 0;
+
+	public function setUp() {
+		parent::setUp();
+
+		$this->old_current_user = get_current_user_id();
+		$this->set_current_user( $this->factory->user->create( array( 'role' => 'subscriber' ) ) );
+	}
+
+	public function tearDown() {
+		parent::tearDown();
+		$this->set_current_user( $this->old_current_user );
+	}
+
+	public function test_check_exists_by_content() {
+		$content  = 'A classy girl who know how to enjoy the freedom of a cup of coffee';
+		$activity = $this->factory->activity->create( array(
+			'content' => $content,
+			'type'    => 'activity_update',
+		) );
+
+		$result = BP_Activity_Activity::check_exists_by_content( $content );
+		$this->assertEquals( $activity, $result );
+	}
+
+	public function test_delete_activity_item_comments() {
+		$parent_activity = $this->factory->activity->create( array(
+			'type' => 'activity_update',
+		) );
+
+		$comments = $this->factory->activity->create_many( 3, array(
+			'item_id' => $parent_activity,
+			'type'    => 'activity_comment',
+		) );
+
+		BP_Activity_Activity::delete_activity_item_comments( $parent_activity );
+
+		$result = BP_Activity_Activity::get( array( 'in' => wp_list_pluck( $comments, 'id' ), ) );
+		$this->assertEmpty( $result['activities'] );
+	}
+
+	/**
+	 * @ticket BP4804
+	 */
+	public function test_delete_activity_meta_entries() {
+		$activity = $this->factory->activity->create( array(
+			'type' => 'activity_update',
+		) );
+
+		bp_activity_update_meta( $activity, 'Paul', 'is cool' );
+		BP_Activity_Activity::delete_activity_meta_entries( $activity );
+
+		$meta = bp_activity_get_meta( $activity, 'Paul' );
+		$this->assertFalse( $meta );
+	}
+
+	public function test_hide_all_for_user() {
+		$activity = $this->factory->activity->create( array(
+			'type' => 'activity_update',
+		) );
+
+		BP_Activity_Activity::hide_all_for_user( get_current_user_id() );
+
+		$activity = BP_Activity_Activity::get( array(
+			'in'          => $activity,
+			'show_hidden' => true,
+		) );
+		$this->assertEquals( $activity['activities'][0]->hide_sitewide, 1 );
+	}
+
+	/**
+	 * @group get
+	 * @group meta_query
+	 */
+	public function test_get_with_meta_query() {
+		$a1 = $this->factory->activity->create();
+		$a2 = $this->factory->activity->create();
+		bp_activity_update_meta( $a1, 'foo', 'bar' );
+
+		$activity = BP_Activity_Activity::get( array(
+			'meta_query' => array(
+				array(
+					'key' => 'foo',
+					'value' => 'bar',
+				),
+			),
+		) );
+		$ids = wp_list_pluck( $activity['activities'], 'id' );
+		$this->assertEquals( $ids, array( $a1 ) );
+	}
+
+	public function test_get_with_meta_query_two_clauses_with_or_relation() {
+		$now = time();
+		$a1 = $this->factory->activity->create( array(
+			'recorded_time' => date( 'Y-m-d H:i:s', $now ),
+		) );
+		$a2 = $this->factory->activity->create( array(
+			'recorded_time' => date( 'Y-m-d H:i:s', $now - 60 ),
+		) );
+		$a3 = $this->factory->activity->create( array(
+			'recorded_time' => date( 'Y-m-d H:i:s', $now - 120 ),
+		) );
+		bp_activity_update_meta( $a1, 'foo', 'bar' );
+		bp_activity_update_meta( $a2, 'foo', 'bar' );
+		bp_activity_update_meta( $a1, 'baz', 'barry' );
+
+		$activity = BP_Activity_Activity::get( array(
+			'meta_query' => array(
+				'relation' => 'OR',
+				array(
+					'key' => 'foo',
+					'value' => 'bar',
+				),
+				array(
+					'key' => 'baz',
+					'value' => 'barry',
+				),
+			),
+		) );
+
+		$ids = wp_list_pluck( $activity['activities'], 'id' );
+		$this->assertEquals( array( $a1, $a2 ), $ids );
+		$this->assertEquals( 2, $activity['total'] );
+	}
+
+	/**
+	 * @group get
+	 */
+	public function test_get_with_search_terms() {
+		$a1 = $this->factory->activity->create( array(
+			'content' => 'Boone is a cool guy',
+		) );
+		$a2 = $this->factory->activity->create( array(
+			'content' => 'No he isn\'t',
+		) );
+
+		$activity = BP_Activity_Activity::get( array(
+			'search_terms' => 'cool',
+		) );
+		$ids = wp_list_pluck( $activity['activities'], 'id' );
+		$this->assertEquals( $ids, array( $a1 ) );
+	}
+
+	/**
+	 * @group get
+	 */
+	public function test_get_with_display_comments_threaded() {
+		$now = time();
+		$a1 = $this->factory->activity->create( array(
+			'content' => 'Life Rules',
+			'recorded_time' => date( 'Y-m-d H:i:s', $now ),
+		) );
+		$a2 = $this->factory->activity->create( array(
+			'content' => 'Life Drools',
+			'recorded_time' => date( 'Y-m-d H:i:s', $now - 100 ),
+		) );
+		$a3 = bp_activity_new_comment( array(
+			'activity_id' => $a1,
+			'content' => 'Candy is good',
+			'recorded_time' => date( 'Y-m-d H:i:s', $now - 50 ),
+		) );
+
+		$activity = BP_Activity_Activity::get( array(
+			'display_comments' => 'threaded',
+		) );
+
+		// Kinda crummy, but let's construct a skeleton
+		$expected = array(
+			$a1 => array( $a3 ),
+			$a2 => array(),
+		);
+
+		$found = array();
+		foreach ( $activity['activities'] as $a ) {
+			$found[ $a->id ] = ! empty( $a->children ) ? array_keys( $a->children ) : array();
+		}
+
+		$this->assertEquals( $expected, $found );
+	}
+
+	/**
+	 * @group get
+	 */
+	public function test_get_with_display_comments_stream() {
+		$now = time();
+		$a1 = $this->factory->activity->create( array(
+			'content' => 'Life Rules',
+			'recorded_time' => date( 'Y-m-d H:i:s', $now ),
+		) );
+		$a2 = $this->factory->activity->create( array(
+			'content' => 'Life Drools',
+			'recorded_time' => date( 'Y-m-d H:i:s', $now - 100 ),
+		) );
+
+		// bp_activity_new_comment() doesn't allow date_recorded
+		$a3 = bp_activity_add( array(
+			'action'            => sprintf( __( '%s posted a new activity comment', 'buddypress' ), bp_get_loggedin_user_link() ) ,
+			'content'           => 'Candy is good',
+			'component'         => buddypress()->activity->id,
+			'type'              => 'activity_comment',
+			'user_id'           => bp_loggedin_user_id(),
+			'item_id'           => $a1,
+			'secondary_item_id' => $a1,
+			'recorded_time'     => date( 'Y-m-d H:i:s', $now - 50 ),
+		) );
+
+		$activity = BP_Activity_Activity::get( array(
+			'display_comments' => 'stream',
+		) );
+		$ids = wp_list_pluck( $activity['activities'], 'id' );
+		$this->assertEquals( array( $a1, $a3, $a2 ), $ids );
+	}
+
+	/**
+	 * @group get
+	 */
+	public function test_get_with_display_comments_false() {
+		$now = time();
+		$a1 = $this->factory->activity->create( array(
+			'content' => 'Life Rules',
+			'recorded_time' => date( 'Y-m-d H:i:s', $now ),
+		) );
+		$a2 = $this->factory->activity->create( array(
+			'content' => 'Life Drools',
+			'recorded_time' => date( 'Y-m-d H:i:s', $now - 100 ),
+		) );
+		$a3 = bp_activity_new_comment( array(
+			'activity_id' => $a1,
+			'content' => 'Candy is good',
+			'recorded_time' => date( 'Y-m-d H:i:s', $now - 50 ),
+		) );
+
+		$activity = BP_Activity_Activity::get( array(
+			'display_comments' => false,
+		) );
+		$ids = wp_list_pluck( $activity['activities'], 'id' );
+		$this->assertEquals( array( $a1, $a2 ), $ids );
+	}
+
+	/**
+	 * @group get_id
+	 */
+	public function test_get_id_with_item_id() {
+		$a1 = $this->factory->activity->create( array(
+			'item_id' => 523,
+		) );
+		$a2 = $this->factory->activity->create( array(
+			'item_id' => 1888,
+		) );
+
+		$activity = BP_Activity_Activity::get_id( false, false, false, 523, false, false, false, false );
+		$this->assertEquals( $a1, $activity );
+	}
+
+	/**
+	 * @group get_id
+	 */
+	public function test_get_id_with_secondary_item_id() {
+		$a1 = $this->factory->activity->create( array(
+			'secondary_item_id' => 523,
+		) );
+		$a2 = $this->factory->activity->create( array(
+			'secondary_content' => 1888,
+		) );
+
+		$activity = BP_Activity_Activity::get_id( false, false, false, false, 523, false, false, false );
+		$this->assertEquals( $a1, $activity );
+	}
+
+	/**
+	 * @group delete
+	 */
+	public function test_delete_with_item_id() {
+		$a1 = $this->factory->activity->create( array(
+			'item_id' => 523,
+		) );
+		$a2 = $this->factory->activity->create( array(
+			'item_id' => 1888,
+		) );
+
+		$activity = BP_Activity_Activity::delete( array(
+			'item_id' => 523,
+		) );
+		$this->assertEquals( array( $a1 ), $activity );
+	}
+
+	/**
+	 * @group delete
+	 */
+	public function test_delete_with_secondary_item_id() {
+		$a1 = $this->factory->activity->create( array(
+			'secondary_item_id' => 523,
+		) );
+		$a2 = $this->factory->activity->create( array(
+			'secondary_item_id' => 1888,
+		) );
+
+		$activity = BP_Activity_Activity::delete( array(
+			'secondary_item_id' => 523,
+		) );
+		$this->assertEquals( array( $a1 ), $activity );
+	}
+}
Index: /tags/1.9/tests/testcases/activity/functions.php
===================================================================
--- /tags/1.9/tests/testcases/activity/functions.php	(revision 7684)
+++ /tags/1.9/tests/testcases/activity/functions.php	(revision 7684)
@@ -0,0 +1,208 @@
+<?php
+/**
+ * @group activity
+ */
+class BP_Tests_Activity_Functions extends BP_UnitTestCase {
+	protected $old_current_user = 0;
+
+	public function setUp() {
+		parent::setUp();
+
+		$this->old_current_user = get_current_user_id();
+		$this->set_current_user( $this->factory->user->create( array( 'role' => 'subscriber' ) ) );
+	}
+
+	public function tearDown() {
+		parent::tearDown();
+		$this->set_current_user( $this->old_current_user );
+	}
+
+	/**
+	 * @ticket BP4488
+	 */
+	public function test_thumbnail_content_images() {
+		// No images
+		$post_content = 'foo bar';
+		$this->assertEquals( bp_activity_thumbnail_content_images( $post_content ), 'foo bar' );
+
+		// Image first, no caption. See #BP4488
+		$post_content = '<img src="http://example.com/foo.jpg" alt="foo" width="40" height="40" class="alignnone size-full wp-image-236" /> foo bar';
+		$this->assertEquals( bp_activity_thumbnail_content_images( $post_content ), '<img src="http://example.com/foo.jpg" width="40" height="40" alt="Thumbnail" class="align-left thumbnail" /> foo bar' );
+
+		// Image first, caption. See #BP4488
+		$post_content = '[caption id="attachment_236" align="alignnone" width="40"]<img src="http://example.com/foo.jpg" alt="FOO!" width="40" height="40" class="size-full wp-image-236" /> FOO![/caption] Awesome.';
+		$this->assertEquals( bp_activity_thumbnail_content_images( $post_content ), '<img src="http://example.com/foo.jpg" width="40" height="40" alt="Thumbnail" class="align-left thumbnail" /> Awesome.' );
+	}
+
+	/**
+	 * @group delete
+	 */
+	public function test_delete_activity_and_meta() {
+		// create an activity update
+		$parent_activity = $this->factory->activity->create( array(
+			'type' => 'activity_update',
+		) );
+
+		// create some activity comments
+		$comment_one = $this->factory->activity->create( array(
+			'type'              => 'activity_comment',
+			'item_id'           => $parent_activity,
+			'secondary_item_id' => $parent_activity,
+		) );
+
+		$comment_two = $this->factory->activity->create( array(
+			'type'              => 'activity_comment',
+			'item_id'           => $parent_activity,
+			'secondary_item_id' => $parent_activity,
+		) );
+
+		// add some meta to the activity items
+		bp_activity_update_meta( $parent_activity, 'foo', 'bar' );
+		bp_activity_update_meta( $comment_one,     'foo', 'bar' );
+		bp_activity_update_meta( $comment_two,     'foo', 'bar' );
+
+		// now delete the parent activity item
+		// this should hopefully delete the associated comments and meta entries
+		bp_activity_delete( array(
+			'id' => $parent_activity
+		) );
+
+		// now fetch the deleted activity entries
+		$get = bp_activity_get( array(
+			'in'               => array( $parent_activity, $comment_one, $comment_two ),
+			'display_comments' => 'stream'
+		) );
+
+		// activities should equal zero
+		$this->assertEquals( 0, $get['total'] );
+
+		// now fetch activity meta for the deleted activity entries
+		$m1 = bp_activity_get_meta( $parent_activity );
+		$m2 = bp_activity_get_meta( $comment_one );
+		$m3 = bp_activity_get_meta( $comment_two );
+
+		// test if activity meta entries still exist
+		$this->assertEquals( false, $m1 );
+		$this->assertEquals( false, $m2 );
+		$this->assertEquals( false, $m3 );
+	}
+
+	/**
+	 * @group bp_activity_update_meta
+	 * @ticket BP5180
+	 */
+	public function test_bp_activity_update_meta_with_line_breaks() {
+		$a = $this->factory->activity->create();
+		$meta_value = 'Foo!
+
+
+Bar!';
+		bp_activity_update_meta( $a, 'linebreak_test', $meta_value );
+		$this->assertEquals( $meta_value, bp_activity_get_meta( $a, 'linebreak_test' ) );
+	}
+
+	/**
+	 * @group bp_activity_update_meta
+	 * @ticket BP5083
+	 */
+	public function test_bp_activity_update_meta_with_0() {
+		$a = $this->factory->activity->create();
+		$meta_value = 0;
+
+		bp_activity_update_meta( $a, '0_test', $meta_value );
+
+		$this->assertNotSame( false, bp_activity_get_meta( $a, '0_test' ) );
+	}
+
+	/**
+	 * @group bp_activity_get_user_mentionname
+	 */
+	public function test_bp_activity_get_user_mentionname_compatibilitymode_off() {
+		add_filter( 'bp_is_username_compatibility_mode', '__return_false' );
+
+		$u = $this->create_user( array(
+			'user_login' => 'foo bar baz',
+			'user_nicename' => 'foo-bar-baz',
+		) );
+
+		$this->assertEquals( 'foo-bar-baz', bp_activity_get_user_mentionname( $u ) );
+
+		remove_filter( 'bp_is_username_compatibility_mode', '__return_false' );
+	}
+
+	/**
+	 * @group bp_activity_get_user_mentionname
+	 */
+	public function test_bp_activity_get_user_mentionname_compatibilitymode_on() {
+		add_filter( 'bp_is_username_compatibility_mode', '__return_true' );
+
+		$u1 = $this->create_user( array(
+			'user_login' => 'foo bar baz',
+			'user_nicename' => 'foo-bar-baz',
+		) );
+
+		$u2 = $this->create_user( array(
+			'user_login' => 'foo.bar.baz',
+			'user_nicename' => 'foo-bar-baz',
+		) );
+
+		$this->assertEquals( 'foo-bar-baz', bp_activity_get_user_mentionname( $u1 ) );
+		$this->assertEquals( 'foo.bar.baz', bp_activity_get_user_mentionname( $u2 ) );
+
+		remove_filter( 'bp_is_username_compatibility_mode', '__return_true' );
+	}
+
+	/**
+	 * @group bp_activity_get_userid_from_mentionname
+	 */
+	public function test_bp_activity_get_userid_from_mentionname_compatibilitymode_off() {
+		add_filter( 'bp_is_username_compatibility_mode', '__return_false' );
+
+		$u = $this->create_user( array(
+			'user_login' => 'foo bar baz',
+			'user_nicename' => 'foo-bar-baz',
+		) );
+
+		$this->assertEquals( $u, bp_activity_get_userid_from_mentionname( 'foo-bar-baz' ) );
+
+		remove_filter( 'bp_is_username_compatibility_mode', '__return_false' );
+	}
+
+	/**
+	 * @group bp_activity_get_userid_from_mentionname
+	 */
+	public function test_bp_activity_get_userid_from_mentionname_compatibilitymode_on() {
+		add_filter( 'bp_is_username_compatibility_mode', '__return_true' );
+
+		// all spaces are hyphens
+		$u1 = $this->create_user( array(
+			'user_login' => 'foo bar baz',
+			'user_nicename' => 'foobarbaz',
+		) );
+
+		// no spaces are hyphens
+		$u2 = $this->create_user( array(
+			'user_login' => 'foo-bar-baz-1',
+			'user_nicename' => 'foobarbaz-1',
+		) );
+
+		// some spaces are hyphens
+		$u3 = $this->create_user( array(
+			'user_login' => 'foo bar-baz 2',
+			'user_nicename' => 'foobarbaz-2',
+		) );
+
+		$u4 = $this->create_user( array(
+			'user_login' => 'foo.bar.baz',
+			'user_nicename' => 'foo-bar-baz',
+		) );
+
+		$this->assertEquals( $u1, bp_activity_get_userid_from_mentionname( 'foo-bar-baz' ) );
+		$this->assertEquals( $u2, bp_activity_get_userid_from_mentionname( 'foo-bar-baz-1' ) );
+		$this->assertEquals( $u3, bp_activity_get_userid_from_mentionname( 'foo-bar-baz-2' ) );
+		$this->assertEquals( $u4, bp_activity_get_userid_from_mentionname( 'foo.bar.baz' ) );
+
+		remove_filter( 'bp_is_username_compatibility_mode', '__return_true' );
+	}
+
+}
Index: /tags/1.9/tests/testcases/activity/template.php
===================================================================
--- /tags/1.9/tests/testcases/activity/template.php	(revision 7684)
+++ /tags/1.9/tests/testcases/activity/template.php	(revision 7684)
@@ -0,0 +1,256 @@
+<?php
+/**
+ * @group activity
+ */
+class BP_Tests_Activity_Template extends BP_UnitTestCase {
+	protected $old_current_user = 0;
+
+	public function setUp() {
+		parent::setUp();
+
+		$this->old_current_user = get_current_user_id();
+		$this->set_current_user( $this->factory->user->create( array( 'role' => 'subscriber' ) ) );
+	}
+
+	public function tearDown() {
+		parent::tearDown();
+		$this->set_current_user( $this->old_current_user );
+	}
+
+	/**
+	 * @ticket BP4735
+	 */
+	public function test_user_can_delete() {
+		global $bp;
+
+		$a = $this->factory->activity->create( array(
+			'type' => 'activity_update',
+		) );
+
+		// User can delete his own items
+		$activity = $this->factory->activity->get_object_by_id( $a );
+		$this->assertTrue( bp_activity_user_can_delete( $activity ) );
+
+		// Stash original user
+		$original_user = get_current_user_id();
+
+		// Logged-out user can't delete
+		$this->set_current_user( 0 );
+		$this->assertFalse( bp_activity_user_can_delete( $activity ) );
+
+		// Miscellaneous user can't delete
+		$misc_user = $this->factory->user->create( array( 'role' => 'subscriber' ) );
+		$this->set_current_user( $misc_user );
+		$this->assertFalse( bp_activity_user_can_delete( $activity ) );
+
+		// Item admin can delete
+		$is_single_item = $bp->is_single_item;
+		$bp->is_single_item = true;
+
+		$is_item_admin = $bp->is_item_admin;
+		$bp->is_item_admin = true;
+
+		$this->assertTrue( bp_activity_user_can_delete( $activity ) );
+
+		$bp->is_single_item = $is_single_item;
+		$bp->is_item_admin = $is_item_admin;
+		$this->set_current_user( $original_user );
+	}
+
+
+	/**
+	 * Make sure that action filters ('activity_update', etc) work when
+	 * limiting query to user favorites
+	 *
+	 * @ticket BP4872
+	 */
+	public function test_bp_has_activities_favorites_action_filter() {
+		$user_id = $this->factory->user->create( array( 'role' => 'subscriber' ) );
+
+		$now = time();
+
+		$a1 = $this->factory->activity->create( array(
+			'type' => 'activity_update',
+			'recorded_time' => date( 'Y-m-d H:i:s', $now ),
+		) );
+
+		$a2 = $this->factory->activity->create( array(
+			'type' => 'joined_group',
+			'recorded_time' => date( 'Y-m-d H:i:s', $now - 100 ),
+		) );
+
+		bp_activity_add_user_favorite( $a1, $user_id );
+		bp_activity_add_user_favorite( $a2, $user_id );
+
+		// groan. It sucks that you have to invoke the global
+		global $activities_template;
+
+		// Case 1: no action filter
+		bp_has_activities( array(
+			'user_id' => $user_id,
+			'scope' => 'favorites',
+		) );
+
+		// The formatting of $activities_template->activities is messed
+		// up, so we're just going to look at the IDs. This should be
+		// fixed in BP at some point
+		$ids = wp_list_pluck( $activities_template->activities, 'id' );
+
+		$this->assertEquals( array( $a1, $a2 ), $ids );
+
+		$activities_template = null;
+
+		// Case 2: action filter
+		bp_has_activities( array(
+			'user_id' => $user_id,
+			'scope' => 'favorites',
+			'action' => 'activity_update',
+		) );
+
+		global $wpdb, $bp;
+
+		$ids = wp_list_pluck( $activities_template->activities, 'id' );
+
+		$this->assertEquals( array( $a1 ), $ids );
+
+		$activities_template = null;
+	}
+
+	/**
+	 * Integration test for 'meta_query' param
+	 */
+	function test_bp_has_activities_with_meta_query() {
+		$a1 = $this->factory->activity->create();
+		$a2 = $this->factory->activity->create();
+		bp_activity_update_meta( $a1, 'foo', 'bar' );
+
+		global $activities_template;
+		bp_has_activities( array(
+			'meta_query' => array(
+				array(
+					'key' => 'foo',
+					'value' => 'bar',
+				),
+			),
+		) );
+
+		$ids = wp_list_pluck( $activities_template->activities, 'id' );
+		$this->assertEquals( $ids, array( $a1 ) );
+	}
+
+	/**
+	 * @ticket BP5029
+	 * @group bp_has_activities
+	 */
+	public function test_bp_has_activities_with_display_comments_false() {
+		$now = time();
+		$a1 = $this->factory->activity->create( array(
+			'content' => 'Life Rules',
+			'recorded_time' => date( 'Y-m-d H:i:s', $now ),
+		) );
+		$a2 = $this->factory->activity->create( array(
+			'content' => 'Life Drools',
+			'recorded_time' => date( 'Y-m-d H:i:s', $now - 100 ),
+		) );
+		$a3 = bp_activity_new_comment( array(
+			'activity_id' => $a1,
+			'content' => 'Candy is good',
+			'recorded_time' => date( 'Y-m-d H:i:s', $now - 50 ),
+		) );
+
+		global $activities_template;
+		bp_has_activities( array(
+			'display_comments' => false,
+		) );
+		$ids = wp_list_pluck( $activities_template->activities, 'id' );
+
+		$this->assertEquals( array( $a1, $a2 ), wp_parse_id_list( $ids ) );
+
+	}
+
+	/**
+	 * @ticket BP5029
+	 * @group bp_has_activities
+	 */
+	public function test_bp_has_activities_with_display_comments_0() {
+		$now = time();
+		$a1 = $this->factory->activity->create( array(
+			'content' => 'Life Rules',
+			'recorded_time' => date( 'Y-m-d H:i:s', $now ),
+		) );
+		$a2 = $this->factory->activity->create( array(
+			'content' => 'Life Drools',
+			'recorded_time' => date( 'Y-m-d H:i:s', $now - 100 ),
+		) );
+		$a3 = bp_activity_new_comment( array(
+			'activity_id' => $a1,
+			'content' => 'Candy is good',
+			'recorded_time' => date( 'Y-m-d H:i:s', $now - 50 ),
+		) );
+
+		global $activities_template;
+		bp_has_activities( array(
+			'display_comments' => 0,
+		) );
+		$ids = wp_list_pluck( $activities_template->activities, 'id' );
+
+		$this->assertEquals( array( $a1, $a2 ), wp_parse_id_list( $ids ) );
+
+	}
+
+	/**
+	 * @ticket BP5029
+	 * @group bp_has_activities
+	 */
+	public function test_bp_has_activities_with_display_comments_0_querystring() {
+		$now = time();
+		$a1 = $this->factory->activity->create( array(
+			'content' => 'Life Rules',
+			'recorded_time' => date( 'Y-m-d H:i:s', $now ),
+		) );
+		$a2 = $this->factory->activity->create( array(
+			'content' => 'Life Drools',
+			'recorded_time' => date( 'Y-m-d H:i:s', $now - 100 ),
+		) );
+		$a3 = bp_activity_new_comment( array(
+			'activity_id' => $a1,
+			'content' => 'Candy is good',
+			'recorded_time' => date( 'Y-m-d H:i:s', $now - 50 ),
+		) );
+
+		global $activities_template;
+		bp_has_activities( 'display_comments=0' );
+		$ids = wp_list_pluck( $activities_template->activities, 'id' );
+
+		$this->assertEquals( array( $a1, $a2 ), $ids );
+
+	}
+
+	/**
+	 * @ticket BP5029
+	 * @group bp_has_activities
+	 */
+	public function test_bp_has_activities_with_display_comments_none_querystring() {
+		$now = time();
+		$a1 = $this->factory->activity->create( array(
+			'content' => 'Life Rules',
+			'recorded_time' => date( 'Y-m-d H:i:s', $now ),
+		) );
+		$a2 = $this->factory->activity->create( array(
+			'content' => 'Life Drools',
+			'recorded_time' => date( 'Y-m-d H:i:s', $now - 100 ),
+		) );
+		$a3 = bp_activity_new_comment( array(
+			'activity_id' => $a1,
+			'content' => 'Candy is good',
+			'recorded_time' => date( 'Y-m-d H:i:s', $now - 50 ),
+		) );
+
+		global $activities_template;
+		bp_has_activities( 'display_comments=none' );
+		$ids = wp_list_pluck( $activities_template->activities, 'id' );
+
+		$this->assertEquals( array( $a1, $a2 ), $ids );
+
+	}
+}
Index: /tags/1.9/tests/testcases/admin/functions.php
===================================================================
--- /tags/1.9/tests/testcases/admin/functions.php	(revision 7684)
+++ /tags/1.9/tests/testcases/admin/functions.php	(revision 7684)
@@ -0,0 +1,123 @@
+<?php
+/**
+ * @group admin
+ */
+class BP_Tests_Admin_Functions extends BP_UnitTestCase {
+	protected $old_current_user = 0;
+
+	public function setUp() {
+		parent::setUp();
+		$this->old_current_user = get_current_user_id();
+		$this->set_current_user( $this->create_user( array( 'role' => 'administrator' ) ) );
+
+		if ( ! function_exists( 'bp_admin' ) ) {
+			require_once( BP_PLUGIN_DIR . 'bp-core/bp-core-admin.php' );
+		}
+
+		if ( ! function_exists( 'bp_new_site' ) ) {
+			bp_admin();
+		}
+	}
+
+	public function tearDown() {
+		parent::tearDown();
+		$this->set_current_user( $this->old_current_user );
+	}
+
+	public function test_bp_admin_list_table_current_bulk_action() {
+		$_REQUEST['action'] = 'foo';
+		$_REQUEST['action2'] = '-1';
+		$this->assertEquals( bp_admin_list_table_current_bulk_action(), 'foo' );
+
+		$_REQUEST['action'] = '-1';
+		$_REQUEST['action2'] = 'foo';
+		$this->assertEquals( bp_admin_list_table_current_bulk_action(), 'foo' );
+
+		$_REQUEST['action'] = 'bar';
+		$_REQUEST['action2'] = 'foo';
+		$this->assertEquals( bp_admin_list_table_current_bulk_action(), 'foo' );
+	}
+
+	public function test_bp_core_admin_get_active_components_from_submitted_settings() {
+		$get_action = isset( $_GET['action'] ) ? $_GET['action'] : null;
+		$ac = buddypress()->active_components;
+
+		// Standard deactivation from All screen
+		unset( $_GET['action'] );
+		buddypress()->active_components = array(
+			'activity' => 1,
+			'friends' => 1,
+			'groups' => 1,
+			'members' => 1,
+			'messages' => 1,
+			'settings' => 1,
+			'xprofile' => 1,
+		);
+
+		$submitted = array(
+			'groups' => 1,
+			'members' => 1,
+			'messages' => 1,
+			'settings' => 1,
+			'xprofile' => 1,
+		);
+
+		$this->assertEquals( bp_core_admin_get_active_components_from_submitted_settings( $submitted ), array( 'groups' => 1, 'members' => 1, 'messages' => 1, 'settings' => 1, 'xprofile' => 1 ) );
+
+		// Activating deactivated components from the Inactive screen
+		$_GET['action'] = 'inactive';
+		buddypress()->active_components = array(
+			'activity' => 1,
+			'members' => 1,
+			'messages' => 1,
+			'settings' => 1,
+			'xprofile' => 1,
+		);
+
+		$submitted2 = array(
+			'groups' => 1,
+		);
+
+		$this->assertEquals( bp_core_admin_get_active_components_from_submitted_settings( $submitted2 ), array( 'activity' => 1, 'groups' => 1, 'members' => 1, 'messages' => 1, 'settings' => 1, 'xprofile' => 1 ) );
+
+		// Activating from the Retired screen
+		$_GET['action'] = 'retired';
+		buddypress()->active_components = array(
+			'activity' => 1,
+			'members' => 1,
+			'messages' => 1,
+			'settings' => 1,
+			'xprofile' => 1,
+		);
+
+		$submitted3 = array(
+			'forums' => 1,
+		);
+
+		$this->assertEquals( bp_core_admin_get_active_components_from_submitted_settings( $submitted3 ), array( 'activity' => 1, 'forums' => 1, 'members' => 1, 'messages' => 1, 'settings' => 1, 'xprofile' => 1 ) );
+
+		// Deactivating from the Retired screen
+		$_GET['action'] = 'retired';
+		buddypress()->active_components = array(
+			'activity' => 1,
+			'forums' => 1,
+			'members' => 1,
+			'messages' => 1,
+			'settings' => 1,
+			'xprofile' => 1,
+		);
+
+		$submitted4 = array();
+
+		$this->assertEquals( bp_core_admin_get_active_components_from_submitted_settings( $submitted4 ), array( 'activity' => 1, 'members' => 1, 'messages' => 1, 'settings' => 1, 'xprofile' => 1 ) );
+
+		// reset
+		if ( $get_action ) {
+			$_GET['action'] = $get_action;
+		} else {
+			unset( $_GET['action'] );
+		}
+
+		buddypress()->active_components = $ac;
+	}
+}
Index: /tags/1.9/tests/testcases/blogs/class-bp-blogs-blog.php
===================================================================
--- /tags/1.9/tests/testcases/blogs/class-bp-blogs-blog.php	(revision 7684)
+++ /tags/1.9/tests/testcases/blogs/class-bp-blogs-blog.php	(revision 7684)
@@ -0,0 +1,67 @@
+<?php
+
+/**
+ * @group blogs
+ */
+class BP_Tests_BP_Blogs_Blog_TestCases extends BP_UnitTestCase {
+	public function setUp() {
+		parent::setUp();
+	}
+
+	public function tearDown() {
+		parent::tearDown();
+	}
+
+	public function test_get_with_search_terms() {
+		if ( ! is_multisite() ) {
+			return;
+		}
+
+		$old_user = get_current_user_id();
+
+		$u = $this->create_user();
+		$this->set_current_user( $u );
+		$b = $this->factory->blog->create( array(
+			'title' => 'The Foo Bar Blog',
+			'user_id' => $u,
+		) );
+		bp_blogs_record_existing_blogs();
+
+		// make the blog public or it won't turn up in generic results
+		update_blog_option( $b, 'blog_public', '1' );
+
+		$blogs = BP_Blogs_Blog::get( 'active', false, false, 0, 'Foo' );
+		$blog_ids = wp_list_pluck( $blogs['blogs'], 'blog_id' );
+
+		$this->assertEquals( array( $b ), $blog_ids );
+
+		$this->set_current_user( $old_user );
+	}
+
+	public function test_search_blogs() {
+		if ( ! is_multisite() ) {
+			return;
+		}
+
+		$old_user = get_current_user_id();
+
+		$u = $this->create_user();
+		$this->set_current_user( $u );
+		$b = $this->factory->blog->create( array(
+			'title' => 'The Foo Bar Blog',
+			'user_id' => $u,
+		) );
+		bp_blogs_record_existing_blogs();
+
+		// make the blog public or it won't turn up in generic results
+		update_blog_option( $b, 'blog_public', '1' );
+
+		$blogs = BP_Blogs_Blog::search_blogs( 'Foo' );
+		$blog_ids = wp_list_pluck( $blogs['blogs'], 'blog_id' );
+
+		$this->assertEquals( array( $b ), $blog_ids );
+
+		$this->set_current_user( $old_user );
+	}
+
+}
Index: /tags/1.9/tests/testcases/core/avatars.php
===================================================================
--- /tags/1.9/tests/testcases/core/avatars.php	(revision 7684)
+++ /tags/1.9/tests/testcases/core/avatars.php	(revision 7684)
@@ -0,0 +1,56 @@
+<?php
+/**
+ * @group core
+ * @group avatars
+ */
+class BP_Tests_Avatars extends BP_UnitTestCase {
+	protected $old_current_user = 0;
+
+	public function setUp() {
+		parent::setUp();
+
+		$this->old_current_user = get_current_user_id();
+		$this->administrator    = $this->factory->user->create( array( 'role' => 'administrator' ) );
+		wp_set_current_user( $this->administrator );
+	}
+
+	public function tearDown() {
+		parent::tearDown();
+		wp_set_current_user( $this->old_current_user );
+	}
+
+	/**
+	 * @ticket 4948
+	 */
+	function test_avatars_on_non_root_blog() {
+		// Do not pass 'Go', do not collect $200
+		if ( ! is_multisite() ) {
+			return;
+		}
+
+		// switch to BP root blog if necessary
+		if ( bp_get_root_blog_id() != get_current_blog_id() ) {
+			$this->go_to_root();
+		}
+
+		// get BP root blog's upload directory data
+		$upload_dir = wp_upload_dir();
+
+		restore_current_blog();
+
+		// create new subsite
+		$blog_id = $this->factory->blog->create( array(
+			'user_id' => $this->administrator,
+			'title'   => 'Test Title'
+		) );
+
+		// emulate a page load on the new sub-site
+		$this->go_to( get_blog_option( $blog_id, 'siteurl' ) );
+
+		// test to see if the upload dir is correct
+		$this->assertEquals( $upload_dir['baseurl'], bp_core_avatar_url() );
+
+		// reset globals
+		$this->go_to_root();
+	}
+}
Index: /tags/1.9/tests/testcases/core/class-bp-core-user.php
===================================================================
--- /tags/1.9/tests/testcases/core/class-bp-core-user.php	(revision 7684)
+++ /tags/1.9/tests/testcases/core/class-bp-core-user.php	(revision 7684)
@@ -0,0 +1,124 @@
+<?php
+
+/**
+ * @group core
+ */
+class BP_Tests_BP_Core_User_TestCases extends BP_UnitTestCase {
+	protected $old_current_user = 0;
+
+	public function setUp() {
+		parent::setUp();
+	}
+
+	public function tearDown() {
+		parent::tearDown();
+	}
+
+	/**
+	 * @expectedDeprecated BP_Core_User::get_users
+	 */
+	public function test_get_users_with_exclude_querystring() {
+		$u1 = $this->create_user();
+		$u2 = $this->create_user();
+		$u3 = $this->create_user();
+
+		$exclude_qs = $u1 . ',junkstring,' . $u3;
+
+		$users = BP_Core_User::get_users( 'active', 0, 1, 0, false, false, true, $exclude_qs );
+		$user_ids = wp_parse_id_list( wp_list_pluck( $users['users'], 'id' ) );
+
+		$this->assertEquals( array( $u2 ), $user_ids );
+	}
+
+	/**
+	 * @expectedDeprecated BP_Core_User::get_users
+	 */
+	public function test_get_users_with_exclude_array() {
+		$u1 = $this->create_user();
+		$u2 = $this->create_user();
+		$u3 = $this->create_user();
+
+		$exclude_array = array(
+			$u1,
+			'junkstring',
+			$u3,
+		);
+
+		$users = BP_Core_User::get_users( 'active', 0, 1, 0, false, false, true, $exclude_array );
+		$user_ids = wp_parse_id_list( wp_list_pluck( $users['users'], 'id' ) );
+
+		$this->assertEquals( array( $u2 ), $user_ids );
+	}
+
+	/**
+	 * @expectedDeprecated BP_Core_User::get_users
+	 */
+	public function test_get_users_with_include_querystring() {
+		$u1 = $this->create_user( array(
+			'last_activity' => gmdate( 'Y-m-d H:i:s' ),
+		) );
+		$u2 = $this->create_user( array(
+			'last_activity' => gmdate( 'Y-m-d H:i:s', time() - 1000 ),
+		) );
+		$u3 = $this->create_user( array(
+			'last_activity' => gmdate( 'Y-m-d H:i:s', time() - 50 ),
+		) );
+
+		$include_qs = $u1 . ',junkstring,' . $u3;
+
+		$users = BP_Core_User::get_users( 'active', 0, 1, 0, $include_qs );
+		$user_ids = wp_parse_id_list( wp_list_pluck( $users['users'], 'id' ) );
+
+		$this->assertEquals( array( $u1, $u3 ), $user_ids );
+	}
+
+	/**
+	 * @expectedDeprecated BP_Core_User::get_users
+	 */
+	public function test_get_users_with_include_array() {
+		$u1 = $this->create_user( array(
+			'last_activity' => gmdate( 'Y-m-d H:i:s' ),
+		) );
+		$u2 = $this->create_user( array(
+			'last_activity' => gmdate( 'Y-m-d H:i:s', time() - 1000 ),
+		) );
+		$u3 = $this->create_user( array(
+			'last_activity' => gmdate( 'Y-m-d H:i:s', time() - 50 ),
+		) );
+
+
+		$include_array = array(
+			$u1,
+			'junkstring',
+			$u3,
+		);
+
+		$users = BP_Core_User::get_users( 'active', 0, 1, 0, $include_array );
+		$user_ids = wp_list_pluck( $users['users'], 'id' );
+
+		// typecast...ugh
+		$user_ids = array_map( 'intval', $user_ids );
+
+		$this->assertEquals( array( $u1, $u3 ), $user_ids );
+	}
+
+	public function test_get_specific_users() {
+		$u1 = $this->create_user();
+		$u2 = $this->create_user();
+		$u3 = $this->create_user();
+
+		$include_array = array(
+			$u1,
+			'junkstring',
+			$u3,
+		);
+
+		$users = BP_Core_User::get_specific_users( $include_array );
+		$user_ids = wp_parse_id_list( wp_list_pluck( $users['users'], 'id' ) );
+
+		$this->assertEquals( array( $u1, $u3 ), $user_ids );
+	}
+
+
+
+}
Index: /tags/1.9/tests/testcases/core/class-bp-user-query.php
===================================================================
--- /tags/1.9/tests/testcases/core/class-bp-user-query.php	(revision 7684)
+++ /tags/1.9/tests/testcases/core/class-bp-user-query.php	(revision 7684)
@@ -0,0 +1,301 @@
+<?php
+
+/**
+ * @group core
+ * @group BP_User_Query
+ */
+class BP_Tests_BP_User_Query_TestCases extends BP_UnitTestCase {
+	protected $old_current_user = 0;
+
+	public function setUp() {
+		parent::setUp();
+
+		$this->old_current_user = get_current_user_id();
+		$this->set_current_user( $this->factory->user->create( array( 'role' => 'administrator' ) ) );
+	}
+
+	public function tearDown() {
+		parent::tearDown();
+		$this->set_current_user( $this->old_current_user );
+	}
+
+	/**
+	 * Checks that user_id returns friends
+	 */
+	public function test_bp_user_query_friends() {
+		$u1 = $this->create_user();
+		$u2 = $this->create_user();
+		$u3 = $this->create_user();
+		friends_add_friend( $u1, $u2, true );
+
+		$q = new BP_User_Query( array(
+			'user_id' => $u2,
+		) );
+
+		$friends = is_array( $q->results ) ? array_values( $q->results ) : array();
+		$friend_ids = wp_list_pluck( $friends, 'ID' );
+		$this->assertEquals( $friend_ids, array( $u1 ) );
+	}
+
+	/**
+	 * @ticket 4938
+	 */
+	public function test_bp_user_query_friends_with_include() {
+		$u1 = $this->create_user();
+		$u2 = $this->create_user();
+		$u3 = $this->create_user();
+		$u4 = $this->create_user();
+		friends_add_friend( $u1, $u2, true );
+		friends_add_friend( $u1, $u3, true );
+
+		$q = new BP_User_Query( array(
+			'user_id' => $u1,
+
+			// Represents an independent filter passed by a plugin
+			// u4 is not a friend of u1 and should not be returned
+			'include' => array( $u2, $u4 ),
+		) );
+
+		$friends = is_array( $q->results ) ? array_values( $q->results ) : array();
+		$friend_ids = wp_list_pluck( $friends, 'ID' );
+		$this->assertEquals( $friend_ids, array( $u2 ) );
+	}
+
+	public function test_bp_user_query_friends_with_include_but_zero_friends() {
+		$u1 = $this->create_user();
+		$u2 = $this->create_user();
+		$u3 = $this->create_user();
+		$u4 = $this->create_user();
+
+		$q = new BP_User_Query( array(
+			'user_id' => $u1,
+
+			// Represents an independent filter passed by a plugin
+			// u4 is not a friend of u1 and should not be returned
+			'include' => array( $u2, $u4 ),
+		) );
+
+		$friends = is_array( $q->results ) ? array_values( $q->results ) : array();
+		$friend_ids = wp_list_pluck( $friends, 'ID' );
+		$this->assertEquals( $friend_ids, array() );
+	}
+
+	public function test_bp_user_query_sort_by_popular() {
+		$u1 = $this->create_user();
+		$u2 = $this->create_user();
+		$u3 = $this->create_user();
+		$u4 = $this->create_user();
+
+		bp_update_user_meta( $u1, bp_get_user_meta_key( 'total_friend_count' ), '5' );
+		bp_update_user_meta( $u2, bp_get_user_meta_key( 'total_friend_count' ), '90' );
+		bp_update_user_meta( $u3, bp_get_user_meta_key( 'total_friend_count' ), '101' );
+		bp_update_user_meta( $u4, bp_get_user_meta_key( 'total_friend_count' ), '3002' );
+
+		$q = new BP_User_Query( array(
+			'type' => 'popular',
+		) );
+
+		$users = is_array( $q->results ) ? array_values( $q->results ) : array();
+		$user_ids = wp_parse_id_list( wp_list_pluck( $users, 'ID' ) );
+
+		$expected = array( $u4, $u3, $u2, $u1 );
+		$this->assertEquals( $expected, $user_ids );
+	}
+
+	/**
+	 * @group online
+	 */
+	public function test_bp_user_query_type_online() {
+		$now = time();
+		$u1 = $this->create_user( array(
+			'last_activity' => date( 'Y-m-d H:i:s', $now ),
+		) );
+		$u2 = $this->create_user( array(
+			'last_activity' => date( 'Y-m-d H:i:s', $now - 60*13 ),
+		) );
+		$u3 = $this->create_user( array(
+			'last_activity' => date( 'Y-m-d H:i:s', $now - 60*16 ),
+		) );
+
+		$q = new BP_User_Query( array(
+			'type' => 'online',
+		) );
+
+		$users = is_array( $q->results ) ? array_values( $q->results ) : array();
+		$user_ids = wp_parse_id_list( wp_list_pluck( $users, 'ID' ) );
+		$this->assertEquals( array( $u1, $u2 ), $user_ids );
+	}
+
+	/**
+	 * @group online
+	 */
+	public function test_bp_user_query_type_online_five_minute_interval() {
+		$now = time();
+		$u1 = $this->create_user( array(
+			'last_activity' => date( 'Y-m-d H:i:s', $now ),
+		) );
+		$u2 = $this->create_user( array(
+			'last_activity' => date( 'Y-m-d H:i:s', $now - 60*4 ),
+		) );
+		$u3 = $this->create_user( array(
+			'last_activity' => date( 'Y-m-d H:i:s', $now - 60*6 ),
+		) );
+
+		add_filter( 'bp_user_query_online_interval', create_function( '', 'return 5;' ) );
+
+		$q = new BP_User_Query( array(
+			'type' => 'online',
+		) );
+
+		$users = is_array( $q->results ) ? array_values( $q->results ) : array();
+		$user_ids = wp_parse_id_list( wp_list_pluck( $users, 'ID' ) );
+		$this->assertEquals( array( $u1, $u2 ), $user_ids );
+	}
+
+
+	public function test_bp_user_query_search_with_apostrophe() {
+		// Apostrophe. Search_terms must escaped to mimic POST payload
+		$user_id = $this->create_user();
+		xprofile_set_field_data( 1, $user_id, "Foo'Bar" );
+		$q = new BP_User_Query( array( 'search_terms' => "oo\'Ba", ) );
+
+		$found_user_id = null;
+		if ( ! empty( $q->results ) ) {
+			$found_user = array_pop( $q->results );
+			$found_user_id = $found_user->ID;
+		}
+
+		$this->assertEquals( $user_id, $found_user_id );
+	}
+
+	public function test_bp_user_query_search_with_percent_sign() {
+
+		// LIKE special character: %
+		$user_id = $this->create_user();
+		xprofile_set_field_data( 1, $user_id, "Foo%Bar" );
+		$q = new BP_User_Query( array( 'search_terms' => "oo%Bar", ) );
+
+		$found_user_id = null;
+		if ( ! empty( $q->results ) ) {
+			$found_user = array_pop( $q->results );
+			$found_user_id = $found_user->ID;
+		}
+
+		$this->assertEquals( $user_id, $found_user_id );
+
+	}
+
+	public function test_bp_user_query_search_with_underscore() {
+
+		// LIKE special character: _
+		$user_id = $this->create_user();
+		xprofile_set_field_data( 1, $user_id, "Foo_Bar" );
+		$q = new BP_User_Query( array( 'search_terms' => "oo_Bar", ) );
+
+		$found_user_id = null;
+		if ( ! empty( $q->results ) ) {
+			$found_user = array_pop( $q->results );
+			$found_user_id = $found_user->ID;
+		}
+
+		$this->assertEquals( $user_id, $found_user_id );
+	}
+
+	/**
+	 * @group exclude
+	 */
+	public function test_bp_user_query_with_exclude() {
+		// Grab list of existing users who should also be excluded
+		global $wpdb;
+		$existing_users = $wpdb->get_col( "SELECT ID FROM {$wpdb->users}" );
+
+		$u1 = $this->create_user();
+		$u2 = $this->create_user();
+
+		$exclude = array_merge( array( $u1 ), $existing_users );
+		$q = new BP_User_Query( array( 'exclude' => $exclude, ) );
+
+		$found_user_ids = null;
+		if ( ! empty( $q->results ) ) {
+			$found_user_ids = array_values( wp_parse_id_list( wp_list_pluck( $q->results, 'ID' ) ) );
+		}
+
+		$this->assertEquals( array( $u2 ), $found_user_ids );
+	}
+
+	/**
+	 * @group type
+	 * @group spam
+	 */
+	public function test_bp_user_query_type_alphabetical_spam_xprofileon() {
+		if ( is_multisite() ) {
+			return;
+		}
+
+		// Make sure xprofile is on
+		$xprofile_toggle = isset( buddypress()->active_components['xprofile'] );
+		buddypress()->active_components['xprofile'] = 1;
+		add_filter( 'bp_disable_profile_sync', '__return_false' );
+
+		$u1 = $this->create_user();
+		$u2 = $this->create_user();
+
+		global $wpdb;
+		bp_core_process_spammer_status( $u1, 'spam' );
+
+		$q = new BP_User_Query( array( 'type' => 'alphabetical', ) );
+
+		// Restore xprofile setting
+		if ( $xprofile_toggle ) {
+			buddypress()->active_components['xprofile'] = 1;
+		} else {
+			unset( buddypress()->active_components['xprofile'] );
+		}
+		remove_filter( 'bp_disable_profile_sync', '__return_false' );
+
+		$found_user_ids = null;
+
+		if ( ! empty( $q->results ) ) {
+			$found_user_ids = array_values( wp_parse_id_list( wp_list_pluck( $q->results, 'ID' ) ) );
+		}
+
+		// Do a assertNotContains because there are weird issues with user #1 as created by WP
+		$this->assertNotContains( $u1, $found_user_ids );
+	}
+
+	/**
+	 * @group type
+	 * @group spam
+	 */
+	public function test_bp_user_query_type_alphabetical_spam_xprofileoff() {
+		$u1 = $this->create_user();
+		$u2 = $this->create_user();
+
+		// Make sure xprofile and profile sync are off
+		$xprofile_toggle = isset( buddypress()->active_components['xprofile'] );
+		buddypress()->active_components['xprofile'] = 0;
+		add_filter( 'bp_disable_profile_sync', '__return_false' );
+
+		bp_core_process_spammer_status( $u1, 'spam' );
+
+		$q = new BP_User_Query( array( 'type' => 'alphabetical', ) );
+
+		// Restore xprofile setting
+		if ( $xprofile_toggle ) {
+			buddypress()->active_components['xprofile'] = 1;
+		} else {
+			unset( buddypress()->active_components['xprofile'] );
+		}
+		remove_filter( 'bp_disable_profile_sync', '__return_false' );
+
+		$found_user_ids = null;
+
+		if ( ! empty( $q->results ) ) {
+			$found_user_ids = array_values( wp_parse_id_list( wp_list_pluck( $q->results, 'ID' ) ) );
+		}
+
+		// Do a assertNotContains because there are weird issues with user #1 as created by WP
+		$this->assertNotContains( $u1, $found_user_ids );
+	}
+
+}
Index: /tags/1.9/tests/testcases/core/functions.php
===================================================================
--- /tags/1.9/tests/testcases/core/functions.php	(revision 7684)
+++ /tags/1.9/tests/testcases/core/functions.php	(revision 7684)
@@ -0,0 +1,258 @@
+<?php
+
+/**
+ * @group core
+ */
+
+class BP_Tests_Core_Functions extends BP_UnitTestCase {
+	/**
+	 * @group bp_esc_sql_order
+	 */
+	public function test_bp_esc_sql_order_ASC() {
+		$this->assertEquals( 'ASC', bp_esc_sql_order( 'ASC' ) );
+	}
+
+	/**
+	 * @group bp_esc_sql_order
+	 */
+	public function test_bp_esc_sql_order_DESC() {
+		$this->assertEquals( 'DESC', bp_esc_sql_order( 'DESC' ) );
+	}
+
+	/**
+	 * @group bp_esc_sql_order
+	 */
+	public function test_bp_esc_sql_order_desc_lowercase() {
+		$this->assertEquals( 'DESC', bp_esc_sql_order( 'desc' ) );
+	}
+
+	/**
+	 * @group bp_esc_sql_order
+	 */
+	public function test_bp_esc_sql_order_desc_whitespace() {
+		$this->assertEquals( 'DESC', bp_esc_sql_order( ' desc ' ) );
+	}
+
+	/**
+	 * @group bp_esc_sql_order
+	 */
+	public function test_bp_esc_sql_order_invalid() {
+		$this->assertEquals( 'ASC', bp_esc_sql_order( 'In ur base killin ur d00dz' ) );
+	}
+
+	/**
+	 * @group bp_core_time_since
+	 */
+	public function test_bp_core_time_since_years_months() {
+		$now = time();
+		$then = $now - ( 3 * YEAR_IN_SECONDS ) - ( 3 * 30 * DAY_IN_SECONDS );
+		$this->assertEquals( '3 years, 3 months ago', bp_core_time_since( $then, $now ) );
+	}
+
+	/**
+	 * @group bp_core_time_since
+	 */
+	public function test_bp_core_time_since_years_nomonths() {
+		$now = time();
+		$then = $now - ( 3 * YEAR_IN_SECONDS );
+		$this->assertEquals( '3 years ago', bp_core_time_since( $then, $now ) );
+	}
+
+	/**
+	 * @group bp_core_time_since
+	 */
+	public function test_bp_core_time_since_months_weeks() {
+		$now = time();
+		$then = $now - ( 3 * 30 * DAY_IN_SECONDS ) - ( 3 * WEEK_IN_SECONDS );
+		$this->assertEquals( '3 months, 3 weeks ago', bp_core_time_since( $then, $now ) );
+	}
+
+	/**
+	 * @group bp_core_time_since
+	 */
+	public function test_bp_core_time_since_months_noweeks() {
+		$now = time();
+		$then = $now - ( 3 * 30 * DAY_IN_SECONDS );
+		$this->assertEquals( '3 months ago', bp_core_time_since( $then, $now ) );
+	}
+
+	/**
+	 * @group bp_core_time_since
+	 */
+	public function test_bp_core_time_since_weeks_days() {
+		$now = time();
+		$then = $now - ( 3 * WEEK_IN_SECONDS ) - ( 3 * DAY_IN_SECONDS );
+		$this->assertEquals( '3 weeks, 3 days ago', bp_core_time_since( $then, $now ) );
+	}
+
+	/**
+	 * @group bp_core_time_since
+	 */
+	public function test_bp_core_time_since_weeks_nodays() {
+		$now = time();
+		$then = $now - ( 3 * WEEK_IN_SECONDS );
+		$this->assertEquals( '3 weeks ago', bp_core_time_since( $then, $now ) );
+	}
+
+	/**
+	 * @group bp_core_time_since
+	 */
+	public function test_bp_core_time_since_days_hours() {
+		$now = time();
+		$then = $now - ( 3 * DAY_IN_SECONDS ) - ( 3 * HOUR_IN_SECONDS );
+		$this->assertEquals( '3 days, 3 hours ago', bp_core_time_since( $then, $now ) );
+	}
+
+	/**
+	 * @group bp_core_time_since
+	 */
+	public function test_bp_core_time_since_days_nohours() {
+		$now = time();
+		$then = $now - ( 3 * DAY_IN_SECONDS );
+		$this->assertEquals( '3 days ago', bp_core_time_since( $then, $now ) );
+	}
+
+	/**
+	 * @group bp_core_time_since
+	 */
+	public function test_bp_core_time_since_hours_minutes() {
+		$now = time();
+		$then = $now - ( 3 * HOUR_IN_SECONDS ) - ( 3 * MINUTE_IN_SECONDS );
+		$this->assertEquals( '3 hours, 3 minutes ago', bp_core_time_since( $then, $now ) );
+	}
+
+	/**
+	 * @group bp_core_time_since
+	 */
+	public function test_bp_core_time_since_hours_nominutes() {
+		$now = time();
+		$then = $now - ( 3 * HOUR_IN_SECONDS );
+		$this->assertEquals( '3 hours ago', bp_core_time_since( $then, $now ) );
+	}
+
+	/**
+	 * @group bp_core_time_since
+	 * @ticket BP5017
+	 */
+	public function test_bp_core_time_since_minutes_seconds() {
+		$now = time();
+		$then = $now - ( 3 * MINUTE_IN_SECONDS ) - 3;
+		$this->assertEquals( '3 minutes ago', bp_core_time_since( $then, $now ) );
+	}
+
+	/**
+	 * @group bp_core_time_since
+	 */
+	public function test_bp_core_time_since_minutes_noseconds() {
+		$now = time();
+		$then = $now - ( 3 * MINUTE_IN_SECONDS );
+		$this->assertEquals( '3 minutes ago', bp_core_time_since( $then, $now ) );
+	}
+
+	/**
+	 * @group bp_core_time_since
+	 */
+	public function test_bp_core_time_since_seconds() {
+		$now = time();
+		$then = $now - 3;
+		$this->assertEquals( '3 seconds ago', bp_core_time_since( $then, $now ) );
+	}
+
+	/**
+	 * Sanity check for the singular version of 'year'
+	 *
+	 * @group bp_core_time_since
+	 */
+	public function test_bp_core_time_since_year() {
+		$now = time();
+		$then = $now - YEAR_IN_SECONDS;
+		$this->assertEquals( '1 year ago', bp_core_time_since( $then, $now ) );
+	}
+
+	/**
+	 * @group bp_core_time_since
+	 */
+	public function test_bp_core_time_since_rightnow() {
+		$now = time();
+		$then = $now;
+		$this->assertEquals( 'right now', bp_core_time_since( $then, $now ) );
+	}
+
+	/**
+	 * @group bp_core_time_since
+	 */
+	public function test_bp_core_time_since_future() {
+		$now = time();
+		$then = $now + 100;
+		$this->assertEquals( 'sometime ago', bp_core_time_since( $then, $now ) );
+	}
+
+	/**
+	 * @group bp_alpha_sort_by_key
+	 */
+	public function test_bp_alpha_sort_by_key_arrays() {
+		$items = array(
+			array(
+				'foo' => 'bar',
+				'name' => 'alpha',
+			),
+			array(
+				'foo' => 'bar',
+				'name' => 'charlie',
+			),
+			array(
+				'foo' => 'bar',
+				'name' => 'beta',
+			),
+		);
+
+		$expected = array(
+			array(
+				'foo' => 'bar',
+				'name' => 'alpha',
+			),
+			array(
+				'foo' => 'bar',
+				'name' => 'beta',
+			),
+			array(
+				'foo' => 'bar',
+				'name' => 'charlie',
+			),
+		);
+
+		$this->assertEquals( $expected, bp_alpha_sort_by_key( $items, 'name' ) );
+	}
+
+	/**
+	 * @group bp_alpha_sort_by_key
+	 */
+	public function test_bp_alpha_sort_by_key_objects() {
+		$items = array(
+			new stdClass,
+			new stdClass,
+			new stdClass,
+		);
+		$items[0]->foo = 'bar';
+		$items[0]->name = 'alpha';
+		$items[1]->foo = 'bar';
+		$items[1]->name = 'charlie';
+		$items[2]->foo = 'bar';
+		$items[2]->name = 'beta';
+
+		$expected = array(
+			new stdClass,
+			new stdClass,
+			new stdClass,
+		);
+		$expected[0]->foo = 'bar';
+		$expected[0]->name = 'alpha';
+		$expected[1]->foo = 'bar';
+		$expected[1]->name = 'beta';
+		$expected[2]->foo = 'bar';
+		$expected[2]->name = 'charlie';
+
+		$this->assertEquals( $expected, bp_alpha_sort_by_key( $items, 'name' ) );
+	}
+
+}
Index: /tags/1.9/tests/testcases/friends/class-bp-friends-friendship.php
===================================================================
--- /tags/1.9/tests/testcases/friends/class-bp-friends-friendship.php	(revision 7684)
+++ /tags/1.9/tests/testcases/friends/class-bp-friends-friendship.php	(revision 7684)
@@ -0,0 +1,118 @@
+<?php
+
+/**
+ * @group friends
+ */
+class BP_Tests_BP_Friends_Friendship_TestCases extends BP_UnitTestCase {
+	protected $old_current_user = 0;
+
+	public function setUp() {
+		parent::setUp();
+
+		$this->old_current_user = get_current_user_id();
+		$this->set_current_user( $this->factory->user->create( array( 'role' => 'subscriber' ) ) );
+	}
+
+	public function tearDown() {
+		parent::tearDown();
+		$this->set_current_user( $this->old_current_user );
+	}
+
+	public function test_search_friends() {
+		$u1 = $this->create_user();
+		$u2 = $this->create_user();
+		$u3 = $this->create_user();
+
+		xprofile_set_field_data( 1, $u2, 'Cool Dude' );
+		xprofile_set_field_data( 1, $u3, 'Rock And Roll America Yeah' );
+
+		friends_add_friend( $u1, $u2, true );
+		friends_add_friend( $u1, $u3, true );
+
+		$friends = BP_Friends_Friendship::search_friends( 'Coo', $u1 );
+		$this->assertEquals( array( $u2 ), $friends['friends'] );
+	}
+
+	public function test_get_bulk_last_active() {
+		$u1 = $this->create_user( array(
+			'last_activity' => gmdate( 'Y-m-d H:i:s' ),
+		) );
+		$u2 = $this->create_user( array(
+			'last_activity' => gmdate( 'Y-m-d H:i:s', time() - 1000 ),
+		) );
+		$u3 = $this->create_user( array(
+			'last_activity' => gmdate( 'Y-m-d H:i:s', time() - 50 ),
+		) );
+
+		$friends = BP_Friends_Friendship::get_bulk_last_active( array( $u1, $u2, $u3, 'junk' ) );
+		$friend_ids = wp_list_pluck( $friends, 'user_id' );
+		$this->assertEquals( array( $u1, $u3, $u2 ), $friend_ids );
+	}
+
+	public function test_search_users() {
+		$u1 = $this->create_user();
+		$u2 = $this->create_user();
+		$u3 = $this->create_user();
+
+		xprofile_set_field_data( 1, $u1, 'Freedom Isn\'t Free' );
+		xprofile_set_field_data( 1, $u2, 'Cool Dude' );
+		xprofile_set_field_data( 1, $u3, 'Rock And Roll America Yeah' );
+
+		// Needs a user_id param though it does nothing
+		$friends = BP_Friends_Friendship::search_users( 'Coo', 1 );
+		$this->assertEquals( array( $u2 ), $friends );
+	}
+
+	public function test_search_users_count() {
+		$u1 = $this->create_user();
+		$u2 = $this->create_user();
+		$u3 = $this->create_user();
+
+		xprofile_set_field_data( 1, $u1, 'Freedom Isn\'t Free' );
+		xprofile_set_field_data( 1, $u2, 'Cool Dude' );
+		xprofile_set_field_data( 1, $u3, 'Rock And Roll America Yeah' );
+
+		// Needs a user_id param though it does nothing
+		$friends = BP_Friends_Friendship::search_users_count( 'Coo' );
+		$this->assertEquals( 1, $friends );
+	}
+
+	/**
+	 * @group check_is_friend
+	 */
+	public function test_check_is_friend_not_friends() {
+		$u1 = $this->create_user();
+		$u2 = $this->create_user();
+		$this->assertEquals( 'not_friends', BP_Friends_Friendship::check_is_friend( $u1, $u2 ) );
+	}
+
+	/**
+	 * @group check_is_friend
+	 */
+	public function test_check_is_friend_pending() {
+		$u1 = $this->create_user();
+		$u2 = $this->create_user();
+		friends_add_friend( $u1, $u2, false );
+		$this->assertEquals( 'pending', BP_Friends_Friendship::check_is_friend( $u1, $u2 ) );
+	}
+
+	/**
+	 * @group check_is_friend
+	 */
+	public function test_check_is_friend_awaiting_response() {
+		$u1 = $this->create_user();
+		$u2 = $this->create_user();
+		friends_add_friend( $u1, $u2, false );
+		$this->assertEquals( 'awaiting_response', BP_Friends_Friendship::check_is_friend( $u2, $u1 ) );
+	}
+
+	/**
+	 * @group check_is_friend
+	 */
+	public function test_check_is_friend_is_friend() {
+		$u1 = $this->create_user();
+		$u2 = $this->create_user();
+		friends_add_friend( $u1, $u2, true );
+		$this->assertEquals( 'is_friend', BP_Friends_Friendship::check_is_friend( $u1, $u2 ) );
+	}
+}
Index: /tags/1.9/tests/testcases/groups/class-bp-group-extension.php
===================================================================
--- /tags/1.9/tests/testcases/groups/class-bp-group-extension.php	(revision 7684)
+++ /tags/1.9/tests/testcases/groups/class-bp-group-extension.php	(revision 7684)
@@ -0,0 +1,225 @@
+<?php
+
+include_once BP_TESTS_DIR . '/assets/group-extensions.php';
+
+/**
+ * @group groups
+ * @group BP_Group_Extension
+ */
+class BP_Tests_Group_Extension_TestCases extends BP_UnitTestCase {
+	public function setUp() {
+		parent::setUp();
+	}
+
+	public function tearDown() {
+		parent::tearDown();
+	}
+
+	public function test_parse_legacy_properties() {
+		$class_name = 'BPTest_Group_Extension_Parse_Legacy_Properties';
+		$class_slug = sanitize_title( $class_name );
+		$e = new $class_name();
+		$e->_register();
+
+		// Test most items separately so we can ignore irrelevant props
+		$l = $e->_get_legacy_properties_converted();
+		$this->assertEquals( $l['name'], $class_name );
+		$this->assertEquals( $l['slug'], $class_slug );
+		$this->assertEquals( $l['visibility'], 'private' );
+		$this->assertEquals( $l['nav_item_position'], 63 );
+		$this->assertEquals( $l['enable_nav_item'], true );
+		$this->assertEquals( $l['nav_item_name'], $class_name . ' Nav' );
+		$this->assertEquals( $l['display_hook'], 'foo_hook' );
+		$this->assertEquals( $l['template_file'], 'foo_template' );
+
+		// Build the screens array manually
+		$expected = array(
+			'create' => array(
+				'name' => $class_name . ' Create',
+				'slug' => $class_slug . '-create',
+				'position' => 58,
+				'enabled' => false,
+			),
+			'edit' => array(
+				'name' => $class_name . ' Edit',
+				'slug' => $class_slug . '-edit',
+				'enabled' => false,
+			),
+			'admin' => array(
+				'enabled' => true,
+				'metabox_context' => 'high',
+				'metabox_priority' => 'side',
+			),
+		);
+
+		$this->assertEquals( $expected, $l['screens'] );
+	}
+
+	public function test_setup_screens_use_global_fallbacks() {
+		$class_name = 'BPTest_Group_Extension_Setup_Screens_Use_Global_Fallbacks';
+		$e = new $class_name();
+		$e->_setup_class_info();
+		$screens = $e->_get_default_screens();
+
+		$fallback = array(
+			'screen_callback' => array( $e, 'settings_screen' ),
+			'screen_save_callback' => array( $e, 'settings_screen_save' ),
+		);
+		$fallbacks = array(
+			'create' => $fallback,
+			'edit' => $fallback,
+			'admin' => $fallback,
+		);
+
+		// strip everything from the screens array but what we we're
+		// testing
+		foreach ( $screens as &$screen ) {
+			foreach ( $screen as $k => $v ) {
+				if ( ! in_array( $k, array( 'screen_callback', 'screen_save_callback' ) ) ) {
+					unset( $screen[ $k ] );
+				}
+			}
+		}
+
+		$this->assertEquals( $fallbacks, $screens );
+	}
+
+	public function test_setup_screens_define_edit_screens_locally() {
+		$class_name = 'BPTest_Group_Extension_Setup_Screens_Define_Edit_Screens_Locally';
+		$e = new $class_name();
+		$e->_setup_class_info();
+		$screens = $e->_get_default_screens();
+
+		$fallback = array(
+			'screen_callback' => array( $e, 'settings_screen' ),
+			'screen_save_callback' => array( $e, 'settings_screen_save' ),
+		);
+		$expected = array(
+			'create' => $fallback,
+			'edit' => array(
+				'screen_callback' => array( $e, 'edit_screen' ),
+				'screen_save_callback' => array( $e, 'edit_screen_save' ),
+			),
+			'admin' => $fallback,
+		);
+
+		// strip everything from the screens array but what we we're
+		// testing
+		foreach ( $screens as &$screen ) {
+			foreach ( $screen as $k => $v ) {
+				if ( ! in_array( $k, array( 'screen_callback', 'screen_save_callback' ) ) ) {
+					unset( $screen[ $k ] );
+				}
+			}
+		}
+
+		$this->assertEquals( $screens, $expected );
+	}
+
+	public function test_parse_args_r() {
+		$a = array(
+			'veggies' => 'yes',
+			'ice_cream' => 'dope',
+			'fruit' => array(
+				'apple' => 'gross',
+				'berries' => array(
+					'blueberries' => array(
+						'in_season' => 'never',
+						'oh' => 'boy',
+					),
+					'cherries' => 'sometimes',
+				),
+			),
+		);
+
+		$b = array(
+			'veggies' => 'no',
+			'cheese' => array(
+				'cheddar' => 'good',
+			),
+			'fruit' => array(
+				'apple' => 'yum',
+				'berries' => array(
+					'strawberries' => 'awesome',
+					'blueberries' => array(
+						'in_season' => 'yes',
+						'out_of_season' => 'no',
+					),
+				),
+			),
+		);
+
+		$expected = array(
+			'veggies' => 'yes',
+			'ice_cream' => 'dope',
+			'cheese' => array(
+				'cheddar' => 'good',
+			),
+			'fruit' => array(
+				'apple' => 'gross',
+				'berries' => array(
+					'strawberries' => 'awesome',
+					'blueberries' => array(
+						'in_season' => 'never',
+						'out_of_season' => 'no',
+						'oh' => 'boy',
+					),
+					'cherries' => 'sometimes',
+				),
+			),
+		);
+
+		$this->assertEquals( $expected, BP_Group_Extension::parse_args_r( $a, $b ) );
+	}
+
+	/**
+	 * Config that gets intentionally stored as a direct property of object
+	 */
+	public function test_access_root_property() {
+		$class_name = 'BPTest_Group_Extension_Access_Root_Property';
+		$e = new $class_name();
+		$e->_register();
+
+		$this->assertEquals( 39, $e->nav_item_position );
+	}
+
+	/**
+	 * Config that gets registered using init(), but is then accessed via
+	 * the legacy location
+	 */
+	public function test_access_init_property_using_legacy_location() {
+		$class_name = 'BPTest_Group_Extension_Access_Init_Property_Using_Legacy_Location';
+		$e = new $class_name();
+		$e->_register();
+
+		$this->assertEquals( 18, $e->create_step_position );
+	}
+
+	/**
+	 * Provides settings_screen* and edit_screen*
+	 */
+	public function test_get_screen_callback_fallbacks() {
+		$class_name = 'BPTest_Group_Extension_Get_Screen_Callback_Fallbacks';
+		$e = new $class_name();
+		$e->_register();
+
+		$this->assertEquals( array( $e, 'settings_screen' ), $e->screens['create']['screen_callback'] );
+		$this->assertEquals( array( $e, 'settings_screen_save' ), $e->screens['create']['screen_save_callback'] );
+		$this->assertEquals( array( $e, 'settings_screen' ), $e->screens['admin']['screen_callback'] );
+		$this->assertEquals( array( $e, 'settings_screen_save' ), $e->screens['admin']['screen_save_callback'] );
+		$this->assertEquals( array( $e, 'edit_screen' ), $e->screens['edit']['screen_callback'] );
+		$this->assertEquals( array( $e, 'edit_screen_save' ), $e->screens['edit']['screen_save_callback'] );
+	}
+
+	public function test_has_submit_button() {
+		$a = '<p>Foo bar</p><input type="text" name="awesome" /><input name="save" type="submit" id="saverrrr" />sweet';
+		$this->assertTrue( BP_Group_Extension::has_submit_button( $a ) );
+
+		$b = '<p>Foo bar</p><input type="text" name="awesome" />sweet';
+		$this->assertFalse( BP_Group_Extension::has_submit_button( $b ) );
+
+		// switch the quotation marks
+		$c = "<p>Foo bar</p><input type='text' name='awesome' /><input name='save' type='submit' id='saverrrr' />sweet";
+		$this->assertTrue( BP_Group_Extension::has_submit_button( $c ) );
+	}
+}
Index: /tags/1.9/tests/testcases/groups/class-bp-group-member-query.php
===================================================================
--- /tags/1.9/tests/testcases/groups/class-bp-group-member-query.php	(revision 7684)
+++ /tags/1.9/tests/testcases/groups/class-bp-group-member-query.php	(revision 7684)
@@ -0,0 +1,337 @@
+<?php
+/**
+ * @group groups
+ * @group BP_Group_Member_Query
+ */
+class BP_Tests_BP_Group_Member_Query_TestCases extends BP_UnitTestCase {
+	/**
+	 * Make sure that a manual 'include' param is parsed correctly with
+	 * BP_Group_Member_Query's limiting of the query to group members
+	 */
+	public function test_with_include() {
+		$g = $this->factory->group->create();
+		$u1 = $this->create_user();
+		$u2 = $this->create_user();
+		$u3 = $this->create_user();
+		$time = time();
+
+		$this->add_user_to_group( $u1, $g, array( 'date_modified' => gmdate( 'Y-m-d H:i:s', $time - 100 ) ) );
+		$this->add_user_to_group( $u2, $g, array( 'date_modified' => gmdate( 'Y-m-d H:i:s', $time - 200 ) ) );
+
+		$query = new BP_Group_Member_Query( array(
+			'group_id' => $g,
+			'include' => array( $u2 ),
+		) );
+
+		$ids = wp_parse_id_list( array_keys( $query->results ) );
+		$this->assertEquals( array( $u2, ), $ids );
+	}
+
+	// Make sure we're falling back on 'member'
+	public function test_with_group_role_null() {
+		$g = $this->factory->group->create();
+		$u1 = $this->create_user();
+		$u2 = $this->create_user();
+		$u3 = $this->create_user();
+		$time = time();
+
+		$this->add_user_to_group( $u1, $g, array( 'date_modified' => gmdate( 'Y-m-d H:i:s', $time - 100 ) ) );
+		$this->add_user_to_group( $u2, $g, array( 'date_modified' => gmdate( 'Y-m-d H:i:s', $time - 200 ) ) );
+		$this->add_user_to_group( $u3, $g, array( 'date_modified' => gmdate( 'Y-m-d H:i:s', $time - 300 ) ) );
+
+		$m1 = new BP_Groups_Member( $u1, $g );
+		$m1->promote( 'admin' );
+		$m2 = new BP_Groups_Member( $u2, $g );
+		$m2->promote( 'mod' );
+
+		$query = new BP_Group_Member_Query( array(
+			'group_id' => $g,
+		) );
+
+		$expected = new BP_Group_Member_Query( array(
+			'group_id' => $g,
+			'group_role' => array( 'member' ),
+		) );
+
+		$this->assertEquals( $expected->results, $query->results );
+	}
+
+	public function test_with_group_role_member() {
+		$g = $this->factory->group->create();
+		$u1 = $this->create_user();
+		$u2 = $this->create_user();
+		$u3 = $this->create_user();
+		$time = time();
+
+		$this->add_user_to_group( $u1, $g, array( 'date_modified' => gmdate( 'Y-m-d H:i:s', $time - 100 ) ) );
+		$this->add_user_to_group( $u2, $g, array( 'date_modified' => gmdate( 'Y-m-d H:i:s', $time - 200 ) ) );
+		$this->add_user_to_group( $u3, $g, array( 'date_modified' => gmdate( 'Y-m-d H:i:s', $time - 300 ) ) );
+
+		$m1 = new BP_Groups_Member( $u1, $g );
+		$m1->promote( 'admin' );
+		$m2 = new BP_Groups_Member( $u2, $g );
+		$m2->promote( 'mod' );
+
+		$query_members = new BP_Group_Member_Query( array(
+			'group_id' => $g,
+			'group_role' => array( 'member' ),
+		) );
+
+		$ids = wp_parse_id_list( array_keys( $query_members->results ) );
+		$this->assertEquals( array( $u3, ), $ids );
+	}
+
+	public function test_with_group_role_mod() {
+		$g = $this->factory->group->create();
+		$u1 = $this->create_user();
+		$u2 = $this->create_user();
+		$u3 = $this->create_user();
+		$time = time();
+
+		$this->add_user_to_group( $u1, $g, array( 'date_modified' => gmdate( 'Y-m-d H:i:s', $time - 100 ) ) );
+		$this->add_user_to_group( $u2, $g, array( 'date_modified' => gmdate( 'Y-m-d H:i:s', $time - 200 ) ) );
+		$this->add_user_to_group( $u3, $g, array( 'date_modified' => gmdate( 'Y-m-d H:i:s', $time - 300 ) ) );
+
+		$m1 = new BP_Groups_Member( $u1, $g );
+		$m1->promote( 'admin' );
+		$m2 = new BP_Groups_Member( $u2, $g );
+		$m2->promote( 'mod' );
+
+		$query_members = new BP_Group_Member_Query( array(
+			'group_id' => $g,
+			'group_role' => array( 'mod' ),
+		) );
+
+		$ids = wp_parse_id_list( array_keys( $query_members->results ) );
+		$this->assertEquals( array( $u2, ), $ids );
+	}
+
+	public function test_with_group_role_admin() {
+		$g = $this->factory->group->create();
+		$u1 = $this->create_user();
+		$u2 = $this->create_user();
+		$u3 = $this->create_user();
+		$time = time();
+
+		$this->add_user_to_group( $u1, $g, array( 'date_modified' => gmdate( 'Y-m-d H:i:s', $time - 100 ) ) );
+		$this->add_user_to_group( $u2, $g, array( 'date_modified' => gmdate( 'Y-m-d H:i:s', $time - 200 ) ) );
+		$this->add_user_to_group( $u3, $g, array( 'date_modified' => gmdate( 'Y-m-d H:i:s', $time - 300 ) ) );
+
+		$m1 = new BP_Groups_Member( $u1, $g );
+		$m1->promote( 'admin' );
+		$m2 = new BP_Groups_Member( $u2, $g );
+		$m2->promote( 'mod' );
+
+		$query_members = new BP_Group_Member_Query( array(
+			'group_id' => $g,
+			'group_role' => array( 'admin' ),
+		) );
+
+		$ids = wp_parse_id_list( array_keys( $query_members->results ) );
+		$this->assertEquals( array( $u1, ), $ids );
+	}
+
+	public function test_with_group_role_member_mod() {
+		$g = $this->factory->group->create();
+		$u1 = $this->create_user();
+		$u2 = $this->create_user();
+		$u3 = $this->create_user();
+		$time = time();
+
+		$this->add_user_to_group( $u1, $g, array( 'date_modified' => gmdate( 'Y-m-d H:i:s', $time - 100 ) ) );
+		$this->add_user_to_group( $u2, $g, array( 'date_modified' => gmdate( 'Y-m-d H:i:s', $time - 200 ) ) );
+		$this->add_user_to_group( $u3, $g, array( 'date_modified' => gmdate( 'Y-m-d H:i:s', $time - 300 ) ) );
+
+		$m1 = new BP_Groups_Member( $u1, $g );
+		$m1->promote( 'admin' );
+		$m2 = new BP_Groups_Member( $u2, $g );
+		$m2->promote( 'mod' );
+
+		$query_members = new BP_Group_Member_Query( array(
+			'group_id' => $g,
+			'group_role' => array( 'member', 'mod' ),
+		) );
+
+		$ids = wp_parse_id_list( array_keys( $query_members->results ) );
+		$this->assertEquals( array( $u2, $u3, ), $ids );
+	}
+
+	public function test_with_group_role_member_admin() {
+		$g = $this->factory->group->create();
+		$u1 = $this->create_user();
+		$u2 = $this->create_user();
+		$u3 = $this->create_user();
+		$time = time();
+
+		$this->add_user_to_group( $u1, $g, array( 'date_modified' => gmdate( 'Y-m-d H:i:s', $time - 100 ) ) );
+		$this->add_user_to_group( $u2, $g, array( 'date_modified' => gmdate( 'Y-m-d H:i:s', $time - 200 ) ) );
+		$this->add_user_to_group( $u3, $g, array( 'date_modified' => gmdate( 'Y-m-d H:i:s', $time - 300 ) ) );
+
+		$m1 = new BP_Groups_Member( $u1, $g );
+		$m1->promote( 'admin' );
+		$m2 = new BP_Groups_Member( $u2, $g );
+		$m2->promote( 'mod' );
+
+		$query_members = new BP_Group_Member_Query( array(
+			'group_id' => $g,
+			'group_role' => array( 'member', 'admin' ),
+		) );
+
+		$ids = wp_parse_id_list( array_keys( $query_members->results ) );
+		$this->assertEquals( array( $u1, $u3, ), $ids );
+	}
+
+	public function test_with_group_role_mod_admin() {
+		$g = $this->factory->group->create();
+		$u1 = $this->create_user();
+		$u2 = $this->create_user();
+		$u3 = $this->create_user();
+		$time = time();
+
+		$this->add_user_to_group( $u1, $g, array( 'date_modified' => gmdate( 'Y-m-d H:i:s', $time - 100 ) ) );
+		$this->add_user_to_group( $u2, $g, array( 'date_modified' => gmdate( 'Y-m-d H:i:s', $time - 200 ) ) );
+		$this->add_user_to_group( $u3, $g, array( 'date_modified' => gmdate( 'Y-m-d H:i:s', $time - 300 ) ) );
+
+		$m1 = new BP_Groups_Member( $u1, $g );
+		$m1->promote( 'admin' );
+		$m2 = new BP_Groups_Member( $u2, $g );
+		$m2->promote( 'mod' );
+
+		$query_members = new BP_Group_Member_Query( array(
+			'group_id' => $g,
+			'group_role' => array( 'mod', 'admin' ),
+		) );
+
+		$ids = wp_parse_id_list( array_keys( $query_members->results ) );
+		$this->assertEquals( array( $u1, $u2, ), $ids );
+	}
+
+	public function test_with_group_role_member_mod_admin() {
+		$g = $this->factory->group->create();
+		$u1 = $this->create_user();
+		$u2 = $this->create_user();
+		$u3 = $this->create_user();
+		$time = time();
+
+		$this->add_user_to_group( $u1, $g, array( 'date_modified' => gmdate( 'Y-m-d H:i:s', $time - 100 ) ) );
+		$this->add_user_to_group( $u2, $g, array( 'date_modified' => gmdate( 'Y-m-d H:i:s', $time - 200 ) ) );
+		$this->add_user_to_group( $u3, $g, array( 'date_modified' => gmdate( 'Y-m-d H:i:s', $time - 300 ) ) );
+
+		$m1 = new BP_Groups_Member( $u1, $g );
+		$m1->promote( 'admin' );
+		$m2 = new BP_Groups_Member( $u2, $g );
+		$m2->promote( 'mod' );
+
+		$query_members = new BP_Group_Member_Query( array(
+			'group_id' => $g,
+			'group_role' => array( 'member', 'mod', 'admin' ),
+		) );
+
+		$ids = wp_parse_id_list( array_keys( $query_members->results ) );
+		$this->assertEquals( array( $u1, $u2, $u3, ), $ids );
+	}
+
+	public function test_with_group_role_member_mod_admin_banned() {
+		$g = $this->factory->group->create();
+		$u1 = $this->create_user();
+		$u2 = $this->create_user();
+		$u3 = $this->create_user();
+		$u4 = $this->create_user();
+		$time = time();
+
+		$this->add_user_to_group( $u1, $g, array( 'date_modified' => gmdate( 'Y-m-d H:i:s', $time - 100 ) ) );
+		$this->add_user_to_group( $u2, $g, array( 'date_modified' => gmdate( 'Y-m-d H:i:s', $time - 200 ) ) );
+		$this->add_user_to_group( $u3, $g, array( 'date_modified' => gmdate( 'Y-m-d H:i:s', $time - 300 ) ) );
+		$this->add_user_to_group( $u4, $g, array( 'date_modified' => gmdate( 'Y-m-d H:i:s', $time - 300 ) ) );
+
+		$m1 = new BP_Groups_Member( $u1, $g );
+		$m1->promote( 'admin' );
+		$m2 = new BP_Groups_Member( $u2, $g );
+		$m2->promote( 'mod' );
+		$m3 = new BP_Groups_Member( $u3, $g );
+		$m3->ban();
+
+		$query_members = new BP_Group_Member_Query( array(
+			'group_id' => $g,
+			'group_role' => array( 'member', 'mod', 'admin', 'banned' ),
+		) );
+
+		$ids = wp_parse_id_list( array_keys( $query_members->results ) );
+		$this->assertEquals( array( $u1, $u2, $u3, $u4, ), $ids );
+	}
+
+	public function test_with_group_role_banned() {
+		$g = $this->factory->group->create();
+		$u1 = $this->create_user();
+		$u2 = $this->create_user();
+		$time = time();
+
+		$this->add_user_to_group( $u1, $g, array( 'date_modified' => gmdate( 'Y-m-d H:i:s', $time - 100 ) ) );
+		$this->add_user_to_group( $u2, $g, array( 'date_modified' => gmdate( 'Y-m-d H:i:s', $time - 200 ) ) );
+
+		$m1 = new BP_Groups_Member( $u1, $g );
+		$m1->ban();
+
+		$query_members = new BP_Group_Member_Query( array(
+			'group_id' => $g,
+			'group_role' => array( 'banned' ),
+		) );
+
+		$ids = wp_parse_id_list( array_keys( $query_members->results ) );
+		$this->assertEquals( array( $u1, ), $ids );
+	}
+
+	public function test_group_has_no_members() {
+		$g = $this->factory->group->create();
+		$u1 = $this->create_user();
+
+		$query_members = new BP_Group_Member_Query( array(
+			'group_id' => $g,
+			'group_role' => array( 'member', 'mod', 'admin' ),
+		) );
+
+		$ids = wp_parse_id_list( array_keys( $query_members->results ) );
+		$this->assertEquals( array(), $ids );
+	}
+
+	public function test_group_has_no_members_of_role_mod() {
+		$g = $this->factory->group->create();
+		$u1 = $this->create_user();
+		$time = time();
+
+		$this->add_user_to_group( $u1, $g, array( 'date_modified' => gmdate( 'Y-m-d H:i:s', $time - 100 ) ) );
+
+		$query_members = new BP_Group_Member_Query( array(
+			'group_id' => $g,
+			'group_role' => array( 'mod' ),
+		) );
+
+		$ids = wp_parse_id_list( array_keys( $query_members->results ) );
+		$this->assertEquals( array(), $ids );
+	}
+
+	public function test_confirmed_members() {
+		$g = $this->factory->group->create();
+		$u1 = $this->create_user();
+		$u2 = $this->create_user();
+		$time = time();
+
+		$this->add_user_to_group( $u1, $g, array(
+			'date_modified' => gmdate( 'Y-m-d H:i:s', $time - 100 ),
+			'is_confirmed' => 0,
+		) );
+
+		$this->add_user_to_group( $u2, $g, array(
+			'date_modified' => gmdate( 'Y-m-d H:i:s', $time - 100 ),
+			'is_confirmed' => 1,
+		) );
+
+		$query_members = new BP_Group_Member_Query( array(
+			'group_id' => $g,
+		) );
+
+		$ids = wp_parse_id_list( array_keys( $query_members->results ) );
+		$this->assertEquals( array( $u2 ), $ids );
+	}
+
+}
Index: /tags/1.9/tests/testcases/groups/class-bp-groups-group.php
===================================================================
--- /tags/1.9/tests/testcases/groups/class-bp-groups-group.php	(revision 7684)
+++ /tags/1.9/tests/testcases/groups/class-bp-groups-group.php	(revision 7684)
@@ -0,0 +1,657 @@
+<?php
+/**
+ * @group groups
+ * @group BP_Groups_Group
+ */
+class BP_Tests_BP_Groups_Group_TestCases extends BP_UnitTestCase {
+	public function setUp() {
+		parent::setUp();
+	}
+
+	public function tearDown() {
+		parent::tearDown();
+	}
+
+	/** __construct()  ***************************************************/
+
+	/**
+	 * @group __construct
+	 */
+	public function test_non_existent_group() {
+		$group = new BP_Groups_Group( 123456789 );
+		$this->assertSame( 0, $group->id );
+	}
+
+	/** get() ************************************************************/
+
+	/**
+	 * @group get
+	 */
+	public function test_get_with_exclude() {
+		$g1 = $this->factory->group->create();
+		$g2 = $this->factory->group->create();
+		groups_update_groupmeta( $g1, 'foo', 'bar' );
+
+		$groups = BP_Groups_Group::get( array(
+			'exclude' => array(
+				$g1,
+				'foobar',
+			),
+		) );
+		$ids = wp_list_pluck( $groups['groups'], 'id' );
+		$this->assertEquals( $ids, array( $g2 ) );
+	}
+
+	/**
+	 * @group get
+	 */
+	public function test_get_with_include() {
+		$g1 = $this->factory->group->create();
+		$g2 = $this->factory->group->create();
+		groups_update_groupmeta( $g1, 'foo', 'bar' );
+
+		$groups = BP_Groups_Group::get( array(
+			'include' => array(
+				$g1,
+				'foobar',
+			),
+		) );
+		$ids = wp_list_pluck( $groups['groups'], 'id' );
+		$this->assertEquals( $ids, array( $g1 ) );
+	}
+
+	/**
+	 * @group get
+	 * @group group_meta_query
+	 */
+	public function test_get_with_meta_query() {
+		$g1 = $this->factory->group->create();
+		$g2 = $this->factory->group->create();
+		groups_update_groupmeta( $g1, 'foo', 'bar' );
+
+		$groups = BP_Groups_Group::get( array(
+			'meta_query' => array(
+				array(
+					'key' => 'foo',
+					'value' => 'bar',
+				),
+			),
+		) );
+		$ids = wp_list_pluck( $groups['groups'], 'id' );
+		$this->assertEquals( $ids, array( $g1 ) );
+	}
+
+	/**
+	 * @group get
+	 * @group group_meta_query
+	 */
+	public function test_get_empty_meta_query() {
+		$g1 = $this->factory->group->create();
+		$g2 = $this->factory->group->create();
+		groups_update_groupmeta( $g1, 'foo', 'bar' );
+
+		$groups = BP_Groups_Group::get( array(
+			'meta_query' => array(),
+		) );
+		$ids = wp_list_pluck( $groups['groups'], 'id' );
+		$this->assertEquals( $ids, array( $g1, $g2, ) );
+	}
+
+	/**
+	 * @group get
+	 * @group group_meta_query
+	 */
+	public function test_get_with_meta_query_multiple_clauses() {
+		$now = time();
+		$g1 = $this->factory->group->create( array(
+			'last_activity' => date( 'Y-m-d H:i:s', $now - 60*60 ),
+		) );
+		$g2 = $this->factory->group->create( array(
+			'last_activity' => date( 'Y-m-d H:i:s', $now - 60*60*2 ),
+		) );
+		$g3 = $this->factory->group->create( array(
+			'last_activity' => date( 'Y-m-d H:i:s', $now - 60*60*3 ),
+		) );
+		groups_update_groupmeta( $g1, 'foo', 'bar' );
+		groups_update_groupmeta( $g2, 'foo', 'bar' );
+		groups_update_groupmeta( $g1, 'bar', 'barry' );
+
+		$groups = BP_Groups_Group::get( array(
+			'meta_query' => array(
+				'relation' => 'AND',
+				array(
+					'key' => 'foo',
+					'value' => 'bar',
+				),
+				array(
+					'key' => 'bar',
+					'value' => 'barry',
+				),
+			),
+		) );
+		$ids = wp_list_pluck( $groups['groups'], 'id' );
+		$this->assertEquals( $ids, array( $g1 ) );
+		$this->assertEquals( 1, $groups['total'] );
+	}
+
+	/**
+	 * @group get
+	 */
+	public function test_get_normal_search() {
+		$g1 = $this->factory->group->create( array(
+			'name' => 'Cool Group',
+			'description' => 'This is one cool group',
+		) );
+		$g2 = $this->factory->group->create();
+
+		$groups = BP_Groups_Group::get( array(
+			'search_terms' => 'Cool',
+		) );
+
+		$found = wp_list_pluck( $groups['groups'], 'id' );
+		$this->assertEquals( array( $g1 ), $found );
+	}
+
+	/**
+	 * @group get
+	 */
+	public function test_get_search_with_underscores() {
+		$g1 = $this->factory->group->create( array(
+			'name' => 'Cool Group',
+			'description' => '_cool_ dude',
+		) );
+		$g2 = $this->factory->group->create();
+
+		$groups = BP_Groups_Group::get( array(
+			'search_terms' => '_cool_',
+		) );
+
+		$found = wp_list_pluck( $groups['groups'], 'id' );
+		$this->assertEquals( array( $g1 ), $found );
+	}
+
+	/**
+	 * @group get
+	 */
+	public function test_get_search_with_percent_sign() {
+		$g1 = $this->factory->group->create( array(
+			'name' => 'Cool Group',
+			'description' => '100% awesome',
+		) );
+		$g2 = $this->factory->group->create();
+
+		$groups = BP_Groups_Group::get( array(
+			'search_terms' => '100%',
+		) );
+
+		$found = wp_list_pluck( $groups['groups'], 'id' );
+		$this->assertEquals( array( $g1 ), $found );
+	}
+
+	/**
+	 * @group get
+	 */
+	public function test_get_search_with_quotes() {
+		$g1 = $this->factory->group->create( array(
+			'name' => 'Cool Group',
+			'description' => "'tis sweet",
+		) );
+		$g2 = $this->factory->group->create();
+
+		$groups = BP_Groups_Group::get( array(
+			'search_terms' => "'tis ",
+		) );
+
+		$found = wp_list_pluck( $groups['groups'], 'id' );
+
+		$this->assertEquals( array( $g1 ), $found );
+	}
+
+	/**
+	 * BP 1.8 will change the default 'type' param in favor of default
+	 * 'order' and 'orderby'. This is to make sure that existing plugins
+	 * will work appropriately
+	 *
+	 * @group get
+	 */
+	public function test_get_with_default_type_value_should_be_newest() {
+		$g1 = $this->factory->group->create( array(
+			'name' => 'A Group',
+			'date_created' => bp_core_current_time(),
+		) );
+		$g2 = $this->factory->group->create( array(
+			'name' => 'D Group',
+			'date_created' => gmdate( 'Y-m-d H:i:s', time() - 100 ),
+		) );
+		$g3 = $this->factory->group->create( array(
+			'name' => 'B Group',
+			'date_created' => gmdate( 'Y-m-d H:i:s', time() - 100000 ),
+		) );
+		$g4 = $this->factory->group->create( array(
+			'name' => 'C Group',
+			'date_created' => gmdate( 'Y-m-d H:i:s', time() - 1000 ),
+		) );
+
+		$found = BP_Groups_Group::get();
+
+		$this->assertEquals( BP_Groups_Group::get( array( 'type' => 'newest' ) ), $found );
+	}
+
+	/**
+	 * @group get
+	 */
+	public function test_get_with_type_newest() {
+		$time = time();
+		$g1 = $this->factory->group->create( array(
+			'name' => 'A Group',
+			'date_created' => bp_core_current_time(),
+		) );
+		$g2 = $this->factory->group->create( array(
+			'name' => 'D Group',
+			'date_created' => gmdate( 'Y-m-d H:i:s', $time - 100 ),
+		) );
+		$g3 = $this->factory->group->create( array(
+			'name' => 'B Group',
+			'date_created' => gmdate( 'Y-m-d H:i:s', $time - 100000 ),
+		) );
+		$g4 = $this->factory->group->create( array(
+			'name' => 'C Group',
+			'date_created' => gmdate( 'Y-m-d H:i:s', $time - 1000 ),
+		) );
+
+		$groups = BP_Groups_Group::get( array( 'type' => 'newest' ) );
+		$found = wp_parse_id_list( wp_list_pluck( $groups['groups'], 'id' ) );
+		$this->assertEquals( array( $g1, $g2, $g4, $g3 ), $found );
+	}
+
+	/**
+	 * @group get
+	 */
+	public function test_get_with_type_popular() {
+		$time = time();
+		$g1 = $this->factory->group->create( array(
+			'name' => 'A Group',
+			'date_created' => bp_core_current_time(),
+		) );
+		$g2 = $this->factory->group->create( array(
+			'name' => 'D Group',
+			'date_created' => gmdate( 'Y-m-d H:i:s', $time - 100 ),
+		) );
+		$g3 = $this->factory->group->create( array(
+			'name' => 'B Group',
+			'date_created' => gmdate( 'Y-m-d H:i:s', $time - 100000 ),
+		) );
+		$g4 = $this->factory->group->create( array(
+			'name' => 'C Group',
+			'date_created' => gmdate( 'Y-m-d H:i:s', $time - 1000 ),
+		) );
+
+		groups_update_groupmeta( $g1, 'total_member_count', 1 );
+		groups_update_groupmeta( $g2, 'total_member_count', 4 );
+		groups_update_groupmeta( $g3, 'total_member_count', 2 );
+		groups_update_groupmeta( $g4, 'total_member_count', 3 );
+
+		$groups = BP_Groups_Group::get( array( 'type' => 'popular' ) );
+		$found = wp_parse_id_list( wp_list_pluck( $groups['groups'], 'id' ) );
+		$this->assertEquals( array( $g2, $g4, $g3, $g1 ), $found );
+	}
+
+	/**
+	 * @group get
+	 * @group group_meta_query
+	 * @ticket BP5099
+	 */
+	public function test_meta_query_and_total_groups() {
+		$time = time();
+
+		$g1 = $this->factory->group->create( array(
+			'name' => 'A Group',
+			'date_created' => bp_core_current_time(),
+		) );
+		$g2 = $this->factory->group->create( array(
+			'name' => 'D Group',
+			'date_created' => gmdate( 'Y-m-d H:i:s', $time - 100 ),
+		) );
+		$g3 = $this->factory->group->create( array(
+			'name' => 'B Group',
+			'date_created' => gmdate( 'Y-m-d H:i:s', $time - 100000 ),
+		) );
+		$g4 = $this->factory->group->create( array(
+			'name' => 'C Group',
+			'date_created' => gmdate( 'Y-m-d H:i:s', $time - 1000 ),
+		) );
+
+		// mark one group with the metakey 'supergroup'
+		groups_update_groupmeta( $g1, 'supergroup', 1 );
+
+		// fetch groups with our 'supergroup' metakey
+		$groups = BP_Groups_Group::get( array(
+			'meta_query' => array(
+				array(
+					'key'     => 'supergroup',
+					'compare' => 'EXISTS',
+				)
+			)
+		) );
+
+		// group total should match 1
+		$this->assertEquals( '1', $groups['total'] );
+	}
+
+	/** convert_type_to_order_orderby() **********************************/
+
+	/**
+	 * @group convert_type_to_order_orderby
+	 */
+	public function test_convert_type_to_order_orderby_newest() {
+		$expected = array(
+			'order' => 'DESC',
+			'orderby' => 'date_created',
+		);
+		$this->assertEquals( $expected, _BP_Groups_Group::_convert_type_to_order_orderby( 'newest' ) );
+	}
+
+	/**
+	 * @group convert_type_to_order_orderby
+	 */
+	public function test_convert_type_to_order_orderby_active() {
+		$expected = array(
+			'order' => 'DESC',
+			'orderby' => 'last_activity',
+		);
+		$this->assertEquals( $expected, _BP_Groups_Group::_convert_type_to_order_orderby( 'active' ) );
+	}
+
+	/**
+	 * @group convert_type_to_order_orderby
+	 */
+	public function test_convert_type_to_order_orderby_popular() {
+		$expected = array(
+			'order' => 'DESC',
+			'orderby' => 'total_member_count',
+		);
+		$this->assertEquals( $expected, _BP_Groups_Group::_convert_type_to_order_orderby( 'popular' ) );
+	}
+
+	/**
+	 * @group convert_type_to_order_orderby
+	 */
+	public function test_convert_type_to_order_orderby_alphabetical() {
+		$expected = array(
+			'order' => 'ASC',
+			'orderby' => 'name',
+		);
+		$this->assertEquals( $expected, _BP_Groups_Group::_convert_type_to_order_orderby( 'alphabetical' ) );
+	}
+
+	/**
+	 * @group convert_type_to_order_orderby
+	 */
+	public function test_convert_type_to_order_orderby_random() {
+		$expected = array(
+			// order gets thrown out
+			'order' => '',
+			'orderby' => 'random',
+		);
+		$this->assertEquals( $expected, _BP_Groups_Group::_convert_type_to_order_orderby( 'random' ) );
+	}
+
+	/**
+	 * @group convert_type_to_order_orderby
+	 */
+	public function test_convert_type_to_order_orderby_invalid() {
+		$expected = array(
+			'order' => '',
+			'orderby' => '',
+		);
+		$this->assertEquals( $expected, _BP_Groups_Group::_convert_type_to_order_orderby( 'foooooooooooooooobar' ) );
+	}
+
+	/** convert_orderby_to_order_by_term() **********************************/
+
+	/**
+	 * @group convert_orderby_to_order_by_term
+	 */
+	public function test_convert_orderby_to_order_by_term_date_created() {
+		$this->assertEquals( 'g.date_created', _BP_Groups_Group::_convert_orderby_to_order_by_term( 'date_created' ) );
+	}
+
+	/**
+	 * @group convert_orderby_to_order_by_term
+	 */
+	public function test_convert_orderby_to_order_by_term_last_activity() {
+		$c = new _BP_Groups_Group();
+		$this->assertEquals( 'last_activity', _BP_Groups_Group::_convert_orderby_to_order_by_term( 'last_activity' ) );
+	}
+
+	/**
+	 * @group convert_orderby_to_order_by_term
+	 */
+	public function test_convert_orderby_to_order_by_term_total_member_count() {
+		$c = new _BP_Groups_Group();
+		$this->assertEquals( 'CONVERT(gm1.meta_value, SIGNED)', _BP_Groups_Group::_convert_orderby_to_order_by_term( 'total_member_count' ) );
+	}
+
+	/**
+	 * @group convert_orderby_to_order_by_term
+	 */
+	public function test_convert_orderby_to_order_by_term_name() {
+		$c = new _BP_Groups_Group();
+		$this->assertEquals( 'g.name', _BP_Groups_Group::_convert_orderby_to_order_by_term( 'name' ) );
+	}
+
+	/**
+	 * @group convert_orderby_to_order_by_term
+	 */
+	public function test_convert_orderby_to_order_by_term_random() {
+		$c = new _BP_Groups_Group();
+		$this->assertEquals( 'rand()', _BP_Groups_Group::_convert_orderby_to_order_by_term( 'random' ) );
+	}
+
+	/**
+	 * @group convert_orderby_to_order_by_term
+	 */
+	public function test_convert_orderby_to_order_by_term_invalid_fallback_to_date_created() {
+		$c = new _BP_Groups_Group();
+		$this->assertEquals( _BP_Groups_Group::_convert_orderby_to_order_by_term( 'date_created' ), _BP_Groups_Group::_convert_orderby_to_order_by_term( 'I am a bad boy' ) );
+	}
+
+	public function test_filter_user_groups_normal_search() {
+		$g1 = $this->factory->group->create( array(
+			'name' => 'Cool Group',
+			'description' => 'This is one cool group',
+		) );
+		$g2 = $this->factory->group->create();
+		$u = $this->factory->user->create();
+		self::add_user_to_group( $u, $g1 );
+
+		$groups = BP_Groups_Group::filter_user_groups( 'Cool', $u );
+
+		$found = wp_list_pluck( $groups['groups'], 'group_id' );
+		$this->assertEquals( array( $g1 ), $found );
+	}
+
+	public function test_filter_user_groups_search_with_underscores() {
+		$g1 = $this->factory->group->create( array(
+			'name' => 'Cool Group',
+			'description' => '_cool_ dude',
+		) );
+		$g2 = $this->factory->group->create();
+
+		$u = $this->factory->user->create();
+		self::add_user_to_group( $u, $g1 );
+		self::add_user_to_group( $u, $g2 );
+
+		$groups = BP_Groups_Group::filter_user_groups( '_cool_', $u );
+
+		$found = wp_list_pluck( $groups['groups'], 'group_id' );
+		$this->assertEquals( array( $g1 ), $found );
+	}
+
+	public function test_filter_user_groups_search_with_percent_sign() {
+		$g1 = $this->factory->group->create( array(
+			'name' => 'Cool Group',
+			'description' => '100% awesome',
+		) );
+		$g2 = $this->factory->group->create();
+
+		$u = $this->factory->user->create();
+		self::add_user_to_group( $u, $g1 );
+		self::add_user_to_group( $u, $g2 );
+
+		$groups = BP_Groups_Group::filter_user_groups( '100%', $u );
+
+		$found = wp_list_pluck( $groups['groups'], 'group_id' );
+		$this->assertEquals( array( $g1 ), $found );
+	}
+
+	public function test_filter_user_groups_search_with_quotes() {
+		$g1 = $this->factory->group->create( array(
+			'name' => 'Cool Group',
+			'description' => "'tis sweet",
+		) );
+		$g2 = $this->factory->group->create();
+
+		$u = $this->factory->user->create();
+		self::add_user_to_group( $u, $g1 );
+		self::add_user_to_group( $u, $g2 );
+
+		$groups = BP_Groups_Group::filter_user_groups( "'tis ", $u );
+
+		$found = wp_list_pluck( $groups['groups'], 'group_id' );
+
+		// @todo
+		//$this->assertEquals( array( $g1->id ), $found );
+	}
+
+	public function test_search_groups_normal_search() {
+		$g1 = $this->factory->group->create( array(
+			'name' => 'Cool Group',
+			'description' => 'This is one cool group',
+		) );
+		$g2 = $this->factory->group->create();
+
+		$groups = BP_Groups_Group::search_groups( 'Cool' );
+
+		$found = wp_list_pluck( $groups['groups'], 'group_id' );
+		$this->assertEquals( array( $g1 ), $found );
+	}
+
+	public function test_search_groups_search_with_underscores() {
+		$g1 = $this->factory->group->create( array(
+			'name' => 'Cool Group',
+			'description' => '_cool_ dude',
+		) );
+		$g2 = $this->factory->group->create();
+
+		$groups = BP_Groups_Group::search_groups( '_cool_' );
+
+		$found = wp_list_pluck( $groups['groups'], 'group_id' );
+		$this->assertEquals( array( $g1 ), $found );
+	}
+
+	public function test_search_groups_search_with_percent_sign() {
+		$g1 = $this->factory->group->create( array(
+			'name' => 'Cool Group',
+			'description' => '100% awesome',
+		) );
+		$g2 = $this->factory->group->create();
+
+		$groups = BP_Groups_Group::search_groups( '100%' );
+
+		$found = wp_list_pluck( $groups['groups'], 'group_id' );
+		$this->assertEquals( array( $g1 ), $found );
+	}
+
+	public function test_search_groups_search_with_quotes() {
+		$g1 = $this->factory->group->create( array(
+			'name' => 'Cool Group',
+			'description' => "'tis sweet",
+		) );
+		$g2 = $this->factory->group->create();
+
+		$groups = BP_Groups_Group::search_groups( "'tis " );
+
+		$found = wp_list_pluck( $groups['groups'], 'group_id' );
+
+		$this->assertEquals( array( $g1 ), $found );
+	}
+
+	public function test_get_by_letter_with_exclude() {
+		$g1 = $this->factory->group->create( array(
+			'name' => 'Awesome Cool Group',
+			'description' => 'Neat',
+		) );
+		$g2 = $this->factory->group->create( array(
+			'name' => 'Another Cool Group',
+			'description' => 'Awesome',
+		) );
+
+		$groups = BP_Groups_Group::get_by_letter( 'A', null, null, true, array( $g1, 'stringthatshouldberemoved' ) );
+
+		$found = wp_list_pluck( $groups['groups'], 'id' );
+
+		$this->assertEquals( array( $g2 ), $found );
+
+	}
+
+	public function test_get_by_letter_starts_with_apostrophe() {
+		$g1 = $this->factory->group->create( array(
+			'name' => "'Tis Sweet",
+			'description' => 'Neat',
+		) );
+		$g2 = $this->factory->group->create( array(
+			'name' => 'Another Cool Group',
+			'description' => 'Awesome',
+		) );
+
+		$groups = BP_Groups_Group::get_by_letter( "'" );
+
+		$found = wp_list_pluck( $groups['groups'], 'id' );
+
+		// @todo
+		// The test fails but at least it's sanitized
+		//$this->assertEquals( array( $g1->id ), $found );
+	}
+
+	public function test_get_random_with_exclude() {
+		$g1 = $this->factory->group->create();
+		$g2 = $this->factory->group->create();
+
+		// There are only two groups, so excluding one should give us the other
+		$groups = BP_Groups_Group::get_random( null, null, 0, false, true, array( $g1, 'ignore this' ) );
+
+		$found = wp_list_pluck( $groups['groups'], 'id' );
+
+		$this->assertEquals( array( $g2 ), $found );
+	}
+
+	public function test_get_random_with_search_terms() {
+		$g1 = $this->factory->group->create( array(
+			'name' => 'Bodacious',
+		) );
+		$g2 = $this->factory->group->create( array(
+			'name' => 'Crummy group',
+		) );
+
+		// Only one group will match, so the random part doesn't matter
+		$groups = BP_Groups_Group::get_random( null, null, 0, 'daci' );
+
+		$found = wp_list_pluck( $groups['groups'], 'id' );
+
+		$this->assertEquals( array( $g1 ), $found );
+	}
+}
+
+/**
+ * Stub class for accessing protected methods
+ */
+class _BP_Groups_Group extends BP_Groups_Group {
+	static public function _convert_type_to_order_orderby( $type ) {
+		return self::convert_type_to_order_orderby( $type );
+	}
+
+	static public function _convert_orderby_to_order_by_term( $term ) {
+		return self::convert_orderby_to_order_by_term( $term );
+	}
+}
Index: /tags/1.9/tests/testcases/groups/class-bp-groups-member.php
===================================================================
--- /tags/1.9/tests/testcases/groups/class-bp-groups-member.php	(revision 7684)
+++ /tags/1.9/tests/testcases/groups/class-bp-groups-member.php	(revision 7684)
@@ -0,0 +1,131 @@
+<?php
+/**
+ * @group groups
+ * @group BP_Groups_Member
+ */
+class BP_Tests_BP_Groups_Member_TestCases extends BP_UnitTestCase {
+	public function setUp() {
+		parent::setUp();
+	}
+
+	public function tearDown() {
+		parent::tearDown();
+	}
+
+	public static function invite_user_to_group( $user_id, $group_id, $inviter_id ) {
+		$invite                = new BP_Groups_Member;
+		$invite->group_id      = $group_id;
+		$invite->user_id       = $user_id;
+		$invite->date_modified = bp_core_current_time();
+		$invite->inviter_id    = $inviter_id;
+		$invite->is_confirmed  = 0;
+		$invite->invite_sent   = 1;
+
+		$invite->save();
+		return $invite->id;
+	}
+
+	public function test_get_recently_joined_with_filter() {
+		$g1 = $this->factory->group->create( array(
+			'name' => 'Tab',
+		) );
+		$g2 = $this->factory->group->create( array(
+			'name' => 'Diet Rite',
+		) );
+
+		$u = $this->factory->user->create();
+		self::add_user_to_group( $u, $g1 );
+		self::add_user_to_group( $u, $g2 );
+
+		$groups = BP_Groups_Member::get_recently_joined( $u, false, false, 'Rite' );
+
+		$ids = wp_list_pluck( $groups['groups'], 'id' );
+		$this->assertEquals( $ids, array( $g2 ) );
+	}
+
+	public function test_get_is_admin_of_with_filter() {
+		$g1 = $this->factory->group->create( array(
+			'name' => 'RC Cola',
+		) );
+		$g2 = $this->factory->group->create( array(
+			'name' => 'Pepsi',
+		) );
+
+		$u = $this->factory->user->create();
+		self::add_user_to_group( $u, $g1 );
+		self::add_user_to_group( $u, $g2 );
+
+		$m1 = new BP_Groups_Member( $u, $g1 );
+		$m1->promote( 'admin' );
+		$m2 = new BP_Groups_Member( $u, $g2 );
+		$m2->promote( 'admin' );
+
+		$groups = BP_Groups_Member::get_is_admin_of( $u, false, false, 'eps' );
+
+		$ids = wp_list_pluck( $groups['groups'], 'id' );
+		$this->assertEquals( $ids, array( $g2 ) );
+	}
+
+	public function test_get_is_mod_of_with_filter() {
+		$g1 = $this->factory->group->create( array(
+			'name' => 'RC Cola',
+		) );
+		$g2 = $this->factory->group->create( array(
+			'name' => 'Pepsi',
+		) );
+
+		$u = $this->factory->user->create();
+		self::add_user_to_group( $u, $g1 );
+		self::add_user_to_group( $u, $g2 );
+
+		$m1 = new BP_Groups_Member( $u, $g1 );
+		$m1->promote( 'mod' );
+		$m2 = new BP_Groups_Member( $u, $g2 );
+		$m2->promote( 'mod' );
+
+		$groups = BP_Groups_Member::get_is_mod_of( $u, false, false, 'eps' );
+
+		$ids = wp_list_pluck( $groups['groups'], 'id' );
+		$this->assertEquals( $ids, array( $g2 ) );
+	}
+
+	public function test_get_invites_with_exclude() {
+		$g1 = $this->factory->group->create( array(
+			'name' => 'RC Cola',
+		) );
+		$g2 = $this->factory->group->create( array(
+			'name' => 'Pepsi',
+		) );
+
+		$u1 = $this->factory->user->create();
+		$u2 = $this->factory->user->create();
+		self::add_user_to_group( $u1, $g1 );
+		self::add_user_to_group( $u1, $g2 );
+		self::invite_user_to_group( $u2, $g1, $u1 );
+		self::invite_user_to_group( $u2, $g2, $u1 );
+
+		$groups = BP_Groups_Member::get_invites( $u2, false, false, array( 'awesome', $g1 ) );
+
+		$ids = wp_list_pluck( $groups['groups'], 'id' );
+		$this->assertEquals( $ids, array( $g2 ) );
+	}
+
+	/**
+	 * @expectedDeprecated BP_Groups_Member::get_all_for_group
+	 */
+	public function test_get_all_for_group_with_exclude() {
+		$g1 = $this->factory->group->create();
+
+		$u1 = $this->create_user();
+		$u2 = $this->create_user();
+		self::add_user_to_group( $u1, $g1 );
+		self::add_user_to_group( $u2, $g1 );
+
+		$members = BP_Groups_Member::get_all_for_group( $g1, false, false, true, true, array( $u1 ) );
+
+		$mm = (array) $members['members'];
+		$ids = wp_list_pluck( $mm, 'user_id' );
+		$this->assertEquals( array( $u2 ), $ids );
+	}
+}
+
Index: /tags/1.9/tests/testcases/groups/functions.php
===================================================================
--- /tags/1.9/tests/testcases/groups/functions.php	(revision 7684)
+++ /tags/1.9/tests/testcases/groups/functions.php	(revision 7684)
@@ -0,0 +1,286 @@
+<?php
+
+/**
+ * @group groups
+ * @group functions
+ */
+class BP_Tests_Groups_Functions extends BP_UnitTestCase {
+	/**
+	 * @group total_group_count
+	 * @group groups_join_group
+	 */
+	public function test_total_group_count_groups_join_group() {
+		$u1 = $this->create_user();
+		$u2 = $this->create_user();
+		$g = $this->factory->group->create( array( 'creator_id' => $u1 ) );
+
+		groups_join_group( $g, $u2 );
+		$this->assertEquals( 1, bp_get_user_meta( $u2, 'total_group_count', true ) );
+	}
+
+	/**
+	 * @group total_group_count
+	 * @group groups_leave_group
+	 */
+	public function test_total_group_count_groups_leave_group() {
+		$u1 = $this->create_user();
+		$u2 = $this->create_user();
+		$g1 = $this->factory->group->create( array( 'creator_id' => $u1 ) );
+		$g2 = $this->factory->group->create( array( 'creator_id' => $u1 ) );
+		groups_join_group( $g1, $u2 );
+		groups_join_group( $g2, $u2 );
+
+		groups_leave_group( $g1, $u2 );
+		$this->assertEquals( 1, bp_get_user_meta( $u2, 'total_group_count', true ) );
+	}
+
+	/**
+	 * @group total_group_count
+	 * @group groups_ban_member
+	 */
+	public function test_total_group_count_groups_ban_member() {
+		$u1 = $this->create_user();
+		$u2 = $this->create_user();
+		$g1 = $this->factory->group->create( array( 'creator_id' => $u1 ) );
+		$g2 = $this->factory->group->create( array( 'creator_id' => $u1 ) );
+		groups_join_group( $g1, $u2 );
+		groups_join_group( $g2, $u2 );
+
+		// Fool the admin check
+		$this->set_current_user( $u1 );
+		buddypress()->is_item_admin = true;
+
+		groups_ban_member( $u2, $g1 );
+
+		$this->assertEquals( 1, bp_get_user_meta( $u2, 'total_group_count', true ) );
+	}
+
+	/**
+	 * @group total_group_count
+	 * @group groups_unban_member
+	 */
+	public function test_total_group_count_groups_unban_member() {
+		$u1 = $this->create_user();
+		$u2 = $this->create_user();
+		$g1 = $this->factory->group->create( array( 'creator_id' => $u1 ) );
+		$g2 = $this->factory->group->create( array( 'creator_id' => $u1 ) );
+		groups_join_group( $g1, $u2 );
+		groups_join_group( $g2, $u2 );
+
+		// Fool the admin check
+		$this->set_current_user( $u1 );
+		buddypress()->is_item_admin = true;
+
+		groups_ban_member( $u2, $g1 );
+
+		groups_unban_member( $u2, $g1 );
+
+		$this->assertEquals( 2, bp_get_user_meta( $u2, 'total_group_count', true ) );
+	}
+
+	/**
+	 * @group total_group_count
+	 * @group groups_accept_invite
+	 */
+	public function test_total_group_count_groups_accept_invite() {
+		$u1 = $this->create_user();
+		$u2 = $this->create_user();
+		$g = $this->factory->group->create();
+		groups_invite_user( array(
+			'user_id' => $u1,
+			'group_id' => $g,
+			'inviter_id' => $u2,
+		) );
+
+		groups_accept_invite( $u2, $g );
+
+		$this->assertEquals( 1, bp_get_user_meta( $u2, 'total_group_count', true ) );
+	}
+
+	/**
+	 * @group total_group_count
+	 * @group groups_accept_membership_request
+	 */
+	public function test_total_group_count_groups_accept_membership_request() {
+		$u = $this->create_user();
+		$g = $this->factory->group->create();
+		groups_send_membership_request( $u, $g );
+
+		groups_accept_membership_request( 0, $u, $g );
+
+		$this->assertEquals( 1, bp_get_user_meta( $u, 'total_group_count', true ) );
+	}
+
+	/**
+	 * @group total_group_count
+	 * @group groups_remove_member
+	 */
+	public function test_total_group_count_groups_remove_member() {
+		$u1 = $this->create_user();
+		$u2 = $this->create_user();
+		$g1 = $this->factory->group->create( array( 'creator_id' => $u1 ) );
+		$g2 = $this->factory->group->create( array( 'creator_id' => $u1 ) );
+		groups_join_group( $g1, $u2 );
+		groups_join_group( $g2, $u2 );
+
+		// Fool the admin check
+		$this->set_current_user( $u1 );
+		buddypress()->is_item_admin = true;
+
+		groups_remove_member( $u2, $g1 );
+
+		$this->assertEquals( 1, bp_get_user_meta( $u2, 'total_group_count', true ) );
+	}
+
+	/**
+	 * @group total_member_count
+	 * @group groups_join_group
+	 */
+	public function test_total_member_count_groups_join_group() {
+		$u1 = $this->create_user();
+		$u2 = $this->create_user();
+		$g = $this->factory->group->create( array( 'creator_id' => $u1 ) );
+
+		groups_join_group( $g, $u2 );
+		$this->assertEquals( 2, groups_get_groupmeta( $g, 'total_member_count' ) );
+	}
+
+	/**
+	 * @group total_member_count
+	 * @group groups_leave_group
+	 */
+	public function test_total_member_count_groups_leave_group() {
+		$u1 = $this->create_user();
+		$g1 = $this->factory->group->create( array( 'creator_id' => $u1 ) );
+		groups_join_group( $g1, $u1 );
+
+		groups_leave_group( $g1, $u1 );
+		$this->assertEquals( 1, groups_get_groupmeta( $g1, 'total_member_count' ) );
+	}
+
+	/**
+	 * @group total_member_count
+	 * @group groups_ban_member
+	 */
+	public function test_total_member_count_groups_ban_member() {
+		$u1 = $this->create_user();
+		$u2 = $this->create_user();
+		$g1 = $this->factory->group->create( array( 'creator_id' => $u1 ) );
+		groups_join_group( $g1, $u2 );
+
+		// Fool the admin check
+		$this->set_current_user( $u1 );
+		buddypress()->is_item_admin = true;
+
+		groups_ban_member( $u2, $g1 );
+
+		$this->assertEquals( 1, groups_get_groupmeta( $g1, 'total_member_count' ) );
+	}
+
+	/**
+	 * @group total_member_count
+	 * @group groups_unban_member
+	 */
+	public function test_total_member_count_groups_unban_member() {
+		$u1 = $this->create_user();
+		$u2 = $this->create_user();
+		$g1 = $this->factory->group->create( array( 'creator_id' => $u1 ) );
+		groups_join_group( $g1, $u2 );
+
+		// Fool the admin check
+		$this->set_current_user( $u1 );
+		buddypress()->is_item_admin = true;
+
+		groups_ban_member( $u2, $g1 );
+
+		groups_unban_member( $u2, $g1 );
+
+		$this->assertEquals( 2, groups_get_groupmeta( $g1, 'total_member_count' ) );
+	}
+
+	/**
+	 * @group total_member_count
+	 * @group groups_accept_invite
+	 */
+	public function test_total_member_count_groups_accept_invite() {
+		$u1 = $this->create_user();
+		$u2 = $this->create_user();
+		$g = $this->factory->group->create( array( 'creator_id' => $u1 ) );
+		groups_invite_user( array(
+			'user_id' => $u1,
+			'group_id' => $g,
+			'inviter_id' => $u2,
+		) );
+
+		groups_accept_invite( $u2, $g );
+
+		$this->assertEquals( 2, groups_get_groupmeta( $g, 'total_member_count' ) );
+	}
+
+	/**
+	 * @group total_member_count
+	 * @group groups_accept_membership_request
+	 */
+	public function test_total_member_count_groups_accept_membership_request() {
+		$u1 = $this->create_user();
+		$u2 = $this->create_user();
+		$g = $this->factory->group->create( array( 'creator_id' => $u1 ) );
+
+		groups_send_membership_request( $u2, $g );
+		groups_accept_membership_request( 0, $u2, $g );
+
+		$this->assertEquals( 2, groups_get_groupmeta( $g, 'total_member_count' ) );
+	}
+
+	/**
+	 * @group total_member_count
+	 * @group groups_remove_member
+	 */
+	public function test_total_member_count_groups_remove_member() {
+		$u1 = $this->create_user();
+		$u2 = $this->create_user();
+		$g1 = $this->factory->group->create( array( 'creator_id' => $u1 ) );
+		groups_join_group( $g1, $u2 );
+
+		// Fool the admin check
+		$this->set_current_user( $u1 );
+		buddypress()->is_item_admin = true;
+
+		groups_remove_member( $u2, $g1 );
+
+		$this->assertEquals( 1, groups_get_groupmeta( $g1, 'total_member_count' ) );
+	}
+
+	/**
+	 * @group total_member_count
+	 * @group groups_create_group
+	 */
+	public function test_total_member_count_groups_create_group() {
+		$u1 = $this->create_user();
+		$g = groups_create_group( array(
+			'creator_id' => $u1,
+			'name' => 'Boone Is Handsome',
+			'description' => 'Yes',
+			'slug' => 'boone-is-handsome',
+			'status' => 'public',
+			'enable_forum' => 0,
+			'date_created' => bp_core_current_time(),
+		) );
+
+		$this->assertEquals( 1, groups_get_groupmeta( $g, 'total_member_count' ) );
+	}
+
+	/**
+	 * @group groupmeta
+	 * @ticket BP5180
+	 */
+	public function test_groups_update_groupmeta_with_line_breaks() {
+		$g = $this->factory->group->create();
+		$meta_value = 'Foo!
+
+Bar!';
+		groups_update_groupmeta( $g, 'linebreak_test', $meta_value );
+
+		$this->assertEquals( $meta_value, groups_get_groupmeta( $g, 'linebreak_test' ) );
+	}
+}
Index: /tags/1.9/tests/testcases/groups/template.php
===================================================================
--- /tags/1.9/tests/testcases/groups/template.php	(revision 7684)
+++ /tags/1.9/tests/testcases/groups/template.php	(revision 7684)
@@ -0,0 +1,410 @@
+<?php
+/**
+ * @group groups
+ * @group template
+ */
+class BP_Tests_Groups_Template extends BP_UnitTestCase {
+	public function setUp() {
+		parent::setUp();
+	}
+
+	public function tearDown() {
+		parent::tearDown();
+	}
+
+	/**
+	 * Integration test to make sure meta_query is getting passed through
+	 *
+	 * @group bp_has_groups
+	 */
+	public function test_bp_has_groups_with_meta_query() {
+		$g1 = $this->factory->group->create();
+		$g2 = $this->factory->group->create();
+		groups_update_groupmeta( $g1, 'foo', 'bar' );
+
+		global $groups_template;
+		bp_has_groups( array(
+			'meta_query' => array(
+				array(
+					'key' => 'foo',
+					'value' => 'bar',
+				),
+			),
+		) );
+
+		$ids = wp_list_pluck( $groups_template->groups, 'id' );
+		$this->assertEquals( $ids, array( $g1, ) );
+	}
+
+	/**
+	 * Integration test to make sure order and orderby are interpreted when
+	 * no 'type' value has been passed
+	 *
+	 * @group bp_has_groups
+	 */
+	public function test_bp_has_groups_with_order_orderby_with_null_type() {
+		$g1 = $this->factory->group->create( array(
+			'name' => 'AAAAA',
+			'date_created' => gmdate( 'Y-m-d H:i:s', time() - 100 ),
+			'last_activity' => gmdate( 'Y-m-d H:i:s', time() - 1000000 ),
+		) );
+		$g2 = $this->factory->group->create( array(
+			'name' => 'BBBBB',
+			'date_created' => gmdate( 'Y-m-d H:i:s', time() - 1000000 ),
+			'last_activity' => gmdate( 'Y-m-d H:i:s', time() - 10000 ),
+		) );
+		$g3 = $this->factory->group->create( array(
+			'name' => 'CCCCC',
+			'date_created' => gmdate( 'Y-m-d H:i:s', time() - 10000 ),
+			'last_activity' => gmdate( 'Y-m-d H:i:s', time() - 10 ),
+		) );
+
+		global $groups_template;
+		bp_has_groups( array(
+			'order' => 'ASC',
+			'orderby' => 'name',
+		) );
+
+		$ids = wp_parse_id_list( wp_list_pluck( $groups_template->groups, 'id' ) );
+		$this->assertEquals( array( $g1, $g2, $g3, ), $ids );
+	}
+
+	/**
+	 * Integration test to make sure 'order' is set to 'DESC' and 'orderby'
+	 * to 'last_activity' when no type or order/orderby params are passed.
+	 * This ensures backpat with the old system, where 'active' was the
+	 * default type param, and there were no order/orderby params.
+	 *
+	 * @group bp_has_groups
+	 */
+	public function test_bp_has_groups_defaults_to_DESC_last_activity_for_default_type_active_backpat() {
+		$g1 = $this->factory->group->create( array(
+			'name' => 'AAAAA',
+			'last_activity' => gmdate( 'Y-m-d H:i:s', time() - 100 ),
+		) );
+		$g2 = $this->factory->group->create( array(
+			'name' => 'BBBBB',
+			'last_activity' => gmdate( 'Y-m-d H:i:s', time() - 1000000 ),
+		) );
+		$g3 = $this->factory->group->create( array(
+			'name' => 'CCCCC',
+			'last_activity' => gmdate( 'Y-m-d H:i:s', time() - 10000 ),
+		) );
+
+		global $groups_template;
+		bp_has_groups();
+
+		$ids = wp_parse_id_list( wp_list_pluck( $groups_template->groups, 'id' ) );
+		$this->assertEquals( array( $g1, $g3, $g2, ), $ids );
+	}
+
+	/**
+	 * @group bp_group_has_members
+	 */
+	public function test_bp_group_has_members_vanilla() {
+		$g = $this->factory->group->create();
+		$u1 = $this->create_user();
+		$u2 = $this->create_user();
+
+		$this->add_user_to_group( $u1, $g );
+
+		global $members_template;
+		bp_group_has_members( array(
+			'group_id' => $g,
+			'exclude_admins_mods' => false,
+		) );
+
+		$ids = wp_parse_id_list( wp_list_pluck( $members_template->members, 'user_id' ) );
+		$this->assertEquals( array( $u1, ), $ids );
+	}
+
+	/**
+	 * Switching from BP_Groups_Member to BP_Group_Member_Query meant a
+	 * change in the format of the values returned from the query. For
+	 * backward compatibility, we translate some of the return values
+	 * of BP_Group_Member_Query to the older format. This test makes sure
+	 * that the translation happens properly.
+	 *
+	 * @group bp_group_has_members
+	 */
+	public function test_bp_group_has_members_backpat_retval_format() {
+		$u1 = $this->create_user();
+		$u2 = $this->create_user();
+		$g = $this->factory->group->create( array( 'creator_id' => $u2 ) );
+
+		$date_modified = gmdate( 'Y-m-d H:i:s', time() - 100 );
+
+		$this->add_user_to_group( $u1, $g, array( 'date_modified' => $date_modified ) );
+
+		global $members_template;
+		bp_group_has_members( array(
+			'group_id' => $g,
+		) );
+
+		$u1_object = new WP_User( $u1 );
+
+		$expected = new stdClass;
+		$expected->user_id = $u1;
+		$expected->date_modified = $date_modified;
+		$expected->is_banned = 0;
+		$expected->user_login = $u1_object->user_login;
+		$expected->user_nicename = $u1_object->user_nicename;
+		$expected->user_email = $u1_object->user_email;
+		$expected->display_name = $u1_object->display_name;
+
+		// In order to use assertEquals, we need to discard the
+		// irrelevant properties of the found object. Hack alert
+		$found = new stdClass;
+		foreach ( array( 'user_id', 'date_modified', 'is_banned', 'user_login', 'user_nicename', 'user_email', 'display_name' ) as $key ) {
+			if ( isset( $members_template->members[0]->{$key} ) ) {
+				$found->{$key} = $members_template->members[0]->{$key};
+			}
+		}
+
+		$this->assertEquals( $expected, $found );
+	}
+
+	/**
+	 * @group bp_group_has_members
+	 */
+	public function test_bp_group_has_members_with_per_page() {
+		$g = $this->factory->group->create();
+
+		$users = array();
+		for ( $i = 1; $i <= 10; $i++ ) {
+			$users[ $i ] = $this->create_user();
+		}
+
+		$expected = array();
+		$now = time();
+		for ( $i = 3; $i <= 10; $i++ ) {
+			$this->add_user_to_group( $users[ $i ], $g, array(
+				'date_modified' => $now - 60 * $i,
+			) );
+			$expected[] = $users[ $i ];
+		}
+
+		// hack it down to 5 (per page arg below)
+		$expected = array_slice( $expected, 0, 5 );
+
+		global $members_template;
+		bp_group_has_members( array(
+			'group_id' => $g,
+			'per_page' => 5,
+		) );
+
+		$ids = wp_parse_id_list( wp_list_pluck( $members_template->members, 'user_id' ) );
+		$this->assertEquals( $expected, $ids );
+	}
+
+	/**
+	 * Note: 'max' is a weird parameter. It just changes the member_count
+	 * in the global - not the sql query at all. I'm testing what it
+	 * appears to be designed to do, not what it feels like it ought to do
+	 * if it made any sense. Programming is fun, QED.
+	 *
+	 * @group bp_group_has_members
+	 */
+	public function test_bp_group_has_members_with_max() {
+		$g = $this->factory->group->create();
+
+		$users = array();
+		for ( $i = 1; $i <= 10; $i++ ) {
+			$users[ $i ] = $this->create_user();
+		}
+
+		$expected = array();
+		for ( $i = 3; $i <= 10; $i++ ) {
+			$this->add_user_to_group( $users[ $i ], $g );
+			$expected[] = $users[ $i ];
+		}
+
+		global $members_template;
+		bp_group_has_members( array(
+			'group_id' => $g,
+			'max' => 5,
+		) );
+
+		$this->assertEquals( 5, $members_template->member_count );
+	}
+
+	/**
+	 * @group bp_group_has_members
+	 */
+	public function test_bp_group_has_members_with_exclude() {
+		$g = $this->factory->group->create();
+		$u1 = $this->create_user();
+		$u2 = $this->create_user();
+
+		$this->add_user_to_group( $u1, $g );
+		$this->add_user_to_group( $u2, $g );
+
+		global $members_template;
+		bp_group_has_members( array(
+			'group_id' => $g,
+			'exclude' => $u1,
+		) );
+
+		$ids = wp_parse_id_list( wp_list_pluck( $members_template->members, 'user_id' ) );
+		$this->assertEquals( array( $u2 ), $ids );
+	}
+
+	/**
+	 * @group bp_group_has_members
+	 */
+	public function test_bp_group_has_members_with_exclude_admins_mods_1() {
+		$g = $this->factory->group->create();
+		$u1 = $this->create_user();
+		$u2 = $this->create_user();
+		$u3 = $this->create_user();
+
+		$this->add_user_to_group( $u1, $g );
+		$this->add_user_to_group( $u2, $g );
+		$this->add_user_to_group( $u3, $g );
+
+		$m1 = new BP_Groups_Member( $u1, $g );
+		$m1->promote( 'admin' );
+		$m2 = new BP_Groups_Member( $u2, $g );
+		$m2->promote( 'mod' );
+
+		global $members_template;
+		bp_group_has_members( array(
+			'group_id' => $g,
+			'exclude_admins_mods' => 1,
+		) );
+
+		$ids = wp_parse_id_list( wp_list_pluck( $members_template->members, 'user_id' ) );
+		$this->assertEquals( array( $u3 ), $ids );
+	}
+
+	/**
+	 * @group bp_group_has_members
+	 */
+	public function test_bp_group_has_members_with_exclude_admins_mods_0() {
+		$u1 = $this->create_user();
+		$u2 = $this->create_user();
+		$u3 = $this->create_user();
+		$g = $this->factory->group->create( array(
+			'creator_id' => $u1,
+		) );
+
+		$now = time();
+		$this->add_user_to_group( $u2, $g, array(
+			'date_modified' => $now - 60,
+		) );
+		$this->add_user_to_group( $u3, $g, array(
+			'date_modified' => $now - 60*60,
+		) );
+
+		$m1 = new BP_Groups_Member( $u1, $g );
+		$m1->promote( 'admin' );
+		$m2 = new BP_Groups_Member( $u2, $g );
+		$m2->promote( 'mod' );
+
+		global $members_template;
+		bp_group_has_members( array(
+			'group_id' => $g,
+			'exclude_admins_mods' => 0,
+		) );
+
+		$ids = wp_parse_id_list( wp_list_pluck( $members_template->members, 'user_id' ) );
+		$this->assertEquals( array( $u1, $u2, $u3 ), $ids );
+	}
+
+	/**
+	 * @group bp_group_has_members
+	 */
+	public function test_bp_group_has_members_with_exclude_banned_1() {
+		$g = $this->factory->group->create();
+		$u1 = $this->create_user();
+		$u2 = $this->create_user();
+
+		$this->add_user_to_group( $u1, $g );
+		$this->add_user_to_group( $u2, $g );
+
+		$m1 = new BP_Groups_Member( $u1, $g );
+		$m1->ban();
+
+		global $members_template;
+		bp_group_has_members( array(
+			'group_id' => $g,
+			'exclude_banned' => 1,
+		) );
+
+		$ids = wp_parse_id_list( wp_list_pluck( $members_template->members, 'user_id' ) );
+		$this->assertEquals( array( $u2, ), $ids );
+	}
+
+	/**
+	 * @group bp_group_has_members
+	 */
+	public function test_bp_group_has_members_with_exclude_banned_0() {
+		$u1 = $this->create_user();
+		$u2 = $this->create_user();
+		$u3 = $this->create_user();
+
+		$g = $this->factory->group->create( array(
+			'creator_id' => $u1,
+		) );
+
+		$this->add_user_to_group( $u2, $g, array(
+			'date_modified' => gmdate( 'Y-m-d H:i:s', time() - 60*60*24 ),
+		) );
+		$this->add_user_to_group( $u3, $g, array(
+			'date_modified' => gmdate( 'Y-m-d H:i:s', time() - 60*60*12 ),
+		) );
+
+		$m2 = new BP_Groups_Member( $u2, $g );
+		$m2->ban();
+
+		global $members_template;
+		bp_group_has_members( array(
+			'group_id' => $g,
+			'exclude_banned' => 0,
+			'exclude_admins_mods' => false,
+		) );
+
+		$ids = wp_parse_id_list( wp_list_pluck( $members_template->members, 'user_id' ) );
+		$this->assertEquals( array( $u1, $u3, $u2 ), $ids );
+	}
+
+	/**
+	 * Default sort order should be the joined date
+	 *
+	 * @tickett BP5106
+	 * @group bp_group_has_members
+	 */
+	public function test_bp_group_has_members_default_order() {
+		$u1 = $this->create_user( array(
+			'last_activity' => gmdate( 'Y-m-d H:i:s', time() - 60 ),
+		) );
+		$u2 = $this->create_user( array(
+			'last_activity' => gmdate( 'Y-m-d H:i:s', time() - 600 ),
+		) );
+		$u3 = $this->create_user( array(
+			'last_activity' => gmdate( 'Y-m-d H:i:s', time() - 6000 ),
+		) );
+
+		$g = $this->factory->group->create( array(
+			'creator_id' => $u1,
+		) );
+
+		$this->add_user_to_group( $u2, $g, array(
+			'date_modified' => gmdate( 'Y-m-d H:i:s', time() - 60*60*24 ),
+		) );
+
+		$this->add_user_to_group( $u3, $g, array(
+			'date_modified' => gmdate( 'Y-m-d H:i:s', time() - 60*60*12 ),
+		) );
+
+		global $members_template;
+		bp_group_has_members( array(
+			'group_id' => $g,
+			'exclude_banned' => 0,
+			'exclude_admins_mods' => false,
+		) );
+
+		$ids = wp_parse_id_list( wp_list_pluck( $members_template->members, 'user_id' ) );
+		$this->assertEquals( array( $u1, $u3, $u2, ), $ids );
+	}
+}
Index: /tags/1.9/tests/testcases/members/functions.php
===================================================================
--- /tags/1.9/tests/testcases/members/functions.php	(revision 7684)
+++ /tags/1.9/tests/testcases/members/functions.php	(revision 7684)
@@ -0,0 +1,79 @@
+<?php
+/**
+ * @group members
+ */
+class BP_Tests_Members_Functions extends BP_UnitTestCase {
+	protected $old_current_user = 0;
+
+	public function setUp() {
+		parent::setUp();
+
+		$this->old_current_user = get_current_user_id();
+		$this->set_current_user( $this->factory->user->create( array( 'role' => 'subscriber' ) ) );
+	}
+
+	public function tearDown() {
+		parent::tearDown();
+		$this->set_current_user( $this->old_current_user );
+	}
+
+	/**
+	 * ticket BP4915
+	 */
+	public function test_bp_core_delete_account() {
+		// Stash
+		$current_user = get_current_user_id();
+		$deletion_disabled = bp_disable_account_deletion();
+
+		// Create an admin for testing
+		$admin_user = $this->factory->user->create( array( 'role' => 'administrator' ) );
+		$this->grant_super_admin( $admin_user );
+
+		// 1. Admin can delete user account
+		$this->set_current_user( $admin_user );
+		$user1 = $this->factory->user->create( array( 'role' => 'subscriber' ) );
+		bp_core_delete_account( $user1 );
+		$maybe_user = new WP_User( $user1 );
+		$this->assertEquals( 0, $maybe_user->ID );
+		unset( $maybe_user );
+
+		// 2. Admin cannot delete superadmin account
+		$user2 = $this->factory->user->create( array( 'role' => 'administrator' ) );
+		$this->grant_super_admin( $user2 );
+		bp_core_delete_account( $user2 );
+		$maybe_user = new WP_User( $user2 );
+		$this->assertNotEquals( 0, $maybe_user->ID );
+		unset( $maybe_user );
+
+		// User cannot delete other's account
+		$user3 = $this->factory->user->create( array( 'role' => 'subscriber' ) );
+		$user4 = $this->factory->user->create( array( 'role' => 'subscriber' ) );
+		$this->set_current_user( $user3 );
+		bp_core_delete_account( $user4 );
+		$maybe_user = new WP_User( $user4 );
+		$this->assertNotEquals( 0, $maybe_user->ID );
+		unset( $maybe_user );
+
+		// User cannot delete own account when account deletion is disabled
+		$user5 = $this->factory->user->create( array( 'role' => 'subscriber' ) );
+		$this->set_current_user( $user5 );
+		bp_update_option( 'bp-disable-account-deletion', 1 );
+		bp_core_delete_account( $user5 );
+		$maybe_user = new WP_User( $user5 );
+		$this->assertNotEquals( 0, $maybe_user->ID );
+		unset( $maybe_user );
+
+		// User can delete own account when account deletion is enabled
+		$user6 = $this->factory->user->create( array( 'role' => 'subscriber' ) );
+		$this->set_current_user( $user6 );
+		bp_update_option( 'bp-disable-account-deletion', 0 );
+		bp_core_delete_account( $user6 );
+		$maybe_user = new WP_User( $user6 );
+		$this->assertEquals( 0, $maybe_user->ID );
+		unset( $maybe_user );
+
+		// Cleanup
+		$this->set_current_user( $current_user );
+		bp_update_option( 'bp-disable-account-deletion', $deletion_disabled );
+	}
+}
Index: /tags/1.9/tests/testcases/members/template.php
===================================================================
--- /tags/1.9/tests/testcases/members/template.php	(revision 7684)
+++ /tags/1.9/tests/testcases/members/template.php	(revision 7684)
@@ -0,0 +1,100 @@
+<?php
+/**
+ * @group members
+ */
+class BP_Tests_Members_Template extends BP_UnitTestCase {
+	protected $old_current_user = 0;
+
+	public function setUp() {
+		parent::setUp();
+
+		$this->old_current_user = get_current_user_id();
+		$new_user = $this->factory->user->create( array( 'role' => 'administrator' ) );
+		$this->set_current_user( $new_user );
+
+	}
+
+	public function tearDown() {
+		parent::tearDown();
+		$this->set_current_user( $this->old_current_user );
+	}
+
+	public function test_bp_has_members_include_on_user_page() {
+		$u1 = $this->create_user();
+		$u2 = $this->create_user();
+
+		$this->go_to( bp_core_get_user_domain( $u1 ) );
+
+		global $members_template;
+		bp_has_members( array(
+			'include' => array( $u1, $u2 ),
+		) );
+
+		$users = is_array( $members_template->members ) ? array_values( $members_template->members ) : array();
+		$user_ids = wp_list_pluck( $users, 'ID' );
+		sort( $user_ids );
+
+		$shouldbe = array( $u1, $u2 );
+		sort( $shouldbe );
+
+		$this->assertEquals( $user_ids, $shouldbe );
+	}
+
+	public function test_bp_has_members_friendship_requests() {
+		$u1 = $this->create_user();
+		$u2 = $this->create_user();
+
+		friends_add_friend( $u1, $u2 );
+
+		$old_user = get_current_user_id();
+		$this->set_current_user( $u2 );
+
+		$this->go_to( bp_core_get_user_domain( $u2 ) . bp_get_friends_slug() . '/requests/' );
+		$this->restore_admins();
+
+		global $members_template;
+		bp_has_members( array(
+			'include' => bp_get_friendship_requests( $u2 ),
+		) );
+
+		$requests = is_array( $members_template->members ) ? array_values( $members_template->members ) : array();
+		$request_ids = wp_list_pluck( $requests, 'ID' );
+		$this->assertEquals( $request_ids, array( $u1 ) );
+
+		$this->set_current_user( $old_user );
+	}
+
+	/**
+	 * @group bp_has_members
+	 * @group friends
+	 * @ticket BP5071
+	 */
+	public function test_bp_has_members_friendship_requests_with_no_requests() {
+		$u1 = $this->create_user();
+		$u2 = $this->create_user();
+
+		$old_user = get_current_user_id();
+		$this->set_current_user( $u2 );
+
+		// For some reason, in all the user switching, the cache gets
+		// confused. Never comes up when BP runs normally, because the
+		// loggedin_user doesn't change on a pageload. @todo Fix for
+		// real in BP
+		wp_cache_delete( 'bp_user_domain_' . $u2, 'bp' );
+
+		$this->go_to( bp_core_get_user_domain( $u2 ) . bp_get_friends_slug() . '/requests/' );
+		$this->restore_admins();
+
+		global $members_template;
+		bp_has_members( array(
+			'include' => bp_get_friendship_requests( $u2 ),
+		) );
+
+		$requests = is_array( $members_template->members ) ? array_values( $members_template->members ) : array();
+		$request_ids = wp_list_pluck( $requests, 'ID' );
+		$this->assertEquals( array(), $request_ids );
+
+		$this->set_current_user( $old_user );
+	}
+
+}
Index: /tags/1.9/tests/testcases/routing/activity.php
===================================================================
--- /tags/1.9/tests/testcases/routing/activity.php	(revision 7684)
+++ /tags/1.9/tests/testcases/routing/activity.php	(revision 7684)
@@ -0,0 +1,68 @@
+<?php
+/**
+ * @group activity
+ * @group routing
+ */
+class BP_Tests_Routing_Activity extends BP_UnitTestCase {
+	protected $old_current_user = 0;
+
+	public function setUp() {
+		parent::setUp();
+
+		$this->old_current_user = get_current_user_id();
+		$this->set_current_user( $this->factory->user->create( array( 'role' => 'subscriber' ) ) );
+	}
+
+	public function tearDown() {
+		parent::tearDown();
+		$this->set_current_user( $this->old_current_user );
+	}
+
+	function test_activity_directory() {
+		$this->go_to( bp_get_activity_directory_permalink() );
+		$this->assertEquals( bp_get_activity_root_slug(), bp_current_component() );
+	}
+
+	/**
+	 * Can't test using bp_activity_get_permalink(); see bp_activity_action_permalink_router().
+	 */
+	function test_activity_permalink() {
+		$a = $this->factory->activity->create();
+		$activity = $this->factory->activity->get_object_by_id( $a );
+
+		$url = bp_core_get_user_domain( $activity->user_id ) . bp_get_activity_slug() . '/' . $activity->id . '/';
+		$this->go_to( $url );
+		$this->assertTrue( bp_is_single_activity() );
+	}
+
+	function test_member_activity() {
+		$this->go_to( bp_core_get_user_domain( bp_loggedin_user_id() ) . bp_get_activity_slug() );
+		$this->assertTrue( bp_is_user_activity() );
+	}
+
+	function test_member_activity_mentions() {
+		$this->go_to( bp_core_get_user_domain( bp_loggedin_user_id() ) . bp_get_activity_slug() . '/mentions'  );
+		$this->assertTrue( bp_is_user_activity() );
+	}
+
+	function test_member_activity_favourites() {
+		$this->go_to( bp_core_get_user_domain( bp_loggedin_user_id() ) . bp_get_activity_slug() . '/favorites'  );
+		$this->assertTrue( bp_is_user_activity() );
+	}
+
+	/**
+	 * @group friends
+	 */
+	function test_member_activity_friends() {
+		$this->go_to( bp_core_get_user_domain( bp_loggedin_user_id() ) . bp_get_activity_slug() . '/' . bp_get_friends_slug() );
+		$this->assertTrue( bp_is_user_friends_activity() );
+	}
+
+	/**
+	 * @group groups
+	 */
+	function test_member_activity_groups() {
+		$this->go_to( bp_core_get_user_domain( bp_loggedin_user_id() ) . bp_get_activity_slug() . '/' . bp_get_groups_slug() );
+		$this->assertTrue( bp_is_user_groups_activity() );
+	}
+}
Index: /tags/1.9/tests/testcases/routing/anonymous.php
===================================================================
--- /tags/1.9/tests/testcases/routing/anonymous.php	(revision 7684)
+++ /tags/1.9/tests/testcases/routing/anonymous.php	(revision 7684)
@@ -0,0 +1,29 @@
+<?php
+/**
+ * @group routing
+ */
+class BP_Tests_Routing_Anonymous extends BP_UnitTestCase {
+	protected $old_current_user = 0;
+
+	public function setUp() {
+		parent::setUp();
+
+		$this->old_current_user = get_current_user_id();
+		$this->set_current_user( 0 );
+	}
+
+	public function tearDown() {
+		parent::tearDown();
+		$this->set_current_user( $this->old_current_user );
+	}
+
+	function test_wordpress_page() {
+		$this->go_to( '/' );
+		$this->assertEmpty( bp_current_component() );
+	}
+
+	function test_nav_menu() {
+		$this->go_to( '/' );
+		$this->assertEmpty( buddypress()->bp_nav );
+	}
+}
Index: /tags/1.9/tests/testcases/routing/core.php
===================================================================
--- /tags/1.9/tests/testcases/routing/core.php	(revision 7684)
+++ /tags/1.9/tests/testcases/routing/core.php	(revision 7684)
@@ -0,0 +1,31 @@
+<?php
+/**
+ * @group core
+ * @group routing
+ */
+class BP_Tests_Routing_Core extends BP_UnitTestCase {
+	protected $old_current_user = 0;
+
+	public function setUp() {
+		parent::setUp();
+
+		$this->old_current_user = get_current_user_id();
+		$this->set_current_user( $this->factory->user->create( array( 'role' => 'subscriber' ) ) );
+	}
+
+	public function tearDown() {
+		parent::tearDown();
+		$this->set_current_user( $this->old_current_user );
+	}
+
+	function test_wordpress_page() {
+		$this->go_to( '/' );
+		$this->assertEmpty( bp_current_component() );
+	}
+
+	function test_nav_menu() {
+		$this->go_to( '/' );
+		$this->assertArrayHasKey( 'activity', buddypress()->bp_nav );
+		$this->assertArrayHasKey( 'profile',  buddypress()->bp_nav );
+	}
+}
Index: /tags/1.9/tests/testcases/routing/friends.php
===================================================================
--- /tags/1.9/tests/testcases/routing/friends.php	(revision 7684)
+++ /tags/1.9/tests/testcases/routing/friends.php	(revision 7684)
@@ -0,0 +1,30 @@
+<?php
+/**
+ * @group friends
+ * @group routing
+ */
+class BP_Tests_Routing_Friends extends BP_UnitTestCase {
+	protected $old_current_user = 0;
+
+	public function setUp() {
+		parent::setUp();
+
+		$this->old_current_user = get_current_user_id();
+		$this->set_current_user( $this->factory->user->create( array( 'role' => 'subscriber' ) ) );
+	}
+
+	public function tearDown() {
+		parent::tearDown();
+		$this->set_current_user( $this->old_current_user );
+	}
+
+	function test_member_friends() {
+		$this->go_to( bp_core_get_user_domain( bp_loggedin_user_id() ) . bp_get_friends_slug() );
+		$this->assertTrue( bp_is_user_friends() );
+	}
+
+	function test_member_friends_requests() {
+		$this->go_to( bp_core_get_user_domain( bp_loggedin_user_id() ) . bp_get_friends_slug()  . '/requests' );
+		$this->assertTrue( bp_is_user_friend_requests() );
+	}
+}
Index: /tags/1.9/tests/testcases/routing/groups.php
===================================================================
--- /tags/1.9/tests/testcases/routing/groups.php	(revision 7684)
+++ /tags/1.9/tests/testcases/routing/groups.php	(revision 7684)
@@ -0,0 +1,30 @@
+<?php
+/**
+ * @group groups
+ * @group routing
+ */
+class BP_Tests_Routing_Groups extends BP_UnitTestCase {
+	protected $old_current_user = 0;
+
+	public function setUp() {
+		parent::setUp();
+
+		$this->old_current_user = get_current_user_id();
+		$this->set_current_user( $this->factory->user->create( array( 'role' => 'subscriber' ) ) );
+	}
+
+	public function tearDown() {
+		parent::tearDown();
+		$this->set_current_user( $this->old_current_user );
+	}
+
+	function test_member_groups() {
+		$this->go_to( bp_core_get_user_domain( bp_loggedin_user_id() ) . bp_get_groups_slug() );
+		$this->assertTrue( bp_is_user_groups() );
+	}
+
+	function test_member_groups_invitations() {
+		$this->go_to( bp_core_get_user_domain( bp_loggedin_user_id() ) . bp_get_groups_slug() . '/invites' );
+		$this->assertTrue( bp_is_user_groups() && bp_is_current_action( 'invites' ) );
+	}
+}
Index: /tags/1.9/tests/testcases/routing/members.php
===================================================================
--- /tags/1.9/tests/testcases/routing/members.php	(revision 7684)
+++ /tags/1.9/tests/testcases/routing/members.php	(revision 7684)
@@ -0,0 +1,30 @@
+<?php
+/**
+ * @group members
+ * @group routing
+ */
+class BP_Tests_Routing_Members extends BP_UnitTestCase {
+	protected $old_current_user = 0;
+
+	public function setUp() {
+		parent::setUp();
+
+		$this->old_current_user = get_current_user_id();
+		$this->set_current_user( $this->factory->user->create( array( 'user_login' => 'paulgibbs', 'role' => 'subscriber' ) ) );
+	}
+
+	public function tearDown() {
+		parent::tearDown();
+		$this->set_current_user( $this->old_current_user );
+	}
+
+	function test_members_directory() {
+		$this->go_to( bp_get_members_directory_permalink() );
+		$this->assertEquals( bp_get_members_root_slug(), bp_current_component() );
+	}
+
+	function test_member_permalink() {
+		$this->go_to( bp_core_get_user_domain( bp_loggedin_user_id() ) );
+		$this->assertTrue( bp_is_my_profile() );
+	}
+}
Index: /tags/1.9/tests/testcases/routing/messages.php
===================================================================
--- /tags/1.9/tests/testcases/routing/messages.php	(revision 7684)
+++ /tags/1.9/tests/testcases/routing/messages.php	(revision 7684)
@@ -0,0 +1,40 @@
+<?php
+/**
+ * @group messages
+ * @group routing
+ */
+class BP_Tests_Routing_Messages extends BP_UnitTestCase {
+	protected $old_current_user = 0;
+
+	public function setUp() {
+		parent::setUp();
+
+		$this->old_current_user = get_current_user_id();
+		$this->set_current_user( $this->factory->user->create( array( 'role' => 'subscriber' ) ) );
+	}
+
+	public function tearDown() {
+		parent::tearDown();
+		$this->set_current_user( $this->old_current_user );
+	}
+
+	function test_member_messages() {
+		$this->go_to( bp_core_get_user_domain( bp_loggedin_user_id() ) . bp_get_messages_slug() );
+		$this->assertTrue( bp_is_messages_inbox() );
+	}
+
+	function test_member_messages_sentbox() {
+		$this->go_to( bp_core_get_user_domain( bp_loggedin_user_id() ) . bp_get_messages_slug() . '/sentbox' );
+		$this->assertTrue( bp_is_messages_sentbox() );
+	}
+
+	function test_member_messages_compose() {
+		$this->go_to( bp_core_get_user_domain( bp_loggedin_user_id() ) . bp_get_messages_slug() . '/compose' );
+		$this->assertTrue( bp_is_messages_compose_screen() );
+	}
+
+	function test_member_messages_notices() {
+		$this->go_to( bp_core_get_user_domain( bp_loggedin_user_id() ) . bp_get_messages_slug() . '/notices' );
+		$this->assertTrue( bp_is_notices() );
+	}
+}
Index: /tags/1.9/tests/testcases/routing/settings.php
===================================================================
--- /tags/1.9/tests/testcases/routing/settings.php	(revision 7684)
+++ /tags/1.9/tests/testcases/routing/settings.php	(revision 7684)
@@ -0,0 +1,40 @@
+<?php
+/**
+ * @group settings
+ * @group routing
+ */
+class BP_Tests_Routing_Settings extends BP_UnitTestCase {
+	protected $old_current_user = 0;
+
+	public function setUp() {
+		parent::setUp();
+
+		$this->old_current_user = get_current_user_id();
+		$this->set_current_user( $this->factory->user->create( array( 'role' => 'subscriber' ) ) );
+	}
+
+	public function tearDown() {
+		parent::tearDown();
+		$this->set_current_user( $this->old_current_user );
+	}
+
+	function test_member_settings() {
+		$this->go_to( bp_core_get_user_domain( bp_loggedin_user_id() ) . bp_get_settings_slug() );
+		$this->assertTrue( bp_is_user_settings_general() );
+	}
+
+	function test_member_settings_notifications() {
+		$this->go_to( bp_core_get_user_domain( bp_loggedin_user_id() ) . bp_get_settings_slug() . '/notifications' );
+		$this->assertTrue( bp_is_user_settings_notifications() );
+	}
+
+	// @todo How best to test this?
+	/*function bp_is_user_settings_account_capbilities() {
+		$this->go_to( bp_core_get_user_domain( bp_loggedin_user_id() ) . bp_get_settings_slug() . '/capabilities' );
+	}*/
+
+	function bp_is_user_settings_account_delete() {
+		$this->go_to( bp_core_get_user_domain( bp_loggedin_user_id() ) . bp_get_settings_slug() . '/delete-account' );
+		$this->assertTrue( bp_is_user_settings_account_delete() );
+	}
+}
Index: /tags/1.9/tests/testcases/routing/xprofile.php
===================================================================
--- /tags/1.9/tests/testcases/routing/xprofile.php	(revision 7684)
+++ /tags/1.9/tests/testcases/routing/xprofile.php	(revision 7684)
@@ -0,0 +1,35 @@
+<?php
+/**
+ * @group xprofile
+ * @group routing
+ */
+class BP_Tests_Routing_XProfile extends BP_UnitTestCase {
+	protected $old_current_user = 0;
+
+	public function setUp() {
+		parent::setUp();
+
+		$this->old_current_user = get_current_user_id();
+		$this->set_current_user( $this->factory->user->create( array( 'role' => 'subscriber' ) ) );
+	}
+
+	public function tearDown() {
+		parent::tearDown();
+		$this->set_current_user( $this->old_current_user );
+	}
+
+	function test_member_profile() {
+		$this->go_to( bp_core_get_user_domain( bp_loggedin_user_id() ) . buddypress()->profile->slug );
+		$this->assertTrue( bp_is_user_profile() );
+	}
+
+	function test_member_profile_edit() {
+		$this->go_to( bp_core_get_user_domain( bp_loggedin_user_id() ) . buddypress()->profile->slug . '/edit' );
+		$this->assertTrue( bp_is_user_profile_edit() );
+	}
+
+	function test_member_profile_change_avatar() {
+		$this->go_to( bp_core_get_user_domain( bp_loggedin_user_id() ) . buddypress()->profile->slug . '/change-avatar' );
+		$this->assertTrue( bp_is_user_change_avatar() );
+	}
+}
Index: /tags/1.9/tests/testcases/url/url.php
===================================================================
--- /tags/1.9/tests/testcases/url/url.php	(revision 7684)
+++ /tags/1.9/tests/testcases/url/url.php	(revision 7684)
@@ -0,0 +1,65 @@
+<?php
+/**
+ * @group url
+ */
+class BP_Tests_URL extends BP_UnitTestCase {
+	protected $old_current_user = 0;
+
+	public function setUp() {
+		parent::setUp();
+
+		$this->old_current_user = get_current_user_id();
+		$this->set_current_user( $this->factory->user->create( array( 'role' => 'subscriber' ) ) );
+	}
+
+	public function tearDown() {
+		parent::tearDown();
+		$this->set_current_user( $this->old_current_user );
+	}
+
+	function test_bp_core_ajax_url() {
+		$forced = force_ssl_admin();
+
+		// (1) HTTPS off
+		force_ssl_admin( false );
+		$_SERVER['HTTPS'] = 'off';
+
+		// (1a) Front-end
+		$this->go_to( '/' );
+		$this->assertEquals( bp_core_ajax_url(), get_site_url( bp_get_root_blog_id(), '/wp-admin/admin-ajax.php', 'http' ) );
+
+		// (1b) Dashboard
+		$this->go_to( '/wp-admin' );
+		$this->assertEquals( bp_core_ajax_url(), get_site_url( bp_get_root_blog_id(), '/wp-admin/admin-ajax.php', 'http' ) );
+
+		// (2) FORCE_SSL_ADMIN
+		force_ssl_admin( true );
+
+		// (2a) Front-end
+		$this->go_to( '/' );
+		$this->assertEquals( bp_core_ajax_url(), get_site_url( bp_get_root_blog_id(), '/wp-admin/admin-ajax.php', 'http' ) );
+
+		// (2b) Dashboard
+		$this->go_to( '/wp-admin' );
+		$this->assertEquals( bp_core_ajax_url(), get_site_url( bp_get_root_blog_id(), '/wp-admin/admin-ajax.php', 'https' ) );
+
+		force_ssl_admin( $forced );
+
+		// (3) Multisite, root blog other than 1
+		if ( is_multisite() ) {
+			$original_root_blog = bp_get_root_blog_id();
+			$blog_id = $this->factory->blog->create();
+			buddypress()->root_blog_id = $blog_id;
+
+			switch_to_blog( $blog_id );
+			$blog_details = get_blog_details();
+
+			$this->go_to( $blog_details->path );
+			$this->assertEquals( $blog_details->siteurl . '/wp-admin/admin-ajax.php', bp_core_ajax_url() );
+
+			restore_current_blog();
+			buddypress()->root_blog_id = $original_root_blog;
+		}
+
+	}
+}
Index: /tags/1.9/tests/testcases/xprofile/class-bp-xprofile-field.php
===================================================================
--- /tags/1.9/tests/testcases/xprofile/class-bp-xprofile-field.php	(revision 7684)
+++ /tags/1.9/tests/testcases/xprofile/class-bp-xprofile-field.php	(revision 7684)
@@ -0,0 +1,29 @@
+<?php
+/**
+ * @group xprofile
+ * @group BP_XProfile_Field
+ */
+class BP_Tests_BP_XProfile_XProfile_TestCases extends BP_UnitTestCase {
+	public function setUp() {
+		parent::setUp();
+	}
+
+	public function tearDown() {
+		parent::tearDown();
+	}
+
+	public function test_can_delete_save() {
+		$group = $this->factory->xprofile_group->create();
+		$field = $this->factory->xprofile_field->create( array(
+			'field_group_id' => $group->id,
+			'type' => 'textbox',
+		) );
+
+		$f = new BP_XProfile_Field( $field->id );
+		$f->can_delete = 0;
+		$f->save();
+
+		$f2 = new BP_XProfile_Field( $field->id );
+		$this->assertEquals( '0', $f2->can_delete );
+	}
+}
Index: /tags/1.9/tests/testcases/xprofile/functions.php
===================================================================
--- /tags/1.9/tests/testcases/xprofile/functions.php	(revision 7684)
+++ /tags/1.9/tests/testcases/xprofile/functions.php	(revision 7684)
@@ -0,0 +1,83 @@
+<?php
+
+/**
+ * @group xprofile
+ * @group functions
+ */
+class BP_Tests_XProfile_Functions extends BP_UnitTestCase {
+	public function setUp() {
+		parent::setUp();
+	}
+
+	public function tearDown() {
+		parent::tearDown();
+	}
+
+	public function test_get_hidden_field_types_for_user_loggedout() {
+		$duser = $this->create_user();
+
+		$old_current_user = bp_loggedin_user_id();
+		$this->set_current_user( 0 );
+
+		$this->assertEquals( array( 'friends', 'loggedin', 'adminsonly' ), bp_xprofile_get_hidden_field_types_for_user( $duser, bp_loggedin_user_id() ) );
+
+		$this->set_current_user( $old_current_user );
+	}
+
+	public function test_get_hidden_field_types_for_user_loggedin() {
+		$duser = $this->create_user();
+		$cuser = $this->create_user();
+
+		$old_current_user = bp_loggedin_user_id();
+		$this->set_current_user( $cuser );
+
+		$this->assertEquals( array( 'friends', 'adminsonly' ), bp_xprofile_get_hidden_field_types_for_user( $duser, bp_loggedin_user_id() ) );
+
+		$this->set_current_user( $old_current_user );
+	}
+
+	public function test_get_hidden_field_types_for_user_friends() {
+		$duser = $this->create_user();
+		$cuser = $this->create_user();
+		friends_add_friend( $duser, $cuser, true );
+
+		$old_current_user = bp_loggedin_user_id();
+		$this->set_current_user( $cuser );
+
+		$this->assertEquals( array( 'adminsonly' ), bp_xprofile_get_hidden_field_types_for_user( $duser, bp_loggedin_user_id() ) );
+
+		$this->set_current_user( $old_current_user );
+	}
+
+	public function test_get_hidden_field_types_for_user_admin() {
+		$duser = $this->create_user();
+		$cuser = $this->create_user();
+		$this->grant_bp_moderate( $cuser );
+
+		$old_current_user = bp_loggedin_user_id();
+		$this->set_current_user( $cuser );
+
+		$this->assertEquals( array(), bp_xprofile_get_hidden_field_types_for_user( $duser, bp_loggedin_user_id() ) );
+
+		$this->revoke_bp_moderate( $cuser );
+		$this->set_current_user( $old_current_user );
+	}
+
+	/**
+	 * @group bp_xprofile_update_meta
+	 * @ticket BP5180
+	 */
+	public function test_bp_xprofile_update_meta_with_line_breaks() {
+		$g = $this->factory->xprofile_group->create();
+		$f = $this->factory->xprofile_field->create( array(
+			'field_group_id' => $g->id,
+			'type' => 'textbox',
+		) );
+
+		$meta_value = 'Foo!
+
+Bar!';
+		bp_xprofile_update_meta( $f->id, 'field', 'linebreak_field', $meta_value );
+		$this->assertEquals( $meta_value, bp_xprofile_get_meta( $f->id, 'field', 'linebreak_field' ) );
+	}
+}
