code:
<?php if ( !defined( 'HABARI_PATH' ) ) { die('No direct access'); } ?>
<?php include('header.php');?>

<?php _e( 'Current Theme' ); ?>

			<a href="<?php echo $active_theme['info']->url; ?>" class="plugin"><?php echo $active_theme['info']->name; ?> <?php echo $active_theme['info']->version; ?> <?php _e('by'); ?>
			<?php
			$authors = array();
			foreach ( $active_theme['info']->author as $author ) {
				$authors[] = isset( $author['url'] ) ? '' . $author . '' : $author;
			}
			echo Format::and_list( $authors, ', ', '' . _t( ' and ' ) . '');
			?>
			<?php
				if ( isset( $active_theme['info']->help ) ):
					if( Controller::get_var('help') == $active_theme['dir'] ):
			?>
				<a class="help active" href="<?php URL::out( 'admin', 'page=themes' ); ?>"><?php _e('Help'); ?>
				<?php else: ?>
				<a class="help" href="<?php URL::out( 'admin', 'page=themes&help=' . $active_theme['dir'] ); ?>"><?php _e('Help'); ?>
				<?php
					endif;
				endif;
			?>

			<?php if ( $configurable ): ?>

<a href="<?php URL::out( 'admin', 'page=themes&configure=' . $active_theme['dir'] ); ?>"><?php _e('Settings'); ?>

			<?php endif; ?>

			<?php if ( $active_theme['info']->update != '' ): ?>

<?php _e('v'); ?><?php echo $active_theme['info']->update; ?> <?php _e('Update Available'); ?>

			<?php endif; ?>

<img src="<?php echo $active_theme['screenshot']; ?>">

<?php echo $active_theme['info']->description; ?>

			<?php if ( $active_theme['info']->license != '' ): ?>

