code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * Lists by a user
 *
 * PHP version 5
 *
 * LICENCE: This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * @category  Personal
 * @package   StatusNet
 * @author    Shashi Gowda <connect2shashi@gmail.com>
 * @copyright 2008-2011 StatusNet, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link      http://status.net/
 */

if (!defined('STATUSNET') && !defined('LACONICA')) {
    exit(1);
}

require_once INSTALLDIR.'/lib/peopletaglist.php';

class PeopletagsbyuserAction extends Action
{
    var $page = null;
    var $tagger = null;
    var $tags = null;

    function isReadOnly($args)
    {
        return true;
    }

    function title()
    {
        if ($this->page == 1) {
            if ($this->isOwner()) {
                if ($this->arg('private')) {
                    // TRANS: Title for lists by a user page for a private tag.
                    return _('Private lists by you');
                } else if ($this->arg('public')) {
                    // TRANS: Title for lists by a user page for a public tag.
                    return _('Public lists by you');
                }
                // TRANS: Title for lists by a user page.
                return _('Lists by you');
            }
            // TRANS: Title for lists by a user page.
            // TRANS: %s is a user nickname.
            return sprintf(_('Lists by %s'), $this->tagger->nickname);
        } else {
            // TRANS: Title for lists by a user page.
            // TRANS: %1$s is a user nickname, %2$d is a page number.
            return sprintf(_('Lists by %1$s, page %2$d'), $this->tagger->nickname, $this->page);
        }
    }

    function prepare($args)
    {
        parent::prepare($args);

        if ($this->arg('public') && $this->arg('private')) {
            $this->args['public'] = $this->args['private'] = false;
        }

        if (common_config('singleuser', 'enabled')) {
            $nickname_arg = User::singleUserNickname();
        } else {
            $nickname_arg = $this->arg('nickname');
        }

        $nickname = common_canonical_nickname($nickname_arg);

        // Permanent redirect on non-canonical nickname

        if ($nickname_arg != $nickname) {
            $args = $this->getSelfUrlArgs();
            if ($this->arg('page') && $this->arg('page') != 1) {
                $args['page'] = $this->arg['page'];
            }
            common_redirect(common_local_url('peopletagsbyuser', $args), 301);
        }

        $this->user = User::getKV('nickname', $nickname);

        if (!$this->user) {
            // TRANS: Client error displayed trying to perform an action related to a non-existing user.
            $this->clientError(_('No such user.'), 404);
        }

        $this->tagger = $this->user->getProfile();

        if (!$this->tagger) {
            // TRANS: Error message displayed when referring to a user without a profile.
            $this->serverError(_('User has no profile.'));
        }

        $this->page = ($this->arg('page')) ? ($this->arg('page')+0) : 1;

        $offset = ($this->page-1) * PEOPLETAGS_PER_PAGE;
        $limit  = PEOPLETAGS_PER_PAGE + 1;

        $user = common_current_user();
        if ($this->arg('public')) {
            $this->tags = $this->tagger->getLists(false, $offset, $limit);
        } else if ($this->arg('private')) {
            if (empty($user)) {
                // TRANS: Error message displayed when trying to perform an action that requires a logged in user.
                $this->clientError(_('Not logged in.'), 403);
            }

            if ($this->isOwner()) {
                $this->tags = $this->tagger->getPrivateTags($offset, $limit);
            } else {
                // TRANS: Client error displayed when trying view another user's private lists.
                $this->clientError(_('You cannot view others\' private lists'), 403);
            }
        } else {
            $this->tags = $this->tagger->getLists(common_current_user(), $offset, $limit);
        }
        return true;
    }

    function handle($args)
    {
        parent::handle($args);

		# Post from the tag dropdown; redirect to a GET

		if ($_SERVER['REQUEST_METHOD'] == 'POST') {
		    common_redirect(common_local_url('peopletagsbyuser', $this->getSelfUrlArgs()), 303);
		}

        $this->showPage();
    }

    function showModeSelector()
    {
        $this->elementStart('dl', array('id'=>'filter_tags'));
        // TRANS: Mode selector label.
        $this->element('dt', null, _('Mode'));
        $this->elementStart('dd');
        $this->elementStart('ul');
        $this->elementStart('li', array('id' => 'filter_tags_for',
                                         'class' => 'child_1'));
        $this->element('a',
                       array('href' =>
                             common_local_url('peopletagsforuser',
                                              array('nickname' => $this->user->nickname))),
                       // TRANS: Link text to show lists for user %s.
                       sprintf(_('Lists for %s'), $this->tagger->nickname));
        $this->elementEnd('li');

        if ($this->isOwner()) {
            $this->elementStart('li', array('id'=>'filter_tags_item'));
            $this->elementStart('form', array('name' => 'modeselector',
                                               'id' => 'form_filter_bymode',
                                               'action' => common_local_url('peopletagsbyuser',
                                                    array('nickname' => $this->tagger->nickname)),
                                               'method' => 'post'));
            $this->elementStart('fieldset');
            // TRANS: Fieldset legend.
            $this->element('legend', null, _('Select tag to filter'));

            $priv = $this->arg('private');
            $pub  = $this->arg('public');

            if (!$priv && !$pub) {
                $priv = $pub = true;
            }
            // TRANS: Checkbox label to show private tags.
            $this->checkbox('private', _m('LABEL','Private'), $priv,
                                // TRANS: Checkbox title.
                                _('Show private tags.'));
            // TRANS: Checkbox label to show public tags.
            $this->checkbox('public', _m('LABEL','Public'), $pub,
                                // TRANS: Checkbox title.
                                _('Show public tags.'));
            $this->hidden('nickname', $this->user->nickname);
            // TRANS: Submit button text for tag filter form.
            $this->submit('submit', _m('BUTTON','Go'));
            $this->elementEnd('fieldset');
            $this->elementEnd('form');
            $this->elementEnd('li');
        }
        $this->elementEnd('ul');
        $this->elementEnd('dd');
        $this->elementEnd('dl');
    }

    function showAnonymousMessage()
    {
        $notice =
          // TRANS: Message displayed for anonymous users on page that displays lists by a user.
          // TRANS: This message contains Markdown links in the form [description](links).
          // TRANS: %s is a tagger nickname.
          sprintf(_('These are lists created by **%s**. ' .
                    'Lists are how you sort similar ' .
                    'people on %%%%site.name%%%%, a [micro-blogging]' .
                    '(http://en.wikipedia.org/wiki/Micro-blogging) service ' .
                    'based on the Free Software [StatusNet](http://status.net/) tool. ' .
                    'You can easily keep track of what they ' .
                    'are doing by subscribing to the list\'s timeline.' ), $this->tagger->nickname);
        $this->elementStart('div', array('id' => 'anon_notice'));
        $this->raw(common_markup_to_html($notice));
        $this->elementEnd('div');
    }

    function showPageNotice()
    {
        $this->elementStart('div', 'instructions');
        $this->showModeSelector();
        $this->elementEnd('div');
    }

    function showContent()
    {
        #TODO: controls here.

        $pl = new PeopletagList($this->tags, $this);
        $cnt = $pl->show();

        if ($cnt == 0) {
            $this->showEmptyListMessage();
        }
        $this->pagination($this->page > 1, $cnt > PEOPLETAGS_PER_PAGE,
                          $this->page, 'peopletagsbyuser', $this->getSelfUrlArgs());
    }

    function getSelfUrlArgs()
    {
        $args = array();
        if ($this->arg('private')) {
            $args['private'] = 1;
        } else if ($this->arg('public')) {
            $args['public'] = 1;
        }
        $args['nickname'] = $this->trimmed('nickname');

        return $args;
    }

    function isOwner()
    {
        $user = common_current_user();
        return !empty($user) && $user->id == $this->tagger->id;
    }

    function showObjectNav()
    {
        $nav = new PeopletagNav($this, $this->tagger);
        $nav->show();
    }

    function showEmptyListMessage()
    {
          // TRANS: Message displayed on page that displays lists by a user when there are none.
          // TRANS: This message contains Markdown links in the form [description](links).
          // TRANS: %s is a tagger nickname.
        $message = sprintf(_('%s has not created any [lists](%%%%doc.lists%%%%) yet.'), $this->tagger->nickname);
        $this->elementStart('div', 'guide');
        $this->raw(common_markup_to_html($message));
        $this->elementEnd('div');
    }

    function showProfileBlock()
    {
        $block = new AccountProfileBlock($this, $this->tagger);
        $block->show();
    }

    function showSections()
    {
        #TODO: tags with most subscribers
        #TODO: tags with most "members"
    }
}


code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * People tags for a user
 *
 * PHP version 5
 *
 * LICENCE: This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * @category  Personal
 * @package   StatusNet
 * @author    Shashi Gowda <connect2shashi@gmail.com>
 * @copyright 2008-2011 StatusNet, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link      http://status.net/
 */

