code:
# Translation file for GNU social - the free software social networking platform
# Copyright (C) 2010 - 2019 Free Software Foundation, Inc http://www.fsf.org
# This file is under https://www.gnu.org/licenses/agpl v3 or later
#
# Translators:
msgid ""
msgstr ""
"Project-Id-Version: GNU social\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-02-02 17:47+0100\n"
"PO-Revision-Date: 2015-02-07 09:42+0000\n"
"Last-Translator: digitaldreamer <digitaldreamer@email.cz>\n"
"Language-Team: Ukrainian (http://www.transifex.com/gnu-social/gnu-social/language/uk/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: uk\n"
"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"

#. TRANS: Plugin description.
#: PiwikAnalyticsPlugin.php:114
msgid ""
"Use Piwik Open Source web analytics "
"software."
msgstr "Використання програмного забезпечення з відкритим кодом Piwik для аналізу веб-потоків."


code:
# Translation file for GNU social - the free software social networking platform
# Copyright (C) 2015 - 2019 Free Software Foundation, Inc http://www.fsf.org
# This file is under https://www.gnu.org/licenses/agpl v3 or later
#
# Translators:
msgid ""
msgstr ""
"Project-Id-Version: GNU social\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-02-02 17:47+0100\n"
"PO-Revision-Date: 2015-02-07 09:35+0000\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: Urdu (Pakistan) (http://www.transifex.com/gnu-social/gnu-social/language/ur_PK/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: ur_PK\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"

#. TRANS: Plugin description.
#: PiwikAnalyticsPlugin.php:114
msgid ""
"Use Piwik Open Source web analytics "
"software."
msgstr ""

license: mit


code:
# Translation file for GNU social - the free software social networking platform
# Copyright (C) 2015 - 2019 Free Software Foundation, Inc http://www.fsf.org
# This file is under https://www.gnu.org/licenses/agpl v3 or later
#
# Translators:
msgid ""
msgstr ""
"Project-Id-Version: GNU social\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-02-02 17:47+0100\n"
"PO-Revision-Date: 2015-02-07 09:35+0000\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: Vietnamese (http://www.transifex.com/gnu-social/gnu-social/language/vi/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: vi\n"
"Plural-Forms: nplurals=1; plural=0;\n"

#. TRANS: Plugin description.
#: PiwikAnalyticsPlugin.php:114
msgid ""
"Use Piwik Open Source web analytics "
"software."
msgstr ""


code:
# Translation file for GNU social - the free software social networking platform
# Copyright (C) 2015 - 2019 Free Software Foundation, Inc http://www.fsf.org
# This file is under https://www.gnu.org/licenses/agpl v3 or later
#
# Translators:
msgid ""
msgstr ""
"Project-Id-Version: GNU social\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-02-02 17:47+0100\n"
"PO-Revision-Date: 2015-02-07 09:35+0000\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: Chinese (http://www.transifex.com/gnu-social/gnu-social/language/zh/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: zh\n"
"Plural-Forms: nplurals=1; plural=0;\n"

#. TRANS: Plugin description.
#: PiwikAnalyticsPlugin.php:114
msgid ""
"Use Piwik Open Source web analytics "
"software."
msgstr ""


code:
# Translation file for GNU social - the free software social networking platform
# Copyright (C) 2015 - 2019 Free Software Foundation, Inc http://www.fsf.org
# This file is under https://www.gnu.org/licenses/agpl v3 or later
#
# Translators:
msgid ""
msgstr ""
"Project-Id-Version: GNU social\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-02-02 17:47+0100\n"
"PO-Revision-Date: 2015-02-07 09:35+0000\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: Chinese (China) (http://www.transifex.com/gnu-social/gnu-social/language/zh_CN/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: zh_CN\n"
"Plural-Forms: nplurals=1; plural=0;\n"

#. TRANS: Plugin description.
#: PiwikAnalyticsPlugin.php:114
msgid ""
"Use Piwik Open Source web analytics "
"software."
msgstr ""


code:
# Translation file for GNU social - the free software social networking platform
# Copyright (C) 2015 - 2019 Free Software Foundation, Inc http://www.fsf.org
# This file is under https://www.gnu.org/licenses/agpl v3 or later
#
# Translators:
msgid ""
msgstr ""
"Project-Id-Version: GNU social\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-02-02 17:47+0100\n"
"PO-Revision-Date: 2015-02-07 09:35+0000\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: Chinese (Taiwan) (http://www.transifex.com/gnu-social/gnu-social/language/zh_TW/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: zh_TW\n"
"Plural-Forms: nplurals=1; plural=0;\n"

#. TRANS: Plugin description.
#: PiwikAnalyticsPlugin.php:114
msgid ""
"Use Piwik Open Source web analytics "
"software."
msgstr ""


