code:
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
#
# 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 10:23+0000\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: Russian (http://www.transifex.com/projects/p/gnu-social/language/ru/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: ru\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.
#: RSSCloudPlugin.php:209
msgid ""
"The RSSCloud plugin enables your StatusNet instance to publish real-time "
"updates for profile RSS feeds using the <a "
"href=\"http://rsscloud.org/\">RSSCloud protocol</a>."
msgstr ""

#. TRANS: Form validation error displayed when a URL parameter is missing.
#: actions/loggingaggregator.php:86
msgid "A URL parameter is required."
msgstr ""

#. TRANS: Form validation error displayed when HTTP GET is not used.
#: actions/loggingaggregator.php:94
msgid "This resource requires an HTTP GET."
msgstr ""

#. TRANS: Form validation error displayed when HTTP POST is not used.
#: actions/loggingaggregator.php:104
msgid "This resource requires an HTTP POST."
msgstr ""

#. TRANS: Form validation error displayed when POST is not used.
#: actions/rsscloudrequestnotify.php:91
msgid "Request must be POST."
msgstr ""

#. TRANS: Form validation error displayed when HTTP POST is not used.
#: actions/rsscloudrequestnotify.php:109
msgid "Only HTTP POST notifications are supported at this time."
msgstr ""

#. TRANS: List separator.
#: actions/rsscloudrequestnotify.php:120
msgctxt "SEPARATOR"
msgid ", "
msgstr ", "

#. TRANS: Form validation error displayed when a request body is missing
#. expected parameters.
#. TRANS: %s is a list of parameters separated by a list separator (default:
#. ", ").
#: actions/rsscloudrequestnotify.php:123
#, php-format
msgid "The following parameters were missing from the request body: %s."
msgstr ""

#. TRANS: Form validation error displayed when not providing any valid profile
#. feed URLs.
#: actions/rsscloudrequestnotify.php:130
msgid ""
"You must provide at least one valid profile feed URL (url1, url2, url3 ... "
"urlN)."
msgstr ""

#. TRANS: Form validation error displayed when not providing a valid feed URL.
#: actions/rsscloudrequestnotify.php:146
msgid "Feed subscription failed: Not a valid feed."
msgstr ""

#. TRANS: Form validation error displayed when feed subscription failed.
#: actions/rsscloudrequestnotify.php:153
msgid ""
"Feed subscription failed: Notification handler does not respond correctly."
msgstr ""

#. TRANS: Success message after subscribing to one or more feeds.
#: actions/rsscloudrequestnotify.php:168
msgid ""
"Thanks for the subscription. When the feed(s) update(s), you will be "
"notified."
msgstr ""


code:
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
#
# 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 10:23+0000\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: Serbian (http://www.transifex.com/projects/p/gnu-social/language/sr/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: sr\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.
#: RSSCloudPlugin.php:209
msgid ""
"The RSSCloud plugin enables your StatusNet instance to publish real-time "
"updates for profile RSS feeds using the <a "
"href=\"http://rsscloud.org/\">RSSCloud protocol</a>."
msgstr ""

#. TRANS: Form validation error displayed when a URL parameter is missing.
#: actions/loggingaggregator.php:86
msgid "A URL parameter is required."
msgstr ""

#. TRANS: Form validation error displayed when HTTP GET is not used.
#: actions/loggingaggregator.php:94
msgid "This resource requires an HTTP GET."
msgstr ""

#. TRANS: Form validation error displayed when HTTP POST is not used.
#: actions/loggingaggregator.php:104
msgid "This resource requires an HTTP POST."
msgstr ""

#. TRANS: Form validation error displayed when POST is not used.
#: actions/rsscloudrequestnotify.php:91
msgid "Request must be POST."
msgstr ""

#. TRANS: Form validation error displayed when HTTP POST is not used.
#: actions/rsscloudrequestnotify.php:109
msgid "Only HTTP POST notifications are supported at this time."
msgstr ""

#. TRANS: List separator.
#: actions/rsscloudrequestnotify.php:120
msgctxt "SEPARATOR"
msgid ", "
msgstr ""

#. TRANS: Form validation error displayed when a request body is missing
#. expected parameters.
#. TRANS: %s is a list of parameters separated by a list separator (default:
#. ", ").
#: actions/rsscloudrequestnotify.php:123
#, php-format
msgid "The following parameters were missing from the request body: %s."
msgstr ""

#. TRANS: Form validation error displayed when not providing any valid profile
#. feed URLs.
#: actions/rsscloudrequestnotify.php:130
msgid ""
"You must provide at least one valid profile feed URL (url1, url2, url3 ... "
"urlN)."
msgstr ""

#. TRANS: Form validation error displayed when not providing a valid feed URL.
#: actions/rsscloudrequestnotify.php:146
msgid "Feed subscription failed: Not a valid feed."
msgstr ""

#. TRANS: Form validation error displayed when feed subscription failed.
#: actions/rsscloudrequestnotify.php:153
msgid ""
"Feed subscription failed: Notification handler does not respond correctly."
msgstr ""

#. TRANS: Success message after subscribing to one or more feeds.
#: actions/rsscloudrequestnotify.php:168
msgid ""
"Thanks for the subscription. When the feed(s) update(s), you will be "
"notified."
msgstr ""

repo_name: piratas/tortuga

license: mit


code:
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
#
# 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 10:23+0000\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: Swedish (http://www.transifex.com/projects/p/gnu-social/language/sv/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: sv\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"

#. TRANS: Plugin description.
#: RSSCloudPlugin.php:209
msgid ""
"The RSSCloud plugin enables your StatusNet instance to publish real-time "
"updates for profile RSS feeds using the <a "
"href=\"http://rsscloud.org/\">RSSCloud protocol</a>."
msgstr ""

#. TRANS: Form validation error displayed when a URL parameter is missing.
#: actions/loggingaggregator.php:86
msgid "A URL parameter is required."
msgstr ""

#. TRANS: Form validation error displayed when HTTP GET is not used.
#: actions/loggingaggregator.php:94
msgid "This resource requires an HTTP GET."
msgstr ""

#. TRANS: Form validation error displayed when HTTP POST is not used.
#: actions/loggingaggregator.php:104
msgid "This resource requires an HTTP POST."
msgstr ""

#. TRANS: Form validation error displayed when POST is not used.
#: actions/rsscloudrequestnotify.php:91
msgid "Request must be POST."
msgstr ""

#. TRANS: Form validation error displayed when HTTP POST is not used.
#: actions/rsscloudrequestnotify.php:109
msgid "Only HTTP POST notifications are supported at this time."
msgstr ""

#. TRANS: List separator.
#: actions/rsscloudrequestnotify.php:120
msgctxt "SEPARATOR"
msgid ", "
msgstr ", "

#. TRANS: Form validation error displayed when a request body is missing
#. expected parameters.
#. TRANS: %s is a list of parameters separated by a list separator (default:
#. ", ").
#: actions/rsscloudrequestnotify.php:123
#, php-format
msgid "The following parameters were missing from the request body: %s."
msgstr ""

#. TRANS: Form validation error displayed when not providing any valid profile
#. feed URLs.
#: actions/rsscloudrequestnotify.php:130
msgid ""
"You must provide at least one valid profile feed URL (url1, url2, url3 ... "
"urlN)."
msgstr ""

#. TRANS: Form validation error displayed when not providing a valid feed URL.
#: actions/rsscloudrequestnotify.php:146
msgid "Feed subscription failed: Not a valid feed."
msgstr ""

#. TRANS: Form validation error displayed when feed subscription failed.
#: actions/rsscloudrequestnotify.php:153
msgid ""
"Feed subscription failed: Notification handler does not respond correctly."
msgstr ""

#. TRANS: Success message after subscribing to one or more feeds.
#: actions/rsscloudrequestnotify.php:168
msgid ""
"Thanks for the subscription. When the feed(s) update(s), you will be "
"notified."
msgstr ""


code:
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
#
# 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 10:23+0000\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: Tamil (http://www.transifex.com/projects/p/gnu-social/language/ta/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: ta\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"

#. TRANS: Plugin description.
#: RSSCloudPlugin.php:209
msgid ""
"The RSSCloud plugin enables your StatusNet instance to publish real-time "
"updates for profile RSS feeds using the <a "
"href=\"http://rsscloud.org/\">RSSCloud protocol</a>."
msgstr ""

#. TRANS: Form validation error displayed when a URL parameter is missing.
#: actions/loggingaggregator.php:86
msgid "A URL parameter is required."
msgstr ""

#. TRANS: Form validation error displayed when HTTP GET is not used.
#: actions/loggingaggregator.php:94
msgid "This resource requires an HTTP GET."
msgstr ""

#. TRANS: Form validation error displayed when HTTP POST is not used.
#: actions/loggingaggregator.php:104
msgid "This resource requires an HTTP POST."
msgstr ""

#. TRANS: Form validation error displayed when POST is not used.
#: actions/rsscloudrequestnotify.php:91
msgid "Request must be POST."
msgstr ""

#. TRANS: Form validation error displayed when HTTP POST is not used.
#: actions/rsscloudrequestnotify.php:109
msgid "Only HTTP POST notifications are supported at this time."
msgstr ""

#. TRANS: List separator.
#: actions/rsscloudrequestnotify.php:120
msgctxt "SEPARATOR"
msgid ", "
msgstr ""

#. TRANS: Form validation error displayed when a request body is missing
#. expected parameters.
#. TRANS: %s is a list of parameters separated by a list separator (default:
#. ", ").
#: actions/rsscloudrequestnotify.php:123
#, php-format
msgid "The following parameters were missing from the request body: %s."
msgstr ""

#. TRANS: Form validation error displayed when not providing any valid profile
#. feed URLs.
#: actions/rsscloudrequestnotify.php:130
msgid ""
"You must provide at least one valid profile feed URL (url1, url2, url3 ... "
"urlN)."
msgstr ""

#. TRANS: Form validation error displayed when not providing a valid feed URL.
#: actions/rsscloudrequestnotify.php:146
msgid "Feed subscription failed: Not a valid feed."
msgstr ""

#. TRANS: Form validation error displayed when feed subscription failed.
#: actions/rsscloudrequestnotify.php:153
msgid ""
"Feed subscription failed: Notification handler does not respond correctly."
msgstr ""

