What is it? BuddyPressDEV.org is the community of BuddyPress' developers that creates and extend this platform.
[ Index ]

PHP Cross Reference of BuddyPress SVN Code

title

Body

[close]

/ -> bp-xprofile.php (source)

   1  <?php
   2  
   3  define ( 'BP_XPROFILE_DB_VERSION', '1300' );
   4  
   5  /* Define the slug for the component */
   6  if ( !defined( 'BP_XPROFILE_SLUG' ) )
   7      define ( 'BP_XPROFILE_SLUG', 'profile' );
   8  
   9  require  ( BP_PLUGIN_DIR . '/bp-xprofile/bp-xprofile-classes.php' );
  10  require  ( BP_PLUGIN_DIR . '/bp-xprofile/bp-xprofile-filters.php' );
  11  require  ( BP_PLUGIN_DIR . '/bp-xprofile/bp-xprofile-signup.php' );
  12  require  ( BP_PLUGIN_DIR . '/bp-xprofile/bp-xprofile-templatetags.php' );
  13  require  ( BP_PLUGIN_DIR . '/bp-xprofile/bp-xprofile-notifications.php' );
  14  require  ( BP_PLUGIN_DIR . '/bp-xprofile/bp-xprofile-cssjs.php' );
  15  
  16  /* Include deprecated functions if settings allow */
  17  if ( !defined( 'BP_IGNORE_DEPRECATED' ) )
  18      require  ( BP_PLUGIN_DIR . '/bp-xprofile/deprecated/bp-xprofile-deprecated.php' );    
  19  
  20  /* Assign the base group and fullname field names to constants to use in SQL statements */
  21  define ( 'BP_XPROFILE_BASE_GROUP_NAME', get_site_option( 'bp-xprofile-base-group-name' ) );
  22  define ( 'BP_XPROFILE_FULLNAME_FIELD_NAME', get_site_option( 'bp-xprofile-fullname-field-name' ) );
  23  
  24  /**
  25   * xprofile_install()
  26   *
  27   * Set up the database tables needed for the xprofile component.
  28   * 
  29   * @package BuddyPress XProfile
  30   * @global $bp The global BuddyPress settings variable created in bp_core_setup_globals()
  31   * @uses dbDelta() Takes SQL statements and compares them to any existing tables and creates/updates them.
  32   * @uses add_site_option() adds a value for a meta_key into the wp_sitemeta table
  33   */
  34  function xprofile_install() {
  35      global $bp, $wpdb;
  36  
  37      if ( !empty($wpdb->charset) )
  38          $charset_collate = "DEFAULT CHARACTER SET $wpdb->charset";
  39      
  40      if ( '' == get_site_option( 'bp-xprofile-base-group-name' ) )
  41          update_site_option( 'bp-xprofile-base-group-name', 'Base' );
  42      
  43      if ( '' == get_site_option( 'bp-xprofile-fullname-field-name' ) )
  44          update_site_option( 'bp-xprofile-fullname-field-name', 'Name' );    
  45      
  46      $sql[] = "CREATE TABLE {$bp->profile->table_name_groups} (
  47                id bigint(20) unsigned NOT NULL AUTO_INCREMENT PRIMARY KEY,
  48                name varchar(150) NOT NULL,
  49                description mediumtext NOT NULL,
  50                can_delete tinyint(1) NOT NULL,
  51                KEY can_delete (can_delete)
  52      ) {$charset_collate};";
  53      
  54      $sql[] = "CREATE TABLE {$bp->profile->table_name_fields} (
  55                id bigint(20) unsigned NOT NULL AUTO_INCREMENT PRIMARY KEY,
  56                group_id bigint(20) unsigned NOT NULL,
  57                parent_id bigint(20) unsigned NOT NULL,
  58                type varchar(150) NOT NULL,
  59                name varchar(150) NOT NULL,
  60                description longtext NOT NULL,
  61                is_required tinyint(1) NOT NULL DEFAULT '0',
  62                is_default_option tinyint(1) NOT NULL DEFAULT '0',
  63                field_order bigint(20) NOT NULL DEFAULT '0',
  64                option_order bigint(20) NOT NULL DEFAULT '0',
  65                order_by varchar(15) NOT NULL,
  66                can_delete tinyint(1) NOT NULL DEFAULT '1',
  67                KEY group_id (group_id),
  68                KEY parent_id (parent_id),
  69                KEY can_delete (can_delete),
  70                KEY is_required (is_required)
  71      ) {$charset_collate};";
  72      
  73      $sql[] = "CREATE TABLE {$bp->profile->table_name_data} (
  74                id bigint(20) unsigned NOT NULL AUTO_INCREMENT PRIMARY KEY,
  75                field_id bigint(20) unsigned NOT NULL,
  76                user_id bigint(20) unsigned NOT NULL,
  77                value longtext NOT NULL,
  78                last_updated datetime NOT NULL,
  79                KEY field_id (field_id),
  80                KEY user_id (user_id)
  81      ) {$charset_collate};";
  82      
  83      if ( '' == get_site_option( 'bp-xprofile-db-version' ) ) {
  84          $sql[] = "INSERT INTO {$bp->profile->table_name_groups} VALUES ( 1, '" . get_site_option( 'bp-xprofile-base-group-name' ) . "', '', 0 );";
  85      
  86          $sql[] = "INSERT INTO {$bp->profile->table_name_fields} ( 
  87                      id, group_id, parent_id, type, name, description, is_required, field_order, option_order, order_by, is_public, can_delete
  88                    ) VALUES (
  89                      1, 1, 0, 'textbox', '" . get_site_option( 'bp-xprofile-fullname-field-name' ) . "', '', 1, 1, 0, '', 1, 0
  90                    );";
  91      }
  92      
  93      require_once( ABSPATH . 'wp-admin/upgrade-functions.php' );
  94      dbDelta($sql);
  95      
  96      if ( function_exists('bp_wire_install') )
  97          xprofile_wire_install();
  98      
  99      update_site_option( 'bp-xprofile-db-version', BP_XPROFILE_DB_VERSION );
 100  }
 101  
 102  function xprofile_wire_install() {
 103      global $bp, $wpdb;
 104  
 105      if ( !empty($wpdb->charset) )
 106          $charset_collate = "DEFAULT CHARACTER SET $wpdb->charset";
 107  
 108      $sql[] = "CREATE TABLE {$bp->profile->table_name_wire} (
 109                   id bigint(20) NOT NULL AUTO_INCREMENT,
 110                 item_id bigint(20) NOT NULL,
 111                 user_id bigint(20) NOT NULL,
 112                 content longtext NOT NULL,
 113                 date_posted datetime NOT NULL,
 114                 PRIMARY KEY id (id),
 115                 KEY item_id (item_id),
 116                 KEY user_id (user_id)
 117                  ) {$charset_collate};";
 118  
 119      require_once( ABSPATH . 'wp-admin/upgrade-functions.php' );
 120      dbDelta($sql);
 121  }
 122  
 123  /**
 124   * xprofile_setup_globals()
 125   *
 126   * Add the profile globals to the $bp global for use across the installation
 127   * 
 128   * @package BuddyPress XProfile
 129   * @global $bp The global BuddyPress settings variable created in bp_core_setup_globals()
 130   * @global $wpdb WordPress DB access object.
 131   * @uses site_url() Returns the site URL
 132   */
 133  function xprofile_setup_globals() {
 134      global $bp, $wpdb;
 135      
 136      $bp->profile->table_name_groups = $wpdb->base_prefix . 'bp_xprofile_groups';
 137      $bp->profile->table_name_fields = $wpdb->base_prefix . 'bp_xprofile_fields';
 138      $bp->profile->table_name_data = $wpdb->base_prefix . 'bp_xprofile_data';
 139      $bp->profile->format_activity_function = 'xprofile_format_activity';
 140      $bp->profile->format_notification_function = 'xprofile_format_notifications';
 141      $bp->profile->image_base = BP_PLUGIN_URL . '/bp-xprofile/images';
 142      $bp->profile->slug = BP_XPROFILE_SLUG;
 143      
 144      $bp->profile->field_types = apply_filters( 'xprofile_field_types', array( 'textbox', 'textarea', 'radio', 'checkbox', 'selectbox', 'multiselectbox', 'datebox' ) );
 145  
 146      $bp->version_numbers->profile = BP_XPROFILE_VERSION;
 147      
 148      if ( function_exists('bp_wire_install') )
 149          $bp->profile->table_name_wire = $wpdb->base_prefix . 'bp_xprofile_wire';
 150  }
 151  add_action( 'plugins_loaded', 'xprofile_setup_globals', 5 );    
 152  add_action( 'admin_menu', 'xprofile_setup_globals', 1 );
 153  
 154  /**
 155   * xprofile_add_admin_menu()
 156   *
 157   * Creates the administration interface menus and checks to see if the DB
 158   * tables are set up.
 159   * 
 160   * @package BuddyPress XProfile
 161   * @global $bp The global BuddyPress settings variable created in bp_core_setup_globals()
 162   * @global $wpdb WordPress DB access object.
 163   * @uses is_site_admin() returns true if the current user is a site admin, false if not
 164   * @uses bp_xprofile_install() runs the installation of DB tables for the xprofile component
 165   * @uses wp_enqueue_script() Adds a JS file to the JS queue ready for output
 166   * @uses add_submenu_page() Adds a submenu tab to a top level tab in the admin area
 167   * @uses xprofile_install() Runs the DB table installation function
 168   * @return 
 169   */
 170  function xprofile_add_admin_menu() {
 171      global $wpdb, $bp;
 172      
 173      if ( !is_site_admin() )
 174          return false;
 175  
 176      require  ( BP_PLUGIN_DIR . '/bp-xprofile/bp-xprofile-admin.php' );
 177      
 178      /* Add the administration tab under the "Site Admin" tab for site administrators */
 179      add_submenu_page( 'bp-core.php', __("Profile Field Setup", 'buddypress'), __("Profile Field Setup", 'buddypress'), 1, __FILE__, "xprofile_admin" );
 180  
 181      /* Need to check db tables exist, activate hook no-worky in mu-plugins folder. */
 182      if ( get_site_option('bp-xprofile-db-version') < BP_XPROFILE_DB_VERSION )
 183          xprofile_install();
 184  }
 185  add_action( 'admin_menu', 'xprofile_add_admin_menu' );
 186  
 187  /**
 188   * xprofile_setup_nav()
 189   *
 190   * Sets up the navigation items for the xprofile component
 191   * 
 192   * @package BuddyPress XProfile
 193   * @global $bp The global BuddyPress settings variable created in bp_core_setup_globals()
 194   * @uses bp_core_add_nav_item() Adds a navigation item to the top level buddypress navigation
 195   * @uses bp_core_add_nav_default() Sets which sub navigation item is selected by default
 196   * @uses bp_core_add_subnav_item() Adds a sub navigation item to a nav item
 197   * @uses bp_is_home() Returns true if the current user being viewed is equal the logged in user
 198   * @uses bp_core_fetch_avatar() Returns the either the thumb or full avatar URL for the user_id passed
 199   */
 200  function xprofile_setup_nav() {
 201      global $bp;
 202      
 203      /* Add 'Profile' to the main navigation */
 204      bp_core_new_nav_item( array( 'name' => __('Profile', 'buddypress'), 'slug' => $bp->profile->slug, 'position' => 20, 'screen_function' => 'xprofile_screen_display_profile', 'default_subnav_slug' => 'public' ) );
 205  
 206      $profile_link = $bp->loggedin_user->domain . $bp->profile->slug . '/';
 207      
 208      /* Add the subnav items to the profile */
 209      bp_core_new_subnav_item( array( 'name' => __( 'Public', 'buddypress' ), 'slug' => 'public', 'parent_url' => $profile_link, 'parent_slug' => $bp->profile->slug, 'screen_function' => 'xprofile_screen_display_profile', 'position' => 10 ) );
 210      bp_core_new_subnav_item( array( 'name' => __( 'Edit Profile', 'buddypress' ), 'slug' => 'edit', 'parent_url' => $profile_link, 'parent_slug' => $bp->profile->slug, 'screen_function' => 'xprofile_screen_edit_profile', 'position' => 20 ) );
 211      bp_core_new_subnav_item( array( 'name' => __( 'Change Avatar', 'buddypress' ), 'slug' => 'change-avatar', 'parent_url' => $profile_link, 'parent_slug' => $bp->profile->slug, 'screen_function' => 'xprofile_screen_change_avatar', 'position' => 30 ) );
 212  
 213      if ( $bp->current_component == $bp->profile->slug ) {
 214          if ( bp_is_home() ) {
 215              $bp->bp_options_title = __('My Profile', 'buddypress');
 216          } else {
 217              $bp->bp_options_avatar = bp_core_fetch_avatar( array( 'item_id' => $bp->displayed_user->id, 'type' => 'thumb' ) );
 218              $bp->bp_options_title = $bp->displayed_user->fullname; 
 219          }
 220      }
 221      
 222      do_action( 'xprofile_setup_nav' );
 223  }
 224  add_action( 'wp', 'xprofile_setup_nav', 2 );
 225  add_action( 'admin_menu', 'xprofile_setup_nav', 2 );
 226  
 227  
 228  /********************************************************************************
 229   * Screen Functions
 230   *
 231   * Screen functions are the controllers of BuddyPress. They will execute when their
 232   * specific URL is caught. They will first save or manipulate data using business
 233   * functions, then pass on the user to a template file.
 234   */
 235  
 236  /**
 237   * xprofile_screen_display_profile()
 238   *
 239   * Handles the display of the profile page by loading the correct template file.
 240   * 
 241   * @package BuddyPress Xprofile
 242   * @uses bp_core_load_template() Looks for and loads a template file within the current member theme (folder/filename)
 243   */
 244  function xprofile_screen_display_profile() {
 245      global $bp, $is_new_friend;
 246      
 247      // If this is a first visit to a new friends profile, delete the friend accepted notifications for the
 248      // logged in user. $is_new_friend is set in bp-core/bp-core-catchuri.php in bp_core_set_uri_globals()
 249      if ( $is_new_friend )
 250          bp_core_delete_notifications_for_user_by_item_id( $bp->loggedin_user->id, $bp->displayed_user->id, 'friends', 'friendship_accepted' );
 251      
 252      do_action( 'xprofile_screen_display_profile', $is_new_friend );
 253      bp_core_load_template( apply_filters( 'xprofile_template_display_profile', 'profile/index' ) );
 254  }
 255  
 256  /**
 257   * xprofile_screen_edit_profile()
 258   *
 259   * Handles the display of the profile edit page by loading the correct template file.
 260   * Also checks to make sure this can only be accessed for the logged in users profile.
 261   * 
 262   * @package BuddyPress Xprofile
 263   * @uses bp_is_home() Checks to make sure the current user being viewed equals the logged in user
 264   * @uses bp_core_load_template() Looks for and loads a template file within the current member theme (folder/filename)
 265   */
 266  function xprofile_screen_edit_profile() {
 267      global $bp;
 268      
 269      if ( !bp_is_home() && !is_site_admin() )
 270          return false;
 271      
 272      /* Check to see if any new information has been submitted */
 273      if ( isset($_POST['field_ids']) ) {
 274          
 275          /* Check the nonce */
 276          check_admin_referer( 'bp_xprofile_edit' );
 277          
 278          /* Check we have field ID's */
 279          if ( empty( $_POST['field_ids'] ) )
 280              bp_core_redirect( $bp->displayed_user->domain . BP_XPROFILE_SLUG . '/edit/group/' . $bp->action_variables[1] . '/' );
 281          
 282          /* Explode the posted field IDs into an array so we know which fields have been submitted */
 283          $posted_field_ids = explode( ',', $_POST['field_ids'] );
 284                  
 285          /* Loop through the posted fields formatting any datebox values then validate the field */
 286          foreach ( $posted_field_ids as $field_id ) {        
 287              
 288              if ( !isset( $_POST['field_' . $field_id] ) ) {
 289                  
 290                  if ( isset( $_POST['field_' . $field_id . '_day'] ) ) {
 291                      /* Concatenate the values. */
 292                      $date_value = $_POST['field_' . $field_id . '_day'] . 
 293                                    $_POST['field_' . $field_id . '_month'] . 
 294                                    $_POST['field_' . $field_id . '_year'];
 295                  
 296                      /* Turn the concatenated value into a timestamp */
 297                      $_POST['field_' . $field_id] = strtotime( $date_value );                    
 298                  }
 299                  
 300              }
 301              
 302              if ( xprofile_check_is_required_field( $field_id ) && empty( $_POST['field_' . $field_id] ) )
 303                  $errors = true;
 304          }
 305          
 306          if ( $errors )
 307              bp_core_add_message( __( 'Please make sure you fill in all required fields in this profile field group before saving.', 'buddypress' ), 'error' );            
 308          else {        
 309              /* Reset the errors var */
 310              $errors = false;
 311          
 312              /* Now we've checked for required fields, lets save the values. */
 313              foreach ( $posted_field_ids as $field_id ) {        
 314                  if ( !xprofile_set_field_data( $field_id, $bp->displayed_user->id, $_POST['field_' . $field_id] ) )
 315                      $errors = true;
 316                  else
 317                      do_action( 'xprofile_profile_field_data_updated', $field_id, $_POST['field_' . $field_id] );
 318              }
 319                  
 320              do_action( 'xprofile_updated_profile', $posted_field_ids, $errors );
 321          
 322              /* Set the feedback messages */
 323              if ( $errors )
 324                  bp_core_add_message( __( 'There was a problem updating some of your profile information, please try again.', 'buddypress' ), 'error' );
 325              else
 326                  bp_core_add_message( __( 'Changes saved.', 'buddypress' ) );
 327  
 328              /* Redirect back to the edit screen to display the updates and message */
 329              bp_core_redirect( $bp->displayed_user->domain . BP_XPROFILE_SLUG . '/edit/group/' . $bp->action_variables[1] . '/' );
 330          }
 331      }
 332  
 333      do_action( 'xprofile_screen_edit_profile' );
 334      bp_core_load_template( apply_filters( 'xprofile_template_edit_profile', 'profile/edit' ) );            
 335  }
 336  
 337  /**
 338   * xprofile_screen_change_avatar()
 339   *
 340   * Handles the uploading and cropping of a user avatar. Displays the change avatar page.
 341   * 
 342   * @package BuddyPress Xprofile
 343   * @uses bp_is_home() Checks to make sure the current user being viewed equals the logged in user
 344   * @uses bp_core_load_template() Looks for and loads a template file within the current member theme (folder/filename)
 345   */
 346  function xprofile_screen_change_avatar() {
 347      global $bp;
 348      
 349      if ( !bp_is_home() && !is_site_admin() )
 350          return false;
 351      
 352      $bp->avatar_admin->step = 'upload-image';
 353      
 354      if ( !empty( $_FILES ) ) {
 355          
 356          /* Check the nonce */
 357          check_admin_referer( 'bp_avatar_upload' );
 358  
 359          /* Pass the file to the avatar upload handler */        
 360          if ( bp_core_avatar_handle_upload( $_FILES, 'xprofile_avatar_upload_dir' ) ) {        
 361              $bp->avatar_admin->step = 'crop-image';
 362  
 363              /* Make sure we include the jQuery jCrop file for image cropping */
 364              add_action( 'wp', 'bp_core_add_jquery_cropper' );
 365          }
 366      }
 367      
 368      /* If the image cropping is done, crop the image and save a full/thumb version */
 369      if ( isset( $_POST['avatar-crop-submit'] ) ) {
 370          
 371          /* Check the nonce */
 372          check_admin_referer( 'bp_avatar_cropstore' );
 373  
 374          if ( !bp_core_avatar_handle_crop( 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'] ) ) )
 375              bp_core_add_message( __( 'There was a problem cropping your avatar, please try uploading it again', 'buddypress' ) );
 376          else
 377              bp_core_add_message( __( 'Your new avatar was uploaded successfully!', 'buddypress' ) );
 378  
 379      }
 380  
 381      do_action( 'xprofile_screen_change_avatar' );
 382      bp_core_load_template( apply_filters( 'xprofile_template_change_avatar', 'profile/change-avatar' ) );
 383  }
 384  
 385  /**
 386   * xprofile_screen_notification_settings()
 387   *
 388   * Loads the notification settings for the xprofile component.
 389   * Settings are hooked into the function: bp_core_screen_notification_settings_content()
 390   * in bp-core/bp-core-settings.php
 391   * 
 392   * @package BuddyPress Xprofile
 393   * @global $current_user WordPress global variable containing current logged in user information
 394   */
 395  function xprofile_screen_notification_settings() { 
 396      global $current_user; ?>
 397      <?php if ( function_exists('bp_wire_install') ) { ?>
 398      <table class="notification-settings" id="profile-notification-settings">
 399          <tr>
 400              <th class="icon"></th>
 401              <th class="title"><?php _e( 'Profile', 'buddypress' ) ?></th>
 402              <th class="yes"><?php _e( 'Yes', 'buddypress' ) ?></th>
 403              <th class="no"><?php _e( 'No', 'buddypress' )?></th>
 404          </tr>
 405  
 406          <tr>
 407              <td></td>
 408              <td><?php _e( 'A member posts on your wire', 'buddypress' ) ?></td>
 409              <td class="yes"><input type="radio" name="notifications[notification_profile_wire_post]" value="yes" <?php if ( !get_usermeta( $current_user->id, 'notification_profile_wire_post' ) || 'yes' == get_usermeta( $current_user->id, 'notification_profile_wire_post' ) ) { ?>checked="checked" <?php } ?>/></td>
 410              <td class="no"><input type="radio" name="notifications[notification_profile_wire_post]" value="no" <?php if ( 'no' == get_usermeta( $current_user->id, 'notification_profile_wire_post' ) ) { ?>checked="checked" <?php } ?>/></td>
 411          </tr>
 412          
 413          <?php do_action( 'xprofile_screen_notification_settings' ) ?>
 414      </table>
 415      <?php } ?>
 416  <?php    
 417  }
 418  add_action( 'bp_notification_settings', 'xprofile_screen_notification_settings', 1 );
 419  
 420  
 421  /********************************************************************************
 422   * Action Functions
 423   *
 424   * Action functions are exactly the same as screen functions, however they do not
 425   * have a template screen associated with them. Usually they will send the user
 426   * back to the default screen after execution.
 427   */
 428  
 429  /**
 430   * xprofile_action_delete_avatar()
 431   *
 432   * This function runs when an action is set for a screen:
 433   * example.com/members/andy/profile/change-avatar/ [delete-avatar]
 434   *
 435   * The function will delete the active avatar for a user.
 436   * 
 437   * @package BuddyPress Xprofile
 438   * @global $bp The global BuddyPress settings variable created in bp_core_setup_globals()
 439   * @uses bp_core_delete_avatar() Deletes the active avatar for the logged in user.
 440   * @uses add_action() Runs a specific function for an action when it fires.
 441   * @uses bp_core_load_template() Looks for and loads a template file within the current member theme (folder/filename)
 442   */
 443  function xprofile_action_delete_avatar() {
 444      global $bp;
 445  
 446      if ( 'delete-avatar' != $bp->current_action )
 447          return false;
 448  
 449      if ( !check_admin_referer( 'bp_delete_avatar_link' ) )
 450          return false;
 451      
 452      if ( !bp_is_home() )
 453          return false;
 454  
 455      bp_core_delete_avatar();
 456      add_action( 'wp_head', 'bp_core_add_cropper_js' );
 457      bp_core_load_template( apply_filters( 'xprofile_template_delete_avatar', 'profile/change-avatar' ) );
 458  }
 459  add_action( 'wp', 'xprofile_action_delete_avatar', 3 );
 460  
 461  /**
 462   * xprofile_action_new_wire_post()
 463   *
 464   * Posts a new wire post to the users profile wire. 
 465   * 
 466   * @package BuddyPress XProfile
 467   * @global $bp The global BuddyPress settings variable created in bp_core_setup_globals()
 468   * @uses bp_wire_new_post() Adds a new wire post to a specific wire using the ID of the item passed and the table name.
 469   * @uses bp_core_add_message() Adds an error/success message to the session to be displayed on the next page load.
 470   * @uses bp_core_redirect() Safe redirects to a new page using the wp_redirect() function
 471   */
 472  function xprofile_action_new_wire_post() {
 473      global $bp;
 474  
 475      if ( $bp->current_component != $bp->wire->slug )
 476          return false;
 477      
 478      if ( 'post' != $bp->current_action )
 479          return false;
 480          
 481      /* Check the nonce */
 482      if ( !check_admin_referer( 'bp_wire_post' ) ) 
 483          return false;
 484          
 485      if ( !$wire_post_id = bp_wire_new_post( $bp->displayed_user->id, $_POST['wire-post-textarea'], $bp->profile->slug, false, $bp->profile->table_name_wire ) ) {
 486          bp_core_add_message( __( 'Wire message could not be posted. Please try again.', 'buddypress' ), 'error' );
 487      } else {
 488          bp_core_add_message( __( 'Wire message successfully posted.', 'buddypress' ) );
 489  
 490          if ( !bp_is_home() ) {
 491              /* Record the notification for the user */
 492              bp_core_add_notification( $bp->loggedin_user->id, $bp->displayed_user->id, 'profile', 'new_wire_post' );    
 493          }
 494          
 495          do_action( 'xprofile_new_wire_post', $wire_post_id );    
 496      }
 497  
 498      if ( !strpos( $_SERVER['HTTP_REFERER'], $bp->wire->slug ) ) {
 499          bp_core_redirect( $bp->displayed_user->domain );
 500      } else {
 501          bp_core_redirect( $bp->displayed_user->domain . $bp->wire->slug );
 502      }
 503  }
 504  add_action( 'wp', 'xprofile_action_new_wire_post', 3 );
 505  
 506  /**
 507   * xprofile_action_delete_wire_post()
 508   *
 509   * Deletes a wire post from the users profile wire. 
 510   * 
 511   * @package BuddyPress XProfile
 512   * @global $bp The global BuddyPress settings variable created in bp_core_setup_globals()
 513   * @uses bp_wire_delete_post() Deletes a wire post for a specific wire using the ID of the item passed and the table name.
 514   * @uses xprofile_delete_activity() Deletes an activity item for the xprofile component and a particular user.
 515   * @uses bp_core_add_message() Adds an error/success message to the session to be displayed on the next page load.
 516   * @uses bp_core_redirect() Safe redirects to a new page using the wp_redirect() function
 517   */
 518  function xprofile_action_delete_wire_post() {
 519      global $bp;
 520      
 521      if ( $bp->current_component != $bp->wire->slug )
 522          return false;
 523      
 524      if ( $bp->current_action != 'delete' )
 525          return false;
 526      
 527      if ( !check_admin_referer( 'bp_wire_delete_link' ) )
 528          return false;
 529              
 530      $wire_post_id = $bp->action_variables[0];
 531      
 532      if ( bp_wire_delete_post( $wire_post_id, $bp->profile->slug, $bp->profile->table_name_wire ) ) {
 533          bp_core_add_message( __('Wire message successfully deleted.', 'buddypress') );
 534  
 535          do_action( 'xprofile_delete_wire_post', $wire_post_id );                        
 536      } else {
 537          bp_core_add_message( __('Wire post could not be deleted, please try again.', 'buddypress'), 'error' );
 538      }
 539      
 540      if ( !strpos( $_SERVER['HTTP_REFERER'], $bp->wire->slug ) ) {
 541          bp_core_redirect( $bp->displayed_user->domain );
 542      } else {
 543          bp_core_redirect( $bp->displayed_user->domain. $bp->wire->slug );
 544      }
 545  }
 546  add_action( 'wp', 'xprofile_action_delete_wire_post', 3 );
 547  
 548  
 549  /********************************************************************************
 550   * Activity & Notification Functions
 551   *
 552   * These functions handle the recording, deleting and formatting of activity and
 553   * notifications for the user and for this specific component.
 554   */
 555  
 556  /**
 557   * xprofile_record_activity()
 558   *
 559   * Records activity for the logged in user within the profile component so that
 560   * it will show in the users activity stream (if installed)
 561   * 
 562   * @package BuddyPress XProfile
 563   * @param $args Array containing all variables used after extract() call
 564   * @global $bp The global BuddyPress settings variable created in bp_core_setup_globals()
 565   * @uses bp_activity_record() Adds an entry to the activity component tables for a specific activity
 566   */
 567  function xprofile_record_activity( $args = true ) {
 568      if ( function_exists('bp_activity_record') ) {
 569          extract($args);
 570          bp_activity_record( $item_id, $component_name, $component_action, $is_private, $secondary_item_id, $user_id, $secondary_user_id );
 571      }
 572  }
 573  
 574  /**
 575   * xprofile_delete_activity()
 576   *
 577   * Deletes activity for a user within the profile component so that
 578   * it will be removed from the users activity stream and sitewide stream (if installed)
 579   * 
 580   * @package BuddyPress XProfile
 581   * @param $args Array containing all variables used after extract() call
 582   * @global $bp The global BuddyPress settings variable created in bp_core_setup_globals()
 583   * @uses bp_activity_delete() Deletes an entry to the activity component tables for a specific activity
 584   */
 585  function xprofile_delete_activity( $args = true ) {
 586      if ( function_exists('bp_activity_delete') ) {
 587          extract($args);
 588          bp_activity_delete( $item_id, $component_name, $component_action, $user_id, $secondary_item_id );
 589      }
 590  }
 591  
 592  /**
 593   * xprofile_format_activity()
 594   *
 595   * The function xprofile_record_activity() simply records ID's, which component and action, and dates into
 596   * the database. These variables need to be formatted into something that can be read and displayed to
 597   * the user.
 598   *
 599   * This function will format an activity item based on the component action and return it for saving
 600   * in the activity cache database tables. It can then be selected and displayed with far less load on
 601   * the server.
 602   * 
 603   * @package BuddyPress Xprofile
 604   * @param $item_id The ID of the specific item for which the activity is recorded (could be a wire post id, user id etc)
 605   * @param $action The component action name e.g. 'new_wire_post' or 'updated_profile'
 606   * @global $bp The global BuddyPress settings variable created in bp_core_setup_globals()
 607   * @global $current_user WordPress global variable containing current logged in user information
 608   * @uses BP_Wire_Post Class Creates a new wire post object based on the table name and ID.
 609   * @uses BP_XProfile_Group Class Creates a new group object based on the group ID.
 610   * @return The readable activity item
 611   */
 612  function xprofile_format_activity( $item_id, $user_id, $action, $secondary_item_id = false, $for_secondary_user = false ) {
 613      global $bp;
 614      
 615      switch( $action ) {
 616          case 'new_wire_post':
 617              if ( class_exists('BP_Wire_Post') ) {
 618                  $wire_post = new BP_Wire_Post( $bp->profile->table_name_wire, $item_id );
 619              }
 620              
 621              if ( !$wire_post )
 622                  return false;
 623              
 624              if ( ( $wire_post->item_id == $bp->loggedin_user->id && $wire_post->user_id == $bp->loggedin_user->id ) || ( $wire_post->item_id == $bp->displayed_user->id && $wire_post->user_id == $bp->displayed_user->id ) ) {
 625                  
 626                  $from_user_link = bp_core_get_userlink($wire_post->user_id);
 627                  $to_user_link = false;
 628                                  
 629                  $content = sprintf( __('%s wrote on their own wire', 'buddypress'), $from_user_link ) . ': <span class="time-since">%s</span>';                
 630                  $return_values['primary_link'] = bp_core_get_userlink( $wire_post->user_id, false, true );
 631              
 632              } else if ( ( $wire_post->item_id != $bp->loggedin_user->id && $wire_post->user_id == $bp->loggedin_user->id ) || ( $wire_post->item_id != $bp->displayed_user->id && $wire_post->user_id == $bp->displayed_user->id ) ) {
 633              
 634                  $from_user_link = bp_core_get_userlink($wire_post->user_id);
 635                  $to_user_link = bp_core_get_userlink( $wire_post->item_id, false, false, true, true );
 636                  
 637                  $content = sprintf( __('%s wrote on %s wire', 'buddypress'), $from_user_link, $to_user_link ) . ': <span class="time-since">%s</span>';            
 638                  $return_values['primary_link'] = bp_core_get_userlink( $wire_post->item_id, false, true );
 639              
 640              } 
 641              
 642              if ( $content != '' ) {
 643                  $post_excerpt = bp_create_excerpt($wire_post->content);
 644                  
 645                  $content .= '<blockquote>' . $post_excerpt . '</blockquote>';
 646                  $return_values['content'] = $content;
 647                  
 648                  $return_values['content'] = apply_filters( 'xprofile_new_wire_post_activity', $content, $from_user_link, $to_user_link, $post_excerpt );
 649                  
 650                  return $return_values;
 651              } 
 652              
 653              return false;
 654          break;
 655          case 'updated_profile':
 656              $profile_group = new BP_XProfile_Group( $item_id );
 657              
 658              if ( !$profile_group )
 659                  return false;
 660              
 661              $user_link = bp_core_get_userlink($user_id);
 662              
 663              return array( 
 664                  'primary_link' => bp_core_get_userlink( $user_id, false, true ),
 665                  'content' => apply_filters( 'xprofile_updated_profile_activity', sprintf( __('%s updated the "%s" information on their profile', 'buddypress'), $user_link, '<a href="' . $bp->displayed_user->domain . $bp->profile->slug . '">' . $profile_group->name . '</a>' ) . ' <span class="time-since">%s</span>', $user_link, $profile_group->name )
 666              );
 667          break;
 668      }
 669      
 670      do_action( 'xprofile_format_activity', $action, $item_id, $user_id, $action, $secondary_item_id, $for_secondary_user );
 671      
 672      return false;
 673  }
 674  
 675  /**
 676   * xprofile_format_notifications()
 677   *
 678   * Format notifications into something that can be read and displayed
 679   * 
 680   * @package BuddyPress Xprofile
 681   * @param $item_id The ID of the specific item for which the activity is recorded (could be a wire post id, user id etc)
 682   * @param $action The component action name e.g. 'new_wire_post' or 'updated_profile'
 683   * @param $total_items The total number of identical notification items (used for grouping)
 684   * @global $bp The global BuddyPress settings variable created in bp_core_setup_globals()
 685   * @uses bp_core_global_user_fullname() Returns the display name for the user
 686   * @return The readable notification item
 687   */
 688  function xprofile_format_notifications( $action, $item_id, $secondary_item_id, $total_items ) {
 689      global $bp;
 690  
 691      if ( 'new_wire_post' == $action ) {
 692          if ( (int)$total_items > 1 ) {
 693              return apply_filters( 'bp_xprofile_multiple_new_wire_post_notification', '<a href="' . $bp->loggedin_user->domain . $bp->wire->slug . '" title="' . __( 'Wire', 'buddypress' ) . '">' . sprintf( __( 'You have %d new posts on your wire', 'buddypress' ), (int)$total_items ) . '</a>', $total_items );        
 694          } else {
 695              $user_fullname = bp_core_get_user_displayname( $item_id );
 696              return apply_filters( 'bp_xprofile_single_new_wire_post_notification', '<a href="' . $bp->loggedin_user->domain . $bp->wire->slug . '" title="' . __( 'Wire', 'buddypress' ) . '">' . sprintf( __( '%s posted on your wire', 'buddypress' ), $user_fullname ) . '</a>', $user_fullname );
 697          }
 698      }
 699      
 700      do_action( 'xprofile_format_notifications', $action, $item_id, $secondary_item_id, $total_items );
 701      
 702      return false;
 703  }
 704  
 705  
 706  /********************************************************************************
 707   * Business Functions
 708   *
 709   * Business functions are where all the magic happens in BuddyPress. They will
 710   * handle the actual saving or manipulation of information. Usually they will
 711   * hand off to a database class for data access, then return
 712   * true or false on success or failure.
 713   */
 714  
 715  
 716  /*** Field Group Management **************************************************/
 717  
 718  function xprofile_insert_field_group( $args = '' ) {
 719      $defaults = array(
 720          'field_group_id' => false,
 721          'name' => false,
 722          'description' => '',
 723          'can_delete' => true
 724      );
 725  
 726      $r = wp_parse_args( $args, $defaults );
 727      extract( $r, EXTR_SKIP );    
 728  
 729      if ( !$name )
 730          return false;
 731          
 732      $field_group = new BP_XProfile_Group( $field_group_id );
 733      $field_group->name = $name;
 734      $field_group->description = $description;
 735      $field_group->can_delete = $can_delete;
 736      
 737      return $field_group->save();
 738  }
 739  
 740  function xprofile_get_field_group( $field_group_id ) {
 741      return new BP_XProfile_Group( $field_group_id );
 742  }
 743  
 744  function xprofile_delete_field_group( $field_group_id ) {
 745      $field_group = new BP_XProfile_Group( $field_group_id );
 746      return $field_group->delete();
 747  }
 748  
 749  
 750  /*** Field Management *********************************************************/
 751  
 752  function xprofile_insert_field( $args = '' ) {
 753      extract( $args );
 754      
 755      /**
 756       * Possible parameters (pass as assoc array):
 757       *    'field_id'
 758       *    'field_group_id'
 759       *    'parent_id'
 760       *    'type'
 761       *    'name'
 762       *    'description'
 763       *    'is_required'
 764       *    'can_delete'
 765       *    'field_order'
 766       *    'order_by'
 767       *    'is_default_option'
 768       *    'option_order'
 769       */
 770      
 771      /* Check we have the minimum details */
 772      if ( !$field_group_id )
 773          return false;
 774      
 775      /* Check this is a valid field type */
 776      if ( !in_array( $type, $bp->profile->field_types ) )
 777          return false;
 778      
 779      /* Instantiate a new field object */
 780      if ( $field_id )
 781          $field = new BP_XProfile_Field( $field_id );
 782      else
 783          $field = new BP_XProfile_Field;
 784  
 785      $field->field_group_id = $field_group_id;
 786      
 787      if ( !empty( $parent_id ) )
 788          $field->parent_id = $parent_id;
 789      
 790      if ( !empty( $type ) )
 791          $field->type = $type;
 792      
 793      if ( !empty( $name ) )
 794          $field->name = $name;
 795  
 796      if ( !empty( $description ) )
 797          $field->description = $description;
 798      
 799      if ( !empty( $is_required ) )
 800          $field->is_required = $is_required;
 801          
 802      if ( !empty( $can_delete ) )
 803          $field->can_delete = $can_delete;
 804      
 805      if ( !empty( $field_order ) )
 806          $field->field_order = $field_order;
 807      
 808      if ( !empty( $order_by ) )
 809          $field->order_by = $order_by;
 810      
 811      if ( !empty( $is_default_option ) )
 812          $field->is_default_option = $is_default_option;
 813      
 814      if ( !empty( $option_order ) )
 815          $field->option_order = $option_order;
 816      
 817      if ( !$field->save() )
 818          return false;
 819  
 820      return true;
 821  }
 822  
 823  function xprofile_get_field( $field_id ) {
 824      return new BP_XProfile_Field( $field_id );
 825  }
 826  
 827  function xprofile_delete_field( $field_id ) {
 828      $field = new BP_XProfile_Field( $field_id );
 829      return $field->delete();
 830  }
 831  
 832  
 833  /*** Field Data Management *****************************************************/
 834  
 835  /**
 836   * xprofile_get_field_data()
 837   *
 838   * Fetches profile data for a specific field for the user.
 839   * 
 840   * @package BuddyPress Core
 841   * @param $field The ID of the field, or the $name of the field.
 842   * @param $user_id The ID of the user
 843   * @global $bp The global BuddyPress settings variable created in bp_core_setup_globals()
 844   * @uses BP_XProfile_ProfileData::get_value_byfieldname() Fetches the value based on the params passed.
 845   * @return The profile field data.
 846   */
 847  function xprofile_get_field_data( $field, $user_id = null ) {
 848      global $bp;
 849      
 850      if ( !$user_id )
 851          $user_id = $bp->displayed_user->id;
 852  
 853      if ( is_numeric( $field ) )
 854          $field_id = $field;
 855      else
 856          $field_id = xprofile_get_field_id_from_name( $field );
 857      
 858      if ( !$field_id )
 859          return false;
 860          
 861      return apply_filters( 'xprofile_get_field_data', BP_XProfile_ProfileData::get_value_byid( $field_id, $user_id ) );
 862  }
 863  
 864  /**
 865   * xprofile_set_field_data()
 866   *
 867   * A simple function to set profile data for a specific field for a specific user.
 868   * 
 869   * @package BuddyPress Core
 870   * @param $field The ID of the field, or the $name of the field.
 871   * @param $user_id The ID of the user
 872   * @param $value The value for the field you want to set for the user.
 873   * @global $bp The global BuddyPress settings variable created in bp_core_setup_globals()
 874   * @uses xprofile_get_field_id_from_name() Gets the ID for the field based on the name.
 875   * @return true on success, false on failure.
 876   */
 877  function xprofile_set_field_data( $field, $user_id, $value ) {
 878      if ( is_numeric( $field ) )
 879          $field_id = $field;
 880      else
 881          $field_id = xprofile_get_field_id_from_name( $field );
 882      
 883      if ( !$field_id )
 884          return false;
 885      
 886      $field = new BP_XProfile_ProfileData();
 887      $field->field_id = $field_id;
 888      $field->user_id = $user_id;
 889      $field->value = maybe_serialize( $value );
 890      
 891      return $field->save();
 892  }
 893  
 894  function xprofile_delete_field_data( $field, $user_id ) {
 895      if ( is_numeric( $field ) )
 896          $field_id = $field;
 897      else
 898          $field_id = xprofile_get_field_id_from_name( $field );
 899      
 900      if ( !$field_id )
 901          return false;
 902      
 903      $field = new BP_XProfile_ProfileData( $field_id );
 904      return $field->delete();
 905  }
 906  
 907  function xprofile_check_is_required_field( $field_id ) {
 908      $field = new BP_Xprofile_Field( $field_id );
 909      
 910      if ( (int)$field->is_required )
 911          return true;
 912      
 913      return false;
 914  }
 915  
 916  /**
 917   * xprofile_get_field_id_from_name()
 918   *
 919   * Returns the ID for the field based on the field name.
 920   * 
 921   * @package BuddyPress Core
 922   * @param $field_name The name of the field to get the ID for.
 923   * @return int $field_id on success, false on failure.
 924   */
 925  function xprofile_get_field_id_from_name( $field_name ) {
 926      return BP_Xprofile_Field::get_id_from_name( $field_name );
 927  }
 928  
 929  /**
 930   * xprofile_get_random_profile_data()
 931   *
 932   * Fetches a random piece of profile data for the user.
 933   * 
 934   * @package BuddyPress Core
 935   * @param $user_id User ID of the user to get random data for
 936   * @param $exclude_fullname whether or not to exclude the full name field as random data.
 937   * @global $bp The global BuddyPress settings variable created in bp_core_setup_globals()
 938   * @global $wpdb WordPress DB access object.
 939   * @global $current_user WordPress global variable containing current logged in user information
 940   * @uses xprofile_format_profile_field() Formats profile field data so it is suitable for display.
 941   * @return $field_data The fetched random data for the user.
 942   */
 943  function xprofile_get_random_profile_data( $user_id, $exclude_fullname = true ) {
 944      $field_data = BP_XProfile_ProfileData::get_random( $user_id, $exclude_fullname );
 945      $field_data[0]->value = xprofile_format_profile_field( $field_data[0]->type, $field_data[0]->value );
 946      
 947      if ( !$field_data[0]->value || empty( $field_data[0]->value ) )
 948          return false;
 949      
 950      return apply_filters( 'xprofile_get_random_profile_data', $field_data );
 951  }
 952  
 953  /**
 954   * xprofile_format_profile_field()
 955   *
 956   * Formats a profile field according to its type. [ TODO: Should really be moved to filters ]
 957   * 
 958   * @package BuddyPress Core
 959   * @param $field_type The type of field: datebox, selectbox, textbox etc
 960   * @param $field_value The actual value
 961   * @uses bp_format_time() Formats a time value based on the WordPress date format setting
 962   * @return $field_value The formatted value
 963   */
 964  function xprofile_format_profile_field( $field_type, $field_value ) {
 965      if ( !isset($field_value) || empty( $field_value ) )
 966          return false;
 967          
 968      $field_value = bp_unserialize_profile_field( $field_value );
 969          
 970      if ( 'datebox' == $field_type ) {
 971          $field_value = bp_format_time( $field_value, true );
 972      } else {
 973          $content = $field_value;
 974          $content = apply_filters('the_content', $content);
 975          $field_value = str_replace(']]>', ']]&gt;', $content);
 976      }
 977      
 978      return stripslashes( stripslashes( $field_value ) );
 979  }
 980  
 981  function xprofile_avatar_upload_dir( $directory = false, $user_id = false ) {
 982      global $bp;
 983  
 984      if ( !$user_id )
 985          $user_id = $bp->displayed_user->id;
 986  
 987      $path  = get_blog_option( BP_ROOT_BLOG, 'upload_path' );
 988      $newdir = path_join( ABSPATH, $path );
 989      $newdir .= '/avatars/' . $user_id;
 990  
 991      $newbdir = $newdir;
 992      
 993      if ( !file_exists( $newdir ) )
 994          @wp_mkdir_p( $newdir );
 995  
 996      $newurl = WP_CONTENT_URL . '/blogs.dir/' . BP_ROOT_BLOG . '/files/avatars/' . $user_id;
 997      $newburl = $newurl;
 998      $newsubdir = '/avatars/' . $user_id;
 999  
1000      return apply_filters( 'xprofile_avatar_upload_dir', array( 'path' => $newdir, 'url' => $newurl, 'subdir' => $newsubdir, 'basedir' => $newbdir, 'baseurl' => $newburl, 'error' => false ) );
1001  }
1002  
1003  
1004  /**
1005   * xprofile_remove_screen_notifications()
1006   *
1007   * Removes notifications from the notification menu when a user clicks on them and
1008   * is taken to a specific screen.
1009   * 
1010   * @package BuddyPress Core
1011   */
1012  function xprofile_remove_screen_notifications() {
1013      global $bp;
1014      
1015      bp_core_delete_notifications_for_user_by_type( $bp->loggedin_user->id, 'profile', 'new_wire_post' );
1016  }
1017  add_action( 'bp_wire_screen_latest', 'xprofile_remove_screen_notifications' );
1018  
1019  /**
1020   * xprofile_remove_data_on_user_deletion()
1021   *
1022   * When a user is deleted, we need to clean up the database and remove all the
1023   * profile data from each table. Also we need to clean anything up in the usermeta table
1024   * that this component uses.
1025   * 
1026   * @package BuddyPress XProfile
1027   * @param $user_id The ID of the deleted user
1028   * @uses get_usermeta() Get a user meta value based on meta key from wp_usermeta
1029   * @uses delete_usermeta() Delete user meta value based on meta key from wp_usermeta
1030   * @uses delete_data_for_user() Removes all profile data from the xprofile tables for the user
1031   */
1032  function xprofile_remove_data( $user_id ) {
1033      BP_XProfile_ProfileData::delete_data_for_user( $user_id );
1034      
1035      // delete any avatar files.
1036      @unlink( get_usermeta( $user_id, 'bp_core_avatar_v1_path' ) );
1037      @unlink( get_usermeta( $user_id, 'bp_core_avatar_v2_path' ) );
1038      
1039      // unset the usermeta for avatars from the usermeta table.
1040      delete_usermeta( $user_id, 'bp_core_avatar_v1' );
1041      delete_usermeta( $user_id, 'bp_core_avatar_v1_path' );
1042      delete_usermeta( $user_id, 'bp_core_avatar_v2' );
1043      delete_usermeta( $user_id, 'bp_core_avatar_v2_path' );
1044  }
1045  add_action( 'wpmu_delete_user', 'xprofile_remove_data', 1 );
1046  add_action( 'delete_user', 'xprofile_remove_data', 1 );
1047  
1048  function xprofile_clear_profile_groups_object_cache( $group_obj ) {
1049      wp_cache_delete( 'xprofile_groups', 'bp' );
1050      wp_cache_delete( 'xprofile_groups_inc_empty', 'bp' );
1051      wp_cache_delete( 'xprofile_group_' . $group_obj->id );
1052  
1053      /* Clear the sitewide activity cache */
1054      wp_cache_delete( 'sitewide_activity', 'bp' );
1055  }
1056  
1057  function xprofile_clear_profile_data_object_cache( $group_id ) {
1058      global $bp;    
1059      wp_cache_delete( 'xprofile_fields_' . $group_id . '_' . $bp->loggedin_user->id, 'bp' );
1060      wp_cache_delete( 'bp_user_fullname_' . $bp->loggedin_user->id, 'bp' );
1061      wp_cache_delete( 'online_users', 'bp' );
1062      wp_cache_delete( 'newest_users', 'bp' );
1063      wp_cache_delete( 'popular_users', 'bp' );
1064  
1065      /* Clear the sitewide activity cache */
1066      wp_cache_delete( 'sitewide_activity', 'bp' );
1067  }
1068  
1069  // List actions to clear object caches on
1070  add_action( 'xprofile_groups_deleted_group', 'xprofile_clear_profile_groups_object_cache' );
1071  add_action( 'xprofile_groups_saved_group', 'xprofile_clear_profile_groups_object_cache' );
1072  add_action( 'xprofile_updated_profile', 'xprofile_clear_profile_data_object_cache' );
1073  
1074  // List actions to clear super cached pages on, if super cache is installed
1075  add_action( 'xprofile_updated_profile', 'bp_core_clear_cache' );
1076  
1077  ?>


Generated: Sat Aug 22 14:49:03 2009 Cross-referenced by PHPXref 0.7 Thanks to