code:
<?php
/**
 * StatusNet - the distributed open-source microblogging tool
 * Copyright (C) 2011, StatusNet, Inc.
 *
 * A plugin to enable social-bookmarking functionality
 *
 * 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  PollPlugin
 * @package   StatusNet
 * @author    Brion Vibber <brion@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')) {
    exit(1);
}

/**
 * Poll plugin main class
 *
 * @category  PollPlugin
 * @package   StatusNet
 * @author    Brion Vibber <brionv@status.net>
 * @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 PollPlugin extends MicroAppPlugin
{
    const PLUGIN_VERSION = '0.1.1';

    // @fixme which domain should we use for these namespaces?
    const POLL_OBJECT = 'http://activityschema.org/object/poll';
    const POLL_RESPONSE_OBJECT = 'http://activityschema.org/object/poll-response';

    public $oldSaveNew = true;

    /**
     * Database schema setup
     *
     * @return boolean hook value; true means continue processing, false means stop.
     * @see ColumnDef
     *
     * @see Schema
     */
    public function onCheckSchema()
    {
        $schema = Schema::get();
        $schema->ensureTable('poll', Poll::schemaDef());
        $schema->ensureTable('poll_response', Poll_response::schemaDef());
        $schema->ensureTable('user_poll_prefs', User_poll_prefs::schemaDef());
        return true;
    }

    /**
     * Show the CSS necessary for this plugin
     *
     * @param Action $action the action being run
     *
     * @return boolean hook value
     */
    public function onEndShowStyles($action)
    {
        $action->cssLink($this->path('css/poll.css'));
        return true;
    }

    /**
     * Map URLs to actions
     *
     * @param URLMapper $m path-to-action mapper
     *
     * @return boolean hook value; true means continue processing, false means stop.
     */
    public function onRouterInitialized(URLMapper $m)
    {
        $m->connect('main/poll/new',
                    ['action' => 'newpoll']);

        $m->connect('main/poll/:id',
                    ['action' => 'showpoll'],
                    ['id' => '[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}']);

        $m->connect('main/poll/response/:id',
                    ['action' => 'showpollresponse'],
                    ['id' => '[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}']);

        $m->connect('main/poll/:id/respond',
                    ['action' => 'respondpoll'],
                    ['id' => '[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}']);

        $m->connect('settings/poll',
                    ['action' => 'pollsettings']);

        return true;
    }

    /**
     * Plugin version data
     *
     * @param array &$versions array of version data
     *
     * @return bool true hook value
     * @throws Exception
     */
    public function onPluginVersion(array &$versions)
    {
        $versions[] = array('name' => 'Poll',
            'version' => self::PLUGIN_VERSION,
            'author' => 'Brion Vibber',
            'homepage' => 'https://git.gnu.io/gnu/gnu-social/tree/master/plugins/Poll',
            'rawdescription' =>
            // TRANS: Plugin description.
                _m('Simple extension for supporting basic polls.'));
        return true;
    }

    public function types()
    {
        return array(self::POLL_OBJECT, self::POLL_RESPONSE_OBJECT);
    }

    /**
     * When a notice is deleted, delete the related Poll
     *
     * @param Notice $notice Notice being deleted
     *
     * @return boolean hook value
     */
    public function deleteRelated(Notice $notice)
    {
        $p = Poll::getByNotice($notice);

        if (!empty($p)) {
            $p->delete();
        }

        return true;
    }

    /**
     * Save a poll from an activity
     *
     * @param Activity $activity Activity to save
     * @param Profile $profile Profile to use as author
     * @param array $options Options to pass to bookmark-saving code
     *
     * @return Notice resulting notice
     * @throws Exception if it failed
     */
    public function saveNoticeFromActivity(Activity $activity, Profile $profile, array $options = array())
    {
        // @fixme
        common_log(LOG_DEBUG, "XXX activity: " . var_export($activity, true));
        common_log(LOG_DEBUG, "XXX profile: " . var_export($profile, true));
        common_log(LOG_DEBUG, "XXX options: " . var_export($options, true));

        // Ok for now, we can grab stuff from the XML entry directly.
        // This won't work when reading from JSON source
        if ($activity->entry) {
            $pollElements = $activity->entry->getElementsByTagNameNS(self::POLL_OBJECT, 'poll');
            $responseElements = $activity->entry->getElementsByTagNameNS(self::POLL_OBJECT, 'response');
            if ($pollElements->length) {
                $question = '';
                $opts = [];

                $data = $pollElements->item(0);
                foreach ($data->getElementsByTagNameNS(self::POLL_OBJECT, 'question') as $node) {
                    $question = $node->textContent;
                }
                foreach ($data->getElementsByTagNameNS(self::POLL_OBJECT, 'option') as $node) {
                    $opts[] = $node->textContent;
                }
                try {
                    $notice = Poll::saveNew($profile, $question, $opts, $options);
                    common_log(LOG_DEBUG, "Saved Poll from ActivityStream data ok: notice id " . $notice->id);
                    return $notice;
                } catch (Exception $e) {
                    common_log(LOG_DEBUG, "Poll save from ActivityStream data failed: " . $e->getMessage());
                }
            } elseif ($responseElements->length) {
                $data = $responseElements->item(0);
                $pollUri = $data->getAttribute('poll');
                $selection = intval($data->getAttribute('selection'));

                if (!$pollUri) {
                    // TRANS: Exception thrown trying to respond to a poll without a poll reference.
                    throw new Exception(_m('Invalid poll response: No poll reference.'));
                }
                $poll = Poll::getKV('uri', $pollUri);
                if (!$poll) {
                    // TRANS: Exception thrown trying to respond to a non-existing poll.
                    throw new Exception(_m('Invalid poll response: Poll is unknown.'));
                }
                try {
                    $notice = Poll_response::saveNew($profile, $poll, $selection, $options);
                    common_log(LOG_DEBUG, "Saved Poll_response ok, notice id: " . $notice->id);
                    return $notice;
                } catch (Exception $e) {
                    common_log(LOG_DEBUG, "Poll response save fail: " . $e->getMessage());
                    // TRANS: Exception thrown trying to respond to a non-existing poll.
                }
            } else {
                common_log(LOG_DEBUG, "YYY no poll data");
            }
        }
        // If it didn't return before
        throw new ServerException(_m('Failed to save Poll response.'));
    }

    public function activityObjectFromNotice(Notice $notice)
    {
        assert($this->isMyNotice($notice));

        switch ($notice->object_type) {
            case self::POLL_OBJECT:
                return $this->activityObjectFromNoticePoll($notice);
            case self::POLL_RESPONSE_OBJECT:
                return $this->activityObjectFromNoticePollResponse($notice);
            default:
                // TRANS: Exception thrown when performing an unexpected action on a poll.
                // TRANS: %s is the unexpected object type.
                throw new Exception(sprintf(_m('Unexpected type for poll plugin: %s.'), $notice->object_type));
        }
    }

    public function activityObjectFromNoticePollResponse(Notice $notice)
    {
        $object = new ActivityObject();
        $object->id = $notice->uri;
        $object->type = self::POLL_RESPONSE_OBJECT;
        $object->title = $notice->content;
        $object->summary = $notice->content;
        $object->link = $notice->getUrl();

        $response = Poll_response::getByNotice($notice);
        if ($response) {
            $poll = $response->getPoll();
            if ($poll) {
                // Stash data to be formatted later by
                // $this->activityObjectOutputAtom() or
                // $this->activityObjectOutputJson()...
                $object->pollSelection = intval($response->selection);
                $object->pollUri = $poll->uri;
            }
        }
        return $object;
    }

    public function activityObjectFromNoticePoll(Notice $notice)
    {
        $object = new ActivityObject();
        $object->id = $notice->uri;
        $object->type = self::POLL_OBJECT;
        $object->title = $notice->content;
        $object->summary = $notice->content;
        $object->link = $notice->getUrl();

        $poll = Poll::getByNotice($notice);
        if ($poll) {
            // Stash data to be formatted later by
            // $this->activityObjectOutputAtom() or
            // $this->activityObjectOutputJson()...
            $object->pollQuestion = $poll->question;
            $object->pollOptions = $poll->getOptions();
        }

        return $object;
    }

    /**
     * Called when generating Atom XML ActivityStreams output from an
     * ActivityObject belonging to this plugin. Gives the plugin
     * a chance to add custom output.
     *
     * Note that you can only add output of additional XML elements,
     * not change existing stuff here.
     *
     * If output is already handled by the base Activity classes,
     * you can leave this base implementation as a no-op.
     *
     * @param ActivityObject $obj
     * @param XMLOutputter $out to add elements at end of object
     */
    public function activityObjectOutputAtom(ActivityObject $obj, XMLOutputter $out)
    {
        if (isset($obj->pollQuestion)) {
            /**
             * <poll:poll xmlns:poll="http://apinamespace.org/activitystreams/object/poll">
             *   <poll:question>Who wants a poll question?</poll:question>
             *   <poll:option>Option one</poll:option>
             *   <poll:option>Option two</poll:option>
             *   <poll:option>Option three</poll:option>
             * </poll:poll>
             */
            $data = array('xmlns:poll' => self::POLL_OBJECT);
            $out->elementStart('poll:poll', $data);
            $out->element('poll:question', array(), $obj->pollQuestion);
            foreach ($obj->pollOptions as $opt) {
                $out->element('poll:option', array(), $opt);
            }
            $out->elementEnd('poll:poll');
        }
        if (isset($obj->pollSelection)) {
            /**
             * <poll:response xmlns:poll="http://apinamespace.org/activitystreams/object/poll">
             *                poll="http://..../poll/...."
             *                selection="3" />
             */
            $data = array('xmlns:poll' => self::POLL_OBJECT,
                'poll' => $obj->pollUri,
                'selection' => $obj->pollSelection);
            $out->element('poll:response', $data, '');
        }
    }

    /**
     * Called when generating JSON ActivityStreams output from an
     * ActivityObject belonging to this plugin. Gives the plugin
     * a chance to add custom output.
     *
     * Modify the array contents to your heart's content, and it'll
     * all get serialized out as JSON.
     *
     * If output is already handled by the base Activity classes,
     * you can leave this base implementation as a no-op.
     *
     * @param ActivityObject $obj
     * @param array &$out JSON-targeted array which can be modified
     */
    public function activityObjectOutputJson(ActivityObject $obj, array &$out)
    {
        common_log(LOG_DEBUG, 'QQQ: ' . var_export($obj, true));
        if (isset($obj->pollQuestion)) {
            /**
             * "poll": {
             *   "question": "Who wants a poll question?",
             *   "options": [
             *     "Option 1",
             *     "Option 2",
             *     "Option 3"
             *   ]
             * }
             */
            $data = array('question' => $obj->pollQuestion,
                'options' => array());
            foreach ($obj->pollOptions as $opt) {
                $data['options'][] = $opt;
            }
            $out['poll'] = $data;
        }
        if (isset($obj->pollSelection)) {
            /**
             * "pollResponse": {
             *   "poll": "http://..../poll/....",
             *   "selection": 3
             * }
             */
            $data = array('poll' => $obj->pollUri,
                'selection' => $obj->pollSelection);
            $out['pollResponse'] = $data;
        }
    }

    public function entryForm($out)
    {
        return new NewPollForm($out);
    }

    // @fixme is this from parent?
    public function tag()
    {
        return 'poll';
    }

    public function appTitle()
    {
        // TRANS: Application title.
        return _m('APPTITLE', 'Poll');
    }

    public function onStartAddNoticeReply($nli, $parent, $child)
    {
        // Filter out any poll responses
        if ($parent->object_type == self::POLL_OBJECT &&
            $child->object_type == self::POLL_RESPONSE_OBJECT) {
            return false;
        }
        return true;
    }

    // Hide poll responses for @chuck

    public function onEndNoticeWhoGets($notice, &$ni)
    {
        if ($notice->object_type == self::POLL_RESPONSE_OBJECT) {
            foreach ($ni as $id => $source) {
                $user = User::getKV('id', $id);
                if (!empty($user)) {
                    $pollPrefs = User_poll_prefs::getKV('user_id', $user->id);
                    if (!empty($pollPrefs) && ($pollPrefs->hide_responses)) {
                        unset($ni[$id]);
                    }
                }
            }
        }
        return true;
    }

    /**
     * Menu item for personal subscriptions/groups area
     *
     * @param Action $action action being executed
     *
     * @return boolean hook return
     */

    public function onEndAccountSettingsNav($action)
    {
        $action_name = $action->trimmed('action');

        $action->menuItem(
            common_local_url('pollsettings'),
            // TRANS: Poll plugin menu item on user settings page.
            _m('MENU', 'Polls'),
            // TRANS: Poll plugin tooltip for user settings menu item.
            _m('Configure poll behavior'),
            $action_name === 'pollsettings'
        );

        return true;
    }

    protected function showNoticeContent(Notice $stored, HTMLOutputter $out, Profile $scoped = null)
    {
        if ($stored->object_type == self::POLL_RESPONSE_OBJECT) {
            parent::showNoticeContent($stored, $out, $scoped);
            return;
        }

        // If the stored notice is a POLL_OBJECT
        $poll = Poll::getByNotice($stored);
        if ($poll instanceof Poll) {
            if (!$scoped instanceof Profile || $poll->getResponse($scoped) instanceof Poll_response) {
                // Either the user is not logged in or it has already responded; show the results.
                $form = new PollResultForm($poll, $out);
            } else {
                $form = new PollResponseForm($poll, $out);
            }
            $form->show();
        } else {
            // TRANS: Error text displayed if no poll data could be found.
            $out->text(_m('Poll data is missing'));
        }
    }
}


code:
Unfinished basic stuff:
* make pretty graphs for response counts
* ActivityStreams output of poll data is temporary; the interfaces need more flexibility
* ActivityStreams input not done yet
* need link -> show results in addition to showing results if you already voted
* way to change/cancel your vote

Known issues:
* HTTP caching needs fixing on show-poll; may show you old data if you voted after

Things todo:
* should we allow anonymous responses? or ways for remote profiles to respond locally?

Fancier things todo:
* make sure backup/restore work
* make sure ostatus transfer works
* a way to do poll responses over ostatus directly?
* allow links, tags, @-references in poll question & answers? or not?

Storage todo:
* probably separate the options into a table instead of squishing them in a text blob

path: plugins/Poll/README


code:
<?php
/**
 * StatusNet - the distributed open-source microblogging tool
 * Copyright (C) 2011, StatusNet, Inc.
 *
 * Add a new Poll
 *
 * 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  Poll
 * @package   StatusNet
 * @author    Brion Vibber <brion@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);
}

/**
 * Add a new Poll
 *
 * @category  Poll
 * @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/
 */
class NewPollAction extends Action
{
    protected $user = null;
    protected $error = null;
    protected $complete = null;

    protected $question = null;
    protected $options = array();