#. TRANS: Success message after subscribing to one or more feeds.
#: actions/rsscloudrequestnotify.php:168
msgid ""
"Thanks for the subscription. When the feed(s) update(s), you will be "
"notified."
msgstr ""


code:
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
#
# 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 10:23+0000\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: Telugu (http://www.transifex.com/projects/p/gnu-social/language/te/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: te\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"

#. TRANS: Plugin description.
#: RSSCloudPlugin.php:209
msgid ""
"The RSSCloud plugin enables your StatusNet instance to publish real-time "
"updates for profile RSS feeds using the <a "
"href=\"http://rsscloud.org/\">RSSCloud protocol</a>."
msgstr ""

#. TRANS: Form validation error displayed when a URL parameter is missing.
#: actions/loggingaggregator.php:86
msgid "A URL parameter is required."
msgstr ""

#. TRANS: Form validation error displayed when HTTP GET is not used.
#: actions/loggingaggregator.php:94
msgid "This resource requires an HTTP GET."
msgstr ""

#. TRANS: Form validation error displayed when HTTP POST is not used.
#: actions/loggingaggregator.php:104
msgid "This resource requires an HTTP POST."
msgstr ""

#. TRANS: Form validation error displayed when POST is not used.
#: actions/rsscloudrequestnotify.php:91
msgid "Request must be POST."
msgstr ""

#. TRANS: Form validation error displayed when HTTP POST is not used.
#: actions/rsscloudrequestnotify.php:109
msgid "Only HTTP POST notifications are supported at this time."
msgstr ""

#. TRANS: List separator.
#: actions/rsscloudrequestnotify.php:120
msgctxt "SEPARATOR"
msgid ", "
msgstr ", "

#. TRANS: Form validation error displayed when a request body is missing
#. expected parameters.
#. TRANS: %s is a list of parameters separated by a list separator (default:
#. ", ").
#: actions/rsscloudrequestnotify.php:123
#, php-format
msgid "The following parameters were missing from the request body: %s."
msgstr ""

#. TRANS: Form validation error displayed when not providing any valid profile
#. feed URLs.
#: actions/rsscloudrequestnotify.php:130
msgid ""
"You must provide at least one valid profile feed URL (url1, url2, url3 ... "
"urlN)."
msgstr ""

#. TRANS: Form validation error displayed when not providing a valid feed URL.
#: actions/rsscloudrequestnotify.php:146
msgid "Feed subscription failed: Not a valid feed."
msgstr ""

#. TRANS: Form validation error displayed when feed subscription failed.
#: actions/rsscloudrequestnotify.php:153
msgid ""
"Feed subscription failed: Notification handler does not respond correctly."
msgstr ""

#. TRANS: Success message after subscribing to one or more feeds.
#: actions/rsscloudrequestnotify.php:168
msgid ""
"Thanks for the subscription. When the feed(s) update(s), you will be "
"notified."
msgstr ""


code:
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
#
# 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 10:32+0000\n"
"Last-Translator: digitaldreamer <digitaldreamer@email.cz>\n"
"Language-Team: Tagalog (http://www.transifex.com/projects/p/gnu-social/language/tl/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: tl\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"

#. TRANS: Plugin description.
#: RSSCloudPlugin.php:209
msgid ""
"The RSSCloud plugin enables your StatusNet instance to publish real-time "
"updates for profile RSS feeds using the RSSCloud protocol."
msgstr "Ang pamasak ng RSSCloud ay nagpapahintulot sa iyong pagkakataon ng StatusNet na maglathala ng mga pagsasapanahong pangtunay na oras para sa mga balangkas ng mga pakain ng RSS na gumagamit ng protokolo ng RSSCloud."

#. TRANS: Form validation error displayed when a URL parameter is missing.
#: actions/loggingaggregator.php:86
msgid "A URL parameter is required."
msgstr "Kailangan ang isang parametro ng URL."

#. TRANS: Form validation error displayed when HTTP GET is not used.
#: actions/loggingaggregator.php:94
msgid "This resource requires an HTTP GET."
msgstr "Ang pinagkunang ito ay nangangailangan ng HTTP GET."

#. TRANS: Form validation error displayed when HTTP POST is not used.
#: actions/loggingaggregator.php:104
msgid "This resource requires an HTTP POST."
msgstr "Ang pinagkukunang ito ay nangangailangan ng HTTP POST."

#. TRANS: Form validation error displayed when POST is not used.
#: actions/rsscloudrequestnotify.php:91
msgid "Request must be POST."
msgstr "Ang hiling ay dapat na POST."

#. TRANS: Form validation error displayed when HTTP POST is not used.
#: actions/rsscloudrequestnotify.php:109
msgid "Only HTTP POST notifications are supported at this time."
msgstr "Tanging mga pabatid na HTTP POST lamang ang tinatangkilik sa panahong ito."

#. TRANS: List separator.
#: actions/rsscloudrequestnotify.php:120
msgctxt "SEPARATOR"
msgid ", "
msgstr ", "

#. TRANS: Form validation error displayed when a request body is missing
#. expected parameters.
#. TRANS: %s is a list of parameters separated by a list separator (default:
#. ", ").
#: actions/rsscloudrequestnotify.php:123
#, php-format
msgid "The following parameters were missing from the request body: %s."
msgstr "Nawawala ang sumusunod na mga parametro mula sa katawan ng hiling: %s."

#. TRANS: Form validation error displayed when not providing any valid profile
#. feed URLs.
#: actions/rsscloudrequestnotify.php:130
msgid ""
"You must provide at least one valid profile feed URL (url1, url2, url3 ... "
"urlN)."
msgstr "Dapat kang magbigay ng kahit na isang katanggap-tanggap na URL ng pakain ng balangkas (url1, url2, url3 ... urlN)."

#. TRANS: Form validation error displayed when not providing a valid feed URL.
#: actions/rsscloudrequestnotify.php:146
msgid "Feed subscription failed: Not a valid feed."
msgstr "Nabigo ang pagtanggap ng pakain: Hindi isang tanggap na pakain."

#. TRANS: Form validation error displayed when feed subscription failed.
#: actions/rsscloudrequestnotify.php:153
msgid ""
"Feed subscription failed: Notification handler does not respond correctly."
msgstr "Nabigo ang pagpapasipi ng pakain: Hindi tama ang pagtugon ng tagapaghawak ng pabatid."

#. TRANS: Success message after subscribing to one or more feeds.
#: actions/rsscloudrequestnotify.php:168
msgid ""
"Thanks for the subscription. When the feed(s) update(s), you will be "
"notified."
msgstr "Salamat sa pagtatanggap.  Kapag nagsapanahon ang (mga) pakain, pababatiran ka."


code:
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
#
# 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 10:23+0000\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: Turkish (http://www.transifex.com/projects/p/gnu-social/language/tr/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: tr\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"

#. TRANS: Plugin description.
#: RSSCloudPlugin.php:209
msgid ""
"The RSSCloud plugin enables your StatusNet instance to publish real-time "
"updates for profile RSS feeds using the <a "
"href=\"http://rsscloud.org/\">RSSCloud protocol</a>."
msgstr ""

#. TRANS: Form validation error displayed when a URL parameter is missing.
#: actions/loggingaggregator.php:86
msgid "A URL parameter is required."
msgstr ""

#. TRANS: Form validation error displayed when HTTP GET is not used.
#: actions/loggingaggregator.php:94
msgid "This resource requires an HTTP GET."
msgstr ""

#. TRANS: Form validation error displayed when HTTP POST is not used.
#: actions/loggingaggregator.php:104
msgid "This resource requires an HTTP POST."
msgstr ""

#. TRANS: Form validation error displayed when POST is not used.
#: actions/rsscloudrequestnotify.php:91
msgid "Request must be POST."
msgstr ""

#. TRANS: Form validation error displayed when HTTP POST is not used.
#: actions/rsscloudrequestnotify.php:109
msgid "Only HTTP POST notifications are supported at this time."
msgstr ""

#. TRANS: List separator.
#: actions/rsscloudrequestnotify.php:120
msgctxt "SEPARATOR"
msgid ", "
msgstr ""

#. TRANS: Form validation error displayed when a request body is missing
#. expected parameters.
#. TRANS: %s is a list of parameters separated by a list separator (default:
#. ", ").
#: actions/rsscloudrequestnotify.php:123
#, php-format
msgid "The following parameters were missing from the request body: %s."
msgstr ""

#. TRANS: Form validation error displayed when not providing any valid profile
#. feed URLs.
#: actions/rsscloudrequestnotify.php:130
msgid ""
"You must provide at least one valid profile feed URL (url1, url2, url3 ... "
"urlN)."
msgstr ""

#. TRANS: Form validation error displayed when not providing a valid feed URL.
#: actions/rsscloudrequestnotify.php:146
msgid "Feed subscription failed: Not a valid feed."
msgstr ""

#. TRANS: Form validation error displayed when feed subscription failed.
#: actions/rsscloudrequestnotify.php:153
msgid ""
"Feed subscription failed: Notification handler does not respond correctly."
msgstr ""

#. TRANS: Success message after subscribing to one or more feeds.
#: actions/rsscloudrequestnotify.php:168
msgid ""
"Thanks for the subscription. When the feed(s) update(s), you will be "
"notified."
msgstr ""


code:
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
#
# 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 10:32+0000\n"
"Last-Translator: digitaldreamer <digitaldreamer@email.cz>\n"
"Language-Team: Ukrainian (http://www.transifex.com/projects/p/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.
#: RSSCloudPlugin.php:209
msgid ""
"The RSSCloud plugin enables your StatusNet instance to publish real-time "
"updates for profile RSS feeds using the RSSCloud protocol."
msgstr "Додаток RSSCloud дозволяє вашому StatusNet-сумісному сайту публікувати оновлення з веб-стрічок у реальному часі, використовуючи протокол RSSCloud."

#. TRANS: Form validation error displayed when a URL parameter is missing.
#: actions/loggingaggregator.php:86
msgid "A URL parameter is required."
msgstr "Параметр URL-адреси є обов’язковим."

#. TRANS: Form validation error displayed when HTTP GET is not used.
#: actions/loggingaggregator.php:94
msgid "This resource requires an HTTP GET."
msgstr "Цей ресурс вимагає форми HTTP GET."