<?php printf( _t('%1$s is licensed under the %2$s'), $active_theme['info']->name, 'license['url'] . '">' . $active_theme['info']->license . '' ); ?>

			<?php endif; ?>

			<?php if ( isset( $active_theme['info']->help ) ): ?>
			<div id="themehelp" class="pct70 <?php if( Controller::get_var('help') == $active_theme['dir'] ): ?>active<?php endif; ?>">

					<?php echo (string) $active_theme['info']->help->value; ?>

			<?php endif; ?>

	<?php
	// Capture the admin config output.  If nothing is there, don't output the section
	ob_start();
	Plugins::act( 'theme_ui', $active_theme );
	$output = ob_get_clean();
	if (trim($output) != '') :
	?>

<?php _e( "General" ); ?>

		<?php echo $output; ?>

	<?php endif; ?>

	<?php if ( isset($active_theme['info']->areas) ): ?>

<?php _e( "Areas" ); ?>

						<?php $this->display('block_instances'); ?>

					<?php $this->display('block_areas'); ?>

<button id="save_areas" disabled="disabled"><?php _e('Save'); ?></button>

			<?php endif; ?>

<?php /* hide this until Scope is implemented

Scopes

Scope config goes here

*/ ?>

<?php _e('Available Themes'); ?>

<?php
foreach ( $all_themes as $inactive_theme ):
	if ( $inactive_theme['path'] != $active_theme_dir ) : ?>
	<div class="item pct30<?php if ($previewed == $inactive_theme['dir']) echo " previewing"; ?>">

			<a href="<?php echo $inactive_theme['info']->url; ?>"><?php echo $inactive_theme['info']->name; ?> <?php echo $inactive_theme['info']->version; ?> <?php _e('by'); ?>
			<?php
			$authors = array();
			foreach ( $inactive_theme['info']->author as $author ) {
				$authors[] = isset( $author['url'] ) ? '' . $author . '' : $author;
			}
			echo Format::and_list( $authors, ', ', '' . _t( ' and ' ) . '');
			?>

			<img src="<?php echo $inactive_theme['screenshot']; ?>" class="themethumb">

<?php echo $inactive_theme['info']->description; ?>

				<?php if ( $inactive_theme['info']->license != '' ): ?>

<?php printf( _t('%1$s is licensed under the %2$s'), $inactive_theme['info']->name, 'license['url'] . '">' . $inactive_theme['info']->license . '' ); ?>

				<?php endif; ?>

	    <?php
	    if ( $inactive_theme['info']->getName() != 'pluggable' || (string) $inactive_theme['info']->attributes()->type != 'theme' ) : ?>

<?php _e( 'Legacy theme.' ); ?>

      <?php elseif(isset($inactive_theme['req_parent'])): ?>

<?php _e( 'This theme requires the parent theme named "%s".', array($inactive_theme['req_parent']) ); ?>

	    <?php else: ?>

			<?php if ($previewed == $inactive_theme['dir']): ?>

<a href="<?php URL::out( 'admin', 'page=preview_theme&theme_dir=' . $inactive_theme['dir'] . '&theme_name=' . $inactive_theme['info']->name ); ?>"><?php _e('End Preview'); ?>

			<?php else: ?>

<a href="<?php URL::out( 'admin', 'page=preview_theme&theme_dir=' . $inactive_theme['dir'] . '&theme_name=' . $inactive_theme['info']->name ); ?>"><?php _e('Preview'); ?>

			<?php endif; ?>

<a href="<?php URL::out( 'admin', 'page=activate_theme&theme_dir=' . $inactive_theme['dir'] . '&theme_name=' . $inactive_theme['info']->name ); ?>"><?php _e('Activate'); ?>

	    <?php endif; ?>

<?php
	endif;
endforeach;
?>

<?php if (isset($theme_loader) && $theme_loader != ''): ?>

<?php echo $theme_loader; ?>

<?php endif; ?>

<?php include('footer.php');?>


code:
<?php if ( !defined( 'HABARI_PATH' ) ) { die('No direct access'); } ?>
<?php foreach ( $years as $year => $year_array ): ?>

	<?php echo $year; ?>

		<?php foreach ( $year_array as $pdata ): ?>

<span style="width: <?php echo $pdata->ct; ?>px"><?php _e( date('M', mktime(0, 0, 0, $pdata->month)) ); ?>

		<?php endforeach; ?>

<?php endforeach; ?>

repo_name: DaSourcerer/habari


code:
<?php if ( !defined( 'HABARI_PATH' ) ) { die('No direct access'); } ?>
<?php include('header.php');?>

		<form>
		<select class="navigationdropdown" onChange="navigationDropdown.filter();" name="navigationdropdown">
			<option value="all"><?php _e('All options'); ?></option>
		</select>
		</form>

		<?php _e('or'); ?>

		<input id="search" type="search" placeholder="<?php _e('search users'); ?>" autofocus="autofocus">

<?php
	$message_bits = array();
	$post_statuses = Post::list_post_statuses();
	unset( $post_statuses[array_search( 'any', $post_statuses )] );
	foreach ( $post_statuses as $status_name => $status_id ) {
		$status_name = Plugins::filter( 'post_status_display', $status_name );
		$count = Posts::count_by_author( $edit_user->id, $status_id );
		if ( $count > 0 ) {
			$message = ' 'posts', 'user_id' => $edit_user->id, 'type' => Post::type( 'any' ), 'status' => $status_id ) ) . '">';
			$message .= _n( _t( '%1$d %2$s post', array( $count, $status_name ) ), _t( '%1$d %2$s posts', array( $count, $status_name ) ), $count );
			$message .= '';
			$message_bits[] = $message;
		}
	}
	if ( count($message_bits) == 0 ) {
		echo "
" . _t('No published posts.') . "
\n";
	}
	else {
		echo Format::and_list( $message_bits );
	}
?>

<?php echo $form; ?>

<?php include('footer.php');?>


code:
<?php if ( !defined( 'HABARI_PATH' ) ) { die('No direct access'); } ?>
<?php include('header.php');?>

<?php
	// @todo this should be done in adminhandler, not here
	$theme->currentuser = User::identify();
?>

		<form>
		<select class="navigationdropdown" onChange="navigationDropdown.changePage(this.form.navigationdropdown)" name="navigationdropdown">
			<?php /*
			foreach ( Users::get_all() as $user ) {
				if ( $user->username == $currentuser->username ) {
					$url = Url::get( 'admin', 'page=user' );
				}
				else {
					$url = Url::get( 'user_profile', array( 'page' => 'user', 'user' => $user->username ) );
				}
				echo '<option id="' . $user->id . '" value="' . $url . '">' . $user->displayname . '</option>';
			} */ ?>
			<option value=""><?php _e('Complete User List'); ?></option>
		</select>
		</form>

		<?php _e('or'); ?>

		<input id="search" type="search" placeholder="<?php _e('search users'); ?>" autofocus="autofocus">

<form method="post" action="" autocomplete="off">

		<?php _e( 'Username' ); ?>
		<input type="text" name="new_username" id="new_username" value="<?php echo ( isset( $settings['new_username'] ) ) ? $settings['new_username'] : ''; ?>" class="border">

			<?php _e( 'E-Mail' ); ?>
			<input type="text" id="new_email" name="new_email" value="<?php echo ( isset( $settings['new_email'] ) ) ? $settings['new_email'] : ''; ?>" class="border">

			<?php _e( 'Password' ); ?>
			<input type="password" name="new_pass1" id="new_pass1" class="border">

			<?php _e( 'Password Again' ); ?>
			<input type="password" name="new_pass2" id="new_pass2" class="border">

		<input type="submit" name="newuser" value="<?php _e('Add User'); ?>">

	<?php $theme->display('users_items'); ?>

			<input type="checkbox" id="master_checkbox" name="master_checkbox">
			<?php _e('None selected'); ?>

		<input type="hidden" name="nonce" id="nonce" value="<?php echo $wsse['nonce']; ?>">
		<input type="hidden" name="timestamp" id="timestamp" value="<?php echo $wsse['timestamp']; ?>">
		<input type="hidden" name="password_digest" id="password_digest" value="<?php echo $wsse['digest']; ?>">

			<?php printf( _t('Reassign posts to %s'), Utils::html_select('reassign', $authors )); ?> and
			<input type="submit" name="delete" value="<?php _e('Delete Selected'); ?>">

</form>

<?php include('footer.php');?>


code:
<?php if ( !defined( 'HABARI_PATH' ) ) { die('No direct access'); } ?>

	<?php foreach (Users::get_all() as $user) {
		if ( $user->username == $currentuser->username ) {
			$url = Url::get( 'admin', 'page=user' );
		}
		else {
			$url = Url::get( 'user_profile', array( 'page' => 'user', 'user' => $user->username ) );
		}
	?>

			<input type="checkbox" class="checkbox" name="checkbox_ids[<?php echo $user->id; ?>]" id="checkbox_ids[<?php echo $user->id; ?>]">
			<a href="<?php echo $url ?>" title="<?php printf( _t('Open %s\'s user page'), $user->displayname ) ?>"><?php echo $user->displayname ?>

			<?php

				if ( !$user->info->authenticate_time ) {
					$last_login_message = _t( 'has not logged in yet' );
				}
				else {

					$last_login_message = _t( 'was last seen %1$s at %2$s' );
					$last_login_message = sprintf( $last_login_message,
						'' . date( HabariDateTime::get_default_date_format(), strtotime( $user->info->authenticate_time ) ) . '',
						'' . date( HabariDateTime::get_default_time_format(), strtotime( $user->info->authenticate_time ) ) . ''
					);

				}

				$message_bits = array();

				$post_statuses = Post::list_post_statuses();
				unset( $post_statuses[ array_search( 'any', $post_statuses ) ] );

				foreach( $post_statuses as $status_name => $status_id ) {
					$status_name = Plugins::filter( 'post_status_display', $status_name );
					$count = Posts::count_by_author( $user->id, $status_id );

					if ( $count > 0 ) {
						$message = ' 'posts', 'user_id' => $user->id, 'type' => Post::type( 'any' ), 'status' => $status_id ) ) ) . '">';
						$message .= _n( _t( '%1$d %2$s post', array( $count, $status_name ) ), _t( '%1$d %2$s posts', array( $count, $status_name ) ), $count );
						$message .= '';
						$message_bits[] = $message;
					}

				}

				if ( !empty( $message_bits ) ) {
					$string = _t( '%1$s and currently has %2$s', array( $last_login_message, Format::and_list( $message_bits ) ) );
				}
				else {
					$string = $last_login_message;
				}

				echo $string;

			?>

	<?php } ?>


code:
<?php

/**
 * Attempt to load the class before PHP fails with an error.
 * This method is called automatically in case you are trying to use a class which hasn't been defined yet.
 *
 * We look for the undefined class in the following folders:
 * - /system/classes/*.php
 * - /system/handlers/*.php
 * - /user/classes/*.php
 * - /user/handlers/*.php
 * - /user/sites/x.y.z/classes/*.php
 * - /user/sites/x.y.z/handlers/*.php
 *
 * @param string $class_name Class called by the user
 */
function habari_autoload( $class_name )
{
	static $files = null;

	$success = false;
	$class_file = strtolower( $class_name ) . '.php';

	if ( empty( $files ) ) {
		$files = array();
		$dirs = array(
			HABARI_PATH . '/system/classes',
			HABARI_PATH . '/system/handlers',
			HABARI_PATH . '/user/classes',
			HABARI_PATH . '/user/handlers',
		);

		$lower_basename = function($string) { return strtolower(basename($string)); };

		// For each directory, save the available files in the $files array.
		foreach ( $dirs as $dir ) {
			$glob = glob( $dir . '/*.php' );
			if ( $glob === false || empty( $glob ) ) continue;
			$fnames = array_map( $lower_basename, $glob );
			$files = array_merge( $files, array_combine( $fnames, $glob ) );
		}

		// Load the Site class, a requirement to get files from a multisite directory.
		if ( isset( $files['site.php'] ) ) {
			require( $files['site.php'] );
		}

		// Verify if this Habari instance is a multisite.
		if ( ( $site_user_dir = Site::get_dir( 'user' ) ) != HABARI_PATH . '/user' ) {
			// We are dealing with a site defined in /user/sites/x.y.z
			// Add the available files in that directory in the $files array.
			$glob_classes = glob( $site_user_dir . '/classes/*.php' );
			$glob_handlers = glob( $site_user_dir . '/handlers/*.php' );
			$glob = array_merge( $glob_classes, $glob_handlers );
			if ( $glob !== false && !empty( $glob ) ) {
				$fnames = array_map( $lower_basename, $glob );
				$files = array_merge( $files, array_combine( $fnames, $glob ) );
			}
		}
	}

	// Search in the available files for the undefined class file.
	if ( isset( $files[$class_file] ) ) {
		require( $files[$class_file] );
		// If the class has a static method named __static(), execute it now, on initial load.
		if ( class_exists( $class_name, false ) && method_exists( $class_name, '__static' ) ) {
			call_user_func( array( $class_name, '__static' ) );
		}
		$success = true;
	}
}

?>


code:
<?php
/**
 * @package Habari
 *
 */

/**
 * Access Control List class
 *
 * The default Habari ACL class implements groups, and group permissions
 * Users are assigned to one or more groups.
 * Groups are assigned one or more permissions.
 * Membership in any group that grants a permission
 * means you have that permission.  Membership in any group that denies
 * that permission denies the user that permission, even if another group
 * grants that permission.
 *
 */

class ACL
{
	/**
	 * How to handle a permission request for a permission that is not in the permission list.
	 * For example, if you request $user->can('some non-existent permission') then this value is returned.
	 */
	const ACCESS_NONEXISTENT_PERMISSION = 0;
	const CACHE_NULL = -1;

	public static $access_names = array( 'read', 'edit', 'delete', 'create' );
	private static $token_cache = null;

	/**
	 * Check a permission bitmask for a particular access type.
	 * @param Bitmask $bitmask The permission bitmask
	 * @param mixed $access The name of the access to check against (read, write, full)
	 * @return bool Returns true if the given access meets exceeds the access to check against
	 */
	public static function access_check( $bitmask, $access )
	{
		if ( $access instanceof Bitmask ) {
			return ( $bitmask->value & $access->value ) == $access->value;
		}

		switch ( $access ) {
			case 'full':
				return $bitmask->value == $bitmask->full;
			case 'any':
				return $bitmask->value != 0;
			case 'deny':
				return $bitmask->value == 0;
			default:
				return $bitmask->$access;
		}
	}

	/**
	 * Get a Bitmask object representing the supplied access integer
	 *
	 * @param integer $mask The access mask, usually stored in the database
	 * @return Bitmask An object representing the access value
	 */
	public static function get_bitmask( $mask )
	{
		$bitmask = new Bitmask( self::$access_names, $mask );
		return $bitmask;
	}

	/**
	 * Create a new permission token, and save it to the permission tokens table
	 * @param string $name The name of the permission
	 * @param string $description The description of the permission
	 * @param string $group The token group for organizational purposes
	 * @param bool $crud Indicates if the token is a CRUD or boolean type token (default is boolean)
	 * @return mixed the ID of the newly created permission, or boolean false
	 */
	public static function create_token( $name, $description, $group, $crud = false )
	{
		$name = self::normalize_token( $name );
		$crud = ( $crud ) ? 1 : 0;
		// first, make sure this isn't a duplicate
		if ( ACL::token_exists( $name ) ) {
			return false;
		}
		$allow = true;
		// Plugins have the opportunity to prevent adding this token
		$allow = Plugins::filter( 'token_create_allow', $allow, $name, $description, $group, $crud );
		if ( ! $allow ) {
			return false;
		}
		Plugins::act( 'token_create_before', $name, $description, $group, $crud );

		$result = DB::query( 'INSERT INTO {tokens} (name, description, token_group, token_type) VALUES (?, ?, ?, ?)', array( $name, $description, $group, $crud ) );

		if ( ! $result ) {
			// if it didn't work, don't bother trying to log it
			return false;
		}

		self::clear_caches();

		// Add the token to the admin group
		$token = ACL::token_id( $name );
		$admin = UserGroup::get( 'admin' );
		if ( $admin ) {
			ACL::grant_group( $admin->id, $token, 'full' );
		}

		EventLog::log( 'New permission token created: ' . $name, 'info', 'default', 'habari' );
		Plugins::act( 'permission_create_after', $name, $description, $group, $crud );
		return $result;
	}

	/**
	 * Remove a permission token, and any assignments of it
	 * @param mixed $permission a permission ID or name
	 * @return bool whether the permission was deleted or not
	 */
	public static function destroy_token( $token )
	{
		// make sure the permission exists, first
		if ( ! self::token_exists( $token ) ) {
			return false;
		}

		// grab token ID
		$token_id = self::token_id( $token );

		$allow = true;
		// plugins have the opportunity to prevent deletion
		$allow = Plugins::filter( 'token_destroy_allow', $allow, $token_id );
		if ( ! $allow ) {
			return false;
		}
		Plugins::act( 'token_destroy_before', $token_id );
		// capture the token name
		$name = DB::get_value( 'SELECT name FROM {tokens} WHERE id=?', array( $token_id ) );
		// remove all references to this permissions
		$result = DB::query( 'DELETE FROM {group_token_permissions} WHERE token_id=?', array( $token_id ) );
		$result = DB::query( 'DELETE FROM {user_token_permissions} WHERE token_id=?', array( $token_id ) );
		$result = DB::query( 'DELETE FROM {post_tokens} WHERE token_id=?', array( $token_id ) );
		ACL::clear_caches();
		// remove this token
		$result = DB::query( 'DELETE FROM {tokens} WHERE id=?', array( $token_id ) );
		if ( ! $result ) {
			// if it didn't work, don't bother trying to log it
			return false;
		}
		EventLog::log( _t( 'Permission token deleted: %s', array( $name ) ), 'info', 'default', 'habari' );
		Plugins::act( 'token_destroy_after', $token_id );
		return $result;
	}

	/**
	 * Get an array of QueryRecord objects containing all permission tokens
	 * @param string $order the order in which to sort the returning array
	 * @return array an array of QueryRecord objects containing all tokens
	 */
	public static function all_tokens( $order = 'id' )
	{
		$order = strtolower( $order );
		if ( ( 'id' != $order ) && ( 'name' != $order ) && ( 'description' != $order ) ) {
			$order = 'id';
		}
		$tokens = DB::get_results( 'SELECT id, name, description, token_group, token_type FROM {tokens} ORDER BY ' . $order );
		return $tokens ? $tokens : array();
	}

	/**
	 * Get a permission token's name by its ID
	 * @param int $id a token ID
	 * @return string the name of the permission, or boolean false
	 */
	public static function token_name( $id )
	{
		if ( ! is_int( $id ) ) {
			return false;
		}
		else {
			$tokens = ACL::cache_tokens();
			return isset( $tokens[ $id ] ) ? $tokens[ $id ] : false;
		}
	}

	/**
	 * Get an associative array of token ids and their name.
	 *
	 * @return array an array in the form id => name
	 */
	private static function cache_tokens()
	{
		if ( ACL::$token_cache == null ) {
			ACL::$token_cache = DB::get_keyvalue( 'SELECT id, name FROM {tokens}' );
		}
		return ACL::$token_cache;
	}

	/**
	 * Get a permission token's ID by its name
	 * @param string $name the name of the permission
	 * @return int the permission's ID
	 */
	public static function token_id( $name )
	{
		if ( is_numeric( $name ) ) {
			return intval( $name );
		}
		$name = self::normalize_token( $name );
		if ( $token = array_search( $name, ACL::cache_tokens() ) ) {
			return $token;
		}
		return false;
	}

	/**
	 * Fetch a permission token's description from the DB
	 * @param mixed $permission a permission name or ID
	 * @return string the description of the permission
	 */
	public static function token_description( $permission )
	{
		if ( is_int( $permission ) ) {
			$query = 'id';
		}
		else {
			$query = 'name';
			$permission = self::normalize_token( $permission );
		}
		return DB::get_value( "SELECT description FROM {tokens} WHERE $query=?", array( $permission ) );
	}

	/**
	 * Determine whether a permission token exists
	 * @param mixed $permission a permission name or ID
	 * @return bool whether the permission exists or not
	 */
	public static function token_exists( $permission )
	{
		if ( is_numeric( $permission ) ) {
			$query = 'id';
		}
		else {
			$query = 'name';
			$permission = self::normalize_token( $permission );
		}
		return ( (int) DB::get_value( "SELECT COUNT(id) FROM {tokens} WHERE $query=?", array( $permission ) ) > 0 );
	}

	/**
	 * Determine whether a group can perform a specific action
	 * @param mixed $group A group ID or name
	 * @param mixed $token_id A permission token ID or name
	 * @param string $access Check for 'create', 'read', 'update', 'delete', or 'full' access
	 * @return bool Whether the group can perform the action
	 */
	public static function group_can( $group, $token_id, $access = 'full' )
	{
		$bitmask = self::get_group_token_access( $group, $token_id );

		if ( isset( $bitmask ) && self::access_check( $bitmask, $access ) ) {
			// the permission has been granted to this group
			return true;
		}
		// either the permission hasn't been granted, or it's been
		// explicitly denied.
		return false;
	}

	/**
	 * Determine whether a group is explicitly denied permission to perform a specific action
	 * This function does not return true if the group is merely not granted a permission
	 * @param mixed $user A group ID or a group name
	 * @param mixed $token_id A permission ID or name
	 * @return bool True if access to the token is denied to the group
	 */
	public static function group_cannot( $group, $token_id )
	{

		$result = self::get_group_token_access( $group, $token_id );
		if ( isset( $result ) && self::access_check( $result, 'deny' ) ) {
			return true;
		}

		// The permission has been granted, or it hasn't been explicitly denied.
		return false;
	}

	/**
	 * Determine whether a user can perform a specific action
	 * @param mixed $user A user object, user ID or a username
	 * @param mixed $token_id A permission ID or name
	 * @param string $access Check for 'create', 'read', 'update', 'delete', or 'full' access
	 * @return bool Whether the user can perform the action
	 */
	public static function user_can( $user, $token_id, $access = 'full' )
	{

		$result = self::get_user_token_access( $user, $token_id );

		if ( isset( $result ) && self::access_check( $result, $access ) ) {
			return true;
		}

		$super_user_access = self::get_user_token_access( $user, 'super_user' );
		if ( isset( $super_user_access ) && self::access_check( $super_user_access, 'any' ) ) {
			return true;
		}

		// either the permission hasn't been granted, or it's been
		// explicitly denied.
		return false;
	}

	/**
	 * Determine whether a user is explicitly denied permission to perform a specific action
	 * This function does not return true if the user is merely not granted a permission
	 * @param mixed $user A User object, user ID or a username
	 * @param mixed $token_id A permission ID or name
	 * @return bool True if access to the token is denied to the user
	 */
	public static function user_cannot( $user, $token_id )
	{

		$result = self::get_user_token_access( $user, $token_id );
		if ( isset( $result ) && self::access_check( $result, 'deny' ) ) {
			return true;
		}

		// The permission has been granted, or it hasn't been explicitly denied.
		return false;
	}

	/**
	 * Return the access bitmask to a specific token for a specific user
	 *
	 * @param User|integer $user A User object instance or user id
	 * @param string|integer $token A permission token name or token ID
	 * @return Bitmask An access bitmask
	 */
	public static function get_user_token_access( $user, $token )
	{
		// Use only numeric ids internally
		$token_id = self::token_id( $token );

		/**
		 * Do we allow perms that don't exist?
		 * When ACL is functional ACCESS_NONEXISTENT_PERMISSION should be false by default.
		 */
		if ( is_null( $token_id ) ) {
			return self::get_bitmask( self::ACCESS_NONEXISTENT_PERMISSION );
		}

		// if we were given a user ID, use that to fetch the group membership from the DB
		if ( is_numeric( $user ) ) {
			$user_id = $user;
		}
		else {
			// otherwise, make sure we have a User object, and get
			// the groups from that
			if ( ! $user instanceof User ) {
				$user = User::get( $user );
			}
			$user_id = $user->id;
		}

		if ( defined( 'LOCKED_OUT_SUPER_USER' ) && $token == 'super_user' ) {
			$su = User::get( LOCKED_OUT_SUPER_USER );
			if ( $su->id == $user_id ) {
				return new Bitmask( self::$access_names, 'read');
			}
		}

		// check the cache first for the user's access_mask on the token
		if ( isset( $_SESSION[ 'user_token_access' ][ $user_id ][ $token_id ] ) ) {
//			Utils::debug($token, $_SESSION['user_token_access'][$token_id]);
			if ( $_SESSION[ 'user_token_access' ][ $user_id ][ $token_id ] == ACL::CACHE_NULL ) {
				return null;
			}
			else {
				return self::get_bitmask( $_SESSION[ 'user_token_access' ][ $user_id ][ $token_id ] );
			}
		}

		/**
		 * Jay Pipe's explanation of the following SQL
		 * 1) Look into user_permissions for the user and the token.
		 * If exists, use that permission flag for the check. If not,
		 * go to 2)
		 *
		 * 2) Look into the group_permissions joined to
		 * users_groups for the user and the token.  Order the results
		 * by the access bitmask. The lower the mask value, the
		 * fewest permissions that group has. Use the first record's
		 * access mask to check the ACL.
		 *
		 * This gives the system very fine grained control and grabbing
		 * the permission flag and can be accomplished in a single SQL
		 * call.
		 */

		$exceptions = '';
		$default_groups = array();
		$default_groups = Plugins::filter( 'user_default_groups', $default_groups, $user_id );
		$default_groups = array_filter( array_map( 'intval', $default_groups ) );
		switch ( count( $default_groups ) ) {
			case 0: // do nothing
				break;
			case 1: // single argument
				$exceptions = 'OR ug.group_id = ' . reset( $default_groups );
				break;
			default: // multiple arguments
				$exceptions = 'OR ug.group_id IN (' . implode( ',', $default_groups ) . ')';
				break;
		}

		$sql = <<<SQL
SELECT access_mask
	FROM {user_token_permissions}
	WHERE user_id = ?
	AND token_id = ?
UNION ALL
SELECT gp.access_mask
	FROM {users_groups} ug
	INNER JOIN {group_token_permissions} gp
	ON ((ug.group_id = gp.group_id
	AND ug.user_id = ?)
	{$exceptions})
	AND gp.token_id = ?
	ORDER BY access_mask ASC
SQL;

		if ( $token_id == '' ) { $token_id = '0'; }

		$accesses = DB::get_column( $sql, array( $user_id, $token_id, $user_id, $token_id ) );

		$accesses = Plugins::filter( 'user_token_access', $accesses, $user_id, $token_id );

		if ( count( $accesses ) == 0 ) {
			$_SESSION[ 'user_token_access' ][ $user_id ][ $token_id ] = ACL::CACHE_NULL;
			return null;
		}
		else {
			$result = 0;
			foreach ( (array) $accesses as $access ) {
				if ( $access == 0 ) {
					$result = 0;
					break;
				}
				else {
					$result |= $access;
				}
			}

			$_SESSION[ 'user_token_access' ][ $user_id ][ $token_id ] = $result;
			return self::get_bitmask( $result );
		}
	}

	/**
	 * Get all the tokens for a given user with a particular kind of access
	 * @param mixed $user A user object, user ID or a username
	 * @param string $access Check for 'create' or 'read', 'update', or 'delete' access
	 * @return array of token IDs
	 */
	public static function user_tokens( $user, $access = 'full', $posts_only = false )
	{
		static $post_tokens = null;

		$bitmask = new Bitmask ( self::$access_names );
		$tokens = array();

		// convert $user to an ID
		if ( is_numeric( $user ) ) {
			$user_id = $user;
		}
		else {
			if ( ! $user instanceof User ) {
				$user = User::get( $user );
			}
			$user_id = $user->id;
		}

		// Implement cache RIGHT HERE
		if ( isset( $_SESSION[ 'user_tokens' ][ $user_id ][ $access ] ) ) {
			return $_SESSION[ 'user_tokens' ][ $user_id ][ $access ];
		}

		$super_user_access = self::get_user_token_access( $user, 'super_user' );
		if ( isset( $super_user_access ) && self::access_check( $super_user_access, 'any' ) ) {
			$token_ids = DB::get_column( 'SELECT id as token_id FROM {tokens}' );
			$result = array();
			foreach ( $token_ids as $id ) {
				$result_row = new StdClass();
				$result_row->token_id = $id;
				$result_row->access_mask = $bitmask->full;
				$result[] = $result_row;
			}
		}
		else {

			$sql = <<<SQL
SELECT token_id, access_mask
	FROM {user_token_permissions}
	WHERE user_id = :user_id
UNION ALL
SELECT gp.token_id, gp.access_mask
	FROM {users_groups} ug
	INNER JOIN {group_token_permissions} gp
	ON ug.group_id = gp.group_id
	AND ug.user_id = :user_id
	ORDER BY token_id ASC
SQL;
			$result = DB::get_results( $sql, array( ':user_id' => $user_id ) );
		}

		if ( $posts_only && !isset( $post_tokens ) ) {
			$post_tokens = DB::get_column( 'SELECT token_id FROM {post_tokens} GROUP BY token_id' );
		}

		foreach ( (array) $result as $token ) {
			$bitmask->value = $token->access_mask;
			if ( $access === 'deny' ) {
				if ( $bitmask->value === 0 ) {
					$tokens[] = $token->token_id;
				}
			}
			elseif ( $bitmask->$access ) {
				$tokens[] = $token->token_id;
			}
		}

		if ( $posts_only ) {
			$tokens = array_intersect( $tokens, $post_tokens );
		}

		$_SESSION[ 'user_tokens' ][ $user_id ][ $access ] = $tokens;
		return $tokens;
	}

	/**
	 * Get the access bitmask of a group for a specific permission token
	 * @param integer $group The group ID
	 * @param mixed $token_id A permission name or ID
	 * @return an access bitmask
	 */
	public static function get_group_token_access( $group, $token_id )
	{
		// Use only numeric ids internally
		$group = UserGroup::id( $group );
		$token_id = self::token_id( $token_id );
		$sql = 'SELECT access_mask FROM {group_token_permissions} WHERE
			group_id=? AND token_id=?;';

		$result = DB::get_value( $sql, array( $group, $token_id ) );

		if ( isset( $result ) ) {
			return self::get_bitmask( $result );
		}
		return null;
	}

	/**
	 * Grant a permission to a group
	 * @param integer $group_id The group ID
	 * @param mixed $token_id The name or ID of the permission token to grant
	 * @param string $access The kind of access to assign the group
	 * @return Result of the DB query
	 */
	public static function grant_group( $group_id, $token_id, $access = 'full' )
	{
		$token_id = self::token_id( $token_id );
		$results = DB::get_column( 'SELECT access_mask FROM {group_token_permissions} WHERE group_id=? AND token_id=?', array( $group_id, $token_id ) );
		$access_mask = 0;
		$row_exists = false;
		if ( $results ) {
			$row_exists = true;
			if ( in_array( 0, $results ) ) {
					$access_mask = 0;
				}
			else {
				$access_mask = Utils::array_or( $results );
			}
		}

		$bitmask = self::get_bitmask( $access_mask );
		$orig_value = $bitmask->value;

		if ( $access instanceof Bitmask ) {
			$bitmask->value = $access->value;
		}
		elseif ( $access == 'full' ) {
			$bitmask->value = $bitmask->full;
		}
		elseif ( $access == 'deny' ) {
			$bitmask->value = 0;
		}
		else {
			$bitmask->$access = true;
		}

		// Only update if the value is changed
		if ( $orig_value != $bitmask->value || ( $orig_value == 0 && !$row_exists && $bitmask->value == 0 ) ) {
			// DB::update will insert if the token is not already in the group tokens table
			$result = DB::update(
				'{group_token_permissions}',
				array( 'access_mask' => $bitmask->value ),
				array( 'group_id' => $group_id, 'token_id' => $token_id )
			);
			ACL::clear_caches();

			$ug = UserGroup::get_by_id( $group_id );
			$ug->clear_permissions_cache();
			$msg = _t( 'Group %1$s: Access to %2$s changed to %3$s', array( $ug->name, ACL::token_name( $token_id ), $bitmask ) );
			EventLog::log( $msg, 'notice', 'user', 'habari' );
		}
		else {
			$result = true;
		}

		return $result;
	}

	/**
	 * Grant a permission to a user
	 * @param integer $user_id The user ID
	 * @param integer $token_id The name or ID of the permission token to grant
	 * @param string $access The kind of access to assign the group
	 * @return Result of the DB query
	 */
	public static function grant_user( $user_id, $token_id, $access = 'full' )
	{
		$token_id = self::token_id( $token_id );
		$access_mask = DB::get_value( 'SELECT access_mask FROM {user_token_permissions} WHERE user_id=? AND token_id=?',
			array( $user_id, $token_id ) );
		if ( $access_mask ===  false ) {
			$permission_bit = 0; // default is 'deny' (bitmask 0)
		}

		$bitmask = self::get_bitmask( $access_mask );

		if ( $access == 'full' ) {
			$bitmask->value= $bitmask->full;
		}
		elseif ( $access == 'deny' ) {
			$bitmask->value = 0;
		}
		else {
			$bitmask->$access = true;
		}

		$result = DB::update(
			'{user_token_permissions}',
			array( 'access_mask' => $bitmask->value ),
			array( 'user_id' => $user_id, 'token_id' => $token_id )
		);

		ACL::clear_caches();

		return $result;
	}

	/**
	 * Deny permission to a group
	 * @param integer $group_id The group ID
	 * @param mixed $token_id The name or ID of the permission token
	 * @return Result of the DB query
	 */
	public static function deny_group( $group_id, $token_id )
	{
		self::grant_group( $group_id, $token_id, 'deny' );
	}

	/**
	 * Deny permission to a user
	 * @param integer $user_id The user ID
	 * @param mixed $token_id The name or ID of the permission token
	 * @return Result of the DB query
	 */
	public static function deny_user( $user_id, $token_id )
	{
		self::grant_user( $user_id, $token_id, 'deny' );
	}

	/**
	 * Remove a permission token from the group permissions table
	 * @param integer $group_id The group ID
	 * @param mixed $token_id The name or ID of the permission token
	 * @return the result of the DB query
	 */
	public static function revoke_group_token( $group_id, $token_id )
	{
		$token_id = self::token_id( $token_id );
		$ug = UserGroup::get_by_id( $group_id );

		$access = self::get_group_token_access( $group_id, $token_id );

		if ( empty( $access ) ) {
			$result = true;
		}
		else {
			$result = DB::delete( '{group_token_permissions}',
				array( 'group_id' => $group_id, 'token_id' => $token_id ) );
			EventLog::log( _t( 'Group %1$s: Permission to %2$s revoked.', array( $ug->name, ACL::token_name( $token_id ) ) ), 'notice', 'user', 'habari' );
		}

		$ug->clear_permissions_cache();
		ACL::clear_caches();

		return $result;
	}

	/**
	 * Remove a permission token from the user permissions table
	 * @param integer $user_id The user ID
	 * @param mixed $token_id The name or ID of the permission token
	 * @return the result of the DB query
	 */
	public static function revoke_user_token( $user_id, $token_id )
	{
		$token_id = self::token_id( $token_id );
		$result = DB::delete( '{user_token_permissions}',
			array( 'user_id' => $user_id, 'token_id' => $token_id ) );

		ACL::clear_caches();

		return $result;
	}

	/**
	 * Convert a token name into a valid format
	 *
	 * @param string $name The name of a permission
	 * @return string The permission with spaces converted to underscores and all lowercase
	 */
	public static function normalize_token( $name )
	{
		return strtolower( preg_replace( '/\s+/u', '_', trim( $name ) ) );
	}

	/**
	 * Clears all caches used to hold permissions
	 *
	 */
	public static function clear_caches()
	{
		if ( isset( $_SESSION[ 'user_token_access' ] ) ) {
			unset( $_SESSION[ 'user_token_access' ] );

		}
		if ( isset( $_SESSION[ 'user_tokens' ] ) ) {
			unset( $_SESSION[ 'user_tokens' ] );
		}
		self::$token_cache = null;
	}

	/**
	 * Creates the default set of permissions.
	 */
	public static function create_default_tokens()
	{
		// super user token
		self::create_token( 'super_user', 'Permissions for super users', 'Super User' );

		// admin tokens
		self::create_token( 'manage_all_comments', _t( 'Manage comments on all posts' ), 'Administration' );
		self::create_token( 'manage_own_post_comments', _t( 'Manage comments on one\'s own posts' ), 'Administration' );
		self::create_token( 'manage_tags', _t( 'Manage tags' ), 'Administration' );
		self::create_token( 'manage_options', _t( 'Manage options' ), 'Administration' );
		self::create_token( 'manage_theme', _t( 'Change theme' ), 'Administration' );
		self::create_token( 'manage_theme_config', _t( 'Configure the active theme' ), 'Administration' );
		self::create_token( 'manage_plugins', _t( 'Activate/deactivate plugins' ), 'Administration' );
		self::create_token( 'manage_plugins_config', _t( 'Configure active plugins' ), 'Administration' );
		self::create_token( 'manage_import', _t( 'Use the importer' ), 'Administration' );
		self::create_token( 'manage_users', _t( 'Add, remove, and edit users' ), 'Administration' );
		self::create_token( 'manage_self', _t( 'Edit own profile' ), 'Administration' );
		self::create_token( 'manage_groups', _t( 'Manage groups and permissions' ), 'Administration' );
		self::create_token( 'manage_logs', _t( 'Manage logs' ), 'Administration' );
		self::create_token( 'manage_dash_modules', _t( 'Manage dashboard modules' ), 'Administration' );

		// content tokens
		self::create_token( 'own_posts', _t( 'Permissions on one\'s own posts' ), _t( 'Content' ), true );
		self::create_token( 'post_any', _t( 'Permissions to all posts' ), _t( 'Content' ), true );
		self::create_token( 'post_unpublished', _t( "Permissions to other users' unpublished posts" ), _t( 'Content' ), true );
		foreach ( Post::list_active_post_types() as $name => $posttype ) {
			self::create_token( 'post_' . Utils::slugify( $name ), _t( 'Permissions to posts of type "%s"', array( $name ) ), _t( 'Content' ), true );
		}

		// comments tokens
		self::create_token( 'comment', 'Make comments on any post', _t( 'Comments' ) );
	}

	/**
	 * Reset premissions to their default state
	 */
	public static function rebuild_permissions( $user = null )
	{
		// Clear out all permission-related values
		DB::query( 'DELETE FROM {tokens}' );
		DB::query( 'DELETE FROM {group_token_permissions}' );
		//DB::query( 'DELETE FROM {groups}' );
		DB::query( 'DELETE FROM {post_tokens}' );
		DB::query( 'DELETE FROM {user_token_permissions}' );
		//DB::query('DELETE FROM {users_groups}');

		// Create initial groups if they don't already exist
		$admin_group = UserGroup::get_by_name( _t( 'admin' ) );
		if ( ! $admin_group instanceof UserGroup ) {
			$admin_group = UserGroup::create( array( 'name' => _t( 'admin' ) ) );
		}

		$anonymous_group = UserGroup::get_by_name( _t( 'anonymous' ) );
		if ( ! $anonymous_group instanceof UserGroup ) {
			$anonymous_group = UserGroup::create( array( 'name' => _t( 'anonymous' ) ) );
		}

		// Add all users or the passed user to the admin group
		if ( empty($user) ) {
			$users = Users::get_all();
			$ids = array();
			foreach ( $users as $user ) {
				$ids[] = $user->id;
			}
			$admin_group->add( $ids );
		}
		else {
			$admin_group->add( $user );
		}

		// create default permissions
		self::create_default_tokens();
		// Make the admin group all superusers
		$admin_group->grant( 'super_user' );
		// Add entry and page read access to the anonymous group
		$anonymous_group->grant( 'post_entry', 'read' );
		$anonymous_group->grant( 'post_page', 'read' );
		$anonymous_group->grant( 'comment' );

		// Add the anonymous user to the anonymous group
		$anonymous_group->add( 0 );

		// Create the default authenticated group
		$authenticated_group = UserGroup::get_by_name( _t( 'authenticated' ) );
		if ( ! $authenticated_group instanceof UserGroup ) {
			$authenticated_group = UserGroup::create( array( 'name' => _t( 'authenticated' ) ) );
		}
		$authenticated_group->grant( 'post_entry', 'read' );
		$authenticated_group->grant( 'post_page', 'read' );
		$authenticated_group->grant( 'comment' );

	}

	/**
	 * Dummy function to inject strings into the .pot
	 */
	private static function translations() {
		// @locale The names of the CRUD group token permissions
		_t( 'read' ); _t( 'edit' ); _t( 'delete' ); _t( 'create' );
	}

}
?>


code:
<?php
/**
 * @package Habari
 *
 */

/**
 * Handles creating ajax responses, creating them in the standard format.
 *
 */
class AjaxResponse
{

	public $data;
	private $response_code;
	private $message;
	private $callback = null;
	private $html = null;

	/* By default, we have a successful operation, with no data to return. */
	function __construct( $response_code = 200, $message = null, $data = null )
	{
		$this->response_code = $response_code;
		$this->message = $message;
		$this->data = $data;
	}

	public function __set( $var, $val )
	{
		switch ( $var ) {
			case 'response_code':
			case 'message':
			case 'data':
			case 'callback':
				$this->$var = $val;
				break;
		}
	}

	public function html( $name, $value )
	{
		if ( empty( $this->html ) ) {
			$this->html = array( $name => $value );
		}
		else {
			$this->html[$name] = $value;
		}
	}

	public function out( $to_iframe = false )
	{
		$ret_array = array(
			'response_code' => $this->response_code,
			'message' => $this->message,
			'data' => $this->data,
		);

		// if some callback js has been provided, include that too.
		if ( $this->callback != null ) {
			$ret_array['habari_callback'] = $this->callback;
		}
		if ( !empty( $this->html ) ) {
			$ret_array['html'] = $this->html;
		}

		// If the output is destined for an iframe, set appropriate headers we
		// know the browser will definitely be able to interpret.
		// See discussion at https://github.com/habari/habari/issues/204
		if ( $to_iframe ) {
			header( 'Content-type: text/plain' );
		} else {
			header( 'Content-type: application/json' );
		}
		echo json_encode( $ret_array );
	}

}

?>


code:
<?php
/**
 * @package Habari
 *
 */

/**
 *
 * Contains the APCCache class
 */
class APCCache extends Cache
{
	protected $enabled = false;
	protected $cache_data = array();
	protected $prefix;

	/**
	 * Constructor for APCCache
	 */
	public function __construct()
	{
		$this->prefix = Options::get( 'GUID' );
		$this->enabled = extension_loaded( 'apc' );
		if ( !$this->enabled ) {
			Session::error( _t( "The APC Cache PHP module is not loaded - the cache is disabled.", "apccache" ), 'filecache' );
			EventLog::log( _t( "The APC Cache PHP module is not loaded - the cache is disabled.", "apccache" ), 'notice', 'cache', 'apccache' );
		}
	}

	/**
	 * Is record with $name in the cache?
	 *
	 * @param string $name name of the cached item
	 * @return boolean true if item is cached, false if not
	 */
	protected function _has( $name, $group )
	{
		if ( !$this->enabled ) {
			return false;
		}
		return apc_fetch( implode( ':', array( $this->prefix, $group, $name ) ) ) !== false;
	}

	/**
	 * Returns the named value from the cache.
	 *
	 * @param string $name The name of the cached item
	 * @return mixed The item value or null if it doesn't exist in cache
	 */
	protected function _get( $name, $group )
	{
		if ( !$this->enabled ) {
			return null;
		}
		return apc_fetch( implode( ':', array( $this->prefix, $group, $name ) ) );
	}

	/**
	 * Returns the named values from a group of cache.
	 *
	 * @param string $name The name of the cached item
	 * @return array The cache records of the group
	 */
	protected function _get_group( $group )
	{
		if ( !$this->enabled ) {
			return null;
		}
		$cache_info = apc_cache_info( 'user' );
		$group_cache = array();

		foreach ( $cache_info['cache_list'] as $cache_item ) {
			if ( strpos( $cache_item['info'], $this->prefix . ":$group:" ) === 0 ) {
				$name = substr( $cache_item['info'], strlen( $this->prefix . ":$group:" ) );
				$group_cache[$name] = apc_fetch( $cache_item['info'] );
			}
		}
		return $group_cache;
	}

	/**
	 * Is group named $group in the cache?
	 *
	 * @param string $name name of the cached item
	 * @return boolean true if group is cached, false if not
	 */
	protected function _has_group( $group )
	{
		if ( !$this->enabled ) {
			return null;
		}
		$cache_info = apc_cache_info( 'user' );
		$group_cache = array();

		foreach ( $cache_info['cache_list'] as $cache_item ) {
			if ( strpos( $cache_item['info'], $this->prefix . ":$group:" ) === 0 ) {
				$group_cache[$cache_item['info']] = apc_fetch( $cache_item['info'] );
			}
		}
		return $this->_get_group( $group ) ? true : false;
	}

	protected function _set( $name, $value, $expiry, $group, $keep )
	{
		if ( !$this->enabled ) {
			return null;
		}

		Plugins::act( 'cache_set_before', $name, $group, $value, $expiry );

		$this->cache_data[$group][$name] = $value;

		if ( $keep ) {
			$keepcache = apc_fetch( $this->prefix . ':keepcache' );
			if ( !is_array( $keepcache ) ) {
				$keepcache = array();
			}
			$keepcache[$group][$name] = intval( $expiry );
			apc_store( $this->prefix . ':keepcache', $keepcache );
			$expiry = 0;
		}

		apc_store( implode( ':', array( $this->prefix, $group, $name ) ), $value, intval( $expiry ) );

		Plugins::act( 'cache_set_after', $name, $group, $value, $expiry );

		return true;
	}

	/**
	 * Expires the named value from the cache.
	 *
	 * @param string $name The name of the cached item
	 * @param string $match_mode (optional) how to match bucket names ('strict', 'regex', 'glob') (default 'strict')
	 */
	protected function _expire( $name, $group, $match_mode = 'strict' )
	{
		if ( !$this->enabled ) {
			return null;
		}
		$keys = array();
		switch ( strtolower( $match_mode ) ) {
			case 'glob':
				if ( array_key_exists( $group, $this->cache_data ) ) {
					$keys = preg_grep( Utils::glob_to_regex( $name ), array_keys( $this->cache_data[$group] ) );
				}
				break;
			case 'regex':
				if ( array_key_exists( $group, $this->cache_data ) ) {
					$keys = preg_grep( $name, array_keys( $this->cache_data[$group] ) );
				}
				break;
			case 'strict':
			default:
				$keys = array( $name );
				break;
		}

		foreach ( $keys as $key ) {
			Plugins::act( 'cache_expire_before', $name, $group );
			apc_delete( implode( ':', array( $this->prefix, $group, $key ) ) );
			Plugins::act( 'cache_expire_after', $name, $group );
		}
	}

	/**
	 * Return whether a named cache value has expired
	 *
	 * @param string $name The name of the cached item
	 * @param string $group The group of the cached item
	 * @return boolean true if the stored value has expired
	 */
	protected function _expired( $name, $group )
	{
		if ( !$this->enabled ) {
			return null;
		}

		// Do not check cached data, since we can return (and cache in this object) data if the cache is set to 'keep'
		$keepcache = apc_fetch( $this->prefix . ':keepcache' );

		if ( !self::_has( $name, $group ) || !isset( $keepcache[$group][$name] ) || $keepcache[$group][$name] < time() ) {
			return true;
		}
		else {
			return false;
		}
	}

	/**
	 * Extend the expiration of the named cached value.
	 *
	 * @param string $name The name of the cached item
	 * @param integer $expiry The duration in seconds to extend the cache expiration by
	 */
	protected function _extend( $name, $expiry, $group )
	{
		if ( !$this->enabled ) {
			return null;
		}

		Plugins::act( 'cache_extend_before', $name, $group, $expiry );

		if ( $this->_has( $name, $group ) ) {
			$cache_data = $this->_get( $name, $group );
			$this->_set( implode( ':', array( $this->prefix, $group, $name ) ), $cache_data, time() + $expiry, $group );
		}

		Plugins::act( 'cache_extend_after', $name, $group, $expiry );
	}

	/**
	 * Remove all cached items
	 */
	protected function _purge()
	{
		Plugins::act( 'cache_purge_before' );

		$cache_info = apc_cache_info( 'user' );

		$delete = array();
		foreach ( $cache_info['cache_list'] as $cache_item ) {
			if ( strpos( $cache_item['info'], $this->prefix . ":" ) === 0 ) {
				$delete[] = $cache_item['info'];
			}
		}
		foreach ( $delete as $item ) {
			apc_delete( $item );
		}

		Plugins::act( 'cache_purge_after' );
	}
}

?>


code:
<?php
/**
 * @package Habari
 *
 */

/**
 * Class to wrap around bitmap field functionality
 *
 * @property integer $value The internal numeric value of the Bitmask
 * @property integer $full The internal value of a fully-on Bitmask
 */
class Bitmask
{
	protected $flags = array();  // set of flag bit masks
	protected $full = 0;         // maximum integer value of the bitmask
	protected $value = 0;        // internal integer value of the bitmask

	/**
	 * Constructor.  Takes an optional array parameter
	 * of bit flags to mask on.
	 *
	 * @param array $flags An array of flag names
	 * @param integer $value (optional) a combined bitmask value
	 * @throws InvalidArgumentException
	 */
	public function __construct( $flags = null, $value = null )
	{
		if ( ! is_array( $flags ) ) {
			// @locale Habari tried to create a Bitmask with the wrong arguments
			throw new InvalidArgumentException( _t( 'Bitmask constructor expects either no arguments or an array as a first argument' ) );
		}

		if ( count( $flags ) > ( PHP_INT_MAX >> 1 ) ) {
			// @locale Habari tried to create a new Bitmask with too many flags
			throw new InvalidArgumentException( _t( 'Bitmask can have a maximum of PHP_INT_MAX >> 1 flags' ) );
		}

		$this->flags = $flags;
		$this->full = ( 1 << ( count( $this->flags ) ) ) - 1;
		if ( ! is_null( $value ) ) {
			if ( $value === 'full' ) {
				$this->value = $this->full;
			}
			elseif ( (string) (int) $value === (string) $value && $value >= 0 && $value <= $this->full ) {
				$this->value = $value;
			}
			elseif ( is_string( $value ) && in_array( $value, $flags ) ) {
				// This calls the setter directly to deal with non-public
				// properties to make sure we have the same behaviour as the
				// normal API.
				$this->__set( $value, true );
			}
			else {
				// @locale Habari tried to create a new Bitmask object with invalid values in the second argument
				throw new InvalidArgumentException( _t( 'Bitmask constructor second argument must either be an integer within the valid range, the name of a flag, or full' ) );
			}
		}

	}

	/**
	 * Magic setter method for flag values.
	 *
	 * @param string $bit The name of the Bitmask part to set
	 * @param mixed $on The value to set the bit to
	 * @throws InvalidArgumentException
	 * @return mixed The set value
	 */
	public function __set( $bit, $on )
	{
		switch ( $bit ) {
			case 'full':
				if ( ! is_bool( $on ) ) {
					// @locale Habari tried to set the wrong type of value
					throw new InvalidArgumentException( _t( 'Bitmask full toggle must be boolean' ) );
				}

				if ( $on ) {
					$this->value = $this->full;
				}
				else {
					$this->value = 0;
				}
				break;
			case 'value':
				if ( is_array( $on ) ) {
					if ( count( $on ) !== count( $this->flags ) ) {
						// @locale Habari tried to set the wrong kind of value
						throw new InvalidArgumentException( _t( 'Setting bitmask value by array must use array with same length as number of flags' ) );
					}
					$this->value = 0;
					foreach ( $on as $flag ) {
						if ( ! is_bool( $flag ) ) {
							// @locale Habari tried to set the wrong kind of value
							throw new InvalidArgumentException( _t( 'Bitmask values must be boolean' ) );
						}
						$this->value <<= 1;
						$this->value |= (int) $flag;
					}
				}
				elseif ( (string) (int) $on === (string) $on && $on >= 0 && $on <= $this->full ) {
					$this->value = $on;
				}
				elseif ( empty($on) ) {
					$this->value = 0;
				}
				else {
					// @locale Habari tried to set the wrong kind of value
					throw new InvalidArgumentException( _t( 'Bitmask value must either be an integer within the valid range or an array of booleans' ) );
				}
				break;
			default:
				if ( ! is_bool( $on ) ) {
					// @locale Habari tried to set the wrong kind of value
					throw new InvalidArgumentException( _t( 'Bitmask values must be boolean' ) );
				}

				$bit = array_search( $bit, $this->flags );

				if ( $bit === false ) {
					// @locale Habari tried to set a value that doesn't exist
					throw new InvalidArgumentException( _t( 'Bitmask cannot set non-existent flag' ) );
				}

				if ( $on ) {
					$this->value |= 1 << $bit;
				}
				else {
					$this->value &= ~( 1 << $bit );
				}
				break;
		}
		return $on;
	}

	/**
	 * Magic getter method for flag status
	 *
	 * @param int $bit representing the mask bit to test
	 * @throws InvalidArgumentException
	 * @return boolean
	 */
	public function __get( $bit )
	{
		if ( $bit === 'value' ) {
			return intval( $this->value );
		}
		elseif ( $bit === 'full' ) {
			return intval( $this->full );
		}
		elseif ( ( $bit = array_search( $bit, $this->flags ) ) !== false ) {
			return ( intval( $this->value ) & ( 1 << $bit ) ) !== 0;
		}
		else {
			// @locale Habari tried to get a flag that doesn't exist
			throw new InvalidArgumentException( _t( 'Bitmask cannot get non-existent flag' ) );
		}
	}

	/**
	 * Magic check-whether-flag-exists method
	 *
	 * @param string $flag of flag name
	 * @return boolean
	 */
	public function __isset( $flag )
	{
		return $flag === 'full' || $flag === 'value' || in_array( $flag, $this->flags );
	}

	/**
	 * Convert this Bitmask into a string, based ont he flags that are set
	 * @return string Converted bitmask value
	 */
	public function __tostring()
	{
		if ( $this->value === $this->full ) {
			return _t( 'full' );
		}
		$output = array();
		foreach ( $this->flags as $flag ) {
			if ( $this->$flag ) {
				$output[] = $flag;
			}
		}
		if ( count( $output ) === 0 ) {
			return _t( 'none' );
		}
		return implode( ',', $output );
	}

}
?>


code:
<?php
/**
 * @package Habari
 *
 */

/**
 * Habari Block class
 * Block class for theme display of pluggable content
 *
 * @property string $type The type of block this is
 * @property string $title The title of this block
 * @property mixed $data The data associated to this block
 * @property integer $id The id of this block in the database
 *
 */
class Block extends QueryRecord implements IsContent, FormStorage
{
	public $_first = false;
	public $_last = false;
	public $_area_index = 0;
	public $_area = '';
	private $data_values = array( '_show_title' => true );

	/**
	 * Constructor for the Block class.
	 * @param array $paramarray an associative array of initial block field values.
	 */
	public function __construct( $paramarray = array() )
	{
		// Defaults
		$this->fields = array_merge(
			self::default_fields(),
			$this->fields,
			$this->newfields
		);
		parent::__construct( $paramarray );

		$this->exclude_fields( 'id' );
		$this->unserialize_data();
	}

	/**
	 * Overrides QueryRecord __get to implement custom object properties
	 *
	 * @param string $name Name of property to return
	 * @return mixed The requested field value
	 */
	public function __get( $name )
	{
		switch($name) {
			case 'css_classes':
				$classes = array();
				if(array_key_exists( $name, $this->data_values )) {
					$classes = $this->data_values[$name];
				}
				if(is_string($classes)) {
					$classes = explode(' ', $classes);
				}
				if($this->_first) {
					$classes[] = 'first';
				}
				if($this->_last) {
					$classes[] = 'last';
				}
				if($this->_area_index) {
					$classes[] = 'index_' . $this->_area_index;
				}
				$classes[] = 'block-type-' . Utils::slugify($this->type);
				$classes[] = 'block';
				$classes = Plugins::filter('block_classes', $classes, $this);
				return implode(' ', $classes);
				break;
			default:
			if ( array_key_exists( $name, $this->data_values ) ) {
				return $this->data_values[$name];
			}
			else {
				return parent::__get( $name );
			}
		}
	}

	/**
	 * Overrides QueryRecord __set to implement custom object properties
	 *
	 * @param string $name Name of property to return
	 * @param mixed $value The value to set the property to
	 * @return mixed The value of the property
	 */
	public function __set( $name, $value )
	{
		switch ( $name ) {
			case 'id':
			case 'title':
			case 'data':
				parent::__set( $name, $value );
				$this->unserialize_data();
				return parent::__get( $name );
				break;
			case 'type':
				return parent::__set( $name, $value );
				break;
			default:
				$this->data_values[ $name ] = $value;
				return $this->data_values[ $name ];
				break;
		}
	}

	/**
	 * Overrides QueryRecord __isset, returns whether this Block has the named
	 * data. Falls back to QueryRecord's __isset.
	 *
	 * @param string $name The name of the parameter
	 * @return boolean True if the value is set, false if not
	 */
	public function __isset( $name )
	{
		return ( isset( $this->data_values[$name] ) || parent::__isset( $name ) );
	}

	/**
	 * Return the defined database columns for a Block.
	 * @return array Array of columns in the Block table
	 */
	public static function default_fields()
	{
		return array(
			'id' => 0,
			'title' => '',
			'data' => '',
			'type' => '',
		);
	}

	/**
	 * Render and return the block content
	 *
	 * @param Theme $theme the theme object with which the block will be rendered
	 * @return string The rendered block content
	 */
	public function fetch( $theme )
	{
		Plugins::act( 'block_content_' . $this->type, $this, $theme );
		Plugins::act( 'block_content', $this, $theme );
		$output = implode( '', $theme->content_return( $this ) );
		return $output;
	}

	/**
	 * Return the content types that this object represents
	 *
	 * @see IsContent
	 * @return array An array of strings representing the content type of this object
	 */
	public function content_type()
	{
		$types = array(
			'block.' . $this->type,
			'block',
		);
		if ( isset( $this->title ) ) {
			array_unshift( $types, 'block.' . $this->type . '.' . Utils::slugify( $this->title ) );
		}
		if ( isset( $this->_area ) ) {
			$areas = array();
			foreach ( $types as $type ) {
				$areas[] = $this->_area . '.' . $type;
			}
			$types = array_merge( $areas, $types );
		}
		$types = Plugins::filter( 'block_content_type_' . $this->type, $types, $this );
		$types = Plugins::filter( 'block_content_type', $types, $this );
		return $types;
	}

	/**
	 * Unserialize the stored block data
	 */
	public function unserialize_data()
	{
		if ( trim( $this->data ) != '' ) {
			$this->data_values = unserialize( $this->data );
		}
	}

	/**
	 * Saves form fields that are tied to this block.  Implements FormStorage.
	 *
	 * @param string $key The name of the form field to store.
	 * @param mixed $value The value of the form field
	 */
	public function field_save( $key, $value )
	{
		$this->$key = $value;
		$this->update();
	}

	/**
	 * Load the form value from the block
	 *
	 * @param string $key The name of the form field to load
	 * @return mixed The value of the block for the form
	 */
	public function field_load( $key )
	{
		return $this->$key;
	}

	/**
	 * Insert this block into the database
	 *
	 * @return boolean|null True on success, null if the action wasn't allowed
	 */
	public function insert()
	{
		// Let plugins disallow and act before we write to the database
		$allow = true;
		$allow = Plugins::filter( 'block_insert_allow', $allow, $this );
		if ( ! $allow ) {
			return null;
		}
		Plugins::act( 'block_insert_before', $this );

		$this->data = serialize( $this->data_values );
		$result = parent::insertRecord( DB::table( 'blocks' ) );

		// Make sure the id is set in the block object to match the row id
		$this->newfields['id'] = DB::last_insert_id();

		// Update the block's fields with anything that changed
		$this->fields = array_merge( $this->fields, $this->newfields );

		// We've inserted the block, reset newfields
		$this->newfields = array();

		EventLog::log( _t( 'New block %1$s: %2$s', array( $this->id, $this->title ) ), 'info', 'content', 'habari' );

		// Let plugins act after we write to the database
		Plugins::act( 'block_insert_after', $this );
		return $result;
	}

	/**
	 * Update this block in the database
	 *
	 * @return boolean|null True on success, null if the update isn't allowed
	 */
	public function update()
	{
		$allow = true;
		$allow = Plugins::filter( 'block_update_allow', $allow, $this );
		if ( ! $allow ) {
			return null;
		}
		Plugins::act( 'block_update_before', $this );

		$this->data = serialize( $this->data_values );
		$result = parent::updateRecord( DB::table( 'blocks' ), array( 'id' => $this->id ) );

		$this->fields = array_merge( $this->fields, $this->newfields );
		$this->newfields = array();

		Plugins::act( 'block_update_after', $this );
		return $result;
	}

	/**
	 * Delete this block
	 *
	 */
	public function delete()
	{
		// Let plugins disallow and act before we write to the database
		$allow = true;
		$allow = Plugins::filter( 'block_delete_allow', $allow, $this );
		if ( !$allow ) {
			return false;
		}
		Plugins::act( 'block_delete_before', $this );

		$result = parent::deleteRecord( '{blocks_areas}', array( 'block_id'=>$this->id ) );
		$result = $result && parent::deleteRecord( '{blocks}', array( 'id'=>$this->id ) );

		EventLog::log( _t( 'Block %1$s (%2$s) deleted.', array( $this->id, $this->title ) ), 'info', 'content', 'habari' );

		// Let plugins act after we write to the database
		Plugins::act( 'block_delete_after', $this );
		return $result;
	}

	/**
	 * Get the form used to update this block
	 *
	 * @return FormUI The altered FormUI element that edits this block
	 */
	public function get_form()
	{
		$form = new FormUI( 'block-' . $this->id, 'block' );
		$form->on_success( array( $this, 'save_block' ) );

		Plugins::act( 'block_form_' . $this->type, $form, $this );
		Plugins::act( 'block_form', $form, $this );
		return $form;
	}

	/**
	 * Display a standard success message upon saving the form
	 *
	 * @param FormUI $form The form that will be saved
	 * @return bool Returning false tells the form that the save was handled
	 */
	public function save_block( FormUI $form )
	{
		$form->save();
		return false;
	}

	/**
	 * Add this block to a particular area in the theme
	 *
	 * @param string $area The name of the area to add to
	 * @param integer $order The position of the block within the area
	 * @param string $scope The scope id into which to add this block
	 */
	public function add_to_area( $area, $order = null, $scope = null )
	{
		if( is_null( $scope ) ) {
			$scope = 0;
		}
		if( is_null( $order ) || ! is_int( $order ) ) {
			$order = DB::get_value( 'SELECT max(display_order) + 1 FROM {blocks_areas} WHERE area = :area AND scope_id = :scope', array( 'area' => $area, 'scope' => $scope ) );
			if( is_null( $order ) ) {
				$order = 1;
			}
		}
		else {
			DB::query( 'UPDATE {blocks_areas} SET display_order = display_order + 1 WHERE area = :area AND scope_id = :scope AND display_order >= :order', array( 'area' => $area, 'scope' => $scope, 'order' => $order ) );
		}

		// If the block isn't saved in the database, insert it.
		if( !$this->id ) {
			$this->insert();
		}

		$result = DB::query( 'INSERT INTO {blocks_areas} (block_id, area, scope_id, display_order) VALUES (:block_id, :area, :scope_id, :display_order)', array( 'block_id' => $this->id, 'area' => $area, 'scope_id' => $scope, 'display_order' => $order ) );
	}

	/**
	 * Convert this block into a string, just in case there isn't a template associated to this block type
	 * @return string The string representation of this content, as a bad fallback
	 */
	public function __toString()
	{
		return $this->title;
	}
}

?>


code:
<?php
/**
 * @package Habari
 *
 */

/**
 * Habari Cache Class
 *
 * Base abstract class for caching computationally expensive or bandwidth intensive data
 */
abstract class Cache
{
	protected static $default_group = 'default';
	protected static $instance;

	/**
	 * Set up the static cache instance in __autoload()
	 */
	public static function __static()
	{
		if ( !defined( 'CACHE_CLASS' ) ) {
			define( 'CACHE_CLASS', 'FileCache' );
		}
		$cache_class = CACHE_CLASS;
		self::$instance = new $cache_class();
	}

	/**
	 * Is record with $name in the cache?
	 *
 	 * @param mixed $name name of the cached item or an array of array( string $group, string $name )
	 * @return boolean true if item is cached, false if not
	 */
	public static function has( $name )
	{
		if ( is_array( $name ) ) {
			$array = $name;
			list( $group, $name ) = $array;
		}
		else {
			$group = self::$default_group;
		}
		return self::$instance->_has( $name, $group );
	}

	/**
	 * A cache instance implements this function to return whether a named cache exists.
	 *
	 * @param string $name The name of the cached item
	 * @return boolean true if the item is cached, false if not
	 */
	abstract protected function _has( $name, $group );

	/**
	 * Is group in the cache?
	 *
 	 * @param string $group name of the cached group
	 * @return boolean true if group is cached, false if not
	 */
	public static function has_group( $group )
	{
		return self::$instance->_has_group( $group );
	}

	/**
	 * A cache instance implements this function to return whether a group exists.
	 *
	 * @param string $name The name of the cached group
	 * @return boolean true if the group is cached, false if not
	 */
	abstract protected function _has_group( $group );

	/**
	 * Returns the named value from the cache.
	 *
	 * @param mixed $name The name of the cached item or an array of array( string $group, string $name )
	 * @return mixed The item value or null if it doesn't exist in cache
	 */
	public static function get( $name )
	{
		if ( is_array( $name ) ) {
			$array = $name;
			list( $group, $name ) = $array;
		}
		else {
			$group = self::$default_group;
		}
		return self::$instance->_get( $name, $group );
	}

	/**
	 * A cache instance implements this to return the named value from the cache.
	 *
	 * @param string $name The name of the cached item
	 * @return mixed The item value or null if it doesn't exist in cache
	 */
	abstract protected function _get( $name, $group );

	/**
	 * Returns the group from the cache.
	 *
	 * @param string $name The name of the cached group
	 * @return mixed The item value or null if it doesn't exist in cache
	 */
	public static function get_group( $group )
	{
		return self::$instance->_get_group( $group );
	}

	/**
	 * A cache instance implements this to return the group from the cache.
	 *
	 * @param string $name The name of the cached group
	 * @return mixed The item value or null if it doesn't exist in cache
	 */
	abstract protected function _get_group( $group );

	/**
	 * Set the named value in the cache with an expiration.
	 *
	 * @param mixed $name The name of the cached item or an array of array( string $group, string $name )
	 * @param mixed $value The value to store
	 * @param integer $expiry Number of second after the call that the cache will expire
	 * @param boolean $keep If true, retain the cache value even after expiry but report the cache as expired
	 */
	public static function set( $name, $value, $expiry = 3600, $keep = false )
	{
		if ( is_array( $name ) ) {
			$array = $name;
			list( $group, $name ) = $array;
		}
		else {
			$group = self::$default_group;
		}
		return self::$instance->_set( $name, $value, $expiry, $group, $keep );
	}

	/**
	 * A cache instance implements this to set the named value in the cache with an expiration.
	 *
	 * @param string $name The name of the cached item
	 * @param mixed $value The value to store
	 * @param integer $expiry Number of second after the call that the cache will expire
	 */
	abstract protected function _set( $name, $value, $expiry, $group, $keep );

	/**
	 * Expires the named value from the cache.
	 *
	 * @param mixed $name The name of the cached item or an array of array( string $group, string $name )
	 * @param string $match_mode (optional) how to match item names ('strict', 'regex', 'glob') (default 'strict')
	 */
	public static function expire( $name, $match_mode = 'strict' )
	{
		if ( is_array( $name ) ) {
			$array = $name;
			list( $group, $name ) = $array;
		}
		else {
			$group = self::$default_group;
		}
		self::$instance->_expire( $name, $group, $match_mode );
	}

	/**
	 * A cache instance implements this to expire the named value from the cache.
	 *
	 * @param string $name The name of the cached item
	 */
	abstract protected function _expire( $name, $group );

	/**
	 * Check if a named value in the cache has expired.
	 *
	 * @param mixed $name The name of the cached item or an array of array( string $group, string $name )
	 */
	public static function expired( $name )
	{
		if ( is_array( $name ) ) {
			$array = $name;
			list( $group, $name ) = $array;
		}
		else {
			$group = self::$default_group;
		}
		return self::$instance->_expired( $name, $group );
	}

	/**
	 * A cache instance implements this to expire the named value from the cache.
	 *
	 * @param string $name The name of the cached item
	 */
	abstract protected function _expired( $name, $group );

	/**
	 * Extend the expiration of the named cached value.
	 *
	 * @param mixed $name The name of the cached item or an array of array( string $group, string $name )
	 * @param integer $expiry The duration in seconds to extend the cache expiration by
	 */
	public static function extend( $name, $expiry )
	{
		if ( is_array( $name ) ) {
			$array = $name;
			list( $group, $name ) = $array;
		}
		else {
			$group = self::$default_group;
		}
		self::$instance->_extend( $name, $expiry, $group );
	}

	/**
	 * A cache instance implements this to extend the expiration of the named cached value.
	 *
	 * @param string $name The name of the cached item
	 * @param integer $expiry The duration in seconds to extend the cache expiration by
	 */
	abstract protected function _extend( $name, $expiry, $group );

	public static function debug() { return self::$instance->debug_data(); }

	/**
	 * Empty the cache completely
	 *
	 */
	public static function purge()
	{
		return self::$instance->_purge();
	}
}

?>


code:
<?php
/**
 * @package Habari
 *
 */

/**
 * Various color utility functions.
 */
class ColorUtils
{
	/**
	 * Convert RGB args to RGB array.
	 */
	public static function rgb_rgbarr( $r, $g, $b )
	{
		return array_map( 'round', array( 'r' => $r, 'g' => $g, 'b' => $b ) );
	}

	/**
	 * Convert HSV args to HSV array.
	 */
	public static function hsv_hsvarr( $h, $s, $v )
	{
		return array_map( 'round', array( 'h' => $h, 's' => $s, 'v' => $v ) );
	}

	/**
	 * Converts a HTML style hex string ('#7f6699') to an RGB array.
	 */
	public static function hex_rgb( $hex_string )
	{
		$hex_string = ltrim( $hex_string, '#' );
		if ( ! preg_match( '/^[0-9a-f]+$/i', $hex_string ) ) {
			return Error::raise( _t( 'Not a valid hex color.' ) );
		}

		$normalized = '';

		switch ( strlen( $hex_string ) ) {
			case 3:
				// 'fed' = 'ffeedd'
				for ( $i = 0; $i < 3; $i++ ) {
					$normalized .= $hex_string{$i} . $hex_string{$i};
				}
				break;
			case 6:
				// already normal
				$normalized = $hex_string;
				break;
			case 2:
			case 4:
				// who uses this anyway!
				$normalized = $hex_string . str_repeat( '0', 6 - strlen( $hex_string ) );
				break;
			default:
				return Error::raise( _t( 'Not a valid color format.' ) );
		}

		return self::rgb_rgbarr(
			hexdec( substr( $normalized, 0, 2 ) ),
			hexdec( substr( $normalized, 2, 2 ) ),
			hexdec( substr( $normalized, 4, 2 ) )
		);
	}

	/**
	 * Convert an RGB array to a HTML style hex color.
	 */
	public static function rgb_hex( $rgb_arr )
	{
		$hex_string = sprintf( '%02x%02x%02x', $rgb_arr['r'], $rgb_arr['g'], $rgb_arr['b'] );

		return $hex_string;
	}

	/**
	 * Convert an RGB array to a HSV array.
	 */
	public static function rgb_hsv( $rgb_arr )
	{
		$var_R = ($rgb_arr['r'] / 255);
		$var_G = ($rgb_arr['g'] / 255);
		$var_B = ($rgb_arr['b'] / 255);

		$var_Min = min($var_R, $var_G, $var_B);
		$var_Max = max($var_R, $var_G, $var_B);
		$del_Max = $var_Max - $var_Min;

		$V = $var_Max;

		if( $del_Max == 0 ) {
			$H = 0;
			$S = 0;
		} else {
			$S = $del_Max / $var_Max;

			$del_R = ((($var_Max - $var_R) / 6) + ($del_Max / 2)) / $del_Max;
			$del_G = ((($var_Max - $var_G) / 6) + ($del_Max / 2)) / $del_Max;
			$del_B = ((($var_Max - $var_B) / 6) + ($del_Max / 2)) / $del_Max;

			if( $var_R == $var_Max ) {
				$H = $del_B - $del_G;
			}
			elseif( $var_G == $var_Max ) {
				$H = (1 / 3) + $del_R - $del_B;
			}
			elseif( $var_B == $var_Max ) {
				$H = (2 / 3) + $del_G - $del_R;
			}
			else {
				$H = 0;  // This never happens, since one of the three is always the max
			}

			if( $H < 0 ) {
				$H += 1;
			}
			if( $H > 1 ) {
				$H -= 1;
			}
		}
		return self::hsv_hsvarr($H * 360, $S * 255, $V * 255);
	}

	/**
	 * Convert a HSV array to RGB.
	 */
	public static function hsv_rgb( $hsv_arr )
	{
		if ( $hsv_arr['s'] == 0 ) {
			// grey
			$r = $g = $b = $hsv_arr['v'];
		}
		else {
			$h = $hsv_arr['h'] / 60; // degrees to sectors
			$s = $hsv_arr['s'] / 100; // percent to fraction
			$f = $h - floor( $h );

			$p = $hsv_arr['v'] * ( 1 - $s );
			$q = $hsv_arr['v'] * ( 1 - $s * $f );
			$t = $hsv_arr['v'] * ( 1 - $s * ( 1 - $f ) );

			switch ( floor( $h ) ) {
				case 0: // first sector
					$r = $hsv_arr['v'];
					$g = $t;
					$b = $p;
					break;
				case 1: // second sector
					$r = $q;
					$g = $hsv_arr['v'];
					$b = $p;
					break;
				case 2: // third sector
					$r = $p;
					$g = $hsv_arr['v'];
					$b = $t;
					break;
				case 3: // fourth sector
					$r = $p;
					$g = $q;
					$b = $hsv_arr['v'];
					break;
				case 4: // fifth sector
					$r = $t;
					$g = $p;
					$b = $hsv_arr['v'];
					break;
				case 5: // sixth sector
					$r = $hsv_arr['v'];
					$g = $p;
					$b = $q;
					break;
			}
		}

		return self::rgb_rgbarr( $r, $g, $b );
	}
}

?>


code:
<?php
/**
 * @package Habari
 *
 */

/**
 * Habari CommentRecord Class
 *
 * Includes an instance of the CommentInfo class; for holding inforecords about the comment
 * If the Comment object describes an existing user; use the internal info object to get, set, unset and test for existence (isset) of
 * info records
 *
 * $this->info = new CommentInfo ( 1 );  // Info records of comment with id = 1
 * $this->info->browser_ua= "Netscape 2.0"; // set info record with name "browser_ua" to value "Netscape 2.0"
 * $info_value= $this->info->browser_ua; // get value of info record with name "browser_ua" into variable $info_value
 * if ( isset ($this->info->browser_ua) )  // test for existence of "browser_ua"
 * unset ( $this->info->browser_ua ); // delete "browser_ua" info record
 *
 *
 */
class Comment extends QueryRecord implements IsContent
{

	// our definitions for comment types and statuses
	const STATUS_UNAPPROVED = 0;
	const STATUS_APPROVED = 1;
	const STATUS_SPAM = 2;
	const STATUS_DELETED = 3;

	const COMMENT = 0;
	const PINGBACK = 1;
	const TRACKBACK = 2;

	private $post_object = null;

	private $inforecords = null;

	// static variables to hold comment status and comment type values
	static $comment_status_list = array();
	static $comment_type_list = array();
	static $comment_status_actions = array();

	/**
	 * static function default_fields
	 * Returns the defined database columns for a comment
	 */
	public static function default_fields()
	{
		return array(
			'id' => 0,
			'post_id' => 0,
			'name' => '',
			'email' => '',
			'url' => '',
			'ip' => 0,
			'content' => '',
			'status' => self::STATUS_UNAPPROVED,
			'date' => HabariDateTime::date_create(),
			'type' => self::COMMENT
		);
	}

	/**
	 * constructor __construct
	 * Constructor for the Post class.
	 * @param array an associative array of initial Post field values.
	 */
	public function __construct( $paramarray = array() )
	{
		// Defaults
		$this->fields = array_merge( self::default_fields(), $this->fields );
		parent::__construct( $paramarray );
		$this->exclude_fields( 'id' );
		/* $this->fields['id'] could be null in case of a new comment. If so, the info object is _not_ safe to use till after set_key has been called. Info records can be set immediately in any other case. */

	}

	/**
	 * Register plugin hooks
	 * @static
	 */
	public static function __static()
	{
		Pluggable::load_hooks('Comment');
	}

	/**
	 * static function get
	 * Returns a single comment, by ID
	 *
	 *
	 * $post = Post::get( 10 );
	 *
	 *
	 * @param int An ID
	 * @return array A single Comment object
	 */
	static function get( $id = 0 )
	{
		if ( ! $id ) {
			return false;
		}
		return DB::get_row( 'SELECT * FROM {comments} WHERE id = ?', array( $id ), 'Comment' );
	}

	/**
	 * static function create
	 * Creates a comment and saves it
	 * @param array An associative array of comment fields
	 * $return Comment The comment object that was created
	 */
	static function create( $paramarray )
	{
		$comment = new Comment( $paramarray );
		$comment->insert();
		return $comment;
	}

	/**
	 * function insert
	 * Saves a new comment to the posts table
	 */
	public function insert()
	{
		$allow = true;
		$allow = Plugins::filter( 'comment_insert_allow', $allow, $this );
		if ( ! $allow ) {
			return;
		}
		Plugins::act( 'comment_insert_before', $this );
		// Invoke plugins for all fields, since they're all "chnaged" when inserted
		foreach ( $this->fields as $fieldname => $value ) {
			Plugins::act( 'comment_update_' . $fieldname, $this, $this->$fieldname, $value );
		}
		$result = parent::insertRecord( DB::table( 'comments' ) );
		$this->newfields['id'] = DB::last_insert_id(); // Make sure the id is set in the comment object to match the row id
		$this->fields = array_merge( $this->fields, $this->newfields );
		$this->newfields = array();
		$this->info->commit( $this->fields['id'] );
		Plugins::act( 'comment_insert_after', $this );
		return $result;
	}

	/**
	 * function update
	 * Updates an existing comment in the posts table
	 */
	public function update()
	{
		$allow = true;
		$allow = Plugins::filter( 'comment_update_allow', $allow, $this );
		if ( ! $allow ) {
			return;
		}
		Plugins::act( 'comment_update_before', $this );
		// invoke plugins for all fields which have been updated
		foreach ( $this->newfields as $fieldname => $value ) {
			Plugins::act( 'comment_update_' . $fieldname, $this, $this->fields[$fieldname], $value );
		}
		$result = parent::updateRecord( DB::table( 'comments' ), array( 'id'=>$this->id ) );
		$this->fields = array_merge( $this->fields, $this->newfields );
		$this->newfields = array();
		$this->info->commit();
		Plugins::act( 'comment_update_after', $this );
		return $result;
	}

	/**
	 * function delete
	 * Deletes this comment
	 */
	public function delete()
	{
		$allow = true;
		$allow = Plugins::filter( 'comment_delete_allow', $allow, $this );
		if ( ! $allow ) {
			return;
		}
		Plugins::act( 'comment_delete_before', $this );

		// Delete all info records associated with this comment
		$this->info->delete_all();

		$result = parent::deleteRecord( DB::table( 'comments' ), array( 'id'=>$this->id ) );
		Plugins::act( 'comment_delete_after', $this );
		return $result;
	}

	/**
	 * function __get
	 * Overrides QueryRecord __get to implement custom object properties
	 * @param string Name of property to return
	 * @return mixed The requested field value
	 */
	public function __get( $name )
	{
		$fieldnames = array_merge( array_keys( $this->fields ), array('post', 'info', 'editlink' ) );
		$filter = false;
		if ( !in_array( $name, $fieldnames ) && strpos( $name, '_' ) !== false ) {
			$field_matches = implode('|', $fieldnames);
			if(preg_match( '/^(' . $field_matches . ')_(.+)$/', $name, $matches )) {
				list( $junk, $name, $filter ) = $matches;
			}
		}

		if ( $name == 'name' && parent::__get( $name ) == '' ) {
			return _t( 'Anonymous' );
		}
		switch ( $name ) {
			case 'post':
				$out = $this->get_post();
				break;
			case 'info':
				$out = $this->get_info();
				break;
			case 'statusname':
				$out = self::status_name( $this->status );
				break;
			case 'typename':
				$out = self::type_name( $this->type );
				break;
			case 'editlink':
				$out = $this->get_editlink();
				break;
			default:
				$out = parent::__get( $name );
				break;
		}
		//$out = parent::__get( $name );
		$out = Plugins::filter( "comment_{$name}", $out, $this );
		if ( $filter ) {
			$out = Plugins::filter( "comment_{$name}_{$filter}", $out, $this );
		}
		return $out;
	}

	/**
	 * function __set
	 * Overrides QueryRecord __set to implement custom object properties
	 * @param string Name of property to return
	 * @return mixed The requested field value
	 */
	public function __set( $name, $value )
	{
		switch ( $name ) {
			case 'status':
				return $this->setstatus( $value );
			case 'date':
				if ( !( $value instanceOf HabariDateTime ) ) {
					$value = HabariDateTime::date_create( $value );
				}
				break;
			case 'post':
				if ( is_int( $value ) ) {
					// a post ID was passed
					$p = Post::get( array( 'id'=>$value ) );
					$this->post_id = $p->id;
					$this->post_object = $p;
				}
				elseif ( is_string( $value ) ) {
					// a post Slug was passed
					$p = Post::get( array( 'slug'=>$value ) );
					$this->post_id = $p->id;
					$this->post_object = $p;
				}
				elseif ( is_object( $value ) ) {
					// a Post object was passed, so just use it directly
					$this->post_id = $p->id;
					$this->post_object = $value;
				}
				return $value;
		}
		return parent::__set( $name, $value );
	}

	/**
	 * private function get_post()
	 * returns a Post object for the post of this comment
	 * @param bool Whether to use the cached version or not.  Default to true
	 * @return Post a Post object for the post of the current comment
	 */
	private function get_post( $use_cache = true )
	{
		if ( ! isset( $this->post_object ) || ( ! $use_cache)  ) {
			$this->post_object = Posts::get( array('id' => $this->post_id, 'fetch_fn' => 'get_row') );
		}
		return $this->post_object;
	}

	/**
	 * function get_info
	 * Gets the info object for this comment, which contains data from the commentinfo table
	 * related to this comment.
	 * @return CommentInfo object
	 */
	private function get_info()
	{
		if ( ! $this->inforecords ) {
			if ( 0 == $this->id ) {
				$this->inforecords = new CommentInfo();
			}
			else {
				$this->inforecords = new CommentInfo( $this->id );
			}
		}
		return $this->inforecords;
	}

	/**
 	 * function setstatus
 	 * @param mixed the status to set it to. String or integer.
 	 * @return integer the status of the comment
 	 * Sets the status for a comment, given a string or integer.
 	 */
	private function setstatus( $value )
	{
		if ( is_numeric( $value ) ) {
			$this->newfields['status'] = $value;
		}
		else {
			switch ( strtolower( $value ) ) {
				case "approved":
				case "approve":
				case "ham":
					$this->newfields['status'] = self::STATUS_APPROVED;
					break;
				case "unapproved":
				case "unapprove":
					$this->newfields['status'] = self::STATUS_UNAPPROVED;
					break;
				case "spam":
					$this->newfields['status'] = self::STATUS_SPAM;
					break;
				case "deleted":
					$this->newfields['status'] = self::STATUS_DELETED;
					break;
			}
		}
		return $this->newfields['status'];
	}

	/**
	 * returns an associative array of comment types
	 * @param bool whether to force a refresh of the cached values
	 * @return array An array of comment type names => integer values
	 */
	public static function list_comment_types( $refresh = false )
	{
		if ( ( ! $refresh ) && ( ! empty( self::$comment_type_list ) ) ) {
			return self::$comment_type_list;
		}
		self::$comment_type_list = array(
			self::COMMENT => 'comment',
			self::PINGBACK => 'pingback',
			self::TRACKBACK => 'trackback',
		);
		return self::$comment_type_list;
	}

	/**
	 * returns an associative array of comment statuses
	 * @param bool whether to force a refresh of the cached values
	 * @return array An array of comment statuses names => interger values
	 */
	public static function list_comment_statuses( $refresh = false )
	{
		if ( ( ! $refresh ) && ( ! empty( self::$comment_status_list ) ) ) {
			return self::$comment_status_list;
		}
		self::$comment_status_list = array(
			self::STATUS_UNAPPROVED => 'unapproved',
			self::STATUS_APPROVED => 'approved',
			self::STATUS_SPAM => 'spam',
			// 'STATUS_DELETED' => self::STATUS_DELETED, // Not supported
		);
		self::$comment_status_list = Plugins::filter( 'list_comment_statuses', self::$comment_status_list );
		return self::$comment_status_list;
	}

	/**
	 * returns the action name of the comment status
	 * @param mixed a comment status value, or name
	 * @return string a string of the status action, or null
	 */
	public static function status_action( $status )
	{
		if ( empty( self::$comment_status_actions ) ) {
			self::$comment_status_actions = array(
				self::STATUS_UNAPPROVED => _t( 'Unapprove' ),
				self::STATUS_APPROVED => _t( 'Approve' ),
				self::STATUS_SPAM => _t( 'Spam' ),
			);
			self::$comment_status_actions = Plugins::filter( 'list_comment_actions', self::$comment_status_actions );
		}
		if ( is_numeric( $status ) && isset( self::$comment_status_actions[$status] ) ) {
			return self::$comment_status_actions[$status];
		}
		$statuses = array_flip( Comment::list_comment_statuses() );
		if ( isset( $statuses[$status] ) ) {
			return self::$comment_status_actions[$statuses[$status]];
		}

		return '';
	}

	/**
	 * returns the integer value of the specified comment status, or false
	 * @param mixed a comment status name or value
	 * @return mixed an integer or boolean false
	 */
	public static function status( $name )
	{
		$statuses = Comment::list_comment_statuses();
		if ( is_numeric( $name ) && ( isset( $statuses[$name] ) ) ) {
			return $name;
		}
		$statuses = array_flip( $statuses );
		if ( isset( $statuses[$name] ) ) {
			return $statuses[$name];
		}
		return false;
	}

	/**
	 * returns the friendly name of a comment status, or null
	 * @param mixed a comment status value, or name
	 * @return mixed a string of the status name, or null
	 */
	public static function status_name( $status )
	{
		$statuses = Comment::list_comment_statuses();
		if ( is_numeric( $status ) && isset( $statuses[$status] ) ) {
			return $statuses[$status];
		}
		$statuses = array_flip( $statuses );
		if ( isset( $statuses[$status] ) ) {
			return $status;
		}
		return '';
	}

	/**
	 * returns the integer value of the specified comment type, or false
	 * @param mixed a comment type name or number
	 * @return mixed an integer or boolean false
	 */
	public static function type( $name )
	{
		$types = Comment::list_comment_types();
		if ( is_numeric( $name ) && ( isset( $types[$name] ) ) ) {
			return $name;
		}
		$types = array_flip( $types );
		if ( isset( $types[$name] ) ) {
			return $types[$name];
		}
		return false;
	}

	/**
	 * returns the friendly name of a comment type, or null
	 * @param mixed a comment type number, or name
	 * @return mixed a string of the comment type, or null
	 */
	public static function type_name( $type )
	{
		$types = Comment::list_comment_types();
		if ( is_numeric( $type ) && isset( $types[$type] ) ) {
			return $types[$type];
		}
		$types = array_flip( $types );
		if ( isset( $types[$type] ) ) {
			return $type;
		}
		return '';
	}

	/**
	 * Return the content type of this object
	 *
	 * @return string The content type of this object
	 * @see IsContent
	 */
	public function content_type()
	{
		return Comment::type_name( $this->type );
	}

	/**
	 * Returns an access Bitmask for the given user on this comment. Read access is determined
	 * by the associated post. Update/delete is determined by the comment management tokens.
	 * @param User $user The user mask to fetch
	 * @return Bitmask
	 */
	public function get_access( $user = null )
	{
		if ( ! $user instanceof User ) {
			$user = User::identify();
		}

		// these tokens automatically grant full access to the comment
		if ( $user->can( 'super_user' ) || $user->can( 'manage_all_comments' ) ||
			( $user->id == $this->post->user_id && $user->can( 'manage_own_post_comments' ) ) ) {
			return ACL::get_bitmask( 'full' );
		}

		/* If we got this far, we can't update or delete a comment. We still need to check if we have
		 * read access to it. Collect a list of applicable tokens
		 */
		$tokens = array(
			'post_any',
			'post_' . Post::type_name( $this->post->content_type ),
		);

		if ( $user->id == $this->post->user_id ) {
			$tokens[] = 'own_posts';
		}

		$tokens = array_merge( $tokens, $this->post->get_tokens() );

		// grab the access masks on these tokens
		foreach ( $tokens as $token ) {
			$access = ACL::get_user_token_access( $user, $token );
			if ( $access instanceof Bitmask ) {
				$token_accesses[] = ACL::get_user_token_access( $user, $token )->value;
			}
		}

		// now that we have all the accesses, loop through them to build the access to the particular post
		if ( in_array( 0, $token_accesses ) ) {
			return ACL::get_bitmask( 0 );
		}

		if ( ACL::get_bitmask( Utils::array_or( $token_accesses ) )->read ) {
			return ACL::get_bitmask( 'read' );
		}

		// if we haven't returned by this point, we can neither manage the comment nor read it
		return ACL::get_bitmask( 0 );
	}

	/**
	 * Returns a URL for the ->editlink property of this class.
	 * @return string A url to edit this comment in the admin.
	 */
	private function get_editlink()
	{
		return URL::get( 'admin', "page=comment&id={$this->id}" );
	}

	/**
	 * Returns a list of CSS classes for the comment
	 *
	 * @param string|array $append Additional classes that should be added to the ones generated
 	 * @return string The resultant classes
	 */
	public function css_class ( $append = array() ) {

		$classes = $append;

		$classes[] = 'comment';
		$classes[] = 'comment-' . $this->id;
		$classes[] = 'type-' . $this->typename;
		$classes[] = 'status-' . $this->statusname;

		$classes[] = 'comment-post-' . $this->post->id;

		return implode( ' ', $classes );

	}

	/**
	 * How to display the built-in comment types.
	 *
	 * @param string $type The type of comment
	 * @param string $foruse Can be 'singular' or 'plural'
	 * @return string The translated type name. This is always lowercase.
	 *	It is up to the caller to uppercase it
	 */
	public static function filter_comment_type_display_4( $type, $foruse )
	{
		$names = array(
			'comment' => array(
				'singular' => _t( 'comment' ),
				'plural' => _t( 'comments' ),
			),
			'pingback' => array(
				'singular' => _t( 'pingback' ),
				'plural' => _t( 'pingbacks' ),
			),
			'trackback' => array(
				'singular' => _t( 'trackback' ),
				'plural' => _t( 'trackbacks' ),
			),
		);
		return isset( $names[$type][$foruse] ) ? $names[$type][$foruse] : $type;
	}

	/**
	 * How to display the built-in comment statuses.
	 *
	 * @param string The name of the status we want to translate
	 * @return string The translated status name. This is always lowercase.
	 *	It is up to the caller to uppercase it.
	 */
	public static function filter_comment_status_display_4( $status )
	{
		$names = array(
			'unapproved' => _t( 'unapproved' ),
			'approved' => _t( 'approved' ),
			'spam' => _t( 'spam' ),
		);
		return isset( $names[$status] ) ? $names[$status] : $status;
	}
}

?>


code:
<?php
/**
 * @package Habari
 *
 */

/**
 * Comment metadata
 */
class CommentInfo extends InfoRecords
{

	function __construct ( $comment_id = null )
	{
		parent::__construct( DB::table( 'commentinfo' ), 'comment_id', $comment_id ); // call parent with appropriate  parameters
	}

}

?>