]> git.mxchange.org Git - friendica.git/commitdiff
Merge pull request #7828 from nupplaphil/task/move_enotify
authorHypolite Petovan <hypolite@mrpetovan.com>
Sat, 9 Nov 2019 21:48:26 +0000 (16:48 -0500)
committerGitHub <noreply@github.com>
Sat, 9 Nov 2019 21:48:26 +0000 (16:48 -0500)
Remove unnecessary code in "include/enotify"

180 files changed:
database.sql
doc/Export-Import-Contacts.md [new file with mode: 0644]
doc/Home.md
doc/de/Export-Import-Contacts.md [new file with mode: 0644]
doc/de/Home.md
include/api.php
include/conversation.php
mod/fbrowser.php
mod/hovercard.php [deleted file]
mod/network.php
mod/photos.php
mod/settings.php
mod/uexport.php [deleted file]
mod/update_contact.php
mod/update_profile.php
mod/wall_upload.php
src/App/Arguments.php
src/App/Module.php
src/App/Page.php
src/App/Router.php
src/BaseModule.php
src/Content/Item.php
src/Content/Text/BBCode.php
src/Content/Widget.php
src/Core/Installer.php
src/LegacyModule.php
src/Model/Contact.php
src/Model/Item.php
src/Model/Photo.php
src/Model/User.php
src/Module/AccountManagementControlDocument.php
src/Module/Acctlink.php
src/Module/Admin/Addons/Details.php
src/Module/Admin/Addons/Index.php
src/Module/Admin/Blocklist/Contact.php
src/Module/Admin/Blocklist/Server.php
src/Module/Admin/DBSync.php
src/Module/Admin/Features.php
src/Module/Admin/Federation.php
src/Module/Admin/Item/Delete.php
src/Module/Admin/Item/Source.php
src/Module/Admin/Logs/Settings.php
src/Module/Admin/Logs/View.php
src/Module/Admin/PhpInfo.php
src/Module/Admin/Queue.php
src/Module/Admin/Site.php
src/Module/Admin/Summary.php
src/Module/Admin/Themes/Details.php
src/Module/Admin/Themes/Embed.php
src/Module/Admin/Themes/Index.php
src/Module/Admin/Tos.php
src/Module/Admin/Users.php
src/Module/AllFriends.php
src/Module/Apps.php
src/Module/Attach.php
src/Module/BaseAdminModule.php
src/Module/BaseSettingsModule.php
src/Module/Bookmarklet.php
src/Module/Contact.php
src/Module/Contact/Hovercard.php [new file with mode: 0644]
src/Module/Credits.php
src/Module/Debug/Babel.php
src/Module/Debug/Feed.php
src/Module/Debug/ItemBody.php
src/Module/Debug/Localtime.php
src/Module/Debug/Probe.php
src/Module/Debug/WebFinger.php
src/Module/Delegation.php
src/Module/Diaspora/Fetch.php
src/Module/Diaspora/Receive.php
src/Module/Directory.php
src/Module/Feed.php
src/Module/Filer/RemoveTag.php
src/Module/Filer/SaveTag.php
src/Module/FollowConfirm.php
src/Module/Followers.php
src/Module/Following.php
src/Module/Friendica.php
src/Module/Group.php
src/Module/HTTPException/MethodNotAllowed.php
src/Module/HTTPException/PageNotFound.php
src/Module/Hashtag.php
src/Module/Help.php
src/Module/Home.php
src/Module/Inbox.php
src/Module/Install.php
src/Module/Invite.php
src/Module/Item/Compose.php
src/Module/Item/Ignore.php
src/Module/Like.php
src/Module/Login.php
src/Module/Logout.php
src/Module/Magic.php
src/Module/Maintenance.php
src/Module/Manifest.php
src/Module/NodeInfo.php
src/Module/Notifications/Notify.php
src/Module/Objects.php
src/Module/Oembed.php
src/Module/OpenSearch.php
src/Module/Outbox.php
src/Module/Owa.php
src/Module/Photo.php
src/Module/Pinned.php [new file with mode: 0644]
src/Module/Profile.php
src/Module/Profile/Contacts.php
src/Module/Proxy.php
src/Module/PublicRSAKey.php
src/Module/RandomProfile.php
src/Module/ReallySimpleDiscovery.php
src/Module/Register.php
src/Module/RobotsTxt.php
src/Module/Search/Acl.php
src/Module/Search/Directory.php
src/Module/Search/Index.php
src/Module/Search/Saved.php
src/Module/Settings/Delegation.php
src/Module/Settings/TwoFactor/AppSpecific.php
src/Module/Settings/TwoFactor/Index.php
src/Module/Settings/TwoFactor/Recovery.php
src/Module/Settings/TwoFactor/Verify.php
src/Module/Settings/UserExport.php [new file with mode: 0644]
src/Module/Smilies.php
src/Module/Starred.php
src/Module/Statistics.php
src/Module/Theme.php
src/Module/ThemeDetails.php
src/Module/ToggleMobile.php
src/Module/Tos.php
src/Module/TwoFactor/Recovery.php
src/Module/TwoFactor/Verify.php
src/Module/Welcome.php
src/Module/WellKnown/HostMeta.php
src/Module/WellKnown/XSocialRelay.php
src/Module/Xrd.php
src/Object/Image.php
src/Object/Post.php
src/Protocol/ActivityPub/Transmitter.php
src/Protocol/DFRN.php
src/Protocol/Diaspora.php
src/Protocol/OStatus.php
src/Util/Images.php [new file with mode: 0644]
src/Util/ParseUrl.php
static/dbstructure.config.php
static/dependencies.config.php
static/routes.config.php
static/settings.config.php
tests/src/App/ModeTest.php
tests/src/App/ModuleTest.php
tests/src/App/RouterTest.php
tests/src/Core/InstallerTest.php
view/js/main.js
view/lang/C/messages.po
view/templates/hovercard.tpl
view/templates/register.tpl
view/templates/settings/settings.tpl
view/templates/settings/userexport.tpl [new file with mode: 0644]
view/templates/wall_thread.tpl
view/theme/duepuntozero/style.css
view/theme/frio/css/style.css
view/theme/frio/frameworks/jsmart/jsmart.custom.js [deleted file]
view/theme/frio/frameworks/jsmart/jsmart.js [deleted file]
view/theme/frio/frameworks/jsmart/jsmart.min.js [deleted file]
view/theme/frio/js/hovercard.js
view/theme/frio/scheme/plusminus.css
view/theme/frio/templates/event_stream_item.tpl
view/theme/frio/templates/head.tpl
view/theme/frio/templates/nav.tpl
view/theme/frio/templates/notify.tpl
view/theme/frio/templates/photo_item.tpl
view/theme/frio/templates/register.tpl
view/theme/frio/templates/search_item.tpl
view/theme/frio/templates/settings/settings.tpl
view/theme/frio/templates/settings/userexport.tpl [new file with mode: 0644]
view/theme/frio/templates/wall_thread.tpl
view/theme/frio/templates/widget/follow.tpl
view/theme/quattro/templates/wall_thread.tpl
view/theme/smoothly/style.css
view/theme/smoothly/templates/wall_thread.tpl
view/theme/vier/templates/wall_thread.tpl

index b09b8290e09f4cd81f77fa924df7655ca82435b7..8630bfba8b412d2fdf9e4f54df3941e9637d357a 100644 (file)
@@ -1,6 +1,6 @@
 -- ------------------------------------------
--- Friendica 2019.09-rc (Dalmatian Bellflower)
--- DB_UPDATE_VERSION 1322
+-- Friendica 2019.12-dev (Dalmatian Bellflower)
+-- DB_UPDATE_VERSION 1324
 -- ------------------------------------------
 
 
@@ -1279,7 +1279,9 @@ CREATE TABLE IF NOT EXISTS `user-item` (
        `uid` mediumint unsigned NOT NULL DEFAULT 0 COMMENT 'User id',
        `hidden` boolean NOT NULL DEFAULT '0' COMMENT 'Marker to hide an item from the user',
        `ignored` boolean COMMENT 'Ignore this thread if set',
-        PRIMARY KEY(`uid`,`iid`)
+       `pinned` boolean COMMENT 'The item is pinned on the profile page',
+        PRIMARY KEY(`uid`,`iid`),
+        INDEX `uid_pinned` (`uid`,`pinned`)
 ) DEFAULT COLLATE utf8mb4_general_ci COMMENT='User specific item data';
 
 --
diff --git a/doc/Export-Import-Contacts.md b/doc/Export-Import-Contacts.md
new file mode 100644 (file)
index 0000000..3e1e911
--- /dev/null
@@ -0,0 +1,23 @@
+# Export / Import of followed Contacts
+
+* [Home](help)
+
+In addition to [move your account](help/Move-Account) you can export and import the list of accounts you follow.
+The exported list is stored as CSV file that is compatible to the format used by other platforms as e.g. Mastodon or Pleroma.
+
+## Export of followed Contacts
+
+To export the list of accounts that you follow, go to the [Settings Export personal date](settings/userexport) and click the [Export Contacts to CSV](settings/userexport/contact).
+
+## Import of followed Contacts
+
+To import contacts from a CSV file, go to the [Settings page](settings).
+At the bottom of the *account settings* page you'll find the *import contacts* section.
+Upload the CSV file there.
+
+### Supported File Format
+
+The CSV file *must* contain at least one column.
+In the first column the table should contain either the handle or URL of an followed account.
+(one account per row.)
+Other columns in the CSV file will be ignored.
index 03e21425700ae86eed8b84175ee08cdf96f4f63d..095be1bb68e6412a37df8ec8ea5b4366e57daabc 100644 (file)
@@ -21,6 +21,7 @@ Friendica Documentation and Resources
        * [Chats](help/Chats)
 * Further information
        * [Move your account](help/Move-Account)
+       * [Export / Import of followed Contacts](help/Export-Import-Contacts)
        * [Delete your account](help/Remove-Account)
        * [Frequently asked questions (FAQ)](help/FAQ)
 
diff --git a/doc/de/Export-Import-Contacts.md b/doc/de/Export-Import-Contacts.md
new file mode 100644 (file)
index 0000000..7390556
--- /dev/null
@@ -0,0 +1,23 @@
+# Export / Import von gefolgten Kontakte
+
+* [Home](help)
+
+Zusätzlich zum [Umziehen des Accounts](help/Move-Account) kannst du die Liste der von dir gefolgten Kontakte exportieren und importieren.
+Die exportierte Liste wird als CSV Datei in einem zu anderen Plattformen, z.B. Mastodon oder Pleroma, kompatiblen Format gespeichert.
+
+## Export der gefolgten Kontakte
+
+Um die Liste der Kontakte *denen du folgst* zu exportieren, geht die [Einstellungen Persönliche Daten exportieren](settings/userexport) und klicke den [Exportiere Kontakte als CSV](settings/userexport/contact) an.
+
+## Import der gefolgten Kontakte
+
+Um die Kontakt CSV Datei zu importieren, gehe in die [Einstellungen](settings).
+Am Ende der Einstellungen zum Nutzerkonto findest du den Abschnitt "Kontakte Importieren".
+Hier kannst du die CSV Datei auswählen und hoch laden.
+
+### Unterstütztes Datei Format
+
+Die CSV Datei *muss* mindestens eine Spalte beinhalten.
+In der ersten Spalte der Tabelle sollte *sollte* entweder das Handle oder die URL des gefolgten Kontakts.
+(Ein Kontakt pro Zeile.)
+Alle anderen Spalten der CSV Datei werden beim Importieren ignoriert.
index 1498ccff1a8ff4c5339987b55284c94f9c160779..536bff72013add754b2dda12218e3d94f7bcd7c8 100644 (file)
@@ -21,6 +21,7 @@ Friendica - Dokumentation und Ressourcen
        * [Chats](help/Chats)
 * Weiterführende Informationen
        * [Account umziehen](help/Move-Account)
+       * [Export / Import gefolgter Kontakte](help/Export-Import-Contacts)
        * [Account löschen](help/Remove-Account)
        * [Bugs und Probleme](help/Bugs-and-Issues)
        * [Häufig gestellte Fragen (FAQ)](help/FAQ)
index 24a0585ee5f05d956f18b9f6fe5d53a4725618f8..d5eb9c54186d12089d719963f78ca92888b9b1c8 100644 (file)
@@ -45,6 +45,7 @@ use Friendica\Object\Image;
 use Friendica\Protocol\Activity;
 use Friendica\Protocol\Diaspora;
 use Friendica\Util\DateTimeFormat;
+use Friendica\Util\Images;
 use Friendica\Util\Network;
 use Friendica\Util\Proxy as ProxyUtils;
 use Friendica\Util\Strings;
@@ -1167,7 +1168,7 @@ function api_statuses_update($type)
                                api_user()
                        );
                        if (DBA::isResult($r)) {
-                               $phototypes = Image::supportedTypes();
+                               $phototypes = Images::supportedTypes();
                                $ext = $phototypes[$r[0]['type']];
                                $description = $r[0]['desc'] ?? '';
                                $_REQUEST['body'] .= "\n\n" . '[url=' . System::baseUrl() . '/photos/' . $r[0]['nickname'] . '/image/' . $r[0]['resource-id'] . ']';
@@ -2564,7 +2565,7 @@ function api_get_attachments(&$body)
        $attachments = [];
 
        foreach ($images[1] as $image) {
-               $imagedata = Image::getInfoFromURL($image);
+               $imagedata = Images::getInfoFromURLCached($image);
 
                if ($imagedata) {
                        $attachments[] = ["url" => $image, "mimetype" => $imagedata["mime"], "size" => $imagedata["size"]];
@@ -2711,7 +2712,7 @@ function api_get_entitities(&$text, $bbcode)
 
                $start = iconv_strpos($text, $url, $offset, "UTF-8");
                if (!($start === false)) {
-                       $image = Image::getInfoFromURL($url);
+                       $image = Images::getInfoFromURLCached($url);
                        if ($image) {
                                // If image cache is activated, then use the following sizes:
                                // thumb  (150), small (340), medium (600) and large (1024)
@@ -2719,19 +2720,19 @@ function api_get_entitities(&$text, $bbcode)
                                        $media_url = ProxyUtils::proxifyUrl($url);
 
                                        $sizes = [];
-                                       $scale = Image::getScalingDimensions($image[0], $image[1], 150);
+                                       $scale = Images::getScalingDimensions($image[0], $image[1], 150);
                                        $sizes["thumb"] = ["w" => $scale["width"], "h" => $scale["height"], "resize" => "fit"];
 
                                        if (($image[0] > 150) || ($image[1] > 150)) {
-                                               $scale = Image::getScalingDimensions($image[0], $image[1], 340);
+                                               $scale = Images::getScalingDimensions($image[0], $image[1], 340);
                                                $sizes["small"] = ["w" => $scale["width"], "h" => $scale["height"], "resize" => "fit"];
                                        }
 
-                                       $scale = Image::getScalingDimensions($image[0], $image[1], 600);
+                                       $scale = Images::getScalingDimensions($image[0], $image[1], 600);
                                        $sizes["medium"] = ["w" => $scale["width"], "h" => $scale["height"], "resize" => "fit"];
 
                                        if (($image[0] > 600) || ($image[1] > 600)) {
-                                               $scale = Image::getScalingDimensions($image[0], $image[1], 1024);
+                                               $scale = Images::getScalingDimensions($image[0], $image[1], 1024);
                                                $sizes["large"] = ["w" => $scale["width"], "h" => $scale["height"], "resize" => "fit"];
                                        }
                                } else {
@@ -4740,7 +4741,7 @@ function save_media_to_database($mediatype, $media, $type, $album, $allow_cid, $
        }
 
        if ($filetype == "") {
-               $filetype=Image::guessType($filename);
+               $filetype = Images::guessType($filename);
        }
        $imagedata = @getimagesize($src);
        if ($imagedata) {
@@ -4787,19 +4788,19 @@ function save_media_to_database($mediatype, $media, $type, $album, $allow_cid, $
        $height = $Image->getHeight();
 
        // create a new resource-id if not already provided
-       $hash = ($photo_id == null) ? Photo::newResource() : $photo_id;
+       $resource_id = ($photo_id == null) ? Photo::newResource() : $photo_id;
 
        if ($mediatype == "photo") {
                // upload normal image (scales 0, 1, 2)
                Logger::log("photo upload: starting new photo upload", Logger::DEBUG);
 
-               $r = Photo::store($Image, local_user(), $visitor, $hash, $filename, $album, 0, 0, $allow_cid, $allow_gid, $deny_cid, $deny_gid, $desc);
+               $r = Photo::store($Image, local_user(), $visitor, $resource_id, $filename, $album, 0, 0, $allow_cid, $allow_gid, $deny_cid, $deny_gid, $desc);
                if (!$r) {
                        Logger::log("photo upload: image upload with scale 0 (original size) failed");
                }
                if ($width > 640 || $height > 640) {
                        $Image->scaleDown(640);
-                       $r = Photo::store($Image, local_user(), $visitor, $hash, $filename, $album, 1, 0, $allow_cid, $allow_gid, $deny_cid, $deny_gid, $desc);
+                       $r = Photo::store($Image, local_user(), $visitor, $resource_id, $filename, $album, 1, 0, $allow_cid, $allow_gid, $deny_cid, $deny_gid, $desc);
                        if (!$r) {
                                Logger::log("photo upload: image upload with scale 1 (640x640) failed");
                        }
@@ -4807,7 +4808,7 @@ function save_media_to_database($mediatype, $media, $type, $album, $allow_cid, $
 
                if ($width > 320 || $height > 320) {
                        $Image->scaleDown(320);
-                       $r = Photo::store($Image, local_user(), $visitor, $hash, $filename, $album, 2, 0, $allow_cid, $allow_gid, $deny_cid, $deny_gid, $desc);
+                       $r = Photo::store($Image, local_user(), $visitor, $resource_id, $filename, $album, 2, 0, $allow_cid, $allow_gid, $deny_cid, $deny_gid, $desc);
                        if (!$r) {
                                Logger::log("photo upload: image upload with scale 2 (320x320) failed");
                        }
@@ -4819,7 +4820,7 @@ function save_media_to_database($mediatype, $media, $type, $album, $allow_cid, $
 
                if ($width > 300 || $height > 300) {
                        $Image->scaleDown(300);
-                       $r = Photo::store($Image, local_user(), $visitor, $hash, $filename, $album, 4, $profile, $allow_cid, $allow_gid, $deny_cid, $deny_gid, $desc);
+                       $r = Photo::store($Image, local_user(), $visitor, $resource_id, $filename, $album, 4, $profile, $allow_cid, $allow_gid, $deny_cid, $deny_gid, $desc);
                        if (!$r) {
                                Logger::log("photo upload: profile image upload with scale 4 (300x300) failed");
                        }
@@ -4827,7 +4828,7 @@ function save_media_to_database($mediatype, $media, $type, $album, $allow_cid, $
 
                if ($width > 80 || $height > 80) {
                        $Image->scaleDown(80);
-                       $r = Photo::store($Image, local_user(), $visitor, $hash, $filename, $album, 5, $profile, $allow_cid, $allow_gid, $deny_cid, $deny_gid, $desc);
+                       $r = Photo::store($Image, local_user(), $visitor, $resource_id, $filename, $album, 5, $profile, $allow_cid, $allow_gid, $deny_cid, $deny_gid, $desc);
                        if (!$r) {
                                Logger::log("photo upload: profile image upload with scale 5 (80x80) failed");
                        }
@@ -4835,7 +4836,7 @@ function save_media_to_database($mediatype, $media, $type, $album, $allow_cid, $
 
                if ($width > 48 || $height > 48) {
                        $Image->scaleDown(48);
-                       $r = Photo::store($Image, local_user(), $visitor, $hash, $filename, $album, 6, $profile, $allow_cid, $allow_gid, $deny_cid, $deny_gid, $desc);
+                       $r = Photo::store($Image, local_user(), $visitor, $resource_id, $filename, $album, 6, $profile, $allow_cid, $allow_gid, $deny_cid, $deny_gid, $desc);
                        if (!$r) {
                                Logger::log("photo upload: profile image upload with scale 6 (48x48) failed");
                        }
@@ -4847,10 +4848,10 @@ function save_media_to_database($mediatype, $media, $type, $album, $allow_cid, $
        if (isset($r) && $r) {
                // create entry in 'item'-table on new uploads to enable users to comment/like/dislike the photo
                if ($photo_id == null && $mediatype == "photo") {
-                       post_photo_item($hash, $allow_cid, $deny_cid, $allow_gid, $deny_gid, $filetype, $visibility);
+                       post_photo_item($resource_id, $allow_cid, $deny_cid, $allow_gid, $deny_gid, $filetype, $visibility);
                }
                // on success return image data in json/xml format (like /api/friendica/photo does when no scale is given)
-               return prepare_photo_data($type, false, $hash);
+               return prepare_photo_data($type, false, $resource_id);
        } else {
                throw new InternalServerErrorException("image upload failed");
        }
index 84e47d34e3020bee2d1d78c6aaa3f47918b6a296..b7f8d91fc40cd37193851788f0cb0383e7949eaf 100644 (file)
@@ -801,10 +801,12 @@ function conversation(App $a, array $items, Pager $pager, $mode, $update, $previ
 /**
  * Fetch all comments from a query. Additionally set the newest resharer as thread owner.
  *
- * @param $thread_items Database statement with thread posts
+ * @param array   $thread_items Database statement with thread posts
+ * @param boolean $pinned       Is the item pinned?
+ *
  * @return array items with parents and comments
  */
-function conversation_fetch_comments($thread_items) {
+function conversation_fetch_comments($thread_items, $pinned) {
        $comments = [];
        $parentlines = [];
        $lineno = 0;
@@ -822,6 +824,10 @@ function conversation_fetch_comments($thread_items) {
                        $parentlines[] = $lineno;
                }
 
+               if ($row['gravity'] == GRAVITY_PARENT) {
+                       $row['pinned'] = $pinned;
+               }
+
                $comments[] = $row;
                $lineno++;
        }
@@ -872,7 +878,7 @@ function conversation_add_children(array $parents, $block_authors, $order, $uid)
 
                $thread_items = Item::selectForUser(local_user(), array_merge(Item::DISPLAY_FIELDLIST, ['contact-uid', 'gravity']), $condition, $params);
 
-               $comments = conversation_fetch_comments($thread_items);
+               $comments = conversation_fetch_comments($thread_items, $parent['pinned'] ?? false);
 
                if (count($comments) != 0) {
                        $items = array_merge($items, $comments);
@@ -1451,7 +1457,9 @@ function conv_sort(array $item_list, $order)
                }
        }
 
-       if (stristr($order, 'received')) {
+       if (stristr($order, 'pinned_received')) {
+               usort($parents, 'sort_thr_pinned_received');
+       } elseif (stristr($order, 'received')) {
                usort($parents, 'sort_thr_received');
        } elseif (stristr($order, 'commented')) {
                usort($parents, 'sort_thr_commented');
@@ -1488,6 +1496,24 @@ function conv_sort(array $item_list, $order)
        return $parents;
 }
 
+/**
+ * @brief usort() callback to sort item arrays by pinned and the received key
+ *
+ * @param array $a
+ * @param array $b
+ * @return int
+ */
+function sort_thr_pinned_received(array $a, array $b)
+{
+       if ($b['pinned'] && !$a['pinned']) {
+               return 1;
+       } elseif (!$b['pinned'] && $a['pinned']) {
+               return -1;
+       }
+
+       return strcmp($b['received'], $a['received']);
+}
+
 /**
  * @brief usort() callback to sort item arrays by the received key
  *
index 102d0c613d1a9cfb22f2d862939e0bd7b624f016..b6df3304d477bab75408272fd60eee1b12f2c049 100644 (file)
@@ -10,7 +10,7 @@ use Friendica\Core\L10n;
 use Friendica\Core\Renderer;
 use Friendica\Core\System;
 use Friendica\Database\DBA;
-use Friendica\Object\Image;
+use Friendica\Util\Images;
 use Friendica\Util\Strings;
 
 /**
@@ -79,7 +79,7 @@ function fbrowser_content(App $a)
                        function _map_files1($rr)
                        {
                                $a = \get_app();
-                               $types = Image::supportedTypes();
+                               $types = Images::supportedTypes();
                                $ext = $types[$rr['type']];
                                $filename_e = $rr['filename'];
 
diff --git a/mod/hovercard.php b/mod/hovercard.php
deleted file mode 100644 (file)
index d5951db..0000000
+++ /dev/null
@@ -1,151 +0,0 @@
-<?php
-
-/**
- * Name: Frio Hovercard
- * Description: Hovercard addon for the frio theme
- * Version: 0.1
- * Author: Rabuzarus <https://github.com/rabuzarus>
- * License: GNU AFFERO GENERAL PUBLIC LICENSE (Version 3)
- */
-
-use Friendica\App;
-use Friendica\Core\Config;
-use Friendica\Core\Renderer;
-use Friendica\Core\System;
-use Friendica\Database\DBA;
-use Friendica\Model\Contact;
-use Friendica\Model\GContact;
-use Friendica\Util\Proxy as ProxyUtils;
-use Friendica\Util\Strings;
-
-function hovercard_init(App $a)
-{
-       // Just for testing purposes
-       $_GET['mode'] = 'minimal';
-}
-
-function hovercard_content()
-{
-       $profileurl =  $_REQUEST['profileurl'] ?? '';
-       $datatype   = ($_REQUEST['datatype']   ?? '') ?: 'json';
-
-       // Get out if the system doesn't have public access allowed
-       if (intval(Config::get('system', 'block_public'))) {
-               throw new \Friendica\Network\HTTPException\ForbiddenException();
-       }
-
-       // Return the raw content of the template. We use this to make templates usable for js functions.
-       // Look at hovercard.js (function getHoverCardTemplate()).
-       // This part should be moved in its own module. Maybe we could make more templates accessible.
-       // (We need to discuss possible security leaks before doing this)
-       if ($datatype == 'tpl') {
-               $templatecontent = get_template_content('hovercard.tpl');
-               echo $templatecontent;
-               exit();
-       }
-
-       // If a contact is connected the url is internally changed to 'redir/CID'. We need the pure url to search for
-       // the contact. So we strip out the contact id from the internal url and look in the contact table for
-       // the real url (nurl)
-       if (strpos($profileurl, 'redir/') === 0) {
-               $cid = intval(substr($profileurl, 6));
-               $remote_contact = DBA::selectFirst('contact', ['nurl'], ['id' => $cid]);
-               $profileurl = $remote_contact['nurl'] ?? '';
-       }
-
-       $contact = [];
-       // if it's the url containing https it should be converted to http
-       $nurl = Strings::normaliseLink(GContact::cleanContactUrl($profileurl));
-       if (!$nurl) {
-               return;
-       }
-
-       // Search for contact data
-       // Look if the local user has got the contact
-       if (local_user()) {
-               $contact = Contact::getDetailsByURL($nurl, local_user());
-       }
-
-       // If not then check the global user
-       if (!count($contact)) {
-               $contact = Contact::getDetailsByURL($nurl);
-       }
-
-       // Feeds url could have been destroyed through "cleanContactUrl", so we now use the original url
-       if (!count($contact) && local_user()) {
-               $nurl = Strings::normaliseLink($profileurl);
-               $contact = Contact::getDetailsByURL($nurl, local_user());
-       }
-
-       if (!count($contact)) {
-               $nurl = Strings::normaliseLink($profileurl);
-               $contact = Contact::getDetailsByURL($nurl);
-       }
-
-       if (!count($contact)) {
-               return;
-       }
-
-       // Get the photo_menu - the menu if possible contact actions
-       if (local_user()) {
-               $actions = Contact::photoMenu($contact);
-       } else {
-               $actions = [];
-       }
-
-       // Move the contact data to the profile array so we can deliver it to
-       $profile = [
-               'name'         => $contact['name'],
-               'nick'         => $contact['nick'],
-               'addr'         => ($contact['addr'] ?? '') ?: $contact['url'],
-               'thumb'        => ProxyUtils::proxifyUrl($contact['thumb'], false, ProxyUtils::SIZE_THUMB),
-               'url'          => Contact::magicLink($contact['url']),
-               'nurl'         => $contact['nurl'], // We additionally store the nurl as identifier
-               'location'     => $contact['location'],
-               'gender'       => $contact['gender'],
-               'about'        => $contact['about'],
-               'network_link' => Strings::formatNetworkName($contact['network'], $contact['url']),
-               'tags'         => $contact['keywords'],
-               'bd'           => $contact['birthday'] <= DBA::NULL_DATE ? '' : $contact['birthday'],
-               'account_type' => Contact::getAccountType($contact),
-               'actions'      => $actions,
-       ];
-       if ($datatype == 'html') {
-               $tpl = Renderer::getMarkupTemplate('hovercard.tpl');
-               $o = Renderer::replaceMacros($tpl, [
-                       '$profile' => $profile,
-               ]);
-
-               return $o;
-       } else {
-               System::jsonExit($profile);
-       }
-}
-
-/**
- * @brief Get the raw content of a template file
- *
- * @param string $template The name of the template
- * @param string $root     Directory of the template
- *
- * @return string|bool Output the raw content if existent, otherwise false
- * @throws Exception
- */
-function get_template_content($template, $root = '')
-{
-       // We load the whole template system to get the filename.
-       // Maybe we can do it a little bit smarter if I get time.
-       $templateEngine = Renderer::getTemplateEngine();
-       $template = $templateEngine->getTemplateFile($template, $root);
-
-       $filename = $template->filename;
-
-       // Get the content of the template file
-       if (file_exists($filename)) {
-               $content = file_get_contents($filename);
-
-               return $content;
-       }
-
-       return false;
-}
index 64f5cf505f64f3530f790713c54c79cd25e5f312..5fbfa9a5d8e736adaaa6c2ba10a4dc66d4072308 100644 (file)
@@ -86,7 +86,7 @@ function network_init(App $a)
 
                if ($remember_tab) {
                        // redirect if current selected tab is '/network' and
-                       // last selected tab is _not_ '/network?order=comment'.
+                       // last selected tab is _not_ '/network?order=activity'.
                        // and this isn't a date query
 
                        $tab_baseurls = [
@@ -98,12 +98,12 @@ function network_init(App $a)
                                '',     //bookmarked
                        ];
                        $tab_args = [
-                               'order=comment', //all
-                               'order=post',    //postord
-                               'conv=1',        //conv
-                               '',                 //new
-                               'star=1',        //starred
-                               'bmark=1',       //bookmarked
+                               'order=activity', //all
+                               'order=post',     //postord
+                               'conv=1',         //conv
+                               '',               //new
+                               'star=1',         //starred
+                               'bmark=1',        //bookmarked
                        ];
 
                        $k = array_search('active', $last_sel_tabs);
@@ -151,16 +151,16 @@ function network_init(App $a)
  * Return selected tab from query
  *
  * urls -> returns
- *        '/network'                    => $no_active = 'active'
- *        '/network?order=comment'    => $comment_active = 'active'
- *        '/network?order=post'    => $postord_active = 'active'
+ *        '/network'                => $no_active = 'active'
+ *        '/network?order=activity' => $activity_active = 'active'
+ *        '/network?order=post'     => $postord_active = 'active'
  *        '/network?conv=1',        => $conv_active = 'active'
- *        '/network/new',                => $new_active = 'active'
+ *        '/network/new',           => $new_active = 'active'
  *        '/network?star=1',        => $starred_active = 'active'
- *        '/network?bmark=1',        => $bookmarked_active = 'active'
+ *        '/network?bmark=1',       => $bookmarked_active = 'active'
  *
  * @param App $a
- * @return array ($no_active, $comment_active, $postord_active, $conv_active, $new_active, $starred_active, $bookmarked_active);
+ * @return array ($no_active, $activity_active, $postord_active, $conv_active, $new_active, $starred_active, $bookmarked_active);
  */
 function network_query_get_sel_tab(App $a)
 {
@@ -194,8 +194,8 @@ function network_query_get_sel_tab(App $a)
 
        if ($no_active == 'active' && !empty($_GET['order'])) {
                switch($_GET['order']) {
-                       case 'post'    : $postord_active = 'active'; $no_active=''; break;
-                       case 'comment' : $all_active     = 'active'; $no_active=''; break;
+                       case 'post' :     $postord_active = 'active'; $no_active=''; break;
+                       case 'activity' : $all_active     = 'active'; $no_active=''; break;
                }
        }
 
@@ -490,7 +490,7 @@ function networkThreadedView(App $a, $update, $parent)
        $star  = intval($_GET['star']  ?? 0);
        $bmark = intval($_GET['bmark'] ?? 0);
        $conv  = intval($_GET['conv']  ?? 0);
-       $order = Strings::escapeTags(($_GET['order'] ?? '') ?: 'comment');
+       $order = Strings::escapeTags(($_GET['order'] ?? '') ?: 'activity');
        $nets  =        $_GET['nets']  ?? '';
 
        $allowedCids = [];
@@ -913,9 +913,9 @@ function network_tabs(App $a)
        // item filter tabs
        /// @TODO fix this logic, reduce duplication
        /// $a->page['content'] .= '<div class="tabs-wrapper">';
-       list($no_active, $all_active, $postord_active, $conv_active, $new_active, $starred_active, $bookmarked_active) = network_query_get_sel_tab($a);
+       list($no_active, $all_active, $post_active, $conv_active, $new_active, $starred_active, $bookmarked_active) = network_query_get_sel_tab($a);
 
-       // if no tabs are selected, defaults to comments
+       // if no tabs are selected, defaults to activitys
        if ($no_active == 'active') {
                $all_active = 'active';
        }
@@ -925,19 +925,19 @@ function network_tabs(App $a)
        // tabs
        $tabs = [
                [
-                       'label' => L10n::t('Commented Order'),
-                       'url'   => str_replace('/new', '', $cmd) . '?order=comment' . (!empty($_GET['cid']) ? '&cid=' . $_GET['cid'] : ''),
+                       'label' => L10n::t('Latest Activity'),
+                       'url'   => str_replace('/new', '', $cmd) . '?order=activity' . (!empty($_GET['cid']) ? '&cid=' . $_GET['cid'] : ''),
                        'sel'   => $all_active,
-                       'title' => L10n::t('Sort by Comment Date'),
-                       'id'    => 'commented-order-tab',
+                       'title' => L10n::t('Sort by latest activity'),
+                       'id'    => 'activity-order-tab',
                        'accesskey' => 'e',
                ],
                [
-                       'label' => L10n::t('Posted Order'),
+                       'label' => L10n::t('Latest Posts'),
                        'url'   => str_replace('/new', '', $cmd) . '?order=post' . (!empty($_GET['cid']) ? '&cid=' . $_GET['cid'] : ''),
-                       'sel'   => $postord_active,
-                       'title' => L10n::t('Sort by Post Date'),
-                       'id'    => 'posted-order-tab',
+                       'sel'   => $post_active,
+                       'title' => L10n::t('Sort by post received date'),
+                       'id'    => 'post-order-tab',
                        'accesskey' => 't',
                ],
        ];
@@ -985,7 +985,7 @@ function network_tabs(App $a)
        // save selected tab, but only if not in file mode
        if (empty($_GET['file'])) {
                PConfig::set(local_user(), 'network.view', 'tab.selected', [
-                       $all_active, $postord_active, $conv_active, $new_active, $starred_active, $bookmarked_active
+                       $all_active, $post_active, $conv_active, $new_active, $starred_active, $bookmarked_active
                ]);
        }
 
index 037da64b10fdd6eb1bb19f7ccc1dafb721237826..e0630e7dc9635266efb22d165125770f8a4ca28e 100644 (file)
@@ -29,6 +29,7 @@ use Friendica\Protocol\Activity;
 use Friendica\Util\ACLFormatter;
 use Friendica\Util\Crypto;
 use Friendica\Util\DateTimeFormat;
+use Friendica\Util\Images;
 use Friendica\Util\Map;
 use Friendica\Util\Security;
 use Friendica\Util\Strings;
@@ -142,7 +143,7 @@ function photos_post(App $a)
        Logger::log('mod_photos: REQUEST ' . print_r($_REQUEST, true), Logger::DATA);
        Logger::log('mod_photos: FILES '   . print_r($_FILES, true), Logger::DATA);
 
-       $phototypes = Image::supportedTypes();
+       $phototypes = Images::supportedTypes();
 
        $can_post  = false;
        $visitor   = 0;
@@ -694,7 +695,7 @@ function photos_post(App $a)
        }
 
        if ($type == "") {
-               $type = Image::guessType($filename);
+               $type = Images::guessType($filename);
        }
 
        Logger::log('photos: upload: received file: ' . $filename . ' as ' . $src . ' ('. $type . ') ' . $filesize . ' bytes', Logger::DEBUG);
@@ -748,9 +749,9 @@ function photos_post(App $a)
 
        $smallest = 0;
 
-       $photo_hash = Photo::newResource();
+       $resource_id = Photo::newResource();
 
-       $r = Photo::store($image, $page_owner_uid, $visitor, $photo_hash, $filename, $album, 0 , 0, $str_contact_allow, $str_group_allow, $str_contact_deny, $str_group_deny);
+       $r = Photo::store($image, $page_owner_uid, $visitor, $resource_id, $filename, $album, 0 , 0, $str_contact_allow, $str_group_allow, $str_contact_deny, $str_group_deny);
 
        if (!$r) {
                Logger::log('mod/photos.php: photos_post(): image store failed', Logger::DEBUG);
@@ -760,13 +761,13 @@ function photos_post(App $a)
 
        if ($width > 640 || $height > 640) {
                $image->scaleDown(640);
-               Photo::store($image, $page_owner_uid, $visitor, $photo_hash, $filename, $album, 1, 0, $str_contact_allow, $str_group_allow, $str_contact_deny, $str_group_deny);
+               Photo::store($image, $page_owner_uid, $visitor, $resource_id, $filename, $album, 1, 0, $str_contact_allow, $str_group_allow, $str_contact_deny, $str_group_deny);
                $smallest = 1;
        }
 
        if ($width > 320 || $height > 320) {
                $image->scaleDown(320);
-               Photo::store($image, $page_owner_uid, $visitor, $photo_hash, $filename, $album, 2, 0, $str_contact_allow, $str_group_allow, $str_contact_deny, $str_group_deny);
+               Photo::store($image, $page_owner_uid, $visitor, $resource_id, $filename, $album, 2, 0, $str_contact_allow, $str_group_allow, $str_contact_deny, $str_group_deny);
                $smallest = 2;
        }
 
@@ -790,7 +791,7 @@ function photos_post(App $a)
        $arr['parent-uri']    = $uri;
        $arr['type']          = 'photo';
        $arr['wall']          = 1;
-       $arr['resource-id']   = $photo_hash;
+       $arr['resource-id']   = $resource_id;
        $arr['contact-id']    = $owner_record['id'];
        $arr['owner-name']    = $owner_record['name'];
        $arr['owner-link']    = $owner_record['url'];
@@ -806,8 +807,8 @@ function photos_post(App $a)
        $arr['visible']       = $visible;
        $arr['origin']        = 1;
 
-       $arr['body']          = '[url=' . System::baseUrl() . '/photos/' . $owner_record['nickname'] . '/image/' . $photo_hash . ']'
-                               . '[img]' . System::baseUrl() . "/photo/{$photo_hash}-{$smallest}.".$image->getExt() . '[/img]'
+       $arr['body']          = '[url=' . System::baseUrl() . '/photos/' . $owner_record['nickname'] . '/image/' . $resource_id . ']'
+                               . '[img]' . System::baseUrl() . "/photo/{$resource_id}-{$smallest}.".$image->getExt() . '[/img]'
                                . '[/url]';
 
        $item_id = Item::insert($arr);
@@ -846,7 +847,7 @@ function photos_content(App $a)
                return;
        }
 
-       $phototypes = Image::supportedTypes();
+       $phototypes = Images::supportedTypes();
 
        $_SESSION['photo_return'] = $a->cmd;
 
index 717dac225e7f6f6bf7e5c069e8b1e7d1350d0718..5ae4086b61741e48ce7145b555a06f073f2569de 100644 (file)
@@ -131,8 +131,8 @@ function settings_init(App $a)
 
        $tabs[] =       [
                'label' => L10n::t('Export personal data'),
-               'url' => 'uexport',
-               'selected' => (($a->argc == 1) && ($a->argv[0] === 'uexport')?'active':''),
+               'url' => 'settings/userexport',
+               'selected' => (($a->argc > 1) && ($a->argv[1] === 'userexport')?'active':''),
                'accesskey' => 'e',
        ];
 
@@ -390,6 +390,33 @@ function settings_post(App $a)
 
        BaseModule::checkFormSecurityTokenRedirectOnError('/settings', 'settings');
 
+       // Import Contacts from CSV file
+       if (!empty($_POST['importcontact-submit'])) {
+               if (isset($_FILES['importcontact-filename'])) {
+                       // was there an error
+                       if ($_FILES['importcontact-filename']['error'] > 0) {
+                               Logger::notice('Contact CSV file upload error');
+                               info(L10n::t('Contact CSV file upload error'));
+                       } else {
+                               $csvArray = array_map('str_getcsv', file($_FILES['importcontact-filename']['tmp_name']));
+                               // import contacts
+                               foreach ($csvArray as $csvRow) {
+                                       // The 1st row may, or may not contain the headers of the table
+                                       // We expect the 1st field of the row to contain either the URL
+                                       // or the handle of the account, therefore we check for either
+                                       // "http" or "@" to be present in the string.
+                                       // All other fields from the row will be ignored
+                                       if ((strpos($csvRow[0],'@') !== false) || (strpos($csvRow[0],'http') !== false)) {
+                                               $arr = Contact::createFromProbe($_SESSION['uid'], $csvRow[0], '', false);
+                                       }
+                               }
+                               info(L10n::t('Importing Contacts done'));
+                               // delete temp file
+                               unlink($filename);
+                       }
+               }
+       }
+
        if (!empty($_POST['resend_relocate'])) {
                Worker::add(PRIORITY_HIGH, 'Notifier', Delivery::RELOCATION, local_user());
                info(L10n::t("Relocate message has been send to your contacts"));
@@ -569,9 +596,9 @@ function settings_post(App $a)
 
        $fields = ['username' => $username, 'email' => $email, 'timezone' => $timezone,
                'allow_cid' => $str_contact_allow, 'allow_gid' => $str_group_allow, 'deny_cid' => $str_contact_deny, 'deny_gid' => $str_group_deny,
-               'notify-flags' => $notify, 'page-flags' => $notify, 'account-type' => $account_type, 'default-location' => $defloc,
+               'notify-flags' => $notify, 'page-flags' => $page_flags, 'account-type' => $account_type, 'default-location' => $defloc,
                'allow_location' => $allow_location, 'maxreq' => $maxreq, 'expire' => $expire, 'def_gid' => $def_gid, 'blockwall' => $blockwall,
-               'hidewall' => $hide_wall, 'blocktags' => $blocktags, 'unkmail' => $unkmail, 'cntunkmail' => $cntunkmail, 'language' => $language];
+               'hidewall' => $hidewall, 'blocktags' => $blocktags, 'unkmail' => $unkmail, 'cntunkmail' => $cntunkmail, 'language' => $language];
 
        if ($delete_openid) {
                $fields['openid'] = '';
@@ -1223,6 +1250,10 @@ function settings_content(App $a)
                '$h_descadvn' => L10n::t('Change the behaviour of this account for special situations'),
                '$pagetype' => $pagetype,
 
+               '$importcontact' => L10n::t('Import Contacts'),
+               '$importcontact_text' => L10n::t('Upload a CSV file that contains the handle of your followed accounts in the first column you exported from the old account.'),
+               '$importcontact_button' => L10n::t('Upload File'),
+               '$importcontact_maxsize' => Config::get('system', 'max_csv_file_size', 30720), 
                '$relocate' => L10n::t('Relocate'),
                '$relocate_text' => L10n::t("If you have moved this profile from another server, and some of your contacts don't receive your updates, try pushing this button."),
                '$relocate_button' => L10n::t("Resend relocate message to contacts"),
diff --git a/mod/uexport.php b/mod/uexport.php
deleted file mode 100644 (file)
index dfeb25a..0000000
+++ /dev/null
@@ -1,197 +0,0 @@
-<?php
-/**
- * @file mod/uexport.php
- */
-
-use Friendica\App;
-use Friendica\Core\Hook;
-use Friendica\Core\L10n;
-use Friendica\Core\Renderer;
-use Friendica\Core\System;
-use Friendica\Database\DBA;
-use Friendica\Database\DBStructure;
-
-function uexport_init(App $a) {
-       /// @todo Don't forget to move this global field as static field in src/Modules
-       global $dbStructure;
-
-       if (!local_user()) {
-               exit();
-       }
-
-       require_once("mod/settings.php");
-       settings_init($a);
-
-       $dbStructure = DBStructure::definition($a->getBasePath());
-}
-
-function uexport_content(App $a) {
-
-       if ($a->argc > 1) {
-               header("Content-type: application/json");
-               header('Content-Disposition: attachment; filename="' . $a->user['nickname'] . '.' . $a->argv[1] . '"');
-               switch ($a->argv[1]) {
-                       case "backup":
-                               uexport_all($a);
-                               exit();
-                               break;
-                       case "account":
-                               uexport_account($a);
-                               exit();
-                               break;
-                       default:
-                               exit();
-               }
-       }
-
-       /**
-        * options shown on "Export personal data" page
-        * list of array( 'link url', 'link text', 'help text' )
-        */
-       $options = [
-               ['uexport/account', L10n::t('Export account'), L10n::t('Export your account info and contacts. Use this to make a backup of your account and/or to move it to another server.')],
-               ['uexport/backup', L10n::t('Export all'), L10n::t("Export your accout info, contacts and all your items as json. Could be a very big file, and could take a lot of time. Use this to make a full backup of your account \x28photos are not exported\x29")],
-       ];
-       Hook::callAll('uexport_options', $options);
-
-       $tpl = Renderer::getMarkupTemplate("uexport.tpl");
-       return Renderer::replaceMacros($tpl, [
-               '$title' => L10n::t('Export personal data'),
-               '$options' => $options
-       ]);
-}
-
-function _uexport_multirow($query) {
-       global $dbStructure;
-
-       preg_match("/\s+from\s+`?([a-z\d_]+)`?/i", $query, $match);
-       $table = $match[1];
-
-       $result = [];
-       $r = q($query);
-       if (DBA::isResult($r)) {
-               foreach ($r as $rr) {
-                       $p = [];
-                       foreach ($rr as $k => $v) {
-                               switch ($dbStructure[$table]['fields'][$k]['type']) {
-                                       case 'datetime':
-                                               $p[$k] = $v ?? DBA::NULL_DATETIME;
-                                               break;
-                                       default:
-                                               $p[$k] = $v;
-                                               break;
-                               }
-                       }
-                       $result[] = $p;
-               }
-       }
-       return $result;
-}
-
-function _uexport_row($query) {
-       global $dbStructure;
-
-       preg_match("/\s+from\s+`?([a-z\d_]+)`?/i", $query, $match);
-       $table = $match[1];
-
-       $result = [];
-       $r = q($query);
-       if (DBA::isResult($r)) {
-
-               foreach ($r as $rr) {
-                       foreach ($rr as $k => $v) {
-                               switch ($dbStructure[$table]['fields'][$k]['type']) {
-                                       case 'datetime':
-                                               $result[$k] = $v ?? DBA::NULL_DATETIME;
-                                               break;
-                                       default:
-                                               $result[$k] = $v;
-                                               break;
-                               }
-                       }
-               }
-       }
-       return $result;
-}
-
-function uexport_account($a) {
-
-       $user = _uexport_row(
-               sprintf("SELECT * FROM `user` WHERE `uid` = %d LIMIT 1", intval(local_user()))
-       );
-
-       $contact = _uexport_multirow(
-               sprintf("SELECT * FROM `contact` WHERE `uid` = %d ", intval(local_user()))
-       );
-
-
-       $profile = _uexport_multirow(
-               sprintf("SELECT * FROM `profile` WHERE `uid` = %d ", intval(local_user()))
-       );
-
-       $photo = _uexport_multirow(
-               sprintf("SELECT * FROM `photo` WHERE uid = %d AND profile = 1", intval(local_user()))
-       );
-       foreach ($photo as &$p) {
-               $p['data'] = bin2hex($p['data']);
-       }
-
-       $pconfig = _uexport_multirow(
-               sprintf("SELECT * FROM `pconfig` WHERE uid = %d", intval(local_user()))
-       );
-
-       $group = _uexport_multirow(
-               sprintf("SELECT * FROM `group` WHERE uid = %d", intval(local_user()))
-       );
-
-       $group_member = _uexport_multirow(
-               sprintf("SELECT `group_member`.`gid`, `group_member`.`contact-id` FROM `group_member` INNER JOIN `group` ON `group`.`id` = `group_member`.`gid` WHERE `group`.`uid` = %d", intval(local_user()))
-       );
-
-       $output = [
-               'version' => FRIENDICA_VERSION,
-               'schema' => DB_UPDATE_VERSION,
-               'baseurl' => System::baseUrl(),
-               'user' => $user,
-               'contact' => $contact,
-               'profile' => $profile,
-               'photo' => $photo,
-               'pconfig' => $pconfig,
-               'group' => $group,
-               'group_member' => $group_member,
-       ];
-
-       echo json_encode($output, JSON_PARTIAL_OUTPUT_ON_ERROR);
-}
-
-/**
- * echoes account data and items as separated json, one per line
- *
- * @param App $a
- * @throws Exception
- */
-function uexport_all(App $a) {
-
-       uexport_account($a);
-       echo "\n";
-
-       $total = 0;
-       $r = q("SELECT count(*) as `total` FROM `item` WHERE `uid` = %d ",
-               intval(local_user())
-       );
-       if (DBA::isResult($r)) {
-               $total = $r[0]['total'];
-       }
-       // chunk the output to avoid exhausting memory
-
-       for ($x = 0; $x < $total; $x += 500) {
-               $r = q("SELECT * FROM `item` WHERE `uid` = %d LIMIT %d, %d",
-                       intval(local_user()),
-                       intval($x),
-                       intval(500)
-               );
-
-               $output = ['item' => $r];
-               echo json_encode($output, JSON_PARTIAL_OUTPUT_ON_ERROR). "\n";
-       }
-}
index 1f96dab25b9403e56a793b2df6f2e50202fd6540..bea33b4841f96286ffd4c9ff4a86b93c5a0e23fa 100644 (file)
@@ -14,7 +14,7 @@ function update_contact_content(App $a)
        echo "<section>";
 
        if ($_GET["force"] == 1) {
-               $text = Contact::content(true);
+               $text = Contact::content([], true);
        } else {
                $text = '';
        }
index 72056703958ef0306251773c101d52c5371aea5c..85ca3d3c975def5d56395fb2dc79cf44980fc329 100644 (file)
@@ -28,7 +28,7 @@ function update_profile_content(App $a) {
         * on the client side and then swap the image back.
         */
 
-       $text = Profile::content($profile_uid);
+       $text = Profile::content([], $profile_uid);
 
        if (PConfig::get(local_user(), "system", "bandwidth_saver")) {
                $replace = "<br />".L10n::t("[Embedded content - reload page to view]")."<br />";
index 1224b6dab0a6cb00fbaea2c0ceacf1c20fda365f..31112367a9442eb0c33253d3e68c4fab3b072d3f 100644 (file)
@@ -9,16 +9,16 @@
  */
 
 use Friendica\App;
+use Friendica\Core\Config;
 use Friendica\Core\L10n;
 use Friendica\Core\Logger;
-use Friendica\Core\System;
 use Friendica\Core\Session;
-use Friendica\Core\Config;
+use Friendica\Core\System;
 use Friendica\Database\DBA;
-use Friendica\Model\Contact;
 use Friendica\Model\Photo;
 use Friendica\Model\User;
 use Friendica\Object\Image;
+use Friendica\Util\Images;
 use Friendica\Util\Strings;
 
 function wall_upload_post(App $a, $desktopmode = true)
@@ -166,7 +166,7 @@ function wall_upload_post(App $a, $desktopmode = true)
        }
 
        if ($filetype == "") {
-               $filetype = Image::guessType($filename);
+               $filetype = Images::guessType($filename);
        }
 
        // If there is a temp name, then do a manual check
@@ -222,7 +222,7 @@ function wall_upload_post(App $a, $desktopmode = true)
        $width = $Image->getWidth();
        $height = $Image->getHeight();
 
-       $hash = Photo::newResource();
+       $resource_id = Photo::newResource();
 
        $smallest = 0;
 
@@ -233,7 +233,7 @@ function wall_upload_post(App $a, $desktopmode = true)
 
        $defperm = '<' . $default_cid . '>';
 
-       $r = Photo::store($Image, $page_owner_uid, $visitor, $hash, $filename, $album, 0, 0, $defperm);
+       $r = Photo::store($Image, $page_owner_uid, $visitor, $resource_id, $filename, $album, 0, 0, $defperm);
 
        if (!$r) {
                $msg = L10n::t('Image upload failed.');
@@ -247,7 +247,7 @@ function wall_upload_post(App $a, $desktopmode = true)
 
        if ($width > 640 || $height > 640) {
                $Image->scaleDown(640);
-               $r = Photo::store($Image, $page_owner_uid, $visitor, $hash, $filename, $album, 1, 0, $defperm);
+               $r = Photo::store($Image, $page_owner_uid, $visitor, $resource_id, $filename, $album, 1, 0, $defperm);
                if ($r) {
                        $smallest = 1;
                }
@@ -255,7 +255,7 @@ function wall_upload_post(App $a, $desktopmode = true)
 
        if ($width > 320 || $height > 320) {
                $Image->scaleDown(320);
-               $r = Photo::store($Image, $page_owner_uid, $visitor, $hash, $filename, $album, 2, 0, $defperm);
+               $r = Photo::store($Image, $page_owner_uid, $visitor, $resource_id, $filename, $album, 2, 0, $defperm);
                if ($r && ($smallest == 0)) {
                        $smallest = 2;
                }
@@ -265,7 +265,7 @@ function wall_upload_post(App $a, $desktopmode = true)
                $r = q("SELECT `id`, `datasize`, `width`, `height`, `type` FROM `photo`
                        WHERE `resource-id` = '%s'
                        ORDER BY `width` DESC LIMIT 1",
-                       $hash
+                       $resource_id
                );
                if (!$r) {
                        if ($r_json) {
@@ -281,9 +281,9 @@ function wall_upload_post(App $a, $desktopmode = true)
                $picture["width"]     = $r[0]["width"];
                $picture["height"]    = $r[0]["height"];
                $picture["type"]      = $r[0]["type"];
-               $picture["albumpage"] = System::baseUrl() . '/photos/' . $page_owner_nick . '/image/' . $hash;
-               $picture["picture"]   = System::baseUrl() . "/photo/{$hash}-0." . $Image->getExt();
-               $picture["preview"]   = System::baseUrl() . "/photo/{$hash}-{$smallest}." . $Image->getExt();
+               $picture["albumpage"] = System::baseUrl() . '/photos/' . $page_owner_nick . '/image/' . $resource_id;
+               $picture["picture"]   = System::baseUrl() . "/photo/{$resource_id}-0." . $Image->getExt();
+               $picture["preview"]   = System::baseUrl() . "/photo/{$resource_id}-{$smallest}." . $Image->getExt();
 
                if ($r_json) {
                        echo json_encode(['picture' => $picture]);
@@ -300,7 +300,7 @@ function wall_upload_post(App $a, $desktopmode = true)
                exit();
        }
 
-       echo  "\n\n" . '[url=' . System::baseUrl() . '/photos/' . $page_owner_nick . '/image/' . $hash . '][img]' . System::baseUrl() . "/photo/{$hash}-{$smallest}.".$Image->getExt()."[/img][/url]\n\n";
+       echo  "\n\n" . '[url=' . System::baseUrl() . '/photos/' . $page_owner_nick . '/image/' . $resource_id . '][img]' . System::baseUrl() . "/photo/{$resource_id}-{$smallest}.".$Image->getExt()."[/img][/url]\n\n";
        exit();
        // NOTREACHED
 }
index e65309f6b0ab18dd38bc4ffebd0dcaa266139683..bd9f3b553bdf01b9d72b0707becca79d7653857c 100644 (file)
@@ -105,9 +105,9 @@ class Arguments
                $queryString = '';
 
                if (!empty($server['QUERY_STRING']) && strpos($server['QUERY_STRING'], 'pagename=') === 0) {
-                       $queryString = substr($server['QUERY_STRING'], 9);
+                       $queryString = urldecode(substr($server['QUERY_STRING'], 9));
                } elseif (!empty($server['QUERY_STRING']) && strpos($server['QUERY_STRING'], 'q=') === 0) {
-                       $queryString = substr($server['QUERY_STRING'], 2);
+                       $queryString = urldecode(substr($server['QUERY_STRING'], 2));
                }
 
                // eventually strip ZRL
index 33a9b2fc2f33d91d0a2754f38448f15999322072..868520c0257b23e5b77c6fa6c7ec7a24f52d1fae 100644 (file)
@@ -63,6 +63,11 @@ class Module
         */
        private $module_class;
 
+       /**
+        * @var array The module parameters
+        */
+       private $module_parameters;
+
        /**
         * @var bool true, if the module is a backend module
         */
@@ -89,6 +94,14 @@ class Module
                return $this->module_class;
        }
 
+       /**
+        * @return array The module parameters extracted from the route
+        */
+       public function getParameters()
+       {
+               return $this->module_parameters;
+       }
+
        /**
         * @return bool True, if the current module is a backend module
         * @see Module::BACKEND_MODULES for a list
@@ -98,10 +111,11 @@ class Module
                return $this->isBackend;
        }
 
-       public function __construct(string $module = self::DEFAULT, string $moduleClass = self::DEFAULT_CLASS, bool $isBackend = false, bool $printNotAllowedAddon = false)
+       public function __construct(string $module = self::DEFAULT, string $moduleClass = self::DEFAULT_CLASS, array $moduleParameters = [], bool $isBackend = false, bool $printNotAllowedAddon = false)
        {
                $this->module               = $module;
                $this->module_class         = $moduleClass;
+               $this->module_parameters    = $moduleParameters;
                $this->isBackend            = $isBackend;
                $this->printNotAllowedAddon = $printNotAllowedAddon;
        }
@@ -129,7 +143,7 @@ class Module
 
                $isBackend = in_array($module, Module::BACKEND_MODULES);;
 
-               return new Module($module, $this->module_class, $isBackend, $this->printNotAllowedAddon);
+               return new Module($module, $this->module_class, [], $isBackend, $this->printNotAllowedAddon);
        }
 
        /**
@@ -148,6 +162,7 @@ class Module
                $printNotAllowedAddon = false;
 
                $module_class = null;
+               $module_parameters = [];
                /**
                 * ROUTING
                 *
@@ -156,6 +171,7 @@ class Module
                 **/
                try {
                        $module_class = $router->getModuleClass($args->getCommand());
+                       $module_parameters = $router->getModuleParameters();
                } catch (MethodNotAllowedException $e) {
                        $module_class = MethodNotAllowed::class;
                } catch (NotFoundException $e) {
@@ -185,7 +201,7 @@ class Module
                        $module_class = $module_class ?: PageNotFound::class;
                }
 
-               return new Module($this->module, $module_class, $this->isBackend, $printNotAllowedAddon);
+               return new Module($this->module, $module_class, $module_parameters, $this->isBackend, $printNotAllowedAddon);
        }
 
        /**
@@ -233,18 +249,18 @@ class Module
 
                Core\Hook::callAll($this->module . '_mod_init', $placeholder);
 
-               call_user_func([$this->module_class, 'init']);
+               call_user_func([$this->module_class, 'init'], $this->module_parameters);
 
                // "rawContent" is especially meant for technical endpoints.
                // This endpoint doesn't need any theme initialization or other comparable stuff.
-               call_user_func([$this->module_class, 'rawContent']);
+               call_user_func([$this->module_class, 'rawContent'], $this->module_parameters);
 
                if ($server['REQUEST_METHOD'] === 'POST') {
                        Core\Hook::callAll($this->module . '_mod_post', $post);
-                       call_user_func([$this->module_class, 'post']);
+                       call_user_func([$this->module_class, 'post'], $this->module_parameters);
                }
 
                Core\Hook::callAll($this->module . '_mod_afterpost', $placeholder);
-               call_user_func([$this->module_class, 'afterpost']);
+               call_user_func([$this->module_class, 'afterpost'], $this->module_parameters);
        }
 }
index ea94f9cfef6a73ba37d7bdc08c206ec243447924..7af0bc8995473b452d7aaef051569c66a127b19b 100644 (file)
@@ -308,7 +308,7 @@ class Page implements ArrayAccess
                        $arr = ['content' => $content];
                        Hook::callAll($moduleClass . '_mod_content', $arr);
                        $content = $arr['content'];
-                       $arr     = ['content' => call_user_func([$moduleClass, 'content'])];
+                       $arr     = ['content' => call_user_func([$moduleClass, 'content'], $module->getParameters())];
                        Hook::callAll($moduleClass . '_mod_aftercontent', $arr);
                        $content .= $arr['content'];
                } catch (HTTPException $e) {
index f723321ac67cf883bfe8a2ab93c26c5e77c78b7c..c9ba21bb3538e2df167dc74176652f2e4ab659c4 100644 (file)
@@ -39,6 +39,11 @@ class Router
         */
        private $httpMethod;
 
+       /**
+        * @var array Module parameters
+        */
+       private $parameters = [];
+
        /**
         * @param array $server The $_SERVER variable
         * @param RouteCollector|null $routeCollector Optional the loaded Route collector
@@ -60,12 +65,21 @@ class Router
         *
         * @throws HTTPException\InternalServerErrorException In case of invalid configs
         */
-       public function addRoutes(array $routes)
+       public function loadRoutes(array $routes)
        {
                $routeCollector = (isset($this->routeCollector) ?
                        $this->routeCollector :
                        new RouteCollector(new Std(), new GroupCountBased()));
 
+               $this->addRoutes($routeCollector, $routes);
+
+               $this->routeCollector = $routeCollector;
+
+               return $this;
+       }
+
+       private function addRoutes(RouteCollector $routeCollector, array $routes)
+       {
                foreach ($routes as $route => $config) {
                        if ($this->isGroup($config)) {
                                $this->addGroup($route, $config, $routeCollector);
@@ -75,10 +89,6 @@ class Router
                                throw new HTTPException\InternalServerErrorException("Wrong route config for route '" . print_r($route, true) . "'");
                        }
                }
-
-               $this->routeCollector = $routeCollector;
-
-               return $this;
        }
 
        /**
@@ -91,15 +101,7 @@ class Router
        private function addGroup(string $groupRoute, array $routes, RouteCollector $routeCollector)
        {
                $routeCollector->addGroup($groupRoute, function (RouteCollector $routeCollector) use ($routes) {
-                       foreach ($routes as $route => $config) {
-                               if ($this->isGroup($config)) {
-                                       $this->addGroup($route, $config, $routeCollector);
-                               } elseif ($this->isRoute($config)) {
-                                       $routeCollector->addRoute($config[1], $route, $config[0]);
-                               }else {
-                                       throw new HTTPException\InternalServerErrorException("Wrong route config for route '" . print_r($route, true) . "'");
-                               }
-                       }
+                       $this->addRoutes($routeCollector, $routes);
                });
        }
 
@@ -169,13 +171,15 @@ class Router
 
                $cmd = '/' . ltrim($cmd, '/');
 
-               $dispatcher = new \FastRoute\Dispatcher\GroupCountBased($this->routeCollector->getData());
+               $dispatcher = new Dispatcher\GroupCountBased($this->routeCollector->getData());
 
                $moduleClass = null;
+               $this->parameters = [];
 
                $routeInfo  = $dispatcher->dispatch($this->httpMethod, $cmd);
                if ($routeInfo[0] === Dispatcher::FOUND) {
                        $moduleClass = $routeInfo[1];
+                       $this->parameters = $routeInfo[2];
                } elseif ($routeInfo[0] === Dispatcher::METHOD_NOT_ALLOWED) {
                        throw new HTTPException\MethodNotAllowedException(L10n::t('Method not allowed for this module. Allowed method(s): %s', implode(', ', $routeInfo[1])));
                } else {
@@ -184,4 +188,14 @@ class Router
 
                return $moduleClass;
        }
+
+       /**
+        * Returns the module parameters.
+        *
+        * @return array parameters
+        */
+       public function getModuleParameters()
+       {
+               return $this->parameters;
+       }
 }
index 5185771d1c51294f0f921c1e13a4cc36bf29a991..be53289e52c41f045fc27ac1ea11a5454786acc6 100644 (file)
@@ -22,7 +22,7 @@ abstract class BaseModule extends BaseObject
         * Extend this method if you need to do any shared processing before both
         * content() or post()
         */
-       public static function init()
+       public static function init(array $parameters = [])
        {
        }
 
@@ -32,7 +32,7 @@ abstract class BaseModule extends BaseObject
         * Extend this method if the module is supposed to return communication data,
         * e.g. from protocol implementations.
         */
-       public static function rawContent()
+       public static function rawContent(array $parameters = [])
        {
                // echo '';
                // exit;
@@ -47,7 +47,7 @@ abstract class BaseModule extends BaseObject
         *
         * @return string
         */
-       public static function content()
+       public static function content(array $parameters = [])
        {
                $o = '';
 
@@ -60,7 +60,7 @@ abstract class BaseModule extends BaseObject
         * Extend this method if the module is supposed to process POST requests.
         * Doesn't display any content
         */
-       public static function post()
+       public static function post(array $parameters = [])
        {
                // $a = self::getApp();
                // $a->internalRedirect('module');
@@ -71,9 +71,8 @@ abstract class BaseModule extends BaseObject
         *
         * Unknown purpose
         */
-       public static function afterpost()
+       public static function afterpost(array $parameters = [])
        {
-
        }
 
        /*
index ed6ec9c877bb729126bb1ed5a00d0805946d0b2b..ea1baef180db2d91addf0ab7818555a1c52a753e 100644 (file)
@@ -43,9 +43,14 @@ final class Item
                $first = true;
 
                foreach (FileTag::fileToArray($item['file'] ?? '', 'category') as $savedFolderName) {
+                       if (!empty($item['author-link'])) {
+                               $url = $item['author-link'] . "?category=" . rawurlencode($savedFolderName);
+                       } else {
+                               $url = '#';
+                       }
                        $categories[] = [
                                'name' => $savedFolderName,
-                               'url' => "#",
+                               'url' => $url,
                                'removeurl' => ((local_user() == $item['uid']) ? 'filerm/' . $item['id'] . '?f=&cat=' . rawurlencode($savedFolderName) : ""),
                                'first' => $first,
                                'last' => false
index c3ad23941d879213f1b36a685bacb9115d187811..1dffb05073b70f7f7f30c6fe35b86894986147b8 100644 (file)
@@ -25,6 +25,7 @@ use Friendica\Model\Photo;
 use Friendica\Network\Probe;
 use Friendica\Object\Image;
 use Friendica\Protocol\Activity;
+use Friendica\Util\Images;
 use Friendica\Util\Map;
 use Friendica\Util\Network;
 use Friendica\Util\ParseUrl;
@@ -76,7 +77,7 @@ class BBCode extends BaseObject
 
                                if (preg_match("/\[img\](.*?)\[\/img\]/ism", $attacheddata, $matches)) {
 
-                                       $picturedata = Image::getInfoFromURL($matches[1]);
+                                       $picturedata = Images::getInfoFromURLCached($matches[1]);
 
                                        if ($picturedata) {
                                                if (($picturedata[0] >= 500) && ($picturedata[0] >= $picturedata[1])) {
@@ -305,7 +306,7 @@ class BBCode extends BaseObject
                                                $post['preview'] = $pictures[0][2];
                                                $post['text'] = trim(str_replace($pictures[0][0], '', $body));
                                        } else {
-                                               $imgdata = Image::getInfoFromURL($pictures[0][1]);
+                                               $imgdata = Images::getInfoFromURLCached($pictures[0][1]);
                                                if ($imgdata && substr($imgdata['mime'], 0, 6) == 'image/') {
                                                        $post['type'] = 'photo';
                                                        $post['image'] = $pictures[0][1];
@@ -446,7 +447,7 @@ class BBCode extends BaseObject
                                }
 
                                // guess mimetype from headers or filename
-                               $type = Image::guessType($mtch[1], true);
+                               $type = Images::guessType($mtch[1], true);
 
                                if ($i) {
                                        $Image = new Image($i, $type);
index 09a5fc6345b75bbe01e25ff10b30ec195935a126..5878bc75d22f7e88a73708d6920215bbb58c647a 100644 (file)
@@ -274,6 +274,10 @@ class Widget
                foreach (FileTag::fileToArray($saved) as $savedFolderName) {
                        $terms[] = ['ref' => $savedFolderName, 'name' => $savedFolderName];
                }
+               
+               usort($terms, function ($a, $b) {
+                       return strcmp($a['name'], $b['name']);
+               });
 
                return self::filter(
                        'file',
index 16d7bf0aad681f19d9f81c3ac87a9200dcb4c1ce..8bdb00f0459131c222cc63804618a8f29285a9c2 100644 (file)
@@ -9,7 +9,7 @@ use Exception;
 use Friendica\Core\Config\Cache\ConfigCache;
 use Friendica\Database\Database;
 use Friendica\Database\DBStructure;
-use Friendica\Object\Image;
+use Friendica\Util\Images;
 use Friendica\Util\Network;
 use Friendica\Util\Strings;
 
@@ -569,7 +569,7 @@ class Installer
 
                if (class_exists('Imagick')) {
                        $imagick = true;
-                       $supported = Image::supportedTypes();
+                       $supported = Images::supportedTypes();
                        if (array_key_exists('image/gif', $supported)) {
                                $gif = true;
                        }
index a0b23a5419d2e2d453f9537468ffbe048aedce5c..950f8faad213868f028e59cf5802262157524b21 100644 (file)
@@ -35,24 +35,24 @@ class LegacyModule extends BaseModule
                require_once $file_path;
        }
 
-       public static function init()
+       public static function init(array $parameters = [])
        {
-               self::runModuleFunction('init');
+               self::runModuleFunction('init', $parameters);
        }
 
-       public static function content()
+       public static function content(array $parameters = [])
        {
-               return self::runModuleFunction('content');
+               return self::runModuleFunction('content', $parameters);
        }
 
-       public static function post()
+       public static function post(array $parameters = [])
        {
-               self::runModuleFunction('post');
+               self::runModuleFunction('post', $parameters);
        }
 
-       public static function afterpost()
+       public static function afterpost(array $parameters = [])
        {
-               self::runModuleFunction('afterpost');
+               self::runModuleFunction('afterpost', $parameters);
        }
 
        /**
@@ -62,7 +62,7 @@ class LegacyModule extends BaseModule
         * @return string
         * @throws \Exception
         */
-       private static function runModuleFunction($function_suffix)
+       private static function runModuleFunction($function_suffix, array $parameters = [])
        {
                $function_name = static::$moduleName . '_' . $function_suffix;
 
@@ -70,7 +70,7 @@ class LegacyModule extends BaseModule
                        $a = self::getApp();
                        return $function_name($a);
                } else {
-                       return parent::{$function_suffix}();
+                       return parent::{$function_suffix}($parameters);
                }
        }
 }
index c7cfddbb84a58e51d0611830fbca259237e7fcdb..d7e05f6e8bb1e5f4b9329a924114b6f9936458d5 100644 (file)
@@ -25,6 +25,7 @@ use Friendica\Protocol\Diaspora;
 use Friendica\Protocol\OStatus;
 use Friendica\Protocol\Salmon;
 use Friendica\Util\DateTimeFormat;
+use Friendica\Util\Images;
 use Friendica\Util\Network;
 use Friendica\Util\Strings;
 
@@ -719,7 +720,7 @@ class Contact extends BaseObject
                        }
 
                        // Creating the path to the avatar, beginning with the file suffix
-                       $types = Image::supportedTypes();
+                       $types = Images::supportedTypes();
                        if (isset($types[$avatar['type']])) {
                                $file_suffix = $types[$avatar['type']];
                        }
@@ -983,41 +984,43 @@ class Contact extends BaseObject
 
                $ssl_url = str_replace('http://', 'https://', $url);
 
+               $nurl = Strings::normaliseLink($url);
+
                // Fetch contact data from the contact table for the given user
                $s = DBA::p("SELECT `id`, `id` AS `cid`, 0 AS `gid`, 0 AS `zid`, `uid`, `url`, `nurl`, `alias`, `network`, `name`, `nick`, `addr`, `location`, `about`, `xmpp`,
-                       `keywords`, `gender`, `photo`, `thumb`, `micro`, `forum`, `prv`, (`forum` | `prv`) AS `community`, `contact-type`, `bd` AS `birthday`, `self`
-               FROM `contact` WHERE `nurl` = ? AND `uid` = ?", Strings::normaliseLink($url), $uid);
+                       `keywords`, `gender`, `photo`, `thumb`, `micro`, `forum`, `prv`, (`forum` | `prv`) AS `community`, `contact-type`, `bd` AS `birthday`, `self`, `rel`, `pending`
+               FROM `contact` WHERE `nurl` = ? AND `uid` = ?", $nurl, $uid);
                $r = DBA::toArray($s);
 
                // Fetch contact data from the contact table for the given user, checking with the alias
                if (!DBA::isResult($r)) {
                        $s = DBA::p("SELECT `id`, `id` AS `cid`, 0 AS `gid`, 0 AS `zid`, `uid`, `url`, `nurl`, `alias`, `network`, `name`, `nick`, `addr`, `location`, `about`, `xmpp`,
-                               `keywords`, `gender`, `photo`, `thumb`, `micro`, `forum`, `prv`, (`forum` | `prv`) AS `community`, `contact-type`, `bd` AS `birthday`, `self`
-                       FROM `contact` WHERE `alias` IN (?, ?, ?) AND `uid` = ?", Strings::normaliseLink($url), $url, $ssl_url, $uid);
+                               `keywords`, `gender`, `photo`, `thumb`, `micro`, `forum`, `prv`, (`forum` | `prv`) AS `community`, `contact-type`, `bd` AS `birthday`, `self`, `rel`, `pending`
+                       FROM `contact` WHERE `alias` IN (?, ?, ?) AND `uid` = ?", $nurl, $url, $ssl_url, $uid);
                        $r = DBA::toArray($s);
                }
 
                // Fetch the data from the contact table with "uid=0" (which is filled automatically)
                if (!DBA::isResult($r)) {
                        $s = DBA::p("SELECT `id`, 0 AS `cid`, `id` AS `zid`, 0 AS `gid`, `uid`, `url`, `nurl`, `alias`, `network`, `name`, `nick`, `addr`, `location`, `about`, `xmpp`,
-                       `keywords`, `gender`, `photo`, `thumb`, `micro`, `forum`, `prv`, (`forum` | `prv`) AS `community`, `contact-type`, `bd` AS `birthday`, 0 AS `self`
-                       FROM `contact` WHERE `nurl` = ? AND `uid` = 0", Strings::normaliseLink($url));
+                       `keywords`, `gender`, `photo`, `thumb`, `micro`, `forum`, `prv`, (`forum` | `prv`) AS `community`, `contact-type`, `bd` AS `birthday`, 0 AS `self`, `rel`, `pending`
+                       FROM `contact` WHERE `nurl` = ? AND `uid` = 0", $nurl);
                        $r = DBA::toArray($s);
                }
 
                // Fetch the data from the contact table with "uid=0" (which is filled automatically) - checked with the alias
                if (!DBA::isResult($r)) {
                        $s = DBA::p("SELECT `id`, 0 AS `cid`, `id` AS `zid`, 0 AS `gid`, `uid`, `url`, `nurl`, `alias`, `network`, `name`, `nick`, `addr`, `location`, `about`, `xmpp`,
-                       `keywords`, `gender`, `photo`, `thumb`, `micro`, `forum`, `prv`, (`forum` | `prv`) AS `community`, `contact-type`, `bd` AS `birthday`, 0 AS `self`
-                       FROM `contact` WHERE `alias` IN (?, ?, ?) AND `uid` = 0", Strings::normaliseLink($url), $url, $ssl_url);
+                       `keywords`, `gender`, `photo`, `thumb`, `micro`, `forum`, `prv`, (`forum` | `prv`) AS `community`, `contact-type`, `bd` AS `birthday`, 0 AS `self`, `rel`, `pending`
+                       FROM `contact` WHERE `alias` IN (?, ?, ?) AND `uid` = 0", $nurl, $url, $ssl_url);
                        $r = DBA::toArray($s);
                }
 
                // Fetch the data from the gcontact table
                if (!DBA::isResult($r)) {
                        $s = DBA::p("SELECT 0 AS `id`, 0 AS `cid`, `id` AS `gid`, 0 AS `zid`, 0 AS `uid`, `url`, `nurl`, `alias`, `network`, `name`, `nick`, `addr`, `location`, `about`, '' AS `xmpp`,
-                       `keywords`, `gender`, `photo`, `photo` AS `thumb`, `photo` AS `micro`, 0 AS `forum`, 0 AS `prv`, `community`, `contact-type`, `birthday`, 0 AS `self`
-                       FROM `gcontact` WHERE `nurl` = ?", Strings::normaliseLink($url));
+                       `keywords`, `gender`, `photo`, `photo` AS `thumb`, `photo` AS `micro`, 0 AS `forum`, 0 AS `prv`, `community`, `contact-type`, `birthday`, 0 AS `self`, 2 AS `rel`, 0 AS `pending`
+                       FROM `gcontact` WHERE `nurl` = ?", $nurl);
                        $r = DBA::toArray($s);
                }
 
@@ -1121,7 +1124,7 @@ class Contact extends BaseObject
 
                // Fetch contact data from the contact table for the given user
                $r = q("SELECT `id`, `id` AS `cid`, 0 AS `gid`, 0 AS `zid`, `uid`, `url`, `nurl`, `alias`, `network`, `name`, `nick`, `addr`, `location`, `about`, `xmpp`,
-                       `keywords`, `gender`, `photo`, `thumb`, `micro`, `forum`, `prv`, (`forum` | `prv`) AS `community`, `contact-type`, `bd` AS `birthday`, `self`
+                       `keywords`, `gender`, `photo`, `thumb`, `micro`, `forum`, `prv`, (`forum` | `prv`) AS `community`, `contact-type`, `bd` AS `birthday`, `self`, `rel`, `pending`
                        FROM `contact` WHERE `addr` = '%s' AND `uid` = %d AND NOT `deleted`",
                        DBA::escape($addr),
                        intval($uid)
@@ -1129,7 +1132,7 @@ class Contact extends BaseObject
                // Fetch the data from the contact table with "uid=0" (which is filled automatically)
                if (!DBA::isResult($r)) {
                        $r = q("SELECT `id`, 0 AS `cid`, `id` AS `zid`, 0 AS `gid`, `uid`, `url`, `nurl`, `alias`, `network`, `name`, `nick`, `addr`, `location`, `about`, `xmpp`,
-                               `keywords`, `gender`, `photo`, `thumb`, `micro`, `forum`, `prv`, (`forum` | `prv`) AS `community`, `contact-type`, `bd` AS `birthday`, 0 AS `self`
+                               `keywords`, `gender`, `photo`, `thumb`, `micro`, `forum`, `prv`, (`forum` | `prv`) AS `community`, `contact-type`, `bd` AS `birthday`, 0 AS `self`, `rel`, `pending`
                                FROM `contact` WHERE `addr` = '%s' AND `uid` = 0 AND NOT `deleted`",
                                DBA::escape($addr)
                        );
@@ -1138,7 +1141,7 @@ class Contact extends BaseObject
                // Fetch the data from the gcontact table
                if (!DBA::isResult($r)) {
                        $r = q("SELECT 0 AS `id`, 0 AS `cid`, `id` AS `gid`, 0 AS `zid`, 0 AS `uid`, `url`, `nurl`, `alias`, `network`, `name`, `nick`, `addr`, `location`, `about`, '' AS `xmpp`,
-                               `keywords`, `gender`, `photo`, `photo` AS `thumb`, `photo` AS `micro`, `community` AS `forum`, 0 AS `prv`, `community`, `contact-type`, `birthday`, 0 AS `self`
+                               `keywords`, `gender`, `photo`, `photo` AS `thumb`, `photo` AS `micro`, `community` AS `forum`, 0 AS `prv`, `community`, `contact-type`, `birthday`, 0 AS `self`, 2 AS `rel`, 0 AS `pending`
                                FROM `gcontact` WHERE `addr` = '%s'",
                                DBA::escape($addr)
                        );
@@ -1225,28 +1228,40 @@ class Contact extends BaseObject
                        $contact_drop_link = System::baseUrl() . '/contact/' . $contact['id'] . '/drop?confirm=1';
                }
 
+               $follow_link = '';
+               $unfollow_link = '';
+               if (in_array($contact['network'], Protocol::NATIVE_SUPPORT)) {
+                       if ($contact['uid'] && in_array($contact['rel'], [self::SHARING, self::FRIEND])) {
+                               $unfollow_link = 'unfollow?url=' . urlencode($contact['url']);
+                       } elseif(!$contact['pending']) {
+                               $follow_link = 'follow?url=' . urlencode($contact['url']);
+                       }
+               }
+
                /**
                 * Menu array:
                 * "name" => [ "Label", "link", (bool)Should the link opened in a new tab? ]
                 */
                if (empty($contact['uid'])) {
-                       $connlnk = 'follow/?url=' . $contact['url'];
                        $menu = [
-                               'profile' => [L10n::t('View Profile'),   $profile_link, true],
-                               'network' => [L10n::t('Network Posts'),  $posts_link,   false],
-                               'edit'    => [L10n::t('View Contact'),   $contact_url,  false],
-                               'follow'  => [L10n::t('Connect/Follow'), $connlnk,      true],
+                               'profile' => [L10n::t('View Profile')  , $profile_link , true],
+                               'network' => [L10n::t('Network Posts') , $posts_link   , false],
+                               'edit'    => [L10n::t('View Contact')  , $contact_url  , false],
+                               'follow'  => [L10n::t('Connect/Follow'), $follow_link  , true],
+                               'unfollow'=> [L10n::t('UnFollow')      , $unfollow_link, true],
                        ];
                } else {
                        $menu = [
-                               'status'  => [L10n::t('View Status'),   $status_link,       true],
-                               'profile' => [L10n::t('View Profile'),  $profile_link,      true],
-                               'photos'  => [L10n::t('View Photos'),   $photos_link,       true],
-                               'network' => [L10n::t('Network Posts'), $posts_link,        false],
-                               'edit'    => [L10n::t('View Contact'),  $contact_url,       false],
-                               'drop'    => [L10n::t('Drop Contact'),  $contact_drop_link, false],
-                               'pm'      => [L10n::t('Send PM'),       $pm_url,            false],
-                               'poke'    => [L10n::t('Poke'),          $poke_link,         false],
+                               'status'  => [L10n::t('View Status')   , $status_link      , true],
+                               'profile' => [L10n::t('View Profile')  , $profile_link     , true],
+                               'photos'  => [L10n::t('View Photos')   , $photos_link      , true],
+                               'network' => [L10n::t('Network Posts') , $posts_link       , false],
+                               'edit'    => [L10n::t('View Contact')  , $contact_url      , false],
+                               'drop'    => [L10n::t('Drop Contact')  , $contact_drop_link, false],
+                               'pm'      => [L10n::t('Send PM')       , $pm_url           , false],
+                               'poke'    => [L10n::t('Poke')          , $poke_link        , false],
+                               'follow'  => [L10n::t('Connect/Follow'), $follow_link      , true],
+                               'unfollow'=> [L10n::t('UnFollow')      , $unfollow_link    , true],
                        ];
 
                        if (!empty($contact['pending'])) {
@@ -2298,7 +2313,13 @@ class Contact extends BaseObject
 
                $hidden = (($protocol === Protocol::MAIL) ? 1 : 0);
 
-               $pending = in_array($protocol, [Protocol::ACTIVITYPUB]);
+               $pending = false;
+               if ($protocol == Protocol::ACTIVITYPUB) {
+                       $apcontact = APContact::getByURL($url, false);
+                       if (isset($apcontact['manually-approve'])) {
+                               $pending = (bool)$apcontact['manually-approve'];
+                       }                       
+               }
 
                if (in_array($protocol, [Protocol::MAIL, Protocol::DIASPORA, Protocol::ACTIVITYPUB])) {
                        $writeable = 1;
index 9501c8e5d240519caed3781703baaa95e3a2e0bf..159fac455b9dd96f33c75da491fab12bda68b351 100644 (file)
@@ -58,7 +58,7 @@ class Item extends BaseObject
                'author-id', 'author-link', 'author-name', 'author-avatar', 'author-network',
                'owner-id', 'owner-link', 'owner-name', 'owner-avatar', 'owner-network',
                'contact-id', 'contact-uid', 'contact-link', 'contact-name', 'contact-avatar',
-               'writable', 'self', 'cid', 'alias',
+               'writable', 'self', 'cid', 'alias', 'pinned',
                'event-id', 'event-created', 'event-edited', 'event-start', 'event-finish',
                'event-summary', 'event-desc', 'event-location', 'event-type',
                'event-nofinish', 'event-adjust', 'event-ignore', 'event-id',
@@ -114,6 +114,80 @@ class Item extends BaseObject
                return self::$legacy_mode;
        }
 
+       /**
+        * Set the pinned state of an item
+        *
+        * @param integer $iid    Item ID
+        * @param integer $uid    User ID
+        * @param boolean $pinned Pinned state
+        */
+       public static function setPinned(int $iid, int $uid, bool $pinned)
+       {
+               DBA::update('user-item', ['pinned' => $pinned], ['iid' => $iid, 'uid' => $uid], true);
+       }
+
+       /**
+        * Get the pinned state
+        *
+        * @param integer $iid Item ID
+        * @param integer $uid User ID
+        *
+        * @return boolean pinned state
+        */
+       public static function getPinned(int $iid, int $uid)
+       {
+               $useritem = DBA::selectFirst('user-item', ['pinned'], ['iid' => $iid, 'uid' => $uid]);
+               if (!DBA::isResult($useritem)) {
+                       return false;
+               }
+               return (bool)$useritem['pinned'];
+       }
+
+       /**
+        * @brief Select pinned rows from the item table for a given user
+        *
+        * @param integer $uid       User ID
+        * @param array   $selected  Array of selected fields, empty for all
+        * @param array   $condition Array of fields for condition
+        * @param array   $params    Array of several parameters
+        *
+        * @return boolean|object
+        * @throws \Exception
+        */
+       public static function selectPinned(int $uid, array $selected = [], array $condition = [], $params = [])
+       {
+               $useritems = DBA::select('user-item', ['iid'], ['uid' => $uid, 'pinned' => true]);
+               if (!DBA::isResult($useritems)) {
+                       return $useritems;
+               }
+
+               $pinned = [];
+               while ($useritem = self::fetch($useritems)) {
+                       $pinned[] = $useritem['iid'];
+               }
+               DBA::close($useritems);
+
+               if (empty($pinned)) {
+                       return [];
+               }
+
+               if (empty($condition) || !is_array($condition)) {
+                       $condition = ['iid' => $pinned];
+               } else {
+                       reset($condition);
+                       $first_key = key($condition);
+                       if (!is_int($first_key)) {
+                               $condition['iid'] = $pinned;
+                       } else {
+                               $values_string = substr(str_repeat("?, ", count($pinned)), 0, -2);
+                               $condition[0] = '(' . $condition[0] . ") AND `iid` IN (" . $values_string . ")";
+                               $condition = array_merge($condition, $pinned);
+                       }
+               }
+
+               return self::selectThreadForUser($uid, $selected, $condition, $params);
+       }
+
        /**
         * @brief returns an activity index from an activity string
         *
@@ -585,7 +659,7 @@ class Item extends BaseObject
                        'iaid' => 'internal-iaid'];
 
                if ($usermode) {
-                       $fields['user-item'] = ['ignored' => 'internal-user-ignored'];
+                       $fields['user-item'] = ['pinned', 'ignored' => 'internal-user-ignored'];
                }
 
                $fields['item-activity'] = ['activity', 'activity' => 'internal-activity'];
index 4baef04b9bc0666d85fe8574e603f96c77560e6f..10e80a4fb5bc8daad21d8abbab828ea1137600fc 100644 (file)
@@ -17,8 +17,8 @@ use Friendica\Database\DBA;
 use Friendica\Database\DBStructure;
 use Friendica\Model\Storage\IStorage;
 use Friendica\Object\Image;
-use Friendica\Protocol\DFRN;
 use Friendica\Util\DateTimeFormat;
+use Friendica\Util\Images;
 use Friendica\Util\Network;
 use Friendica\Util\Security;
 use Friendica\Util\Strings;
@@ -404,9 +404,9 @@ class Photo extends BaseObject
                        "photo", ["resource-id"], ["uid" => $uid, "contact-id" => $cid, "scale" => 4, "album" => "Contact Photos"]
                );
                if (!empty($photo['resource-id'])) {
-                       $hash = $photo["resource-id"];
+                       $resource_id = $photo["resource-id"];
                } else {
-                       $hash = self::newResource();
+                       $resource_id = self::newResource();
                }
 
                $photo_failure = false;
@@ -425,14 +425,14 @@ class Photo extends BaseObject
                }
 
                if (empty($type)) {
-                       $type = Image::guessType($image_url, true);
+                       $type = Images::guessType($image_url, true);
                }
 
                $Image = new Image($img_str, $type);
                if ($Image->isValid()) {
                        $Image->scaleToSquare(300);
 
-                       $r = self::store($Image, $uid, $cid, $hash, $filename, "Contact Photos", 4);
+                       $r = self::store($Image, $uid, $cid, $resource_id, $filename, "Contact Photos", 4);
 
                        if ($r === false) {
                                $photo_failure = true;
@@ -440,7 +440,7 @@ class Photo extends BaseObject
 
                        $Image->scaleDown(80);
 
-                       $r = self::store($Image, $uid, $cid, $hash, $filename, "Contact Photos", 5);
+                       $r = self::store($Image, $uid, $cid, $resource_id, $filename, "Contact Photos", 5);
 
                        if ($r === false) {
                                $photo_failure = true;
@@ -448,7 +448,7 @@ class Photo extends BaseObject
 
                        $Image->scaleDown(48);
 
-                       $r = self::store($Image, $uid, $cid, $hash, $filename, "Contact Photos", 6);
+                       $r = self::store($Image, $uid, $cid, $resource_id, $filename, "Contact Photos", 6);
 
                        if ($r === false) {
                                $photo_failure = true;
@@ -456,24 +456,24 @@ class Photo extends BaseObject
 
                        $suffix = "?ts=" . time();
 
-                       $image_url = System::baseUrl() . "/photo/" . $hash . "-4." . $Image->getExt() . $suffix;
-                       $thumb = System::baseUrl() . "/photo/" . $hash . "-5." . $Image->getExt() . $suffix;
-                       $micro = System::baseUrl() . "/photo/" . $hash . "-6." . $Image->getExt() . $suffix;
+                       $image_url = System::baseUrl() . "/photo/" . $resource_id . "-4." . $Image->getExt() . $suffix;
+                       $thumb = System::baseUrl() . "/photo/" . $resource_id . "-5." . $Image->getExt() . $suffix;
+                       $micro = System::baseUrl() . "/photo/" . $resource_id . "-6." . $Image->getExt() . $suffix;
 
                        // Remove the cached photo
                        $a = \get_app();
                        $basepath = $a->getBasePath();
 
                        if (is_dir($basepath . "/photo")) {
-                               $filename = $basepath . "/photo/" . $hash . "-4." . $Image->getExt();
+                               $filename = $basepath . "/photo/" . $resource_id . "-4." . $Image->getExt();
                                if (file_exists($filename)) {
                                        unlink($filename);
                                }
-                               $filename = $basepath . "/photo/" . $hash . "-5." . $Image->getExt();
+                               $filename = $basepath . "/photo/" . $resource_id . "-5." . $Image->getExt();
                                if (file_exists($filename)) {
                                        unlink($filename);
                                }
-                               $filename = $basepath . "/photo/" . $hash . "-6." . $Image->getExt();
+                               $filename = $basepath . "/photo/" . $resource_id . "-6." . $Image->getExt();
                                if (file_exists($filename)) {
                                        unlink($filename);
                                }
@@ -664,7 +664,7 @@ class Photo extends BaseObject
        public static function stripExtension($name)
        {
                $name = str_replace([".jpg", ".png", ".gif"], ["", "", ""], $name);
-               foreach (Image::supportedTypes() as $m => $e) {
+               foreach (Images::supportedTypes() as $m => $e) {
                        $name = str_replace("." . $e, "", $name);
                }
                return $name;
index 83375115ecef6a61a3847454dc4840cbcae93614..7ecf4a576c5405fdd16ce22f8a657e82e3400fe4 100644 (file)
@@ -22,6 +22,7 @@ use Friendica\Model\TwoFactor\AppSpecificPassword;
 use Friendica\Object\Image;
 use Friendica\Util\Crypto;
 use Friendica\Util\DateTimeFormat;
+use Friendica\Util\Images;
 use Friendica\Util\Network;
 use Friendica\Util\Strings;
 use Friendica\Worker\Delivery;
@@ -829,15 +830,15 @@ class User
                        $filename = basename($photo);
                        $img_str = Network::fetchUrl($photo, true);
                        // guess mimetype from headers or filename
-                       $type = Image::guessType($photo, true);
+                       $type = Images::guessType($photo, true);
 
                        $Image = new Image($img_str, $type);
                        if ($Image->isValid()) {
                                $Image->scaleToSquare(300);
 
-                               $hash = Photo::newResource();
+                               $resource_id = Photo::newResource();
 
-                               $r = Photo::store($Image, $uid, 0, $hash, $filename, L10n::t('Profile Photos'), 4);
+                               $r = Photo::store($Image, $uid, 0, $resource_id, $filename, L10n::t('Profile Photos'), 4);
 
                                if ($r === false) {
                                        $photo_failure = true;
@@ -845,7 +846,7 @@ class User
 
                                $Image->scaleDown(80);
 
-                               $r = Photo::store($Image, $uid, 0, $hash, $filename, L10n::t('Profile Photos'), 5);
+                               $r = Photo::store($Image, $uid, 0, $resource_id, $filename, L10n::t('Profile Photos'), 5);
 
                                if ($r === false) {
                                        $photo_failure = true;
@@ -853,14 +854,14 @@ class User
 
                                $Image->scaleDown(48);
 
-                               $r = Photo::store($Image, $uid, 0, $hash, $filename, L10n::t('Profile Photos'), 6);
+                               $r = Photo::store($Image, $uid, 0, $resource_id, $filename, L10n::t('Profile Photos'), 6);
 
                                if ($r === false) {
                                        $photo_failure = true;
                                }
 
                                if (!$photo_failure) {
-                                       Photo::update(['profile' => 1], ['resource-id' => $hash]);
+                                       Photo::update(['profile' => 1], ['resource-id' => $resource_id]);
                                }
                        }
                }
index 2e2a9e496d85ac5bbf9810f40429ed57058d1747..8e7ee0243a7e1b4faab42b39c42830b423704acc 100644 (file)
@@ -11,7 +11,7 @@ use Friendica\BaseModule;
  */
 class AccountManagementControlDocument extends BaseModule
 {
-       public static function rawContent()
+       public static function rawContent(array $parameters = [])
        {
                $output = [
                        'version' => 1,
index 1c2500a224e6cc6dd0e2fcffa0200650cb8c5694..a3577da320b541952438d2ec4c152b18df019f3b 100644 (file)
@@ -11,7 +11,7 @@ use Friendica\Core\System;
  */
 class Acctlink extends BaseModule
 {
-       public static function content()
+       public static function content(array $parameters = [])
        {
                $addr = trim($_GET['addr'] ?? '');
 
index 1965102f03ef5fe4d8abac2420baf47a96d5d0c8..a196e7834f2ec49373b14e04a6305f445e821842 100644 (file)
@@ -11,9 +11,9 @@ use Friendica\Util\Strings;
 
 class Details extends BaseAdminModule
 {
-       public static function post()
+       public static function post(array $parameters = [])
        {
-               parent::post();
+               parent::post($parameters);
 
                $a = self::getApp();
 
@@ -35,9 +35,9 @@ class Details extends BaseAdminModule
                $a->internalRedirect('admin/addons');
        }
 
-       public static function content()
+       public static function content(array $parameters = [])
        {
-               parent::content();
+               parent::content($parameters);
 
                $a = self::getApp();
 
index eed47defb4a973fc43581f080de1930040072848..f327f0dc92ef906fee8e64cab5b2faa82f28e549 100644 (file)
@@ -9,9 +9,9 @@ use Friendica\Module\BaseAdminModule;
 
 class Index extends BaseAdminModule
 {
-       public static function content()
+       public static function content(array $parameters = [])
        {
-               parent::content();
+               parent::content($parameters);
 
                $a = self::getApp();
 
index bf1c7bc081d86cfec1dacb12a2c681dbbeb130bb..38ae233715b95b2afc062f59c7a5315e2d7cb87a 100644 (file)
@@ -11,9 +11,9 @@ use Friendica\Model;
 
 class Contact extends BaseAdminModule
 {
-       public static function post()
+       public static function post(array $parameters = [])
        {
-               parent::post();
+               parent::post($parameters);
 
                $contact_url  = $_POST['contact_url'] ?? '';
                $block_reason = $_POST['contact_block_reason'] ?? '';
@@ -41,9 +41,9 @@ class Contact extends BaseAdminModule
                self::getApp()->internalRedirect('admin/blocklist/contact');
        }
 
-       public static function content()
+       public static function content(array $parameters = [])
        {
-               parent::content();
+               parent::content($parameters);
 
                $a = self::getApp();
 
index 384e346b0d67c5db1f26d6d2163e48b8a1688e7d..53647e64efdc0a3bc595c167db4bca11a7905931 100644 (file)
@@ -10,9 +10,9 @@ use Friendica\Util\Strings;
 
 class Server extends BaseAdminModule
 {
-       public static function post()
+       public static function post(array $parameters = [])
        {
-               parent::post();
+               parent::post($parameters);
 
                if (empty($_POST['page_blocklist_save']) && empty($_POST['page_blocklist_edit'])) {
                        return;
@@ -50,9 +50,9 @@ class Server extends BaseAdminModule
                self::getApp()->internalRedirect('admin/blocklist/server');
        }
 
-       public static function content()
+       public static function content(array $parameters = [])
        {
-               parent::content();
+               parent::content($parameters);
 
                $a = self::getApp();
 
index 4c29eea34f550e15bb64c72dcc457096dc93c054..0d68a564813019c4b92078e88d8d0c8853fd06db 100644 (file)
@@ -12,9 +12,9 @@ use Friendica\Module\BaseAdminModule;
 
 class DBSync extends BaseAdminModule
 {
-       public static function content()
+       public static function content(array $parameters = [])
        {
-               parent::content();
+               parent::content($parameters);
 
                $a = self::getApp();
 
index 328e7e68b57c1e2d91d5c3fa32df7972a995d6be..85683d238f3bab32c5d14022bf35943ebd356cd9 100644 (file)
@@ -10,9 +10,9 @@ use Friendica\Module\BaseAdminModule;
 
 class Features extends BaseAdminModule
 {
-       public static function post()
+       public static function post(array $parameters = [])
        {
-               parent::post();
+               parent::post($parameters);
 
                parent::checkFormSecurityTokenRedirectOnError('/admin/features', 'admin_manage_features');
 
@@ -42,9 +42,9 @@ class Features extends BaseAdminModule
                self::getApp()->internalRedirect('admin/features');
        }
 
-       public static function content()
+       public static function content(array $parameters = [])
        {
-               parent::content();
+               parent::content($parameters);
 
                $arr = [];
                $features = Feature::get(false);
index 8776f21e194bacd7b881ce96edb8bc1444faf005..35afb214485f7a05d41040aa6ff763c99f2a615b 100644 (file)
@@ -10,9 +10,9 @@ use Friendica\Module\BaseAdminModule;
 
 class Federation extends BaseAdminModule
 {
-       public static function content()
+       public static function content(array $parameters = [])
        {
-               parent::content();
+               parent::content($parameters);
 
                // get counts on active friendica, diaspora, redmatrix, hubzilla, gnu
                // social and statusnet nodes this node is knowing
index 766e65c9a0eeccc38c2b9060fd7a2901869c61d3..f5f4687cec51a33cf79d2a06585f0c6538ca7adc 100644 (file)
@@ -10,9 +10,9 @@ use Friendica\Util\Strings;
 
 class Delete extends BaseAdminModule
 {
-       public static function post()
+       public static function post(array $parameters = [])
        {
-               parent::post();
+               parent::post($parameters);
 
                if (empty($_POST['page_deleteitem_submit'])) {
                        return;
@@ -36,9 +36,9 @@ class Delete extends BaseAdminModule
                self::getApp()->internalRedirect('admin/item/delete');
        }
 
-       public static function content()
+       public static function content(array $parameters = [])
        {
-               parent::content();
+               parent::content($parameters);
 
                $t = Renderer::getMarkupTemplate('admin/item/delete.tpl');
 
index 6da9eec6d320da91c94dc261f1db3e3abacd034e..9c41e60f4784aafc97ea6ec271e707440aaec254 100644 (file)
@@ -13,9 +13,9 @@ use Friendica\Module\BaseAdminModule;
 class Source extends BaseAdminModule
 
 {
-       public static function content()
+       public static function content(array $parameters = [])
        {
-               parent::content();
+               parent::content($parameters);
 
                $a = self::getApp();
 
index be060e05359baf2012ffa540e62ef1a41ad918fe..42f3435f6506724453925c9adab32df3f76d783a 100644 (file)
@@ -11,9 +11,9 @@ use Psr\Log\LogLevel;
 
 class Settings extends BaseAdminModule
 {
-       public static function post()
+       public static function post(array $parameters = [])
        {
-               parent::post();
+               parent::post($parameters);
 
                if (!empty($_POST['page_logs'])) {
                        parent::checkFormSecurityTokenRedirectOnError('/admin/logs', 'admin_logs');
@@ -37,9 +37,9 @@ class Settings extends BaseAdminModule
                self::getApp()->internalRedirect('admin/logs');
        }
 
-       public static function content()
+       public static function content(array $parameters = [])
        {
-               parent::content();
+               parent::content($parameters);
 
                $a = self::getApp();
 
index b66a6781e50836cc9dbfb5a32606dc0a8e0fe1c0..51e083473498cf5015c879372e3b21eeadbe209c 100644 (file)
@@ -10,9 +10,9 @@ use Friendica\Util\Strings;
 
 class View extends BaseAdminModule
 {
-       public static function content()
+       public static function content(array $parameters = [])
        {
-               parent::content();
+               parent::content($parameters);
 
                $t = Renderer::getMarkupTemplate('admin/logs/view.tpl');
                $f = Config::get('system', 'logfile');
index b912117dc1446aff732bf5430f904048f5ebaa27..3ac7421816bdbd59f4a70bd758dda5d0c9d65092 100644 (file)
@@ -6,9 +6,9 @@ use Friendica\Module\BaseAdminModule;
 
 class PhpInfo extends BaseAdminModule
 {
-       public static function rawContent()
+       public static function rawContent(array $parameters = [])
        {
-               parent::rawContent();
+               parent::rawContent($parameters);
 
                phpinfo();
                exit();
index aadd5b768d42fb9ce5928ce107d9026496134bef..9ce44ff15a37345c922655b179159d14cff7033a 100644 (file)
@@ -19,9 +19,9 @@ use Friendica\Util\DateTimeFormat;
  */
 class Queue extends BaseAdminModule
 {
-       public static function content()
+       public static function content(array $parameters = [])
        {
-               parent::content();
+               parent::content($parameters);
 
                $a = self::getApp();
 
index 18a1cbf2a835f5d214e1731a478945c52672e492..4a02e98b82c34c0835428b69dcf7bd49278544bd 100644 (file)
@@ -21,9 +21,9 @@ require_once __DIR__ . '/../../../boot.php';
 
 class Site extends BaseAdminModule
 {
-       public static function post()
+       public static function post(array $parameters = [])
        {
-               parent::post();
+               parent::post($parameters);
 
                self::checkFormSecurityTokenRedirectOnError('/admin/site', 'admin_site');
 
@@ -412,9 +412,9 @@ class Site extends BaseAdminModule
                $a->internalRedirect('admin/site' . $active_panel);
        }
 
-       public static function content()
+       public static function content(array $parameters = [])
        {
-               parent::content();
+               parent::content($parameters);
 
                $a = self::getApp();
 
index cfd9aa984041edc7e2d7ed389601f9be3e27eeef..e10533ee9496530895a6cb373953262fd29afad2 100644 (file)
@@ -20,9 +20,9 @@ use Friendica\Util\Network;
 
 class Summary extends BaseAdminModule
 {
-       public static function content()
+       public static function content(array $parameters = [])
        {
-               parent::content();
+               parent::content($parameters);
 
                $a = self::getApp();
 
index 3750e96070ad9fd7514f63f34c8adc1c3f49ef76..912adc4297383bf26e54726acfe50e3845ef6a32 100644 (file)
@@ -11,9 +11,9 @@ use Friendica\Util\Strings;
 
 class Details extends BaseAdminModule
 {
-       public static function post()
+       public static function post(array $parameters = [])
        {
-               parent::post();
+               parent::post($parameters);
 
                $a = self::getApp();
 
@@ -39,9 +39,9 @@ class Details extends BaseAdminModule
                }
        }
 
-       public static function content()
+       public static function content(array $parameters = [])
        {
-               parent::content();
+               parent::content($parameters);
 
                $a = self::getApp();
 
index 904d9eb46e8dcc1f6098b624c745bdba0388e1eb..70a12dadd26edf45ade0f99604a774d145c80816 100644 (file)
@@ -9,7 +9,7 @@ use Friendica\Util\Strings;
 
 class Embed extends BaseAdminModule
 {
-       public static function init()
+       public static function init(array $parameters = [])
        {
                $a = self::getApp();
 
@@ -23,9 +23,9 @@ class Embed extends BaseAdminModule
                }
        }
 
-       public static function post()
+       public static function post(array $parameters = [])
        {
-               parent::post();
+               parent::post($parameters);
 
                $a = self::getApp();
 
@@ -53,9 +53,9 @@ class Embed extends BaseAdminModule
                }
        }
 
-       public static function content()
+       public static function content(array $parameters = [])
        {
-               parent::content();
+               parent::content($parameters);
 
                $a = self::getApp();
 
index af2d1f28e11e0ae91e6b90ab79d2afaf93251c8c..8f7843e293eb2b7ed20851f2269b2b3a472d6336 100644 (file)
@@ -11,9 +11,9 @@ use Friendica\Util\Strings;
 
 class Index extends BaseAdminModule
 {
-       public static function content()
+       public static function content(array $parameters = [])
        {
-               parent::content();
+               parent::content($parameters);
 
                $a = self::getApp();
 
index 4eb6e3426c477358567d034f87dbf2667709e5b4..6fbdc21e8f4b3fdbcaef42cbee9d0f9e8b7c3b43 100644 (file)
@@ -9,9 +9,9 @@ use Friendica\Module\BaseAdminModule;
 
 class Tos extends BaseAdminModule
 {
-       public static function post()
+       public static function post(array $parameters = [])
        {
-               parent::post();
+               parent::post($parameters);
 
                parent::checkFormSecurityTokenRedirectOnError('/admin/tos', 'admin_tos');
 
@@ -32,9 +32,9 @@ class Tos extends BaseAdminModule
                self::getApp()->internalRedirect('admin/tos');
        }
 
-       public static function content()
+       public static function content(array $parameters = [])
        {
-               parent::content();
+               parent::content($parameters);
 
                $tos = new \Friendica\Module\Tos();
                $t = Renderer::getMarkupTemplate('admin/tos.tpl');
index a949c9331b51c37df41e8196850dcce11f115767..84332c979f79462414e8dde7bb4836e1bf150e45 100644 (file)
@@ -15,9 +15,9 @@ use Friendica\Util\Temporal;
 
 class Users extends BaseAdminModule
 {
-       public static function post()
+       public static function post(array $parameters = [])
        {
-               parent::post();
+               parent::post($parameters);
 
                $a = self::getApp();
 
@@ -131,9 +131,9 @@ class Users extends BaseAdminModule
                $a->internalRedirect('admin/users');
        }
 
-       public static function content()
+       public static function content(array $parameters = [])
        {
-               parent::content();
+               parent::content($parameters);
 
                $a = self::getApp();
 
index e5fbe697128d576374fd6fed2d9b2e75da3ee3ab..0d9bf598580dee6ffe4f4851bb76ae15fa1a1a9b 100644 (file)
@@ -16,7 +16,7 @@ use Friendica\Util\Proxy as ProxyUtils;
  */
 class AllFriends extends BaseModule
 {
-       public static function content()
+       public static function content(array $parameters = [])
        {
                $app = self::getApp();
 
index efba071aa3010b3a3cd5f6a0b345401136053b49..bc099ce8bbb8a5b6fd854f506ee131b6e2228113 100644 (file)
@@ -13,7 +13,7 @@ use Friendica\Core\Renderer;
  */
 class Apps extends BaseModule
 {
-       public static function init()
+       public static function init(array $parameters = [])
        {
                $privateaddons = Config::get('config', 'private_addons');
                if ($privateaddons === "1" && !local_user()) {
@@ -21,7 +21,7 @@ class Apps extends BaseModule
                }
        }
 
-       public static function content()
+       public static function content(array $parameters = [])
        {
                $apps = Nav::getAppMenu();
 
index e9af90facc3fb1b0cc053acb93909e238c962e91..f67104015d768622e2740b56517443b71915ca55 100644 (file)
@@ -20,7 +20,7 @@ class Attach extends BaseModule
        /**
         * @brief Return to user an attached file given the id
         */
-       public static function rawContent()
+       public static function rawContent(array $parameters = [])
        {
                $a = self::getApp();
                if ($a->argc != 2) {
index 6802d09c18b89f516b7ab0233ad391bcb100bd9d..01aa00d42392cee738a954649054d51ff8acca8a 100644 (file)
@@ -23,7 +23,7 @@ require_once 'boot.php';
  */
 abstract class BaseAdminModule extends BaseModule
 {
-       public static function post()
+       public static function post(array $parameters = [])
        {
                if (!is_site_admin()) {
                        return;
@@ -35,7 +35,7 @@ abstract class BaseAdminModule extends BaseModule
                }
        }
 
-       public static function rawContent()
+       public static function rawContent(array $parameters = [])
        {
                if (!is_site_admin()) {
                        return '';
@@ -48,7 +48,7 @@ abstract class BaseAdminModule extends BaseModule
                return '';
        }
 
-       public static function content()
+       public static function content(array $parameters = [])
        {
                $a = self::getApp();
 
index 4c9173db79d9c0e96d879e43f2fadb15ac4c0939..4900de42e6d9a1b2e668ac9c96e81f249191a68b 100644 (file)
@@ -9,7 +9,7 @@ use Friendica\Core\Renderer;
 
 class BaseSettingsModule extends BaseModule
 {
-       public static function content()
+       public static function content(array $parameters = [])
        {
                $a = self::getApp();
 
@@ -87,8 +87,8 @@ class BaseSettingsModule extends BaseModule
 
                $tabs[] = [
                        'label' => L10n::t('Export personal data'),
-                       'url' => 'uexport',
-                       'selected' => (($a->argc == 1) && ($a->argv[0] === 'uexport') ? 'active' : ''),
+                       'url' => 'settings/userexport',
+                       'selected' => (($a->argc > 1) && ($a->argv[1] === 'userexport') ? 'active' : ''),
                        'accesskey' => 'e',
                ];
 
index 92130eeff1510d7adc5c5707db9525aaf2379c54..a50f23c256963e160fb4d501b778cad28fee3e47 100644 (file)
@@ -14,7 +14,7 @@ use Friendica\Util\Strings;
  */
 class Bookmarklet extends BaseModule
 {
-       public static function content()
+       public static function content(array $parameters = [])
        {
                $_GET['mode'] = 'minimal';
 
index c8bbbfe2e69a1d45b9467670375fd235d14e682e..ded5ffbe2343ec2e15161e1425b9263aca27241a 100644 (file)
@@ -75,7 +75,7 @@ class Contact extends BaseModule
                $a->internalRedirect('contact');
        }
 
-       public static function post()
+       public static function post(array $parameters = [])
        {
                $a = self::getApp();
 
@@ -240,7 +240,7 @@ class Contact extends BaseModule
                Model\Contact::remove($orig_record['id']);
        }
 
-       public static function content($update = 0)
+       public static function content(array $parameters = [], $update = 0)
        {
                if (!local_user()) {
                        return Login::form($_SERVER['REQUEST_URI']);
diff --git a/src/Module/Contact/Hovercard.php b/src/Module/Contact/Hovercard.php
new file mode 100644 (file)
index 0000000..a72a7f0
--- /dev/null
@@ -0,0 +1,104 @@
+<?php
+
+namespace Friendica\Module\Contact;
+
+use Friendica\BaseModule;
+use Friendica\Core\Config;
+use Friendica\Core\Renderer;
+use Friendica\Core\Session;
+use Friendica\Database\DBA;
+use Friendica\Model\Contact;
+use Friendica\Model\GContact;
+use Friendica\Network\HTTPException;
+use Friendica\Util\Strings;
+use Friendica\Util\Proxy;
+
+/**
+ * Asynchronous HTML fragment provider for frio contact hovercards
+ */
+class Hovercard extends BaseModule
+{
+       public static function rawContent(array $parameters = [])
+       {
+               $contact_url = $_REQUEST['url'] ?? '';
+
+               // Get out if the system doesn't have public access allowed
+               if (Config::get('system', 'block_public') && !Session::isAuthenticated()) {
+                       throw new HTTPException\ForbiddenException();
+               }
+
+               // If a contact is connected the url is internally changed to 'redir/CID'. We need the pure url to search for
+               // the contact. So we strip out the contact id from the internal url and look in the contact table for
+               // the real url (nurl)
+               if (strpos($contact_url, 'redir/') === 0) {
+                       $cid = intval(substr($contact_url, 6));
+                       $remote_contact = Contact::selectFirst(['nurl'], ['id' => $cid]);
+                       $contact_url = $remote_contact['nurl'] ?? '';
+               }
+
+               $contact = [];
+
+               // if it's the url containing https it should be converted to http
+               $contact_nurl = Strings::normaliseLink(GContact::cleanContactUrl($contact_url));
+               if (!$contact_nurl) {
+                       throw new HTTPException\BadRequestException();
+               }
+
+               // Search for contact data
+               // Look if the local user has got the contact
+               if (Session::isAuthenticated()) {
+                       $contact = Contact::getDetailsByURL($contact_nurl, local_user());
+               }
+
+               // If not then check the global user
+               if (!count($contact)) {
+                       $contact = Contact::getDetailsByURL($contact_nurl);
+               }
+
+               // Feeds url could have been destroyed through "cleanContactUrl", so we now use the original url
+               if (!count($contact) && Session::isAuthenticated()) {
+                       $contact_nurl = Strings::normaliseLink($contact_url);
+                       $contact = Contact::getDetailsByURL($contact_nurl, local_user());
+               }
+
+               if (!count($contact)) {
+                       $contact_nurl = Strings::normaliseLink($contact_url);
+                       $contact = Contact::getDetailsByURL($contact_nurl);
+               }
+
+               if (!count($contact)) {
+                       throw new HTTPException\NotFoundException();
+               }
+
+               // Get the photo_menu - the menu if possible contact actions
+               if (Session::isAuthenticated()) {
+                       $actions = Contact::photoMenu($contact);
+               } else {
+                       $actions = [];
+               }
+
+               // Move the contact data to the profile array so we can deliver it to
+               $tpl = Renderer::getMarkupTemplate('hovercard.tpl');
+               $o = Renderer::replaceMacros($tpl, [
+                       '$profile' => [
+                               'name'         => $contact['name'],
+                               'nick'         => $contact['nick'],
+                               'addr'         => $contact['addr'] ?: $contact['url'],
+                               'thumb'        => Proxy::proxifyUrl($contact['thumb'], false, Proxy::SIZE_THUMB),
+                               'url'          => Contact::magicLink($contact['url']),
+                               'nurl'         => $contact['nurl'],
+                               'location'     => $contact['location'],
+                               'gender'       => $contact['gender'],
+                               'about'        => $contact['about'],
+                               'network_link' => Strings::formatNetworkName($contact['network'], $contact['url']),
+                               'tags'         => $contact['keywords'],
+                               'bd'           => $contact['birthday'] <= DBA::NULL_DATE ? '' : $contact['birthday'],
+                               'account_type' => Contact::getAccountType($contact),
+                               'actions'      => $actions,
+                       ],
+               ]);
+
+               echo $o;
+               exit();
+       }
+}
index b0a6545c38b0ca8d875595657353d1f97d1a7f52..c536dcaa5e8fae16f5d77215a91d2853bc08b2c4 100644 (file)
@@ -13,7 +13,7 @@ use Friendica\Core\Renderer;
  */
 class Credits extends BaseModule
 {
-       public static function content()
+       public static function content(array $parameters = [])
        {
                /* fill the page with credits */
                $credits_string = file_get_contents('CREDITS.txt');
index cf1f869552e6116b0c3bb097c97120bdafdb5851..17187a37c7b0d4af9bb56f4e577d3a71cea65d07 100644 (file)
@@ -14,7 +14,7 @@ use Friendica\Util\XML;
  */
 class Babel extends BaseModule
 {
-       public static function content()
+       public static function content(array $parameters = [])
        {
                function visible_whitespace($s)
                {
index cc0be643b3030b858230b3248d8c9ed1af9f7e1a..c764c900032d514818488cec05c82bae3f66137a 100644 (file)
@@ -14,7 +14,7 @@ use Friendica\Util\Network;
  */
 class Feed extends BaseModule
 {
-       public static function init()
+       public static function init(array $parameters = [])
        {
                if (!local_user()) {
                        info(L10n::t('You must be logged in to use this module'));
@@ -22,7 +22,7 @@ class Feed extends BaseModule
                }
        }
 
-       public static function content()
+       public static function content(array $parameters = [])
        {
                $result = [];
                if (!empty($_REQUEST['url'])) {
index fead2553585bf6162665c64ba0f82a2ecc8f7d76..f166fb0a2782a9f62b51a9e6ad15a33313f12452 100644 (file)
@@ -12,7 +12,7 @@ use Friendica\Network\HTTPException;
  */
 class ItemBody extends BaseModule
 {
-       public static function content()
+       public static function content(array $parameters = [])
        {
                if (!local_user()) {
                        throw new HTTPException\UnauthorizedException(L10n::t('Access denied.'));
index 197149837ae5f161f2e4d6caaf1b271b669b3921..0d78f08d796a990ac0c5099983421f3c44bb807a 100644 (file)
@@ -10,7 +10,7 @@ use Friendica\Util\Temporal;
 
 class Localtime extends BaseModule
 {
-       public static function post()
+       public static function post(array $parameters = [])
        {
                $time = ($_REQUEST['time'] ?? '') ?: 'now';
 
@@ -21,7 +21,7 @@ class Localtime extends BaseModule
                }
        }
 
-       public static function content()
+       public static function content(array $parameters = [])
        {
                $app = self::getApp();
 
index 6762c5b82c99bc87bba154da10d283338ad5334e..85c5f900fad4fc2d3c927665eb61b8d435c8e3fb 100644 (file)
@@ -13,7 +13,7 @@ use Friendica\Network\Probe as NetworkProbe;
  */
 class Probe extends BaseModule
 {
-       public static function content()
+       public static function content(array $parameters = [])
        {
                if (!local_user()) {
                        $e           = new HTTPException\ForbiddenException(L10n::t('Only logged in users are permitted to perform a probing.'));
index 18cf4bb2a7386cbc86df382b8265a5097bf80d09..90da40bf09d12d5e15a289b5eea203965e570b3b 100644 (file)
@@ -12,7 +12,7 @@ use Friendica\Network\Probe;
  */
 class WebFinger extends BaseModule
 {
-       public static function content()
+       public static function content(array $parameters = [])
        {
                if (!local_user()) {
                        $e           = new \Friendica\Network\HTTPException\ForbiddenException(L10n::t('Only logged in users are permitted to perform a probing.'));
index 77baefeaa5871321adfd47418476c4c1ad0872a8..d2930317c08ce638aa22b54e10dec3485a33265d 100644 (file)
@@ -17,7 +17,7 @@ use Friendica\Network\HTTPException\ForbiddenException;
  */
 class Delegation extends BaseModule
 {
-       public static function post()
+       public static function post(array $parameters = [])
        {
                if (!local_user()) {
                        return;
@@ -92,7 +92,7 @@ class Delegation extends BaseModule
                // NOTREACHED
        }
 
-       public static function content()
+       public static function content(array $parameters = [])
        {
                if (!local_user()) {
                        throw new ForbiddenException(L10n::t('Permission denied.'));
index 467d64566b769048d1f5a106866afcfa7c49754d..6e3469c292c279366b973923d8c3259be9926a20 100644 (file)
@@ -17,7 +17,7 @@ use Friendica\Util\Strings;
  */
 class Fetch extends BaseModule
 {
-       public static function rawContent()
+       public static function rawContent(array $parameters = [])
        {
                $app = self::getApp();
 
index c787b5f97068d0164319aba888e7c3149f5c5509..72b060a8489b0580779c1d69c899e8529e091673 100644 (file)
@@ -21,13 +21,13 @@ class Receive extends BaseModule
        /** @var LoggerInterface */
        private static $logger;
 
-       public static function init()
+       public static function init(array $parameters = [])
        {
                /** @var LoggerInterface $logger */
                self::$logger = self::getClass(LoggerInterface::class);
        }
 
-       public static function post()
+       public static function post(array $parameters = [])
        {
                /** @var Configuration $config */
                $config = self::getClass(Configuration::class);
index 1cdd971e8ac21c8753c0b158112b16635473b46d..f24c0665074d4f4f942c9aad427edd76e0ad45a9 100644 (file)
@@ -21,7 +21,7 @@ use Friendica\Util\Strings;
  */
 class Directory extends BaseModule
 {
-       public static function content()
+       public static function content(array $parameters = [])
        {
                $app = self::getApp();
                $config = $app->getConfig();
index 49ecfed96c166cd6d6676f77816ec1a100e77e43..ba2153762754c24d9f3e59a8437d87d8c7156c4c 100644 (file)
@@ -23,7 +23,7 @@ use Friendica\Protocol\OStatus;
  */
 class Feed extends BaseModule
 {
-       public static function content()
+       public static function content(array $parameters = [])
        {
                $a = self::getApp();
 
index 1dcc2e41e20a0f3a2a2b67bcc4d54c0e1f64bcb2..0246f1db36db4c274b7dd0dd34e3bb997cea1ec0 100644 (file)
@@ -12,7 +12,7 @@ use Friendica\Util\XML;
  */
 class RemoveTag extends BaseModule
 {
-       public static function content()
+       public static function content(array $parameters = [])
        {
                if (!local_user()) {
                        throw new HTTPException\ForbiddenException();
index e8e311268149575843312fe9ed6e6bd88d22e386..7f0da83bceaf12f017465199cbf116be4d50fd1d 100644 (file)
@@ -14,7 +14,7 @@ use Friendica\Util\XML;
  */
 class SaveTag extends BaseModule
 {
-       public static function init()
+       public static function init(array $parameters = [])
        {
                if (!local_user()) {
                        info(L10n::t('You must be logged in to use this module'));
@@ -22,7 +22,7 @@ class SaveTag extends BaseModule
                }
        }
 
-       public static function rawContent()
+       public static function rawContent(array $parameters = [])
        {
                $a = self::getApp();
                $logger = $a->getLogger();
index f4f2a877c4f55fb1833f443ead4ebf0b304b3f44..d1a0a5dda573183aba2f5f944fe370f5d3140b79 100644 (file)
@@ -18,7 +18,7 @@ use Friendica\Util\DateTimeFormat;
  */
 class FollowConfirm extends BaseModule
 {
-       public static function post()
+       public static function post(array $parameters = [])
        {
                $a = self::getApp();
 
index 5bd3fe0ce2ef238b165fa52999c491400ecf4bc8..c2096cd052b28b6d99dd88e83860ce58bce57bbc 100644 (file)
@@ -14,7 +14,7 @@ use Friendica\Protocol\ActivityPub;
  */
 class Followers extends BaseModule
 {
-       public static function rawContent()
+       public static function rawContent(array $parameters = [])
        {
                $a = self::getApp();
 
index 5b5f4dc986d491d5c086f1f459ffef8bf5645e1e..8eaa1835c2eb3eebb8c0080d70a40cce16ba5681 100644 (file)
@@ -14,7 +14,7 @@ use Friendica\Protocol\ActivityPub;
  */
 class Following extends BaseModule
 {
-       public static function rawContent()
+       public static function rawContent(array $parameters = [])
        {
                $a = self::getApp();
 
index ae8ea1496831699ec1df175bbcc3b5da4ae818cf..ee8b2206119d53262c354de26721d1addbf3df6a 100644 (file)
@@ -15,7 +15,7 @@ use Friendica\Model\User;
  */
 class Friendica extends BaseModule
 {
-       public static function content()
+       public static function content(array $parameters = [])
        {
                $app = self::getApp();
                $config = $app->getConfig();
@@ -88,7 +88,7 @@ class Friendica extends BaseModule
                ]);
        }
 
-       public static function rawContent()
+       public static function rawContent(array $parameters = [])
        {
                $app = self::getApp();
 
index d8d5fb1c592086e9e2574fb246fbdf8eb08a5992..4c7672c01a7285d855547028cfb8072f7fd9c0be 100644 (file)
@@ -19,7 +19,7 @@ require_once 'boot.php';
 
 class Group extends BaseModule
 {
-       public static function post()
+       public static function post(array $parameters = [])
        {
                $a = self::getApp();
 
@@ -132,7 +132,7 @@ class Group extends BaseModule
                }
        }
 
-       public static function content()
+       public static function content(array $parameters = [])
        {
                $change = false;
 
index 8d2d280a59385060052423671088aa6f242ea1c7..b4f9e9766165eb0d400bf71cc88ef3d5d7794306 100644 (file)
@@ -8,7 +8,7 @@ use Friendica\Network\HTTPException;
 
 class MethodNotAllowed extends BaseModule
 {
-       public static function content()
+       public static function content(array $parameters = [])
        {
                throw new HTTPException\MethodNotAllowedException(L10n::t('Method Not Allowed.'));
        }
index d848905c5e2e4857b5b6b213202a403fa5f95ad9..c79d9c2778521d0e24c1b21fea021ca30a091e3e 100644 (file)
@@ -8,7 +8,7 @@ use Friendica\Network\HTTPException;
 
 class PageNotFound extends BaseModule
 {
-       public static function content()
+       public static function content(array $parameters = [])
        {
                throw new HTTPException\NotFoundException(L10n::t('Page not found.'));
        }
index 411da5ce5eafd0300b0a1d38eb318d59acb53792..a460ae1d98887a25562e6299d2f91e9b5347177b 100644 (file)
@@ -15,7 +15,7 @@ use Friendica\Util\Strings;
 class Hashtag extends BaseModule
 {
 
-       public static function content()
+       public static function content(array $parameters = [])
        {
                $result = [];
 
index ddf5b06d8337398015598897d4df0ae591367623..3b3ce58704663cc6422e5da1284fafe04d5e0224 100644 (file)
@@ -14,7 +14,7 @@ use Friendica\Util\Strings;
  */
 class Help extends BaseModule
 {
-       public static function content()
+       public static function content(array $parameters = [])
        {
                Nav::setSelected('help');
 
index 5a1dccde2a7bd0e47c3e8dc55941454d3ff6949f..e6fb8c349669b241f53b702300c65a22da60f4d1 100644 (file)
@@ -12,7 +12,7 @@ use Friendica\Core\Renderer;
  */
 class Home extends BaseModule
 {
-       public static function content()
+       public static function content(array $parameters = [])
        {
                $app = self::getApp();
                $config = $app->getConfig();
index 2cc273b139910c647a141b42bcf484fcdcd58fee..8ab169567e021087782b2655935b53f9f0f2de42 100644 (file)
@@ -19,7 +19,7 @@ use Friendica\Util\Network;
  */
 class Inbox extends BaseModule
 {
-       public static function rawContent()
+       public static function rawContent(array $parameters = [])
        {
                $a = self::getApp();
 
index 39d6a062afd438cb47437da531660251e4117f14..71547ad51e4778250fcf84ad2fbc43224fd31cf5 100644 (file)
@@ -46,7 +46,7 @@ class Install extends BaseModule
         */
        private static $installer;
 
-       public static function init()
+       public static function init(array $parameters = [])
        {
                $a = self::getApp();
 
@@ -76,7 +76,7 @@ class Install extends BaseModule
                self::$currentWizardStep = ($_POST['pass'] ?? '') ?: self::SYSTEM_CHECK;
        }
 
-       public static function post()
+       public static function post(array $parameters = [])
        {
                $a           = self::getApp();
                $configCache = $a->getConfigCache();
@@ -149,7 +149,7 @@ class Install extends BaseModule
                }
        }
 
-       public static function content()
+       public static function content(array $parameters = [])
        {
                $a           = self::getApp();
                $configCache = $a->getConfigCache();
index 7860c703c116239074ba0de762993f476a9147cf..cd616001bef04ddfe7f24fb77c7686db7bc0d3e2 100644 (file)
@@ -16,7 +16,7 @@ use Friendica\Util\Strings;
  */
 class Invite extends BaseModule
 {
-       public static function post()
+       public static function post(array $parameters = [])
        {
                if (!local_user()) {
                        throw new HTTPException\ForbiddenException(L10n::t('Permission denied.'));
@@ -104,7 +104,7 @@ class Invite extends BaseModule
                notice(L10n::tt('%d message sent.', '%d messages sent.', $total) . EOL);
        }
 
-       public static function content()
+       public static function content(array $parameters = [])
        {
                if (!local_user()) {
                        throw new HTTPException\ForbiddenException(L10n::t('Permission denied.'));
index c44e4c61ab8f66eef3afc77276f43569fa2a9d19..ad0a2d805cc6fd70199b949f87f575cd9edb8be2 100644 (file)
@@ -21,7 +21,7 @@ use Friendica\Util\Crypto;
 
 class Compose extends BaseModule
 {
-       public static function post()
+       public static function post(array $parameters = [])
        {
                if (!empty($_REQUEST['body'])) {
                        $_REQUEST['return'] = 'network';
@@ -32,7 +32,7 @@ class Compose extends BaseModule
                }
        }
 
-       public static function content()
+       public static function content(array $parameters = [])
        {
                if (!local_user()) {
                        return Login::form('compose', false);
index 6a28310b401146e8a4db4f5c749575d8b244a7c5..4590bc8c84c80e3cadc8e2a2962fe7462ce7837f 100644 (file)
@@ -16,7 +16,7 @@ use Friendica\Network\HTTPException;
  */
 class Ignore extends BaseModule
 {
-       public static function rawContent()
+       public static function rawContent(array $parameters = [])
        {
                /** @var L10n $l10n */
                $l10n = self::getClass(L10n::class);
index cc450dd9d0d381e2f7c2df211eb04ff1cc727135..1c98cbc38c6ba6ef0a4c8c0c2df043694f7d3a14 100644 (file)
@@ -13,7 +13,7 @@ use Friendica\Util\Strings;
  */
 class Like extends BaseModule
 {
-       public static function rawContent()
+       public static function rawContent(array $parameters = [])
        {
                if (!Session::isAuthenticated()) {
                        throw new HTTPException\ForbiddenException();
index 0048fefaaebcb6a638b2b344bb082c4aa2d21175..c84af17ccb99483ce42b2347f6215df2e0cb046c 100644 (file)
@@ -30,7 +30,7 @@ use LightOpenID;
  */
 class Login extends BaseModule
 {
-       public static function content()
+       public static function content(array $parameters = [])
        {
                $a = self::getApp();
 
@@ -41,7 +41,7 @@ class Login extends BaseModule
                return self::form(Session::get('return_path'), intval(Config::get('config', 'register_policy')) !== \Friendica\Module\Register::CLOSED);
        }
 
-       public static function post()
+       public static function post(array $parameters = [])
        {
                $openid_identity = Session::get('openid_identity');
                $openid_server = Session::get('openid_server');
index bf6a39e19f961a55a38a64b2e9d8ee5a4ecaa77c..49ede01a3d7a1544c32417ff1606ec36a6ff0cdd 100644 (file)
@@ -23,7 +23,7 @@ class Logout extends BaseModule
        /**
         * @brief Process logout requests
         */
-       public static function init()
+       public static function init(array $parameters = [])
        {
                $visitor_home = null;
                if (remote_user()) {
index b04ea80c04bdd73f84ae90a4b515fa7f02c05dd5..0f610d123c3c0b7a1a2dc9795f9f2c96ddc3b2f4 100644 (file)
@@ -20,7 +20,7 @@ use Friendica\Util\Strings;
  */
 class Magic extends BaseModule
 {
-       public static function init()
+       public static function init(array $parameters = [])
        {
                $a = self::getApp();
                $ret = ['success' => false, 'url' => '', 'message' => ''];
index 24140bb3512e981cdfb6e466e86043357d3d6eb7..056bde7325db78718ae8ca780d38f97d9b30feec 100644 (file)
@@ -14,7 +14,7 @@ use Friendica\Util\Strings;
  */
 class Maintenance extends BaseModule
 {
-       public static function content()
+       public static function content(array $parameters = [])
        {
                $config = self::getApp()->getConfig();
 
index 9dadcf0f76206fa10dc3166939de27b3d92352d2..9e09740594c9a73156d9bc801c34a8d68d29a519 100644 (file)
@@ -7,7 +7,7 @@ use Friendica\Core\Renderer;
 
 class Manifest extends BaseModule
 {
-       public static function rawContent()
+       public static function rawContent(array $parameters = [])
        {
                $app = self::getApp();
                $config = $app->getConfig();
index 3261ef690241b33ddbd47696fb2265c11a1b2a0b..28f23196f9a44417f5aed95b5f51d66d0ec5b169 100644 (file)
@@ -13,7 +13,7 @@ use Friendica\Core\System;
  */
 class NodeInfo extends BaseModule
 {
-       public static function init()
+       public static function init(array $parameters = [])
        {
                $config = self::getApp()->getConfig();
 
@@ -22,7 +22,7 @@ class NodeInfo extends BaseModule
                }
        }
 
-       public static function rawContent()
+       public static function rawContent(array $parameters = [])
        {
                $app = self::getApp();
 
index bad0900ea2540ba65bb4542f0a576fc3d9164c69..721a89a6942a3206aa85ade4354b695c6c02babb 100644 (file)
@@ -14,14 +14,14 @@ use Friendica\Network\HTTPException;
  */
 class Notify extends BaseModule
 {
-       public static function init()
+       public static function init(array $parameters = [])
        {
                if (!local_user()) {
                        throw new HTTPException\UnauthorizedException(L10n::t('Permission denied.'));
                }
        }
 
-       public static function rawContent()
+       public static function rawContent(array $parameters = [])
        {
                $a = self::getApp();
 
@@ -45,7 +45,7 @@ class Notify extends BaseModule
         * @return string|void
         * @throws HTTPException\InternalServerErrorException
         */
-       public static function content()
+       public static function content(array $parameters = [])
        {
                $a = self::getApp();
 
index 2104e8042fd98e3c2cc9f7bc57eb9782a7627826..5538be18889910c035ec0c83275ef69d6e3b7035 100644 (file)
@@ -15,7 +15,7 @@ use Friendica\Protocol\ActivityPub;
  */
 class Objects extends BaseModule
 {
-       public static function rawContent()
+       public static function rawContent(array $parameters = [])
        {
                $a = self::getApp();
 
index 0107782122b5c0c877025d09805eca4a22794315..f9d928428169d4def9383fb56c08272af40e2d1b 100644 (file)
@@ -17,7 +17,7 @@ use Friendica\Util\Strings;
  */
 class Oembed extends BaseModule
 {
-       public static function content()
+       public static function content(array $parameters = [])
        {
                $a = self::getApp();
 
index ff005bd56b6d4a9c31743464e16ed86112ac8a67..309db6af950c5b2ae5f64313e5627377a21bd659 100644 (file)
@@ -16,7 +16,7 @@ class OpenSearch extends BaseModule
        /**
         * @throws \Exception
         */
-       public static function rawContent()
+       public static function rawContent(array $parameters = [])
        {
                header('Content-type: application/opensearchdescription+xml');
 
index 4fc05076310ad2593fb6dff4d469b9c243eb6da1..c2024151e5b0fe7059a51d3077aaa43f944c5204 100644 (file)
@@ -14,7 +14,7 @@ use Friendica\Protocol\ActivityPub;
  */
 class Outbox extends BaseModule
 {
-       public static function rawContent()
+       public static function rawContent(array $parameters = [])
        {
                $a = self::getApp();
 
index 7243c111344b4d159e5fa6d5a86b701936ecd241..ca4eec47ffad0f2cfd94624b15cd9d638ef47ac7 100644 (file)
@@ -27,7 +27,7 @@ use Friendica\Util\Strings;
  */
 class Owa extends BaseModule
 {
-       public static function init()
+       public static function init(array $parameters = [])
        {
 
                $ret = [ 'success' => false ];
index 4ec4f204c3c4efee2973ca7f94454fbe479ba9a9..9987c38f517041224be88a2895ed961e0b83dbb9 100644 (file)
@@ -23,7 +23,7 @@ class Photo extends BaseModule
         * Fetch a photo or an avatar, in optional size, check for permissions and
         * return the image
         */
-       public static function init()
+       public static function init(array $parameters = [])
        {
                $a = self::getApp();
                // @TODO: Replace with parameter from router
diff --git a/src/Module/Pinned.php b/src/Module/Pinned.php
new file mode 100644 (file)
index 0000000..e4c0d2b
--- /dev/null
@@ -0,0 +1,40 @@
+<?php
+
+namespace Friendica\Module;
+
+use Friendica\BaseModule;
+use Friendica\Model\Item;
+
+/**
+ * Toggle pinned items
+ */
+class Pinned extends BaseModule
+{
+       public static function rawContent(array $parameters = [])
+       {
+               if (!local_user()) {
+                       throw new \Friendica\Network\HTTPException\ForbiddenException();
+               }
+
+               if (empty($parameters['item'])) {
+                       throw new \Friendica\Network\HTTPException\BadRequestException();
+               }
+
+               $itemId = intval($parameters['item']);
+
+               $pinned = !Item::getPinned($itemId, local_user());
+
+               Item::setPinned($itemId, local_user(), $pinned);
+
+               // See if we've been passed a return path to redirect to
+               $returnPath = $_REQUEST['return'] ?? '';
+               if (!empty($returnPath)) {
+                       $rand = '_=' . time() . (strpos($returnPath, '?') ? '&' : '?') . 'rand';
+                       self::getApp()->internalRedirect($returnPath . $rand);
+               }
+
+               // the json doesn't really matter, it will either be 0 or 1
+               echo json_encode((int)$pinned);
+               exit();
+       }
+}
index f38c77f2cdcb5d8ba79d8484af15f8325da4e7e9..aab5918567fbab92582531c7967e1ced93bc32d1 100644 (file)
@@ -33,7 +33,7 @@ class Profile extends BaseModule
        public static $which = '';
        public static $profile = 0;
 
-       public static function init()
+       public static function init(array $parameters = [])
        {
                $a = self::getApp();
 
@@ -51,7 +51,7 @@ class Profile extends BaseModule
                }
        }
 
-       public static function rawContent()
+       public static function rawContent(array $parameters = [])
        {
                if (ActivityPub::isRequest()) {
                        $user = DBA::selectFirst('user', ['uid'], ['nickname' => self::$which]);
@@ -75,7 +75,7 @@ class Profile extends BaseModule
                }
        }
 
-       public static function content($update = 0)
+       public static function content(array $parameters = [], $update = 0)
        {
                $a = self::getApp();
 
@@ -177,7 +177,7 @@ class Profile extends BaseModule
                }
 
                if (!$update) {
-            $tab = Strings::escapeTags(trim($_GET['tab'] ?? ''));
+                       $tab = Strings::escapeTags(trim($_GET['tab'] ?? ''));
 
                        $o .= ProfileModel::getTabs($a, $tab, $is_owner, $a->profile['nickname']);
 
@@ -349,7 +349,13 @@ class Profile extends BaseModule
 
                $items = DBA::toArray($items_stmt);
 
-               $o .= conversation($a, $items, $pager, 'profile', $update, false, 'received', $a->profile['profile_uid']);
+               if ($pager->getStart() == 0 && !empty($a->profile['profile_uid'])) {
+                       $pinned_items = Item::selectPinned($a->profile['profile_uid'], ['uri', 'pinned'], ['true' . $sql_extra]);
+                       $pinned = Item::inArray($pinned_items);
+                       $items = array_merge($items, $pinned);
+               }
+
+               $o .= conversation($a, $items, $pager, 'profile', $update, false, 'pinned_received', $a->profile['profile_uid']);
 
                if (!$update) {
                        $o .= $pager->renderMinimal(count($items));
index 1bf88d7c5b820b7da0741f0674d7d5740cc057e7..8069248f82f632974cc4b839d210d8399925dcec 100644 (file)
@@ -18,7 +18,7 @@ use Friendica\Util\Proxy as ProxyUtils;
 
 class Contacts extends BaseModule
 {
-       public static function content()
+       public static function content(array $parameters = [])
        {
                if (Config::get('system', 'block_public') && !Session::isAuthenticated()) {
                        throw new \Friendica\Network\HTTPException\NotFoundException(L10n::t('User not found.'));
index 2b8ad01ddadfd9cd89346ceec962350850845ff5..fbf4b8bd5cbfea81a6e216e583e016f160571820 100644 (file)
@@ -30,7 +30,7 @@ class Proxy extends BaseModule
         * Sets application instance and checks if /proxy/ path is writable.
         *
         */
-       public static function init()
+       public static function init(array $parameters = [])
        {
                // Set application instance here
                $a = self::getApp();
index ed099616ad41126a69ec0b41a11e92edbf888ec4..f652811b54bd5a7b1d417d6359e4ff1eabf1848c 100644 (file)
@@ -12,7 +12,7 @@ use Friendica\Network\HTTPException\BadRequestException;
  */
 class PublicRSAKey extends BaseModule
 {
-       public static function rawContent()
+       public static function rawContent(array $parameters = [])
        {
                $app = self::getApp();
 
index 3ecaa54b7607bc51f32099997380cd47defc64bc..c5b31afeef2e176d7e264171a3f3cf1844e868ba 100644 (file)
@@ -11,7 +11,7 @@ use Friendica\Model\GContact;
  */
 class RandomProfile extends BaseModule
 {
-       public static function content()
+       public static function content(array $parameters = [])
        {
                $a = self::getApp();
 
index 515285dbfcd070b1ba2417b9021d73c55c1ad35d..7cf0db6c7b965d6ac4b4507d628ee74468b1e912 100644 (file)
@@ -11,7 +11,7 @@ use Friendica\Util\XML;
  */
 class ReallySimpleDiscovery extends BaseModule
 {
-       public static function rawContent()
+       public static function rawContent(array $parameters = [])
        {
                header('Content-Type: text/xml');
 
index 03f9dbb69871dd44fb666b778fabede9aa6a2cfd..ad49555e699d77bd4aa06b24b085c977756e9a9a 100644 (file)
@@ -35,7 +35,7 @@ class Register extends BaseModule
         *
         * @return string
         */
-       public static function content()
+       public static function content(array $parameters = [])
        {
                // logged in users can register others (people/pages/groups)
                // even with closed registrations, unless specifically prohibited by site policy.
@@ -152,7 +152,7 @@ class Register extends BaseModule
         * Extend this method if the module is supposed to process POST requests.
         * Doesn't display any content
         */
-       public static function post()
+       public static function post(array $parameters = [])
        {
                BaseModule::checkFormSecurityTokenRedirectOnError('/register', 'register');
 
@@ -261,6 +261,11 @@ class Register extends BaseModule
 
                                $a->internalRedirect('register/');
                        }
+                       // Is there text in the tar pit?
+                       if (!empty($_POST['registertarpit'])) {
+                               \notice(L10n::t('You have entered too much information.'));
+                               $a->internalRedirect('register/');
+                       }
 
                        Model\Register::createForApproval($user['uid'], Config::get('system', 'language'), $_POST['permonlybox']);
 
index 635056a0ad999348483233daa23ad3d46d57288a..db83777e8e4ff02e3d8c597c78623eadd91580fc 100644 (file)
@@ -9,7 +9,7 @@ use Friendica\BaseModule;
  */
 class RobotsTxt extends BaseModule
 {
-       public static function rawContent()
+       public static function rawContent(array $parameters = [])
        {
                $allDisalloweds = [
                        '/settings/',
index 1016756008973291dca02bba042ac73454f950fe..74ce55fb53597a66d29ba705a3ded9458d3acdd0 100644 (file)
@@ -31,7 +31,7 @@ class Acl extends BaseModule
        const TYPE_PRIVATE_MESSAGE       = 'm';
        const TYPE_ANY_CONTACT           = 'a';
 
-       public static function rawContent()
+       public static function rawContent(array $parameters = [])
        {
                if (!local_user()) {
                        throw new HTTPException\UnauthorizedException(L10n::t('You must be logged in to use this module.'));
index 405fb0cc8246c313b914526420ddcf7c7ae9ed50..b18847afe9b41edb629a292c2a635208b582a717 100644 (file)
@@ -13,7 +13,7 @@ use Friendica\Util\Strings;
  */
 class Directory extends BaseSearchModule
 {
-       public static function content()
+       public static function content(array $parameters = [])
        {
                if (!local_user()) {
                        notice(L10n::t('Permission denied.'));
index 73de090a71acb429e32100ff67d66e607e116074..7c52c7e79de1d07f188dccd5531835e6ca82226f 100644 (file)
@@ -23,7 +23,7 @@ use Friendica\Util\Strings;
 
 class Index extends BaseSearchModule
 {
-       public static function content()
+       public static function content(array $parameters = [])
        {
                $search = (!empty($_GET['q']) ? Strings::escapeTags(trim(rawurldecode($_GET['q']))) : '');
 
index 9d8d84b55a9bb10337af8801500435e1e36f723a..88668272de313a56cbb939d77a2440df58f23629 100644 (file)
@@ -10,7 +10,7 @@ use Friendica\Util\Strings;
 
 class Saved extends BaseModule
 {
-       public static function init()
+       public static function init(array $parameters = [])
        {
                /** @var Arguments $args */
                $args = self::getClass(Arguments::class);
index f7edc72c946b84027a4a5ebf162afc0d2f81578a..e3c2b8d34c8a70df38cc4b5649c73d00969b5d06 100644 (file)
@@ -20,7 +20,7 @@ use Friendica\Util\Strings;
  */
 class Delegation extends BaseSettingsModule
 {
-       public static function post()
+       public static function post(array $parameters = [])
        {
                if (!local_user() || !empty(self::getApp()->user['uid']) && self::getApp()->user['uid'] != local_user()) {
                        throw new HTTPException\ForbiddenException(L10n::t('Permission denied.'));
@@ -46,9 +46,9 @@ class Delegation extends BaseSettingsModule
                DBA::update('user', ['parent-uid' => $parent_uid], ['uid' => local_user()]);
        }
 
-       public static function content()
+       public static function content(array $parameters = [])
        {
-               parent::content();
+               parent::content($parameters);
 
                if (!local_user()) {
                        throw new HTTPException\ForbiddenException(L10n::t('Permission denied.'));
index c62b0bbff0e00851797ccfc036312b00bcf0472f..72b233f422f094483c9fa9ebfc93fff1dc999a72 100644 (file)
@@ -20,7 +20,7 @@ class AppSpecific extends BaseSettingsModule
 {
        private static $appSpecificPassword = null;
 
-       public static function init()
+       public static function init(array $parameters = [])
        {
                if (!local_user()) {
                        return;
@@ -38,7 +38,7 @@ class AppSpecific extends BaseSettingsModule
                }
        }
 
-       public static function post()
+       public static function post(array $parameters = [])
        {
                if (!local_user()) {
                        return;
@@ -81,13 +81,13 @@ class AppSpecific extends BaseSettingsModule
                }
        }
 
-       public static function content()
+       public static function content(array $parameters = [])
        {
                if (!local_user()) {
                        return Login::form('settings/2fa/app_specific');
                }
 
-               parent::content();
+               parent::content($parameters);
 
                $appSpecificPasswords = AppSpecificPassword::getListForUser(local_user());
 
index e7694225c43f9bb3ef607e42bc7bf50d838c1a80..34d6f97b49c0092e5c0425872795e192bc3402d2 100644 (file)
@@ -17,7 +17,7 @@ use PragmaRX\Google2FA\Google2FA;
 
 class Index extends BaseSettingsModule
 {
-       public static function post()
+       public static function post(array $parameters = [])
        {
                if (!local_user()) {
                        return;
@@ -73,13 +73,13 @@ class Index extends BaseSettingsModule
                }
        }
 
-       public static function content()
+       public static function content(array $parameters = [])
        {
                if (!local_user()) {
                        return Login::form('settings/2fa');
                }
 
-               parent::content();
+               parent::content($parameters);
 
                $has_secret = (bool) PConfig::get(local_user(), '2fa', 'secret');
                $verified = PConfig::get(local_user(), '2fa', 'verified');
index 6937fa503f4eec65a0bc3bfe92cb8fff668d84c5..0d7de7d9023a0eccdb3c60196e41e82facb54fdb 100644 (file)
@@ -18,7 +18,7 @@ use Friendica\Module\Login;
  */
 class Recovery extends BaseSettingsModule
 {
-       public static function init()
+       public static function init(array $parameters = [])
        {
                if (!local_user()) {
                        return;
@@ -36,7 +36,7 @@ class Recovery extends BaseSettingsModule
                }
        }
 
-       public static function post()
+       public static function post(array $parameters = [])
        {
                if (!local_user()) {
                        return;
@@ -53,13 +53,13 @@ class Recovery extends BaseSettingsModule
                }
        }
 
-       public static function content()
+       public static function content(array $parameters = [])
        {
                if (!local_user()) {
                        return Login::form('settings/2fa/recovery');
                }
 
-               parent::content();
+               parent::content($parameters);
 
                if (!RecoveryCode::countValidForUser(local_user())) {
                        RecoveryCode::generateForUser(local_user());
index b9205852d835199170a6ac79c2a14d2c5d91ebcd..63c186e3a8f6129a613607ac77dbcb9d65c15a44 100644 (file)
@@ -24,7 +24,7 @@ use PragmaRX\Google2FA\Google2FA;
  */
 class Verify extends BaseSettingsModule
 {
-       public static function init()
+       public static function init(array $parameters = [])
        {
                if (!local_user()) {
                        return;
@@ -43,7 +43,7 @@ class Verify extends BaseSettingsModule
                }
        }
 
-       public static function post()
+       public static function post(array $parameters = [])
        {
                if (!local_user()) {
                        return;
@@ -69,13 +69,13 @@ class Verify extends BaseSettingsModule
                }
        }
 
-       public static function content()
+       public static function content(array $parameters = [])
        {
                if (!local_user()) {
                        return Login::form('settings/2fa/verify');
                }
 
-               parent::content();
+               parent::content($parameters);
 
                $company = 'Friendica';
                $holder = Session::get('my_address');
diff --git a/src/Module/Settings/UserExport.php b/src/Module/Settings/UserExport.php
new file mode 100644 (file)
index 0000000..19722a1
--- /dev/null
@@ -0,0 +1,236 @@
+<?php
+/**
+ * @file src/Modules/Settings/UserExport.php
+ */
+
+namespace Friendica\Module\Settings;
+
+use Friendica\App;
+use Friendica\App\Arguments;
+use Friendica\BaseModule;
+use Friendica\Core\Hook;
+use Friendica\Core\L10n;
+use Friendica\Core\Renderer;
+use Friendica\Core\System;
+use Friendica\Database\DBA;
+use Friendica\Database\DBStructure;
+use Friendica\Module\BaseSettingsModule;
+
+/**
+ * Module to export user data
+ **/
+class UserExport extends BaseSettingsModule
+{
+       /**
+        * Handle the request to export data.
+        * At the moment one can export three different data set
+        * 1. The profile data that can be used by uimport to resettle
+        *    to a different Friendica instance
+        * 2. The entire data-set, profile plus postings
+        * 3. A list of contacts as CSV file similar to the export of Mastodon
+        *
+        * If there is an action required through the URL / path, react
+        * accordingly and export the requested data.
+        **/
+       public static function content(array $parameters = [])
+       {
+               parent::content($parameters);
+
+               /**
+                * options shown on "Export personal data" page
+                * list of array( 'link url', 'link text', 'help text' )
+                */
+               $options = [
+                       ['settings/userexport/account', L10n::t('Export account'), L10n::t('Export your account info and contacts. Use this to make a backup of your account and/or to move it to another server.')],
+                       ['settings/userexport/backup', L10n::t('Export all'), L10n::t("Export your accout info, contacts and all your items as json. Could be a very big file, and could take a lot of time. Use this to make a full backup of your account \x28photos are not exported\x29")],
+                       ['settings/userexport/contact', L10n::t('Export Contacts to CSV'), L10n::t("Export the list of the accounts you are following as CSV file. Compatible to e.g. Mastodon.")],
+               ];
+               Hook::callAll('uexport_options', $options);
+
+               $tpl = Renderer::getMarkupTemplate("settings/userexport.tpl");
+               return Renderer::replaceMacros($tpl, [
+                       '$title' => L10n::t('Export personal data'),
+                       '$options' => $options
+               ]);
+       }
+       /**
+        * raw content generated for the different choices made
+        * by the user. At the moment this returns a JSON file
+        * to the browser which then offers a save / open dialog
+        * to the user.
+        **/
+       public static function rawContent(array $parameters = [])
+       {
+               $args = self::getClass(Arguments::class);
+               if ($args->getArgc() == 3) {
+                       // @TODO Replace with router-provided arguments
+                       $action = $args->get(2);
+                       $user = self::getApp()->user;
+                       switch ($action) {
+                               case "backup":
+                                       header("Content-type: application/json");
+                                       header('Content-Disposition: attachment; filename="' . $user['nickname'] . '.' . $action . '"');
+                                       self::exportAll(self::getApp());
+                                       exit();
+                                       break;
+                               case "account":
+                                       header("Content-type: application/json");
+                                       header('Content-Disposition: attachment; filename="' . $user['nickname'] . '.' . $action . '"');
+                                       self::exportAccount(self::getApp());
+                                       exit();
+                                       break;
+                               case "contact":
+                                       header("Content-type: application/csv");
+                                       header('Content-Disposition: attachment; filename="' . $user['nickname'] . '-contacts.csv'. '"');
+                                       self::exportContactsAsCSV();
+                                       exit();
+                                       break;
+                               default:
+                                       exit();
+                       }
+               }
+       }
+       private static function exportMultiRow(string $query)
+       {
+               $dbStructure = DBStructure::definition(self::getApp()->getBasePath(), false);
+
+               preg_match("/\s+from\s+`?([a-z\d_]+)`?/i", $query, $match);
+               $table = $match[1];
+
+               $result = [];
+               $rows = DBA::p($query);
+               while ($row = DBA::fetch($rows)) {
+                       $p = [];
+                       foreach ($row as $k => $v) {
+                               switch ($dbStructure[$table]['fields'][$k]['type']) {
+                                       case 'datetime':
+                                               $p[$k] = $v ?? DBA::NULL_DATETIME;
+                                               break;
+                                       default:
+                                               $p[$k] = $v;
+                                               break;
+                               }
+                       }
+                       $result[] = $p;
+               }
+               DBA::close($rows);
+               return $result;
+       }
+
+       private static function exportRow(string $query)
+       {
+               $dbStructure = DBStructure::definition(self::getApp()->getBasePath(), false);
+
+               preg_match("/\s+from\s+`?([a-z\d_]+)`?/i", $query, $match);
+               $table = $match[1];
+
+               $result = [];
+               $r = q($query);
+               if (DBA::isResult($r)) {
+
+                       foreach ($r as $rr) {
+                               foreach ($rr as $k => $v) {
+                                       switch ($dbStructure[$table]['fields'][$k]['type']) {
+                                               case 'datetime':
+                                                       $result[$k] = $v ?? DBA::NULL_DATETIME;
+                                                       break;
+                                               default:
+                                                       $result[$k] = $v;
+                                                       break;
+                                       }
+                               }
+                       }
+               }
+               return $result;
+       }
+
+       /**
+        * Export a list of the contacts as CSV file as e.g. Mastodon and Pleroma are doing.
+        **/
+       private static function exportContactsAsCSV()
+       {
+               // write the table header (like Mastodon)
+               echo "Account address, Show boosts\n";
+               // get all the contacts
+               $contacts = DBA::select('contact', ['addr'], ['uid' => $_SESSION['uid'], 'self' => false, 'rel' => [1,3], 'deleted' => false]);
+               while ($contact = DBA::fetch($contacts)) {
+                       echo $contact['addr'] . ", true\n";
+               }
+               DBA::close($contacts);
+       }
+       private static function exportAccount(App $a)
+       {
+               $user = self::exportRow(
+                       sprintf("SELECT * FROM `user` WHERE `uid` = %d LIMIT 1", intval(local_user()))
+               );
+
+               $contact = self::exportMultiRow(
+                       sprintf("SELECT * FROM `contact` WHERE `uid` = %d ", intval(local_user()))
+               );
+
+
+               $profile = self::exportMultiRow(
+                       sprintf("SELECT * FROM `profile` WHERE `uid` = %d ", intval(local_user()))
+               );
+
+               $photo = self::exportMultiRow(
+                       sprintf("SELECT * FROM `photo` WHERE uid = %d AND profile = 1", intval(local_user()))
+               );
+               foreach ($photo as &$p) {
+                       $p['data'] = bin2hex($p['data']);
+               }
+
+               $pconfig = self::exportMultiRow(
+                       sprintf("SELECT * FROM `pconfig` WHERE uid = %d", intval(local_user()))
+               );
+
+               $group = self::exportMultiRow(
+                       sprintf("SELECT * FROM `group` WHERE uid = %d", intval(local_user()))
+               );
+
+               $group_member = self::exportMultiRow(
+                       sprintf("SELECT `group_member`.`gid`, `group_member`.`contact-id` FROM `group_member` INNER JOIN `group` ON `group`.`id` = `group_member`.`gid` WHERE `group`.`uid` = %d", intval(local_user()))
+               );
+
+               $output = [
+                       'version' => FRIENDICA_VERSION,
+                       'schema' => DB_UPDATE_VERSION,
+                       'baseurl' => System::baseUrl(),
+                       'user' => $user,
+                       'contact' => $contact,
+                       'profile' => $profile,
+                       'photo' => $photo,
+                       'pconfig' => $pconfig,
+                       'group' => $group,
+                       'group_member' => $group_member,
+               ];
+
+               echo json_encode($output, JSON_PARTIAL_OUTPUT_ON_ERROR);
+       }
+
+       /**
+        * echoes account data and items as separated json, one per line
+        *
+        * @param App $a
+        * @throws Exception
+        */
+       private static function exportAll(App $a)
+       {
+               self::exportAccount($a);
+               echo "\n";
+
+               $total = DBA::count('item', ['uid' => local_user()]);
+               // chunk the output to avoid exhausting memory
+
+               for ($x = 0; $x < $total; $x += 500) {
+                       $r = q("SELECT * FROM `item` WHERE `uid` = %d LIMIT %d, %d",
+                               intval(local_user()),
+                               intval($x),
+                               intval(500)
+                       );
+
+                       $output = ['item' => $r];
+                       echo json_encode($output, JSON_PARTIAL_OUTPUT_ON_ERROR). "\n";
+               }
+       }
+}
index ded58768fe347cf7f6913eb4a00c3c8e66637abf..a808ce820c2305a8233c3674c1f3e782acc4c08f 100644 (file)
@@ -12,7 +12,7 @@ use Friendica\Core\System;
  */
 class Smilies extends BaseModule
 {
-       public static function rawContent()
+       public static function rawContent(array $parameters = [])
        {
                $app = self::getApp();
 
@@ -26,7 +26,7 @@ class Smilies extends BaseModule
                }
        }
 
-       public static function content()
+       public static function content(array $parameters = [])
        {
                $smilies = Content\Smilies::getList();
                $count = count($smilies['texts'] ?? []);
index 70cd3973518a81584604b2ef68439701a5fcfb7e..c1fa4c3b8be318df533003a9c581d0ee24da8540 100644 (file)
@@ -10,51 +10,36 @@ use Friendica\Model\Item;
  */
 class Starred extends BaseModule
 {
-       public static function rawContent()
+       public static function rawContent(array $parameters = [])
        {
-               $a = self::getApp();
-               $starred = 0;
-               $itemId = null;
-
                if (!local_user()) {
-                       exit();
+                       throw new \Friendica\Network\HTTPException\ForbiddenException();
                }
 
-               // @TODO: Replace with parameter from router
-               if ($a->argc > 1) {
-                       $itemId = intval($a->argv[1]);
+               if (empty($parameters['item'])) {
+                       throw new \Friendica\Network\HTTPException\BadRequestException();
                }
 
-               if (!$itemId) {
-                       exit();
-               }
+               $itemId = intval($parameters['item']);
 
                $item = Item::selectFirstForUser(local_user(), ['starred'], ['uid' => local_user(), 'id' => $itemId]);
                if (empty($item)) {
-                       exit();
+                       throw new \Friendica\Network\HTTPException\NotFoundException();
                }
 
-               if (!intval($item['starred'])) {
-                       $starred = 1;
-               }
+               $starred = !(bool)$item['starred'];
 
                Item::update(['starred' => $starred], ['id' => $itemId]);
 
                // See if we've been passed a return path to redirect to
                $returnPath = $_REQUEST['return'] ?? '';
-               if ($returnPath) {
-                       $rand = '_=' . time();
-                       if (strpos($returnPath, '?')) {
-                               $rand = "&$rand";
-                       } else {
-                               $rand = "?$rand";
-                       }
-
-                       $a->internalRedirect($returnPath . $rand);
+               if (!empty($returnPath)) {
+                       $rand = '_=' . time() . (strpos($returnPath, '?') ? '&' : '?') . 'rand';
+                       self::getApp()->internalRedirect($returnPath . $rand);
                }
 
                // the json doesn't really matter, it will either be 0 or 1
-               echo json_encode($starred);
+               echo json_encode((int)$starred);
                exit();
        }
 }
index 3e64828e7b64b3dfe33897d9dad3dd85e703b4f7..6e599ac9b1fc3d0602f5bc43638d2ab6936e2a74 100644 (file)
@@ -8,7 +8,7 @@ use Friendica\Core\System;
 
 class Statistics extends BaseModule
 {
-       public static function init()
+       public static function init(array $parameters = [])
        {
                $config = self::getApp()->getConfig();
 
@@ -17,7 +17,7 @@ class Statistics extends BaseModule
                }
        }
 
-       public static function rawContent()
+       public static function rawContent(array $parameters = [])
        {
                $config = self::getApp()->getConfig();
                $logger = self::getApp()->getLogger();
index 0540267af71787ab759b487ea5576bd8aeca3406..e9ce8d396f239cf63d9becfc4e91105ef39c0f4b 100644 (file)
@@ -10,7 +10,7 @@ use Friendica\Util\Strings;
  */
 class Theme extends BaseModule
 {
-       public static function rawContent()
+       public static function rawContent(array $parameters = [])
        {
                header("Content-Type: text/css");
 
index 9a2e913bcad00e7cd58144b226eb65ddbcc95f89..40bfb7a87189889d1ed893cd3d114ddc637ac22b 100644 (file)
@@ -10,7 +10,7 @@ use Friendica\Core\Theme;
  */
 class ThemeDetails extends BaseModule
 {
-       public static function rawContent()
+       public static function rawContent(array $parameters = [])
        {
                if (!empty($_REQUEST['theme'])) {
                        $theme = $_REQUEST['theme'];
index 9788c0b5db40700021a07aa7c65a84bfb46ac85c..0efc2e54b5fa3d492fb2906f47c83c527dc17cf5 100644 (file)
@@ -9,7 +9,7 @@ use Friendica\BaseModule;
  */
 class ToggleMobile extends BaseModule
 {
-       public static function content()
+       public static function content(array $parameters = [])
        {
                $a = self::getApp();
 
index 6dca554b25a593c6bc44a885c380d4ab52483525..ea29a5e072d3ab6b14b56bfef3a66fb8075aa040 100644 (file)
@@ -34,7 +34,7 @@ class Tos extends BaseModule
        {
                $this->privacy_operate = L10n::t('At the time of registration, and for providing communications between the user account and their contacts, the user has to provide a display name (pen name), an username (nickname) and a working email address. The names will be accessible on the profile page of the account by any visitor of the page, even if other profile details are not displayed. The email address will only be used to send the user notifications about interactions, but wont be visibly displayed. The listing of an account in the node\'s user directory or the global user directory is optional and can be controlled in the user settings, it is not necessary for communication.');
                $this->privacy_distribute = L10n::t('This data is required for communication and is passed on to the nodes of the communication partners and is stored there. Users can enter additional private data that may be transmitted to the communication partners accounts.');
-               $this->privacy_delete = L10n::t('At any point in time a logged in user can export their account data from the <a href="%1$s/settings/uexport">account settings</a>. If the user wants to delete their account they can do so at <a href="%1$s/removeme">%1$s/removeme</a>. The deletion of the account will be permanent. Deletion of the data will also be requested from the nodes of the communication partners.', System::baseurl());
+               $this->privacy_delete = L10n::t('At any point in time a logged in user can export their account data from the <a href="%1$s/settings/userexport">account settings</a>. If the user wants to delete their account they can do so at <a href="%1$s/removeme">%1$s/removeme</a>. The deletion of the account will be permanent. Deletion of the data will also be requested from the nodes of the communication partners.', System::baseurl());
                // In some cases we don't need every single one of the above separate, but all in one block.
                // So here is an array to look over
                $this->privacy_complete = [L10n::t('Privacy Statement'), $this->privacy_operate, $this->privacy_distribute, $this->privacy_delete];
@@ -47,7 +47,7 @@ class Tos extends BaseModule
         * dealings with their own node so a TOS is not necessary.
         *
         **/
-       public static function init()
+       public static function init(array $parameters = [])
        {
                if (strlen(Config::get('system','singleuser'))) {
                        self::getApp()->internalRedirect('profile/' . Config::get('system','singleuser'));
@@ -66,7 +66,7 @@ class Tos extends BaseModule
         * @return string
         * @throws \Friendica\Network\HTTPException\InternalServerErrorException
         */
-       public static function content() {
+       public static function content(array $parameters = []) {
                $tpl = Renderer::getMarkupTemplate('tos.tpl');
                if (Config::get('system', 'tosdisplay')) {
                        return Renderer::replaceMacros($tpl, [
@@ -76,7 +76,7 @@ class Tos extends BaseModule
                                '$privstatementtitle' => L10n::t('Privacy Statement'),
                                '$privacy_operate' => L10n::t('At the time of registration, and for providing communications between the user account and their contacts, the user has to provide a display name (pen name), an username (nickname) and a working email address. The names will be accessible on the profile page of the account by any visitor of the page, even if other profile details are not displayed. The email address will only be used to send the user notifications about interactions, but wont be visibly displayed. The listing of an account in the node\'s user directory or the global user directory is optional and can be controlled in the user settings, it is not necessary for communication.'),
                                '$privacy_distribute' => L10n::t('This data is required for communication and is passed on to the nodes of the communication partners and is stored there. Users can enter additional private data that may be transmitted to the communication partners accounts.'),
-                               '$privacy_delete' => L10n::t('At any point in time a logged in user can export their account data from the <a href="%1$s/settings/uexport">account settings</a>. If the user wants to delete their account they can do so at <a href="%1$s/removeme">%1$s/removeme</a>. The deletion of the account will be permanent. Deletion of the data will also be requested from the nodes of the communication partners.', System::baseurl())
+                               '$privacy_delete' => L10n::t('At any point in time a logged in user can export their account data from the <a href="%1$s/settings/userexport">account settings</a>. If the user wants to delete their account they can do so at <a href="%1$s/removeme">%1$s/removeme</a>. The deletion of the account will be permanent. Deletion of the data will also be requested from the nodes of the communication partners.', System::baseurl())
                        ]);
                } else {
                        return;
index 7c17fdace028893003c69bfd61057522b810d38e..bd87836463c7f9df4800868861340a96a3248bc9 100644 (file)
@@ -15,14 +15,14 @@ use Friendica\Model\TwoFactor\RecoveryCode;
  */
 class Recovery extends BaseModule
 {
-       public static function init()
+       public static function init(array $parameters = [])
        {
                if (!local_user()) {
                        return;
                }
        }
 
-       public static function post()
+       public static function post(array $parameters = [])
        {
                if (!local_user()) {
                        return;
@@ -48,7 +48,7 @@ class Recovery extends BaseModule
                }
        }
 
-       public static function content()
+       public static function content(array $parameters = [])
        {
                if (!local_user()) {
                        self::getApp()->internalRedirect();
index 4b1c974d8ff7ddf84b4f4f5217335960b9244a51..f6f040f5a781f1c9271bb3bf2c17674e60713568 100644 (file)
@@ -18,7 +18,7 @@ class Verify extends BaseModule
 {
        private static $errors = [];
 
-       public static function post()
+       public static function post(array $parameters = [])
        {
                if (!local_user()) {
                        return;
@@ -45,7 +45,7 @@ class Verify extends BaseModule
                }
        }
 
-       public static function content()
+       public static function content(array $parameters = [])
        {
                if (!local_user()) {
                        self::getApp()->internalRedirect();
index 9e1eace9b6ec80cc6d33906b57f2a3ee915018a7..f69991e4968869cc98b1e8bdd597e2e820978de9 100644 (file)
@@ -11,7 +11,7 @@ use Friendica\Core\Renderer;
  */
 class Welcome extends BaseModule
 {
-       public static function content()
+       public static function content(array $parameters = [])
        {
                $config = self::getApp()->getConfig();
 
index fd04467f7536816a50f3c93e21d4dc99f66062f3..cb344b695e35dad1c13473ac520341c11482214d 100644 (file)
@@ -13,7 +13,7 @@ use Friendica\Util\Crypto;
  */
 class HostMeta extends BaseModule
 {
-       public static function rawContent()
+       public static function rawContent(array $parameters = [])
        {
                $app = self::getApp();
                $config = $app->getConfig();
index a1bbeb78aacbe9fdb880e818e1dcecb3c7ef8ddb..5d8f4e817c1c558378fc824f041a2143179baecc 100644 (file)
@@ -11,7 +11,7 @@ use Friendica\Model\Search;
  */
 class XSocialRelay extends BaseModule
 {
-       public static function rawContent()
+       public static function rawContent(array $parameters = [])
        {
                $app = self::getApp();
                $config = $app->getConfig();
index 1028bfd531f3054265d677c1eef698d00445d997..79e0883a872bf10dd026cf8c33f7f374bb8d8c29 100644 (file)
@@ -17,7 +17,7 @@ use Friendica\Util\Strings;
  */
 class Xrd extends BaseModule
 {
-       public static function rawContent()
+       public static function rawContent(array $parameters = [])
        {
                $app = self::getApp();
 
index 803aa08b38f58b7e28da83ce0506769aea38f766..972b48359f6d51b918b46605ed1f236c58a92b76 100644 (file)
@@ -6,11 +6,9 @@
 namespace Friendica\Object;
 
 use Exception;
-use Friendica\Core\Cache;
 use Friendica\Core\Config;
-use Friendica\Core\Logger;
 use Friendica\Core\System;
-use Friendica\Util\Network;
+use Friendica\Util\Images;
 use Imagick;
 use ImagickPixel;
 
@@ -32,31 +30,6 @@ class Image
        private $type;
        private $types;
 
-       /**
-        * @brief supported mimetypes and corresponding file extensions
-        * @return array
-        */
-       public static function supportedTypes()
-       {
-               if (class_exists('Imagick')) {
-                       // Imagick::queryFormats won't help us a lot there...
-                       // At least, not yet, other parts of friendica uses this array
-                       $t = [
-                               'image/jpeg' => 'jpg',
-                               'image/png' => 'png',
-                               'image/gif' => 'gif'
-                       ];
-               } else {
-                       $t = [];
-                       $t['image/jpeg'] ='jpg';
-                       if (imagetypes() & IMG_PNG) {
-                               $t['image/png'] = 'png';
-                       }
-               }
-
-               return $t;
-       }
-
        /**
         * @brief Constructor
         * @param string  $data
@@ -67,9 +40,9 @@ class Image
        public function __construct($data, $type = null)
        {
                $this->imagick = class_exists('Imagick');
-               $this->types = static::supportedTypes();
+               $this->types = Images::supportedTypes();
                if (!array_key_exists($type, $this->types)) {
-                       $type='image/jpeg';
+                       $type = 'image/jpeg';
                }
                $this->type = $type;
 
@@ -108,20 +81,6 @@ class Image
                return $this->imagick;
        }
 
-       /**
-        * @brief Maps Mime types to Imagick formats
-        * @return array With with image formats (mime type as key)
-        */
-       public static function getFormatsMap()
-       {
-               $m = [
-                       'image/jpeg' => 'JPG',
-                       'image/png' => 'PNG',
-                       'image/gif' => 'GIF'
-               ];
-               return $m;
-       }
-
        /**
         * @param string $data data
         * @return boolean
@@ -142,7 +101,7 @@ class Image
                        /*
                         * Setup the image to the format it will be saved to
                         */
-                       $map = self::getFormatsMap();
+                       $map = Images::getFormatsMap();
                        $format = $map[$this->type];
                        $this->image->setFormat($format);
 
@@ -712,6 +671,26 @@ class Image
                return $string;
        }
 
+       /**
+        * @brief supported mimetypes and corresponding file extensions
+        * @return array
+        * @deprecated in version 2019.12 please use Util\Images::supportedTypes() instead.
+        */
+       public static function supportedTypes()
+       {
+               return Images::supportedTypes();
+       }
+
+       /**
+        * @brief Maps Mime types to Imagick formats
+        * @return array With with image formats (mime type as key)
+        * @deprecated in version 2019.12 please use Util\Images::getFormatsMap() instead.
+        */
+       public static function getFormatsMap()
+       {
+               return Images::getFormatsMap();
+       }
+
        /**
         * Guess image mimetype from filename or from Content-Type header
         *
@@ -719,102 +698,24 @@ class Image
         * @param boolean $fromcurl Check Content-Type header from curl request
         * @param string  $header   passed headers to take into account
         *
-        * @return object
-        * @throws \ImagickException
+        * @return string|null
+        * @throws Exception
+        * @deprecated in version 2019.12 please use Util\Images::guessType() instead.
         */
        public static function guessType($filename, $fromcurl = false, $header = '')
        {
-               Logger::log('Image: guessType: '.$filename . ($fromcurl?' from curl headers':''), Logger::DEBUG);
-               $type = null;
-               if ($fromcurl) {
-                       $headers=[];
-                       $h = explode("\n", $header);
-                       foreach ($h as $l) {
-                               $data = array_map("trim", explode(":", trim($l), 2));
-                               if (count($data) > 1) {
-                                       list($k,$v) = $data;
-                                       $headers[$k] = $v;
-                               }
-                       }
-                       if (array_key_exists('Content-Type', $headers))
-                               $type = $headers['Content-Type'];
-               }
-               if (is_null($type)) {
-                       // Guessing from extension? Isn't that... dangerous?
-                       if (class_exists('Imagick') && file_exists($filename) && is_readable($filename)) {
-                               /**
-                                * Well, this not much better,
-                                * but at least it comes from the data inside the image,
-                                * we won't be tricked by a manipulated extension
-                                */
-                               $image = new Imagick($filename);
-                               $type = $image->getImageMimeType();
-                               $image->setInterlaceScheme(Imagick::INTERLACE_PLANE);
-                       } else {
-                               $ext = pathinfo($filename, PATHINFO_EXTENSION);
-                               $types = self::supportedTypes();
-                               $type = "image/jpeg";
-                               foreach ($types as $m => $e) {
-                                       if ($ext == $e) {
-                                               $type = $m;
-                                       }
-                               }
-                       }
-               }
-               Logger::log('Image: guessType: type='.$type, Logger::DEBUG);
-               return $type;
+               return Images::guessType($filename, $fromcurl, $header);
        }
 
        /**
         * @param string $url url
-        * @return object
+        * @return array
         * @throws \Friendica\Network\HTTPException\InternalServerErrorException
+        * @deprecated in version 2019.12 please use Util\Images::getInfoFromURLCached() instead.
         */
        public static function getInfoFromURL($url)
        {
-               $data = [];
-
-               if (empty($url)) {
-                       return $data;
-               }
-
-               $data = Cache::get($url);
-
-               if (is_null($data) || !$data || !is_array($data)) {
-                       $img_str = Network::fetchUrl($url, true, 4);
-
-                       if (!$img_str) {
-                               return false;
-                       }
-
-                       $filesize = strlen($img_str);
-
-                       try {
-                               if (function_exists("getimagesizefromstring")) {
-                                       $data = @getimagesizefromstring($img_str);
-                               } else {
-                                       $tempfile = tempnam(get_temppath(), "cache");
-
-                                       $a = \get_app();
-                                       $stamp1 = microtime(true);
-                                       file_put_contents($tempfile, $img_str);
-                                       $a->getProfiler()->saveTimestamp($stamp1, "file", System::callstack());
-
-                                       $data = getimagesize($tempfile);
-                                       unlink($tempfile);
-                               }
-                       } catch (Exception $e) {
-                               return false;
-                       }
-
-                       if ($data) {
-                               $data["size"] = $filesize;
-                       }
-
-                       Cache::set($url, $data);
-               }
-
-               return $data;
+               return Images::getInfoFromURLCached($url);
        }
 
        /**
@@ -822,50 +723,10 @@ class Image
         * @param integer $height height
         * @param integer $max    max
         * @return array
+        * @deprecated in version 2019.12 please use Util\Images::getScalingDimensions() instead.
         */
        public static function getScalingDimensions($width, $height, $max)
        {
-               if ((!$width) || (!$height)) {
-                       return false;
-               }
-
-               if ($width > $max && $height > $max) {
-                       // very tall image (greater than 16:9)
-                       // constrain the width - let the height float.
-
-                       if ((($height * 9) / 16) > $width) {
-                               $dest_width = $max;
-                               $dest_height = intval(($height * $max) / $width);
-                       } elseif ($width > $height) {
-                               // else constrain both dimensions
-                               $dest_width = $max;
-                               $dest_height = intval(($height * $max) / $width);
-                       } else {
-                               $dest_width = intval(($width * $max) / $height);
-                               $dest_height = $max;
-                       }
-               } else {
-                       if ($width > $max) {
-                               $dest_width = $max;
-                               $dest_height = intval(($height * $max) / $width);
-                       } else {
-                               if ($height > $max) {
-                                       // very tall image (greater than 16:9)
-                                       // but width is OK - don't do anything
-
-                                       if ((($height * 9) / 16) > $width) {
-                                               $dest_width = $width;
-                                               $dest_height = $height;
-                                       } else {
-                                               $dest_width = intval(($width * $max) / $height);
-                                               $dest_height = $max;
-                                       }
-                               } else {
-                                       $dest_width = $width;
-                                       $dest_height = $height;
-                               }
-                       }
-               }
-               return ["width" => $dest_width, "height" => $dest_height];
+               return Images::getScalingDimensions($width, $height, $max);
        }
 }
index babf24e0d6ccd1c1f24ee32fe55de6b65808b534..981bf76c7d6f576423265d9d4ac358f7da542065 100644 (file)
@@ -140,8 +140,11 @@ class Post extends BaseObject
                $sparkle = '';
                $buttons = '';
                $dropping = false;
+               $pinned = '';
+               $pin = false;
                $star = false;
                $ignore = false;
+               $ispinned = "unpinned";
                $isstarred = "unstarred";
                $indent = '';
                $shiny = '';
@@ -190,6 +193,8 @@ class Post extends BaseObject
                        if (DBA::isResult($parent)) {
                                $origin = $parent['origin'];
                        }
+               } elseif ($item['pinned']) {
+                       $pinned = L10n::t('pinned item');
                }
 
                if ($origin && ($item['id'] != $item['parent']) && ($item['network'] == Protocol::ACTIVITYPUB)) {
@@ -284,6 +289,19 @@ class Post extends BaseObject
                                }
 
                                if ($conv->getProfileOwner() == local_user() && ($item['uid'] != 0)) {
+                                       if ($origin) {
+                                               $ispinned = ($item['pinned'] ? 'pinned' : 'unpinned');
+
+                                               $pin = [
+                                                       'do'        => L10n::t('pin'),
+                                                       'undo'      => L10n::t('unpin'),
+                                                       'toggle'    => L10n::t('toggle pin status'),
+                                                       'classdo'   => $item['pinned'] ? 'hidden' : '',
+                                                       'classundo' => $item['pinned'] ? '' : 'hidden',
+                                                       'pinned'   => L10n::t('pinned'),
+                                               ];
+                                       }
+
                                        $isstarred = (($item['starred']) ? "starred" : "unstarred");
 
                                        $star = [
@@ -407,6 +425,9 @@ class Post extends BaseObject
                        'owner_name'      => $owner_name_e,
                        'plink'           => Item::getPlink($item),
                        'edpost'          => $edpost,
+                       'ispinned'        => $ispinned,
+                       'pin'             => $pin,
+                       'pinned'          => $pinned,
                        'isstarred'       => $isstarred,
                        'star'            => $star,
                        'ignore'          => $ignore,
index 531b4c6621d0c9791e18c3f6c60ba1a6697c1560..c5f3bae4700dc90d62e6a09e171c3764c987da13 100644 (file)
@@ -6,31 +6,31 @@ namespace Friendica\Protocol\ActivityPub;
 
 use Friendica\BaseObject;
 use Friendica\Content\Feature;
-use Friendica\Database\DBA;
+use Friendica\Content\Text\BBCode;
+use Friendica\Content\Text\Plaintext;
+use Friendica\Core\Cache;
 use Friendica\Core\Config;
 use Friendica\Core\Logger;
-use Friendica\Core\System;
-use Friendica\Protocol\Activity;
-use Friendica\Util\HTTPSignature;
 use Friendica\Core\Protocol;
-use Friendica\Model\Conversation;
-use Friendica\Model\Contact;
+use Friendica\Core\System;
+use Friendica\Database\DBA;
 use Friendica\Model\APContact;
+use Friendica\Model\Contact;
+use Friendica\Model\Conversation;
 use Friendica\Model\Item;
+use Friendica\Model\Profile;
 use Friendica\Model\Term;
 use Friendica\Model\User;
+use Friendica\Protocol\Activity;
+use Friendica\Protocol\ActivityPub;
 use Friendica\Util\DateTimeFormat;
-use Friendica\Content\Text\BBCode;
-use Friendica\Content\Text\Plaintext;
-use Friendica\Util\XML;
+use Friendica\Util\HTTPSignature;
+use Friendica\Util\Images;
 use Friendica\Util\JsonLD;
 use Friendica\Util\LDSignature;
-use Friendica\Model\Profile;
-use Friendica\Object\Image;
-use Friendica\Protocol\ActivityPub;
-use Friendica\Core\Cache;
 use Friendica\Util\Map;
 use Friendica\Util\Network;
+use Friendica\Util\XML;
 
 require_once 'include/api.php';
 require_once 'mod/share.php';
@@ -1049,7 +1049,7 @@ class Transmitter
                // Grab all pictures without alternative descriptions and create attachments out of them
                if (preg_match_all("/\[img\]([^\[\]]*)\[\/img\]/Usi", $body, $pictures)) {
                        foreach ($pictures[1] as $picture) {
-                               $imgdata = Image::getInfoFromURL($picture);
+                               $imgdata = Images::getInfoFromURLCached($picture);
                                if ($imgdata) {
                                        $attachments[] = ['type' => 'Document',
                                                'mediaType' => $imgdata['mime'],
@@ -1062,7 +1062,7 @@ class Transmitter
                // Grab all pictures with alternative description and create attachments out of them
                if (preg_match_all("/\[img=([^\[\]]*)\]([^\[\]]*)\[\/img\]/Usi", $body, $pictures, PREG_SET_ORDER)) {
                        foreach ($pictures as $picture) {
-                               $imgdata = Image::getInfoFromURL($picture[1]);
+                               $imgdata = Images::getInfoFromURLCached($picture[1]);
                                if ($imgdata) {
                                        $attachments[] = ['type' => 'Document',
                                                'mediaType' => $imgdata['mime'],
index 2016c7339d51e91d19690ffef2acefd2e16e42e3..0b6e02f096118ad37e98076193262a9a9ea59515 100644 (file)
@@ -35,6 +35,7 @@ use Friendica\Object\Image;
 use Friendica\Protocol\ActivityNamespace;
 use Friendica\Util\Crypto;
 use Friendica\Util\DateTimeFormat;
+use Friendica\Util\Images;
 use Friendica\Util\Network;
 use Friendica\Util\Strings;
 use Friendica\Util\XML;
@@ -504,7 +505,7 @@ class DFRN
                        $uid
                );
                $photos = [];
-               $ext = Image::supportedTypes();
+               $ext = Images::supportedTypes();
 
                foreach ($rp as $p) {
                        $photos[$p['scale']] = System::baseUrl().'/photo/'.$p['resource-id'].'-'.$p['scale'].'.'.$ext[$p['type']];
index 3b283504ccadc8f5f665657251e85f0789f741b0..e8c576a94cd09c7dd3cd147a9b3514437d5b989e 100644 (file)
@@ -2476,101 +2476,30 @@ class Diaspora
                        return false;
                }
 
-               $batch = (($ret["batch"]) ? $ret["batch"] : implode("/", array_slice(explode("/", $ret["url"]), 0, 3))."/receive/public");
-
-               q(
-                       "INSERT INTO `contact` (`uid`, `network`,`addr`,`created`,`url`,`nurl`,`batch`,`name`,`nick`,`photo`,`pubkey`,`notify`,`poll`,`blocked`,`priority`)
-                       VALUES (%d, '%s', '%s', '%s', '%s','%s','%s','%s','%s','%s','%s','%s','%s',%d,%d)",
-                       intval($importer["uid"]),
-                       DBA::escape($ret["network"]),
-                       DBA::escape($ret["addr"]),
-                       DateTimeFormat::utcNow(),
-                       DBA::escape($ret["url"]),
-                       DBA::escape(Strings::normaliseLink($ret["url"])),
-                       DBA::escape($batch),
-                       DBA::escape($ret["name"]),
-                       DBA::escape($ret["nick"]),
-                       DBA::escape($ret["photo"]),
-                       DBA::escape($ret["pubkey"]),
-                       DBA::escape($ret["notify"]),
-                       DBA::escape($ret["poll"]),
-                       1,
-                       2
-               );
-
-               // find the contact record we just created
-
-               $contact_record = self::contactByHandle($importer["uid"], $author);
-
-               if (!$contact_record) {
-                       Logger::log("unable to locate newly created contact record.");
-                       return;
-               }
-
-               Logger::log("Author ".$author." was added as contact number ".$contact_record["id"].".", Logger::DEBUG);
-
-               Group::addMember(User::getDefaultGroup($importer['uid'], $ret["network"]), $contact_record['id']);
-
-               Contact::updateAvatar($ret["photo"], $importer['uid'], $contact_record["id"], true);
-
-               if (in_array($importer["page-flags"], [User::PAGE_FLAGS_NORMAL, User::PAGE_FLAGS_PRVGROUP])) {
-                       Logger::log("Sending intra message for author ".$author.".", Logger::DEBUG);
-
-                       $hash = Strings::getRandomHex().(string)time();   // Generate a confirm_key
-
-                       q(
-                               "INSERT INTO `intro` (`uid`, `contact-id`, `blocked`, `knowyou`, `note`, `hash`, `datetime`)
-                               VALUES (%d, %d, %d, %d, '%s', '%s', '%s')",
-                               intval($importer["uid"]),
-                               intval($contact_record["id"]),
-                               0,
-                               0,
-                               DBA::escape(L10n::t("Sharing notification from Diaspora network")),
-                               DBA::escape($hash),
-                               DBA::escape(DateTimeFormat::utcNow())
-                       );
+               $cid = Contact::getIdForURL($ret['url'], $importer['uid']);
+               if (!empty($cid)) {
+                       $contact = DBA::selectFirst('contact', [], ['id' => $cid, 'network' => Protocol::NATIVE_SUPPORT]);
                } else {
-                       // automatic friend approval
-
-                       Logger::log("Does an automatic friend approval for author ".$author.".", Logger::DEBUG);
+                       $contact = [];
+               }
 
-                       Contact::updateAvatar($contact_record["photo"], $importer["uid"], $contact_record["id"]);
+               $item = ['author-id' => Contact::getIdForURL($ret['url']),
+                       'author-link' => $ret['url']];
 
-                       /*
-                        * technically they are sharing with us (Contact::SHARING),
-                        * but if our page-type is Profile::PAGE_COMMUNITY or Profile::PAGE_SOAPBOX
-                        * we are going to change the relationship and make them a follower.
-                        */
-                       if (($importer["page-flags"] == User::PAGE_FLAGS_FREELOVE) && $sharing && $following) {
-                               $new_relation = Contact::FRIEND;
-                       } elseif (($importer["page-flags"] == User::PAGE_FLAGS_FREELOVE) && $sharing) {
-                               $new_relation = Contact::SHARING;
-                       } else {
-                               $new_relation = Contact::FOLLOWER;
+               $result = Contact::addRelationship($importer, $contact, $item, false);
+               if ($result === true) {
+                       $contact_record = self::contactByHandle($importer['uid'], $author);
+                       if (!$contact_record) {
+                               Logger::info('unable to locate newly created contact record.');
+                               return;
                        }
 
-                       q(
-                               "UPDATE `contact` SET `rel` = %d,
-                               `name-date` = '%s',
-                               `uri-date` = '%s',
-                               `blocked` = 0,
-                               `pending` = 0,
-                               `writable` = 1
-                               WHERE `id` = %d
-                               ",
-                               intval($new_relation),
-                               DBA::escape(DateTimeFormat::utcNow()),
-                               DBA::escape(DateTimeFormat::utcNow()),
-                               intval($contact_record["id"])
-                       );
-
-                       $user = DBA::selectFirst('user', [], ['uid' => $importer["uid"]]);
+                       $user = DBA::selectFirst('user', [], ['uid' => $importer['uid']]);
                        if (DBA::isResult($user)) {
-                               Logger::log("Sending share message (Relation: ".$new_relation.") to author ".$author." - Contact: ".$contact_record["id"]." - User: ".$importer["uid"], Logger::DEBUG);
                                self::sendShare($user, $contact_record);
 
                                // Send the profile data, maybe it weren't transmitted before
-                               self::sendProfile($importer["uid"], [$contact_record]);
+                               self::sendProfile($importer['uid'], [$contact_record]);
                        }
                }
 
index c88a740c0e48e8ac8146fbf8d084ba8ba107665f..597645a8ec2bf556d6a556bb9ac258c917e61ac8 100644 (file)
@@ -27,6 +27,7 @@ use Friendica\Network\Probe;
 use Friendica\Object\Image;
 use Friendica\Protocol\ActivityNamespace;
 use Friendica\Util\DateTimeFormat;
+use Friendica\Util\Images;
 use Friendica\Util\Network;
 use Friendica\Util\Proxy as ProxyUtils;
 use Friendica\Util\Strings;
@@ -1389,7 +1390,7 @@ class OStatus
                switch ($siteinfo["type"]) {
                        case 'photo':
                                if (!empty($siteinfo["image"])) {
-                                       $imgdata = Image::getInfoFromURL($siteinfo["image"]);
+                                       $imgdata = Images::getInfoFromURLCached($siteinfo["image"]);
                                        if ($imgdata) {
                                                $attributes = ["rel" => "enclosure",
                                                                "href" => $siteinfo["image"],
@@ -1413,7 +1414,7 @@ class OStatus
                }
 
                if (!Config::get('system', 'ostatus_not_attach_preview') && ($siteinfo["type"] != "photo") && isset($siteinfo["image"])) {
-                       $imgdata = Image::getInfoFromURL($siteinfo["image"]);
+                       $imgdata = Images::getInfoFromURLCached($siteinfo["image"]);
                        if ($imgdata) {
                                $attributes = ["rel" => "enclosure",
                                                "href" => $siteinfo["image"],
diff --git a/src/Util/Images.php b/src/Util/Images.php
new file mode 100644 (file)
index 0000000..c69c944
--- /dev/null
@@ -0,0 +1,236 @@
+<?php
+
+namespace Friendica\Util;
+
+use Friendica\BaseObject;
+use Friendica\Core\Cache;
+use Friendica\Core\Logger;
+use Friendica\Core\System;
+use Imagick;
+
+/**
+ * Image utilities
+ */
+class Images
+{
+       /**
+        * Maps Mime types to Imagick formats
+        *
+        * @return array
+        */
+       public static function getFormatsMap()
+       {
+               $m = [
+                       'image/jpeg' => 'JPG',
+                       'image/png' => 'PNG',
+                       'image/gif' => 'GIF'
+               ];
+
+               return $m;
+       }
+
+       /**
+        * Returns supported image mimetypes and corresponding file extensions
+        *
+        * @return array
+        */
+       public static function supportedTypes()
+       {
+               $types = [
+                       'image/jpeg' => 'jpg'
+               ];
+               if (class_exists('Imagick')) {
+                       // Imagick::queryFormats won't help us a lot there...
+                       // At least, not yet, other parts of friendica uses this array
+                       $types += [
+                               'image/png' => 'png',
+                               'image/gif' => 'gif'
+                       ];
+               } elseif (imagetypes() & IMG_PNG) {
+                       $types += [
+                               'image/png' => 'png'
+                       ];
+               }
+
+               return $types;
+       }
+
+       /**
+        * Guess image mimetype from filename or from Content-Type header
+        *
+        * @param string  $filename Image filename
+        * @param boolean $fromcurl Check Content-Type header from curl request
+        * @param string  $header   passed headers to take into account
+        *
+        * @return string|null
+        * @throws \Exception
+        */
+       public static function guessType($filename, $fromcurl = false, $header = '')
+       {
+               Logger::info('Image: guessType: ' . $filename . ($fromcurl ? ' from curl headers' : ''));
+               $type = null;
+               if ($fromcurl) {
+                       $headers = [];
+                       $h = explode("\n", $header);
+                       foreach ($h as $l) {
+                               $data = array_map("trim", explode(":", trim($l), 2));
+                               if (count($data) > 1) {
+                                       list($k, $v) = $data;
+                                       $headers[$k] = $v;
+                               }
+                       }
+
+                       if (array_key_exists('Content-Type', $headers)) {
+                               $type = $headers['Content-Type'];
+                       }
+               }
+
+               if (is_null($type)) {
+                       // Guessing from extension? Isn't that... dangerous?
+                       if (class_exists('Imagick') && file_exists($filename) && is_readable($filename)) {
+                               /**
+                                * Well, this not much better,
+                                * but at least it comes from the data inside the image,
+                                * we won't be tricked by a manipulated extension
+                                */
+                               $image = new Imagick($filename);
+                               $type = $image->getImageMimeType();
+                       } else {
+                               $ext = pathinfo($filename, PATHINFO_EXTENSION);
+                               $types = self::supportedTypes();
+                               $type = 'image/jpeg';
+                               foreach ($types as $m => $e) {
+                                       if ($ext == $e) {
+                                               $type = $m;
+                                       }
+                               }
+                       }
+               }
+
+               Logger::info('Image: guessType: type=' . $type);
+               return $type;
+       }
+
+
+       /**
+        * @param string $url
+        * @return array
+        * @throws \Friendica\Network\HTTPException\InternalServerErrorException
+        */
+       public static function getInfoFromURLCached($url)
+       {
+               $data = [];
+
+               if (empty($url)) {
+                       return $data;
+               }
+
+               $data = Cache::get($url);
+
+               if (empty($data) || !is_array($data)) {
+                       $data = self::getInfoFromURL($url);
+
+                       Cache::set($url, $data);
+               }
+
+               return $data;
+       }
+
+       /**
+        * @param string $url
+        * @return array
+        * @throws \Friendica\Network\HTTPException\InternalServerErrorException
+        */
+       public static function getInfoFromURL($url)
+       {
+               $data = [];
+
+               if (empty($url)) {
+                       return $data;
+               }
+
+               $img_str = Network::fetchUrl($url, true, 4);
+
+               if (!$img_str) {
+                       return [];
+               }
+
+               $filesize = strlen($img_str);
+
+               try {
+                       if (function_exists("getimagesizefromstring")) {
+                               $data = @getimagesizefromstring($img_str);
+                       } else {
+                               $tempfile = tempnam(get_temppath(), "cache");
+
+                               $stamp1 = microtime(true);
+                               file_put_contents($tempfile, $img_str);
+                               BaseObject::getApp()->getProfiler()->saveTimestamp($stamp1, "file", System::callstack());
+
+                               $data = getimagesize($tempfile);
+                               unlink($tempfile);
+                       }
+               } catch (\Exception $e) {
+                       return [];
+               }
+
+               if ($data) {
+                       $data['size'] = $filesize;
+               }
+
+               return $data;
+       }
+
+       /**
+        * @param integer $width
+        * @param integer $height
+        * @param integer $max
+        * @return array
+        */
+       public static function getScalingDimensions($width, $height, $max)
+       {
+               if ((!$width) || (!$height)) {
+                       return ['width' => 0, 'height' => 0];
+               }
+
+               if ($width > $max && $height > $max) {
+                       // very tall image (greater than 16:9)
+                       // constrain the width - let the height float.
+
+                       if ((($height * 9) / 16) > $width) {
+                               $dest_width = $max;
+                               $dest_height = intval(($height * $max) / $width);
+                       } elseif ($width > $height) {
+                               // else constrain both dimensions
+                               $dest_width = $max;
+                               $dest_height = intval(($height * $max) / $width);
+                       } else {
+                               $dest_width = intval(($width * $max) / $height);
+                               $dest_height = $max;
+                       }
+               } else {
+                       if ($width > $max) {
+                               $dest_width = $max;
+                               $dest_height = intval(($height * $max) / $width);
+                       } else {
+                               if ($height > $max) {
+                                       // very tall image (greater than 16:9)
+                                       // but width is OK - don't do anything
+
+                                       if ((($height * 9) / 16) > $width) {
+                                               $dest_width = $width;
+                                               $dest_height = $height;
+                                       } else {
+                                               $dest_width = intval(($width * $max) / $height);
+                                               $dest_height = $max;
+                                       }
+                               } else {
+                                       $dest_width = $width;
+                                       $dest_height = $height;
+                               }
+                       }
+               }
+
+               return ['width' => $dest_width, 'height' => $dest_height];
+       }
+}
index 4590f39a99cfa83aa813199619ce0323eff8d47f..1f8fbdeabe4e8898d2a4442196a46a2093c2afd3 100644 (file)
@@ -11,7 +11,6 @@ use Friendica\Content\OEmbed;
 use Friendica\Core\Hook;
 use Friendica\Core\Logger;
 use Friendica\Database\DBA;
-use Friendica\Object\Image;
 
 /**
  * @brief Class with methods for extracting certain content from an url
@@ -348,7 +347,7 @@ class ParseUrl
                                }
 
                                $src = self::completeUrl($img_tag['src'], $url);
-                               $photodata = Image::getInfoFromURL($src);
+                               $photodata = Images::getInfoFromURLCached($src);
 
                                if (($photodata) && ($photodata[0] > 150) && ($photodata[1] > 150)) {
                                        if ($photodata[0] > 300) {
@@ -371,7 +370,7 @@ class ParseUrl
 
                        unset($siteinfo['image']);
 
-                       $photodata = Image::getInfoFromURL($src);
+                       $photodata = Images::getInfoFromURLCached($src);
 
                        if (($photodata) && ($photodata[0] > 10) && ($photodata[1] > 10)) {
                                $siteinfo['images'][] = ['src' => $src,
index e87a84ef9218b4d2e24d08ed3f01011b1c97b032..05c065d9fbd854cc16baea3ba87cd160c1d971b5 100755 (executable)
@@ -1382,10 +1382,12 @@ return [
                        "iid" => ["type" => "int unsigned", "not null" => "1", "default" => "0", "primary" => "1", "relation" => ["item" => "id"], "comment" => "Item id"],
                        "uid" => ["type" => "mediumint unsigned", "not null" => "1", "default" => "0", "primary" => "1", "relation" => ["user" => "uid"], "comment" => "User id"],
                        "hidden" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => "Marker to hide an item from the user"],
-                       "ignored" => ["type" => "boolean", "comment" => "Ignore this thread if set"]
+                       "ignored" => ["type" => "boolean", "comment" => "Ignore this thread if set"],
+                       "pinned" => ["type" => "boolean", "comment" => "The item is pinned on the profile page"]
                ],
                "indexes" => [
-                       "PRIMARY" => ["uid", "iid"]
+                       "PRIMARY" => ["uid", "iid"],
+                       "uid_pinned" => ["uid", "pinned"]
                ]
        ],
        "worker-ipc" => [
index 938b13495b56cd6db6bd8ff9f2a062b600b74433..fbc085f4bc347dcc8dae17fecb7cb3eb79e29b61 100644 (file)
@@ -171,7 +171,7 @@ return [
                        $_SERVER, null
                ],
                'call' => [
-                       ['addRoutes', [include __DIR__ . '/routes.config.php'], Dice::CHAIN_CALL],
+                       ['loadRoutes', [include __DIR__ . '/routes.config.php'], Dice::CHAIN_CALL],
                ],
        ],
        L10n::class => [
index 3379ee113831395fdb177daf2c26ba05ba8d771b..339860afe636588723491aca074d94b0fa5dea39 100644 (file)
@@ -74,23 +74,25 @@ return [
        '/compose[/{type}]'    => [Module\Item\Compose::class, [R::GET, R::POST]],
 
        '/contact'   => [
-               '[/]'                     => [Module\Contact::class, [R::GET]],
-               '/{id:\d+}[/]'            => [Module\Contact::class, [R::GET, R::POST]],
-               '/{id:\d+}/archive'       => [Module\Contact::class, [R::GET]],
-               '/{id:\d+}/block'         => [Module\Contact::class, [R::GET]],
-               '/{id:\d+}/conversations' => [Module\Contact::class, [R::GET]],
-               '/{id:\d+}/drop'          => [Module\Contact::class, [R::GET]],
-               '/{id:\d+}/ignore'        => [Module\Contact::class, [R::GET]],
-               '/{id:\d+}/posts'         => [Module\Contact::class, [R::GET]],
-               '/{id:\d+}/update'        => [Module\Contact::class, [R::GET]],
-               '/{id:\d+}/updateprofile' => [Module\Contact::class, [R::GET]],
-               '/archived'               => [Module\Contact::class, [R::GET]],
-               '/batch'                  => [Module\Contact::class, [R::GET, R::POST]],
-               '/pending'                => [Module\Contact::class, [R::GET]],
-               '/blocked'                => [Module\Contact::class, [R::GET]],
-               '/hidden'                 => [Module\Contact::class, [R::GET]],
-               '/ignored'                => [Module\Contact::class, [R::GET]],
+               '[/]'                     => [Module\Contact::class,           [R::GET]],
+               '/{id:\d+}[/]'            => [Module\Contact::class,           [R::GET, R::POST]],
+               '/{id:\d+}/archive'       => [Module\Contact::class,           [R::GET]],
+               '/{id:\d+}/block'         => [Module\Contact::class,           [R::GET]],
+               '/{id:\d+}/conversations' => [Module\Contact::class,           [R::GET]],
+               '/{id:\d+}/drop'          => [Module\Contact::class,           [R::GET]],
+               '/{id:\d+}/ignore'        => [Module\Contact::class,           [R::GET]],
+               '/{id:\d+}/posts'         => [Module\Contact::class,           [R::GET]],
+               '/{id:\d+}/update'        => [Module\Contact::class,           [R::GET]],
+               '/{id:\d+}/updateprofile' => [Module\Contact::class,           [R::GET]],
+               '/archived'               => [Module\Contact::class,           [R::GET]],
+               '/batch'                  => [Module\Contact::class,           [R::GET, R::POST]],
+               '/pending'                => [Module\Contact::class,           [R::GET]],
+               '/blocked'                => [Module\Contact::class,           [R::GET]],
+               '/hidden'                 => [Module\Contact::class,           [R::GET]],
+               '/ignored'                => [Module\Contact::class,           [R::GET]],
+               '/hovercard'              => [Module\Contact\Hovercard::class, [R::GET]],
        ],
+
        '/credits'   => [Module\Credits::class,          [R::GET]],
        '/delegation'=> [Module\Delegation::class,       [R::GET, R::POST]],
        '/dirfind'   => [Module\Search\Directory::class, [R::GET]],
@@ -177,8 +179,9 @@ return [
                '/{type}/{customize}/{name}' => [Module\Photo::class, [R::GET]],
        ],
 
-       '/pretheme' => [Module\ThemeDetails::class, [R::GET]],
-       '/probe'    => [Module\Debug\Probe::class,  [R::GET]],
+       '/pinned/{item:\d+}' => [Module\Pinned::class,       [R::GET]],
+       '/pretheme'          => [Module\ThemeDetails::class, [R::GET]],
+       '/probe'             => [Module\Debug\Probe::class,  [R::GET]],
 
        '/profile' => [
                '/{nickname}'                                                 => [Module\Profile::class,          [R::GET]],
@@ -214,6 +217,7 @@ return [
                        '/verify'       => [Module\Settings\TwoFactor\Verify::class,      [R::GET, R::POST]],
                ],
                '/delegation[/{action}/{user_id}]' => [Module\Settings\Delegation::class,       [R::GET, R::POST]],
+               '/userexport[/{action}]' => [Module\Settings\UserExport::class,             [R::GET, R::POST]],
        ],
 
        '/randprof'                      => [Module\RandomProfile::class,         [R::GET]],
index bf8b62f1583b1be24cc2f721278127b093e5baf2..a5c6c3aeab22222d3f7ed88ab00981fe5a5ec02e 100644 (file)
@@ -124,6 +124,12 @@ return [
                // The fully-qualified URL of this Friendica node.
                // Used by the worker in a non-HTTP execution environment.
                'url' => '',
+
+               // max_csv_file_size (Integer)
+               // When uploading a CSV with account addresses to follow
+               // in the user settings, this controls the maximum file
+               // size of the upload file.
+               'max_csv_file_size' => 30720,
        ],
 
        // Used in the admin settings to lock certain features
index fe65793f8e1b92e5699bf80aa447bd45d8a83a30..12ec2b4db86fc4759fb4bb157e0351063bcf643c 100644 (file)
@@ -200,7 +200,7 @@ class ModeTest extends MockedTest
        public function testIsBackendButIndex()
        {
                $server = [];
-               $module = new Module(Module::DEFAULT, Module::DEFAULT_CLASS, true);
+               $module = new Module(Module::DEFAULT, Module::DEFAULT_CLASS, [], true);
                $mobileDetect = new MobileDetect();
 
                $mode = (new Mode())->determineRunMode(false, $module, $server, $mobileDetect);
@@ -214,7 +214,7 @@ class ModeTest extends MockedTest
        public function testIsNotBackend()
        {
                $server = [];
-               $module = new Module(Module::DEFAULT, Module::DEFAULT_CLASS, false);
+               $module = new Module(Module::DEFAULT, Module::DEFAULT_CLASS, [], false);
                $mobileDetect = new MobileDetect();
 
                $mode = (new Mode())->determineRunMode(false, $module, $server, $mobileDetect);
@@ -232,7 +232,7 @@ class ModeTest extends MockedTest
                        'HTTP_X_REQUESTED_WITH' => 'xmlhttprequest',
                ];
 
-               $module = new Module(Module::DEFAULT, Module::DEFAULT_CLASS, false);
+               $module = new Module(Module::DEFAULT, Module::DEFAULT_CLASS, [], false);
                $mobileDetect = new MobileDetect();
 
                $mode = (new Mode())->determineRunMode(true, $module, $server, $mobileDetect);
@@ -246,7 +246,7 @@ class ModeTest extends MockedTest
        public function testIsNotAjax()
        {
                $server = [];
-               $module = new Module(Module::DEFAULT, Module::DEFAULT_CLASS, false);
+               $module = new Module(Module::DEFAULT, Module::DEFAULT_CLASS, [], false);
                $mobileDetect = new MobileDetect();
 
                $mode = (new Mode())->determineRunMode(true, $module, $server, $mobileDetect);
@@ -260,7 +260,7 @@ class ModeTest extends MockedTest
        public function testIsMobileIsTablet()
        {
                $server = [];
-               $module = new Module(Module::DEFAULT, Module::DEFAULT_CLASS, false);
+               $module = new Module(Module::DEFAULT, Module::DEFAULT_CLASS, [], false);
                $mobileDetect = \Mockery::mock(MobileDetect::class);
                $mobileDetect->shouldReceive('isMobile')->andReturn(true);
                $mobileDetect->shouldReceive('isTablet')->andReturn(true);
@@ -278,7 +278,7 @@ class ModeTest extends MockedTest
        public function testIsNotMobileIsNotTablet()
        {
                $server = [];
-               $module = new Module(Module::DEFAULT, Module::DEFAULT_CLASS, false);
+               $module = new Module(Module::DEFAULT, Module::DEFAULT_CLASS, [], false);
                $mobileDetect = \Mockery::mock(MobileDetect::class);
                $mobileDetect->shouldReceive('isMobile')->andReturn(false);
                $mobileDetect->shouldReceive('isTablet')->andReturn(false);
index 8327bc706dd479e8d8c4159966f7150c0be67636..ce2a40b80640bca61ee2a4caa4fdf9b30527763b 100644 (file)
@@ -152,7 +152,7 @@ class ModuleTest extends DatabaseTest
                $config = \Mockery::mock(Configuration::class);
                $config->shouldReceive('get')->with('config', 'private_addons', false)->andReturn($privAdd)->atMost()->once();
 
-               $router = (new App\Router([]))->addRoutes(include __DIR__ . '/../../../static/routes.config.php');
+               $router = (new App\Router([]))->loadRoutes(include __DIR__ . '/../../../static/routes.config.php');
 
                $module = (new App\Module($name))->determineClass(new App\Arguments('', $command), $router, $config);
 
index b2dbaed20c8536440da9fa1626d37353bd8db8fa..102808f6ac22e677180df6545807c8600fb54667 100644 (file)
@@ -159,7 +159,7 @@ class RouterTest extends TestCase
        {
                $router = (new Router([
                        'REQUEST_METHOD' => Router::GET
-               ]))->addRoutes($routes);
+               ]))->loadRoutes($routes);
 
                $this->assertEquals(Module\Home::class, $router->getModuleClass('/'));
                $this->assertEquals(Module\Friendica::class, $router->getModuleClass('/group/route'));
@@ -174,7 +174,7 @@ class RouterTest extends TestCase
        {
                $router = (new Router([
                        'REQUEST_METHOD' => Router::POST
-               ]))->addRoutes($routes);
+               ]))->loadRoutes($routes);
 
                // Don't find GET
                $this->assertEquals(Module\NodeInfo::class, $router->getModuleClass('/post/it'));
index 735a52cd09f3d87db68079d27017d3980b87fc4c..3b41e4739cff218fa349b5f3e65f3dbd7caeba04 100644 (file)
@@ -351,12 +351,9 @@ class InstallerTest extends MockedTest
         */
        public function testImagick()
        {
-               $this->l10nMock->shouldReceive('t')->andReturnUsing(function ($args) { return $args; });
+               $this->markTestIncomplete('needs adapted class_exists() mock');
 
-               $imageMock = \Mockery::mock('alias:'. Image::class);
-               $imageMock
-                       ->shouldReceive('supportedTypes')
-                       ->andReturn(['image/gif' => 'gif']);
+               $this->l10nMock->shouldReceive('t')->andReturnUsing(function ($args) { return $args; });
 
                $this->setClasses(['Imagick' => true]);
 
@@ -382,11 +379,6 @@ class InstallerTest extends MockedTest
        {
                $this->l10nMock->shouldReceive('t')->andReturnUsing(function ($args) { return $args; });
 
-               $imageMock = \Mockery::mock('alias:' . Image::class);
-               $imageMock
-                       ->shouldReceive('supportedTypes')
-                       ->andReturn([]);
-
                $this->setClasses(['Imagick' => true]);
 
                $install = new Installer();
index 40db7c2a13cfb2b9d6223004a0f5815f8ef42c0e..94644c5dfd2c3467d796b6449f71959cb8e89d6e 100644 (file)
@@ -626,6 +626,25 @@ function dostar(ident) {
        });
 }
 
+function dopin(ident) {
+       ident = ident.toString();
+       $('#like-rotator-' + ident).show();
+       $.get('pinned/' + ident, function(data) {
+               if (data.match(/1/)) {
+                       $('#pinned-' + ident).addClass('pinned');
+                       $('#pinned-' + ident).removeClass('unpinned');
+                       $('#pin-' + ident).addClass('hidden');
+                       $('#unpin-' + ident).removeClass('hidden');
+               } else {
+                       $('#pinned-' + ident).addClass('unpinned');
+                       $('#pinned-' + ident).removeClass('pinned');
+                       $('#pin-' + ident).removeClass('hidden');
+                       $('#unpin-' + ident).addClass('hidden');
+               }
+               $('#like-rotator-' + ident).hide();
+       });
+}
+
 function doignore(ident) {
        ident = ident.toString();
        $('#like-rotator-' + ident).show();
index 5289dccdd168600a37532f3f1588fe96e1465606..3894baee4fdc6b2f73034970df035efcb0622501 100644 (file)
@@ -8,7 +8,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: \n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2019-09-15 07:45+0200\n"
+"POT-Creation-Date: 2019-11-04 10:26+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"
@@ -18,824 +18,780 @@ msgstr ""
 "Content-Transfer-Encoding: 8bit\n"
 
 
-#: include/items.php:354 src/Module/Admin/Themes/Details.php:53
-#: src/Module/Admin/Themes/Index.php:43 src/Module/Debug/ItemBody.php:27
-#: src/Module/Debug/ItemBody.php:40
-msgid "Item not found."
-msgstr ""
-
-#: include/items.php:392
-msgid "Do you really want to delete this item?"
-msgstr ""
-
-#: include/items.php:394 mod/api.php:109 mod/profiles.php:526
-#: mod/profiles.php:529 mod/profiles.php:551 mod/dfrn_request.php:640
-#: mod/follow.php:163 mod/message.php:150 mod/suggest.php:73
-#: mod/settings.php:1089 mod/settings.php:1095 mod/settings.php:1102
-#: mod/settings.php:1106 mod/settings.php:1110 mod/settings.php:1114
-#: mod/settings.php:1118 mod/settings.php:1122 mod/settings.php:1142
-#: mod/settings.php:1143 mod/settings.php:1144 mod/settings.php:1145
-#: mod/settings.php:1146 src/Module/Register.php:97 src/Module/Contact.php:423
-msgid "Yes"
-msgstr ""
-
-#: include/items.php:397 include/conversation.php:1251 mod/tagrm.php:20
-#: mod/tagrm.php:115 mod/unfollow.php:132 mod/dfrn_request.php:650
-#: mod/editpost.php:110 mod/fbrowser.php:110 mod/fbrowser.php:139
-#: mod/follow.php:174 mod/message.php:153 mod/photos.php:1084
-#: mod/photos.php:1191 mod/suggest.php:76 mod/settings.php:678
-#: mod/settings.php:704 src/Module/Contact.php:426
-msgid "Cancel"
-msgstr ""
-
-#: include/items.php:444 mod/api.php:34 mod/api.php:39 mod/delegate.php:30
-#: mod/delegate.php:48 mod/delegate.php:59 mod/ostatus_subscribe.php:18
-#: mod/regmod.php:89 mod/repair_ostatus.php:16 mod/uimport.php:17
-#: mod/unfollow.php:22 mod/unfollow.php:77 mod/unfollow.php:109
-#: mod/wall_attach.php:76 mod/wall_attach.php:79 mod/wall_upload.php:107
-#: mod/wall_upload.php:110 mod/wallmessage.php:19 mod/wallmessage.php:43
-#: mod/wallmessage.php:82 mod/wallmessage.php:106 mod/profiles.php:182
-#: mod/profiles.php:499 mod/cal.php:301 mod/common.php:27 mod/crepair.php:90
-#: mod/dfrn_confirm.php:64 mod/editpost.php:21 mod/follow.php:57
-#: mod/follow.php:134 mod/fsuggest.php:63 mod/manage.php:130 mod/message.php:56
-#: mod/message.php:101 mod/network.php:37 mod/notes.php:27 mod/photos.php:178
-#: mod/photos.php:962 mod/poke.php:141 mod/profile_photo.php:32
-#: mod/profile_photo.php:177 mod/profile_photo.php:197 mod/suggest.php:39
-#: mod/events.php:208 mod/item.php:170 mod/notifications.php:73
-#: mod/settings.php:52 mod/settings.php:165 mod/settings.php:667
-#: src/Module/Attach.php:42 src/Module/FollowConfirm.php:27
-#: src/Module/Group.php:31 src/Module/Group.php:77 src/Module/Invite.php:22
-#: src/Module/Invite.php:110 src/Module/Notifications/Notify.php:19
-#: src/Module/Profile/Contacts.php:50 src/Module/Register.php:192
-#: src/Module/Search/Directory.php:18 src/Module/Contact.php:340
-msgid "Permission denied."
-msgstr ""
-
-#: include/api.php:1119
+#: include/api.php:1121
 #, php-format
 msgid "Daily posting limit of %d post reached. The post was rejected."
 msgid_plural "Daily posting limit of %d posts reached. The post was rejected."
 msgstr[0] ""
 msgstr[1] ""
 
-#: include/api.php:1133
+#: include/api.php:1135
 #, php-format
 msgid "Weekly posting limit of %d post reached. The post was rejected."
 msgid_plural "Weekly posting limit of %d posts reached. The post was rejected."
 msgstr[0] ""
 msgstr[1] ""
 
-#: include/api.php:1147
+#: include/api.php:1149
 #, php-format
 msgid "Monthly posting limit of %d post reached. The post was rejected."
 msgstr ""
 
-#: include/api.php:4589 mod/photos.php:91 mod/photos.php:196 mod/photos.php:640
-#: mod/photos.php:1090 mod/photos.php:1107 mod/photos.php:1610
-#: mod/profile_photo.php:85 mod/profile_photo.php:94 mod/profile_photo.php:103
-#: mod/profile_photo.php:210 mod/profile_photo.php:298
-#: mod/profile_photo.php:308 src/Model/User.php:796 src/Model/User.php:804
-#: src/Model/User.php:812
+#: include/api.php:4566 mod/profile_photo.php:85 mod/profile_photo.php:94
+#: mod/profile_photo.php:103 mod/profile_photo.php:210
+#: mod/profile_photo.php:298 mod/profile_photo.php:308 mod/photos.php:90
+#: mod/photos.php:181 mod/photos.php:628 mod/photos.php:1055
+#: mod/photos.php:1072 mod/photos.php:1580 src/Model/User.php:841
+#: src/Model/User.php:849 src/Model/User.php:857
 msgid "Profile Photos"
 msgstr ""
 
-#: include/conversation.php:161 include/conversation.php:298
-#: src/Model/Item.php:3309
+#: include/conversation.php:167 include/conversation.php:304
+#: src/Model/Item.php:3322
 msgid "event"
 msgstr ""
 
-#: include/conversation.php:164 include/conversation.php:174
-#: include/conversation.php:301 include/conversation.php:310
-#: mod/subthread.php:88 mod/tagger.php:69
+#: include/conversation.php:170 include/conversation.php:180
+#: include/conversation.php:307 include/conversation.php:316
+#: mod/subthread.php:91 mod/tagger.php:72
 msgid "status"
 msgstr ""
 
-#: include/conversation.php:169 include/conversation.php:306
-#: mod/subthread.php:88 mod/tagger.php:69 src/Model/Item.php:3311
+#: include/conversation.php:175 include/conversation.php:312
+#: mod/subthread.php:91 mod/tagger.php:72 src/Model/Item.php:3324
 msgid "photo"
 msgstr ""
 
-#: include/conversation.php:182
+#: include/conversation.php:188
 #, php-format
 msgid "%1$s likes %2$s's %3$s"
 msgstr ""
 
-#: include/conversation.php:184
+#: include/conversation.php:190
 #, php-format
 msgid "%1$s doesn't like %2$s's %3$s"
 msgstr ""
 
-#: include/conversation.php:186
+#: include/conversation.php:192
 #, php-format
 msgid "%1$s attends %2$s's %3$s"
 msgstr ""
 
-#: include/conversation.php:188
+#: include/conversation.php:194
 #, php-format
 msgid "%1$s doesn't attend %2$s's %3$s"
 msgstr ""
 
-#: include/conversation.php:190
+#: include/conversation.php:196
 #, php-format
 msgid "%1$s attends maybe %2$s's %3$s"
 msgstr ""
 
-#: include/conversation.php:225
+#: include/conversation.php:231
 #, php-format
 msgid "%1$s is now friends with %2$s"
 msgstr ""
 
-#: include/conversation.php:266
+#: include/conversation.php:272
 #, php-format
 msgid "%1$s poked %2$s"
 msgstr ""
 
-#: include/conversation.php:320 mod/tagger.php:102
+#: include/conversation.php:326 mod/tagger.php:105
 #, php-format
 msgid "%1$s tagged %2$s's %3$s with %4$s"
 msgstr ""
 
-#: include/conversation.php:342
+#: include/conversation.php:348
 msgid "post/item"
 msgstr ""
 
-#: include/conversation.php:343
+#: include/conversation.php:349
 #, php-format
 msgid "%1$s marked %2$s's %3$s as favorite"
 msgstr ""
 
-#: include/conversation.php:569 mod/profiles.php:352 mod/photos.php:1442
+#: include/conversation.php:574 mod/photos.php:1407 mod/profiles.php:352
 msgid "Likes"
 msgstr ""
 
-#: include/conversation.php:570 mod/profiles.php:355 mod/photos.php:1442
+#: include/conversation.php:575 mod/photos.php:1407 mod/profiles.php:355
 msgid "Dislikes"
 msgstr ""
 
-#: include/conversation.php:571 include/conversation.php:1566
-#: mod/photos.php:1443
+#: include/conversation.php:576 include/conversation.php:1577
+#: mod/photos.php:1408
 msgid "Attending"
 msgid_plural "Attending"
 msgstr[0] ""
 msgstr[1] ""
 
-#: include/conversation.php:572 mod/photos.php:1443
+#: include/conversation.php:577 mod/photos.php:1408
 msgid "Not attending"
 msgstr ""
 
-#: include/conversation.php:573 mod/photos.php:1443
+#: include/conversation.php:578 mod/photos.php:1408
 msgid "Might attend"
 msgstr ""
 
-#: include/conversation.php:574
+#: include/conversation.php:579
 msgid "Reshares"
 msgstr ""
 
-#: include/conversation.php:654 mod/photos.php:1499 src/Object/Post.php:209
+#: include/conversation.php:659 mod/photos.php:1469 src/Object/Post.php:206
 msgid "Select"
 msgstr ""
 
-#: include/conversation.php:655 mod/photos.php:1500 mod/settings.php:738
-#: src/Module/Admin/Users.php:288 src/Module/Contact.php:805
-#: src/Module/Contact.php:1086
+#: include/conversation.php:660 mod/photos.php:1470 mod/settings.php:730
+#: src/Module/Admin/Users.php:288 src/Module/Contact.php:826
+#: src/Module/Contact.php:1107
 msgid "Delete"
 msgstr ""
 
-#: include/conversation.php:681 src/Object/Post.php:383 src/Object/Post.php:384
+#: include/conversation.php:689 src/Object/Post.php:383 src/Object/Post.php:384
 #, php-format
 msgid "View %s's profile @ %s"
 msgstr ""
 
-#: include/conversation.php:694 src/Object/Post.php:371
+#: include/conversation.php:702 src/Object/Post.php:371
 msgid "Categories:"
 msgstr ""
 
-#: include/conversation.php:695 src/Object/Post.php:372
+#: include/conversation.php:703 src/Object/Post.php:372
 msgid "Filed under:"
 msgstr ""
 
-#: include/conversation.php:702 src/Object/Post.php:397
+#: include/conversation.php:710 src/Object/Post.php:397
 #, php-format
 msgid "%s from %s"
 msgstr ""
 
-#: include/conversation.php:717
+#: include/conversation.php:725
 msgid "View in context"
 msgstr ""
 
-#: include/conversation.php:719 include/conversation.php:1232
-#: mod/wallmessage.php:141 mod/editpost.php:86 mod/message.php:260
-#: mod/message.php:442 mod/photos.php:1415 src/Module/Item/Compose.php:193
+#: include/conversation.php:727 include/conversation.php:1243
+#: mod/editpost.php:87 mod/message.php:260 mod/message.php:442
+#: mod/photos.php:1380 mod/wallmessage.php:141 src/Module/Item/Compose.php:197
 #: src/Object/Post.php:424
 msgid "Please wait"
 msgstr ""
 
-#: include/conversation.php:783
+#: include/conversation.php:791
 msgid "remove"
 msgstr ""
 
-#: include/conversation.php:787
+#: include/conversation.php:795
 msgid "Delete Selected Items"
 msgstr ""
 
-#: include/conversation.php:942 view/theme/frio/theme.php:363
+#: include/conversation.php:950 view/theme/frio/theme.php:363
 msgid "Follow Thread"
 msgstr ""
 
-#: include/conversation.php:943 src/Model/Contact.php:1225
+#: include/conversation.php:951 src/Model/Contact.php:1255
 msgid "View Status"
 msgstr ""
 
-#: include/conversation.php:944 include/conversation.php:962 mod/match.php:87
-#: mod/suggest.php:87 src/Model/Contact.php:1165 src/Model/Contact.php:1218
-#: src/Model/Contact.php:1226 src/Module/AllFriends.php:74
-#: src/Module/BaseSearchModule.php:133 src/Module/Directory.php:150
+#: include/conversation.php:952 include/conversation.php:970 mod/suggest.php:87
+#: mod/match.php:87 src/Model/Contact.php:1185 src/Model/Contact.php:1247
+#: src/Model/Contact.php:1256 src/Module/AllFriends.php:74
+#: src/Module/BaseSearchModule.php:137 src/Module/Directory.php:148
 msgid "View Profile"
 msgstr ""
 
-#: include/conversation.php:945 src/Model/Contact.php:1227
+#: include/conversation.php:953 src/Model/Contact.php:1257
 msgid "View Photos"
 msgstr ""
 
-#: include/conversation.php:946 src/Model/Contact.php:1219
-#: src/Model/Contact.php:1228
+#: include/conversation.php:954 src/Model/Contact.php:1248
+#: src/Model/Contact.php:1258
 msgid "Network Posts"
 msgstr ""
 
-#: include/conversation.php:947 src/Model/Contact.php:1220
-#: src/Model/Contact.php:1229
+#: include/conversation.php:955 src/Model/Contact.php:1249
+#: src/Model/Contact.php:1259
 msgid "View Contact"
 msgstr ""
 
-#: include/conversation.php:948 src/Model/Contact.php:1231
+#: include/conversation.php:956 src/Model/Contact.php:1261
 msgid "Send PM"
 msgstr ""
 
-#: include/conversation.php:949 src/Module/Admin/Blocklist/Contact.php:67
-#: src/Module/Admin/Users.php:289 src/Module/Contact.php:585
-#: src/Module/Contact.php:802 src/Module/Contact.php:1061
+#: include/conversation.php:957 src/Module/Admin/Blocklist/Contact.php:67
+#: src/Module/Admin/Users.php:289 src/Module/Contact.php:606
+#: src/Module/Contact.php:823 src/Module/Contact.php:1082
 msgid "Block"
 msgstr ""
 
-#: include/conversation.php:950 mod/notifications.php:63
-#: mod/notifications.php:197 mod/notifications.php:290
-#: src/Module/Contact.php:586 src/Module/Contact.php:803
-#: src/Module/Contact.php:1069
+#: include/conversation.php:958 mod/notifications.php:66
+#: mod/notifications.php:201 mod/notifications.php:294
+#: src/Module/Contact.php:607 src/Module/Contact.php:824
+#: src/Module/Contact.php:1090
 msgid "Ignore"
 msgstr ""
 
-#: include/conversation.php:954 src/Model/Contact.php:1232
+#: include/conversation.php:962 src/Model/Contact.php:1262
 msgid "Poke"
 msgstr ""
 
-#: include/conversation.php:959 mod/match.php:88 mod/follow.php:160
-#: mod/suggest.php:88 view/theme/vier/theme.php:201 src/Content/Widget.php:66
-#: src/Model/Contact.php:1221 src/Module/AllFriends.php:75
-#: src/Module/BaseSearchModule.php:134
+#: include/conversation.php:967 mod/suggest.php:88 mod/follow.php:160
+#: mod/match.php:88 view/theme/vier/theme.php:178 src/Content/Widget.php:67
+#: src/Model/Contact.php:1250 src/Model/Contact.php:1263
+#: src/Module/AllFriends.php:75 src/Module/BaseSearchModule.php:138
 msgid "Connect/Follow"
 msgstr ""
 
-#: include/conversation.php:1084
+#: include/conversation.php:1095
 #, php-format
 msgid "%s likes this."
 msgstr ""
 
-#: include/conversation.php:1087
+#: include/conversation.php:1098
 #, php-format
 msgid "%s doesn't like this."
 msgstr ""
 
-#: include/conversation.php:1090
+#: include/conversation.php:1101
 #, php-format
 msgid "%s attends."
 msgstr ""
 
-#: include/conversation.php:1093
+#: include/conversation.php:1104
 #, php-format
 msgid "%s doesn't attend."
 msgstr ""
 
-#: include/conversation.php:1096
+#: include/conversation.php:1107
 #, php-format
 msgid "%s attends maybe."
 msgstr ""
 
-#: include/conversation.php:1099 include/conversation.php:1142
+#: include/conversation.php:1110 include/conversation.php:1153
 #, php-format
 msgid "%s reshared this."
 msgstr ""
 
-#: include/conversation.php:1107
+#: include/conversation.php:1118
 msgid "and"
 msgstr ""
 
-#: include/conversation.php:1113
+#: include/conversation.php:1124
 #, php-format
 msgid "and %d other people"
 msgstr ""
 
-#: include/conversation.php:1121
+#: include/conversation.php:1132
 #, php-format
 msgid "<span  %1$s>%2$d people</span> like this"
 msgstr ""
 
-#: include/conversation.php:1122
+#: include/conversation.php:1133
 #, php-format
 msgid "%s like this."
 msgstr ""
 
-#: include/conversation.php:1125
+#: include/conversation.php:1136
 #, php-format
 msgid "<span  %1$s>%2$d people</span> don't like this"
 msgstr ""
 
-#: include/conversation.php:1126
+#: include/conversation.php:1137
 #, php-format
 msgid "%s don't like this."
 msgstr ""
 
-#: include/conversation.php:1129
+#: include/conversation.php:1140
 #, php-format
 msgid "<span  %1$s>%2$d people</span> attend"
 msgstr ""
 
-#: include/conversation.php:1130
+#: include/conversation.php:1141
 #, php-format
 msgid "%s attend."
 msgstr ""
 
-#: include/conversation.php:1133
+#: include/conversation.php:1144
 #, php-format
 msgid "<span  %1$s>%2$d people</span> don't attend"
 msgstr ""
 
-#: include/conversation.php:1134
+#: include/conversation.php:1145
 #, php-format
 msgid "%s don't attend."
 msgstr ""
 
-#: include/conversation.php:1137
+#: include/conversation.php:1148
 #, php-format
 msgid "<span  %1$s>%2$d people</span> attend maybe"
 msgstr ""
 
-#: include/conversation.php:1138
+#: include/conversation.php:1149
 #, php-format
 msgid "%s attend maybe."
 msgstr ""
 
-#: include/conversation.php:1141
+#: include/conversation.php:1152
 #, php-format
 msgid "<span  %1$s>%2$d people</span> reshared this"
 msgstr ""
 
-#: include/conversation.php:1171
+#: include/conversation.php:1182
 msgid "Visible to <strong>everybody</strong>"
 msgstr ""
 
-#: include/conversation.php:1172 src/Module/Item/Compose.php:187
-#: src/Object/Post.php:888
+#: include/conversation.php:1183 src/Module/Item/Compose.php:191
+#: src/Object/Post.php:893
 msgid "Please enter a image/video/audio/webpage URL:"
 msgstr ""
 
-#: include/conversation.php:1173
+#: include/conversation.php:1184
 msgid "Tag term:"
 msgstr ""
 
-#: include/conversation.php:1174 src/Module/Filer/SaveTag.php:48
+#: include/conversation.php:1185 src/Module/Filer/SaveTag.php:48
 msgid "Save to Folder:"
 msgstr ""
 
-#: include/conversation.php:1175
+#: include/conversation.php:1186
 msgid "Where are you right now?"
 msgstr ""
 
-#: include/conversation.php:1176
+#: include/conversation.php:1187
 msgid "Delete item(s)?"
 msgstr ""
 
-#: include/conversation.php:1208
+#: include/conversation.php:1219
 msgid "New Post"
 msgstr ""
 
-#: include/conversation.php:1211
+#: include/conversation.php:1222
 msgid "Share"
 msgstr ""
 
-#: include/conversation.php:1212 mod/wallmessage.php:139 mod/editpost.php:72
-#: mod/message.php:258 mod/message.php:439
+#: include/conversation.php:1223 mod/editpost.php:73 mod/message.php:258
+#: mod/message.php:439 mod/wallmessage.php:139
 msgid "Upload photo"
 msgstr ""
 
-#: include/conversation.php:1213 mod/editpost.php:73
+#: include/conversation.php:1224 mod/editpost.php:74
 msgid "upload photo"
 msgstr ""
 
-#: include/conversation.php:1214 mod/editpost.php:74
+#: include/conversation.php:1225 mod/editpost.php:75
 msgid "Attach file"
 msgstr ""
 
-#: include/conversation.php:1215 mod/editpost.php:75
+#: include/conversation.php:1226 mod/editpost.php:76
 msgid "attach file"
 msgstr ""
 
-#: include/conversation.php:1216 src/Module/Item/Compose.php:179
-#: src/Object/Post.php:880
+#: include/conversation.php:1227 src/Module/Item/Compose.php:183
+#: src/Object/Post.php:885
 msgid "Bold"
 msgstr ""
 
-#: include/conversation.php:1217 src/Module/Item/Compose.php:180
-#: src/Object/Post.php:881
+#: include/conversation.php:1228 src/Module/Item/Compose.php:184
+#: src/Object/Post.php:886
 msgid "Italic"
 msgstr ""
 
-#: include/conversation.php:1218 src/Module/Item/Compose.php:181
-#: src/Object/Post.php:882
+#: include/conversation.php:1229 src/Module/Item/Compose.php:185
+#: src/Object/Post.php:887
 msgid "Underline"
 msgstr ""
 
-#: include/conversation.php:1219 src/Module/Item/Compose.php:182
-#: src/Object/Post.php:883
+#: include/conversation.php:1230 src/Module/Item/Compose.php:186
+#: src/Object/Post.php:888
 msgid "Quote"
 msgstr ""
 
-#: include/conversation.php:1220 src/Module/Item/Compose.php:183
-#: src/Object/Post.php:884
+#: include/conversation.php:1231 src/Module/Item/Compose.php:187
+#: src/Object/Post.php:889
 msgid "Code"
 msgstr ""
 
-#: include/conversation.php:1221 src/Module/Item/Compose.php:184
-#: src/Object/Post.php:885
+#: include/conversation.php:1232 src/Module/Item/Compose.php:188
+#: src/Object/Post.php:890
 msgid "Image"
 msgstr ""
 
-#: include/conversation.php:1222 src/Module/Item/Compose.php:185
-#: src/Object/Post.php:886
+#: include/conversation.php:1233 src/Module/Item/Compose.php:189
+#: src/Object/Post.php:891
 msgid "Link"
 msgstr ""
 
-#: include/conversation.php:1223 src/Module/Item/Compose.php:186
-#: src/Object/Post.php:887
+#: include/conversation.php:1234 src/Module/Item/Compose.php:190
+#: src/Object/Post.php:892
 msgid "Link or Media"
 msgstr ""
 
-#: include/conversation.php:1224 mod/editpost.php:82
-#: src/Module/Item/Compose.php:189
+#: include/conversation.php:1235 mod/editpost.php:83
+#: src/Module/Item/Compose.php:193
 msgid "Set your location"
 msgstr ""
 
-#: include/conversation.php:1225 mod/editpost.php:83
+#: include/conversation.php:1236 mod/editpost.php:84
 msgid "set location"
 msgstr ""
 
-#: include/conversation.php:1226 mod/editpost.php:84
+#: include/conversation.php:1237 mod/editpost.php:85
 msgid "Clear browser location"
 msgstr ""
 
-#: include/conversation.php:1227 mod/editpost.php:85
+#: include/conversation.php:1238 mod/editpost.php:86
 msgid "clear location"
 msgstr ""
 
-#: include/conversation.php:1229 mod/editpost.php:99
-#: src/Module/Item/Compose.php:194
+#: include/conversation.php:1240 mod/editpost.php:100
+#: src/Module/Item/Compose.php:198
 msgid "Set title"
 msgstr ""
 
-#: include/conversation.php:1231 mod/editpost.php:101
-#: src/Module/Item/Compose.php:195
+#: include/conversation.php:1242 mod/editpost.php:102
+#: src/Module/Item/Compose.php:199
 msgid "Categories (comma-separated list)"
 msgstr ""
 
-#: include/conversation.php:1233 mod/editpost.php:87
+#: include/conversation.php:1244 mod/editpost.php:88
 msgid "Permission settings"
 msgstr ""
 
-#: include/conversation.php:1234 mod/editpost.php:116
+#: include/conversation.php:1245 mod/editpost.php:117
 msgid "permissions"
 msgstr ""
 
-#: include/conversation.php:1243 mod/editpost.php:96
+#: include/conversation.php:1254 mod/editpost.php:97
 msgid "Public post"
 msgstr ""
 
-#: include/conversation.php:1247 mod/editpost.php:107 mod/photos.php:1433
-#: mod/photos.php:1472 mod/photos.php:1532 mod/events.php:550
-#: src/Module/Item/Compose.php:188 src/Object/Post.php:889
+#: include/conversation.php:1258 mod/editpost.php:108 mod/events.php:556
+#: mod/photos.php:1398 mod/photos.php:1437 mod/photos.php:1502
+#: src/Module/Item/Compose.php:192 src/Object/Post.php:894
 msgid "Preview"
 msgstr ""
 
-#: include/conversation.php:1256
+#: include/conversation.php:1262 include/items.php:392 mod/suggest.php:76
+#: mod/dfrn_request.php:652 mod/editpost.php:111 mod/fbrowser.php:110
+#: mod/fbrowser.php:139 mod/follow.php:174 mod/message.php:153
+#: mod/photos.php:1049 mod/photos.php:1156 mod/settings.php:670
+#: mod/settings.php:696 mod/tagrm.php:20 mod/tagrm.php:115 mod/unfollow.php:132
+#: src/Module/Contact.php:447
+msgid "Cancel"
+msgstr ""
+
+#: include/conversation.php:1267
 msgid "Post to Groups"
 msgstr ""
 
-#: include/conversation.php:1257
+#: include/conversation.php:1268
 msgid "Post to Contacts"
 msgstr ""
 
-#: include/conversation.php:1258
+#: include/conversation.php:1269
 msgid "Private post"
 msgstr ""
 
-#: include/conversation.php:1263 mod/editpost.php:114 src/Model/Profile.php:550
-#: src/Module/Contact.php:301
+#: include/conversation.php:1274 mod/editpost.php:115 src/Model/Profile.php:546
+#: src/Module/Contact.php:322
 msgid "Message"
 msgstr ""
 
-#: include/conversation.php:1264 mod/editpost.php:115
+#: include/conversation.php:1275 mod/editpost.php:116
 msgid "Browser"
 msgstr ""
 
-#: include/conversation.php:1536
+#: include/conversation.php:1547
 msgid "View all"
 msgstr ""
 
-#: include/conversation.php:1560
+#: include/conversation.php:1571
 msgid "Like"
 msgid_plural "Likes"
 msgstr[0] ""
 msgstr[1] ""
 
-#: include/conversation.php:1563
+#: include/conversation.php:1574
 msgid "Dislike"
 msgid_plural "Dislikes"
 msgstr[0] ""
 msgstr[1] ""
 
-#: include/conversation.php:1569
+#: include/conversation.php:1580
 msgid "Not Attending"
 msgid_plural "Not Attending"
 msgstr[0] ""
 msgstr[1] ""
 
-#: include/conversation.php:1572 src/Content/ContactSelector.php:243
+#: include/conversation.php:1583 src/Content/ContactSelector.php:243
 msgid "Undecided"
 msgid_plural "Undecided"
 msgstr[0] ""
 msgstr[1] ""
 
-#: include/enotify.php:57
+#: include/enotify.php:58
 msgid "Friendica Notification"
 msgstr ""
 
-#: include/enotify.php:60
+#: include/enotify.php:61
 msgid "Thank You,"
 msgstr ""
 
-#: include/enotify.php:63
+#: include/enotify.php:64
 #, php-format
 msgid "%1$s, %2$s Administrator"
 msgstr ""
 
-#: include/enotify.php:65
+#: include/enotify.php:66
 #, php-format
 msgid "%s Administrator"
 msgstr ""
 
-#: include/enotify.php:134
+#: include/enotify.php:135
 #, php-format
 msgid "[Friendica:Notify] New mail received at %s"
 msgstr ""
 
-#: include/enotify.php:136
+#: include/enotify.php:137
 #, php-format
 msgid "%1$s sent you a new private message at %2$s."
 msgstr ""
 
-#: include/enotify.php:137
+#: include/enotify.php:138
 msgid "a private message"
 msgstr ""
 
-#: include/enotify.php:137
+#: include/enotify.php:138
 #, php-format
 msgid "%1$s sent you %2$s."
 msgstr ""
 
-#: include/enotify.php:139
+#: include/enotify.php:140
 #, php-format
 msgid "Please visit %s to view and/or reply to your private messages."
 msgstr ""
 
-#: include/enotify.php:172
+#: include/enotify.php:173
 #, php-format
 msgid "%1$s tagged you on [url=%2$s]a %3$s[/url]"
 msgstr ""
 
-#: include/enotify.php:178
+#: include/enotify.php:179
 #, php-format
 msgid "%1$s commented on [url=%2$s]a %3$s[/url]"
 msgstr ""
 
-#: include/enotify.php:188
+#: include/enotify.php:189
 #, php-format
 msgid "%1$s tagged you on [url=%2$s]%3$s's %4$s[/url]"
 msgstr ""
 
-#: include/enotify.php:195
+#: include/enotify.php:196
 #, php-format
 msgid "%1$s commented on [url=%2$s]%3$s's %4$s[/url]"
 msgstr ""
 
-#: include/enotify.php:207
+#: include/enotify.php:208
 #, php-format
 msgid "%1$s tagged you on [url=%2$s]your %3$s[/url]"
 msgstr ""
 
-#: include/enotify.php:213
+#: include/enotify.php:214
 #, php-format
 msgid "%1$s commented on [url=%2$s]your %3$s[/url]"
 msgstr ""
 
-#: include/enotify.php:224
+#: include/enotify.php:225
 #, php-format
 msgid "%1$s tagged you on [url=%2$s]their %3$s[/url]"
 msgstr ""
 
-#: include/enotify.php:230
+#: include/enotify.php:231
 #, php-format
 msgid "%1$s commented on [url=%2$s]their %3$s[/url]"
 msgstr ""
 
-#: include/enotify.php:243
+#: include/enotify.php:244
 #, php-format
 msgid "[Friendica:Notify] %s tagged you"
 msgstr ""
 
-#: include/enotify.php:245
+#: include/enotify.php:246
 #, php-format
 msgid "%1$s tagged you at %2$s"
 msgstr ""
 
-#: include/enotify.php:247
+#: include/enotify.php:248
 #, php-format
 msgid "[Friendica:Notify] Comment to conversation #%1$d by %2$s"
 msgstr ""
 
-#: include/enotify.php:249
+#: include/enotify.php:250
 #, php-format
 msgid "%s commented on an item/conversation you have been following."
 msgstr ""
 
-#: include/enotify.php:254 include/enotify.php:269 include/enotify.php:284
-#: include/enotify.php:303 include/enotify.php:319
+#: include/enotify.php:255 include/enotify.php:270 include/enotify.php:285
+#: include/enotify.php:304 include/enotify.php:320
 #, php-format
 msgid "Please visit %s to view and/or reply to the conversation."
 msgstr ""
 
-#: include/enotify.php:261
+#: include/enotify.php:262
 #, php-format
 msgid "[Friendica:Notify] %s posted to your profile wall"
 msgstr ""
 
-#: include/enotify.php:263
+#: include/enotify.php:264
 #, php-format
 msgid "%1$s posted to your profile wall at %2$s"
 msgstr ""
 
-#: include/enotify.php:264
+#: include/enotify.php:265
 #, php-format
 msgid "%1$s posted to [url=%2$s]your wall[/url]"
 msgstr ""
 
-#: include/enotify.php:276
+#: include/enotify.php:277
 #, php-format
 msgid "[Friendica:Notify] %s shared a new post"
 msgstr ""
 
-#: include/enotify.php:278
+#: include/enotify.php:279
 #, php-format
 msgid "%1$s shared a new post at %2$s"
 msgstr ""
 
-#: include/enotify.php:279
+#: include/enotify.php:280
 #, php-format
 msgid "%1$s [url=%2$s]shared a post[/url]."
 msgstr ""
 
-#: include/enotify.php:291
+#: include/enotify.php:292
 #, php-format
 msgid "[Friendica:Notify] %1$s poked you"
 msgstr ""
 
-#: include/enotify.php:293
+#: include/enotify.php:294
 #, php-format
 msgid "%1$s poked you at %2$s"
 msgstr ""
 
-#: include/enotify.php:294
+#: include/enotify.php:295
 #, php-format
 msgid "%1$s [url=%2$s]poked you[/url]."
 msgstr ""
 
-#: include/enotify.php:311
+#: include/enotify.php:312
 #, php-format
 msgid "[Friendica:Notify] %s tagged your post"
 msgstr ""
 
-#: include/enotify.php:313
+#: include/enotify.php:314
 #, php-format
 msgid "%1$s tagged your post at %2$s"
 msgstr ""
 
-#: include/enotify.php:314
+#: include/enotify.php:315
 #, php-format
 msgid "%1$s tagged [url=%2$s]your post[/url]"
 msgstr ""
 
-#: include/enotify.php:326
+#: include/enotify.php:327
 msgid "[Friendica:Notify] Introduction received"
 msgstr ""
 
-#: include/enotify.php:328
+#: include/enotify.php:329
 #, php-format
 msgid "You've received an introduction from '%1$s' at %2$s"
 msgstr ""
 
-#: include/enotify.php:329
+#: include/enotify.php:330
 #, php-format
 msgid "You've received [url=%1$s]an introduction[/url] from %2$s."
 msgstr ""
 
-#: include/enotify.php:334 include/enotify.php:380
+#: include/enotify.php:335 include/enotify.php:381
 #, php-format
 msgid "You may visit their profile at %s"
 msgstr ""
 
-#: include/enotify.php:336
+#: include/enotify.php:337
 #, php-format
 msgid "Please visit %s to approve or reject the introduction."
 msgstr ""
 
-#: include/enotify.php:343
+#: include/enotify.php:344
 msgid "[Friendica:Notify] A new person is sharing with you"
 msgstr ""
 
-#: include/enotify.php:345 include/enotify.php:346
+#: include/enotify.php:346 include/enotify.php:347
 #, php-format
 msgid "%1$s is sharing with you at %2$s"
 msgstr ""
 
-#: include/enotify.php:353
+#: include/enotify.php:354
 msgid "[Friendica:Notify] You have a new follower"
 msgstr ""
 
-#: include/enotify.php:355 include/enotify.php:356
+#: include/enotify.php:356 include/enotify.php:357
 #, php-format
 msgid "You have a new follower at %2$s : %1$s"
 msgstr ""
 
-#: include/enotify.php:369
+#: include/enotify.php:370
 msgid "[Friendica:Notify] Friend suggestion received"
 msgstr ""
 
-#: include/enotify.php:371
+#: include/enotify.php:372
 #, php-format
 msgid "You've received a friend suggestion from '%1$s' at %2$s"
 msgstr ""
 
-#: include/enotify.php:372
+#: include/enotify.php:373
 #, php-format
 msgid "You've received [url=%1$s]a friend suggestion[/url] for %2$s from %3$s."
 msgstr ""
 
-#: include/enotify.php:378
+#: include/enotify.php:379
 msgid "Name:"
 msgstr ""
 
-#: include/enotify.php:379
+#: include/enotify.php:380
 msgid "Photo:"
 msgstr ""
 
-#: include/enotify.php:382
+#: include/enotify.php:383
 #, php-format
 msgid "Please visit %s to approve or reject the suggestion."
 msgstr ""
 
-#: include/enotify.php:390 include/enotify.php:405
+#: include/enotify.php:391 include/enotify.php:406
 msgid "[Friendica:Notify] Connection accepted"
 msgstr ""
 
-#: include/enotify.php:392 include/enotify.php:407
+#: include/enotify.php:393 include/enotify.php:408
 #, php-format
 msgid "'%1$s' has accepted your connection request at %2$s"
 msgstr ""
 
-#: include/enotify.php:393 include/enotify.php:408
+#: include/enotify.php:394 include/enotify.php:409
 #, php-format
 msgid "%2$s has accepted your [url=%1$s]connection request[/url]."
 msgstr ""
 
-#: include/enotify.php:398
+#: include/enotify.php:399
 msgid ""
 "You are now mutual friends and may exchange status updates, photos, and "
 "email without restriction."
 msgstr ""
 
-#: include/enotify.php:400
+#: include/enotify.php:401
 #, php-format
 msgid "Please visit %s if you wish to make any changes to this relationship."
 msgstr ""
 
-#: include/enotify.php:413
+#: include/enotify.php:414
 #, php-format
 msgid ""
 "'%1$s' has chosen to accept you a fan, which restricts some forms of "
@@ -844,37 +800,37 @@ msgid ""
 "automatically."
 msgstr ""
 
-#: include/enotify.php:415
+#: include/enotify.php:416
 #, php-format
 msgid ""
 "'%1$s' may choose to extend this into a two-way or more permissive "
 "relationship in the future."
 msgstr ""
 
-#: include/enotify.php:417
+#: include/enotify.php:418
 #, php-format
 msgid "Please visit %s  if you wish to make any changes to this relationship."
 msgstr ""
 
-#: include/enotify.php:427 mod/removeme.php:46
+#: include/enotify.php:428 mod/removeme.php:46
 msgid "[Friendica System Notify]"
 msgstr ""
 
-#: include/enotify.php:427
+#: include/enotify.php:428
 msgid "registration request"
 msgstr ""
 
-#: include/enotify.php:429
+#: include/enotify.php:430
 #, php-format
 msgid "You've received a registration request from '%1$s' at %2$s"
 msgstr ""
 
-#: include/enotify.php:430
+#: include/enotify.php:431
 #, php-format
 msgid "You've received a [url=%1$s]registration request[/url] from %2$s."
 msgstr ""
 
-#: include/enotify.php:435
+#: include/enotify.php:436
 #, php-format
 msgid ""
 "Full Name:\t%s\n"
@@ -882,107 +838,53 @@ msgid ""
 "Login Name:\t%s (%s)"
 msgstr ""
 
-#: include/enotify.php:441
+#: include/enotify.php:442
 #, php-format
 msgid "Please visit %s to approve or reject the request."
 msgstr ""
 
-#: mod/api.php:84 mod/api.php:106
-msgid "Authorize application connection"
-msgstr ""
-
-#: mod/api.php:85
-msgid "Return to your app and insert this Securty Code:"
-msgstr ""
-
-#: mod/api.php:94 src/Module/BaseAdminModule.php:56
-msgid "Please login to continue."
-msgstr ""
-
-#: mod/api.php:108
-msgid ""
-"Do you want to authorize this application to access your posts and contacts, "
-"and/or create new posts for you?"
-msgstr ""
-
-#: mod/api.php:110 mod/profiles.php:526 mod/profiles.php:530
-#: mod/profiles.php:551 mod/dfrn_request.php:640 mod/follow.php:163
-#: mod/settings.php:1089 mod/settings.php:1095 mod/settings.php:1102
-#: mod/settings.php:1106 mod/settings.php:1110 mod/settings.php:1114
-#: mod/settings.php:1118 mod/settings.php:1122 mod/settings.php:1142
-#: mod/settings.php:1143 mod/settings.php:1144 mod/settings.php:1145
-#: mod/settings.php:1146 src/Module/Register.php:98
-msgid "No"
-msgstr ""
-
-#: mod/delegate.php:42
-msgid "Parent user not found."
-msgstr ""
-
-#: mod/delegate.php:149
-msgid "No parent user"
-msgstr ""
-
-#: mod/delegate.php:164
-msgid "Parent Password:"
-msgstr ""
-
-#: mod/delegate.php:164
-msgid ""
-"Please enter the password of the parent account to legitimize your request."
-msgstr ""
-
-#: mod/delegate.php:171
-msgid "Parent User"
-msgstr ""
-
-#: mod/delegate.php:174
-msgid ""
-"Parent users have total control about this account, including the account "
-"settings. Please double check whom you give this access."
-msgstr ""
-
-#: mod/delegate.php:175 mod/settings.php:677 mod/settings.php:784
-#: mod/settings.php:874 mod/settings.php:953 mod/settings.php:1178
-#: src/Module/Admin/Addons/Index.php:52 src/Module/Admin/Features.php:69
-#: src/Module/Admin/Logs/Settings.php:65 src/Module/Admin/Themes/Index.php:97
-#: src/Module/Admin/Tos.php:50 src/Module/Admin/Site.php:568
-msgid "Save Settings"
-msgstr ""
-
-#: mod/delegate.php:176 src/Content/Nav.php:263
-msgid "Delegate Page Management"
-msgstr ""
-
-#: mod/delegate.php:177
-msgid "Delegates"
-msgstr ""
-
-#: mod/delegate.php:179
-msgid ""
-"Delegates are able to manage all aspects of this account/page except for "
-"basic account settings. Please do not delegate your personal account to "
-"anybody that you do not trust completely."
-msgstr ""
-
-#: mod/delegate.php:180
-msgid "Existing Page Delegates"
-msgstr ""
-
-#: mod/delegate.php:182
-msgid "Potential Delegates"
+#: include/items.php:355 src/Module/Admin/Themes/Details.php:53
+#: src/Module/Admin/Themes/Index.php:43 src/Module/Debug/ItemBody.php:27
+#: src/Module/Debug/ItemBody.php:40
+msgid "Item not found."
 msgstr ""
 
-#: mod/delegate.php:184 mod/tagrm.php:114
-msgid "Remove"
+#: include/items.php:387
+msgid "Do you really want to delete this item?"
 msgstr ""
 
-#: mod/delegate.php:185
-msgid "Add"
+#: include/items.php:389 mod/suggest.php:73 mod/api.php:110
+#: mod/dfrn_request.php:642 mod/follow.php:163 mod/message.php:150
+#: mod/profiles.php:526 mod/profiles.php:529 mod/profiles.php:551
+#: mod/settings.php:1081 mod/settings.php:1087 mod/settings.php:1094
+#: mod/settings.php:1098 mod/settings.php:1102 mod/settings.php:1106
+#: mod/settings.php:1110 mod/settings.php:1114 mod/settings.php:1134
+#: mod/settings.php:1135 mod/settings.php:1136 mod/settings.php:1137
+#: mod/settings.php:1138 src/Module/Contact.php:444 src/Module/Register.php:91
+msgid "Yes"
 msgstr ""
 
-#: mod/delegate.php:186
-msgid "No entries."
+#: include/items.php:439 mod/ostatus_subscribe.php:18 mod/repair_ostatus.php:16
+#: mod/notes.php:27 mod/profile_photo.php:32 mod/profile_photo.php:177
+#: mod/profile_photo.php:197 mod/suggest.php:39 mod/api.php:35 mod/api.php:40
+#: mod/cal.php:291 mod/common.php:27 mod/crepair.php:90 mod/dfrn_confirm.php:65
+#: mod/editpost.php:22 mod/events.php:214 mod/follow.php:57 mod/follow.php:134
+#: mod/fsuggest.php:63 mod/item.php:174 mod/message.php:56 mod/message.php:101
+#: mod/network.php:38 mod/notifications.php:76 mod/photos.php:163
+#: mod/photos.php:927 mod/poke.php:142 mod/profiles.php:182
+#: mod/profiles.php:499 mod/regmod.php:89 mod/settings.php:54
+#: mod/settings.php:167 mod/settings.php:659 mod/uimport.php:17
+#: mod/unfollow.php:22 mod/unfollow.php:77 mod/unfollow.php:109
+#: mod/wall_attach.php:63 mod/wall_attach.php:66 mod/wall_upload.php:95
+#: mod/wall_upload.php:98 mod/wallmessage.php:19 mod/wallmessage.php:43
+#: mod/wallmessage.php:82 mod/wallmessage.php:106 src/Module/Attach.php:42
+#: src/Module/Group.php:31 src/Module/Group.php:77 src/Module/Invite.php:22
+#: src/Module/Invite.php:110 src/Module/Notifications/Notify.php:20
+#: src/Module/Profile/Contacts.php:50 src/Module/Search/Directory.php:19
+#: src/Module/Settings/Delegation.php:26 src/Module/Settings/Delegation.php:54
+#: src/Module/Contact.php:361 src/Module/Delegation.php:98
+#: src/Module/FollowConfirm.php:27 src/Module/Register.php:186
+msgid "Permission denied."
 msgstr ""
 
 #: mod/oexchange.php:32
@@ -1017,7 +919,7 @@ msgstr ""
 msgid "failed"
 msgstr ""
 
-#: mod/ostatus_subscribe.php:89 src/Object/Post.php:285
+#: mod/ostatus_subscribe.php:89 src/Object/Post.php:282
 msgid "ignored"
 msgstr ""
 
@@ -1038,9 +940,9 @@ msgid "Profile Visibility Editor"
 msgstr ""
 
 #: mod/profperm.php:117 view/theme/frio/theme.php:268 src/Content/Nav.php:161
-#: src/Model/Profile.php:889 src/Model/Profile.php:925
-#: src/Module/Welcome.php:38 src/Module/Contact.php:618
-#: src/Module/Contact.php:847
+#: src/Model/Profile.php:885 src/Model/Profile.php:921
+#: src/Module/Welcome.php:38 src/Module/Contact.php:639
+#: src/Module/Contact.php:868
 msgid "Profile"
 msgstr ""
 
@@ -1056,19 +958,6 @@ msgstr ""
 msgid "All Contacts (with secure profile access)"
 msgstr ""
 
-#: mod/regmod.php:53
-msgid "Account approved."
-msgstr ""
-
-#: mod/regmod.php:77
-#, php-format
-msgid "Registration revoked for %s"
-msgstr ""
-
-#: mod/regmod.php:84
-msgid "Please login."
-msgstr ""
-
 #: mod/removeme.php:46
 msgid "User deleted their account"
 msgstr ""
@@ -1108,1190 +997,914 @@ msgid_plural "Errors"
 msgstr[0] ""
 msgstr[1] ""
 
-#: mod/tagrm.php:31
-msgid "Tag(s) removed"
-msgstr ""
-
-#: mod/tagrm.php:101
-msgid "Remove Item Tag"
+#: mod/update_community.php:23 mod/update_contact.php:23
+#: mod/update_display.php:24 mod/update_network.php:33 mod/update_notes.php:36
+#: mod/update_profile.php:34
+msgid "[Embedded content - reload page to view]"
 msgstr ""
 
-#: mod/tagrm.php:103
-msgid "Select a tag to remove: "
+#: mod/notes.php:34 src/Model/Profile.php:971
+msgid "Personal Notes"
 msgstr ""
 
-#: mod/uimport.php:30
-msgid "User imports on closed servers can only be done by an administrator."
+#: mod/notes.php:46 mod/editpost.php:72 src/Content/Text/HTML.php:905
+#: src/Module/Filer/SaveTag.php:49
+msgid "Save"
 msgstr ""
 
-#: mod/uimport.php:39 src/Module/Register.php:59
-msgid ""
-"This site has exceeded the number of allowed daily account registrations. "
-"Please try again tomorrow."
+#: mod/ping.php:272
+msgid "{0} wants to be your friend"
 msgstr ""
 
-#: mod/uimport.php:54 src/Module/Register.php:141
-msgid "Import"
+#: mod/ping.php:288
+msgid "{0} requested registration"
 msgstr ""
 
-#: mod/uimport.php:56
-msgid "Move account"
+#: mod/profile_photo.php:58
+msgid "Image uploaded but image cropping failed."
 msgstr ""
 
-#: mod/uimport.php:57
-msgid "You can import an account from another Friendica server."
+#: mod/profile_photo.php:88 mod/profile_photo.php:97 mod/profile_photo.php:106
+#: mod/profile_photo.php:311
+#, php-format
+msgid "Image size reduction [%s] failed."
 msgstr ""
 
-#: mod/uimport.php:58
+#: mod/profile_photo.php:125
 msgid ""
-"You need to export your account from the old server and upload it here. We "
-"will recreate your old account here with all your contacts. We will try also "
-"to inform your friends that you moved here."
+"Shift-reload the page or clear browser cache if the new photo does not "
+"display immediately."
 msgstr ""
 
-#: mod/uimport.php:59
-msgid ""
-"This feature is experimental. We can't import contacts from the OStatus "
-"network (GNU Social/Statusnet) or from Diaspora"
+#: mod/profile_photo.php:133
+msgid "Unable to process image"
 msgstr ""
 
-#: mod/uimport.php:60
-msgid "Account file"
+#: mod/profile_photo.php:152 mod/photos.php:674 mod/photos.php:677
+#: mod/photos.php:706 mod/wall_upload.php:186
+#, php-format
+msgid "Image exceeds size limit of %s"
 msgstr ""
 
-#: mod/uimport.php:60
-msgid ""
-"To export your account, go to \"Settings->Export your personal data\" and "
-"select \"Export account\""
+#: mod/profile_photo.php:161 mod/photos.php:729 mod/wall_upload.php:200
+msgid "Unable to process image."
 msgstr ""
 
-#: mod/unfollow.php:36 mod/unfollow.php:92
-msgid "You aren't following this contact."
+#: mod/profile_photo.php:244
+msgid "Upload File:"
 msgstr ""
 
-#: mod/unfollow.php:46 mod/unfollow.php:98
-msgid "Unfollowing is currently not supported by your network."
+#: mod/profile_photo.php:245
+msgid "Select a profile:"
 msgstr ""
 
-#: mod/unfollow.php:67
-msgid "Contact unfollowed"
+#: mod/profile_photo.php:246 mod/profiles.php:583 src/Module/Welcome.php:39
+msgid "Upload Profile Photo"
 msgstr ""
 
-#: mod/unfollow.php:118
-msgid "Disconnect/Unfollow"
+#: mod/profile_photo.php:247 mod/fbrowser.php:112 mod/fbrowser.php:141
+msgid "Upload"
 msgstr ""
 
-#: mod/unfollow.php:128 mod/dfrn_request.php:647 mod/follow.php:170
-msgid "Your Identity Address:"
+#: mod/profile_photo.php:250
+msgid "or"
 msgstr ""
 
-#: mod/unfollow.php:131 mod/dfrn_request.php:649 mod/follow.php:76
-msgid "Submit Request"
+#: mod/profile_photo.php:251
+msgid "skip this step"
 msgstr ""
 
-#: mod/unfollow.php:137 mod/follow.php:179 mod/notifications.php:190
-#: mod/notifications.php:282 src/Module/Admin/Blocklist/Contact.php:83
-#: src/Module/Contact.php:603
-msgid "Profile URL"
+#: mod/profile_photo.php:251
+msgid "select a photo from your photo albums"
 msgstr ""
 
-#: mod/unfollow.php:147 mod/follow.php:195 src/Model/Profile.php:920
-#: src/Module/Contact.php:842
-msgid "Status Messages and Posts"
+#: mod/profile_photo.php:264
+msgid "Crop Image"
 msgstr ""
 
-#: mod/update_community.php:23 mod/update_contact.php:23
-#: mod/update_display.php:24 mod/update_network.php:33 mod/update_notes.php:36
-#: mod/update_profile.php:34
-msgid "[Embedded content - reload page to view]"
+#: mod/profile_photo.php:265
+msgid "Please adjust the image cropping for optimum viewing."
 msgstr ""
 
-#: mod/wall_attach.php:26 mod/wall_attach.php:33 mod/wall_attach.php:85
-#: mod/wall_upload.php:42 mod/wall_upload.php:58 mod/wall_upload.php:116
-#: mod/wall_upload.php:167 mod/wall_upload.php:170
-msgid "Invalid request."
+#: mod/profile_photo.php:267
+msgid "Done Editing"
 msgstr ""
 
-#: mod/wall_attach.php:103
-msgid "Sorry, maybe your upload is bigger than the PHP configuration allows"
+#: mod/profile_photo.php:301
+msgid "Image uploaded successfully."
 msgstr ""
 
-#: mod/wall_attach.php:103
-msgid "Or - did you try to upload an empty file?"
+#: mod/profile_photo.php:303 mod/photos.php:758 mod/wall_upload.php:239
+msgid "Image upload failed."
 msgstr ""
 
-#: mod/wall_attach.php:114
-#, php-format
-msgid "File exceeds size limit of %s"
+#: mod/suggest.php:28
+msgid "Contact suggestion successfully ignored."
 msgstr ""
 
-#: mod/wall_attach.php:129
-msgid "File upload failed."
+#: mod/suggest.php:52
+msgid ""
+"No suggestions available. If this is a new site, please try again in 24 "
+"hours."
 msgstr ""
 
-#: mod/wall_upload.php:198 mod/photos.php:683 mod/photos.php:686
-#: mod/photos.php:715 mod/profile_photo.php:152
-#, php-format
-msgid "Image exceeds size limit of %s"
+#: mod/suggest.php:71
+msgid "Do you really want to delete this suggestion?"
 msgstr ""
 
-#: mod/wall_upload.php:212 mod/photos.php:738 mod/profile_photo.php:161
-msgid "Unable to process image."
+#: mod/suggest.php:89 mod/suggest.php:109
+msgid "Ignore/Hide"
 msgstr ""
 
-#: mod/wall_upload.php:243
-msgid "Wall Photos"
+#: mod/suggest.php:106 mod/match.php:102 src/Content/Widget.php:43
+#: src/Module/AllFriends.php:91 src/Module/BaseSearchModule.php:135
+msgid "Connect"
 msgstr ""
 
-#: mod/wall_upload.php:251 mod/photos.php:767 mod/profile_photo.php:303
-msgid "Image upload failed."
+#: mod/suggest.php:119 view/theme/vier/theme.php:181 src/Content/Widget.php:70
+msgid "Friend Suggestions"
 msgstr ""
 
-#: mod/wallmessage.php:52 mod/wallmessage.php:115
-#, php-format
-msgid "Number of daily wall messages for %s exceeded. Message failed."
+#: mod/api.php:85 mod/api.php:107
+msgid "Authorize application connection"
 msgstr ""
 
-#: mod/wallmessage.php:60 mod/message.php:70
-msgid "No recipient selected."
+#: mod/api.php:86
+msgid "Return to your app and insert this Securty Code:"
 msgstr ""
 
-#: mod/wallmessage.php:63
-msgid "Unable to check your home location."
+#: mod/api.php:95 src/Module/BaseAdminModule.php:56
+msgid "Please login to continue."
 msgstr ""
 
-#: mod/wallmessage.php:66 mod/message.php:77
-msgid "Message could not be sent."
+#: mod/api.php:109
+msgid ""
+"Do you want to authorize this application to access your posts and contacts, "
+"and/or create new posts for you?"
 msgstr ""
 
-#: mod/wallmessage.php:69 mod/message.php:80
-msgid "Message collection failure."
+#: mod/api.php:111 mod/dfrn_request.php:642 mod/follow.php:163
+#: mod/profiles.php:526 mod/profiles.php:530 mod/profiles.php:551
+#: mod/settings.php:1081 mod/settings.php:1087 mod/settings.php:1094
+#: mod/settings.php:1098 mod/settings.php:1102 mod/settings.php:1106
+#: mod/settings.php:1110 mod/settings.php:1114 mod/settings.php:1134
+#: mod/settings.php:1135 mod/settings.php:1136 mod/settings.php:1137
+#: mod/settings.php:1138 src/Module/Register.php:92
+msgid "No"
 msgstr ""
 
-#: mod/wallmessage.php:72 mod/message.php:83
-msgid "Message sent."
+#: mod/cal.php:31 mod/cal.php:35 mod/community.php:32 mod/follow.php:20
+#: src/Module/Debug/ItemBody.php:18 src/Module/Diaspora/Receive.php:39
+#: src/Module/Item/Ignore.php:25
+msgid "Access denied."
 msgstr ""
 
-#: mod/wallmessage.php:89 mod/wallmessage.php:98
-msgid "No recipient."
+#: mod/cal.php:130 mod/display.php:296 src/Module/Profile.php:175
+msgid "Access to this profile has been restricted."
 msgstr ""
 
-#: mod/wallmessage.php:123 mod/message.php:204 mod/message.php:360
-msgid "Please enter a link URL:"
+#: mod/cal.php:261 mod/events.php:389 view/theme/frio/theme.php:271
+#: view/theme/frio/theme.php:275 src/Content/Nav.php:164
+#: src/Content/Nav.php:228 src/Model/Profile.php:949 src/Model/Profile.php:960
+msgid "Events"
 msgstr ""
 
-#: mod/wallmessage.php:128 mod/message.php:246
-msgid "Send Private Message"
+#: mod/cal.php:262 mod/events.php:390
+msgid "View"
 msgstr ""
 
-#: mod/wallmessage.php:129
-#, php-format
-msgid ""
-"If you wish for %s to respond, please check that the privacy settings on "
-"your site allow private mail from unknown senders."
+#: mod/cal.php:263 mod/events.php:392
+msgid "Previous"
 msgstr ""
 
-#: mod/wallmessage.php:130 mod/message.php:247 mod/message.php:430
-msgid "To:"
+#: mod/cal.php:264 mod/events.php:393 src/Module/Install.php:174
+msgid "Next"
 msgstr ""
 
-#: mod/wallmessage.php:131 mod/message.php:251 mod/message.php:432
-msgid "Subject:"
+#: mod/cal.php:267 mod/events.php:398 src/Model/Event.php:429
+msgid "today"
 msgstr ""
 
-#: mod/wallmessage.php:137 mod/message.php:255 mod/message.php:435
-#: src/Module/Invite.php:150
-msgid "Your message:"
+#: mod/cal.php:268 mod/events.php:399 src/Util/Temporal.php:313
+#: src/Model/Event.php:430
+msgid "month"
 msgstr ""
 
-#: mod/wallmessage.php:140 mod/editpost.php:76 mod/message.php:259
-#: mod/message.php:440
-msgid "Insert web link"
+#: mod/cal.php:269 mod/events.php:400 src/Util/Temporal.php:314
+#: src/Model/Event.php:431
+msgid "week"
 msgstr ""
 
-#: mod/match.php:49
-msgid "No keywords to match. Please add keywords to your default profile."
+#: mod/cal.php:270 mod/events.php:401 src/Util/Temporal.php:315
+#: src/Model/Event.php:432
+msgid "day"
 msgstr ""
 
-#: mod/match.php:102 mod/suggest.php:106 src/Content/Widget.php:42
-#: src/Module/AllFriends.php:91 src/Module/BaseSearchModule.php:131
-msgid "Connect"
+#: mod/cal.php:271 mod/events.php:402
+msgid "list"
 msgstr ""
 
-#: mod/match.php:115 src/Content/Pager.php:198
-msgid "first"
+#: mod/cal.php:284 src/Model/User.php:415 src/Console/NewPassword.php:88
+msgid "User not found"
 msgstr ""
 
-#: mod/match.php:120 src/Content/Pager.php:258
-msgid "next"
+#: mod/cal.php:300
+msgid "This calendar format is not supported"
 msgstr ""
 
-#: mod/match.php:130 src/Module/BaseSearchModule.php:92
-msgid "No matches"
+#: mod/cal.php:302
+msgid "No exportable data found"
 msgstr ""
 
-#: mod/match.php:135
-msgid "Profile Match"
+#: mod/cal.php:319
+msgid "calendar"
 msgstr ""
 
-#: mod/profiles.php:43 mod/profiles.php:152 mod/profiles.php:196
-#: mod/profiles.php:511 mod/dfrn_confirm.php:70
-msgid "Profile not found."
+#: mod/common.php:90
+msgid "No contacts in common."
 msgstr ""
 
-#: mod/profiles.php:62
-msgid "Profile deleted."
+#: mod/common.php:141 src/Module/Contact.php:891
+msgid "Common Friends"
 msgstr ""
 
-#: mod/profiles.php:78 mod/profiles.php:114
-msgid "Profile-"
+#: mod/community.php:25 mod/dfrn_request.php:599 mod/display.php:200
+#: mod/photos.php:841 mod/videos.php:115 src/Module/Debug/Probe.php:20
+#: src/Module/Debug/WebFinger.php:19 src/Module/Search/Index.php:31
+#: src/Module/Search/Index.php:36 src/Module/Directory.php:31
+msgid "Public access denied."
 msgstr ""
 
-#: mod/profiles.php:97 mod/profiles.php:135
-msgid "New profile created."
+#: mod/community.php:68
+msgid "Community option not available."
 msgstr ""
 
-#: mod/profiles.php:120
-msgid "Profile unavailable to clone."
+#: mod/community.php:85
+msgid "Not available."
 msgstr ""
 
-#: mod/profiles.php:206
-msgid "Profile Name is required."
+#: mod/community.php:95
+msgid "Local Community"
 msgstr ""
 
-#: mod/profiles.php:346
-msgid "Marital Status"
+#: mod/community.php:98
+msgid "Posts from local users on this server"
 msgstr ""
 
-#: mod/profiles.php:349
-msgid "Romantic Partner"
+#: mod/community.php:106
+msgid "Global Community"
 msgstr ""
 
-#: mod/profiles.php:358
-msgid "Work/Employment"
+#: mod/community.php:109
+msgid "Posts from users of the whole federated network"
 msgstr ""
 
-#: mod/profiles.php:361
-msgid "Religion"
+#: mod/community.php:155 src/Module/Search/Index.php:178
+msgid "No results."
 msgstr ""
 
-#: mod/profiles.php:364
-msgid "Political Views"
+#: mod/community.php:207
+msgid ""
+"This community stream shows all public posts received by this node. They may "
+"not reflect the opinions of this node’s users."
 msgstr ""
 
-#: mod/profiles.php:367
-msgid "Gender"
+#: mod/crepair.php:79
+msgid "Contact settings applied."
 msgstr ""
 
-#: mod/profiles.php:370
-msgid "Sexual Preference"
+#: mod/crepair.php:81
+msgid "Contact update failed."
 msgstr ""
 
-#: mod/profiles.php:373
-msgid "XMPP"
+#: mod/crepair.php:102 mod/dfrn_confirm.php:126 mod/fsuggest.php:32
+#: mod/fsuggest.php:75 mod/redir.php:32 mod/redir.php:122 mod/redir.php:137
+#: src/Module/Group.php:92 src/Module/FollowConfirm.php:46
+msgid "Contact not found."
 msgstr ""
 
-#: mod/profiles.php:376
-msgid "Homepage"
+#: mod/crepair.php:115
+msgid ""
+"<strong>WARNING: This is highly advanced</strong> and if you enter incorrect "
+"information your communications with this contact may stop working."
 msgstr ""
 
-#: mod/profiles.php:379 mod/profiles.php:578
-msgid "Interests"
+#: mod/crepair.php:116
+msgid ""
+"Please use your browser 'Back' button <strong>now</strong> if you are "
+"uncertain what to do on this page."
 msgstr ""
 
-#: mod/profiles.php:382
-msgid "Address"
+#: mod/crepair.php:130 mod/crepair.php:132
+msgid "No mirroring"
 msgstr ""
 
-#: mod/profiles.php:389 mod/profiles.php:574
-msgid "Location"
+#: mod/crepair.php:130
+msgid "Mirror as forwarded posting"
 msgstr ""
 
-#: mod/profiles.php:469
-msgid "Profile updated."
+#: mod/crepair.php:130 mod/crepair.php:132
+msgid "Mirror as my own posting"
 msgstr ""
 
-#: mod/profiles.php:523
-msgid "Hide contacts and friends:"
+#: mod/crepair.php:145
+msgid "Return to contact editor"
 msgstr ""
 
-#: mod/profiles.php:528
-msgid "Hide your contact/friend list from viewers of this profile?"
+#: mod/crepair.php:147
+msgid "Refetch contact data"
 msgstr ""
 
-#: mod/profiles.php:548
-msgid "Show more profile fields:"
+#: mod/crepair.php:149 mod/events.php:558 mod/fsuggest.php:92
+#: mod/message.php:261 mod/message.php:441 mod/photos.php:956
+#: mod/photos.php:1066 mod/photos.php:1352 mod/photos.php:1397
+#: mod/photos.php:1436 mod/photos.php:1501 mod/poke.php:185
+#: mod/profiles.php:562 view/theme/duepuntozero/config.php:72
+#: view/theme/frio/config.php:127 view/theme/quattro/config.php:74
+#: view/theme/vier/config.php:122 src/Module/Debug/Localtime.php:45
+#: src/Module/Invite.php:157 src/Module/Item/Compose.php:182
+#: src/Module/Contact.php:581 src/Module/Delegation.php:131
+#: src/Module/Install.php:212 src/Module/Install.php:252
+#: src/Module/Install.php:288 src/Object/Post.php:884
+msgid "Submit"
 msgstr ""
 
-#: mod/profiles.php:560
-msgid "Profile Actions"
+#: mod/crepair.php:150
+msgid "Remote Self"
 msgstr ""
 
-#: mod/profiles.php:561
-msgid "Edit Profile Details"
+#: mod/crepair.php:153
+msgid "Mirror postings from this contact"
 msgstr ""
 
-#: mod/profiles.php:562 mod/crepair.php:149 mod/fsuggest.php:92
-#: mod/manage.php:183 mod/message.php:261 mod/message.php:441
-#: mod/photos.php:991 mod/photos.php:1101 mod/photos.php:1387
-#: mod/photos.php:1432 mod/photos.php:1471 mod/photos.php:1531 mod/poke.php:184
-#: mod/events.php:552 view/theme/duepuntozero/config.php:72
-#: view/theme/frio/config.php:127 view/theme/quattro/config.php:74
-#: view/theme/vier/config.php:120 src/Module/Debug/Localtime.php:45
-#: src/Module/Invite.php:157 src/Module/Item/Compose.php:178
-#: src/Module/Contact.php:560 src/Module/Install.php:212
-#: src/Module/Install.php:252 src/Module/Install.php:288
-#: src/Object/Post.php:879
-msgid "Submit"
+#: mod/crepair.php:155
+msgid ""
+"Mark this contact as remote_self, this will cause friendica to repost new "
+"entries from this contact."
 msgstr ""
 
-#: mod/profiles.php:563
-msgid "Change Profile Photo"
+#: mod/crepair.php:159 mod/settings.php:671 mod/settings.php:697
+#: src/Module/Admin/Blocklist/Contact.php:73 src/Module/Admin/Users.php:272
+#: src/Module/Admin/Users.php:283 src/Module/Admin/Users.php:297
+#: src/Module/Admin/Users.php:313
+msgid "Name"
 msgstr ""
 
-#: mod/profiles.php:565
-msgid "View this profile"
+#: mod/crepair.php:160
+msgid "Account Nickname"
 msgstr ""
 
-#: mod/profiles.php:566
-msgid "View all profiles"
+#: mod/crepair.php:161
+msgid "@Tagname - overrides Name/Nickname"
 msgstr ""
 
-#: mod/profiles.php:567 mod/profiles.php:662 src/Model/Profile.php:423
-msgid "Edit visibility"
+#: mod/crepair.php:162
+msgid "Account URL"
 msgstr ""
 
-#: mod/profiles.php:568
-msgid "Create a new profile using these settings"
+#: mod/crepair.php:163
+msgid "Account URL Alias"
 msgstr ""
 
-#: mod/profiles.php:569
-msgid "Clone this profile"
+#: mod/crepair.php:164
+msgid "Friend Request URL"
 msgstr ""
 
-#: mod/profiles.php:570
-msgid "Delete this profile"
+#: mod/crepair.php:165
+msgid "Friend Confirm URL"
 msgstr ""
 
-#: mod/profiles.php:572
-msgid "Basic information"
+#: mod/crepair.php:166
+msgid "Notification Endpoint URL"
 msgstr ""
 
-#: mod/profiles.php:573
-msgid "Profile picture"
+#: mod/crepair.php:167
+msgid "Poll/Feed URL"
 msgstr ""
 
-#: mod/profiles.php:575
-msgid "Preferences"
+#: mod/crepair.php:168
+msgid "New photo from this URL"
 msgstr ""
 
-#: mod/profiles.php:576
-msgid "Status information"
+#: mod/dfrn_confirm.php:71 mod/profiles.php:43 mod/profiles.php:152
+#: mod/profiles.php:196 mod/profiles.php:511
+msgid "Profile not found."
 msgstr ""
 
-#: mod/profiles.php:577
-msgid "Additional information"
+#: mod/dfrn_confirm.php:127
+msgid ""
+"This may occasionally happen if contact was requested by both persons and it "
+"has already been approved."
 msgstr ""
 
-#: mod/profiles.php:579 mod/network.php:992
-#: src/Core/NotificationsManager.php:158
-msgid "Personal"
+#: mod/dfrn_confirm.php:228
+msgid "Response from remote site was not understood."
 msgstr ""
 
-#: mod/profiles.php:580
-msgid "Relation"
+#: mod/dfrn_confirm.php:235 mod/dfrn_confirm.php:241
+msgid "Unexpected response from remote site: "
 msgstr ""
 
-#: mod/profiles.php:581 src/Util/Temporal.php:79 src/Util/Temporal.php:81
-msgid "Miscellaneous"
+#: mod/dfrn_confirm.php:250
+msgid "Confirmation completed successfully."
 msgstr ""
 
-#: mod/profiles.php:583 mod/profile_photo.php:246 src/Module/Welcome.php:39
-msgid "Upload Profile Photo"
+#: mod/dfrn_confirm.php:262
+msgid "Temporary failure. Please wait and try again."
 msgstr ""
 
-#: mod/profiles.php:584
-msgid "Your Gender:"
+#: mod/dfrn_confirm.php:265
+msgid "Introduction failed or was revoked."
 msgstr ""
 
-#: mod/profiles.php:585
-msgid "<span class=\"heart\">&hearts;</span> Marital Status:"
+#: mod/dfrn_confirm.php:270
+msgid "Remote site reported: "
 msgstr ""
 
-#: mod/profiles.php:586 src/Model/Profile.php:808
-msgid "Sexual Preference:"
+#: mod/dfrn_confirm.php:375
+#, php-format
+msgid "No user record found for '%s' "
 msgstr ""
 
-#: mod/profiles.php:587
-msgid "Example: fishing photography software"
+#: mod/dfrn_confirm.php:385
+msgid "Our site encryption key is apparently messed up."
 msgstr ""
 
-#: mod/profiles.php:592
-msgid "Profile Name:"
+#: mod/dfrn_confirm.php:396
+msgid "Empty site URL was provided or URL could not be decrypted by us."
 msgstr ""
 
-#: mod/profiles.php:592 mod/events.php:510 mod/events.php:542
-msgid "Required"
+#: mod/dfrn_confirm.php:412
+msgid "Contact record was not found for you on our site."
 msgstr ""
 
-#: mod/profiles.php:594
+#: mod/dfrn_confirm.php:426
+#, php-format
+msgid "Site public key not available in contact record for URL %s."
+msgstr ""
+
+#: mod/dfrn_confirm.php:442
 msgid ""
-"This is your <strong>public</strong> profile.<br />It <strong>may</strong> "
-"be visible to anybody using the internet."
+"The ID provided by your system is a duplicate on our system. It should work "
+"if you try again."
 msgstr ""
 
-#: mod/profiles.php:595
-msgid "Your Full Name:"
+#: mod/dfrn_confirm.php:453
+msgid "Unable to set your contact credentials on our system."
 msgstr ""
 
-#: mod/profiles.php:596
-msgid "Title/Description:"
+#: mod/dfrn_confirm.php:509
+msgid "Unable to update your contact profile details on our system"
 msgstr ""
 
-#: mod/profiles.php:599
-msgid "Street Address:"
+#: mod/dfrn_confirm.php:539 mod/dfrn_request.php:562 src/Model/Contact.php:2589
+msgid "[Name Withheld]"
 msgstr ""
 
-#: mod/profiles.php:600
-msgid "Locality/City:"
+#: mod/dfrn_poll.php:123 mod/dfrn_poll.php:526
+#, php-format
+msgid "%1$s welcomes %2$s"
 msgstr ""
 
-#: mod/profiles.php:601
-msgid "Region/State:"
+#: mod/dfrn_request.php:100
+msgid "This introduction has already been accepted."
 msgstr ""
 
-#: mod/profiles.php:602
-msgid "Postal/Zip Code:"
+#: mod/dfrn_request.php:118 mod/dfrn_request.php:356
+msgid "Profile location is not valid or does not contain profile information."
 msgstr ""
 
-#: mod/profiles.php:603
-msgid "Country:"
+#: mod/dfrn_request.php:122 mod/dfrn_request.php:360
+msgid "Warning: profile location has no identifiable owner name."
 msgstr ""
 
-#: mod/profiles.php:604 src/Util/Temporal.php:149
-msgid "Age: "
+#: mod/dfrn_request.php:125 mod/dfrn_request.php:363
+msgid "Warning: profile location has no profile photo."
 msgstr ""
 
-#: mod/profiles.php:607
-msgid "Who: (if applicable)"
-msgstr ""
+#: mod/dfrn_request.php:129 mod/dfrn_request.php:367
+#, php-format
+msgid "%d required parameter was not found at the given location"
+msgid_plural "%d required parameters were not found at the given location"
+msgstr[0] ""
+msgstr[1] ""
 
-#: mod/profiles.php:607
-msgid "Examples: cathy123, Cathy Williams, cathy@example.com"
+#: mod/dfrn_request.php:167
+msgid "Introduction complete."
 msgstr ""
 
-#: mod/profiles.php:608
-msgid "Since [date]:"
+#: mod/dfrn_request.php:203
+msgid "Unrecoverable protocol error."
 msgstr ""
 
-#: mod/profiles.php:610
-msgid "Tell us about yourself..."
+#: mod/dfrn_request.php:230
+msgid "Profile unavailable."
 msgstr ""
 
-#: mod/profiles.php:611
-msgid "XMPP (Jabber) address:"
+#: mod/dfrn_request.php:251
+#, php-format
+msgid "%s has received too many connection requests today."
 msgstr ""
 
-#: mod/profiles.php:611
-msgid ""
-"The XMPP address will be propagated to your contacts so that they can follow "
-"you."
+#: mod/dfrn_request.php:252
+msgid "Spam protection measures have been invoked."
 msgstr ""
 
-#: mod/profiles.php:612
-msgid "Homepage URL:"
+#: mod/dfrn_request.php:253
+msgid "Friends are advised to please try again in 24 hours."
 msgstr ""
 
-#: mod/profiles.php:613 src/Model/Profile.php:816
-msgid "Hometown:"
+#: mod/dfrn_request.php:277
+msgid "Invalid locator"
 msgstr ""
 
-#: mod/profiles.php:614 src/Model/Profile.php:824
-msgid "Political Views:"
+#: mod/dfrn_request.php:313
+msgid "You have already introduced yourself here."
 msgstr ""
 
-#: mod/profiles.php:615
-msgid "Religious Views:"
+#: mod/dfrn_request.php:316
+#, php-format
+msgid "Apparently you are already friends with %s."
 msgstr ""
 
-#: mod/profiles.php:616
-msgid "Public Keywords:"
+#: mod/dfrn_request.php:336
+msgid "Invalid profile URL."
 msgstr ""
 
-#: mod/profiles.php:616
-msgid "(Used for suggesting potential friends, can be seen by others)"
+#: mod/dfrn_request.php:342 src/Model/Contact.php:2212
+msgid "Disallowed profile URL."
 msgstr ""
 
-#: mod/profiles.php:617
-msgid "Private Keywords:"
+#: mod/dfrn_request.php:348 src/Model/Contact.php:2217
+#: src/Module/Friendica.php:59
+msgid "Blocked domain"
 msgstr ""
 
-#: mod/profiles.php:617
-msgid "(Used for searching profiles, never shown to others)"
+#: mod/dfrn_request.php:415 src/Module/Contact.php:143
+msgid "Failed to update contact record."
 msgstr ""
 
-#: mod/profiles.php:618 src/Model/Profile.php:840
-msgid "Likes:"
+#: mod/dfrn_request.php:435
+msgid "Your introduction has been sent."
 msgstr ""
 
-#: mod/profiles.php:619 src/Model/Profile.php:844
-msgid "Dislikes:"
+#: mod/dfrn_request.php:473
+msgid ""
+"Remote subscription can't be done for your network. Please subscribe "
+"directly on your system."
 msgstr ""
 
-#: mod/profiles.php:620
-msgid "Musical interests"
+#: mod/dfrn_request.php:489
+msgid "Please login to confirm introduction."
 msgstr ""
 
-#: mod/profiles.php:621
-msgid "Books, literature"
+#: mod/dfrn_request.php:497
+msgid ""
+"Incorrect identity currently logged in. Please login to <strong>this</"
+"strong> profile."
 msgstr ""
 
-#: mod/profiles.php:622
-msgid "Television"
+#: mod/dfrn_request.php:511 mod/dfrn_request.php:526
+msgid "Confirm"
 msgstr ""
 
-#: mod/profiles.php:623
-msgid "Film/dance/culture/entertainment"
+#: mod/dfrn_request.php:522
+msgid "Hide this contact"
 msgstr ""
 
-#: mod/profiles.php:624
-msgid "Hobbies/Interests"
+#: mod/dfrn_request.php:524
+#, php-format
+msgid "Welcome home %s."
 msgstr ""
 
-#: mod/profiles.php:625
-msgid "Love/romance"
+#: mod/dfrn_request.php:525
+#, php-format
+msgid "Please confirm your introduction/connection request to %s."
 msgstr ""
 
-#: mod/profiles.php:626
-msgid "Work/employment"
+#: mod/dfrn_request.php:634
+msgid ""
+"Please enter your 'Identity Address' from one of the following supported "
+"communications networks:"
 msgstr ""
 
-#: mod/profiles.php:627
-msgid "School/education"
+#: mod/dfrn_request.php:636
+#, php-format
+msgid ""
+"If you are not yet a member of the free social web, <a href=\"%s\">follow "
+"this link to find a public Friendica site and join us today</a>."
 msgstr ""
 
-#: mod/profiles.php:628
-msgid "Contact information and Social Networks"
+#: mod/dfrn_request.php:639
+msgid "Friend/Connection Request"
 msgstr ""
 
-#: mod/profiles.php:659 src/Model/Profile.php:419
-msgid "Profile Image"
+#: mod/dfrn_request.php:640
+msgid ""
+"Examples: jojo@demo.friendica.com, http://demo.friendica.com/profile/jojo, "
+"testuser@gnusocial.de"
 msgstr ""
 
-#: mod/profiles.php:661 src/Model/Profile.php:422
-msgid "visible to everybody"
+#: mod/dfrn_request.php:641 mod/follow.php:162
+msgid "Please answer the following:"
 msgstr ""
 
-#: mod/profiles.php:668
-msgid "Edit/Manage Profiles"
+#: mod/dfrn_request.php:642 mod/follow.php:163
+#, php-format
+msgid "Does %s know you?"
 msgstr ""
 
-#: mod/profiles.php:669 src/Model/Profile.php:409 src/Model/Profile.php:430
-msgid "Change profile photo"
+#: mod/dfrn_request.php:643 mod/follow.php:164
+msgid "Add a personal note:"
 msgstr ""
 
-#: mod/profiles.php:670 src/Model/Profile.php:410
-msgid "Create New Profile"
+#: mod/dfrn_request.php:645
+msgid "Friendica"
 msgstr ""
 
-#: mod/cal.php:34 mod/cal.php:38 mod/community.php:40 mod/follow.php:20
-#: src/Module/Debug/ItemBody.php:18
-msgid "Access denied."
+#: mod/dfrn_request.php:646
+msgid "GNU Social (Pleroma, Mastodon)"
 msgstr ""
 
-#: mod/cal.php:140 mod/display.php:303 src/Module/Profile.php:185
-msgid "Access to this profile has been restricted."
+#: mod/dfrn_request.php:647
+msgid "Diaspora (Socialhome, Hubzilla)"
 msgstr ""
 
-#: mod/cal.php:271 mod/events.php:383 view/theme/frio/theme.php:271
-#: view/theme/frio/theme.php:275 src/Content/Nav.php:164
-#: src/Content/Nav.php:228 src/Model/Profile.php:953 src/Model/Profile.php:964
-msgid "Events"
+#: mod/dfrn_request.php:648
+#, php-format
+msgid ""
+" - please do not use this form.  Instead, enter %s into your Diaspora search "
+"bar."
 msgstr ""
 
-#: mod/cal.php:272 mod/events.php:384
-msgid "View"
+#: mod/dfrn_request.php:649 mod/follow.php:170 mod/unfollow.php:128
+msgid "Your Identity Address:"
 msgstr ""
 
-#: mod/cal.php:273 mod/events.php:386
-msgid "Previous"
+#: mod/dfrn_request.php:651 mod/follow.php:76 mod/unfollow.php:131
+msgid "Submit Request"
 msgstr ""
 
-#: mod/cal.php:274 mod/events.php:387 src/Module/Install.php:174
-msgid "Next"
+#: mod/display.php:255 mod/display.php:332
+msgid "The requested item doesn't exist or has been deleted."
 msgstr ""
 
-#: mod/cal.php:277 mod/events.php:392 src/Model/Event.php:428
-msgid "today"
+#: mod/display.php:410
+msgid "The feed for this item is unavailable."
 msgstr ""
 
-#: mod/cal.php:278 mod/events.php:393 src/Util/Temporal.php:314
-#: src/Model/Event.php:429
-msgid "month"
+#: mod/editpost.php:29 mod/editpost.php:39
+msgid "Item not found"
 msgstr ""
 
-#: mod/cal.php:279 mod/events.php:394 src/Util/Temporal.php:315
-#: src/Model/Event.php:430
-msgid "week"
+#: mod/editpost.php:46
+msgid "Edit post"
 msgstr ""
 
-#: mod/cal.php:280 mod/events.php:395 src/Util/Temporal.php:316
-#: src/Model/Event.php:431
-msgid "day"
+#: mod/editpost.php:77 mod/message.php:259 mod/message.php:440
+#: mod/wallmessage.php:140
+msgid "Insert web link"
 msgstr ""
 
-#: mod/cal.php:281 mod/events.php:396
-msgid "list"
+#: mod/editpost.php:78
+msgid "web link"
 msgstr ""
 
-#: mod/cal.php:294 src/Model/User.php:384 src/Console/NewPassword.php:88
-msgid "User not found"
+#: mod/editpost.php:79
+msgid "Insert video link"
 msgstr ""
 
-#: mod/cal.php:310
-msgid "This calendar format is not supported"
+#: mod/editpost.php:80
+msgid "video link"
 msgstr ""
 
-#: mod/cal.php:312
-msgid "No exportable data found"
+#: mod/editpost.php:81
+msgid "Insert audio link"
 msgstr ""
 
-#: mod/cal.php:329
-msgid "calendar"
+#: mod/editpost.php:82
+msgid "audio link"
 msgstr ""
 
-#: mod/common.php:90
-msgid "No contacts in common."
+#: mod/editpost.php:96 src/Core/ACL.php:309 src/Module/Item/Compose.php:204
+msgid "CC: email addresses"
 msgstr ""
 
-#: mod/common.php:141 src/Module/Contact.php:870
-msgid "Common Friends"
+#: mod/editpost.php:103 src/Core/ACL.php:310
+msgid "Example: bob@example.com, mary@example.com"
 msgstr ""
 
-#: mod/community.php:33 mod/dfrn_request.php:597 mod/photos.php:850
-#: mod/search.php:87 mod/search.php:93 mod/videos.php:118 mod/display.php:201
-#: src/Module/Debug/Probe.php:20 src/Module/Debug/WebFinger.php:19
-#: src/Module/Directory.php:30
-msgid "Public access denied."
+#: mod/events.php:120 mod/events.php:122
+msgid "Event can not end before it has started."
 msgstr ""
 
-#: mod/community.php:76
-msgid "Community option not available."
+#: mod/events.php:129 mod/events.php:131
+msgid "Event title and start time are required."
 msgstr ""
 
-#: mod/community.php:93
-msgid "Not available."
+#: mod/events.php:391
+msgid "Create New Event"
 msgstr ""
 
-#: mod/community.php:103
-msgid "Local Community"
+#: mod/events.php:514
+msgid "Event details"
 msgstr ""
 
-#: mod/community.php:106
-msgid "Posts from local users on this server"
+#: mod/events.php:515
+msgid "Starting date and Title are required."
 msgstr ""
 
-#: mod/community.php:114
-msgid "Global Community"
+#: mod/events.php:516 mod/events.php:521
+msgid "Event Starts:"
 msgstr ""
 
-#: mod/community.php:117
-msgid "Posts from users of the whole federated network"
+#: mod/events.php:516 mod/events.php:548 mod/profiles.php:592
+msgid "Required"
 msgstr ""
 
-#: mod/community.php:163 mod/search.php:222
-msgid "No results."
+#: mod/events.php:529 mod/events.php:554
+msgid "Finish date/time is not known or not relevant"
 msgstr ""
 
-#: mod/community.php:215
-msgid ""
-"This community stream shows all public posts received by this node. They may "
-"not reflect the opinions of this node’s users."
+#: mod/events.php:531 mod/events.php:536
+msgid "Event Finishes:"
 msgstr ""
 
-#: mod/crepair.php:79
-msgid "Contact settings applied."
+#: mod/events.php:542 mod/events.php:555
+msgid "Adjust for viewer timezone"
 msgstr ""
 
-#: mod/crepair.php:81
-msgid "Contact update failed."
+#: mod/events.php:544
+msgid "Description:"
 msgstr ""
 
-#: mod/crepair.php:102 mod/dfrn_confirm.php:125 mod/fsuggest.php:32
-#: mod/fsuggest.php:75 mod/redir.php:32 mod/redir.php:140
-#: src/Module/FollowConfirm.php:46 src/Module/Group.php:92
-msgid "Contact not found."
+#: mod/events.php:546 mod/notifications.php:276 src/Model/Event.php:69
+#: src/Model/Event.php:96 src/Model/Event.php:438 src/Model/Event.php:934
+#: src/Model/Profile.php:443 src/Module/Contact.php:628
+#: src/Module/Directory.php:135
+msgid "Location:"
 msgstr ""
 
-#: mod/crepair.php:115
-msgid ""
-"<strong>WARNING: This is highly advanced</strong> and if you enter incorrect "
-"information your communications with this contact may stop working."
+#: mod/events.php:548 mod/events.php:550
+msgid "Title:"
 msgstr ""
 
-#: mod/crepair.php:116
-msgid ""
-"Please use your browser 'Back' button <strong>now</strong> if you are "
-"uncertain what to do on this page."
+#: mod/events.php:551 mod/events.php:552
+msgid "Share this event"
 msgstr ""
 
-#: mod/crepair.php:130 mod/crepair.php:132
-msgid "No mirroring"
+#: mod/events.php:559 src/Model/Profile.php:886
+msgid "Basic"
 msgstr ""
 
-#: mod/crepair.php:130
-msgid "Mirror as forwarded posting"
+#: mod/events.php:560 src/Model/Profile.php:887 src/Module/Admin/Site.php:573
+#: src/Module/Contact.php:901
+msgid "Advanced"
 msgstr ""
 
-#: mod/crepair.php:130 mod/crepair.php:132
-msgid "Mirror as my own posting"
+#: mod/events.php:561 mod/photos.php:974 mod/photos.php:1348
+#: src/Core/ACL.php:315
+msgid "Permissions"
 msgstr ""
 
-#: mod/crepair.php:145
-msgid "Return to contact editor"
+#: mod/events.php:577
+msgid "Failed to remove event"
 msgstr ""
 
-#: mod/crepair.php:147
-msgid "Refetch contact data"
+#: mod/events.php:579
+msgid "Event removed"
 msgstr ""
 
-#: mod/crepair.php:150
-msgid "Remote Self"
+#: mod/fbrowser.php:43 view/theme/frio/theme.php:269 src/Content/Nav.php:162
+#: src/Model/Profile.php:929
+msgid "Photos"
 msgstr ""
 
-#: mod/crepair.php:153
-msgid "Mirror postings from this contact"
+#: mod/fbrowser.php:52 mod/fbrowser.php:76 mod/photos.php:181
+#: mod/photos.php:938 mod/photos.php:1055 mod/photos.php:1072
+#: mod/photos.php:1554 mod/photos.php:1569 src/Model/Photo.php:560
+#: src/Model/Photo.php:569
+msgid "Contact Photos"
 msgstr ""
 
-#: mod/crepair.php:155
-msgid ""
-"Mark this contact as remote_self, this will cause friendica to repost new "
-"entries from this contact."
+#: mod/fbrowser.php:136
+msgid "Files"
 msgstr ""
 
-#: mod/crepair.php:159 mod/settings.php:679 mod/settings.php:705
-#: src/Module/Admin/Blocklist/Contact.php:73 src/Module/Admin/Users.php:272
-#: src/Module/Admin/Users.php:283 src/Module/Admin/Users.php:297
-#: src/Module/Admin/Users.php:313
-msgid "Name"
+#: mod/follow.php:46
+msgid "The contact could not be added."
 msgstr ""
 
-#: mod/crepair.php:160
-msgid "Account Nickname"
+#: mod/follow.php:87
+msgid "You already added this contact."
 msgstr ""
 
-#: mod/crepair.php:161
-msgid "@Tagname - overrides Name/Nickname"
+#: mod/follow.php:99
+msgid "Diaspora support isn't enabled. Contact can't be added."
 msgstr ""
 
-#: mod/crepair.php:162
-msgid "Account URL"
+#: mod/follow.php:106
+msgid "OStatus support is disabled. Contact can't be added."
 msgstr ""
 
-#: mod/crepair.php:163
-msgid "Account URL Alias"
-msgstr ""
-
-#: mod/crepair.php:164
-msgid "Friend Request URL"
-msgstr ""
-
-#: mod/crepair.php:165
-msgid "Friend Confirm URL"
-msgstr ""
-
-#: mod/crepair.php:166
-msgid "Notification Endpoint URL"
-msgstr ""
-
-#: mod/crepair.php:167
-msgid "Poll/Feed URL"
-msgstr ""
-
-#: mod/crepair.php:168
-msgid "New photo from this URL"
-msgstr ""
-
-#: mod/dfrn_confirm.php:126
-msgid ""
-"This may occasionally happen if contact was requested by both persons and it "
-"has already been approved."
-msgstr ""
-
-#: mod/dfrn_confirm.php:227
-msgid "Response from remote site was not understood."
-msgstr ""
-
-#: mod/dfrn_confirm.php:234 mod/dfrn_confirm.php:240
-msgid "Unexpected response from remote site: "
-msgstr ""
-
-#: mod/dfrn_confirm.php:249
-msgid "Confirmation completed successfully."
-msgstr ""
-
-#: mod/dfrn_confirm.php:261
-msgid "Temporary failure. Please wait and try again."
-msgstr ""
-
-#: mod/dfrn_confirm.php:264
-msgid "Introduction failed or was revoked."
-msgstr ""
-
-#: mod/dfrn_confirm.php:269
-msgid "Remote site reported: "
-msgstr ""
-
-#: mod/dfrn_confirm.php:374
-#, php-format
-msgid "No user record found for '%s' "
-msgstr ""
-
-#: mod/dfrn_confirm.php:384
-msgid "Our site encryption key is apparently messed up."
-msgstr ""
-
-#: mod/dfrn_confirm.php:395
-msgid "Empty site URL was provided or URL could not be decrypted by us."
-msgstr ""
-
-#: mod/dfrn_confirm.php:411
-msgid "Contact record was not found for you on our site."
-msgstr ""
-
-#: mod/dfrn_confirm.php:425
-#, php-format
-msgid "Site public key not available in contact record for URL %s."
-msgstr ""
-
-#: mod/dfrn_confirm.php:441
-msgid ""
-"The ID provided by your system is a duplicate on our system. It should work "
-"if you try again."
-msgstr ""
-
-#: mod/dfrn_confirm.php:452
-msgid "Unable to set your contact credentials on our system."
-msgstr ""
-
-#: mod/dfrn_confirm.php:508
-msgid "Unable to update your contact profile details on our system"
-msgstr ""
-
-#: mod/dfrn_confirm.php:538 mod/dfrn_request.php:560 src/Model/Contact.php:2551
-msgid "[Name Withheld]"
-msgstr ""
-
-#: mod/dfrn_poll.php:125 mod/dfrn_poll.php:530
-#, php-format
-msgid "%1$s welcomes %2$s"
-msgstr ""
-
-#: mod/dfrn_request.php:98
-msgid "This introduction has already been accepted."
-msgstr ""
-
-#: mod/dfrn_request.php:116 mod/dfrn_request.php:354
-msgid "Profile location is not valid or does not contain profile information."
-msgstr ""
-
-#: mod/dfrn_request.php:120 mod/dfrn_request.php:358
-msgid "Warning: profile location has no identifiable owner name."
-msgstr ""
-
-#: mod/dfrn_request.php:123 mod/dfrn_request.php:361
-msgid "Warning: profile location has no profile photo."
-msgstr ""
-
-#: mod/dfrn_request.php:127 mod/dfrn_request.php:365
-#, php-format
-msgid "%d required parameter was not found at the given location"
-msgid_plural "%d required parameters were not found at the given location"
-msgstr[0] ""
-msgstr[1] ""
-
-#: mod/dfrn_request.php:165
-msgid "Introduction complete."
-msgstr ""
-
-#: mod/dfrn_request.php:201
-msgid "Unrecoverable protocol error."
+#: mod/follow.php:113
+msgid "The network type couldn't be detected. Contact can't be added."
 msgstr ""
 
-#: mod/dfrn_request.php:228
-msgid "Profile unavailable."
+#: mod/follow.php:179 mod/notifications.php:194 mod/notifications.php:286
+#: mod/unfollow.php:137 src/Module/Admin/Blocklist/Contact.php:83
+#: src/Module/Contact.php:624
+msgid "Profile URL"
 msgstr ""
 
-#: mod/dfrn_request.php:249
-#, php-format
-msgid "%s has received too many connection requests today."
+#: mod/follow.php:183 mod/notifications.php:280 src/Model/Profile.php:816
+#: src/Module/Contact.php:634
+msgid "Tags:"
 msgstr ""
 
-#: mod/dfrn_request.php:250
-msgid "Spam protection measures have been invoked."
+#: mod/follow.php:195 mod/unfollow.php:147 src/Model/Profile.php:916
+#: src/Module/Contact.php:863
+msgid "Status Messages and Posts"
 msgstr ""
 
-#: mod/dfrn_request.php:251
-msgid "Friends are advised to please try again in 24 hours."
+#: mod/fsuggest.php:44
+msgid "Suggested contact not found."
 msgstr ""
 
-#: mod/dfrn_request.php:275
-msgid "Invalid locator"
+#: mod/fsuggest.php:57
+msgid "Friend suggestion sent."
 msgstr ""
 
-#: mod/dfrn_request.php:311
-msgid "You have already introduced yourself here."
+#: mod/fsuggest.php:79
+msgid "Suggest Friends"
 msgstr ""
 
-#: mod/dfrn_request.php:314
+#: mod/fsuggest.php:81
 #, php-format
-msgid "Apparently you are already friends with %s."
-msgstr ""
-
-#: mod/dfrn_request.php:334
-msgid "Invalid profile URL."
-msgstr ""
-
-#: mod/dfrn_request.php:340 src/Model/Contact.php:2182
-msgid "Disallowed profile URL."
-msgstr ""
-
-#: mod/dfrn_request.php:346 src/Model/Contact.php:2187
-#: src/Module/Friendica.php:59
-msgid "Blocked domain"
-msgstr ""
-
-#: mod/dfrn_request.php:413 src/Module/Contact.php:143
-msgid "Failed to update contact record."
-msgstr ""
-
-#: mod/dfrn_request.php:433
-msgid "Your introduction has been sent."
-msgstr ""
-
-#: mod/dfrn_request.php:471
-msgid ""
-"Remote subscription can't be done for your network. Please subscribe "
-"directly on your system."
-msgstr ""
-
-#: mod/dfrn_request.php:487
-msgid "Please login to confirm introduction."
-msgstr ""
-
-#: mod/dfrn_request.php:495
-msgid ""
-"Incorrect identity currently logged in. Please login to <strong>this</"
-"strong> profile."
-msgstr ""
-
-#: mod/dfrn_request.php:509 mod/dfrn_request.php:524
-msgid "Confirm"
-msgstr ""
-
-#: mod/dfrn_request.php:520
-msgid "Hide this contact"
+msgid "Suggest a friend for %s"
 msgstr ""
 
-#: mod/dfrn_request.php:522
-#, php-format
-msgid "Welcome home %s."
+#: mod/hcard.php:21
+msgid "No profile"
 msgstr ""
 
-#: mod/dfrn_request.php:523
-#, php-format
-msgid "Please confirm your introduction/connection request to %s."
+#: mod/item.php:127
+msgid "Unable to locate original post."
 msgstr ""
 
-#: mod/dfrn_request.php:632
-msgid ""
-"Please enter your 'Identity Address' from one of the following supported "
-"communications networks:"
+#: mod/item.php:330
+msgid "Empty post discarded."
 msgstr ""
 
-#: mod/dfrn_request.php:634
+#: mod/item.php:801
 #, php-format
 msgid ""
-"If you are not yet a member of the free social web, <a href=\"%s\">follow "
-"this link to find a public Friendica site and join us today</a>."
-msgstr ""
-
-#: mod/dfrn_request.php:637
-msgid "Friend/Connection Request"
-msgstr ""
-
-#: mod/dfrn_request.php:638
-msgid ""
-"Examples: jojo@demo.friendica.com, http://demo.friendica.com/profile/jojo, "
-"testuser@gnusocial.de"
-msgstr ""
-
-#: mod/dfrn_request.php:639 mod/follow.php:162
-msgid "Please answer the following:"
+"This message was sent to you by %s, a member of the Friendica social network."
 msgstr ""
 
-#: mod/dfrn_request.php:640 mod/follow.php:163
+#: mod/item.php:803
 #, php-format
-msgid "Does %s know you?"
-msgstr ""
-
-#: mod/dfrn_request.php:641 mod/follow.php:164
-msgid "Add a personal note:"
-msgstr ""
-
-#: mod/dfrn_request.php:643
-msgid "Friendica"
-msgstr ""
-
-#: mod/dfrn_request.php:644
-msgid "GNU Social (Pleroma, Mastodon)"
-msgstr ""
-
-#: mod/dfrn_request.php:645
-msgid "Diaspora (Socialhome, Hubzilla)"
+msgid "You may visit them online at %s"
 msgstr ""
 
-#: mod/dfrn_request.php:646
-#, php-format
+#: mod/item.php:804
 msgid ""
-" - please do not use this form.  Instead, enter %s into your Diaspora search "
-"bar."
-msgstr ""
-
-#: mod/editpost.php:28 mod/editpost.php:38
-msgid "Item not found"
-msgstr ""
-
-#: mod/editpost.php:45
-msgid "Edit post"
-msgstr ""
-
-#: mod/editpost.php:71 mod/notes.php:46 src/Content/Text/HTML.php:887
-#: src/Module/Filer/SaveTag.php:49
-msgid "Save"
-msgstr ""
-
-#: mod/editpost.php:77
-msgid "web link"
-msgstr ""
-
-#: mod/editpost.php:78
-msgid "Insert video link"
-msgstr ""
-
-#: mod/editpost.php:79
-msgid "video link"
-msgstr ""
-
-#: mod/editpost.php:80
-msgid "Insert audio link"
-msgstr ""
-
-#: mod/editpost.php:81
-msgid "audio link"
-msgstr ""
-
-#: mod/editpost.php:95 src/Core/ACL.php:308 src/Module/Item/Compose.php:200
-msgid "CC: email addresses"
-msgstr ""
-
-#: mod/editpost.php:102 src/Core/ACL.php:309
-msgid "Example: bob@example.com, mary@example.com"
-msgstr ""
-
-#: mod/fbrowser.php:43 view/theme/frio/theme.php:269 src/Content/Nav.php:162
-#: src/Model/Profile.php:933
-msgid "Photos"
-msgstr ""
-
-#: mod/fbrowser.php:52 mod/fbrowser.php:76 mod/photos.php:196
-#: mod/photos.php:973 mod/photos.php:1090 mod/photos.php:1107
-#: mod/photos.php:1584 mod/photos.php:1599 src/Model/Photo.php:574
-#: src/Model/Photo.php:583
-msgid "Contact Photos"
-msgstr ""
-
-#: mod/fbrowser.php:112 mod/fbrowser.php:141 mod/profile_photo.php:247
-msgid "Upload"
-msgstr ""
-
-#: mod/fbrowser.php:136
-msgid "Files"
-msgstr ""
-
-#: mod/follow.php:46
-msgid "The contact could not be added."
-msgstr ""
-
-#: mod/follow.php:87
-msgid "You already added this contact."
-msgstr ""
-
-#: mod/follow.php:99
-msgid "Diaspora support isn't enabled. Contact can't be added."
-msgstr ""
-
-#: mod/follow.php:106
-msgid "OStatus support is disabled. Contact can't be added."
-msgstr ""
-
-#: mod/follow.php:113
-msgid "The network type couldn't be detected. Contact can't be added."
-msgstr ""
-
-#: mod/follow.php:183 mod/notifications.php:276 src/Model/Profile.php:820
-#: src/Module/Contact.php:613
-msgid "Tags:"
-msgstr ""
-
-#: mod/fsuggest.php:44
-msgid "Suggested contact not found."
-msgstr ""
-
-#: mod/fsuggest.php:57
-msgid "Friend suggestion sent."
-msgstr ""
-
-#: mod/fsuggest.php:79
-msgid "Suggest Friends"
+"Please contact the sender by replying to this post if you do not wish to "
+"receive these messages."
 msgstr ""
 
-#: mod/fsuggest.php:81
+#: mod/item.php:808
 #, php-format
-msgid "Suggest a friend for %s"
-msgstr ""
-
-#: mod/hcard.php:20
-msgid "No profile"
+msgid "%s posted an update."
 msgstr ""
 
-#: mod/lockview.php:47 mod/lockview.php:58
+#: mod/lockview.php:49 mod/lockview.php:60
 msgid "Remote privacy information not available."
 msgstr ""
 
-#: mod/lockview.php:67
+#: mod/lockview.php:72
 msgid "Visible to:"
 msgstr ""
 
-#: mod/lockview.php:73 mod/lockview.php:108 src/Content/Widget.php:192
-#: src/Module/Item/Compose.php:97 src/Module/Profile/Contacts.php:126
-#: src/Module/Contact.php:771
+#: mod/lockview.php:78 mod/lockview.php:113 src/Content/Widget.php:193
+#: src/Module/Item/Compose.php:101 src/Module/Profile/Contacts.php:126
+#: src/Module/Contact.php:792
 msgid "Followers"
 msgstr ""
 
-#: mod/lockview.php:79 mod/lockview.php:114 src/Module/Item/Compose.php:104
+#: mod/lockview.php:84 mod/lockview.php:119 src/Module/Item/Compose.php:108
 msgid "Mutuals"
 msgstr ""
 
-#: mod/lostpass.php:26
+#: mod/lostpass.php:27
 msgid "No valid account found."
 msgstr ""
 
-#: mod/lostpass.php:38
+#: mod/lostpass.php:39
 msgid "Password reset request issued. Check your email."
 msgstr ""
 
-#: mod/lostpass.php:44
+#: mod/lostpass.php:45
 #, php-format
 msgid ""
 "\n"
@@ -2309,7 +1922,7 @@ msgid ""
 "\t\tissued this request."
 msgstr ""
 
-#: mod/lostpass.php:55
+#: mod/lostpass.php:56
 #, php-format
 msgid ""
 "\n"
@@ -2327,66 +1940,66 @@ msgid ""
 "\t\tLogin Name:\t%3$s"
 msgstr ""
 
-#: mod/lostpass.php:74
+#: mod/lostpass.php:75
 #, php-format
 msgid "Password reset requested at %s"
 msgstr ""
 
-#: mod/lostpass.php:89
+#: mod/lostpass.php:90
 msgid ""
 "Request could not be verified. (You may have previously submitted it.) "
 "Password reset failed."
 msgstr ""
 
-#: mod/lostpass.php:102
+#: mod/lostpass.php:103
 msgid "Request has expired, please make a new one."
 msgstr ""
 
-#: mod/lostpass.php:117
+#: mod/lostpass.php:118
 msgid "Forgot your Password?"
 msgstr ""
 
-#: mod/lostpass.php:118
+#: mod/lostpass.php:119
 msgid ""
 "Enter your email address and submit to have your password reset. Then check "
 "your email for further instructions."
 msgstr ""
 
-#: mod/lostpass.php:119 src/Module/Login.php:318
+#: mod/lostpass.php:120 src/Module/Login.php:355
 msgid "Nickname or Email: "
 msgstr ""
 
-#: mod/lostpass.php:120
+#: mod/lostpass.php:121
 msgid "Reset"
 msgstr ""
 
-#: mod/lostpass.php:135 src/Module/Login.php:330
+#: mod/lostpass.php:136 src/Module/Login.php:367
 msgid "Password Reset"
 msgstr ""
 
-#: mod/lostpass.php:136
+#: mod/lostpass.php:137
 msgid "Your password has been reset as requested."
 msgstr ""
 
-#: mod/lostpass.php:137
+#: mod/lostpass.php:138
 msgid "Your new password is"
 msgstr ""
 
-#: mod/lostpass.php:138
+#: mod/lostpass.php:139
 msgid "Save or copy your new password - and then"
 msgstr ""
 
-#: mod/lostpass.php:139
+#: mod/lostpass.php:140
 msgid "click here to login"
 msgstr ""
 
-#: mod/lostpass.php:140
+#: mod/lostpass.php:141
 msgid ""
 "Your password may be changed from the <em>Settings</em> page after "
 "successful login."
 msgstr ""
 
-#: mod/lostpass.php:147
+#: mod/lostpass.php:148
 #, php-format
 msgid ""
 "\n"
@@ -2397,7 +2010,7 @@ msgid ""
 "\t\t"
 msgstr ""
 
-#: mod/lostpass.php:153
+#: mod/lostpass.php:154
 #, php-format
 msgid ""
 "\n"
@@ -2412,35 +2025,57 @@ msgid ""
 "\t\t"
 msgstr ""
 
-#: mod/lostpass.php:169
+#: mod/lostpass.php:170
 #, php-format
 msgid "Your password has been changed at %s"
 msgstr ""
 
-#: mod/manage.php:179
-msgid "Manage Identities and/or Pages"
+#: mod/match.php:49
+msgid "No keywords to match. Please add keywords to your default profile."
 msgstr ""
 
-#: mod/manage.php:180
-msgid ""
-"Toggle between different identities or community/group pages which share "
-"your account details or which you have been granted \"manage\" permissions"
+#: mod/match.php:115 src/Content/Pager.php:198
+msgid "first"
 msgstr ""
 
-#: mod/manage.php:181
-msgid "Select an identity to manage: "
+#: mod/match.php:120 src/Content/Pager.php:258
+msgid "next"
+msgstr ""
+
+#: mod/match.php:130 src/Module/BaseSearchModule.php:96
+msgid "No matches"
+msgstr ""
+
+#: mod/match.php:135
+msgid "Profile Match"
 msgstr ""
 
 #: mod/message.php:33 mod/message.php:116 src/Content/Nav.php:257
 msgid "New Message"
 msgstr ""
 
+#: mod/message.php:70 mod/wallmessage.php:60
+msgid "No recipient selected."
+msgstr ""
+
 #: mod/message.php:74
 msgid "Unable to locate contact information."
 msgstr ""
 
-#: mod/message.php:110 mod/notifications.php:49 mod/notifications.php:198
-#: mod/notifications.php:254
+#: mod/message.php:77 mod/wallmessage.php:66
+msgid "Message could not be sent."
+msgstr ""
+
+#: mod/message.php:80 mod/wallmessage.php:69
+msgid "Message collection failure."
+msgstr ""
+
+#: mod/message.php:83 mod/wallmessage.php:72
+msgid "Message sent."
+msgstr ""
+
+#: mod/message.php:110 mod/notifications.php:48 mod/notifications.php:202
+#: mod/notifications.php:258
 msgid "Discard"
 msgstr ""
 
@@ -2464,6 +2099,27 @@ msgstr ""
 msgid "Conversation removed."
 msgstr ""
 
+#: mod/message.php:204 mod/message.php:360 mod/wallmessage.php:123
+msgid "Please enter a link URL:"
+msgstr ""
+
+#: mod/message.php:246 mod/wallmessage.php:128
+msgid "Send Private Message"
+msgstr ""
+
+#: mod/message.php:247 mod/message.php:430 mod/wallmessage.php:130
+msgid "To:"
+msgstr ""
+
+#: mod/message.php:251 mod/message.php:432 mod/wallmessage.php:131
+msgid "Subject:"
+msgstr ""
+
+#: mod/message.php:255 mod/message.php:435 mod/wallmessage.php:137
+#: src/Module/Invite.php:150
+msgid "Your message:"
+msgstr ""
+
 #: mod/message.php:289
 msgid "No messages."
 msgstr ""
@@ -2480,1026 +2136,1113 @@ msgstr ""
 msgid "D, d M Y - g:i A"
 msgstr ""
 
-#: mod/message.php:423 mod/message.php:537
-msgid "Delete conversation"
+#: mod/message.php:423 mod/message.php:537
+msgid "Delete conversation"
+msgstr ""
+
+#: mod/message.php:425
+msgid ""
+"No secure communications available. You <strong>may</strong> be able to "
+"respond from the sender's profile page."
+msgstr ""
+
+#: mod/message.php:429
+msgid "Send Reply"
+msgstr ""
+
+#: mod/message.php:512
+#, php-format
+msgid "Unknown sender - %s"
+msgstr ""
+
+#: mod/message.php:514
+#, php-format
+msgid "You and %s"
+msgstr ""
+
+#: mod/message.php:516
+#, php-format
+msgid "%s and You"
+msgstr ""
+
+#: mod/message.php:543
+#, php-format
+msgid "%d message"
+msgid_plural "%d messages"
+msgstr[0] ""
+msgstr[1] ""
+
+#: mod/network.php:525
+#, php-format
+msgid ""
+"Warning: This group contains %s member from a network that doesn't allow non "
+"public messages."
+msgid_plural ""
+"Warning: This group contains %s members from a network that doesn't allow "
+"non public messages."
+msgstr[0] ""
+msgstr[1] ""
+
+#: mod/network.php:528
+msgid "Messages in this group won't be send to these receivers."
+msgstr ""
+
+#: mod/network.php:595
+msgid "No such group"
+msgstr ""
+
+#: mod/network.php:616 src/Module/Group.php:288
+msgid "Group is empty"
+msgstr ""
+
+#: mod/network.php:620
+#, php-format
+msgid "Group: %s"
+msgstr ""
+
+#: mod/network.php:646
+msgid "Private messages to this person are at risk of public disclosure."
+msgstr ""
+
+#: mod/network.php:649 src/Module/AllFriends.php:35
+#: src/Module/AllFriends.php:43
+msgid "Invalid contact."
+msgstr ""
+
+#: mod/network.php:928
+msgid "Latest Activity"
+msgstr ""
+
+#: mod/network.php:931
+msgid "Sort by latest activity"
+msgstr ""
+
+#: mod/network.php:936
+msgid "Latest Posts"
+msgstr ""
+
+#: mod/network.php:939
+msgid "Sort by post received date"
+msgstr ""
+
+#: mod/network.php:946 mod/profiles.php:579
+msgid "Personal"
+msgstr ""
+
+#: mod/network.php:949
+msgid "Posts that mention or involve you"
+msgstr ""
+
+#: mod/network.php:956
+msgid "New"
+msgstr ""
+
+#: mod/network.php:959
+msgid "Activity Stream - by date"
+msgstr ""
+
+#: mod/network.php:967
+msgid "Shared Links"
+msgstr ""
+
+#: mod/network.php:970
+msgid "Interesting Links"
+msgstr ""
+
+#: mod/network.php:977
+msgid "Starred"
+msgstr ""
+
+#: mod/network.php:980
+msgid "Favourite Posts"
+msgstr ""
+
+#: mod/notifications.php:39
+msgid "Invalid request identifier."
+msgstr ""
+
+#: mod/notifications.php:100 src/Content/Nav.php:249
+msgid "Notifications"
+msgstr ""
+
+#: mod/notifications.php:119
+msgid "Network Notifications"
+msgstr ""
+
+#: mod/notifications.php:124
+msgid "System Notifications"
+msgstr ""
+
+#: mod/notifications.php:129
+msgid "Personal Notifications"
 msgstr ""
 
-#: mod/message.php:425
-msgid ""
-"No secure communications available. You <strong>may</strong> be able to "
-"respond from the sender's profile page."
+#: mod/notifications.php:134
+msgid "Home Notifications"
 msgstr ""
 
-#: mod/message.php:429
-msgid "Send Reply"
+#: mod/notifications.php:157
+msgid "Show unread"
 msgstr ""
 
-#: mod/message.php:512
-#, php-format
-msgid "Unknown sender - %s"
+#: mod/notifications.php:157
+msgid "Show all"
 msgstr ""
 
-#: mod/message.php:514
-#, php-format
-msgid "You and %s"
+#: mod/notifications.php:168
+msgid "Show Ignored Requests"
 msgstr ""
 
-#: mod/message.php:516
-#, php-format
-msgid "%s and You"
+#: mod/notifications.php:168
+msgid "Hide Ignored Requests"
 msgstr ""
 
-#: mod/message.php:543
-#, php-format
-msgid "%d message"
-msgid_plural "%d messages"
-msgstr[0] ""
-msgstr[1] ""
+#: mod/notifications.php:181 mod/notifications.php:266
+msgid "Notification type:"
+msgstr ""
 
-#: mod/network.php:183 mod/search.php:35
-msgid "Remove term"
+#: mod/notifications.php:184
+msgid "Suggested by:"
 msgstr ""
 
-#: mod/network.php:190 mod/search.php:44
-msgid "Saved Searches"
+#: mod/notifications.php:196 mod/notifications.php:283
+#: src/Module/Contact.php:615
+msgid "Hide this contact from others"
 msgstr ""
 
-#: mod/network.php:191 src/Model/Group.php:483
-msgid "add"
+#: mod/notifications.php:198 mod/notifications.php:292
+#: src/Model/Contact.php:1270 src/Module/Admin/Users.php:286
+msgid "Approve"
 msgstr ""
 
-#: mod/network.php:571
-#, php-format
-msgid ""
-"Warning: This group contains %s member from a network that doesn't allow non "
-"public messages."
-msgid_plural ""
-"Warning: This group contains %s members from a network that doesn't allow "
-"non public messages."
-msgstr[0] ""
-msgstr[1] ""
+#: mod/notifications.php:218
+msgid "Claims to be known to you: "
+msgstr ""
 
-#: mod/network.php:574
-msgid "Messages in this group won't be send to these receivers."
+#: mod/notifications.php:219
+msgid "yes"
 msgstr ""
 
-#: mod/network.php:641
-msgid "No such group"
+#: mod/notifications.php:219
+msgid "no"
 msgstr ""
 
-#: mod/network.php:662 src/Module/Group.php:288
-msgid "Group is empty"
+#: mod/notifications.php:220 mod/notifications.php:224
+msgid "Shall your connection be bidirectional or not?"
 msgstr ""
 
-#: mod/network.php:666
+#: mod/notifications.php:221 mod/notifications.php:225
 #, php-format
-msgid "Group: %s"
+msgid ""
+"Accepting %s as a friend allows %s to subscribe to your posts, and you will "
+"also receive updates from them in your news feed."
 msgstr ""
 
-#: mod/network.php:692
-msgid "Private messages to this person are at risk of public disclosure."
+#: mod/notifications.php:222
+#, php-format
+msgid ""
+"Accepting %s as a subscriber allows them to subscribe to your posts, but you "
+"will not receive updates from them in your news feed."
 msgstr ""
 
-#: mod/network.php:695 src/Module/AllFriends.php:35
-#: src/Module/AllFriends.php:43
-msgid "Invalid contact."
+#: mod/notifications.php:226
+#, php-format
+msgid ""
+"Accepting %s as a sharer allows them to subscribe to your posts, but you "
+"will not receive updates from them in your news feed."
 msgstr ""
 
-#: mod/network.php:974
-msgid "Commented Order"
+#: mod/notifications.php:237
+msgid "Friend"
 msgstr ""
 
-#: mod/network.php:977
-msgid "Sort by Comment Date"
+#: mod/notifications.php:238
+msgid "Sharer"
 msgstr ""
 
-#: mod/network.php:982
-msgid "Posted Order"
+#: mod/notifications.php:238
+msgid "Subscriber"
 msgstr ""
 
-#: mod/network.php:985
-msgid "Sort by Post Date"
+#: mod/notifications.php:278 src/Model/Profile.php:449
+#: src/Model/Profile.php:828 src/Module/Contact.php:632
+#: src/Module/Directory.php:143
+msgid "About:"
 msgstr ""
 
-#: mod/network.php:995
-msgid "Posts that mention or involve you"
+#: mod/notifications.php:282 src/Model/Profile.php:446
+#: src/Model/Profile.php:767 src/Module/Directory.php:140
+msgid "Gender:"
 msgstr ""
 
-#: mod/network.php:1002
-msgid "New"
+#: mod/notifications.php:289 src/Model/Profile.php:554
+#: src/Module/Contact.php:316
+msgid "Network:"
 msgstr ""
 
-#: mod/network.php:1005
-msgid "Activity Stream - by date"
+#: mod/notifications.php:303
+msgid "No introductions."
 msgstr ""
 
-#: mod/network.php:1013
-msgid "Shared Links"
+#: mod/notifications.php:337
+#, php-format
+msgid "No more %s notifications."
 msgstr ""
 
-#: mod/network.php:1016
-msgid "Interesting Links"
+#: mod/openid.php:30
+msgid "OpenID protocol error. No ID returned."
 msgstr ""
 
-#: mod/network.php:1023
-msgid "Starred"
+#: mod/openid.php:67
+msgid ""
+"Account not found. Please login to your existing account to add the OpenID "
+"to it."
 msgstr ""
 
-#: mod/network.php:1026
-msgid "Favourite Posts"
+#: mod/openid.php:69
+msgid ""
+"Account not found. Please register a new account or login to your existing "
+"account to add the OpenID to it."
 msgstr ""
 
-#: mod/notes.php:34 src/Model/Profile.php:975
-msgid "Personal Notes"
+#: mod/openid.php:75 src/Module/Login.php:90 src/Module/Login.php:144
+msgid "Login failed."
 msgstr ""
 
-#: mod/photos.php:113 src/Model/Profile.php:936
+#: mod/photos.php:112 src/Model/Profile.php:932
 msgid "Photo Albums"
 msgstr ""
 
-#: mod/photos.php:114 mod/photos.php:1639
+#: mod/photos.php:113 mod/photos.php:1609
 msgid "Recent Photos"
 msgstr ""
 
-#: mod/photos.php:116 mod/photos.php:1152 mod/photos.php:1641
+#: mod/photos.php:115 mod/photos.php:1117 mod/photos.php:1611
 msgid "Upload New Photos"
 msgstr ""
 
-#: mod/photos.php:134 mod/settings.php:60 src/Module/BaseSettingsModule.php:18
+#: mod/photos.php:133 mod/settings.php:62 src/Module/BaseSettingsModule.php:18
 msgid "everybody"
 msgstr ""
 
-#: mod/photos.php:185
+#: mod/photos.php:170
 msgid "Contact information unavailable"
 msgstr ""
 
-#: mod/photos.php:207
+#: mod/photos.php:192
 msgid "Album not found."
 msgstr ""
 
-#: mod/photos.php:265
+#: mod/photos.php:250
 msgid "Album successfully deleted"
 msgstr ""
 
-#: mod/photos.php:267
+#: mod/photos.php:252
 msgid "Album was empty."
 msgstr ""
 
-#: mod/photos.php:590
+#: mod/photos.php:578
 msgid "a photo"
 msgstr ""
 
-#: mod/photos.php:590
+#: mod/photos.php:578
 #, php-format
 msgid "%1$s was tagged in %2$s by %3$s"
 msgstr ""
 
-#: mod/photos.php:689
+#: mod/photos.php:680
 msgid "Image upload didn't complete, please try again"
 msgstr ""
 
-#: mod/photos.php:692
+#: mod/photos.php:683
 msgid "Image file is missing"
 msgstr ""
 
-#: mod/photos.php:697
+#: mod/photos.php:688
 msgid ""
 "Server can't accept new file upload at this time, please contact your "
 "administrator"
 msgstr ""
 
-#: mod/photos.php:723
+#: mod/photos.php:714
 msgid "Image file is empty."
 msgstr ""
 
-#: mod/photos.php:855
+#: mod/photos.php:846
 msgid "No photos selected"
 msgstr ""
 
-#: mod/photos.php:947 mod/videos.php:210
+#: mod/photos.php:912 mod/videos.php:168
 msgid "Access to this item is restricted."
 msgstr ""
 
-#: mod/photos.php:1001
+#: mod/photos.php:966
 msgid "Upload Photos"
 msgstr ""
 
-#: mod/photos.php:1005 mod/photos.php:1097
+#: mod/photos.php:970 mod/photos.php:1062
 msgid "New album name: "
 msgstr ""
 
-#: mod/photos.php:1006
+#: mod/photos.php:971
 msgid "or select existing album:"
 msgstr ""
 
-#: mod/photos.php:1007
+#: mod/photos.php:972
 msgid "Do not show a status post for this upload"
 msgstr ""
 
-#: mod/photos.php:1009 mod/photos.php:1383 mod/events.php:555
-#: src/Core/ACL.php:314
-msgid "Permissions"
-msgstr ""
-
-#: mod/photos.php:1023 mod/photos.php:1391 mod/settings.php:1213
+#: mod/photos.php:988 mod/photos.php:1356 mod/settings.php:1206
 msgid "Show to Groups"
 msgstr ""
 
-#: mod/photos.php:1024 mod/photos.php:1392 mod/settings.php:1214
+#: mod/photos.php:989 mod/photos.php:1357 mod/settings.php:1207
 msgid "Show to Contacts"
 msgstr ""
 
-#: mod/photos.php:1079
+#: mod/photos.php:1044
 msgid "Do you really want to delete this photo album and all its photos?"
 msgstr ""
 
-#: mod/photos.php:1081 mod/photos.php:1102
+#: mod/photos.php:1046 mod/photos.php:1067
 msgid "Delete Album"
 msgstr ""
 
-#: mod/photos.php:1108
+#: mod/photos.php:1073
 msgid "Edit Album"
 msgstr ""
 
-#: mod/photos.php:1109
+#: mod/photos.php:1074
 msgid "Drop Album"
 msgstr ""
 
-#: mod/photos.php:1114
+#: mod/photos.php:1079
 msgid "Show Newest First"
 msgstr ""
 
-#: mod/photos.php:1116
+#: mod/photos.php:1081
 msgid "Show Oldest First"
 msgstr ""
 
-#: mod/photos.php:1137 mod/photos.php:1624
+#: mod/photos.php:1102 mod/photos.php:1594
 msgid "View Photo"
 msgstr ""
 
-#: mod/photos.php:1174
+#: mod/photos.php:1139
 msgid "Permission denied. Access to this item may be restricted."
 msgstr ""
 
-#: mod/photos.php:1176
+#: mod/photos.php:1141
 msgid "Photo not available"
 msgstr ""
 
-#: mod/photos.php:1186
+#: mod/photos.php:1151
 msgid "Do you really want to delete this photo?"
 msgstr ""
 
-#: mod/photos.php:1188 mod/photos.php:1388
+#: mod/photos.php:1153 mod/photos.php:1353
 msgid "Delete Photo"
 msgstr ""
 
-#: mod/photos.php:1279
+#: mod/photos.php:1244
 msgid "View photo"
 msgstr ""
 
-#: mod/photos.php:1281
+#: mod/photos.php:1246
 msgid "Edit photo"
 msgstr ""
 
-#: mod/photos.php:1282
+#: mod/photos.php:1247
 msgid "Delete photo"
 msgstr ""
 
-#: mod/photos.php:1283
+#: mod/photos.php:1248
 msgid "Use as profile photo"
 msgstr ""
 
-#: mod/photos.php:1290
+#: mod/photos.php:1255
 msgid "Private Photo"
 msgstr ""
 
-#: mod/photos.php:1296
+#: mod/photos.php:1261
 msgid "View Full Size"
 msgstr ""
 
-#: mod/photos.php:1356
+#: mod/photos.php:1321
 msgid "Tags: "
 msgstr ""
 
-#: mod/photos.php:1359
+#: mod/photos.php:1324
 msgid "[Select tags to remove]"
 msgstr ""
 
-#: mod/photos.php:1374
+#: mod/photos.php:1339
 msgid "New album name"
 msgstr ""
 
-#: mod/photos.php:1375
+#: mod/photos.php:1340
 msgid "Caption"
 msgstr ""
 
-#: mod/photos.php:1376
+#: mod/photos.php:1341
 msgid "Add a Tag"
 msgstr ""
 
-#: mod/photos.php:1376
+#: mod/photos.php:1341
 msgid "Example: @bob, @Barbara_Jensen, @jim@example.com, #California, #camping"
 msgstr ""
 
-#: mod/photos.php:1377
+#: mod/photos.php:1342
 msgid "Do not rotate"
 msgstr ""
 
-#: mod/photos.php:1378
+#: mod/photos.php:1343
 msgid "Rotate CW (right)"
 msgstr ""
 
-#: mod/photos.php:1379
+#: mod/photos.php:1344
 msgid "Rotate CCW (left)"
 msgstr ""
 
-#: mod/photos.php:1413 src/Object/Post.php:313
+#: mod/photos.php:1378 src/Object/Post.php:310
 msgid "I like this (toggle)"
 msgstr ""
 
-#: mod/photos.php:1414 src/Object/Post.php:314
+#: mod/photos.php:1379 src/Object/Post.php:311
 msgid "I don't like this (toggle)"
 msgstr ""
 
-#: mod/photos.php:1429 mod/photos.php:1468 mod/photos.php:1528
-#: src/Module/Item/Compose.php:176 src/Module/Contact.php:1002
-#: src/Object/Post.php:876
+#: mod/photos.php:1394 mod/photos.php:1433 mod/photos.php:1498
+#: src/Module/Item/Compose.php:180 src/Module/Contact.php:1023
+#: src/Object/Post.php:881
 msgid "This is you"
 msgstr ""
 
-#: mod/photos.php:1431 mod/photos.php:1470 mod/photos.php:1530
-#: src/Object/Post.php:420 src/Object/Post.php:878
+#: mod/photos.php:1396 mod/photos.php:1435 mod/photos.php:1500
+#: src/Object/Post.php:420 src/Object/Post.php:883
 msgid "Comment"
 msgstr ""
 
-#: mod/photos.php:1559
+#: mod/photos.php:1529
 msgid "Map"
 msgstr ""
 
-#: mod/photos.php:1630 mod/videos.php:287
+#: mod/photos.php:1600 mod/videos.php:245
 msgid "View Album"
 msgstr ""
 
-#: mod/ping.php:272
-msgid "{0} wants to be your friend"
-msgstr ""
-
-#: mod/ping.php:288
-msgid "{0} requested registration"
-msgstr ""
-
-#: mod/poke.php:177
+#: mod/poke.php:178
 msgid "Poke/Prod"
 msgstr ""
 
-#: mod/poke.php:178
+#: mod/poke.php:179
 msgid "poke, prod or do other things to somebody"
 msgstr ""
 
-#: mod/poke.php:179
+#: mod/poke.php:180
 msgid "Recipient"
 msgstr ""
 
-#: mod/poke.php:180
+#: mod/poke.php:181
 msgid "Choose what you wish to do to recipient"
 msgstr ""
 
-#: mod/poke.php:183
+#: mod/poke.php:184
 msgid "Make this post private"
 msgstr ""
 
-#: mod/profile_photo.php:58
-msgid "Image uploaded but image cropping failed."
-msgstr ""
-
-#: mod/profile_photo.php:88 mod/profile_photo.php:97 mod/profile_photo.php:106
-#: mod/profile_photo.php:311
-#, php-format
-msgid "Image size reduction [%s] failed."
-msgstr ""
-
-#: mod/profile_photo.php:125
-msgid ""
-"Shift-reload the page or clear browser cache if the new photo does not "
-"display immediately."
-msgstr ""
-
-#: mod/profile_photo.php:133
-msgid "Unable to process image"
-msgstr ""
-
-#: mod/profile_photo.php:244
-msgid "Upload File:"
-msgstr ""
-
-#: mod/profile_photo.php:245
-msgid "Select a profile:"
-msgstr ""
-
-#: mod/profile_photo.php:250
-msgid "or"
+#: mod/profiles.php:62
+msgid "Profile deleted."
 msgstr ""
 
-#: mod/profile_photo.php:251
-msgid "skip this step"
+#: mod/profiles.php:78 mod/profiles.php:114
+msgid "Profile-"
 msgstr ""
 
-#: mod/profile_photo.php:251
-msgid "select a photo from your photo albums"
+#: mod/profiles.php:97 mod/profiles.php:135
+msgid "New profile created."
 msgstr ""
 
-#: mod/profile_photo.php:264
-msgid "Crop Image"
+#: mod/profiles.php:120
+msgid "Profile unavailable to clone."
 msgstr ""
 
-#: mod/profile_photo.php:265
-msgid "Please adjust the image cropping for optimum viewing."
+#: mod/profiles.php:206
+msgid "Profile Name is required."
 msgstr ""
 
-#: mod/profile_photo.php:267
-msgid "Done Editing"
+#: mod/profiles.php:346
+msgid "Marital Status"
 msgstr ""
 
-#: mod/profile_photo.php:301
-msgid "Image uploaded successfully."
+#: mod/profiles.php:349
+msgid "Romantic Partner"
 msgstr ""
 
-#: mod/search.php:92
-msgid "Only logged in users are permitted to perform a search."
+#: mod/profiles.php:358
+msgid "Work/Employment"
 msgstr ""
 
-#: mod/search.php:114
-msgid "Only one search per minute is permitted for not logged in users."
+#: mod/profiles.php:361
+msgid "Religion"
 msgstr ""
 
-#: mod/search.php:134 src/Content/Text/HTML.php:893 src/Content/Nav.php:200
-msgid "Search"
+#: mod/profiles.php:364
+msgid "Political Views"
 msgstr ""
 
-#: mod/search.php:228
-#, php-format
-msgid "Items tagged with: %s"
+#: mod/profiles.php:367
+msgid "Gender"
 msgstr ""
 
-#: mod/search.php:230 src/Module/Contact.php:794
-#, php-format
-msgid "Results for: %s"
+#: mod/profiles.php:370
+msgid "Sexual Preference"
 msgstr ""
 
-#: mod/subthread.php:104
-#, php-format
-msgid "%1$s is following %2$s's %3$s"
+#: mod/profiles.php:373
+msgid "XMPP"
 msgstr ""
 
-#: mod/suggest.php:28
-msgid "Contact suggestion successfully ignored."
+#: mod/profiles.php:376
+msgid "Homepage"
 msgstr ""
 
-#: mod/suggest.php:52
-msgid ""
-"No suggestions available. If this is a new site, please try again in 24 "
-"hours."
+#: mod/profiles.php:379 mod/profiles.php:578
+msgid "Interests"
 msgstr ""
 
-#: mod/suggest.php:71
-msgid "Do you really want to delete this suggestion?"
+#: mod/profiles.php:382
+msgid "Address"
 msgstr ""
 
-#: mod/suggest.php:89 mod/suggest.php:109
-msgid "Ignore/Hide"
+#: mod/profiles.php:389 mod/profiles.php:574
+msgid "Location"
 msgstr ""
 
-#: mod/suggest.php:119 view/theme/vier/theme.php:204 src/Content/Widget.php:69
-msgid "Friend Suggestions"
+#: mod/profiles.php:469
+msgid "Profile updated."
 msgstr ""
 
-#: mod/uexport.php:52
-msgid "Export account"
+#: mod/profiles.php:523
+msgid "Hide contacts and friends:"
 msgstr ""
 
-#: mod/uexport.php:52
-msgid ""
-"Export your account info and contacts. Use this to make a backup of your "
-"account and/or to move it to another server."
+#: mod/profiles.php:528
+msgid "Hide your contact/friend list from viewers of this profile?"
 msgstr ""
 
-#: mod/uexport.php:53
-msgid "Export all"
+#: mod/profiles.php:548
+msgid "Show more profile fields:"
 msgstr ""
 
-#: mod/uexport.php:53
-msgid ""
-"Export your accout info, contacts and all your items as json. Could be a "
-"very big file, and could take a lot of time. Use this to make a full backup "
-"of your account (photos are not exported)"
+#: mod/profiles.php:560
+msgid "Profile Actions"
 msgstr ""
 
-#: mod/uexport.php:59 mod/settings.php:131 src/Module/BaseSettingsModule.php:89
-msgid "Export personal data"
+#: mod/profiles.php:561
+msgid "Edit Profile Details"
 msgstr ""
 
-#: mod/videos.php:123
-msgid "No videos selected"
+#: mod/profiles.php:563
+msgid "Change Profile Photo"
 msgstr ""
 
-#: mod/videos.php:280 src/Model/Item.php:3477
-msgid "View Video"
+#: mod/profiles.php:565
+msgid "View this profile"
 msgstr ""
 
-#: mod/videos.php:295
-msgid "Recent Videos"
+#: mod/profiles.php:566
+msgid "View all profiles"
 msgstr ""
 
-#: mod/videos.php:297
-msgid "Upload New Videos"
+#: mod/profiles.php:567 mod/profiles.php:662 src/Model/Profile.php:419
+msgid "Edit visibility"
 msgstr ""
 
-#: mod/display.php:254 mod/display.php:339
-msgid "The requested item doesn't exist or has been deleted."
+#: mod/profiles.php:568
+msgid "Create a new profile using these settings"
 msgstr ""
 
-#: mod/display.php:417
-msgid "The feed for this item is unavailable."
+#: mod/profiles.php:569
+msgid "Clone this profile"
 msgstr ""
 
-#: mod/events.php:118 mod/events.php:120
-msgid "Event can not end before it has started."
+#: mod/profiles.php:570
+msgid "Delete this profile"
 msgstr ""
 
-#: mod/events.php:127 mod/events.php:129
-msgid "Event title and start time are required."
+#: mod/profiles.php:572
+msgid "Basic information"
 msgstr ""
 
-#: mod/events.php:385
-msgid "Create New Event"
+#: mod/profiles.php:573
+msgid "Profile picture"
 msgstr ""
 
-#: mod/events.php:508
-msgid "Event details"
+#: mod/profiles.php:575
+msgid "Preferences"
 msgstr ""
 
-#: mod/events.php:509
-msgid "Starting date and Title are required."
+#: mod/profiles.php:576
+msgid "Status information"
 msgstr ""
 
-#: mod/events.php:510 mod/events.php:515
-msgid "Event Starts:"
+#: mod/profiles.php:577
+msgid "Additional information"
 msgstr ""
 
-#: mod/events.php:523 mod/events.php:548
-msgid "Finish date/time is not known or not relevant"
+#: mod/profiles.php:580
+msgid "Relation"
 msgstr ""
 
-#: mod/events.php:525 mod/events.php:530
-msgid "Event Finishes:"
+#: mod/profiles.php:581 src/Util/Temporal.php:79 src/Util/Temporal.php:81
+msgid "Miscellaneous"
 msgstr ""
 
-#: mod/events.php:536 mod/events.php:549
-msgid "Adjust for viewer timezone"
+#: mod/profiles.php:584
+msgid "Your Gender:"
 msgstr ""
 
-#: mod/events.php:538
-msgid "Description:"
+#: mod/profiles.php:585
+msgid "<span class=\"heart\">&hearts;</span> Marital Status:"
 msgstr ""
 
-#: mod/events.php:540 mod/notifications.php:272 src/Model/Event.php:68
-#: src/Model/Event.php:95 src/Model/Event.php:437 src/Model/Event.php:933
-#: src/Model/Profile.php:447 src/Module/Directory.php:137
-#: src/Module/Contact.php:607
-msgid "Location:"
+#: mod/profiles.php:586 src/Model/Profile.php:804
+msgid "Sexual Preference:"
 msgstr ""
 
-#: mod/events.php:542 mod/events.php:544
-msgid "Title:"
+#: mod/profiles.php:587
+msgid "Example: fishing photography software"
 msgstr ""
 
-#: mod/events.php:545 mod/events.php:546
-msgid "Share this event"
+#: mod/profiles.php:592
+msgid "Profile Name:"
 msgstr ""
 
-#: mod/events.php:553 src/Model/Profile.php:890
-msgid "Basic"
+#: mod/profiles.php:594
+msgid ""
+"This is your <strong>public</strong> profile.<br />It <strong>may</strong> "
+"be visible to anybody using the internet."
 msgstr ""
 
-#: mod/events.php:554 src/Model/Profile.php:891 src/Module/Admin/Site.php:573
-#: src/Module/Contact.php:880
-msgid "Advanced"
+#: mod/profiles.php:595
+msgid "Your Full Name:"
 msgstr ""
 
-#: mod/events.php:571
-msgid "Failed to remove event"
+#: mod/profiles.php:596
+msgid "Title/Description:"
 msgstr ""
 
-#: mod/events.php:573
-msgid "Event removed"
+#: mod/profiles.php:599
+msgid "Street Address:"
 msgstr ""
 
-#: mod/item.php:123
-msgid "Unable to locate original post."
+#: mod/profiles.php:600
+msgid "Locality/City:"
 msgstr ""
 
-#: mod/item.php:323
-msgid "Empty post discarded."
+#: mod/profiles.php:601
+msgid "Region/State:"
 msgstr ""
 
-#: mod/item.php:803
-#, php-format
-msgid ""
-"This message was sent to you by %s, a member of the Friendica social network."
+#: mod/profiles.php:602
+msgid "Postal/Zip Code:"
 msgstr ""
 
-#: mod/item.php:805
-#, php-format
-msgid "You may visit them online at %s"
+#: mod/profiles.php:603
+msgid "Country:"
 msgstr ""
 
-#: mod/item.php:806
-msgid ""
-"Please contact the sender by replying to this post if you do not wish to "
-"receive these messages."
+#: mod/profiles.php:604 src/Util/Temporal.php:148
+msgid "Age: "
 msgstr ""
 
-#: mod/item.php:810
-#, php-format
-msgid "%s posted an update."
+#: mod/profiles.php:607
+msgid "Who: (if applicable)"
 msgstr ""
 
-#: mod/notifications.php:40
-msgid "Invalid request identifier."
+#: mod/profiles.php:607
+msgid "Examples: cathy123, Cathy Williams, cathy@example.com"
 msgstr ""
 
-#: mod/notifications.php:96 src/Content/Nav.php:249
-msgid "Notifications"
+#: mod/profiles.php:608
+msgid "Since [date]:"
 msgstr ""
 
-#: mod/notifications.php:115
-msgid "Network Notifications"
+#: mod/profiles.php:610
+msgid "Tell us about yourself..."
 msgstr ""
 
-#: mod/notifications.php:120
-msgid "System Notifications"
+#: mod/profiles.php:611
+msgid "XMPP (Jabber) address:"
 msgstr ""
 
-#: mod/notifications.php:125
-msgid "Personal Notifications"
+#: mod/profiles.php:611
+msgid ""
+"The XMPP address will be propagated to your contacts so that they can follow "
+"you."
 msgstr ""
 
-#: mod/notifications.php:130
-msgid "Home Notifications"
+#: mod/profiles.php:612
+msgid "Homepage URL:"
 msgstr ""
 
-#: mod/notifications.php:153
-msgid "Show unread"
+#: mod/profiles.php:613 src/Model/Profile.php:812
+msgid "Hometown:"
 msgstr ""
 
-#: mod/notifications.php:153
-msgid "Show all"
+#: mod/profiles.php:614 src/Model/Profile.php:820
+msgid "Political Views:"
 msgstr ""
 
-#: mod/notifications.php:164
-msgid "Show Ignored Requests"
+#: mod/profiles.php:615
+msgid "Religious Views:"
 msgstr ""
 
-#: mod/notifications.php:164
-msgid "Hide Ignored Requests"
+#: mod/profiles.php:616
+msgid "Public Keywords:"
 msgstr ""
 
-#: mod/notifications.php:177 mod/notifications.php:262
-msgid "Notification type:"
+#: mod/profiles.php:616
+msgid "(Used for suggesting potential friends, can be seen by others)"
 msgstr ""
 
-#: mod/notifications.php:180
-msgid "Suggested by:"
+#: mod/profiles.php:617
+msgid "Private Keywords:"
 msgstr ""
 
-#: mod/notifications.php:192 mod/notifications.php:279
-#: src/Module/Contact.php:594
-msgid "Hide this contact from others"
+#: mod/profiles.php:617
+msgid "(Used for searching profiles, never shown to others)"
 msgstr ""
 
-#: mod/notifications.php:194 mod/notifications.php:288
-#: src/Model/Contact.php:1238 src/Module/Admin/Users.php:286
-msgid "Approve"
+#: mod/profiles.php:618 src/Model/Profile.php:836
+msgid "Likes:"
 msgstr ""
 
-#: mod/notifications.php:214
-msgid "Claims to be known to you: "
+#: mod/profiles.php:619 src/Model/Profile.php:840
+msgid "Dislikes:"
 msgstr ""
 
-#: mod/notifications.php:215
-msgid "yes"
+#: mod/profiles.php:620
+msgid "Musical interests"
 msgstr ""
 
-#: mod/notifications.php:215
-msgid "no"
+#: mod/profiles.php:621
+msgid "Books, literature"
 msgstr ""
 
-#: mod/notifications.php:216 mod/notifications.php:220
-msgid "Shall your connection be bidirectional or not?"
+#: mod/profiles.php:622
+msgid "Television"
 msgstr ""
 
-#: mod/notifications.php:217 mod/notifications.php:221
-#, php-format
-msgid ""
-"Accepting %s as a friend allows %s to subscribe to your posts, and you will "
-"also receive updates from them in your news feed."
+#: mod/profiles.php:623
+msgid "Film/dance/culture/entertainment"
 msgstr ""
 
-#: mod/notifications.php:218
-#, php-format
-msgid ""
-"Accepting %s as a subscriber allows them to subscribe to your posts, but you "
-"will not receive updates from them in your news feed."
+#: mod/profiles.php:624
+msgid "Hobbies/Interests"
 msgstr ""
 
-#: mod/notifications.php:222
-#, php-format
-msgid ""
-"Accepting %s as a sharer allows them to subscribe to your posts, but you "
-"will not receive updates from them in your news feed."
+#: mod/profiles.php:625
+msgid "Love/romance"
 msgstr ""
 
-#: mod/notifications.php:233
-msgid "Friend"
+#: mod/profiles.php:626
+msgid "Work/employment"
 msgstr ""
 
-#: mod/notifications.php:234
-msgid "Sharer"
+#: mod/profiles.php:627
+msgid "School/education"
 msgstr ""
 
-#: mod/notifications.php:234
-msgid "Subscriber"
+#: mod/profiles.php:628
+msgid "Contact information and Social Networks"
 msgstr ""
 
-#: mod/notifications.php:274 src/Model/Profile.php:453
-#: src/Model/Profile.php:832 src/Module/Directory.php:145
-#: src/Module/Contact.php:611
-msgid "About:"
+#: mod/profiles.php:659 src/Model/Profile.php:415
+msgid "Profile Image"
 msgstr ""
 
-#: mod/notifications.php:278 src/Model/Profile.php:450
-#: src/Model/Profile.php:771 src/Module/Directory.php:142
-msgid "Gender:"
+#: mod/profiles.php:661 src/Model/Profile.php:418
+msgid "visible to everybody"
 msgstr ""
 
-#: mod/notifications.php:285 src/Model/Profile.php:558
-#: src/Module/Contact.php:295
-msgid "Network:"
+#: mod/profiles.php:668
+msgid "Edit/Manage Profiles"
 msgstr ""
 
-#: mod/notifications.php:299
-msgid "No introductions."
+#: mod/profiles.php:669 src/Model/Profile.php:405 src/Model/Profile.php:426
+msgid "Change profile photo"
 msgstr ""
 
-#: mod/notifications.php:333
-#, php-format
-msgid "No more %s notifications."
+#: mod/profiles.php:670 src/Model/Profile.php:406
+msgid "Create New Profile"
 msgstr ""
 
-#: mod/openid.php:30
-msgid "OpenID protocol error. No ID returned."
+#: mod/regmod.php:53
+msgid "Account approved."
 msgstr ""
 
-#: mod/openid.php:60
-msgid ""
-"Account not found and OpenID registration is not permitted on this site."
+#: mod/regmod.php:77
+#, php-format
+msgid "Registration revoked for %s"
 msgstr ""
 
-#: mod/openid.php:108 src/Module/Login.php:88 src/Module/Login.php:139
-msgid "Login failed."
+#: mod/regmod.php:84
+msgid "Please login."
 msgstr ""
 
-#: mod/settings.php:65 src/Module/BaseSettingsModule.php:24
+#: mod/settings.php:67 src/Module/BaseSettingsModule.php:24
 msgid "Account"
 msgstr ""
 
-#: mod/settings.php:73 src/Module/BaseSettingsModule.php:31
-#: src/Module/Settings/TwoFactor/Index.php:89
-#: src/Module/TwoFactor/Verify.php:62
+#: mod/settings.php:75 src/Module/Settings/TwoFactor/Index.php:89
+#: src/Module/TwoFactor/Verify.php:62 src/Module/BaseSettingsModule.php:31
 msgid "Two-factor authentication"
 msgstr ""
 
-#: mod/settings.php:80 src/Content/Nav.php:268 src/Model/Profile.php:402
+#: mod/settings.php:82 src/Content/Nav.php:266 src/Model/Profile.php:398
 #: src/Module/BaseSettingsModule.php:38
 msgid "Profiles"
 msgstr ""
 
-#: mod/settings.php:88 src/Module/BaseAdminModule.php:84
+#: mod/settings.php:90 src/Module/BaseAdminModule.php:84
 #: src/Module/BaseSettingsModule.php:46
 msgid "Additional features"
 msgstr ""
 
-#: mod/settings.php:96 src/Module/BaseSettingsModule.php:54
+#: mod/settings.php:98 src/Module/BaseSettingsModule.php:54
 msgid "Display"
 msgstr ""
 
-#: mod/settings.php:103 mod/settings.php:843
+#: mod/settings.php:105 mod/settings.php:835
 #: src/Module/BaseSettingsModule.php:61
 msgid "Social Networks"
 msgstr ""
 
-#: mod/settings.php:110 src/Module/Admin/Addons/Details.php:100
+#: mod/settings.php:112 src/Module/Admin/Addons/Details.php:100
 #: src/Module/Admin/Addons/Index.php:51 src/Module/BaseAdminModule.php:82
 #: src/Module/BaseSettingsModule.php:68
 msgid "Addons"
 msgstr ""
 
-#: mod/settings.php:117 src/Content/Nav.php:263
-#: src/Module/BaseSettingsModule.php:75
+#: mod/settings.php:119 src/Module/BaseSettingsModule.php:75
 msgid "Delegations"
 msgstr ""
 
-#: mod/settings.php:124 src/Module/BaseSettingsModule.php:82
+#: mod/settings.php:126 src/Module/BaseSettingsModule.php:82
 msgid "Connected apps"
 msgstr ""
 
-#: mod/settings.php:138 src/Module/BaseSettingsModule.php:96
+#: mod/settings.php:133 src/Module/Settings/UserExport.php:52
+#: src/Module/BaseSettingsModule.php:89
+msgid "Export personal data"
+msgstr ""
+
+#: mod/settings.php:140 src/Module/BaseSettingsModule.php:96
 msgid "Remove account"
 msgstr ""
 
-#: mod/settings.php:147 view/theme/frio/theme.php:277 src/Content/Nav.php:265
+#: mod/settings.php:149 view/theme/frio/theme.php:277 src/Content/Nav.php:263
 #: src/Module/Admin/Addons/Details.php:102
-#: src/Module/Admin/Themes/Details.php:107
-#: src/Module/BaseSettingsModule.php:105 src/Module/Welcome.php:33
+#: src/Module/Admin/Themes/Details.php:107 src/Module/Welcome.php:33
+#: src/Module/BaseSettingsModule.php:105
 msgid "Settings"
 msgstr ""
 
-#: mod/settings.php:190
+#: mod/settings.php:192
 msgid "Missing some important data!"
 msgstr ""
 
-#: mod/settings.php:192 mod/settings.php:703 src/Module/Contact.php:801
+#: mod/settings.php:194 mod/settings.php:695 src/Module/Contact.php:822
 msgid "Update"
 msgstr ""
 
-#: mod/settings.php:302
+#: mod/settings.php:301
 msgid "Failed to connect with email account using the settings provided."
 msgstr ""
 
-#: mod/settings.php:307
+#: mod/settings.php:306
 msgid "Email settings updated."
 msgstr ""
 
-#: mod/settings.php:323
+#: mod/settings.php:322
 msgid "Features updated"
 msgstr ""
 
-#: mod/settings.php:384
+#: mod/settings.php:383
 msgid "The theme you chose isn't available."
 msgstr ""
 
-#: mod/settings.php:396
+#: mod/settings.php:399
+msgid "Contact CSV file upload error"
+msgstr ""
+
+#: mod/settings.php:413
+msgid "Importing Contacts done"
+msgstr ""
+
+#: mod/settings.php:422
 msgid "Relocate message has been send to your contacts"
 msgstr ""
 
-#: mod/settings.php:408
+#: mod/settings.php:434
 msgid "Passwords do not match."
 msgstr ""
 
-#: mod/settings.php:416 src/Console/NewPassword.php:101
+#: mod/settings.php:442 src/Console/NewPassword.php:101
 msgid "Password update failed. Please try again."
 msgstr ""
 
-#: mod/settings.php:419 src/Console/NewPassword.php:104
+#: mod/settings.php:445 src/Console/NewPassword.php:104
 msgid "Password changed."
 msgstr ""
 
-#: mod/settings.php:422
+#: mod/settings.php:448
 msgid "Password unchanged."
 msgstr ""
 
-#: mod/settings.php:503
+#: mod/settings.php:530
 msgid " Please use a shorter name."
 msgstr ""
 
-#: mod/settings.php:506
+#: mod/settings.php:533
 msgid " Name too short."
 msgstr ""
 
-#: mod/settings.php:513 src/Module/Settings/TwoFactor/Index.php:72
+#: mod/settings.php:540 src/Module/Settings/TwoFactor/Index.php:72
 msgid "Wrong Password"
 msgstr ""
 
-#: mod/settings.php:518
+#: mod/settings.php:545
 msgid "Invalid email."
 msgstr ""
 
-#: mod/settings.php:524
+#: mod/settings.php:551
 msgid "Cannot change to that email."
 msgstr ""
 
-#: mod/settings.php:574
+#: mod/settings.php:589
 msgid "Private forum has no privacy permissions. Using default privacy group."
 msgstr ""
 
-#: mod/settings.php:577
+#: mod/settings.php:592
 msgid "Private forum has no privacy permissions and no default privacy group."
 msgstr ""
 
-#: mod/settings.php:617
+#: mod/settings.php:609
 msgid "Settings updated."
 msgstr ""
 
-#: mod/settings.php:676 mod/settings.php:702 mod/settings.php:736
+#: mod/settings.php:668 mod/settings.php:694 mod/settings.php:728
 msgid "Add application"
 msgstr ""
 
-#: mod/settings.php:680 mod/settings.php:706
+#: mod/settings.php:669 mod/settings.php:776 mod/settings.php:866
+#: mod/settings.php:945 mod/settings.php:1170
+#: src/Module/Admin/Addons/Index.php:52 src/Module/Admin/Features.php:69
+#: src/Module/Admin/Logs/Settings.php:65 src/Module/Admin/Themes/Index.php:97
+#: src/Module/Admin/Tos.php:50 src/Module/Admin/Site.php:568
+#: src/Module/Settings/Delegation.php:158
+msgid "Save Settings"
+msgstr ""
+
+#: mod/settings.php:672 mod/settings.php:698
 msgid "Consumer Key"
 msgstr ""
 
-#: mod/settings.php:681 mod/settings.php:707
+#: mod/settings.php:673 mod/settings.php:699
 msgid "Consumer Secret"
 msgstr ""
 
-#: mod/settings.php:682 mod/settings.php:708
+#: mod/settings.php:674 mod/settings.php:700
 msgid "Redirect"
 msgstr ""
 
-#: mod/settings.php:683 mod/settings.php:709
+#: mod/settings.php:675 mod/settings.php:701
 msgid "Icon url"
 msgstr ""
 
-#: mod/settings.php:694
+#: mod/settings.php:686
 msgid "You can't edit this application."
 msgstr ""
 
-#: mod/settings.php:735
+#: mod/settings.php:727
 msgid "Connected Apps"
 msgstr ""
 
-#: mod/settings.php:737 src/Object/Post.php:168 src/Object/Post.php:170
+#: mod/settings.php:729 src/Object/Post.php:165 src/Object/Post.php:167
 msgid "Edit"
 msgstr ""
 
-#: mod/settings.php:739
+#: mod/settings.php:731
 msgid "Client key starts with"
 msgstr ""
 
-#: mod/settings.php:740
+#: mod/settings.php:732
 msgid "No name"
 msgstr ""
 
-#: mod/settings.php:741
+#: mod/settings.php:733
 msgid "Remove authorization"
 msgstr ""
 
-#: mod/settings.php:752
+#: mod/settings.php:744
 msgid "No Addon settings configured"
 msgstr ""
 
-#: mod/settings.php:761
+#: mod/settings.php:753
 msgid "Addon Settings"
 msgstr ""
 
-#: mod/settings.php:775 src/Module/Admin/Features.php:58
+#: mod/settings.php:767 src/Module/Admin/Features.php:58
 #: src/Module/Admin/Features.php:59
 msgid "Off"
 msgstr ""
 
-#: mod/settings.php:775 src/Module/Admin/Features.php:58
+#: mod/settings.php:767 src/Module/Admin/Features.php:58
 #: src/Module/Admin/Features.php:59
 msgid "On"
 msgstr ""
 
-#: mod/settings.php:782
+#: mod/settings.php:774
 msgid "Additional Features"
 msgstr ""
 
-#: mod/settings.php:806 src/Content/ContactSelector.php:120
+#: mod/settings.php:798 src/Content/ContactSelector.php:120
 msgid "Diaspora"
 msgstr ""
 
-#: mod/settings.php:806 mod/settings.php:807
+#: mod/settings.php:798 mod/settings.php:799
 msgid "enabled"
 msgstr ""
 
-#: mod/settings.php:806 mod/settings.php:807
+#: mod/settings.php:798 mod/settings.php:799
 msgid "disabled"
 msgstr ""
 
-#: mod/settings.php:806 mod/settings.php:807
+#: mod/settings.php:798 mod/settings.php:799
 #, php-format
 msgid "Built-in support for %s connectivity is %s"
 msgstr ""
 
-#: mod/settings.php:807
+#: mod/settings.php:799
 msgid "GNU Social (OStatus)"
 msgstr ""
 
-#: mod/settings.php:838
+#: mod/settings.php:830
 msgid "Email access is disabled on this site."
 msgstr ""
 
-#: mod/settings.php:848
+#: mod/settings.php:840
 msgid "General Social Media Settings"
 msgstr ""
 
-#: mod/settings.php:849
+#: mod/settings.php:841
 msgid "Accept only top level posts by contacts you follow"
 msgstr ""
 
-#: mod/settings.php:849
+#: mod/settings.php:841
 msgid ""
 "The system does an auto completion of threads when a comment arrives. This "
 "has got the side effect that you can receive posts that had been started by "
@@ -3508,11 +3251,11 @@ msgid ""
 "posts from people you really do follow."
 msgstr ""
 
-#: mod/settings.php:850
+#: mod/settings.php:842
 msgid "Disable Content Warning"
 msgstr ""
 
-#: mod/settings.php:850
+#: mod/settings.php:842
 msgid ""
 "Users on networks like Mastodon or Pleroma are able to set a content warning "
 "field which collapse their post by default. This disables the automatic "
@@ -3520,352 +3263,352 @@ msgid ""
 "any other content filtering you eventually set up."
 msgstr ""
 
-#: mod/settings.php:851
+#: mod/settings.php:843
 msgid "Disable intelligent shortening"
 msgstr ""
 
-#: mod/settings.php:851
+#: mod/settings.php:843
 msgid ""
 "Normally the system tries to find the best link to add to shortened posts. "
 "If this option is enabled then every shortened post will always point to the "
 "original friendica post."
 msgstr ""
 
-#: mod/settings.php:852
+#: mod/settings.php:844
 msgid "Automatically follow any GNU Social (OStatus) followers/mentioners"
 msgstr ""
 
-#: mod/settings.php:852
+#: mod/settings.php:844
 msgid ""
 "If you receive a message from an unknown OStatus user, this option decides "
 "what to do. If it is checked, a new contact will be created for every "
 "unknown user."
 msgstr ""
 
-#: mod/settings.php:853
+#: mod/settings.php:845
 msgid "Default group for OStatus contacts"
 msgstr ""
 
-#: mod/settings.php:854
+#: mod/settings.php:846
 msgid "Your legacy GNU Social account"
 msgstr ""
 
-#: mod/settings.php:854
+#: mod/settings.php:846
 msgid ""
 "If you enter your old GNU Social/Statusnet account name here (in the format "
 "user@domain.tld), your contacts will be added automatically. The field will "
 "be emptied when done."
 msgstr ""
 
-#: mod/settings.php:857
+#: mod/settings.php:849
 msgid "Repair OStatus subscriptions"
 msgstr ""
 
-#: mod/settings.php:861
+#: mod/settings.php:853
 msgid "Email/Mailbox Setup"
 msgstr ""
 
-#: mod/settings.php:862
+#: mod/settings.php:854
 msgid ""
 "If you wish to communicate with email contacts using this service "
 "(optional), please specify how to connect to your mailbox."
 msgstr ""
 
-#: mod/settings.php:863
+#: mod/settings.php:855
 msgid "Last successful email check:"
 msgstr ""
 
-#: mod/settings.php:865
+#: mod/settings.php:857
 msgid "IMAP server name:"
 msgstr ""
 
-#: mod/settings.php:866
+#: mod/settings.php:858
 msgid "IMAP port:"
 msgstr ""
 
-#: mod/settings.php:867
+#: mod/settings.php:859
 msgid "Security:"
 msgstr ""
 
-#: mod/settings.php:867 mod/settings.php:872
+#: mod/settings.php:859 mod/settings.php:864
 msgid "None"
 msgstr ""
 
-#: mod/settings.php:868
+#: mod/settings.php:860
 msgid "Email login name:"
 msgstr ""
 
-#: mod/settings.php:869
+#: mod/settings.php:861
 msgid "Email password:"
 msgstr ""
 
-#: mod/settings.php:870
+#: mod/settings.php:862
 msgid "Reply-to address:"
 msgstr ""
 
-#: mod/settings.php:871
+#: mod/settings.php:863
 msgid "Send public posts to all email contacts:"
 msgstr ""
 
-#: mod/settings.php:872
+#: mod/settings.php:864
 msgid "Action after import:"
 msgstr ""
 
-#: mod/settings.php:872 src/Content/Nav.php:251
+#: mod/settings.php:864 src/Content/Nav.php:251
 msgid "Mark as seen"
 msgstr ""
 
-#: mod/settings.php:872
+#: mod/settings.php:864
 msgid "Move to folder"
 msgstr ""
 
-#: mod/settings.php:873
+#: mod/settings.php:865
 msgid "Move to folder:"
 msgstr ""
 
-#: mod/settings.php:897 src/Module/Admin/Site.php:433
+#: mod/settings.php:889 src/Module/Admin/Site.php:433
 msgid "No special theme for mobile devices"
 msgstr ""
 
-#: mod/settings.php:905
+#: mod/settings.php:897
 #, php-format
 msgid "%s - (Unsupported)"
 msgstr ""
 
-#: mod/settings.php:907 src/Module/Admin/Site.php:450
+#: mod/settings.php:899 src/Module/Admin/Site.php:450
 #, php-format
 msgid "%s - (Experimental)"
 msgstr ""
 
-#: mod/settings.php:935 src/Core/L10n/L10n.php:370 src/Model/Event.php:395
+#: mod/settings.php:927 src/Core/L10n/L10n.php:404 src/Model/Event.php:396
 msgid "Sunday"
 msgstr ""
 
-#: mod/settings.php:935 src/Core/L10n/L10n.php:370 src/Model/Event.php:396
+#: mod/settings.php:927 src/Core/L10n/L10n.php:404 src/Model/Event.php:397
 msgid "Monday"
 msgstr ""
 
-#: mod/settings.php:951
+#: mod/settings.php:943
 msgid "Display Settings"
 msgstr ""
 
-#: mod/settings.php:957
+#: mod/settings.php:949
 msgid "Display Theme:"
 msgstr ""
 
-#: mod/settings.php:958
+#: mod/settings.php:950
 msgid "Mobile Theme:"
 msgstr ""
 
-#: mod/settings.php:959
+#: mod/settings.php:951
 msgid "Suppress warning of insecure networks"
 msgstr ""
 
-#: mod/settings.php:959
+#: mod/settings.php:951
 msgid ""
 "Should the system suppress the warning that the current group contains "
 "members of networks that can't receive non public postings."
 msgstr ""
 
-#: mod/settings.php:960
+#: mod/settings.php:952
 msgid "Update browser every xx seconds"
 msgstr ""
 
-#: mod/settings.php:960
+#: mod/settings.php:952
 msgid "Minimum of 10 seconds. Enter -1 to disable it."
 msgstr ""
 
-#: mod/settings.php:961
+#: mod/settings.php:953
 msgid "Number of items to display per page:"
 msgstr ""
 
-#: mod/settings.php:961 mod/settings.php:962
+#: mod/settings.php:953 mod/settings.php:954
 msgid "Maximum of 100 items"
 msgstr ""
 
-#: mod/settings.php:962
+#: mod/settings.php:954
 msgid "Number of items to display per page when viewed from mobile device:"
 msgstr ""
 
-#: mod/settings.php:963
+#: mod/settings.php:955
 msgid "Don't show emoticons"
 msgstr ""
 
-#: mod/settings.php:964
+#: mod/settings.php:956
 msgid "Calendar"
 msgstr ""
 
-#: mod/settings.php:965
+#: mod/settings.php:957
 msgid "Beginning of week:"
 msgstr ""
 
-#: mod/settings.php:966
+#: mod/settings.php:958
 msgid "Don't show notices"
 msgstr ""
 
-#: mod/settings.php:967
+#: mod/settings.php:959
 msgid "Infinite scroll"
 msgstr ""
 
-#: mod/settings.php:968
+#: mod/settings.php:960
 msgid "Automatic updates only at the top of the network page"
 msgstr ""
 
-#: mod/settings.php:968
+#: mod/settings.php:960
 msgid ""
 "When disabled, the network page is updated all the time, which could be "
 "confusing while reading."
 msgstr ""
 
-#: mod/settings.php:969
+#: mod/settings.php:961
 msgid "Bandwidth Saver Mode"
 msgstr ""
 
-#: mod/settings.php:969
+#: mod/settings.php:961
 msgid ""
 "When enabled, embedded content is not displayed on automatic updates, they "
 "only show on page reload."
 msgstr ""
 
-#: mod/settings.php:970
+#: mod/settings.php:962
 msgid "Smart Threading"
 msgstr ""
 
-#: mod/settings.php:970
+#: mod/settings.php:962
 msgid ""
 "When enabled, suppress extraneous thread indentation while keeping it where "
 "it matters. Only works if threading is available and enabled."
 msgstr ""
 
-#: mod/settings.php:972
+#: mod/settings.php:964
 msgid "General Theme Settings"
 msgstr ""
 
-#: mod/settings.php:973
+#: mod/settings.php:965
 msgid "Custom Theme Settings"
 msgstr ""
 
-#: mod/settings.php:974
+#: mod/settings.php:966
 msgid "Content Settings"
 msgstr ""
 
-#: mod/settings.php:975 view/theme/duepuntozero/config.php:73
+#: mod/settings.php:967 view/theme/duepuntozero/config.php:73
 #: view/theme/frio/config.php:128 view/theme/quattro/config.php:75
-#: view/theme/vier/config.php:121
+#: view/theme/vier/config.php:123
 msgid "Theme settings"
 msgstr ""
 
-#: mod/settings.php:989
+#: mod/settings.php:981
 msgid "Unable to find your profile. Please contact your admin."
 msgstr ""
 
-#: mod/settings.php:1028
+#: mod/settings.php:1020
 msgid "Account Types"
 msgstr ""
 
-#: mod/settings.php:1029
+#: mod/settings.php:1021
 msgid "Personal Page Subtypes"
 msgstr ""
 
-#: mod/settings.php:1030
+#: mod/settings.php:1022
 msgid "Community Forum Subtypes"
 msgstr ""
 
-#: mod/settings.php:1037 src/Module/Admin/Users.php:229
+#: mod/settings.php:1029 src/Module/Admin/Users.php:229
 msgid "Personal Page"
 msgstr ""
 
-#: mod/settings.php:1038
+#: mod/settings.php:1030
 msgid "Account for a personal profile."
 msgstr ""
 
-#: mod/settings.php:1041 src/Module/Admin/Users.php:230
+#: mod/settings.php:1033 src/Module/Admin/Users.php:230
 msgid "Organisation Page"
 msgstr ""
 
-#: mod/settings.php:1042
+#: mod/settings.php:1034
 msgid ""
 "Account for an organisation that automatically approves contact requests as "
 "\"Followers\"."
 msgstr ""
 
-#: mod/settings.php:1045 src/Module/Admin/Users.php:231
+#: mod/settings.php:1037 src/Module/Admin/Users.php:231
 msgid "News Page"
 msgstr ""
 
-#: mod/settings.php:1046
+#: mod/settings.php:1038
 msgid ""
 "Account for a news reflector that automatically approves contact requests as "
 "\"Followers\"."
 msgstr ""
 
-#: mod/settings.php:1049 src/Module/Admin/Users.php:232
+#: mod/settings.php:1041 src/Module/Admin/Users.php:232
 msgid "Community Forum"
 msgstr ""
 
-#: mod/settings.php:1050
+#: mod/settings.php:1042
 msgid "Account for community discussions."
 msgstr ""
 
-#: mod/settings.php:1053 src/Module/Admin/Users.php:222
+#: mod/settings.php:1045 src/Module/Admin/Users.php:222
 msgid "Normal Account Page"
 msgstr ""
 
-#: mod/settings.php:1054
+#: mod/settings.php:1046
 msgid ""
 "Account for a regular personal profile that requires manual approval of "
 "\"Friends\" and \"Followers\"."
 msgstr ""
 
-#: mod/settings.php:1057 src/Module/Admin/Users.php:223
+#: mod/settings.php:1049 src/Module/Admin/Users.php:223
 msgid "Soapbox Page"
 msgstr ""
 
-#: mod/settings.php:1058
+#: mod/settings.php:1050
 msgid ""
 "Account for a public profile that automatically approves contact requests as "
 "\"Followers\"."
 msgstr ""
 
-#: mod/settings.php:1061 src/Module/Admin/Users.php:224
+#: mod/settings.php:1053 src/Module/Admin/Users.php:224
 msgid "Public Forum"
 msgstr ""
 
-#: mod/settings.php:1062
+#: mod/settings.php:1054
 msgid "Automatically approves all contact requests."
 msgstr ""
 
-#: mod/settings.php:1065 src/Module/Admin/Users.php:225
+#: mod/settings.php:1057 src/Module/Admin/Users.php:225
 msgid "Automatic Friend Page"
 msgstr ""
 
-#: mod/settings.php:1066
+#: mod/settings.php:1058
 msgid ""
 "Account for a popular profile that automatically approves contact requests "
 "as \"Friends\"."
 msgstr ""
 
-#: mod/settings.php:1069
+#: mod/settings.php:1061
 msgid "Private Forum [Experimental]"
 msgstr ""
 
-#: mod/settings.php:1070
+#: mod/settings.php:1062
 msgid "Requires manual approval of contact requests."
 msgstr ""
 
-#: mod/settings.php:1081
+#: mod/settings.php:1073
 msgid "OpenID:"
 msgstr ""
 
-#: mod/settings.php:1081
+#: mod/settings.php:1073
 msgid "(Optional) Allow this OpenID to login to this account."
 msgstr ""
 
-#: mod/settings.php:1089
+#: mod/settings.php:1081
 msgid "Publish your default profile in your local site directory?"
 msgstr ""
 
-#: mod/settings.php:1089
+#: mod/settings.php:1081
 #, php-format
 msgid ""
 "Your profile will be published in this node's <a href=\"%s\">local "
@@ -3873,324 +3616,487 @@ msgid ""
 "system settings."
 msgstr ""
 
-#: mod/settings.php:1095
+#: mod/settings.php:1087
 msgid "Publish your default profile in the global social directory?"
 msgstr ""
 
-#: mod/settings.php:1095
+#: mod/settings.php:1087
 #, php-format
 msgid ""
 "Your profile will be published in the global friendica directories (e.g. <a "
 "href=\"%s\">%s</a>). Your profile will be visible in public."
 msgstr ""
 
-#: mod/settings.php:1095
+#: mod/settings.php:1087
 msgid ""
 "This setting also determines whether Friendica will inform search engines "
 "that your profile should be indexed or not. Third-party search engines may "
 "or may not respect this setting."
 msgstr ""
 
-#: mod/settings.php:1102
+#: mod/settings.php:1094
 msgid "Hide your contact/friend list from viewers of your default profile?"
 msgstr ""
 
-#: mod/settings.php:1102
+#: mod/settings.php:1094
 msgid ""
 "Your contact list won't be shown in your default profile page. You can "
 "decide to show your contact list separately for each additional profile you "
 "create"
 msgstr ""
 
-#: mod/settings.php:1106
+#: mod/settings.php:1098
 msgid "Hide your profile details from anonymous viewers?"
 msgstr ""
 
-#: mod/settings.php:1106
+#: mod/settings.php:1098
 msgid ""
 "Anonymous visitors will only see your profile picture, your display name and "
 "the nickname you are using on your profile page. Your public posts and "
 "replies will still be accessible by other means."
 msgstr ""
 
-#: mod/settings.php:1110
+#: mod/settings.php:1102
 msgid "Allow friends to post to your profile page?"
 msgstr ""
 
-#: mod/settings.php:1110
+#: mod/settings.php:1102
 msgid ""
 "Your contacts may write posts on your profile wall. These posts will be "
 "distributed to your contacts"
 msgstr ""
 
-#: mod/settings.php:1114
+#: mod/settings.php:1106
 msgid "Allow friends to tag your posts?"
 msgstr ""
 
-#: mod/settings.php:1114
+#: mod/settings.php:1106
 msgid "Your contacts can add additional tags to your posts."
 msgstr ""
 
-#: mod/settings.php:1118
+#: mod/settings.php:1110
 msgid "Allow us to suggest you as a potential friend to new members?"
 msgstr ""
 
-#: mod/settings.php:1118
+#: mod/settings.php:1110
 msgid "If you like, Friendica may suggest new members to add you as a contact."
 msgstr ""
 
-#: mod/settings.php:1122
+#: mod/settings.php:1114
 msgid "Permit unknown people to send you private mail?"
 msgstr ""
 
-#: mod/settings.php:1122
+#: mod/settings.php:1114
 msgid ""
 "Friendica network users may send you private messages even if they are not "
 "in your contact list."
 msgstr ""
 
-#: mod/settings.php:1126
+#: mod/settings.php:1118
 msgid "Profile is <strong>not published</strong>."
 msgstr ""
 
-#: mod/settings.php:1132
+#: mod/settings.php:1124
 #, php-format
 msgid "Your Identity Address is <strong>'%s'</strong> or '%s'."
 msgstr ""
 
-#: mod/settings.php:1139
+#: mod/settings.php:1131
 msgid "Automatically expire posts after this many days:"
 msgstr ""
 
-#: mod/settings.php:1139
+#: mod/settings.php:1131
 msgid "If empty, posts will not expire. Expired posts will be deleted"
 msgstr ""
 
-#: mod/settings.php:1140
+#: mod/settings.php:1132
 msgid "Advanced expiration settings"
 msgstr ""
 
-#: mod/settings.php:1141
+#: mod/settings.php:1133
 msgid "Advanced Expiration"
 msgstr ""
 
-#: mod/settings.php:1142
+#: mod/settings.php:1134
 msgid "Expire posts:"
 msgstr ""
 
-#: mod/settings.php:1143
+#: mod/settings.php:1135
 msgid "Expire personal notes:"
 msgstr ""
 
-#: mod/settings.php:1144
+#: mod/settings.php:1136
 msgid "Expire starred posts:"
 msgstr ""
 
-#: mod/settings.php:1145
+#: mod/settings.php:1137
 msgid "Expire photos:"
 msgstr ""
 
-#: mod/settings.php:1146
+#: mod/settings.php:1138
 msgid "Only expire posts by others:"
 msgstr ""
 
-#: mod/settings.php:1176
+#: mod/settings.php:1168
 msgid "Account Settings"
 msgstr ""
 
-#: mod/settings.php:1184
+#: mod/settings.php:1176
 msgid "Password Settings"
 msgstr ""
 
-#: mod/settings.php:1185 src/Module/Register.php:130
+#: mod/settings.php:1177 src/Module/Register.php:124
 msgid "New Password:"
 msgstr ""
 
-#: mod/settings.php:1185
+#: mod/settings.php:1177
 msgid ""
 "Allowed characters are a-z, A-Z, 0-9 and special characters except white "
 "spaces, accentuated letters and colon (:)."
 msgstr ""
 
-#: mod/settings.php:1186 src/Module/Register.php:131
+#: mod/settings.php:1178 src/Module/Register.php:125
 msgid "Confirm:"
 msgstr ""
 
-#: mod/settings.php:1186
+#: mod/settings.php:1178
 msgid "Leave password fields blank unless changing"
 msgstr ""
 
-#: mod/settings.php:1187
+#: mod/settings.php:1179
 msgid "Current Password:"
 msgstr ""
 
-#: mod/settings.php:1187 mod/settings.php:1188
+#: mod/settings.php:1179 mod/settings.php:1180
 msgid "Your current password to confirm the changes"
 msgstr ""
 
-#: mod/settings.php:1188
+#: mod/settings.php:1180
 msgid "Password:"
 msgstr ""
 
-#: mod/settings.php:1192
+#: mod/settings.php:1183
+msgid "Delete OpenID URL"
+msgstr ""
+
+#: mod/settings.php:1185
 msgid "Basic Settings"
 msgstr ""
 
-#: mod/settings.php:1193 src/Model/Profile.php:764
+#: mod/settings.php:1186 src/Model/Profile.php:760
 msgid "Full Name:"
 msgstr ""
 
-#: mod/settings.php:1194
+#: mod/settings.php:1187
 msgid "Email Address:"
 msgstr ""
 
-#: mod/settings.php:1195
+#: mod/settings.php:1188
 msgid "Your Timezone:"
 msgstr ""
 
-#: mod/settings.php:1196
+#: mod/settings.php:1189
 msgid "Your Language:"
 msgstr ""
 
-#: mod/settings.php:1196
+#: mod/settings.php:1189
 msgid ""
 "Set the language we use to show you friendica interface and to send you "
 "emails"
 msgstr ""
 
-#: mod/settings.php:1197
+#: mod/settings.php:1190
 msgid "Default Post Location:"
 msgstr ""
 
-#: mod/settings.php:1198
+#: mod/settings.php:1191
 msgid "Use Browser Location:"
 msgstr ""
 
-#: mod/settings.php:1201
+#: mod/settings.php:1194
 msgid "Security and Privacy Settings"
 msgstr ""
 
-#: mod/settings.php:1203
+#: mod/settings.php:1196
 msgid "Maximum Friend Requests/Day:"
 msgstr ""
 
-#: mod/settings.php:1203 mod/settings.php:1232
+#: mod/settings.php:1196 mod/settings.php:1225
 msgid "(to prevent spam abuse)"
 msgstr ""
 
-#: mod/settings.php:1204
+#: mod/settings.php:1197
 msgid "Default Post Permissions"
 msgstr ""
 
-#: mod/settings.php:1205
+#: mod/settings.php:1198
 msgid "(click to open/close)"
 msgstr ""
 
-#: mod/settings.php:1215
+#: mod/settings.php:1208
 msgid "Default Private Post"
 msgstr ""
 
-#: mod/settings.php:1216
+#: mod/settings.php:1209
 msgid "Default Public Post"
 msgstr ""
 
-#: mod/settings.php:1220
+#: mod/settings.php:1213
 msgid "Default Permissions for New Posts"
 msgstr ""
 
-#: mod/settings.php:1232
+#: mod/settings.php:1225
 msgid "Maximum private messages per day from unknown people:"
 msgstr ""
 
-#: mod/settings.php:1235
+#: mod/settings.php:1228
 msgid "Notification Settings"
 msgstr ""
 
-#: mod/settings.php:1236
+#: mod/settings.php:1229
 msgid "Send a notification email when:"
 msgstr ""
 
-#: mod/settings.php:1237
+#: mod/settings.php:1230
 msgid "You receive an introduction"
 msgstr ""
 
-#: mod/settings.php:1238
+#: mod/settings.php:1231
 msgid "Your introductions are confirmed"
 msgstr ""
 
-#: mod/settings.php:1239
+#: mod/settings.php:1232
 msgid "Someone writes on your profile wall"
 msgstr ""
 
-#: mod/settings.php:1240
+#: mod/settings.php:1233
 msgid "Someone writes a followup comment"
 msgstr ""
 
-#: mod/settings.php:1241
+#: mod/settings.php:1234
 msgid "You receive a private message"
 msgstr ""
 
-#: mod/settings.php:1242
+#: mod/settings.php:1235
 msgid "You receive a friend suggestion"
 msgstr ""
 
-#: mod/settings.php:1243
+#: mod/settings.php:1236
 msgid "You are tagged in a post"
 msgstr ""
 
-#: mod/settings.php:1244
+#: mod/settings.php:1237
 msgid "You are poked/prodded/etc. in a post"
 msgstr ""
 
-#: mod/settings.php:1246
+#: mod/settings.php:1239
 msgid "Activate desktop notifications"
 msgstr ""
 
-#: mod/settings.php:1246
+#: mod/settings.php:1239
 msgid "Show desktop popup on new notifications"
 msgstr ""
 
-#: mod/settings.php:1248
+#: mod/settings.php:1241
 msgid "Text-only notification emails"
 msgstr ""
 
-#: mod/settings.php:1250
+#: mod/settings.php:1243
 msgid "Send text only notification emails, without the html part"
 msgstr ""
 
-#: mod/settings.php:1252
+#: mod/settings.php:1245
 msgid "Show detailled notifications"
 msgstr ""
 
-#: mod/settings.php:1254
+#: mod/settings.php:1247
 msgid ""
 "Per default, notifications are condensed to a single notification per item. "
 "When enabled every notification is displayed."
 msgstr ""
 
-#: mod/settings.php:1256
+#: mod/settings.php:1249
 msgid "Advanced Account/Page Type Settings"
 msgstr ""
 
-#: mod/settings.php:1257
+#: mod/settings.php:1250
 msgid "Change the behaviour of this account for special situations"
 msgstr ""
 
-#: mod/settings.php:1260
+#: mod/settings.php:1253
+msgid "Import Contacts"
+msgstr ""
+
+#: mod/settings.php:1254
+msgid ""
+"Upload a CSV file that contains the handle of your followed accounts in the "
+"first column you exported from the old account."
+msgstr ""
+
+#: mod/settings.php:1255
+msgid "Upload File"
+msgstr ""
+
+#: mod/settings.php:1257
 msgid "Relocate"
 msgstr ""
 
-#: mod/settings.php:1261
+#: mod/settings.php:1258
 msgid ""
 "If you have moved this profile from another server, and some of your "
 "contacts don't receive your updates, try pushing this button."
 msgstr ""
 
-#: mod/settings.php:1262
+#: mod/settings.php:1259
 msgid "Resend relocate message to contacts"
 msgstr ""
 
-#: view/theme/duepuntozero/config.php:55 src/Model/User.php:745
+#: mod/subthread.php:107
+#, php-format
+msgid "%1$s is following %2$s's %3$s"
+msgstr ""
+
+#: mod/tagrm.php:31
+msgid "Tag(s) removed"
+msgstr ""
+
+#: mod/tagrm.php:101
+msgid "Remove Item Tag"
+msgstr ""
+
+#: mod/tagrm.php:103
+msgid "Select a tag to remove: "
+msgstr ""
+
+#: mod/tagrm.php:114 src/Module/Settings/Delegation.php:167
+msgid "Remove"
+msgstr ""
+
+#: mod/uimport.php:30
+msgid "User imports on closed servers can only be done by an administrator."
+msgstr ""
+
+#: mod/uimport.php:39 src/Module/Register.php:60
+msgid ""
+"This site has exceeded the number of allowed daily account registrations. "
+"Please try again tomorrow."
+msgstr ""
+
+#: mod/uimport.php:46 src/Module/Register.php:135
+msgid "Import"
+msgstr ""
+
+#: mod/uimport.php:48
+msgid "Move account"
+msgstr ""
+
+#: mod/uimport.php:49
+msgid "You can import an account from another Friendica server."
+msgstr ""
+
+#: mod/uimport.php:50
+msgid ""
+"You need to export your account from the old server and upload it here. We "
+"will recreate your old account here with all your contacts. We will try also "
+"to inform your friends that you moved here."
+msgstr ""
+
+#: mod/uimport.php:51
+msgid ""
+"This feature is experimental. We can't import contacts from the OStatus "
+"network (GNU Social/Statusnet) or from Diaspora"
+msgstr ""
+
+#: mod/uimport.php:52
+msgid "Account file"
+msgstr ""
+
+#: mod/uimport.php:52
+msgid ""
+"To export your account, go to \"Settings->Export your personal data\" and "
+"select \"Export account\""
+msgstr ""
+
+#: mod/unfollow.php:36 mod/unfollow.php:92
+msgid "You aren't following this contact."
+msgstr ""
+
+#: mod/unfollow.php:46 mod/unfollow.php:98
+msgid "Unfollowing is currently not supported by your network."
+msgstr ""
+
+#: mod/unfollow.php:67
+msgid "Contact unfollowed"
+msgstr ""
+
+#: mod/unfollow.php:118
+msgid "Disconnect/Unfollow"
+msgstr ""
+
+#: mod/videos.php:120
+msgid "No videos selected"
+msgstr ""
+
+#: mod/videos.php:238 src/Model/Item.php:3514
+msgid "View Video"
+msgstr ""
+
+#: mod/videos.php:253
+msgid "Recent Videos"
+msgstr ""
+
+#: mod/videos.php:255
+msgid "Upload New Videos"
+msgstr ""
+
+#: mod/wall_attach.php:27 mod/wall_attach.php:34 mod/wall_attach.php:72
+#: mod/wall_upload.php:43 mod/wall_upload.php:59 mod/wall_upload.php:104
+#: mod/wall_upload.php:155 mod/wall_upload.php:158
+msgid "Invalid request."
+msgstr ""
+
+#: mod/wall_attach.php:90
+msgid "Sorry, maybe your upload is bigger than the PHP configuration allows"
+msgstr ""
+
+#: mod/wall_attach.php:90
+msgid "Or - did you try to upload an empty file?"
+msgstr ""
+
+#: mod/wall_attach.php:101
+#, php-format
+msgid "File exceeds size limit of %s"
+msgstr ""
+
+#: mod/wall_attach.php:116
+msgid "File upload failed."
+msgstr ""
+
+#: mod/wall_upload.php:231
+msgid "Wall Photos"
+msgstr ""
+
+#: mod/wallmessage.php:52 mod/wallmessage.php:115
+#, php-format
+msgid "Number of daily wall messages for %s exceeded. Message failed."
+msgstr ""
+
+#: mod/wallmessage.php:63
+msgid "Unable to check your home location."
+msgstr ""
+
+#: mod/wallmessage.php:89 mod/wallmessage.php:98
+msgid "No recipient."
+msgstr ""
+
+#: mod/wallmessage.php:129
+#, php-format
+msgid ""
+"If you wish for %s to respond, please check that the privacy settings on "
+"your site allow private mail from unknown senders."
+msgstr ""
+
+#: view/theme/duepuntozero/config.php:55 src/Model/User.php:790
 msgid "default"
 msgstr ""
 
@@ -4250,12 +4156,84 @@ msgid ""
 "Resize image to repeat it on a single row, either vertical or horizontal."
 msgstr ""
 
-#: view/theme/frio/php/Image.php:27
-msgid "Mosaic"
+#: view/theme/frio/php/Image.php:27
+msgid "Mosaic"
+msgstr ""
+
+#: view/theme/frio/php/Image.php:27
+msgid "Repeat image to fill the screen."
+msgstr ""
+
+#: view/theme/frio/theme.php:246
+msgid "Guest"
+msgstr ""
+
+#: view/theme/frio/theme.php:251
+msgid "Visitor"
+msgstr ""
+
+#: view/theme/frio/theme.php:267 src/Content/Nav.php:160
+#: src/Model/Profile.php:913 src/Module/Settings/TwoFactor/Index.php:91
+#: src/Module/Contact.php:637 src/Module/Contact.php:852
+msgid "Status"
+msgstr ""
+
+#: view/theme/frio/theme.php:267 src/Content/Nav.php:160
+#: src/Content/Nav.php:244
+msgid "Your posts and conversations"
+msgstr ""
+
+#: view/theme/frio/theme.php:268 src/Content/Nav.php:161
+msgid "Your profile page"
+msgstr ""
+
+#: view/theme/frio/theme.php:269 src/Content/Nav.php:162
+msgid "Your photos"
+msgstr ""
+
+#: view/theme/frio/theme.php:270 src/Content/Nav.php:163
+#: src/Model/Profile.php:937 src/Model/Profile.php:940
+msgid "Videos"
+msgstr ""
+
+#: view/theme/frio/theme.php:270 src/Content/Nav.php:163
+msgid "Your videos"
+msgstr ""
+
+#: view/theme/frio/theme.php:271 src/Content/Nav.php:164
+msgid "Your events"
+msgstr ""
+
+#: view/theme/frio/theme.php:274 src/Content/Nav.php:241
+msgid "Network"
+msgstr ""
+
+#: view/theme/frio/theme.php:274 src/Content/Nav.php:241
+msgid "Conversations from your friends"
+msgstr ""
+
+#: view/theme/frio/theme.php:275 src/Content/Nav.php:228
+#: src/Model/Profile.php:952 src/Model/Profile.php:963
+msgid "Events and Calendar"
+msgstr ""
+
+#: view/theme/frio/theme.php:276 src/Content/Nav.php:254
+msgid "Private mail"
+msgstr ""
+
+#: view/theme/frio/theme.php:277 src/Content/Nav.php:263
+msgid "Account settings"
+msgstr ""
+
+#: view/theme/frio/theme.php:278 src/Content/Text/HTML.php:922
+#: src/Content/Nav.php:205 src/Content/Nav.php:269 src/Model/Profile.php:992
+#: src/Model/Profile.php:995 src/Module/Contact.php:795
+#: src/Module/Contact.php:880
+msgid "Contacts"
 msgstr ""
 
-#: view/theme/frio/php/Image.php:27
-msgid "Repeat image to fill the screen."
+#: view/theme/frio/theme.php:278 src/Content/Nav.php:269
+msgid "Manage/edit friends and contacts"
 msgstr ""
 
 #: view/theme/frio/config.php:111
@@ -4334,79 +4312,6 @@ msgstr ""
 msgid "Leave background image and color empty for theme defaults"
 msgstr ""
 
-#: view/theme/frio/theme.php:246
-msgid "Guest"
-msgstr ""
-
-#: view/theme/frio/theme.php:251
-msgid "Visitor"
-msgstr ""
-
-#: view/theme/frio/theme.php:267 src/Content/Nav.php:160
-#: src/Model/Profile.php:917 src/Module/Settings/TwoFactor/Index.php:91
-#: src/Module/Contact.php:616 src/Module/Contact.php:831
-msgid "Status"
-msgstr ""
-
-#: view/theme/frio/theme.php:267 src/Content/Nav.php:160
-#: src/Content/Nav.php:244
-msgid "Your posts and conversations"
-msgstr ""
-
-#: view/theme/frio/theme.php:268 src/Content/Nav.php:161
-msgid "Your profile page"
-msgstr ""
-
-#: view/theme/frio/theme.php:269 src/Content/Nav.php:162
-msgid "Your photos"
-msgstr ""
-
-#: view/theme/frio/theme.php:270 src/Content/Nav.php:163
-#: src/Model/Profile.php:941 src/Model/Profile.php:944
-msgid "Videos"
-msgstr ""
-
-#: view/theme/frio/theme.php:270 src/Content/Nav.php:163
-msgid "Your videos"
-msgstr ""
-
-#: view/theme/frio/theme.php:271 src/Content/Nav.php:164
-msgid "Your events"
-msgstr ""
-
-#: view/theme/frio/theme.php:274 src/Core/NotificationsManager.php:151
-#: src/Content/Nav.php:241
-msgid "Network"
-msgstr ""
-
-#: view/theme/frio/theme.php:274 src/Content/Nav.php:241
-msgid "Conversations from your friends"
-msgstr ""
-
-#: view/theme/frio/theme.php:275 src/Content/Nav.php:228
-#: src/Model/Profile.php:956 src/Model/Profile.php:967
-msgid "Events and Calendar"
-msgstr ""
-
-#: view/theme/frio/theme.php:276 src/Content/Nav.php:254
-msgid "Private mail"
-msgstr ""
-
-#: view/theme/frio/theme.php:277 src/Content/Nav.php:265
-msgid "Account settings"
-msgstr ""
-
-#: view/theme/frio/theme.php:278 src/Content/Text/HTML.php:904
-#: src/Content/Nav.php:205 src/Content/Nav.php:271 src/Model/Profile.php:996
-#: src/Model/Profile.php:999 src/Module/Contact.php:774
-#: src/Module/Contact.php:859
-msgid "Contacts"
-msgstr ""
-
-#: view/theme/frio/theme.php:278 src/Content/Nav.php:271
-msgid "Manage/edit friends and contacts"
-msgstr ""
-
 #: view/theme/quattro/config.php:76
 msgid "Alignment"
 msgstr ""
@@ -4431,296 +4336,296 @@ msgstr ""
 msgid "Textareas font size"
 msgstr ""
 
-#: view/theme/vier/config.php:76
+#: view/theme/vier/config.php:78
 msgid "Comma separated list of helper forums"
 msgstr ""
 
-#: view/theme/vier/config.php:116 src/Core/ACL.php:302
+#: view/theme/vier/config.php:118 src/Core/ACL.php:303
 msgid "don't show"
 msgstr ""
 
-#: view/theme/vier/config.php:116 src/Core/ACL.php:301
+#: view/theme/vier/config.php:118 src/Core/ACL.php:302
 msgid "show"
 msgstr ""
 
-#: view/theme/vier/config.php:122
+#: view/theme/vier/config.php:124
 msgid "Set style"
 msgstr ""
 
-#: view/theme/vier/config.php:123
+#: view/theme/vier/config.php:125
 msgid "Community Pages"
 msgstr ""
 
-#: view/theme/vier/config.php:124 view/theme/vier/theme.php:151
+#: view/theme/vier/config.php:126 view/theme/vier/theme.php:128
 msgid "Community Profiles"
 msgstr ""
 
-#: view/theme/vier/config.php:125
+#: view/theme/vier/config.php:127
 msgid "Help or @NewHere ?"
 msgstr ""
 
-#: view/theme/vier/config.php:126 view/theme/vier/theme.php:373
+#: view/theme/vier/config.php:128 view/theme/vier/theme.php:350
 msgid "Connect Services"
 msgstr ""
 
-#: view/theme/vier/config.php:127
+#: view/theme/vier/config.php:129
 msgid "Find Friends"
 msgstr ""
 
-#: view/theme/vier/config.php:128 view/theme/vier/theme.php:181
+#: view/theme/vier/config.php:130 view/theme/vier/theme.php:158
 msgid "Last users"
 msgstr ""
 
-#: view/theme/vier/theme.php:199 src/Content/Widget.php:64
+#: view/theme/vier/theme.php:176 src/Content/Widget.php:65
 msgid "Find People"
 msgstr ""
 
-#: view/theme/vier/theme.php:200 src/Content/Widget.php:65
+#: view/theme/vier/theme.php:177 src/Content/Widget.php:66
 msgid "Enter name or interest"
 msgstr ""
 
-#: view/theme/vier/theme.php:202 src/Content/Widget.php:67
+#: view/theme/vier/theme.php:179 src/Content/Widget.php:68
 msgid "Examples: Robert Morgenstein, Fishing"
 msgstr ""
 
-#: view/theme/vier/theme.php:203 src/Content/Widget.php:68
-#: src/Module/Directory.php:86 src/Module/Contact.php:795
+#: view/theme/vier/theme.php:180 src/Content/Widget.php:69
+#: src/Module/Contact.php:816 src/Module/Directory.php:84
 msgid "Find"
 msgstr ""
 
-#: view/theme/vier/theme.php:205 src/Content/Widget.php:70
+#: view/theme/vier/theme.php:182 src/Content/Widget.php:71
 msgid "Similar Interests"
 msgstr ""
 
-#: view/theme/vier/theme.php:206 src/Content/Widget.php:71
+#: view/theme/vier/theme.php:183 src/Content/Widget.php:72
 msgid "Random Profile"
 msgstr ""
 
-#: view/theme/vier/theme.php:207 src/Content/Widget.php:72
+#: view/theme/vier/theme.php:184 src/Content/Widget.php:73
 msgid "Invite Friends"
 msgstr ""
 
-#: view/theme/vier/theme.php:208 src/Content/Widget.php:73
-#: src/Module/Directory.php:78
+#: view/theme/vier/theme.php:185 src/Content/Widget.php:74
+#: src/Module/Directory.php:76
 msgid "Global Directory"
 msgstr ""
 
-#: view/theme/vier/theme.php:210 src/Content/Widget.php:75
+#: view/theme/vier/theme.php:187 src/Content/Widget.php:76
 msgid "Local Directory"
 msgstr ""
 
-#: view/theme/vier/theme.php:250 src/Content/Text/HTML.php:907
-#: src/Content/Nav.php:209 src/Content/ForumManager.php:130
+#: view/theme/vier/theme.php:227 src/Content/Text/HTML.php:926
+#: src/Content/ForumManager.php:130 src/Content/Nav.php:209
 msgid "Forums"
 msgstr ""
 
-#: view/theme/vier/theme.php:252 src/Content/ForumManager.php:132
+#: view/theme/vier/theme.php:229 src/Content/ForumManager.php:132
 msgid "External link to forum"
 msgstr ""
 
-#: view/theme/vier/theme.php:255 src/Content/Widget.php:407
-#: src/Content/Widget.php:507 src/Content/ForumManager.php:135
+#: view/theme/vier/theme.php:232 src/Content/ForumManager.php:135
+#: src/Content/Widget.php:405 src/Content/Widget.php:505
 msgid "show more"
 msgstr ""
 
-#: view/theme/vier/theme.php:288
+#: view/theme/vier/theme.php:265
 msgid "Quick Start"
 msgstr ""
 
-#: view/theme/vier/theme.php:294 src/Content/Nav.php:192 src/Module/Help.php:50
+#: view/theme/vier/theme.php:271 src/Content/Nav.php:192 src/Module/Help.php:50
 #: src/Module/Settings/TwoFactor/AppSpecific.php:99
-#: src/Module/Settings/TwoFactor/Index.php:90
 #: src/Module/Settings/TwoFactor/Recovery.php:77
+#: src/Module/Settings/TwoFactor/Index.php:90
 #: src/Module/Settings/TwoFactor/Verify.php:117
 msgid "Help"
 msgstr ""
 
-#: src/Core/L10n/L10n.php:370 src/Model/Event.php:397
+#: src/Core/L10n/L10n.php:404 src/Model/Event.php:398
 msgid "Tuesday"
 msgstr ""
 
-#: src/Core/L10n/L10n.php:370 src/Model/Event.php:398
+#: src/Core/L10n/L10n.php:404 src/Model/Event.php:399
 msgid "Wednesday"
 msgstr ""
 
-#: src/Core/L10n/L10n.php:370 src/Model/Event.php:399
+#: src/Core/L10n/L10n.php:404 src/Model/Event.php:400
 msgid "Thursday"
 msgstr ""
 
-#: src/Core/L10n/L10n.php:370 src/Model/Event.php:400
+#: src/Core/L10n/L10n.php:404 src/Model/Event.php:401
 msgid "Friday"
 msgstr ""
 
-#: src/Core/L10n/L10n.php:370 src/Model/Event.php:401
+#: src/Core/L10n/L10n.php:404 src/Model/Event.php:402
 msgid "Saturday"
 msgstr ""
 
-#: src/Core/L10n/L10n.php:374 src/Model/Event.php:416
+#: src/Core/L10n/L10n.php:408 src/Model/Event.php:417
 msgid "January"
 msgstr ""
 
-#: src/Core/L10n/L10n.php:374 src/Model/Event.php:417
+#: src/Core/L10n/L10n.php:408 src/Model/Event.php:418
 msgid "February"
 msgstr ""
 
-#: src/Core/L10n/L10n.php:374 src/Model/Event.php:418
+#: src/Core/L10n/L10n.php:408 src/Model/Event.php:419
 msgid "March"
 msgstr ""
 
-#: src/Core/L10n/L10n.php:374 src/Model/Event.php:419
+#: src/Core/L10n/L10n.php:408 src/Model/Event.php:420
 msgid "April"
 msgstr ""
 
-#: src/Core/L10n/L10n.php:374 src/Core/L10n/L10n.php:394
-#: src/Model/Event.php:407
+#: src/Core/L10n/L10n.php:408 src/Core/L10n/L10n.php:428
+#: src/Model/Event.php:408
 msgid "May"
 msgstr ""
 
-#: src/Core/L10n/L10n.php:374 src/Model/Event.php:420
+#: src/Core/L10n/L10n.php:408 src/Model/Event.php:421
 msgid "June"
 msgstr ""
 
-#: src/Core/L10n/L10n.php:374 src/Model/Event.php:421
+#: src/Core/L10n/L10n.php:408 src/Model/Event.php:422
 msgid "July"
 msgstr ""
 
-#: src/Core/L10n/L10n.php:374 src/Model/Event.php:422
+#: src/Core/L10n/L10n.php:408 src/Model/Event.php:423
 msgid "August"
 msgstr ""
 
-#: src/Core/L10n/L10n.php:374 src/Model/Event.php:423
+#: src/Core/L10n/L10n.php:408 src/Model/Event.php:424
 msgid "September"
 msgstr ""
 
-#: src/Core/L10n/L10n.php:374 src/Model/Event.php:424
+#: src/Core/L10n/L10n.php:408 src/Model/Event.php:425
 msgid "October"
 msgstr ""
 
-#: src/Core/L10n/L10n.php:374 src/Model/Event.php:425
+#: src/Core/L10n/L10n.php:408 src/Model/Event.php:426
 msgid "November"
 msgstr ""
 
-#: src/Core/L10n/L10n.php:374 src/Model/Event.php:426
+#: src/Core/L10n/L10n.php:408 src/Model/Event.php:427
 msgid "December"
 msgstr ""
 
-#: src/Core/L10n/L10n.php:390 src/Model/Event.php:388
+#: src/Core/L10n/L10n.php:424 src/Model/Event.php:389
 msgid "Mon"
 msgstr ""
 
-#: src/Core/L10n/L10n.php:390 src/Model/Event.php:389
+#: src/Core/L10n/L10n.php:424 src/Model/Event.php:390
 msgid "Tue"
 msgstr ""
 
-#: src/Core/L10n/L10n.php:390 src/Model/Event.php:390
+#: src/Core/L10n/L10n.php:424 src/Model/Event.php:391
 msgid "Wed"
 msgstr ""
 
-#: src/Core/L10n/L10n.php:390 src/Model/Event.php:391
+#: src/Core/L10n/L10n.php:424 src/Model/Event.php:392
 msgid "Thu"
 msgstr ""
 
-#: src/Core/L10n/L10n.php:390 src/Model/Event.php:392
+#: src/Core/L10n/L10n.php:424 src/Model/Event.php:393
 msgid "Fri"
 msgstr ""
 
-#: src/Core/L10n/L10n.php:390 src/Model/Event.php:393
+#: src/Core/L10n/L10n.php:424 src/Model/Event.php:394
 msgid "Sat"
 msgstr ""
 
-#: src/Core/L10n/L10n.php:390 src/Model/Event.php:387
+#: src/Core/L10n/L10n.php:424 src/Model/Event.php:388
 msgid "Sun"
 msgstr ""
 
-#: src/Core/L10n/L10n.php:394 src/Model/Event.php:403
+#: src/Core/L10n/L10n.php:428 src/Model/Event.php:404
 msgid "Jan"
 msgstr ""
 
-#: src/Core/L10n/L10n.php:394 src/Model/Event.php:404
+#: src/Core/L10n/L10n.php:428 src/Model/Event.php:405
 msgid "Feb"
 msgstr ""
 
-#: src/Core/L10n/L10n.php:394 src/Model/Event.php:405
+#: src/Core/L10n/L10n.php:428 src/Model/Event.php:406
 msgid "Mar"
 msgstr ""
 
-#: src/Core/L10n/L10n.php:394 src/Model/Event.php:406
+#: src/Core/L10n/L10n.php:428 src/Model/Event.php:407
 msgid "Apr"
 msgstr ""
 
-#: src/Core/L10n/L10n.php:394 src/Model/Event.php:408
+#: src/Core/L10n/L10n.php:428 src/Model/Event.php:409
 msgid "Jun"
 msgstr ""
 
-#: src/Core/L10n/L10n.php:394 src/Model/Event.php:409
+#: src/Core/L10n/L10n.php:428 src/Model/Event.php:410
 msgid "Jul"
 msgstr ""
 
-#: src/Core/L10n/L10n.php:394 src/Model/Event.php:410
+#: src/Core/L10n/L10n.php:428 src/Model/Event.php:411
 msgid "Aug"
 msgstr ""
 
-#: src/Core/L10n/L10n.php:394
+#: src/Core/L10n/L10n.php:428
 msgid "Sep"
 msgstr ""
 
-#: src/Core/L10n/L10n.php:394 src/Model/Event.php:412
+#: src/Core/L10n/L10n.php:428 src/Model/Event.php:413
 msgid "Oct"
 msgstr ""
 
-#: src/Core/L10n/L10n.php:394 src/Model/Event.php:413
+#: src/Core/L10n/L10n.php:428 src/Model/Event.php:414
 msgid "Nov"
 msgstr ""
 
-#: src/Core/L10n/L10n.php:394 src/Model/Event.php:414
+#: src/Core/L10n/L10n.php:428 src/Model/Event.php:415
 msgid "Dec"
 msgstr ""
 
-#: src/Core/L10n/L10n.php:413
+#: src/Core/L10n/L10n.php:447
 msgid "poke"
 msgstr ""
 
-#: src/Core/L10n/L10n.php:413
+#: src/Core/L10n/L10n.php:447
 msgid "poked"
 msgstr ""
 
-#: src/Core/L10n/L10n.php:414
+#: src/Core/L10n/L10n.php:448
 msgid "ping"
 msgstr ""
 
-#: src/Core/L10n/L10n.php:414
+#: src/Core/L10n/L10n.php:448
 msgid "pinged"
 msgstr ""
 
-#: src/Core/L10n/L10n.php:415
+#: src/Core/L10n/L10n.php:449
 msgid "prod"
 msgstr ""
 
-#: src/Core/L10n/L10n.php:415
+#: src/Core/L10n/L10n.php:449
 msgid "prodded"
 msgstr ""
 
-#: src/Core/L10n/L10n.php:416
+#: src/Core/L10n/L10n.php:450
 msgid "slap"
 msgstr ""
 
-#: src/Core/L10n/L10n.php:416
+#: src/Core/L10n/L10n.php:450
 msgid "slapped"
 msgstr ""
 
-#: src/Core/L10n/L10n.php:417
+#: src/Core/L10n/L10n.php:451
 msgid "finger"
 msgstr ""
 
-#: src/Core/L10n/L10n.php:417
+#: src/Core/L10n/L10n.php:451
 msgid "fingered"
 msgstr ""
 
-#: src/Core/L10n/L10n.php:418
+#: src/Core/L10n/L10n.php:452
 msgid "rebuff"
 msgstr ""
 
-#: src/Core/L10n/L10n.php:418
+#: src/Core/L10n/L10n.php:452
 msgid "rebuffed"
 msgstr ""
 
@@ -4791,6 +4696,31 @@ msgstr[1] ""
 msgid "Done. You can now login with your username and password"
 msgstr ""
 
+#: src/Core/ACL.php:289 src/Module/Item/Compose.php:143
+msgid "Post to Email"
+msgstr ""
+
+#: src/Core/ACL.php:301
+msgid "Visible to everybody"
+msgstr ""
+
+#: src/Core/ACL.php:312
+msgid "Connectors"
+msgstr ""
+
+#: src/Core/ACL.php:314
+msgid "Hide your profile details from unknown viewers?"
+msgstr ""
+
+#: src/Core/ACL.php:314
+#, php-format
+msgid "Connectors disabled, since \"%s\" is enabled."
+msgstr ""
+
+#: src/Core/ACL.php:316
+msgid "Close"
+msgstr ""
+
 #: src/Core/Installer.php:162
 msgid ""
 "The database configuration file \"config/local.config.php\" could not be "
@@ -5050,8 +4980,8 @@ msgstr ""
 msgid "ImageMagick PHP extension is installed"
 msgstr ""
 
-#: src/Core/Installer.php:582 tests/src/Core/InstallerTest.php:372
-#: tests/src/Core/InstallerTest.php:400
+#: src/Core/Installer.php:582 tests/src/Core/InstallerTest.php:366
+#: tests/src/Core/InstallerTest.php:389
 msgid "ImageMagick supports GIF"
 msgstr ""
 
@@ -5063,265 +4993,153 @@ msgstr ""
 msgid "Could not connect to database."
 msgstr ""
 
-#: src/Core/NotificationsManager.php:144
-msgid "System"
-msgstr ""
-
-#: src/Core/NotificationsManager.php:165 src/Content/Nav.php:182
-#: src/Content/Nav.php:244
-msgid "Home"
-msgstr ""
-
-#: src/Core/NotificationsManager.php:172 src/Content/Nav.php:248
-msgid "Introductions"
-msgstr ""
-
-#: src/Core/NotificationsManager.php:234 src/Core/NotificationsManager.php:246
-#, php-format
-msgid "%s commented on %s's post"
-msgstr ""
-
-#: src/Core/NotificationsManager.php:245
-#, php-format
-msgid "%s created a new post"
-msgstr ""
-
-#: src/Core/NotificationsManager.php:259
-#, php-format
-msgid "%s liked %s's post"
-msgstr ""
-
-#: src/Core/NotificationsManager.php:272
-#, php-format
-msgid "%s disliked %s's post"
-msgstr ""
-
-#: src/Core/NotificationsManager.php:285
-#, php-format
-msgid "%s is attending %s's event"
-msgstr ""
-
-#: src/Core/NotificationsManager.php:298
-#, php-format
-msgid "%s is not attending %s's event"
-msgstr ""
-
-#: src/Core/NotificationsManager.php:311
-#, php-format
-msgid "%s may attend %s's event"
-msgstr ""
-
-#: src/Core/NotificationsManager.php:344
-#, php-format
-msgid "%s is now friends with %s"
-msgstr ""
-
-#: src/Core/NotificationsManager.php:629
-msgid "Friend Suggestion"
-msgstr ""
-
-#: src/Core/NotificationsManager.php:663
-msgid "Friend/Connect Request"
-msgstr ""
-
-#: src/Core/NotificationsManager.php:663
-msgid "New Follower"
-msgstr ""
-
-#: src/Core/Session.php:186
+#: src/Core/Session.php:199
 #, php-format
 msgid "Welcome %s"
 msgstr ""
 
-#: src/Core/Session.php:187
+#: src/Core/Session.php:200
 msgid "Please upload a profile photo."
 msgstr ""
 
-#: src/Core/Session.php:190
+#: src/Core/Session.php:203
 #, php-format
 msgid "Welcome back %s"
 msgstr ""
 
-#: src/Core/ACL.php:288 src/Module/Item/Compose.php:139
-msgid "Post to Email"
-msgstr ""
-
-#: src/Core/ACL.php:300
-msgid "Visible to everybody"
-msgstr ""
-
-#: src/Core/ACL.php:311
-msgid "Connectors"
-msgstr ""
-
-#: src/Core/ACL.php:313
-msgid "Hide your profile details from unknown viewers?"
-msgstr ""
-
-#: src/Core/ACL.php:313
-#, php-format
-msgid "Connectors disabled, since \"%s\" is enabled."
-msgstr ""
-
-#: src/Core/ACL.php:315
-msgid "Close"
-msgstr ""
-
-#: src/Util/Temporal.php:147 src/Model/Profile.php:784
+#: src/Util/Temporal.php:146 src/Model/Profile.php:780
 msgid "Birthday:"
 msgstr ""
 
-#: src/Util/Temporal.php:151
+#: src/Util/Temporal.php:150
 msgid "YYYY-MM-DD or MM-DD"
 msgstr ""
 
-#: src/Util/Temporal.php:298
+#: src/Util/Temporal.php:297
 msgid "never"
 msgstr ""
 
-#: src/Util/Temporal.php:305
+#: src/Util/Temporal.php:304
 msgid "less than a second ago"
 msgstr ""
 
-#: src/Util/Temporal.php:313
+#: src/Util/Temporal.php:312
 msgid "year"
 msgstr ""
 
-#: src/Util/Temporal.php:313
+#: src/Util/Temporal.php:312
 msgid "years"
 msgstr ""
 
-#: src/Util/Temporal.php:314
+#: src/Util/Temporal.php:313
 msgid "months"
 msgstr ""
 
-#: src/Util/Temporal.php:315
+#: src/Util/Temporal.php:314
 msgid "weeks"
 msgstr ""
 
-#: src/Util/Temporal.php:316
+#: src/Util/Temporal.php:315
 msgid "days"
 msgstr ""
 
-#: src/Util/Temporal.php:317
+#: src/Util/Temporal.php:316
 msgid "hour"
 msgstr ""
 
-#: src/Util/Temporal.php:317
+#: src/Util/Temporal.php:316
 msgid "hours"
 msgstr ""
 
-#: src/Util/Temporal.php:318
+#: src/Util/Temporal.php:317
 msgid "minute"
 msgstr ""
 
-#: src/Util/Temporal.php:318
+#: src/Util/Temporal.php:317
 msgid "minutes"
 msgstr ""
 
-#: src/Util/Temporal.php:319
+#: src/Util/Temporal.php:318
 msgid "second"
 msgstr ""
 
-#: src/Util/Temporal.php:319
+#: src/Util/Temporal.php:318
 msgid "seconds"
 msgstr ""
 
-#: src/Util/Temporal.php:329
+#: src/Util/Temporal.php:328
 #, php-format
 msgid "in %1$d %2$s"
 msgstr ""
 
-#: src/Util/Temporal.php:332
+#: src/Util/Temporal.php:331
 #, php-format
 msgid "%1$d %2$s ago"
 msgstr ""
 
-#: src/Content/Text/HTML.php:793
-msgid "Loading more entries..."
-msgstr ""
-
-#: src/Content/Text/HTML.php:794
-msgid "The end"
-msgstr ""
-
-#: src/Content/Text/HTML.php:887 src/Model/Profile.php:544
-#: src/Module/Contact.php:297
-msgid "Follow"
-msgstr ""
-
-#: src/Content/Text/HTML.php:896 src/Content/Nav.php:79
-msgid "@name, !forum, #tags, content"
-msgstr ""
-
-#: src/Content/Text/HTML.php:902 src/Content/Nav.php:203
-msgid "Full Text"
-msgstr ""
-
-#: src/Content/Text/HTML.php:903 src/Content/Widget/TagCloud.php:54
-#: src/Content/Nav.php:204
-msgid "Tags"
-msgstr ""
-
-#: src/Content/Text/HTML.php:944 src/Content/Text/BBCode.php:1478
-msgid "Click to open/close"
-msgstr ""
-
-#: src/Content/Text/BBCode.php:465
+#: src/Content/Text/BBCode.php:467
 msgid "view full size"
 msgstr ""
 
-#: src/Content/Text/BBCode.php:899 src/Content/Text/BBCode.php:1560
-#: src/Content/Text/BBCode.php:1561
+#: src/Content/Text/BBCode.php:913 src/Content/Text/BBCode.php:1579
+#: src/Content/Text/BBCode.php:1580
 msgid "Image/photo"
 msgstr ""
 
-#: src/Content/Text/BBCode.php:1017
+#: src/Content/Text/BBCode.php:1031
 #, php-format
 msgid "<a href=\"%1$s\" target=\"_blank\">%2$s</a> %3$s"
 msgstr ""
 
-#: src/Content/Text/BBCode.php:1509
+#: src/Content/Text/BBCode.php:1497 src/Content/Text/HTML.php:963
+msgid "Click to open/close"
+msgstr ""
+
+#: src/Content/Text/BBCode.php:1528
 msgid "$1 wrote:"
 msgstr ""
 
-#: src/Content/Text/BBCode.php:1563 src/Content/Text/BBCode.php:1564
+#: src/Content/Text/BBCode.php:1582 src/Content/Text/BBCode.php:1583
 msgid "Encrypted content"
 msgstr ""
 
-#: src/Content/Text/BBCode.php:1788
+#: src/Content/Text/BBCode.php:1805
 msgid "Invalid source protocol"
 msgstr ""
 
-#: src/Content/Text/BBCode.php:1803
+#: src/Content/Text/BBCode.php:1820
 msgid "Invalid link protocol"
 msgstr ""
 
-#: src/Content/Widget/CalendarExport.php:64
-msgid "Export"
+#: src/Content/Text/HTML.php:811
+msgid "Loading more entries..."
 msgstr ""
 
-#: src/Content/Widget/CalendarExport.php:65
-msgid "Export calendar as ical"
+#: src/Content/Text/HTML.php:812
+msgid "The end"
 msgstr ""
 
-#: src/Content/Widget/CalendarExport.php:66
-msgid "Export calendar as csv"
+#: src/Content/Text/HTML.php:905 src/Model/Profile.php:540
+#: src/Module/Contact.php:318
+msgid "Follow"
 msgstr ""
 
-#: src/Content/Widget/ContactBlock.php:58
-msgid "No contacts"
+#: src/Content/Text/HTML.php:911 src/Content/Nav.php:200
+#: src/Module/Search/Index.php:80
+msgid "Search"
 msgstr ""
 
-#: src/Content/Widget/ContactBlock.php:90
-#, php-format
-msgid "%d Contact"
-msgid_plural "%d Contacts"
-msgstr[0] ""
-msgstr[1] ""
+#: src/Content/Text/HTML.php:913 src/Content/Nav.php:79
+msgid "@name, !forum, #tags, content"
+msgstr ""
 
-#: src/Content/Widget/ContactBlock.php:109
-msgid "View Contacts"
+#: src/Content/Text/HTML.php:920 src/Content/Nav.php:203
+msgid "Full Text"
+msgstr ""
+
+#: src/Content/Text/HTML.php:921 src/Content/Widget/TagCloud.php:54
+#: src/Content/Nav.php:204
+msgid "Tags"
 msgstr ""
 
 #: src/Content/Widget/TrendingTags.php:34
@@ -5335,20 +5153,39 @@ msgstr[1] ""
 msgid "More Trending Tags"
 msgstr ""
 
-#: src/Content/Pager.php:153
-msgid "newer"
+#: src/Content/Widget/CalendarExport.php:64
+msgid "Export"
+msgstr ""
+
+#: src/Content/Widget/CalendarExport.php:65
+msgid "Export calendar as ical"
+msgstr ""
+
+#: src/Content/Widget/CalendarExport.php:66
+msgid "Export calendar as csv"
+msgstr ""
+
+#: src/Content/Widget/ContactBlock.php:58
+msgid "No contacts"
 msgstr ""
 
-#: src/Content/Pager.php:158
-msgid "older"
+#: src/Content/Widget/ContactBlock.php:90
+#, php-format
+msgid "%d Contact"
+msgid_plural "%d Contacts"
+msgstr[0] ""
+msgstr[1] ""
+
+#: src/Content/Widget/ContactBlock.php:109
+msgid "View Contacts"
 msgstr ""
 
-#: src/Content/Pager.php:203
-msgid "prev"
+#: src/Content/Widget/SavedSearches.php:29
+msgid "Remove term"
 msgstr ""
 
-#: src/Content/Pager.php:263
-msgid "last"
+#: src/Content/Widget/SavedSearches.php:37
+msgid "Saved Searches"
 msgstr ""
 
 #: src/Content/Feature.php:82
@@ -5418,7 +5255,7 @@ msgstr ""
 msgid "Network Sidebar"
 msgstr ""
 
-#: src/Content/Feature.php:100 src/Content/Widget.php:501
+#: src/Content/Feature.php:100 src/Content/Widget.php:499
 msgid "Archives"
 msgstr ""
 
@@ -5494,156 +5331,6 @@ msgstr ""
 msgid "Display membership date in profile"
 msgstr ""
 
-#: src/Content/Nav.php:74
-msgid "Nothing new here"
-msgstr ""
-
-#: src/Content/Nav.php:78
-msgid "Clear notifications"
-msgstr ""
-
-#: src/Content/Nav.php:153 src/Module/Login.php:315
-msgid "Logout"
-msgstr ""
-
-#: src/Content/Nav.php:153
-msgid "End this session"
-msgstr ""
-
-#: src/Content/Nav.php:155 src/Module/Login.php:316
-#: src/Module/Bookmarklet.php:25
-msgid "Login"
-msgstr ""
-
-#: src/Content/Nav.php:155
-msgid "Sign in"
-msgstr ""
-
-#: src/Content/Nav.php:165
-msgid "Personal notes"
-msgstr ""
-
-#: src/Content/Nav.php:165
-msgid "Your personal notes"
-msgstr ""
-
-#: src/Content/Nav.php:182
-msgid "Home Page"
-msgstr ""
-
-#: src/Content/Nav.php:186 src/Module/Login.php:287 src/Module/Register.php:136
-msgid "Register"
-msgstr ""
-
-#: src/Content/Nav.php:186
-msgid "Create an account"
-msgstr ""
-
-#: src/Content/Nav.php:192
-msgid "Help and documentation"
-msgstr ""
-
-#: src/Content/Nav.php:196
-msgid "Apps"
-msgstr ""
-
-#: src/Content/Nav.php:196
-msgid "Addon applications, utilities, games"
-msgstr ""
-
-#: src/Content/Nav.php:200
-msgid "Search site content"
-msgstr ""
-
-#: src/Content/Nav.php:224
-msgid "Community"
-msgstr ""
-
-#: src/Content/Nav.php:224
-msgid "Conversations on this and other servers"
-msgstr ""
-
-#: src/Content/Nav.php:231
-msgid "Directory"
-msgstr ""
-
-#: src/Content/Nav.php:231
-msgid "People directory"
-msgstr ""
-
-#: src/Content/Nav.php:233 src/Module/BaseAdminModule.php:75
-msgid "Information"
-msgstr ""
-
-#: src/Content/Nav.php:233
-msgid "Information about this friendica instance"
-msgstr ""
-
-#: src/Content/Nav.php:236 src/Module/Tos.php:73 src/Module/Admin/Tos.php:43
-#: src/Module/BaseAdminModule.php:85 src/Module/Register.php:144
-msgid "Terms of Service"
-msgstr ""
-
-#: src/Content/Nav.php:236
-msgid "Terms of Service of this Friendica instance"
-msgstr ""
-
-#: src/Content/Nav.php:242
-msgid "Network Reset"
-msgstr ""
-
-#: src/Content/Nav.php:242
-msgid "Load Network page with no filters"
-msgstr ""
-
-#: src/Content/Nav.php:248
-msgid "Friend Requests"
-msgstr ""
-
-#: src/Content/Nav.php:250
-msgid "See all notifications"
-msgstr ""
-
-#: src/Content/Nav.php:251
-msgid "Mark all system notifications seen"
-msgstr ""
-
-#: src/Content/Nav.php:255
-msgid "Inbox"
-msgstr ""
-
-#: src/Content/Nav.php:256
-msgid "Outbox"
-msgstr ""
-
-#: src/Content/Nav.php:260
-msgid "Manage"
-msgstr ""
-
-#: src/Content/Nav.php:260
-msgid "Manage other pages"
-msgstr ""
-
-#: src/Content/Nav.php:268
-msgid "Manage/Edit Profiles"
-msgstr ""
-
-#: src/Content/Nav.php:276 src/Module/BaseAdminModule.php:114
-msgid "Admin"
-msgstr ""
-
-#: src/Content/Nav.php:276
-msgid "Site setup and configuration"
-msgstr ""
-
-#: src/Content/Nav.php:279
-msgid "Navigation"
-msgstr ""
-
-#: src/Content/Nav.php:279
-msgid "Site map"
-msgstr ""
-
 #: src/Content/OEmbed.php:254
 msgid "Embedding disabled"
 msgstr ""
@@ -5652,71 +5339,6 @@ msgstr ""
 msgid "Embedded content"
 msgstr ""
 
-#: src/Content/Widget.php:38
-msgid "Add New Contact"
-msgstr ""
-
-#: src/Content/Widget.php:39
-msgid "Enter address or web location"
-msgstr ""
-
-#: src/Content/Widget.php:40
-msgid "Example: bob@example.com, http://example.com/barbara"
-msgstr ""
-
-#: src/Content/Widget.php:58
-#, php-format
-msgid "%d invitation available"
-msgid_plural "%d invitations available"
-msgstr[0] ""
-msgstr[1] ""
-
-#: src/Content/Widget.php:193 src/Module/Profile/Contacts.php:127
-#: src/Module/Contact.php:772
-msgid "Following"
-msgstr ""
-
-#: src/Content/Widget.php:194 src/Module/Profile/Contacts.php:128
-#: src/Module/Contact.php:773
-msgid "Mutual friends"
-msgstr ""
-
-#: src/Content/Widget.php:199
-msgid "Relationships"
-msgstr ""
-
-#: src/Content/Widget.php:201 src/Module/Group.php:287
-#: src/Module/Contact.php:660
-msgid "All Contacts"
-msgstr ""
-
-#: src/Content/Widget.php:244
-msgid "Protocols"
-msgstr ""
-
-#: src/Content/Widget.php:246
-msgid "All Protocols"
-msgstr ""
-
-#: src/Content/Widget.php:279
-msgid "Saved Folders"
-msgstr ""
-
-#: src/Content/Widget.php:281 src/Content/Widget.php:320
-msgid "Everything"
-msgstr ""
-
-#: src/Content/Widget.php:318
-msgid "Categories"
-msgstr ""
-
-#: src/Content/Widget.php:402
-#, php-format
-msgid "%d contact in common"
-msgid_plural "%d contacts in common"
-msgstr[0] ""
-msgstr[1] ""
-
 #: src/Content/ContactSelector.php:58
 msgid "Frequently"
 msgstr ""
@@ -5944,7 +5566,7 @@ msgstr ""
 msgid "Sex Addict"
 msgstr ""
 
-#: src/Content/ContactSelector.php:316 src/Model/User.php:762
+#: src/Content/ContactSelector.php:316 src/Model/User.php:807
 msgid "Friends"
 msgstr ""
 
@@ -6032,419 +5654,462 @@ msgstr ""
 msgid "Ask me"
 msgstr ""
 
-#: src/Database/DBStructure.php:50
-msgid "There are no tables on MyISAM."
+#: src/Content/Nav.php:74
+msgid "Nothing new here"
 msgstr ""
 
-#: src/Database/DBStructure.php:74
-#, php-format
-msgid ""
-"\n"
-"Error %d occurred during database update:\n"
-"%s\n"
+#: src/Content/Nav.php:78
+msgid "Clear notifications"
 msgstr ""
 
-#: src/Database/DBStructure.php:77
-msgid "Errors encountered performing database changes: "
+#: src/Content/Nav.php:153 src/Module/Login.php:352
+msgid "Logout"
 msgstr ""
 
-#: src/Database/DBStructure.php:266
-#, php-format
-msgid "%s: Database update"
+#: src/Content/Nav.php:153
+msgid "End this session"
 msgstr ""
 
-#: src/Database/DBStructure.php:527
-#, php-format
-msgid "%s: updating %s table."
+#: src/Content/Nav.php:155 src/Module/Bookmarklet.php:25
+#: src/Module/Login.php:353
+msgid "Login"
 msgstr ""
 
-#: src/Model/Storage/Filesystem.php:63
-#, php-format
-msgid ""
-"Filesystem storage failed to create \"%s\". Check you write permissions."
+#: src/Content/Nav.php:155
+msgid "Sign in"
 msgstr ""
 
-#: src/Model/Storage/Filesystem.php:105
-#, php-format
-msgid ""
-"Filesystem storage failed to save data to \"%s\". Check your write "
-"permissions"
+#: src/Content/Nav.php:165
+msgid "Personal notes"
 msgstr ""
 
-#: src/Model/Storage/Filesystem.php:126
-msgid "Storage base path"
+#: src/Content/Nav.php:165
+msgid "Your personal notes"
 msgstr ""
 
-#: src/Model/Storage/Filesystem.php:128
-msgid ""
-"Folder where uploaded files are saved. For maximum security, This should be "
-"a path outside web server folder tree"
+#: src/Content/Nav.php:182 src/Content/Nav.php:244
+msgid "Home"
+msgstr ""
+
+#: src/Content/Nav.php:182
+msgid "Home Page"
+msgstr ""
+
+#: src/Content/Nav.php:186 src/Module/Login.php:313 src/Module/Register.php:130
+msgid "Register"
 msgstr ""
 
-#: src/Model/Storage/Filesystem.php:138
-msgid "Enter a valid existing folder"
+#: src/Content/Nav.php:186
+msgid "Create an account"
 msgstr ""
 
-#: src/Model/Storage/Database.php:36
-#, php-format
-msgid "Database storage failed to update %s"
+#: src/Content/Nav.php:192
+msgid "Help and documentation"
 msgstr ""
 
-#: src/Model/Storage/Database.php:43
-msgid "Database storage failed to insert data"
+#: src/Content/Nav.php:196
+msgid "Apps"
 msgstr ""
 
-#: src/Model/Event.php:34 src/Model/Event.php:847
-#: src/Module/Debug/Localtime.php:17
-msgid "l F d, Y \\@ g:i A"
+#: src/Content/Nav.php:196
+msgid "Addon applications, utilities, games"
 msgstr ""
 
-#: src/Model/Event.php:61 src/Model/Event.php:78 src/Model/Event.php:435
-#: src/Model/Event.php:915
-msgid "Starts:"
+#: src/Content/Nav.php:200
+msgid "Search site content"
 msgstr ""
 
-#: src/Model/Event.php:64 src/Model/Event.php:84 src/Model/Event.php:436
-#: src/Model/Event.php:919
-msgid "Finishes:"
+#: src/Content/Nav.php:224
+msgid "Community"
 msgstr ""
 
-#: src/Model/Event.php:385
-msgid "all-day"
+#: src/Content/Nav.php:224
+msgid "Conversations on this and other servers"
 msgstr ""
 
-#: src/Model/Event.php:411
-msgid "Sept"
+#: src/Content/Nav.php:231
+msgid "Directory"
 msgstr ""
 
-#: src/Model/Event.php:433
-msgid "No events to display"
+#: src/Content/Nav.php:231
+msgid "People directory"
 msgstr ""
 
-#: src/Model/Event.php:561
-msgid "l, F j"
+#: src/Content/Nav.php:233 src/Module/BaseAdminModule.php:75
+msgid "Information"
 msgstr ""
 
-#: src/Model/Event.php:592
-msgid "Edit event"
+#: src/Content/Nav.php:233
+msgid "Information about this friendica instance"
 msgstr ""
 
-#: src/Model/Event.php:593
-msgid "Duplicate event"
+#: src/Content/Nav.php:236 src/Module/Admin/Tos.php:43
+#: src/Module/BaseAdminModule.php:85 src/Module/Register.php:138
+#: src/Module/Tos.php:73
+msgid "Terms of Service"
 msgstr ""
 
-#: src/Model/Event.php:594
-msgid "Delete event"
+#: src/Content/Nav.php:236
+msgid "Terms of Service of this Friendica instance"
 msgstr ""
 
-#: src/Model/Event.php:626 src/Model/Item.php:3547 src/Model/Item.php:3554
-msgid "link to source"
+#: src/Content/Nav.php:242
+msgid "Network Reset"
 msgstr ""
 
-#: src/Model/Event.php:848
-msgid "D g:i A"
+#: src/Content/Nav.php:242
+msgid "Load Network page with no filters"
 msgstr ""
 
-#: src/Model/Event.php:849
-msgid "g:i A"
+#: src/Content/Nav.php:248
+msgid "Introductions"
 msgstr ""
 
-#: src/Model/Event.php:934 src/Model/Event.php:936
-msgid "Show map"
+#: src/Content/Nav.php:248
+msgid "Friend Requests"
 msgstr ""
 
-#: src/Model/Event.php:935
-msgid "Hide map"
+#: src/Content/Nav.php:250
+msgid "See all notifications"
 msgstr ""
 
-#: src/Model/Event.php:1027
-#, php-format
-msgid "%s's birthday"
+#: src/Content/Nav.php:251
+msgid "Mark all system notifications seen"
 msgstr ""
 
-#: src/Model/Event.php:1028
-#, php-format
-msgid "Happy Birthday %s"
+#: src/Content/Nav.php:255
+msgid "Inbox"
 msgstr ""
 
-#: src/Model/FileTag.php:265
-msgid "Item filed"
+#: src/Content/Nav.php:256
+msgid "Outbox"
 msgstr ""
 
-#: src/Model/User.php:331
-msgid "Login failed"
+#: src/Content/Nav.php:260
+msgid "Delegation"
 msgstr ""
 
-#: src/Model/User.php:362
-msgid "Not enough information to authenticate"
+#: src/Content/Nav.php:260
+msgid "Manage other pages"
 msgstr ""
 
-#: src/Model/User.php:440
-msgid "Password can't be empty"
+#: src/Content/Nav.php:266
+msgid "Manage/Edit Profiles"
 msgstr ""
 
-#: src/Model/User.php:459
-msgid "Empty passwords are not allowed."
+#: src/Content/Nav.php:274 src/Module/BaseAdminModule.php:114
+msgid "Admin"
 msgstr ""
 
-#: src/Model/User.php:463
-msgid ""
-"The new password has been exposed in a public data dump, please choose "
-"another."
+#: src/Content/Nav.php:274
+msgid "Site setup and configuration"
 msgstr ""
 
-#: src/Model/User.php:469
-msgid ""
-"The password can't contain accentuated letters, white spaces or colons (:)"
+#: src/Content/Nav.php:277
+msgid "Navigation"
 msgstr ""
 
-#: src/Model/User.php:569
-msgid "Passwords do not match. Password unchanged."
+#: src/Content/Nav.php:277
+msgid "Site map"
 msgstr ""
 
-#: src/Model/User.php:576
-msgid "An invitation is required."
+#: src/Content/Pager.php:153
+msgid "newer"
 msgstr ""
 
-#: src/Model/User.php:580
-msgid "Invitation could not be verified."
+#: src/Content/Pager.php:158
+msgid "older"
 msgstr ""
 
-#: src/Model/User.php:587
-msgid "Invalid OpenID url"
+#: src/Content/Pager.php:203
+msgid "prev"
 msgstr ""
 
-#: src/Model/User.php:600 src/Module/Login.php:102
-msgid ""
-"We encountered a problem while logging in with the OpenID you provided. "
-"Please check the correct spelling of the ID."
+#: src/Content/Pager.php:263
+msgid "last"
 msgstr ""
 
-#: src/Model/User.php:600 src/Module/Login.php:102
-msgid "The error message was:"
+#: src/Content/Widget.php:39
+msgid "Add New Contact"
 msgstr ""
 
-#: src/Model/User.php:606
-msgid "Please enter the required information."
+#: src/Content/Widget.php:40
+msgid "Enter address or web location"
 msgstr ""
 
-#: src/Model/User.php:620
-#, php-format
-msgid ""
-"system.username_min_length (%s) and system.username_max_length (%s) are "
-"excluding each other, swapping values."
+#: src/Content/Widget.php:41
+msgid "Example: bob@example.com, http://example.com/barbara"
 msgstr ""
 
-#: src/Model/User.php:627
+#: src/Content/Widget.php:59
 #, php-format
-msgid "Username should be at least %s character."
-msgid_plural "Username should be at least %s characters."
+msgid "%d invitation available"
+msgid_plural "%d invitations available"
 msgstr[0] ""
 msgstr[1] ""
 
-#: src/Model/User.php:631
-#, php-format
-msgid "Username should be at most %s character."
-msgid_plural "Username should be at most %s characters."
-msgstr[0] ""
-msgstr[1] ""
+#: src/Content/Widget.php:194 src/Module/Profile/Contacts.php:127
+#: src/Module/Contact.php:793
+msgid "Following"
+msgstr ""
 
-#: src/Model/User.php:639
-msgid "That doesn't appear to be your full (First Last) name."
+#: src/Content/Widget.php:195 src/Module/Profile/Contacts.php:128
+#: src/Module/Contact.php:794
+msgid "Mutual friends"
 msgstr ""
 
-#: src/Model/User.php:644
-msgid "Your email domain is not among those allowed on this site."
+#: src/Content/Widget.php:200
+msgid "Relationships"
 msgstr ""
 
-#: src/Model/User.php:648
-msgid "Not a valid email address."
+#: src/Content/Widget.php:202 src/Module/Group.php:287
+#: src/Module/Contact.php:681
+msgid "All Contacts"
 msgstr ""
 
-#: src/Model/User.php:651
-msgid "The nickname was blocked from registration by the nodes admin."
+#: src/Content/Widget.php:245
+msgid "Protocols"
 msgstr ""
 
-#: src/Model/User.php:655 src/Model/User.php:663
-msgid "Cannot use that email."
+#: src/Content/Widget.php:247
+msgid "All Protocols"
 msgstr ""
 
-#: src/Model/User.php:670
-msgid "Your nickname can only contain a-z, 0-9 and _."
+#: src/Content/Widget.php:284
+msgid "Saved Folders"
 msgstr ""
 
-#: src/Model/User.php:677 src/Model/User.php:734
-msgid "Nickname is already registered. Please choose another."
+#: src/Content/Widget.php:286 src/Content/Widget.php:325
+msgid "Everything"
 msgstr ""
 
-#: src/Model/User.php:687
-msgid "SERIOUS ERROR: Generation of security keys failed."
+#: src/Content/Widget.php:323
+msgid "Categories"
 msgstr ""
 
-#: src/Model/User.php:721 src/Model/User.php:725
-msgid "An error occurred during registration. Please try again."
+#: src/Content/Widget.php:400
+#, php-format
+msgid "%d contact in common"
+msgid_plural "%d contacts in common"
+msgstr[0] ""
+msgstr[1] ""
+
+#: src/Database/DBStructure.php:50
+msgid "There are no tables on MyISAM."
 msgstr ""
 
-#: src/Model/User.php:750
-msgid "An error occurred creating your default profile. Please try again."
+#: src/Database/DBStructure.php:74
+#, php-format
+msgid ""
+"\n"
+"Error %d occurred during database update:\n"
+"%s\n"
 msgstr ""
 
-#: src/Model/User.php:757
-msgid "An error occurred creating your self contact. Please try again."
+#: src/Database/DBStructure.php:77
+msgid "Errors encountered performing database changes: "
 msgstr ""
 
-#: src/Model/User.php:766
-msgid ""
-"An error occurred creating your default contact group. Please try again."
+#: src/Database/DBStructure.php:266
+#, php-format
+msgid "%s: Database update"
 msgstr ""
 
-#: src/Model/User.php:842
+#: src/Database/DBStructure.php:527
 #, php-format
-msgid ""
-"\n"
-"\t\t\tDear %1$s,\n"
-"\t\t\t\tThank you for registering at %2$s. Your account is pending for "
-"approval by the administrator.\n"
-"\n"
-"\t\t\tYour login details are as follows:\n"
-"\n"
-"\t\t\tSite Location:\t%3$s\n"
-"\t\t\tLogin Name:\t\t%4$s\n"
-"\t\t\tPassword:\t\t%5$s\n"
-"\t\t"
+msgid "%s: updating %s table."
 msgstr ""
 
-#: src/Model/User.php:859
+#: src/Model/Storage/Database.php:36
 #, php-format
-msgid "Registration at %s"
+msgid "Database storage failed to update %s"
+msgstr ""
+
+#: src/Model/Storage/Database.php:43
+msgid "Database storage failed to insert data"
 msgstr ""
 
-#: src/Model/User.php:878
+#: src/Model/Storage/Filesystem.php:63
 #, php-format
 msgid ""
-"\n"
-"\t\t\tDear %1$s,\n"
-"\t\t\t\tThank you for registering at %2$s. Your account has been created.\n"
-"\t\t"
+"Filesystem storage failed to create \"%s\". Check you write permissions."
 msgstr ""
 
-#: src/Model/User.php:884
+#: src/Model/Storage/Filesystem.php:105
 #, php-format
 msgid ""
-"\n"
-"\t\t\tThe login details are as follows:\n"
-"\n"
-"\t\t\tSite Location:\t%3$s\n"
-"\t\t\tLogin Name:\t\t%1$s\n"
-"\t\t\tPassword:\t\t%5$s\n"
-"\n"
-"\t\t\tYou may change your password from your account \"Settings\" page after "
-"logging\n"
-"\t\t\tin.\n"
-"\n"
-"\t\t\tPlease take a few moments to review the other account settings on that "
-"page.\n"
-"\n"
-"\t\t\tYou may also wish to add some basic information to your default "
-"profile\n"
-"\t\t\t(on the \"Profiles\" page) so that other people can easily find you.\n"
-"\n"
-"\t\t\tWe recommend setting your full name, adding a profile photo,\n"
-"\t\t\tadding some profile \"keywords\" (very useful in making new friends) - "
-"and\n"
-"\t\t\tperhaps what country you live in; if you do not wish to be more "
-"specific\n"
-"\t\t\tthan that.\n"
-"\n"
-"\t\t\tWe fully respect your right to privacy, and none of these items are "
-"necessary.\n"
-"\t\t\tIf you are new and do not know anybody here, they may help\n"
-"\t\t\tyou to make some new and interesting friends.\n"
-"\n"
-"\t\t\tIf you ever want to delete your account, you can do so at %3$s/"
-"removeme\n"
-"\n"
-"\t\t\tThank you and welcome to %2$s."
+"Filesystem storage failed to save data to \"%s\". Check your write "
+"permissions"
 msgstr ""
 
-#: src/Model/User.php:919 src/Module/Admin/Users.php:88
-#, php-format
-msgid "Registration details for %s"
+#: src/Model/Storage/Filesystem.php:126
+msgid "Storage base path"
+msgstr ""
+
+#: src/Model/Storage/Filesystem.php:128
+msgid ""
+"Folder where uploaded files are saved. For maximum security, This should be "
+"a path outside web server folder tree"
+msgstr ""
+
+#: src/Model/Storage/Filesystem.php:138
+msgid "Enter a valid existing folder"
+msgstr ""
+
+#: src/Model/FileTag.php:265
+msgid "Item filed"
+msgstr ""
+
+#: src/Model/Contact.php:1251 src/Model/Contact.php:1264
+msgid "UnFollow"
 msgstr ""
 
-#: src/Model/Contact.php:1230
+#: src/Model/Contact.php:1260
 msgid "Drop Contact"
 msgstr ""
 
-#: src/Model/Contact.php:1783
+#: src/Model/Contact.php:1814
 msgid "Organisation"
 msgstr ""
 
-#: src/Model/Contact.php:1787
+#: src/Model/Contact.php:1818
 msgid "News"
 msgstr ""
 
-#: src/Model/Contact.php:1791
+#: src/Model/Contact.php:1822
 msgid "Forum"
 msgstr ""
 
-#: src/Model/Contact.php:2192
+#: src/Model/Contact.php:2222
 msgid "Connect URL missing."
 msgstr ""
 
-#: src/Model/Contact.php:2201
+#: src/Model/Contact.php:2231
 msgid ""
 "The contact could not be added. Please check the relevant network "
 "credentials in your Settings -> Social Networks page."
 msgstr ""
 
-#: src/Model/Contact.php:2242
+#: src/Model/Contact.php:2272
 msgid ""
 "This site is not configured to allow communications with other networks."
 msgstr ""
 
-#: src/Model/Contact.php:2243 src/Model/Contact.php:2256
+#: src/Model/Contact.php:2273 src/Model/Contact.php:2286
 msgid "No compatible communication protocols or feeds were discovered."
 msgstr ""
 
-#: src/Model/Contact.php:2254
+#: src/Model/Contact.php:2284
 msgid "The profile address specified does not provide adequate information."
 msgstr ""
 
-#: src/Model/Contact.php:2259
+#: src/Model/Contact.php:2289
 msgid "An author or name was not found."
 msgstr ""
 
-#: src/Model/Contact.php:2262
+#: src/Model/Contact.php:2292
 msgid "No browser URL could be matched to this address."
 msgstr ""
 
-#: src/Model/Contact.php:2265
+#: src/Model/Contact.php:2295
 msgid ""
 "Unable to match @-style Identity Address with a known protocol or email "
 "contact."
 msgstr ""
 
-#: src/Model/Contact.php:2266
+#: src/Model/Contact.php:2296
 msgid "Use mailto: in front of address to force email check."
 msgstr ""
 
-#: src/Model/Contact.php:2272
+#: src/Model/Contact.php:2302
 msgid ""
 "The profile address specified belongs to a network which has been disabled "
 "on this site."
 msgstr ""
 
-#: src/Model/Contact.php:2277
+#: src/Model/Contact.php:2307
 msgid ""
 "Limited profile. This person will be unable to receive direct/personal "
 "notifications from you."
 msgstr ""
 
-#: src/Model/Contact.php:2332
+#: src/Model/Contact.php:2368
 msgid "Unable to retrieve contact information."
 msgstr ""
 
+#: src/Model/Event.php:35 src/Model/Event.php:848
+#: src/Module/Debug/Localtime.php:17
+msgid "l F d, Y \\@ g:i A"
+msgstr ""
+
+#: src/Model/Event.php:62 src/Model/Event.php:79 src/Model/Event.php:436
+#: src/Model/Event.php:916
+msgid "Starts:"
+msgstr ""
+
+#: src/Model/Event.php:65 src/Model/Event.php:85 src/Model/Event.php:437
+#: src/Model/Event.php:920
+msgid "Finishes:"
+msgstr ""
+
+#: src/Model/Event.php:386
+msgid "all-day"
+msgstr ""
+
+#: src/Model/Event.php:412
+msgid "Sept"
+msgstr ""
+
+#: src/Model/Event.php:434
+msgid "No events to display"
+msgstr ""
+
+#: src/Model/Event.php:562
+msgid "l, F j"
+msgstr ""
+
+#: src/Model/Event.php:593
+msgid "Edit event"
+msgstr ""
+
+#: src/Model/Event.php:594
+msgid "Duplicate event"
+msgstr ""
+
+#: src/Model/Event.php:595
+msgid "Delete event"
+msgstr ""
+
+#: src/Model/Event.php:627 src/Model/Item.php:3584 src/Model/Item.php:3591
+msgid "link to source"
+msgstr ""
+
+#: src/Model/Event.php:849
+msgid "D g:i A"
+msgstr ""
+
+#: src/Model/Event.php:850
+msgid "g:i A"
+msgstr ""
+
+#: src/Model/Event.php:935 src/Model/Event.php:937
+msgid "Show map"
+msgstr ""
+
+#: src/Model/Event.php:936
+msgid "Hide map"
+msgstr ""
+
+#: src/Model/Event.php:1028
+#, php-format
+msgid "%s's birthday"
+msgstr ""
+
+#: src/Model/Event.php:1029
+#, php-format
+msgid "Happy Birthday %s"
+msgstr ""
+
 #: src/Model/Group.php:77
 msgid ""
 "A deleted group with this name was revived. Existing item permissions "
@@ -6464,7 +6129,11 @@ msgstr ""
 msgid "edit"
 msgstr ""
 
-#: src/Model/Group.php:484 src/Module/Welcome.php:57 src/Module/Contact.php:708
+#: src/Model/Group.php:483
+msgid "add"
+msgstr ""
+
+#: src/Model/Group.php:484 src/Module/Welcome.php:57 src/Module/Contact.php:729
 msgid "Groups"
 msgstr ""
 
@@ -6489,266 +6158,481 @@ msgstr ""
 msgid "Edit groups"
 msgstr ""
 
-#: src/Model/Mail.php:113 src/Model/Mail.php:250
+#: src/Model/Item.php:3326
+msgid "activity"
+msgstr ""
+
+#: src/Model/Item.php:3328 src/Object/Post.php:474
+msgid "comment"
+msgid_plural "comments"
+msgstr[0] ""
+msgstr[1] ""
+
+#: src/Model/Item.php:3331
+msgid "post"
+msgstr ""
+
+#: src/Model/Item.php:3454
+#, php-format
+msgid "Content warning: %s"
+msgstr ""
+
+#: src/Model/Item.php:3531
+msgid "bytes"
+msgstr ""
+
+#: src/Model/Item.php:3578
+msgid "View on separate page"
+msgstr ""
+
+#: src/Model/Item.php:3579
+msgid "view on separate page"
+msgstr ""
+
+#: src/Model/Mail.php:114 src/Model/Mail.php:251
 msgid "[no subject]"
 msgstr ""
 
-#: src/Model/Profile.php:212 src/Model/Profile.php:428
-#: src/Model/Profile.php:885
+#: src/Model/Notify.php:275 src/Model/Notify.php:287
+#, php-format
+msgid "%s commented on %s's post"
+msgstr ""
+
+#: src/Model/Notify.php:286
+#, php-format
+msgid "%s created a new post"
+msgstr ""
+
+#: src/Model/Notify.php:300
+#, php-format
+msgid "%s liked %s's post"
+msgstr ""
+
+#: src/Model/Notify.php:313
+#, php-format
+msgid "%s disliked %s's post"
+msgstr ""
+
+#: src/Model/Notify.php:326
+#, php-format
+msgid "%s is attending %s's event"
+msgstr ""
+
+#: src/Model/Notify.php:339
+#, php-format
+msgid "%s is not attending %s's event"
+msgstr ""
+
+#: src/Model/Notify.php:352
+#, php-format
+msgid "%s may attend %s's event"
+msgstr ""
+
+#: src/Model/Notify.php:385
+#, php-format
+msgid "%s is now friends with %s"
+msgstr ""
+
+#: src/Model/Notify.php:678
+msgid "Friend Suggestion"
+msgstr ""
+
+#: src/Model/Notify.php:712
+msgid "Friend/Connect Request"
+msgstr ""
+
+#: src/Model/Notify.php:712
+msgid "New Follower"
+msgstr ""
+
+#: src/Model/Profile.php:213 src/Model/Profile.php:424
+#: src/Model/Profile.php:881
 msgid "Edit profile"
 msgstr ""
 
-#: src/Model/Profile.php:402
+#: src/Model/Profile.php:398
 msgid "Manage/edit profiles"
 msgstr ""
 
-#: src/Model/Profile.php:451 src/Model/Profile.php:795
-#: src/Module/Directory.php:143
+#: src/Model/Profile.php:447 src/Model/Profile.php:791
+#: src/Module/Directory.php:141
 msgid "Status:"
 msgstr ""
 
-#: src/Model/Profile.php:452 src/Model/Profile.php:812
-#: src/Module/Directory.php:144
+#: src/Model/Profile.php:448 src/Model/Profile.php:808
+#: src/Module/Directory.php:142
 msgid "Homepage:"
 msgstr ""
 
-#: src/Model/Profile.php:454 src/Module/Contact.php:609
+#: src/Model/Profile.php:450 src/Module/Contact.php:630
 msgid "XMPP:"
 msgstr ""
 
-#: src/Model/Profile.php:546 src/Module/Contact.php:299
+#: src/Model/Profile.php:542 src/Module/Contact.php:320
 msgid "Unfollow"
 msgstr ""
 
-#: src/Model/Profile.php:548
+#: src/Model/Profile.php:544
 msgid "Atom feed"
 msgstr ""
 
-#: src/Model/Profile.php:588 src/Model/Profile.php:685
+#: src/Model/Profile.php:584 src/Model/Profile.php:681
 msgid "g A l F d"
 msgstr ""
 
-#: src/Model/Profile.php:589
+#: src/Model/Profile.php:585
 msgid "F d"
 msgstr ""
 
-#: src/Model/Profile.php:651 src/Model/Profile.php:736
+#: src/Model/Profile.php:647 src/Model/Profile.php:732
 msgid "[today]"
 msgstr ""
 
-#: src/Model/Profile.php:661
+#: src/Model/Profile.php:657
 msgid "Birthday Reminders"
 msgstr ""
 
-#: src/Model/Profile.php:662
+#: src/Model/Profile.php:658
 msgid "Birthdays this week:"
 msgstr ""
 
-#: src/Model/Profile.php:723
+#: src/Model/Profile.php:719
 msgid "[No description]"
 msgstr ""
 
-#: src/Model/Profile.php:749
+#: src/Model/Profile.php:745
 msgid "Event Reminders"
 msgstr ""
 
-#: src/Model/Profile.php:750
+#: src/Model/Profile.php:746
 msgid "Upcoming events the next 7 days:"
 msgstr ""
 
-#: src/Model/Profile.php:767
+#: src/Model/Profile.php:763
 msgid "Member since:"
 msgstr ""
 
-#: src/Model/Profile.php:775
+#: src/Model/Profile.php:771
 msgid "j F, Y"
 msgstr ""
 
-#: src/Model/Profile.php:776
+#: src/Model/Profile.php:772
 msgid "j F"
 msgstr ""
 
-#: src/Model/Profile.php:791
+#: src/Model/Profile.php:787
 msgid "Age:"
 msgstr ""
 
-#: src/Model/Profile.php:804
+#: src/Model/Profile.php:800
 #, php-format
 msgid "for %1$d %2$s"
 msgstr ""
 
-#: src/Model/Profile.php:828
+#: src/Model/Profile.php:824
 msgid "Religion:"
 msgstr ""
 
-#: src/Model/Profile.php:836
+#: src/Model/Profile.php:832
 msgid "Hobbies/Interests:"
 msgstr ""
 
-#: src/Model/Profile.php:848
+#: src/Model/Profile.php:844
 msgid "Contact information and Social Networks:"
 msgstr ""
 
-#: src/Model/Profile.php:852
+#: src/Model/Profile.php:848
 msgid "Musical interests:"
 msgstr ""
 
-#: src/Model/Profile.php:856
+#: src/Model/Profile.php:852
 msgid "Books, literature:"
 msgstr ""
 
-#: src/Model/Profile.php:860
+#: src/Model/Profile.php:856
 msgid "Television:"
 msgstr ""
 
-#: src/Model/Profile.php:864
+#: src/Model/Profile.php:860
 msgid "Film/dance/culture/entertainment:"
 msgstr ""
 
-#: src/Model/Profile.php:868
+#: src/Model/Profile.php:864
 msgid "Love/Romance:"
 msgstr ""
 
-#: src/Model/Profile.php:872
+#: src/Model/Profile.php:868
 msgid "Work/employment:"
 msgstr ""
 
-#: src/Model/Profile.php:876
+#: src/Model/Profile.php:872
 msgid "School/education:"
 msgstr ""
 
-#: src/Model/Profile.php:881
+#: src/Model/Profile.php:877
 msgid "Forums:"
 msgstr ""
 
-#: src/Model/Profile.php:928 src/Module/Contact.php:850
+#: src/Model/Profile.php:924 src/Module/Contact.php:871
 msgid "Profile Details"
 msgstr ""
 
-#: src/Model/Profile.php:978
+#: src/Model/Profile.php:974
 msgid "Only You Can See This"
 msgstr ""
 
-#: src/Model/Profile.php:986 src/Model/Profile.php:989
+#: src/Model/Profile.php:982 src/Model/Profile.php:985
 msgid "Tips for New Members"
 msgstr ""
 
-#: src/Model/Profile.php:1186
+#: src/Model/Profile.php:1180
+#, php-format
+msgid "OpenWebAuth: %1$s welcomes %2$s"
+msgstr ""
+
+#: src/Model/User.php:357
+msgid "Login failed"
+msgstr ""
+
+#: src/Model/User.php:389
+msgid "Not enough information to authenticate"
+msgstr ""
+
+#: src/Model/User.php:483
+msgid "Password can't be empty"
+msgstr ""
+
+#: src/Model/User.php:502
+msgid "Empty passwords are not allowed."
+msgstr ""
+
+#: src/Model/User.php:506
+msgid ""
+"The new password has been exposed in a public data dump, please choose "
+"another."
+msgstr ""
+
+#: src/Model/User.php:512
+msgid ""
+"The password can't contain accentuated letters, white spaces or colons (:)"
+msgstr ""
+
+#: src/Model/User.php:612
+msgid "Passwords do not match. Password unchanged."
+msgstr ""
+
+#: src/Model/User.php:619
+msgid "An invitation is required."
+msgstr ""
+
+#: src/Model/User.php:623
+msgid "Invitation could not be verified."
+msgstr ""
+
+#: src/Model/User.php:631
+msgid "Invalid OpenID url"
+msgstr ""
+
+#: src/Model/User.php:644 src/Module/Login.php:105
+msgid ""
+"We encountered a problem while logging in with the OpenID you provided. "
+"Please check the correct spelling of the ID."
+msgstr ""
+
+#: src/Model/User.php:644 src/Module/Login.php:105
+msgid "The error message was:"
+msgstr ""
+
+#: src/Model/User.php:650
+msgid "Please enter the required information."
+msgstr ""
+
+#: src/Model/User.php:664
+#, php-format
+msgid ""
+"system.username_min_length (%s) and system.username_max_length (%s) are "
+"excluding each other, swapping values."
+msgstr ""
+
+#: src/Model/User.php:671
+#, php-format
+msgid "Username should be at least %s character."
+msgid_plural "Username should be at least %s characters."
+msgstr[0] ""
+msgstr[1] ""
+
+#: src/Model/User.php:675
+#, php-format
+msgid "Username should be at most %s character."
+msgid_plural "Username should be at most %s characters."
+msgstr[0] ""
+msgstr[1] ""
+
+#: src/Model/User.php:683
+msgid "That doesn't appear to be your full (First Last) name."
+msgstr ""
+
+#: src/Model/User.php:688
+msgid "Your email domain is not among those allowed on this site."
+msgstr ""
+
+#: src/Model/User.php:692
+msgid "Not a valid email address."
+msgstr ""
+
+#: src/Model/User.php:695
+msgid "The nickname was blocked from registration by the nodes admin."
+msgstr ""
+
+#: src/Model/User.php:699 src/Model/User.php:707
+msgid "Cannot use that email."
+msgstr ""
+
+#: src/Model/User.php:714
+msgid "Your nickname can only contain a-z, 0-9 and _."
+msgstr ""
+
+#: src/Model/User.php:722 src/Model/User.php:779
+msgid "Nickname is already registered. Please choose another."
+msgstr ""
+
+#: src/Model/User.php:732
+msgid "SERIOUS ERROR: Generation of security keys failed."
+msgstr ""
+
+#: src/Model/User.php:766 src/Model/User.php:770
+msgid "An error occurred during registration. Please try again."
+msgstr ""
+
+#: src/Model/User.php:795
+msgid "An error occurred creating your default profile. Please try again."
+msgstr ""
+
+#: src/Model/User.php:802
+msgid "An error occurred creating your self contact. Please try again."
+msgstr ""
+
+#: src/Model/User.php:811
+msgid ""
+"An error occurred creating your default contact group. Please try again."
+msgstr ""
+
+#: src/Model/User.php:888
+#, php-format
+msgid ""
+"\n"
+"\t\t\tDear %1$s,\n"
+"\t\t\t\tThank you for registering at %2$s. Your account is pending for "
+"approval by the administrator.\n"
+"\n"
+"\t\t\tYour login details are as follows:\n"
+"\n"
+"\t\t\tSite Location:\t%3$s\n"
+"\t\t\tLogin Name:\t\t%4$s\n"
+"\t\t\tPassword:\t\t%5$s\n"
+"\t\t"
+msgstr ""
+
+#: src/Model/User.php:909
 #, php-format
-msgid "OpenWebAuth: %1$s welcomes %2$s"
-msgstr ""
-
-#: src/Model/Item.php:3313
-msgid "activity"
-msgstr ""
-
-#: src/Model/Item.php:3315 src/Object/Post.php:474
-msgid "comment"
-msgid_plural "comments"
-msgstr[0] ""
-msgstr[1] ""
-
-#: src/Model/Item.php:3318
-msgid "post"
+msgid "Registration at %s"
 msgstr ""
 
-#: src/Model/Item.php:3417
+#: src/Model/User.php:929
 #, php-format
-msgid "Content warning: %s"
+msgid ""
+"\n"
+"\t\t\t\tDear %1$s,\n"
+"\t\t\t\tThank you for registering at %2$s. Your account has been created.\n"
+"\t\t\t"
 msgstr ""
 
-#: src/Model/Item.php:3494
-msgid "bytes"
+#: src/Model/User.php:937
+#, php-format
+msgid ""
+"\n"
+"\t\t\tThe login details are as follows:\n"
+"\n"
+"\t\t\tSite Location:\t%3$s\n"
+"\t\t\tLogin Name:\t\t%1$s\n"
+"\t\t\tPassword:\t\t%5$s\n"
+"\n"
+"\t\t\tYou may change your password from your account \"Settings\" page after "
+"logging\n"
+"\t\t\tin.\n"
+"\n"
+"\t\t\tPlease take a few moments to review the other account settings on that "
+"page.\n"
+"\n"
+"\t\t\tYou may also wish to add some basic information to your default "
+"profile\n"
+"\t\t\t(on the \"Profiles\" page) so that other people can easily find you.\n"
+"\n"
+"\t\t\tWe recommend setting your full name, adding a profile photo,\n"
+"\t\t\tadding some profile \"keywords\" (very useful in making new friends) - "
+"and\n"
+"\t\t\tperhaps what country you live in; if you do not wish to be more "
+"specific\n"
+"\t\t\tthan that.\n"
+"\n"
+"\t\t\tWe fully respect your right to privacy, and none of these items are "
+"necessary.\n"
+"\t\t\tIf you are new and do not know anybody here, they may help\n"
+"\t\t\tyou to make some new and interesting friends.\n"
+"\n"
+"\t\t\tIf you ever want to delete your account, you can do so at %3$s/"
+"removeme\n"
+"\n"
+"\t\t\tThank you and welcome to %2$s."
 msgstr ""
 
-#: src/Model/Item.php:3541
-msgid "View on separate page"
+#: src/Model/User.php:976 src/Module/Admin/Users.php:88
+#, php-format
+msgid "Registration details for %s"
 msgstr ""
 
-#: src/Model/Item.php:3542
-msgid "view on separate page"
+#: src/Protocol/Diaspora.php:3604
+msgid "Attachments:"
 msgstr ""
 
-#: src/Protocol/OStatus.php:1300 src/Module/Profile.php:119
-#: src/Module/Profile.php:122
+#: src/Protocol/OStatus.php:1302 src/Module/Profile.php:117
+#: src/Module/Profile.php:120
 #, php-format
 msgid "%s's timeline"
 msgstr ""
 
-#: src/Protocol/OStatus.php:1304 src/Module/Profile.php:120
+#: src/Protocol/OStatus.php:1306 src/Module/Profile.php:118
 #, php-format
 msgid "%s's posts"
 msgstr ""
 
-#: src/Protocol/OStatus.php:1307 src/Module/Profile.php:121
+#: src/Protocol/OStatus.php:1309 src/Module/Profile.php:119
 #, php-format
 msgid "%s's comments"
 msgstr ""
 
-#: src/Protocol/OStatus.php:1861
+#: src/Protocol/OStatus.php:1864
 #, php-format
 msgid "%s is now following %s."
 msgstr ""
 
-#: src/Protocol/OStatus.php:1862
+#: src/Protocol/OStatus.php:1865
 msgid "following"
 msgstr ""
 
-#: src/Protocol/OStatus.php:1865
+#: src/Protocol/OStatus.php:1868
 #, php-format
 msgid "%s stopped following %s."
 msgstr ""
 
-#: src/Protocol/OStatus.php:1866
+#: src/Protocol/OStatus.php:1869
 msgid "stopped following"
 msgstr ""
 
-#: src/Protocol/Diaspora.php:2527
-msgid "Sharing notification from Diaspora network"
-msgstr ""
-
-#: src/Protocol/Diaspora.php:3674
-msgid "Attachments:"
-msgstr ""
-
-#: src/Worker/Delivery.php:508
+#: src/Worker/Delivery.php:516
 msgid "(no subject)"
 msgstr ""
 
-#: src/Module/Tos.php:35 src/Module/Tos.php:77
-msgid ""
-"At the time of registration, and for providing communications between the "
-"user account and their contacts, the user has to provide a display name (pen "
-"name), an username (nickname) and a working email address. The names will be "
-"accessible on the profile page of the account by any visitor of the page, "
-"even if other profile details are not displayed. The email address will only "
-"be used to send the user notifications about interactions, but wont be "
-"visibly displayed. The listing of an account in the node's user directory or "
-"the global user directory is optional and can be controlled in the user "
-"settings, it is not necessary for communication."
-msgstr ""
-
-#: src/Module/Tos.php:36 src/Module/Tos.php:78
-msgid ""
-"This data is required for communication and is passed on to the nodes of the "
-"communication partners and is stored there. Users can enter additional "
-"private data that may be transmitted to the communication partners accounts."
-msgstr ""
-
-#: src/Module/Tos.php:37 src/Module/Tos.php:79
-#, php-format
-msgid ""
-"At any point in time a logged in user can export their account data from the "
-"<a href=\"%1$s/settings/uexport\">account settings</a>. If the user wants to "
-"delete their account they can do so at <a href=\"%1$s/removeme\">%1$s/"
-"removeme</a>. The deletion of the account will be permanent. Deletion of the "
-"data will also be requested from the nodes of the communication partners."
-msgstr ""
-
-#: src/Module/Tos.php:40 src/Module/Tos.php:76
-msgid "Privacy Statement"
-msgstr ""
-
 #: src/Module/Apps.php:29
 msgid "No installed applications."
 msgstr ""
@@ -6793,13 +6677,14 @@ msgid "Enable"
 msgstr ""
 
 #: src/Module/Admin/Addons/Details.php:99 src/Module/Admin/Addons/Index.php:50
+#: src/Module/Admin/Blocklist/Server.php:73
 #: src/Module/Admin/Blocklist/Contact.php:61
-#: src/Module/Admin/Blocklist/Server.php:73 src/Module/Admin/Federation.php:187
-#: src/Module/Admin/Item/Delete.php:46 src/Module/Admin/Logs/Settings.php:63
-#: src/Module/Admin/Logs/View.php:46 src/Module/Admin/Themes/Details.php:104
-#: src/Module/Admin/Themes/Index.php:95 src/Module/Admin/Tos.php:42
-#: src/Module/Admin/Users.php:277 src/Module/Admin/Queue.php:56
-#: src/Module/Admin/Site.php:566 src/Module/Admin/Summary.php:173
+#: src/Module/Admin/Federation.php:187 src/Module/Admin/Item/Delete.php:46
+#: src/Module/Admin/Logs/View.php:46 src/Module/Admin/Logs/Settings.php:63
+#: src/Module/Admin/Themes/Details.php:104 src/Module/Admin/Themes/Index.php:95
+#: src/Module/Admin/Tos.php:42 src/Module/Admin/Queue.php:56
+#: src/Module/Admin/Site.php:566 src/Module/Admin/Summary.php:192
+#: src/Module/Admin/Users.php:277
 msgid "Administration"
 msgstr ""
 
@@ -6835,87 +6720,6 @@ msgid ""
 "the open addon registry at %2$s"
 msgstr ""
 
-#: src/Module/Admin/Blocklist/Contact.php:28
-#: src/Console/GlobalCommunityBlock.php:87
-msgid "The contact has been blocked from the node"
-msgstr ""
-
-#: src/Module/Admin/Blocklist/Contact.php:30
-#: src/Console/GlobalCommunityBlock.php:82
-#, php-format
-msgid "Could not find any contact entry for this URL (%s)"
-msgstr ""
-
-#: src/Module/Admin/Blocklist/Contact.php:38
-#, php-format
-msgid "%s contact unblocked"
-msgid_plural "%s contacts unblocked"
-msgstr[0] ""
-msgstr[1] ""
-
-#: src/Module/Admin/Blocklist/Contact.php:62
-msgid "Remote Contact Blocklist"
-msgstr ""
-
-#: src/Module/Admin/Blocklist/Contact.php:63
-msgid ""
-"This page allows you to prevent any message from a remote contact to reach "
-"your node."
-msgstr ""
-
-#: src/Module/Admin/Blocklist/Contact.php:64
-msgid "Block Remote Contact"
-msgstr ""
-
-#: src/Module/Admin/Blocklist/Contact.php:65 src/Module/Admin/Users.php:280
-msgid "select all"
-msgstr ""
-
-#: src/Module/Admin/Blocklist/Contact.php:66
-msgid "select none"
-msgstr ""
-
-#: src/Module/Admin/Blocklist/Contact.php:68 src/Module/Admin/Users.php:291
-#: src/Module/Contact.php:585 src/Module/Contact.php:802
-#: src/Module/Contact.php:1061
-msgid "Unblock"
-msgstr ""
-
-#: src/Module/Admin/Blocklist/Contact.php:69
-msgid "No remote contact is blocked from this node."
-msgstr ""
-
-#: src/Module/Admin/Blocklist/Contact.php:71
-msgid "Blocked Remote Contacts"
-msgstr ""
-
-#: src/Module/Admin/Blocklist/Contact.php:72
-msgid "Block New Remote Contact"
-msgstr ""
-
-#: src/Module/Admin/Blocklist/Contact.php:73
-msgid "Photo"
-msgstr ""
-
-#: src/Module/Admin/Blocklist/Contact.php:73
-msgid "Reason"
-msgstr ""
-
-#: src/Module/Admin/Blocklist/Contact.php:81
-#, php-format
-msgid "%s total blocked contact"
-msgid_plural "%s total blocked contacts"
-msgstr[0] ""
-msgstr[1] ""
-
-#: src/Module/Admin/Blocklist/Contact.php:83
-msgid "URL of the remote contact to block."
-msgstr ""
-
-#: src/Module/Admin/Blocklist/Contact.php:84
-msgid "Block Reason"
-msgstr ""
-
 #: src/Module/Admin/Blocklist/Server.php:31
 msgid "Server domain pattern added to blocklist."
 msgstr ""
@@ -6997,20 +6801,101 @@ msgstr ""
 msgid "Add Entry"
 msgstr ""
 
-#: src/Module/Admin/Blocklist/Server.php:87
-msgid "Save changes to the blocklist"
+#: src/Module/Admin/Blocklist/Server.php:87
+msgid "Save changes to the blocklist"
+msgstr ""
+
+#: src/Module/Admin/Blocklist/Server.php:88
+msgid "Current Entries in the Blocklist"
+msgstr ""
+
+#: src/Module/Admin/Blocklist/Server.php:91
+msgid "Delete entry from blocklist"
+msgstr ""
+
+#: src/Module/Admin/Blocklist/Server.php:94
+msgid "Delete entry from blocklist?"
+msgstr ""
+
+#: src/Module/Admin/Blocklist/Contact.php:28
+#: src/Console/GlobalCommunityBlock.php:87
+msgid "The contact has been blocked from the node"
+msgstr ""
+
+#: src/Module/Admin/Blocklist/Contact.php:30
+#: src/Console/GlobalCommunityBlock.php:82
+#, php-format
+msgid "Could not find any contact entry for this URL (%s)"
+msgstr ""
+
+#: src/Module/Admin/Blocklist/Contact.php:38
+#, php-format
+msgid "%s contact unblocked"
+msgid_plural "%s contacts unblocked"
+msgstr[0] ""
+msgstr[1] ""
+
+#: src/Module/Admin/Blocklist/Contact.php:62
+msgid "Remote Contact Blocklist"
+msgstr ""
+
+#: src/Module/Admin/Blocklist/Contact.php:63
+msgid ""
+"This page allows you to prevent any message from a remote contact to reach "
+"your node."
+msgstr ""
+
+#: src/Module/Admin/Blocklist/Contact.php:64
+msgid "Block Remote Contact"
+msgstr ""
+
+#: src/Module/Admin/Blocklist/Contact.php:65 src/Module/Admin/Users.php:280
+msgid "select all"
+msgstr ""
+
+#: src/Module/Admin/Blocklist/Contact.php:66
+msgid "select none"
+msgstr ""
+
+#: src/Module/Admin/Blocklist/Contact.php:68 src/Module/Admin/Users.php:291
+#: src/Module/Contact.php:606 src/Module/Contact.php:823
+#: src/Module/Contact.php:1082
+msgid "Unblock"
+msgstr ""
+
+#: src/Module/Admin/Blocklist/Contact.php:69
+msgid "No remote contact is blocked from this node."
+msgstr ""
+
+#: src/Module/Admin/Blocklist/Contact.php:71
+msgid "Blocked Remote Contacts"
+msgstr ""
+
+#: src/Module/Admin/Blocklist/Contact.php:72
+msgid "Block New Remote Contact"
+msgstr ""
+
+#: src/Module/Admin/Blocklist/Contact.php:73
+msgid "Photo"
 msgstr ""
 
-#: src/Module/Admin/Blocklist/Server.php:88
-msgid "Current Entries in the Blocklist"
+#: src/Module/Admin/Blocklist/Contact.php:73
+msgid "Reason"
 msgstr ""
 
-#: src/Module/Admin/Blocklist/Server.php:91
-msgid "Delete entry from blocklist"
+#: src/Module/Admin/Blocklist/Contact.php:81
+#, php-format
+msgid "%s total blocked contact"
+msgid_plural "%s total blocked contacts"
+msgstr[0] ""
+msgstr[1] ""
+
+#: src/Module/Admin/Blocklist/Contact.php:83
+msgid "URL of the remote contact to block."
 msgstr ""
 
-#: src/Module/Admin/Blocklist/Server.php:94
-msgid "Delete entry from blocklist?"
+#: src/Module/Admin/Blocklist/Contact.php:84
+msgid "Block Reason"
 msgstr ""
 
 #: src/Module/Admin/DBSync.php:32
@@ -7146,8 +7031,25 @@ msgstr ""
 msgid "Item Guid"
 msgstr ""
 
-#: src/Module/Admin/Logs/Settings.php:27 src/Module/Admin/Summary.php:83
-#: src/Module/Admin/Summary.php:90
+#: src/Module/Admin/Logs/View.php:22
+#, php-format
+msgid ""
+"Error trying to open <strong>%1$s</strong> log file.\\r\\n<br/>Check to see "
+"if file %1$s exist and is readable."
+msgstr ""
+
+#: src/Module/Admin/Logs/View.php:26
+#, php-format
+msgid ""
+"Couldn't open <strong>%1$s</strong> log file.\\r\\n<br/>Check to see if file "
+"%1$s is readable."
+msgstr ""
+
+#: src/Module/Admin/Logs/View.php:47 src/Module/BaseAdminModule.php:99
+msgid "View Logs"
+msgstr ""
+
+#: src/Module/Admin/Logs/Settings.php:27
 #, php-format
 msgid "The logfile '%s' is not writable. No logging possible"
 msgstr ""
@@ -7204,24 +7106,6 @@ msgid ""
 "'display_errors' is to enable these options, set to '0' to disable them."
 msgstr ""
 
-#: src/Module/Admin/Logs/View.php:22
-#, php-format
-msgid ""
-"Error trying to open <strong>%1$s</strong> log file.\\r\\n<br/>Check to see "
-"if file %1$s exist and is readable."
-msgstr ""
-
-#: src/Module/Admin/Logs/View.php:26
-#, php-format
-msgid ""
-"Couldn't open <strong>%1$s</strong> log file.\\r\\n<br/>Check to see if file "
-"%1$s is readable."
-msgstr ""
-
-#: src/Module/Admin/Logs/View.php:47 src/Module/BaseAdminModule.php:99
-msgid "View Logs"
-msgstr ""
-
 #: src/Module/Admin/Themes/Details.php:32 src/Module/Admin/Themes/Embed.php:46
 msgid "Theme settings updated."
 msgstr ""
@@ -7245,261 +7129,69 @@ msgstr ""
 msgid "Screenshot"
 msgstr ""
 
-#: src/Module/Admin/Themes/Details.php:105 src/Module/Admin/Themes/Index.php:96
-#: src/Module/BaseAdminModule.php:83
-msgid "Themes"
-msgstr ""
-
-#: src/Module/Admin/Themes/Embed.php:67
-msgid "Unknown theme."
-msgstr ""
-
-#: src/Module/Admin/Themes/Index.php:98
-msgid "Reload active themes"
-msgstr ""
-
-#: src/Module/Admin/Themes/Index.php:103
-#, php-format
-msgid "No themes found on the system. They should be placed in %1$s"
-msgstr ""
-
-#: src/Module/Admin/Themes/Index.php:104
-msgid "[Experimental]"
-msgstr ""
-
-#: src/Module/Admin/Themes/Index.php:105
-msgid "[Unsupported]"
-msgstr ""
-
-#: src/Module/Admin/Tos.php:30
-msgid "The Terms of Service settings have been updated."
-msgstr ""
-
-#: src/Module/Admin/Tos.php:44
-msgid "Display Terms of Service"
-msgstr ""
-
-#: src/Module/Admin/Tos.php:44
-msgid ""
-"Enable the Terms of Service page. If this is enabled a link to the terms "
-"will be added to the registration form and the general information page."
-msgstr ""
-
-#: src/Module/Admin/Tos.php:45
-msgid "Display Privacy Statement"
-msgstr ""
-
-#: src/Module/Admin/Tos.php:45
-#, php-format
-msgid ""
-"Show some informations regarding the needed information to operate the node "
-"according e.g. to <a href=\"%s\" target=\"_blank\">EU-GDPR</a>."
-msgstr ""
-
-#: src/Module/Admin/Tos.php:46
-msgid "Privacy Statement Preview"
-msgstr ""
-
-#: src/Module/Admin/Tos.php:48
-msgid "The Terms of Service"
-msgstr ""
-
-#: src/Module/Admin/Tos.php:48
-msgid ""
-"Enter the Terms of Service for your node here. You can use BBCode. Headers "
-"of sections should be [h2] and below."
-msgstr ""
-
-#: src/Module/Admin/Users.php:48
-#, php-format
-msgid ""
-"\n"
-"\t\t\tDear %1$s,\n"
-"\t\t\t\tthe administrator of %2$s has set up an account for you."
-msgstr ""
-
-#: src/Module/Admin/Users.php:51
-#, php-format
-msgid ""
-"\n"
-"\t\t\tThe login details are as follows:\n"
-"\n"
-"\t\t\tSite Location:\t%1$s\n"
-"\t\t\tLogin Name:\t\t%2$s\n"
-"\t\t\tPassword:\t\t%3$s\n"
-"\n"
-"\t\t\tYou may change your password from your account \"Settings\" page after "
-"logging\n"
-"\t\t\tin.\n"
-"\n"
-"\t\t\tPlease take a few moments to review the other account settings on that "
-"page.\n"
-"\n"
-"\t\t\tYou may also wish to add some basic information to your default "
-"profile\n"
-"\t\t\t(on the \"Profiles\" page) so that other people can easily find you.\n"
-"\n"
-"\t\t\tWe recommend setting your full name, adding a profile photo,\n"
-"\t\t\tadding some profile \"keywords\" (very useful in making new friends) - "
-"and\n"
-"\t\t\tperhaps what country you live in; if you do not wish to be more "
-"specific\n"
-"\t\t\tthan that.\n"
-"\n"
-"\t\t\tWe fully respect your right to privacy, and none of these items are "
-"necessary.\n"
-"\t\t\tIf you are new and do not know anybody here, they may help\n"
-"\t\t\tyou to make some new and interesting friends.\n"
-"\n"
-"\t\t\tIf you ever want to delete your account, you can do so at %1$s/"
-"removeme\n"
-"\n"
-"\t\t\tThank you and welcome to %4$s."
-msgstr ""
-
-#: src/Module/Admin/Users.php:96
-#, php-format
-msgid "%s user blocked"
-msgid_plural "%s users blocked"
-msgstr[0] ""
-msgstr[1] ""
-
-#: src/Module/Admin/Users.php:102
-#, php-format
-msgid "%s user unblocked"
-msgid_plural "%s users unblocked"
-msgstr[0] ""
-msgstr[1] ""
-
-#: src/Module/Admin/Users.php:110 src/Module/Admin/Users.php:160
-msgid "You can't remove yourself"
-msgstr ""
-
-#: src/Module/Admin/Users.php:114
-#, php-format
-msgid "%s user deleted"
-msgid_plural "%s users deleted"
-msgstr[0] ""
-msgstr[1] ""
-
-#: src/Module/Admin/Users.php:158
-#, php-format
-msgid "User \"%s\" deleted"
-msgstr ""
-
-#: src/Module/Admin/Users.php:167
-#, php-format
-msgid "User \"%s\" blocked"
-msgstr ""
-
-#: src/Module/Admin/Users.php:173
-#, php-format
-msgid "User \"%s\" unblocked"
-msgstr ""
-
-#: src/Module/Admin/Users.php:226
-msgid "Private Forum"
-msgstr ""
-
-#: src/Module/Admin/Users.php:233
-msgid "Relay"
-msgstr ""
-
-#: src/Module/Admin/Users.php:272 src/Module/Admin/Users.php:297
-msgid "Register date"
-msgstr ""
-
-#: src/Module/Admin/Users.php:272 src/Module/Admin/Users.php:297
-msgid "Last login"
-msgstr ""
-
-#: src/Module/Admin/Users.php:272 src/Module/Admin/Users.php:297
-msgid "Last item"
-msgstr ""
-
-#: src/Module/Admin/Users.php:272
-msgid "Type"
-msgstr ""
-
-#: src/Module/Admin/Users.php:278 src/Module/Admin/Users.php:295
-#: src/Module/Admin/Site.php:471 src/Module/BaseAdminModule.php:81
-msgid "Users"
-msgstr ""
-
-#: src/Module/Admin/Users.php:279
-msgid "Add User"
-msgstr ""
-
-#: src/Module/Admin/Users.php:281
-msgid "User registrations waiting for confirm"
-msgstr ""
-
-#: src/Module/Admin/Users.php:282
-msgid "User waiting for permanent deletion"
-msgstr ""
-
-#: src/Module/Admin/Users.php:283
-msgid "Request date"
-msgstr ""
-
-#: src/Module/Admin/Users.php:284
-msgid "No registrations."
+#: src/Module/Admin/Themes/Details.php:105 src/Module/Admin/Themes/Index.php:96
+#: src/Module/BaseAdminModule.php:83
+msgid "Themes"
 msgstr ""
 
-#: src/Module/Admin/Users.php:285
-msgid "Note from the user"
+#: src/Module/Admin/Themes/Embed.php:67
+msgid "Unknown theme."
 msgstr ""
 
-#: src/Module/Admin/Users.php:287
-msgid "Deny"
+#: src/Module/Admin/Themes/Index.php:98
+msgid "Reload active themes"
 msgstr ""
 
-#: src/Module/Admin/Users.php:290
-msgid "User blocked"
+#: src/Module/Admin/Themes/Index.php:103
+#, php-format
+msgid "No themes found on the system. They should be placed in %1$s"
 msgstr ""
 
-#: src/Module/Admin/Users.php:292
-msgid "Site admin"
+#: src/Module/Admin/Themes/Index.php:104
+msgid "[Experimental]"
 msgstr ""
 
-#: src/Module/Admin/Users.php:293
-msgid "Account expired"
+#: src/Module/Admin/Themes/Index.php:105
+msgid "[Unsupported]"
 msgstr ""
 
-#: src/Module/Admin/Users.php:296
-msgid "New User"
+#: src/Module/Admin/Tos.php:30
+msgid "The Terms of Service settings have been updated."
 msgstr ""
 
-#: src/Module/Admin/Users.php:297
-msgid "Permanent deletion"
+#: src/Module/Admin/Tos.php:44
+msgid "Display Terms of Service"
 msgstr ""
 
-#: src/Module/Admin/Users.php:302
+#: src/Module/Admin/Tos.php:44
 msgid ""
-"Selected users will be deleted!\\n\\nEverything these users had posted on "
-"this site will be permanently deleted!\\n\\nAre you sure?"
+"Enable the Terms of Service page. If this is enabled a link to the terms "
+"will be added to the registration form and the general information page."
 msgstr ""
 
-#: src/Module/Admin/Users.php:303
-msgid ""
-"The user {0} will be deleted!\\n\\nEverything this user has posted on this "
-"site will be permanently deleted!\\n\\nAre you sure?"
+#: src/Module/Admin/Tos.php:45
+msgid "Display Privacy Statement"
 msgstr ""
 
-#: src/Module/Admin/Users.php:313
-msgid "Name of the new user."
+#: src/Module/Admin/Tos.php:45
+#, php-format
+msgid ""
+"Show some informations regarding the needed information to operate the node "
+"according e.g. to <a href=\"%s\" target=\"_blank\">EU-GDPR</a>."
 msgstr ""
 
-#: src/Module/Admin/Users.php:314
-msgid "Nickname"
+#: src/Module/Admin/Tos.php:46
+msgid "Privacy Statement Preview"
 msgstr ""
 
-#: src/Module/Admin/Users.php:314
-msgid "Nickname of the new user."
+#: src/Module/Admin/Tos.php:48
+msgid "The Terms of Service"
 msgstr ""
 
-#: src/Module/Admin/Users.php:315
-msgid "Email address of the new user."
+#: src/Module/Admin/Tos.php:48
+msgid ""
+"Enter the Terms of Service for your node here. You can use BBCode. Headers "
+"of sections should be [h2] and below."
 msgstr ""
 
 #: src/Module/Admin/Queue.php:34
@@ -7572,10 +7264,15 @@ msgstr ""
 
 #: src/Module/Admin/Site.php:470 src/Module/Admin/Site.php:665
 #: src/Module/Admin/Site.php:675 src/Module/Settings/TwoFactor/Index.php:97
-#: src/Module/Contact.php:525
+#: src/Module/Contact.php:546
 msgid "Disabled"
 msgstr ""
 
+#: src/Module/Admin/Site.php:471 src/Module/Admin/Users.php:278
+#: src/Module/Admin/Users.php:295 src/Module/BaseAdminModule.php:81
+msgid "Users"
+msgstr ""
+
 #: src/Module/Admin/Site.php:472
 msgid "Users, Global Contacts"
 msgstr ""
@@ -7652,7 +7349,7 @@ msgstr ""
 msgid "Republish users to directory"
 msgstr ""
 
-#: src/Module/Admin/Site.php:570 src/Module/Register.php:121
+#: src/Module/Admin/Site.php:570 src/Module/Register.php:115
 msgid "Registration"
 msgstr ""
 
@@ -8482,164 +8179,357 @@ msgstr ""
 msgid "Comma separated list of tags for the \"tags\" subscription."
 msgstr ""
 
-#: src/Module/Admin/Site.php:677
-msgid "Allow user tags"
-msgstr ""
+#: src/Module/Admin/Site.php:677
+msgid "Allow user tags"
+msgstr ""
+
+#: src/Module/Admin/Site.php:677
+msgid ""
+"If enabled, the tags from the saved searches will used for the \"tags\" "
+"subscription in addition to the \"relay_server_tags\"."
+msgstr ""
+
+#: src/Module/Admin/Site.php:680
+msgid "Start Relocation"
+msgstr ""
+
+#: src/Module/Admin/Summary.php:32
+#, php-format
+msgid ""
+"Your DB still runs with MyISAM tables. You should change the engine type to "
+"InnoDB. As Friendica will use InnoDB only features in the future, you should "
+"change this! See <a href=\"%s\">here</a> for a guide that may be helpful "
+"converting the table engines. You may also use the command <tt>php bin/"
+"console.php dbstructure toinnodb</tt> of your Friendica installation for an "
+"automatic conversion.<br />"
+msgstr ""
+
+#: src/Module/Admin/Summary.php:40
+#, php-format
+msgid ""
+"There is a new version of Friendica available for download. Your current "
+"version is %1$s, upstream version is %2$s"
+msgstr ""
+
+#: src/Module/Admin/Summary.php:49
+msgid ""
+"The database update failed. Please run \"php bin/console.php dbstructure "
+"update\" from the command line and have a look at the errors that might "
+"appear."
+msgstr ""
+
+#: src/Module/Admin/Summary.php:53
+msgid ""
+"The last update failed. Please run \"php bin/console.php dbstructure update"
+"\" from the command line and have a look at the errors that might appear. "
+"(Some of the errors are possibly inside the logfile.)"
+msgstr ""
+
+#: src/Module/Admin/Summary.php:58
+msgid "The worker was never executed. Please check your database structure!"
+msgstr ""
+
+#: src/Module/Admin/Summary.php:60
+#, php-format
+msgid ""
+"The last worker execution was on %s UTC. This is older than one hour. Please "
+"check your crontab settings."
+msgstr ""
+
+#: src/Module/Admin/Summary.php:65
+#, php-format
+msgid ""
+"Friendica's configuration now is stored in config/local.config.php, please "
+"copy config/local-sample.config.php and move your config from <code>."
+"htconfig.php</code>. See <a href=\"%s\">the Config help page</a> for help "
+"with the transition."
+msgstr ""
+
+#: src/Module/Admin/Summary.php:69
+#, php-format
+msgid ""
+"Friendica's configuration now is stored in config/local.config.php, please "
+"copy config/local-sample.config.php and move your config from <code>config/"
+"local.ini.php</code>. See <a href=\"%s\">the Config help page</a> for help "
+"with the transition."
+msgstr ""
+
+#: src/Module/Admin/Summary.php:75
+#, php-format
+msgid ""
+"<a href=\"%s\">%s</a> is not reachable on your system. This is a severe "
+"configuration issue that prevents server to server communication. See <a "
+"href=\"%s\">the installation page</a> for help."
+msgstr ""
+
+#: src/Module/Admin/Summary.php:94
+#, php-format
+msgid "The logfile '%s' is not usable. No logging possible (error: '%s')"
+msgstr ""
+
+#: src/Module/Admin/Summary.php:109
+#, php-format
+msgid "The debug logfile '%s' is not usable. No logging possible (error: '%s')"
+msgstr ""
+
+#: src/Module/Admin/Summary.php:125
+#, php-format
+msgid ""
+"Friendica's system.basepath was updated from '%s' to '%s'. Please remove the "
+"system.basepath from your db to avoid differences."
+msgstr ""
+
+#: src/Module/Admin/Summary.php:133
+#, php-format
+msgid ""
+"Friendica's current system.basepath '%s' is wrong and the config file '%s' "
+"isn't used."
+msgstr ""
+
+#: src/Module/Admin/Summary.php:141
+#, php-format
+msgid ""
+"Friendica's current system.basepath '%s' is not equal to the config file "
+"'%s'. Please fix your configuration."
+msgstr ""
+
+#: src/Module/Admin/Summary.php:148
+msgid "Normal Account"
+msgstr ""
+
+#: src/Module/Admin/Summary.php:149
+msgid "Automatic Follower Account"
+msgstr ""
+
+#: src/Module/Admin/Summary.php:150
+msgid "Public Forum Account"
+msgstr ""
+
+#: src/Module/Admin/Summary.php:151
+msgid "Automatic Friend Account"
+msgstr ""
+
+#: src/Module/Admin/Summary.php:152
+msgid "Blog Account"
+msgstr ""
+
+#: src/Module/Admin/Summary.php:153
+msgid "Private Forum Account"
+msgstr ""
+
+#: src/Module/Admin/Summary.php:173
+msgid "Message queues"
+msgstr ""
+
+#: src/Module/Admin/Summary.php:179
+msgid "Server Settings"
+msgstr ""
+
+#: src/Module/Admin/Summary.php:193
+msgid "Summary"
+msgstr ""
+
+#: src/Module/Admin/Summary.php:195
+msgid "Registered users"
+msgstr ""
+
+#: src/Module/Admin/Summary.php:197
+msgid "Pending registrations"
+msgstr ""
+
+#: src/Module/Admin/Summary.php:198
+msgid "Version"
+msgstr ""
+
+#: src/Module/Admin/Summary.php:202
+msgid "Active addons"
+msgstr ""
+
+#: src/Module/Admin/Users.php:48
+#, php-format
+msgid ""
+"\n"
+"\t\t\tDear %1$s,\n"
+"\t\t\t\tthe administrator of %2$s has set up an account for you."
+msgstr ""
+
+#: src/Module/Admin/Users.php:51
+#, php-format
+msgid ""
+"\n"
+"\t\t\tThe login details are as follows:\n"
+"\n"
+"\t\t\tSite Location:\t%1$s\n"
+"\t\t\tLogin Name:\t\t%2$s\n"
+"\t\t\tPassword:\t\t%3$s\n"
+"\n"
+"\t\t\tYou may change your password from your account \"Settings\" page after "
+"logging\n"
+"\t\t\tin.\n"
+"\n"
+"\t\t\tPlease take a few moments to review the other account settings on that "
+"page.\n"
+"\n"
+"\t\t\tYou may also wish to add some basic information to your default "
+"profile\n"
+"\t\t\t(on the \"Profiles\" page) so that other people can easily find you.\n"
+"\n"
+"\t\t\tWe recommend setting your full name, adding a profile photo,\n"
+"\t\t\tadding some profile \"keywords\" (very useful in making new friends) - "
+"and\n"
+"\t\t\tperhaps what country you live in; if you do not wish to be more "
+"specific\n"
+"\t\t\tthan that.\n"
+"\n"
+"\t\t\tWe fully respect your right to privacy, and none of these items are "
+"necessary.\n"
+"\t\t\tIf you are new and do not know anybody here, they may help\n"
+"\t\t\tyou to make some new and interesting friends.\n"
+"\n"
+"\t\t\tIf you ever want to delete your account, you can do so at %1$s/"
+"removeme\n"
+"\n"
+"\t\t\tThank you and welcome to %4$s."
+msgstr ""
+
+#: src/Module/Admin/Users.php:96
+#, php-format
+msgid "%s user blocked"
+msgid_plural "%s users blocked"
+msgstr[0] ""
+msgstr[1] ""
 
-#: src/Module/Admin/Site.php:677
-msgid ""
-"If enabled, the tags from the saved searches will used for the \"tags\" "
-"subscription in addition to the \"relay_server_tags\"."
+#: src/Module/Admin/Users.php:102
+#, php-format
+msgid "%s user unblocked"
+msgid_plural "%s users unblocked"
+msgstr[0] ""
+msgstr[1] ""
+
+#: src/Module/Admin/Users.php:110 src/Module/Admin/Users.php:160
+msgid "You can't remove yourself"
 msgstr ""
 
-#: src/Module/Admin/Site.php:680
-msgid "Start Relocation"
+#: src/Module/Admin/Users.php:114
+#, php-format
+msgid "%s user deleted"
+msgid_plural "%s users deleted"
+msgstr[0] ""
+msgstr[1] ""
+
+#: src/Module/Admin/Users.php:158
+#, php-format
+msgid "User \"%s\" deleted"
 msgstr ""
 
-#: src/Module/Admin/Summary.php:30
+#: src/Module/Admin/Users.php:167
 #, php-format
-msgid ""
-"Your DB still runs with MyISAM tables. You should change the engine type to "
-"InnoDB. As Friendica will use InnoDB only features in the future, you should "
-"change this! See <a href=\"%s\">here</a> for a guide that may be helpful "
-"converting the table engines. You may also use the command <tt>php bin/"
-"console.php dbstructure toinnodb</tt> of your Friendica installation for an "
-"automatic conversion.<br />"
+msgid "User \"%s\" blocked"
 msgstr ""
 
-#: src/Module/Admin/Summary.php:38
+#: src/Module/Admin/Users.php:173
 #, php-format
-msgid ""
-"There is a new version of Friendica available for download. Your current "
-"version is %1$s, upstream version is %2$s"
+msgid "User \"%s\" unblocked"
 msgstr ""
 
-#: src/Module/Admin/Summary.php:47
-msgid ""
-"The database update failed. Please run \"php bin/console.php dbstructure "
-"update\" from the command line and have a look at the errors that might "
-"appear."
+#: src/Module/Admin/Users.php:226
+msgid "Private Forum"
 msgstr ""
 
-#: src/Module/Admin/Summary.php:51
-msgid ""
-"The last update failed. Please run \"php bin/console.php dbstructure update"
-"\" from the command line and have a look at the errors that might appear. "
-"(Some of the errors are possibly inside the logfile.)"
+#: src/Module/Admin/Users.php:233
+msgid "Relay"
 msgstr ""
 
-#: src/Module/Admin/Summary.php:56
-msgid "The worker was never executed. Please check your database structure!"
+#: src/Module/Admin/Users.php:272 src/Module/Admin/Users.php:297
+msgid "Register date"
 msgstr ""
 
-#: src/Module/Admin/Summary.php:58
-#, php-format
-msgid ""
-"The last worker execution was on %s UTC. This is older than one hour. Please "
-"check your crontab settings."
+#: src/Module/Admin/Users.php:272 src/Module/Admin/Users.php:297
+msgid "Last login"
 msgstr ""
 
-#: src/Module/Admin/Summary.php:63
-#, php-format
-msgid ""
-"Friendica's configuration now is stored in config/local.config.php, please "
-"copy config/local-sample.config.php and move your config from <code>."
-"htconfig.php</code>. See <a href=\"%s\">the Config help page</a> for help "
-"with the transition."
+#: src/Module/Admin/Users.php:272 src/Module/Admin/Users.php:297
+msgid "Last item"
 msgstr ""
 
-#: src/Module/Admin/Summary.php:67
-#, php-format
-msgid ""
-"Friendica's configuration now is stored in config/local.config.php, please "
-"copy config/local-sample.config.php and move your config from <code>config/"
-"local.ini.php</code>. See <a href=\"%s\">the Config help page</a> for help "
-"with the transition."
+#: src/Module/Admin/Users.php:272
+msgid "Type"
 msgstr ""
 
-#: src/Module/Admin/Summary.php:73
-#, php-format
-msgid ""
-"<a href=\"%s\">%s</a> is not reachable on your system. This is a severe "
-"configuration issue that prevents server to server communication. See <a "
-"href=\"%s\">the installation page</a> for help."
+#: src/Module/Admin/Users.php:279
+msgid "Add User"
 msgstr ""
 
-#: src/Module/Admin/Summary.php:106
-#, php-format
-msgid ""
-"Friendica's system.basepath was updated from '%s' to '%s'. Please remove the "
-"system.basepath from your db to avoid differences."
+#: src/Module/Admin/Users.php:281
+msgid "User registrations waiting for confirm"
 msgstr ""
 
-#: src/Module/Admin/Summary.php:114
-#, php-format
-msgid ""
-"Friendica's current system.basepath '%s' is wrong and the config file '%s' "
-"isn't used."
+#: src/Module/Admin/Users.php:282
+msgid "User waiting for permanent deletion"
 msgstr ""
 
-#: src/Module/Admin/Summary.php:122
-#, php-format
-msgid ""
-"Friendica's current system.basepath '%s' is not equal to the config file "
-"'%s'. Please fix your configuration."
+#: src/Module/Admin/Users.php:283
+msgid "Request date"
 msgstr ""
 
-#: src/Module/Admin/Summary.php:129
-msgid "Normal Account"
+#: src/Module/Admin/Users.php:284
+msgid "No registrations."
 msgstr ""
 
-#: src/Module/Admin/Summary.php:130
-msgid "Automatic Follower Account"
+#: src/Module/Admin/Users.php:285
+msgid "Note from the user"
 msgstr ""
 
-#: src/Module/Admin/Summary.php:131
-msgid "Public Forum Account"
+#: src/Module/Admin/Users.php:287
+msgid "Deny"
 msgstr ""
 
-#: src/Module/Admin/Summary.php:132
-msgid "Automatic Friend Account"
+#: src/Module/Admin/Users.php:290
+msgid "User blocked"
 msgstr ""
 
-#: src/Module/Admin/Summary.php:133
-msgid "Blog Account"
+#: src/Module/Admin/Users.php:292
+msgid "Site admin"
 msgstr ""
 
-#: src/Module/Admin/Summary.php:134
-msgid "Private Forum Account"
+#: src/Module/Admin/Users.php:293
+msgid "Account expired"
 msgstr ""
 
-#: src/Module/Admin/Summary.php:154
-msgid "Message queues"
+#: src/Module/Admin/Users.php:296
+msgid "New User"
 msgstr ""
 
-#: src/Module/Admin/Summary.php:160
-msgid "Server Settings"
+#: src/Module/Admin/Users.php:297
+msgid "Permanent deletion"
 msgstr ""
 
-#: src/Module/Admin/Summary.php:174
-msgid "Summary"
+#: src/Module/Admin/Users.php:302
+msgid ""
+"Selected users will be deleted!\\n\\nEverything these users had posted on "
+"this site will be permanently deleted!\\n\\nAre you sure?"
 msgstr ""
 
-#: src/Module/Admin/Summary.php:176
-msgid "Registered users"
+#: src/Module/Admin/Users.php:303
+msgid ""
+"The user {0} will be deleted!\\n\\nEverything this user has posted on this "
+"site will be permanently deleted!\\n\\nAre you sure?"
 msgstr ""
 
-#: src/Module/Admin/Summary.php:178
-msgid "Pending registrations"
+#: src/Module/Admin/Users.php:313
+msgid "Name of the new user."
 msgstr ""
 
-#: src/Module/Admin/Summary.php:179
-msgid "Version"
+#: src/Module/Admin/Users.php:314
+msgid "Nickname"
 msgstr ""
 
-#: src/Module/Admin/Summary.php:183
-msgid "Active addons"
+#: src/Module/Admin/Users.php:314
+msgid "Nickname of the new user."
 msgstr ""
 
-#: src/Module/AllFriends.php:55
-msgid "No friends to display."
+#: src/Module/Admin/Users.php:315
+msgid "Email address of the new user."
 msgstr ""
 
 #: src/Module/Attach.php:36 src/Module/Attach.php:48
@@ -8720,61 +8610,6 @@ msgstr ""
 msgid "User registrations waiting for confirmation"
 msgstr ""
 
-#: src/Module/BaseSearchModule.php:52
-#, php-format
-msgid "People Search - %s"
-msgstr ""
-
-#: src/Module/BaseSearchModule.php:62
-#, php-format
-msgid "Forum Search - %s"
-msgstr ""
-
-#: src/Module/Debug/Feed.php:20 src/Module/Filer/SaveTag.php:20
-msgid "You must be logged in to use this module"
-msgstr ""
-
-#: src/Module/Debug/Feed.php:49
-msgid "Source URL"
-msgstr ""
-
-#: src/Module/Debug/Localtime.php:30
-msgid "Time Conversion"
-msgstr ""
-
-#: src/Module/Debug/Localtime.php:31
-msgid ""
-"Friendica provides this service for sharing events with other networks and "
-"friends in unknown timezones."
-msgstr ""
-
-#: src/Module/Debug/Localtime.php:32
-#, php-format
-msgid "UTC time: %s"
-msgstr ""
-
-#: src/Module/Debug/Localtime.php:35
-#, php-format
-msgid "Current timezone: %s"
-msgstr ""
-
-#: src/Module/Debug/Localtime.php:39
-#, php-format
-msgid "Converted localtime: %s"
-msgstr ""
-
-#: src/Module/Debug/Localtime.php:43
-msgid "Please select your timezone:"
-msgstr ""
-
-#: src/Module/Debug/Probe.php:19 src/Module/Debug/WebFinger.php:18
-msgid "Only logged in users are permitted to perform a probing."
-msgstr ""
-
-#: src/Module/Debug/Probe.php:35
-msgid "Lookup address"
-msgstr ""
-
 #: src/Module/Debug/Babel.php:32
 msgid "Source input"
 msgstr ""
@@ -8887,20 +8722,49 @@ msgstr ""
 msgid "HTML"
 msgstr ""
 
-#: src/Module/Directory.php:61
-msgid "No entries (some entries may be hidden)."
+#: src/Module/Debug/Feed.php:20 src/Module/Filer/SaveTag.php:20
+msgid "You must be logged in to use this module"
 msgstr ""
 
-#: src/Module/Directory.php:80
-msgid "Find on this site"
+#: src/Module/Debug/Feed.php:49
+msgid "Source URL"
 msgstr ""
 
-#: src/Module/Directory.php:82
-msgid "Results for:"
+#: src/Module/Debug/Localtime.php:30
+msgid "Time Conversion"
 msgstr ""
 
-#: src/Module/Directory.php:84
-msgid "Site Directory"
+#: src/Module/Debug/Localtime.php:31
+msgid ""
+"Friendica provides this service for sharing events with other networks and "
+"friends in unknown timezones."
+msgstr ""
+
+#: src/Module/Debug/Localtime.php:32
+#, php-format
+msgid "UTC time: %s"
+msgstr ""
+
+#: src/Module/Debug/Localtime.php:35
+#, php-format
+msgid "Current timezone: %s"
+msgstr ""
+
+#: src/Module/Debug/Localtime.php:39
+#, php-format
+msgid "Converted localtime: %s"
+msgstr ""
+
+#: src/Module/Debug/Localtime.php:43
+msgid "Please select your timezone:"
+msgstr ""
+
+#: src/Module/Debug/Probe.php:19 src/Module/Debug/WebFinger.php:18
+msgid "Only logged in users are permitted to perform a probing."
+msgstr ""
+
+#: src/Module/Debug/Probe.php:35
+msgid "Lookup address"
 msgstr ""
 
 #: src/Module/Filer/SaveTag.php:39
@@ -8912,10 +8776,6 @@ msgstr ""
 msgid "- select -"
 msgstr ""
 
-#: src/Module/FollowConfirm.php:37
-msgid "No given contact."
-msgstr ""
-
 #: src/Module/Friendica.php:40
 msgid "Installed addons/apps:"
 msgstr ""
@@ -9059,11 +8919,6 @@ msgstr ""
 msgid "Help:"
 msgstr ""
 
-#: src/Module/Home.php:42
-#, php-format
-msgid "Welcome to %s"
-msgstr ""
-
 #: src/Module/Invite.php:37
 msgid "Total invitation limit exceeded."
 msgstr ""
@@ -9168,110 +9023,66 @@ msgid ""
 "important, please visit http://friendi.ca"
 msgstr ""
 
-#: src/Module/Item/Compose.php:30
+#: src/Module/Item/Compose.php:31
 msgid "Please enter a post body."
 msgstr ""
 
-#: src/Module/Item/Compose.php:43
+#: src/Module/Item/Compose.php:44
 msgid "This feature is only available with the frio theme."
 msgstr ""
 
-#: src/Module/Item/Compose.php:63
+#: src/Module/Item/Compose.php:67
 msgid "Compose new personal note"
 msgstr ""
 
-#: src/Module/Item/Compose.php:70
+#: src/Module/Item/Compose.php:74
 msgid "Compose new post"
 msgstr ""
 
-#: src/Module/Item/Compose.php:190
+#: src/Module/Item/Compose.php:194
 msgid "Clear the location"
 msgstr ""
 
-#: src/Module/Item/Compose.php:191
+#: src/Module/Item/Compose.php:195
 msgid "Location services are unavailable on your device"
 msgstr ""
 
-#: src/Module/Item/Compose.php:192
+#: src/Module/Item/Compose.php:196
 msgid ""
 "Location services are disabled. Please check the website's permissions on "
 "your device"
 msgstr ""
 
-#: src/Module/Item/Compose.php:196
+#: src/Module/Item/Compose.php:200
 msgid "Public"
 msgstr ""
 
-#: src/Module/Item/Compose.php:197
+#: src/Module/Item/Compose.php:201
 msgid ""
 "This post will be sent to all your followers and can be seen in the "
 "community pages and by anyone with its link."
 msgstr ""
 
-#: src/Module/Item/Compose.php:198
+#: src/Module/Item/Compose.php:202
 msgid "Limited/Private"
 msgstr ""
 
-#: src/Module/Item/Compose.php:199
+#: src/Module/Item/Compose.php:203
 msgid ""
 "This post will be sent only to the people in the first box, to the exception "
 "of the people mentioned in the second box. It won't appear anywhere public."
 msgstr ""
 
-#: src/Module/Login.php:286
-msgid "Create a New Account"
-msgstr ""
-
-#: src/Module/Login.php:319
-msgid "Password: "
-msgstr ""
-
-#: src/Module/Login.php:320
-msgid "Remember me"
-msgstr ""
-
-#: src/Module/Login.php:323
-msgid "Or login using OpenID: "
-msgstr ""
-
-#: src/Module/Login.php:329
-msgid "Forgot your password?"
-msgstr ""
-
-#: src/Module/Login.php:332
-msgid "Website Terms of Service"
-msgstr ""
-
-#: src/Module/Login.php:333
-msgid "terms of service"
-msgstr ""
-
-#: src/Module/Login.php:335
-msgid "Website Privacy Policy"
-msgstr ""
-
-#: src/Module/Login.php:336
-msgid "privacy policy"
-msgstr ""
-
-#: src/Module/Logout.php:38
-msgid "Logged out."
-msgstr ""
-
 #: src/Module/Maintenance.php:29
 msgid "System down for maintenance"
 msgstr ""
 
-#: src/Module/PageNotFound.php:13
-msgid "Page not found."
-msgstr ""
-
 #: src/Module/Photo.php:87
 #, php-format
 msgid "Invalid photo with id %s."
 msgstr ""
 
-#: src/Module/Profile/Contacts.php:23 src/Module/Profile/Contacts.php:36
+#: src/Module/Profile/Contacts.php:24 src/Module/Profile/Contacts.php:37
 msgid "User not found."
 msgstr ""
 
@@ -9279,8 +9090,8 @@ msgstr ""
 msgid "No contacts."
 msgstr ""
 
-#: src/Module/Profile/Contacts.php:93 src/Module/Contact.php:569
-#: src/Module/Contact.php:1008
+#: src/Module/Profile/Contacts.php:93 src/Module/Contact.php:590
+#: src/Module/Contact.php:1029
 #, php-format
 msgid "Visit %s's profile [%s]"
 msgstr ""
@@ -9317,97 +9128,38 @@ msgstr[1] ""
 msgid "All contacts"
 msgstr ""
 
-#: src/Module/Register.php:83
-msgid ""
-"You may (optionally) fill in this form via OpenID by supplying your OpenID "
-"and clicking \"Register\"."
-msgstr ""
-
-#: src/Module/Register.php:84
-msgid ""
-"If you are not familiar with OpenID, please leave that field blank and fill "
-"in the rest of the items."
-msgstr ""
-
-#: src/Module/Register.php:85
-msgid "Your OpenID (optional): "
-msgstr ""
-
-#: src/Module/Register.php:94
-msgid "Include your profile in member directory?"
-msgstr ""
-
-#: src/Module/Register.php:117
-msgid "Note for the admin"
-msgstr ""
-
-#: src/Module/Register.php:117
-msgid "Leave a message for the admin, why you want to join this node"
-msgstr ""
-
-#: src/Module/Register.php:118
-msgid "Membership on this site is by invitation only."
-msgstr ""
-
-#: src/Module/Register.php:119
-msgid "Your invitation code: "
-msgstr ""
-
-#: src/Module/Register.php:127
-msgid "Your Full Name (e.g. Joe Smith, real or real-looking): "
+#: src/Module/Search/Acl.php:37
+msgid "You must be logged in to use this module."
 msgstr ""
 
-#: src/Module/Register.php:128
-msgid ""
-"Your Email Address: (Initial information will be send there, so this has to "
-"be an existing address.)"
+#: src/Module/Search/Index.php:35
+msgid "Only logged in users are permitted to perform a search."
 msgstr ""
 
-#: src/Module/Register.php:130
-msgid "Leave empty for an auto generated password."
+#: src/Module/Search/Index.php:57
+msgid "Only one search per minute is permitted for not logged in users."
 msgstr ""
 
-#: src/Module/Register.php:132
+#: src/Module/Search/Index.php:183
 #, php-format
-msgid ""
-"Choose a profile nickname. This must begin with a text character. Your "
-"profile address on this site will then be \"<strong>nickname@%s</strong>\"."
-msgstr ""
-
-#: src/Module/Register.php:133
-msgid "Choose a nickname: "
-msgstr ""
-
-#: src/Module/Register.php:142
-msgid "Import your profile to this friendica instance"
-msgstr ""
-
-#: src/Module/Register.php:149
-msgid "Note: This node explicitly contains adult content"
-msgstr ""
-
-#: src/Module/Register.php:242
-msgid ""
-"Registration successful. Please check your email for further instructions."
+msgid "Items tagged with: %s"
 msgstr ""
 
-#: src/Module/Register.php:246
+#: src/Module/Search/Index.php:185 src/Module/Contact.php:815
 #, php-format
-msgid ""
-"Failed to send email message. Here your accout details:<br> login: %s<br> "
-"password: %s<br><br>You can change your password after login."
+msgid "Results for: %s"
 msgstr ""
 
-#: src/Module/Register.php:253
-msgid "Registration successful."
+#: src/Module/Search/Saved.php:29
+msgid "Search term successfully saved."
 msgstr ""
 
-#: src/Module/Register.php:258
-msgid "Your registration can not be processed."
+#: src/Module/Search/Saved.php:31
+msgid "Search term already saved."
 msgstr ""
 
-#: src/Module/Register.php:304
-msgid "Your registration is pending approval by the site owner."
+#: src/Module/Search/Saved.php:37
+msgid "Search term successfully removed."
 msgstr ""
 
 #: src/Module/Settings/TwoFactor/AppSpecific.php:36
@@ -9488,6 +9240,36 @@ msgstr ""
 msgid "Generate"
 msgstr ""
 
+#: src/Module/Settings/TwoFactor/Recovery.php:50
+msgid "New recovery codes successfully generated."
+msgstr ""
+
+#: src/Module/Settings/TwoFactor/Recovery.php:76
+msgid "Two-factor recovery codes"
+msgstr ""
+
+#: src/Module/Settings/TwoFactor/Recovery.php:78
+msgid ""
+"<p>Recovery codes can be used to access your account in the event you lose "
+"access to your device and cannot receive two-factor authentication codes.</"
+"p><p><strong>Put these in a safe spot!</strong> If you lose your device and "
+"don’t have the recovery codes you will lose access to your account.</p>"
+msgstr ""
+
+#: src/Module/Settings/TwoFactor/Recovery.php:80
+msgid ""
+"When you generate new recovery codes, you must copy the new codes. Your old "
+"codes won’t work anymore."
+msgstr ""
+
+#: src/Module/Settings/TwoFactor/Recovery.php:81
+msgid "Generate new recovery codes"
+msgstr ""
+
+#: src/Module/Settings/TwoFactor/Recovery.php:83
+msgid "Next: Verification"
+msgstr ""
+
 #: src/Module/Settings/TwoFactor/Index.php:51
 msgid "Two-factor authentication successfully disabled."
 msgstr ""
@@ -9546,7 +9328,7 @@ msgid ""
 "supporting two-factor authentication.</p>"
 msgstr ""
 
-#: src/Module/Settings/TwoFactor/Index.php:111 src/Module/Contact.php:614
+#: src/Module/Settings/TwoFactor/Index.php:111 src/Module/Contact.php:635
 msgid "Actions"
 msgstr ""
 
@@ -9580,42 +9362,12 @@ msgstr ""
 msgid "Finish app configuration"
 msgstr ""
 
-#: src/Module/Settings/TwoFactor/Recovery.php:50
-msgid "New recovery codes successfully generated."
-msgstr ""
-
-#: src/Module/Settings/TwoFactor/Recovery.php:76
-msgid "Two-factor recovery codes"
-msgstr ""
-
-#: src/Module/Settings/TwoFactor/Recovery.php:78
-msgid ""
-"<p>Recovery codes can be used to access your account in the event you lose "
-"access to your device and cannot receive two-factor authentication codes.</"
-"p><p><strong>Put these in a safe spot!</strong> If you lose your device and "
-"don’t have the recovery codes you will lose access to your account.</p>"
-msgstr ""
-
-#: src/Module/Settings/TwoFactor/Recovery.php:80
-msgid ""
-"When you generate new recovery codes, you must copy the new codes. Your old "
-"codes won’t work anymore."
-msgstr ""
-
-#: src/Module/Settings/TwoFactor/Recovery.php:81
-msgid "Generate new recovery codes"
-msgstr ""
-
-#: src/Module/Settings/TwoFactor/Recovery.php:83
-msgid "Next: Verification"
-msgstr ""
-
 #: src/Module/Settings/TwoFactor/Verify.php:63
 msgid "Two-factor authentication successfully activated."
 msgstr ""
 
 #: src/Module/Settings/TwoFactor/Verify.php:67
-#: src/Module/TwoFactor/Recovery.php:46 src/Module/TwoFactor/Verify.php:43
+#: src/Module/TwoFactor/Verify.php:43 src/Module/TwoFactor/Recovery.php:46
 msgid "Invalid code, please retry."
 msgstr ""
 
@@ -9665,6 +9417,112 @@ msgstr ""
 msgid "Verify code and enable two-factor authentication"
 msgstr ""
 
+#: src/Module/Settings/Delegation.php:37
+msgid "Delegation successfully granted."
+msgstr ""
+
+#: src/Module/Settings/Delegation.php:39
+msgid "Parent user not found, unavailable or password doesn't match."
+msgstr ""
+
+#: src/Module/Settings/Delegation.php:43
+msgid "Delegation successfully revoked."
+msgstr ""
+
+#: src/Module/Settings/Delegation.php:66 src/Module/Settings/Delegation.php:88
+msgid ""
+"Delegated administrators can view but not change delegation permissions."
+msgstr ""
+
+#: src/Module/Settings/Delegation.php:80
+msgid "Delegate user not found."
+msgstr ""
+
+#: src/Module/Settings/Delegation.php:137
+msgid "No parent user"
+msgstr ""
+
+#: src/Module/Settings/Delegation.php:149
+msgid "Parent Password:"
+msgstr ""
+
+#: src/Module/Settings/Delegation.php:149
+msgid ""
+"Please enter the password of the parent account to legitimize your request."
+msgstr ""
+
+#: src/Module/Settings/Delegation.php:154
+msgid "Parent User"
+msgstr ""
+
+#: src/Module/Settings/Delegation.php:157
+msgid ""
+"Parent users have total control about this account, including the account "
+"settings. Please double check whom you give this access."
+msgstr ""
+
+#: src/Module/Settings/Delegation.php:159
+msgid "Delegate Page Management"
+msgstr ""
+
+#: src/Module/Settings/Delegation.php:160
+msgid "Delegates"
+msgstr ""
+
+#: src/Module/Settings/Delegation.php:162
+msgid ""
+"Delegates are able to manage all aspects of this account/page except for "
+"basic account settings. Please do not delegate your personal account to "
+"anybody that you do not trust completely."
+msgstr ""
+
+#: src/Module/Settings/Delegation.php:163
+msgid "Existing Page Delegates"
+msgstr ""
+
+#: src/Module/Settings/Delegation.php:165
+msgid "Potential Delegates"
+msgstr ""
+
+#: src/Module/Settings/Delegation.php:168
+msgid "Add"
+msgstr ""
+
+#: src/Module/Settings/Delegation.php:169
+msgid "No entries."
+msgstr ""
+
+#: src/Module/Settings/UserExport.php:44
+msgid "Export account"
+msgstr ""
+
+#: src/Module/Settings/UserExport.php:44
+msgid ""
+"Export your account info and contacts. Use this to make a backup of your "
+"account and/or to move it to another server."
+msgstr ""
+
+#: src/Module/Settings/UserExport.php:45
+msgid "Export all"
+msgstr ""
+
+#: src/Module/Settings/UserExport.php:45
+msgid ""
+"Export your accout info, contacts and all your items as json. Could be a "
+"very big file, and could take a lot of time. Use this to make a full backup "
+"of your account (photos are not exported)"
+msgstr ""
+
+#: src/Module/Settings/UserExport.php:46
+msgid "Export Contacts to CSV"
+msgstr ""
+
+#: src/Module/Settings/UserExport.php:46
+msgid ""
+"Export the list of the accounts you are following as CSV file. Compatible to "
+"e.g. Mastodon."
+msgstr ""
+
 #: src/Module/Special/HTTPException.php:32
 msgid "Bad Request"
 msgstr ""
@@ -9726,6 +9584,22 @@ msgstr ""
 msgid "Go back"
 msgstr ""
 
+#: src/Module/TwoFactor/Verify.php:63
+msgid ""
+"<p>Open the two-factor authentication app on your device to get an "
+"authentication code and verify your identity.</p>"
+msgstr ""
+
+#: src/Module/TwoFactor/Verify.php:66 src/Module/TwoFactor/Recovery.php:67
+#, php-format
+msgid ""
+"Don’t have your phone? <a href=\"%s\">Enter a two-factor recovery code</a>"
+msgstr ""
+
+#: src/Module/TwoFactor/Verify.php:68
+msgid "Verify code and complete login"
+msgstr ""
+
 #: src/Module/TwoFactor/Recovery.php:41
 #, php-format
 msgid "Remaining recovery codes: %d"
@@ -9741,12 +9615,6 @@ msgid ""
 "to your mobile device.</p>"
 msgstr ""
 
-#: src/Module/TwoFactor/Recovery.php:67 src/Module/TwoFactor/Verify.php:66
-#, php-format
-msgid ""
-"Don’t have your phone? <a href=\"%s\">Enter a two-factor recovery code</a>"
-msgstr ""
-
 #: src/Module/TwoFactor/Recovery.php:68
 msgid "Please enter a recovery code"
 msgstr ""
@@ -9755,16 +9623,6 @@ msgstr ""
 msgid "Submit recovery code and complete login"
 msgstr ""
 
-#: src/Module/TwoFactor/Verify.php:63
-msgid ""
-"<p>Open the two-factor authentication app on your device to get an "
-"authentication code and verify your identity.</p>"
-msgstr ""
-
-#: src/Module/TwoFactor/Verify.php:68
-msgid "Verify code and complete login"
-msgstr ""
-
 #: src/Module/Welcome.php:25
 msgid "Welcome to Friendica"
 msgstr ""
@@ -9930,6 +9788,20 @@ msgid ""
 "features and resources."
 msgstr ""
 
+#: src/Module/AllFriends.php:55
+msgid "No friends to display."
+msgstr ""
+
+#: src/Module/BaseSearchModule.php:54
+#, php-format
+msgid "People Search - %s"
+msgstr ""
+
+#: src/Module/BaseSearchModule.php:64
+#, php-format
+msgid "Forum Search - %s"
+msgstr ""
+
 #: src/Module/Bookmarklet.php:35
 msgid "This page is missing a url parameter."
 msgstr ""
@@ -9957,340 +9829,387 @@ msgstr ""
 msgid "Contact updated."
 msgstr ""
 
-#: src/Module/Contact.php:355
+#: src/Module/Contact.php:376
 msgid "Contact not found"
 msgstr ""
 
-#: src/Module/Contact.php:374
+#: src/Module/Contact.php:395
 msgid "Contact has been blocked"
 msgstr ""
 
-#: src/Module/Contact.php:374
+#: src/Module/Contact.php:395
 msgid "Contact has been unblocked"
 msgstr ""
 
-#: src/Module/Contact.php:384
+#: src/Module/Contact.php:405
 msgid "Contact has been ignored"
 msgstr ""
 
-#: src/Module/Contact.php:384
+#: src/Module/Contact.php:405
 msgid "Contact has been unignored"
 msgstr ""
 
-#: src/Module/Contact.php:394
+#: src/Module/Contact.php:415
 msgid "Contact has been archived"
 msgstr ""
 
-#: src/Module/Contact.php:394
+#: src/Module/Contact.php:415
 msgid "Contact has been unarchived"
 msgstr ""
 
-#: src/Module/Contact.php:418
+#: src/Module/Contact.php:439
 msgid "Drop contact"
 msgstr ""
 
-#: src/Module/Contact.php:421 src/Module/Contact.php:798
+#: src/Module/Contact.php:442 src/Module/Contact.php:819
 msgid "Do you really want to delete this contact?"
 msgstr ""
 
-#: src/Module/Contact.php:435
+#: src/Module/Contact.php:456
 msgid "Contact has been removed."
 msgstr ""
 
-#: src/Module/Contact.php:465
+#: src/Module/Contact.php:486
 #, php-format
 msgid "You are mutual friends with %s"
 msgstr ""
 
-#: src/Module/Contact.php:470
+#: src/Module/Contact.php:491
 #, php-format
 msgid "You are sharing with %s"
 msgstr ""
 
-#: src/Module/Contact.php:475
+#: src/Module/Contact.php:496
 #, php-format
 msgid "%s is sharing with you"
 msgstr ""
 
-#: src/Module/Contact.php:499
+#: src/Module/Contact.php:520
 msgid "Private communications are not available for this contact."
 msgstr ""
 
-#: src/Module/Contact.php:501
+#: src/Module/Contact.php:522
 msgid "Never"
 msgstr ""
 
-#: src/Module/Contact.php:504
+#: src/Module/Contact.php:525
 msgid "(Update was successful)"
 msgstr ""
 
-#: src/Module/Contact.php:504
+#: src/Module/Contact.php:525
 msgid "(Update was not successful)"
 msgstr ""
 
-#: src/Module/Contact.php:506 src/Module/Contact.php:1042
+#: src/Module/Contact.php:527 src/Module/Contact.php:1063
 msgid "Suggest friends"
 msgstr ""
 
-#: src/Module/Contact.php:510
+#: src/Module/Contact.php:531
 #, php-format
 msgid "Network type: %s"
 msgstr ""
 
-#: src/Module/Contact.php:515
+#: src/Module/Contact.php:536
 msgid "Communications lost with this contact!"
 msgstr ""
 
-#: src/Module/Contact.php:521
+#: src/Module/Contact.php:542
 msgid "Fetch further information for feeds"
 msgstr ""
 
-#: src/Module/Contact.php:523
+#: src/Module/Contact.php:544
 msgid ""
 "Fetch information like preview pictures, title and teaser from the feed "
 "item. You can activate this if the feed doesn't contain much text. Keywords "
 "are taken from the meta header in the feed item and are posted as hash tags."
 msgstr ""
 
-#: src/Module/Contact.php:526
+#: src/Module/Contact.php:547
 msgid "Fetch information"
 msgstr ""
 
-#: src/Module/Contact.php:527
+#: src/Module/Contact.php:548
 msgid "Fetch keywords"
 msgstr ""
 
-#: src/Module/Contact.php:528
+#: src/Module/Contact.php:549
 msgid "Fetch information and keywords"
 msgstr ""
 
-#: src/Module/Contact.php:547
+#: src/Module/Contact.php:568
 msgid "Profile Visibility"
 msgstr ""
 
-#: src/Module/Contact.php:548
+#: src/Module/Contact.php:569
 msgid "Contact Information / Notes"
 msgstr ""
 
-#: src/Module/Contact.php:549
+#: src/Module/Contact.php:570
 msgid "Contact Settings"
 msgstr ""
 
-#: src/Module/Contact.php:558
+#: src/Module/Contact.php:579
 msgid "Contact"
 msgstr ""
 
-#: src/Module/Contact.php:562
+#: src/Module/Contact.php:583
 #, php-format
 msgid ""
 "Please choose the profile you would like to display to %s when viewing your "
 "profile securely."
 msgstr ""
 
-#: src/Module/Contact.php:564
+#: src/Module/Contact.php:585
 msgid "Their personal note"
 msgstr ""
 
-#: src/Module/Contact.php:566
+#: src/Module/Contact.php:587
 msgid "Edit contact notes"
 msgstr ""
 
-#: src/Module/Contact.php:570
+#: src/Module/Contact.php:591
 msgid "Block/Unblock contact"
 msgstr ""
 
-#: src/Module/Contact.php:571
+#: src/Module/Contact.php:592
 msgid "Ignore contact"
 msgstr ""
 
-#: src/Module/Contact.php:572
+#: src/Module/Contact.php:593
 msgid "Repair URL settings"
 msgstr ""
 
-#: src/Module/Contact.php:573
+#: src/Module/Contact.php:594
 msgid "View conversations"
 msgstr ""
 
-#: src/Module/Contact.php:578
+#: src/Module/Contact.php:599
 msgid "Last update:"
 msgstr ""
 
-#: src/Module/Contact.php:580
+#: src/Module/Contact.php:601
 msgid "Update public posts"
 msgstr ""
 
-#: src/Module/Contact.php:582 src/Module/Contact.php:1052
+#: src/Module/Contact.php:603 src/Module/Contact.php:1073
 msgid "Update now"
 msgstr ""
 
-#: src/Module/Contact.php:586 src/Module/Contact.php:803
-#: src/Module/Contact.php:1069
+#: src/Module/Contact.php:607 src/Module/Contact.php:824
+#: src/Module/Contact.php:1090
 msgid "Unignore"
 msgstr ""
 
-#: src/Module/Contact.php:590
+#: src/Module/Contact.php:611
 msgid "Currently blocked"
 msgstr ""
 
-#: src/Module/Contact.php:591
+#: src/Module/Contact.php:612
 msgid "Currently ignored"
 msgstr ""
 
-#: src/Module/Contact.php:592
+#: src/Module/Contact.php:613
 msgid "Currently archived"
 msgstr ""
 
-#: src/Module/Contact.php:593
+#: src/Module/Contact.php:614
 msgid "Awaiting connection acknowledge"
 msgstr ""
 
-#: src/Module/Contact.php:594
+#: src/Module/Contact.php:615
 msgid ""
 "Replies/likes to your public posts <strong>may</strong> still be visible"
 msgstr ""
 
-#: src/Module/Contact.php:595
+#: src/Module/Contact.php:616
 msgid "Notification for new posts"
 msgstr ""
 
-#: src/Module/Contact.php:595
+#: src/Module/Contact.php:616
 msgid "Send a notification of every new post of this contact"
 msgstr ""
 
-#: src/Module/Contact.php:597
+#: src/Module/Contact.php:618
 msgid "Blacklisted keywords"
 msgstr ""
 
-#: src/Module/Contact.php:597
+#: src/Module/Contact.php:618
 msgid ""
 "Comma separated list of keywords that should not be converted to hashtags, "
 "when \"Fetch information and keywords\" is selected"
 msgstr ""
 
-#: src/Module/Contact.php:663
+#: src/Module/Contact.php:684
 msgid "Show all contacts"
 msgstr ""
 
-#: src/Module/Contact.php:668 src/Module/Contact.php:778
+#: src/Module/Contact.php:689 src/Module/Contact.php:799
 msgid "Pending"
 msgstr ""
 
-#: src/Module/Contact.php:671
+#: src/Module/Contact.php:692
 msgid "Only show pending contacts"
 msgstr ""
 
-#: src/Module/Contact.php:676 src/Module/Contact.php:779
+#: src/Module/Contact.php:697 src/Module/Contact.php:800
 msgid "Blocked"
 msgstr ""
 
-#: src/Module/Contact.php:679
+#: src/Module/Contact.php:700
 msgid "Only show blocked contacts"
 msgstr ""
 
-#: src/Module/Contact.php:684 src/Module/Contact.php:781
+#: src/Module/Contact.php:705 src/Module/Contact.php:802
 msgid "Ignored"
 msgstr ""
 
-#: src/Module/Contact.php:687
+#: src/Module/Contact.php:708
 msgid "Only show ignored contacts"
 msgstr ""
 
-#: src/Module/Contact.php:692 src/Module/Contact.php:782
+#: src/Module/Contact.php:713 src/Module/Contact.php:803
 msgid "Archived"
 msgstr ""
 
-#: src/Module/Contact.php:695
+#: src/Module/Contact.php:716
 msgid "Only show archived contacts"
 msgstr ""
 
-#: src/Module/Contact.php:700 src/Module/Contact.php:780
+#: src/Module/Contact.php:721 src/Module/Contact.php:801
 msgid "Hidden"
 msgstr ""
 
-#: src/Module/Contact.php:703
+#: src/Module/Contact.php:724
 msgid "Only show hidden contacts"
 msgstr ""
 
-#: src/Module/Contact.php:711
+#: src/Module/Contact.php:732
 msgid "Organize your contact groups"
 msgstr ""
 
-#: src/Module/Contact.php:793
+#: src/Module/Contact.php:814
 msgid "Search your contacts"
 msgstr ""
 
-#: src/Module/Contact.php:804 src/Module/Contact.php:1078
+#: src/Module/Contact.php:825 src/Module/Contact.php:1099
 msgid "Archive"
 msgstr ""
 
-#: src/Module/Contact.php:804 src/Module/Contact.php:1078
+#: src/Module/Contact.php:825 src/Module/Contact.php:1099
 msgid "Unarchive"
 msgstr ""
 
-#: src/Module/Contact.php:807
+#: src/Module/Contact.php:828
 msgid "Batch Actions"
 msgstr ""
 
-#: src/Module/Contact.php:834
+#: src/Module/Contact.php:855
 msgid "Conversations started by this contact"
 msgstr ""
 
-#: src/Module/Contact.php:839
+#: src/Module/Contact.php:860
 msgid "Posts and Comments"
 msgstr ""
 
-#: src/Module/Contact.php:862
+#: src/Module/Contact.php:883
 msgid "View all contacts"
 msgstr ""
 
-#: src/Module/Contact.php:873
+#: src/Module/Contact.php:894
 msgid "View all common friends"
 msgstr ""
 
-#: src/Module/Contact.php:883
+#: src/Module/Contact.php:904
 msgid "Advanced Contact Settings"
 msgstr ""
 
-#: src/Module/Contact.php:966
+#: src/Module/Contact.php:987
 msgid "Mutual Friendship"
 msgstr ""
 
-#: src/Module/Contact.php:971
+#: src/Module/Contact.php:992
 msgid "is a fan of yours"
 msgstr ""
 
-#: src/Module/Contact.php:976
+#: src/Module/Contact.php:997
 msgid "you are a fan of"
 msgstr ""
 
-#: src/Module/Contact.php:994
+#: src/Module/Contact.php:1015
 msgid "Pending outgoing contact request"
 msgstr ""
 
-#: src/Module/Contact.php:996
+#: src/Module/Contact.php:1017
 msgid "Pending incoming contact request"
 msgstr ""
 
-#: src/Module/Contact.php:1009
+#: src/Module/Contact.php:1030
 msgid "Edit contact"
 msgstr ""
 
-#: src/Module/Contact.php:1063
+#: src/Module/Contact.php:1084
 msgid "Toggle Blocked status"
 msgstr ""
 
-#: src/Module/Contact.php:1071
+#: src/Module/Contact.php:1092
 msgid "Toggle Ignored status"
 msgstr ""
 
-#: src/Module/Contact.php:1080
+#: src/Module/Contact.php:1101
 msgid "Toggle Archive status"
 msgstr ""
 
-#: src/Module/Contact.php:1088
+#: src/Module/Contact.php:1109
 msgid "Delete contact"
 msgstr ""
 
+#: src/Module/Delegation.php:127
+msgid "Manage Identities and/or Pages"
+msgstr ""
+
+#: src/Module/Delegation.php:128
+msgid ""
+"Toggle between different identities or community/group pages which share "
+"your account details or which you have been granted \"manage\" permissions"
+msgstr ""
+
+#: src/Module/Delegation.php:129
+msgid "Select an identity to manage: "
+msgstr ""
+
+#: src/Module/Directory.php:59
+msgid "No entries (some entries may be hidden)."
+msgstr ""
+
+#: src/Module/Directory.php:78
+msgid "Find on this site"
+msgstr ""
+
+#: src/Module/Directory.php:80
+msgid "Results for:"
+msgstr ""
+
+#: src/Module/Directory.php:82
+msgid "Site Directory"
+msgstr ""
+
+#: src/Module/FollowConfirm.php:37
+msgid "No given contact."
+msgstr ""
+
+#: src/Module/HTTPException/MethodNotAllowed.php:13
+msgid "Method Not Allowed."
+msgstr ""
+
+#: src/Module/HTTPException/PageNotFound.php:13 src/App/Router.php:182
+msgid "Page not found."
+msgstr ""
+
+#: src/Module/Home.php:34
+#, php-format
+msgid "Welcome to %s"
+msgstr ""
+
 #: src/Module/Install.php:159
 msgid "Friendica Communications Server - Setup"
 msgstr ""
@@ -10434,87 +10353,268 @@ msgid ""
 "administrator email. This will allow you to enter the site admin panel."
 msgstr ""
 
-#: src/Object/Post.php:138
+#: src/Module/Login.php:312
+msgid "Create a New Account"
+msgstr ""
+
+#: src/Module/Login.php:337
+msgid "Your OpenID: "
+msgstr ""
+
+#: src/Module/Login.php:340
+msgid ""
+"Please enter your username and password to add the OpenID to your existing "
+"account."
+msgstr ""
+
+#: src/Module/Login.php:342
+msgid "Or login using OpenID: "
+msgstr ""
+
+#: src/Module/Login.php:356
+msgid "Password: "
+msgstr ""
+
+#: src/Module/Login.php:357
+msgid "Remember me"
+msgstr ""
+
+#: src/Module/Login.php:366
+msgid "Forgot your password?"
+msgstr ""
+
+#: src/Module/Login.php:369
+msgid "Website Terms of Service"
+msgstr ""
+
+#: src/Module/Login.php:370
+msgid "terms of service"
+msgstr ""
+
+#: src/Module/Login.php:372
+msgid "Website Privacy Policy"
+msgstr ""
+
+#: src/Module/Login.php:373
+msgid "privacy policy"
+msgstr ""
+
+#: src/Module/Logout.php:40
+msgid "Logged out."
+msgstr ""
+
+#: src/Module/Register.php:77
+msgid ""
+"You may (optionally) fill in this form via OpenID by supplying your OpenID "
+"and clicking \"Register\"."
+msgstr ""
+
+#: src/Module/Register.php:78
+msgid ""
+"If you are not familiar with OpenID, please leave that field blank and fill "
+"in the rest of the items."
+msgstr ""
+
+#: src/Module/Register.php:79
+msgid "Your OpenID (optional): "
+msgstr ""
+
+#: src/Module/Register.php:88
+msgid "Include your profile in member directory?"
+msgstr ""
+
+#: src/Module/Register.php:111
+msgid "Note for the admin"
+msgstr ""
+
+#: src/Module/Register.php:111
+msgid "Leave a message for the admin, why you want to join this node"
+msgstr ""
+
+#: src/Module/Register.php:112
+msgid "Membership on this site is by invitation only."
+msgstr ""
+
+#: src/Module/Register.php:113
+msgid "Your invitation code: "
+msgstr ""
+
+#: src/Module/Register.php:121
+msgid "Your Full Name (e.g. Joe Smith, real or real-looking): "
+msgstr ""
+
+#: src/Module/Register.php:122
+msgid ""
+"Your Email Address: (Initial information will be send there, so this has to "
+"be an existing address.)"
+msgstr ""
+
+#: src/Module/Register.php:124
+msgid "Leave empty for an auto generated password."
+msgstr ""
+
+#: src/Module/Register.php:126
+#, php-format
+msgid ""
+"Choose a profile nickname. This must begin with a text character. Your "
+"profile address on this site will then be \"<strong>nickname@%s</strong>\"."
+msgstr ""
+
+#: src/Module/Register.php:127
+msgid "Choose a nickname: "
+msgstr ""
+
+#: src/Module/Register.php:136
+msgid "Import your profile to this friendica instance"
+msgstr ""
+
+#: src/Module/Register.php:143
+msgid "Note: This node explicitly contains adult content"
+msgstr ""
+
+#: src/Module/Register.php:238
+msgid ""
+"Registration successful. Please check your email for further instructions."
+msgstr ""
+
+#: src/Module/Register.php:242
+#, php-format
+msgid ""
+"Failed to send email message. Here your accout details:<br> login: %s<br> "
+"password: %s<br><br>You can change your password after login."
+msgstr ""
+
+#: src/Module/Register.php:248
+msgid "Registration successful."
+msgstr ""
+
+#: src/Module/Register.php:253 src/Module/Register.php:260
+msgid "Your registration can not be processed."
+msgstr ""
+
+#: src/Module/Register.php:259
+msgid "You have to leave a request note for the admin."
+msgstr ""
+
+#: src/Module/Register.php:307
+msgid "Your registration is pending approval by the site owner."
+msgstr ""
+
+#: src/Module/Tos.php:35 src/Module/Tos.php:77
+msgid ""
+"At the time of registration, and for providing communications between the "
+"user account and their contacts, the user has to provide a display name (pen "
+"name), an username (nickname) and a working email address. The names will be "
+"accessible on the profile page of the account by any visitor of the page, "
+"even if other profile details are not displayed. The email address will only "
+"be used to send the user notifications about interactions, but wont be "
+"visibly displayed. The listing of an account in the node's user directory or "
+"the global user directory is optional and can be controlled in the user "
+"settings, it is not necessary for communication."
+msgstr ""
+
+#: src/Module/Tos.php:36 src/Module/Tos.php:78
+msgid ""
+"This data is required for communication and is passed on to the nodes of the "
+"communication partners and is stored there. Users can enter additional "
+"private data that may be transmitted to the communication partners accounts."
+msgstr ""
+
+#: src/Module/Tos.php:37 src/Module/Tos.php:79
+#, php-format
+msgid ""
+"At any point in time a logged in user can export their account data from the "
+"<a href=\"%1$s/settings/userexport\">account settings</a>. If the user wants "
+"to delete their account they can do so at <a href=\"%1$s/removeme\">%1$s/"
+"removeme</a>. The deletion of the account will be permanent. Deletion of the "
+"data will also be requested from the nodes of the communication partners."
+msgstr ""
+
+#: src/Module/Tos.php:40 src/Module/Tos.php:76
+msgid "Privacy Statement"
+msgstr ""
+
+#: src/Object/Post.php:135
 msgid "This entry was edited"
 msgstr ""
 
-#: src/Object/Post.php:158
+#: src/Object/Post.php:155
 msgid "Private Message"
 msgstr ""
 
-#: src/Object/Post.php:200
+#: src/Object/Post.php:197
 msgid "Delete locally"
 msgstr ""
 
-#: src/Object/Post.php:203
+#: src/Object/Post.php:200
 msgid "Delete globally"
 msgstr ""
 
-#: src/Object/Post.php:203
+#: src/Object/Post.php:200
 msgid "Remove locally"
 msgstr ""
 
-#: src/Object/Post.php:217
+#: src/Object/Post.php:214
 msgid "save to folder"
 msgstr ""
 
-#: src/Object/Post.php:252
+#: src/Object/Post.php:249
 msgid "I will attend"
 msgstr ""
 
-#: src/Object/Post.php:252
+#: src/Object/Post.php:249
 msgid "I will not attend"
 msgstr ""
 
-#: src/Object/Post.php:252
+#: src/Object/Post.php:249
 msgid "I might attend"
 msgstr ""
 
-#: src/Object/Post.php:280
+#: src/Object/Post.php:277
 msgid "ignore thread"
 msgstr ""
 
-#: src/Object/Post.php:281
+#: src/Object/Post.php:278
 msgid "unignore thread"
 msgstr ""
 
-#: src/Object/Post.php:282
+#: src/Object/Post.php:279
 msgid "toggle ignore status"
 msgstr ""
 
-#: src/Object/Post.php:293
+#: src/Object/Post.php:290
 msgid "add star"
 msgstr ""
 
-#: src/Object/Post.php:294
+#: src/Object/Post.php:291
 msgid "remove star"
 msgstr ""
 
-#: src/Object/Post.php:295
+#: src/Object/Post.php:292
 msgid "toggle star status"
 msgstr ""
 
-#: src/Object/Post.php:298
+#: src/Object/Post.php:295
 msgid "starred"
 msgstr ""
 
-#: src/Object/Post.php:302
+#: src/Object/Post.php:299
 msgid "add tag"
 msgstr ""
 
-#: src/Object/Post.php:313
+#: src/Object/Post.php:310
 msgid "like"
 msgstr ""
 
-#: src/Object/Post.php:314
+#: src/Object/Post.php:311
 msgid "dislike"
 msgstr ""
 
-#: src/Object/Post.php:317
+#: src/Object/Post.php:314
 msgid "Share this"
 msgstr ""
 
-#: src/Object/Post.php:317
+#: src/Object/Post.php:314
 msgid "share"
 msgstr ""
 
@@ -10586,15 +10686,14 @@ msgstr ""
 msgid "toggle mobile"
 msgstr ""
 
-#: src/LegacyModule.php:30
+#: src/App/Router.php:180
 #, php-format
-msgid "Legacy module file not found: %s"
+msgid "Method not allowed for this module. Allowed method(s): %s"
 msgstr ""
 
-#: src/BaseModule.php:135
-msgid ""
-"The form security token was not correct. This probably happened because the "
-"form has been opened for too long (>3 hours) before submitting it."
+#: src/LegacyModule.php:30
+#, php-format
+msgid "Legacy module file not found: %s"
 msgstr ""
 
 #: src/Console/ArchiveContact.php:86
@@ -10631,10 +10730,16 @@ msgstr ""
 msgid "All pending post updates are done."
 msgstr ""
 
-#: src/App.php:485
+#: src/App.php:519
 msgid "No system theme config value set."
 msgstr ""
 
+#: src/BaseModule.php:134
+msgid ""
+"The form security token was not correct. This probably happened because the "
+"form has been opened for too long (>3 hours) before submitting it."
+msgstr ""
+
 #: update.php:218
 #, php-format
 msgid "%s: Updating author-id and owner-id in item and thread table. "
index 017e096afc561b89c5bb77aaecb89b6fc4c22b09..4f41c204ee2efe770a32c4dd6555f2451c27f961 100644 (file)
@@ -28,6 +28,7 @@
                                        {{if $profile.actions.network}}<a class="btn btn-labeled btn-primary btn-sm" href="{{$profile.actions.network.1}}" aria-label="{{$profile.actions.network.0}}" title="{{$profile.actions.network.0}}"><i class="fa fa-cloud" aria-hidden="true"></i></a>{{/if}}
                                        {{if $profile.actions.edit}}<a class="btn btn-labeled btn-primary btn-sm" href="{{$profile.actions.edit.1}}" aria-label="{{$profile.actions.edit.0}}" title="{{$profile.actions.edit.0}}"><i class="fa fa-user" aria-hidden="true"></i></a>{{/if}}
                                        {{if $profile.actions.follow}}<a class="btn btn-labeled btn-primary btn-sm" href="{{$profile.actions.follow.1}}" aria-label="{{$profile.actions.follow.0}}" title="{{$profile.actions.follow.0}}"><i class="fa fa-user-plus" aria-hidden="true"></i></a>{{/if}}
+                                       {{if $profile.actions.unfollow}}<a class="btn btn-labeled btn-primary btn-sm" href="{{$profile.actions.unfollow.1}}" aria-label="{{$profile.actions.unfollow.0}}" title="{{$profile.actions.unfollow.0}}"><i class="fa fa-user-times" aria-hidden="true"></i></a>{{/if}}
                                </div>
                        </div>
                </div>
index 456fadaab841825fac65ad83dc858603d2cf518f..7aa1a4d991f1c3f138233ef9f21818f9b1199812 100644 (file)
@@ -56,6 +56,7 @@
 
 {{if $permonly}}
     {{include file="field_textarea.tpl" field=$permonlybox}}
+       <input type="input" id="registertarpit" style="display: none;" placeholder="Don't enter anything here" />
 {{/if}}
 
        {{$publish nofilter}}
index c95c0b14307787e6935a6f60f953ac5d4482eede..af1352c4cbeb1b5913bdbd56485f8f8d59b788f8 100644 (file)
@@ -2,7 +2,7 @@
 
 {{$nickname_block nofilter}}
 
-<form action="settings" id="settings-form" method="post" autocomplete="off" >
+<form action="settings" id="settings-form" method="post" autocomplete="off" enctype="multipart/form-data" >
 <input type='hidden' name='form_security_token' value='{{$form_security_token}}'>
 
 <h3 class="settings-heading"><a href="javascript:;">{{$h_pass}}</a></h3>
 </div>
 </div>
 
+<h3 class="settings-heading"><a href="javascript:;">{{$importcontact}}</a></h3>
+<div class="settings-content-block">
+<input type="hidden" name="MAX_FILE_SIZE" value="{{$importcontact_maxsize}}" />
+<div id="settings-pagetype-desc">{{$importcontact_text}}</div>
+<input type="file" name="importcontact-filename" />
+
+<div class="settings-submit-wrapper" >
+<input type="submit" name="importcontact-submit" class="importcontact-submit" value="{{$importcontact_button}}" />
+</div>
+</div>
+
 <h3 class="settings-heading"><a href="javascript:;">{{$relocate}}</a></h3>
 <div class="settings-content-block">
 <div id="settings-pagetype-desc">{{$relocate_text}}</div>
diff --git a/view/templates/settings/userexport.tpl b/view/templates/settings/userexport.tpl
new file mode 100644 (file)
index 0000000..b9e177a
--- /dev/null
@@ -0,0 +1,10 @@
+
+<h3>{{$title}}</h3>
+
+
+{{foreach $options as $o}}
+<dl>
+    <dt><a href="{{$o.0}}">{{$o.1}}</a></dt>
+    <dd>{{$o.2}}</dd>
+</dl>
+{{/foreach}}
index 01cd7559f188fe57f6982c0a4104084f89827b21..0816400d5258ee811e8886a240bc00a62a4cf96d 100644 (file)
@@ -50,7 +50,7 @@
                </div>
                <div class="wall-item-author">
                                <a href="{{$item.profile_url}}" target="redir" title="{{$item.linktitle}}" class="wall-item-name-link"><span class="wall-item-name{{$item.sparkle}}" id="wall-item-name-{{$item.id}}" >{{$item.name}}</span></a>{{if $item.owner_url}} {{$item.to}} <a href="{{$item.owner_url}}" target="redir" title="{{$item.olinktitle}}" class="wall-item-name-link"><span class="wall-item-name{{$item.osparkle}}" id="wall-item-ownername-{{$item.id}}">{{$item.owner_name}}</span></a> {{$item.vwall}}{{/if}}<br />
-                               <div class="wall-item-ago"  id="wall-item-ago-{{$item.id}}" title="{{$item.localtime}}"><time class="dt-published" datetime="{{$item.localtime}}">{{$item.ago}}</time></div>
+                               <div class="wall-item-ago" id="wall-item-ago-{{$item.id}}" title="{{$item.localtime}}"><time class="dt-published" datetime="{{$item.localtime}}">{{$item.ago}}</time><span class="pinned">{{$item.pinned}}</span></div>
                </div>
                <div class="wall-item-content" id="wall-item-content-{{$item.id}}" >
                        <div class="wall-item-title p-name" id="wall-item-title-{{$item.id}}">{{$item.title}}</div>
@@ -64,7 +64,7 @@
                        {{/if}}
                        </div>
                        {{if $item.has_cats}}
-                       <div class="categorytags"><span>{{$item.txt_cats}} {{foreach $item.categories as $cat}}<span class="p-category">{{$cat.name}}</span>{{if $cat.removeurl}} <a href="{{$cat.removeurl}}" title="{{$remove}}">[{{$remove}}]</a>{{/if}} {{if $cat.last}}{{else}}, {{/if}}{{/foreach}}
+                       <div class="categorytags"><span>{{$item.txt_cats}} {{foreach $item.categories as $cat}}<span class="p-category"><a href="{{$cat.url}}">{{$cat.name}}</a></span>{{if $cat.removeurl}} <a href="{{$cat.removeurl}}" title="{{$remove}}">[{{$remove}}]</a>{{/if}} {{if $cat.last}}{{else}}, {{/if}}{{/foreach}}
                        </div>
                        {{/if}}
 
@@ -90,6 +90,9 @@
                                <a class="editpost icon pencil" href="{{$item.edpost.0}}" title="{{$item.edpost.1}}"></a>
                        {{/if}}
 
+                       {{if $item.pin}}
+                       <a href="#" id="pinned-{{$item.id}}" onclick="dopin({{$item.id}}); return false;" class="pin-item icon {{$item.ispinned}}" title="{{$item.pin.toggle}}"></a>
+                       {{/if}}
                        {{if $item.star}}
                        <a href="#" id="starred-{{$item.id}}" onclick="dostar({{$item.id}}); return false;" class="star-item icon {{$item.isstarred}}" title="{{$item.star.toggle}}"></a>
                        {{/if}}
index 9bad9d3480a97b0400e714fe743d7aa1476a3dae..bb5a25490e8078a8ab4127571ad37aea3d444ffd 100644 (file)
@@ -1162,6 +1162,10 @@ input#dfrn-url {
        margin-left: 10px;
        float: left;
 }
+.pin-item {
+       margin-left: 10px;
+       float: left;
+}
 .star-item {
        margin-left: 10px;
        float: left;
@@ -3201,6 +3205,8 @@ aside input[type='text'] {
 .on { background-position: -144px -32px; }
 
 .off { background-position: 0px -48px; }
+.pinned { background-position: -16px -48px; }
+.unpinned { background-position: -32px -48px; }
 .starred { background-position: -16px -48px; }
 .unstarred { background-position: -32px -48px; }
 .tagged { background-position: -48px -48px; }
index f1c78abc777b291b9c1799005dff2fb6866b577b..b0458d513c432d104e581111ec15fc2f88ded740 100644 (file)
@@ -1800,6 +1800,28 @@ aside .panel-body {
     font-size: 14px;
 }
 
+/* Contact avatar click card */
+.userinfo.click-card {
+       position: relative;
+}
+
+.userinfo.click-card > *:hover:after {
+       content: '⌄';
+       color: #bebebe;
+       font-size: 1em;
+       font-weight: bold;
+       background-color: #ffffff;
+       text-align: center;
+       line-height: 40%;
+       position: absolute;
+       top: 0;
+       left: 0;
+       width: 33%;
+       height: 33%;
+       opacity: .8;
+       border-radius: 0 0 40% 0;
+}
+
 /* The lock symbol popup */
 #panel {
     position: absolute;
diff --git a/view/theme/frio/frameworks/jsmart/jsmart.custom.js b/view/theme/frio/frameworks/jsmart/jsmart.custom.js
deleted file mode 100644 (file)
index 7a611a2..0000000
+++ /dev/null
@@ -1,3456 +0,0 @@
-/*!
- * jSmart Javascript template engine
- * https://github.com/umakantp/jsmart
- *
- * Copyright 2011-2015, Max Miroshnikov <miroshnikov at gmail dot com>
- *                      Umakant Patil <me at umakantpatil dot.com>
- * jSmart is licensed under the GNU Lesser General Public License
- * http://opensource.org/licenses/LGPL-3.0
- */
-
-
-(function() {
-
-    /**
-       merges two or more objects into one
-       shallow copy for objects
-    */
-    function obMerge(ob1, ob2 /*, ...*/)
-    {
-        for (var i=1; i<arguments.length; ++i)
-        {
-           for (var nm in arguments[i])
-           {
-              ob1[nm] = arguments[i][nm];
-           }
-        }
-        return ob1;
-    }
-
-    /**
-       @return  number of own properties in ob
-    */
-    function countProperties(ob)
-    {
-        var count = 0;
-        for (var nm in ob)
-        {
-            if (ob.hasOwnProperty(nm))
-            {
-                count++;
-            }
-        }
-        return count;
-    }
-
-    /**
-       IE workaround
-    */
-    function findInArray(a, v)
-    {
-        if (Array.prototype.indexOf) {
-            return a.indexOf(v);
-        }
-        for (var i=0; i < a.length; ++i)
-        {
-            if (a[i] === v)
-            {
-                return i;
-            }
-        }
-        return -1;
-    }
-
-    function evalString(s)
-    {
-        return s.replace(/\\t/,'\t').replace(/\\n/,'\n').replace(/\\(['"\\])/g,'$1');
-    }
-
-    /**
-       @return  s trimmed and without quotes
-    */
-    function trimQuotes(s)
-    {
-        return evalString(s.replace(/^['"](.*)['"]$/,'$1')).replace(/^\s+|\s+$/g,'');
-    }
-
-    /**
-       finds first {tag} in string
-       @param re string with regular expression or an empty string to find any tag
-       @return  null or s.match(re) result object where
-       [0] - full tag matched with delimiters (and whitespaces at the begin and the end): { tag }
-       [1] - found part from passed re
-       [index] - position of tag starting { in s
-    */
-    function findTag(re,s)
-    {
-        var openCount = 0;
-        var offset = 0;
-        var ldelim = jSmart.prototype.left_delimiter;
-        var rdelim = jSmart.prototype.right_delimiter;
-        var skipInWS = jSmart.prototype.auto_literal;
-
-        var reAny = /^\s*(.+)\s*$/i;
-        var reTag = re ? new RegExp('^\\s*('+re+')\\s*$','i') : reAny;
-
-        for (var i=0; i<s.length; ++i)
-        {
-            if (s.substr(i,ldelim.length) == ldelim)
-            {
-                if (skipInWS && i+1 < s.length && s.substr(i+1,1).match(/\s/))
-                {
-                    continue;
-                }
-                if (!openCount)
-                {
-                    s = s.slice(i);
-                    offset += parseInt(i);
-                    i = 0;
-                }
-                ++openCount;
-            }
-            else if (s.substr(i,rdelim.length) == rdelim)
-            {
-                if (skipInWS && i-1 >= 0 && s.substr(i-1,1).match(/\s/))
-                {
-                    continue;
-                }
-                if (!--openCount)
-                {
-                    var sTag = s.slice(ldelim.length,i).replace(/[\r\n]/g, ' ');
-                    var found = sTag.match(reTag);
-                    if (found)
-                    {
-                        found.index = offset;
-                        found[0] = s.slice(0,i+rdelim.length);
-                        return found;
-                    }
-                }
-                if (openCount < 0) //ignore any number of unmatched right delimiters
-                {
-                    openCount = 0;
-                }
-            }
-        }
-        return null;
-    }
-
-    function findCloseTag(reClose,reOpen,s)
-    {
-        var sInner = '';
-        var closeTag = null;
-        var openTag = null;
-        var findIndex = 0;
-
-        do
-        {
-            if (closeTag)
-            {
-                findIndex += closeTag[0].length;
-            }
-            closeTag = findTag(reClose,s);
-            if (!closeTag)
-            {
-                throw new Error('Unclosed {'+reOpen+'}');
-            }
-            sInner += s.slice(0,closeTag.index);
-            findIndex += closeTag.index;
-            s = s.slice(closeTag.index+closeTag[0].length);
-
-            openTag = findTag(reOpen,sInner);
-            if (openTag)
-            {
-                sInner = sInner.slice(openTag.index+openTag[0].length);
-            }
-        }
-        while (openTag);
-
-        closeTag.index = findIndex;
-        return closeTag;
-    }
-
-    function findElseTag(reOpen, reClose, reElse, s)
-    {
-        var offset = 0;
-        for (var elseTag=findTag(reElse,s); elseTag; elseTag=findTag(reElse,s))
-        {
-            var openTag = findTag(reOpen,s);
-            if (!openTag || openTag.index > elseTag.index)
-            {
-                elseTag.index += offset;
-                return elseTag;
-            }
-            else
-            {
-                s = s.slice(openTag.index+openTag[0].length);
-                offset += openTag.index+openTag[0].length;
-                var closeTag = findCloseTag(reClose,reOpen,s);
-                s = s.slice(closeTag.index + closeTag[0].length);
-                offset += closeTag.index + closeTag[0].length;
-            }
-        }
-        return null;
-    }
-
-    function execute(code, data)
-    {
-        if (typeof(code) == 'string')
-        {
-            with ({'__code':code})
-            {
-                with (modifiers)
-                {
-                    with (data)
-                    {
-                        try {
-                            return eval(__code);
-                        }
-                        catch(e)
-                        {
-                            throw new Error(e.message + ' in \n' + code);
-                        }
-                    }
-                }
-            }
-        }
-        return code;
-    }
-
-    /**
-     * Execute function when we have a object.
-     *
-     * @param object obj  Object of the function to be called.
-     * @param array  args Arguments to pass to a function.
-     *
-     * @return
-     * @throws Error If function obj does not exists.
-     */
-    function executeByFuncObject(obj, args) {
-        try {
-            return obj.apply(this, args);
-        } catch (e) {
-            throw new Error(e.message);
-        }
-    }
-
-    function assignVar(nm, val, data)
-    {
-        if (nm.match(/\[\]$/))  //ar[] =
-        {
-            data[ nm.replace(/\[\]$/,'') ].push(val);
-        }
-        else
-        {
-            data[nm] = val;
-        }
-    }
-
-    var buildInFunctions =
-        {
-            expression:
-            {
-                parse: function(s, tree)
-                {
-                    var e = parseExpression(s);
-
-                    tree.push({
-                        type: 'build-in',
-                        name: 'expression',
-                        expression: e.tree,
-                        params: parseParams(s.slice(e.value.length).replace(/^\s+|\s+$/g,''))
-                    });
-
-                    return e.tree;
-
-                },
-                process: function(node, data)
-                {
-                    var params = getActualParamValues(node.params, data);
-                    var res = process([node.expression],data);
-
-                    if (findInArray(params, 'nofilter') < 0)
-                    {
-                        for (var i=0; i<default_modifiers.length; ++i)
-                        {
-                            var m = default_modifiers[i];
-                            m.params.__parsed[0] = {type:'text', data:res};
-                            res = process([m],data);
-                        }
-                        if (escape_html)
-                        {
-                            res = modifiers.escape(res);
-                        }
-                        res = applyFilters(varFilters,res);
-
-                        if (tpl_modifiers.length) {
-                            __t = function(){ return res; }
-                            res = process(tpl_modifiers,data);
-                        }
-                    }
-                    return res;
-                }
-            },
-
-            operator:
-            {
-                process: function(node, data)
-                {
-                    var params = getActualParamValues(node.params, data);
-                    var arg1 = params[0];
-
-                    if (node.optype == 'binary')
-                    {
-                        var arg2 = params[1];
-                        if (node.op == '=')
-                        {
-                            getVarValue(node.params.__parsed[0], data, arg2);
-                            return '';
-                        }
-                        else if (node.op.match(/(\+=|-=|\*=|\/=|%=)/))
-                        {
-                            arg1 = getVarValue(node.params.__parsed[0], data);
-                            switch (node.op)
-                            {
-                            case '+=': arg1+=arg2; break;
-                            case '-=': arg1-=arg2; break;
-                            case '*=': arg1*=arg2; break;
-                            case '/=': arg1/=arg2; break;
-                            case '%=': arg1%=arg2; break;
-                            }
-                            return getVarValue(node.params.__parsed[0], data, arg1);
-                        }
-                        else if (node.op.match(/div/))
-                        {
-                            return (node.op!='div')^(arg1%arg2==0);
-                        }
-                        else if (node.op.match(/even/))
-                        {
-                            return (node.op!='even')^((arg1/arg2)%2==0);
-                        }
-                        else if (node.op.match(/xor/))
-                        {
-                            return (arg1||arg2) && !(arg1&&arg2);
-                        }
-
-                        switch (node.op)
-                        {
-                        case '==': return arg1==arg2;
-                        case '!=': return arg1!=arg2;
-                        case '+':  return Number(arg1)+Number(arg2);
-                        case '-':  return Number(arg1)-Number(arg2);
-                        case '*':  return Number(arg1)*Number(arg2);
-                        case '/':  return Number(arg1)/Number(arg2);
-                        case '%':  return Number(arg1)%Number(arg2);
-                        case '&&': return arg1&&arg2;
-                        case '||': return arg1||arg2;
-                        case '<':  return arg1<arg2;
-                        case '<=': return arg1<=arg2;
-                        case '>':  return arg1>arg2;
-                        case '>=': return arg1>=arg2;
-                        case '===': return arg1===arg2;
-                        case '!==': return arg1!==arg2;
-                        }
-                    }
-                    else if (node.op == '!')
-                    {
-                        return !arg1;
-                    }
-                    else
-                    {
-                        var isVar = node.params.__parsed[0].type == 'var';
-                        if (isVar)
-                        {
-                            arg1 = getVarValue(node.params.__parsed[0], data);
-                        }
-                        var v = arg1;
-                        if (node.optype == 'pre-unary')
-                        {
-                            switch (node.op)
-                            {
-                            case '-':  v=-arg1;  break;
-                            case '++': v=++arg1; break;
-                            case '--': v=--arg1; break;
-                            }
-                            if (isVar)
-                            {
-                                getVarValue(node.params.__parsed[0], data, arg1);
-                            }
-                        }
-                        else
-                        {
-                            switch (node.op)
-                            {
-                            case '++': arg1++; break;
-                            case '--': arg1--; break;
-                            }
-                            getVarValue(node.params.__parsed[0], data, arg1);
-                        }
-                        return v;
-                    }
-                }
-            },
-
-            section:
-            {
-                type: 'block',
-                parse: function(params, tree, content)
-                {
-                    var subTree = [];
-                    var subTreeElse = [];
-                    tree.push({
-                        type: 'build-in',
-                        name: 'section',
-                        params: params,
-                        subTree: subTree,
-                        subTreeElse: subTreeElse
-                    });
-
-                    var findElse = findElseTag('section [^}]+', '\/section', 'sectionelse', content);
-                    if (findElse)
-                    {
-                        parse(content.slice(0,findElse.index),subTree);
-                        parse(content.slice(findElse.index+findElse[0].length).replace(/^[\r\n]/,''), subTreeElse);
-                    }
-                    else
-                    {
-                        parse(content, subTree);
-                    }
-                },
-
-                process: function(node, data)
-                {
-                    var params = getActualParamValues(node.params, data);
-
-                    var props = {};
-                    data.smarty.section[params.__get('name',null,0)] = props;
-
-                    var show = params.__get('show',true);
-                    props.show = show;
-                    if (!show)
-                    {
-                        return process(node.subTreeElse, data);
-                    }
-
-                    var from = parseInt(params.__get('start',0));
-                    var to = (params.loop instanceof Object) ? countProperties(params.loop) : isNaN(params.loop) ? 0 : parseInt(params.loop);
-                    var step = parseInt(params.__get('step',1));
-                    var max = parseInt(params.__get('max'));
-                    if (isNaN(max))
-                    {
-                        max = Number.MAX_VALUE;
-                    }
-
-                    if (from < 0)
-                    {
-                        from += to;
-                        if (from < 0)
-                        {
-                            from = 0;
-                        }
-                    }
-                    else if (from >= to)
-                    {
-                        from = to ? to-1 : 0;
-                    }
-
-                    var count = 0;
-                    var loop = 0;
-                    var i = from;
-                    for (; i>=0 && i<to && count<max; i+=step,++count)
-                    {
-                        loop = i;
-                    }
-                    props.total = count;
-                    props.loop = count;  //? - because it is so in Smarty
-
-                    count = 0;
-                    var s = '';
-                    for (i=from; i>=0 && i<to && count<max; i+=step,++count)
-                    {
-                        if (data.smarty['break'])
-                        {
-                            break;
-                        }
-
-                        props.first = (i==from);
-                        props.last = ((i+step)<0 || (i+step)>=to);
-                        props.index = i;
-                        props.index_prev = i-step;
-                        props.index_next = i+step;
-                        props.iteration = props.rownum = count+1;
-
-                        s += process(node.subTree, data);
-                        data.smarty['continue'] = false;
-                    }
-                    data.smarty['break'] = false;
-
-                    if (count)
-                    {
-                        return s;
-                    }
-                    return process(node.subTreeElse, data);
-                }
-            },
-
-            setfilter:
-            {
-                type: 'block',
-                parseParams: function(paramStr)
-                {
-                    return [parseExpression('__t()|' + paramStr).tree];
-                },
-
-                parse: function(params, tree, content)
-                {
-                    tree.push({
-                        type: 'build-in',
-                        name: 'setfilter',
-                        params: params,
-                        subTree: parse(content,[])
-                    });
-                },
-
-                process: function(node, data)
-                {
-                    tpl_modifiers = node.params;
-                    var s = process(node.subTree, data);
-                    tpl_modifiers = [];
-                    return s;
-                }
-            },
-
-            'for':
-            {
-                type: 'block',
-                parseParams: function(paramStr)
-                {
-                    var res = paramStr.match(/^\s*\$(\w+)\s*=\s*([^\s]+)\s*to\s*([^\s]+)\s*(?:step\s*([^\s]+))?\s*(.*)$/);
-                    if (!res)
-                    {
-                        throw new Error('Invalid {for} parameters: '+paramStr);
-                    }
-                    return parseParams("varName='"+res[1]+"' from="+res[2]+" to="+res[3]+" step="+(res[4]?res[4]:'1')+" "+res[5]);
-                },
-
-                parse: function(params, tree, content)
-                {
-                    var subTree = [];
-                    var subTreeElse = [];
-                    tree.push({
-                        type: 'build-in',
-                        name: 'for',
-                        params: params,
-                        subTree: subTree,
-                        subTreeElse: subTreeElse
-                    });
-
-                    var findElse = findElseTag('for\\s[^}]+', '\/for', 'forelse', content);
-                    if (findElse)
-                    {
-                        parse(content.slice(0,findElse.index),subTree);
-                        parse(content.slice(findElse.index+findElse[0].length), subTreeElse);
-                    }
-                    else
-                    {
-                        parse(content, subTree);
-                    }
-                },
-
-                process: function(node, data)
-                {
-                    var params = getActualParamValues(node.params, data);
-                    var from = parseInt(params.__get('from'));
-                    var to = parseInt(params.__get('to'));
-                    var step = parseInt(params.__get('step'));
-                    if (isNaN(step))
-                    {
-                        step = 1;
-                    }
-                    var max = parseInt(params.__get('max'));
-                    if (isNaN(max))
-                    {
-                        max = Number.MAX_VALUE;
-                    }
-
-                    var count = 0;
-                    var s = '';
-                    var total = Math.min( Math.ceil( ((step > 0 ? to-from : from-to)+1) / Math.abs(step)  ), max);
-
-                    for (var i=parseInt(params.from); count<total; i+=step,++count)
-                    {
-                        if (data.smarty['break'])
-                        {
-                            break;
-                        }
-                        data[params.varName] = i;
-                        s += process(node.subTree, data);
-                        data.smarty['continue'] = false;
-                    }
-                    data.smarty['break'] = false;
-
-                    if (!count)
-                    {
-                        s = process(node.subTreeElse, data);
-                    }
-                    return s;
-                }
-            },
-
-            'if':
-            {
-                type: 'block',
-                parse: function(params, tree, content)
-                {
-                    var subTreeIf = [];
-                    var subTreeElse = [];
-                    tree.push({
-                        type: 'build-in',
-                        name: 'if',
-                        params: params,
-                        subTreeIf: subTreeIf,
-                        subTreeElse: subTreeElse
-                    });
-
-                    var findElse = findElseTag('if\\s+[^}]+', '\/if', 'else[^}]*', content);
-                    if (findElse)
-                    {
-                        parse(content.slice(0,findElse.index),subTreeIf);
-
-                        content = content.slice(findElse.index+findElse[0].length);
-                        var findElseIf = findElse[1].match(/^else\s*if(.*)/);
-                        if (findElseIf)
-                        {
-                            buildInFunctions['if'].parse(parseParams(findElseIf[1]), subTreeElse, content.replace(/^\n/,''));
-                        }
-                        else
-                        {
-                            parse(content.replace(/^\n/,''), subTreeElse);
-                        }
-                    }
-                    else
-                    {
-                        parse(content, subTreeIf);
-                    }
-                },
-
-                process: function(node, data) {
-                    var value = getActualParamValues(node.params,data)[0];
-                    // Zero length arrays or empty associative arrays are false in PHP.
-                    if (value && !((value instanceof Array && value.length == 0)
-                        || (typeof value == 'object' && isEmptyObject(value)))
-                    ) {
-                        return process(node.subTreeIf, data);
-                    } else {
-                        return process(node.subTreeElse, data);
-                    }
-                }
-            },
-
-            foreach:
-            {
-                type: 'block',
-                parseParams: function(paramStr)
-                {
-                    var params = {};
-                    var res = paramStr.match(/^\s*([$].+)\s*as\s*[$](\w+)\s*(=>\s*[$](\w+))?\s*$/i);
-                    if (res) //Smarty 3.x syntax => Smarty 2.x syntax
-                    {
-                        paramStr = 'from='+res[1] + ' item='+(res[4]||res[2]);
-                        if (res[4])
-                        {
-                            paramStr += ' key='+res[2];
-                        }
-                    }
-                    return parseParams(paramStr);
-                },
-
-                parse: function(params, tree, content)
-                {
-                    var subTree = [];
-                    var subTreeElse = [];
-                    tree.push({
-                        type: 'build-in',
-                        name: 'foreach',
-                        params: params,
-                        subTree: subTree,
-                        subTreeElse: subTreeElse
-                    });
-
-                    var findElse = findElseTag('foreach\\s[^}]+', '\/foreach', 'foreachelse', content);
-                    if (findElse)
-                    {
-                        parse(content.slice(0,findElse.index),subTree);
-                        parse(content.slice(findElse.index+findElse[0].length).replace(/^[\r\n]/,''), subTreeElse);
-                    }
-                    else
-                    {
-                        parse(content, subTree);
-                    }
-                },
-
-                process: function(node, data)
-                {
-                    var params = getActualParamValues(node.params, data);
-                    var a = params.from;
-                    if (typeof a == 'undefined')
-                    {
-                        a = [];
-                    }
-                    if (typeof a != 'object')
-                    {
-                        a = [a];
-                    }
-
-                    var total = countProperties(a);
-
-                    data[params.item+'__total'] = total;
-                    if ('name' in params)
-                    {
-                        data.smarty.foreach[params.name] = {};
-                        data.smarty.foreach[params.name].total = total;
-                    }
-
-                    var s = '';
-                    var i=0;
-                    for (var key in a)
-                    {
-                        if (!a.hasOwnProperty(key))
-                        {
-                            continue;
-                        }
-
-                        if (data.smarty['break'])
-                        {
-                            break;
-                        }
-
-                        data[params.item+'__key'] = isNaN(key) ? key : parseInt(key);
-                        if ('key' in params)
-                        {
-                            data[params.key] = data[params.item+'__key'];
-                        }
-                        data[params.item] = a[key];
-                        data[params.item+'__index'] = parseInt(i);
-                        data[params.item+'__iteration'] = parseInt(i+1);
-                        data[params.item+'__first'] = (i===0);
-                        data[params.item+'__last'] = (i==total-1);
-
-                        if ('name' in params)
-                        {
-                            data.smarty.foreach[params.name].index = parseInt(i);
-                            data.smarty.foreach[params.name].iteration = parseInt(i+1);
-                            data.smarty.foreach[params.name].first = (i===0) ? 1 : '';
-                            data.smarty.foreach[params.name].last = (i==total-1) ? 1 : '';
-                        }
-
-                        ++i;
-
-                        s += process(node.subTree, data);
-                        data.smarty['continue'] = false;
-                    }
-                    data.smarty['break'] = false;
-
-                    data[params.item+'__show'] = (i>0);
-                    if (params.name)
-                    {
-                        data.smarty.foreach[params.name].show = (i>0) ? 1 : '';
-                    }
-                    if (i>0)
-                    {
-                        return s;
-                    }
-                    return process(node.subTreeElse, data);
-                }
-            },
-
-            'function':
-            {
-                type: 'block',
-                parse: function(params, tree, content)
-                {
-                    var subTree = [];
-                    plugins[trimQuotes(params.name?params.name:params[0])] =
-                        {
-                            type: 'function',
-                            subTree: subTree,
-                            defautParams: params,
-                            process: function(params, data)
-                            {
-                                var defaults = getActualParamValues(this.defautParams,data);
-                                delete defaults.name;
-                                return process(this.subTree, obMerge({},data,defaults,params));
-                            }
-                        };
-                    parse(content, subTree);
-                }
-            },
-
-            php:
-            {
-                type: 'block',
-                parse: function(params, tree, content) {}
-            },
-
-            'extends':
-            {
-                type: 'function',
-                parse: function(params, tree)
-                {
-                    tree.splice(0,tree.length);
-                    getTemplate(trimQuotes(params.file?params.file:params[0]),tree);
-                }
-            },
-
-            block:
-            {
-                type: 'block',
-                parse: function(params, tree, content)
-                {
-                    tree.push({
-                        type: 'build-in',
-                        name: 'block',
-                        params: params
-                    });
-                    params.append = findInArray(params,'append') >= 0;
-                    params.prepend = findInArray(params,'prepend') >= 0;
-                    params.hide = findInArray(params,'hide') >= 0;
-                    params.hasChild = params.hasParent = false;
-
-                    onParseVar = function(nm)
-                    {
-                        if (nm.match(/^\s*[$]smarty.block.child\s*$/))
-                        {
-                            params.hasChild = true;
-                        }
-                        if (nm.match(/^\s*[$]smarty.block.parent\s*$/))
-                        {
-                            params.hasParent = true;
-                        }
-                    }
-                    var tree = parse(content, []);
-                    onParseVar = function(nm) {}
-
-                    var blockName = trimQuotes(params.name?params.name:params[0]);
-                    if (!(blockName in blocks))
-                    {
-                        blocks[blockName] = [];
-                    }
-                    blocks[blockName].push({tree:tree, params:params});
-                },
-
-                process: function(node, data)
-                {
-                    data.smarty.block.parent = data.smarty.block.child = '';
-                    var blockName = trimQuotes(node.params.name?node.params.name:node.params[0]);
-                    this.processBlocks(blocks[blockName], blocks[blockName].length-1, data);
-                    return data.smarty.block.child;
-                },
-
-                processBlocks: function(blockAncestry, i, data)
-                {
-                    if (!i && blockAncestry[i].params.hide) {
-                        data.smarty.block.child = '';
-                        return;
-                    }
-                    var append = true;
-                    var prepend = false;
-                    for (; i>=0; --i)
-                    {
-                        if (blockAncestry[i].params.hasParent)
-                        {
-                            var tmpChild = data.smarty.block.child;
-                            data.smarty.block.child = '';
-                            this.processBlocks(blockAncestry, i-1, data);
-                            data.smarty.block.parent = data.smarty.block.child;
-                            data.smarty.block.child = tmpChild;
-                        }
-
-                        var tmpChild = data.smarty.block.child;
-                        var s = process(blockAncestry[i].tree, data);
-                        data.smarty.block.child = tmpChild;
-
-                        if (blockAncestry[i].params.hasChild)
-                        {
-                            data.smarty.block.child = s;
-                        }
-                        else if (append)
-                        {
-                            data.smarty.block.child = s + data.smarty.block.child;
-                        }
-                        else if (prepend)
-                        {
-                            data.smarty.block.child += s;
-                        }
-                        append = blockAncestry[i].params.append;
-                        prepend = blockAncestry[i].params.prepend;
-                    }
-                }
-            },
-
-            strip:
-            {
-                type: 'block',
-                parse: function(params, tree, content)
-                {
-                    parse(content.replace(/[ \t]*[\r\n]+[ \t]*/g, ''), tree);
-                }
-            },
-
-            literal:
-            {
-                type: 'block',
-                parse: function(params, tree, content)
-                {
-                    parseText(content, tree);
-                }
-            },
-
-            ldelim:
-            {
-                type: 'function',
-                parse: function(params, tree)
-                {
-                    parseText(jSmart.prototype.left_delimiter, tree);
-                }
-            },
-
-            rdelim:
-            {
-                type: 'function',
-                parse: function(params, tree)
-                {
-                    parseText(jSmart.prototype.right_delimiter, tree);
-                }
-            },
-
-            'while':
-            {
-                type: 'block',
-                parse: function(params, tree, content)
-                {
-                    tree.push({
-                        type: 'build-in',
-                        name: 'while',
-                        params: params,
-                        subTree: parse(content, [])
-                    });
-                },
-
-                process: function(node, data)
-                {
-                    var s = '';
-                    while (getActualParamValues(node.params,data)[0])
-                    {
-                        if (data.smarty['break'])
-                        {
-                            break;
-                        }
-                        s += process(node.subTree, data);
-                        data.smarty['continue'] = false;
-                    }
-                    data.smarty['break'] = false;
-                    return s;
-                }
-            }
-        };
-
-    var plugins = {};
-    var modifiers = {};
-    var files = {};
-    var blocks = null;
-    var scripts = null;
-    var tpl_modifiers = [];
-
-    function parse(s, tree)
-    {
-        for (var openTag=findTag('',s); openTag; openTag=findTag('',s))
-        {
-            if (openTag.index)
-            {
-                parseText(s.slice(0,openTag.index),tree);
-            }
-            s = s.slice(openTag.index + openTag[0].length);
-
-            var res = openTag[1].match(/^\s*(\w+)(.*)$/);
-            if (res)         //function
-            {
-                var nm = res[1];
-                var paramStr = (res.length>2) ? res[2].replace(/^\s+|\s+$/g,'') : '';
-
-                if (nm in buildInFunctions)
-                {
-                    var buildIn = buildInFunctions[nm];
-                    var params = ('parseParams' in buildIn ? buildIn.parseParams : parseParams)(paramStr);
-                    if (buildIn.type == 'block')
-                    {
-                        s = s.replace(/^\n/,'');  //remove new line after block open tag (like in Smarty)
-                        var closeTag = findCloseTag('\/'+nm, nm+' +[^}]*', s);
-                        buildIn.parse(params, tree, s.slice(0,closeTag.index));
-                        s = s.slice(closeTag.index+closeTag[0].length);
-                    }
-                    else
-                    {
-                        buildIn.parse(params, tree);
-                        if (nm == 'extends')
-                        {
-                            tree = []; //throw away further parsing except for {block}
-                        }
-                    }
-                    s = s.replace(/^\n/,'');
-                }
-                else if (nm in plugins)
-                {
-                    var plugin = plugins[nm];
-                    if (plugin.type == 'block')
-                    {
-                        var closeTag = findCloseTag('\/'+nm, nm+' +[^}]*', s);
-                        parsePluginBlock(nm, parseParams(paramStr), tree, s.slice(0,closeTag.index));
-                        s = s.slice(closeTag.index+closeTag[0].length);
-                    }
-                    else if (plugin.type == 'function')
-                    {
-                        parsePluginFunc(nm, parseParams(paramStr), tree);
-                    }
-                    if (nm=='append' || nm=='assign' || nm=='capture' || nm=='eval' || nm=='include')
-                    {
-                        s = s.replace(/^\n/,'');
-                    }
-                }
-                else   //variable
-                {
-                    buildInFunctions.expression.parse(openTag[1],tree);
-                }
-            }
-            else         //variable
-            {
-                var node = buildInFunctions.expression.parse(openTag[1],tree);
-                if (node.type=='build-in' && node.name=='operator' && node.op == '=')
-                {
-                    s = s.replace(/^\n/,'');
-                }
-            }
-        }
-        if (s)
-        {
-            parseText(s, tree);
-        }
-        return tree;
-    }
-
-    function parseText(text, tree)
-    {
-        if (parseText.parseEmbeddedVars)
-        {
-            var re = /([$][\w@]+)|`([^`]*)`/;
-            for (var found=re.exec(text); found; found=re.exec(text))
-            {
-                tree.push({type: 'text', data: text.slice(0,found.index)});
-                tree.push( parseExpression(found[1] ? found[1] : found[2]).tree );
-                text = text.slice(found.index + found[0].length);
-            }
-        }
-        tree.push({type: 'text', data: text});
-        return tree;
-    }
-
-    function parseFunc(name, params, tree)
-    {
-        params.__parsed.name = parseText(name,[])[0];
-        tree.push({
-            type: 'plugin',
-            name: '__func',
-            params: params
-        });
-        return tree;
-    }
-
-    function parseOperator(op, type, precedence, tree)
-    {
-        tree.push({
-            type: 'build-in',
-            name: 'operator',
-            op: op,
-            optype: type,
-            precedence: precedence,
-            params: {}
-        });
-    }
-
-    function parseVar(s, e, nm)
-    {
-        var rootName = e.token;
-        var parts = [{type:'text', data:nm.replace(/^(\w+)@(key|index|iteration|first|last|show|total)/gi, "$1__$2")}];
-
-        var re = /^(?:\.|\s*->\s*|\[\s*)/;
-        for (var op=s.match(re); op; op=s.match(re))
-        {
-            e.token += op[0];
-            s = s.slice(op[0].length);
-
-            var eProp = {value:'', tree:[]};
-            if (op[0].match(/\[/))
-            {
-                eProp = parseExpression(s);
-                if (eProp)
-                {
-                    e.token += eProp.value;
-                    parts.push( eProp.tree );
-                    s = s.slice(eProp.value.length);
-                }
-
-                var closeOp = s.match(/\s*\]/);
-                if (closeOp)
-                {
-                    e.token += closeOp[0];
-                    s = s.slice(closeOp[0].length);
-                }
-            }
-            else
-            {
-                var parseMod = parseModifiers.stop;
-                parseModifiers.stop = true;
-                if (lookUp(s,eProp))
-                {
-                    e.token += eProp.value;
-                    var part = eProp.tree[0];
-                    if (part.type == 'plugin' && part.name == '__func')
-                    {
-                        part.hasOwner = true;
-                    }
-                    parts.push( part );
-                    s = s.slice(eProp.value.length);
-                }
-                else
-                {
-                    eProp = false;
-                }
-                parseModifiers.stop = parseMod;
-            }
-
-            if (!eProp)
-            {
-                parts.push({type:'text', data:''});
-            }
-        }
-
-        e.tree.push({type: 'var', parts: parts});
-
-        e.value += e.token.substr(rootName.length);
-
-        onParseVar(e.token);
-
-        return s;
-    }
-
-    function onParseVar(nm)  {}
-
-
-    var tokens =
-        [
-            {
-                re: /^\$([\w@]+)/,   //var
-                parse: function(e, s)
-                {
-                    parseModifiers(parseVar(s, e, RegExp.$1), e);
-                }
-            },
-            {
-                re: /^(true|false)/i,  //bool
-                parse: function(e, s)
-                {
-                    parseText(e.token.match(/true/i) ? '1' : '', e.tree);
-                }
-            },
-            {
-                re: /^'([^'\\]*(?:\\.[^'\\]*)*)'/, //single quotes
-                parse: function(e, s)
-                {
-                    parseText(evalString(RegExp.$1), e.tree);
-                    parseModifiers(s, e);
-                }
-            },
-            {
-                re: /^"([^"\\]*(?:\\.[^"\\]*)*)"/,  //double quotes
-                parse: function(e, s)
-                {
-                    var v = evalString(RegExp.$1);
-                    var isVar = v.match(tokens[0].re);
-                    if (isVar)
-                    {
-                        var eVar = {token:isVar[0], tree:[]};
-                        parseVar(v, eVar, isVar[1]);
-                        if (eVar.token.length == v.length)
-                        {
-                            e.tree.push( eVar.tree[0] );
-                            return;
-                        }
-                    }
-                    parseText.parseEmbeddedVars = true;
-                    e.tree.push({
-                        type: 'plugin',
-                        name: '__quoted',
-                        params: {__parsed: parse(v,[])}
-                    });
-                    parseText.parseEmbeddedVars = false;
-                    parseModifiers(s, e);
-                }
-            },
-            {
-                re: /^(\w+)\s*[(]([)]?)/,  //func()
-                parse: function(e, s)
-                {
-                    var fnm = RegExp.$1;
-                    var noArgs = RegExp.$2;
-                    var params = parseParams(noArgs?'':s,/^\s*,\s*/);
-                    parseFunc(fnm, params, e.tree);
-                    e.value += params.toString();
-                    parseModifiers(s.slice(params.toString().length), e);
-                }
-            },
-            {
-                re: /^\s*\(\s*/,  //expression in parentheses
-                parse: function(e, s)
-                {
-                    var parens = [];
-                    e.tree.push(parens);
-                    parens.parent = e.tree;
-                    e.tree = parens;
-                }
-            },
-            {
-                re: /^\s*\)\s*/,
-                parse: function(e, s)
-                {
-                    if (e.tree.parent) //it may be the end of func() or (expr)
-                    {
-                        e.tree = e.tree.parent;
-                    }
-                }
-            },
-            {
-                re: /^\s*(\+\+|--)\s*/,
-                parse: function(e, s)
-                {
-                    if (e.tree.length && e.tree[e.tree.length-1].type == 'var')
-                    {
-                        parseOperator(RegExp.$1, 'post-unary', 1, e.tree);
-                    }
-                    else
-                    {
-                        parseOperator(RegExp.$1, 'pre-unary', 1, e.tree);
-                    }
-                }
-            },
-            {
-                re: /^\s*(===|!==|==|!=)\s*/,
-                parse: function(e, s)
-                {
-                    parseOperator(RegExp.$1, 'binary', 6, e.tree);
-                }
-            },
-            {
-                re: /^\s+(eq|ne|neq)\s+/i,
-                parse: function(e, s)
-                {
-                    var op = RegExp.$1.replace(/ne(q)?/,'!=').replace(/eq/,'==');
-                    parseOperator(op, 'binary', 6, e.tree);
-                }
-            },
-            {
-                re: /^\s*!\s*/,
-                parse: function(e, s)
-                {
-                    parseOperator('!', 'pre-unary', 2, e.tree);
-                }
-            },
-            {
-                re: /^\s+not\s+/i,
-                parse: function(e, s)
-                {
-                    parseOperator('!', 'pre-unary', 2, e.tree);
-                }
-            },
-            {
-                re: /^\s*(=|\+=|-=|\*=|\/=|%=)\s*/,
-                parse: function(e, s)
-                {
-                    parseOperator(RegExp.$1, 'binary', 10, e.tree);
-                }
-            },
-            {
-                re: /^\s*(\*|\/|%)\s*/,
-                parse: function(e, s)
-                {
-                    parseOperator(RegExp.$1, 'binary', 3, e.tree);
-                }
-            },
-            {
-                re: /^\s+mod\s+/i,
-                parse: function(e, s)
-                {
-                    parseOperator('%', 'binary', 3, e.tree);
-                }
-            },
-            {
-                re: /^\s*(\+|-)\s*/,
-                parse: function(e, s)
-                {
-                    if (!e.tree.length || e.tree[e.tree.length-1].name == 'operator')
-                    {
-                        parseOperator(RegExp.$1, 'pre-unary', 4, e.tree);
-                    }
-                    else
-                    {
-                        parseOperator(RegExp.$1, 'binary', 4, e.tree);
-                    }
-                }
-            },
-            {
-                re: /^\s*(<=|>=|<>|<|>)\s*/,
-                parse: function(e, s)
-                {
-                    parseOperator(RegExp.$1.replace(/<>/,'!='), 'binary', 5, e.tree);
-                }
-            },
-            {
-                re: /^\s+(lt|lte|le|gt|gte|ge)\s+/i,
-                parse: function(e, s)
-                {
-                    var op = RegExp.$1.replace(/lt/,'<').replace(/l(t)?e/,'<=').replace(/gt/,'>').replace(/g(t)?e/,'>=');
-                    parseOperator(op, 'binary', 5, e.tree);
-                }
-            },
-            {
-                re: /^\s+(is\s+(not\s+)?div\s+by)\s+/i,
-                parse: function(e, s)
-                {
-                    parseOperator(RegExp.$2?'div_not':'div', 'binary', 7, e.tree);
-                }
-            },
-            {
-                re: /^\s+is\s+(not\s+)?(even|odd)(\s+by\s+)?\s*/i,
-                parse: function(e, s)
-                {
-                    var op = RegExp.$1 ? ((RegExp.$2=='odd')?'even':'even_not') : ((RegExp.$2=='odd')?'even_not':'even');
-                    parseOperator(op, 'binary', 7, e.tree);
-                    if (!RegExp.$3)
-                    {
-                        parseText('1', e.tree);
-                    }
-                }
-            },
-            {
-                re: /^\s*(&&)\s*/,
-                parse: function(e, s)
-                {
-                    parseOperator(RegExp.$1, 'binary', 8, e.tree);
-                }
-            },
-            {
-                re: /^\s*(\|\|)\s*/,
-                parse: function(e, s)
-                {
-                    parseOperator(RegExp.$1, 'binary', 9, e.tree);
-                }
-            },
-            {
-                re: /^\s+and\s+/i,
-                parse: function(e, s)
-                {
-                    parseOperator('&&', 'binary', 11, e.tree);
-                }
-            },
-            {
-                re: /^\s+xor\s+/i,
-                parse: function(e, s)
-                {
-                    parseOperator('xor', 'binary', 12, e.tree);
-                }
-            },
-            {
-                re: /^\s+or\s+/i,
-                parse: function(e, s)
-                {
-                    parseOperator('||', 'binary', 13, e.tree);
-                }
-            },
-            {
-                re: /^#(\w+)#/,  //config variable
-                parse: function(e, s)
-                {
-                    var eVar = {token:'$smarty',tree:[]};
-                    parseVar('.config.'+RegExp.$1, eVar, 'smarty');
-                    e.tree.push( eVar.tree[0] );
-                    parseModifiers(s, e);
-                }
-            },
-            {
-                re: /^\s*\[\s*/,   //array
-                parse: function(e, s)
-                {
-                    var params = parseParams(s, /^\s*,\s*/, /^('[^'\\]*(?:\\.[^'\\]*)*'|"[^"\\]*(?:\\.[^"\\]*)*"|\w+)\s*=>\s*/);
-                    parsePluginFunc('__array',params,e.tree);
-                    e.value += params.toString();
-                    var paren = s.slice(params.toString().length).match(/\s*\]/);
-                    if (paren)
-                    {
-                        e.value += paren[0];
-                    }
-                }
-            },
-            {
-                re: /^[\d.]+/, //number
-                parse: function(e, s)
-                {
-                    if (e.token.indexOf('.') > -1) {
-                        e.token = parseFloat(e.token);
-                    } else {
-                        e.token = parseInt(e.token, 10);
-                    }
-                    parseText(e.token, e.tree);
-                    parseModifiers(s, e);
-                }
-            },
-            {
-                re: /^\w+/, //static
-                parse: function(e, s)
-                {
-                    parseText(e.token, e.tree);
-                    parseModifiers(s, e);
-                }
-            }
-        ];
-
-    function parseModifiers(s, e)
-    {
-        if (parseModifiers.stop)
-        {
-            return;
-        }
-
-        var modifier = s.match(/^\|(\w+)/);
-        if (!modifier)
-        {
-            return;
-        }
-
-        e.value += modifier[0];
-
-        var fnm = modifier[1]=='default' ? 'defaultValue' : modifier[1];
-        s = s.slice(modifier[0].length).replace(/^\s+/,'');
-
-        parseModifiers.stop = true;
-        var params = [];
-        for (var colon=s.match(/^\s*:\s*/); colon; colon=s.match(/^\s*:\s*/))
-        {
-            e.value += s.slice(0,colon[0].length);
-            s = s.slice(colon[0].length);
-
-            var param = {value:'', tree:[]};
-            if (lookUp(s, param))
-            {
-                e.value += param.value;
-                params.push(param.tree[0]);
-                s = s.slice(param.value.length);
-            }
-            else
-            {
-                parseText('',params);
-            }
-        }
-        parseModifiers.stop = false;
-
-        params.unshift(e.tree.pop());  //modifiers have the highest priority
-        e.tree.push(parseFunc(fnm,{__parsed:params},[])[0]);
-
-        parseModifiers(s, e);  //modifiers can be combined
-    }
-
-    function lookUp(s,e)
-    {
-        if (!s)
-        {
-            return false;
-        }
-
-        if (s.substr(0,jSmart.prototype.left_delimiter.length)==jSmart.prototype.left_delimiter)
-        {
-            var tag = findTag('',s);
-            if (tag)
-            {
-                e.token = tag[0];
-                e.value += tag[0];
-                parse(tag[0], e.tree);
-                parseModifiers(s.slice(e.value.length), e);
-                return true;
-            }
-        }
-
-        for (var i=0; i<tokens.length; ++i)
-        {
-            if (s.match(tokens[i].re))
-            {
-                e.token = RegExp.lastMatch;
-                e.value += RegExp.lastMatch;
-                tokens[i].parse(e, s.slice(e.token.length));
-                return true;
-            }
-        }
-        return false;
-    }
-
-    function bundleOp(i, tree, precedence)
-    {
-        var op = tree[i];
-        if (op.name == 'operator' && op.precedence == precedence && !op.params.__parsed)
-        {
-            if (op.optype == 'binary')
-            {
-                op.params.__parsed = [tree[i-1],tree[i+1]];
-                tree.splice(i-1,3,op);
-                return true;
-            }
-            else if (op.optype == 'post-unary')
-            {
-                op.params.__parsed = [tree[i-1]];
-                tree.splice(i-1,2,op);
-                return true;
-            }
-
-            op.params.__parsed = [tree[i+1]];
-            tree.splice(i,2,op);
-        }
-        return false;
-    }
-
-    function composeExpression(tree)
-    {
-        var i = 0;
-        for (i=0; i<tree.length; ++i)
-        {
-            if (tree[i] instanceof Array)
-            {
-                tree[i] = composeExpression(tree[i])
-            }
-        }
-
-        for (var precedence=1; precedence<14; ++precedence)
-        {
-            if (precedence==2 || precedence==10)
-            {
-                for (i=tree.length; i>0; --i)
-                {
-                    i -= bundleOp(i-1, tree, precedence);
-                }
-            }
-            else
-            {
-                for (i=0; i<tree.length; ++i)
-                {
-                    i -= bundleOp(i, tree, precedence);
-                }
-            }
-        }
-        return tree[0]; //only one node must be left
-    }
-
-    function parseExpression(s)
-    {
-        var e = { value:'', tree:[] };
-        while (lookUp(s.slice(e.value.length), e)){}
-        if (!e.tree.length)
-        {
-            return false;
-        }
-        e.tree = composeExpression(e.tree);
-        return e;
-    }
-
-    function parseParams(paramsStr, reDelim, reName)
-    {
-        var s = paramsStr.replace(/\n/g,' ').replace(/^\s+|\s+$/g,'');
-        var params = [];
-        params.__parsed = [];
-        var paramsStr = '';
-
-        if (!s)
-        {
-            return params;
-        }
-
-        if (!reDelim)
-        {
-            reDelim = /^\s+/;
-            reName = /^(\w+)\s*=\s*/;
-        }
-
-        while (s)
-        {
-            var nm = null;
-            if (reName)
-            {
-                var foundName = s.match(reName);
-                if (foundName)
-                {
-                    nm = trimQuotes(foundName[1]);
-                    paramsStr += s.slice(0,foundName[0].length);
-                    s = s.slice(foundName[0].length);
-                }
-            }
-
-            var param = parseExpression(s);
-            if (!param)
-            {
-                break;
-            }
-
-            if (nm)
-            {
-                params[nm] = param.value;
-                params.__parsed[nm] = param.tree;
-            }
-            else
-            {
-                params.push(param.value);
-                params.__parsed.push(param.tree);
-            }
-
-            paramsStr += s.slice(0,param.value.length);
-            s = s.slice(param.value.length);
-
-            var foundDelim = s.match(reDelim);
-            if (foundDelim)
-            {
-                paramsStr += s.slice(0,foundDelim[0].length);
-                s = s.slice(foundDelim[0].length);
-            }
-            else
-            {
-                break;
-            }
-        }
-        params.toString = function() { return paramsStr; }
-        return params;
-    }
-
-    function parsePluginBlock(name, params, tree, content)
-    {
-        tree.push({
-            type: 'plugin',
-            name: name,
-            params: params,
-            subTree: parse(content,[])
-        });
-    }
-
-    function parsePluginFunc(name, params, tree)
-    {
-        tree.push({
-            type: 'plugin',
-            name: name,
-            params: params
-        });
-    }
-
-    function getActualParamValues(params,data)
-    {
-        var actualParams = [];
-        for (var nm in params.__parsed)
-        {
-            if (params.__parsed.hasOwnProperty(nm))
-            {
-                var v = process([params.__parsed[nm]], data);
-                actualParams[nm] = v;
-            }
-        }
-
-        actualParams.__get = function(nm,defVal,id)
-        {
-            if (nm in actualParams && typeof(actualParams[nm]) != 'undefined')
-            {
-                return actualParams[nm];
-            }
-            if (typeof(id)!='undefined' && typeof(actualParams[id]) != 'undefined')
-            {
-                return actualParams[id];
-            }
-            if (defVal === null)
-            {
-                throw new Error("The required attribute '"+nm+"' is missing");
-            }
-            return defVal;
-        };
-        return actualParams;
-    }
-
-    /**
-     * Returns boolean true if object is empty otherwise false.
-     *
-     * @param object hash Object you are testing against.
-     *
-     * @return boolean
-     */
-    function isEmptyObject(hash) {
-        for (var i in hash) {
-            if (hash.hasOwnProperty(i)) {
-                return false;
-            }
-        }
-        return true;
-    }
-
-    function getVarValue(node, data, val)
-    {
-        var v = data;
-        var nm = '';
-        for (var i=0; i<node.parts.length; ++i)
-        {
-            var part = node.parts[i];
-            if (part.type == 'plugin' && part.name == '__func' && part.hasOwner)
-            {
-                data.__owner = v;
-                v = process([node.parts[i]],data);
-                delete data.__owner;
-            }
-            else
-            {
-                nm = process([part],data);
-
-                //section name
-                if (nm in data.smarty.section && part.type=='text' && process([node.parts[0]],data)!='smarty')
-                {
-                    nm = data.smarty.section[nm].index;
-                }
-
-                //add to array
-                if (!nm && typeof val != 'undefined' && v instanceof Array)
-                {
-                    nm = v.length;
-                }
-
-                //set new value
-                if (typeof val != 'undefined' && i==node.parts.length-1)
-                {
-                    v[nm] = val;
-                }
-
-                if (typeof v == 'object' && v !== null && nm in v)
-                {
-                    v = v[nm];
-                }
-                else
-                {
-                    if (typeof val == 'undefined')
-                    {
-                        return val;
-                    }
-                    v[nm] = {};
-                    v = v[nm];
-                }
-            }
-        }
-        return v;
-    }
-
-    function process(tree, data)
-    {
-        var res = '';
-        for (var i=0; i<tree.length; ++i)
-        {
-            var s = '';
-            var node = tree[i];
-            if (node.type == 'text')
-            {
-                s = node.data;
-            }
-            else if (node.type == 'var')
-            {
-                s = getVarValue(node,data);
-            }
-            else if (node.type == 'build-in')
-            {
-                s = buildInFunctions[node.name].process(node,data);
-            }
-            else if (node.type == 'plugin')
-            {
-                var plugin = plugins[node.name];
-                if (plugin.type == 'block')
-                {
-                    var repeat = {value:true};
-                    plugin.process(getActualParamValues(node.params,data), '', data, repeat);
-                    while (repeat.value)
-                    {
-                        repeat.value = false;
-                        s += plugin.process(
-                            getActualParamValues(node.params,data),
-                            process(node.subTree, data),
-                            data,
-                            repeat
-                        );
-                    }
-                }
-                else if (plugin.type == 'function')
-                {
-                    s = plugin.process(getActualParamValues(node.params,data), data);
-                }
-            }
-            if (typeof s == 'boolean')
-            {
-                s = s ? '1' : '';
-            }
-            if (s == null) {
-                s = '';
-            }
-            if (tree.length == 1)
-            {
-                return s;
-            }
-            res += s!==null ? s : '';
-
-            if (data.smarty['continue'] || data.smarty['break'])
-            {
-                return res;
-            }
-        }
-        return res;
-    }
-
-    function getTemplate(name, tree, nocache)
-    {
-        if (nocache || !(name in files))
-        {
-            var tpl = jSmart.prototype.getTemplate(name);
-            if (typeof(tpl) != 'string')
-            {
-                throw new Error('No template for '+ name);
-            }
-            parse(applyFilters(jSmart.prototype.filters_global.pre, stripComments(tpl.replace(/\r\n/g,'\n'))), tree);
-            files[name] = tree;
-        }
-        else
-        {
-            tree = files[name];
-        }
-        return tree;
-    }
-
-    function stripComments(s)
-    {
-        var sRes = '';
-        for (var openTag=s.match(/{{\*/); openTag; openTag=s.match(/{{\*/))
-        {
-            sRes += s.slice(0,openTag.index);
-            s = s.slice(openTag.index+openTag[0].length);
-            var closeTag = s.match(/\*}}/);
-            if (!closeTag)
-            {
-                throw new Error('Unclosed {*');
-            }
-            s = s.slice(closeTag.index+closeTag[0].length);
-        }
-        return sRes + s;
-    }
-
-    function applyFilters(filters, s)
-    {
-        for (var i=0; i<filters.length; ++i)
-        {
-            s = filters[i](s);
-        }
-        return s;
-    }
-
-
-    jSmart = function(tpl)
-    {
-        this.tree = [];
-        this.tree.blocks = {};
-        this.scripts = {};
-        this.default_modifiers = [];
-        this.filters = {'variable':[], 'post':[]};
-        this.smarty = {
-            'smarty': {
-                block: {},
-                'break': false,
-                capture: {},
-                'continue': false,
-                counter: {},
-                cycle: {},
-                foreach: {},
-                section: {},
-                now: Math.floor( (new Date()).getTime()/1000 ),
-                'const': {},
-                config: {},
-                current_dir: '/',
-                template: '',
-                ldelim: jSmart.prototype.left_delimiter,
-                rdelim: jSmart.prototype.right_delimiter,
-                version: '2.15.0'
-            }
-        };
-        blocks = this.tree.blocks;
-        parse(
-            applyFilters(jSmart.prototype.filters_global.pre, stripComments((new String(tpl?tpl:'')).replace(/\r\n/g,'\n'))),
-            this.tree
-        );
-    };
-
-    jSmart.prototype.fetch = function(data)
-    {
-        blocks = this.tree.blocks;
-        scripts = this.scripts;
-        escape_html = this.escape_html;
-        default_modifiers = jSmart.prototype.default_modifiers_global.concat(this.default_modifiers);
-        this.data = obMerge((typeof data == 'object') ? data : {}, this.smarty);
-        varFilters = jSmart.prototype.filters_global.variable.concat(this.filters.variable);
-        var res = process(this.tree, this.data);
-        if (jSmart.prototype.debugging)
-        {
-            plugins.debug.process([],this.data);
-        }
-        return applyFilters(jSmart.prototype.filters_global.post.concat(this.filters.post), res);
-    };
-
-    jSmart.prototype.escape_html = false;
-
-    /**
-       @param type  valid values are 'function', 'block', 'modifier'
-       @param callback  func(params,data)  or  block(params,content,data,repeat)
-    */
-    jSmart.prototype.registerPlugin = function(type, name, callback)
-    {
-        if (type == 'modifier')
-        {
-            modifiers[name] = callback;
-        }
-        else
-        {
-            plugins[name] = {'type': type, 'process': callback};
-        }
-    };
-
-    /**
-       @param type  valid values are 'pre', 'variable', 'post'
-       @param callback function(textValue) { ... }
-    */
-    jSmart.prototype.registerFilter = function(type, callback)
-    {
-        (this.tree ? this.filters : jSmart.prototype.filters_global)[type=='output'?'post':type].push(callback);
-    }
-
-    jSmart.prototype.filters_global = {'pre':[],'variable':[],'post':[]};
-
-    jSmart.prototype.configLoad = function(confValues, section, data)
-    {
-        data = data ? data : this.data;
-        var s = confValues.replace(/\r\n/g,'\n').replace(/^\s+|\s+$/g,'');
-        var re = /^\s*(?:\[([^\]]+)\]|(?:(\w+)[ \t]*=[ \t]*("""|'[^'\\\n]*(?:\\.[^'\\\n]*)*'|"[^"\\\n]*(?:\\.[^"\\\n]*)*"|[^\n]*)))/m;
-        var currSect = '';
-        for (var f=s.match(re); f; f=s.match(re))
-        {
-                s = s.slice(f.index+f[0].length);
-                if (f[1])
-                {
-                         currSect = f[1];
-                }
-                else if ((!currSect || currSect == section) && currSect.substr(0,1) != '.')
-                {
-                         if (f[3] == '"""')
-                         {
-                                  var triple = s.match(/"""/);
-                                  if (triple)
-                                  {
-                                           data.smarty.config[f[2]] = s.slice(0,triple.index);
-                                           s = s.slice(triple.index + triple[0].length);
-                                  }
-                         }
-                         else
-                         {
-                                  data.smarty.config[f[2]] = trimQuotes(f[3]);
-                         }
-                }
-                var newln = s.match(/\n+/);
-                if (newln)
-                {
-                         s = s.slice(newln.index + newln[0].length);
-                }
-                else
-                {
-                         break;
-                }
-        }
-    }
-
-    jSmart.prototype.clearConfig = function(varName)
-    {
-        if (varName)
-        {
-            delete this.data.smarty.config[varName];
-        }
-        else
-        {
-            this.data.smarty.config = {};
-        }
-    }
-
-    /**
-       add modifier to implicitly apply to every variable in a template
-       @param modifiers  single string (e.g. "replace:'from':'to'")
-                         or array of strings (e.g. ['escape:"htmlall"', "replace:'from':'to'"])
-     */
-    jSmart.prototype.addDefaultModifier = function(modifiers)
-    {
-        if (!(modifiers instanceof Array))
-        {
-            modifiers = [modifiers];
-        }
-
-        for (var i=0; i<modifiers.length; ++i)
-        {
-            var e = { value:'', tree:[0] };
-            parseModifiers('|'+modifiers[i], e);
-            (this.tree ? this.default_modifiers : this.default_modifiers_global).push( e.tree[0] );
-        }
-    }
-
-    jSmart.prototype.default_modifiers_global = [];
-
-    /**
-       override this function
-       @param name  value of 'file' parameter in {include} and {extends}
-       @return template text
-    */
-    jSmart.prototype.getTemplate = function(name)
-    {
-        throw new Error('No template for ' + name);
-    }
-
-    /**
-       override this function
-       @param name  value of 'file' parameter in {fetch}
-       @return file content
-    */
-    jSmart.prototype.getFile = function(name)
-    {
-        throw new Error('No file for ' + name);
-    }
-
-    /**
-       override this function
-       @param name  value of 'file' parameter in {include_php} and {include_javascript}
-                     or value of 'script' parameter in {insert}
-       @return Javascript script
-    */
-    jSmart.prototype.getJavascript = function(name)
-    {
-        throw new Error('No Javascript for ' + name);
-    }
-
-    /**
-       override this function
-       @param name  value of 'file' parameter in {config_load}
-       @return config file content
-    */
-    jSmart.prototype.getConfig = function(name)
-    {
-        throw new Error('No config for ' + name);
-    }
-
-
-
-    /**
-       whether to skip tags in open brace { followed by white space(s) and close brace } with white space(s) before
-    */
-    jSmart.prototype.auto_literal = true;
-
-    jSmart.prototype.left_delimiter = '{';
-    jSmart.prototype.right_delimiter = '}';
-
-    /** enables the debugging console */
-    jSmart.prototype.debugging = false;
-
-
-    jSmart.prototype.PHPJS = function(fnm, modifier)
-    {
-        if (eval('typeof '+fnm) == 'function')
-        {
-            return (typeof window == 'object') ? window : global;
-        }
-        else if (typeof(PHP_JS) == 'function')
-        {
-            return new PHP_JS();
-        }
-        throw new Error("Modifier '" + modifier + "' uses JavaScript port of PHP function '" + fnm + "'. You can find one at http://phpjs.org");
-    }
-
-    jSmart.prototype.makeTimeStamp = function(s)
-    {
-        if (!s)
-        {
-            return Math.floor( (new Date()).getTime()/1000 );
-        }
-        if (isNaN(s))
-        {
-            var tm = jSmart.prototype.PHPJS('strtotime','date_format').strtotime(s);
-            if (tm == -1 || tm === false) {
-                return Math.floor( (new Date()).getTime()/1000 );
-            }
-            return tm;
-        }
-        s = new String(s);
-        if (s.length == 14) //mysql timestamp format of YYYYMMDDHHMMSS
-        {
-            return Math.floor( (new Date(s.substr(0,4),s.substr(4,2)-1,s.substr(6,2),s.substr(8,2),s.substr(10,2)).getTime()/1000 ) );
-        }
-        return parseInt(s);
-    }
-
-
-
-    /**
-       register custom functions
-    */
-    jSmart.prototype.registerPlugin(
-        'function',
-        '__array',
-        function(params, data)
-        {
-            var a = [];
-            for (var nm in params)
-            {
-                if (params.hasOwnProperty(nm) && params[nm] && typeof params[nm] != 'function')
-                {
-                    a[nm] = params[nm];
-                }
-            }
-            return a;
-        }
-    );
-
-    jSmart.prototype.registerPlugin(
-        'function',
-        '__func',
-        function(params, data) {
-            var paramNames = [], paramValues = {}, paramData = [];
-            for (var i=0; i<params.length; ++i) {
-                paramNames.push(params.name+'__p'+i);
-                paramData.push(params[i]);
-                paramValues[params.name+'__p'+i] = params[i];
-            }
-            var fname, mergedParams = obMerge({}, data, paramValues);
-            if (('__owner' in data && params.name in data.__owner)) {
-                fname = '__owner.'+params.name;
-                return execute(fname + '(' + paramNames.join(',') + ')', mergedParams);
-            } else if (modifiers.hasOwnProperty(params.name)) {
-                fname = modifiers[params.name]
-                return executeByFuncObject(fname, paramData, mergedParams);
-            } else {
-                fname = params.name;
-                return execute(fname + '(' + paramNames.join(',') + ')', mergedParams);
-            }
-        }
-    );
-
-    jSmart.prototype.registerPlugin(
-        'function',
-        '__quoted',
-        function(params, data)
-        {
-            return params.join('');
-        }
-    );
-
-    jSmart.prototype.registerPlugin(
-        'function',
-        'append',
-        function(params, data)
-        {
-            var varName = params.__get('var',null,0);
-            if (!(varName in data) || !(data[varName] instanceof Array))
-            {
-                data[varName] = [];
-            }
-            var index = params.__get('index',false);
-            var val = params.__get('value',null,1);
-            if (index === false)
-            {
-                data[varName].push(val);
-            }
-            else
-            {
-                data[varName][index] = val;
-            }
-            return '';
-        }
-    );
-
-    jSmart.prototype.registerPlugin(
-        'function',
-        'assign',
-        function(params, data)
-        {
-            assignVar(params.__get('var',null,0), params.__get('value',null,1), data);
-            return '';
-        }
-    );
-
-    jSmart.prototype.registerPlugin(
-        'function',
-        'break',
-        function(params, data)
-        {
-            data.smarty['break'] = true;
-            return '';
-        }
-    );
-
-    jSmart.prototype.registerPlugin(
-        'function',
-        'call',
-        function(params, data)
-        {
-            var fname = params.__get('name',null,0);
-            delete params.name;
-            var assignTo = params.__get('assign',false);
-            delete params.assign;
-            var s = plugins[fname].process(params, data);
-            if (assignTo)
-            {
-                assignVar(assignTo, s, data);
-                return '';
-            }
-            return s;
-        }
-    );
-
-    jSmart.prototype.registerPlugin(
-        'block',
-        'capture',
-        function(params, content, data, repeat)
-        {
-            if (content)
-            {
-                content = content.replace(/^\n/,'');
-                data.smarty.capture[params.__get('name','default',0)] = content;
-
-                if ('assign' in params)
-                {
-                    assignVar(params.assign, content, data);
-                }
-
-                var append = params.__get('append',false);
-                if (append)
-                {
-                    if (append in data)
-                    {
-                        if (data[append] instanceof Array)
-                        {
-                            data[append].push(content);
-                        }
-                    }
-                                       else
-                                       {
-                                                data[append] = [content];
-                                       }
-                }
-            }
-            return '';
-        }
-    );
-
-    jSmart.prototype.registerPlugin(
-        'function',
-        'continue',
-        function(params, data)
-        {
-            data.smarty['continue'] = true;
-            return '';
-        }
-    );
-
-    jSmart.prototype.registerPlugin(
-        'function',
-        'counter',
-        function(params, data)
-        {
-            var name = params.__get('name','default');
-            if (name in data.smarty.counter)
-            {
-                var counter = data.smarty.counter[name];
-                if ('start' in params)
-                {
-                    counter.value = parseInt(params['start']);
-                }
-                else
-                {
-                    counter.value = parseInt(counter.value);
-                    counter.skip = parseInt(counter.skip);
-                    if ('down' == counter.direction)
-                    {
-                        counter.value -= counter.skip;
-                    }
-                    else
-                    {
-                        counter.value += counter.skip;
-                    }
-                }
-                counter.skip = params.__get('skip',counter.skip);
-                counter.direction = params.__get('direction',counter.direction);
-                counter.assign = params.__get('assign',counter.assign);
-            }
-            else
-            {
-                data.smarty.counter[name] = {
-                    value: parseInt(params.__get('start',1)),
-                    skip: parseInt(params.__get('skip',1)),
-                    direction: params.__get('direction','up'),
-                    assign: params.__get('assign',false)
-                };
-            }
-
-            if (data.smarty.counter[name].assign)
-            {
-                data[data.smarty.counter[name].assign] = data.smarty.counter[name].value;
-                return '';
-            }
-
-            if (params.__get('print',true))
-            {
-                return data.smarty.counter[name].value;
-            }
-
-            return '';
-        }
-    );
-
-    jSmart.prototype.registerPlugin(
-        'function',
-        'cycle',
-        function(params, data)
-        {
-            var name = params.__get('name','default');
-            var reset = params.__get('reset',false);
-            if (!(name in data.smarty.cycle))
-            {
-                data.smarty.cycle[name] = {arr: [''], delimiter: params.__get('delimiter',','), index: 0};
-                reset = true;
-            }
-
-            if (params.__get('delimiter',false))
-            {
-                data.smarty.cycle[name].delimiter = params.delimiter;
-            }
-            var values = params.__get('values',false);
-            if (values)
-            {
-                var arr = [];
-                if (values instanceof Object)
-                {
-                    for (nm in values)
-                    {
-                        arr.push(values[nm]);
-                    }
-                }
-                else
-                {
-                    arr = values.split(data.smarty.cycle[name].delimiter);
-                }
-
-                if (arr.length != data.smarty.cycle[name].arr.length || arr[0] != data.smarty.cycle[name].arr[0])
-                {
-                    data.smarty.cycle[name].arr = arr;
-                    data.smarty.cycle[name].index = 0;
-                    reset = true;
-                }
-            }
-
-            if (params.__get('advance','true'))
-            {
-                data.smarty.cycle[name].index += 1;
-            }
-            if (data.smarty.cycle[name].index >= data.smarty.cycle[name].arr.length || reset)
-            {
-                data.smarty.cycle[name].index = 0;
-            }
-
-            if (params.__get('assign',false))
-            {
-                assignVar(params.assign, data.smarty.cycle[name].arr[ data.smarty.cycle[name].index ], data);
-                return '';
-            }
-
-            if (params.__get('print',true))
-            {
-                return data.smarty.cycle[name].arr[ data.smarty.cycle[name].index ];
-            }
-
-            return '';
-        }
-    );
-
-    jSmart.prototype.print_r = function(v,indent)
-    {
-        if (v instanceof Object)
-        {
-            var s = ((v instanceof Array) ? 'Array['+v.length+']' : 'Object') + '<br>';
-            for (var nm in v)
-            {
-                if (v.hasOwnProperty(nm))
-                {
-                    s += indent + '&nbsp;&nbsp;<strong>' + nm + '</strong> : ' + jSmart.prototype.print_r(v[nm],indent+'&nbsp;&nbsp;&nbsp;') + '<br>';
-                }
-            }
-            return s;
-        }
-        return v;
-    }
-
-    jSmart.prototype.registerPlugin(
-        'function',
-        'debug',
-        function(params, data)
-        {
-            if (typeof dbgWnd != 'undefined')
-            {
-                dbgWnd.close();
-            }
-            dbgWnd = window.open('','','width=680,height=600,resizable,scrollbars=yes');
-            var sVars = '';
-            var i=0;
-            for (var nm in data)
-            {
-                sVars += '<tr class=' + (++i%2?'odd':'even') + '><td><strong>' + nm + '</strong></td><td>' + jSmart.prototype.print_r(data[nm],'') + '</td></tr>';
-            }
-            dbgWnd.document.write(" \
-               <html xmlns='http://www.w3.org/1999/xhtml' xml:lang='en'> \
-               <head> \
-                           <title>jSmart Debug Console</title> \
-                  <style type='text/css'> \
-                     table {width: 100%;} \
-                     td {vertical-align:top;width: 50%;} \
-                     .even td {background-color: #fafafa;} \
-                  </style> \
-               </head> \
-               <body> \
-                  <h1>jSmart Debug Console</h1> \
-                  <h2>assigned template variables</h2> \
-                  <table>" + sVars + "</table> \
-               </body> \
-               </html> \
-            ");
-            return '';
-        }
-    );
-
-    jSmart.prototype.registerPlugin(
-        'function',
-        'eval',
-        function(params, data)
-        {
-            var tree = [];
-            parse(params.__get('var','',0), tree);
-            var s = process(tree, data);
-            if ('assign' in params)
-            {
-                assignVar(params.assign, s, data);
-                return '';
-            }
-            return s;
-        }
-    );
-
-    jSmart.prototype.registerPlugin(
-        'function',
-        'fetch',
-        function(params, data)
-        {
-            var s = jSmart.prototype.getFile(params.__get('file',null,0));
-            if ('assign' in params)
-            {
-                assignVar(params.assign, s, data);
-                return '';
-            }
-            return s;
-        }
-    );
-
-    jSmart.prototype.registerPlugin(
-        'function',
-        'html_checkboxes',
-        function (params, data) {
-            var type = params.__get('type','checkbox'),
-                name = params.__get('name',type),
-                realName = params.__get('name',type),
-                values = params.__get('values',params.options),
-                output = params.__get('options',[]),
-                useName = ('options' in params),
-                selected = params.__get('selected',false),
-                separator = params.__get('separator',''),
-                labels = Boolean(params.__get('labels',true)),
-                label_ids = Boolean(params.__get('label_ids',false)),
-                p,
-                res = [],
-                i = 0,
-                s = '',
-                value,
-                id;
-
-            if (type == 'checkbox') {
-                name += '[]';
-            }
-            if (!useName) {
-                for (p in params.output) {
-                    output.push(params.output[p]);
-                }
-            }
-
-            for (p in values) {
-                if (values.hasOwnProperty(p)) {
-                    value = (useName ? p : values[p]);
-                    id = realName + '_' + value;
-                    s = (labels ? ( label_ids ? '<label for="'+id+'">' : '<label>') : '');
-
-                    s += '<input type="' + type + '" name="' + name + '" value="' + value + '" ';
-                    if (label_ids) {
-                        s += 'id="'+id+'" ';
-                    }
-                    if (selected == (useName ? p : values[p])) {
-                        s += 'checked="checked" ';
-                    }
-                    s += '/>' + output[useName?p:i++];
-                    s += (labels ? '</label>' : '');
-                    s += separator;
-                    res.push(s);
-                }
-            }
-            if ('assign' in params) {
-                assignVar(params.assign, res, data);
-                return '';
-            }
-            return res.join('\n');
-        }
-    );
-
-    jSmart.prototype.registerPlugin(
-        'function',
-        'html_image',
-        function (params, data) {
-            var url = params.__get('file', null),
-                width = params.__get('width', false),
-                height = params.__get('height', false),
-                alt = params.__get('alt', ''),
-                href = params.__get('href', params.__get('link', false)),
-                path_prefix = params.__get('path_prefix', ''),
-                paramNames = {file:1, width:1, height:1, alt:1, href:1, basedir:1, path_prefix:1, link:1},
-                s = '<img src="' + path_prefix + url + '"' + ' alt="'+alt+'"' + (width ? ' width="'+width+'"':'') + (height ? ' height="'+height+'"':''),
-                p;
-
-            for (p in params) {
-                if (params.hasOwnProperty(p) && typeof(params[p]) == 'string') {
-                    if (!(p in paramNames)) {
-                        s += ' ' + p + '="' + params[p] + '"';
-                    }
-                }
-            }
-            s += ' />';
-            return href ? '<a href="'+href+'">'+s+'</a>' : s;
-        }
-    );
-
-    jSmart.prototype.registerPlugin(
-        'function',
-        'html_options',
-        function(params, data)
-        {
-            var values = params.__get('values',params.options);
-            var output = params.__get('options',[]);
-            var useName = ('options' in params);
-            var p;
-            if (!useName)
-            {
-                for (p in params.output)
-                {
-                    output.push(params.output[p]);
-                }
-            }
-            var selected = params.__get('selected',false);
-
-            var res = [];
-            var s = '';
-            var i = 0;
-            for (p in values)
-            {
-                if (values.hasOwnProperty(p))
-                {
-                    s = '<option value="' + (useName ? p : values[p]) + '"';
-                    if (selected == (useName ? p : values[p]))
-                    {
-                        s += ' selected="selected"';
-                    }
-                    s += '>' + output[useName ? p : i++] + '</option>';
-                    res.push(s);
-                }
-            }
-            var name = params.__get('name',false);
-            return (name ? ('<select name="' + name + '">\n' + res.join('\n') + '\n</select>') : res.join('\n')) + '\n';
-        }
-    );
-
-    jSmart.prototype.registerPlugin(
-        'function',
-        'html_radios',
-        function(params, data)
-        {
-            params.type = 'radio';
-            return plugins.html_checkboxes.process(params,data);
-        }
-    );
-
-    jSmart.prototype.registerPlugin(
-        'function',
-        'html_select_date',
-        function(params, data)
-        {
-            var prefix = params.__get('prefix','Date_');
-            var months = ['January','February','March','April','May','June','July','August','September','October','November','December'];
-
-            var s = '';
-            s += '<select name="'+prefix+'Month">\n';
-            var i=0;
-            for (i=0; i<months.length; ++i)
-            {
-                s += '<option value="' + i + '">' + months[i] + '</option>\n';
-            }
-            s += '</select>\n'
-
-            s += '<select name="'+prefix+'Day">\n';
-            for (i=0; i<31; ++i)
-            {
-                s += '<option value="' + i + '">' + i + '</option>\n';
-            }
-            s += '</select>\n'
-            return s;
-        }
-    );
-
-    jSmart.prototype.registerPlugin(
-        'function',
-        'html_table',
-        function(params, data)
-        {
-            var loop = [];
-            var p;
-            if (params.loop instanceof Array)
-            {
-                loop = params.loop
-            }
-            else
-            {
-                for (p in params.loop)
-                {
-                    if (params.loop.hasOwnProperty(p))
-                    {
-                        loop.push( params.loop[p] );
-                    }
-                }
-            }
-            var rows = params.__get('rows',false);
-            var cols = params.__get('cols',false);
-            if (!cols)
-            {
-                cols = rows ? Math.ceil(loop.length/rows) : 3;
-            }
-            var colNames = [];
-            if (isNaN(cols))
-            {
-                if (typeof cols == 'object')
-                {
-                    for (p in cols)
-                    {
-                        if (cols.hasOwnProperty(p))
-                        {
-                            colNames.push(cols[p]);
-                        }
-                    }
-                }
-                else
-                {
-                    colNames = cols.split(/\s*,\s*/);
-                }
-                cols = colNames.length;
-            }
-            rows = rows ? rows : Math.ceil(loop.length/cols);
-
-            var inner = params.__get('inner','cols');
-            var caption = params.__get('caption','');
-            var table_attr = params.__get('table_attr','border="1"');
-            var th_attr = params.__get('th_attr',false);
-            if (th_attr && typeof th_attr != 'object')
-            {
-                th_attr = [th_attr];
-            }
-            var tr_attr = params.__get('tr_attr',false);
-            if (tr_attr && typeof tr_attr != 'object')
-            {
-                tr_attr = [tr_attr];
-            }
-            var td_attr = params.__get('td_attr',false);
-            if (td_attr && typeof td_attr != 'object')
-            {
-                td_attr = [td_attr];
-            }
-            var trailpad = params.__get('trailpad','&nbsp;');
-            var hdir = params.__get('hdir','right');
-            var vdir = params.__get('vdir','down');
-
-            var s = '';
-            for (var row=0; row<rows; ++row)
-            {
-                s += '<tr' + (tr_attr ? ' '+tr_attr[row%tr_attr.length] : '') + '>\n';
-                for (var col=0; col<cols; ++col)
-                {
-                    var idx = (inner=='cols') ? ((vdir=='down'?row:rows-1-row) * cols + (hdir=='right'?col:cols-1-col)) : ((hdir=='right'?col:cols-1-col) * rows + (vdir=='down'?row:rows-1-row));
-
-                    s += '<td' + (td_attr ? ' '+td_attr[col%td_attr.length] : '') + '>' + (idx < loop.length ? loop[idx] : trailpad) + '</td>\n';
-                }
-                s += '</tr>\n';
-            }
-
-            var sHead = '';
-            if (colNames.length)
-            {
-                sHead = '\n<thead><tr>';
-                for (var i=0; i<colNames.length; ++i)
-                {
-                    sHead += '\n<th' + (th_attr ? ' '+th_attr[i%th_attr.length] : '') + '>' + colNames[hdir=='right'?i:colNames.length-1-i] + '</th>';
-                }
-                sHead += '\n</tr></thead>';
-            }
-
-            return '<table ' + table_attr + '>' + (caption?'\n<caption>'+caption+'</caption>':'') + sHead + '\n<tbody>\n' + s + '</tbody>\n</table>\n';
-        }
-    );
-
-    jSmart.prototype.registerPlugin(
-        'function',
-        'include',
-        function(params, data)
-        {
-            var file = params.__get('file',null,0);
-            var incData = obMerge({},data,params);
-            incData.smarty.template = file;
-            var s = process(getTemplate(file,[],findInArray(params,'nocache')>=0), incData);
-            if ('assign' in params)
-            {
-                assignVar(params.assign, s, data);
-                return '';
-            }
-            return s;
-        }
-    );
-
-    jSmart.prototype.registerPlugin(
-        'function',
-        'include_javascript',
-        function(params, data)
-        {
-            var file = params.__get('file',null,0);
-            if (params.__get('once',true) && file in scripts)
-            {
-                return '';
-            }
-            scripts[file] = true;
-            var s = execute(jSmart.prototype.getJavascript(file), {'$this':data});
-            if ('assign' in params)
-            {
-                assignVar(params.assign, s, data);
-                return '';
-            }
-            return s;
-        }
-    );
-
-    jSmart.prototype.registerPlugin(
-        'function',
-        'include_php',
-        function(params, data)
-        {
-            return plugins['include_javascript'].process(params,data);
-        }
-    );
-
-    jSmart.prototype.registerPlugin(
-        'function',
-        'insert',
-        function(params, data)
-        {
-            var fparams = {};
-            for (var nm in params)
-            {
-                if (params.hasOwnProperty(nm) && isNaN(nm) && params[nm] && typeof params[nm] == 'string' && nm != 'name' && nm != 'assign' && nm != 'script')
-                {
-                    fparams[nm] = params[nm];
-                }
-            }
-            var prefix = 'insert_';
-            if ('script' in params)
-            {
-                eval(jSmart.prototype.getJavascript(params.script));
-                prefix = 'smarty_insert_';
-            }
-            var func = eval(prefix+params.__get('name',null,0));
-            var s = func(fparams, data);
-            if ('assign' in params)
-            {
-                assignVar(params.assign, s, data);
-                return '';
-            }
-            return s;
-        }
-    );
-
-    jSmart.prototype.registerPlugin(
-        'block',
-        'javascript',
-        function(params, content, data, repeat)
-        {
-            data['$this'] = data;
-            execute(content,data);
-            delete data['$this'];
-            return '';
-        }
-    );
-
-    jSmart.prototype.registerPlugin(
-        'function',
-        'config_load',
-        function(params, data)
-        {
-            jSmart.prototype.configLoad(jSmart.prototype.getConfig(params.__get('file',null,0)), params.__get('section','',1), data);
-            return '';
-        }
-    );
-
-    jSmart.prototype.registerPlugin(
-        'function',
-        'mailto',
-        function(params, data)
-        {
-            var address = params.__get('address',null);
-            var encode = params.__get('encode','none');
-            var text = params.__get('text',address);
-            var cc = jSmart.prototype.PHPJS('rawurlencode','mailto').rawurlencode(params.__get('cc','')).replace('%40','@');
-            var bcc = jSmart.prototype.PHPJS('rawurlencode','mailto').rawurlencode(params.__get('bcc','')).replace('%40','@');
-            var followupto = jSmart.prototype.PHPJS('rawurlencode','mailto').rawurlencode(params.__get('followupto','')).replace('%40','@');
-            var subject = jSmart.prototype.PHPJS('rawurlencode','mailto').rawurlencode( params.__get('subject','') );
-            var newsgroups = jSmart.prototype.PHPJS('rawurlencode','mailto').rawurlencode(params.__get('newsgroups',''));
-            var extra = params.__get('extra','');
-
-            address += (cc?'?cc='+cc:'');
-            address += (bcc?(cc?'&':'?')+'bcc='+bcc:'');
-            address += (subject ? ((cc||bcc)?'&':'?') + 'subject='+subject : '');
-            address += (newsgroups ? ((cc||bcc||subject)?'&':'?') + 'newsgroups='+newsgroups : '');
-            address += (followupto ? ((cc||bcc||subject||newsgroups)?'&':'?') + 'followupto='+followupto : '');
-
-            s = '<a href="mailto:' + address + '" ' + extra + '>' + text + '</a>';
-
-            if (encode == 'javascript')
-            {
-                s = "document.write('" + s + "');";
-                var sEncoded = '';
-                for (var i=0; i<s.length; ++i)
-                {
-                    sEncoded += '%' + jSmart.prototype.PHPJS('bin2hex','mailto').bin2hex(s.substr(i,1));
-                }
-                return '<script type="text/javascript">eval(unescape(\'' + sEncoded + "'))</script>";
-            }
-            else if (encode == 'javascript_charcode')
-            {
-                var codes = [];
-                for (var i=0; i<s.length; ++i)
-                {
-                    codes.push(jSmart.prototype.PHPJS('ord','mailto').ord(s.substr(i,1)));
-                }
-                return '<script type="text/javascript" language="javascript">\n<!--\n{document.write(String.fromCharCode('
-                    + codes.join(',') + '))}\n//-->\n</script>\n';
-            }
-            else if (encode == 'hex')
-            {
-                if (address.match(/^.+\?.+$/))
-                {
-                    throw new Error('mailto: hex encoding does not work with extra attributes. Try javascript.');
-                }
-                var aEncoded = '';
-                for (var i=0; i<address.length; ++i)
-                {
-                    if (address.substr(i,1).match(/\w/))
-                    {
-                        aEncoded += '%' + jSmart.prototype.PHPJS('bin2hex','mailto').bin2hex(address.substr(i,1));
-                    }
-                    else
-                    {
-                        aEncoded += address.substr(i,1);
-                    }
-                }
-                aEncoded = aEncoded.toLowerCase();
-                var tEncoded = '';
-                for (var i=0; i<text.length; ++i)
-                {
-                    tEncoded += '&#x' + jSmart.prototype.PHPJS('bin2hex','mailto').bin2hex(text.substr(i,1)) + ';';
-                }
-                tEncoded = tEncoded.toLowerCase();
-                return '<a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;' + aEncoded + '" ' + extra + '>' + tEncoded + '</a>';
-            }
-            return s;
-        }
-    );
-
-    jSmart.prototype.registerPlugin(
-        'function',
-        'math',
-        function(params, data)
-        {
-            with (Math)
-            {
-                with (params)
-                {
-                    var res = eval(params.__get('equation',null).replace(/pi\(\s*\)/g,'PI'));
-                }
-            }
-
-            if ('format' in params)
-            {
-                res = jSmart.prototype.PHPJS('sprintf','math').sprintf(params.format,res);
-            }
-
-            if ('assign' in params)
-            {
-                assignVar(params.assign, res, data);
-                return '';
-            }
-            return res;
-        }
-    );
-
-    jSmart.prototype.registerPlugin(
-        'block',
-        'nocache',
-        function(params, content, data, repeat)
-        {
-            return content;
-        }
-    );
-
-    jSmart.prototype.registerPlugin(
-        'block',
-        'textformat',
-        function(params, content, data, repeat)
-        {
-            if (!content) {
-                return '';
-            }
-
-            content = new String(content);
-
-            var wrap = params.__get('wrap',80);
-            var wrap_char = params.__get('wrap_char','\n');
-            var wrap_cut = params.__get('wrap_cut',false);
-            var indent_char = params.__get('indent_char',' ');
-            var indent = params.__get('indent',0);
-            var indentStr = (new Array(indent+1)).join(indent_char);
-            var indent_first = params.__get('indent_first',0);
-            var indentFirstStr = (new Array(indent_first+1)).join(indent_char);
-
-            var style = params.__get('style','');
-
-            if (style == 'email') {
-                wrap = 72;
-            }
-
-            var paragraphs = content.split(/[\r\n]{2}/);
-            for (var i=0; i<paragraphs.length; ++i) {
-                var p = paragraphs[i];
-                if (!p) {
-                    continue;
-                }
-                p = p.replace(/^\s+|\s+$/,'').replace(/\s+/g,' ');
-                if (indent_first> 0 ) {
-                    p = indentFirstStr + p;
-                }
-                p = modifiers.wordwrap(p, wrap-indent, wrap_char, wrap_cut);
-                if (indent > 0) {
-                    p = p.replace(/^/mg, indentStr);
-                }
-                paragraphs[i] = p;
-            }
-            var s = paragraphs.join(wrap_char+wrap_char);
-            if ('assign' in params)
-            {
-                assignVar(params.assign, s, data);
-                return '';
-            }
-            return s;
-        }
-    );
-
-
-    /**
-       register modifiers
-    */
-    jSmart.prototype.registerPlugin(
-        'modifier',
-        'capitalize',
-        function(s, upDigits, lcRest) {
-            if (typeof s != 'string') {
-                return s;
-            }
-            var re = new RegExp(upDigits ? '[^a-zA-Z_\u00E0-\u00FC]+' : '[^a-zA-Z0-9_\u00E0-\u00FC]');
-            var found = null;
-            var res = '';
-            if (lcRest) {
-                s = s.toLowerCase();
-            }
-            for (found=s.match(re); found; found=s.match(re))
-            {
-                    var word = s.slice(0,found.index);
-                if (word.match(/\d/))
-                {
-                    res += word;
-                }
-                else
-                {
-                        res += word.charAt(0).toUpperCase() + word.slice(1);
-                }
-                res += s.slice(found.index, found.index+found[0].length);
-                    s = s.slice(found.index+found[0].length);
-            }
-            if (s.match(/\d/))
-            {
-                return res + s;
-            }
-            return res + s.charAt(0).toUpperCase() + s.slice(1);
-        }
-    );
-
-    jSmart.prototype.registerPlugin(
-        'modifier',
-        'cat',
-        function(s, value)
-        {
-            value = value ? value : '';
-            return new String(s) + value;
-        }
-    );
-
-    jSmart.prototype.registerPlugin(
-        'modifier',
-        'count',
-        function(v, recursive)
-        {
-            if (v === null || typeof v === 'undefined') {
-                return 0;
-            } else if (v.constructor !== Array && v.constructor !== Object) {
-                return 1;
-            }
-
-            recursive = Boolean(recursive);
-            var k, cnt = 0;
-            for (k in v)
-            {
-                if (v.hasOwnProperty(k))
-                {
-                    cnt++;
-                    if (recursive && v[k] && (v[k].constructor === Array || v[k].constructor === Object)) {
-                        cnt += modifiers.count(v[k], true);
-                    }
-                }
-            }
-            return cnt;
-        }
-    );
-
-    jSmart.prototype.registerPlugin(
-        'modifier',
-        'count_characters',
-        function(s, includeWhitespaces)
-        {
-            s = new String(s);
-            return includeWhitespaces ? s.length : s.replace(/\s/g,'').length;
-        }
-    );
-
-    jSmart.prototype.registerPlugin(
-        'modifier',
-        'count_paragraphs',
-        function(s)
-        {
-            var found = (new String(s)).match(/\n+/g);
-            if (found)
-            {
-                    return found.length+1;
-            }
-            return 1;
-        }
-    );
-
-    jSmart.prototype.registerPlugin(
-        'modifier',
-        'count_sentences',
-        function(s)
-        {
-            if (typeof s == 'string')
-            {
-                var found = s.match(/[^\s]\.(?!\w)/g);
-                if (found)
-                {
-                        return found.length;
-                }
-            }
-            return 0;
-        }
-    );
-
-    jSmart.prototype.registerPlugin(
-        'modifier',
-        'count_words',
-        function(s)
-        {
-            if (typeof s == 'string')
-            {
-                var found = s.match(/\w+/g);
-                if (found)
-                {
-                        return found.length;
-                }
-            }
-            return 0;
-        }
-    );
-
-    jSmart.prototype.registerPlugin(
-        'modifier',
-        'date_format',
-        function(s, fmt, defaultDate)
-        {
-            return jSmart.prototype.PHPJS('strftime','date_format').strftime(fmt?fmt:'%b %e, %Y', jSmart.prototype.makeTimeStamp(s?s:defaultDate));
-        }
-    );
-
-    jSmart.prototype.registerPlugin(
-        'modifier',
-        'defaultValue',
-        function(s, value)
-        {
-            return (s && s!='null' && s!='undefined') ? s : (value ? value : '');
-        }
-    );
-
-    jSmart.prototype.registerPlugin(
-        'modifier',
-        'unescape',
-        function(s, esc_type, char_set)
-        {
-            s = new String(s);
-            esc_type = esc_type || 'html';
-            char_set = char_set || 'UTF-8';
-
-            switch (esc_type)
-            {
-            case 'html':
-                return s.replace(/&lt;/g, '<').replace(/&gt;/g,'>').replace(/&#039;/g,"'").replace(/&quot;/g,'"');
-            case 'entity':
-            case 'htmlall':
-                return jSmart.prototype.PHPJS('html_entity_decode','unescape').html_entity_decode(s, 1);
-            case 'url':
-                return jSmart.prototype.PHPJS('rawurldecode','unescape').rawurldecode(s);
-            };
-            return s;
-        }
-    );
-
-    jSmart.prototype.registerPlugin(
-        'modifier',
-        'escape',
-        function(s, esc_type, char_set, double_encode)
-        {
-            s = new String(s);
-            esc_type = esc_type || 'html';
-            char_set = char_set || 'UTF-8';
-            double_encode = (typeof double_encode != 'undefined') ? Boolean(double_encode) : true;
-
-            switch (esc_type)
-            {
-            case 'html':
-                if (double_encode) {
-                                  s = s.replace(/&/g, '&amp;');
-                         }
-                return s.replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/'/g,'&#039;').replace(/"/g,'&quot;');
-            case 'htmlall':
-                return jSmart.prototype.PHPJS('htmlentities','escape').htmlentities(s, 3, char_set);
-            case 'url':
-                return jSmart.prototype.PHPJS('rawurlencode','escape').rawurlencode(s);
-            case 'urlpathinfo':
-                return jSmart.prototype.PHPJS('rawurlencode','escape').rawurlencode(s).replace(/%2F/g, '/');
-            case 'quotes':
-                return s.replace(/(^|[^\\])'/g, "$1\\'");
-            case 'hex':
-                var res = '';
-                for (var i=0; i<s.length; ++i)
-                {
-                    res += '%' + jSmart.prototype.PHPJS('bin2hex','escape').bin2hex(s.substr(i,1)).toLowerCase();
-                }
-                return res;
-            case 'hexentity':
-                var res = '';
-                for (var i=0; i<s.length; ++i) {
-                    res += '&#x' + jSmart.prototype.PHPJS('bin2hex','escape').bin2hex(s.substr(i,1)) + ';';
-                }
-                return res;
-            case 'decentity':
-                var res = '';
-                for (var i=0; i<s.length; ++i) {
-                    res += '&#' + jSmart.prototype.PHPJS('ord','escape').ord(s.substr(i,1)) + ';';
-                }
-                return res;
-            case 'mail':
-                return s.replace(/@/g,' [AT] ').replace(/[.]/g,' [DOT] ');
-            case 'nonstd':
-                var res = '';
-                for (var i=0; i<s.length; ++i)
-                {
-                    var _ord = jSmart.prototype.PHPJS('ord','escape').ord(s.substr(i,1));
-                    if (_ord >= 126) {
-                        res += '&#' + _ord + ';';
-                    } else {
-                        res += s.substr(i, 1);
-                    }
-
-                }
-                return res;
-            case 'javascript':
-                return s.replace(/\\/g,'\\\\').replace(/'/g,"\\'").replace(/"/g,'\\"').replace(/\r/g,'\\r').replace(/\n/g,'\\n').replace(/<\//g,'<\/');
-            };
-            return s;
-        }
-    );
-
-    jSmart.prototype.registerPlugin(
-        'modifier',
-        'indent',
-        function(s, repeat, indentWith)
-        {
-            s = new String(s);
-            repeat = repeat ? repeat : 4;
-            indentWith = indentWith ? indentWith : ' ';
-
-            var indentStr = '';
-            while (repeat--)
-            {
-                indentStr += indentWith;
-            }
-
-            var tail = s.match(/\n+$/);
-            return indentStr + s.replace(/\n+$/,'').replace(/\n/g,'\n'+indentStr) + (tail ? tail[0] : '');
-        }
-    );
-
-    jSmart.prototype.registerPlugin(
-        'modifier',
-        'lower',
-        function(s)
-        {
-            return new String(s).toLowerCase();
-        }
-    );
-
-    jSmart.prototype.registerPlugin(
-        'modifier',
-        'nl2br',
-        function(s)
-        {
-            return new String(s).replace(/\n/g,'<br />\n');
-        }
-    );
-
-    /**
-        only modifiers (flags) 'i' and 'm' are supported
-        backslashes should be escaped e.g. \\s
-    */
-    jSmart.prototype.registerPlugin(
-        'modifier',
-        'regex_replace',
-        function(s, re, replaceWith)
-        {
-            var pattern = re.match(/^ *\/(.*)\/(.*) *$/);
-            return (new String(s)).replace(new RegExp(pattern[1],'g'+(pattern.length>1?pattern[2]:'')), replaceWith);
-        }
-    );
-
-    jSmart.prototype.registerPlugin(
-        'modifier',
-        'replace',
-        function(s, search, replaceWith)
-        {
-            if (!search)
-            {
-                return s;
-            }
-            s = new String(s);
-            search = new String(search);
-            replaceWith = new String(replaceWith);
-            var res = '';
-            var pos = -1;
-            for (pos=s.indexOf(search); pos>=0; pos=s.indexOf(search))
-            {
-                res += s.slice(0,pos) + replaceWith;
-                pos += search.length;
-                s = s.slice(pos);
-            }
-            return res + s;
-        }
-    );
-
-    jSmart.prototype.registerPlugin(
-        'modifier',
-        'spacify',
-        function(s, space)
-        {
-            if (!space)
-            {
-                space = ' ';
-            }
-            return (new String(s)).replace(/(\n|.)(?!$)/g,'$1'+space);
-        }
-    );
-
-    jSmart.prototype.registerPlugin(
-        'modifier',
-        'noprint',
-        function(s)
-        {
-            return '';
-        }
-    );
-
-    jSmart.prototype.registerPlugin(
-        'modifier',
-        'string_format',
-        function(s, fmt)
-        {
-            return jSmart.prototype.PHPJS('sprintf','string_format').sprintf(fmt,s);
-        }
-    );
-
-    jSmart.prototype.registerPlugin(
-        'modifier',
-        'strip',
-        function(s, replaceWith)
-        {
-            replaceWith = replaceWith ? replaceWith : ' ';
-            return (new String(s)).replace(/[\s]+/g, replaceWith);
-        }
-    );
-
-    jSmart.prototype.registerPlugin(
-        'modifier',
-        'strip_tags',
-        function(s, addSpace)
-        {
-            addSpace = (addSpace==null) ? true : addSpace;
-            return (new String(s)).replace(/<[^>]*?>/g, addSpace ? ' ' : '');
-        }
-    );
-
-    jSmart.prototype.registerPlugin(
-        'modifier',
-        'truncate',
-        function(s, length, etc, breakWords, middle)
-        {
-            s = new String(s);
-            length = length ? length : 80;
-            etc = (etc!=null) ? etc : '...';
-
-            if (s.length <= length)
-            {
-                return s;
-            }
-
-            length -= Math.min(length,etc.length);
-            if (middle)
-            {
-                //one of floor()'s should be replaced with ceil() but it so in Smarty
-                return s.slice(0,Math.floor(length/2)) + etc + s.slice(s.length-Math.floor(length/2));
-            }
-
-            if (!breakWords)
-            {
-                s = s.slice(0,length+1).replace(/\s+?(\S+)?$/,'');
-            }
-
-            return s.slice(0,length) + etc;
-        }
-    );
-
-    jSmart.prototype.registerPlugin(
-        'modifier',
-        'upper',
-        function(s)
-        {
-            return (new String(s)).toUpperCase();
-        }
-    );
-
-    jSmart.prototype.registerPlugin(
-        'modifier',
-        'wordwrap',
-        function(s, width, wrapWith, breakWords)
-        {
-               width = width || 80;
-               wrapWith = wrapWith || '\n';
-
-               var lines = (new String(s)).split('\n');
-               for (var i=0; i<lines.length; ++i)
-               {
-                       var line = lines[i];
-                var parts = ''
-                       while (line.length > width)
-                       {
-                    var pos = 0;
-                    var found = line.slice(pos).match(/\s+/);
-                    for (;found && (pos+found.index)<=width; found=line.slice(pos).match(/\s+/))
-                    {
-                        pos += found.index + found[0].length;
-                    }
-                    pos = pos || (breakWords ? width : (found ? found.index+found[0].length : line.length));
-                    parts += line.slice(0,pos).replace(/\s+$/,'');// + wrapWith;
-                    if (pos < line.length)
-                    {
-                        parts += wrapWith;
-                    }
-                    line = line.slice(pos);
-                }
-                       lines[i] = parts + line;
-               }
-               return lines.join('\n');
-        }
-    );
-
-
-    String.prototype.fetch = function(data)
-    {
-        var tpl = new jSmart(this);
-        return tpl.fetch(data);
-    };
-
-    if (typeof module === "object" && module && typeof module.exports === "object") {
-        module.exports = jSmart;
-    } else {
-        if (typeof global !== "undefined") {
-            global.jSmart = jSmart;
-        }
-
-        if (typeof define === "function" && define.amd) {
-            define("jSmart", [], function () { return jSmart; });
-        }
-    }
-})();
diff --git a/view/theme/frio/frameworks/jsmart/jsmart.js b/view/theme/frio/frameworks/jsmart/jsmart.js
deleted file mode 100644 (file)
index 758e928..0000000
+++ /dev/null
@@ -1,3456 +0,0 @@
-/*!
- * jSmart Javascript template engine
- * https://github.com/umakantp/jsmart
- *
- * Copyright 2011-2015, Max Miroshnikov <miroshnikov at gmail dot com>
- *                      Umakant Patil <me at umakantpatil dot.com>
- * jSmart is licensed under the GNU Lesser General Public License
- * http://opensource.org/licenses/LGPL-3.0
- */
-
-
-(function() {
-
-    /**
-       merges two or more objects into one
-       shallow copy for objects
-    */
-    function obMerge(ob1, ob2 /*, ...*/)
-    {
-        for (var i=1; i<arguments.length; ++i)
-        {
-           for (var nm in arguments[i])
-           {
-              ob1[nm] = arguments[i][nm];
-           }
-        }
-        return ob1;
-    }
-
-    /**
-       @return  number of own properties in ob
-    */
-    function countProperties(ob)
-    {
-        var count = 0;
-        for (var nm in ob)
-        {
-            if (ob.hasOwnProperty(nm))
-            {
-                count++;
-            }
-        }
-        return count;
-    }
-
-    /**
-       IE workaround
-    */
-    function findInArray(a, v)
-    {
-        if (Array.prototype.indexOf) {
-            return a.indexOf(v);
-        }
-        for (var i=0; i < a.length; ++i)
-        {
-            if (a[i] === v)
-            {
-                return i;
-            }
-        }
-        return -1;
-    }
-
-    function evalString(s)
-    {
-        return s.replace(/\\t/,'\t').replace(/\\n/,'\n').replace(/\\(['"\\])/g,'$1');
-    }
-
-    /**
-       @return  s trimmed and without quotes
-    */
-    function trimQuotes(s)
-    {
-        return evalString(s.replace(/^['"](.*)['"]$/,'$1')).replace(/^\s+|\s+$/g,'');
-    }
-
-    /**
-       finds first {tag} in string
-       @param re string with regular expression or an empty string to find any tag
-       @return  null or s.match(re) result object where
-       [0] - full tag matched with delimiters (and whitespaces at the begin and the end): { tag }
-       [1] - found part from passed re
-       [index] - position of tag starting { in s
-    */
-    function findTag(re,s)
-    {
-        var openCount = 0;
-        var offset = 0;
-        var ldelim = jSmart.prototype.left_delimiter;
-        var rdelim = jSmart.prototype.right_delimiter;
-        var skipInWS = jSmart.prototype.auto_literal;
-
-        var reAny = /^\s*(.+)\s*$/i;
-        var reTag = re ? new RegExp('^\\s*('+re+')\\s*$','i') : reAny;
-
-        for (var i=0; i<s.length; ++i)
-        {
-            if (s.substr(i,ldelim.length) == ldelim)
-            {
-                if (skipInWS && i+1 < s.length && s.substr(i+1,1).match(/\s/))
-                {
-                    continue;
-                }
-                if (!openCount)
-                {
-                    s = s.slice(i);
-                    offset += parseInt(i);
-                    i = 0;
-                }
-                ++openCount;
-            }
-            else if (s.substr(i,rdelim.length) == rdelim)
-            {
-                if (skipInWS && i-1 >= 0 && s.substr(i-1,1).match(/\s/))
-                {
-                    continue;
-                }
-                if (!--openCount)
-                {
-                    var sTag = s.slice(ldelim.length,i).replace(/[\r\n]/g, ' ');
-                    var found = sTag.match(reTag);
-                    if (found)
-                    {
-                        found.index = offset;
-                        found[0] = s.slice(0,i+rdelim.length);
-                        return found;
-                    }
-                }
-                if (openCount < 0) //ignore any number of unmatched right delimiters
-                {
-                    openCount = 0;
-                }
-            }
-        }
-        return null;
-    }
-
-    function findCloseTag(reClose,reOpen,s)
-    {
-        var sInner = '';
-        var closeTag = null;
-        var openTag = null;
-        var findIndex = 0;
-
-        do
-        {
-            if (closeTag)
-            {
-                findIndex += closeTag[0].length;
-            }
-            closeTag = findTag(reClose,s);
-            if (!closeTag)
-            {
-                throw new Error('Unclosed {'+reOpen+'}');
-            }
-            sInner += s.slice(0,closeTag.index);
-            findIndex += closeTag.index;
-            s = s.slice(closeTag.index+closeTag[0].length);
-
-            openTag = findTag(reOpen,sInner);
-            if (openTag)
-            {
-                sInner = sInner.slice(openTag.index+openTag[0].length);
-            }
-        }
-        while (openTag);
-
-        closeTag.index = findIndex;
-        return closeTag;
-    }
-
-    function findElseTag(reOpen, reClose, reElse, s)
-    {
-        var offset = 0;
-        for (var elseTag=findTag(reElse,s); elseTag; elseTag=findTag(reElse,s))
-        {
-            var openTag = findTag(reOpen,s);
-            if (!openTag || openTag.index > elseTag.index)
-            {
-                elseTag.index += offset;
-                return elseTag;
-            }
-            else
-            {
-                s = s.slice(openTag.index+openTag[0].length);
-                offset += openTag.index+openTag[0].length;
-                var closeTag = findCloseTag(reClose,reOpen,s);
-                s = s.slice(closeTag.index + closeTag[0].length);
-                offset += closeTag.index + closeTag[0].length;
-            }
-        }
-        return null;
-    }
-
-    function execute(code, data)
-    {
-        if (typeof(code) == 'string')
-        {
-            with ({'__code':code})
-            {
-                with (modifiers)
-                {
-                    with (data)
-                    {
-                        try {
-                            return eval(__code);
-                        }
-                        catch(e)
-                        {
-                            throw new Error(e.message + ' in \n' + code);
-                        }
-                    }
-                }
-            }
-        }
-        return code;
-    }
-
-    /**
-     * Execute function when we have a object.
-     *
-     * @param object obj  Object of the function to be called.
-     * @param array  args Arguments to pass to a function.
-     *
-     * @return
-     * @throws Error If function obj does not exists.
-     */
-    function executeByFuncObject(obj, args) {
-        try {
-            return obj.apply(this, args);
-        } catch (e) {
-            throw new Error(e.message);
-        }
-    }
-
-    function assignVar(nm, val, data)
-    {
-        if (nm.match(/\[\]$/))  //ar[] =
-        {
-            data[ nm.replace(/\[\]$/,'') ].push(val);
-        }
-        else
-        {
-            data[nm] = val;
-        }
-    }
-
-    var buildInFunctions =
-        {
-            expression:
-            {
-                parse: function(s, tree)
-                {
-                    var e = parseExpression(s);
-
-                    tree.push({
-                        type: 'build-in',
-                        name: 'expression',
-                        expression: e.tree,
-                        params: parseParams(s.slice(e.value.length).replace(/^\s+|\s+$/g,''))
-                    });
-
-                    return e.tree;
-
-                },
-                process: function(node, data)
-                {
-                    var params = getActualParamValues(node.params, data);
-                    var res = process([node.expression],data);
-
-                    if (findInArray(params, 'nofilter') < 0)
-                    {
-                        for (var i=0; i<default_modifiers.length; ++i)
-                        {
-                            var m = default_modifiers[i];
-                            m.params.__parsed[0] = {type:'text', data:res};
-                            res = process([m],data);
-                        }
-                        if (escape_html)
-                        {
-                            res = modifiers.escape(res);
-                        }
-                        res = applyFilters(varFilters,res);
-
-                        if (tpl_modifiers.length) {
-                            __t = function(){ return res; }
-                            res = process(tpl_modifiers,data);
-                        }
-                    }
-                    return res;
-                }
-            },
-
-            operator:
-            {
-                process: function(node, data)
-                {
-                    var params = getActualParamValues(node.params, data);
-                    var arg1 = params[0];
-
-                    if (node.optype == 'binary')
-                    {
-                        var arg2 = params[1];
-                        if (node.op == '=')
-                        {
-                            getVarValue(node.params.__parsed[0], data, arg2);
-                            return '';
-                        }
-                        else if (node.op.match(/(\+=|-=|\*=|\/=|%=)/))
-                        {
-                            arg1 = getVarValue(node.params.__parsed[0], data);
-                            switch (node.op)
-                            {
-                            case '+=': arg1+=arg2; break;
-                            case '-=': arg1-=arg2; break;
-                            case '*=': arg1*=arg2; break;
-                            case '/=': arg1/=arg2; break;
-                            case '%=': arg1%=arg2; break;
-                            }
-                            return getVarValue(node.params.__parsed[0], data, arg1);
-                        }
-                        else if (node.op.match(/div/))
-                        {
-                            return (node.op!='div')^(arg1%arg2==0);
-                        }
-                        else if (node.op.match(/even/))
-                        {
-                            return (node.op!='even')^((arg1/arg2)%2==0);
-                        }
-                        else if (node.op.match(/xor/))
-                        {
-                            return (arg1||arg2) && !(arg1&&arg2);
-                        }
-
-                        switch (node.op)
-                        {
-                        case '==': return arg1==arg2;
-                        case '!=': return arg1!=arg2;
-                        case '+':  return Number(arg1)+Number(arg2);
-                        case '-':  return Number(arg1)-Number(arg2);
-                        case '*':  return Number(arg1)*Number(arg2);
-                        case '/':  return Number(arg1)/Number(arg2);
-                        case '%':  return Number(arg1)%Number(arg2);
-                        case '&&': return arg1&&arg2;
-                        case '||': return arg1||arg2;
-                        case '<':  return arg1<arg2;
-                        case '<=': return arg1<=arg2;
-                        case '>':  return arg1>arg2;
-                        case '>=': return arg1>=arg2;
-                        case '===': return arg1===arg2;
-                        case '!==': return arg1!==arg2;
-                        }
-                    }
-                    else if (node.op == '!')
-                    {
-                        return !arg1;
-                    }
-                    else
-                    {
-                        var isVar = node.params.__parsed[0].type == 'var';
-                        if (isVar)
-                        {
-                            arg1 = getVarValue(node.params.__parsed[0], data);
-                        }
-                        var v = arg1;
-                        if (node.optype == 'pre-unary')
-                        {
-                            switch (node.op)
-                            {
-                            case '-':  v=-arg1;  break;
-                            case '++': v=++arg1; break;
-                            case '--': v=--arg1; break;
-                            }
-                            if (isVar)
-                            {
-                                getVarValue(node.params.__parsed[0], data, arg1);
-                            }
-                        }
-                        else
-                        {
-                            switch (node.op)
-                            {
-                            case '++': arg1++; break;
-                            case '--': arg1--; break;
-                            }
-                            getVarValue(node.params.__parsed[0], data, arg1);
-                        }
-                        return v;
-                    }
-                }
-            },
-
-            section:
-            {
-                type: 'block',
-                parse: function(params, tree, content)
-                {
-                    var subTree = [];
-                    var subTreeElse = [];
-                    tree.push({
-                        type: 'build-in',
-                        name: 'section',
-                        params: params,
-                        subTree: subTree,
-                        subTreeElse: subTreeElse
-                    });
-
-                    var findElse = findElseTag('section [^}]+', '\/section', 'sectionelse', content);
-                    if (findElse)
-                    {
-                        parse(content.slice(0,findElse.index),subTree);
-                        parse(content.slice(findElse.index+findElse[0].length).replace(/^[\r\n]/,''), subTreeElse);
-                    }
-                    else
-                    {
-                        parse(content, subTree);
-                    }
-                },
-
-                process: function(node, data)
-                {
-                    var params = getActualParamValues(node.params, data);
-
-                    var props = {};
-                    data.smarty.section[params.__get('name',null,0)] = props;
-
-                    var show = params.__get('show',true);
-                    props.show = show;
-                    if (!show)
-                    {
-                        return process(node.subTreeElse, data);
-                    }
-
-                    var from = parseInt(params.__get('start',0));
-                    var to = (params.loop instanceof Object) ? countProperties(params.loop) : isNaN(params.loop) ? 0 : parseInt(params.loop);
-                    var step = parseInt(params.__get('step',1));
-                    var max = parseInt(params.__get('max'));
-                    if (isNaN(max))
-                    {
-                        max = Number.MAX_VALUE;
-                    }
-
-                    if (from < 0)
-                    {
-                        from += to;
-                        if (from < 0)
-                        {
-                            from = 0;
-                        }
-                    }
-                    else if (from >= to)
-                    {
-                        from = to ? to-1 : 0;
-                    }
-
-                    var count = 0;
-                    var loop = 0;
-                    var i = from;
-                    for (; i>=0 && i<to && count<max; i+=step,++count)
-                    {
-                        loop = i;
-                    }
-                    props.total = count;
-                    props.loop = count;  //? - because it is so in Smarty
-
-                    count = 0;
-                    var s = '';
-                    for (i=from; i>=0 && i<to && count<max; i+=step,++count)
-                    {
-                        if (data.smarty['break'])
-                        {
-                            break;
-                        }
-
-                        props.first = (i==from);
-                        props.last = ((i+step)<0 || (i+step)>=to);
-                        props.index = i;
-                        props.index_prev = i-step;
-                        props.index_next = i+step;
-                        props.iteration = props.rownum = count+1;
-
-                        s += process(node.subTree, data);
-                        data.smarty['continue'] = false;
-                    }
-                    data.smarty['break'] = false;
-
-                    if (count)
-                    {
-                        return s;
-                    }
-                    return process(node.subTreeElse, data);
-                }
-            },
-
-            setfilter:
-            {
-                type: 'block',
-                parseParams: function(paramStr)
-                {
-                    return [parseExpression('__t()|' + paramStr).tree];
-                },
-
-                parse: function(params, tree, content)
-                {
-                    tree.push({
-                        type: 'build-in',
-                        name: 'setfilter',
-                        params: params,
-                        subTree: parse(content,[])
-                    });
-                },
-
-                process: function(node, data)
-                {
-                    tpl_modifiers = node.params;
-                    var s = process(node.subTree, data);
-                    tpl_modifiers = [];
-                    return s;
-                }
-            },
-
-            'for':
-            {
-                type: 'block',
-                parseParams: function(paramStr)
-                {
-                    var res = paramStr.match(/^\s*\$(\w+)\s*=\s*([^\s]+)\s*to\s*([^\s]+)\s*(?:step\s*([^\s]+))?\s*(.*)$/);
-                    if (!res)
-                    {
-                        throw new Error('Invalid {for} parameters: '+paramStr);
-                    }
-                    return parseParams("varName='"+res[1]+"' from="+res[2]+" to="+res[3]+" step="+(res[4]?res[4]:'1')+" "+res[5]);
-                },
-
-                parse: function(params, tree, content)
-                {
-                    var subTree = [];
-                    var subTreeElse = [];
-                    tree.push({
-                        type: 'build-in',
-                        name: 'for',
-                        params: params,
-                        subTree: subTree,
-                        subTreeElse: subTreeElse
-                    });
-
-                    var findElse = findElseTag('for\\s[^}]+', '\/for', 'forelse', content);
-                    if (findElse)
-                    {
-                        parse(content.slice(0,findElse.index),subTree);
-                        parse(content.slice(findElse.index+findElse[0].length), subTreeElse);
-                    }
-                    else
-                    {
-                        parse(content, subTree);
-                    }
-                },
-
-                process: function(node, data)
-                {
-                    var params = getActualParamValues(node.params, data);
-                    var from = parseInt(params.__get('from'));
-                    var to = parseInt(params.__get('to'));
-                    var step = parseInt(params.__get('step'));
-                    if (isNaN(step))
-                    {
-                        step = 1;
-                    }
-                    var max = parseInt(params.__get('max'));
-                    if (isNaN(max))
-                    {
-                        max = Number.MAX_VALUE;
-                    }
-
-                    var count = 0;
-                    var s = '';
-                    var total = Math.min( Math.ceil( ((step > 0 ? to-from : from-to)+1) / Math.abs(step)  ), max);
-
-                    for (var i=parseInt(params.from); count<total; i+=step,++count)
-                    {
-                        if (data.smarty['break'])
-                        {
-                            break;
-                        }
-                        data[params.varName] = i;
-                        s += process(node.subTree, data);
-                        data.smarty['continue'] = false;
-                    }
-                    data.smarty['break'] = false;
-
-                    if (!count)
-                    {
-                        s = process(node.subTreeElse, data);
-                    }
-                    return s;
-                }
-            },
-
-            'if':
-            {
-                type: 'block',
-                parse: function(params, tree, content)
-                {
-                    var subTreeIf = [];
-                    var subTreeElse = [];
-                    tree.push({
-                        type: 'build-in',
-                        name: 'if',
-                        params: params,
-                        subTreeIf: subTreeIf,
-                        subTreeElse: subTreeElse
-                    });
-
-                    var findElse = findElseTag('if\\s+[^}]+', '\/if', 'else[^}]*', content);
-                    if (findElse)
-                    {
-                        parse(content.slice(0,findElse.index),subTreeIf);
-
-                        content = content.slice(findElse.index+findElse[0].length);
-                        var findElseIf = findElse[1].match(/^else\s*if(.*)/);
-                        if (findElseIf)
-                        {
-                            buildInFunctions['if'].parse(parseParams(findElseIf[1]), subTreeElse, content.replace(/^\n/,''));
-                        }
-                        else
-                        {
-                            parse(content.replace(/^\n/,''), subTreeElse);
-                        }
-                    }
-                    else
-                    {
-                        parse(content, subTreeIf);
-                    }
-                },
-
-                process: function(node, data) {
-                    var value = getActualParamValues(node.params,data)[0];
-                    // Zero length arrays or empty associative arrays are false in PHP.
-                    if (value && !((value instanceof Array && value.length == 0)
-                        || (typeof value == 'object' && isEmptyObject(value)))
-                    ) {
-                        return process(node.subTreeIf, data);
-                    } else {
-                        return process(node.subTreeElse, data);
-                    }
-                }
-            },
-
-            foreach:
-            {
-                type: 'block',
-                parseParams: function(paramStr)
-                {
-                    var params = {};
-                    var res = paramStr.match(/^\s*([$].+)\s*as\s*[$](\w+)\s*(=>\s*[$](\w+))?\s*$/i);
-                    if (res) //Smarty 3.x syntax => Smarty 2.x syntax
-                    {
-                        paramStr = 'from='+res[1] + ' item='+(res[4]||res[2]);
-                        if (res[4])
-                        {
-                            paramStr += ' key='+res[2];
-                        }
-                    }
-                    return parseParams(paramStr);
-                },
-
-                parse: function(params, tree, content)
-                {
-                    var subTree = [];
-                    var subTreeElse = [];
-                    tree.push({
-                        type: 'build-in',
-                        name: 'foreach',
-                        params: params,
-                        subTree: subTree,
-                        subTreeElse: subTreeElse
-                    });
-
-                    var findElse = findElseTag('foreach\\s[^}]+', '\/foreach', 'foreachelse', content);
-                    if (findElse)
-                    {
-                        parse(content.slice(0,findElse.index),subTree);
-                        parse(content.slice(findElse.index+findElse[0].length).replace(/^[\r\n]/,''), subTreeElse);
-                    }
-                    else
-                    {
-                        parse(content, subTree);
-                    }
-                },
-
-                process: function(node, data)
-                {
-                    var params = getActualParamValues(node.params, data);
-                    var a = params.from;
-                    if (typeof a == 'undefined')
-                    {
-                        a = [];
-                    }
-                    if (typeof a != 'object')
-                    {
-                        a = [a];
-                    }
-
-                    var total = countProperties(a);
-
-                    data[params.item+'__total'] = total;
-                    if ('name' in params)
-                    {
-                        data.smarty.foreach[params.name] = {};
-                        data.smarty.foreach[params.name].total = total;
-                    }
-
-                    var s = '';
-                    var i=0;
-                    for (var key in a)
-                    {
-                        if (!a.hasOwnProperty(key))
-                        {
-                            continue;
-                        }
-
-                        if (data.smarty['break'])
-                        {
-                            break;
-                        }
-
-                        data[params.item+'__key'] = isNaN(key) ? key : parseInt(key);
-                        if ('key' in params)
-                        {
-                            data[params.key] = data[params.item+'__key'];
-                        }
-                        data[params.item] = a[key];
-                        data[params.item+'__index'] = parseInt(i);
-                        data[params.item+'__iteration'] = parseInt(i+1);
-                        data[params.item+'__first'] = (i===0);
-                        data[params.item+'__last'] = (i==total-1);
-
-                        if ('name' in params)
-                        {
-                            data.smarty.foreach[params.name].index = parseInt(i);
-                            data.smarty.foreach[params.name].iteration = parseInt(i+1);
-                            data.smarty.foreach[params.name].first = (i===0) ? 1 : '';
-                            data.smarty.foreach[params.name].last = (i==total-1) ? 1 : '';
-                        }
-
-                        ++i;
-
-                        s += process(node.subTree, data);
-                        data.smarty['continue'] = false;
-                    }
-                    data.smarty['break'] = false;
-
-                    data[params.item+'__show'] = (i>0);
-                    if (params.name)
-                    {
-                        data.smarty.foreach[params.name].show = (i>0) ? 1 : '';
-                    }
-                    if (i>0)
-                    {
-                        return s;
-                    }
-                    return process(node.subTreeElse, data);
-                }
-            },
-
-            'function':
-            {
-                type: 'block',
-                parse: function(params, tree, content)
-                {
-                    var subTree = [];
-                    plugins[trimQuotes(params.name?params.name:params[0])] =
-                        {
-                            type: 'function',
-                            subTree: subTree,
-                            defautParams: params,
-                            process: function(params, data)
-                            {
-                                var defaults = getActualParamValues(this.defautParams,data);
-                                delete defaults.name;
-                                return process(this.subTree, obMerge({},data,defaults,params));
-                            }
-                        };
-                    parse(content, subTree);
-                }
-            },
-
-            php:
-            {
-                type: 'block',
-                parse: function(params, tree, content) {}
-            },
-
-            'extends':
-            {
-                type: 'function',
-                parse: function(params, tree)
-                {
-                    tree.splice(0,tree.length);
-                    getTemplate(trimQuotes(params.file?params.file:params[0]),tree);
-                }
-            },
-
-            block:
-            {
-                type: 'block',
-                parse: function(params, tree, content)
-                {
-                    tree.push({
-                        type: 'build-in',
-                        name: 'block',
-                        params: params
-                    });
-                    params.append = findInArray(params,'append') >= 0;
-                    params.prepend = findInArray(params,'prepend') >= 0;
-                    params.hide = findInArray(params,'hide') >= 0;
-                    params.hasChild = params.hasParent = false;
-
-                    onParseVar = function(nm)
-                    {
-                        if (nm.match(/^\s*[$]smarty.block.child\s*$/))
-                        {
-                            params.hasChild = true;
-                        }
-                        if (nm.match(/^\s*[$]smarty.block.parent\s*$/))
-                        {
-                            params.hasParent = true;
-                        }
-                    }
-                    var tree = parse(content, []);
-                    onParseVar = function(nm) {}
-
-                    var blockName = trimQuotes(params.name?params.name:params[0]);
-                    if (!(blockName in blocks))
-                    {
-                        blocks[blockName] = [];
-                    }
-                    blocks[blockName].push({tree:tree, params:params});
-                },
-
-                process: function(node, data)
-                {
-                    data.smarty.block.parent = data.smarty.block.child = '';
-                    var blockName = trimQuotes(node.params.name?node.params.name:node.params[0]);
-                    this.processBlocks(blocks[blockName], blocks[blockName].length-1, data);
-                    return data.smarty.block.child;
-                },
-
-                processBlocks: function(blockAncestry, i, data)
-                {
-                    if (!i && blockAncestry[i].params.hide) {
-                        data.smarty.block.child = '';
-                        return;
-                    }
-                    var append = true;
-                    var prepend = false;
-                    for (; i>=0; --i)
-                    {
-                        if (blockAncestry[i].params.hasParent)
-                        {
-                            var tmpChild = data.smarty.block.child;
-                            data.smarty.block.child = '';
-                            this.processBlocks(blockAncestry, i-1, data);
-                            data.smarty.block.parent = data.smarty.block.child;
-                            data.smarty.block.child = tmpChild;
-                        }
-
-                        var tmpChild = data.smarty.block.child;
-                        var s = process(blockAncestry[i].tree, data);
-                        data.smarty.block.child = tmpChild;
-
-                        if (blockAncestry[i].params.hasChild)
-                        {
-                            data.smarty.block.child = s;
-                        }
-                        else if (append)
-                        {
-                            data.smarty.block.child = s + data.smarty.block.child;
-                        }
-                        else if (prepend)
-                        {
-                            data.smarty.block.child += s;
-                        }
-                        append = blockAncestry[i].params.append;
-                        prepend = blockAncestry[i].params.prepend;
-                    }
-                }
-            },
-
-            strip:
-            {
-                type: 'block',
-                parse: function(params, tree, content)
-                {
-                    parse(content.replace(/[ \t]*[\r\n]+[ \t]*/g, ''), tree);
-                }
-            },
-
-            literal:
-            {
-                type: 'block',
-                parse: function(params, tree, content)
-                {
-                    parseText(content, tree);
-                }
-            },
-
-            ldelim:
-            {
-                type: 'function',
-                parse: function(params, tree)
-                {
-                    parseText(jSmart.prototype.left_delimiter, tree);
-                }
-            },
-
-            rdelim:
-            {
-                type: 'function',
-                parse: function(params, tree)
-                {
-                    parseText(jSmart.prototype.right_delimiter, tree);
-                }
-            },
-
-            'while':
-            {
-                type: 'block',
-                parse: function(params, tree, content)
-                {
-                    tree.push({
-                        type: 'build-in',
-                        name: 'while',
-                        params: params,
-                        subTree: parse(content, [])
-                    });
-                },
-
-                process: function(node, data)
-                {
-                    var s = '';
-                    while (getActualParamValues(node.params,data)[0])
-                    {
-                        if (data.smarty['break'])
-                        {
-                            break;
-                        }
-                        s += process(node.subTree, data);
-                        data.smarty['continue'] = false;
-                    }
-                    data.smarty['break'] = false;
-                    return s;
-                }
-            }
-        };
-
-    var plugins = {};
-    var modifiers = {};
-    var files = {};
-    var blocks = null;
-    var scripts = null;
-    var tpl_modifiers = [];
-
-    function parse(s, tree)
-    {
-        for (var openTag=findTag('',s); openTag; openTag=findTag('',s))
-        {
-            if (openTag.index)
-            {
-                parseText(s.slice(0,openTag.index),tree);
-            }
-            s = s.slice(openTag.index + openTag[0].length);
-
-            var res = openTag[1].match(/^\s*(\w+)(.*)$/);
-            if (res)         //function
-            {
-                var nm = res[1];
-                var paramStr = (res.length>2) ? res[2].replace(/^\s+|\s+$/g,'') : '';
-
-                if (nm in buildInFunctions)
-                {
-                    var buildIn = buildInFunctions[nm];
-                    var params = ('parseParams' in buildIn ? buildIn.parseParams : parseParams)(paramStr);
-                    if (buildIn.type == 'block')
-                    {
-                        s = s.replace(/^\n/,'');  //remove new line after block open tag (like in Smarty)
-                        var closeTag = findCloseTag('\/'+nm, nm+' +[^}]*', s);
-                        buildIn.parse(params, tree, s.slice(0,closeTag.index));
-                        s = s.slice(closeTag.index+closeTag[0].length);
-                    }
-                    else
-                    {
-                        buildIn.parse(params, tree);
-                        if (nm == 'extends')
-                        {
-                            tree = []; //throw away further parsing except for {block}
-                        }
-                    }
-                    s = s.replace(/^\n/,'');
-                }
-                else if (nm in plugins)
-                {
-                    var plugin = plugins[nm];
-                    if (plugin.type == 'block')
-                    {
-                        var closeTag = findCloseTag('\/'+nm, nm+' +[^}]*', s);
-                        parsePluginBlock(nm, parseParams(paramStr), tree, s.slice(0,closeTag.index));
-                        s = s.slice(closeTag.index+closeTag[0].length);
-                    }
-                    else if (plugin.type == 'function')
-                    {
-                        parsePluginFunc(nm, parseParams(paramStr), tree);
-                    }
-                    if (nm=='append' || nm=='assign' || nm=='capture' || nm=='eval' || nm=='include')
-                    {
-                        s = s.replace(/^\n/,'');
-                    }
-                }
-                else   //variable
-                {
-                    buildInFunctions.expression.parse(openTag[1],tree);
-                }
-            }
-            else         //variable
-            {
-                var node = buildInFunctions.expression.parse(openTag[1],tree);
-                if (node.type=='build-in' && node.name=='operator' && node.op == '=')
-                {
-                    s = s.replace(/^\n/,'');
-                }
-            }
-        }
-        if (s)
-        {
-            parseText(s, tree);
-        }
-        return tree;
-    }
-
-    function parseText(text, tree)
-    {
-        if (parseText.parseEmbeddedVars)
-        {
-            var re = /([$][\w@]+)|`([^`]*)`/;
-            for (var found=re.exec(text); found; found=re.exec(text))
-            {
-                tree.push({type: 'text', data: text.slice(0,found.index)});
-                tree.push( parseExpression(found[1] ? found[1] : found[2]).tree );
-                text = text.slice(found.index + found[0].length);
-            }
-        }
-        tree.push({type: 'text', data: text});
-        return tree;
-    }
-
-    function parseFunc(name, params, tree)
-    {
-        params.__parsed.name = parseText(name,[])[0];
-        tree.push({
-            type: 'plugin',
-            name: '__func',
-            params: params
-        });
-        return tree;
-    }
-
-    function parseOperator(op, type, precedence, tree)
-    {
-        tree.push({
-            type: 'build-in',
-            name: 'operator',
-            op: op,
-            optype: type,
-            precedence: precedence,
-            params: {}
-        });
-    }
-
-    function parseVar(s, e, nm)
-    {
-        var rootName = e.token;
-        var parts = [{type:'text', data:nm.replace(/^(\w+)@(key|index|iteration|first|last|show|total)/gi, "$1__$2")}];
-
-        var re = /^(?:\.|\s*->\s*|\[\s*)/;
-        for (var op=s.match(re); op; op=s.match(re))
-        {
-            e.token += op[0];
-            s = s.slice(op[0].length);
-
-            var eProp = {value:'', tree:[]};
-            if (op[0].match(/\[/))
-            {
-                eProp = parseExpression(s);
-                if (eProp)
-                {
-                    e.token += eProp.value;
-                    parts.push( eProp.tree );
-                    s = s.slice(eProp.value.length);
-                }
-
-                var closeOp = s.match(/\s*\]/);
-                if (closeOp)
-                {
-                    e.token += closeOp[0];
-                    s = s.slice(closeOp[0].length);
-                }
-            }
-            else
-            {
-                var parseMod = parseModifiers.stop;
-                parseModifiers.stop = true;
-                if (lookUp(s,eProp))
-                {
-                    e.token += eProp.value;
-                    var part = eProp.tree[0];
-                    if (part.type == 'plugin' && part.name == '__func')
-                    {
-                        part.hasOwner = true;
-                    }
-                    parts.push( part );
-                    s = s.slice(eProp.value.length);
-                }
-                else
-                {
-                    eProp = false;
-                }
-                parseModifiers.stop = parseMod;
-            }
-
-            if (!eProp)
-            {
-                parts.push({type:'text', data:''});
-            }
-        }
-
-        e.tree.push({type: 'var', parts: parts});
-
-        e.value += e.token.substr(rootName.length);
-
-        onParseVar(e.token);
-
-        return s;
-    }
-
-    function onParseVar(nm)  {}
-
-
-    var tokens =
-        [
-            {
-                re: /^\$([\w@]+)/,   //var
-                parse: function(e, s)
-                {
-                    parseModifiers(parseVar(s, e, RegExp.$1), e);
-                }
-            },
-            {
-                re: /^(true|false)/i,  //bool
-                parse: function(e, s)
-                {
-                    parseText(e.token.match(/true/i) ? '1' : '', e.tree);
-                }
-            },
-            {
-                re: /^'([^'\\]*(?:\\.[^'\\]*)*)'/, //single quotes
-                parse: function(e, s)
-                {
-                    parseText(evalString(RegExp.$1), e.tree);
-                    parseModifiers(s, e);
-                }
-            },
-            {
-                re: /^"([^"\\]*(?:\\.[^"\\]*)*)"/,  //double quotes
-                parse: function(e, s)
-                {
-                    var v = evalString(RegExp.$1);
-                    var isVar = v.match(tokens[0].re);
-                    if (isVar)
-                    {
-                        var eVar = {token:isVar[0], tree:[]};
-                        parseVar(v, eVar, isVar[1]);
-                        if (eVar.token.length == v.length)
-                        {
-                            e.tree.push( eVar.tree[0] );
-                            return;
-                        }
-                    }
-                    parseText.parseEmbeddedVars = true;
-                    e.tree.push({
-                        type: 'plugin',
-                        name: '__quoted',
-                        params: {__parsed: parse(v,[])}
-                    });
-                    parseText.parseEmbeddedVars = false;
-                    parseModifiers(s, e);
-                }
-            },
-            {
-                re: /^(\w+)\s*[(]([)]?)/,  //func()
-                parse: function(e, s)
-                {
-                    var fnm = RegExp.$1;
-                    var noArgs = RegExp.$2;
-                    var params = parseParams(noArgs?'':s,/^\s*,\s*/);
-                    parseFunc(fnm, params, e.tree);
-                    e.value += params.toString();
-                    parseModifiers(s.slice(params.toString().length), e);
-                }
-            },
-            {
-                re: /^\s*\(\s*/,  //expression in parentheses
-                parse: function(e, s)
-                {
-                    var parens = [];
-                    e.tree.push(parens);
-                    parens.parent = e.tree;
-                    e.tree = parens;
-                }
-            },
-            {
-                re: /^\s*\)\s*/,
-                parse: function(e, s)
-                {
-                    if (e.tree.parent) //it may be the end of func() or (expr)
-                    {
-                        e.tree = e.tree.parent;
-                    }
-                }
-            },
-            {
-                re: /^\s*(\+\+|--)\s*/,
-                parse: function(e, s)
-                {
-                    if (e.tree.length && e.tree[e.tree.length-1].type == 'var')
-                    {
-                        parseOperator(RegExp.$1, 'post-unary', 1, e.tree);
-                    }
-                    else
-                    {
-                        parseOperator(RegExp.$1, 'pre-unary', 1, e.tree);
-                    }
-                }
-            },
-            {
-                re: /^\s*(===|!==|==|!=)\s*/,
-                parse: function(e, s)
-                {
-                    parseOperator(RegExp.$1, 'binary', 6, e.tree);
-                }
-            },
-            {
-                re: /^\s+(eq|ne|neq)\s+/i,
-                parse: function(e, s)
-                {
-                    var op = RegExp.$1.replace(/ne(q)?/,'!=').replace(/eq/,'==');
-                    parseOperator(op, 'binary', 6, e.tree);
-                }
-            },
-            {
-                re: /^\s*!\s*/,
-                parse: function(e, s)
-                {
-                    parseOperator('!', 'pre-unary', 2, e.tree);
-                }
-            },
-            {
-                re: /^\s+not\s+/i,
-                parse: function(e, s)
-                {
-                    parseOperator('!', 'pre-unary', 2, e.tree);
-                }
-            },
-            {
-                re: /^\s*(=|\+=|-=|\*=|\/=|%=)\s*/,
-                parse: function(e, s)
-                {
-                    parseOperator(RegExp.$1, 'binary', 10, e.tree);
-                }
-            },
-            {
-                re: /^\s*(\*|\/|%)\s*/,
-                parse: function(e, s)
-                {
-                    parseOperator(RegExp.$1, 'binary', 3, e.tree);
-                }
-            },
-            {
-                re: /^\s+mod\s+/i,
-                parse: function(e, s)
-                {
-                    parseOperator('%', 'binary', 3, e.tree);
-                }
-            },
-            {
-                re: /^\s*(\+|-)\s*/,
-                parse: function(e, s)
-                {
-                    if (!e.tree.length || e.tree[e.tree.length-1].name == 'operator')
-                    {
-                        parseOperator(RegExp.$1, 'pre-unary', 4, e.tree);
-                    }
-                    else
-                    {
-                        parseOperator(RegExp.$1, 'binary', 4, e.tree);
-                    }
-                }
-            },
-            {
-                re: /^\s*(<=|>=|<>|<|>)\s*/,
-                parse: function(e, s)
-                {
-                    parseOperator(RegExp.$1.replace(/<>/,'!='), 'binary', 5, e.tree);
-                }
-            },
-            {
-                re: /^\s+(lt|lte|le|gt|gte|ge)\s+/i,
-                parse: function(e, s)
-                {
-                    var op = RegExp.$1.replace(/lt/,'<').replace(/l(t)?e/,'<=').replace(/gt/,'>').replace(/g(t)?e/,'>=');
-                    parseOperator(op, 'binary', 5, e.tree);
-                }
-            },
-            {
-                re: /^\s+(is\s+(not\s+)?div\s+by)\s+/i,
-                parse: function(e, s)
-                {
-                    parseOperator(RegExp.$2?'div_not':'div', 'binary', 7, e.tree);
-                }
-            },
-            {
-                re: /^\s+is\s+(not\s+)?(even|odd)(\s+by\s+)?\s*/i,
-                parse: function(e, s)
-                {
-                    var op = RegExp.$1 ? ((RegExp.$2=='odd')?'even':'even_not') : ((RegExp.$2=='odd')?'even_not':'even');
-                    parseOperator(op, 'binary', 7, e.tree);
-                    if (!RegExp.$3)
-                    {
-                        parseText('1', e.tree);
-                    }
-                }
-            },
-            {
-                re: /^\s*(&&)\s*/,
-                parse: function(e, s)
-                {
-                    parseOperator(RegExp.$1, 'binary', 8, e.tree);
-                }
-            },
-            {
-                re: /^\s*(\|\|)\s*/,
-                parse: function(e, s)
-                {
-                    parseOperator(RegExp.$1, 'binary', 9, e.tree);
-                }
-            },
-            {
-                re: /^\s+and\s+/i,
-                parse: function(e, s)
-                {
-                    parseOperator('&&', 'binary', 11, e.tree);
-                }
-            },
-            {
-                re: /^\s+xor\s+/i,
-                parse: function(e, s)
-                {
-                    parseOperator('xor', 'binary', 12, e.tree);
-                }
-            },
-            {
-                re: /^\s+or\s+/i,
-                parse: function(e, s)
-                {
-                    parseOperator('||', 'binary', 13, e.tree);
-                }
-            },
-            {
-                re: /^#(\w+)#/,  //config variable
-                parse: function(e, s)
-                {
-                    var eVar = {token:'$smarty',tree:[]};
-                    parseVar('.config.'+RegExp.$1, eVar, 'smarty');
-                    e.tree.push( eVar.tree[0] );
-                    parseModifiers(s, e);
-                }
-            },
-            {
-                re: /^\s*\[\s*/,   //array
-                parse: function(e, s)
-                {
-                    var params = parseParams(s, /^\s*,\s*/, /^('[^'\\]*(?:\\.[^'\\]*)*'|"[^"\\]*(?:\\.[^"\\]*)*"|\w+)\s*=>\s*/);
-                    parsePluginFunc('__array',params,e.tree);
-                    e.value += params.toString();
-                    var paren = s.slice(params.toString().length).match(/\s*\]/);
-                    if (paren)
-                    {
-                        e.value += paren[0];
-                    }
-                }
-            },
-            {
-                re: /^[\d.]+/, //number
-                parse: function(e, s)
-                {
-                    if (e.token.indexOf('.') > -1) {
-                        e.token = parseFloat(e.token);
-                    } else {
-                        e.token = parseInt(e.token, 10);
-                    }
-                    parseText(e.token, e.tree);
-                    parseModifiers(s, e);
-                }
-            },
-            {
-                re: /^\w+/, //static
-                parse: function(e, s)
-                {
-                    parseText(e.token, e.tree);
-                    parseModifiers(s, e);
-                }
-            }
-        ];
-
-    function parseModifiers(s, e)
-    {
-        if (parseModifiers.stop)
-        {
-            return;
-        }
-
-        var modifier = s.match(/^\|(\w+)/);
-        if (!modifier)
-        {
-            return;
-        }
-
-        e.value += modifier[0];
-
-        var fnm = modifier[1]=='default' ? 'defaultValue' : modifier[1];
-        s = s.slice(modifier[0].length).replace(/^\s+/,'');
-
-        parseModifiers.stop = true;
-        var params = [];
-        for (var colon=s.match(/^\s*:\s*/); colon; colon=s.match(/^\s*:\s*/))
-        {
-            e.value += s.slice(0,colon[0].length);
-            s = s.slice(colon[0].length);
-
-            var param = {value:'', tree:[]};
-            if (lookUp(s, param))
-            {
-                e.value += param.value;
-                params.push(param.tree[0]);
-                s = s.slice(param.value.length);
-            }
-            else
-            {
-                parseText('',params);
-            }
-        }
-        parseModifiers.stop = false;
-
-        params.unshift(e.tree.pop());  //modifiers have the highest priority
-        e.tree.push(parseFunc(fnm,{__parsed:params},[])[0]);
-
-        parseModifiers(s, e);  //modifiers can be combined
-    }
-
-    function lookUp(s,e)
-    {
-        if (!s)
-        {
-            return false;
-        }
-
-        if (s.substr(0,jSmart.prototype.left_delimiter.length)==jSmart.prototype.left_delimiter)
-        {
-            var tag = findTag('',s);
-            if (tag)
-            {
-                e.token = tag[0];
-                e.value += tag[0];
-                parse(tag[0], e.tree);
-                parseModifiers(s.slice(e.value.length), e);
-                return true;
-            }
-        }
-
-        for (var i=0; i<tokens.length; ++i)
-        {
-            if (s.match(tokens[i].re))
-            {
-                e.token = RegExp.lastMatch;
-                e.value += RegExp.lastMatch;
-                tokens[i].parse(e, s.slice(e.token.length));
-                return true;
-            }
-        }
-        return false;
-    }
-
-    function bundleOp(i, tree, precedence)
-    {
-        var op = tree[i];
-        if (op.name == 'operator' && op.precedence == precedence && !op.params.__parsed)
-        {
-            if (op.optype == 'binary')
-            {
-                op.params.__parsed = [tree[i-1],tree[i+1]];
-                tree.splice(i-1,3,op);
-                return true;
-            }
-            else if (op.optype == 'post-unary')
-            {
-                op.params.__parsed = [tree[i-1]];
-                tree.splice(i-1,2,op);
-                return true;
-            }
-
-            op.params.__parsed = [tree[i+1]];
-            tree.splice(i,2,op);
-        }
-        return false;
-    }
-
-    function composeExpression(tree)
-    {
-        var i = 0;
-        for (i=0; i<tree.length; ++i)
-        {
-            if (tree[i] instanceof Array)
-            {
-                tree[i] = composeExpression(tree[i])
-            }
-        }
-
-        for (var precedence=1; precedence<14; ++precedence)
-        {
-            if (precedence==2 || precedence==10)
-            {
-                for (i=tree.length; i>0; --i)
-                {
-                    i -= bundleOp(i-1, tree, precedence);
-                }
-            }
-            else
-            {
-                for (i=0; i<tree.length; ++i)
-                {
-                    i -= bundleOp(i, tree, precedence);
-                }
-            }
-        }
-        return tree[0]; //only one node must be left
-    }
-
-    function parseExpression(s)
-    {
-        var e = { value:'', tree:[] };
-        while (lookUp(s.slice(e.value.length), e)){}
-        if (!e.tree.length)
-        {
-            return false;
-        }
-        e.tree = composeExpression(e.tree);
-        return e;
-    }
-
-    function parseParams(paramsStr, reDelim, reName)
-    {
-        var s = paramsStr.replace(/\n/g,' ').replace(/^\s+|\s+$/g,'');
-        var params = [];
-        params.__parsed = [];
-        var paramsStr = '';
-
-        if (!s)
-        {
-            return params;
-        }
-
-        if (!reDelim)
-        {
-            reDelim = /^\s+/;
-            reName = /^(\w+)\s*=\s*/;
-        }
-
-        while (s)
-        {
-            var nm = null;
-            if (reName)
-            {
-                var foundName = s.match(reName);
-                if (foundName)
-                {
-                    nm = trimQuotes(foundName[1]);
-                    paramsStr += s.slice(0,foundName[0].length);
-                    s = s.slice(foundName[0].length);
-                }
-            }
-
-            var param = parseExpression(s);
-            if (!param)
-            {
-                break;
-            }
-
-            if (nm)
-            {
-                params[nm] = param.value;
-                params.__parsed[nm] = param.tree;
-            }
-            else
-            {
-                params.push(param.value);
-                params.__parsed.push(param.tree);
-            }
-
-            paramsStr += s.slice(0,param.value.length);
-            s = s.slice(param.value.length);
-
-            var foundDelim = s.match(reDelim);
-            if (foundDelim)
-            {
-                paramsStr += s.slice(0,foundDelim[0].length);
-                s = s.slice(foundDelim[0].length);
-            }
-            else
-            {
-                break;
-            }
-        }
-        params.toString = function() { return paramsStr; }
-        return params;
-    }
-
-    function parsePluginBlock(name, params, tree, content)
-    {
-        tree.push({
-            type: 'plugin',
-            name: name,
-            params: params,
-            subTree: parse(content,[])
-        });
-    }
-
-    function parsePluginFunc(name, params, tree)
-    {
-        tree.push({
-            type: 'plugin',
-            name: name,
-            params: params
-        });
-    }
-
-    function getActualParamValues(params,data)
-    {
-        var actualParams = [];
-        for (var nm in params.__parsed)
-        {
-            if (params.__parsed.hasOwnProperty(nm))
-            {
-                var v = process([params.__parsed[nm]], data);
-                actualParams[nm] = v;
-            }
-        }
-
-        actualParams.__get = function(nm,defVal,id)
-        {
-            if (nm in actualParams && typeof(actualParams[nm]) != 'undefined')
-            {
-                return actualParams[nm];
-            }
-            if (typeof(id)!='undefined' && typeof(actualParams[id]) != 'undefined')
-            {
-                return actualParams[id];
-            }
-            if (defVal === null)
-            {
-                throw new Error("The required attribute '"+nm+"' is missing");
-            }
-            return defVal;
-        };
-        return actualParams;
-    }
-
-    /**
-     * Returns boolean true if object is empty otherwise false.
-     *
-     * @param object hash Object you are testing against.
-     *
-     * @return boolean
-     */
-    function isEmptyObject(hash) {
-        for (var i in hash) {
-            if (hash.hasOwnProperty(i)) {
-                return false;
-            }
-        }
-        return true;
-    }
-
-    function getVarValue(node, data, val)
-    {
-        var v = data;
-        var nm = '';
-        for (var i=0; i<node.parts.length; ++i)
-        {
-            var part = node.parts[i];
-            if (part.type == 'plugin' && part.name == '__func' && part.hasOwner)
-            {
-                data.__owner = v;
-                v = process([node.parts[i]],data);
-                delete data.__owner;
-            }
-            else
-            {
-                nm = process([part],data);
-
-                //section name
-                if (nm in data.smarty.section && part.type=='text' && process([node.parts[0]],data)!='smarty')
-                {
-                    nm = data.smarty.section[nm].index;
-                }
-
-                //add to array
-                if (!nm && typeof val != 'undefined' && v instanceof Array)
-                {
-                    nm = v.length;
-                }
-
-                //set new value
-                if (typeof val != 'undefined' && i==node.parts.length-1)
-                {
-                    v[nm] = val;
-                }
-
-                if (typeof v == 'object' && v !== null && nm in v)
-                {
-                    v = v[nm];
-                }
-                else
-                {
-                    if (typeof val == 'undefined')
-                    {
-                        return val;
-                    }
-                    v[nm] = {};
-                    v = v[nm];
-                }
-            }
-        }
-        return v;
-    }
-
-    function process(tree, data)
-    {
-        var res = '';
-        for (var i=0; i<tree.length; ++i)
-        {
-            var s = '';
-            var node = tree[i];
-            if (node.type == 'text')
-            {
-                s = node.data;
-            }
-            else if (node.type == 'var')
-            {
-                s = getVarValue(node,data);
-            }
-            else if (node.type == 'build-in')
-            {
-                s = buildInFunctions[node.name].process(node,data);
-            }
-            else if (node.type == 'plugin')
-            {
-                var plugin = plugins[node.name];
-                if (plugin.type == 'block')
-                {
-                    var repeat = {value:true};
-                    plugin.process(getActualParamValues(node.params,data), '', data, repeat);
-                    while (repeat.value)
-                    {
-                        repeat.value = false;
-                        s += plugin.process(
-                            getActualParamValues(node.params,data),
-                            process(node.subTree, data),
-                            data,
-                            repeat
-                        );
-                    }
-                }
-                else if (plugin.type == 'function')
-                {
-                    s = plugin.process(getActualParamValues(node.params,data), data);
-                }
-            }
-            if (typeof s == 'boolean')
-            {
-                s = s ? '1' : '';
-            }
-            if (s == null) {
-                s = '';
-            }
-            if (tree.length == 1)
-            {
-                return s;
-            }
-            res += s!==null ? s : '';
-
-            if (data.smarty['continue'] || data.smarty['break'])
-            {
-                return res;
-            }
-        }
-        return res;
-    }
-
-    function getTemplate(name, tree, nocache)
-    {
-        if (nocache || !(name in files))
-        {
-            var tpl = jSmart.prototype.getTemplate(name);
-            if (typeof(tpl) != 'string')
-            {
-                throw new Error('No template for '+ name);
-            }
-            parse(applyFilters(jSmart.prototype.filters_global.pre, stripComments(tpl.replace(/\r\n/g,'\n'))), tree);
-            files[name] = tree;
-        }
-        else
-        {
-            tree = files[name];
-        }
-        return tree;
-    }
-
-    function stripComments(s)
-    {
-        var sRes = '';
-        for (var openTag=s.match(/{\*/); openTag; openTag=s.match(/{\*/))
-        {
-            sRes += s.slice(0,openTag.index);
-            s = s.slice(openTag.index+openTag[0].length);
-            var closeTag = s.match(/\*}/);
-            if (!closeTag)
-            {
-                throw new Error('Unclosed {*');
-            }
-            s = s.slice(closeTag.index+closeTag[0].length);
-        }
-        return sRes + s;
-    }
-
-    function applyFilters(filters, s)
-    {
-        for (var i=0; i<filters.length; ++i)
-        {
-            s = filters[i](s);
-        }
-        return s;
-    }
-
-
-    jSmart = function(tpl)
-    {
-        this.tree = [];
-        this.tree.blocks = {};
-        this.scripts = {};
-        this.default_modifiers = [];
-        this.filters = {'variable':[], 'post':[]};
-        this.smarty = {
-            'smarty': {
-                block: {},
-                'break': false,
-                capture: {},
-                'continue': false,
-                counter: {},
-                cycle: {},
-                foreach: {},
-                section: {},
-                now: Math.floor( (new Date()).getTime()/1000 ),
-                'const': {},
-                config: {},
-                current_dir: '/',
-                template: '',
-                ldelim: jSmart.prototype.left_delimiter,
-                rdelim: jSmart.prototype.right_delimiter,
-                version: '2.15.0'
-            }
-        };
-        blocks = this.tree.blocks;
-        parse(
-            applyFilters(jSmart.prototype.filters_global.pre, stripComments((new String(tpl?tpl:'')).replace(/\r\n/g,'\n'))),
-            this.tree
-        );
-    };
-
-    jSmart.prototype.fetch = function(data)
-    {
-        blocks = this.tree.blocks;
-        scripts = this.scripts;
-        escape_html = this.escape_html;
-        default_modifiers = jSmart.prototype.default_modifiers_global.concat(this.default_modifiers);
-        this.data = obMerge((typeof data == 'object') ? data : {}, this.smarty);
-        varFilters = jSmart.prototype.filters_global.variable.concat(this.filters.variable);
-        var res = process(this.tree, this.data);
-        if (jSmart.prototype.debugging)
-        {
-            plugins.debug.process([],this.data);
-        }
-        return applyFilters(jSmart.prototype.filters_global.post.concat(this.filters.post), res);
-    };
-
-    jSmart.prototype.escape_html = false;
-
-    /**
-       @param type  valid values are 'function', 'block', 'modifier'
-       @param callback  func(params,data)  or  block(params,content,data,repeat)
-    */
-    jSmart.prototype.registerPlugin = function(type, name, callback)
-    {
-        if (type == 'modifier')
-        {
-            modifiers[name] = callback;
-        }
-        else
-        {
-            plugins[name] = {'type': type, 'process': callback};
-        }
-    };
-
-    /**
-       @param type  valid values are 'pre', 'variable', 'post'
-       @param callback function(textValue) { ... }
-    */
-    jSmart.prototype.registerFilter = function(type, callback)
-    {
-        (this.tree ? this.filters : jSmart.prototype.filters_global)[type=='output'?'post':type].push(callback);
-    }
-
-    jSmart.prototype.filters_global = {'pre':[],'variable':[],'post':[]};
-
-    jSmart.prototype.configLoad = function(confValues, section, data)
-    {
-        data = data ? data : this.data;
-        var s = confValues.replace(/\r\n/g,'\n').replace(/^\s+|\s+$/g,'');
-        var re = /^\s*(?:\[([^\]]+)\]|(?:(\w+)[ \t]*=[ \t]*("""|'[^'\\\n]*(?:\\.[^'\\\n]*)*'|"[^"\\\n]*(?:\\.[^"\\\n]*)*"|[^\n]*)))/m;
-        var currSect = '';
-        for (var f=s.match(re); f; f=s.match(re))
-        {
-                s = s.slice(f.index+f[0].length);
-                if (f[1])
-                {
-                         currSect = f[1];
-                }
-                else if ((!currSect || currSect == section) && currSect.substr(0,1) != '.')
-                {
-                         if (f[3] == '"""')
-                         {
-                                  var triple = s.match(/"""/);
-                                  if (triple)
-                                  {
-                                           data.smarty.config[f[2]] = s.slice(0,triple.index);
-                                           s = s.slice(triple.index + triple[0].length);
-                                  }
-                         }
-                         else
-                         {
-                                  data.smarty.config[f[2]] = trimQuotes(f[3]);
-                         }
-                }
-                var newln = s.match(/\n+/);
-                if (newln)
-                {
-                         s = s.slice(newln.index + newln[0].length);
-                }
-                else
-                {
-                         break;
-                }
-        }
-    }
-
-    jSmart.prototype.clearConfig = function(varName)
-    {
-        if (varName)
-        {
-            delete this.data.smarty.config[varName];
-        }
-        else
-        {
-            this.data.smarty.config = {};
-        }
-    }
-
-    /**
-       add modifier to implicitly apply to every variable in a template
-       @param modifiers  single string (e.g. "replace:'from':'to'")
-                         or array of strings (e.g. ['escape:"htmlall"', "replace:'from':'to'"])
-     */
-    jSmart.prototype.addDefaultModifier = function(modifiers)
-    {
-        if (!(modifiers instanceof Array))
-        {
-            modifiers = [modifiers];
-        }
-
-        for (var i=0; i<modifiers.length; ++i)
-        {
-            var e = { value:'', tree:[0] };
-            parseModifiers('|'+modifiers[i], e);
-            (this.tree ? this.default_modifiers : this.default_modifiers_global).push( e.tree[0] );
-        }
-    }
-
-    jSmart.prototype.default_modifiers_global = [];
-
-    /**
-       override this function
-       @param name  value of 'file' parameter in {include} and {extends}
-       @return template text
-    */
-    jSmart.prototype.getTemplate = function(name)
-    {
-        throw new Error('No template for ' + name);
-    }
-
-    /**
-       override this function
-       @param name  value of 'file' parameter in {fetch}
-       @return file content
-    */
-    jSmart.prototype.getFile = function(name)
-    {
-        throw new Error('No file for ' + name);
-    }
-
-    /**
-       override this function
-       @param name  value of 'file' parameter in {include_php} and {include_javascript}
-                     or value of 'script' parameter in {insert}
-       @return Javascript script
-    */
-    jSmart.prototype.getJavascript = function(name)
-    {
-        throw new Error('No Javascript for ' + name);
-    }
-
-    /**
-       override this function
-       @param name  value of 'file' parameter in {config_load}
-       @return config file content
-    */
-    jSmart.prototype.getConfig = function(name)
-    {
-        throw new Error('No config for ' + name);
-    }
-
-
-
-    /**
-       whether to skip tags in open brace { followed by white space(s) and close brace } with white space(s) before
-    */
-    jSmart.prototype.auto_literal = true;
-
-    jSmart.prototype.left_delimiter = '{';
-    jSmart.prototype.right_delimiter = '}';
-
-    /** enables the debugging console */
-    jSmart.prototype.debugging = false;
-
-
-    jSmart.prototype.PHPJS = function(fnm, modifier)
-    {
-        if (eval('typeof '+fnm) == 'function')
-        {
-            return (typeof window == 'object') ? window : global;
-        }
-        else if (typeof(PHP_JS) == 'function')
-        {
-            return new PHP_JS();
-        }
-        throw new Error("Modifier '" + modifier + "' uses JavaScript port of PHP function '" + fnm + "'. You can find one at http://phpjs.org");
-    }
-
-    jSmart.prototype.makeTimeStamp = function(s)
-    {
-        if (!s)
-        {
-            return Math.floor( (new Date()).getTime()/1000 );
-        }
-        if (isNaN(s))
-        {
-            var tm = jSmart.prototype.PHPJS('strtotime','date_format').strtotime(s);
-            if (tm == -1 || tm === false) {
-                return Math.floor( (new Date()).getTime()/1000 );
-            }
-            return tm;
-        }
-        s = new String(s);
-        if (s.length == 14) //mysql timestamp format of YYYYMMDDHHMMSS
-        {
-            return Math.floor( (new Date(s.substr(0,4),s.substr(4,2)-1,s.substr(6,2),s.substr(8,2),s.substr(10,2)).getTime()/1000 ) );
-        }
-        return parseInt(s);
-    }
-
-
-
-    /**
-       register custom functions
-    */
-    jSmart.prototype.registerPlugin(
-        'function',
-        '__array',
-        function(params, data)
-        {
-            var a = [];
-            for (var nm in params)
-            {
-                if (params.hasOwnProperty(nm) && params[nm] && typeof params[nm] != 'function')
-                {
-                    a[nm] = params[nm];
-                }
-            }
-            return a;
-        }
-    );
-
-    jSmart.prototype.registerPlugin(
-        'function',
-        '__func',
-        function(params, data) {
-            var paramNames = [], paramValues = {}, paramData = [];
-            for (var i=0; i<params.length; ++i) {
-                paramNames.push(params.name+'__p'+i);
-                paramData.push(params[i]);
-                paramValues[params.name+'__p'+i] = params[i];
-            }
-            var fname, mergedParams = obMerge({}, data, paramValues);
-            if (('__owner' in data && params.name in data.__owner)) {
-                fname = '__owner.'+params.name;
-                return execute(fname + '(' + paramNames.join(',') + ')', mergedParams);
-            } else if (modifiers.hasOwnProperty(params.name)) {
-                fname = modifiers[params.name]
-                return executeByFuncObject(fname, paramData, mergedParams);
-            } else {
-                fname = params.name;
-                return execute(fname + '(' + paramNames.join(',') + ')', mergedParams);
-            }
-        }
-    );
-
-    jSmart.prototype.registerPlugin(
-        'function',
-        '__quoted',
-        function(params, data)
-        {
-            return params.join('');
-        }
-    );
-
-    jSmart.prototype.registerPlugin(
-        'function',
-        'append',
-        function(params, data)
-        {
-            var varName = params.__get('var',null,0);
-            if (!(varName in data) || !(data[varName] instanceof Array))
-            {
-                data[varName] = [];
-            }
-            var index = params.__get('index',false);
-            var val = params.__get('value',null,1);
-            if (index === false)
-            {
-                data[varName].push(val);
-            }
-            else
-            {
-                data[varName][index] = val;
-            }
-            return '';
-        }
-    );
-
-    jSmart.prototype.registerPlugin(
-        'function',
-        'assign',
-        function(params, data)
-        {
-            assignVar(params.__get('var',null,0), params.__get('value',null,1), data);
-            return '';
-        }
-    );
-
-    jSmart.prototype.registerPlugin(
-        'function',
-        'break',
-        function(params, data)
-        {
-            data.smarty['break'] = true;
-            return '';
-        }
-    );
-
-    jSmart.prototype.registerPlugin(
-        'function',
-        'call',
-        function(params, data)
-        {
-            var fname = params.__get('name',null,0);
-            delete params.name;
-            var assignTo = params.__get('assign',false);
-            delete params.assign;
-            var s = plugins[fname].process(params, data);
-            if (assignTo)
-            {
-                assignVar(assignTo, s, data);
-                return '';
-            }
-            return s;
-        }
-    );
-
-    jSmart.prototype.registerPlugin(
-        'block',
-        'capture',
-        function(params, content, data, repeat)
-        {
-            if (content)
-            {
-                content = content.replace(/^\n/,'');
-                data.smarty.capture[params.__get('name','default',0)] = content;
-
-                if ('assign' in params)
-                {
-                    assignVar(params.assign, content, data);
-                }
-
-                var append = params.__get('append',false);
-                if (append)
-                {
-                    if (append in data)
-                    {
-                        if (data[append] instanceof Array)
-                        {
-                            data[append].push(content);
-                        }
-                    }
-                                       else
-                                       {
-                                                data[append] = [content];
-                                       }
-                }
-            }
-            return '';
-        }
-    );
-
-    jSmart.prototype.registerPlugin(
-        'function',
-        'continue',
-        function(params, data)
-        {
-            data.smarty['continue'] = true;
-            return '';
-        }
-    );
-
-    jSmart.prototype.registerPlugin(
-        'function',
-        'counter',
-        function(params, data)
-        {
-            var name = params.__get('name','default');
-            if (name in data.smarty.counter)
-            {
-                var counter = data.smarty.counter[name];
-                if ('start' in params)
-                {
-                    counter.value = parseInt(params['start']);
-                }
-                else
-                {
-                    counter.value = parseInt(counter.value);
-                    counter.skip = parseInt(counter.skip);
-                    if ('down' == counter.direction)
-                    {
-                        counter.value -= counter.skip;
-                    }
-                    else
-                    {
-                        counter.value += counter.skip;
-                    }
-                }
-                counter.skip = params.__get('skip',counter.skip);
-                counter.direction = params.__get('direction',counter.direction);
-                counter.assign = params.__get('assign',counter.assign);
-            }
-            else
-            {
-                data.smarty.counter[name] = {
-                    value: parseInt(params.__get('start',1)),
-                    skip: parseInt(params.__get('skip',1)),
-                    direction: params.__get('direction','up'),
-                    assign: params.__get('assign',false)
-                };
-            }
-
-            if (data.smarty.counter[name].assign)
-            {
-                data[data.smarty.counter[name].assign] = data.smarty.counter[name].value;
-                return '';
-            }
-
-            if (params.__get('print',true))
-            {
-                return data.smarty.counter[name].value;
-            }
-
-            return '';
-        }
-    );
-
-    jSmart.prototype.registerPlugin(
-        'function',
-        'cycle',
-        function(params, data)
-        {
-            var name = params.__get('name','default');
-            var reset = params.__get('reset',false);
-            if (!(name in data.smarty.cycle))
-            {
-                data.smarty.cycle[name] = {arr: [''], delimiter: params.__get('delimiter',','), index: 0};
-                reset = true;
-            }
-
-            if (params.__get('delimiter',false))
-            {
-                data.smarty.cycle[name].delimiter = params.delimiter;
-            }
-            var values = params.__get('values',false);
-            if (values)
-            {
-                var arr = [];
-                if (values instanceof Object)
-                {
-                    for (nm in values)
-                    {
-                        arr.push(values[nm]);
-                    }
-                }
-                else
-                {
-                    arr = values.split(data.smarty.cycle[name].delimiter);
-                }
-
-                if (arr.length != data.smarty.cycle[name].arr.length || arr[0] != data.smarty.cycle[name].arr[0])
-                {
-                    data.smarty.cycle[name].arr = arr;
-                    data.smarty.cycle[name].index = 0;
-                    reset = true;
-                }
-            }
-
-            if (params.__get('advance','true'))
-            {
-                data.smarty.cycle[name].index += 1;
-            }
-            if (data.smarty.cycle[name].index >= data.smarty.cycle[name].arr.length || reset)
-            {
-                data.smarty.cycle[name].index = 0;
-            }
-
-            if (params.__get('assign',false))
-            {
-                assignVar(params.assign, data.smarty.cycle[name].arr[ data.smarty.cycle[name].index ], data);
-                return '';
-            }
-
-            if (params.__get('print',true))
-            {
-                return data.smarty.cycle[name].arr[ data.smarty.cycle[name].index ];
-            }
-
-            return '';
-        }
-    );
-
-    jSmart.prototype.print_r = function(v,indent)
-    {
-        if (v instanceof Object)
-        {
-            var s = ((v instanceof Array) ? 'Array['+v.length+']' : 'Object') + '<br>';
-            for (var nm in v)
-            {
-                if (v.hasOwnProperty(nm))
-                {
-                    s += indent + '&nbsp;&nbsp;<strong>' + nm + '</strong> : ' + jSmart.prototype.print_r(v[nm],indent+'&nbsp;&nbsp;&nbsp;') + '<br>';
-                }
-            }
-            return s;
-        }
-        return v;
-    }
-
-    jSmart.prototype.registerPlugin(
-        'function',
-        'debug',
-        function(params, data)
-        {
-            if (typeof dbgWnd != 'undefined')
-            {
-                dbgWnd.close();
-            }
-            dbgWnd = window.open('','','width=680,height=600,resizable,scrollbars=yes');
-            var sVars = '';
-            var i=0;
-            for (var nm in data)
-            {
-                sVars += '<tr class=' + (++i%2?'odd':'even') + '><td><strong>' + nm + '</strong></td><td>' + jSmart.prototype.print_r(data[nm],'') + '</td></tr>';
-            }
-            dbgWnd.document.write(" \
-               <html xmlns='http://www.w3.org/1999/xhtml' xml:lang='en'> \
-               <head> \
-                           <title>jSmart Debug Console</title> \
-                  <style type='text/css'> \
-                     table {width: 100%;} \
-                     td {vertical-align:top;width: 50%;} \
-                     .even td {background-color: #fafafa;} \
-                  </style> \
-               </head> \
-               <body> \
-                  <h1>jSmart Debug Console</h1> \
-                  <h2>assigned template variables</h2> \
-                  <table>" + sVars + "</table> \
-               </body> \
-               </html> \
-            ");
-            return '';
-        }
-    );
-
-    jSmart.prototype.registerPlugin(
-        'function',
-        'eval',
-        function(params, data)
-        {
-            var tree = [];
-            parse(params.__get('var','',0), tree);
-            var s = process(tree, data);
-            if ('assign' in params)
-            {
-                assignVar(params.assign, s, data);
-                return '';
-            }
-            return s;
-        }
-    );
-
-    jSmart.prototype.registerPlugin(
-        'function',
-        'fetch',
-        function(params, data)
-        {
-            var s = jSmart.prototype.getFile(params.__get('file',null,0));
-            if ('assign' in params)
-            {
-                assignVar(params.assign, s, data);
-                return '';
-            }
-            return s;
-        }
-    );
-
-    jSmart.prototype.registerPlugin(
-        'function',
-        'html_checkboxes',
-        function (params, data) {
-            var type = params.__get('type','checkbox'),
-                name = params.__get('name',type),
-                realName = params.__get('name',type),
-                values = params.__get('values',params.options),
-                output = params.__get('options',[]),
-                useName = ('options' in params),
-                selected = params.__get('selected',false),
-                separator = params.__get('separator',''),
-                labels = Boolean(params.__get('labels',true)),
-                label_ids = Boolean(params.__get('label_ids',false)),
-                p,
-                res = [],
-                i = 0,
-                s = '',
-                value,
-                id;
-
-            if (type == 'checkbox') {
-                name += '[]';
-            }
-            if (!useName) {
-                for (p in params.output) {
-                    output.push(params.output[p]);
-                }
-            }
-
-            for (p in values) {
-                if (values.hasOwnProperty(p)) {
-                    value = (useName ? p : values[p]);
-                    id = realName + '_' + value;
-                    s = (labels ? ( label_ids ? '<label for="'+id+'">' : '<label>') : '');
-
-                    s += '<input type="' + type + '" name="' + name + '" value="' + value + '" ';
-                    if (label_ids) {
-                        s += 'id="'+id+'" ';
-                    }
-                    if (selected == (useName ? p : values[p])) {
-                        s += 'checked="checked" ';
-                    }
-                    s += '/>' + output[useName?p:i++];
-                    s += (labels ? '</label>' : '');
-                    s += separator;
-                    res.push(s);
-                }
-            }
-            if ('assign' in params) {
-                assignVar(params.assign, res, data);
-                return '';
-            }
-            return res.join('\n');
-        }
-    );
-
-    jSmart.prototype.registerPlugin(
-        'function',
-        'html_image',
-        function (params, data) {
-            var url = params.__get('file', null),
-                width = params.__get('width', false),
-                height = params.__get('height', false),
-                alt = params.__get('alt', ''),
-                href = params.__get('href', params.__get('link', false)),
-                path_prefix = params.__get('path_prefix', ''),
-                paramNames = {file:1, width:1, height:1, alt:1, href:1, basedir:1, path_prefix:1, link:1},
-                s = '<img src="' + path_prefix + url + '"' + ' alt="'+alt+'"' + (width ? ' width="'+width+'"':'') + (height ? ' height="'+height+'"':''),
-                p;
-
-            for (p in params) {
-                if (params.hasOwnProperty(p) && typeof(params[p]) == 'string') {
-                    if (!(p in paramNames)) {
-                        s += ' ' + p + '="' + params[p] + '"';
-                    }
-                }
-            }
-            s += ' />';
-            return href ? '<a href="'+href+'">'+s+'</a>' : s;
-        }
-    );
-
-    jSmart.prototype.registerPlugin(
-        'function',
-        'html_options',
-        function(params, data)
-        {
-            var values = params.__get('values',params.options);
-            var output = params.__get('options',[]);
-            var useName = ('options' in params);
-            var p;
-            if (!useName)
-            {
-                for (p in params.output)
-                {
-                    output.push(params.output[p]);
-                }
-            }
-            var selected = params.__get('selected',false);
-
-            var res = [];
-            var s = '';
-            var i = 0;
-            for (p in values)
-            {
-                if (values.hasOwnProperty(p))
-                {
-                    s = '<option value="' + (useName ? p : values[p]) + '"';
-                    if (selected == (useName ? p : values[p]))
-                    {
-                        s += ' selected="selected"';
-                    }
-                    s += '>' + output[useName ? p : i++] + '</option>';
-                    res.push(s);
-                }
-            }
-            var name = params.__get('name',false);
-            return (name ? ('<select name="' + name + '">\n' + res.join('\n') + '\n</select>') : res.join('\n')) + '\n';
-        }
-    );
-
-    jSmart.prototype.registerPlugin(
-        'function',
-        'html_radios',
-        function(params, data)
-        {
-            params.type = 'radio';
-            return plugins.html_checkboxes.process(params,data);
-        }
-    );
-
-    jSmart.prototype.registerPlugin(
-        'function',
-        'html_select_date',
-        function(params, data)
-        {
-            var prefix = params.__get('prefix','Date_');
-            var months = ['January','February','March','April','May','June','July','August','September','October','November','December'];
-
-            var s = '';
-            s += '<select name="'+prefix+'Month">\n';
-            var i=0;
-            for (i=0; i<months.length; ++i)
-            {
-                s += '<option value="' + i + '">' + months[i] + '</option>\n';
-            }
-            s += '</select>\n'
-
-            s += '<select name="'+prefix+'Day">\n';
-            for (i=0; i<31; ++i)
-            {
-                s += '<option value="' + i + '">' + i + '</option>\n';
-            }
-            s += '</select>\n'
-            return s;
-        }
-    );
-
-    jSmart.prototype.registerPlugin(
-        'function',
-        'html_table',
-        function(params, data)
-        {
-            var loop = [];
-            var p;
-            if (params.loop instanceof Array)
-            {
-                loop = params.loop
-            }
-            else
-            {
-                for (p in params.loop)
-                {
-                    if (params.loop.hasOwnProperty(p))
-                    {
-                        loop.push( params.loop[p] );
-                    }
-                }
-            }
-            var rows = params.__get('rows',false);
-            var cols = params.__get('cols',false);
-            if (!cols)
-            {
-                cols = rows ? Math.ceil(loop.length/rows) : 3;
-            }
-            var colNames = [];
-            if (isNaN(cols))
-            {
-                if (typeof cols == 'object')
-                {
-                    for (p in cols)
-                    {
-                        if (cols.hasOwnProperty(p))
-                        {
-                            colNames.push(cols[p]);
-                        }
-                    }
-                }
-                else
-                {
-                    colNames = cols.split(/\s*,\s*/);
-                }
-                cols = colNames.length;
-            }
-            rows = rows ? rows : Math.ceil(loop.length/cols);
-
-            var inner = params.__get('inner','cols');
-            var caption = params.__get('caption','');
-            var table_attr = params.__get('table_attr','border="1"');
-            var th_attr = params.__get('th_attr',false);
-            if (th_attr && typeof th_attr != 'object')
-            {
-                th_attr = [th_attr];
-            }
-            var tr_attr = params.__get('tr_attr',false);
-            if (tr_attr && typeof tr_attr != 'object')
-            {
-                tr_attr = [tr_attr];
-            }
-            var td_attr = params.__get('td_attr',false);
-            if (td_attr && typeof td_attr != 'object')
-            {
-                td_attr = [td_attr];
-            }
-            var trailpad = params.__get('trailpad','&nbsp;');
-            var hdir = params.__get('hdir','right');
-            var vdir = params.__get('vdir','down');
-
-            var s = '';
-            for (var row=0; row<rows; ++row)
-            {
-                s += '<tr' + (tr_attr ? ' '+tr_attr[row%tr_attr.length] : '') + '>\n';
-                for (var col=0; col<cols; ++col)
-                {
-                    var idx = (inner=='cols') ? ((vdir=='down'?row:rows-1-row) * cols + (hdir=='right'?col:cols-1-col)) : ((hdir=='right'?col:cols-1-col) * rows + (vdir=='down'?row:rows-1-row));
-
-                    s += '<td' + (td_attr ? ' '+td_attr[col%td_attr.length] : '') + '>' + (idx < loop.length ? loop[idx] : trailpad) + '</td>\n';
-                }
-                s += '</tr>\n';
-            }
-
-            var sHead = '';
-            if (colNames.length)
-            {
-                sHead = '\n<thead><tr>';
-                for (var i=0; i<colNames.length; ++i)
-                {
-                    sHead += '\n<th' + (th_attr ? ' '+th_attr[i%th_attr.length] : '') + '>' + colNames[hdir=='right'?i:colNames.length-1-i] + '</th>';
-                }
-                sHead += '\n</tr></thead>';
-            }
-
-            return '<table ' + table_attr + '>' + (caption?'\n<caption>'+caption+'</caption>':'') + sHead + '\n<tbody>\n' + s + '</tbody>\n</table>\n';
-        }
-    );
-
-    jSmart.prototype.registerPlugin(
-        'function',
-        'include',
-        function(params, data)
-        {
-            var file = params.__get('file',null,0);
-            var incData = obMerge({},data,params);
-            incData.smarty.template = file;
-            var s = process(getTemplate(file,[],findInArray(params,'nocache')>=0), incData);
-            if ('assign' in params)
-            {
-                assignVar(params.assign, s, data);
-                return '';
-            }
-            return s;
-        }
-    );
-
-    jSmart.prototype.registerPlugin(
-        'function',
-        'include_javascript',
-        function(params, data)
-        {
-            var file = params.__get('file',null,0);
-            if (params.__get('once',true) && file in scripts)
-            {
-                return '';
-            }
-            scripts[file] = true;
-            var s = execute(jSmart.prototype.getJavascript(file), {'$this':data});
-            if ('assign' in params)
-            {
-                assignVar(params.assign, s, data);
-                return '';
-            }
-            return s;
-        }
-    );
-
-    jSmart.prototype.registerPlugin(
-        'function',
-        'include_php',
-        function(params, data)
-        {
-            return plugins['include_javascript'].process(params,data);
-        }
-    );
-
-    jSmart.prototype.registerPlugin(
-        'function',
-        'insert',
-        function(params, data)
-        {
-            var fparams = {};
-            for (var nm in params)
-            {
-                if (params.hasOwnProperty(nm) && isNaN(nm) && params[nm] && typeof params[nm] == 'string' && nm != 'name' && nm != 'assign' && nm != 'script')
-                {
-                    fparams[nm] = params[nm];
-                }
-            }
-            var prefix = 'insert_';
-            if ('script' in params)
-            {
-                eval(jSmart.prototype.getJavascript(params.script));
-                prefix = 'smarty_insert_';
-            }
-            var func = eval(prefix+params.__get('name',null,0));
-            var s = func(fparams, data);
-            if ('assign' in params)
-            {
-                assignVar(params.assign, s, data);
-                return '';
-            }
-            return s;
-        }
-    );
-
-    jSmart.prototype.registerPlugin(
-        'block',
-        'javascript',
-        function(params, content, data, repeat)
-        {
-            data['$this'] = data;
-            execute(content,data);
-            delete data['$this'];
-            return '';
-        }
-    );
-
-    jSmart.prototype.registerPlugin(
-        'function',
-        'config_load',
-        function(params, data)
-        {
-            jSmart.prototype.configLoad(jSmart.prototype.getConfig(params.__get('file',null,0)), params.__get('section','',1), data);
-            return '';
-        }
-    );
-
-    jSmart.prototype.registerPlugin(
-        'function',
-        'mailto',
-        function(params, data)
-        {
-            var address = params.__get('address',null);
-            var encode = params.__get('encode','none');
-            var text = params.__get('text',address);
-            var cc = jSmart.prototype.PHPJS('rawurlencode','mailto').rawurlencode(params.__get('cc','')).replace('%40','@');
-            var bcc = jSmart.prototype.PHPJS('rawurlencode','mailto').rawurlencode(params.__get('bcc','')).replace('%40','@');
-            var followupto = jSmart.prototype.PHPJS('rawurlencode','mailto').rawurlencode(params.__get('followupto','')).replace('%40','@');
-            var subject = jSmart.prototype.PHPJS('rawurlencode','mailto').rawurlencode( params.__get('subject','') );
-            var newsgroups = jSmart.prototype.PHPJS('rawurlencode','mailto').rawurlencode(params.__get('newsgroups',''));
-            var extra = params.__get('extra','');
-
-            address += (cc?'?cc='+cc:'');
-            address += (bcc?(cc?'&':'?')+'bcc='+bcc:'');
-            address += (subject ? ((cc||bcc)?'&':'?') + 'subject='+subject : '');
-            address += (newsgroups ? ((cc||bcc||subject)?'&':'?') + 'newsgroups='+newsgroups : '');
-            address += (followupto ? ((cc||bcc||subject||newsgroups)?'&':'?') + 'followupto='+followupto : '');
-
-            s = '<a href="mailto:' + address + '" ' + extra + '>' + text + '</a>';
-
-            if (encode == 'javascript')
-            {
-                s = "document.write('" + s + "');";
-                var sEncoded = '';
-                for (var i=0; i<s.length; ++i)
-                {
-                    sEncoded += '%' + jSmart.prototype.PHPJS('bin2hex','mailto').bin2hex(s.substr(i,1));
-                }
-                return '<script type="text/javascript">eval(unescape(\'' + sEncoded + "'))</script>";
-            }
-            else if (encode == 'javascript_charcode')
-            {
-                var codes = [];
-                for (var i=0; i<s.length; ++i)
-                {
-                    codes.push(jSmart.prototype.PHPJS('ord','mailto').ord(s.substr(i,1)));
-                }
-                return '<script type="text/javascript" language="javascript">\n<!--\n{document.write(String.fromCharCode('
-                    + codes.join(',') + '))}\n//-->\n</script>\n';
-            }
-            else if (encode == 'hex')
-            {
-                if (address.match(/^.+\?.+$/))
-                {
-                    throw new Error('mailto: hex encoding does not work with extra attributes. Try javascript.');
-                }
-                var aEncoded = '';
-                for (var i=0; i<address.length; ++i)
-                {
-                    if (address.substr(i,1).match(/\w/))
-                    {
-                        aEncoded += '%' + jSmart.prototype.PHPJS('bin2hex','mailto').bin2hex(address.substr(i,1));
-                    }
-                    else
-                    {
-                        aEncoded += address.substr(i,1);
-                    }
-                }
-                aEncoded = aEncoded.toLowerCase();
-                var tEncoded = '';
-                for (var i=0; i<text.length; ++i)
-                {
-                    tEncoded += '&#x' + jSmart.prototype.PHPJS('bin2hex','mailto').bin2hex(text.substr(i,1)) + ';';
-                }
-                tEncoded = tEncoded.toLowerCase();
-                return '<a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;' + aEncoded + '" ' + extra + '>' + tEncoded + '</a>';
-            }
-            return s;
-        }
-    );
-
-    jSmart.prototype.registerPlugin(
-        'function',
-        'math',
-        function(params, data)
-        {
-            with (Math)
-            {
-                with (params)
-                {
-                    var res = eval(params.__get('equation',null).replace(/pi\(\s*\)/g,'PI'));
-                }
-            }
-
-            if ('format' in params)
-            {
-                res = jSmart.prototype.PHPJS('sprintf','math').sprintf(params.format,res);
-            }
-
-            if ('assign' in params)
-            {
-                assignVar(params.assign, res, data);
-                return '';
-            }
-            return res;
-        }
-    );
-
-    jSmart.prototype.registerPlugin(
-        'block',
-        'nocache',
-        function(params, content, data, repeat)
-        {
-            return content;
-        }
-    );
-
-    jSmart.prototype.registerPlugin(
-        'block',
-        'textformat',
-        function(params, content, data, repeat)
-        {
-            if (!content) {
-                return '';
-            }
-
-            content = new String(content);
-
-            var wrap = params.__get('wrap',80);
-            var wrap_char = params.__get('wrap_char','\n');
-            var wrap_cut = params.__get('wrap_cut',false);
-            var indent_char = params.__get('indent_char',' ');
-            var indent = params.__get('indent',0);
-            var indentStr = (new Array(indent+1)).join(indent_char);
-            var indent_first = params.__get('indent_first',0);
-            var indentFirstStr = (new Array(indent_first+1)).join(indent_char);
-
-            var style = params.__get('style','');
-
-            if (style == 'email') {
-                wrap = 72;
-            }
-
-            var paragraphs = content.split(/[\r\n]{2}/);
-            for (var i=0; i<paragraphs.length; ++i) {
-                var p = paragraphs[i];
-                if (!p) {
-                    continue;
-                }
-                p = p.replace(/^\s+|\s+$/,'').replace(/\s+/g,' ');
-                if (indent_first> 0 ) {
-                    p = indentFirstStr + p;
-                }
-                p = modifiers.wordwrap(p, wrap-indent, wrap_char, wrap_cut);
-                if (indent > 0) {
-                    p = p.replace(/^/mg, indentStr);
-                }
-                paragraphs[i] = p;
-            }
-            var s = paragraphs.join(wrap_char+wrap_char);
-            if ('assign' in params)
-            {
-                assignVar(params.assign, s, data);
-                return '';
-            }
-            return s;
-        }
-    );
-
-
-    /**
-       register modifiers
-    */
-    jSmart.prototype.registerPlugin(
-        'modifier',
-        'capitalize',
-        function(s, upDigits, lcRest) {
-            if (typeof s != 'string') {
-                return s;
-            }
-            var re = new RegExp(upDigits ? '[^a-zA-Z_\u00E0-\u00FC]+' : '[^a-zA-Z0-9_\u00E0-\u00FC]');
-            var found = null;
-            var res = '';
-            if (lcRest) {
-                s = s.toLowerCase();
-            }
-            for (found=s.match(re); found; found=s.match(re))
-            {
-                    var word = s.slice(0,found.index);
-                if (word.match(/\d/))
-                {
-                    res += word;
-                }
-                else
-                {
-                        res += word.charAt(0).toUpperCase() + word.slice(1);
-                }
-                res += s.slice(found.index, found.index+found[0].length);
-                    s = s.slice(found.index+found[0].length);
-            }
-            if (s.match(/\d/))
-            {
-                return res + s;
-            }
-            return res + s.charAt(0).toUpperCase() + s.slice(1);
-        }
-    );
-
-    jSmart.prototype.registerPlugin(
-        'modifier',
-        'cat',
-        function(s, value)
-        {
-            value = value ? value : '';
-            return new String(s) + value;
-        }
-    );
-
-    jSmart.prototype.registerPlugin(
-        'modifier',
-        'count',
-        function(v, recursive)
-        {
-            if (v === null || typeof v === 'undefined') {
-                return 0;
-            } else if (v.constructor !== Array && v.constructor !== Object) {
-                return 1;
-            }
-
-            recursive = Boolean(recursive);
-            var k, cnt = 0;
-            for (k in v)
-            {
-                if (v.hasOwnProperty(k))
-                {
-                    cnt++;
-                    if (recursive && v[k] && (v[k].constructor === Array || v[k].constructor === Object)) {
-                        cnt += modifiers.count(v[k], true);
-                    }
-                }
-            }
-            return cnt;
-        }
-    );
-
-    jSmart.prototype.registerPlugin(
-        'modifier',
-        'count_characters',
-        function(s, includeWhitespaces)
-        {
-            s = new String(s);
-            return includeWhitespaces ? s.length : s.replace(/\s/g,'').length;
-        }
-    );
-
-    jSmart.prototype.registerPlugin(
-        'modifier',
-        'count_paragraphs',
-        function(s)
-        {
-            var found = (new String(s)).match(/\n+/g);
-            if (found)
-            {
-                    return found.length+1;
-            }
-            return 1;
-        }
-    );
-
-    jSmart.prototype.registerPlugin(
-        'modifier',
-        'count_sentences',
-        function(s)
-        {
-            if (typeof s == 'string')
-            {
-                var found = s.match(/[^\s]\.(?!\w)/g);
-                if (found)
-                {
-                        return found.length;
-                }
-            }
-            return 0;
-        }
-    );
-
-    jSmart.prototype.registerPlugin(
-        'modifier',
-        'count_words',
-        function(s)
-        {
-            if (typeof s == 'string')
-            {
-                var found = s.match(/\w+/g);
-                if (found)
-                {
-                        return found.length;
-                }
-            }
-            return 0;
-        }
-    );
-
-    jSmart.prototype.registerPlugin(
-        'modifier',
-        'date_format',
-        function(s, fmt, defaultDate)
-        {
-            return jSmart.prototype.PHPJS('strftime','date_format').strftime(fmt?fmt:'%b %e, %Y', jSmart.prototype.makeTimeStamp(s?s:defaultDate));
-        }
-    );
-
-    jSmart.prototype.registerPlugin(
-        'modifier',
-        'defaultValue',
-        function(s, value)
-        {
-            return (s && s!='null' && s!='undefined') ? s : (value ? value : '');
-        }
-    );
-
-    jSmart.prototype.registerPlugin(
-        'modifier',
-        'unescape',
-        function(s, esc_type, char_set)
-        {
-            s = new String(s);
-            esc_type = esc_type || 'html';
-            char_set = char_set || 'UTF-8';
-
-            switch (esc_type)
-            {
-            case 'html':
-                return s.replace(/&lt;/g, '<').replace(/&gt;/g,'>').replace(/&#039;/g,"'").replace(/&quot;/g,'"');
-            case 'entity':
-            case 'htmlall':
-                return jSmart.prototype.PHPJS('html_entity_decode','unescape').html_entity_decode(s, 1);
-            case 'url':
-                return jSmart.prototype.PHPJS('rawurldecode','unescape').rawurldecode(s);
-            };
-            return s;
-        }
-    );
-
-    jSmart.prototype.registerPlugin(
-        'modifier',
-        'escape',
-        function(s, esc_type, char_set, double_encode)
-        {
-            s = new String(s);
-            esc_type = esc_type || 'html';
-            char_set = char_set || 'UTF-8';
-            double_encode = (typeof double_encode != 'undefined') ? Boolean(double_encode) : true;
-
-            switch (esc_type)
-            {
-            case 'html':
-                if (double_encode) {
-                                  s = s.replace(/&/g, '&amp;');
-                         }
-                return s.replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/'/g,'&#039;').replace(/"/g,'&quot;');
-            case 'htmlall':
-                return jSmart.prototype.PHPJS('htmlentities','escape').htmlentities(s, 3, char_set);
-            case 'url':
-                return jSmart.prototype.PHPJS('rawurlencode','escape').rawurlencode(s);
-            case 'urlpathinfo':
-                return jSmart.prototype.PHPJS('rawurlencode','escape').rawurlencode(s).replace(/%2F/g, '/');
-            case 'quotes':
-                return s.replace(/(^|[^\\])'/g, "$1\\'");
-            case 'hex':
-                var res = '';
-                for (var i=0; i<s.length; ++i)
-                {
-                    res += '%' + jSmart.prototype.PHPJS('bin2hex','escape').bin2hex(s.substr(i,1)).toLowerCase();
-                }
-                return res;
-            case 'hexentity':
-                var res = '';
-                for (var i=0; i<s.length; ++i) {
-                    res += '&#x' + jSmart.prototype.PHPJS('bin2hex','escape').bin2hex(s.substr(i,1)) + ';';
-                }
-                return res;
-            case 'decentity':
-                var res = '';
-                for (var i=0; i<s.length; ++i) {
-                    res += '&#' + jSmart.prototype.PHPJS('ord','escape').ord(s.substr(i,1)) + ';';
-                }
-                return res;
-            case 'mail':
-                return s.replace(/@/g,' [AT] ').replace(/[.]/g,' [DOT] ');
-            case 'nonstd':
-                var res = '';
-                for (var i=0; i<s.length; ++i)
-                {
-                    var _ord = jSmart.prototype.PHPJS('ord','escape').ord(s.substr(i,1));
-                    if (_ord >= 126) {
-                        res += '&#' + _ord + ';';
-                    } else {
-                        res += s.substr(i, 1);
-                    }
-
-                }
-                return res;
-            case 'javascript':
-                return s.replace(/\\/g,'\\\\').replace(/'/g,"\\'").replace(/"/g,'\\"').replace(/\r/g,'\\r').replace(/\n/g,'\\n').replace(/<\//g,'<\/');
-            };
-            return s;
-        }
-    );
-
-    jSmart.prototype.registerPlugin(
-        'modifier',
-        'indent',
-        function(s, repeat, indentWith)
-        {
-            s = new String(s);
-            repeat = repeat ? repeat : 4;
-            indentWith = indentWith ? indentWith : ' ';
-
-            var indentStr = '';
-            while (repeat--)
-            {
-                indentStr += indentWith;
-            }
-
-            var tail = s.match(/\n+$/);
-            return indentStr + s.replace(/\n+$/,'').replace(/\n/g,'\n'+indentStr) + (tail ? tail[0] : '');
-        }
-    );
-
-    jSmart.prototype.registerPlugin(
-        'modifier',
-        'lower',
-        function(s)
-        {
-            return new String(s).toLowerCase();
-        }
-    );
-
-    jSmart.prototype.registerPlugin(
-        'modifier',
-        'nl2br',
-        function(s)
-        {
-            return new String(s).replace(/\n/g,'<br />\n');
-        }
-    );
-
-    /**
-        only modifiers (flags) 'i' and 'm' are supported
-        backslashes should be escaped e.g. \\s
-    */
-    jSmart.prototype.registerPlugin(
-        'modifier',
-        'regex_replace',
-        function(s, re, replaceWith)
-        {
-            var pattern = re.match(/^ *\/(.*)\/(.*) *$/);
-            return (new String(s)).replace(new RegExp(pattern[1],'g'+(pattern.length>1?pattern[2]:'')), replaceWith);
-        }
-    );
-
-    jSmart.prototype.registerPlugin(
-        'modifier',
-        'replace',
-        function(s, search, replaceWith)
-        {
-            if (!search)
-            {
-                return s;
-            }
-            s = new String(s);
-            search = new String(search);
-            replaceWith = new String(replaceWith);
-            var res = '';
-            var pos = -1;
-            for (pos=s.indexOf(search); pos>=0; pos=s.indexOf(search))
-            {
-                res += s.slice(0,pos) + replaceWith;
-                pos += search.length;
-                s = s.slice(pos);
-            }
-            return res + s;
-        }
-    );
-
-    jSmart.prototype.registerPlugin(
-        'modifier',
-        'spacify',
-        function(s, space)
-        {
-            if (!space)
-            {
-                space = ' ';
-            }
-            return (new String(s)).replace(/(\n|.)(?!$)/g,'$1'+space);
-        }
-    );
-
-    jSmart.prototype.registerPlugin(
-        'modifier',
-        'noprint',
-        function(s)
-        {
-            return '';
-        }
-    );
-
-    jSmart.prototype.registerPlugin(
-        'modifier',
-        'string_format',
-        function(s, fmt)
-        {
-            return jSmart.prototype.PHPJS('sprintf','string_format').sprintf(fmt,s);
-        }
-    );
-
-    jSmart.prototype.registerPlugin(
-        'modifier',
-        'strip',
-        function(s, replaceWith)
-        {
-            replaceWith = replaceWith ? replaceWith : ' ';
-            return (new String(s)).replace(/[\s]+/g, replaceWith);
-        }
-    );
-
-    jSmart.prototype.registerPlugin(
-        'modifier',
-        'strip_tags',
-        function(s, addSpace)
-        {
-            addSpace = (addSpace==null) ? true : addSpace;
-            return (new String(s)).replace(/<[^>]*?>/g, addSpace ? ' ' : '');
-        }
-    );
-
-    jSmart.prototype.registerPlugin(
-        'modifier',
-        'truncate',
-        function(s, length, etc, breakWords, middle)
-        {
-            s = new String(s);
-            length = length ? length : 80;
-            etc = (etc!=null) ? etc : '...';
-
-            if (s.length <= length)
-            {
-                return s;
-            }
-
-            length -= Math.min(length,etc.length);
-            if (middle)
-            {
-                //one of floor()'s should be replaced with ceil() but it so in Smarty
-                return s.slice(0,Math.floor(length/2)) + etc + s.slice(s.length-Math.floor(length/2));
-            }
-
-            if (!breakWords)
-            {
-                s = s.slice(0,length+1).replace(/\s+?(\S+)?$/,'');
-            }
-
-            return s.slice(0,length) + etc;
-        }
-    );
-
-    jSmart.prototype.registerPlugin(
-        'modifier',
-        'upper',
-        function(s)
-        {
-            return (new String(s)).toUpperCase();
-        }
-    );
-
-    jSmart.prototype.registerPlugin(
-        'modifier',
-        'wordwrap',
-        function(s, width, wrapWith, breakWords)
-        {
-               width = width || 80;
-               wrapWith = wrapWith || '\n';
-
-               var lines = (new String(s)).split('\n');
-               for (var i=0; i<lines.length; ++i)
-               {
-                       var line = lines[i];
-                var parts = ''
-                       while (line.length > width)
-                       {
-                    var pos = 0;
-                    var found = line.slice(pos).match(/\s+/);
-                    for (;found && (pos+found.index)<=width; found=line.slice(pos).match(/\s+/))
-                    {
-                        pos += found.index + found[0].length;
-                    }
-                    pos = pos || (breakWords ? width : (found ? found.index+found[0].length : line.length));
-                    parts += line.slice(0,pos).replace(/\s+$/,'');// + wrapWith;
-                    if (pos < line.length)
-                    {
-                        parts += wrapWith;
-                    }
-                    line = line.slice(pos);
-                }
-                       lines[i] = parts + line;
-               }
-               return lines.join('\n');
-        }
-    );
-
-
-    String.prototype.fetch = function(data)
-    {
-        var tpl = new jSmart(this);
-        return tpl.fetch(data);
-    };
-
-    if (typeof module === "object" && module && typeof module.exports === "object") {
-        module.exports = jSmart;
-    } else {
-        if (typeof global !== "undefined") {
-            global.jSmart = jSmart;
-        }
-
-        if (typeof define === "function" && define.amd) {
-            define("jSmart", [], function () { return jSmart; });
-        }
-    }
-})();
diff --git a/view/theme/frio/frameworks/jsmart/jsmart.min.js b/view/theme/frio/frameworks/jsmart/jsmart.min.js
deleted file mode 100644 (file)
index 51764df..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-/*!
- * jSmart Javascript template engine (v2.15.0)
- * https://github.com/umakantp/jsmart
- * http://opensource.org/licenses/LGPL-3.0
- *
- * Copyright 2011-2015, Max Miroshnikov <miroshnikov at gmail dot com>
- *                      Umakant Patil <me @ umakantpatil dot com>
- */
-!function(){function obMerge(a){for(var b=1;b<arguments.length;++b)for(var c in arguments[b])a[c]=arguments[b][c];return a}function countProperties(a){var b=0;for(var c in a)a.hasOwnProperty(c)&&b++;return b}function findInArray(a,b){if(Array.prototype.indexOf)return a.indexOf(b);for(var c=0;c<a.length;++c)if(a[c]===b)return c;return-1}function evalString(a){return a.replace(/\\t/,"      ").replace(/\\n/,"\n").replace(/\\(['"\\])/g,"$1")}function trimQuotes(a){return evalString(a.replace(/^['"](.*)['"]$/,"$1")).replace(/^\s+|\s+$/g,"")}function findTag(a,b){for(var c=0,d=0,e=jSmart.prototype.left_delimiter,f=jSmart.prototype.right_delimiter,g=jSmart.prototype.auto_literal,h=/^\s*(.+)\s*$/i,i=a?new RegExp("^\\s*("+a+")\\s*$","i"):h,j=0;j<b.length;++j)if(b.substr(j,e.length)==e){if(g&&j+1<b.length&&b.substr(j+1,1).match(/\s/))continue;c||(b=b.slice(j),d+=parseInt(j),j=0),++c}else if(b.substr(j,f.length)==f){if(g&&j-1>=0&&b.substr(j-1,1).match(/\s/))continue;if(!--c){var k=b.slice(e.length,j).replace(/[\r\n]/g," "),l=k.match(i);if(l)return l.index=d,l[0]=b.slice(0,j+f.length),l}0>c&&(c=0)}return null}function findCloseTag(a,b,c){var d="",e=null,f=null,g=0;do{if(e&&(g+=e[0].length),e=findTag(a,c),!e)throw new Error("Unclosed {"+b+"}");d+=c.slice(0,e.index),g+=e.index,c=c.slice(e.index+e[0].length),f=findTag(b,d),f&&(d=d.slice(f.index+f[0].length))}while(f);return e.index=g,e}function findElseTag(a,b,c,d){for(var e=0,f=findTag(c,d);f;f=findTag(c,d)){var g=findTag(a,d);if(!g||g.index>f.index)return f.index+=e,f;d=d.slice(g.index+g[0].length),e+=g.index+g[0].length;var h=findCloseTag(b,a,d);d=d.slice(h.index+h[0].length),e+=h.index+h[0].length}return null}function execute(code,data){if("string"==typeof code)with({__code:code})with(modifiers)with(data)try{return eval(__code)}catch(e){throw new Error(e.message+" in \n"+code)}return code}function executeByFuncObject(a,b){try{return a.apply(this,b)}catch(c){throw new Error(c.message)}}function assignVar(a,b,c){a.match(/\[\]$/)?c[a.replace(/\[\]$/,"")].push(b):c[a]=b}function parse(a,b){for(var c=findTag("",a);c;c=findTag("",a)){c.index&&parseText(a.slice(0,c.index),b),a=a.slice(c.index+c[0].length);var d=c[1].match(/^\s*(\w+)(.*)$/);if(d){var e=d[1],f=d.length>2?d[2].replace(/^\s+|\s+$/g,""):"";if(e in buildInFunctions){var g=buildInFunctions[e],h=("parseParams"in g?g.parseParams:parseParams)(f);if("block"==g.type){a=a.replace(/^\n/,"");var i=findCloseTag("/"+e,e+" +[^}]*",a);g.parse(h,b,a.slice(0,i.index)),a=a.slice(i.index+i[0].length)}else g.parse(h,b),"extends"==e&&(b=[]);a=a.replace(/^\n/,"")}else if(e in plugins){var j=plugins[e];if("block"==j.type){var i=findCloseTag("/"+e,e+" +[^}]*",a);parsePluginBlock(e,parseParams(f),b,a.slice(0,i.index)),a=a.slice(i.index+i[0].length)}else"function"==j.type&&parsePluginFunc(e,parseParams(f),b);("append"==e||"assign"==e||"capture"==e||"eval"==e||"include"==e)&&(a=a.replace(/^\n/,""))}else buildInFunctions.expression.parse(c[1],b)}else{var k=buildInFunctions.expression.parse(c[1],b);"build-in"==k.type&&"operator"==k.name&&"="==k.op&&(a=a.replace(/^\n/,""))}}return a&&parseText(a,b),b}function parseText(a,b){if(parseText.parseEmbeddedVars)for(var c=/([$][\w@]+)|`([^`]*)`/,d=c.exec(a);d;d=c.exec(a))b.push({type:"text",data:a.slice(0,d.index)}),b.push(parseExpression(d[1]?d[1]:d[2]).tree),a=a.slice(d.index+d[0].length);return b.push({type:"text",data:a}),b}function parseFunc(a,b,c){return b.__parsed.name=parseText(a,[])[0],c.push({type:"plugin",name:"__func",params:b}),c}function parseOperator(a,b,c,d){d.push({type:"build-in",name:"operator",op:a,optype:b,precedence:c,params:{}})}function parseVar(a,b,c){for(var d=b.token,e=[{type:"text",data:c.replace(/^(\w+)@(key|index|iteration|first|last|show|total)/gi,"$1__$2")}],f=/^(?:\.|\s*->\s*|\[\s*)/,g=a.match(f);g;g=a.match(f)){b.token+=g[0],a=a.slice(g[0].length);var h={value:"",tree:[]};if(g[0].match(/\[/)){h=parseExpression(a),h&&(b.token+=h.value,e.push(h.tree),a=a.slice(h.value.length));var i=a.match(/\s*\]/);i&&(b.token+=i[0],a=a.slice(i[0].length))}else{var j=parseModifiers.stop;if(parseModifiers.stop=!0,lookUp(a,h)){b.token+=h.value;var k=h.tree[0];"plugin"==k.type&&"__func"==k.name&&(k.hasOwner=!0),e.push(k),a=a.slice(h.value.length)}else h=!1;parseModifiers.stop=j}h||e.push({type:"text",data:""})}return b.tree.push({type:"var",parts:e}),b.value+=b.token.substr(d.length),onParseVar(b.token),a}function onParseVar(){}function parseModifiers(a,b){if(!parseModifiers.stop){var c=a.match(/^\|(\w+)/);if(c){b.value+=c[0];var d="default"==c[1]?"defaultValue":c[1];a=a.slice(c[0].length).replace(/^\s+/,""),parseModifiers.stop=!0;for(var e=[],f=a.match(/^\s*:\s*/);f;f=a.match(/^\s*:\s*/)){b.value+=a.slice(0,f[0].length),a=a.slice(f[0].length);var g={value:"",tree:[]};lookUp(a,g)?(b.value+=g.value,e.push(g.tree[0]),a=a.slice(g.value.length)):parseText("",e)}parseModifiers.stop=!1,e.unshift(b.tree.pop()),b.tree.push(parseFunc(d,{__parsed:e},[])[0]),parseModifiers(a,b)}}}function lookUp(a,b){if(!a)return!1;if(a.substr(0,jSmart.prototype.left_delimiter.length)==jSmart.prototype.left_delimiter){var c=findTag("",a);if(c)return b.token=c[0],b.value+=c[0],parse(c[0],b.tree),parseModifiers(a.slice(b.value.length),b),!0}for(var d=0;d<tokens.length;++d)if(a.match(tokens[d].re))return b.token=RegExp.lastMatch,b.value+=RegExp.lastMatch,tokens[d].parse(b,a.slice(b.token.length)),!0;return!1}function bundleOp(a,b,c){var d=b[a];if("operator"==d.name&&d.precedence==c&&!d.params.__parsed){if("binary"==d.optype)return d.params.__parsed=[b[a-1],b[a+1]],b.splice(a-1,3,d),!0;if("post-unary"==d.optype)return d.params.__parsed=[b[a-1]],b.splice(a-1,2,d),!0;d.params.__parsed=[b[a+1]],b.splice(a,2,d)}return!1}function composeExpression(a){var b=0;for(b=0;b<a.length;++b)a[b]instanceof Array&&(a[b]=composeExpression(a[b]));for(var c=1;14>c;++c)if(2==c||10==c)for(b=a.length;b>0;--b)b-=bundleOp(b-1,a,c);else for(b=0;b<a.length;++b)b-=bundleOp(b,a,c);return a[0]}function parseExpression(a){for(var b={value:"",tree:[]};lookUp(a.slice(b.value.length),b););return b.tree.length?(b.tree=composeExpression(b.tree),b):!1}function parseParams(a,b,c){var d=a.replace(/\n/g," ").replace(/^\s+|\s+$/g,""),e=[];e.__parsed=[];var a="";if(!d)return e;for(b||(b=/^\s+/,c=/^(\w+)\s*=\s*/);d;){var f=null;if(c){var g=d.match(c);g&&(f=trimQuotes(g[1]),a+=d.slice(0,g[0].length),d=d.slice(g[0].length))}var h=parseExpression(d);if(!h)break;f?(e[f]=h.value,e.__parsed[f]=h.tree):(e.push(h.value),e.__parsed.push(h.tree)),a+=d.slice(0,h.value.length),d=d.slice(h.value.length);var i=d.match(b);if(!i)break;a+=d.slice(0,i[0].length),d=d.slice(i[0].length)}return e.toString=function(){return a},e}function parsePluginBlock(a,b,c,d){c.push({type:"plugin",name:a,params:b,subTree:parse(d,[])})}function parsePluginFunc(a,b,c){c.push({type:"plugin",name:a,params:b})}function getActualParamValues(a,b){var c=[];for(var d in a.__parsed)if(a.__parsed.hasOwnProperty(d)){var e=process([a.__parsed[d]],b);c[d]=e}return c.__get=function(a,b,d){if(a in c&&"undefined"!=typeof c[a])return c[a];if("undefined"!=typeof d&&"undefined"!=typeof c[d])return c[d];if(null===b)throw new Error("The required attribute '"+a+"' is missing");return b},c}function isEmptyObject(a){for(var b in a)if(a.hasOwnProperty(b))return!1;return!0}function getVarValue(a,b,c){for(var d=b,e="",f=0;f<a.parts.length;++f){var g=a.parts[f];if("plugin"==g.type&&"__func"==g.name&&g.hasOwner)b.__owner=d,d=process([a.parts[f]],b),delete b.__owner;else if(e=process([g],b),e in b.smarty.section&&"text"==g.type&&"smarty"!=process([a.parts[0]],b)&&(e=b.smarty.section[e].index),!e&&"undefined"!=typeof c&&d instanceof Array&&(e=d.length),"undefined"!=typeof c&&f==a.parts.length-1&&(d[e]=c),"object"==typeof d&&null!==d&&e in d)d=d[e];else{if("undefined"==typeof c)return c;d[e]={},d=d[e]}}return d}function process(a,b){for(var c="",d=0;d<a.length;++d){var e="",f=a[d];if("text"==f.type)e=f.data;else if("var"==f.type)e=getVarValue(f,b);else if("build-in"==f.type)e=buildInFunctions[f.name].process(f,b);else if("plugin"==f.type){var g=plugins[f.name];if("block"==g.type){var h={value:!0};for(g.process(getActualParamValues(f.params,b),"",b,h);h.value;)h.value=!1,e+=g.process(getActualParamValues(f.params,b),process(f.subTree,b),b,h)}else"function"==g.type&&(e=g.process(getActualParamValues(f.params,b),b))}if("boolean"==typeof e&&(e=e?"1":""),1==a.length)return e;if(c+=e,b.smarty["continue"]||b.smarty["break"])return c}return c}function getTemplate(a,b,c){if(!c&&a in files)b=files[a];else{var d=jSmart.prototype.getTemplate(a);if("string"!=typeof d)throw new Error("No template for "+a);parse(applyFilters(jSmart.prototype.filters_global.pre,stripComments(d.replace(/\r\n/g,"\n"))),b),files[a]=b}return b}function stripComments(a){for(var b="",c=a.match(/{\*/);c;c=a.match(/{\*/)){b+=a.slice(0,c.index),a=a.slice(c.index+c[0].length);var d=a.match(/\*}/);if(!d)throw new Error("Unclosed {*");a=a.slice(d.index+d[0].length)}return b+a}function applyFilters(a,b){for(var c=0;c<a.length;++c)b=a[c](b);return b}var buildInFunctions={expression:{parse:function(a,b){var c=parseExpression(a);return b.push({type:"build-in",name:"expression",expression:c.tree,params:parseParams(a.slice(c.value.length).replace(/^\s+|\s+$/g,""))}),c.tree},process:function(a,b){var c=getActualParamValues(a.params,b),d=process([a.expression],b);if(findInArray(c,"nofilter")<0){for(var e=0;e<default_modifiers.length;++e){var f=default_modifiers[e];f.params.__parsed[0]={type:"text",data:d},d=process([f],b)}escape_html&&(d=modifiers.escape(d)),d=applyFilters(varFilters,d),tpl_modifiers.length&&(__t=function(){return d},d=process(tpl_modifiers,b))}return d}},operator:{process:function(a,b){var c=getActualParamValues(a.params,b),d=c[0];if("binary"!=a.optype){if("!"==a.op)return!d;var e="var"==a.params.__parsed[0].type;e&&(d=getVarValue(a.params.__parsed[0],b));var f=d;if("pre-unary"==a.optype){switch(a.op){case"-":f=-d;break;case"++":f=++d;break;case"--":f=--d}e&&getVarValue(a.params.__parsed[0],b,d)}else{switch(a.op){case"++":d++;break;case"--":d--}getVarValue(a.params.__parsed[0],b,d)}return f}var g=c[1];if("="==a.op)return getVarValue(a.params.__parsed[0],b,g),"";if(a.op.match(/(\+=|-=|\*=|\/=|%=)/)){switch(d=getVarValue(a.params.__parsed[0],b),a.op){case"+=":d+=g;break;case"-=":d-=g;break;case"*=":d*=g;break;case"/=":d/=g;break;case"%=":d%=g}return getVarValue(a.params.__parsed[0],b,d)}if(a.op.match(/div/))return"div"!=a.op^d%g==0;if(a.op.match(/even/))return"even"!=a.op^d/g%2==0;if(a.op.match(/xor/))return(d||g)&&!(d&&g);switch(a.op){case"==":return d==g;case"!=":return d!=g;case"+":return Number(d)+Number(g);case"-":return Number(d)-Number(g);case"*":return Number(d)*Number(g);case"/":return Number(d)/Number(g);case"%":return Number(d)%Number(g);case"&&":return d&&g;case"||":return d||g;case"<":return g>d;case"<=":return g>=d;case">":return d>g;case">=":return d>=g;case"===":return d===g;case"!==":return d!==g}}},section:{type:"block",parse:function(a,b,c){var d=[],e=[];b.push({type:"build-in",name:"section",params:a,subTree:d,subTreeElse:e});var f=findElseTag("section [^}]+","/section","sectionelse",c);f?(parse(c.slice(0,f.index),d),parse(c.slice(f.index+f[0].length).replace(/^[\r\n]/,""),e)):parse(c,d)},process:function(a,b){var c=getActualParamValues(a.params,b),d={};b.smarty.section[c.__get("name",null,0)]=d;var e=c.__get("show",!0);if(d.show=e,!e)return process(a.subTreeElse,b);var f=parseInt(c.__get("start",0)),g=c.loop instanceof Object?countProperties(c.loop):isNaN(c.loop)?0:parseInt(c.loop),h=parseInt(c.__get("step",1)),i=parseInt(c.__get("max"));isNaN(i)&&(i=Number.MAX_VALUE),0>f?(f+=g,0>f&&(f=0)):f>=g&&(f=g?g-1:0);for(var j=0,k=0,l=f;l>=0&&g>l&&i>j;l+=h,++j)k=l;d.total=j,d.loop=j,j=0;var m="";for(l=f;l>=0&&g>l&&i>j&&!b.smarty["break"];l+=h,++j)d.first=l==f,d.last=0>l+h||l+h>=g,d.index=l,d.index_prev=l-h,d.index_next=l+h,d.iteration=d.rownum=j+1,m+=process(a.subTree,b),b.smarty["continue"]=!1;return b.smarty["break"]=!1,j?m:process(a.subTreeElse,b)}},setfilter:{type:"block",parseParams:function(a){return[parseExpression("__t()|"+a).tree]},parse:function(a,b,c){b.push({type:"build-in",name:"setfilter",params:a,subTree:parse(c,[])})},process:function(a,b){tpl_modifiers=a.params;var c=process(a.subTree,b);return tpl_modifiers=[],c}},"for":{type:"block",parseParams:function(a){var b=a.match(/^\s*\$(\w+)\s*=\s*([^\s]+)\s*to\s*([^\s]+)\s*(?:step\s*([^\s]+))?\s*(.*)$/);if(!b)throw new Error("Invalid {for} parameters: "+a);return parseParams("varName='"+b[1]+"' from="+b[2]+" to="+b[3]+" step="+(b[4]?b[4]:"1")+" "+b[5])},parse:function(a,b,c){var d=[],e=[];b.push({type:"build-in",name:"for",params:a,subTree:d,subTreeElse:e});var f=findElseTag("for\\s[^}]+","/for","forelse",c);f?(parse(c.slice(0,f.index),d),parse(c.slice(f.index+f[0].length),e)):parse(c,d)},process:function(a,b){var c=getActualParamValues(a.params,b),d=parseInt(c.__get("from")),e=parseInt(c.__get("to")),f=parseInt(c.__get("step"));isNaN(f)&&(f=1);var g=parseInt(c.__get("max"));isNaN(g)&&(g=Number.MAX_VALUE);for(var h=0,i="",j=Math.min(Math.ceil(((f>0?e-d:d-e)+1)/Math.abs(f)),g),k=parseInt(c.from);j>h&&!b.smarty["break"];k+=f,++h)b[c.varName]=k,i+=process(a.subTree,b),b.smarty["continue"]=!1;return b.smarty["break"]=!1,h||(i=process(a.subTreeElse,b)),i}},"if":{type:"block",parse:function(a,b,c){var d=[],e=[];b.push({type:"build-in",name:"if",params:a,subTreeIf:d,subTreeElse:e});var f=findElseTag("if\\s+[^}]+","/if","else[^}]*",c);if(f){parse(c.slice(0,f.index),d),c=c.slice(f.index+f[0].length);var g=f[1].match(/^else\s*if(.*)/);g?buildInFunctions["if"].parse(parseParams(g[1]),e,c.replace(/^\n/,"")):parse(c.replace(/^\n/,""),e)}else parse(c,d)},process:function(a,b){var c=getActualParamValues(a.params,b)[0];return c&&!(c instanceof Array&&0==c.length||"object"==typeof c&&isEmptyObject(c))?process(a.subTreeIf,b):process(a.subTreeElse,b)}},foreach:{type:"block",parseParams:function(a){var b=a.match(/^\s*([$].+)\s*as\s*[$](\w+)\s*(=>\s*[$](\w+))?\s*$/i);return b&&(a="from="+b[1]+" item="+(b[4]||b[2]),b[4]&&(a+=" key="+b[2])),parseParams(a)},parse:function(a,b,c){var d=[],e=[];b.push({type:"build-in",name:"foreach",params:a,subTree:d,subTreeElse:e});var f=findElseTag("foreach\\s[^}]+","/foreach","foreachelse",c);f?(parse(c.slice(0,f.index),d),parse(c.slice(f.index+f[0].length).replace(/^[\r\n]/,""),e)):parse(c,d)},process:function(a,b){var c=getActualParamValues(a.params,b),d=c.from;d instanceof Object||(d=[d]);var e=countProperties(d);b[c.item+"__total"]=e,"name"in c&&(b.smarty.foreach[c.name]={},b.smarty.foreach[c.name].total=e);var f="",g=0;for(var h in d)if(d.hasOwnProperty(h)){if(b.smarty["break"])break;b[c.item+"__key"]=isNaN(h)?h:parseInt(h),"key"in c&&(b[c.key]=b[c.item+"__key"]),b[c.item]=d[h],b[c.item+"__index"]=parseInt(g),b[c.item+"__iteration"]=parseInt(g+1),b[c.item+"__first"]=0===g,b[c.item+"__last"]=g==e-1,"name"in c&&(b.smarty.foreach[c.name].index=parseInt(g),b.smarty.foreach[c.name].iteration=parseInt(g+1),b.smarty.foreach[c.name].first=0===g?1:"",b.smarty.foreach[c.name].last=g==e-1?1:""),++g,f+=process(a.subTree,b),b.smarty["continue"]=!1}return b.smarty["break"]=!1,b[c.item+"__show"]=g>0,c.name&&(b.smarty.foreach[c.name].show=g>0?1:""),g>0?f:process(a.subTreeElse,b)}},"function":{type:"block",parse:function(a,b,c){var d=[];plugins[trimQuotes(a.name?a.name:a[0])]={type:"function",subTree:d,defautParams:a,process:function(a,b){var c=getActualParamValues(this.defautParams,b);return delete c.name,process(this.subTree,obMerge({},b,c,a))}},parse(c,d)}},php:{type:"block",parse:function(){}},"extends":{type:"function",parse:function(a,b){b.splice(0,b.length),getTemplate(trimQuotes(a.file?a.file:a[0]),b)}},block:{type:"block",parse:function(a,b,c){b.push({type:"build-in",name:"block",params:a}),a.append=findInArray(a,"append")>=0,a.prepend=findInArray(a,"prepend")>=0,a.hide=findInArray(a,"hide")>=0,a.hasChild=a.hasParent=!1,onParseVar=function(b){b.match(/^\s*[$]smarty.block.child\s*$/)&&(a.hasChild=!0),b.match(/^\s*[$]smarty.block.parent\s*$/)&&(a.hasParent=!0)};var b=parse(c,[]);onParseVar=function(){};var d=trimQuotes(a.name?a.name:a[0]);d in blocks||(blocks[d]=[]),blocks[d].push({tree:b,params:a})},process:function(a,b){b.smarty.block.parent=b.smarty.block.child="";var c=trimQuotes(a.params.name?a.params.name:a.params[0]);return this.processBlocks(blocks[c],blocks[c].length-1,b),b.smarty.block.child},processBlocks:function(a,b,c){if(!b&&a[b].params.hide)return void(c.smarty.block.child="");for(var d=!0,e=!1;b>=0;--b){if(a[b].params.hasParent){var f=c.smarty.block.child;c.smarty.block.child="",this.processBlocks(a,b-1,c),c.smarty.block.parent=c.smarty.block.child,c.smarty.block.child=f}var f=c.smarty.block.child,g=process(a[b].tree,c);c.smarty.block.child=f,a[b].params.hasChild?c.smarty.block.child=g:d?c.smarty.block.child=g+c.smarty.block.child:e&&(c.smarty.block.child+=g),d=a[b].params.append,e=a[b].params.prepend}}},strip:{type:"block",parse:function(a,b,c){parse(c.replace(/[ \t]*[\r\n]+[ \t]*/g,""),b)}},literal:{type:"block",parse:function(a,b,c){parseText(c,b)}},ldelim:{type:"function",parse:function(a,b){parseText(jSmart.prototype.left_delimiter,b)}},rdelim:{type:"function",parse:function(a,b){parseText(jSmart.prototype.right_delimiter,b)}},"while":{type:"block",parse:function(a,b,c){b.push({type:"build-in",name:"while",params:a,subTree:parse(c,[])})},process:function(a,b){for(var c="";getActualParamValues(a.params,b)[0]&&!b.smarty["break"];)c+=process(a.subTree,b),b.smarty["continue"]=!1;return b.smarty["break"]=!1,c}}},plugins={},modifiers={},files={},blocks=null,scripts=null,tpl_modifiers=[],tokens=[{re:/^\$([\w@]+)/,parse:function(a,b){parseModifiers(parseVar(b,a,RegExp.$1),a)}},{re:/^(true|false)/i,parse:function(a){parseText(a.token.match(/true/i)?"1":"",a.tree)}},{re:/^'([^'\\]*(?:\\.[^'\\]*)*)'/,parse:function(a,b){parseText(evalString(RegExp.$1),a.tree),parseModifiers(b,a)}},{re:/^"([^"\\]*(?:\\.[^"\\]*)*)"/,parse:function(a,b){var c=evalString(RegExp.$1),d=c.match(tokens[0].re);if(d){var e={token:d[0],tree:[]};if(parseVar(c,e,d[1]),e.token.length==c.length)return void a.tree.push(e.tree[0])}parseText.parseEmbeddedVars=!0,a.tree.push({type:"plugin",name:"__quoted",params:{__parsed:parse(c,[])}}),parseText.parseEmbeddedVars=!1,parseModifiers(b,a)}},{re:/^(\w+)\s*[(]([)]?)/,parse:function(a,b){var c=RegExp.$1,d=RegExp.$2,e=parseParams(d?"":b,/^\s*,\s*/);parseFunc(c,e,a.tree),a.value+=e.toString(),parseModifiers(b.slice(e.toString().length),a)}},{re:/^\s*\(\s*/,parse:function(a){var b=[];a.tree.push(b),b.parent=a.tree,a.tree=b}},{re:/^\s*\)\s*/,parse:function(a){a.tree.parent&&(a.tree=a.tree.parent)}},{re:/^\s*(\+\+|--)\s*/,parse:function(a){a.tree.length&&"var"==a.tree[a.tree.length-1].type?parseOperator(RegExp.$1,"post-unary",1,a.tree):parseOperator(RegExp.$1,"pre-unary",1,a.tree)}},{re:/^\s*(===|!==|==|!=)\s*/,parse:function(a){parseOperator(RegExp.$1,"binary",6,a.tree)}},{re:/^\s+(eq|ne|neq)\s+/i,parse:function(a){var b=RegExp.$1.replace(/ne(q)?/,"!=").replace(/eq/,"==");parseOperator(b,"binary",6,a.tree)}},{re:/^\s*!\s*/,parse:function(a){parseOperator("!","pre-unary",2,a.tree)}},{re:/^\s+not\s+/i,parse:function(a){parseOperator("!","pre-unary",2,a.tree)}},{re:/^\s*(=|\+=|-=|\*=|\/=|%=)\s*/,parse:function(a){parseOperator(RegExp.$1,"binary",10,a.tree)}},{re:/^\s*(\*|\/|%)\s*/,parse:function(a){parseOperator(RegExp.$1,"binary",3,a.tree)}},{re:/^\s+mod\s+/i,parse:function(a){parseOperator("%","binary",3,a.tree)}},{re:/^\s*(\+|-)\s*/,parse:function(a){a.tree.length&&"operator"!=a.tree[a.tree.length-1].name?parseOperator(RegExp.$1,"binary",4,a.tree):parseOperator(RegExp.$1,"pre-unary",4,a.tree)}},{re:/^\s*(<=|>=|<>|<|>)\s*/,parse:function(a){parseOperator(RegExp.$1.replace(/<>/,"!="),"binary",5,a.tree)}},{re:/^\s+(lt|lte|le|gt|gte|ge)\s+/i,parse:function(a){var b=RegExp.$1.replace(/lt/,"<").replace(/l(t)?e/,"<=").replace(/gt/,">").replace(/g(t)?e/,">=");parseOperator(b,"binary",5,a.tree)}},{re:/^\s+(is\s+(not\s+)?div\s+by)\s+/i,parse:function(a){parseOperator(RegExp.$2?"div_not":"div","binary",7,a.tree)}},{re:/^\s+is\s+(not\s+)?(even|odd)(\s+by\s+)?\s*/i,parse:function(a){var b=RegExp.$1?"odd"==RegExp.$2?"even":"even_not":"odd"==RegExp.$2?"even_not":"even";parseOperator(b,"binary",7,a.tree),RegExp.$3||parseText("1",a.tree)}},{re:/^\s*(&&)\s*/,parse:function(a){parseOperator(RegExp.$1,"binary",8,a.tree)}},{re:/^\s*(\|\|)\s*/,parse:function(a){parseOperator(RegExp.$1,"binary",9,a.tree)}},{re:/^\s+and\s+/i,parse:function(a){parseOperator("&&","binary",11,a.tree)}},{re:/^\s+xor\s+/i,parse:function(a){parseOperator("xor","binary",12,a.tree)}},{re:/^\s+or\s+/i,parse:function(a){parseOperator("||","binary",13,a.tree)}},{re:/^#(\w+)#/,parse:function(a,b){var c={token:"$smarty",tree:[]};parseVar(".config."+RegExp.$1,c,"smarty"),a.tree.push(c.tree[0]),parseModifiers(b,a)}},{re:/^\s*\[\s*/,parse:function(a,b){var c=parseParams(b,/^\s*,\s*/,/^('[^'\\]*(?:\\.[^'\\]*)*'|"[^"\\]*(?:\\.[^"\\]*)*"|\w+)\s*=>\s*/);parsePluginFunc("__array",c,a.tree),a.value+=c.toString();var d=b.slice(c.toString().length).match(/\s*\]/);d&&(a.value+=d[0])}},{re:/^[\d.]+/,parse:function(a,b){a.token=a.token.indexOf(".")>-1?parseFloat(a.token):parseInt(a.token,10),parseText(a.token,a.tree),parseModifiers(b,a)}},{re:/^\w+/,parse:function(a,b){parseText(a.token,a.tree),parseModifiers(b,a)}}];jSmart=function(a){this.tree=[],this.tree.blocks={},this.scripts={},this.default_modifiers=[],this.filters={variable:[],post:[]},this.smarty={smarty:{block:{},"break":!1,capture:{},"continue":!1,counter:{},cycle:{},foreach:{},section:{},now:Math.floor((new Date).getTime()/1e3),"const":{},config:{},current_dir:"/",template:"",ldelim:jSmart.prototype.left_delimiter,rdelim:jSmart.prototype.right_delimiter,version:"2.15.0"}},blocks=this.tree.blocks,parse(applyFilters(jSmart.prototype.filters_global.pre,stripComments(new String(a?a:"").replace(/\r\n/g,"\n"))),this.tree)},jSmart.prototype.fetch=function(a){blocks=this.tree.blocks,scripts=this.scripts,escape_html=this.escape_html,default_modifiers=jSmart.prototype.default_modifiers_global.concat(this.default_modifiers),this.data=obMerge("object"==typeof a?a:{},this.smarty),varFilters=jSmart.prototype.filters_global.variable.concat(this.filters.variable);var b=process(this.tree,this.data);return jSmart.prototype.debugging&&plugins.debug.process([],this.data),applyFilters(jSmart.prototype.filters_global.post.concat(this.filters.post),b)},jSmart.prototype.escape_html=!1,jSmart.prototype.registerPlugin=function(a,b,c){"modifier"==a?modifiers[b]=c:plugins[b]={type:a,process:c}},jSmart.prototype.registerFilter=function(a,b){(this.tree?this.filters:jSmart.prototype.filters_global)["output"==a?"post":a].push(b)},jSmart.prototype.filters_global={pre:[],variable:[],post:[]},jSmart.prototype.configLoad=function(a,b,c){c=c?c:this.data;for(var d=a.replace(/\r\n/g,"\n").replace(/^\s+|\s+$/g,""),e=/^\s*(?:\[([^\]]+)\]|(?:(\w+)[ \t]*=[ \t]*("""|'[^'\\\n]*(?:\\.[^'\\\n]*)*'|"[^"\\\n]*(?:\\.[^"\\\n]*)*"|[^\n]*)))/m,f="",g=d.match(e);g;g=d.match(e)){if(d=d.slice(g.index+g[0].length),g[1])f=g[1];else if((!f||f==b)&&"."!=f.substr(0,1))if('"""'==g[3]){var h=d.match(/"""/);h&&(c.smarty.config[g[2]]=d.slice(0,h.index),d=d.slice(h.index+h[0].length))}else c.smarty.config[g[2]]=trimQuotes(g[3]);var i=d.match(/\n+/);if(!i)break;d=d.slice(i.index+i[0].length)}},jSmart.prototype.clearConfig=function(a){a?delete this.data.smarty.config[a]:this.data.smarty.config={}},jSmart.prototype.addDefaultModifier=function(a){a instanceof Array||(a=[a]);for(var b=0;b<a.length;++b){var c={value:"",tree:[0]};parseModifiers("|"+a[b],c),(this.tree?this.default_modifiers:this.default_modifiers_global).push(c.tree[0])}},jSmart.prototype.default_modifiers_global=[],jSmart.prototype.getTemplate=function(a){throw new Error("No template for "+a)},jSmart.prototype.getFile=function(a){throw new Error("No file for "+a)},jSmart.prototype.getJavascript=function(a){throw new Error("No Javascript for "+a)},jSmart.prototype.getConfig=function(a){throw new Error("No config for "+a)},jSmart.prototype.auto_literal=!0,jSmart.prototype.left_delimiter="{",jSmart.prototype.right_delimiter="}",jSmart.prototype.debugging=!1,jSmart.prototype.PHPJS=function(fnm,modifier){if("function"==eval("typeof "+fnm))return"object"==typeof window?window:global;if("function"==typeof PHP_JS)return new PHP_JS;throw new Error("Modifier '"+modifier+"' uses JavaScript port of PHP function '"+fnm+"'. You can find one at http://phpjs.org")},jSmart.prototype.makeTimeStamp=function(a){if(!a)return Math.floor((new Date).getTime()/1e3);if(isNaN(a)){var b=jSmart.prototype.PHPJS("strtotime","date_format").strtotime(a);return-1==b||b===!1?Math.floor((new Date).getTime()/1e3):b}return a=new String(a),14==a.length?Math.floor(new Date(a.substr(0,4),a.substr(4,2)-1,a.substr(6,2),a.substr(8,2),a.substr(10,2)).getTime()/1e3):parseInt(a)},jSmart.prototype.registerPlugin("function","__array",function(a){var b=[];for(var c in a)a.hasOwnProperty(c)&&a[c]&&"function"!=typeof a[c]&&(b[c]=a[c]);return b}),jSmart.prototype.registerPlugin("function","__func",function(a,b){for(var c=[],d={},e=[],f=0;f<a.length;++f)c.push(a.name+"__p"+f),e.push(a[f]),d[a.name+"__p"+f]=a[f];var g,h=obMerge({},b,d);return"__owner"in b&&a.name in b.__owner?(g="__owner."+a.name,execute(g+"("+c.join(",")+")",h)):modifiers.hasOwnProperty(a.name)?(g=modifiers[a.name],executeByFuncObject(g,e,h)):(g=a.name,execute(g+"("+c.join(",")+")",h))}),jSmart.prototype.registerPlugin("function","__quoted",function(a){return a.join("")}),jSmart.prototype.registerPlugin("function","append",function(a,b){var c=a.__get("var",null,0);c in b&&b[c]instanceof Array||(b[c]=[]);var d=a.__get("index",!1),e=a.__get("value",null,1);return d===!1?b[c].push(e):b[c][d]=e,""}),jSmart.prototype.registerPlugin("function","assign",function(a,b){return assignVar(a.__get("var",null,0),a.__get("value",null,1),b),""}),jSmart.prototype.registerPlugin("function","break",function(a,b){return b.smarty["break"]=!0,""}),jSmart.prototype.registerPlugin("function","call",function(a,b){var c=a.__get("name",null,0);delete a.name;var d=a.__get("assign",!1);delete a.assign;var e=plugins[c].process(a,b);return d?(assignVar(d,e,b),""):e}),jSmart.prototype.registerPlugin("block","capture",function(a,b,c){if(b){b=b.replace(/^\n/,""),c.smarty.capture[a.__get("name","default",0)]=b,"assign"in a&&assignVar(a.assign,b,c);var d=a.__get("append",!1);d&&(d in c?c[d]instanceof Array&&c[d].push(b):c[d]=[b])}return""}),jSmart.prototype.registerPlugin("function","continue",function(a,b){return b.smarty["continue"]=!0,""}),jSmart.prototype.registerPlugin("function","counter",function(a,b){var c=a.__get("name","default");if(c in b.smarty.counter){var d=b.smarty.counter[c];"start"in a?d.value=parseInt(a.start):(d.value=parseInt(d.value),d.skip=parseInt(d.skip),"down"==d.direction?d.value-=d.skip:d.value+=d.skip),d.skip=a.__get("skip",d.skip),d.direction=a.__get("direction",d.direction),d.assign=a.__get("assign",d.assign)}else b.smarty.counter[c]={value:parseInt(a.__get("start",1)),skip:parseInt(a.__get("skip",1)),direction:a.__get("direction","up"),assign:a.__get("assign",!1)};return b.smarty.counter[c].assign?(b[b.smarty.counter[c].assign]=b.smarty.counter[c].value,""):a.__get("print",!0)?b.smarty.counter[c].value:""}),jSmart.prototype.registerPlugin("function","cycle",function(a,b){var c=a.__get("name","default"),d=a.__get("reset",!1);c in b.smarty.cycle||(b.smarty.cycle[c]={arr:[""],delimiter:a.__get("delimiter",","),index:0},d=!0),a.__get("delimiter",!1)&&(b.smarty.cycle[c].delimiter=a.delimiter);var e=a.__get("values",!1);if(e){var f=[];if(e instanceof Object)for(nm in e)f.push(e[nm]);else f=e.split(b.smarty.cycle[c].delimiter);(f.length!=b.smarty.cycle[c].arr.length||f[0]!=b.smarty.cycle[c].arr[0])&&(b.smarty.cycle[c].arr=f,b.smarty.cycle[c].index=0,d=!0)}return a.__get("advance","true")&&(b.smarty.cycle[c].index+=1),(b.smarty.cycle[c].index>=b.smarty.cycle[c].arr.length||d)&&(b.smarty.cycle[c].index=0),a.__get("assign",!1)?(assignVar(a.assign,b.smarty.cycle[c].arr[b.smarty.cycle[c].index],b),""):a.__get("print",!0)?b.smarty.cycle[c].arr[b.smarty.cycle[c].index]:""}),jSmart.prototype.print_r=function(a,b){if(a instanceof Object){var c=(a instanceof Array?"Array["+a.length+"]":"Object")+"<br>";for(var d in a)a.hasOwnProperty(d)&&(c+=b+"&nbsp;&nbsp;<strong>"+d+"</strong> : "+jSmart.prototype.print_r(a[d],b+"&nbsp;&nbsp;&nbsp;")+"<br>");return c}return a},jSmart.prototype.registerPlugin("function","debug",function(a,b){"undefined"!=typeof dbgWnd&&dbgWnd.close(),dbgWnd=window.open("","","width=680,height=600,resizable,scrollbars=yes");var c="",d=0;for(var e in b)c+="<tr class="+(++d%2?"odd":"even")+"><td><strong>"+e+"</strong></td><td>"+jSmart.prototype.print_r(b[e],"")+"</td></tr>";return dbgWnd.document.write("                <html xmlns='http://www.w3.org/1999/xhtml' xml:lang='en'>                <head>                       <title>jSmart Debug Console</title>                   <style type='text/css'>                      table {width: 100%;}                      td {vertical-align:top;width: 50%;}                      .even td {background-color: #fafafa;}                   </style>                </head>                <body>                   <h1>jSmart Debug Console</h1>                   <h2>assigned template variables</h2>                   <table>"+c+"</table>                </body>                </html>             "),""}),jSmart.prototype.registerPlugin("function","eval",function(a,b){var c=[];parse(a.__get("var","",0),c);var d=process(c,b);return"assign"in a?(assignVar(a.assign,d,b),""):d}),jSmart.prototype.registerPlugin("function","fetch",function(a,b){var c=jSmart.prototype.getFile(a.__get("file",null,0));return"assign"in a?(assignVar(a.assign,c,b),""):c}),jSmart.prototype.registerPlugin("function","html_checkboxes",function(a,b){var c,d,e,f=a.__get("type","checkbox"),g=a.__get("name",f),h=a.__get("name",f),i=a.__get("values",a.options),j=a.__get("options",[]),k="options"in a,l=a.__get("selected",!1),m=a.__get("separator",""),n=Boolean(a.__get("labels",!0)),o=Boolean(a.__get("label_ids",!1)),p=[],q=0,r="";if("checkbox"==f&&(g+="[]"),!k)for(c in a.output)j.push(a.output[c]);for(c in i)i.hasOwnProperty(c)&&(d=k?c:i[c],e=h+"_"+d,r=n?o?'<label for="'+e+'">':"<label>":"",r+='<input type="'+f+'" name="'+g+'" value="'+d+'" ',o&&(r+='id="'+e+'" '),l==(k?c:i[c])&&(r+='checked="checked" '),r+="/>"+j[k?c:q++],r+=n?"</label>":"",r+=m,p.push(r));return"assign"in a?(assignVar(a.assign,p,b),""):p.join("\n")}),jSmart.prototype.registerPlugin("function","html_image",function(a){var b,c=a.__get("file",null),d=a.__get("width",!1),e=a.__get("height",!1),f=a.__get("alt",""),g=a.__get("href",a.__get("link",!1)),h=a.__get("path_prefix",""),i={file:1,width:1,height:1,alt:1,href:1,basedir:1,path_prefix:1,link:1},j='<img src="'+h+c+'" alt="'+f+'"'+(d?' width="'+d+'"':"")+(e?' height="'+e+'"':"");for(b in a)a.hasOwnProperty(b)&&"string"==typeof a[b]&&(b in i||(j+=" "+b+'="'+a[b]+'"'));return j+=" />",g?'<a href="'+g+'">'+j+"</a>":j}),jSmart.prototype.registerPlugin("function","html_options",function(a){var b,c=a.__get("values",a.options),d=a.__get("options",[]),e="options"in a;if(!e)for(b in a.output)d.push(a.output[b]);var f=a.__get("selected",!1),g=[],h="",i=0;for(b in c)c.hasOwnProperty(b)&&(h='<option value="'+(e?b:c[b])+'"',f==(e?b:c[b])&&(h+=' selected="selected"'),h+=">"+d[e?b:i++]+"</option>",g.push(h));var j=a.__get("name",!1);return(j?'<select name="'+j+'">\n'+g.join("\n")+"\n</select>":g.join("\n"))+"\n"}),jSmart.prototype.registerPlugin("function","html_radios",function(a,b){return a.type="radio",plugins.html_checkboxes.process(a,b)}),jSmart.prototype.registerPlugin("function","html_select_date",function(a){var b=a.__get("prefix","Date_"),c=["January","February","March","April","May","June","July","August","September","October","November","December"],d="";d+='<select name="'+b+'Month">\n';
-var e=0;for(e=0;e<c.length;++e)d+='<option value="'+e+'">'+c[e]+"</option>\n";for(d+="</select>\n",d+='<select name="'+b+'Day">\n',e=0;31>e;++e)d+='<option value="'+e+'">'+e+"</option>\n";return d+="</select>\n"}),jSmart.prototype.registerPlugin("function","html_table",function(a){var b,c=[];if(a.loop instanceof Array)c=a.loop;else for(b in a.loop)a.loop.hasOwnProperty(b)&&c.push(a.loop[b]);var d=a.__get("rows",!1),e=a.__get("cols",!1);e||(e=d?Math.ceil(c.length/d):3);var f=[];if(isNaN(e)){if("object"==typeof e)for(b in e)e.hasOwnProperty(b)&&f.push(e[b]);else f=e.split(/\s*,\s*/);e=f.length}d=d?d:Math.ceil(c.length/e);var g=a.__get("inner","cols"),h=a.__get("caption",""),i=a.__get("table_attr",'border="1"'),j=a.__get("th_attr",!1);j&&"object"!=typeof j&&(j=[j]);var k=a.__get("tr_attr",!1);k&&"object"!=typeof k&&(k=[k]);var l=a.__get("td_attr",!1);l&&"object"!=typeof l&&(l=[l]);for(var m=a.__get("trailpad","&nbsp;"),n=a.__get("hdir","right"),o=a.__get("vdir","down"),p="",q=0;d>q;++q){p+="<tr"+(k?" "+k[q%k.length]:"")+">\n";for(var r=0;e>r;++r){var s="cols"==g?("down"==o?q:d-1-q)*e+("right"==n?r:e-1-r):("right"==n?r:e-1-r)*d+("down"==o?q:d-1-q);p+="<td"+(l?" "+l[r%l.length]:"")+">"+(s<c.length?c[s]:m)+"</td>\n"}p+="</tr>\n"}var t="";if(f.length){t="\n<thead><tr>";for(var u=0;u<f.length;++u)t+="\n<th"+(j?" "+j[u%j.length]:"")+">"+f["right"==n?u:f.length-1-u]+"</th>";t+="\n</tr></thead>"}return"<table "+i+">"+(h?"\n<caption>"+h+"</caption>":"")+t+"\n<tbody>\n"+p+"</tbody>\n</table>\n"}),jSmart.prototype.registerPlugin("function","include",function(a,b){var c=a.__get("file",null,0),d=obMerge({},b,a);d.smarty.template=c;var e=process(getTemplate(c,[],findInArray(a,"nocache")>=0),d);return"assign"in a?(assignVar(a.assign,e,b),""):e}),jSmart.prototype.registerPlugin("function","include_javascript",function(a,b){var c=a.__get("file",null,0);if(a.__get("once",!0)&&c in scripts)return"";scripts[c]=!0;var d=execute(jSmart.prototype.getJavascript(c),{$this:b});return"assign"in a?(assignVar(a.assign,d,b),""):d}),jSmart.prototype.registerPlugin("function","include_php",function(a,b){return plugins.include_javascript.process(a,b)}),jSmart.prototype.registerPlugin("function","insert",function(params,data){var fparams={};for(var nm in params)params.hasOwnProperty(nm)&&isNaN(nm)&&params[nm]&&"string"==typeof params[nm]&&"name"!=nm&&"assign"!=nm&&"script"!=nm&&(fparams[nm]=params[nm]);var prefix="insert_";"script"in params&&(eval(jSmart.prototype.getJavascript(params.script)),prefix="smarty_insert_");var func=eval(prefix+params.__get("name",null,0)),s=func(fparams,data);return"assign"in params?(assignVar(params.assign,s,data),""):s}),jSmart.prototype.registerPlugin("block","javascript",function(a,b,c){return c.$this=c,execute(b,c),delete c.$this,""}),jSmart.prototype.registerPlugin("function","config_load",function(a,b){return jSmart.prototype.configLoad(jSmart.prototype.getConfig(a.__get("file",null,0)),a.__get("section","",1),b),""}),jSmart.prototype.registerPlugin("function","mailto",function(a){var b=a.__get("address",null),c=a.__get("encode","none"),d=a.__get("text",b),e=jSmart.prototype.PHPJS("rawurlencode","mailto").rawurlencode(a.__get("cc","")).replace("%40","@"),f=jSmart.prototype.PHPJS("rawurlencode","mailto").rawurlencode(a.__get("bcc","")).replace("%40","@"),g=jSmart.prototype.PHPJS("rawurlencode","mailto").rawurlencode(a.__get("followupto","")).replace("%40","@"),h=jSmart.prototype.PHPJS("rawurlencode","mailto").rawurlencode(a.__get("subject","")),i=jSmart.prototype.PHPJS("rawurlencode","mailto").rawurlencode(a.__get("newsgroups","")),j=a.__get("extra","");if(b+=e?"?cc="+e:"",b+=f?(e?"&":"?")+"bcc="+f:"",b+=h?(e||f?"&":"?")+"subject="+h:"",b+=i?(e||f||h?"&":"?")+"newsgroups="+i:"",b+=g?(e||f||h||i?"&":"?")+"followupto="+g:"",s='<a href="mailto:'+b+'" '+j+">"+d+"</a>","javascript"==c){s="document.write('"+s+"');";for(var k="",l=0;l<s.length;++l)k+="%"+jSmart.prototype.PHPJS("bin2hex","mailto").bin2hex(s.substr(l,1));return'<script type="text/javascript">eval(unescape(\''+k+"'))</script>"}if("javascript_charcode"==c){for(var m=[],l=0;l<s.length;++l)m.push(jSmart.prototype.PHPJS("ord","mailto").ord(s.substr(l,1)));return'<script type="text/javascript" language="javascript">\n<!--\n{document.write(String.fromCharCode('+m.join(",")+"))}\n//-->\n</script>\n"}if("hex"==c){if(b.match(/^.+\?.+$/))throw new Error("mailto: hex encoding does not work with extra attributes. Try javascript.");for(var n="",l=0;l<b.length;++l)n+=b.substr(l,1).match(/\w/)?"%"+jSmart.prototype.PHPJS("bin2hex","mailto").bin2hex(b.substr(l,1)):b.substr(l,1);for(var o="",l=0;l<d.length;++l)o+="&#x"+jSmart.prototype.PHPJS("bin2hex","mailto").bin2hex(d.substr(l,1))+";";return'<a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;'+n+'" '+j+">"+o+"</a>"}return s}),jSmart.prototype.registerPlugin("function","math",function(params,data){with(Math)with(params)var res=eval(params.__get("equation",null).replace(/pi\(\s*\)/g,"PI"));return"format"in params&&(res=jSmart.prototype.PHPJS("sprintf","math").sprintf(params.format,res)),"assign"in params?(assignVar(params.assign,res,data),""):res}),jSmart.prototype.registerPlugin("block","nocache",function(a,b){return b}),jSmart.prototype.registerPlugin("block","textformat",function(a,b,c){if(!b)return"";var d=a.__get("wrap",80),e=a.__get("wrap_char","\n"),f=a.__get("wrap_cut",!1),g=a.__get("indent_char"," "),h=a.__get("indent",0),i=new Array(h+1).join(g),j=a.__get("indent_first",0),k=new Array(j+1).join(g),l=a.__get("style","");"email"==l&&(d=72);for(var m=b.split(/[\r\n]{2}/),n=0;n<m.length;++n){var o=m[n];o&&(o=o.replace(/^\s+|\s+$/,"").replace(/\s+/g," "),j>0&&(o=k+o),o=modifiers.wordwrap(o,d-h,e,f),h>0&&(o=o.replace(/^/gm,i)),m[n]=o)}var p=m.join(e+e);return"assign"in a?(assignVar(a.assign,p,c),""):p}),jSmart.prototype.registerPlugin("modifier","capitalize",function(a,b,c){var d=new RegExp(b?"[^a-zA-Z_à-ü]+":"[^a-zA-Z0-9_à-ü]"),e=null,f="";for(c&&(a=a.toLowerCase()),e=a.match(d);e;e=a.match(d)){var g=a.slice(0,e.index);f+=g.match(/\d/)?g:g.charAt(0).toUpperCase()+g.slice(1),f+=a.slice(e.index,e.index+e[0].length),a=a.slice(e.index+e[0].length)}return a.match(/\d/)?f+a:f+a.charAt(0).toUpperCase()+a.slice(1)}),jSmart.prototype.registerPlugin("modifier","cat",function(a,b){return b=b?b:"",a+b}),jSmart.prototype.registerPlugin("modifier","count",function(a,b){if(null===a||"undefined"==typeof a)return 0;if(a.constructor!==Array&&a.constructor!==Object)return 1;b=Boolean(b);var c,d=0;for(c in a)a.hasOwnProperty(c)&&(d++,b&&a[c]&&(a[c].constructor===Array||a[c].constructor===Object)&&(d+=modifiers.count(a[c],!0)));return d}),jSmart.prototype.registerPlugin("modifier","count_characters",function(a,b){return b?a.length:a.replace(/\s/g,"").length}),jSmart.prototype.registerPlugin("modifier","count_paragraphs",function(a){var b=a.match(/\n+/g);return b?b.length+1:1}),jSmart.prototype.registerPlugin("modifier","count_sentences",function(a){var b=a.match(/[^\s]\.(?!\w)/g);return b?b.length:0}),jSmart.prototype.registerPlugin("modifier","count_words",function(a){var b=a.match(/\w+/g);return b?b.length:0}),jSmart.prototype.registerPlugin("modifier","date_format",function(a,b,c){return jSmart.prototype.PHPJS("strftime","date_format").strftime(b?b:"%b %e, %Y",jSmart.prototype.makeTimeStamp(a?a:c))}),jSmart.prototype.registerPlugin("modifier","defaultValue",function(a,b){return a&&"null"!=a&&"undefined"!=a?a:b?b:""}),jSmart.prototype.registerPlugin("modifier","unescape",function(a,b,c){switch(a=new String(a),b=b||"html",c=c||"UTF-8",b){case"html":return a.replace(/&lt;/g,"<").replace(/&gt;/g,">").replace(/&#039;/g,"'").replace(/&quot;/g,'"');case"entity":case"htmlall":return jSmart.prototype.PHPJS("html_entity_decode","unescape").html_entity_decode(a,0);case"url":return jSmart.prototype.PHPJS("rawurldecode","unescape").rawurldecode(a)}return a}),jSmart.prototype.registerPlugin("modifier","escape",function(a,b,c,d){switch(a=new String(a),b=b||"html",c=c||"UTF-8",d="undefined"!=typeof d?Boolean(d):!0,b){case"html":return d&&(a=a.replace(/&/g,"&amp;")),a.replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/'/g,"&#039;").replace(/"/g,"&quot;");case"htmlall":return jSmart.prototype.PHPJS("htmlentities","escape").htmlentities(a,3,c);case"url":return jSmart.prototype.PHPJS("rawurlencode","escape").rawurlencode(a);case"urlpathinfo":return jSmart.prototype.PHPJS("rawurlencode","escape").rawurlencode(a).replace(/%2F/g,"/");case"quotes":return a.replace(/(^|[^\\])'/g,"$1\\'");case"hex":for(var e="",f=0;f<a.length;++f)e+="%"+jSmart.prototype.PHPJS("bin2hex","escape").bin2hex(a.substr(f,1));return e;case"hexentity":for(var e="",f=0;f<a.length;++f)e+="&#x"+jSmart.prototype.PHPJS("bin2hex","escape").bin2hex(a.substr(f,1)).toLowerCase()+";";return e;case"decentity":for(var e="",f=0;f<a.length;++f)e+="&#"+jSmart.prototype.PHPJS("ord","escape").ord(a.substr(f,1))+";";return e;case"mail":return a.replace(/@/g," [AT] ").replace(/[.]/g," [DOT] ");case"nonstd":for(var e="",f=0;f<a.length;++f){var g=jSmart.prototype.PHPJS("ord","escape").ord(a.substr(f,1));e+=g>=126?"&#"+g+";":a.substr(f,1)}return e;case"javascript":return a.replace(/\\/g,"\\\\").replace(/'/g,"\\'").replace(/"/g,'\\"').replace(/\r/g,"\\r").replace(/\n/g,"\\n").replace(/<\//g,"</")}return a}),jSmart.prototype.registerPlugin("modifier","indent",function(a,b,c){b=b?b:4,c=c?c:" ";for(var d="";b--;)d+=c;var e=a.match(/\n+$/);return d+a.replace(/\n+$/,"").replace(/\n/g,"\n"+d)+(e?e[0]:"")}),jSmart.prototype.registerPlugin("modifier","lower",function(a){return a.toLowerCase()}),jSmart.prototype.registerPlugin("modifier","nl2br",function(a){return a.replace(/\n/g,"<br />\n")}),jSmart.prototype.registerPlugin("modifier","regex_replace",function(a,b,c){var d=b.match(/^ *\/(.*)\/(.*) *$/);return new String(a).replace(new RegExp(d[1],"g"+(d.length>1?d[2]:"")),c)}),jSmart.prototype.registerPlugin("modifier","replace",function(a,b,c){if(!b)return a;a=new String(a),b=new String(b),c=new String(c);var d="",e=-1;for(e=a.indexOf(b);e>=0;e=a.indexOf(b))d+=a.slice(0,e)+c,e+=b.length,a=a.slice(e);return d+a}),jSmart.prototype.registerPlugin("modifier","spacify",function(a,b){return b||(b=" "),a.replace(/(\n|.)(?!$)/g,"$1"+b)}),jSmart.prototype.registerPlugin("modifier","noprint",function(){return""}),jSmart.prototype.registerPlugin("modifier","string_format",function(a,b){return jSmart.prototype.PHPJS("sprintf","string_format").sprintf(b,a)}),jSmart.prototype.registerPlugin("modifier","strip",function(a,b){return b=b?b:" ",new String(a).replace(/[\s]+/g,b)}),jSmart.prototype.registerPlugin("modifier","strip_tags",function(a,b){return b=null==b?!0:b,new String(a).replace(/<[^>]*?>/g,b?" ":"")}),jSmart.prototype.registerPlugin("modifier","truncate",function(a,b,c,d,e){return b=b?b:80,c=null!=c?c:"...",a.length<=b?a:(b-=Math.min(b,c.length),e?a.slice(0,Math.floor(b/2))+c+a.slice(a.length-Math.floor(b/2)):(d||(a=a.slice(0,b+1).replace(/\s+?(\S+)?$/,"")),a.slice(0,b)+c))}),jSmart.prototype.registerPlugin("modifier","upper",function(a){return a.toUpperCase()}),jSmart.prototype.registerPlugin("modifier","wordwrap",function(a,b,c,d){b=b||80,c=c||"\n";for(var e=a.split("\n"),f=0;f<e.length;++f){for(var g=e[f],h="";g.length>b;){for(var i=0,j=g.slice(i).match(/\s+/);j&&i+j.index<=b;j=g.slice(i).match(/\s+/))i+=j.index+j[0].length;i=i||(d?b:j?j.index+j[0].length:g.length),h+=g.slice(0,i).replace(/\s+$/,""),i<g.length&&(h+=c),g=g.slice(i)}e[f]=h+g}return e.join("\n")}),String.prototype.fetch=function(a){var b=new jSmart(this);return b.fetch(a)},"object"==typeof module&&module&&"object"==typeof module.exports?module.exports=jSmart:("undefined"!=typeof global&&(global.jSmart=jSmart),"function"==typeof define&&define.amd&&define("jSmart",[],function(){return jSmart}))}();
\ No newline at end of file
index 4e6cc8f7bb56d45281f3427435e7f0dbd4e81f21..464c7e06e1af84e015fab5f3a9f527d547157892 100644 (file)
  * It is licensed under the GNU Affero General Public License <http://www.gnu.org/licenses/>
  *
  */
-$(document).ready(function(){
-       // Elements with the class "userinfo" will get a hover-card.
-       // Note that this elements does need a href attribute which links to
-       // a valid profile url
-       $("body").on("mouseover", ".userinfo, .wall-item-responses a, .wall-item-bottom .mention a", function(e) {
-                       var timeNow = new Date().getTime();
-                       removeAllhoverCards(e,timeNow);
-                       var hoverCardData = false;
-                       var hrefAttr = false;
-                       var targetElement = $(this);
-
-                       // get href-attribute
-                       if(targetElement.is('[href]')) {
-                               hrefAttr = targetElement.attr('href');
-                       } else {
-                               return true;
-                       }
-
-                       // no hover card if the element has the no-hover-card class
-                       if(targetElement.hasClass('no-hover-card')) {
-                               return true;
-                       }
-
-                       // no hovercard for anchor links
-                       if(hrefAttr.substring(0,1) == '#') {
-                               return true;
-                       }
+$(document).ready(function () {
+       let $body = $('body');
+       // Prevents normal click action on click hovercard elements
+       $body.on('click', '.userinfo.click-card', function (e) {
+               e.preventDefault();
+       });
+       // This event listener needs to be declared before the one that removes
+       // all cards so that we can stop the immediate propagation of the event
+       // Since the manual popover appears instantly and the hovercard removal is
+       // on a 100ms delay, leaving event propagation immediately hides any click hovercard
+       $body.on('mousedown', '.userinfo.click-card', function (e) {
+               e.stopImmediatePropagation();
+               let timeNow = new Date().getTime();
+
+               let contactUrl = false;
+               let targetElement = $(this);
+
+               // get href-attribute
+               if (targetElement.is('[href]')) {
+                       contactUrl = targetElement.attr('href');
+               } else {
+                       return true;
+               }
 
-                       targetElement.attr('data-awaiting-hover-card',timeNow);
+               // no hovercard for anchor links
+               if (contactUrl.substring(0, 1) === '#') {
+                       return true;
+               }
 
-                       // Take link href attribute as link to the profile
-                       var profileurl = hrefAttr;
-                       // the url to get the contact and template data
-                       var url = baseurl + "/hovercard";
+               openHovercard(targetElement, contactUrl, timeNow);
+       });
 
-                       // store the title in an other data attribute beause bootstrap
-                       // popover destroys the title.attribute. We can restore it later
-                       var title = targetElement.attr("title");
-                       targetElement.attr({"data-orig-title": title, title: ""});
+       // hover cards should be removed very easily, e.g. when any of these events happens
+       $body.on('mouseleave touchstart scroll mousedown submit keydown', function (e) {
+               // remove hover card only for desktiop user, since on mobile we open the hovercards
+               // by click event insteadof hover
+               removeAllHovercards(e, new Date().getTime());
+       });
 
-                       // if the device is a mobile open the hover card by click and not by hover
-                       if(typeof is_mobile != "undefined") {
-                                       targetElement[0].removeAttribute("href");
-                                       var hctrigger = 'click';
-                               } else {
-                                       var hctrigger = 'manual';
-                       };
+       $body.on('mouseover', '.userinfo.hover-card, .wall-item-responses a, .wall-item-bottom .mention a', function (e) {
+               let timeNow = new Date().getTime();
+               removeAllHovercards(e, timeNow);
+               let contactUrl = false;
+               let targetElement = $(this);
+
+               // get href-attribute
+               if (targetElement.is('[href]')) {
+                       contactUrl = targetElement.attr('href');
+               } else {
+                       return true;
+               }
 
-                       // Timeout until the hover-card does appear
-                       setTimeout(function(){
-                               if(targetElement.is(":hover") && parseInt(targetElement.attr('data-awaiting-hover-card'),10) == timeNow) {
-                                       if($('.hovercard').length == 0) {       // no card if there already is one open
-                                               // get an additional data atribute if the card is active
-                                               targetElement.attr('data-hover-card-active',timeNow);
-                                               // get the whole html content of the hover card and
-                                               // push it to the bootstrap popover
-                                               getHoverCardContent(profileurl, url, function(data){
-                                                       if(data) {
-                                                               targetElement.popover({
-                                                                       html: true,
-                                                                       placement: function () {
-                                                                               // Calculate the placement of the the hovercard (if top or bottom)
-                                                                               // The placement depence on the distance between window top and the element
-                                                                               // which triggers the hover-card
-                                                                               var get_position = $(targetElement).offset().top - $(window).scrollTop();
-                                                                               if (get_position < 270 ){
-                                                                                       return "bottom";
-                                                                               }
-                                                                               return "top";
-                                                                       },
-                                                                       trigger: hctrigger,
-                                                                       template: '<div class="popover hovercard" data-card-created="' + timeNow + '"><div class="arrow"></div><div class="popover-content hovercard-content"></div></div>',
-                                                                       content: data,
-                                                                       container: "body",
-                                                                       sanitizeFn: function (content) {
-                                                                               return DOMPurify.sanitize(content)
-                                                                       },
-                                                               }).popover('show');
-                                                       }
-                                               });
-                                       }
-                               }
-                       }, 500);
-       }).on("mouseleave", ".userinfo, .wall-item-responses a, .wall-item-bottom .mention a", function(e) { // action when mouse leaves the hover-card
-               var timeNow = new Date().getTime();
-               // copy the original title to the title atribute
-               var title = $(this).attr("data-orig-title");
-               $(this).attr({"data-orig-title": "", title: title});
-               removeAllhoverCards(e,timeNow);
-       });
+               // no hover card if the element has the no-hover-card class
+               if (targetElement.hasClass('no-hover-card')) {
+                       return true;
+               }
 
+               // no hovercard for anchor links
+               if (contactUrl.substring(0, 1) === '#') {
+                       return true;
+               }
 
+               targetElement.attr('data-awaiting-hover-card', timeNow);
 
-       // hover cards should be removed very easily, e.g. when any of these events happen
-       $('body').on("mouseleave touchstart scroll click dblclick mousedown mouseup submit keydown keypress keyup", function(e){
-               // remove hover card only for desktiop user, since on mobile we openen the hovercards
-               // by click event insteadof hover
-               if(typeof is_mobile == "undefined") {
-                       var timeNow = new Date().getTime();
-                       removeAllhoverCards(e,timeNow);
-               };
+               // Delay until the hover-card does appear
+               setTimeout(function () {
+                       if (
+                               targetElement.is(':hover')
+                               && parseInt(targetElement.attr('data-awaiting-hover-card'), 10) === timeNow
+                               && $('.hovercard').length === 0
+                       ) {
+                               openHovercard(targetElement, contactUrl, timeNow);
+                       }
+               }, 500);
+       }).on('mouseleave', '.userinfo.hover-card, .wall-item-responses a, .wall-item-bottom .mention a', function (e) { // action when mouse leaves the hover-card
+               removeAllHovercards(e, new Date().getTime());
        });
 
        // if we're hovering a hover card, give it a class, so we don't remove it
-       $('body').on('mouseover','.hovercard', function(e) {
+       $body.on('mouseover', '.hovercard', function (e) {
                $(this).addClass('dont-remove-card');
        });
-       $('body').on('mouseleave','.hovercard', function(e) {
+
+       $body.on('mouseleave', '.hovercard', function (e) {
                $(this).removeClass('dont-remove-card');
-               $(this).popover("hide");
+               $(this).popover('hide');
        });
-
 }); // End of $(document).ready
 
 // removes all hover cards
-function removeAllhoverCards(event,priorTo) {
+function removeAllHovercards(event, priorTo) {
        // don't remove hovercards until after 100ms, so user have time to move the cursor to it (which gives it the dont-remove-card class)
-       setTimeout(function(){
-               $.each($('.hovercard'),function(){
-                       var title = $(this).attr("data-orig-title");
+       setTimeout(function () {
+               $.each($('.hovercard'), function () {
+                       let title = $(this).attr('data-orig-title');
                        // don't remove card if it was created after removeAllhoverCards() was called
-                       if($(this).data('card-created') < priorTo) {
+                       if ($(this).data('card-created') < priorTo) {
                                // don't remove it if we're hovering it right now!
-                               if(!$(this).hasClass('dont-remove-card')) {
-                                       $('[data-hover-card-active="' + $(this).data('card-created') + '"]').removeAttr('data-hover-card-active');
-                                       $(this).popover("hide");
-                               }
-                       }
-               });
-       },100);
-}
+                               if (!$(this).hasClass('dont-remove-card')) {
+                                       let $handle = $('[data-hover-card-active="' + $(this).data('card-created') + '"]');
+                                       $handle.removeAttr('data-hover-card-active');
 
-// Ajax request to get json contact data
-function getContactData(purl, url, actionOnSuccess) {
-       var postdata = {
-               mode            : 'none',
-               profileurl      : purl,
-               datatype        : 'json',
-       };
+                                       // Restoring the popover handle title
+                                       let title = $handle.attr('data-orig-title');
+                                       $handle.attr({'data-orig-title': '', title: title});
 
-       // Normalize and clean the profile so we can use a standardized url
-       // as key for the cache
-       var nurl = cleanContactUrl(purl).normalizeLink();
-
-       // If the contact is allready in the cache use the cached result instead
-       // of doing a new ajax request
-       if(nurl in getContactData.cache) {
-               setTimeout(function() { actionOnSuccess(getContactData.cache[nurl]); } , 1);
-               return;
-       }
-
-       $.ajax({
-               url: url,
-               data: postdata,
-               dataType: "json",
-               success: function(data, textStatus, request){
-                       // Check if the nurl (normalized profile url) is present and store it to the cache
-                       // The nurl will be the identifier in the object
-                       if(data.nurl.length > 0) {
-                               // Test if the contact is allready connected with the user (if url containing
-                               // the expression ("redir/") We will store different cache keys
-                               if((data.url.search("redir/")) >= 0 ) {
-                                       var key = data.url;
-                               } else {
-                                       var key = data.nurl;
+                                       $(this).popover('hide');
                                }
-                               getContactData.cache[key] = data;
                        }
-                       actionOnSuccess(data, url, request);
-               },
-               error: function(data) {
-                       actionOnSuccess(false, data, url);
-               }
-       });
+               });
+       }, 100);
 }
-getContactData.cache = {};
-
-// Get hover-card template data and the contact-data and transform it with
-// the help of jSmart. At the end we have full html content of the hovercard
-function getHoverCardContent(purl, url, callback) {
-       // fetch the raw content of the template
-       getHoverCardTemplate(url, function(stpl) {
-               var template = unescape(stpl);
-
-               // get the contact data
-               getContactData (purl, url, function(data) {
-                       if(typeof template != 'undefined') {
-                               // get the hover-card variables
-                               var variables = getHoverCardVariables(data);
-                               var tpl;
-
-                               // use friendicas template delimiters instead of
-                               // the original one
-                               jSmart.prototype.left_delimiter = '{{';
-                               jSmart.prototype.right_delimiter = '}}';
 
-                               // create a new jSmart instant with the raw content
-                               // of the template
-                               var tpl = new jSmart (template);
-                               // insert the variables content into the template content
-                               var HoverCardContent = tpl.fetch(variables);
-
-                               callback(HoverCardContent);
-                       }
-               });
+function openHovercard(targetElement, contactUrl, timeNow) {
+       // store the title in a data attribute because Bootstrap
+       // popover destroys the title attribute.
+       let title = targetElement.attr('title');
+       targetElement.attr({'data-orig-title': title, title: ''});
+
+       // get an additional data atribute if the card is active
+       targetElement.attr('data-hover-card-active', timeNow);
+       // get the whole html content of the hover card and
+       // push it to the bootstrap popover
+       getHoverCardContent(contactUrl, function (data) {
+               if (data) {
+                       targetElement.popover({
+                               html: true,
+                               placement: function () {
+                                       // Calculate the placement of the the hovercard (if top or bottom)
+                                       // The placement depence on the distance between window top and the element
+                                       // which triggers the hover-card
+                                       let get_position = $(targetElement).offset().top - $(window).scrollTop();
+                                       if (get_position < 270) {
+                                               return 'bottom';
+                                       }
+                                       return 'top';
+                               },
+                               trigger: 'manual',
+                               template: '<div class="popover hovercard" data-card-created="' + timeNow + '"><div class="arrow"></div><div class="popover-content hovercard-content"></div></div>',
+                               content: data,
+                               container: 'body',
+                               sanitizeFn: function (content) {
+                                       return DOMPurify.sanitize(content)
+                               },
+                       }).popover('show');
+               }
        });
-
-// This is interisting. this pice of code ajax request are done asynchron.
-// To make it work getHOverCardTemplate() and getHOverCardData have to return it's
-// data (no succes handler for each of this). I leave it here, because it could be useful.
-// https://lostechies.com/joshuaflanagan/2011/10/20/coordinating-multiple-ajax-requests-with-jquery-when/
-//     $.when(
-//             getHoverCardTemplate(url),
-//             getContactData (term, url )
-//
-//     ).done(function(template, profile){
-//             if(typeof template != 'undefined') {
-//                     var variables = getHoverCardVariables(profile);
-//
-//                     jSmart.prototype.left_delimiter = '{{';
-//                     jSmart.prototype.right_delimiter = '}}';
-//                     var tpl = new jSmart (template);
-//                     var html = tpl.fetch(variables);
-//
-//                     return html;
-//             }
-//     });
 }
 
+getHoverCardContent.cache = {};
 
-// Ajax request to get the raw template content
-function getHoverCardTemplate (url, callback) {
-       var postdata = {
-               mode: 'none',
-               datatype: 'tpl'
+function getHoverCardContent(contact_url, callback) {
+       let postdata = {
+               url: contact_url,
        };
 
-       // Look if we have the template already in the cace, so we don't have
-       // request it again
-       if('hovercard' in getHoverCardTemplate.cache) {
-               setTimeout(function() { callback(getHoverCardTemplate.cache['hovercard']); } , 1);
+       // Normalize and clean the profile so we can use a standardized url
+       // as key for the cache
+       let nurl = cleanContactUrl(contact_url).normalizeLink();
+
+       // If the contact is already in the cache use the cached result instead
+       // of doing a new ajax request
+       if (nurl in getHoverCardContent.cache) {
+               callback(getHoverCardContent.cache[nurl]);
                return;
        }
 
        $.ajax({
-               url: url,
+               url: baseurl + '/contact/hovercard',
                data: postdata,
-               success: function(data, textStatus) {
-                       // write the data in the cache
-                       getHoverCardTemplate.cache['hovercard'] = data;
+               success: function (data, textStatus, request) {
+                       getHoverCardContent.cache[nurl] = data;
                        callback(data);
-               }
-       }).fail(function () {callback([]); });
-}
-getHoverCardTemplate.cache = {};
-
-// The Variables used for the template
-function getHoverCardVariables(object) {
-       var profile = {
-                       name:           object.name,
-                       nick:           object.nick,
-                       addr:           object.addr,
-                       thumb:          object.thumb,
-                       url:            object.url,
-                       nurl:           object.nurl,
-                       location:       object.location,
-                       gender:         object.gender,
-                       about:          object.about,
-                       network:        object.network,
-                       tags:           object.tags,
-                       bd:             object.bd,
-                       account_type:   object.account_type,
-                       actions:        object.actions
-       };
-
-       var variables = { profile:  profile};
-
-       return variables;
+               },
+       });
 }
index 9d99d7984e12e4742fcd460372a642cabba7afbc..a9878efccaaf735d6929c2e74ca49856818962c4 100644 (file)
@@ -106,3 +106,25 @@ aside .widget, .form-control, .panel, .nav-container, .wall-item-content, .e-con
     height: 0px;
 }
 
+/* Contact-page */
+#connect-desc {
+    color: grey;
+}
+
+.search-input.form-control.form-search {
+    background-color: #ebebeb;
+    border-color:lightgrey;
+}
+
+.search-input.form-control.form-search:focus {
+    background-color: white;
+    border-color:grey;
+}
+
+/* Addon-Showmore*/
+.showmore-wrap {
+    background-color:lightgrey;
+    text-decoration: underline;
+    text-decoration-color: black;
+    text-decoration-style: wavy;
+}
index 9264e9d2e3e92861606755ccb185b826475ff3d9..2f2af2732eea3984b7357fcc0b2170bc90468a77 100644 (file)
@@ -27,7 +27,7 @@
                                                {{/if}}
                                        </div>
                                        <div class="event-card-profile-name profile-entry-name">
-                                               <a href="{{$author_link}}" class="userinfo">{{$author_name}}</a>
+                                               <a href="{{$author_link}}" class="userinfo hover-card">{{$author_name}}</a>
                                        </div>
                                        {{if $location.map}}
                                        <div id="event-location-map-{{$id}}" class="event-location-map">{{$location.map nofilter}}</div>
index 287e696cb2a3fc5144c7624a99b57f93970fcfa6..f944c80ae9ad0aaf234371ae2c7d706ad52efe25 100644 (file)
@@ -75,7 +75,6 @@
 <script type="text/javascript" src="view/theme/frio/frameworks/justifiedGallery/jquery.justifiedGallery.min.js"></script>
 <script type="text/javascript" src="view/theme/frio/frameworks/bootstrap-colorpicker/js/bootstrap-colorpicker.min.js"></script>
 <script type="text/javascript" src="view/theme/frio/frameworks/flexMenu/flexmenu.custom.js"></script>
-<script type="text/javascript" src="view/theme/frio/frameworks/jsmart/jsmart.custom.js"></script>
 <script type="text/javascript" src="view/theme/frio/frameworks/jquery-scrollspy/jquery-scrollspy.js"></script>
 <script type="text/javascript" src="view/theme/frio/frameworks/autosize/autosize.min.js"></script>
 <script type="text/javascript" src="view/theme/frio/frameworks/sticky-kit/jquery.sticky-kit.min.js"></script>
index 4b515efcd1872de00b4305cb8ecd99905c59799e..a2b5106a61c120039135219e0d032183ef957919 100644 (file)
 <ul id="nav-notifications-template" class="media-list" style="display:none;" rel="template">
        <li class="{4} notif-entry">
                <div class="notif-entry-wrapper media">
-                       <div class="notif-photo-wrapper media-object pull-left"><a href="{6}" class="userinfo"><img data-src="{1}"></a></div>
+                       <div class="notif-photo-wrapper media-object pull-left"><a href="{6}" class="userinfo click-card"><img data-src="{1}"></a></div>
                        <a href="{0}" class="notif-desc-wrapper media-body">
                                {2}
                                <div><time class="notif-when time" data-toggle="tooltip" title="{5}">{3}</time></div>
index a42647cff8915564537244b2c3bc104c20c61c03..58f3b0da9f646b1ba6a2a85690c306e6525f8e6f 100644 (file)
@@ -1,7 +1,7 @@
 
 <div class="notif-item {{if !$item_seen}}unseen{{/if}} {{$item_label}} media">
        <div class="notif-photo-wrapper media-object pull-left">
-               <a class="userinfo" href="{{$item_url}}"><img src="{{$item_image}}" class="notif-image"></a>
+               <a class="userinfo click-card" href="{{$item_url}}"><img src="{{$item_image}}" class="notif-image"></a>
        </div>
        <div class="notif-desc-wrapper media-body">
                <a href="{{$item_link}}">
index 935e6288b3ef8bd344fe7a0739b049138a08bf1e..54eb3c1d43e97084081876908667e593b340d6b5 100644 (file)
@@ -21,7 +21,7 @@
 
        {{* avatar picture *}}
        <div class="contact-photo-wrapper mframe p-author h-card pull-left">
-               <a class="userinfo u-url" id="wall-item-photo-menu-{{$id}}" href="{{$profile_url}}">
+               <a class="userinfo click-card u-url" id="wall-item-photo-menu-{{$id}}" href="{{$profile_url}}">
                        <div class="contact-photo-image-wrapper">
                                <img src="{{$thumb}}" class="contact-photo-xs media-object p-name u-photo" id="wall-item-photo-{{$id}}" alt="{{$name}}" />
                        </div>
@@ -33,7 +33,7 @@
                {{* the header with the comment author name *}}
                <div role="heading " class="contact-info-comment">
                        <h5 class="media-heading">
-                               <a href="{{$profile_url}}" title="View {{$name}}'s profile" class="wall-item-name-link userinfo"><span class="btn-link">{{$name}}</span></a>
+                               <a href="{{$profile_url}}" title="View {{$name}}'s profile" class="wall-item-name-link userinfo hover-card"><span class="btn-link">{{$name}}</span></a>
                        </h5>
                </div>
 
index 4819c5ee817964a2801c20fb0db73a69777ed90b..81e519ef7505eaa6c0bc3f3f83d3a140fa577729 100644 (file)
@@ -56,6 +56,7 @@
 
                {{if $permonly}}
                {{include file="field_textarea.tpl" field=$permonlybox}}
+               <input type="input" id="registertarpit" style="display: none;" placeholder="Don't enter anything here"/>
                {{/if}}
 
                {{$publish nofilter}}
index 7f3c0936d1e2fc9baa786ef8b967bce1ce364b1c..6c2b8151618b5d3c5feaf7f9718b9771fc13784f 100644 (file)
                        {{* The avatar picture and the photo-menu *}}
                        <div class="dropdown pull-left"><!-- Dropdown -->
                                <div class="hidden-sm hidden-xs contact-photo-wrapper mframe{{if $item.owner_url}} wwfrom{{/if}}">
-                                       <a href="{{$item.profile_url}}" class="userinfo u-url" id="wall-item-photo-menu-{{$item.id}}">
+                                       <a href="{{$item.profile_url}}" class="userinfo click-card u-url" id="wall-item-photo-menu-{{$item.id}}">
                                                <div class="contact-photo-image-wrapper">
                                                        <img src="{{$item.thumb}}" class="contact-photo media-object {{$item.sparkle}}" id="wall-item-photo-{{$item.id}}" alt="{{$item.name}}" />
                                                </div>
                                        </a>
                                </div>
                                <div class="hidden-lg hidden-md contact-photo-wrapper mframe{{if $item.owner_url}} wwfrom{{/if}}">
-                                       <a href="{{$item.profile_url}}" class="userinfo u-url" id="wall-item-photo-menu-xs-{{$item.id}}">
+                                       <a href="{{$item.profile_url}}" class="userinfo click-card u-url" id="wall-item-photo-menu-xs-{{$item.id}}">
                                                <div class="contact-photo-image-wrapper">
                                                        <img src="{{$item.thumb}}" class="contact-photo-xs media-object {{$item.sparkle}}" id="wall-item-photo-xs-{{$item.id}}" alt="{{$item.name}}" />
                                                </div>
 
 
                        {{* contact info header*}}
-                       <div role="heading " class="contact-info hidden-sm hidden-xs media-body"><!-- <= For computer -->
-                               <h4 class="media-heading"><a href="{{$item.profile_url}}" title="{{$item.linktitle}}" class="wall-item-name-link userinfo"><span class="wall-item-name {{$item.sparkle}}">{{$item.name}}</span></a>
-                                       {{if $item.owner_url}}{{$item.via}} <a href="{{$item.owner_url}}" target="redir" title="{{$item.olinktitle}}" class="wall-item-name-link userinfo"><span class="wall-item-name {{$item.osparkle}}" id="wall-item-ownername-{{$item.id}}">{{$item.owner_name}}</span></a>{{/if}}
-                                       {{if $item.lock}}<span class="navicon lock fakelink" onClick="lockview(event, {{$item.id}});" title="{{$item.lock}}">&nbsp;<small><i class="fa fa-lock" aria-hidden="true"></i></small></span>{{/if}}
+                       <div role="heading" class="contact-info hidden-sm hidden-xs media-body"><!-- <= For computer -->
+                               <h4 class="media-heading">
+                                       <a href="{{$item.profile_url}}" title="{{$item.linktitle}}" class="wall-item-name-link userinfo hover-card">
+                                               <span class="wall-item-name {{$item.sparkle}}">{{$item.name}}</span>
+                                       </a>
+                               {{if $item.owner_url}}
+                                       {{$item.via}}
+                                       <a href="{{$item.owner_url}}" target="redir" title="{{$item.olinktitle}}" class="wall-item-name-link userinfo hover-card">
+                                               <span class="wall-item-name {{$item.osparkle}}" id="wall-item-ownername-{{$item.id}}">{{$item.owner_name}}</span>
+                                       </a>
+                               {{/if}}
+                               {{if $item.lock}}
+                                       <span class="navicon lock fakelink" onClick="lockview(event, {{$item.id}});" title="{{$item.lock}}">
+                                               &nbsp;<small><i class="fa fa-lock" aria-hidden="true"></i></small>
+                                       </span>
+                               {{/if}}
 
                                        <div class="additional-info text-muted">
                                                <div id="wall-item-ago-{{$item.id}}" class="wall-item-ago">
                        {{* contact info header for smartphones *}}
                        <div role="heading " class="contact-info-xs hidden-lg hidden-md">
                                <h5 class="media-heading">
-                                       <a href="{{$item.profile_url}}" title="{{$item.linktitle}}" class="wall-item-name-link userinfo"><span>{{$item.name}}</span></a>
+                                       <a href="{{$item.profile_url}}" title="{{$item.linktitle}}" class="wall-item-name-link userinfo hover-card"><span>{{$item.name}}</span></a>
                                        <p class="text-muted"><small>
                                                <span class="wall-item-ago">{{$item.ago}}</span> {{if $item.location}}&nbsp;&mdash;&nbsp;({{$item.location nofilter}}){{/if}}</small>
                                        </p>
index 700c2c06c4c24d4d6ffe458059ee8d31c197fa92..4ed94b182736603c035b750546abf440867f2952 100644 (file)
                                </div>
                        </div>
 
+                       {{* Import contacts CSV *}}
+                       <div class="panel">
+                               <div class="section-subtitle-wrapper" role="tab" id="importcontact-settings">
+                                       <h4>
+                                               <a class="accordion-toggle collapsed" data-toggle="collapse" data-parent="#settings" href="#importcontact-settings-collapse" aria-expanded="false" aria-controls="importcontact-settings-collapse">
+                                                       {{$importcontact}}
+                                               </a>
+                                       </h4>
+                               </div>
+                               <div id="importcontact-settings-collapse" class="panel-collapse collapse" role="tabpanel" aria-labelledby="importcontact-settings">
+                                       <div class="section-content-tools-wrapper">
+
+                                               <div id="importcontact-relocate-desc">{{$importcontact_text}}</div>
+                                               <input type="hidden" name="MAX_FILE_SIZE" value="{{$importcontact_maxsize}}" />
+                                               <input type="file" name="importcontact-filename" />
+
+                                               <br/>
+                                               <div class="form-group pull-right settings-submit-wrapper" >
+                                                       <button type="submit" name="importcontact-submit" class="btn btn-primary" value="{{$importcontact_button}}">{{$importcontact_button}}</button>
+                                               </div>
+                                               <div class="clear"></div>
+                                       </div>
+                               </div>
+                       </div>
+
                        {{* The relocate setting section *}}
                        <div class="panel">
                                <div class="section-subtitle-wrapper" role="tab" id="relocate-settings">
diff --git a/view/theme/frio/templates/settings/userexport.tpl b/view/theme/frio/templates/settings/userexport.tpl
new file mode 100644 (file)
index 0000000..247ed86
--- /dev/null
@@ -0,0 +1,12 @@
+
+<div class="generic-page-wrapper">
+       {{* include the title template for the settings title *}}
+       {{include file="section_title.tpl" title=$title}}
+
+       {{foreach $options as $o}}
+       <dl>
+               <dt><a href="{{$o.0}}">{{$o.1}}</a></dt>
+               <dd>{{$o.2}}</dd>
+       </dl>
+       {{/foreach}}
+</div>
index 5a10a025521874e5bc66e75e3b3fbac6d3a91fc4..94955581d1dc2497f46b6fefe58ad8b7acf5ac3c 100644 (file)
@@ -118,6 +118,13 @@ as the value of $top_child_total (this is done at the end of this file)
                                        </li>
                                        {{/if}}
 
+                                       {{if $item.pin}}
+                                       <li role="menuitem">
+                                               <button type="button" id="pin-{{$item.id}}" onclick="dopin({{$item.id}});" class="btn-link {{$item.pin.classdo}}" title="{{$item.pin.do}}"><i class="fa fa-circle-o" aria-hidden="true"></i>&nbsp;{{$item.pin.do}}</button>
+                                               <button type="button" id="unpin-{{$item.id}}" onclick="dopin({{$item.id}});" class="btn-link {{$item.pin.classundo}}" title="{{$item.pin.undo}}"><i class="fa fa-dot-circle-o" aria-hidden="true"></i>&nbsp;{{$item.pin.undo}}</button>
+                                       </li>
+                                       {{/if}}
+
                                        {{if $item.star}}
                                        <li role="menuitem">
                                                <button type="button" id="star-{{$item.id}}" onclick="dostar({{$item.id}});" class="btn-link {{$item.star.classdo}}" title="{{$item.star.do}}"><i class="fa fa-star-o" aria-hidden="true"></i>&nbsp;{{$item.star.do}}</button>
@@ -159,14 +166,14 @@ as the value of $top_child_total (this is done at the end of this file)
                <div class="dropdown pull-left"><!-- Dropdown -->
                        {{if $item.thread_level==1}}
                        <div class="hidden-sm hidden-xs contact-photo-wrapper mframe{{if $item.owner_url}} wwfrom{{/if}} p-author h-card">
-                               <a class="userinfo  u-url" id="wall-item-photo-menu-{{$item.id}}" href="{{$item.profile_url}}">
+                               <a class="userinfo click-card u-url" id="wall-item-photo-menu-{{$item.id}}" href="{{$item.profile_url}}">
                                        <div class="contact-photo-image-wrapper">
                                                <img src="{{$item.thumb}}" class="contact-photo media-object {{$item.sparkle}} p-name u-photo" id="wall-item-photo-{{$item.id}}" alt="{{$item.name}}" />
                                        </div>
                                </a>
                        </div>
                        <div class="hidden-lg hidden-md contact-photo-wrapper mframe{{if $item.owner_url}} wwfrom{{/if}}">
-                               <a class="userinfo u-url" id="wall-item-photo-menu-xs-{{$item.id}}" href="{{$item.profile_url}}">
+                               <a class="userinfo click-card u-url" id="wall-item-photo-menu-xs-{{$item.id}}" href="{{$item.profile_url}}">
                                        <div class="contact-photo-image-wrapper">
                                                <img src="{{$item.thumb}}" class="contact-photo-xs media-object {{$item.sparkle}}" id="wall-item-photo-xs-{{$item.id}}" alt="{{$item.name}}" />
                                        </div>
@@ -187,7 +194,7 @@ as the value of $top_child_total (this is done at the end of this file)
                        {{* The avatar picture for comments *}}
                        {{if $item.thread_level!=1}}
                        <div class="contact-photo-wrapper mframe{{if $item.owner_url}} wwfrom{{/if}} p-author h-card">
-                               <a class="userinfo u-url" id="wall-item-photo-menu-{{$item.id}}" href="{{$item.profile_url}}">
+                               <a class="userinfo click-card u-url" id="wall-item-photo-menu-{{$item.id}}" href="{{$item.profile_url}}">
                                        <div class="contact-photo-image-wrapper">
                                                <img src="{{$item.thumb}}" class="contact-photo-xs media-object {{$item.sparkle}} p-name u-photo" id="wall-item-photo-comment-{{$item.id}}" alt="{{$item.name}}" />
                                        </div>
@@ -201,9 +208,21 @@ as the value of $top_child_total (this is done at the end of this file)
                {{* contact info header*}}
                {{if $item.thread_level==1}}
                <div role="heading " aria-level="{{$item.thread_level}}" class="contact-info hidden-sm hidden-xs media-body"><!-- <= For computer -->
-                       <h4 class="media-heading"><a href="{{$item.profile_url}}" title="{{$item.linktitle}}" class="wall-item-name-link userinfo"><span class="wall-item-name {{$item.sparkle}}">{{$item.name}}</span></a>
-                       {{if $item.owner_url}}{{$item.via}} <a href="{{$item.owner_url}}" target="redir" title="{{$item.olinktitle}}" class="wall-item-name-link userinfo"><span class="wall-item-name {{$item.osparkle}}" id="wall-item-ownername-{{$item.id}}">{{$item.owner_name}}</span></a>{{/if}}
-                       {{if $item.lock}}<span class="navicon lock fakelink" onClick="lockview(event,{{$item.id}});" title="{{$item.lock}}" data-toggle="tooltip">&nbsp;<small><i class="fa fa-lock" aria-hidden="true"></i></small></span>{{/if}}
+                       <h4 class="media-heading">
+                               <a href="{{$item.profile_url}}" title="{{$item.linktitle}}" class="wall-item-name-link userinfo hover-card">
+                                       <span class="wall-item-name {{$item.sparkle}}">{{$item.name}}</span>
+                               </a>
+                       {{if $item.owner_url}}
+                               {{$item.via}}
+                               <a href="{{$item.owner_url}}" target="redir" title="{{$item.olinktitle}}" class="wall-item-name-link userinfo hover-card">
+                                       <span class="wall-item-name {{$item.osparkle}}" id="wall-item-ownername-{{$item.id}}">{{$item.owner_name}}</span>
+                               </a>
+                       {{/if}}
+                       {{if $item.lock}}
+                               <span class="navicon lock fakelink" onClick="lockview(event,{{$item.id}});" title="{{$item.lock}}" data-toggle="tooltip">
+                                       &nbsp;<small><i class="fa fa-lock" aria-hidden="true"></i></small>
+                               </span>
+                       {{/if}}
                        </h4>
 
                        <div class="additional-info text-muted">
@@ -217,6 +236,7 @@ as the value of $top_child_total (this is done at the end of this file)
                                                {{if $item.owner_self}}
                                                        {{include file="sub/delivery_count.tpl" delivery=$item.delivery}}
                                                {{/if}}
+                                               <span class="pinned">{{$item.pinned}}</span>
                                        </small>
                                </div>
 
@@ -232,7 +252,7 @@ as the value of $top_child_total (this is done at the end of this file)
                {{* contact info header for smartphones *}}
                <div role="heading " aria-level="{{$item.thread_level}}" class="contact-info-xs hidden-lg hidden-md"><!-- <= For smartphone (responsive) -->
                        <h5 class="media-heading">
-                               <a href="{{$item.profile_url}}" title="{{$item.linktitle}}" class="wall-item-name-link userinfo"><span>{{$item.name}}</span></a>
+                               <a href="{{$item.profile_url}}" title="{{$item.linktitle}}" class="wall-item-name-link userinfo hover-card"><span>{{$item.name}}</span></a>
                                <p class="text-muted">
                                        <small>
                                                <a class="time" href="{{$item.plink.orig}}"><span class="wall-item-ago">{{$item.ago}}</span></a>
@@ -251,7 +271,7 @@ as the value of $top_child_total (this is done at the end of this file)
                <div class="media-body">{{*this is the media body for comments - this div must be closed at the end of the file *}}
                <div role="heading " aria-level="{{$item.thread_level}}" class="contact-info-comment">
                        <h5 class="media-heading">
-                               <a href="{{$item.profile_url}}" title="{{$item.linktitle}}" class="wall-item-name-link userinfo"><span class="fakelink">{{$item.name}}</span></a>
+                               <a href="{{$item.profile_url}}" title="{{$item.linktitle}}" class="wall-item-name-link userinfo hover-card"><span class="fakelink">{{$item.name}}</span></a>
                                <span class="text-muted">
                                        <small>
                                                <a class="time" href="{{$item.plink.orig}}" title="{{$item.localtime}}" data-toggle="tooltip">{{$item.ago}}</a>
@@ -301,7 +321,7 @@ as the value of $top_child_total (this is done at the end of this file)
                        {{/foreach}}
 
                        {{foreach $item.categories as $cat}}
-                               <span class="category label btn-success sm p-category">{{$cat.name}}{{if $cat.removeurl}} (<a href="{{$cat.removeurl}}" title="{{$remove}}">x</a>) {{/if}} </span>
+                               <span class="category label btn-success sm p-category"><a href="{{$cat.url}}">{{$cat.name}}</a>{{if $cat.removeurl}} (<a href="{{$cat.removeurl}}" title="{{$remove}}">x</a>) {{/if}} </span>
                        {{/foreach}}
                        </div>
                        {{if $item.edited}}<div class="itemedited text-muted">{{$item.edited['label']}} (<span title="{{$item.edited['date']}}">{{$item.edited['relative']}}</span>)</div>{{/if}}
index fadd0a6dfbd923e69fac036b79249a8d5cd2058a..b2a902fff3010e23ca1fd52f4e7be768d250d6d9 100644 (file)
@@ -3,7 +3,6 @@
        <h3>{{$connect}}</h3>
 
        <form action="follow" method="get">
-               <label for="side-follow-url" id="connect-desc">{{$desc nofilter}}</label>
                {{* The input field - For visual consistence we are using a search input field*}}
                <div class="form-group form-group-search">
                        <input id="side-follow-url" class="search-input form-control form-search" type="text" name="url" value="{{$value}}" placeholder="{{$hint}}" data-toggle="tooltip" title="{{$hint}}" />
index a80aabf4b47202b8c2d1e1d76138f11f829d317d..77d63f6e5d94c9f8bb9424b58afa68d95edd603a 100644 (file)
@@ -72,7 +72,7 @@
                                <span class="folder p-category">{{$cat.name}}</a>{{if $cat.removeurl}} (<a href="{{$cat.removeurl}}" title="{{$remove}}">x</a>) {{/if}} </span>
                        {{/foreach}}
                        {{foreach $item.categories as $cat}}
-                               <span class="category p-category">{{$cat.name}}</a>{{if $cat.removeurl}} (<a href="{{$cat.removeurl}}" title="{{$remove}}">x</a>) {{/if}} </span>
+                               <span class="category p-category"><a href="{{$cat.url}}">{{$cat.name}}</a>{{if $cat.removeurl}} (<a href="{{$cat.removeurl}}" title="{{$remove}}">x</a>) {{/if}} </span>
                        {{/foreach}}
                {{/if}}
                </div>
                                 class="wall-item-name-link"><span
                                 class="wall-item-name{{$item.sparkle}}">{{$item.name}}</span></a>
                                 <span class="wall-item-ago" title="{{$item.localtime}}"><time class="dt-published" datetime="{{$item.localtime}}">{{$item.ago}}</time></span>
+                               <span class="pinned">{{$item.pinned}}</span>
                                 {{if $item.owner_url}}<br/>{{$item.to}} <a href="{{$item.owner_url}}" target="redir" title="{{$item.olinktitle}}" class="wall-item-name-link"><span class="wall-item-name{{$item.osparkle}}" id="wall-item-ownername-{{$item.id}}">{{$item.owner_name}}</span></a> {{$item.vwall}}
                                 {{/if}}
                        </div>
 
                        <div class="wall-item-actions-social">
+                       {{if $item.pin}}
+                               <a href="#" id="pin-{{$item.id}}" onclick="dopin({{$item.id}}); return false;"  class="{{$item.pin.classdo}}"  title="{{$item.pin.do}}">{{$item.pin.do}}</a>
+                               <a href="#" id="unpin-{{$item.id}}" onclick="dopin({{$item.id}}); return false;"  class="{{$item.pin.classundo}}"  title="{{$item.pin.undo}}">{{$item.pin.undo}}</a>
+                       {{/if}}
                        {{if $item.star}}
                                <a href="#" id="star-{{$item.id}}" onclick="dostar({{$item.id}}); return false;"  class="{{$item.star.classdo}}"  title="{{$item.star.do}}">{{$item.star.do}}</a>
                                <a href="#" id="unstar-{{$item.id}}" onclick="dostar({{$item.id}}); return false;"  class="{{$item.star.classundo}}"  title="{{$item.star.undo}}">{{$item.star.undo}}</a>
index edbd705747fe79757d05ae5c035e8acb7c38ba2f..ea84f0166886d849f398b527d0994140872483aa 100644 (file)
@@ -1615,6 +1615,7 @@ ul .sidebar-group-li .icon {
        margin-right: 20px;
 }
 
+.pin-item,
 .star-item,
 .tag-item {
        float: left;
@@ -3990,6 +3991,15 @@ margin-left: 0px;
        height: 20px;
        background-image: url("images/icons.png");
 }
+.pinned {
+       background-image: url("images/star.png");
+       repeat: no-repeat;
+}
+.unpinned {
+       background-image: url("images/premium.png");
+       repeat: no-repeat;
+}
+
 .starred {
        background-image: url("images/star.png");
        repeat: no-repeat;
index 08ff557670e9a12edbba650b6f6e3f7751d468e3..b372fbefbc0667113b7e65e65c4868011f94c707 100644 (file)
@@ -54,7 +54,7 @@
                        <span class="wall-item-name{{$item.sparkle}}" id="wall-item-name-{{$item.id}}" >{{$item.name}}</span>
                        </a>
                        <div class="wall-item-ago">&bull;</div>
-                       <div class="wall-item-ago" id="wall-item-ago-{{$item.id}}" title="{{$item.localtime}}"><time class="dt-published" datetime="{{$item.localtime}}">{{$item.ago}}</time></div>
+                       <div class="wall-item-ago" id="wall-item-ago-{{$item.id}}" title="{{$item.localtime}}"><time class="dt-published" datetime="{{$item.localtime}}">{{$item.ago}}</time><span class="pinned">{{$item.pinned}}</span></div>
                </div>
 
                <div>
@@ -72,7 +72,7 @@
                                </div>
 
                                {{if $item.has_cats}}
-                               <div class="categorytags"><span>{{$item.txt_cats}} {{foreach $item.categories as $cat}}<span class="p-category">{{$cat.name}}</span>
+                               <div class="categorytags"><span>{{$item.txt_cats}} {{foreach $item.categories as $cat}}<span class="p-category"><a href="{{$cat.url}}">{{$cat.name}}</a></span>
                                <a href="{{$cat.removeurl}}" title="{{$remove}}">[{{$remove}}]</a>
                                {{if $cat.last}}{{else}}, {{/if}}{{/foreach}}
                                </div>
                        </div>
                        {{/if}}
 
+                       {{if $item.pin}}
+                       <a href="#" id="pinned-{{$item.id}}" onclick="dopin({{$item.id}}); return false;" class="pin-item icon {{$item.ispinned}}" title="{{$item.pin.toggle}}"></a>
+                       {{/if}}
                        {{if $item.star}}
                        <a href="#" id="starred-{{$item.id}}" onclick="dostar({{$item.id}}); return false;" class="star-item icon {{$item.isstarred}}" title="{{$item.star.toggle}}"></a>
                        {{/if}}
index 37e01f75a40898465eb28d25410c15b7cc0755f1..169d1b21405487b29cbff20560c67d48e28d5307 100644 (file)
@@ -60,6 +60,7 @@
                                {{if $item.owner_self}}
                                        {{include file="sub/delivery_count.tpl" delivery=$item.delivery}}
                                {{/if}}
+                               <span class="pinned">{{$item.pinned}}</span>
                        </span>
                        {{if $item.lock}}<span class="icon s10 lock fakelink" onclick="lockview(event,{{$item.id}});" title="{{$item.lock}}">{{$item.lock}}</span>{{/if}}
                        <span class="wall-item-network" title="{{$item.app}}">
@@ -89,7 +90,7 @@
                                <span class="folder p-category">{{$cat.name}}{{if $cat.removeurl}} (<a href="{{$cat.removeurl}}" title="{{$remove}}">x</a>) {{/if}} </span>
                        {{/foreach}}
                        {{foreach $item.categories as $cat}}
-                               <span class="category p-category">{{$cat.name}}{{if $cat.removeurl}} (<a href="{{$cat.removeurl}}" title="{{$remove}}">x</a>) {{/if}} </span>
+                               <span class="category p-category"><a href="{{$cat.url}}">{{$cat.name}}</a>{{if $cat.removeurl}} (<a href="{{$cat.removeurl}}" title="{{$remove}}">x</a>) {{/if}} </span>
                        {{/foreach}}
                </div>
        </div>
                            {{/if}}
                        {{/if}}
 
+                       {{if $item.pin}}
+                               <a role="button" id="pin-{{$item.id}}" onclick="dopin({{$item.id}}); return false;"  class="{{$item.pin.classdo}}" title="{{$item.pin.do}}"><i class="icon-circle icon-large"><span class="sr-only">{{$item.pin.do}}</span></i></a>
+                               <a role="button" id="unpin-{{$item.id}}" onclick="dopin({{$item.id}}); return false;"  class="{{$item.pin.classundo}}"  title="{{$item.pin.undo}}"><i class="icon-remove-circle icon-large"><span class="sr-only">{{$item.pin.undo}}</span></i></a>
+                       {{/if}}
                        {{if $item.star}}
                                <a role="button" id="star-{{$item.id}}" onclick="dostar({{$item.id}}); return false;"  class="{{$item.star.classdo}}" title="{{$item.star.do}}"><i class="icon-star icon-large"><span class="sr-only">{{$item.star.do}}</span></i></a>
                                <a role="button" id="unstar-{{$item.id}}" onclick="dostar({{$item.id}}); return false;"  class="{{$item.star.classundo}}"  title="{{$item.star.undo}}"><i class="icon-star-empty icon-large"><span class="sr-only">{{$item.star.undo}}</span></i></a>