    /**
     * Returns the title of the action
     *
     * @return string Action title
     * @throws Exception
     */
    public function title()
    {
        // TRANS: Title for poll page.
        return _m('New poll');
    }

    /**
     * For initializing members of the class.
     *
     * @param array $args misc. arguments
     *
     * @return boolean true
     * @throws ClientException
     */
    public function prepare(array $args = [])
    {
        parent::prepare($args);

        $this->user = common_current_user();

        if (empty($this->user)) {
            // TRANS: Client exception thrown trying to create a poll while not logged in.
            throw new ClientException(
                _m('You must be logged in to post a poll.'),
                403
            );
        }

        if ($this->isPost()) {
            $this->checkSessionToken();
        }

        $this->question = $this->trimmed('question');
        for ($i = 1; $i < 20; $i++) {
            $opt = $this->trimmed('option' . $i);
            if ($opt != '') {
                $this->options[] = $opt;
            }
        }

        return true;
    }

    /**
     * Handler method
     *
     * @return void
     * @throws ClientException
     * @throws InvalidUrlException
     * @throws ReflectionException
     * @throws ServerException
     */
    public function handle()
    {
        parent::handle();

        if ($this->isPost()) {
            $this->newPoll();
        } else {
            $this->showPage();
        }

        return;
    }

    /**
     * Add a new Poll
     *
     * @return void
     * @throws ClientException
     * @throws InvalidUrlException
     * @throws ReflectionException
     * @throws ServerException
     */
    public function newPoll()
    {
        if ($this->boolean('ajax')) {
            GNUsocial::setApi(true);
        }
        try {
            if (empty($this->question)) {
                // TRANS: Client exception thrown trying to create a poll without a question.
                throw new ClientException(_m('Poll must have a question.'));
            }

            if (count($this->options) < 2) {
                // TRANS: Client exception thrown trying to create a poll with fewer than two options.
                throw new ClientException(_m('Poll must have at least two options.'));
            }

            // Notice options; distinct from choices for the poll

            $options = array();

            // Does the heavy-lifting for getting "To:" information

            ToSelector::fillOptions($this, $options);

            $saved = Poll::saveNew(
                $this->user->getProfile(),
                $this->question,
                $this->options,
                $options
            );
        } catch (ClientException $ce) {
            $this->error = $ce->getMessage();
            $this->showPage();
            return;
        }

        if ($this->boolean('ajax')) {
            $this->startHTML('text/xml;charset=utf-8');
            $this->elementStart('head');
            // TRANS: Page title after sending a notice.
            $this->element('title', null, _m('Notice posted'));
            $this->elementEnd('head');
            $this->elementStart('body');
            $this->showNotice($saved);
            $this->elementEnd('body');
            $this->endHTML();
        } else {
            common_redirect($saved->getUrl(), 303);
        }
    }

    /**
     * Output a notice
     *
     * Used to generate the notice code for Ajax results.
     *
     * @param Notice $notice Notice that was saved
     *
     * @return void
     */
    public function showNotice(Notice $notice)
    {
        class_exists('NoticeList'); // @fixme hack for autoloader
        $nli = new NoticeListItem($notice, $this);
        $nli->show();
    }

    /**
     * Show the Poll form
     *
     * @return void
     */
    public function showContent()
    {
        if (!empty($this->error)) {
            $this->element('p', 'error', $this->error);
        }

        $form = new NewPollForm(
            $this,
            $this->question,
            $this->options
        );

        $form->show();

        return;
    }

    /**
     * Return true if read only.
     *
     * MAY override
     *
     * @param array $args other arguments
     *
     * @return boolean is read only action?
     */
    public function isReadOnly($args)
    {
        if ($_SERVER['REQUEST_METHOD'] == 'GET' ||
            $_SERVER['REQUEST_METHOD'] == 'HEAD') {
            return true;
        } else {
            return false;
        }
    }
}


code:
<?php
/**
 * Form to set your personal poll settings
 *
 * StatusNet, the distributed open-source microblogging tool
 *
 * 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  Plugins
 * @package   StatusNet
 * @author    Brion Vibber <brion@status.net>
 * @copyright 2012 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);
}

class PollSettingsAction extends SettingsAction
{
    /**
     * Title of the page
     *
     * @return string Page title
     */
    public function title()
    {
        // TRANS: Page title.
        return _m('Poll settings');
    }

    /**
     * Instructions for use
     *
     * @return string Instructions for use
     */

    public function getInstructions()
    {
        // TRANS: Page instructions.
        return _m('Set your poll preferences');
    }

    protected function getForm()
    {
        $prefs = User_poll_prefs::getKV('user_id', $this->scoped->getID());
        $form = new PollPrefsForm($this, $prefs ? $prefs : null);
        return $form;
    }

    protected function doPost()
    {
        $upp = User_poll_prefs::getKV('user_id', $this->scoped->getID());
        $orig = null;

        if ($upp instanceof User_poll_prefs) {
            $orig = clone($upp);
        } else {
            $upp = new User_poll_prefs();
            $upp->user_id = $this->scoped->getID();
            $upp->created = common_sql_now();
        }

        $upp->hide_responses = $this->boolean('hide_responses');
        $upp->modified = common_sql_now();

        if ($orig instanceof User_poll_prefs) {
            $upp->update($orig);
        } else {
            $upp->insert();
        }

        // TRANS: Confirmation shown when user profile settings are saved.
        return _('Settings saved.');
    }
}


code:
<?php
/**
 * StatusNet - the distributed open-source microblogging tool
 * Copyright (C) 2011, StatusNet, Inc.
 *
 * Respond to a Poll
 *
 * 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  Poll
 * @package   StatusNet
 * @author    Brion Vibber <brion@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);
}

/**
 * Respond to a Poll
 *
 * @category  Poll
 * @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/
 */
class RespondPollAction extends Action
{
    protected $user = null;
    protected $error = null;
    protected $complete = null;

    protected $poll = null;
    protected $selection = null;

    /**
     * Returns the title of the action
     *
     * @return string Action title
     * @throws Exception
     */
    public function title()
    {
        // TRANS: Page title for poll response.
        return _m('Poll response');
    }

    /**
     * For initializing members of the class.
     *
     * @param array $args misc. arguments
     *
     * @return boolean true
     * @throws ClientException
     * @throws Exception
     * @throws Exception
     */
    public function prepare(array $args = [])
    {
        parent::prepare($args);
        if ($this->boolean('ajax')) {
            GNUsocial::setApi(true);
        }

        $this->user = common_current_user();

        if (empty($this->user)) {
            // TRANS: Client exception thrown trying to respond to a poll while not logged in.
            throw new ClientException(
                _m('You must be logged in to respond to a poll.'),
                403
            );
        }

        if ($this->isPost()) {
            $this->checkSessionToken();
        }

        $id = $this->trimmed('id');
        $this->poll = Poll::getKV('id', $id);
        if (empty($this->poll)) {
            // TRANS: Client exception thrown trying to respond to a non-existing poll.
            throw new ClientException(_m('Invalid or missing poll.'), 404);
        }

        $selection = intval($this->trimmed('pollselection'));
        if ($selection < 1 || $selection > count($this->poll->getOptions())) {
            // TRANS: Client exception thrown responding to a poll with an invalid answer.
            throw new ClientException(_m('Invalid poll selection.'));
        }
        $this->selection = $selection;

        return true;
    }

    /**
     * Handler method
     *
     * @return void
     * @throws ClientException
     * @throws ReflectionException
     * @throws ServerException
     */
    public function handle()
    {
        parent::handle();

        if ($this->isPost()) {
            $this->respondPoll();
        } else {
            $this->showPage();
        }

        return;
    }

    /**
     * Add a new Poll
     *
     * @return void
     * @throws ClientException
     * @throws ReflectionException
     * @throws ServerException
     */
    public function respondPoll()
    {
        try {
            Poll_response::saveNew(
                $this->user->getProfile(),
                $this->poll,
                $this->selection
            );
        } catch (ClientException $ce) {
            $this->error = $ce->getMessage();
            $this->showPage();
            return;
        }

        if ($this->boolean('ajax')) {
            $this->startHTML('text/xml;charset=utf-8');
            $this->elementStart('head');
            // TRANS: Page title after sending a poll response.
            $this->element('title', null, _m('Poll results'));
            $this->elementEnd('head');
            $this->elementStart('body');
            $form = new PollResultForm($this->poll, $this);
            $form->show();
            $this->elementEnd('body');
            $this->endHTML();
        } else {
            common_redirect($this->poll->getUrl(), 303);
        }
    }

    /**
     * Show the Poll form
     *
     * @return void
     */
    public function showContent()
    {
        if (!empty($this->error)) {
            $this->element('p', 'error', $this->error);
        }

        $form = new PollResponseForm($this->poll, $this);

        $form->show();

        return;
    }

    /**
     * Return true if read only.
     *
     * MAY override
     *
     * @param array $args other arguments
     *
     * @return boolean is read only action?
     */
    public function isReadOnly($args)
    {
        if ($_SERVER['REQUEST_METHOD'] == 'GET' ||
            $_SERVER['REQUEST_METHOD'] == 'HEAD') {
            return true;
        } else {
            return false;
        }
    }
}