if (!defined('STATUSNET') && !defined('LACONICA')) {
    exit(1);
}

require_once INSTALLDIR.'/lib/peopletaglist.php';

class PeopletagsforuserAction extends Action
{
    var $page = null;
    var $tagged = null;

    function isReadOnly($args)
    {
        return true;
    }

    function title()
    {
        if ($this->page == 1) {
            // TRANS: Page title. %s is a tagged user's nickname.
            return sprintf(_('Lists with %s in them'), $this->tagged->nickname);
        } else {
            // TRANS: Page title. %1$s is a tagged user's nickname, %2$s is a page number.
            return sprintf(_('Lists with %1$s, page %2$d'), $this->tagged->nickname, $this->page);
        }
    }

    function prepare($args)
    {
        parent::prepare($args);

        if (common_config('singleuser', 'enabled')) {
            $nickname_arg = User::singleUserNickname();
        } else {
            $nickname_arg = $this->arg('nickname');
        }

        $nickname = common_canonical_nickname($nickname_arg);

        // Permanent redirect on non-canonical nickname

        if ($nickname_arg != $nickname) {
            $args = array('nickname' => $nickname);
            if ($this->arg('page') && $this->arg('page') != 1) {
                $args['page'] = $this->arg['page'];
            }
            common_redirect(common_local_url('peopletagsforuser', $args), 301);
        }

        $this->user = User::getKV('nickname', $nickname);

        if (!$this->user) {
            // TRANS: Client error displayed trying to perform an action related to a non-existing user.
            $this->clientError(_('No such user.'), 404);
        }

        $this->tagged = $this->user->getProfile();

        if (!$this->tagged) {
            // TRANS: Error message displayed when referring to a user without a profile.
            $this->serverError(_('User has no profile.'));
        }

        $this->page = ($this->arg('page')) ? ($this->arg('page')+0) : 1;

        return true;
    }

    function handle($args)
    {
        parent::handle($args);
        $this->showPage();
    }

    function showAnonymousMessage()
    {
        $notice =
          // TRANS: Message displayed for anonymous users on page that displays lists for a user.
          // TRANS: This message contains Markdown links in the form [description](links).
          // TRANS: %s is a tagger nickname.
          sprintf(_('These are lists for **%s**. ' .
                    'lists are how you sort similar ' .
                    'people on %%%%site.name%%%%, a [micro-blogging]' .
                    '(http://en.wikipedia.org/wiki/Micro-blogging) service ' .
                    'based on the Free Software [StatusNet](http://status.net/) tool. ' .
                    'You can easily keep track of what they ' .
                    'are doing by subscribing to the list\'s timeline.' ), $this->tagged->nickname);
        $this->elementStart('div', array('id' => 'anon_notice'));
        $this->raw(common_markup_to_html($notice));
        $this->elementEnd('div');
    }

    function showContent()
    {
        #TODO: controls here.

        $offset = ($this->page-1) * PEOPLETAGS_PER_PAGE;
        $limit  = PEOPLETAGS_PER_PAGE + 1;

        $ptags = $this->tagged->getOtherTags(common_current_user(), $offset, $limit);

        $pl = new PeopletagList($ptags, $this);
        $cnt = $pl->show();

        if ($cnt == 0) {
            $this->showEmptyListMessage();
        }
        $this->pagination($this->page > 1, $cnt > PEOPLETAGS_PER_PAGE,
                          $this->page, 'peopletagsforuser', array('nickname' => $this->tagged->id));
    }

    function showEmptyListMessage()
    {
        // TRANS: Message displayed on page that displays lists a user was added to when there are none.
        // TRANS: This message contains Markdown links in the form [description](links).
        // TRANS: %s is a user nickname.
        $message = sprintf(_('%s has not been [listed](%%%%doc.lists%%%%) by anyone yet.'), $this->tagged->nickname);
        $this->elementStart('div', 'guide');
        $this->raw(common_markup_to_html($message));
        $this->elementEnd('div');
    }

    function showObjectNav()
    {
        $nav = new PeopletagNav($this, $this->tagged);
        $nav->show();
    }

    function showProfileBlock()
    {
        $block = new AccountProfileBlock($this, $this->tagged);
        $block->show();
    }

    function showSections()
    {
        #TODO: tags with most subscribers
        #TODO: tags with most "members"
    }
}

license: mit


code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * List of peopletag subscribers
 *
 * PHP version 5
 *
 * LICENCE: This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * @category  Group
 * @package   StatusNet
 * @author    Evan Prodromou <evan@status.net>
 * @copyright 2008-2011 StatusNet, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link      http://status.net/
 */

if (!defined('STATUSNET') && !defined('LACONICA')) {
    exit(1);
}

require_once(INSTALLDIR.'/lib/profilelist.php');

/**
 * List of peopletag subscribers
 *
 * @category Peopletag
 * @package  StatusNet
 * @author   Evan Prodromou <evan@status.net>
 * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link     http://status.net/
 */
class PeopletagsubscribersAction extends Action
{
    var $page = null;
    var $peopletag = null;
    var $tagger = null;

    function isReadOnly($args)
    {
        return true;
    }

    function prepare($args)
    {
        parent::prepare($args);
        $this->page = ($this->arg('page')) ? ($this->arg('page')+0) : 1;

        if (common_config('singleuser', 'enabled')) {
            $tagger_arg = User::singleUserNickname();
        } else {
            $tagger_arg = $this->arg('tagger');
        }

        $tag_arg = $this->arg('tag');
        $tagger = common_canonical_nickname($tagger_arg);
        $tag = common_canonical_tag($tag_arg);

        // Permanent redirect on non-canonical nickname

        if ($tagger_arg != $tagger || $tag_arg != $tag) {
            $args = array('tagger' => $nickname, 'tag' => $tag);
            if ($this->page != 1) {
                $args['page'] = $this->page;
            }
            common_redirect(common_local_url('peopletagged', $args), 301);
        }

        if (!$tagger) {
            // TRANS: Client error displayed when a tagger is expected but not provided.
            $this->clientError(_('No tagger.'), 404);
        }

        $user = User::getKV('nickname', $tagger);

        if (!$user) {
            // TRANS: Client error displayed trying to perform an action related to a non-existing user.
            $this->clientError(_('No such user.'), 404);
        }

        $this->tagger = $user->getProfile();
        $this->peopletag = Profile_list::pkeyGet(array('tagger' => $user->id, 'tag' => $tag));

        if (!$this->peopletag) {
            // TRANS: Client error displayed trying to reference a non-existing list.
            $this->clientError(_('No such list.'), 404);
        }

        return true;
    }

    function title()
    {
        if ($this->page == 1) {
            // TRANS: Page title for list of list subscribers.
            // TRANS: %1$s is a list, %2$s is a user nickname.
            return sprintf(_('Subscribers to list %1$s by %2$s'),
                           $this->peopletag->tag, $this->tagger->nickname);
        } else {
            // TRANS: Page title for list of list subscribers.
            // TRANS: %1$s is a list, %2$s is a user nickname, %3$d is a page number.
            return sprintf(_('Subscribers to list %1$s by %2$s, page %3$d'),
                           $this->peopletag->tag, $this->tagger->nickname,
                           $this->page);
        }
    }

    function handle($args)
    {
        parent::handle($args);
        $this->showPage();
    }

    function showPageNotice()
    {
    }

    function showLocalNav()
    {
        $nav = new PeopletagGroupNav($this);
        $nav->show();
    }

    function showContent()
    {
        $offset = ($this->page-1) * PROFILES_PER_PAGE;
        $limit =  PROFILES_PER_PAGE + 1;

        $cnt = 0;

        $subs = $this->peopletag->getSubscribers($offset, $limit);

        if ($subs) {
            $subscriber_list = new PeopletagSubscriberList($subs, $this->peopletag, $this);
            $cnt = $subscriber_list->show();
        }

        $subs->free();

        $this->pagination($this->page > 1, $cnt > PROFILES_PER_PAGE,
                          $this->page, 'peopletagsubscribers',
                          array('tagger' => $this->tagger->nickname,
                                'tag'    => $this->peopletag->tag));
    }
}

class PeopletagSubscriberList extends ProfileList
{
    var $peopletag = null;

    function __construct($profile, $peopletag, $action)
    {
        parent::__construct($profile, $action);

        $this->peopletag = $peopletag;
    }

    function newListItem($profile)
    {
        return new PeopletagSubscriberListItem($profile, $this->peopletag, $this->action);
    }
}

class PeopletagSubscriberListItem extends ProfileListItem
{
    var $peopletag = null;

    function __construct($profile, $peopletag, $action)
    {
        parent::__construct($profile, $action);

        $this->peopletag = $peopletag;
    }

