code:
<?php
/**
 * StatusNet - the distributed open-source microblogging tool
 * Copyright (C) 2011, StatusNet, Inc.
 *
 * Superclass for microapp plugin
 *
 * PHP version 5
 *
 * 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  Microapp
 * @package   StatusNet
 * @author    Evan Prodromou <evan@status.net>
 * @copyright 2011 StatusNet, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
 * @link      http://status.net/
 */

if (!defined('STATUSNET')) {
    // This check helps protect against security problems;
    // your code file can't be executed directly from the web.
    exit(1);
}

/**
 * Superclass for microapp plugins
 *
 * This class lets you define micro-applications with different kinds of activities.
 *
 * The applications work more-or-less like other
 *
 * @category  Microapp
 * @package   StatusNet
 * @author    Evan Prodromou <evan@status.net>
 * @copyright 2011 StatusNet, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
 * @link      http://status.net/
 */
abstract class MicroAppPlugin extends ActivityHandlerPlugin
{
    /**
     * Returns a localized string which represents this micro-app,
     * to be shown to users selecting what type of post to make.
     * This is paired with the key string in $this->tag().
     *
     * All micro-app classes must override this method.
     *
     * @return string
     */
    abstract function appTitle();

    /**
     * When building the primary notice form, we'll fetch also some
     * alternate forms for specialized types -- that's you!
     *
     * Return a custom Widget or Form object for the given output
     * object, and it'll be included in the HTML output. Beware that
     * your form may be initially hidden.
     *
     * All micro-app classes must override this method.
     *
     * @param HTMLOutputter $out
     * @return Widget
     */
    abstract function entryForm($out);

    /**
     *
     */
    public function newFormAction() {
        // such as 'newbookmark' or 'newevent' route
        return 'new'.$this->tag();
    }

    /**
     * Output the HTML for this kind of object in a list
     *
     * @param NoticeListItem $nli The list item being shown.
     *
     * @return boolean hook value
     */
    function onStartShowNoticeItem(NoticeListItem $nli)
    {
        if (!$this->isMyNotice($nli->notice)) {
            return true;
        }

        // Legacy use was creating a "NoticeListItemAdapter", but
        // nowadays we solve that using event handling for microapps.
        // This section will remain until all plugins are fixed.
        $adapter = $this->adaptNoticeListItem($nli) ?: $nli;

        $adapter->showNotice();
        $adapter->showNoticeAttachments();
        $adapter->showNoticeFooter();

        return false;
    }

    /**
     * Given a notice list item, returns an adapter specific
     * to this plugin.
     *
     * @param NoticeListItem $nli item to adapt
     *
     * @return NoticeListItemAdapter adapter or null
     */
    function adaptNoticeListItem($nli)
    {
      return null;
    }

    function onStartShowEntryForms(&$tabs)
    {
        $tabs[$this->tag()] = array('title' => $this->appTitle(),
                                    'href'  => common_local_url($this->newFormAction()),
                                   );
        return true;
    }

    function onStartMakeEntryForm($tag, $out, &$form)
    {
        if ($tag == $this->tag()) {
            $form = $this->entryForm($out);
            return false;
        }

        return true;
    }
}


code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * Microid class
 *
 * 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  ID
 * @package   StatusNet
 * @author    Evan Prodromou <evan@status.net>
 * @copyright 2008 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);
}

/**
 * A class for microids
 *
 * @category ID
 * @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      http://microid.org/
 */

class Microid
{
    /** Agent part of the ID. */

    var $agent = null;

    /** Resource part of the ID. */

    var $resource = null;

    /**
     * Constructor
     *
     * @param string $agent    Agent of the ID
     * @param string $resource Resource part
     */

    function __construct($agent, $resource)
    {
        $this->agent    = $agent;
        $this->resource = $resource;

    }

    /**
     * Generate a MicroID string
     *
     * @return string MicroID for agent and resource
     */

    function toString()
    {
        $agent_proto    = $this->_getProto($this->agent);
        $resource_proto = $this->_getProto($this->resource);

        return $agent_proto.'+'.$resource_proto.':sha1:'.
          sha1(sha1($this->agent).sha1($this->resource));
    }

    /**
     * Utility for getting the protocol part of a URI
     *
     * @param string $uri URI to parse
     *
     * @return string scheme part of the URI
     */

    function _getProto($uri)
    {
        $colon = strpos($uri, ':');
        return substr($uri, 0, $colon);
    }
}

license: mit


code:
<?php
/**
 * StatusNet - the distributed open-source microblogging tool
 * Copyright (C) 2011, StatusNet, Inc.
 *
 * A menu with a More... button to show more elements
 *
 * PHP version 5
 *
 * 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  Widget
 * @package   StatusNet
 * @author    Evan Prodromou <evan@status.net>
 * @copyright 2011 StatusNet, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
 * @link      http://status.net/
 */

if (!defined('STATUSNET')) {
    // This check helps protect against security problems;
    // your code file can't be executed directly from the web.
    exit(1);
}

/**
 * A menu with a More... element to show more items
 *
 * @category  General
 * @package   StatusNet
 * @author    Evan Prodromou <evan@status.net>
 * @copyright 2011 StatusNet, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
 * @link      http://status.net/
 */
class MoreMenu extends Menu
{
    const SOFT_MAX = 5;
    const HARD_MAX = 15;

    /**
     * Show a menu with a limited number of elements
     *
     * @param
     *
     * @return
     */
    function show()
    {
        $items = $this->getItems();
        $tag = $this->tag();
        $menuID  = null;

        $attrs = array('class' => 'nav');

        if (!is_null($tag)) {
            $menuID = 'nav_' . $tag;
            $attrs['id'] = $menuID;
        }

        if (Event::handle('StartNav', array($this, &$tag, &$items))) {
            $this->out->elementStart('ul', $attrs);

            $total = count($items);

            if ($total <= self::SOFT_MAX + 1) {
                $toShow = $items;
            } else {
                $toShow = array_slice($items, 0, self::SOFT_MAX);
            }

            foreach ($toShow as $item) {
            	if (count($item) == 5) {
                	list($actionName, $args, $label, $description, $id) = $item;
            	} else {
                	list($actionName, $args, $label, $description) = $item;
                	$id = null;
            	}
                $this->item($actionName, $args, $label, $description, $id);
            }

            if ($total > self::SOFT_MAX + 1) {
                $this->out->elementStart('li', array('class' => 'more_link'));
                $this->out->element('a', array('href' => '#',
                                               'onclick' => 'SN.U.showMoreMenuItems("'.$menuID.'"); return false;'),
                                    // TRANS: Link description to show more items in a list.
                                    _('More ▼'));
                $this->out->elementEnd('li');

                $extended = array_slice($items, self::SOFT_MAX, self::HARD_MAX - self::SOFT_MAX);

                foreach ($extended as $item) {
            		if (count($item) == 5) {
                		list($actionName, $args, $label, $description, $id) = $item;
            		} else {
                		list($actionName, $args, $label, $description) = $item;
                		$id = null;
            		}
                    $this->item($actionName, $args, $label, $description, $id, 'extended_menu');
                }

                if ($total > self::HARD_MAX) {
                    $seeAll = $this->seeAllItem();

                    if (!empty($seeAll)) {
            			if (count($seeAll) == 5) {
                			list($actionName, $args, $label, $description, $id) = $seeAll;
            			} else {
                			list($actionName, $args, $label, $description) = $seeAll;
                			$id = null;
            			}
                        $this->item($actionName, $args, $label, $description, $id, 'extended_menu see_all');
                    }
                }
            }

            $this->out->elementEnd('ul');

            Event::handle('EndNav', array($this, $tag, $items));
        }
    }

    function seeAllItem()
    {
        return null;
    }
}


code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * Database schema utilities
 *
 * 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  Database
 * @package   StatusNet
 * @author    Evan Prodromou <evan@status.net>
 * @copyright 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')) {
    exit(1);
}