code:
<?php
/**
 * StatusNet - the distributed open-source microblogging tool
 * Copyright (C) 2011, StatusNet, Inc.
 *
 * Show a single Poll
 *
 * 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  PollPlugin
 * @package   StatusNet
 * @author    Brion Vibber <brion@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);
}

/**
 * Show a single Poll, with associated information
 *
 * @category  PollPlugin
 * @package   StatusNet
 * @author    Brion Vibber <brion@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 ShowPollAction extends ShownoticeAction
{
    protected $poll = null;

    public function getNotice()
    {
        $this->id = $this->trimmed('id');

        $this->poll = Poll::getKV('id', $this->id);

        if (empty($this->poll)) {
            // TRANS: Client exception thrown trying to view a non-existing poll.
            throw new ClientException(_m('No such poll.'), 404);
        }

        $notice = $this->poll->getNotice();

        if (empty($notice)) {
            // Did we used to have it, and it got deleted?
            // TRANS: Client exception thrown trying to view a non-existing poll notice.
            throw new ClientException(_m('No such poll notice.'), 404);
        }

        return $notice;
    }

    /**
     * Title of the page
     *
     * Used by Action class for layout.
     *
     * @return string page tile
     */
    public function title()
    {
        // TRANS: Page title for a poll.
        // TRANS: %1$s is the nickname of the user that created the poll, %2$s is the poll question.
        return sprintf(
            _m('%1$s\'s poll: %2$s'),
            $this->user->nickname,
            $this->poll->question
        );
    }

    /**
     * @fixme combine the notice time with poll update time
     */
    public function lastModified()
    {
        return Action::lastModified();
    }

    /**
     * @fixme combine the notice time with poll update time
     */
    public function etag()
    {
        return Action::etag();
    }
}


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

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

/**
 * For storing the poll options and such
 *
 * @category PollPlugin
 * @package  StatusNet
 * @author   Brion Vibber <brion@status.net>
 * @license  http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
 * @link     http://status.net/
 *
 * @see      DB_DataObject
 */
class Poll extends Managed_DataObject
{
    public $__table = 'poll'; // table name
    public $id;          // char(36) primary key not null -> UUID
    public $uri;         // varchar(191)   not 255 because utf8mb4 takes more space
    public $profile_id;  // int -> profile.id
    public $question;    // text
    public $options;     // text; newline(?)-delimited
    public $created;     // datetime

    /**
     * The One True Thingy that must be defined and declared.
     */
    public static function schemaDef()
    {
        return array(
            'description' => 'Per-notice poll data for Poll plugin',
            'fields' => array(
                'id' => array('type' => 'char', 'length' => 36, 'not null' => true, 'description' => 'UUID'),
                'uri' => array('type' => 'varchar', 'length' => 191, 'not null' => true),
                'profile_id' => array('type' => 'int'),
                'question' => array('type' => 'text'),
                'options' => array('type' => 'text'),
                'created' => array('type' => 'datetime', 'not null' => true),
            ),
            'primary key' => array('id'),
            'unique keys' => array(
                'poll_uri_key' => array('uri'),
            ),
        );
    }

    /**
     * Get a bookmark based on a notice
     *
     * @param Notice $notice Notice to check for
     *
     * @return get_called_class found poll or null
     */
    public static function getByNotice($notice)
    {
        return self::getKV('uri', $notice->uri);
    }

    public function getOptions()
    {
        return explode("\n", $this->options);
    }

    /**
     * Is this a valid selection index?
     *
     * @param int $selection (1-based)
     * @return boolean
     */
    public function isValidSelection($selection)
    {
        if ($selection != intval($selection)) {
            return false;
        }
        if ($selection < 1 || $selection > count($this->getOptions())) {
            return false;
        }
        return true;
    }

    public function getNotice()
    {
        return Notice::getKV('uri', $this->uri);
    }

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

    /**
     * Get the response of a particular user to this poll, if any.
     *
     * @param Profile $profile
     * @return get_called_class object or null
     */
    public function getResponse(Profile $profile)
    {
        $pr = Poll_response::pkeyGet(array('poll_id' => $this->id,
            'profile_id' => $profile->id));
        return $pr;
    }

    public function countResponses()
    {
        $pr = new Poll_response();
        $pr->poll_id = $this->id;
        $pr->groupBy('selection');
        $pr->selectAdd('count(profile_id) as votes');
        $pr->find();

        $raw = array();
        while ($pr->fetch()) {
            // Votes list 1-based
            // Array stores 0-based
            $raw[$pr->selection - 1] = $pr->votes;
        }

        $counts = array();
        foreach (array_keys($this->getOptions()) as $key) {
            if (isset($raw[$key])) {
                $counts[$key] = $raw[$key];
            } else {
                $counts[$key] = 0;
            }
        }
        return $counts;
    }

    /**
     * Save a new poll notice
     *
     * @param Profile $profile
     * @param string $question
     * @param array $opts (poll responses)
     *
     * @param null $options
     * @return Notice saved notice
     * @throws ClientException
     */
    public static function saveNew($profile, $question, $opts, $options = null)
    {
        if (empty($options)) {
            $options = array();
        }

        $p = new Poll();

        $p->id = UUID::gen();
        $p->profile_id = $profile->id;
        $p->question = $question;
        $p->options = implode("\n", $opts);

        if (array_key_exists('created', $options)) {
            $p->created = $options['created'];
        } else {
            $p->created = common_sql_now();
        }

        if (array_key_exists('uri', $options)) {
            $p->uri = $options['uri'];
        } else {
            $p->uri = common_local_url(
                'showpoll',
                array('id' => $p->id)
            );
        }

        common_log(LOG_DEBUG, "Saving poll: $p->id $p->uri");
        $p->insert();

        // TRANS: Notice content creating a poll.
        // TRANS: %1$s is the poll question, %2$s is a link to the poll.
        $content = sprintf(
            _m('Poll: %1$s %2$s'),
            $question,
            $p->uri
        );
        $link = 'uri) . '">' . htmlspecialchars($question) . '';
        // TRANS: Rendered version of the notice content creating a poll.
        // TRANS: %s is a link to the poll with the question as link description.
        $rendered = sprintf(_m('Poll: %s'), $link);

        $tags = array('poll');
        $replies = array();

        $options = array_merge(
            array('urls' => array(),
                'rendered' => $rendered,
                'tags' => $tags,
                'replies' => $replies,
                'object_type' => PollPlugin::POLL_OBJECT),
            $options
        );

        if (!array_key_exists('uri', $options)) {
            $options['uri'] = $p->uri;
        }

        $saved = Notice::saveNew(
            $profile->id,
            $content,
            array_key_exists('source', $options) ?
                $options['source'] : 'web',
            $options
        );

        return $saved;
    }
}


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

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

/**
 * For storing the poll options and such
 *
 * @category PollPlugin
 * @package  StatusNet
 * @author   Brion Vibber <brion@status.net>
 * @license  http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
 * @link     http://status.net/
 *
 * @see      DB_DataObject
 */
class Poll_response extends Managed_DataObject
{
    public $__table = 'poll_response'; // table name
    public $id;          // char(36) primary key not null -> UUID
    public $uri;         // varchar(191)   not 255 because utf8mb4 takes more space
    public $poll_id;     // char(36) -> poll.id UUID
    public $profile_id;  // int -> profile.id
    public $selection;   // int -> choice #
    public $created;     // datetime

    /**
     * The One True Thingy that must be defined and declared.
     */
    public static function schemaDef()
    {
        return array(
            'description' => 'Record of responses to polls',
            'fields' => array(
                'id' => array('type' => 'char', 'length' => 36, 'not null' => true, 'description' => 'UUID of the response'),
                'uri' => array('type' => 'varchar', 'length' => 191, 'not null' => true, 'description' => 'UUID to the response notice'),
                'poll_id' => array('type' => 'char', 'length' => 36, 'not null' => true, 'description' => 'UUID of poll being responded to'),
                'profile_id' => array('type' => 'int'),
                'selection' => array('type' => 'int'),
                'created' => array('type' => 'datetime', 'not null' => true),
            ),
            'primary key' => array('id'),
            'unique keys' => array(
                'poll_uri_key' => array('uri'),
                'poll_response_poll_id_profile_id_key' => array('poll_id', 'profile_id'),
            ),
            'indexes' => array(
                'poll_response_profile_id_poll_id_index' => array('profile_id', 'poll_id'),
            )
        );
    }

    /**
     * Get a poll response based on a notice
     *
     * @param Notice $notice Notice to check for
     *
     * @return get_called_class found response or null
     */
    public static function getByNotice($notice)
    {
        return self::getKV('uri', $notice->uri);
    }

    /**
     * Get the notice that belongs to this response...
     *
     * @return get_called_class
     */
    public function getNotice()
    {
        return Notice::getKV('uri', $this->uri);
    }

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

    /**
     *
     * @return get_called_class
     */
    public function getPoll()
    {
        return Poll::getKV('id', $this->poll_id);
    }

    /**
     * Save a new poll notice
     *
     * @param Profile $profile
     * @param Poll $poll the poll being responded to
     * @param int $selection (1-based)
     * @param null $options
     * @return Notice saved notice
     * @throws ClientException
     */
    public static function saveNew($profile, $poll, $selection, $options = null)
    {
        if (empty($options)) {
            $options = [];
        }

        if (!$poll->isValidSelection($selection)) {
            // TRANS: Client exception thrown when responding to a poll with an invalid option.
            throw new ClientException(_m('Invalid poll selection.'));
        }
        $opts = $poll->getOptions();
        $answer = $opts[$selection - 1];

        $pr = new Poll_response();
        $pr->id = UUID::gen();
        $pr->profile_id = $profile->id;
        $pr->poll_id = $poll->id;
        $pr->selection = $selection;

        if (array_key_exists('created', $options)) {
            $pr->created = $options['created'];
        } else {
            $pr->created = common_sql_now();
        }

        if (array_key_exists('uri', $options)) {
            $pr->uri = $options['uri'];
        } else {
            $pr->uri = common_local_url(
                'showpollresponse',
                array('id' => $pr->id)
            );
        }

        common_log(LOG_DEBUG, "Saving poll response: $pr->id $pr->uri");
        $pr->insert();

        // TRANS: Notice content voting for a poll.
        // TRANS: %s is the chosen option in the poll.
        $content = sprintf(
            _m('voted for "%s"'),
            $answer
        );
        $link = 'uri) . '">' . htmlspecialchars($answer) . '';
        // TRANS: Rendered version of the notice content voting for a poll.
        // TRANS: %s a link to the poll with the chosen option as link description.
        $rendered = sprintf(_m('voted for "%s"'), $link);

        $tags = array();

        $options = array_merge(
            array('urls' => array(),
                'rendered' => $rendered,
                'tags' => $tags,
                'reply_to' => $poll->getNotice()->id,
                'object_type' => PollPlugin::POLL_RESPONSE_OBJECT),
            $options
        );

        if (!array_key_exists('uri', $options)) {
            $options['uri'] = $pr->uri;
        }

        $saved = Notice::saveNew(
            $profile->id,
            $content,
            array_key_exists('source', $options) ?
                $options['source'] : 'web',
            $options
        );

        return $saved;
    }
}


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

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