#. TRANS: Form validation error displayed when HTTP POST is not used.
#: actions/loggingaggregator.php:104
msgid "This resource requires an HTTP POST."
msgstr "Цей ресурс вимагає форми HTTP POST."

#. TRANS: Form validation error displayed when POST is not used.
#: actions/rsscloudrequestnotify.php:91
msgid "Request must be POST."
msgstr "Запит вимагає форми POST."

#. TRANS: Form validation error displayed when HTTP POST is not used.
#: actions/rsscloudrequestnotify.php:109
msgid "Only HTTP POST notifications are supported at this time."
msgstr "На даний момент підтримуються лише сповіщення форми http-post."

#. TRANS: List separator.
#: actions/rsscloudrequestnotify.php:120
msgctxt "SEPARATOR"
msgid ", "
msgstr ", "

#. TRANS: Form validation error displayed when a request body is missing
#. expected parameters.
#. TRANS: %s is a list of parameters separated by a list separator (default:
#. ", ").
#: actions/rsscloudrequestnotify.php:123
#, php-format
msgid "The following parameters were missing from the request body: %s."
msgstr "У формі запиту відсутні наступні параметри: %s."

#. TRANS: Form validation error displayed when not providing any valid profile
#. feed URLs.
#: actions/rsscloudrequestnotify.php:130
msgid ""
"You must provide at least one valid profile feed URL (url1, url2, url3 ... "
"urlN)."
msgstr "Ви повинні зазначити щонайменше одну дійсну  URL-адресу веб-стрічки (URL-адреси через кому та пробіл)."

#. TRANS: Form validation error displayed when not providing a valid feed URL.
#: actions/rsscloudrequestnotify.php:146
msgid "Feed subscription failed: Not a valid feed."
msgstr "Підписатися до веб-стрічки не вдалося: ця веб-стрічка не є дійсною."

#. TRANS: Form validation error displayed when feed subscription failed.
#: actions/rsscloudrequestnotify.php:153
msgid ""
"Feed subscription failed: Notification handler does not respond correctly."
msgstr "Підписатися до веб-стрічки не вдалося: обробник сповіщень відреагував неправильно."

#. TRANS: Success message after subscribing to one or more feeds.
#: actions/rsscloudrequestnotify.php:168
msgid ""
"Thanks for the subscription. When the feed(s) update(s), you will be "
"notified."
msgstr "Дякуємо за підписку. Коли веб-стрічки оновляться, вас буде поінформовано."


code:
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
#
# 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 10:23+0000\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: Urdu (Pakistan) (http://www.transifex.com/projects/p/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.
#: RSSCloudPlugin.php:209
msgid ""
"The RSSCloud plugin enables your StatusNet instance to publish real-time "
"updates for profile RSS feeds using the <a "
"href=\"http://rsscloud.org/\">RSSCloud protocol</a>."
msgstr ""

#. TRANS: Form validation error displayed when a URL parameter is missing.
#: actions/loggingaggregator.php:86
msgid "A URL parameter is required."
msgstr ""

#. TRANS: Form validation error displayed when HTTP GET is not used.
#: actions/loggingaggregator.php:94
msgid "This resource requires an HTTP GET."
msgstr ""

#. TRANS: Form validation error displayed when HTTP POST is not used.
#: actions/loggingaggregator.php:104
msgid "This resource requires an HTTP POST."
msgstr ""

#. TRANS: Form validation error displayed when POST is not used.
#: actions/rsscloudrequestnotify.php:91
msgid "Request must be POST."
msgstr ""

#. TRANS: Form validation error displayed when HTTP POST is not used.
#: actions/rsscloudrequestnotify.php:109
msgid "Only HTTP POST notifications are supported at this time."
msgstr ""

#. TRANS: List separator.
#: actions/rsscloudrequestnotify.php:120
msgctxt "SEPARATOR"
msgid ", "
msgstr "،"

#. TRANS: Form validation error displayed when a request body is missing
#. expected parameters.
#. TRANS: %s is a list of parameters separated by a list separator (default:
#. ", ").
#: actions/rsscloudrequestnotify.php:123
#, php-format
msgid "The following parameters were missing from the request body: %s."
msgstr ""

#. TRANS: Form validation error displayed when not providing any valid profile
#. feed URLs.
#: actions/rsscloudrequestnotify.php:130
msgid ""
"You must provide at least one valid profile feed URL (url1, url2, url3 ... "
"urlN)."
msgstr ""

#. TRANS: Form validation error displayed when not providing a valid feed URL.
#: actions/rsscloudrequestnotify.php:146
msgid "Feed subscription failed: Not a valid feed."
msgstr ""

#. TRANS: Form validation error displayed when feed subscription failed.
#: actions/rsscloudrequestnotify.php:153
msgid ""
"Feed subscription failed: Notification handler does not respond correctly."
msgstr ""

#. TRANS: Success message after subscribing to one or more feeds.
#: actions/rsscloudrequestnotify.php:168
msgid ""
"Thanks for the subscription. When the feed(s) update(s), you will be "
"notified."
msgstr ""


code:
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
#
# 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 10:23+0000\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: Vietnamese (http://www.transifex.com/projects/p/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.
#: RSSCloudPlugin.php:209
msgid ""
"The RSSCloud plugin enables your StatusNet instance to publish real-time "
"updates for profile RSS feeds using the <a "
"href=\"http://rsscloud.org/\">RSSCloud protocol</a>."
msgstr ""

#. TRANS: Form validation error displayed when a URL parameter is missing.
#: actions/loggingaggregator.php:86
msgid "A URL parameter is required."
msgstr ""

#. TRANS: Form validation error displayed when HTTP GET is not used.
#: actions/loggingaggregator.php:94
msgid "This resource requires an HTTP GET."
msgstr ""

#. TRANS: Form validation error displayed when HTTP POST is not used.
#: actions/loggingaggregator.php:104
msgid "This resource requires an HTTP POST."
msgstr ""

#. TRANS: Form validation error displayed when POST is not used.
#: actions/rsscloudrequestnotify.php:91
msgid "Request must be POST."
msgstr ""

#. TRANS: Form validation error displayed when HTTP POST is not used.
#: actions/rsscloudrequestnotify.php:109
msgid "Only HTTP POST notifications are supported at this time."
msgstr ""

#. TRANS: List separator.
#: actions/rsscloudrequestnotify.php:120
msgctxt "SEPARATOR"
msgid ", "
msgstr ""

#. TRANS: Form validation error displayed when a request body is missing
#. expected parameters.
#. TRANS: %s is a list of parameters separated by a list separator (default:
#. ", ").
#: actions/rsscloudrequestnotify.php:123
#, php-format
msgid "The following parameters were missing from the request body: %s."
msgstr ""

#. TRANS: Form validation error displayed when not providing any valid profile
#. feed URLs.
#: actions/rsscloudrequestnotify.php:130
msgid ""
"You must provide at least one valid profile feed URL (url1, url2, url3 ... "
"urlN)."
msgstr ""

#. TRANS: Form validation error displayed when not providing a valid feed URL.
#: actions/rsscloudrequestnotify.php:146
msgid "Feed subscription failed: Not a valid feed."
msgstr ""

#. TRANS: Form validation error displayed when feed subscription failed.
#: actions/rsscloudrequestnotify.php:153
msgid ""
"Feed subscription failed: Notification handler does not respond correctly."
msgstr ""

#. TRANS: Success message after subscribing to one or more feeds.
#: actions/rsscloudrequestnotify.php:168
msgid ""
"Thanks for the subscription. When the feed(s) update(s), you will be "
"notified."
msgstr ""


code:
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
#
# 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 10:23+0000\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: Chinese (China) (http://www.transifex.com/projects/p/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.
#: RSSCloudPlugin.php:209
msgid ""
"The RSSCloud plugin enables your StatusNet instance to publish real-time "
"updates for profile RSS feeds using the <a "
"href=\"http://rsscloud.org/\">RSSCloud protocol</a>."
msgstr ""

#. TRANS: Form validation error displayed when a URL parameter is missing.
#: actions/loggingaggregator.php:86
msgid "A URL parameter is required."
msgstr ""

#. TRANS: Form validation error displayed when HTTP GET is not used.
#: actions/loggingaggregator.php:94
msgid "This resource requires an HTTP GET."
msgstr ""

#. TRANS: Form validation error displayed when HTTP POST is not used.
#: actions/loggingaggregator.php:104
msgid "This resource requires an HTTP POST."
msgstr ""

#. TRANS: Form validation error displayed when POST is not used.
#: actions/rsscloudrequestnotify.php:91
msgid "Request must be POST."
msgstr ""

#. TRANS: Form validation error displayed when HTTP POST is not used.
#: actions/rsscloudrequestnotify.php:109
msgid "Only HTTP POST notifications are supported at this time."
msgstr ""

#. TRANS: List separator.
#: actions/rsscloudrequestnotify.php:120
msgctxt "SEPARATOR"
msgid ", "
msgstr "、"

#. TRANS: Form validation error displayed when a request body is missing
#. expected parameters.
#. TRANS: %s is a list of parameters separated by a list separator (default:
#. ", ").
#: actions/rsscloudrequestnotify.php:123
#, php-format
msgid "The following parameters were missing from the request body: %s."
msgstr ""

#. TRANS: Form validation error displayed when not providing any valid profile
#. feed URLs.
#: actions/rsscloudrequestnotify.php:130
msgid ""
"You must provide at least one valid profile feed URL (url1, url2, url3 ... "
"urlN)."
msgstr ""

#. TRANS: Form validation error displayed when not providing a valid feed URL.
#: actions/rsscloudrequestnotify.php:146
msgid "Feed subscription failed: Not a valid feed."
msgstr ""

#. TRANS: Form validation error displayed when feed subscription failed.
#: actions/rsscloudrequestnotify.php:153
msgid ""
"Feed subscription failed: Notification handler does not respond correctly."
msgstr ""

#. TRANS: Success message after subscribing to one or more feeds.
#: actions/rsscloudrequestnotify.php:168
msgid ""
"Thanks for the subscription. When the feed(s) update(s), you will be "
"notified."
msgstr ""