/**
 * Class representing the database schema
 *
 * A class representing the database schema. Can be used to
 * manipulate the schema -- especially for plugins and upgrade
 * utilities.
 *
 * @category Database
 * @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 MysqlSchema extends Schema
{
    static $_single = null;
    protected $conn = null;

    /**
     * Main public entry point. Use this to get
     * the singleton object.
     *
     * @return Schema the (single) Schema object
     */

    static function get()
    {
        if (empty(self::$_single)) {
            self::$_single = new Schema();
        }
        return self::$_single;
    }

    /**
     * Returns a TableDef object for the table
     * in the schema with the given name.
     *
     * Throws an exception if the table is not found.
     *
     * @param string $table Name of the table to get
     *
     * @return TableDef tabledef for that table.
     * @throws SchemaTableMissingException
     */

    public function getTableDef($table)
    {
        $def = array();
        $hasKeys = false;

        // Pull column data from INFORMATION_SCHEMA
        $columns = $this->fetchMetaInfo($table, 'COLUMNS', 'ORDINAL_POSITION');
        if (count($columns) == 0) {
            throw new SchemaTableMissingException("No such table: $table");
        }

        foreach ($columns as $row) {

            $name = $row['COLUMN_NAME'];
            $field = array();

            // warning -- 'unsigned' attr on numbers isn't given in DATA_TYPE and friends.
            // It is stuck in on COLUMN_TYPE though (eg 'bigint(20) unsigned')
            $field['type'] = $type = $row['DATA_TYPE'];

            if ($type == 'char' || $type == 'varchar') {
                if ($row['CHARACTER_MAXIMUM_LENGTH'] !== null) {
                    $field['length'] = intval($row['CHARACTER_MAXIMUM_LENGTH']);
                }
            }
            if ($type == 'decimal') {
                // Other int types may report these values, but they're irrelevant.
                // Just ignore them!
                if ($row['NUMERIC_PRECISION'] !== null) {
                    $field['precision'] = intval($row['NUMERIC_PRECISION']);
                }
                if ($row['NUMERIC_SCALE'] !== null) {
                    $field['scale'] = intval($row['NUMERIC_SCALE']);
                }
            }
            if ($row['IS_NULLABLE'] == 'NO') {
                $field['not null'] = true;
            }
            if ($row['COLUMN_DEFAULT'] !== null) {
                // Hack for timestamp cols
                if ($type == 'timestamp' && $row['COLUMN_DEFAULT'] == 'CURRENT_TIMESTAMP') {
                    // skip
                } else {
                    $field['default'] = $row['COLUMN_DEFAULT'];
                    if ($this->isNumericType($type)) {
                        $field['default'] = intval($field['default']);
                    }
                }
            }
            if ($row['COLUMN_KEY'] !== null) {
                // We'll need to look up key info...
                $hasKeys = true;
            }
            if ($row['COLUMN_COMMENT'] !== null && $row['COLUMN_COMMENT'] != '') {
                $field['description'] = $row['COLUMN_COMMENT'];
            }

            $extra = $row['EXTRA'];
            if ($extra) {
                if (preg_match('/(^|\s)auto_increment(\s|$)/i', $extra)) {
                    $field['auto_increment'] = true;
                }
                // $row['EXTRA'] may contain 'on update CURRENT_TIMESTAMP'
                // ^ ...... how to specify?
            }

            if ($row['CHARACTER_SET_NAME'] !== null) {
                // @fixme check against defaults?
                //$def['charset'] = $row['CHARACTER_SET_NAME'];
                //$def['collate']  = $row['COLLATION_NAME'];
            }

            $def['fields'][$name] = $field;
        }

        if ($hasKeys) {
            // INFORMATION_SCHEMA's CONSTRAINTS and KEY_COLUMN_USAGE tables give
            // good info on primary and unique keys but don't list ANY info on
            // multi-value keys, which is lame-o. Sigh.
            //
            // Let's go old school and use SHOW INDEX :D
            //
            $keyInfo = $this->fetchIndexInfo($table);
            $keys = array();
            foreach ($keyInfo as $row) {
                $name = $row['Key_name'];
                $column = $row['Column_name'];

                if (!isset($keys[$name])) {
                    $keys[$name] = array();
                }
                $keys[$name][] = $column;

                if ($name == 'PRIMARY') {
                    $type = 'primary key';
                } else if ($row['Non_unique'] == 0) {
                    $type = 'unique keys';
                } else if ($row['Index_type'] == 'FULLTEXT') {
                    $type = 'fulltext indexes';
                } else {
                    $type = 'indexes';
                }
                $keyTypes[$name] = $type;
            }

            foreach ($keyTypes as $name => $type) {
                if ($type == 'primary key') {
                    // there can be only one
                    $def[$type] = $keys[$name];
                } else {
                    $def[$type][$name] = $keys[$name];
                }
            }
        }
        return $def;
    }

    /**
     * Pull the given table properties from INFORMATION_SCHEMA.
     * Most of the good stuff is MySQL extensions.
     *
     * @return array
     * @throws Exception if table info can't be looked up
     */

    function getTableProperties($table, $props)
    {
        $data = $this->fetchMetaInfo($table, 'TABLES');
        if ($data) {
            return $data[0];
        } else {
            throw new SchemaTableMissingException("No such table: $table");
        }
    }

    /**
     * Pull some INFORMATION.SCHEMA data for the given table.
     *
     * @param string $table
     * @return array of arrays
     */
    function fetchMetaInfo($table, $infoTable, $orderBy=null)
    {
        $query = "SELECT * FROM INFORMATION_SCHEMA.%s " .
                 "WHERE TABLE_SCHEMA='%s' AND TABLE_NAME='%s'";
        $schema = $this->conn->dsn['database'];
        $sql = sprintf($query, $infoTable, $schema, $table);
        if ($orderBy) {
            $sql .= ' ORDER BY ' . $orderBy;
        }
        return $this->fetchQueryData($sql);
    }

    /**
     * Pull 'SHOW INDEX' data for the given table.
     *
     * @param string $table
     * @return array of arrays
     */
    function fetchIndexInfo($table)
    {
        $query = "SHOW INDEX FROM `%s`";
        $sql = sprintf($query, $table);
        return $this->fetchQueryData($sql);
    }

    /**
     * Append an SQL statement with an index definition for a full-text search
     * index over one or more columns on a table.
     *
     * @param array $statements
     * @param string $table
     * @param string $name
     * @param array $def
     */
    function appendCreateFulltextIndex(array &$statements, $table, $name, array $def)
    {
        $statements[] = "CREATE FULLTEXT INDEX $name ON $table " . $this->buildIndexList($def);
    }

    /**
     * Close out a 'create table' SQL statement.
     *
     * @param string $name
     * @param array $def
     * @return string;
     *
     * @fixme ENGINE may need to be set differently in some cases,
     * such as to support fulltext index.
     */
    function endCreateTable($name, array $def)
    {
        $engine = $this->preferredEngine($def);
        return ") ENGINE=$engine CHARACTER SET utf8 COLLATE utf8_bin";
    }

    function preferredEngine($def)
    {
        if (!empty($def['fulltext indexes'])) {
            return 'MyISAM';
        }
        return 'InnoDB';
    }

    /**
     * Get the unique index key name for a given column on this table
     */
    function _uniqueKey($tableName, $columnName)
    {
        return $this->_key($tableName, $columnName);
    }

    /**
     * Get the index key name for a given column on this table
     */
    function _key($tableName, $columnName)
    {
        return "{$tableName}_{$columnName}_idx";
    }

    /**
     * MySQL doesn't take 'DROP CONSTRAINT', need to treat primary keys as
     * if they were indexes here, but can use 'PRIMARY KEY' special name.
     *
     * @param array $phrase
     */
    function appendAlterDropPrimary(array &$phrase)
    {
        $phrase[] = 'DROP PRIMARY KEY';
    }

    /**
     * MySQL doesn't take 'DROP CONSTRAINT', need to treat unique keys as
     * if they were indexes here.
     *
     * @param array $phrase
     * @param <type> $keyName MySQL
     */
    function appendAlterDropUnique(array &$phrase, $keyName)
    {
        $phrase[] = 'DROP INDEX ' . $keyName;
    }

    /**
     * Throw some table metadata onto the ALTER TABLE if we have a mismatch
     * in expected type, collation.
     */
    function appendAlterExtras(array &$phrase, $tableName, array $def)
    {
        // Check for table properties: make sure we're using a sane
        // engine type and charset/collation.
        // @fixme make the default engine configurable?
        $oldProps = $this->getTableProperties($tableName, array('ENGINE', 'TABLE_COLLATION'));
        $engine = $this->preferredEngine($def);
        if (strtolower($oldProps['ENGINE']) != strtolower($engine)) {
            $phrase[] = "ENGINE=$engine";
        }
        if (strtolower($oldProps['TABLE_COLLATION']) != 'utf8_bin') {
            $phrase[] = 'DEFAULT CHARSET=utf8';
            $phrase[] = 'COLLATE=utf8_bin';
        }
    }

    /**
     * Is this column a string type?
     */
    private function _isString(array $cd)
    {
        $strings = array('char', 'varchar', 'text');
        return in_array(strtolower($cd['type']), $strings);
    }

    /**
     * Return the proper SQL for creating or
     * altering a column.
     *
     * Appropriate for use in CREATE TABLE or
     * ALTER TABLE statements.
     *
     * @param ColumnDef $cd column to create
     *
     * @return string correct SQL for that column
     */

    function columnSql(array $cd)
    {
        $line = array();
        $line[] = parent::columnSql($cd);

        // This'll have been added from our transform of 'serial' type
        if (!empty($cd['auto_increment'])) {
            $line[] = 'auto_increment';
        }

        if (!empty($cd['description'])) {
            $line[] = 'comment';
            $line[] = $this->quoteValue($cd['description']);
        }

        return implode(' ', $line);
    }

    function mapType($column)
    {
        $map = array('serial' => 'int',
                     'integer' => 'int',
                     'numeric' => 'decimal');

        $type = $column['type'];
        if (isset($map[$type])) {
            $type = $map[$type];
        }

        if (!empty($column['size'])) {
            $size = $column['size'];
            if ($type == 'int' &&
                       in_array($size, array('tiny', 'small', 'medium', 'big'))) {
                $type = $size . $type;
            } else if (in_array($type, array('blob', 'text')) &&
                       in_array($size, array('tiny', 'medium', 'long'))) {
                $type = $size . $type;
            }
        }

        return $type;
    }

    function typeAndSize($column)
    {
        if ($column['type'] == 'enum') {
            $vals = array_map(array($this, 'quote'), $column['enum']);
            return 'enum(' . implode(',', $vals) . ')';
        } else if ($this->_isString($column)) {
            $col = parent::typeAndSize($column);
            if (!empty($column['charset'])) {
                $col .= ' CHARSET ' . $column['charset'];
            }
            if (!empty($column['collate'])) {
                $col .= ' COLLATE ' . $column['collate'];
            }
            return $col;
        } else {
            return parent::typeAndSize($column);
        }
    }

    /**
     * Filter the given table definition array to match features available
     * in this database.
     *
     * This lets us strip out unsupported things like comments, foreign keys,
     * or type variants that we wouldn't get back from getTableDef().
     *
     * @param array $tableDef
     */
    function filterDef(array $tableDef)
    {
        foreach ($tableDef['fields'] as $name => &$col) {
            if ($col['type'] == 'serial') {
                $col['type'] = 'int';
                $col['auto_increment'] = true;
            }
            if ($col['type'] == 'datetime' && isset($col['default']) && $col['default'] == 'CURRENT_TIMESTAMP') {
                $col['type'] = 'timestamp';
            }
            $col['type'] = $this->mapType($col);
            unset($col['size']);
        }
        if (!common_config('db', 'mysql_foreign_keys')) {
            unset($tableDef['foreign keys']);
        }
        return $tableDef;
    }
}