    function showFullName()
    {
        parent::showFullName();
        if ($this->profile->id == $this->peopletag->tagger) {
            $this->out->text(' ');
            // TRANS: Addition in tag subscribers list for creator of a tag.
            $this->out->element('span', 'role', _('Creator'));
        }
    }

    function showActions()
    {
        $this->startActions();
        if (Event::handle('StartProfileListItemActionElements', array($this))) {
            $this->showSubscribeButton();
            Event::handle('EndProfileListItemActionElements', array($this));
        }
        $this->endActions();
    }

    function linkAttributes()
    {
        $aAttrs = parent::linkAttributes();

        if (common_config('nofollow', 'members')) {
            $aAttrs['rel'] .= ' nofollow';
        }

        return $aAttrs;
    }

    function homepageAttributes()
    {
        $aAttrs = parent::linkAttributes();

        if (common_config('nofollow', 'members')) {
            $aAttrs['rel'] = 'nofollow';
        }

        return $aAttrs;
    }

    /**
     * Fetch necessary return-to arguments for the profile forms
     * to return to this list when they're done.
     *
     * @return array
     */
    protected function returnToArgs()
    {
        $args = array('action' => 'peopletagsubscribers',
                      'tag' => $this->peopletag->tag,
                      'tagger' => $this->profile->nickname);
        $page = $this->out->arg('page');
        if ($page) {
            $args['param-page'] = $page;
        }
        return $args;
    }
}


code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * People tags subscribed to by a user
 *
 * PHP version 5
 *
 * LICENCE: This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * @category  Personal
 * @package   StatusNet
 * @author    Shashi Gowda <connect2shashi@gmail.com>
 * @copyright 2008-2011 StatusNet, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link      http://status.net/
 */

if (!defined('STATUSNET') && !defined('LACONICA')) {
    exit(1);
}

require_once INSTALLDIR.'/lib/peopletaglist.php';

class PeopletagsubscriptionsAction extends Action
{
    var $page = null;
    var $profile = null;

    function isReadOnly($args)
    {
        return true;
    }

    function title()
    {
        if ($this->page == 1) {
            // TRANS: Title for page that displays lists subscribed to by a user.
            // TRANS: %s is a profile nickname.
            return sprintf(_('Lists subscribed to by %s'), $this->profile->nickname);
        } else {
            // TRANS: Title for page that displays lists subscribed to by a user.
            // TRANS: %1$s is a profile nickname, %2$d is a page number.
            return sprintf(_('Lists subscribed to by %1$s, page %2$d'), $this->profile->nickname, $this->page);
        }
    }

    function prepare($args)
    {
        parent::prepare($args);

        if (common_config('singleuser', 'enabled')) {
            $nickname_arg = User::singleUserNickname();
        } else {
            $nickname_arg = $this->arg('nickname');
        }

        $nickname = common_canonical_nickname($nickname_arg);

        // Permanent redirect on non-canonical nickname

        if ($nickname_arg != $nickname) {
            $args = array('nickname' => $nickname);
            if ($this->arg('page') && $this->arg('page') != 1) {
                $args['page'] = $this->arg['page'];
            }
            common_redirect(common_local_url('peopletagsbyuser', $args), 301);
        }

        $user = User::getKV('nickname', $nickname);

        if (!$user) {
            // TRANS: Client error displayed trying to perform an action related to a non-existing user.
            $this->clientError(_('No such user.'), 404);
        }

        $this->profile = $user->getProfile();

        if (!$this->profile) {
            // TRANS: Error message displayed when referring to a user without a profile.
            $this->serverError(_('User has no profile.'));
        }

        $this->page = ($this->arg('page')) ? ($this->arg('page')+0) : 1;

        return true;
    }

    function handle($args)
    {
        parent::handle($args);
        $this->showPage();
    }

    function showAnonymousMessage()
    {
        $notice =
          // TRANS: Message displayed for anonymous users on page that displays lists subscribed to by a user.
          // TRANS: This message contains Markdown links in the form [description](links).
          // TRANS: %s is a profile nickname.
          sprintf(_('These are lists subscribed to by **%s**. ' .
                    'Lists are how you sort similar ' .
                    'people on %%%%site.name%%%%, a [micro-blogging]' .
                    '(http://en.wikipedia.org/wiki/Micro-blogging) service ' .
                    'based on the Free Software [StatusNet](http://status.net/) tool. ' .
                    'You can easily keep track of what they ' .
                    'are doing by subscribing to the list\'s timeline.' ), $this->profile->nickname);
        $this->elementStart('div', array('id' => 'anon_notice'));
        $this->raw(common_markup_to_html($notice));
        $this->elementEnd('div');
    }

    function showContent()
    {
        $offset = ($this->page-1) * PEOPLETAGS_PER_PAGE;
        $limit  = PEOPLETAGS_PER_PAGE + 1;

        $ptags = $this->profile->getTagSubscriptions($offset, $limit);

        $pl = new PeopletagList($ptags, $this);
        $cnt = $pl->show();

        $this->pagination($this->page > 1, $cnt > PEOPLETAGS_PER_PAGE,
                          $this->page, 'peopletagsubscriptions', array('nickname' => $this->profile->id));
    }

    function showObjectNav()
    {
        $nav = new PeopletagNav($this, $this->profile);
        $nav->show();
    }

    function showProfileBlock()
    {
        $block = new AccountProfileBlock($this, $this->profile);
        $block->show();
    }

    function showSections()
    {
        #TODO: tags with most subscribers
        #TODO: tags with most "members"
    }
}


code:
<?php
/**
 * StatusNet - the distributed open-source microblogging tool
 * Copyright (C) 2010, StatusNet, Inc.
 *
 * Plugin enable action.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * PHP version 5
 *
 * @category  Action
 * @package   StatusNet
 * @author    Brion Vibber <brion@status.net>
 * @copyright 2010 StatusNet, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPLv3
 * @link      http://status.net/
 */

if (!defined('STATUSNET')) {
    exit(1);
}

/**
 * Plugin enable action.
 *
 * (Re)-enables a plugin from the default plugins list.
 *
 * Takes parameters:
 *
 *    - plugin: plugin name
 *    - token: session token to prevent CSRF attacks
 *    - ajax: boolean; whether to return Ajax or full-browser results
 *
 * Only works if the current user is logged in.
 *
 * @category  Action
 * @package   StatusNet
 * @author    Brion Vibber <brion@status.net>
 * @copyright 2010 StatusNet, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPLv3
 * @link      http://status.net/
 */
class PluginDisableAction extends PluginEnableAction
{
    /**
     * Value to save into $config['plugins']['disable-<name>']
     */
    protected function overrideValue()
    {
        return 1;
    }

    protected function successShortTitle()
    {
        // TRANS: Page title for AJAX form return when a disabling a plugin.
        return _m('plugin', 'Disabled');
    }

    protected function successNextForm()
    {
        return new EnablePluginForm($this, $this->plugin);
    }
}


code:
<?php
/**
 * StatusNet - the distributed open-source microblogging tool
 * Copyright (C) 2010, StatusNet, Inc.
 *
 * Plugin enable action.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * PHP version 5
 *
 * @category  Action
 * @package   StatusNet
 * @author    Brion Vibber <brion@status.net>
 * @copyright 2010 StatusNet, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPLv3
 * @link      http://status.net/
 */

if (!defined('STATUSNET')) {
    exit(1);
}

/**
 * Plugin enable action.
 *
 * (Re)-enables a plugin from the default plugins list.
 *
 * Takes parameters:
 *
 *    - plugin: plugin name
 *    - token: session token to prevent CSRF attacks
 *    - ajax: boolean; whether to return Ajax or full-browser results
 *
 * Only works if the current user is logged in.
 *
 * @category  Action
 * @package   StatusNet
 * @author    Brion Vibber <brion@status.net>
 * @copyright 2010 StatusNet, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPLv3
 * @link      http://status.net/
 */
class PluginEnableAction extends Action
{
    var $user;
    var $plugin;

    /**
     * Check pre-requisites and instantiate attributes
     *
     * @param Array $args array of arguments (URL, GET, POST)
     *
     * @return boolean success flag
     */
    function prepare($args)
    {
        parent::prepare($args);

        // @fixme these are pretty common, should a parent class factor these out?

        // Only allow POST requests

        if ($_SERVER['REQUEST_METHOD'] != 'POST') {
            // TRANS: Client error displayed when trying to use another method than POST.
            // TRANS: Do not translate POST.
            $this->clientError(_('This action only accepts POST requests.'));
        }

        // CSRF protection

        $token = $this->trimmed('token');

        if (!$token || $token != common_session_token()) {
            // TRANS: Client error displayed when the session token does not match or is not given.
            $this->clientError(_('There was a problem with your session token.'.
                                 ' Try again, please.'));
        }

        // Only for logged-in users

        $this->user = common_current_user();

        if (empty($this->user)) {
            // TRANS: Error message displayed when trying to perform an action that requires a logged in user.
            $this->clientError(_('Not logged in.'));
        }

        if (!AdminPanelAction::canAdmin('plugins')) {
            // TRANS: Client error displayed when trying to enable or disable a plugin without access rights.
            $this->clientError(_('You cannot administer plugins.'));
        }

        $this->plugin = $this->arg('plugin');
        $defaultPlugins = common_config('plugins', 'default');
        if (!array_key_exists($this->plugin, $defaultPlugins)) {
            // TRANS: Client error displayed when trying to enable or disable a non-existing plugin.
            $this->clientError(_('No such plugin.'));
        }

        return true;
    }