code:
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
#
# 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 10:23+0000\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: Chinese (Taiwan) (http://www.transifex.com/projects/p/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.
#: RSSCloudPlugin.php:209
msgid ""
"The RSSCloud plugin enables your StatusNet instance to publish real-time "
"updates for profile RSS feeds using the <a "
"href=\"http://rsscloud.org/\">RSSCloud protocol</a>."
msgstr ""

#. TRANS: Form validation error displayed when a URL parameter is missing.
#: actions/loggingaggregator.php:86
msgid "A URL parameter is required."
msgstr ""

#. TRANS: Form validation error displayed when HTTP GET is not used.
#: actions/loggingaggregator.php:94
msgid "This resource requires an HTTP GET."
msgstr ""

#. TRANS: Form validation error displayed when HTTP POST is not used.
#: actions/loggingaggregator.php:104
msgid "This resource requires an HTTP POST."
msgstr ""

#. TRANS: Form validation error displayed when POST is not used.
#: actions/rsscloudrequestnotify.php:91
msgid "Request must be POST."
msgstr ""

#. TRANS: Form validation error displayed when HTTP POST is not used.
#: actions/rsscloudrequestnotify.php:109
msgid "Only HTTP POST notifications are supported at this time."
msgstr ""

#. TRANS: List separator.
#: actions/rsscloudrequestnotify.php:120
msgctxt "SEPARATOR"
msgid ", "
msgstr ""

#. TRANS: Form validation error displayed when a request body is missing
#. expected parameters.
#. TRANS: %s is a list of parameters separated by a list separator (default:
#. ", ").
#: actions/rsscloudrequestnotify.php:123
#, php-format
msgid "The following parameters were missing from the request body: %s."
msgstr ""

#. TRANS: Form validation error displayed when not providing any valid profile
#. feed URLs.
#: actions/rsscloudrequestnotify.php:130
msgid ""
"You must provide at least one valid profile feed URL (url1, url2, url3 ... "
"urlN)."
msgstr ""

#. TRANS: Form validation error displayed when not providing a valid feed URL.
#: actions/rsscloudrequestnotify.php:146
msgid "Feed subscription failed: Not a valid feed."
msgstr ""

#. TRANS: Form validation error displayed when feed subscription failed.
#: actions/rsscloudrequestnotify.php:153
msgid ""
"Feed subscription failed: Notification handler does not respond correctly."
msgstr ""

#. TRANS: Success message after subscribing to one or more feeds.
#: actions/rsscloudrequestnotify.php:168
msgid ""
"Thanks for the subscription. When the feed(s) update(s), you will be "
"notified."
msgstr ""


code:
.fake: all clean

all: realtimeupdate.min.js

clean:
	rm -f js/realtimeupdate.min.js

realtimeupdate.min.js: js/realtimeupdate.js
	yui-compressor js/realtimeupdate.js > js/realtimeupdate.min.js

path: plugins/Realtime/Makefile


code:
As of StatusNet 1.0.x, actual formatting of the notices is done server-side,
loaded by AJAX after the real-time notification comes in. This has the drawback
that we may make extra HTTP requests and delay incoming notices a little, but
means that formatting and internationalization is consistent.

== TODO ==
* Update mark behaviour (on notice send)
* Pause, Send a notice ~ should not update counter
* Pause ~ retain up to 50-100 most recent notices
* Make it work for Conversation page (perhaps a little tricky)
* IE is updating the counter in document title all the time (Not sure if this
  is still an issue)
* Reconsider the timestamp approach

path: plugins/Realtime/README


code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * Superclass for plugins that do "real time" updates of timelines using Ajax
 *
 * 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  Plugin
 * @package   StatusNet
 * @author    Evan Prodromou <evan@status.net>
 * @author    Mikael Nordfeldth <mmn@hethane.se>
 * @copyright 2009 StatusNet, Inc.
 * @copyright 2014 Free Software Foundation, 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); }

/**
 * Superclass for plugin to do realtime updates
 *
 * Based on experience with the Comet and Meteor plugins,
 * this superclass extracts out some of the common functionality
 *
 * Currently depends on Favorite plugin.
 *
 * @category Plugin
 * @package  StatusNet
 * @author   Evan Prodromou <evan@status.net>
 * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link     http://status.net/
 */
class RealtimePlugin extends Plugin
{
    protected $showurl = null;

    /**
     * When it's time to initialize the plugin, calculate and
     * pass the URLs we need.
     */
    function onInitializePlugin()
    {
        // FIXME: need to find a better way to pass this pattern in
        $this->showurl = common_local_url('shownotice',
                                            array('notice' => '0000000000'));
        return true;
    }

    function onCheckSchema()
    {
        $schema = Schema::get();
        $schema->ensureTable('realtime_channel', Realtime_channel::schemaDef());
        return true;
    }

    /**
     * Hook for RouterInitialized event.
     *
     * @param URLMapper $m path-to-action mapper
     * @return boolean hook return
     */
    public function onRouterInitialized(URLMapper $m)
    {
        $m->connect('main/channel/:channelkey/keepalive',
                    array('action' => 'keepalivechannel'),
                    array('channelkey' => '[a-z0-9]{32}'));
        $m->connect('main/channel/:channelkey/close',
                    array('action' => 'closechannel'),
                    array('channelkey' => '[a-z0-9]{32}'));
        return true;
    }

    function onEndShowScripts($action)
    {
        $channel = $this->_getChannel($action);

        if (empty($channel)) {
            return true;
        }

        $timeline = $this->_pathToChannel(array($channel->channel_key));

        // If there's not a timeline on this page,
        // just return true

        if (empty($timeline)) {
            return true;
        }

        $base = $action->selfUrl();
        if (mb_strstr($base, '?')) {
            $url = $base . '&realtime=1';
        } else {
            $url = $base . '?realtime=1';
        }

        $scripts = $this->_getScripts();

        foreach ($scripts as $script) {
            $action->script($script);
        }

        $user = common_current_user();

        if (!empty($user->id)) {
            $user_id = $user->id;
        } else {
            $user_id = 0;
        }

        if ($action->boolean('realtime')) {
            $realtimeUI = ' RealtimeUpdate.initPopupWindow();';
        }
        else {
            $pluginPath = common_path('plugins/Realtime/');
            $keepalive = common_local_url('keepalivechannel', array('channelkey' => $channel->channel_key));
            $close = common_local_url('closechannel', array('channelkey' => $channel->channel_key));
            $realtimeUI = ' RealtimeUpdate.initActions('.json_encode($url).', '.json_encode($timeline).', '.json_encode($pluginPath).', '.json_encode($keepalive).', '.json_encode($close).'); ';
        }

        $script = ' $(document).ready(function() { '.
          $realtimeUI.
            $this->_updateInitialize($timeline, $user_id).
          '}); ';
        $action->inlineScript($script);

        return true;
    }

    public function onEndShowStylesheets(Action $action)
    {
        $urlpath = self::staticPath(str_replace('Plugin','',__CLASS__),
                                    'css/realtimeupdate.css');
        $action->cssLink($urlpath, null, 'screen, projection, tv');
        return true;
    }

    public function onHandleQueuedNotice(Notice $notice)
    {
        $paths = array();

        // Add to the author's timeline

        try {
            $profile = $notice->getProfile();
        } catch (Exception $e) {
            $this->log(LOG_ERR, $e->getMessage());
            return true;
        }

        try {
            $user = $profile->getUser();
            $paths[] = array('showstream', $user->nickname, null);
        } catch (NoSuchUserException $e) {
            // We really should handle the remote profile views too
            $user = null;
        }

        // Add to the public timeline

        if ($notice->is_local == Notice::LOCAL_PUBLIC ||
            ($notice->is_local == Notice::REMOTE && !common_config('public', 'localonly'))) {
            $paths[] = array('public', null, null);
        }

        // Add to the tags timeline

        $tags = $this->getNoticeTags($notice);

        if (!empty($tags)) {
            foreach ($tags as $tag) {
                $paths[] = array('tag', $tag, null);
            }
        }

        // Add to inbox timelines
        // XXX: do a join

        $ni = $notice->whoGets();

        foreach (array_keys($ni) as $user_id) {
            $user = User::getKV('id', $user_id);
            $paths[] = array('all', $user->nickname, null);
        }

        // Add to the replies timeline

        $reply = new Reply();
        $reply->notice_id = $notice->id;

        if ($reply->find()) {
            while ($reply->fetch()) {
                $user = User::getKV('id', $reply->profile_id);
                if (!empty($user)) {
                    $paths[] = array('replies', $user->nickname, null);
                }
            }
        }

        // Add to the group timeline
        // XXX: join

        $gi = new Group_inbox();
        $gi->notice_id = $notice->id;

        if ($gi->find()) {
            while ($gi->fetch()) {
                $ug = User_group::getKV('id', $gi->group_id);
                $paths[] = array('showgroup', $ug->nickname, null);
            }
        }

        if (count($paths) > 0) {

            $json = $this->noticeAsJson($notice);

            $this->_connect();

            // XXX: We should probably fan-out here and do a
            // new queue item for each path

            foreach ($paths as $path) {

                list($action, $arg1, $arg2) = $path;

                $channels = Realtime_channel::getAllChannels($action, $arg1, $arg2);
                $this->log(LOG_INFO, sprintf(_("%d candidate channels for notice %d"),
                                             count($channels),
                                             $notice->id));

                foreach ($channels as $channel) {

                    // XXX: We should probably fan-out here and do a
                    // new queue item for each user/path combo

                    if (is_null($channel->user_id)) {
                        $profile = null;
                    } else {
                        $profile = Profile::getKV('id', $channel->user_id);
                    }
                    if ($notice->inScope($profile)) {
                        $this->log(LOG_INFO,
                                   sprintf(_("Delivering notice %d to channel (%s, %s, %s) for user '%s'"),
                                           $notice->id,
                                           $channel->action,
                                           $channel->arg1,
                                           $channel->arg2,
                                           ($profile) ? ($profile->nickname) : "<public>"));
                        $timeline = $this->_pathToChannel(array($channel->channel_key));
                        $this->_publish($timeline, $json);
                    }
                }
            }

            $this->_disconnect();
        }

        return true;
    }