code:
<?php

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

class NetworkPublicNoticeStream extends ScopingNoticeStream
{
    function __construct(Profile $scoped=null)
    {
        parent::__construct(new CachingNoticeStream(new RawNetworkPublicNoticeStream(),
                                                    'networkpublic'),
                            $scoped);
    }
}

/**
 * Raw public stream
 *
 * @category  Stream
 * @package   StatusNet
 * @author    Evan Prodromou <evan@status.net>
 * @copyright 2011 StatusNet, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
 * @link      http://status.net/
 */

class RawNetworkPublicNoticeStream extends NoticeStream
{
    function getNoticeIds($offset, $limit, $since_id, $max_id)
    {
        $notice = new Notice();

        $notice->selectAdd(); // clears it
        $notice->selectAdd('id');

        $notice->orderBy('created DESC, id DESC');

        if (!is_null($offset)) {
            $notice->limit($offset, $limit);
        }

        $notice->whereAdd('is_local ='. Notice::REMOTE);
        // -1 == blacklisted, -2 == gateway (i.e. Twitter)
        $notice->whereAdd('is_local !='. Notice::LOCAL_NONPUBLIC);
        $notice->whereAdd('is_local !='. Notice::GATEWAY);

        Notice::addWhereSinceId($notice, $since_id);
        Notice::addWhereMaxId($notice, $max_id);

        if (!empty($this->selectVerbs)) {
            $notice->whereAddIn('verb', $this->selectVerbs, $notice->columnType('verb'));
        }

        $ids = array();

        if ($notice->find()) {
            while ($notice->fetch()) {
                $ids[] = $notice->id;
            }
        }

        $notice->free();
        $notice = NULL;

        return $ids;
    }
}


code:
<?php
/*
 * 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/>.
 */

class Nickname
{
    /**
     * Regex fragment for pulling a formated nickname *OR* ID number.
     * Suitable for router def of 'id' parameters on API actions.
     *
     * Not guaranteed to be valid after normalization; run the string through
     * Nickname::normalize() to get the canonical form, or Nickname::isValid()
     * if you just need to check if it's properly formatted.
     *
     * This, DISPLAY_FMT, and CANONICAL_FMT should not be enclosed in []s.
     *
     * @fixme would prefer to define in reference to the other constants
     */
    const INPUT_FMT = '(?:[0-9]+|[0-9a-zA-Z_]{1,64})';

    /**
     * Regex fragment for acceptable user-formatted variant of a nickname.
     *
     * This includes some chars such as underscore which will be removed
     * from the normalized canonical form, but still must fit within
     * field length limits.
     *
     * Not guaranteed to be valid after normalization; run the string through
     * Nickname::normalize() to get the canonical form, or Nickname::isValid()
     * if you just need to check if it's properly formatted.
     *
     * This, INPUT_FMT and CANONICAL_FMT should not be enclosed in []s.
     */
    const DISPLAY_FMT = '[0-9a-zA-Z_]{1,64}';

    /**
     * Regex fragment for checking a canonical nickname.
     *
     * Any non-matching string is not a valid canonical/normalized nickname.
     * Matching strings are valid and canonical form, but may still be
     * unavailable for registration due to blacklisting et.
     *
     * Only the canonical forms should be stored as keys in the database;
     * there are multiple possible denormalized forms for each valid
     * canonical-form name.
     *
     * This, INPUT_FMT and DISPLAY_FMT should not be enclosed in []s.
     */
    const CANONICAL_FMT = '[0-9a-z]{1,64}';

    /**
     * Maximum number of characters in a canonical-form nickname.
     */
    const MAX_LEN = 64;

    /**
     * Nice simple check of whether the given string is a valid input nickname,
     * which can be normalized into an internally canonical form.
     *
     * Note that valid nicknames may be in use or reserved.
     *
     * @param string    $str       The nickname string to test
     * @param boolean   $checkuse  Check if it's in use (return false if it is)
     *
     * @return boolean  True if nickname is valid. False if invalid (or taken if checkuse==true).
     */
    public static function isValid($str, $checkuse=false)
    {
        try {
            self::normalize($str, $checkuse);
        } catch (NicknameException $e) {
            return false;
        }

        return true;
    }

    /**
     * Validate an input nickname string, and normalize it to its canonical form.
     * The canonical form will be returned, or an exception thrown if invalid.
     *
     * @param string    $str       The nickname string to test
     * @param boolean   $checkuse  Check if it's in use (return false if it is)
     * @return string Normalized canonical form of $str
     *
     * @throws NicknameException (base class)
     * @throws   NicknameBlacklistedException
     * @throws   NicknameEmptyException
     * @throws   NicknameInvalidException
     * @throws   NicknamePathCollisionException
     * @throws   NicknameTakenException
     * @throws   NicknameTooLongException
     */
    public static function normalize($str, $checkuse=false)
    {
        // We should also have UTF-8 normalization (å to a etc.)
        $str = trim($str);
        $str = str_replace('_', '', $str);
        $str = mb_strtolower($str);

        if (mb_strlen($str) > self::MAX_LEN) {
            // Display forms must also fit!
            throw new NicknameTooLongException();
        } elseif (mb_strlen($str) < 1) {
            throw new NicknameEmptyException();
        } elseif (!self::isCanonical($str)) {
            throw new NicknameInvalidException();
        } elseif (self::isBlacklisted($str)) {
            throw new NicknameBlacklistedException();
        } elseif (self::isSystemPath($str)) {
            throw new NicknamePathCollisionException();
        } elseif ($checkuse) {
            $profile = self::isTaken($str);
            if ($profile instanceof Profile) {
                throw new NicknameTakenException($profile);
            }
        }

        return $str;
    }

    /**
     * Is the given string a valid canonical nickname form?
     *
     * @param string $str
     * @return boolean
     */
    public static function isCanonical($str)
    {
        return preg_match('/^(?:' . self::CANONICAL_FMT . ')$/', $str);
    }

    /**
     * Is the given string in our nickname blacklist?
     *
     * @param string $str
     * @return boolean
     */
     public static function isBlacklisted($str)
     {
         $blacklist = common_config('nickname', 'blacklist');
         return in_array($str, $blacklist);
     }

    /**
     * Is the given string identical to a system path or route?
     * This could probably be put in some other class, but at
     * at the moment, only Nickname requires this functionality.
     *
     * @param string $str
     * @return boolean
     */
     public static function isSystemPath($str)
     {
        $paths = array();

        // All directory and file names in site root should be blacklisted
        $d = dir(INSTALLDIR);
        while (false !== ($entry = $d->read())) {
            $paths[] = $entry;
        }
        $d->close();

        // All top level names in the router should be blacklisted
        $router = Router::get();
        foreach (array_keys($router->m->getPaths()) as $path) {
            if (preg_match('/^\/(.*?)[\/\?]/',$path,$matches)) {
                $paths[] = $matches[1];
            }
        }
        return in_array($str, $paths);
    }