/**
 * For storing the poll prefs
 *
 * @category PollPlugin
 * @package  StatusNet
 * @author   Brion Vibber <brion@status.net>
 * @license  http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
 * @link     http://status.net/
 *
 * @see      DB_DataObject
 */
class User_poll_prefs extends Managed_DataObject
{
    public $__table = 'user_poll_prefs'; // table name
    public $user_id;          // int id
    public $hide_responses;   // boolean
    public $created;          // datetime
    public $modified;         // datetime

    /**
     * The One True Thingy that must be defined and declared.
     */
    public static function schemaDef()
    {
        return array(
            'description' => 'Record of user preferences for polls',
            'fields' => array(
                'user_id' => array('type' => 'int', 'not null' => true, 'description' => 'user id'),
                'hide_responses' => array('type' => 'int', 'size' => 'tiny', 'default' => 0, 'description' => 'Hide all poll responses'),
                'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),
                'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),
            ),
            'primary key' => array('user_id')
        );
    }
}


code:
<?php
/**
 * StatusNet - the distributed open-source microblogging tool
 * Copyright (C) 2011, StatusNet, Inc.
 *
 * Form for adding a new poll
 *
 * 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  PollPlugin
 * @package   StatusNet
 * @author    Brion Vibber <brion@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);
}

/**
 * Form to add a new poll thingy
 *
 * @category  PollPlugin
 * @package   StatusNet
 * @author    Brion Vibber <brion@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 NewpollForm extends Form
{
    protected $question = null;
    protected $options = array();

    /**
     * Construct a new poll form
     *
     * @param HTMLOutputter $out output channel
     *
     * @param null $question
     * @param null $options
     */
    public function __construct(HTMLOutputter $out = null, $question = null, $options = null)
    {
        parent::__construct($out);
    }

    /**
     * ID of the form
     *
     * @return int ID of the form
     */
    public function id()
    {
        return 'newpoll-form';
    }

    /**
     * class of the form
     *
     * @return string class of the form
     */
    public function formClass()
    {
        return 'form_settings ajax-notice';
    }

    /**
     * Action of the form
     *
     * @return string URL of the action
     */
    public function action()
    {
        return common_local_url('newpoll');
    }

    /**
     * Data elements of the form
     *
     * @return void
     */
    public function formData()
    {
        $this->out->elementStart('fieldset', array('id' => 'newpoll-data'));
        $this->out->elementStart('ul', 'form_data');

        $this->li();
        $this->out->input(
            'question',
            // TRANS: Field label on the page to create a poll.
            _m('Question'),
            $this->question,
            // TRANS: Field title on the page to create a poll.
            _m('What question are people answering?'),
            'question',
            true
        );    // HTML5 "required" attribute
        $this->unli();

        $max = 5;
        if (count($this->options) + 1 > $max) {
            $max = count($this->options) + 2;
        }
        for ($i = 0; $i < $max; $i++) {
            // @fixme make extensible
            if (isset($this->options[$i])) {
                $default = $this->options[$i];
            } else {
                $default = '';
            }
            $this->li();
            $this->out->input(
                'poll-option' . ($i + 1),
                // TRANS: Field label for an answer option on the page to create a poll.
                // TRANS: %d is the option number.
                sprintf(_m('Option %d'), $i + 1),
                $default,
                null,
                'option' . ($i + 1),
                $i < 2
            );   // HTML5 "required" attribute for 2 options
            $this->unli();
        }

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

        $toWidget = new ToSelector(
            $this->out,
            common_current_user(),
            null
        );
        $toWidget->show();

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

    /**
     * Action elements
     *
     * @return void
     */
    public function formActions()
    {
        // TRANS: Button text for saving a new poll.
        $this->out->submit('poll-submit', _m('BUTTON', 'Save'), 'submit', 'submit');
    }
}


code:
<?php

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

class PollPrefsForm extends Form
{
    public function __construct(Action $out, User_poll_prefs $prefs = null)
    {
        parent::__construct($out);
        $this->prefs = $prefs;
    }

    /**
     * Visible or invisible data elements
     *
     * Display the form fields that make up the data of the form.
     * Sub-classes should overload this to show their data.
     *
     * @return void
     */

    public function formData()
    {
        $this->elementStart('fieldset');
        $this->elementStart('ul', 'form_data');
        $this->elementStart('li');
        $this->checkbox(
            'hide_responses',
            _('Do not deliver poll responses to my home timeline'),
            ($this->prefs instanceof User_poll_prefs && $this->prefs->hide_responses)
        );
        $this->elementEnd('li');
        $this->elementEnd('ul');
        $this->elementEnd('fieldset');
    }

    /**
     * Buttons for form actions
     *
     * Submit and cancel buttons (or whatever)
     * Sub-classes should overload this to show their own buttons.
     *
     * @return void
     */

    public function formActions()
    {
        $this->submit('submit', _('Save'));
    }

    /**
     * ID of the form
     *
     * Should be unique on the page. Sub-classes should overload this
     * to show their own IDs.
     *
     * @return int ID of the form
     */

    public function id()
    {
        return 'form_poll_prefs';
    }

    /**
     * Action of the form.
     *
     * URL to post to. Should be overloaded by subclasses to give
     * somewhere to post to.
     *
     * @return string URL to post to
     */

    public function action()
    {
        return common_local_url('pollsettings');
    }

    /**
     * Class of the form. May include space-separated list of multiple classes.
     *
     * @return string the form's class
     */

    public function formClass()
    {
        return 'form_settings';
    }
}


code:
<?php
/**
 * StatusNet - the distributed open-source microblogging tool
 * Copyright (C) 2011, StatusNet, Inc.
 *
 * Form for adding a new poll
 *
 * 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  PollPlugin
 * @package   StatusNet
 * @author    Brion Vibber <brion@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);
}

/**
 * Form to add a new poll thingy
 *
 * @category  PollPlugin
 * @package   StatusNet
 * @author    Brion Vibber <brion@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 PollResponseForm extends Form
{
    protected $poll;

    /**
     * Construct a new poll form
     *
     * @param Poll $poll
     * @param HTMLOutputter $out output channel
     *
     * @return void
     */
    public function __construct(Poll $poll, HTMLOutputter $out)
    {
        parent::__construct($out);
        $this->poll = $poll;
    }

    /**
     * ID of the form
     *
     * @return int ID of the form
     */
    public function id()
    {
        return 'pollresponse-form';
    }

    /**
     * class of the form
     *
     * @return string class of the form
     */
    public function formClass()
    {
        return 'form_settings ajax';
    }

    /**
     * Action of the form
     *
     * @return string URL of the action
     */
    public function action()
    {
        return common_local_url('respondpoll', array('id' => $this->poll->id));
    }

    /**
     * Data elements of the form
     *
     * @return void
     */
    public function formData()
    {
        $poll = $this->poll;
        $out = $this->out;

        $out->element('p', 'poll-question', $poll->question);
        $out->elementStart('ul', 'poll-options');
        foreach ($poll->getOptions() as $i => $opt) {
            $out->elementStart('li');
            $out->elementStart('label');
            $out->element('input', ['type' => 'radio', 'name' => 'pollselection', 'value' => $i + 1], '');
            $out->text(' ' . $opt);
            $out->elementEnd('label');
            $out->elementEnd('li');
        }
        $out->elementEnd('ul');
    }

    /**
     * Action elements
     *
     * @return void
     */
    public function formActions()
    {
        // TRANS: Button text for submitting a poll response.
        $this->out->submit('poll-response-submit', _m('BUTTON', 'Submit'), 'submit', 'submit');
    }
}


code:
<?php
/**
 * StatusNet - the distributed open-source microblogging tool
 * Copyright (C) 2011, StatusNet, Inc.
 *
 * Form for adding a new poll
 *
 * 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  PollPlugin
 * @package   StatusNet
 * @author    Brion Vibber <brion@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);
}

/**
 * Form to add a new poll thingy
 *
 * @category  PollPlugin
 * @package   StatusNet
 * @author    Brion Vibber <brion@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 PollResultForm extends Form
{
    protected $poll;

    /**
     * Construct a new poll form
     *
     * @param Poll $poll
     * @param HTMLOutputter $out output channel
     *
     * @return void
     */
    public function __construct(Poll $poll, HTMLOutputter $out)
    {
        parent::__construct($out);
        $this->poll = $poll;
    }

    /**
     * ID of the form
     *
     * @return int ID of the form
     */
    public function id()
    {
        return 'pollresult-form';
    }

    /**
     * class of the form
     *
     * @return string class of the form
     */
    public function formClass()
    {
        return 'form_settings ajax';
    }

    /**
     * Action of the form
     *
     * @return string URL of the action
     */
    public function action()
    {
        return common_local_url('respondpoll', array('id' => $this->poll->id));
    }

    /**
     * Data elements of the form
     *
     * @return void
     */
    public function formData()
    {
        $poll = $this->poll;
        $out = $this->out;
        $counts = $poll->countResponses();

        $width = 200;
        $max = max($counts);
        if ($max == 0) {
            $max = 1; // quick hack :D
        }

        $out->element('p', 'poll-question', $poll->question);
        $out->elementStart('table', 'poll-results');
        foreach ($poll->getOptions() as $i => $opt) {
            $w = intval($counts[$i] * $width / $max) + 1;

            $out->elementStart('tr');

            $out->elementStart('td');
            $out->text($opt);
            $out->elementEnd('td');

            $out->elementStart('td');
            $out->element(
                'span',
                array('class' => 'poll-block',
                    'style' => "width: {$w}px"),
                "\xc2\xa0"
            ); // nbsp
            $out->text($counts[$i]);
            $out->elementEnd('td');

            $out->elementEnd('tr');
        }
        $out->elementEnd('table');
    }

    /**
     * Action elements
     *
     * @return void
     */
    public function formActions()
    {
    }
}