    function onStartShowBody($action)
    {
        $realtime = $action->boolean('realtime');
        if (!$realtime) {
            return true;
        }

        $action->elementStart('body',
                              (common_current_user()) ? array('id' => $action->trimmed('action'),
                                                              'class' => 'user_in realtime-popup')
                              : array('id' => $action->trimmed('action'),
                                      'class'=> 'realtime-popup'));

        // XXX hack to deal with JS that tries to get the
        // root url from page output

        $action->elementStart('address');

        if (common_config('singleuser', 'enabled')) {
            $user = User::singleUser();
            $url = common_local_url('showstream', array('nickname' => $user->nickname));
        } else {
            $url = common_local_url('public');
        }

        $action->element('a', array('class' => 'url',
                                    'href' => $url),
                         '');

        $action->elementEnd('address');

        $action->showContentBlock();
        $action->showScripts();
        $action->elementEnd('body');
        return false; // No default processing
    }

    function noticeAsJson($notice)
    {
        // FIXME: this code should be abstracted to a neutral third
        // party, like Notice::asJson(). I'm not sure of the ethics
        // of refactoring from within a plugin, so I'm just abusing
        // the ApiAction method. Don't do this unless you're me!

        $act = new ApiAction('/dev/null');

        $arr = $act->twitterStatusArray($notice, true);
        $arr['url'] = $notice->getUrl(true);
        $arr['html'] = htmlspecialchars($notice->rendered);
        $arr['source'] = htmlspecialchars($arr['source']);
        $arr['conversation_url'] = $notice->getConversationUrl();

        $profile = $notice->getProfile();
        $arr['user']['profile_url'] = $profile->profileurl;

        // Add needed repeat data

        if (!empty($notice->repeat_of)) {
            $original = Notice::getKV('id', $notice->repeat_of);
            if ($original instanceof Notice) {
                $arr['retweeted_status']['url'] = $original->getUrl(true);
                $arr['retweeted_status']['html'] = htmlspecialchars($original->rendered);
                $arr['retweeted_status']['source'] = htmlspecialchars($original->source);
                $originalProfile = $original->getProfile();
                $arr['retweeted_status']['user']['profile_url'] = $originalProfile->profileurl;
                $arr['retweeted_status']['conversation_url'] = $original->getConversationUrl();
            }
            unset($original);
        }

        return $arr;
    }

    function getNoticeTags($notice)
    {
        $tags = null;

        $nt = new Notice_tag();
        $nt->notice_id = $notice->id;

        if ($nt->find()) {
            $tags = array();
            while ($nt->fetch()) {
                $tags[] = $nt->tag;
            }
        }

        $nt->free();
        $nt = null;

        return $tags;
    }

    function _getScripts()
    {
        $urlpath = self::staticPath(str_replace('Plugin','',__CLASS__),
                                    'js/realtimeupdate.js');
        return array($urlpath);
    }

    /**
     * Export any i18n messages that need to be loaded at runtime...
     *
     * @param Action $action
     * @param array $messages
     *
     * @return boolean hook return value
     */
    function onEndScriptMessages($action, &$messages)
    {
        // TRANS: Text label for realtime view "play" button, usually replaced by an icon.
        $messages['realtime_play'] = _m('BUTTON', 'Play');
        // TRANS: Tooltip for realtime view "play" button.
        $messages['realtime_play_tooltip'] = _m('TOOLTIP', 'Play');
        // TRANS: Text label for realtime view "pause" button
        $messages['realtime_pause'] = _m('BUTTON', 'Pause');
        // TRANS: Tooltip for realtime view "pause" button
        $messages['realtime_pause_tooltip'] = _m('TOOLTIP', 'Pause');
        // TRANS: Text label for realtime view "popup" button, usually replaced by an icon.
        $messages['realtime_popup'] = _m('BUTTON', 'Pop up');
        // TRANS: Tooltip for realtime view "popup" button.
        $messages['realtime_popup_tooltip'] = _m('TOOLTIP', 'Pop up in a window');

        return true;
    }

    function _updateInitialize($timeline, $user_id)
    {
        return "RealtimeUpdate.init($user_id, \"$this->showurl\"); ";
    }

    function _connect()
    {
    }

    function _publish($timeline, $json)
    {
    }

    function _disconnect()
    {
    }

    function _pathToChannel($path)
    {
        return '';
    }

    function _getTimeline($action)
    {
        $channel = $this->_getChannel($action);
        if (empty($channel)) {
            return null;
        }

        return $this->_pathToChannel(array($channel->channel_key));
    }

    function _getChannel($action)
    {
        $timeline = null;
        $arg1     = null;
        $arg2     = null;

        $action_name = $action->trimmed('action');

        // FIXME: lists
        // FIXME: search (!)
        // FIXME: profile + tag

        switch ($action_name) {
         case 'public':
            // no arguments
            break;
         case 'tag':
            $tag = $action->trimmed('tag');
            if (!empty($tag)) {
                $arg1 = $tag;
            } else {
                $this->log(LOG_NOTICE, "Unexpected 'tag' action without tag argument");
                return null;
            }
            break;
         case 'showstream':
         case 'all':
         case 'replies':
         case 'showgroup':
            $nickname = common_canonical_nickname($action->trimmed('nickname'));
            if (!empty($nickname)) {
                $arg1 = $nickname;
            } else {
                $this->log(LOG_NOTICE, "Unexpected $action_name action without nickname argument.");
                return null;
            }
            break;
         default:
            return null;
        }

        $user = common_current_user();

        $user_id = (!empty($user)) ? $user->id : null;

        $channel = Realtime_channel::getChannel($user_id,
                                                $action_name,
                                                $arg1,
                                                $arg2);

        return $channel;
    }

    function onStartReadWriteTables(&$alwaysRW, &$rwdb)
    {
        $alwaysRW[] = 'realtime_channel';
        return true;
    }
}


code:
<?php
/**
 * StatusNet - the distributed open-source microblogging tool
 * Copyright (C) 2011, StatusNet, Inc.
 *
 * action to close a channel
 *
 * 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  Realtime
 * @package   StatusNet
 * @author    Evan Prodromou <evan@status.net>
 * @copyright 2011 StatusNet, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
 * @link      http://status.net/
 */

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

/**
 * Action to close a channel
 *
 * @category  Realtime
 * @package   StatusNet
 * @author    Evan Prodromou <evan@status.net>
 * @copyright 2011 StatusNet, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
 * @link      http://status.net/
 */
class ClosechannelAction extends Action
{
    protected $channelKey = null;
    protected $channel    = null;

    /**
     * For initializing members of the class.
     *
     * @param array $argarray misc. arguments
     *
     * @return boolean true
     */
    function prepare($argarray)
    {
        parent::prepare($argarray);

        if (!$this->isPost()) {
            // TRANS: Client exception. Do not translate POST.
            throw new ClientException(_m('You have to POST it.'));
        }

        $this->channelKey = $this->trimmed('channelkey');

        if (empty($this->channelKey)) {
            // TRANS: Client exception thrown when the channel key argument is missing.
            throw new ClientException(_m('No channel key argument.'));
        }

        $this->channel = Realtime_channel::getKV('channel_key', $this->channelKey);

        if (empty($this->channel)) {
            // TRANS: Client exception thrown when referring to a non-existing channel.
            throw new ClientException(_m('No such channel.'));
        }

        return true;
    }

    /**
     * Handler method
     *
     * @param array $argarray is ignored since it's now passed in in prepare()
     *
     * @return void
     */
    function handle($argarray=null)
    {
        $this->channel->decrement();

        header('HTTP/1.1 204 No Content');

        return;
    }

    /**
     * Return true if read only.
     *
     * MAY override
     *
     * @param array $args other arguments
     *
     * @return boolean is read only action?
     */
    function isReadOnly($args)
    {
        return false;
    }
}


code:
<?php
/**
 * StatusNet - the distributed open-source microblogging tool
 * Copyright (C) 2011, StatusNet, Inc.
 *
 * action periodically pinged by a page to keep a channel alive
 *
 * 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  Realtime
 * @package   StatusNet
 * @author    Evan Prodromou <evan@status.net>
 * @copyright 2011 StatusNet, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
 * @link      http://status.net/
 */

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

/**
 * Action periodically pinged by a page to keep a channel alive
 *
 * @category  Realtime
 * @package   StatusNet
 * @author    Evan Prodromou <evan@status.net>
 * @copyright 2011 StatusNet, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
 * @link      http://status.net/
 */
class KeepalivechannelAction extends Action
{
    protected $channelKey = null;
    protected $channel    = null;

    /**
     * For initializing members of the class.
     *
     * @param array $argarray misc. arguments
     *
     * @return boolean true
     */
    function prepare($argarray)
    {
        parent::prepare($argarray);

        if (!$this->isPost()) {
            // TRANS: Client exception. Do not translate POST.
            throw new ClientException(_m('You have to POST it.'));
        }

        $this->channelKey = $this->trimmed('channelkey');

        if (empty($this->channelKey)) {
            // TRANS: Client exception thrown when the channel key argument is missing.
            throw new ClientException(_m('No channel key argument.'));
        }

        $this->channel = Realtime_channel::getKV('channel_key', $this->channelKey);

        if (empty($this->channel)) {
            // TRANS: Client exception thrown when referring to a non-existing channel.
            throw new ClientException(_m('No such channel.'));
        }

        return true;
    }

    /**
     * Handler method
     *
     * @param array $argarray is ignored since it's now passed in in prepare()
     *
     * @return void
     */
    function handle($argarray=null)
    {
        $this->channel->touch();

        header('HTTP/1.1 204 No Content');

        return;
    }

    /**
     * Return true if read only.
     *
     * MAY override
     *
     * @param array $args other arguments
     *
     * @return boolean is read only action?
     */
    function isReadOnly($args)
    {
        return false;
    }
}


code:
<?php
/**
 * StatusNet - the distributed open-source microblogging tool
 * Copyright (C) 2011, StatusNet, Inc.
 *
 * A channel for real-time browser data
 *
 * 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  Realtime
 * @package   StatusNet
 * @author    Evan Prodromou <evan@status.net>
 * @copyright 2011 StatusNet, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
 * @link      http://status.net/
 */

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

/**
 * A channel for real-time browser data
 *
 * For each user currently browsing the site, we want to know which page they're on
 * so we can send real-time updates to their browser.
 *
 * @category Realtime
 * @package  StatusNet
 * @author   Evan Prodromou <evan@status.net>
 * @license  http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
 * @link     http://status.net/
 *
 * @see      DB_DataObject
 */