    /**
     * Is the nickname already in use locally? Checks the User table.
     *
     * @param   string $str
     * @return  Profile|null   Returns Profile if nickname found, otherwise null
     */
    public static function isTaken($str)
    {
        $found = User::getKV('nickname', $str);
        if ($found instanceof User) {
            return $found->getProfile();
        }

        $found = Local_group::getKV('nickname', $str);
        if ($found instanceof Local_group) {
            return $found->getProfile();
        }

        $found = Group_alias::getKV('alias', $str);
        if ($found instanceof Group_alias) {
            return $found->getProfile();
        }

        return null;
    }
}

class NicknameException extends ClientException
{
    function __construct($msg=null, $code=400)
    {
        if ($msg === null) {
            $msg = $this->defaultMessage();
        }
        parent::__construct($msg, $code);
    }

    /**
     * Default localized message for this type of exception.
     * @return string
     */
    protected function defaultMessage()
    {
        return null;
    }
}

class NicknameInvalidException extends NicknameException {
    /**
     * Default localized message for this type of exception.
     * @return string
     */
    protected function defaultMessage()
    {
        // TRANS: Validation error in form for registration, profile and group settings, etc.
        return _('Nickname must have only lowercase letters and numbers and no spaces.');
    }
}

class NicknameEmptyException extends NicknameInvalidException
{
    /**
     * Default localized message for this type of exception.
     * @return string
     */
    protected function defaultMessage()
    {
        // TRANS: Validation error in form for registration, profile and group settings, etc.
        return _('Nickname cannot be empty.');
    }
}

class NicknameTooLongException extends NicknameInvalidException
{
    /**
     * Default localized message for this type of exception.
     * @return string
     */
    protected function defaultMessage()
    {
        // TRANS: Validation error in form for registration, profile and group settings, etc.
        return sprintf(_m('Nickname cannot be more than %d character long.',
                          'Nickname cannot be more than %d characters long.',
                          Nickname::MAX_LEN),
                       Nickname::MAX_LEN);
    }
}

class NicknameBlacklistedException extends NicknameException
{
    protected function defaultMessage()
    {
        // TRANS: Validation error in form for registration, profile and group settings, etc.
        return _('Nickname is disallowed through blacklist.');
    }
}

class NicknamePathCollisionException extends NicknameException
{
    protected function defaultMessage()
    {
        // TRANS: Validation error in form for registration, profile and group settings, etc.
        return _('Nickname is identical to system path names.');
    }
}

class NicknameTakenException extends NicknameException
{
    public $profile = null;    // the Profile which occupies the nickname

    public function __construct(Profile $profile, $msg=null, $code=400)
    {
        $this->profile = $profile;

        if ($msg === null) {
            $msg = $this->defaultMessage();
        }

        parent::__construct($msg, $code);
    }

    protected function defaultMessage()
    {
        // TRANS: Validation error in form for registration, profile and group settings, etc.
        return _('Nickname is already in use on this server.');
    }
}


code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * Class for an exception when unable to retrieve or resize a profile's avatar.
 *
 * 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  Exception
 * @package   GNUsocial
 * @author    Mikael Nordfeldth <mmn@hethane.se>
 * @copyright 2013 Free Software Foundation, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPLv3
 * @link      http://www.gnu.org/software/social/
 */

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

class NoAvatarException extends NoResultException
{
    public $target;

    public function __construct(Profile $target, Avatar $obj)
    {
        $this->target = $target;
        parent::__construct($obj);
    }
}


code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * Parent class for an exception when a profile is missing
 *
 * 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  Exception
 * @package   StatusNet
 * @author    Evan Prodromou <evan@status.net>
 * @copyright 2010 StatusNet, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPLv3
 * @link      http://status.net/
 */

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

/**
 * Parent class for an exception when a profile is missing
 *
 * @category Exception
 * @package  StatusNet
 * @author   Evan Prodromou <evan@status.net>
 * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPLv3
 * @link     http://status.net/
 */

class NoProfileException extends ServerException
{
    public $profile_id = null;

    public function __construct($profile_id, $msg=null)
    {
        $this->profile_id = $profile_id;

        if ($msg === null) {
            // TRANS: Exception text shown when no profile can be found for a user.
            // TRANS: %u is a profile ID (number).
            $msg = sprintf(_('There is no profile with id==%u'), $this->profile_id);
        }

        parent::__construct($msg, 404);
    }
}


code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * Class for an exception when a database lookup returns no results
 *
 * 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  Exception
 * @package   GNUsocial
 * @author    Mikael Nordfeldth <mmn@hethane.se>
 * @copyright 2013 Free Software Foundation, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPLv3
 * @link      http://www.gnu.org/software/social/
 */

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

class NoResultException extends ServerException
{
    public $obj;    // The object with query that gave no results

    public function __construct(Memcached_DataObject $obj)
    {
        $this->obj = $obj;
        // We could log an entry here with the search parameters
        parent::__construct(sprintf(_('No result found on %s lookup.'), get_class($obj)));
    }
}


code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * class for an exception when a User_group is not found by certain criteria
 *
 * 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  Exception
 * @package   GNUsocial
 * @author    Evan Prodromou <evan@status.net>
 * @author    Mikael Nordfeldth <mmn@hethane.se>
 * @copyright 2013 Free Software Foundation, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPLv3
 * @link      http://status.net/
 */

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

/**
 * Class for an exception when a local user is not found by certain criteria
 *
 * @category Exception
 * @package  StatusNet
 * @author   Evan Prodromou <evan@status.net>
 * @author   Mikael Nordfeldth <mmn@hethane.se>
 * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPLv3
 * @link     http://status.net/
 */

class NoSuchGroupException extends ServerException
{
    public $data = array();

    /**
     * constructor
     *
     * @param array $data User_group search criteria
     */

    public function __construct(array $data)
    {
        // filter on unique keys for User_group entries
        foreach(array('id', 'profile_id') as $key) {
            if (isset($data[$key]) && !empty($data[$key])) {
                $this->data[$key] = $data[$key];
            }
        }

        // Here we could log the failed lookup

        parent::__construct(_('No such group found.'));
    }
}


code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * class for an exception when a local user is not found by certain criteria
 *
 * 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  Exception
 * @package   StatusNet
 * @author    Evan Prodromou <evan@status.net>
 * @author    Mikael Nordfeldth <mmn@hethane.se>
 * @copyright 2013 Free Software Foundation, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPLv3
 * @link      http://status.net/
 */

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

/**
 * Class for an exception when a local user is not found by certain criteria
 *
 * @category Exception
 * @package  StatusNet
 * @author   Evan Prodromou <evan@status.net>
 * @author   Mikael Nordfeldth <mmn@hethane.se>
 * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPLv3
 * @link     http://status.net/
 */

class NoSuchUserException extends ServerException
{
    public $data = array();

    /**
     * constructor
     *
     * @param array $data user search criteria
     */

    public function __construct(array $data)
    {
        // filter on unique keys for local users
        foreach(array('id', 'email', 'nickname') as $key) {
            if (isset($data[$key]) && !empty($data[$key])) {
                $this->data[$key] = $data[$key];
            }
        }

        // Here we could log the failed lookup

        parent::__construct(_('No such user found.'));
    }
}


code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * Form for posting a notice
 *
 * 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  Form
 * @package   StatusNet
 * @author    Evan Prodromou <evan@status.net>
 * @author    Sarven Capadisli <csarven@status.net>
 * @copyright 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); }

/**
 * Form for posting a notice
 *
 * Frequently-used form for posting a notice
 *
 * @category Form
 * @package  StatusNet
 * @author   Evan Prodromou <evan@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/
 *
 * @see      HTMLOutputter
 */
class NoticeForm extends Form
{
    /**
     * Current action, used for returning to this page.
     */
    var $actionName = null;

    /**
     * Pre-filled content of the form
     */
    var $content = null;

    /**
     * The current user
     */
    var $user = null;

    /**
     * The notice being replied to
     */
    var $inreplyto = null;

    /**
     * Pre-filled location content of the form
     */

    var $lat;
    var $lon;
    var $location_id;
    var $location_ns;

    /** select this group from the drop-down by default. */
    var $to_group;

    /** select this user from the drop-down by default. */
    var $to_profile;

    /** Pre-click the private checkbox. */
    var $private;

    /**
     * Constructor
     *
     * @param Action $action  Action we're being embedded into
     * @param array  $options Array of optional parameters
     *                        'user' a user instead of current
     *                        'content' notice content
     *                        'inreplyto' ID of notice to reply to
     *                        'lat' Latitude
     *                        'lon' Longitude
     *                        'location_id' ID of location
     *                        'location_ns' Namespace of location
     */
    function __construct($action, $options=null)
    {
        // XXX: ??? Is this to keep notice forms distinct?
        // Do we have to worry about sub-second race conditions?
        // XXX: Needs to be above the parent::__construct() call...?

        $this->id_suffix = rand();

        parent::__construct($action);

        if (is_null($options)) {
            $options = array();
        }

        $this->actionName  = $action->trimmed('action');

        $prefill = array('content', 'inreplyto', 'lat',
                         'lon', 'location_id', 'location_ns',
                         'to_group', 'to_profile', 'private');

        foreach ($prefill as $fieldName) {
            if (array_key_exists($fieldName, $options)) {
                $this->$fieldName = $options[$fieldName];
            }
        }

        // Prefill the profile if we're replying

        if (empty($this->to_profile) &&
            !empty($this->inreplyto)) {
            $notice = Notice::getKV('id', $this->inreplyto);
            if (!empty($notice)) {
                $this->to_profile = $notice->getProfile();
            }
        }

        if (array_key_exists('user', $options)) {
            $this->user = $options['user'];
        } else {
            $this->user = common_current_user();
        }

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

        if (common_config('attachments', 'uploads')) {
            $this->enctype = 'multipart/form-data';
        }
    }