code:
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2019-06-08 18:20+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=CHARSET\n"
"Content-Transfer-Encoding: 8bit\n"

#. TRANS: Page title for poll response.
#: actions/respondpoll.php:63
msgid "Poll response"
msgstr ""

#. TRANS: Client exception thrown trying to respond to a poll while not logged in.
#: actions/respondpoll.php:85
msgid "You must be logged in to respond to a poll."
msgstr ""

#. TRANS: Client exception thrown trying to respond to a non-existing poll.
#: actions/respondpoll.php:97
msgid "Invalid or missing poll."
msgstr ""

#. TRANS: Client exception thrown responding to a poll with an invalid answer.
#. TRANS: Client exception thrown when responding to a poll with an invalid option.
#: actions/respondpoll.php:103 classes/Poll_response.php:134
msgid "Invalid poll selection."
msgstr ""

#. TRANS: Page title after sending a poll response.
#: actions/respondpoll.php:149
msgid "Poll results"
msgstr ""

#. TRANS: Title for poll page.
#: actions/newpoll.php:63
msgid "New poll"
msgstr ""

#. TRANS: Client exception thrown trying to create a poll while not logged in.
#: actions/newpoll.php:82
msgid "You must be logged in to post a poll."
msgstr ""

#. TRANS: Client exception thrown trying to create a poll without a question.
#: actions/newpoll.php:132
msgid "Poll must have a question."
msgstr ""

#. TRANS: Client exception thrown trying to create a poll with fewer than two options.
#: actions/newpoll.php:137
msgid "Poll must have at least two options."
msgstr ""

#. TRANS: Page title after sending a notice.
#: actions/newpoll.php:163
msgid "Notice posted"
msgstr ""

#. TRANS: Page title.
#: actions/pollsettings.php:42
msgid "Poll settings"
msgstr ""

#. TRANS: Page instructions.
#: actions/pollsettings.php:54
msgid "Set your poll preferences"
msgstr ""

#. TRANS: Client exception thrown trying to view a non-existing poll.
#: actions/showpoll.php:59
msgid "No such poll."
msgstr ""

#. TRANS: Client exception thrown trying to view a non-existing poll notice.
#: actions/showpoll.php:67
msgid "No such poll notice."
msgstr ""

#. TRANS: Page title for a poll.
#. TRANS: %1$s is the nickname of the user that created the poll, %2$s is the poll question.
#: actions/showpoll.php:84
#, php-format
msgid "%1$s's poll: %2$s"
msgstr ""

#. TRANS: Notice content creating a poll.
#. TRANS: %1$s is the poll question, %2$s is a link to the poll.
#: classes/Poll.php:201
#, php-format
msgid "Poll: %1$s %2$s"
msgstr ""

#. TRANS: Rendered version of the notice content creating a poll.
#. TRANS: %s is a link to the poll with the question as link description.
#: classes/Poll.php:207
#, php-format
msgid "Poll: %s"
msgstr ""

#. TRANS: Notice content voting for a poll.
#. TRANS: %s is the chosen option in the poll.
#. TRANS: Rendered version of the notice content voting for a poll.
#. TRANS: %s a link to the poll with the chosen option as link description.
#: classes/Poll_response.php:163 classes/Poll_response.php:168
#, php-format
msgid "voted for \"%s\""
msgstr ""

#. TRANS: Plugin description.
#: PollPlugin.php:131
msgid "Simple extension for supporting basic polls."
msgstr ""

#. TRANS: Exception thrown trying to respond to a poll without a poll reference.
#: PollPlugin.php:204
msgid "Invalid poll response: No poll reference."
msgstr ""

#. TRANS: Exception thrown trying to respond to a non-existing poll.
#: PollPlugin.php:209
msgid "Invalid poll response: Poll is unknown."
msgstr ""

#. TRANS: Exception thrown when performing an unexpected action on a poll.
#. TRANS: %s is the unexpected object type.
#: PollPlugin.php:236
#, php-format
msgid "Unexpected type for poll plugin: %s."
msgstr ""

#. TRANS: Application title.
#: PollPlugin.php:392
msgctxt "APPTITLE"
msgid "Poll"
msgstr ""

#. TRANS: Poll plugin menu item on user settings page.
#: PollPlugin.php:436
msgctxt "MENU"
msgid "Polls"
msgstr ""

#. TRANS: Poll plugin tooltip for user settings menu item.
#: PollPlugin.php:438
msgid "Configure poll behavior"
msgstr ""

#. TRANS: Error text displayed if no poll data could be found.
#: PollPlugin.php:463
msgid "Poll data is missing"
msgstr ""

#. TRANS: Button text for submitting a poll response.
#: forms/pollresponse.php:127
msgctxt "BUTTON"
msgid "Submit"
msgstr ""

#. TRANS: Field label on the page to create a poll.
#: forms/newpoll.php:107
msgid "Question"
msgstr ""

#. TRANS: Field title on the page to create a poll.
#: forms/newpoll.php:110
msgid "What question are people answering?"
msgstr ""

#. TRANS: Field label for an answer option on the page to create a poll.
#. TRANS: %d is the option number.
#: forms/newpoll.php:130
#, php-format
msgid "Option %d"
msgstr ""

#. TRANS: Button text for saving a new poll.
#: forms/newpoll.php:156
msgctxt "BUTTON"
msgid "Save"
msgstr ""


code:
# Translation file for GNU social - the free software social networking platform
# Copyright (C) 2015 - 2019 Free Software Foundation, Inc http://www.fsf.org
# This file is under https://www.gnu.org/licenses/agpl v3 or later
#
# Translators:
msgid ""
msgstr ""
"Project-Id-Version: GNU social\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-02-02 17:47+0100\n"
"PO-Revision-Date: 2015-02-05 16:27+0000\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: Afrikaans (http://www.transifex.com/gnu-social/gnu-social/language/af/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: af\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"

#. TRANS: Field label on the page to create a poll.
#: forms/newpoll.php:107
msgid "Question"
msgstr ""

#. TRANS: Field title on the page to create a poll.
#: forms/newpoll.php:110
msgid "What question are people answering?"
msgstr ""

#. TRANS: Field label for an answer option on the page to create a poll.
#. TRANS: %d is the option number.
#: forms/newpoll.php:130
#, php-format
msgid "Option %d"
msgstr ""

#. TRANS: Button text for saving a new poll.
#: forms/newpoll.php:156
msgctxt "BUTTON"
msgid "Save"
msgstr "Stoor"

#. TRANS: Button text for submitting a poll response.
#: forms/pollresponse.php:127
msgctxt "BUTTON"
msgid "Submit"
msgstr ""

#. TRANS: Page title.
#: actions/pollsettings.php:44
msgid "Poll settings"
msgstr ""

#. TRANS: Page instructions.
#: actions/pollsettings.php:56
msgid "Set your poll preferences"
msgstr ""

#. TRANS: Title for poll page.
#: actions/newpoll.php:63
msgid "New poll"
msgstr ""

#. TRANS: Client exception thrown trying to create a poll while not logged in.
#: actions/newpoll.php:81
msgid "You must be logged in to post a poll."
msgstr ""

#. TRANS: Client exception thrown trying to create a poll without a question.
#: actions/newpoll.php:133
msgid "Poll must have a question."
msgstr ""

#. TRANS: Client exception thrown trying to create a poll with fewer than two
#. options.
#: actions/newpoll.php:138
msgid "Poll must have at least two options."
msgstr ""

#. TRANS: Page title after sending a notice.
#: actions/newpoll.php:164
msgid "Notice posted"
msgstr ""

#. TRANS: Page title for poll response.
#: actions/respondpoll.php:63
msgid "Poll response"
msgstr ""

#. TRANS: Client exception thrown trying to respond to a poll while not logged
#. in.
#: actions/respondpoll.php:84
msgid "You must be logged in to respond to a poll."
msgstr ""

#. TRANS: Client exception thrown trying to respond to a non-existing poll.
#: actions/respondpoll.php:96
msgid "Invalid or missing poll."
msgstr ""

#. TRANS: Client exception thrown responding to a poll with an invalid answer.
#. TRANS: Client exception thrown when responding to a poll with an invalid
#. option.
#: actions/respondpoll.php:102 classes/Poll_response.php:134
msgid "Invalid poll selection."
msgstr ""

#. TRANS: Page title after sending a poll response.
#: actions/respondpoll.php:150
msgid "Poll results"
msgstr ""

#. TRANS: Client exception thrown trying to view a non-existing poll.
#: actions/showpoll.php:59
msgid "No such poll."
msgstr ""

#. TRANS: Client exception thrown trying to view a non-existing poll notice.
#: actions/showpoll.php:67
msgid "No such poll notice."
msgstr ""

#. TRANS: Page title for a poll.
#. TRANS: %1$s is the nickname of the user that created the poll, %2$s is the
#. poll question.
#: actions/showpoll.php:84
#, php-format
msgid "%1$s's poll: %2$s"
msgstr ""

#. TRANS: Notice content creating a poll.
#. TRANS: %1$s is the poll question, %2$s is a link to the poll.
#: classes/Poll.php:201
#, php-format
msgid "Poll: %1$s %2$s"
msgstr ""