class Realtime_channel extends Managed_DataObject
{
    const TIMEOUT = 1800; // 30 minutes

    public $__table = 'realtime_channel'; // table name

    public $user_id;       // int -> user.id, can be null
    public $action;        // varchar(191)                  not 255 because utf8mb4 takes more space
    public $arg1;          // varchar(191)   argument       not 255 because utf8mb4 takes more space
    public $arg2;          // varchar(191)   usually null   not 255 because utf8mb4 takes more space
    public $channel_key;   // 128-bit shared secret key
    public $audience;      // listener count
    public $created;       // created date
    public $modified;      // modified date

    /**
     * The One True Thingy that must be defined and declared.
     */
    public static function schemaDef()
    {
        return array(
            'description' => 'A channel of realtime notice data',
            'fields' => array(
                'user_id' => array('type' => 'int',
                                   'not null' => false,
                                   'description' => 'user viewing page; can be null'),
                'action' => array('type' => 'varchar',
                                  'length' => 191,
                                  'not null' => true,
                                  'description' => 'page being viewed'),
                'arg1' => array('type' => 'varchar',
                                'length' => 191,
                                'not null' => false,
                                'description' => 'page argument, like username or tag'),
                'arg2' => array('type' => 'varchar',
                                'length' => 191,
                                'not null' => false,
                                'description' => 'second page argument, like tag for showstream'),
                'channel_key' => array('type' => 'varchar',
                               'length' => 32,
                               'not null' => true,
                               'description' => 'shared secret key for this channel'),
                'audience' => array('type' => 'integer',
                                    'not null' => true,
                                    'default' => 0,
                                    'description' => 'reference count'),
                'created' => array('type' => 'datetime',
                                   'not null' => true,
                                   'description' => 'date this record was created'),
                'modified' => array('type' => 'datetime',
                                    'not null' => true,
                                    'description' => 'date this record was modified'),
            ),
            'primary key' => array('channel_key'),
            'unique keys' => array('realtime_channel_user_page_idx' => array('user_id', 'action', 'arg1', 'arg2')),
            'foreign keys' => array(
                'realtime_channel_user_id_fkey' => array('user', array('user_id' => 'id')),
            ),
            'indexes' => array(
                'realtime_channel_modified_idx' => array('modified'),
                'realtime_channel_page_idx' => array('action', 'arg1', 'arg2')
            ),
        );
    }

    static function saveNew($user_id, $action, $arg1, $arg2)
    {
        $channel = new Realtime_channel();

        $channel->user_id = $user_id;
        $channel->action  = $action;
        $channel->arg1    = $arg1;
        $channel->arg2    = $arg2;
        $channel->audience  = 1;

        $channel->channel_key = common_random_hexstr(16); // 128-bit key, 32 hex chars

        $channel->created  = common_sql_now();
        $channel->modified = $channel->created;

        $channel->insert();

        return $channel;
    }

    static function getChannel($user_id, $action, $arg1, $arg2)
    {
        $channel = self::fetchChannel($user_id, $action, $arg1, $arg2);

        // Ignore (and delete!) old channels

        if (!empty($channel)) {
            $modTime = strtotime($channel->modified);
            if ((time() - $modTime) > self::TIMEOUT) {
                $channel->delete();
                $channel = null;
            }
        }

        if (empty($channel)) {
            $channel = self::saveNew($user_id, $action, $arg1, $arg2);
        }

        return $channel;
    }

    static function getAllChannels($action, $arg1, $arg2)
    {
        $channel = new Realtime_channel();

        $channel->action = $action;

        if (is_null($arg1)) {
            $channel->whereAdd('arg1 is null');
        } else {
            $channel->arg1 = $arg1;
        }

        if (is_null($arg2)) {
            $channel->whereAdd('arg2 is null');
        } else {
            $channel->arg2 = $arg2;
        }

        $channel->whereAdd('modified > "' . common_sql_date(time() - self::TIMEOUT) . '"');

        $channels = array();

        if ($channel->find()) {
            $channels = $channel->fetchAll();
        }

        return $channels;
    }

    static function fetchChannel($user_id, $action, $arg1, $arg2)
    {
        $channel = new Realtime_channel();

        if (is_null($user_id)) {
            $channel->whereAdd('user_id is null');
        } else {
            $channel->user_id = $user_id;
        }

        $channel->action = $action;

        if (is_null($arg1)) {
            $channel->whereAdd('arg1 is null');
        } else {
            $channel->arg1 = $arg1;
        }

        if (is_null($arg2)) {
            $channel->whereAdd('arg2 is null');
        } else {
            $channel->arg2 = $arg2;
        }

        if ($channel->find(true)) {
            $channel->increment();
            return $channel;
        } else {
            return null;
        }
    }

    function increment()
    {
        // XXX: race
        $orig = clone($this);
        $this->audience++;
        $this->modified = common_sql_now();
        $this->update($orig);
    }

    function touch()
    {
        // XXX: race
        $orig = clone($this);
        $this->modified = common_sql_now();
        $this->update($orig);
    }

    function decrement()
    {
        // XXX: race
        if ($this->audience == 1) {
            $this->delete();
        } else {
            $orig = clone($this);
            $this->audience--;
            $this->modified = common_sql_now();
            $this->update($orig);
        }
    }
}


code:
.realtime-popup address {
display:none;
}

.realtime-popup #content {
width:93.5%;
}

.realtime-popup #form_notice {
margin:18px 0 18px 1.795%;
width:93%;
max-width:451px;
}

.realtime-popup #form_notice label[for=notice_data-text],
.realtime-popup h1 {
display:none;
}

.realtime-popup #form_notice label.notice_data-attach,
.realtime-popup #form_notice input.notice_data-attach,
.realtime-popup #form_notice label.notice_data-geo {
top:0;
}

.realtime-popup #form_notice input.notice_data-attach {
left:auto;
right:0;
}

.realtime-popup .entity_profile {
width:70%;
}
.realtime-popup .entity_actions {
margin-left:1%;
}

#notices_primary {
position:relative;
}

#realtime_actions {
position: absolute;
top: -20px;
right: 0;
margin: 0 0 11px 0;
}

#realtime_actions li {
margin-left: 18px;
list-style-type: none;
float: left;
}

#realtime_actions button {
width: 16px;
height: 16px;
display: block;
border: none;
cursor: pointer;
text-indent: -9999px;
float: left;
}

#realtime_play {
margin-left: 4px;
}

#queued_counter {
float:left;
line-height:1.2;
}

#showstream #notices_primary {
margin-top: 18px;
}


code:
/*
 * StatusNet - a distributed open-source microblogging tool
 * Copyright (C) 2009-2011, StatusNet, Inc.
 *
 * Add a notice encoded as JSON into the current timeline
 *
 * 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  Plugin
 * @package   StatusNet
 * @author    Evan Prodromou <evan@status.net>
 * @author    Sarven Capadisli <csarven@status.net>
 * @copyright 2009-2011 StatusNet, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link      http://status.net/
 */

/**
 * This is the UI portion of the Realtime plugin base class, handling
 * queueing up and displaying of notices that have been received through
 * other code in one of the subclassed plugin implementations such as
 * Meteor or Orbited.
 *
 * Notices are passed in as JSON objects formatted per the Twitter-compatible
 * API.
 *
 * @todo Currently we duplicate a lot of formatting and layout code from
 *       the PHP side of StatusNet, which makes it very difficult to maintain
 *       this package. Internationalization as well as newer features such
 *       as location data, customized source links for OStatus profiles,
 *       and image thumbnails are not yet supported in Realtime yet because
 *       they have not been implemented here.
 */