    /**
     * Handle request
     *
     * Does the subscription and returns results.
     *
     * @param Array $args unused.
     *
     * @return void
     */
    function handle($args)
    {
        $key = 'disable-' . $this->plugin;
        Config::save('plugins', $key, $this->overrideValue());

        // @fixme this is a pretty common pattern and should be refactored down
        if ($this->boolean('ajax')) {
            $this->startHTML('text/xml;charset=utf-8');
            $this->elementStart('head');
            $this->element('title', null, $this->successShortTitle());
            $this->elementEnd('head');
            $this->elementStart('body');
            $form = $this->successNextForm();
            $form->show();
            $this->elementEnd('body');
            $this->endHTML();
        } else {
            $url = common_local_url('pluginsadminpanel');
            common_redirect($url, 303);
        }
    }

    /**
     * Value to save into $config['plugins']['disable-<name>']
     */
    protected function overrideValue()
    {
        return 0;
    }

    protected function successShortTitle()
    {
        // TRANS: Page title for AJAX form return when enabling a plugin.
        return _m('plugin', 'Enabled');
    }

    protected function successNextForm()
    {
        return new DisablePluginForm($this, $this->plugin);
    }
}


code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * Plugins administration panel
 *
 * PHP version 5
 *
 * LICENCE: This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * @category  Settings
 * @package   StatusNet
 * @author    Brion Vibber <brion@status.net>
 * @copyright 2010 StatusNet, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link      http://status.net/
 */

if (!defined('STATUSNET')) {
    exit(1);
}

/**
 * Plugins settings
 *
 * @category Admin
 * @package  StatusNet
 * @author   Brion Vibber <brion@status.net>
 * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link     http://status.net/
 */
class PluginsadminpanelAction extends AdminPanelAction
{
    /**
     * Returns the page title
     *
     * @return string page title
     */
    function title()
    {
        // TRANS: Tab and title for plugins admin panel.
        return _m('TITLE','Plugins');
    }

    /**
     * Instructions for using this form.
     *
     * @return string instructions
     */
    function getInstructions()
    {
        // TRANS: Instructions at top of plugin admin page.
        return _('Additional plugins can be enabled and configured manually. ' .
                 'See the online plugin ' .
                 'documentation for more details.');
    }

    /**
     * Show the plugins admin panel form
     *
     * @return void
     */
    function showForm()
    {
        $this->elementStart('fieldset', array('id' => 'settings_plugins_default'));

        // TRANS: Admin form section header
        $this->element('legend', null, _('Default plugins'), 'default');

        $this->showDefaultPlugins();

        $this->elementEnd('fieldset');
    }

    /**
     * Until we have a general plugin metadata infrastructure, for now
     * we'll just list up the ones we know from the global default
     * plugins list.
     */
    protected function showDefaultPlugins()
    {
        $plugins = array_keys(common_config('plugins', 'default'));
        natsort($plugins);

        if ($plugins) {
            $list = new PluginList($plugins, $this);
            $list->show();
        } else {
            $this->element('p', null,
                           // TRANS: Text displayed on plugin admin page when no plugin are enabled.
                           _('All default plugins have been disabled from the ' .
                             'site\'s configuration file.'));
        }
    }
}


code:
<?php
/**
 * StatusNet - the distributed open-source microblogging tool
 * Copyright (C) 2008-2010, StatusNet, Inc.
 *
 * Subscription action.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * PHP version 5
 *
 * @category  Action
 * @package   StatusNet
 * @author    Shashi Gowda <connect2shashi@gmail.com>
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPLv3
 * @link      http://status.net/
 */

if (!defined('STATUSNET')) {
    exit(1);
}

require_once INSTALLDIR . '/lib/peopletageditform.php';

/**
 * Subscription action
 *
 * Subscribing to a profile. Does not work for OMB 0.1 remote subscriptions,
 * but may work for other remote subscription protocols, like OStatus.
 *
 * Takes parameters:
 *
 *    - subscribeto: a profile ID
 *    - token: session token to prevent CSRF attacks
 *    - ajax: boolean; whether to return Ajax or full-browser results
 *
 * Only works if the current user is logged in.
 *
 * @category  Action
 * @package   StatusNet
 * @author    Shashi Gowda <connect2shashi@gmail.com>
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPLv3
 * @link      http://status.net/
 */

class ProfilecompletionAction extends Action
{
    var $user;
    var $peopletag;
    var $field;
    var $msg;

    /**
     * Check pre-requisites and instantiate attributes
     *
     * @param Array $args array of arguments (URL, GET, POST)
     *
     * @return boolean success flag
     */
    function prepare($args)
    {
        parent::prepare($args);

        // CSRF protection

        $token = $this->trimmed('token');

        if (!$token || $token != common_session_token()) {
            // TRANS: Client error displayed when the session token does not match or is not given.
            $this->clientError(_('There was a problem with your session token.'.
                                 ' Try again, please.'));
        }

        // Only for logged-in users

        $this->user = common_current_user();

        if (empty($this->user)) {
            // TRANS: Error message displayed when trying to perform an action that requires a logged in user.
            $this->clientError(_('Not logged in.'));
        }

        $id = $this->arg('peopletag_id');
        $this->peopletag = Profile_list::getKV('id', $id);

        if (empty($this->peopletag)) {
            // TRANS: Client error displayed trying to reference a non-existing list.
            $this->clientError(_('No such list.'));
        }

        $field = $this->arg('field');
        if (!in_array($field, array('fulltext', 'nickname', 'fullname', 'description', 'location', 'uri'))) {
            // TRANS: Client error displayed when trying to add an unindentified field to profile.
            // TRANS: %s is a field name.
            $this->clientError(sprintf(_('Unidentified field %s.'), htmlspecialchars($field)), 404);
        }
        $this->field = $field;

        return true;
    }

    /**
     * Handle request
     *
     * Does the subscription and returns results.
     *
     * @param Array $args unused.
     *
     * @return void
     */

    function handle($args)
    {
        $this->msg = null;

        $this->startHTML('text/xml;charset=utf-8');
        $this->elementStart('head');
        // TRANS: Page title.
        $this->element('title', null, _m('TITLE','Search results'));
        $this->elementEnd('head');
        $this->elementStart('body');
        $profiles = $this->getResults();

        if ($this->msg !== null) {
            $this->element('p', 'error', $this->msg);
        } else {
            if (count($profiles) > 0) {
                $this->elementStart('ul', array('id' => 'profile_search_results', 'class' => 'profile-lister'));
                foreach ($profiles as $profile) {
                    $this->showProfileItem($profile);
                }
                $this->elementEnd('ul');
            } else {
                // TRANS: Output when there are no results for a search.
                $this->element('p', 'error', _('No results.'));
            }
        }
        $this->elementEnd('body');
        $this->endHTML();
    }

    function getResults()
    {
        $profiles = array();
        $q = $this->arg('q');
        $q = strtolower($q);
        if (strlen($q) < 3) {
            // TRANS: Error message in case a search is shorter than three characters.
            $this->msg = _('The search string must be at least 3 characters long.');
        }
        $page = $this->arg('page');
        $page = (int) (empty($page) ? 1 : $page);

        $profile = new Profile();
        $search_engine = $profile->getSearchEngine('profile');

        if (Event::handle('StartProfileCompletionSearch', array($this, &$profile, $search_engine))) {
            $search_engine->set_sort_mode('chron');
            $search_engine->limit((($page-1)*PROFILES_PER_PAGE), PROFILES_PER_PAGE + 1);

            if (false === $search_engine->query($q)) {
                $cnt = 0;
            }
            else {
                $cnt = $profile->find();
            }
            Event::handle('EndProfileCompletionSearch', array($this, &$profile, $search_engine));
        }

        while ($profile->fetch()) {
            $profiles[] = clone($profile);
        }
        return $this->filter($profiles);
    }

    function filter($profiles)
    {
        $current = $this->user->getProfile();
        $filtered_profiles = array();
        foreach ($profiles as $profile) {
            if ($current->canTag($profile)) {
                $filtered_profiles[] = $profile;
            }
        }
        return $filtered_profiles;
    }