#. TRANS: Rendered version of the notice content creating a poll.
#. TRANS: %s is a link to the poll with the question as link description.
#: classes/Poll.php:207
#, php-format
msgid "Poll: %s"
msgstr ""

#. TRANS: Notice content voting for a poll.
#. TRANS: %s is the chosen option in the poll.
#. TRANS: Rendered version of the notice content voting for a poll.
#. TRANS: %s a link to the poll with the chosen option as link description.
#: classes/Poll_response.php:163 classes/Poll_response.php:168
#, php-format
msgid "voted for \"%s\""
msgstr ""

#. TRANS: Plugin description.
#: PollPlugin.php:131
msgid "Simple extension for supporting basic polls."
msgstr ""

#. TRANS: Exception thrown trying to respond to a poll without a poll
#. reference.
#: PollPlugin.php:204
msgid "Invalid poll response: No poll reference."
msgstr ""

#. TRANS: Exception thrown trying to respond to a non-existing poll.
#: PollPlugin.php:209
msgid "Invalid poll response: Poll is unknown."
msgstr ""

#. TRANS: Exception thrown when performing an unexpected action on a poll.
#. TRANS: %s is the unexpected object type.
#: PollPlugin.php:236
#, php-format
msgid "Unexpected type for poll plugin: %s."
msgstr ""

#. TRANS: Application title.
#: PollPlugin.php:392
msgctxt "APPTITLE"
msgid "Poll"
msgstr ""

#. TRANS: Poll plugin menu item on user settings page.
#: PollPlugin.php:436
msgctxt "MENU"
msgid "Polls"
msgstr ""

#. TRANS: Poll plugin tooltip for user settings menu item.
#: PollPlugin.php:438
msgid "Configure poll behavior"
msgstr ""

#. TRANS: Error text displayed if no poll data could be found.
#: PollPlugin.php:463
msgid "Poll data is missing"
msgstr ""


code:
# Translation file for GNU social - the free software social networking platform
# Copyright (C) 2011 - 2019 Free Software Foundation, Inc http://www.fsf.org
# This file is under https://www.gnu.org/licenses/agpl v3 or later
#
# Translators:
msgid ""
msgstr ""
"Project-Id-Version: GNU social\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-02-02 17:47+0100\n"
"PO-Revision-Date: 2015-02-07 14:32+0000\n"
"Last-Translator: digitaldreamer <digitaldreamer@email.cz>\n"
"Language-Team: Arabic (http://www.transifex.com/gnu-social/gnu-social/language/ar/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: ar\n"
"Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5;\n"

#. TRANS: Field label on the page to create a poll.
#: forms/newpoll.php:107
msgid "Question"
msgstr "السؤال"

#. TRANS: Field title on the page to create a poll.
#: forms/newpoll.php:110
msgid "What question are people answering?"
msgstr "ما السؤال الذي سيجيبه الناس؟"

#. TRANS: Field label for an answer option on the page to create a poll.
#. TRANS: %d is the option number.
#: forms/newpoll.php:130
#, php-format
msgid "Option %d"
msgstr "الخيار %d"

#. TRANS: Button text for saving a new poll.
#: forms/newpoll.php:156
msgctxt "BUTTON"
msgid "Save"
msgstr "احفظ"

#. TRANS: Button text for submitting a poll response.
#: forms/pollresponse.php:127
msgctxt "BUTTON"
msgid "Submit"
msgstr "أرسل"

#. TRANS: Page title.
#: actions/pollsettings.php:44
msgid "Poll settings"
msgstr ""

#. TRANS: Page instructions.
#: actions/pollsettings.php:56
msgid "Set your poll preferences"
msgstr ""

#. TRANS: Title for poll page.
#: actions/newpoll.php:63
msgid "New poll"
msgstr "استطلاع جديد"

#. TRANS: Client exception thrown trying to create a poll while not logged in.
#: actions/newpoll.php:81
msgid "You must be logged in to post a poll."
msgstr ""

#. TRANS: Client exception thrown trying to create a poll without a question.
#: actions/newpoll.php:133
msgid "Poll must have a question."
msgstr ""

#. TRANS: Client exception thrown trying to create a poll with fewer than two
#. options.
#: actions/newpoll.php:138
msgid "Poll must have at least two options."
msgstr ""

#. TRANS: Page title after sending a notice.
#: actions/newpoll.php:164
msgid "Notice posted"
msgstr "أُرسل الإشعار"

#. TRANS: Page title for poll response.
#: actions/respondpoll.php:63
msgid "Poll response"
msgstr ""

#. TRANS: Client exception thrown trying to respond to a poll while not logged
#. in.
#: actions/respondpoll.php:84
msgid "You must be logged in to respond to a poll."
msgstr ""

#. TRANS: Client exception thrown trying to respond to a non-existing poll.
#: actions/respondpoll.php:96
msgid "Invalid or missing poll."
msgstr ""

#. TRANS: Client exception thrown responding to a poll with an invalid answer.
#. TRANS: Client exception thrown when responding to a poll with an invalid
#. option.
#: actions/respondpoll.php:102 classes/Poll_response.php:134
msgid "Invalid poll selection."
msgstr ""

#. TRANS: Page title after sending a poll response.
#: actions/respondpoll.php:150
msgid "Poll results"
msgstr "نتائج الاستطلاع"

#. TRANS: Client exception thrown trying to view a non-existing poll.
#: actions/showpoll.php:59
msgid "No such poll."
msgstr ""

#. TRANS: Client exception thrown trying to view a non-existing poll notice.
#: actions/showpoll.php:67
msgid "No such poll notice."
msgstr ""

#. TRANS: Page title for a poll.
#. TRANS: %1$s is the nickname of the user that created the poll, %2$s is the
#. poll question.
#: actions/showpoll.php:84
#, php-format
msgid "%1$s's poll: %2$s"
msgstr "استطلاع %1$s: %2$s"

#. TRANS: Notice content creating a poll.
#. TRANS: %1$s is the poll question, %2$s is a link to the poll.
#: classes/Poll.php:201
#, php-format
msgid "Poll: %1$s %2$s"
msgstr "استطلاع: %1$s %2$s"

#. TRANS: Rendered version of the notice content creating a poll.
#. TRANS: %s is a link to the poll with the question as link description.
#: classes/Poll.php:207
#, php-format
msgid "Poll: %s"
msgstr "استطلاع: %s"

#. TRANS: Notice content voting for a poll.
#. TRANS: %s is the chosen option in the poll.
#. TRANS: Rendered version of the notice content voting for a poll.
#. TRANS: %s a link to the poll with the chosen option as link description.
#: classes/Poll_response.php:163 classes/Poll_response.php:168
#, php-format
msgid "voted for \"%s\""
msgstr "صوت ل\"%s\""

#. TRANS: Plugin description.
#: PollPlugin.php:131
msgid "Simple extension for supporting basic polls."
msgstr ""

#. TRANS: Exception thrown trying to respond to a poll without a poll
#. reference.
#: PollPlugin.php:204
msgid "Invalid poll response: No poll reference."
msgstr ""

#. TRANS: Exception thrown trying to respond to a non-existing poll.
#: PollPlugin.php:209
msgid "Invalid poll response: Poll is unknown."
msgstr ""

#. TRANS: Exception thrown when performing an unexpected action on a poll.
#. TRANS: %s is the unexpected object type.
#: PollPlugin.php:236
#, php-format
msgid "Unexpected type for poll plugin: %s."
msgstr ""

#. TRANS: Application title.
#: PollPlugin.php:392
msgctxt "APPTITLE"
msgid "Poll"
msgstr "استطلاع"

#. TRANS: Poll plugin menu item on user settings page.
#: PollPlugin.php:436
msgctxt "MENU"
msgid "Polls"
msgstr ""

#. TRANS: Poll plugin tooltip for user settings menu item.
#: PollPlugin.php:438
msgid "Configure poll behavior"
msgstr ""

#. TRANS: Error text displayed if no poll data could be found.
#: PollPlugin.php:463
msgid "Poll data is missing"
msgstr ""


code:
# Translation file for GNU social - the free software social networking platform
# Copyright (C) 2015 - 2019 Free Software Foundation, Inc http://www.fsf.org
# This file is under https://www.gnu.org/licenses/agpl v3 or later
#
# Translators:
msgid ""
msgstr ""
"Project-Id-Version: GNU social\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-02-02 17:47+0100\n"
"PO-Revision-Date: 2015-02-05 16:27+0000\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: Arabic (Egypt) (http://www.transifex.com/gnu-social/gnu-social/language/ar_EG/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: ar_EG\n"
"Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5;\n"

#. TRANS: Field label on the page to create a poll.
#: forms/newpoll.php:107
msgid "Question"
msgstr ""

#. TRANS: Field title on the page to create a poll.
#: forms/newpoll.php:110
msgid "What question are people answering?"
msgstr ""

#. TRANS: Field label for an answer option on the page to create a poll.
#. TRANS: %d is the option number.
#: forms/newpoll.php:130
#, php-format
msgid "Option %d"
msgstr ""

#. TRANS: Button text for saving a new poll.
#: forms/newpoll.php:156
msgctxt "BUTTON"
msgid "Save"
msgstr "أرسل"

#. TRANS: Button text for submitting a poll response.
#: forms/pollresponse.php:127
msgctxt "BUTTON"
msgid "Submit"
msgstr ""

#. TRANS: Page title.
#: actions/pollsettings.php:44
msgid "Poll settings"
msgstr ""

#. TRANS: Page instructions.
#: actions/pollsettings.php:56
msgid "Set your poll preferences"
msgstr ""

#. TRANS: Title for poll page.
#: actions/newpoll.php:63
msgid "New poll"
msgstr ""

#. TRANS: Client exception thrown trying to create a poll while not logged in.
#: actions/newpoll.php:81
msgid "You must be logged in to post a poll."
msgstr ""