    /**
     * ID of the form
     *
     * @return string ID of the form
     */

    function id()
    {
        return 'form_notice_' . $this->id_suffix;
    }

   /**
     * Class of the form
     *
     * @return string class of the form
     */

    function formClass()
    {
        return 'form_notice ajax-notice';
    }

    /**
     * Action of the form
     *
     * @return string URL of the action
     */

    function action()
    {
        return common_local_url('newnotice');
    }

    /**
     * Legend of the Form
     *
     * @return void
     */
    function formLegend()
    {
        // TRANS: Form legend for notice form.
        $this->out->element('legend', null, _('Send a notice'));
    }

    /**
     * Data elements
     *
     * @return void
     */
    function formData()
    {
        if (Event::handle('StartShowNoticeFormData', array($this))) {
            $this->out->element('label', array('for' => 'notice_data-text',
                                               'id' => 'notice_data-text-label'),
                                // TRANS: Title for notice label. %s is the user's nickname.
                                sprintf(_('What\'s up, %s?'), $this->user->nickname));
            // XXX: vary by defined max size
            $this->out->element('textarea', array('class' => 'notice_data-text',
                                                  'required' => 'required',
                                                  'placeholder' => _('Share your status...'),
                                                  'cols' => 35,
                                                  'rows' => 4,
                                                  'name' => 'status_textarea'),
                                ($this->content) ? $this->content : '');

            $contentLimit = Notice::maxContent();

            if ($contentLimit > 0) {
                $this->out->element('span',
                                    array('class' => 'count'),
                                    $contentLimit);
            }

            if (common_config('attachments', 'uploads')) {
                $this->out->hidden('MAX_FILE_SIZE', common_config('attachments', 'file_quota'));
                $this->out->elementStart('label', array('class' => 'notice_data-attach'));
                // TRANS: Input label in notice form for adding an attachment.
                $this->out->text(_('Attach'));
                $this->out->element('input', array('class' => 'notice_data-attach',
                                                   'type' => 'file',
                                                   'name' => 'attach',
                                                   // TRANS: Title for input field to attach a file to a notice.
                                                   'title' => _('Attach a file.')));
                $this->out->elementEnd('label');
            }
            if (!empty($this->actionName)) {
                $this->out->hidden('notice_return-to', $this->actionName, 'returnto');
            }
            $this->out->hidden('notice_in-reply-to', $this->inreplyto, 'inreplyto');

            $this->out->elementStart('div', 'to-selector');
            $toWidget = new ToSelector($this->out,
                                       $this->user,
                                       (!empty($this->to_group) ? $this->to_group : $this->to_profile));

            $toWidget->show();
            $this->out->elementEnd('div');

            if ($this->profile->shareLocation()) {
                $this->out->hidden('notice_data-lat', empty($this->lat) ? (empty($this->profile->lat) ? null : $this->profile->lat) : $this->lat, 'lat');
                $this->out->hidden('notice_data-lon', empty($this->lon) ? (empty($this->profile->lon) ? null : $this->profile->lon) : $this->lon, 'lon');
                $this->out->hidden('notice_data-location_id', empty($this->location_id) ? (empty($this->profile->location_id) ? null : $this->profile->location_id) : $this->location_id, 'location_id');
                $this->out->hidden('notice_data-location_ns', empty($this->location_ns) ? (empty($this->profile->location_ns) ? null : $this->profile->location_ns) : $this->location_ns, 'location_ns');

                $this->out->elementStart('div', array('class' => 'notice_data-geo_wrap',
                                                      'data-api' => common_local_url('geocode')));

                // @fixme checkbox method allows no way to change the id without changing the name
                //// TRANS: Checkbox label to allow sharing geo location in notices.
                //$this->out->checkbox('notice_data-geo', _('Share my location'), true);
                $this->out->elementStart('label', 'notice_data-geo');
                $this->out->element('input', array(
                    'name' => 'notice_data-geo',
                    'type' => 'checkbox',
                    'class' => 'checkbox',
                    'id' => $this->id() . '-notice_data-geo',
                    'checked' => true, // ?
                ));
                $this->out->text(' ');
                // TRANS: Field label to add location to a notice.
                $this->out->text(_('Share my location'));
                $this->out->elementEnd('label');

                $this->out->elementEnd('div');
                // TRANS: Text to not share location for a notice in notice form.
                $share_disable_text = _('Do not share my location');
                // TRANS: Timeout error text for location retrieval in notice form.
                $error_timeout_text = _('Sorry, retrieving your geo location is taking longer than expected, please try again later');
                $this->out->inlineScript(' var NoticeDataGeo_text = {'.
                    'ShareDisable: ' .json_encode($share_disable_text).','.
                    'ErrorTimeout: ' .json_encode($error_timeout_text).
                    '}');
            }

            Event::handle('EndShowNoticeFormData', array($this));
        }
    }

    /**
     * Action elements
     *
     * @return void
     */

    function formActions()
    {
        $this->out->element('input', array('id' => 'notice_action-submit',
                                           'class' => 'submit',
                                           'name' => 'status_submit',
                                           'type' => 'submit',
                                           // TRANS: Button text for sending notice.
                                           'value' => _m('BUTTON', 'Send')));
    }
}


code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * widget for displaying a list of 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  UI
 * @package   StatusNet
 * @author    Evan Prodromou <evan@status.net>
 * @author    Sarven Capadisli <csarven@status.net>
 * @copyright 2008 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') && !defined('STATUSNET')) { exit(1); }

/**
 * widget for displaying a list of notices
 *
 * There are a number of actions that display a list of notices, in
 * reverse chronological order. This widget abstracts out most of the
 * code for UI for notice lists. It's overridden to hide some
 * data for e.g. the profile page.
 *
 * @category UI
 * @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      Notice
 * @see      NoticeListItem
 * @see      ProfileNoticeList
 */
class NoticeList extends Widget
{
    /** the current stream of notices being displayed. */

    var $notice = null;

    protected $addressees = true;
    protected $attachments = true;
    protected $id_prefix = null;
    protected $maxchars = 0;
    protected $options = true;
    protected $show_n = NOTICES_PER_PAGE;

    /**
     * constructor
     *
     * @param Notice $notice stream of notices from DB_DataObject
     */
    function __construct(Notice $notice, $out=null, array $prefs=array())
    {
        parent::__construct($out);
        $this->notice = $notice;

        // integer preferences
        foreach(array('show_n', 'maxchars') as $key) {
            if (array_key_exists($key, $prefs)) {
                $this->$key = (int)$prefs[$key];
            }
        }
        // boolean preferences
        foreach(array('addressees', 'attachments', 'options') as $key) {
            if (array_key_exists($key, $prefs)) {
                $this->$key = (bool)$prefs[$key];
            }
        }
        // string preferences
        foreach(array('id_prefix') as $key) {
            if (array_key_exists($key, $prefs)) {
                $this->$key = $prefs[$key];
            }
        }
    }

    /**
     * show the list of notices
     *
     * "Uses up" the stream by looping through it. So, probably can't
     * be called twice on the same list.
     *
     * @param integer $n    The amount of notices to show.
     *
     * @return int  Total amount of notices actually available.
     */
    public function show()
    {
        $this->out->elementStart('ol', array('class' => 'notices xoxo'));

		$notices = $this->notice->fetchAll();
		$total   = count($notices);
		$notices = array_slice($notices, 0, $this->show_n);

    	self::prefill($notices);

    	foreach ($notices as $notice) {

            try {
                $item = $this->newListItem($notice);
                $item->show();
            } catch (Exception $e) {
                // we log exceptions and continue
                common_log(LOG_ERR, $e->getMessage());
                continue;
            }
        }

        $this->out->elementEnd('ol');
        return $total;
    }

    /**
     * returns a new list item for the current notice
     *
     * Recipe (factory?) method; overridden by sub-classes to give
     * a different list item class.
     *
     * @param Notice $notice the current notice
     *
     * @return NoticeListItem a list item for displaying the notice
     */
    function newListItem(Notice $notice)
    {
        $prefs = array('addressees' => $this->addressees,
                       'attachments' => $this->attachments,
                       'id_prefix' => $this->id_prefix,
                       'maxchars' => $this->maxchars,
                       'options' => $this->options);
        return new NoticeListItem($notice, $this->out, $prefs);
    }