    function showProfileItem($profile)
    {
        $this->elementStart('li', 'entity_removable_profile');
        $item = new TaggedProfileItem($this, $profile);
        $item->show();
        $this->elementStart('span', 'entity_actions');

        if ($profile->isTagged($this->peopletag)) {
            $untag = new UntagButton($this, $profile, $this->peopletag);
            $untag->show();
        } else {
            $tag = new TagButton($this, $profile, $this->peopletag);
            $tag->show();
        }

        $this->elementEnd('span');
        $this->elementEnd('li');
    }
}


code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * Change profile settings
 *
 * PHP version 5
 *
 * LICENCE: This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * @category  Settings
 * @package   StatusNet
 * @author    Evan Prodromou <evan@status.net>
 * @author    Zach Copley <zach@status.net>
 * @author    Sarven Capadisli <csarven@status.net>
 * @copyright 2008-2009 StatusNet, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link      http://status.net/
 */

if (!defined('GNUSOCIAL')) { exit(1); }

/**
 * Change profile settings
 *
 * @category Settings
 * @package  StatusNet
 * @author   Evan Prodromou <evan@status.net>
 * @author   Zach Copley <zach@status.net>
 * @author   Sarven Capadisli <csarven@status.net>
 * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link     http://status.net/
 */
class ProfilesettingsAction extends SettingsAction
{
    /**
     * Title of the page
     *
     * @return string Title of the page
     */
    function title()
    {
        // TRANS: Page title for profile settings.
        return _('Profile settings');
    }

    /**
     * Instructions for use
     *
     * @return instructions for use
     */
    function getInstructions()
    {
        // TRANS: Usage instructions for profile settings.
        return _('You can update your personal profile info here '.
                 'so people know more about you.');
    }

    function showScripts()
    {
        parent::showScripts();
        $this->autofocus('fullname');
    }

    /**
     * Content area of the page
     *
     * Shows a form for uploading an avatar.
     *
     * @return void
     */
    function showContent()
    {
        $user = common_current_user();
        $profile = $user->getProfile();

        $this->elementStart('form', array('method' => 'post',
                                          'id' => 'form_settings_profile',
                                          'class' => 'form_settings',
                                          'action' => common_local_url('profilesettings')));
        $this->elementStart('fieldset');
        // TRANS: Profile settings form legend.
        $this->element('legend', null, _('Profile information'));
        $this->hidden('token', common_session_token());

        // too much common patterns here... abstractable?
        $this->elementStart('ul', 'form_data');
        if (Event::handle('StartProfileFormData', array($this))) {
            $this->elementStart('li');
            // TRANS: Field label in form for profile settings.
            $this->input('nickname', _('Nickname'),
                         $this->arg('nickname') ?: $profile->nickname,
                         // TRANS: Tooltip for field label in form for profile settings.
                         _('1-64 lowercase letters or numbers, no punctuation or spaces.'),
                         null, false,   // "name" (will be set to id), then "required"
                         !common_config('profile', 'changenick') ? array('disabled'=>'disabled') : array());
            $this->elementEnd('li');
            $this->elementStart('li');
            // TRANS: Field label in form for profile settings.
            $this->input('fullname', _('Full name'),
                         ($this->arg('fullname')) ? $this->arg('fullname') : $profile->fullname);
            $this->elementEnd('li');
            $this->elementStart('li');
            // TRANS: Field label in form for profile settings.
            $this->input('homepage', _('Homepage'),
                         ($this->arg('homepage')) ? $this->arg('homepage') : $profile->homepage,
                         // TRANS: Tooltip for field label in form for profile settings.
                         _('URL of your homepage, blog, or profile on another site.'));
            $this->elementEnd('li');
            $this->elementStart('li');
            $maxBio = Profile::maxBio();
            if ($maxBio > 0) {
                // TRANS: Tooltip for field label in form for profile settings. Plural
                // TRANS: is decided by the number of characters available for the
                // TRANS: biography (%d).
                $bioInstr = sprintf(_m('Describe yourself and your interests in %d character.',
                                       'Describe yourself and your interests in %d characters.',
                                       $maxBio),
                                    $maxBio);
            } else {
                // TRANS: Tooltip for field label in form for profile settings.
                $bioInstr = _('Describe yourself and your interests.');
            }
            // TRANS: Text area label in form for profile settings where users can provide
            // TRANS: their biography.
            $this->textarea('bio', _('Bio'),
                            ($this->arg('bio')) ? $this->arg('bio') : $profile->bio,
                            $bioInstr);
            $this->elementEnd('li');
            $this->elementStart('li');
            // TRANS: Field label in form for profile settings.
            $this->input('location', _('Location'),
                         ($this->arg('location')) ? $this->arg('location') : $profile->location,
                         // TRANS: Tooltip for field label in form for profile settings.
                         _('Where you are, like "City, State (or Region), Country".'));
            $this->elementEnd('li');
            if (common_config('location', 'share') == 'user') {
                $this->elementStart('li');
                // TRANS: Checkbox label in form for profile settings.
                $this->checkbox('sharelocation', _('Share my current location when posting notices'),
                                ($this->arg('sharelocation')) ?
                                $this->arg('sharelocation') : $this->scoped->shareLocation());
                $this->elementEnd('li');
            }
            Event::handle('EndProfileFormData', array($this));
            $this->elementStart('li');
            // TRANS: Field label in form for profile settings.
            $this->input('tags', _('Tags'),
                         ($this->arg('tags')) ? $this->arg('tags') : implode(' ', $user->getSelfTags()),
                         // TRANS: Tooltip for field label in form for profile settings.
                         _('Tags for yourself (letters, numbers, -, ., and _), comma- or space- separated.'));
            $this->elementEnd('li');
            $this->elementStart('li');
            $language = common_language();
            // TRANS: Dropdownlist label in form for profile settings.
            $this->dropdown('language', _('Language'),
                         // TRANS: Tooltip for dropdown list label in form for profile settings.
                            get_nice_language_list(), _('Preferred language.'),
                            false, $language);
            $this->elementEnd('li');
            $timezone = common_timezone();
            $timezones = array();
            foreach(DateTimeZone::listIdentifiers() as $k => $v) {
                $timezones[$v] = $v;
            }
            $this->elementStart('li');
            // TRANS: Dropdownlist label in form for profile settings.
            $this->dropdown('timezone', _('Timezone'),
                         // TRANS: Tooltip for dropdown list label in form for profile settings.
                            $timezones, _('What timezone are you normally in?'),
                            true, $timezone);
            $this->elementEnd('li');
            $this->elementStart('li');
            $this->checkbox('autosubscribe',
                            // TRANS: Checkbox label in form for profile settings.
                            _('Automatically subscribe to whoever '.
                              'subscribes to me (best for non-humans)'),
                            ($this->arg('autosubscribe')) ?
                            $this->boolean('autosubscribe') : $user->autosubscribe);
            $this->elementEnd('li');
            $this->elementStart('li');
            $this->dropdown('subscribe_policy',
                            // TRANS: Dropdown field label on profile settings, for what policies to apply when someone else tries to subscribe to your updates.
                            _('Subscription policy'),
                            // TRANS: Dropdown field option for following policy.
                            array(User::SUBSCRIBE_POLICY_OPEN     => _('Let anyone follow me'),
                                  // TRANS: Dropdown field option for following policy.
                                  User::SUBSCRIBE_POLICY_MODERATE => _('Ask me first')),
                            // TRANS: Dropdown field title on group edit form.
                            _('Whether other users need your permission to follow your updates.'),
                            false,
                            (empty($user->subscribe_policy)) ? User::SUBSCRIBE_POLICY_OPEN : $user->subscribe_policy);
            $this->elementEnd('li');
        }
        $this->elementStart('li');
        $this->checkbox('private_stream',
                        // TRANS: Checkbox label in profile settings.
                        _('Make updates visible only to my followers'),
                        ($this->arg('private_stream')) ?
                        $this->boolean('private_stream') : $user->private_stream);
        $this->elementEnd('li');
        $this->elementEnd('ul');
        // TRANS: Button to save input in profile settings.
        $this->submit('save', _m('BUTTON','Save'));

        $this->elementEnd('fieldset');
        $this->elementEnd('form');
    }