#. TRANS: Client exception thrown trying to create a poll without a question.
#: actions/newpoll.php:133
msgid "Poll must have a question."
msgstr ""

#. TRANS: Client exception thrown trying to create a poll with fewer than two
#. options.
#: actions/newpoll.php:138
msgid "Poll must have at least two options."
msgstr ""

#. TRANS: Page title after sending a notice.
#: actions/newpoll.php:164
msgid "Notice posted"
msgstr "أُرسل الإشعار"

#. TRANS: Page title for poll response.
#: actions/respondpoll.php:63
msgid "Poll response"
msgstr ""

#. TRANS: Client exception thrown trying to respond to a poll while not logged
#. in.
#: actions/respondpoll.php:84
msgid "You must be logged in to respond to a poll."
msgstr ""

#. TRANS: Client exception thrown trying to respond to a non-existing poll.
#: actions/respondpoll.php:96
msgid "Invalid or missing poll."
msgstr ""

#. TRANS: Client exception thrown responding to a poll with an invalid answer.
#. TRANS: Client exception thrown when responding to a poll with an invalid
#. option.
#: actions/respondpoll.php:102 classes/Poll_response.php:134
msgid "Invalid poll selection."
msgstr ""

#. TRANS: Page title after sending a poll response.
#: actions/respondpoll.php:150
msgid "Poll results"
msgstr ""

#. TRANS: Client exception thrown trying to view a non-existing poll.
#: actions/showpoll.php:59
msgid "No such poll."
msgstr ""

#. TRANS: Client exception thrown trying to view a non-existing poll notice.
#: actions/showpoll.php:67
msgid "No such poll notice."
msgstr ""

#. TRANS: Page title for a poll.
#. TRANS: %1$s is the nickname of the user that created the poll, %2$s is the
#. poll question.
#: actions/showpoll.php:84
#, php-format
msgid "%1$s's poll: %2$s"
msgstr ""

#. TRANS: Notice content creating a poll.
#. TRANS: %1$s is the poll question, %2$s is a link to the poll.
#: classes/Poll.php:201
#, php-format
msgid "Poll: %1$s %2$s"
msgstr ""

#. TRANS: Rendered version of the notice content creating a poll.
#. TRANS: %s is a link to the poll with the question as link description.
#: classes/Poll.php:207
#, php-format
msgid "Poll: %s"
msgstr ""

#. TRANS: Notice content voting for a poll.
#. TRANS: %s is the chosen option in the poll.
#. TRANS: Rendered version of the notice content voting for a poll.
#. TRANS: %s a link to the poll with the chosen option as link description.
#: classes/Poll_response.php:163 classes/Poll_response.php:168
#, php-format
msgid "voted for \"%s\""
msgstr ""

#. TRANS: Plugin description.
#: PollPlugin.php:131
msgid "Simple extension for supporting basic polls."
msgstr ""

#. TRANS: Exception thrown trying to respond to a poll without a poll
#. reference.
#: PollPlugin.php:204
msgid "Invalid poll response: No poll reference."
msgstr ""

#. TRANS: Exception thrown trying to respond to a non-existing poll.
#: PollPlugin.php:209
msgid "Invalid poll response: Poll is unknown."
msgstr ""

#. TRANS: Exception thrown when performing an unexpected action on a poll.
#. TRANS: %s is the unexpected object type.
#: PollPlugin.php:236
#, php-format
msgid "Unexpected type for poll plugin: %s."
msgstr ""

#. TRANS: Application title.
#: PollPlugin.php:392
msgctxt "APPTITLE"
msgid "Poll"
msgstr ""

#. TRANS: Poll plugin menu item on user settings page.
#: PollPlugin.php:436
msgctxt "MENU"
msgid "Polls"
msgstr ""

#. TRANS: Poll plugin tooltip for user settings menu item.
#: PollPlugin.php:438
msgid "Configure poll behavior"
msgstr ""

#. TRANS: Error text displayed if no poll data could be found.
#: PollPlugin.php:463
msgid "Poll data is missing"
msgstr ""


code:
# Translation file for GNU social - the free software social networking platform
# Copyright (C) 2015 - 2019 Free Software Foundation, Inc http://www.fsf.org
# This file is under https://www.gnu.org/licenses/agpl v3 or later
#
# Translators:
msgid ""
msgstr ""
"Project-Id-Version: GNU social\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-02-02 17:47+0100\n"
"PO-Revision-Date: 2015-02-05 17:29+0000\n"
"Last-Translator: digitaldreamer <digitaldreamer@email.cz>\n"
"Language-Team: Asturian (http://www.transifex.com/gnu-social/gnu-social/language/ast/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: ast\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"

#. TRANS: Field label on the page to create a poll.
#: forms/newpoll.php:107
msgid "Question"
msgstr ""

#. TRANS: Field title on the page to create a poll.
#: forms/newpoll.php:110
msgid "What question are people answering?"
msgstr ""

#. TRANS: Field label for an answer option on the page to create a poll.
#. TRANS: %d is the option number.
#: forms/newpoll.php:130
#, php-format
msgid "Option %d"
msgstr ""

#. TRANS: Button text for saving a new poll.
#: forms/newpoll.php:156
msgctxt "BUTTON"
msgid "Save"
msgstr ""

#. TRANS: Button text for submitting a poll response.
#: forms/pollresponse.php:127
msgctxt "BUTTON"
msgid "Submit"
msgstr ""

#. TRANS: Page title.
#: actions/pollsettings.php:44
msgid "Poll settings"
msgstr ""

#. TRANS: Page instructions.
#: actions/pollsettings.php:56
msgid "Set your poll preferences"
msgstr ""

#. TRANS: Title for poll page.
#: actions/newpoll.php:63
msgid "New poll"
msgstr ""

#. TRANS: Client exception thrown trying to create a poll while not logged in.
#: actions/newpoll.php:81
msgid "You must be logged in to post a poll."
msgstr ""

#. TRANS: Client exception thrown trying to create a poll without a question.
#: actions/newpoll.php:133
msgid "Poll must have a question."
msgstr ""

#. TRANS: Client exception thrown trying to create a poll with fewer than two
#. options.
#: actions/newpoll.php:138
msgid "Poll must have at least two options."
msgstr ""

#. TRANS: Page title after sending a notice.
#: actions/newpoll.php:164
msgid "Notice posted"
msgstr ""

#. TRANS: Page title for poll response.
#: actions/respondpoll.php:63
msgid "Poll response"
msgstr ""

#. TRANS: Client exception thrown trying to respond to a poll while not logged
#. in.
#: actions/respondpoll.php:84
msgid "You must be logged in to respond to a poll."
msgstr ""

#. TRANS: Client exception thrown trying to respond to a non-existing poll.
#: actions/respondpoll.php:96
msgid "Invalid or missing poll."
msgstr ""

#. TRANS: Client exception thrown responding to a poll with an invalid answer.
#. TRANS: Client exception thrown when responding to a poll with an invalid
#. option.
#: actions/respondpoll.php:102 classes/Poll_response.php:134
msgid "Invalid poll selection."
msgstr ""

#. TRANS: Page title after sending a poll response.
#: actions/respondpoll.php:150
msgid "Poll results"
msgstr ""

#. TRANS: Client exception thrown trying to view a non-existing poll.
#: actions/showpoll.php:59
msgid "No such poll."
msgstr ""

#. TRANS: Client exception thrown trying to view a non-existing poll notice.
#: actions/showpoll.php:67
msgid "No such poll notice."
msgstr ""

#. TRANS: Page title for a poll.
#. TRANS: %1$s is the nickname of the user that created the poll, %2$s is the
#. poll question.
#: actions/showpoll.php:84
#, php-format
msgid "%1$s's poll: %2$s"
msgstr ""

#. TRANS: Notice content creating a poll.
#. TRANS: %1$s is the poll question, %2$s is a link to the poll.
#: classes/Poll.php:201
#, php-format
msgid "Poll: %1$s %2$s"
msgstr ""

#. TRANS: Rendered version of the notice content creating a poll.
#. TRANS: %s is a link to the poll with the question as link description.
#: classes/Poll.php:207
#, php-format
msgid "Poll: %s"
msgstr ""

#. TRANS: Notice content voting for a poll.
#. TRANS: %s is the chosen option in the poll.
#. TRANS: Rendered version of the notice content voting for a poll.
#. TRANS: %s a link to the poll with the chosen option as link description.
#: classes/Poll_response.php:163 classes/Poll_response.php:168
#, php-format
msgid "voted for \"%s\""
msgstr ""

#. TRANS: Plugin description.
#: PollPlugin.php:131
msgid "Simple extension for supporting basic polls."
msgstr ""

#. TRANS: Exception thrown trying to respond to a poll without a poll
#. reference.
#: PollPlugin.php:204
msgid "Invalid poll response: No poll reference."
msgstr ""

#. TRANS: Exception thrown trying to respond to a non-existing poll.
#: PollPlugin.php:209
msgid "Invalid poll response: Poll is unknown."
msgstr ""

#. TRANS: Exception thrown when performing an unexpected action on a poll.
#. TRANS: %s is the unexpected object type.
#: PollPlugin.php:236
#, php-format
msgid "Unexpected type for poll plugin: %s."
msgstr ""

#. TRANS: Application title.
#: PollPlugin.php:392
msgctxt "APPTITLE"
msgid "Poll"
msgstr ""

#. TRANS: Poll plugin menu item on user settings page.
#: PollPlugin.php:436
msgctxt "MENU"
msgid "Polls"
msgstr ""

#. TRANS: Poll plugin tooltip for user settings menu item.
#: PollPlugin.php:438
msgid "Configure poll behavior"
msgstr ""

#. TRANS: Error text displayed if no poll data could be found.
#: PollPlugin.php:463
msgid "Poll data is missing"
msgstr ""