    static function prefill(array &$notices)
    {
        $scoped = Profile::current();
        $notice_ids = Notice::_idsOf($notices);

        if (Event::handle('StartNoticeListPrefill', array(&$notices, $notice_ids, $scoped))) {

            // Prefill attachments
            Notice::fillAttachments($notices);
            // Prefill repeat data
            Notice::fillRepeats($notices);
            // Prefill the profiles
            $profiles = Notice::fillProfiles($notices);

            if ($scoped instanceof Profile) {
                Notice::pivotGet('repeat_of', $notice_ids, array('profile_id' => $scoped->id));
            }

            Event::handle('EndNoticeListPrefill', array(&$notices, &$profiles, $notice_ids, $scoped));
        }
    }
}


code:
<?php
/**
 * GNU Social - a federating social network
 * Copyright (C) 2014, Free Software Foundation, 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('GNUSOCIAL')) { exit(1); }

/**
 * Placeholder for showing faves...
 */
abstract class NoticeListActorsItem extends NoticeListItem
{
    /**
     * @return array of profile IDs
     */
    abstract function getProfiles();

    abstract function getListMessage($count, $you);

    function show()
    {
        $links = array();
        $you = false;
        $cur = common_current_user();
        foreach ($this->getProfiles() as $id) {
            if ($cur && $cur->id == $id) {
                $you = true;
                // TRANS: Reference to the logged in user in favourite list.
                array_unshift($links, _m('FAVELIST', 'You'));
            } else {
                $profile = Profile::getKV('id', $id);
                if ($profile instanceof Profile) {
                    $links[] = sprintf('%s',
                                       htmlspecialchars($profile->getUrl()),
                                       htmlspecialchars($profile->getBestName()));
                }
            }
        }

        if ($links) {
            $count = count($links);
            $msg = $this->getListMessage($count, $you);
            $out = sprintf($msg, $this->magicList($links));

            $this->showStart();
            $this->out->raw($out);
            $this->showEnd();
            return $count;
        } else {
            return 0;
        }
    }

    function magicList($items)
    {
        if (count($items) == 0) {
            return '';
        } else if (count($items) == 1) {
            return $items[0];
        } else {
            $first = array_slice($items, 0, -1);
            $last = array_slice($items, -1, 1);
            // TRANS: Separator in list of user names like "Jim, Bob, Mary".
            $separator = _(', ');
            // TRANS: For building a list such as "Jim, Bob, Mary and 5 others like this".
            // TRANS: %1$s is a list of users, separated by a separator (default: ", "), %2$s is the last user in the list.
            return sprintf(_m('FAVELIST', '%1$s and %2$s'), implode($separator, $first), implode($separator, $last));
        }
    }
}


code:
<?php
/**
 * StatusNet - the distributed open-source microblogging tool
 * Copyright (C) 2010, StatusNet, Inc.
 *
 * An item in a notice list
 *
 * PHP version 5
 *
 * 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  Widget
 * @package   StatusNet
 * @author    Evan Prodromou <evan@status.net>
 * @copyright 2010 StatusNet, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
 * @link      http://status.net/
 */

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

/**
 * widget for displaying a single notice
 *
 * This widget has the core smarts for showing a single notice: what to display,
 * where, and under which circumstances. Its key method is show(); this is a recipe
 * that calls all the other show*() methods to build up a single notice. The
 * ProfileNoticeListItem subclass, for example, overrides showAuthor() to skip
 * author info (since that's implicit by the data in the page).
 *
 * @category UI
 * @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      NoticeList
 * @see      ProfileNoticeListItem
 */
class NoticeListItem extends Widget
{
    /** The notice this item will show. */
    var $notice = null;

    /** The notice that was repeated. */
    var $repeat = null;

    /** The profile of the author of the notice, extracted once for convenience. */
    var $profile = null;

    protected $addressees = true;
    protected $attachments = true;
    protected $id_prefix = null;
    protected $options = true;
    protected $maxchars = 0;   // if <= 0 it means use full posts

    /**
     * constructor
     *
     * Also initializes the profile attribute.
     *
     * @param Notice $notice The notice we'll display
     */
    function __construct(Notice $notice, Action $out=null, array $prefs=array())
    {
        parent::__construct($out);
        if (!empty($notice->repeat_of)) {
            $original = Notice::getKV('id', $notice->repeat_of);
            if (!$original instanceof Notice) { // could have been deleted
                $this->notice = $notice;
            } else {
                $this->notice = $original;
                $this->repeat = $notice;
            }
        } else {
            $this->notice  = $notice;
        }

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

        // integer preferences
        foreach(array('maxchars') as $key) {
            if (array_key_exists($key, $prefs)) {
                $this->$key = (int)$prefs[$key];
            }
        }
        // boolean preferences
        foreach(array('addressees', 'attachments', 'options') as $key) {
            if (array_key_exists($key, $prefs)) {
                $this->$key = (bool)$prefs[$key];
            }
        }
        // string preferences
        foreach(array('id_prefix') as $key) {
            if (array_key_exists($key, $prefs)) {
                $this->$key = $prefs[$key];
            }
        }
    }

    /**
     * recipe function for displaying a single notice.
     *
     * This uses all the other methods to correctly display a notice. Override
     * it or one of the others to fine-tune the output.
     *
     * @return void
     */
    function show()
    {
        if (empty($this->notice)) {
            common_log(LOG_WARNING, "Trying to show missing notice; skipping.");
            return;
        } else if (empty($this->profile)) {
            common_log(LOG_WARNING, "Trying to show missing profile (" . $this->notice->profile_id . "); skipping.");
            return;
        }

        $this->showStart();
        if (Event::handle('StartShowNoticeItem', array($this))) {
            $this->showNotice();
            Event::handle('EndShowNoticeItem', array($this));
        }
        $this->showEnd();
    }

    function showNotice()
    {
        if (Event::handle('StartShowNoticeItemNotice', array($this))) {
            $this->showNoticeHeaders();
            $this->showContent();
            $this->showNoticeFooter();
            Event::handle('EndShowNoticeItemNotice', array($this));
        }
    }

    function showNoticeHeaders()
    {
        $this->elementStart('section', array('class'=>'notice-headers'));
        $this->showNoticeTitle();
        $this->showAuthor();
        if ($this->addressees) { $this->showAddressees(); }
        $this->elementEnd('section');
    }

    function showNoticeFooter()
    {
        $this->elementStart('footer');
        $this->showNoticeInfo();
        if ($this->attachments) { $this->showNoticeAttachments(); }
        if ($this->options) { $this->showNoticeOptions(); }
        $this->elementEnd('footer');
    }

    function showNoticeTitle()
    {
        if (Event::handle('StartShowNoticeTitle', array($this))) {
            $this->element('a', array('href' => $this->notice->getUrl(),
                                      'class' => 'notice-title'),
                           $this->notice->getTitle());
            Event::handle('EndShowNoticeTitle', array($this));
        }
    }

    function showNoticeInfo()
    {
        if (Event::handle('StartShowNoticeInfo', array($this))) {
            $this->showNoticeLink();
            $this->showNoticeSource();
            $this->showNoticeLocation();
            $this->showPermalink();
            $this->showRepeat();
            Event::handle('EndShowNoticeInfo', array($this));
        }
    }

    function showNoticeOptions()
    {
        if (Event::handle('StartShowNoticeOptions', array($this))) {
            $user = common_current_user();
            if ($user) {
                $this->out->elementStart('div', 'notice-options');
                if (Event::handle('StartShowNoticeOptionItems', array($this))) {
                    $this->showReplyLink();
                    $this->showRepeatForm();
                    $this->showDeleteLink();
                    Event::handle('EndShowNoticeOptionItems', array($this));
                }
                $this->out->elementEnd('div');
            }
            Event::handle('EndShowNoticeOptions', array($this));
        }
    }

    /**
     * start a single notice.
     *
     * @return void
     */
    function showStart()
    {
        if (Event::handle('StartOpenNoticeListItemElement', array($this))) {
            $id = (empty($this->repeat)) ? $this->notice->id : $this->repeat->id;
            $class = 'h-entry notice';
            if ($this->notice->scope != 0 && $this->notice->scope != 1) {
                $class .= ' limited-scope';
            }
            if (!empty($this->notice->source)) {
                $class .= ' notice-source-'.$this->notice->source;
            }
            $id_prefix = (strlen($this->id_prefix) ? $this->id_prefix . '-' : '');
            $this->out->elementStart('li', array('class' => $class,
                                                 'id' => "${id_prefix}notice-${id}"));
            Event::handle('EndOpenNoticeListItemElement', array($this));
        }
    }

    /**
     * show the author of a notice
     *
     * By default, this shows the avatar and (linked) nickname of the author.
     *
     * @return void
     */