    /**
     * Handle a post
     *
     * Validate input and save changes. Reload the form with a success
     * or error message.
     *
     * @return void
     */
    function handlePost()
    {
        // CSRF protection
        $token = $this->trimmed('token');
        if (!$token || $token != common_session_token()) {
            // TRANS: Form validation error.
            $this->showForm(_('There was a problem with your session token. '.
                              'Try again, please.'));
            return;
        }

        if (Event::handle('StartProfileSaveForm', array($this))) {

            // $nickname will only be set if this changenick value is true.
            if (common_config('profile', 'changenick') == true) {
                try {
                    $nickname = Nickname::normalize($this->trimmed('nickname'), true);
                } catch (NicknameTakenException $e) {
                    // Abort only if the nickname is occupied by another local profile
                    if ($e->profile->id != $this->scoped->id) {
                        $this->showForm($e->getMessage());
                        return;
                    }
                    $nickname = Nickname::normalize($this->trimmed('nickname')); // without in-use check this time
                } catch (NicknameException $e) {
                    $this->showForm($e->getMessage());
                    return;
                }
            }

            $fullname = $this->trimmed('fullname');
            $homepage = $this->trimmed('homepage');
            $bio = $this->trimmed('bio');
            $location = $this->trimmed('location');
            $autosubscribe = $this->boolean('autosubscribe');
            $subscribe_policy = $this->trimmed('subscribe_policy');
            $private_stream = $this->boolean('private_stream');
            $language = $this->trimmed('language');
            $timezone = $this->trimmed('timezone');
            $tagstring = $this->trimmed('tags');

            // Some validation
            if (!is_null($homepage) && (strlen($homepage) > 0) &&
                       !common_valid_http_url($homepage)) {
                // TRANS: Validation error in form for profile settings.
                $this->showForm(_('Homepage is not a valid URL.'));
                return;
            } else if (!is_null($fullname) && mb_strlen($fullname) > 255) {
                // TRANS: Validation error in form for profile settings.
                $this->showForm(_('Full name is too long (maximum 255 characters).'));
                return;
            } else if (Profile::bioTooLong($bio)) {
                // TRANS: Validation error in form for profile settings.
                // TRANS: Plural form is used based on the maximum number of allowed
                // TRANS: characters for the biography (%d).
                $this->showForm(sprintf(_m('Bio is too long (maximum %d character).',
                                           'Bio is too long (maximum %d characters).',
                                           Profile::maxBio()),
                                        Profile::maxBio()));
                return;
            } else if (!is_null($location) && mb_strlen($location) > 255) {
                // TRANS: Validation error in form for profile settings.
                $this->showForm(_('Location is too long (maximum 255 characters).'));
                return;
            }  else if (is_null($timezone) || !in_array($timezone, DateTimeZone::listIdentifiers())) {
                // TRANS: Validation error in form for profile settings.
                $this->showForm(_('Timezone not selected.'));
                return;
            } else if (!is_null($language) && strlen($language) > 50) {
                // TRANS: Validation error in form for profile settings.
                $this->showForm(_('Language is too long (maximum 50 characters).'));
                return;
            }

            $tags = array();
            $tag_priv = array();
            if (is_string($tagstring) && strlen($tagstring) > 0) {

                $tags = preg_split('/[\s,]+/', $tagstring);

                foreach ($tags as &$tag) {
                    $private = @$tag[0] === '.';

                    $tag = common_canonical_tag($tag);
                    if (!common_valid_profile_tag($tag)) {
                        // TRANS: Validation error in form for profile settings.
                        // TRANS: %s is an invalid tag.
                        $this->showForm(sprintf(_('Invalid tag: "%s".'), $tag));
                        return;
                    }

                    $tag_priv[$tag] = $private;
                }
            }

            $user = common_current_user();
            $user->query('BEGIN');

            // $user->nickname is updated through Profile->update();

            // XXX: XOR
            if (($user->autosubscribe ^ $autosubscribe)
                    || ($user->private_stream ^ $private_stream)
                    || $user->timezone != $timezone
                    || $user->language != $language
                    || $user->subscribe_policy != $subscribe_policy) {

                $original = clone($user);

                $user->autosubscribe    = $autosubscribe;
                $user->language         = $language;
                $user->private_stream   = $private_stream;
                $user->subscribe_policy = $subscribe_policy;
                $user->timezone         = $timezone;

                $result = $user->update($original);
                if ($result === false) {
                    common_log_db_error($user, 'UPDATE', __FILE__);
                    // TRANS: Server error thrown when user profile settings could not be updated to
                    // TRANS: automatically subscribe to any subscriber.
                    $this->serverError(_('Could not update user for autosubscribe or subscribe_policy.'));
                }

                // Re-initialize language environment if it changed
                common_init_language();
            }

            $profile = $user->getProfile();

            $orig_profile = clone($profile);

            if (common_config('profile', 'changenick') == true && $profile->nickname !== $nickname) {
                assert(Nickname::normalize($nickname)===$nickname);
                common_debug("Changing user nickname from '{$profile->nickname}' to '{$nickname}'.");
                $profile->nickname = $nickname;
                $profile->profileurl = common_profile_url($profile->nickname);
            }
            $profile->fullname = $fullname;
            $profile->homepage = $homepage;
            $profile->bio = $bio;
            $profile->location = $location;

            $loc = Location::fromName($location);

            if (empty($loc)) {
                $profile->lat         = null;
                $profile->lon         = null;
                $profile->location_id = null;
                $profile->location_ns = null;
            } else {
                $profile->lat         = $loc->lat;
                $profile->lon         = $loc->lon;
                $profile->location_id = $loc->location_id;
                $profile->location_ns = $loc->location_ns;
            }

            if (common_config('location', 'share') == 'user') {

                $exists = false;

                $prefs = User_location_prefs::getKV('user_id', $user->id);

                if (empty($prefs)) {
                    $prefs = new User_location_prefs();

                    $prefs->user_id = $user->id;
                    $prefs->created = common_sql_now();
                } else {
                    $exists = true;
                    $orig = clone($prefs);
                }

                $prefs->share_location = $this->boolean('sharelocation');

                if ($exists) {
                    $result = $prefs->update($orig);
                } else {
                    $result = $prefs->insert();
                }

                if ($result === false) {
                    common_log_db_error($prefs, ($exists) ? 'UPDATE' : 'INSERT', __FILE__);
                    // TRANS: Server error thrown when user profile location preference settings could not be updated.
                    $this->serverError(_('Could not save location prefs.'));
                }
            }

            common_debug('Old profile: ' . common_log_objstring($orig_profile), __FILE__);
            common_debug('New profile: ' . common_log_objstring($profile), __FILE__);

            $result = $profile->update($orig_profile);

            if ($result === false) {
                common_log_db_error($profile, 'UPDATE', __FILE__);
                // TRANS: Server error thrown when user profile settings could not be saved.
                $this->serverError(_('Could not save profile.'));
            }

            // Set the user tags
            $result = $user->setSelfTags($tags, $tag_priv);

            if (!$result) {
                // TRANS: Server error thrown when user profile settings tags could not be saved.
                $this->serverError(_('Could not save tags.'));
            }

            $user->query('COMMIT');
            Event::handle('EndProfileSaveForm', array($this));

            // TRANS: Confirmation shown when user profile settings are saved.
            $this->showForm(_('Settings saved.'), true);

        }
    }

    function showAside() {
        $user = common_current_user();

        $this->elementStart('div', array('id' => 'aside_primary',
                                         'class' => 'aside'));

        $this->elementStart('div', array('id' => 'account_actions',
                                         'class' => 'section'));
        $this->elementStart('ul');
        if (Event::handle('StartProfileSettingsActions', array($this))) {
            if ($user->hasRight(Right::BACKUPACCOUNT)) {
                $this->elementStart('li');
                $this->element('a',
                               array('href' => common_local_url('backupaccount')),
                               // TRANS: Option in profile settings to create a backup of the account of the currently logged in user.
                               _('Backup account'));
                $this->elementEnd('li');
            }
            if ($user->hasRight(Right::DELETEACCOUNT)) {
                $this->elementStart('li');
                $this->element('a',
                               array('href' => common_local_url('deleteaccount')),
                               // TRANS: Option in profile settings to delete the account of the currently logged in user.
                               _('Delete account'));
                $this->elementEnd('li');
            }
            if ($user->hasRight(Right::RESTOREACCOUNT)) {
                $this->elementStart('li');
                $this->element('a',
                               array('href' => common_local_url('restoreaccount')),
                               // TRANS: Option in profile settings to restore the account of the currently logged in user from a backup.
                               _('Restore account'));
                $this->elementEnd('li');
            }
            Event::handle('EndProfileSettingsActions', array($this));
        }
        $this->elementEnd('ul');
        $this->elementEnd('div');
        $this->elementEnd('div');
    }
}


code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * Permalink for a peopletag
 *
 * PHP version 5
 *
 * LICENCE: This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * @category  Peopletag
 * @package   StatusNet
 * @author    Shashi Gowda <connect2shashi@gmail.com>
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link      http://status.net/
 */

if (!defined('STATUSNET') && !defined('LACONICA')) {
    exit(1);
}

class ProfiletagbyidAction extends Action
{
    /** peopletag we're viewing. */
    var $peopletag = null;

    /**
     * Is this page read-only?
     *
     * @return boolean true
     */
    function isReadOnly($args)
    {
        return true;
    }