RealtimeUpdate = {
     _userid: 0,
     _showurl: '',
     _keepaliveurl: '',
     _closeurl: '',
     _updatecounter: 0,
     _maxnotices: 50,
     _windowhasfocus: true,
     _documenttitle: '',
     _paused:false,
     _queuedNotices:[],

     /**
      * Initialize the Realtime plugin UI on a page with a timeline view.
      *
      * This function is called from a JS fragment inserted by the PHP side
      * of the Realtime plugin, and provides us with base information
      * needed to build a near-replica of StatusNet's NoticeListItem output.
      *
      * Once the UI is initialized, a plugin subclass will need to actually
      * feed data into the RealtimeUpdate object!
      *
      * @param {int} userid: local profile ID of the currently logged-in user
      * @param {String} showurl: URL for shownotice action, used when fetching formatting notices.
      *                            This URL contains a stub value of 0000000000 which will be replaced with the notice ID.
      *
      * @access public
      */
     init: function(userid, showurl)
     {
        RealtimeUpdate._userid = userid;
        RealtimeUpdate._showurl = showurl;

        RealtimeUpdate._documenttitle = document.title;

        $(window).bind('focus', function() {
          RealtimeUpdate._windowhasfocus = true;

          // Clear the counter on the window title when we focus in.
          RealtimeUpdate._updatecounter = 0;
          RealtimeUpdate.removeWindowCounter();
        });

        $(window).bind('blur', function() {
          $('#notices_primary .notice').removeClass('mark-top');

          $('#notices_primary .notice:first').addClass('mark-top');

          // While we're in the background, received messages will increment
          // a counter that we put on the window title. This will cause some
          // browsers to also flash or mark the tab or window title bar until
          // you seek attention (eg Firefox 4 pinned app tabs).
          RealtimeUpdate._windowhasfocus = false;

          return false;
        });
     },

     /**
      * Accept a notice in a Twitter-API JSON style and either show it
      * or queue it up, depending on whether the realtime display is
      * active.
      *
      * The meat of a Realtime plugin subclass is to provide a substrate
      * transport to receive data and shove it into this function. :)
      *
      * Note that the JSON data is extended from the standard API return
      * with additional fields added by RealtimePlugin's PHP code.
      *
      * @param {Object} data: extended JSON API-formatted notice
      *
      * @access public
      */
     receive: function(data)
     {
          if (RealtimeUpdate.isNoticeVisible(data.id)) {
              // Probably posted by the user in this window, and so already
              // shown by the AJAX form handler. Ignore it.
              return;
          }
          if (RealtimeUpdate._paused === false) {
              RealtimeUpdate.purgeLastNoticeItem();

              RealtimeUpdate.insertNoticeItem(data);
          }
          else {
              RealtimeUpdate._queuedNotices.push(data);

              RealtimeUpdate.updateQueuedCounter();
          }

          RealtimeUpdate.updateWindowCounter();
     },

     /**
      * Add a visible representation of the given notice at the top of
      * the current timeline.
      *
      * If the notice is already in the timeline, nothing will be added.
      *
      * @param {Object} data: extended JSON API-formatted notice
      *
      * @fixme while core UI JS code is used to activate the AJAX UI controls,
      *        the actual production of HTML (in makeNoticeItem and its subs)
      *        duplicates core code without plugin hook points or i18n support.
      *
      * @access private
      */
     insertNoticeItem: function(data) {
        // Don't add it if it already exists
        if (RealtimeUpdate.isNoticeVisible(data.id)) {
            return;
        }

        RealtimeUpdate.makeNoticeItem(data, function(noticeItem) {
            // Check again in case it got shown while we were waiting for data...
            if (RealtimeUpdate.isNoticeVisible(data.id)) {
                return;
            }
            var noticeItemID = $(noticeItem).attr('id');

            var list = $("#notices_primary .notices:first")
            var prepend = true;

            var threaded = list.hasClass('threaded-notices');
            if (threaded && data.in_reply_to_status_id) {
                // aho!
                var parent = $('#notice-' + data.in_reply_to_status_id);
                if (parent.length == 0) {
                    // @todo fetch the original, insert it, and finish the rest
                } else {
                    // Check the parent notice to make sure it's not a reply itself.
                    // If so, use it's parent as the parent.
                    var parentList = parent.closest('.notices');
                    if (parentList.hasClass('threaded-replies')) {
                        parent = parentList.closest('.notice');
                    }
                    list = parent.find('.threaded-replies');
                    if (list.length == 0) {
                        list = $('

');
                        parent.append(list);
                        SN.U.NoticeInlineReplyPlaceholder(parent);
                    }
                    prepend = false;
                }
            }

            var newNotice = $(noticeItem);
            if (prepend) {
                list.prepend(newNotice);
            } else {
                var placeholder = list.find('li.notice-reply-placeholder')
                if (placeholder.length > 0) {
                    newNotice.insertBefore(placeholder)
                } else {
                    newNotice.appendTo(list);
                }
            }
            newNotice.css({display:"none"}).fadeIn(1000);

            SN.U.NoticeReplyTo($('#'+noticeItemID));
            SN.U.NoticeWithAttachment($('#'+noticeItemID));
        });
     },

     /**
      * Check if the given notice is visible in the timeline currently.
      * Used to avoid duplicate processing of notices that have been
      * displayed by other means.
      *
      * @param {number} id: notice ID to check
      *
      * @return boolean
      *
      * @access private
      */
     isNoticeVisible: function(id) {
        return ($("#notice-"+id).length > 0);
     },

     /**
      * Trims a notice off the end of the timeline if we have more than the
      * maximum number of notices visible.
      *
      * @access private
      */
     purgeLastNoticeItem: function() {
        if ($('#notices_primary .notice').length > RealtimeUpdate._maxnotices) {
            $("#notices_primary .notice:last").remove();
        }
     },

     /**
      * If the window/tab is in background, increment the counter of newly
      * received notices and append it onto the window title.
      *
      * Has no effect if the window is in foreground.
      *
      * @access private
      */
     updateWindowCounter: function() {
          if (RealtimeUpdate._windowhasfocus === false) {
              RealtimeUpdate._updatecounter += 1;
              document.title = '('+RealtimeUpdate._updatecounter+') ' + RealtimeUpdate._documenttitle;
          }
     },

     /**
      * Clear the background update counter from the window title.
      *
      * @access private
      *
      * @fixme could interfere with anything else trying similar tricks
      */
     removeWindowCounter: function() {
          document.title = RealtimeUpdate._documenttitle;
     },

     /**
      * Builds a notice HTML block from JSON API-style data;
      * loads data from server, so runs async.
      *
      * @param {Object} data: extended JSON API-formatted notice
      * @param {function} callback: function(DOMNode) to receive new code
      *
      * @access private
      */
     makeNoticeItem: function(data, callback)
     {
         var url = RealtimeUpdate._showurl.replace('0000000000', data.id);
         $.get(url, {ajax: 1}, function(data, textStatus, xhr) {
             var notice = $('li.notice:first', data);
             if (notice.length) {
                 var node = document._importNode(notice[0], true);
                 callback(node);
             }
         });
     },

     /**
      * Creates a favorite button.
      *
      * @param {number} id: notice ID to work with
      * @param {String} session_key: session token for form CSRF protection
      * @return {String} HTML fragment
      *
      * @fixme this replicates core StatusNet code, making maintenance harder
      * @fixme sloppy HTML building (raw concat without escaping)
      * @fixme no i18n support
      *
      * @access private
      */
     makeFavoriteForm: function(id, session_key)
     {
          var ff;

          ff = "<form id=\"favor-"+id+"\" class=\"form_favor\" method=\"post\" action=\""+RealtimeUpdate._favorurl+"\">"+
                "<fieldset>"+
               "<legend>Favor this notice</legend>"+
               "<input name=\"token\" type=\"hidden\" id=\"token-"+id+"\" value=\""+session_key+"\"/>"+
               "<input name=\"notice\" type=\"hidden\" id=\"notice-n"+id+"\" value=\""+id+"\"/>"+
               "<input type=\"submit\" id=\"favor-submit-"+id+"\" name=\"favor-submit-"+id+"\" class=\"submit\" value=\"Favor\" title=\"Favor this notice\"/>"+
                "</fieldset>"+
               "</form>";
          return ff;
     },

     /**
      * Creates a reply button.
      *
      * @param {number} id: notice ID to work with
      * @param {String} nickname: nick of the user to whom we are replying
      * @return {String} HTML fragment
      *
      * @fixme this replicates core StatusNet code, making maintenance harder
      * @fixme sloppy HTML building (raw concat without escaping)
      * @fixme no i18n support
      *
      * @access private
      */
     makeReplyLink: function(id, nickname)
     {
          var rl;
          rl = "Reply "+id+"";
          return rl;
     },

     /**
      * Creates a repeat button.
      *
      * @param {number} id: notice ID to work with
      * @param {String} session_key: session token for form CSRF protection
      * @return {String} HTML fragment
      *
      * @fixme this replicates core StatusNet code, making maintenance harder
      * @fixme sloppy HTML building (raw concat without escaping)
      * @fixme no i18n support
      *
      * @access private
      */
     makeRepeatForm: function(id, session_key)
     {
          var rf;
          rf = "<form id=\"repeat-"+id+"\" class=\"form_repeat\" method=\"post\" action=\""+RealtimeUpdate._repeaturl+"\">"+
               "<fieldset>"+
               "<legend>Repeat this notice?</legend>"+
               "<input name=\"token\" type=\"hidden\" id=\"token-"+id+"\" value=\""+session_key+"\"/>"+
               "<input name=\"notice\" type=\"hidden\" id=\"notice-"+id+"\" value=\""+id+"\"/>"+
               "<input type=\"submit\" id=\"repeat-submit-"+id+"\" name=\"repeat-submit-"+id+"\" class=\"submit\" value=\"Yes\" title=\"Repeat this notice\"/>"+
               "</fieldset>"+
               "</form>";

          return rf;
     },

     /**
      * Creates a delete button.
      *
      * @param {number} id: notice ID to create a delete link for
      * @return {String} HTML fragment
      *
      * @fixme this replicates core StatusNet code, making maintenance harder
      * @fixme sloppy HTML building (raw concat without escaping)
      * @fixme no i18n support
      *
      * @access private
      */
     makeDeleteLink: function(id)
     {
          var dl, delurl;
          delurl = RealtimeUpdate._deleteurl.replace("0000000000", id);

          dl = "Delete";

          return dl;
     },

     /**
      * Adds a control widget at the top of the timeline view, containing
      * pause/play and popup buttons.
      *
      * @param {String} url: full URL to the popup window variant of this timeline page
      * @param {String} timeline: string key for the timeline (eg 'public' or 'evan-all')
      * @param {String} path: URL to the base directory containing the Realtime plugin,
      *                       used to fetch resources if needed.
      *
      * @todo timeline and path parameters are unused and probably should be removed.
      *
      * @access private
      */
    initActions: function(url, timeline, path, keepaliveurl, closeurl)
     {
        $('#notices_primary').prepend('

');

        RealtimeUpdate._pluginPath = path;
        RealtimeUpdate._keepaliveurl = keepaliveurl;
        RealtimeUpdate._closeurl = closeurl;

	 // On unload, let the server know we're no longer listening
         $(window).unload(function() {
            $.ajax({
                type: 'POST',
                url: RealtimeUpdate._closeurl});
	 });

	setInterval(function() {
            $.ajax({
                type: 'POST',
                url: RealtimeUpdate._keepaliveurl});

	}, 15 * 60 * 1000 ); // every 15 min; timeout in 30 min

        RealtimeUpdate.initPlayPause();
        RealtimeUpdate.initAddPopup(url, timeline, RealtimeUpdate._pluginPath);
     },

     /**
      * Initialize the state of the play/pause controls.
      *
      * If the browser supports the localStorage interface, we'll attempt
      * to retrieve a pause state from there; otherwise we default to paused.
      *
      * @access private
      */
     initPlayPause: function()
     {
        if (typeof(localStorage) == 'undefined') {
            RealtimeUpdate.showPause();
        }
        else {
            if (localStorage.getItem('RealtimeUpdate_paused') === 'true') {
                RealtimeUpdate.showPlay();
            }
            else {
                RealtimeUpdate.showPause();
            }
        }
     },

     /**
      * Switch the realtime UI into paused state.
      * Uses SN.msg i18n system for the button label and tooltip.
      *
      * State will be saved and re-used next time if the browser supports
      * the localStorage interface (via setPause).
      *
      * @access private
      */
     showPause: function()
     {
        RealtimeUpdate.setPause(false);
        RealtimeUpdate.showQueuedNotices();
        RealtimeUpdate.addNoticesHover();

        $('#realtime_playpause').remove();
        $('#realtime_actions').prepend('
<button id="realtime_pause" class="pause"></button>
');
        $('#realtime_pause').text(SN.msg('realtime_pause'))
                            .attr('title', SN.msg('realtime_pause_tooltip'))
                            .bind('click', function() {
            RealtimeUpdate.removeNoticesHover();
            RealtimeUpdate.showPlay();
            return false;
        });
     },

     /**
      * Switch the realtime UI into play state.
      * Uses SN.msg i18n system for the button label and tooltip.
      *
      * State will be saved and re-used next time if the browser supports
      * the localStorage interface (via setPause).
      *
      * @access private
      */
     showPlay: function()
     {
        RealtimeUpdate.setPause(true);
        $('#realtime_playpause').remove();
        $('#realtime_actions').prepend('
 <button id="realtime_play" class="play"></button>
');
        $('#realtime_play').text(SN.msg('realtime_play'))
                           .attr('title', SN.msg('realtime_play_tooltip'))
                           .bind('click', function() {
            RealtimeUpdate.showPause();
            return false;
        });
     },

     /**
      * Update the internal pause/play state.
      * Do not call directly; use showPause() and showPlay().
      *
      * State will be saved and re-used next time if the browser supports
      * the localStorage interface.
      *
      * @param {boolean} state: true = paused, false = not paused
      *
      * @access private
      */
     setPause: function(state)
     {
        RealtimeUpdate._paused = state;
        if (typeof(localStorage) != 'undefined') {
            localStorage.setItem('RealtimeUpdate_paused', RealtimeUpdate._paused);
        }
     },

     /**
      * Go through notices we have previously received while paused,
      * dumping them into the timeline view.
      *
      * @fixme long timelines are not trimmed here as they are for things received while not paused
      *
      * @access private
      */
     showQueuedNotices: function()
     {
        $.each(RealtimeUpdate._queuedNotices, function(i, n) {
            RealtimeUpdate.insertNoticeItem(n);
        });

        RealtimeUpdate._queuedNotices = [];

        RealtimeUpdate.removeQueuedCounter();
     },

     /**
      * Update the Realtime widget control's counter of queued notices to show
      * the current count. This will be called after receiving and queueing
      * a notice while paused.
      *
      * @access private
      */
     updateQueuedCounter: function()
     {
        $('#realtime_playpause #queued_counter').html('('+RealtimeUpdate._queuedNotices.length+')');
     },

     /**
      * Clear the Realtime widget control's counter of queued notices.
      *
      * @access private
      */
     removeQueuedCounter: function()
     {
        $('#realtime_playpause #queued_counter').empty();
     },

     /**
      * Set up event handlers on the timeline view to automatically pause
      * when the mouse is over the timeline, as this indicates the user's
      * desire to interact with the UI. (Which is hard to do when it's moving!)
      *
      * @access private
      */
     addNoticesHover: function()
     {
        $('#notices_primary .notices').hover(
            function() {
                if (RealtimeUpdate._paused === false) {
                    RealtimeUpdate.showPlay();
                }
            },
            function() {
                if (RealtimeUpdate._paused === true) {
                    RealtimeUpdate.showPause();
                }
            }
        );
     },

     /**
      * Tear down event handlers on the timeline view to automatically pause
      * when the mouse is over the timeline.
      *
      * @fixme this appears to remove *ALL* event handlers from the timeline,
      *        which assumes that nobody else is adding any event handlers.
      *        Sloppy -- we should only remove the ones we add.
      *
      * @access private
      */
     removeNoticesHover: function()
     {
        $('#notices_primary .notices').unbind();
     },

     /**
      * UI initialization, to be called from Realtime plugin code on regular
      * timeline pages.
      *
      * Adds a button to the control widget at the top of the timeline view,
      * allowing creation of a popup window with a more compact real-time
      * view of the current timeline.
      *
      * @param {String} url: full URL to the popup window variant of this timeline page
      * @param {String} timeline: string key for the timeline (eg 'public' or 'evan-all')
      * @param {String} path: URL to the base directory containing the Realtime plugin,
      *                       used to fetch resources if needed.
      *
      * @todo timeline and path parameters are unused and probably should be removed.
      *
      * @access public
      */
     initAddPopup: function(url, timeline, path)
     {
         $('#realtime_timeline').append('<button id="realtime_popup"></button>');
         $('#realtime_popup').text(SN.msg('realtime_popup'))
                             .attr('title', SN.msg('realtime_popup_tooltip'))
                             .bind('click', function() {
                window.open(url,
                         '',
                         'toolbar=no,resizable=yes,scrollbars=yes,status=no,menubar=no,personalbar=no,location=no,width=500,height=550');

             return false;
         });
     },

     /**
      * UI initialization, to be called from Realtime plugin code on popup
      * compact timeline pages.
      *
      * Sets up links in notices to open in a new window.
      *
      * @fixme fails to do the same for UI links like context view which will
      *        look bad in the tiny chromeless window.
      *
      * @access public
      */
     initPopupWindow: function()
     {
         $('.notices .entry-title a, .notices .e-content a').bind('click', function() {
            window.open(this.href, '');

            return false;
         });

         $('#showstream .entity_profile').css({'width':'69%'});
     }
}


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: 2015-02-27 16:31+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: Client exception. Do not translate POST.
#: actions/keepalivechannel.php:65 actions/closechannel.php:65
msgid "You have to POST it."
msgstr ""

#. TRANS: Client exception thrown when the channel key argument is missing.
#: actions/keepalivechannel.php:72 actions/closechannel.php:72
msgid "No channel key argument."
msgstr ""

#. TRANS: Client exception thrown when referring to a non-existing channel.
#: actions/keepalivechannel.php:79 actions/closechannel.php:79
msgid "No such channel."
msgstr ""

#. TRANS: Text label for realtime view "play" button, usually replaced by an icon.
#: RealtimePlugin.php:387
msgctxt "BUTTON"
msgid "Play"
msgstr ""

#. TRANS: Tooltip for realtime view "play" button.
#: RealtimePlugin.php:389
msgctxt "TOOLTIP"
msgid "Play"
msgstr ""

#. TRANS: Text label for realtime view "pause" button
#: RealtimePlugin.php:391
msgctxt "BUTTON"
msgid "Pause"
msgstr ""

#. TRANS: Tooltip for realtime view "pause" button
#: RealtimePlugin.php:393
msgctxt "TOOLTIP"
msgid "Pause"
msgstr ""

#. TRANS: Text label for realtime view "popup" button, usually replaced by an icon.
#: RealtimePlugin.php:395
msgctxt "BUTTON"
msgid "Pop up"
msgstr ""

#. TRANS: Tooltip for realtime view "popup" button.
#: RealtimePlugin.php:397
msgctxt "TOOLTIP"
msgid "Pop up in a window"
msgstr ""


code:
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
#
# 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: Afrikaans (http://www.transifex.com/projects/p/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: Client exception. Do not translate POST.
#: actions/keepalivechannel.php:65 actions/closechannel.php:65
msgid "You have to POST it."
msgstr ""

#. TRANS: Client exception thrown when the channel key argument is missing.
#: actions/keepalivechannel.php:72 actions/closechannel.php:72
msgid "No channel key argument."
msgstr ""

#. TRANS: Client exception thrown when referring to a non-existing channel.
#: actions/keepalivechannel.php:79 actions/closechannel.php:79
msgid "No such channel."
msgstr ""

#. TRANS: Text label for realtime view "play" button, usually replaced by an
#. icon.
#: RealtimePlugin.php:387
msgctxt "BUTTON"
msgid "Play"
msgstr "Speel"

#. TRANS: Tooltip for realtime view "play" button.
#: RealtimePlugin.php:389
msgctxt "TOOLTIP"
msgid "Play"
msgstr "Speel"

#. TRANS: Text label for realtime view "pause" button
#: RealtimePlugin.php:391
msgctxt "BUTTON"
msgid "Pause"
msgstr "Wag"

#. TRANS: Tooltip for realtime view "pause" button
#: RealtimePlugin.php:393
msgctxt "TOOLTIP"
msgid "Pause"
msgstr "Wag"

#. TRANS: Text label for realtime view "popup" button, usually replaced by an
#. icon.
#: RealtimePlugin.php:395
msgctxt "BUTTON"
msgid "Pop up"
msgstr "Pop-up"

#. TRANS: Tooltip for realtime view "popup" button.
#: RealtimePlugin.php:397
msgctxt "TOOLTIP"
msgid "Pop up in a window"
msgstr "Wys in 'n venstertjie"


code:
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
#
# 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: Arabic (http://www.transifex.com/projects/p/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: Client exception. Do not translate POST.
#: actions/keepalivechannel.php:65 actions/closechannel.php:65
msgid "You have to POST it."
msgstr ""

#. TRANS: Client exception thrown when the channel key argument is missing.
#: actions/keepalivechannel.php:72 actions/closechannel.php:72
msgid "No channel key argument."
msgstr ""

#. TRANS: Client exception thrown when referring to a non-existing channel.
#: actions/keepalivechannel.php:79 actions/closechannel.php:79
msgid "No such channel."
msgstr ""

#. TRANS: Text label for realtime view "play" button, usually replaced by an
#. icon.
#: RealtimePlugin.php:387
msgctxt "BUTTON"
msgid "Play"
msgstr "شغّل"

#. TRANS: Tooltip for realtime view "play" button.
#: RealtimePlugin.php:389
msgctxt "TOOLTIP"
msgid "Play"
msgstr "شغّل"

#. TRANS: Text label for realtime view "pause" button
#: RealtimePlugin.php:391
msgctxt "BUTTON"
msgid "Pause"
msgstr "ألبث"

#. TRANS: Tooltip for realtime view "pause" button
#: RealtimePlugin.php:393
msgctxt "TOOLTIP"
msgid "Pause"
msgstr "ألبث"

#. TRANS: Text label for realtime view "popup" button, usually replaced by an
#. icon.
#: RealtimePlugin.php:395
msgctxt "BUTTON"
msgid "Pop up"
msgstr "منبثق"

#. TRANS: Tooltip for realtime view "popup" button.
#: RealtimePlugin.php:397
msgctxt "TOOLTIP"
msgid "Pop up in a window"
msgstr "منبثق في نافذة"