    function showAuthor()
    {
        $attrs = array('href' => $this->profile->profileurl,
                       'class' => 'h-card p-author',
                       'title' => $this->profile->getNickname());

        if (Event::handle('StartShowNoticeItemAuthor', array($this->profile, $this->out, &$attrs))) {
            $this->out->elementStart('a', $attrs);
            $this->showAvatar($this->profile);
            $this->out->text($this->profile->getStreamName());
            $this->out->elementEnd('a');
            Event::handle('EndShowNoticeItemAuthor', array($this->profile, $this->out));
        }
    }

    function showAddressees()
    {
        $pa = $this->getProfileAddressees();

        if (!empty($pa)) {
            $this->out->elementStart('ul', 'addressees');
            $first = true;
            foreach ($pa as $addr) {
                $this->out->elementStart('li', 'h-card');
                $text = $addr['text'];
                unset($addr['text']);
                $this->out->element('a', $addr, $text);
                $this->out->elementEnd('li');
            }
            $this->out->elementEnd('ul', 'addressees');
        }
    }

    function getProfileAddressees()
    {
        $pa = array();

        $attentions = $this->getReplyProfiles();

        foreach ($attentions as $attn) {
            $class = $attn->isGroup() ? 'group' : 'account';
            $pa[] = array('href' => $attn->profileurl,
                          'title' => $attn->getNickname(),
                          'class' => "addressee {$class}",
                          'text' => $attn->getStreamName());
        }

        return $pa;
    }

    function getReplyProfiles()
    {
        return $this->notice->getReplyProfiles();
    }

    /**
     * show the nickname of the author
     *
     * Links to the author's profile page
     *
     * @return void
     */
    function showNickname()
    {
        $this->out->raw('' .
                        htmlspecialchars($this->profile->getNickname()) .
                        '');
    }

    /**
     * show the content of the notice
     *
     * Shows the content of the notice. This is pre-rendered for efficiency
     * at save time. Some very old notices might not be pre-rendered, so
     * they're rendered on the spot.
     *
     * @return void
     */
    function showContent()
    {
        // FIXME: URL, image, video, audio
        $this->out->elementStart('article', array('class' => 'e-content'));
        if (Event::handle('StartShowNoticeContent', array($this->notice, $this->out, $this->out->getScoped()))) {
            if ($this->maxchars > 0 && mb_strlen($this->notice->content) > $this->maxchars) {
                $this->out->text(mb_substr($this->notice->content, 0, $this->maxchars) . '[…]');
            } elseif ($this->notice->rendered) {
                $this->out->raw($this->notice->rendered);
            } else {
                // XXX: may be some uncooked notices in the DB,
                // we cook them right now. This should probably disappear in future
                // versions (>> 0.4.x)
                $this->out->raw(common_render_content($this->notice->content, $this->notice));
            }
            Event::handle('EndShowNoticeContent', array($this->notice, $this->out, $this->out->getScoped()));
        }
        $this->out->elementEnd('article');
    }

    function showNoticeAttachments() {
        if (common_config('attachments', 'show_thumbs')) {
            $al = new InlineAttachmentList($this->notice, $this->out);
            $al->show();
        }
    }

    /**
     * show the link to the main page for the notice
     *
     * Displays a local link to the rendered notice, with "relative" time.
     *
     * @return void
     */
    function showNoticeLink()
    {
        $this->out->elementStart('a', array('rel' => 'bookmark',
                                            'class' => 'timestamp',
                                            'href' => Conversation::getUrlFromNotice($this->notice)));
        $this->out->element('time', array('class' => 'dt-published',
                                          'datetime' => common_date_iso8601($this->notice->created),
                                          // TRANS: Timestamp title (tooltip text) for NoticeListItem
                                          'title' => common_exact_date($this->notice->created)),
                            common_date_string($this->notice->created));
        $this->out->elementEnd('a');
    }

    /**
     * show the notice location
     *
     * shows the notice location in the correct language.
     *
     * If an URL is available, makes a link. Otherwise, just a span.
     *
     * @return void
     */
    function showNoticeLocation()
    {
        $id = $this->notice->id;

        $location = $this->notice->getLocation();

        if (empty($location)) {
            return;
        }

        $name = $location->getName();

        $lat = $this->notice->lat;
        $lon = $this->notice->lon;
        $latlon = (!empty($lat) && !empty($lon)) ? $lat.';'.$lon : '';

        if (empty($name)) {
            $latdms = $this->decimalDegreesToDMS(abs($lat));
            $londms = $this->decimalDegreesToDMS(abs($lon));
            // TRANS: Used in coordinates as abbreviation of north.
            $north = _('N');
            // TRANS: Used in coordinates as abbreviation of south.
            $south = _('S');
            // TRANS: Used in coordinates as abbreviation of east.
            $east = _('E');
            // TRANS: Used in coordinates as abbreviation of west.
            $west = _('W');
            $name = sprintf(
                // TRANS: Coordinates message.
                // TRANS: %1$s is lattitude degrees, %2$s is lattitude minutes,
                // TRANS: %3$s is lattitude seconds, %4$s is N (north) or S (south) depending on lattitude,
                // TRANS: %5$s is longitude degrees, %6$s is longitude minutes,
                // TRANS: %7$s is longitude seconds, %8$s is E (east) or W (west) depending on longitude,
                _('%1$u°%2$u\'%3$u"%4$s %5$u°%6$u\'%7$u"%8$s'),
                $latdms['deg'],$latdms['min'], $latdms['sec'],($lat>0? $north:$south),
                $londms['deg'],$londms['min'], $londms['sec'],($lon>0? $east:$west));
        }

        $url  = $location->getUrl();

        $this->out->text(' ');
        $this->out->elementStart('span', array('class' => 'location'));
        // TRANS: Followed by geo location.
        $this->out->text(_('at'));
        $this->out->text(' ');
        if (empty($url)) {
            $this->out->element('abbr', array('class' => 'geo',
                                              'title' => $latlon),
                                $name);
        } else {
            $xstr = new XMLStringer(false);
            $xstr->elementStart('a', array('href' => $url,
                                           'rel' => 'external'));
            $xstr->element('abbr', array('class' => 'geo',
                                         'title' => $latlon),
                           $name);
            $xstr->elementEnd('a');
            $this->out->raw($xstr->getString());
        }
        $this->out->elementEnd('span');
    }

    /**
     * @param number $dec decimal degrees
     * @return array split into 'deg', 'min', and 'sec'
     */
    function decimalDegreesToDMS($dec)
    {
        $deg = intval($dec);
        $tempma = abs($dec) - abs($deg);

        $tempma = $tempma * 3600;
        $min = floor($tempma / 60);
        $sec = $tempma - ($min*60);

        return array("deg"=>$deg,"min"=>$min,"sec"=>$sec);
    }