    function prepare($args)
    {
        parent::prepare($args);

        $id = $this->arg('id');
        $tagger_id = $this->arg('tagger_id');

        if (!$id) {
            // TRANS: Client error displayed trying to perform an action without providing an ID.
            $this->clientError(_('No ID.'));
        }

        common_debug("Peopletag id $id by user id $tagger_id");

        $this->peopletag = Profile_list::getKV('id', $id);

        if (!$this->peopletag) {
            // TRANS: Client error displayed trying to reference a non-existing list.
            $this->clientError(_('No such list.'), 404);
        }

        $user = User::getKV('id', $tagger_id);
        if (!$user) {
            // remote peopletag, permanently redirect
            common_redirect($this->peopletag->permalink(), 301);
        }

        return true;
    }

    /**
     * Handle the request
     *
     * Shows a profile for the group, some controls, and a list of
     * group notices.
     *
     * @return void
     */
    function handle($args)
    {
        common_redirect($this->peopletag->homeUrl(), 303);
    }
}


code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * Action for displaying the public stream
 *
 * PHP version 5
 *
 * LICENCE: This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * @category  Public
 * @package   StatusNet
 * @author    Evan Prodromou <evan@status.net>
 * @copyright 2008-2009 StatusNet, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link      http://status.net/
 */

if (!defined('GNUSOCIAL')) { exit(1); }

// Farther than any human will go

define('MAX_PUBLIC_PAGE', 100);

/**
 * Action for displaying the public stream
 *
 * @category Public
 * @package  StatusNet
 * @author   Evan Prodromou <evan@status.net>
 * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link     http://status.net/
 *
 * @see      PublicrssAction
 * @see      PublicxrdsAction
 */
class PublicAction extends ManagedAction
{
    /**
     * page of the stream we're on; default = 1
     */

    var $page = null;
    var $notice;

    protected $stream = null;

    function isReadOnly($args)
    {
        return true;
    }

    protected function doPreparation()
    {
        $this->page = ($this->arg('page')) ? ($this->arg('page')+0) : 1;

        if ($this->page > MAX_PUBLIC_PAGE) {
            // TRANS: Client error displayed when requesting a public timeline page beyond the page limit.
            // TRANS: %s is the page limit.
            $this->clientError(sprintf(_('Beyond the page limit (%s).'), MAX_PUBLIC_PAGE));
        }

        common_set_returnto($this->selfUrl());

        $this->streamPrepare();

        $this->notice = $this->stream->getNotices(($this->page-1)*NOTICES_PER_PAGE,
                                            NOTICES_PER_PAGE + 1);

        if (!$this->notice) {
            // TRANS: Server error displayed when a public timeline cannot be retrieved.
            $this->serverError(_('Could not retrieve public timeline.'));
        }

        if ($this->page > 1 && $this->notice->N == 0){
            // TRANS: Client error when page not found (404).
            $this->clientError(_('No such page.'), 404);
        }

        return true;
    }

    protected function streamPrepare()
    {
        if ($this->scoped instanceof Profile && $this->scoped->isLocal() && $this->scoped->getUser()->streamModeOnly()) {
            $this->stream = new PublicNoticeStream($this->scoped);
        } else {
            $this->stream = new ThreadingPublicNoticeStream($this->scoped);
        }
    }

    /**
     * Title of the page
     *
     * @return page title, including page number if over 1
     */
    function title()
    {
        if ($this->page > 1) {
            // TRANS: Title for all public timeline pages but the first.
            // TRANS: %d is the page number.
            return sprintf(_('Public timeline, page %d'), $this->page);
        } else {
            // TRANS: Title for the first public timeline page.
            return _('Public timeline');
        }
    }

    function extraHead()
    {
        parent::extraHead();
        $this->element('meta', array('http-equiv' => 'X-XRDS-Location',
                                           'content' => common_local_url('publicxrds')));

        $rsd = common_local_url('rsd');

        // RSD, http://tales.phrasewise.com/rfc/rsd

        $this->element('link', array('rel' => 'EditURI',
                                     'type' => 'application/rsd+xml',
                                     'href' => $rsd));

        if ($this->page != 1) {
            $this->element('link', array('rel' => 'canonical',
                                         'href' => common_local_url('public')));
        }
    }

    /**
     * Output <head> elements for RSS and Atom feeds
     *
     * @return void
     */
    function getFeeds()
    {
        return array(new Feed(Feed::JSON,
                              common_local_url('ApiTimelinePublic',
                                               array('format' => 'as')),
                              // TRANS: Link description for public timeline feed.
                              _('Public Timeline Feed (Activity Streams JSON)')),
                    new Feed(Feed::RSS1, common_local_url('publicrss'),
                              // TRANS: Link description for public timeline feed.
                              _('Public Timeline Feed (RSS 1.0)')),
                     new Feed(Feed::RSS2,
                              common_local_url('ApiTimelinePublic',
                                               array('format' => 'rss')),
                              // TRANS: Link description for public timeline feed.
                              _('Public Timeline Feed (RSS 2.0)')),
                     new Feed(Feed::ATOM,
                              common_local_url('ApiTimelinePublic',
                                               array('format' => 'atom')),
                              // TRANS: Link description for public timeline feed.
                              _('Public Timeline Feed (Atom)')));
    }

    function showEmptyList()
    {
        // TRANS: Text displayed for public feed when there are no public notices.
        $message = _('This is the public timeline for %%site.name%% but no one has posted anything yet.') . ' ';

        if (common_logged_in()) {
            // TRANS: Additional text displayed for public feed when there are no public notices for a logged in user.
            $message .= _('Be the first to post!');
        }
        else {
            if (! (common_config('site','closed') || common_config('site','inviteonly'))) {
                // TRANS: Additional text displayed for public feed when there are no public notices for a not logged in user.
                $message .= _('Why not [register an account](%%action.register%%) and be the first to post!');
            }
        }

        $this->elementStart('div', 'guide');
        $this->raw(common_markup_to_html($message));
        $this->elementEnd('div');
    }

    /**
     * Fill the content area
     *
     * Shows a list of the notices in the public stream, with some pagination
     * controls.
     *
     * @return void
     */
    function showContent()
    {
        if ($this->scoped instanceof Profile && $this->scoped->isLocal() && $this->scoped->getUser()->streamModeOnly()) {
            $nl = new PrimaryNoticeList($this->notice, $this, array('show_n'=>NOTICES_PER_PAGE));
        } else {
            $nl = new ThreadedNoticeList($this->notice, $this, $this->scoped);
        }

        $cnt = $nl->show();

        if ($cnt == 0) {
            $this->showEmptyList();
        }

        $this->pagination($this->page > 1, $cnt > NOTICES_PER_PAGE,
                          $this->page, $this->action);
    }

    function showSections()
    {
        // Show invite button, as long as site isn't closed, and
        // we have a logged in user.
        if (common_config('invite', 'enabled') && !common_config('site', 'closed') && common_logged_in()) {
            if (!common_config('site', 'private')) {
                $ibs = new InviteButtonSection(
                    $this,
                    // TRANS: Button text for inviting more users to the StatusNet instance.
                    // TRANS: Less business/enterprise-oriented language for public sites.
                    _m('BUTTON', 'Send invite')
                );
            } else {
                $ibs = new InviteButtonSection($this);
            }
            $ibs->show();
        }

        $p = Profile::current();

        if (!common_config('performance', 'high')) {
            $cloud = new PublicTagCloudSection($this);
            $cloud->show();
        }
        $feat = new FeaturedUsersSection($this);
        $feat->show();
    }

    function showAnonymousMessage()
    {
        if (! (common_config('site','closed') || common_config('site','inviteonly'))) {
            // TRANS: Message for not logged in users at an invite-only site trying to view the public feed of notices.
            // TRANS: This message contains Markdown links. Please mind the formatting.
            $m = _('This is %%site.name%%, a [micro-blogging](http://en.wikipedia.org/wiki/Micro-blogging) service ' .
                   'based on the Free Software [StatusNet](http://status.net/) tool. ' .
                   '[Join now](%%action.register%%) to share notices about yourself with friends, family, and colleagues! ' .
                   '([Read more](%%doc.help%%))');
        } else {
            // TRANS: Message for not logged in users at a closed site trying to view the public feed of notices.
            // TRANS: This message contains Markdown links. Please mind the formatting.
            $m = _('This is %%site.name%%, a [micro-blogging](http://en.wikipedia.org/wiki/Micro-blogging) service ' .
                   'based on the Free Software [StatusNet](http://status.net/) tool.');
        }
        $this->elementStart('div', array('id' => 'anon_notice'));
        $this->raw(common_markup_to_html($m));
        $this->elementEnd('div');
    }
}


code:
<?php
/**
 * Public RSS action class.
 *
 * PHP version 5
 *
 * @category Action
 * @package  StatusNet
 * @author   Evan Prodromou <evan@status.net>
 * @author   Robin Millette <millette@status.net>
 * @license  http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
 * @link     http://status.net/
 *
 * StatusNet - the distributed open-source microblogging tool
 * Copyright (C) 2008, 2009, StatusNet, Inc.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

if (!defined('STATUSNET') && !defined('LACONICA')) {
    exit(1);
}

require_once INSTALLDIR.'/lib/rssaction.php';

/**
 * RSS feed for public timeline.
 *
 * Formatting of RSS handled by Rss10Action
 *
 * @category Action
 * @package  StatusNet
 * @author   Evan Prodromou <evan@status.net>
 * @author   Robin Millette <millette@status.net>
 * @license  http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
 * @link     http://status.net/
 */
class PublicrssAction extends Rss10Action
{
    /**
     * Read arguments and initialize members
     *
     * @param array $args Arguments from $_REQUEST
     * @return boolean success
     */
    function prepare($args)
    {
        parent::prepare($args);
        $this->notices = $this->getNotices($this->limit);
        return true;
    }

    /**
     * Initialization.
     *
     * @return boolean true
     */
    function init()
    {
        return true;
    }

    /**
     * Get notices
     *
     * @param integer $limit max number of notices to return
     *
     * @return array notices
     */
    function getNotices($limit=0)
    {
        $notices = array();
        $notice  = Notice::publicStream(0, ($limit == 0) ? 48 : $limit);
        while ($notice->fetch()) {
            $notices[] = clone($notice);
        }

        return $notices;
    }

     /**
     * Get channel.
     *
     * @return array associative array on channel information
     */
    function getChannel()
    {
        $sitename = common_config('site', 'name');
        $c = array(
              'url' => common_local_url('publicrss'),
            // TRANS: Public RSS feed title. %s is the StatusNet site name.
              'title' => sprintf(_('%s public timeline'), $sitename),
              'link' => common_local_url('public'),
            // TRANS: Public RSS feed description. %s is the StatusNet site name.
              'description' => sprintf(_('%s updates from everyone.'), $sitename));
        return $c;
    }

    /**
     * Get image.
     *
     * @return nothing
     */
    function getImage()
    {
        // nop
    }

    function isReadOnly($args)
    {
        return true;
    }
}


code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * Public tag cloud for notices
 *
 * PHP version 5
 *
 * LICENCE: This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * @category  Public
 * @package   StatusNet
 * @author    Mike Cochrane <mikec@mikenz.geek.nz>
 * @author    Evan Prodromou <evan@status.net>
 * @copyright 2008 Mike Cochrane
 * @copyright 2008-2009 StatusNet, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link      http://status.net/
 */

if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }

define('TAGS_PER_PAGE', 100);

/**
 * Public tag cloud for notices
 *
 * @category Personal
 * @package  StatusNet
 * @author    Mike Cochrane <mikec@mikenz.geek.nz>
 * @author    Evan Prodromou <evan@status.net>
 * @copyright 2008 Mike Cochrane
 * @copyright 2008-2009 StatusNet, Inc.
 * @link     http://status.net/
 */
class PublictagcloudAction extends Action
{
    function isReadOnly($args)
    {
        return true;
    }

    function title()
    {
        // TRANS: Title for public tag cloud.
        return _('Public tag cloud');
    }

    function showPageNotice()
    {
        $this->element('p', 'instructions',
                       // TRANS: Instructions (more used like an explanation/header).
                       // TRANS: %s is the StatusNet sitename.
                       sprintf(_('These are most popular recent tags on %s'),
                               common_config('site', 'name')));
    }

    function showEmptyList()
    {
        // TRANS: This message contains a Markdown URL. The link description is between
        // TRANS: square brackets, and the link between parentheses. Do not separate "]("
        // TRANS: and do not change the URL part.
        $message = _('No one has posted a notice with a [hashtag](%%doc.tags%%) yet.') . ' ';

        if (common_logged_in()) {
            // TRANS: Message shown to a logged in user for the public tag cloud
            // TRANS: while no tags exist yet. "One" refers to the non-existing hashtag.
            $message .= _('Be the first to post one!');
        }
        else {
            // TRANS: Message shown to a anonymous user for the public tag cloud
            // TRANS: while no tags exist yet. "One" refers to the non-existing hashtag.
            // TRANS: This message contains a Markdown URL. The link description is between
            // TRANS: square brackets, and the link between parentheses. Do not separate "]("
            // TRANS: and do not change the URL part.
            $message .= _('Why not [register an account](%%action.register%%) and be the first to post one!');
        }

        $this->elementStart('div', 'guide');
        $this->raw(common_markup_to_html($message));
        $this->elementEnd('div');
    }

    function handle($args)
    {
        parent::handle($args);
        $this->showPage();
    }

    function showContent()
    {
        // This should probably be cached rather than recalculated
        $tags = new Notice_tag();

        #Need to clear the selection and then only re-add the field
        #we are grouping by, otherwise it's not a valid 'group by'
        #even though MySQL seems to let it slide...
        $tags->selectAdd();
        $tags->selectAdd('tag');

        #Add the aggregated columns...
        $tags->selectAdd('max(notice_id) as last_notice_id');
        $calc = common_sql_weight('created', common_config('tag', 'dropoff'));
        $cutoff = sprintf("notice_tag.created > '%s'",
                          common_sql_date(time() - common_config('tag', 'cutoff')));
        $tags->selectAdd($calc . ' as weight');
        $tags->whereAdd($cutoff);
        $tags->groupBy('tag');
        $tags->orderBy('weight DESC');

        $tags->limit(TAGS_PER_PAGE);

        $cnt = $tags->find();

        if ($cnt > 0) {
            $this->elementStart('div', array('id' => 'tagcloud',
                                             'class' => 'section'));

            $tw = array();
            $sum = 0;
            while ($tags->fetch()) {
                $tw[$tags->tag] = $tags->weight;
                $sum += $tags->weight;
            }

            ksort($tw);

            $this->elementStart('ul', 'tags xoxo tag-cloud');
            foreach ($tw as $tag => $weight) {
                if ($sum) {
                    $weightedSum = $weight/$sum;
                } else {
                    $weightedSum = 0.5;
                }
                $this->showTag($tag, $weight, $weightedSum);
            }
            $this->elementEnd('ul');

            $this->elementEnd('div');
        } else {
            $this->showEmptyList();
        }
    }

    function showTag($tag, $weight, $relative)
    {
        if ($relative > 0.1) {
            $rel =  'tag-cloud-7';
        } else if ($relative > 0.05) {
            $rel = 'tag-cloud-6';
        } else if ($relative > 0.02) {
            $rel = 'tag-cloud-5';
        } else if ($relative > 0.01) {
            $rel = 'tag-cloud-4';
        } else if ($relative > 0.005) {
            $rel = 'tag-cloud-3';
        } else if ($relative > 0.002) {
            $rel = 'tag-cloud-2';
        } else {
            $rel = 'tag-cloud-1';
        }

        $this->elementStart('li', $rel);
        $this->element('a', array('href' => common_local_url('tag', array('tag' => $tag))),
                       $tag);
        $this->elementEnd('li');
    }
}


code:
<?php
/**
 * Public XRDS for OpenID
 *
 * PHP version 5
 *
 * @category Action
 * @package  StatusNet
 * @author   Evan Prodromou <evan@status.net>
 * @author   Craig Andrews <candrews@integralblue.com>
 * @author   Robin Millette <millette@status.net>
 * @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
 * @license  http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
 * @link     http://status.net/
 *
 * StatusNet - the distributed open-source microblogging tool
 * Copyright (C) 2008, 2009, StatusNet, Inc.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

if (!defined('STATUSNET') && !defined('LACONICA')) {
    exit(1);
}

require_once INSTALLDIR.'/plugins/OpenID/openid.php';
require_once INSTALLDIR.'/lib/xrdsoutputter.php';

/**
 * Public XRDS
 *
 * @category Action
 * @package  StatusNet
 * @author   Evan Prodromou <evan@status.net>
 * @author   Robin Millette <millette@status.net>
 * @author   Craig Andrews <candrews@integralblue.com>
 * @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
 * @license  http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
 * @link     http://status.net/
 *
 * @todo factor out similarities with XrdsAction
 */
class PublicxrdsAction extends Action
{
    /**
     * Is read only?
     *
     * @return boolean true
     */
    function isReadOnly($args)
    {
        return true;
    }

    /**
     * Class handler.
     *
     * @param array $args array of arguments
     *
     * @return nothing
     */
    function handle($args)
    {
        parent::handle($args);
        $xrdsOutputter = new XRDSOutputter();
        $xrdsOutputter->startXRDS();
        Event::handle('StartPublicXRDS', array($this,&$xrdsOutputter));
        Event::handle('EndPublicXRDS', array($this,&$xrdsOutputter));
        $xrdsOutputter->endXRDS();
    }
}