    /**
     * Show the source of the notice
     *
     * Either the name (and link) of the API client that posted the notice,
     * or one of other other channels.
     *
     * @return void
     */
    function showNoticeSource()
    {
        $ns = $this->notice->getSource();

        if (!$ns instanceof Notice_source) {
            return false;
        }

        // TRANS: A possible notice source (web interface).
        $source_name = (empty($ns->name)) ? ($ns->code ? _($ns->code) : _m('SOURCE','web')) : _($ns->name);
        $this->out->text(' ');
        $this->out->elementStart('span', 'source');
        // @todo FIXME: probably i18n issue. If "from" is followed by text, that should be a parameter to "from" (from %s).
        // TRANS: Followed by notice source.
        $this->out->text(_('from'));
        $this->out->text(' ');

        $name  = $source_name;
        $url   = $ns->url;
        $title = null;

        if (Event::handle('StartNoticeSourceLink', array($this->notice, &$name, &$url, &$title))) {
            $name = $source_name;
            $url  = $ns->url;
        }
        Event::handle('EndNoticeSourceLink', array($this->notice, &$name, &$url, &$title));

        // if $ns->name and $ns->url are populated we have
        // configured a source attr somewhere
        if (!empty($name) && !empty($url)) {
            $this->out->elementStart('span', 'device');

            $attrs = array(
                'href' => $url,
                'rel' => 'external'
            );

            if (!empty($title)) {
                $attrs['title'] = $title;
            }

            $this->out->element('a', $attrs, $name);
            $this->out->elementEnd('span');
        } else {
            $this->out->element('span', 'device', $name);
        }

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

    /**
     * show link to single-notice view for this notice item
     *
     * A permalink that goes to this specific object and nothing else
     *
     * @return void
     */
    function showPermalink()
    {
        $class = 'permalink u-url';
        if (!$this->notice->isLocal()) {
            $class .= ' external';
        }
        try {
            $this->out->element('a',
                        array('href' => $this->notice->getUrl(),
                              'class' => $class),
                        // TRANS: Addition in notice list item for single-notice view.
                        _('permalink'));
        } catch (InvalidUrlException $e) {
            // no permalink available
        }
    }

    /**
     * show a link to the author of repeat
     *
     * @return void
     */
    function showRepeat()
    {
        if (!empty($this->repeat)) {

            $repeater = Profile::getKV('id', $this->repeat->profile_id);

            $attrs = array('href' => $repeater->profileurl,
                           'class' => 'h-card p-author',
                           'title' => $repeater->getFancyName());

            $this->out->elementStart('span', 'repeat h-entry');

            // TRANS: Addition in notice list item if notice was repeated. Followed by a span with a nickname.
            $this->out->raw(_('Repeated by').' ');

            $this->out->element('a', $attrs, $repeater->getNickname());

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

    /**
     * show a link to reply to the current notice
     *
     * Should either do the reply in the current notice form (if available), or
     * link out to the notice-posting form. A little flakey, doesn't always work.
     *
     * @return void
     */
    function showReplyLink()
    {
        if (common_logged_in()) {
            $this->out->text(' ');
            $reply_url = common_local_url('newnotice',
                                          array('replyto' => $this->profile->getNickname(), 'inreplyto' => $this->notice->id));
            $this->out->elementStart('a', array('href' => $reply_url,
                                                'class' => 'notice_reply',
                                                // TRANS: Link title in notice list item to reply to a notice.
                                                'title' => _('Reply to this notice.')));
            // TRANS: Link text in notice list item to reply to a notice.
            $this->out->text(_('Reply'));
            $this->out->text(' ');
            $this->out->element('span', 'notice_id', $this->notice->id);
            $this->out->elementEnd('a');
        }
    }

    /**
     * if the user is the author, let them delete the notice
     *
     * @return void
     */
    function showDeleteLink()
    {
        $user = common_current_user();

        $todel = (empty($this->repeat)) ? $this->notice : $this->repeat;

        if (!empty($user) &&
            ($todel->profile_id == $user->id || $user->hasRight(Right::DELETEOTHERSNOTICE))) {
            $this->out->text(' ');
            $deleteurl = common_local_url('deletenotice',
                                          array('notice' => $todel->id));
            $this->out->element('a', array('href' => $deleteurl,
                                           'class' => 'notice_delete',
                                           // TRANS: Link title in notice list item to delete a notice.
                                           'title' => _('Delete this notice from the timeline.')),
                                           // TRANS: Link text in notice list item to delete a notice.
                                           _('Delete'));
        }
    }

    /**
     * show the form to repeat a notice
     *
     * @return void
     */
    function showRepeatForm()
    {
        if ($this->notice->scope == Notice::PUBLIC_SCOPE ||
            $this->notice->scope == Notice::SITE_SCOPE) {
            $user = common_current_user();
            if (!empty($user) &&
                $user->id != $this->notice->profile_id) {
                $this->out->text(' ');
                $profile = $user->getProfile();
                if ($profile->hasRepeated($this->notice)) {
                    $this->out->element('span', array('class' => 'repeated',
                                                      // TRANS: Title for repeat form status in notice list when a notice has been repeated.
                                                      'title' => _('Notice repeated.')),
                                        // TRANS: Repeat form status in notice list when a notice has been repeated.
                                        _('Repeated'));
                } else {
                    $rf = new RepeatForm($this->out, $this->notice);
                    $rf->show();
                }
            }
        }
    }

    /**
     * finish the notice
     *
     * Close the last elements in the notice list item
     *
     * @return void
     */
    function showEnd()
    {
        if (Event::handle('StartCloseNoticeListItemElement', array($this))) {
            $this->out->elementEnd('li');
            Event::handle('EndCloseNoticeListItemElement', array($this));
        }
    }

    /**
     * Get the notice in question
     *
     * For hooks, etc., this may be useful
     *
     * @return Notice The notice we're showing
     */

    function getNotice()
    {
        return $this->notice;
    }
}


code:
<?php
/**
 * StatusNet - the distributed open-source microblogging tool
 * Copyright (C) 2011, StatusNet, Inc.
 *
 * For use by microapps to customize notice list item output
 *
 * PHP version 5
 *
 * 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  Microapp
 * @package   StatusNet
 * @author    Evan Prodromou <evan@status.net>
 * @copyright 2011 StatusNet, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
 * @link      http://status.net/
 */

if (!defined('STATUSNET')) {
    // This check helps protect against security problems;
    // your code file can't be executed directly from the web.
    exit(1);
}

/**
 * For use by microapps to customize NoticeListItem output
 *
 * @category  Microapp
 * @package   StatusNet
 * @author    Evan Prodromou <evan@status.net>
 * @copyright 2011 StatusNet, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
 * @link      http://status.net/
 */
class NoticeListItemAdapter
{
    protected $nli;

    /**
     * Wrap a notice list item.
     *
     * @param NoticeListItem $nli item to wrap
     */
    function __construct($nli)
    {
        $this->nli = $nli;
    }

    /**
     * Delegate unimplemented methods to the notice list item attribute.
     *
     * @param string $name      Name of the method
     * @param array  $arguments Arguments called
     *
     * @return mixed Return value of the method.
     */
    function __call($name, $arguments)
    {
        return call_user_func_array(array($this->nli, $name), $arguments);
    }

    function __get($name)
    {
        return $this->nli->$name;
    }
}


code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * Base class for sections showing lists of 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  Widget
 * @package   StatusNet
 * @author    Evan Prodromou <evan@status.net>
 * @copyright 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') && !defined('GNUSOCIAL')) { exit(1); }

define('NOTICES_PER_SECTION', 6);

/**
 * Base class for sections showing lists of notices
 *
 * These are the widgets that show interesting data about a person
 * group, or site.
 *
 * @todo migrate this to use a variant of NoticeList
 *
 * @category Widget
 * @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/
 */

abstract class NoticeSection extends Section
{
    protected $addressees = false;
    protected $attachments = false;
    protected $maxchars = 140;
    protected $options = false;
    protected $show_n = NOTICES_PER_SECTION;

    function showContent()
    {
        $prefs = array();
        foreach (array('addressees', 'attachments', 'maxchars', 'options', 'show_n') as $key) {
            $prefs[$key] = $this->$key;
        }
        $prefs['id_prefix'] = $this->divId();

        // args: notice object, html outputter, preference array for notice lists and their items
        $list = new NoticeList($this->getNotices(), $this->out, $prefs);
        $total = $list->show(); // returns total amount of notices available
        return ($total > $this->show_n);  // do we have more to show?
    }

    function getNotices()
    {
        return null;
    }
}


code:
<?php
/**
 * StatusNet - the distributed open-source microblogging tool
 * Copyright (C) 2011, StatusNet, Inc.
 *
 * A stream of notices
 *
 * PHP version 5
 *
 * 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  Stream
 * @package   StatusNet
 * @author    Evan Prodromou <evan@status.net>
 * @copyright 2011 StatusNet, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
 * @link      http://status.net/
 */

if (!defined('STATUSNET')) {
    // This check helps protect against security problems;
    // your code file can't be executed directly from the web.
    exit(1);
}

/**
 * Class for notice streams
 *
 * @category  Stream
 * @package   StatusNet
 * @author    Evan Prodromou <evan@status.net>
 * @copyright 2011 StatusNet, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
 * @link      http://status.net/
 */
abstract class NoticeStream
{
    // Will only get notices with the 'post' activityverb by default.
    protected $selectVerbs = array();

    public function __construct()
    {
        $this->selectVerbs = array(ActivityVerb::POST, ActivityUtils::resolveUri(ActivityVerb::POST, true));
    }

    abstract function getNoticeIds($offset, $limit, $since_id, $max_id);

    function getNotices($offset, $limit, $sinceId = null, $maxId = null)
    {
        $ids = $this->getNoticeIds($offset, $limit, $sinceId, $maxId);

        $notices = self::getStreamByIds($ids);

        return $notices;
    }

    static function getStreamByIds($ids)
    {
    	return Notice::multiGet('id', $ids);
    }
}


code:
<?php

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

/**
 * Parent class for an exception when a POST upload does not contain a file.
 *
 * @category Exception
 * @package  GNUsocial
 * @author   Mikael Nordfeldth <mmn@hethane.se>
 * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPLv3
 * @link     http://gnu.io/
 */

class NoUploadedMediaException extends ClientException
{
    public $fieldname = null;

    public function __construct($fieldname, $msg=null)
    {
        $this->fieldname = $fieldname;

        if ($msg === null) {
            // TRANS: Exception text shown when no uploaded media was provided in POST
            // TRANS: %s is the HTML input field name.
            $msg = sprintf(_('There is no uploaded media for input field "%s".'), $this->fieldname);
        }

        parent::__construct($msg, 400);
    }
}


code:
<?php
/**
 * GNU social - a federating social network
 *
 * class for when an object that's supposed to have a URI is missing it
 *
 * 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  Exception
 * @package   GNUsocial
 * @author    Mikael Nordfeldth <mmn@hethane.se>
 * @copyright 2014 Free Software Foundation, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPLv3
 * @link      https://www.gnu.org/software/social/
 */

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

class NoUriException extends ServerException
{
    var $object = null;

    public function __construct(Managed_DataObject $object)
    {
        $this->object = $object;
        $msg = get_class($object) . ' does not have a URI.';
        parent::__construct($msg);
    }
}