Просмотр исходного кода

Merge branch 'master' of https://github.com/unacms/UNA

AntonLV 4 месяцев назад
Родитель
Сommit
a2db7352ae
100 измененных файлов с 26228 добавлено и 0 удалено
  1. 51 0
      modules/boonex/artificer/updates/15.0.2_15.0.3/install/config.php
  2. 26 0
      modules/boonex/artificer/updates/15.0.2_15.0.3/install/installer.php
  3. 91 0
      modules/boonex/artificer/updates/15.0.2_15.0.3/source/data/template/bx_timeline/item_timeline.html
  4. 58 0
      modules/boonex/artificer/updates/15.0.2_15.0.3/source/data/template/mod_groups/cover_block.html
  5. 370 0
      modules/boonex/artificer/updates/15.0.2_15.0.3/source/data/template/system/css/common.css
  6. 435 0
      modules/boonex/artificer/updates/15.0.2_15.0.3/source/data/template/system/css/forms.css
  7. 224 0
      modules/boonex/artificer/updates/15.0.2_15.0.3/source/data/template/system/css/menu.css
  8. 117 0
      modules/boonex/artificer/updates/15.0.2_15.0.3/source/data/template/system/pt_application.html
  9. 21 0
      modules/boonex/artificer/updates/15.0.2_15.0.3/source/data/template/system/scripts/BxTemplCmtsMenuUnitMeta.php
  10. 304 0
      modules/boonex/artificer/updates/15.0.2_15.0.3/source/data/template/system/scripts/BxTemplFunctions.php
  11. 79 0
      modules/boonex/artificer/updates/15.0.2_15.0.3/source/data/template/system/scripts/BxTemplMenu.php
  12. 37 0
      modules/boonex/artificer/updates/15.0.2_15.0.3/source/data/template/system/scripts/BxTemplMenuCustom.php
  13. 68 0
      modules/boonex/artificer/updates/15.0.2_15.0.3/source/install/config.php
  14. 52 0
      modules/boonex/english/updates/15.0.2_15.0.3/install/config.php
  15. 15 0
      modules/boonex/english/updates/15.0.2_15.0.3/install/installer.php
  16. 181 0
      modules/boonex/english/updates/15.0.2_15.0.3/install/langs/en.xml
  17. 4486 0
      modules/boonex/english/updates/15.0.2_15.0.3/source/data/langs/system/en.xml
  18. 71 0
      modules/boonex/english/updates/15.0.2_15.0.3/source/install/config.php
  19. 51 0
      modules/boonex/lucid/updates/15.0.2_15.0.3/install/config.php
  20. 26 0
      modules/boonex/lucid/updates/15.0.2_15.0.3/install/installer.php
  21. 43 0
      modules/boonex/lucid/updates/15.0.2_15.0.3/source/data/template/system/_sub_footer.html
  22. 61 0
      modules/boonex/lucid/updates/15.0.2_15.0.3/source/data/template/system/_sub_header.html
  23. 116 0
      modules/boonex/lucid/updates/15.0.2_15.0.3/source/data/template/system/pt_application.html
  24. 68 0
      modules/boonex/lucid/updates/15.0.2_15.0.3/source/install/config.php
  25. 51 0
      modules/boonex/notifications/updates/15.0.2_15.0.3/install/config.php
  26. 13 0
      modules/boonex/notifications/updates/15.0.2_15.0.3/install/installer.php
  27. 40 0
      modules/boonex/notifications/updates/15.0.2_15.0.3/install/langs/en.xml
  28. 32 0
      modules/boonex/notifications/updates/15.0.2_15.0.3/install/sql/enable.sql
  29. 51 0
      modules/boonex/notifications/updates/15.0.2_15.0.3/install/sql/install.sql
  30. 323 0
      modules/boonex/notifications/updates/15.0.2_15.0.3/source/classes/BxNtfsConfig.php
  31. 183 0
      modules/boonex/notifications/updates/15.0.2_15.0.3/source/classes/BxNtfsCronNotify.php
  32. 48 0
      modules/boonex/notifications/updates/15.0.2_15.0.3/source/classes/BxNtfsCronQueue.php
  33. 618 0
      modules/boonex/notifications/updates/15.0.2_15.0.3/source/classes/BxNtfsDb.php
  34. 180 0
      modules/boonex/notifications/updates/15.0.2_15.0.3/source/classes/BxNtfsGridEtemplates.php
  35. 332 0
      modules/boonex/notifications/updates/15.0.2_15.0.3/source/classes/BxNtfsGridSettingsAdministration.php
  36. 860 0
      modules/boonex/notifications/updates/15.0.2_15.0.3/source/classes/BxNtfsModule.php
  37. 64 0
      modules/boonex/notifications/updates/15.0.2_15.0.3/source/classes/BxNtfsStudioPage.php
  38. 633 0
      modules/boonex/notifications/updates/15.0.2_15.0.3/source/classes/BxNtfsTemplate.php
  39. 82 0
      modules/boonex/notifications/updates/15.0.2_15.0.3/source/install/config.php
  40. 223 0
      modules/boonex/notifications/updates/15.0.2_15.0.3/source/install/langs/en.xml
  41. 205 0
      modules/boonex/notifications/updates/15.0.2_15.0.3/source/install/sql/enable.sql
  42. 279 0
      modules/boonex/notifications/updates/15.0.2_15.0.3/source/install/sql/install.sql
  43. 19 0
      modules/boonex/notifications/updates/15.0.2_15.0.3/source/install/sql/uninstall.sql
  44. 54 0
      modules/boonex/notifications/updates/15.0.2_15.0.3/source/js/main.js
  45. 19 0
      modules/boonex/notifications/updates/15.0.2_15.0.3/source/template/etemplate_form.html
  46. 12 0
      modules/boonex/notifications/updates/15.0.2_15.0.3/source/template/etemplate_preview.html
  47. 1 0
      modules/boonex/notifications/updates/15.0.2_15.0.3/source/template/field_actions.html
  48. 58 0
      modules/boonex/organizations/updates/15.0.2_15.0.3/install/config.php
  49. 13 0
      modules/boonex/organizations/updates/15.0.2_15.0.3/install/installer.php
  50. 153 0
      modules/boonex/organizations/updates/15.0.2_15.0.3/source/install/config.php
  51. 59 0
      modules/boonex/organizations/updates/15.0.2_15.0.3/source/install/sql/uninstall.sql
  52. 51 0
      modules/boonex/payment/updates/15.0.1_15.0.2/install/config.php
  53. 25 0
      modules/boonex/payment/updates/15.0.1_15.0.2/install/installer.php
  54. 30 0
      modules/boonex/payment/updates/15.0.1_15.0.2/install/langs/en.xml
  55. 13 0
      modules/boonex/payment/updates/15.0.1_15.0.2/install/sql/enable.sql
  56. 50 0
      modules/boonex/payment/updates/15.0.1_15.0.2/install/sql/install.sql
  57. 423 0
      modules/boonex/payment/updates/15.0.1_15.0.2/source/classes/BxPaymentCart.php
  58. 384 0
      modules/boonex/payment/updates/15.0.1_15.0.2/source/classes/BxPaymentConfig.php
  59. 912 0
      modules/boonex/payment/updates/15.0.1_15.0.2/source/classes/BxPaymentDb.php
  60. 130 0
      modules/boonex/payment/updates/15.0.1_15.0.2/source/classes/BxPaymentDetails.php
  61. 210 0
      modules/boonex/payment/updates/15.0.1_15.0.2/source/classes/BxPaymentFormDetails.php
  62. 334 0
      modules/boonex/payment/updates/15.0.1_15.0.2/source/classes/BxPaymentGridCart.php
  63. 115 0
      modules/boonex/payment/updates/15.0.1_15.0.2/source/classes/BxPaymentGridSbsAdministration.php
  64. 30 0
      modules/boonex/payment/updates/15.0.1_15.0.2/source/classes/BxPaymentGridSbsHistory.php
  65. 82 0
      modules/boonex/payment/updates/15.0.1_15.0.2/source/classes/BxPaymentGridSbsList.php
  66. 95 0
      modules/boonex/payment/updates/15.0.1_15.0.2/source/classes/BxPaymentMenuSbsActions.php
  67. 2129 0
      modules/boonex/payment/updates/15.0.1_15.0.2/source/classes/BxPaymentModule.php
  68. 444 0
      modules/boonex/payment/updates/15.0.1_15.0.2/source/classes/BxPaymentProviderChargebeeV3.php
  69. 310 0
      modules/boonex/payment/updates/15.0.1_15.0.2/source/classes/BxPaymentProviderPayPal.php
  70. 588 0
      modules/boonex/payment/updates/15.0.1_15.0.2/source/classes/BxPaymentProviderStripe.php
  71. 757 0
      modules/boonex/payment/updates/15.0.1_15.0.2/source/classes/BxPaymentProviderStripeBasic.php
  72. 1192 0
      modules/boonex/payment/updates/15.0.1_15.0.2/source/classes/BxPaymentProviderStripeV3.php
  73. 689 0
      modules/boonex/payment/updates/15.0.1_15.0.2/source/classes/BxPaymentSubscriptions.php
  74. 649 0
      modules/boonex/payment/updates/15.0.1_15.0.2/source/classes/BxPaymentTemplate.php
  75. 70 0
      modules/boonex/payment/updates/15.0.1_15.0.2/source/install/config.php
  76. 715 0
      modules/boonex/payment/updates/15.0.1_15.0.2/source/install/langs/en.xml
  77. 213 0
      modules/boonex/payment/updates/15.0.1_15.0.2/source/install/sql/enable.sql
  78. 701 0
      modules/boonex/payment/updates/15.0.1_15.0.2/source/install/sql/install.sql
  79. 110 0
      modules/boonex/payment/updates/15.0.1_15.0.2/source/js/subscriptions.js
  80. 34 0
      modules/boonex/payment/updates/15.0.1_15.0.2/source/template/css/subscriptions.css
  81. 45 0
      modules/boonex/payment/updates/15.0.1_15.0.2/source/template/order_subscription.html
  82. 19 0
      modules/boonex/payment/updates/15.0.1_15.0.2/source/template/subscription_form.html
  83. 51 0
      modules/boonex/persons/updates/15.0.2_15.0.3/install/config.php
  84. 13 0
      modules/boonex/persons/updates/15.0.2_15.0.3/install/installer.php
  85. 4 0
      modules/boonex/persons/updates/15.0.2_15.0.3/install/langs/en.xml
  86. 153 0
      modules/boonex/persons/updates/15.0.2_15.0.3/source/install/config.php
  87. 374 0
      modules/boonex/persons/updates/15.0.2_15.0.3/source/install/langs/en.xml
  88. 51 0
      modules/boonex/posts/updates/15.0.2_15.0.3/install/config.php
  89. 13 0
      modules/boonex/posts/updates/15.0.2_15.0.3/install/installer.php
  90. 4 0
      modules/boonex/posts/updates/15.0.2_15.0.3/install/langs/en.xml
  91. 2 0
      modules/boonex/posts/updates/15.0.2_15.0.3/install/sql/install.sql
  92. 137 0
      modules/boonex/posts/updates/15.0.2_15.0.3/source/classes/BxPostsSearchResult.php
  93. 155 0
      modules/boonex/posts/updates/15.0.2_15.0.3/source/install/config.php
  94. 367 0
      modules/boonex/posts/updates/15.0.2_15.0.3/source/install/langs/en.xml
  95. 716 0
      modules/boonex/posts/updates/15.0.2_15.0.3/source/install/sql/install.sql
  96. 51 0
      modules/boonex/profiler/updates/15.0.1_15.0.2/install/config.php
  97. 13 0
      modules/boonex/profiler/updates/15.0.1_15.0.2/install/installer.php
  98. 799 0
      modules/boonex/profiler/updates/15.0.1_15.0.2/source/classes/BxProfiler.php
  99. 69 0
      modules/boonex/profiler/updates/15.0.1_15.0.2/source/install/config.php
  100. 51 0
      modules/boonex/protean/updates/15.0.2_15.0.3/install/config.php

+ 51 - 0
modules/boonex/artificer/updates/15.0.2_15.0.3/install/config.php

@@ -0,0 +1,51 @@
+<?php
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ */
+
+$aConfig = array(
+    /**
+     * Main Section.
+     */
+    'title' => 'Artificer',
+    'version_from' => '15.0.2',
+    'version_to' => '15.0.3',
+    'vendor' => 'UNA INC',
+
+    'compatible_with' => array(
+        '15.0.0-B2'
+    ),
+
+    /**
+     * 'home_dir' and 'home_uri' - should be unique. Don't use spaces in 'home_uri' and the other special chars.
+     */
+    'home_dir' => 'boonex/artificer/updates/update_15.0.2_15.0.3/',
+    'home_uri' => 'artificer_update_1502_1503',
+
+    'module_dir' => 'boonex/artificer/',
+    'module_uri' => 'artificer',
+
+    'db_prefix' => 'bx_artificer_',
+    'class_prefix' => 'BxArtificer',
+
+    /**
+     * Installation/Uninstallation Section.
+     */
+    'install' => array(
+        'execute_sql' => 0,
+        'update_files' => 1,
+        'update_languages' => 0,
+        'clear_db_cache' => 0,
+    ),
+
+    /**
+     * Category for language keys.
+     */
+    'language_category' => 'Boonex Artificer Template',
+
+    /**
+     * Files Section
+     */
+    'delete_files' => array(),
+);

+ 26 - 0
modules/boonex/artificer/updates/15.0.2_15.0.3/install/installer.php

@@ -0,0 +1,26 @@
+<?php
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ */
+
+class BxArtificerUpdater extends BxDolStudioUpdater
+{
+    function __construct($aConfig)
+    {
+        parent::__construct($aConfig);
+    }
+
+    public function update($aParams)
+    {
+        $aResult = parent::update($aParams);
+        if(!$aResult['result'])
+            return $aResult;
+
+        $oCacheUtilities = BxDolCacheUtilities::getInstance();
+        $oCacheUtilities->clear('css');
+        $oCacheUtilities->clear('template');
+
+        return $aResult;
+    }
+}

+ 91 - 0
modules/boonex/artificer/updates/15.0.2_15.0.3/source/data/template/bx_timeline/item_timeline.html

@@ -0,0 +1,91 @@
+<div id="__html_id__" class="__style_prefix__-item __class__ bx-def-thumb-size-min-height relative pb-3 md:pb-4 lg:pb-6 bx-clearfix ">
+    <a name="timeline-event-__id__"></a>
+    <div class="__style_prefix__-item-cnt bx-lnk-cnt bx-def-box bx-def-box-round-corners bx-def-color-bg-box __class_content__ group/item hover:bg-gray-50 dark:hover:bg-gray-900 hover:shadow-lg">
+        <div class="__style_prefix__-blink-plate"></div>
+        <bx_if:show_note>
+            <div class="__style_prefix__-item-notes mt-3 md:mt-4">
+                <bx_repeat:notes>
+                    <div class="__style_prefix__-item-note mt-2 first:mt-0 text-sm text-gray-500 dark:text-gray-400">
+                        <div class="__style_prefix__-in-text mx-3 md:mx-4 lg:mx-6<bx_if:show_note_color> col-__item_note_color__</bx_if:show_note_color>">__item_note__</div>
+                    </div>
+                </bx_repeat:notes>
+            </div>
+            <div class="__style_prefix__-in-divider bx-def-hr mt-3 md:mt-4"></div>
+        </bx_if:show_note>
+        <div class="__style_prefix__-item-owner flex items-center px-3 md:px-4 mt-3 md:mt-4 __class_owner__"> 
+            <div class="__style_prefix__-owner-avatar flex-shrink-0">__item_owner_unit__</div>
+            <div class="__style_prefix__-owner-info min-w-0 ltr:ml-3 rtl:mr-3 overflow-hidden">
+                <div class="__style_prefix__-owner-name flex flex-wrap items-center">
+                    <a href="__item_owner_url__" class="__style_prefix__-owner-name bx-def-font-author flex items-center min-w-0 mr-1 hover:text-gray-900 dark:hover:text-white" title="__item_owner_title__"><div class="truncate">__item_owner_name__</div>__item_owner_badges__</a> 
+                    <bx_if:show_owner_actions>
+                        <span class="__style_prefix__-owner-actions bx-def-font-meta">
+                            <bx_repeat:owner_actions>
+                                <span class="__style_prefix__-oa-div mr-1">&#183;</span><a class="__style_prefix__-owner-action hover:underline" href="__href__" onclick="__onclick__">__content__</a>
+                            </bx_repeat:owner_actions>
+                        </span>
+                    </bx_if:show_owner_actions>
+                </div>
+                <div class="__style_prefix__-item-meta bx-def-font-meta flex items-center flex-wrap">
+                    <bx_if:show_menu_item_meta>
+                        <span class="__style_prefix__-meta mr-1">__meta__</span>
+                    </bx_if:show_menu_item_meta>
+                    <bx_if:show_item_action>
+                        <span class="__style_prefix__-div mr-1">&#183;</span>
+                        <div class="__style_prefix__-item-action flex items-center mr-1">
+                            <span class="flex items-center mr-1 lowercase"><i class="sys-icon __item_icon__ mr-1"></i>__item_owner_action__</span>
+                            <bx_if:show_timeline_owner>
+                                <span class="mr-1"><bx_text:_bx_timeline_txt_to /></span> 
+                                <span class="__style_prefix__-timeline-owner-name mr-1">
+                                    <bx_repeat:owners><span class="__style_prefix__-ton-div">, </span><a href="__owner_url__" class="__style_prefix__-ton-item text-blue-600 dark:text-blue-500 font-semibold hover:underline">__owner_username__</a></bx_repeat:owners>
+                                </span> 
+                            </bx_if:show_timeline_owner>
+                        </div>
+                    </bx_if:show_item_action>
+                    <bx_if:show_pinned>
+                        <span class="__style_prefix__-div mr-1">&#183;</span>
+                        <span class="__style_prefix__-pinned ml-1">
+                            <i class="sys-icon thumbtack" title="<bx_text_attribute:_bx_timeline_txt_pinned />"></i>
+                        </span>
+                    </bx_if:show_pinned>
+                    <bx_if:show_sticked>
+                        <span class="__style_prefix__-div mr-1">&#183;</span>
+                        <span class="__style_prefix__-sticked ml-1">
+                            <i class="sys-icon thumbtack" title="<bx_text_attribute:_bx_timeline_txt_sticked />"></i>
+                        </span>
+                    </bx_if:show_sticked>
+                    <bx_if:show_hot>
+                        <span class="__style_prefix__-div mr-1">&#183;</span>
+                        <span class="__style_prefix__-hot ml-1">
+                            <i class="sys-icon fire" title="<bx_text_attribute:_bx_timeline_txt_hot />"></i>
+                        </span>
+                    </bx_if:show_hot>
+                </div>
+                
+            </div>
+        </div>
+        
+        <div class="__style_prefix__-item-content __style_prefix__-ic-__content_type__ bx-clearfix">__content__</div>
+        <bx_if:show_location>
+            <div class="__style_prefix__-item-location mx-3 md:mx-4 mt-3 md:mt-4 bx-def-font-grayed bx-clearfix">__location__</div>
+        </bx_if:show_location>
+        <bx_if:show_fields>
+            <div class="__style_prefix__-item-fields mx-3 md:mx-4 mt-3 md:mt-4 bx-def-font-grayed bx-clearfix">__fields__</div>
+        </bx_if:show_fields>
+        <bx_if:show_menu_item_counters>
+            <div class="__style_prefix__-item-activity __style_prefix__-ia-counters space-x-4 px-2 md:px-3">__menu_item_counters__</div>
+        </bx_if:show_menu_item_counters>
+        <div class="flex justify-between space-x-8 mt-2 md:mt-3 p-3 md:p-4 border-t border-gray-200 dark:border-gray-700">
+            <bx_if:show_menu_item_actions>
+                <div class="__style_prefix__-item-activity">__menu_item_actions__</div>
+            </bx_if:show_menu_item_actions>
+            <bx_if:show_manage>
+                <div class="__style_prefix__-item-manage">
+                    <a class="group bx-lnk-cnt bx-stl-mil-sm" href="javascript:void(0)" onclick="__onclick__">
+                        <span class="bx-menu-item-icon bx-def-align-center leading-5"><i class="sys-icon ellipsis-h"></i></span>
+                    </a>
+                </div>
+            </bx_if:show_manage>
+        </div>
+        <div class="__style_prefix__-item-comments-holder">__comments__</div>
+    </div>
+</div>

+ 58 - 0
modules/boonex/artificer/updates/15.0.2_15.0.3/source/data/template/mod_groups/cover_block.html

@@ -0,0 +1,58 @@
+<div class="bx-base-profile-cover-block-wrapper">
+    <div class="bx-base-pofile-cover-wrapper __class__ relative bg-gradient-to-b from-gray-100 to-white dark:from-black dark:to-gray-900 rounded-md">
+        <div class="bx-base-pofile-cover relative <bx_if:show_clickable>bx-lnk-cnt</bx_if:show_clickable>">
+            <a href="__content_url__" class="bx-lnk-src hidden"></a>
+            <bx_if:show_cover>
+                <div class="bx-base-pofile-cover-image-wrp relative overflow-hidden">
+                    <div class="bx-base-pofile-cover-image relative h-64 lg:h-40 max-w-7xl mx-auto opacity-100 bg-gradient-to-b from-blue-400 to-blue-500 rounded-t-md __add_class__">
+                        <p class="bx-base-pofile-cover-image box-border absolute h-full w-full">
+                            <img class="bx-base-pofile-cover-image relative h-64 mx-auto w-full object-cover bg-cover lg:h-40 rounded-t-md __img_class__ bx-image-edit-source-__unique_id__" style="background-image:url(__cover_url__);__cover_settins__" src="<bx_icon_url:spacer.gif />" />
+                        </p>
+                    </div>
+                </div>
+            </bx_if:show_cover>
+            <div class="bx-base-pofile-cover-info relative mx-auto px-6">
+                <div class="bx-base-pofile-ci-cnt relative flex flex-col items-center -mt-24">
+                    <bx_if:show_avatar>
+                        <div class="bx-base-pofile-cover-thumb relative inline-flex justify-center __add_class__">
+                            <a class="bx-base-pofile-cover-thumb" href="__picture_href__" href="javascript:" <bx_if:is_avatar>onclick="$('#__picture_popup_id__').dolPopupImage('__picture_url__', $(this).parent()); event.stopPropagation();"</bx_if:is_avatar>>
+                                <img class="bx-base-pofile-unit-thumb bx-def-ava-big bx-def-ava-big-size rounded-full ring-4 mx-auto ring-white dark:ring-gray-900 h-48 w-48 lg:h-32 lg:w-32 __img_class__ bx-image-edit-source-__unique_id__" src="__ava_url__"  <bx_if:show_ava_letter> style="display:none" </bx_if:show_ava_letter> />
+                                <p class="bx-base-pofile-unit-thumb bx-def-ava-big bx-def-ava-big-size flex items-center justify-center box-border m-0 rounded-full ring-4 mx-auto ring-white dark:ring-gray-900 h-48 w-48 lg:h-32 lg:w-32 text-white font-bold text-5xl __img_class__-placeholder" style="background-color:rgba(__color__);<bx_if:show_ava_image>display:none</bx_if:show_ava_image>" >__letter__</p>
+                            </a>
+                            <bx_if:show_online>
+                                <div class="bx-base-pofile-unit-online"></div>
+                            </bx_if:show_online>
+                            __picture_tweak__
+                        </div>
+                    </bx_if:show_avatar>
+                    <bx_if:show_avatar_placeholder>
+                        <div class="bx-base-pofile-cover-thumb-placeholder h-24 lg:h-36"></div>
+                    </bx_if:show_avatar_placeholder>
+                </div>
+                <div class="bx-base-pofile-cover-user relative flex flex-col flex-colmt-6 pt-6 sm:pb-1">
+                    <div class="bx-base-profile-cover-title-bages min-w-0 flex-1 mb-4">
+                        <bx_if:show_title_as_tag>
+                            <h1 class="bx-def-unit-info text-2xl font-bold text-gray-900 dark:text-gray-50 text-center sm:truncate">__title__</h1>
+                        </bx_if:show_title_as_tag>
+                        <bx_if:show_title_as_text>
+                            <div class="bx-def-unit-info text-2xl font-bold text-gray-900 dark:text-gray-50 text-center sm:truncate">__title__</div>
+                        </bx_if:show_title_as_text>
+                        <div class="bx-base-profile-cover-meta-holder">
+                            <div class="bx-base-profile-cover-meta flex flex-row flex-wrap justify-center mt-6 md:mt-2 -ml-1  text-base font-medium">__meta__</div>
+                        </div>
+                    </div>
+                    <div class="bx-base-pofile-cover-actions relative flex lg:flex-1 h-14 md:h-10 mb-4" onclick="event.stopPropagation();">__action_menu__</div>
+                    <bx_if:show_text>
+                        <div class="flex justify-between mb-4">
+                            <div class="font-normal text-sm lg:text-base text-gray-500 group-hover:text-gray-600 dark:text-gray-400 dark:group-hover:text-gray-300">__text__</div>
+                        </div>
+                    </bx_if:show_text>
+                </div>
+                __show_data__
+            </div>
+            __cover_tweak__
+        </div>
+    </div>
+    __picture_popup__
+</div>
+__additional_code__

+ 370 - 0
modules/boonex/artificer/updates/15.0.2_15.0.3/source/data/template/system/css/common.css

@@ -0,0 +1,370 @@
+/*
+import url(../../../../../../../template/css/common.css);
+*/
+
+/*--- General ---*/
+.bx-clear {
+    clear:both;
+    float:none;
+    display:block;
+    width: 0px;
+    height: 0px;
+    font-size:1px;
+}
+.bx-clearfix:before,
+.bx-clearfix:after {
+    content:"";
+    display:table;
+}
+.bx-clearfix:after {
+    clear:both;
+}
+
+.bx-tag-link b,
+.bx-tag-link s {
+    text-decoration: none;
+    font-weight: normal;
+}
+
+.sys-icon-emoji {
+    font-weight: normal !important;
+}
+
+.sys-icon-image,
+.sys-icon-svg {
+    display: inline-block;
+    width: 1.5rem;
+    height: 1.5rem;
+    background-size: contain;
+    background-position: center;
+    background-repeat: no-repeat;
+}
+
+/*--- Application ---*/
+.bx-main.bx-pt-application .bx-menu-toolbar-padding {
+    padding-top: 0;
+}
+.bx-main.bx-pt-application .bx-main-column.narrow {
+    z-index: 4999;
+}
+.bx-main.bx-pt-application .bx-main-column.narrow.bx-mc-narrowed .bx-mc-cnt {
+    padding: 0;
+}
+
+/*--- Design Boxes ---*/
+.bx-db-container {
+    position:relative;
+}
+.bx-db-header {
+    display: -webkit-box;
+    display: -webkit-flex;
+    display: -ms-flexbox;
+    display: flex;
+
+    -webkit-box-align: center;
+    -webkit-align-items: center;
+    -ms-flex-align: center;
+    align-items: center;
+
+    -webkit-flex-wrap: nowrap;
+    -ms-flex-wrap: nowrap;
+    flex-wrap: nowrap;
+}
+.bx-db-container.bx-dbc-nopadding > .bx-db-header {
+    padding-left: 0;
+    padding-right: 0;
+}
+.bx-db-container.bx-dbc-nobg .bx-db-divider {
+    display: none;
+}
+.bx-db-title {
+    -webkit-flex: 1 1 auto;
+    -ms-flex: 1 1 auto;
+    flex: 1 1 auto;
+
+    white-space: nowrap;
+    text-overflow: ellipsis;
+    overflow: hidden;
+}
+
+.bx-dbt-cnt {
+    display: flex;
+    align-items: center;
+}
+
+.bx-db-menu {
+    -webkit-flex: 1 2 auto;
+    -ms-flex: 1 2 auto;
+    flex: 1 2 auto;
+
+    max-width: 75%;
+}
+
+.bx-media-phone .bx-db-menu {
+    max-width: 65%;
+}
+
+.bx-dbc-notitle .bx-db-menu,
+.bx-media-phone .bx-dbc-notitle .bx-db-menu {
+    max-width: none;
+}
+
+/*-- START FROM HERE --*/
+.bx-db-menu-tab {
+    margin-left: 5px;
+    text-align: right;
+    overflow-x: auto;
+}
+.bx-dir-rtl .bx-db-menu-tab {
+    text-align: left;
+}
+.bx-db-menu-tab.bx-db-menu-tab-more-auto {
+    overflow-x: visible;
+}
+
+.bx-db-menu-tab .bx-menu-custom-hor:not(.bx-menu-more-auto) {
+    width: max-content;
+}
+
+.bx-db-menu-tab-active {
+    text-decoration:underline;
+}
+
+.bx-db-menu-tab-btn a {
+    text-decoration:none;
+}
+
+.bx-db-menu-tab-btn > ul > li {
+    display: flex;
+}
+
+.bx-db-menu .sys-icon-a {
+    vertical-align:middle;
+}
+
+.bx-db-menu-popup {
+    text-align: left;
+}
+
+.bx-db-content {
+    position: relative;
+}
+
+.bx-content-padding-block {
+    padding: 1rem;
+}
+
+.bx-db-content .bx-db-help {
+    position: absolute;
+    top: 0;
+    right: 0;
+    width: 2.0rem;
+    height: 2.0rem;
+    border-radius: 2rem;
+    background-color: rgba(0, 0, 0, 0.1);
+    line-height: 2rem;
+    text-align: center;
+}
+
+.bx-db-help-popup {
+    max-width: 25rem;
+    max-height: 25rem;
+    overflow: auto;
+}
+
+/*--- Design Boxes Menu ---*/
+.bx-db-menu ul li {
+    white-space: nowrap;
+}
+.bx-db-menu ul li:not(.bx-stl-mil-sm) {
+    border-radius: 0;
+}
+.bx-db-menu ul.bx-menu-hor,
+.bx-db-menu ul.bx-menu-custom.bx-menu-custom-hor,
+.bx-db-menu ul.bx-menu-custom.bx-menu-custom-hor.bx-menu-more-auto:not(.bx-menu-submenu-more-auto) {
+    display: -webkit-inline-flex;
+    display: inline-flex;
+    -webkit-justify-content: flex-end;
+    justify-content: flex-end;
+}
+.bx-db-menu ul.bx-menu-hor > li:not(.bx-stl-mil-sm),
+.bx-db-menu ul.bx-menu-custom.bx-menu-custom-hor > li:not(.bx-stl-mil-sm) {
+    display: block;
+
+    -webkit-flex: 0 1 auto; 
+    -ms-flex:  0 1 auto; 
+    flex:  0 1 auto;
+
+    padding: 0 0.25rem;
+
+    border-bottom: 1px solid transparent;
+}
+.bx-db-menu .bx-menu-custom.bx-menu-custom-hor > li:not(.bx-stl-mil-sm) > span {
+    display: block;
+
+    margin: 0;
+    padding: 0;
+}
+.bx-db-menu ul.bx-menu-hor > li a.bx-btn,
+.bx-db-menu ul.bx-menu-custom.bx-menu-custom-hor > li a.bx-btn {
+    display: inline-block;
+    float: none;
+}
+.bx-db-menu ul.bx-menu-hor > li a > span,
+.bx-db-menu ul.bx-menu-custom.bx-menu-custom-hor > li a > span {
+    vertical-align: middle;
+}
+.bx-db-menu ul > li:not(.bx-menu-item-more-auto) a .bx-mi-icon {
+    display: none;
+}
+.bx-db-menu ul.bx-menu-submenu-more-auto {
+    line-height: normal;
+}
+.bx-db-menu ul li:not(.bx-menu-item-more-auto) a span,
+.bx-db-menu .bx-menu-item-more-popup ul.bx-menu-custom.bx-menu-submenu-more-auto li:not(.bx-menu-item-more-auto) a span,
+.bx-db-menu .bx-popup .bx-db-menu-popup ul.bx-menu-custom.bx-menu-custom-ver li a > span,
+.bx-db-menu .bx-popup .bx-db-menu-popup ul.bx-menu-ver li a > div > span {
+    margin: 0;
+}
+.bx-db-menu ul.bx-menu-hor li.bx-menu-tab-active,
+.bx-db-menu ul.bx-menu-custom.bx-menu-custom-hor li.bx-menu-tab-active {
+    border-bottom: 0;
+}
+.bx-db-menu ul.bx-menu-custom-ver li.bx-menu-item-more-auto {
+    display: none;
+}
+
+
+/*--- Popup boxes ---*/
+html.bx-popup-lock,
+body.bx-popup-lock {
+    overflow: hidden;
+}
+
+.bx-popup-transitions {
+    -webkit-transition: opacity 0.2s ease-in-out, -webkit-transform 0.2s ease-in-out;
+    transition: opacity 0.2s ease-in-out, transform 0.2s ease-in-out;
+}
+
+.bx-popup-inactive {
+    -webkit-opacity: 0;
+    opacity: 0;
+
+    -webkit-transform: scale(0.75);
+    transform: scale(0.75);
+}
+
+.bx-popup-active {
+    max-height:100%;
+    overflow-y:auto;
+
+    -webkit-opacity: 1;
+    opacity: 1;
+
+    -webkit-transform: scale(1);
+    transform: scale(1);
+
+    -webkit-transition: opacity 0.2s ease-in-out, -webkit-transform 0.2s ease-in-out;
+    transition: opacity 0.2s ease-in-out, transform 0.2s ease-in-out;
+}
+.bx-popup-fog {
+    position: fixed;
+    top: 0;
+    left: 0;
+    -webkit-backface-visibility: hidden;
+}
+.bx-popup-menu .bx-popup-close-wrapper {
+    display: none;
+}
+.bx-popup-menu .bx-popup-content-indent {
+    padding: 0.5rem 0 !important;
+}
+.bx-popup-menu ul.bx-menu-ver,
+.bx-popup-menu ul.bx-menu-verlit,
+.bx-popup-menu ul.bx-menu-custom-ver,
+.bx-popup-menu.bx-popup-menu-main.sys-add-content ul {
+    margin-top: 0.5rem;
+    margin-bottom: 0.5rem;
+}
+.bx-popup-image-wrapper .bx-def-border-radius-block {
+    border-top-left-radius: 0;
+    border-top-right-radius: 0
+}
+
+
+/*--- Loading indicator ---*/
+.bx-loading-ajax {
+    position: absolute;
+    width: 6rem;
+    height: 6rem;
+    margin-left: auto;
+    margin-right: auto;
+
+    background-color: transparent;
+
+    border-radius: 0.5rem;
+    -moz-border-radius: 0.5rem;
+    -webkit-border-radius: 0.5rem;
+
+    text-align: center;
+    color: #CCCCCC;
+}
+.bx-loading-ajax.static {
+    position: static;
+}
+.bx-loading-ajax-btn {
+    position: relative;
+    display: inline-block;
+    vertical-align: top;
+
+    min-width: 2.0rem;
+
+    margin-left: 0.25rem;
+}
+
+button.bx-btn:focus,
+button.bx-btn:focus .bx-loading-ajax-btn {
+    outline: 0;	
+}
+
+.bx-form-element-wrapper .bx-loading-ajax {
+    width: 4rem;
+    height: 4rem;
+}
+
+/*-- Show More --*/
+.bx-overflow-ready {
+    max-height: 16rem;
+    overflow: hidden;
+}
+.bx-overflow-ready.bx-or-cmt {
+    max-height: 10rem;
+}
+.bx-overflow:before {
+    position: absolute;
+    bottom: 0;
+    width: 100%;
+    height: 20%;
+
+    content: '';
+}
+
+.bx-show-more {
+    padding-top: 0.25rem;
+    padding-bottom: 0.25rem;
+
+    text-align: center
+}
+
+/*-- Flickity: Tailwind overwrite --*/
+.flickity-enabled .flickity-viewport .flickity-slider img,
+.flickity-enabled .flickity-viewport .flickity-slider video {
+    display: inline;
+    max-width: none;
+}
+
+.bx-popup-element-close:hover,
+.bx-popup-element-close {
+    text-decoration: none;
+    font-size: 1.5rem !important;
+}

+ 435 - 0
modules/boonex/artificer/updates/15.0.2_15.0.3/source/data/template/system/css/forms.css

@@ -0,0 +1,435 @@
+/*--
+import url(../../../../../../../template/css/forms.css);
+--*/
+
+.bx-form-advanced-wrapper .bx-form-section-wrapper:first-child {
+    margin-top:0;
+}
+
+.bx-form-advanced-wrapper .bx-form-section-wrapper:last-child {
+    margin-bottom:0;
+}
+
+.bx-form-advanced-wrapper .bx-form-section-divider:first-child {
+    border: none; 
+    padding: 0; 
+}
+
+.bx-form-advanced-wrapper .bx-form-section-divider:first-child .bx-form-section-content {
+    padding-top:0; 
+}
+
+.bx-form-advanced-wrapper .bx-form-section-divider:last-child .bx-form-section-content {
+    padding-bottom:0;
+}
+
+.bx-form-input-wrapper-pgc {
+    position: relative;
+}
+
+.bx-form-option-info {
+    display: inline-flex;
+    flex-direction: column;
+}
+
+/*-- Section Toggler ---*/
+.bx-form-section-wrapper {
+    position: relative;
+}
+
+.bx-form-section {
+    margin: 0;
+}
+
+.bx-form-section-header .bx-form-section-title {
+    display: -webkit-flex;
+    display: flex;
+    -webkit-align-items: center;
+    align-items: center;
+    -webkit-flex-wrap: nowrap;
+    flex-wrap: nowrap;
+
+    line-height: 1.25rem;
+    text-transform: uppercase;
+}
+
+.bx-form-section-header .bx-form-section-title .sys-icon {
+    color: inherit !important;
+}
+
+.bx-form-section-header .bx-form-section-title u {
+    cursor: pointer;
+}
+
+.bx-form-section-header .bx-form-section-title span {
+    white-space: nowrap;
+    text-transform: none;
+    font-size: 0.75rem;
+}
+
+.bx-form-section-hidden .bx-form-section-content {
+    display:none;
+}
+
+.bx-form-collapsable .bx-form-section-toggler {
+    display: -webkit-flex;
+    display: flex;
+    -webkit-align-items: center;
+    align-items: center;
+    -webkit-justify-content: center;
+    justify-content: center;
+
+    width: 1.25rem;
+    height: 1.25rem;
+
+    text-decoration: none;
+
+    -moz-transform: rotate(180deg);
+    -webkit-transform: rotate(180deg);
+    -ms-transform: rotate(180deg);
+    -o-transform: rotate(180deg);
+
+    -webkit-transition: all 0.5s ease;
+    -moz-transition: all 0.5s ease;
+    -ms-transition: all 0.5s ease;
+    -o-transition: all 0.5s ease;
+
+    line-height: 1.25rem;
+}
+
+.bx-form-collapsed .bx-form-section-toggler {
+    -moz-transform: rotate(0deg);
+    -webkit-transform: rotate(0deg);
+    -ms-transform: rotate(0deg);
+    -o-transform: rotate(0deg);
+}
+
+.bx-form-section-toggler .sys-icon {
+    font-size:0.875rem;
+}
+
+/*--- One Line fields ---*/
+.bx-form-element-wrapper-oneline .bx-form-element {
+    display: -webkit-flex;
+    display: flex;
+    -webkit-flex-flow: row nowrap;
+    flex-flow: row nowrap;
+    -webkit-align-items: flex-start;
+    align-items: flex-start;
+    -webkit-justify-content: flex-start;
+    justify-content: flex-start;
+}
+.bx-form-input-wrapper-submit .bx-btn {
+    float: none;
+}
+.bx-form-input-wrapper-input_set .bx-btn {
+    float: left;
+}
+
+
+/*-- Form field: Password --*/
+.bx-artificer .bx-form-input-wrapper-password > a {
+    position: absolute;
+    z-index: 1000;
+    
+    display: -webkit-flex;
+    display: flex;
+    -webkit-align-items: center;
+    align-items: center;
+    -webkit-justify-content: center;
+    justify-content: center;
+
+    top: 0;
+    right: 0;    
+    height: 100%;
+
+    margin: 0 0.5rem;
+}
+.bx-dir-rtl.bx-artificer .bx-form-input-wrapper-password > a {
+    left: 0;
+    right: auto;
+}
+.bx-artificer .bx-form-input-password {
+    position: relative;
+
+    -moz-box-sizing: border-box;
+    -ms-box-sizing: border-box;
+    -webkit-box-sizing: border-box;
+    box-sizing: border-box;
+
+    width: 100%;
+    height: 100%;
+
+    margin: 0;
+    padding: 0.5rem 0;
+
+    border: 0;
+    background-color: transparent;
+}
+.bx-artificer .bx-form-input-password:focus {
+    border-color: transparent;
+    outline: none;
+    box-shadow: none;
+}
+
+
+/*-- Form field: Slider/Doublerange --*/
+.bx-form-input-wrapper-slider,
+.bx-form-input-wrapper-doublerange {
+    position: relative;
+}
+.bx-form-input-wrapper-slider .ui-slider,
+.bx-form-input-wrapper-doublerange .ui-slider {
+    position: absolute;
+    top: 0px;
+    right: 0px;
+}
+.bx-form-input-wrapper-slider .ui-slider .ui-slider-handle,
+.bx-form-input-wrapper-doublerange .ui-slider .ui-slider-handle { 
+    z-index: 1;
+}
+
+/*-- Form field: Price --*/
+.bx-form-element .bx-form-value .bx-form-input-wrapper-price {
+    display: -webkit-flex;
+    display: flex;
+    -webkit-align-items: stretch;
+    align-items: stretch;
+}
+.bx-form-element .bx-form-value .bx-form-input-wrapper-price span {
+    display: -webkit-flex;
+    display: flex;
+    -webkit-align-items: center;
+    align-items: center;
+
+    width: auto;
+}
+.bx-dir-ltr .bx-form-element .bx-form-value .bx-form-input-wrapper-price span {
+    border-right-width: 0;
+    border-top-right-radius: 0;
+    border-bottom-right-radius: 0;
+}
+.bx-dir-rtl .bx-form-element .bx-form-value .bx-form-input-wrapper-price span {
+    border-left-width: 0;
+    border-top-left-radius: 0;
+    border-bottom-left-radius: 0;
+}
+.bx-dir-ltr .bx-form-element .bx-form-value .bx-form-input-price:not(:first-child) {
+    border-top-left-radius: 0;
+    border-bottom-left-radius: 0;
+}
+.bx-dir-rtl .bx-form-element .bx-form-value .bx-form-input-price:not(:first-child) {
+    border-top-right-radius: 0;
+    border-bottom-right-radius: 0;
+}
+
+
+/*-- Form field: Date/Time Pickers --*/
+.bx-form-datepicker-modal {
+    z-index: 10001 !important;
+}
+
+
+/*-- Form field: Switcher --*/
+.bx-switcher-cont input {
+   display: none !important;
+}
+
+
+/*-- Form field: Checkbox/Radio Set --*/
+.bx-form-input-wrapper-checkbox_set label,
+.bx-artificer .bx-form-input-wrapper-radio_set label {
+    margin-left: 0.5rem;
+    vertical-align: text-bottom;
+}
+.bx-dir-rtl .bx-form-input-wrapper-checkbox_set label,
+.bx-dir-rtl.bx-artificer .bx-form-input-wrapper-radio_set label {
+    margin-left: 0;
+    margin-right: 0.5rem;
+}
+
+
+/*--- Form field: File ---*/
+.bx-form-input-wrapper-file .bx-btn {
+    display: inline-block;
+    float: none;
+}
+.bx-form-input-file {
+    position: fixed;
+    top: -1000px;
+
+    border: none;
+    background-color: transparent;
+    visibility: hidden;
+}
+
+
+/*--- Form field: Location ---*/
+.bx-form-element .bx-form-value .bx-form-input-location-cont input,
+.bx-form-element .bx-form-value .bx-form-input-location-cont select {
+    display: inline-block;
+}
+.bx-form-element .bx-form-value .bx-form-input-location-cont.minimized input,
+.bx-form-element .bx-form-value .bx-form-input-location-cont.minimized select {
+    display: block;
+}
+.bx-form-element .bx-form-input-location-cont:not(.minimized) .bx-form-input-location-country,
+.bx-form-element .bx-form-input-location-cont:not(.minimized) .bx-form-input-location-zip,
+.bx-form-element .bx-form-input-location-cont:not(.minimized) .bx-form-input-location-state,
+.bx-form-element .bx-form-input-location-cont:not(.minimized) .bx-form-input-location-city {
+    width:49%;
+}
+.bx-form-element .bx-form-input-location-street {
+    width:83%;
+}
+.bx-form-element .bx-form-input-location-street_number {
+    width:15%;
+}
+.bx-form-element .bx-form-input-location-street_number,
+.bx-form-element .bx-form-input-location-street,
+.bx-form-element .bx-form-input-location-state,
+.bx-form-element .bx-form-input-location-city {
+    margin-bottom: 0.25rem;
+}
+.bx-form-element .bx-form-input-location-cont:not(.minimized) .bx-form-input-location-street,
+.bx-form-element .bx-form-input-location-cont:not(.minimized) .bx-form-input-location-state,
+.bx-form-element .bx-form-input-location-cont:not(.minimized) .bx-form-input-location-country {
+    margin-left: 0.25rem;
+}
+.bx-dir-rtl .bx-form-element .bx-form-input-location-cont:not(.minimized) .bx-form-input-location-street,
+.bx-dir-rtl .bx-form-element .bx-form-input-location-cont:not(.minimized) .bx-form-input-location-state,
+.bx-dir-rtl .bx-form-element .bx-form-input-location-cont:not(.minimized) .bx-form-input-location-country {
+    margin-left: 0;
+    margin-right: 0.25rem;
+}
+.bx-form-element .bx-form-input-location-cont .bx-form-input-location-status-cont {
+    float:none;
+    width:98%;
+    line-height:normal;
+}
+.bx-form-element .bx-form-input-location-cont.minimized .bx-form-input-location-status-cont {
+    display: flex;
+    flex-direction: column;
+    width: auto;
+}
+.bx-form-element .bx-form-input-location-status {
+    float:left;
+}
+.bx-form-element .bx-form-input-location-copyright {
+    float:right;
+}
+.bx-form-element .bx-form-input-location-cont.minimized .bx-form-input-location-copyright {
+    float: none;
+    margin-top: 0.25rem;
+}
+
+.bx-form-element .bx-form-input-location-auto-cont {
+    display:table;
+}
+.bx-form-element .bx-form-input-location-auto-cont > div {
+    display: table-cell;
+    vertical-align: middle;
+}
+
+
+/*--- Form field: Auto-siggestion ---*/
+.bx-form-value .bx-form-input-autotoken:not(.bx-form-input-labels) {
+    float: left;
+    padding: 0.125rem 0;
+    height: auto;
+    box-shadow: none;
+    min-height: 2.375rem;
+}
+.bx-form-value .bx-form-input-autotoken:not(.bx-form-input-labels) b {
+    display: flex;
+    align-items: center;
+    float: left;
+    margin: 0.125rem;
+    padding-right: 0.5rem;
+    border-radius: 1.25rem;
+
+    line-height: 2rem;
+    white-space: nowrap;
+    font-weight: normal;    
+    cursor: pointer;
+}
+.bx-dir-rtl .bx-form-value .bx-form-input-autotoken:not(.bx-form-input-labels) b {
+    padding-left: 1.5rem;
+    padding-right: 0;
+}
+.bx-form-value .bx-form-input-autotoken:not(.bx-form-input-labels) b.val-wo-icon {
+    padding-left: 1.5rem;
+}
+.bx-form-value .bx-form-input-autotoken:not(.bx-form-input-labels) b:hover {
+    opacity: 0.7;
+}
+.bx-form-value .bx-form-input-autotoken:not(.bx-form-input-labels) b .sys-icon {
+    display: inline-block;
+    width: 1.0rem;
+    height: 1.0rem;
+    line-height: 1.0rem;
+    text-align: center;
+    font-size: 0.7em;
+    font-weight: bold;
+    vertical-align: middle;
+}
+.bx-form-value .bx-form-input-autotoken:not(.bx-form-input-labels).bx-form-input-disabled b {
+    cursor: default;
+}
+.bx-form-value .bx-form-input-autotoken:not(.bx-form-input-labels).bx-form-input-disabled b .sys-icon {
+    display: none;
+}
+.bx-form-value .bx-form-input-autotoken:not(.bx-form-input-labels) input {
+    float: left;
+    width: auto;
+    margin: 0;
+    padding: 0 0 0 0.5rem;
+    border: 0;
+    box-shadow: none;
+}
+.bx-form-value .bx-form-input-autotoken:not(.bx-form-input-labels) .bx-account-unit-wo-info,
+.bx-form-value .bx-form-input-autotoken:not(.bx-form-input-labels) .bx-base-pofile-unit-wo-info {
+    display: inline-block;
+    vertical-align: top;
+
+    margin-right: 0.5rem;
+}
+.bx-dir-rtl .bx-form-value .bx-form-input-autotoken:not(.bx-form-input-labels) .bx-account-unit-wo-info,
+.bx-dir-rtl .bx-form-value .bx-form-input-autotoken:not(.bx-form-input-labels) .bx-base-pofile-unit-wo-info {
+    margin-left: 0.5rem;
+    margin-right: 0;
+}
+
+.sys-labels .bx-form-input-text.bx-form-input-autotoken.bx-form-input-disabled b {
+    height: 2rem;
+    line-height: 2rem;
+}
+
+.select2-container {
+    width:100% !important;
+}
+.bx-form-input-select {
+    -webkit-appearance:none;
+}
+
+/* MiniColors plug-in */
+.bx-form-input-wrapper.bx-form-input-wrapper-text .minicolors-theme-bootstrap .minicolors-swatch {
+    top: 0.5rem;
+    left: 0.5rem;
+
+    width: 1.5625rem;
+    height: 1.5625rem;
+}
+
+/* tiny mce */
+.bx-form-input-wrapper-html .gray-theme.fr-toolbar.fr-top{
+   border-radius: .375rem .375rem 0 0 !important; 
+}
+.bx-form-input-wrapper-html .fr-wrapper{
+    border-radius: 0 0 .375rem .375rem !important; 
+    border-bottom-color: #CCCCCC !important;
+}
+.bx-form-input-wrapper-html .second-toolbar{
+    border-bottom:none !important;
+}
+

+ 224 - 0
modules/boonex/artificer/updates/15.0.2_15.0.3/source/data/template/system/css/menu.css

@@ -0,0 +1,224 @@
+/*--
+import url(../../../../../../../template/css/menu.css);
+--*/
+
+ul.bx-menu-hor,
+ul.bx-menu-custom-hor,
+ul.bx-menu-notif,
+ul.bx-menu-verlit,
+ul.bx-menu-ver,
+ul.bx-menu-custom-ver,
+ul.bx-menu-main,
+ul.bx-menu-main-submenu,
+ul.bx-menu-toolbar,
+ul.bx-menu-floating-blocks-wide,
+ul.bx-menu-floating-blocks-big,
+ul.bx-menu-floating-blocks-dash,
+ul.bx-menu-floating-blocks,
+ul.bx-menu-inter,
+ul.bx-menu-inter-vert,
+ul.bx-menu-btns-ver,
+ul.bx-menu-btns-hor,
+ul.bx-menu-btns-icon-hor {
+    padding: 0;
+    margin: 0;
+    list-style: none;
+}
+
+li.bx-mi-aux {}
+li.bx-mi-hidden {
+    display: none;
+}
+
+/* --- Vertical, Vertical lite, Custom Vertical Menus ---*/
+.bx-menu-ver li,
+.bx-menu-verlit li,
+.bx-menu-custom-ver li {
+    margin-top: 1px;
+}
+.bx-menu-ver li:first-child,
+.bx-menu-verlit li:first-child,
+.bx-menu-custom-ver li:first-child {
+    margin-top: 0px;
+}
+
+/*--- Vertical, Vertical lite, Custom Vertical Menus (in Popup) ---*/
+.bx-popup .bx-menu-custom-ver li > span {
+    -webkit-flex: 1 1 auto;
+    -ms-flex: 1 1 auto;
+    flex: 1 1 auto;
+
+    display: -webkit-flex;
+    display: flex;
+    -webkit-align-items: center;
+    align-items: center;
+    -webkit-justify-content: space-between;
+    justify-content: space-between;
+}
+.bx-popup .bx-menu-custom-ver li > span .bx-menu-addon {
+    padding-right: 1.0rem;
+}
+
+/* --- Horizontal, Custom Horizontal Menus --- */
+.bx-menu-custom .bx-menu-item.bx-menu-item-more-auto .bx-popup .bx-menu-custom .bx-menu-item,
+.bx-menu-custom .bx-menu-item.bx-menu-item-more-auto .bx-popup .bx-menu-custom .bx-menu-item a,
+.bx-menu-custom .bx-menu-item.bx-menu-item-more-auto .bx-popup .bx-menu-custom .bx-menu-item > span {
+    border-radius: 0;
+}
+
+/*--- Interactive Menu ---*/
+.bx-menu-inter li.bx-menu-inter-hidden,
+.bx-menu-inter-vert li.bx-menu-inter-hidden {
+    display: none;
+}
+
+/*--- Custom Menu with More Auto ---*/
+.bx-menu-main-submenu.bx-menu-more-auto .bx-menu-item.bx-menu-item-more-auto,
+.bx-menu-custom.bx-menu-custom-hor.bx-menu-more-auto .bx-menu-item.bx-menu-item-more-auto {
+    display: none;
+}
+.bx-menu-more-auto .bx-menu-item.bx-menu-item-more-auto .bx-popup .bx-menu-item a.p-2,
+.bx-menu-more-auto .bx-menu-item.bx-menu-item-more-auto .bx-popup .bx-menu-item a.px-2 {
+    padding-left: 1rem;
+    padding-right: 1rem;
+}
+
+/*--- Page Main menu ---*/
+.bx-menu-main .bx-menu-item.bx-menu-item-more-auto {
+    display: none;
+}
+.bx-menu-main .bx-menu-item.bx-menu-item-more-auto .bx-popup .bx-menu-custom .bx-menu-item,
+.bx-menu-main .bx-menu-item.bx-menu-item-more-auto .bx-popup .bx-menu-custom .bx-menu-item a {
+    border-radius: 0;
+}
+
+/*--- Page Submenu ---*/
+.bx-menu-main-submenu {
+    -webkit-justify-content: center;
+    justify-content: center;
+}
+.bx-menu-main-submenu .bx-menu-item.bx-menu-item-more-auto .bx-popup .bx-menu-custom .bx-menu-item > a {
+    width: 100%;
+    padding: 0.5rem 1.0rem; 
+    text-align: left;
+}
+.bx-menu-main-submenu .bx-menu-item.bx-menu-item-more-auto .bx-popup .bx-menu-custom .bx-menu-item .bx-mi-underline {
+    display: none;
+}
+
+/*--- Toolbar Menu ---*/
+.bx-menu-toolbar .bx-menu-toolbar-item .bx-menu-item-addon {
+    position: absolute;
+    top: -0.375rem;
+    right: -0.375rem;
+    padding: 0 0.25rem;
+}
+.bx-menu-toolbar .bx-menu-toolbar-item .bx-menu-toolbar-item-unit .bx-base-pofile-unit-online {
+    display: none;
+}
+
+/*--- Account Popup ---*/
+#bx-sliding-menu-account .bx-menu-account-popup .bx-menu-item-addon.bx-def-unit-alert {
+    position: relative;
+    padding: 0 0.25rem;
+}
+#bx-sliding-menu-account .bx-menu-account-popup-profile-create {
+    display: -webkit-flex;
+    display: flex;
+    -webkit-justify-content: center;
+    justify-content: center;
+}
+
+/*--- Add Popup ---*/
+div.bx-popup-menu-main.sys-add-content ul {
+    flex-direction: column;
+}
+
+/*--- Pannel Menu ---*/
+.bx-menu-panel {}
+
+.bx-main-column.bx-mc-narrowed .bx-menu-panel .bx-menu-panel-item .bx-mpi-toggle-hidden {
+    position: absolute;
+    display: none;
+}
+
+.bx-mc-narrowed .bx-menu-panel li .bx-stl-mil {
+    -webkit-justify-content: center;
+    justify-content: center;
+
+    padding-left: 0;
+    padding-right: 0;
+}
+.bx-mc-narrowed .bx-menu-panel li .bx-stl-mii {
+    width: 100%;
+    text-align: center;
+}
+.bx-mc-narrowed .bx-menu-panel li .bx-stl-mii,
+.bx-mc-narrowed .bx-menu-panel li .bx-stl-mii > * {
+    margin: 0;
+}
+.bx-mc-narrowed .bx-menu-panel .bx-def-thumb-size {
+    width: 2rem;
+    height: 2rem;
+}
+.bx-mc-narrowed .bx-menu-panel .bx-profile-avatar-cnt {
+    -webkit-justify-content: center;
+    justify-content: center;
+}
+
+/*--- Footer Menu ---*/
+#bx-menu-footer.bx-menu-hor > li.bx-menu-item-powered_by .sys-icon-svg {
+    width: auto;
+}
+
+/*--- Profile Stats/Followings Menu ---*/
+.bx-db-content .bx-profile-stats .bx-profile-avatar-cnt,
+.bx-db-content .bx-profile-stats .bx-menu-vertical-more-less,
+.bx-db-container:not(.bx-dbc-nopadding) .bx-menu-vertical-more-less,
+.bx-db-container:not(.bx-dbc-nopadding) .bx-menu-profile-followings {
+    margin: -0.75rem;
+}
+.bx-db-container:not(.bx-dbc-notitle) .bx-menu-vertical-more-less,
+.bx-db-container:not(.bx-dbc-notitle) .bx-menu-profile-followings {
+    margin-top: 0;
+}
+
+/*--- Profile Followings Menu ---*/
+.bx-menu-contents .bx-menu-show,
+.bx-menu-ver.bx-menu-multilevel li .bx-menu-show,
+.bx-menu-ver.bx-menu-object-sys_profile_followings li .bx-menu-show {
+    display: none;
+}
+.bx-menu-contents .bx-menu-hide,
+.bx-menu-ver.bx-menu-multilevel li .bx-menu-hide, 
+.bx-menu-ver.bx-menu-object-sys_profile_followings li .bx-menu-hide {
+    display: inline;
+}
+.bx-menu-contents.bx-m-collapsed .bx-menu-show,
+.bx-menu-ver.bx-menu-multilevel li.bx-mi-collapsed .bx-menu-show,
+.bx-menu-ver.bx-menu-object-sys_profile_followings li.bx-mi-collapsed .bx-menu-show {
+    display: inline;
+}
+.bx-menu-contents.bx-m-collapsed .bx-menu-hide,
+.bx-menu-ver.bx-menu-multilevel li.bx-mi-collapsed .bx-menu-hide,
+.bx-menu-ver.bx-menu-object-sys_profile_followings li.bx-mi-collapsed .bx-menu-hide {
+    display: none;
+}
+.bx-menu-ver.bx-menu-multilevel li.bx-mi-collapsed .bx-menu-item-subitems,
+.bx-menu-ver.bx-menu-object-sys_profile_followings li.bx-mi-collapsed .bx-menu-item-subitems {
+    display: none;
+}
+
+/*--- Object counters in menu items (e.g. Profiles meta menu) ---*/
+.bx-menu-item .sys-action-counter .sys-action-counter-label .sys-action-counter-icon .sys-icon-image,
+.bx-menu-item .sys-action-counter .sys-action-counter-label .sys-action-counter-icon .sys-icon {
+    width: 1rem;
+    height: 1rem;
+    font-size: 0.75rem;
+    line-height: 1.1rem;
+    text-align: center;
+}
+.bx-menu-item .sys-action-counter .sys-action-counter-label .sys-action-counter-icon .sys-icon-image,
+.bx-menu-item .sys-action-counter .sys-action-counter-label .sys-action-counter-icon .sys-icon.sys-icon-emoji {
+    line-height: 1rem;
+}

+ 117 - 0
modules/boonex/artificer/updates/15.0.2_15.0.3/source/data/template/system/pt_application.html

@@ -0,0 +1,117 @@
+<bx_include_auto:_header.html />
+<div class="bx-main bx-pt-application <bx_injection:injection_main_class />">
+    <bx_injection:top />
+    <!-- BEG: Navigation -->
+    <nav class="bx-def-z-index-nav fixed w-full bg-white border-b border-gray-200 dark:bg-gray-800 dark:border-gray-700">
+        <div class="px-3 py-3 lg:px-5 lg:pl-3">
+            <div class="flex items-center justify-between">
+                <div class="flex flex-1 items-center justify-start">
+                    <!-- Sidebar Toggler -->
+                    <button id="toggleSidebar" aria-expanded="true" aria-controls="sidebar" class="hidden mr-6 bg-gray-100 dark:bg-gray-700/50 text-gray-600 rounded-full cursor-pointer xl:inline hover:text-gray-900 hover:bg-gray-100 dark:text-gray-400 dark:hover:text-white dark:hover:bg-gray-700">
+                      <div class="bx-icon bx-icon-hamburger flex items-center justify-center h-10 w-10">
+                          <bx_image_auto:bars />
+                      </div>
+                    </button>
+                    <button id="toggleSidebarMobile" aria-expanded="true" aria-controls="sidebar" class="mr-2 bg-gray-100 dark:bg-gray-700/50 text-gray-600 rounded-full cursor-pointer xl:hidden hover:text-gray-900 hover:bg-gray-100 focus:bg-gray-100 dark:focus:bg-gray-700 focus:ring-2 focus:ring-gray-100 dark:focus:ring-gray-700 dark:text-gray-400 dark:hover:bg-gray-700 dark:hover:text-white">
+                      <div id="toggleSidebarMobileHamburger" class="bx-icon bx-icon-hamburger flex items-center justify-center h-10 w-10">
+                          <bx_image_auto:bars />
+                      </div>
+                      <div id="toggleSidebarMobileClose" class="bx-icon bx-icon-close hidden flex items-center justify-center h-10 w-10">
+                        <bx_image_auto:times />
+                      </div>
+                    </button>
+                    <div class="bx-toolbar-items-group relative flex flex-1 items-center justify-start">
+                        <!-- Logo -->
+                        <div id="bx-logo-container" class="bx-toolbar-item bx-ti-left bx-ti-logo flex-none items-center">
+                            <bx_injection:injection_logo_before />
+                            __main_logo__
+                            <bx_injection:injection_logo_after />
+                        </div>
+                        <!-- Menu -->
+                        <div class="bx-toolbar-item bx-ti-menu flex-2 hidden xl:block w-64 ml-4">
+                            <div id="bx-menu-toolbar-1-container" class="bx-toolbar-item bx-ti-menu w-full">
+                                <bx_menu:sys_application />
+                            </div>
+                        </div>
+                        <!-- Search -->
+                        <div class="bx-toolbar-item bx-ti-search flex flex-1 items-center justify-end">
+                            __sys_toolbar_search__
+                        </div>
+                    </div>
+                </div>
+                <bx_menu:sys_toolbar_member />
+            </div>
+        </div>
+    </nav>
+    <!-- END: Navigation -->
+
+    <div class="bx-main-content flex pt-16 overflow-hidden">
+        <!-- BEG: Sidebar -->
+        <aside id="sidebar" class="bx-main-column narrow fixed top-0 left-0 z-20 hidden xl:flex flex-col flex-shrink-0 w-64 h-full pt-16 duration-75 transition-width" aria-label="Sidebar">
+            <div class="bx-mc-border relative flex flex-col flex-1 min-h-0 max-h-full h-full pt-0 bg-white border-r border-gray-200 dark:bg-gray-800 dark:border-gray-700">
+                <div class="flex flex-col flex-1 py-2 overflow-y-auto">
+                    <div class="bx-mc-cnt flex-1 px-4 space-y-1 bg-white divide-y divide-gray-200 dark:bg-gray-800 dark:divide-gray-700">
+                        <bx_menu:sys_site_panel />
+                    </div>
+                </div>
+                <div class="absolute bottom-0 left-0 justify-center hidden w-full p-4 space-x-4 xl:flex" sidebar-bottom-menu>
+                    <!-- Some button based menu may be here -->
+                </div>
+            </div>
+        </aside>
+        <div class="fixed inset-0 z-10 hidden bg-gray-900/50 dark:bg-gray-900/90" id="sidebarBackdrop"></div>
+        <!-- END: Sidebar -->    
+
+        <!-- BEG: Main Content -->
+        <div id="main-content" class="bx-main-column wide relative w-full h-full overflow-y-auto xl:ml-64">
+            <main>
+                <bx_injection:injection_between_cover_logo />
+                __cover__
+                <bx_injection:injection_between_cover_top_menu />
+                <div id="bx-menu-main-bar-wrapper" class="bx-menu-main-bar-wrapper bg-white dark:bg-gray-900 border-b border-gray-200 dark:border-gray-800 __site_submenu_hidden__">
+                    <div id="bx-menu-main-bar" class="bx-menu-main-bar __site_submenu_class__ mx-auto px-4 sm:px-6 lg:px-8 box-border">
+                        <div class="bx-menu-main-bar-cnt -mb-px">
+                            <bx_injection:injection_top_menu_before />
+                            <div class="flex items-center h-full text-center">
+                                <div class="relative flex-1 h-full">
+                                    <div class="absolute w-full h-full">
+                                        <bx_menu:sys_site_submenu />
+                                    </div>
+                                </div>
+                                <div class="flex-none">
+                                    <bx_menu:sys_site_manage />
+                                </div>
+                            </div>
+                            <bx_injection:injection_top_menu_after />
+                        </div>
+                    </div>
+                </div>
+                <bx_injection:injection_between_content_menu />
+                <div id="bx-content-wrapper" class="bx-def-page-width mx-auto">
+                    __informer__
+                    <div class="bx-page-wrapper mx-auto px-3 md:px-4 lg:px-6 box-border">
+                        <div id="bx-content-container" class="bx-content-container">
+                            <main role="main"  id="bx-content-main" class="bx-content-main my-2 lg:my-3">
+                                <bx_injection:injection_content_before />
+                                __page_main_code__
+                                <bx_injection:injection_content_after />
+                                <bx_injection:banner_bottom />
+                            </main> <!-- #bx-content-main -->
+                            <bx_injection:injection_between_content_footer />
+                        </div> <!-- #bx-content-container -->
+                    </div> <!-- .bx-page-wrapper -->
+                </div> <!-- #bx-content-wrapper -->
+            </main>
+            <footer class="p-4 m-4 bg-white rounded-lg shadow md:flex md:items-center md:justify-between md:p-6 xl:p-8 dark:bg-gray-800">
+                <bx_injection:injection_footer_before />
+                <div id="bx-menu-bottom">
+                    <bx_menu:sys_footer />
+                </div>
+                <bx_injection:injection_footer_after />
+            </footer>
+        </div>
+        <!-- END: Main Content -->
+    </div>
+    <bx_menu:sys_site_action />
+</div> <!-- .bx-main -->
+<bx_include_auto:_footer.html />

+ 21 - 0
modules/boonex/artificer/updates/15.0.2_15.0.3/source/data/template/system/scripts/BxTemplCmtsMenuUnitMeta.php

@@ -0,0 +1,21 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    UnaTemplate UNA Template Classes
+ * @{
+ */
+
+/**
+ * @see BxDolMenu
+ */
+class BxTemplCmtsMenuUnitMeta extends BxBaseCmtsMenuUnitMeta
+{
+    public function __construct ($aObject, $oTemplate = false)
+    {
+        parent::__construct ($aObject, $oTemplate);
+    }
+}
+
+/** @} */

+ 304 - 0
modules/boonex/artificer/updates/15.0.2_15.0.3/source/data/template/system/scripts/BxTemplFunctions.php

@@ -0,0 +1,304 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    UnaTemplate UNA Template Classes
+ * @{
+ */
+
+bx_import('BxDolDesigns');
+
+class BxTemplFunctions extends BxBaseFunctions
+{
+    protected $_sModule;
+
+    public function __construct($oTemplate = null)
+    {
+        parent::__construct($oTemplate);
+
+        $this->_sModule = 'bx_artificer';
+    }
+
+    public function getMainLogoDarkUrl()
+    {
+        return BxDolDesigns::getInstance()->getSiteLogoDarkUrl();
+    }
+
+    public function getMainLogoInline()
+    {
+        return BxDolDesigns::getInstance()->getSiteLogoParam('logo_inline');
+    }
+
+    public function getMainMarkDarkUrl()
+    {
+        return BxDolDesigns::getInstance()->getSiteMarkDarkUrl();
+    }
+
+    public function getMainMarkInline()
+    {
+        return BxDolDesigns::getInstance()->getSiteLogoParam('mark_inline');
+    }
+
+    public function getMainLogo($aParams = [])
+    {
+        $oModule = BxDolModule::getInstance($this->_sModule);
+        $oDesigns = BxDolDesigns::getInstance();
+
+        $sTitle = getParam('site_title');
+
+        $sAlt = $oDesigns->getSiteLogoAlt();
+        if(empty($sAlt) && !empty($sTitle))
+            $sAlt = $sTitle;
+        $sAltAttr = bx_html_attribute($sAlt, BX_ESCAPE_STR_QUOTE);
+
+        $aImages = [
+            'logo' => ['uc' => 'Logo', 'gi' => 'logo-generic.svg'], 
+            'logo_dark' => ['uc' => 'LogoDark', 'gi' => 'logo-dark-generic.svg'], 
+            'mark' => ['uc' => 'Mark', 'gi' => 'mark-generic.svg'], 
+            'mark_dark' => ['uc' => 'MarkDark', 'gi' => 'mark-dark-generic.svg'], 
+        ];
+
+        $aTmplVarsImages = [];
+        $bLogo = $bLogoDark = $bMark = $bMarkDark = false;
+        foreach($aImages as $sType => &$aParams)
+            if(($aParams['g'] = false) || ($sFileUrl = $this->{'getMain' . $aParams['uc'] . 'Url'}()) !== false || ($aParams['g'] = (($sType == 'logo' || $aImages['logo']['g']) && ($sFileUrl = $this->_oTemplate->getImageUrl($aParams['gi'])) != ''))) {
+                $iLogoHeight = (int)$oDesigns->{'getSite' . $aParams['uc'] . 'Height'}();
+                $sLogoHeight = $iLogoHeight > 0 ? 'height:' . round($iLogoHeight/16, 3) . 'rem;' : '';
+
+                if(!empty($aParams['g'])) {
+                    list($iDlWidth, $iDlHeight) = bx_get_svg_image_size($sFileUrl);
+                    $fDlAspectRation = $iDlHeight ? $iDlWidth / $iDlHeight : BxDolDesigns::getAspectRatioDefault($sType);
+
+                    $iLogoWidth = $iLogoHeight * $fDlAspectRation;
+                }
+                else
+                    $iLogoWidth = $oDesigns->{'getSite' . $aParams['uc'] . 'Width'}();
+
+                $sLogoWidth = $iLogoWidth > 0 ? 'width:' . round($iLogoWidth/16, 3) . 'rem;' : '';
+
+                $aTmplVarsImages[$sType] = [
+                    'id' => 'bx-' . str_replace('_', '-', $sType),
+                    'src' => $sFileUrl,
+                    'alt' => $sAltAttr,
+                    'class' => '',
+                    'style' => $sLogoWidth . ' ' . $sLogoHeight,
+                ];
+
+                ${'b' . $aParams['uc']} = true;
+            }
+
+        $sLogoInline = $sLogoInlineClass = '';
+        if($aImages['logo']['g'] && ($sLogoInline = $this->getMainLogoInline()) != '') {
+            $bLogo = true;
+            $bLogoDark = false;
+            unset($aTmplVarsImages['logo'], $aTmplVarsImages['logo_dark']);
+        }
+
+        $sMarkInline = $sMarkInlineClass = '';
+        if($aImages['mark']['g'] && ($sMarkInline = $this->getMainMarkInline()) != '') {
+            $bMark = true;
+            $bMarkDark = false;
+            unset($aTmplVarsImages['mark'], $aTmplVarsImages['mark_dark']);
+        }
+
+        if($bLogo) {
+            if($bLogoDark && !$bMark)
+                $aTmplVarsImages['logo']['class'] = 'block dark:hidden';
+            if(!$bLogoDark && $bMark) {
+                $sLogoInlineClass = 'hidden lg:block';
+                if(isset($aTmplVarsImages['logo']))
+                    $aTmplVarsImages['logo']['class'] = $sLogoInlineClass;
+            }
+            if($bLogoDark && $bMark)
+                $aTmplVarsImages['logo']['class'] = 'hidden dark:hidden lg:block'; 
+        }
+
+        if($bLogoDark) {
+            $aTmplVarsImages['logo_dark']['class'] = 'hidden dark:block';
+
+            if($bMark || $bMarkDark)
+                $aTmplVarsImages['logo_dark']['class'] = 'hidden dark:lg:block';
+        }
+
+        if($bMark) {
+            $sMarkInlineClass = 'block lg:hidden';
+            if(isset($aTmplVarsImages['mark']))
+                $aTmplVarsImages['mark']['class'] = $sMarkInlineClass;
+
+            if($bMarkDark)
+                $aTmplVarsImages['mark']['class'] = 'block dark:hidden lg:hidden';
+        }
+
+        if($bMarkDark) {
+            $aTmplVarsImages['mark_dark']['class'] = 'hidden dark:block dark:lg:hidden';
+        }
+
+
+        $aAttrs = [
+            'href' => BX_DOL_URL_ROOT, 
+            'title' => $sAltAttr
+        ];
+        if(!empty($aParams['attrs']) && is_array($aParams['attrs']))
+            $aAttrs = array_merge($aAttrs, $aParams['attrs']);
+
+        $sTmplName = 'logo_main.html';
+        $aTmplVars = [
+            'attrs' => bx_convert_array2attrs($aAttrs),
+            'bx_if:show_title' => [
+                'condition' => !$bLogo && !$sLogoInline,
+                'content' => [
+                    'logo' => $sTitle,
+                ]
+            ],
+            'bx_if:show_logo_inline' => [
+                'condition' => !empty($sLogoInline),
+                'content' => [
+                    'class' => $sLogoInlineClass,
+                    'height' => $oModule->_oConfig->getLogoHeight() . 'px',
+                    'content' => $sLogoInline
+                ]
+            ],
+            'bx_if:show_mark_inline' => [
+                'condition' => !empty($sMarkInline),
+                'content' => [
+                    'class' => $sMarkInlineClass,
+                    'height' => $oModule->_oConfig->getMarkHeight() . 'px',
+                    'content' => $sMarkInline
+                ]
+            ]
+        ];
+
+        foreach($aImages as $sType => $aParams) {
+            if(($sTypeIf = 'bx_if:show_' . $sType) && isset($aTmplVarsImages[$sType]))
+                $aTmplVars[$sTypeIf] = [
+                    'condition' => true,
+                    'content' => $aTmplVarsImages[$sType]
+                ];
+            else 
+                $aTmplVars[$sTypeIf] = [
+                    'condition' => false,
+                    'content' => []
+                ];
+        }
+
+        bx_alert('system', 'get_logo', 0, 0, [
+            'tmpl_name' => &$sTmplName,
+            'tmpl_vars' => &$aTmplVars,
+            'tmpl_name_ref' => &$sTmplName,
+            'tmpl_vars_ref' => &$aTmplVars,
+        ]);
+
+        return $this->_oTemplate->parseHtmlByName($sTmplName, $aTmplVars);
+    }
+
+    public function TemplPageAddComponent($sKey)
+    {
+        $mixedResult = false;
+
+        switch($sKey) {
+            case 'sys_header_width':
+                $mixedResult = '';
+                if(getParam('bx_artificer_header_stretched') != 'on')
+                    $mixedResult = parent::TemplPageAddComponent($sKey);
+                break;
+
+            case 'sys_toolbar_search':
+                if(getParam('bx_artificer_header_search') == 'on')
+                    $mixedResult = parent::TemplPageAddComponent($sKey);
+                else
+                    $mixedResult = '';
+                break;
+
+            default:
+                $mixedResult = parent::TemplPageAddComponent($sKey);
+        }
+
+        return $mixedResult;
+    }
+
+    public function getColorSchemeSwitcher()
+    {
+        $oModule = BxDolModule::getInstance($this->_sModule);
+
+        if($oModule->_oConfig->getColorScheme() != 'auto')
+            return '';
+        
+        $aMenu = [
+            ['id' => $this->_sModule . '-css-sun', 'name' => $this->_sModule . '-css-sun', 'class' => '', 'link' => 'javascript:void(0)', 'onclick' => 'javascript:oBxArtificerUtils.setColorScheme(1)', 'target' => '_self', 'icon' => 'sun', 'title' => _t('_bx_artificer_txt_color_scheme_light')],
+            ['id' => $this->_sModule . '-css-moon', 'name' => $this->_sModule . '-css-moon', 'class' => '', 'link' => 'javascript:void(0)', 'onclick' => 'javascript:oBxArtificerUtils.setColorScheme(2)', 'target' => '_self', 'icon' => 'moon', 'title' => _t('_bx_artificer_txt_color_scheme_dark')],
+            ['id' => $this->_sModule . '-css-desktop', 'name' => $this->_sModule . '-css-desktop', 'class' => '', 'link' => 'javascript:void(0)', 'onclick' => 'javascript:oBxArtificerUtils.setColorScheme(0)', 'target' => '_self', 'icon' => 'desktop', 'title' => _t('_bx_artificer_txt_color_scheme_system')],
+        ];
+        $oMenu = new BxTemplMenu(['template' => 'menu_vertical.html', 'menu_id'=> $this->_sModule . '-css-menu', 'menu_items' => $aMenu]);
+
+        return $oModule->_oTemplate->parseHtmlByName('color_scheme_switcher.html', [
+            'popup' => $this->transBox('bx-sb-theme-switcher-menu', $oMenu->getCode(), true)
+        ]);
+    }
+
+    protected function getInjFooterPopupMenus() 
+    {
+        $sContent = '';
+
+        $oSearch = new BxTemplSearch();
+        $oSearch->setLiveSearch(true);
+        $sContent .= $this->_oTemplate->parsePageByName('search.html', array(
+            'search_form' => $oSearch->getForm(BX_DB_CONTENT_ONLY),
+            'results' => $oSearch->getResultsContainer(),
+        ));
+
+        if(isLogged())
+            $sContent .= $this->_oTemplate->getMenu('sys_add_content');
+
+        return $sContent;
+    }
+
+    protected function getInjFooterSidebarSite() 
+    {
+        $oSearch = new BxTemplSearch();
+        $oSearch->setLiveSearch(true);
+        $sSearch = $oSearch->getForm(BX_DB_CONTENT_ONLY);
+
+        $sLogoUrl = $this->getMainLogoUrl();
+        $bLogoUrl = !empty($sLogoUrl);
+
+        $sLogoText = BxDolDesigns::getInstance()->getSiteLogoAlt();
+        if(empty($sLogoText))
+            $sLogoText = getParam('site_title');
+
+        return $this->_oTemplate->parsePageByName('sidebar_site.html', array(
+            'bx_if:show_logo_image' => array(
+                'condition' => $bLogoUrl,
+                'content' => array(
+                    'logo_url' => $sLogoUrl,
+                    'logo_text' => $sLogoText
+                )
+            ),
+            'bx_if:show_logo_text' => array(
+                'condition' => !$bLogoUrl,
+                'content' => array(
+                    'logo_text' => $sLogoText
+                )
+            ),
+            'search_form' => $sSearch,
+        ));
+    }
+
+    protected function getInjFooterSidebarAccount() 
+    {
+        $oProfile = BxDolProfile::getInstance();
+        if(!$oProfile)
+            return '';
+
+        $sMenuAccountPopup = 'sys_account_popup';
+        $oMenuAccountPopup = BxTemplMenu::getObjectInstance($sMenuAccountPopup);
+
+        return $this->_oTemplate->parsePageByName('sidebar_account.html', [
+            'color_scheme_switcher' => $this->getColorSchemeSwitcher(),
+            'ap_menu_object' => $sMenuAccountPopup,
+            'bx_repeat:ap_menu_items' => $oMenuAccountPopup->getMenuItems(),
+        ]);
+    }
+}
+
+/** @} */

+ 79 - 0
modules/boonex/artificer/updates/15.0.2_15.0.3/source/data/template/system/scripts/BxTemplMenu.php

@@ -0,0 +1,79 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    UnaTemplate UNA Template Classes
+ * @{
+ */
+
+/**
+ * @see BxDolMenu
+ */
+class BxTemplMenu extends BxBaseMenu
+{
+    public function __construct ($aObject, $oTemplate = false)
+    {
+        parent::__construct ($aObject, $oTemplate);
+
+        if(isset($aObject['object'])) {
+            //--- For page submenus ---//
+            if(strpos($aObject['object'], '_submenu') !== false) {
+                $this->_bHx = getParam('bx_artificer_use_htmx') == 'on';
+                $this->_bHxHead = $this->_bHx && true;
+                $this->_mHxPreload = $this->_bHx && true;
+                $this->_aHx = [
+                    'get' => '',
+                    'trigger' => 'click',
+                    'target' => '#bx-content-wrapper',
+                    'swap' => 'outerHTML swap:400ms settle:400ms',
+                    'push-url' => 'true',
+                    'on::before-on-load' => 'oBxArtificerUtils.submenuClickBl(this)',
+                    'on::after-on-load' => 'oBxArtificerUtils.submenuClickAl(this)'
+                ];
+
+                $sExtensions = '';
+                if($this->_bHxHead)
+                    $sExtensions .= ' head-support';
+                if($this->_mHxPreload)
+                    $sExtensions .= ' preload';
+
+                $sInjection = '';
+                if(($sExtensions = trim($sExtensions)) != '')
+                    $this->_oTemplate->addInjection('injection_body', 'text', 'hx-ext="' . $sExtensions . '"');
+            }
+        }
+
+        $this->_aOptionalParams['popup'] = '';
+    }
+
+    protected function _getTemplateVars()
+    {
+        return array_merge(parent::_getTemplateVars(), array(
+            'html_id' => '',
+            'bx_if:show_more_auto_class' => array(
+                'condition' => false,
+                'content' => array()
+            ),
+            'js_code' => ''
+        ));
+    }
+
+    protected function _getMenuItem ($a)
+    {
+        $aResult = parent::_getMenuItem($a);
+        if($aResult === false)
+            return $aResult;
+
+        if(!$this->_bIsApi && !empty($a['primary'])) {
+            if(!isset($aResult['class_add']))
+                $aResult['class_add'] = '';
+
+            $aResult['class_add'] .= ' bx-mi-primary'; 
+        }
+
+        return $aResult;
+    }
+}
+
+/** @} */

+ 37 - 0
modules/boonex/artificer/updates/15.0.2_15.0.3/source/data/template/system/scripts/BxTemplMenuCustom.php

@@ -0,0 +1,37 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    UnaTemplate UNA Template Classes
+ * @{
+ */
+
+/**
+ * @see BxDolMenu
+ */
+class BxTemplMenuCustom extends BxBaseMenuCustom
+{
+    public function __construct ($aObject, $oTemplate = false)
+    {
+        parent::__construct ($aObject, $oTemplate);
+    }
+
+    protected function _getMenuItem ($a)
+    {
+        $aResult = parent::_getMenuItem($a);
+        if($aResult === false)
+            return $aResult;
+
+        if(!$this->_bIsApi && !empty($a['primary'])) {
+            if(!isset($aResult['class']))
+                $aResult['class'] = '';
+
+            $aResult['class'] .= ' bx-mi-primary'; 
+        }
+
+        return $aResult;
+    }
+}
+
+/** @} */

+ 68 - 0
modules/boonex/artificer/updates/15.0.2_15.0.3/source/install/config.php

@@ -0,0 +1,68 @@
+<?php
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Artificer Artificer template
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+$aConfig = array(
+    /**
+     * Main Section.
+     */
+    'type' => BX_DOL_MODULE_TYPE_TEMPLATE,
+    'name' => 'bx_artificer',
+    'title' => 'Artificer',
+    'note' => 'Design template',
+    'version' => '15.0.3',
+    'vendor' => 'UNA INC',
+    'help_url' => 'http://feed.una.io/?section={module_name}',
+
+    'compatible_with' => array(
+        '15.0.0-B2'
+    ),
+
+    /**
+     * 'home_dir' and 'home_uri' - should be unique. Don't use spaces in 'home_uri' and the other special chars.
+     */
+    'home_dir' => 'boonex/artificer/',
+    'home_uri' => 'artificer',
+
+    'db_prefix' => 'bx_artificer_',
+    'class_prefix' => 'BxArtificer',
+
+    /**
+     * Category for language keys.
+     */
+    'language_category' => 'Boonex Artificer Template',
+
+    /**
+     * Installation/Uninstallation Section.
+     */
+    'install' => array(
+        'execute_sql' => 1,
+        'update_languages' => 1,
+    	'clear_db_cache' => 1
+    ),
+    'uninstall' => array (
+        'execute_sql' => 1,
+        'update_languages' => 1,
+    	'clear_db_cache' => 1
+    ),
+    'enable' => array(
+        'execute_sql' => 1
+    ),
+    'disable' => array(
+        'execute_sql' => 1
+    ),
+
+    /**
+     * Dependencies Section
+     */
+    'dependencies' => array(),
+);
+
+/** @} */

+ 52 - 0
modules/boonex/english/updates/15.0.2_15.0.3/install/config.php

@@ -0,0 +1,52 @@
+<?php
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ */
+
+$aConfig = array(
+    /**
+     * Main Section.
+     */
+    'title' => 'English',
+    'version_from' => '15.0.2',
+    'version_to' => '15.0.3',
+    'vendor' => 'UNA INC',
+
+    'compatible_with' => array(
+        '15.0.0-B2'
+    ),
+
+    /**
+     * 'home_dir' and 'home_uri' - should be unique. Don't use spaces in 'home_uri' and the other special chars.
+     */
+    'home_dir' => 'boonex/english/updates/update_15.0.2_15.0.3/',
+    'home_uri' => 'en_update_1502_1503',
+
+    'module_dir' => 'boonex/english/',
+    'module_uri' => 'en',
+
+    'db_prefix' => 'bx_eng_',
+    'class_prefix' => 'BxEng',
+
+    /**
+     * Installation/Uninstallation Section.
+     */
+    'install' => array(
+        'execute_sql' => 0,
+        'update_files' => 1,
+        'update_languages' => 1,
+        'restore_languages' => 0,
+        'clear_db_cache' => 0,
+    ),
+
+    /**
+     * Category for language keys.
+     */
+    'language_category' => 'System',
+
+    /**
+     * Files Section
+     */
+    'delete_files' => array(),
+);

+ 15 - 0
modules/boonex/english/updates/15.0.2_15.0.3/install/installer.php

@@ -0,0 +1,15 @@
+<?php
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ */
+
+bx_import('BxDolStudioUpdater');
+
+class BxEngUpdater extends BxDolStudioUpdater
+{
+    function __construct($aConfig)
+    {
+        parent::__construct($aConfig);
+    }
+}

+ 181 - 0
modules/boonex/english/updates/15.0.2_15.0.3/install/langs/en.xml

@@ -0,0 +1,181 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources name="en" flag="gb" title="English">
+	<string_add name="_Level"><![CDATA[Level]]></string_add>
+	<string_add name="_Logs"><![CDATA[Logs]]></string_add>
+	<string_add name="_adm_bp_dsc_block_description"><![CDATA[Short description for the block, visible in block header.]]></string_add>
+	<string_add name="_adm_bp_dsc_block_icon"><![CDATA[An icon (font icon, SVG or Emoji code) for the block, visible in block header.]]></string_add>
+	<string_add name="_adm_bp_txt_block_description"><![CDATA[Description]]></string_add>
+	<string_add name="_adm_bp_txt_block_icon"><![CDATA[Icon]]></string_add>
+	<string_add name="_adm_form_txt_field_checker_password"><![CDATA[Password (correct password format with regular expression)]]></string_add>
+	<string_add name="_adm_lmi_cpt_agents"><![CDATA[Agents]]></string_add>
+	<string_add name="_adm_lmi_cpt_ai_providers"><![CDATA[AI Providers]]></string_add>
+	<string_add name="_adm_lmi_cpt_tools"><![CDATA[Tools]]></string_add>
+	<string_add name="_adm_lmi_cpt_vector_store"><![CDATA[Vector Store]]></string_add>
+	<string_add name="_adm_pgt_btn_et_hf_editor"><![CDATA[Use visual editor]]></string_add>
+	<string_add name="_adm_prm_dsc_level_unavailable_to"><![CDATA[Select nothing if a level should be available to all profile types.]]></string_add>
+	<string_add name="_adm_prm_txt_level_unavailable_to"><![CDATA[Unavailable for]]></string_add>
+	<string_add name="_adm_stg_cpt_option_sys_account_welcome_letter"><![CDATA[Enable welcome letter]]></string_add>
+	<string_add name="_adm_stg_cpt_option_sys_embed_lifetime"><![CDATA[Generated embed lifetime in days (0 - do not track time)]]></string_add>
+	<string_add name="_adm_stg_cpt_option_sys_per_page_recommendations"><![CDATA[Browse Recommendations]]></string_add>
+	<string_add name="_adm_stg_inf_option_sys_per_page_recommendations"><![CDATA[Set the maximum number of results displayed per page]]></string_add>
+	<string_add name="_adm_stg_cpt_option_sys_per_page_recommendations_showcase"><![CDATA[Browse Recommendations in showcase view]]></string_add>
+	<string_add name="_adm_stg_inf_option_sys_per_page_recommendations_showcase"><![CDATA[Set the maximum number of results displayed per page in showcase view]]></string_add>
+	<string_add name="_adm_stg_cpt_option_sys_push_wonderpush_app_id"><![CDATA[WonderPush: App ID]]></string_add>
+	<string_add name="_adm_stg_cpt_option_sys_push_wonderpush_access_token"><![CDATA[WonderPush: Access Token]]></string_add>
+	<string_add name="_adm_stg_cpt_option_sys_push_wonderpush_web_key"><![CDATA[WonderPush: Web Key]]></string_add>
+	<string_add name="_adm_stg_cpt_option_sys_logs_level"><![CDATA[Log Level]]></string_add>
+	<string_add name="_adm_stg_cpt_option_sys_api_root_page_guest"><![CDATA[Root page for non-logged user]]></string_add>
+	<string_add name="_adm_stg_cpt_option_sys_api_root_page_member"><![CDATA[Root page for logged user]]></string_add>
+	<string_add name="_adm_stg_cpt_option_sys_api_root_page_home"><![CDATA[Home]]></string_add>
+	<string_add name="_adm_stg_cpt_option_sys_api_root_page_dashboard"><![CDATA[Dashboard]]></string_add>
+	<string_add name="_adm_stg_cpt_option_sys_api_root_page_profile"><![CDATA[Profile]]></string_add>
+	<string_add name="_adm_stg_cpt_option_sys_api_root_page_splash"><![CDATA[Splash]]></string_add>
+	<string_add name="_adm_stg_cpt_option_sys_agents_inspector_key"><![CDATA[Inspector key]]></string_add>
+	<string_add name="_adm_stg_cpt_option_sys_agents_inspector_key_info"><![CDATA[Get key at https://app.inspector.dev/]]></string_add>
+	<string_add name="_adm_stg_cpt_option_sys_std_pgt_etemplates_editor"><![CDATA[Studio Polyglot: Enable visual editor]]></string_add>
+	<string_add name="_adm_stg_cpt_option_sys_bg_jobs_process_per_run"><![CDATA[Background jobs: Number of jobs to process per run]]></string_add>
+	<string_add name="_adm_stg_cpt_option_sys_bg_jobs_workers_limit"><![CDATA[Background jobs: Max number of parallel workers]]></string_add>
+	<string_add name="_adm_stg_cpt_option_sys_bg_jobs_cleanup_timeout"><![CDATA[Background jobs: Cleanup jobs with errors after (in days)]]></string_add>
+	<string_add name="_sys_acl_downgrade"><![CDATA[Downgrade]]></string_add>
+	<string_add name="_sys_agents_form_field_err_profile_has_agent"><![CDATA[This profile is already used in another agent({0}) with the same 'message' trigger.]]></string_add>
+	<string_add name="_sys_agents_json_field_err"><![CDATA[Invalid JSON format.]]></string_add>
+	<string_add name="_sys_agents_agents_txt_name"><![CDATA[Name]]></string_add>
+	<string_add name="_sys_agents_agents_txt_trigger"><![CDATA[Trigger]]></string_add>
+	<string_add name="_sys_agents_agents_txt_profile_id"><![CDATA[Profile]]></string_add>
+	<string_add name="_sys_agents_agents_popup_add"><![CDATA[Add agent]]></string_add>
+	<string_add name="_Run"><![CDATA[Run]]></string_add>
+	<string_add name="_sys_agents_count_today"><![CDATA[{0} calls today]]></string_add>
+	<string_add name="_sys_agents_count_per_req"><![CDATA[{0} calls per request]]></string_add>
+	<string_add name="_sys_agents_field_async"><![CDATA[Delayed execution]]></string_add>
+	<string_add name="_sys_agents_field_async_inf"><![CDATA[Run agent later to not block/delay normal code execution. Not applicable for 'manual' and 'scheduler'. For 'alert' - overriding values will not work. For 'messenger' - messages will not appear automatically.]]></string_add>
+	<string_add name="_sys_agents_popup_edit"><![CDATA[Edit automator]]></string_add>
+	<string_add name="_sys_agents_field_name"><![CDATA[Name]]></string_add>
+	<string_add name="_sys_agents_field_name_info"><![CDATA[Uniq agent name]]></string_add>
+	<string_add name="_sys_agents_field_model_id"><![CDATA[Model]]></string_add>
+	<string_add name="_sys_agents_field_model_id_info"><![CDATA[AI model to use for this agent.]]></string_add>
+	<string_add name="_sys_agents_field_profile_id"><![CDATA[Profile]]></string_add>
+	<string_add name="_sys_agents_field_profile_id_inf"><![CDATA[AI agent will perform actions under this profile]]></string_add>
+	<string_add name="_sys_agents_field_trigger"><![CDATA[Trigger]]></string_add>
+	<string_add name="_sys_agents_field_trigger_info"><![CDATA[Trigger which will initiate agent to run. Alert — system event notification. Scheduler — time-based scheduled execution. Webhook — external HTTP trigger. Manual — user-initiated run. Agent — triggered by another agent. Message — triggered by chat message.]]></string_add>
+	<string_add name="_sys_agents_field_alert_sample"><![CDATA[Alert: payload]]></string_add>
+	<string_add name="_sys_agents_waiting_for_sample_data_alert"><![CDATA[Please select an alert to see its payload.]]></string_add>
+	<string_add name="_sys_agents_waiting_for_sample_data_webhook"><![CDATA[Trigger webhook to see its payload.]]></string_add>
+	<string_add name="_sys_agents_field_alert"><![CDATA[Alert: event name]]></string_add>
+	<string_add name="_sys_agents_field_alert_info"><![CDATA[Event that triggers the agent. Usually starts with system or module_name. Only events that have occurred at least once are shown.]]></string_add>
+	<string_add name="_sys_agents_field_scheduler_cron"><![CDATA[Scheduler (CRON)]]></string_add>
+	<string_add name="_sys_agents_field_scheduler_cron_info"><![CDATA[CRON expression for scheduling the agent.]]></string_add>
+	<string_add name="_sys_agents_field_webhook_key"><![CDATA[Webhook: key]]></string_add>
+	<string_add name="_sys_agents_field_webhook_key_info"><![CDATA[Unique key for webhook endpoint, used as Bearer Authentication header.]]></string_add>
+	<string_add name="_sys_agents_field_webhook_sample"><![CDATA[Webhook: sample payload]]></string_add>
+	<string_add name="_sys_agents_field_message_profile"><![CDATA[Message: profile for communication with agent]]></string_add>
+	<string_add name="_sys_agents_field_message_profile_info"><![CDATA[Profile to use for sending messages to the agent, messages from other users are ignored.]]></string_add>
+	<string_add name="_sys_agents_field_vector_store_id"><![CDATA[Knowledge]]></string_add>
+	<string_add name="_sys_agents_field_vector_store_id_info"><![CDATA[Vector store for knowledge retrieval.]]></string_add>
+	<string_add name="_sys_agents_field_tools"><![CDATA[Tools]]></string_add>
+	<string_add name="_sys_agents_field_tools_info"><![CDATA[Tools available for the agent to use.]]></string_add>
+	<string_add name="_sys_agents_field_tools_max_run"><![CDATA[Max tool calls]]></string_add>
+	<string_add name="_sys_agents_field_tools_max_run_info"><![CDATA[Limits how many times the AI can call external tools (such as search or actions) while completing a task. Higher values may increase execution time.]]></string_add>
+	<string_add name="_sys_agents_field_prompt_system"><![CDATA[System Prompt]]></string_add>
+	<string_add name="_sys_agents_field_prompt_system_info"><![CDATA[System prompt for the agent.]]></string_add>
+	<string_add name="_sys_agents_field_prompt_steps"><![CDATA[Steps Prompt]]></string_add>
+	<string_add name="_sys_agents_field_prompt_steps_info"><![CDATA[Instructions for executing agent steps.]]></string_add>
+	<string_add name="_sys_agents_field_prompt_output"><![CDATA[Output Prompt]]></string_add>
+	<string_add name="_sys_agents_field_prompt_output_info"><![CDATA[Instructions for formatting the output.]]></string_add>
+	<string_add name="_sys_agents_field_prompt_tools"><![CDATA[Tools Prompt]]></string_add>
+	<string_add name="_sys_agents_field_prompt_tools_info"><![CDATA[Instructions for using available tools.]]></string_add>
+	<string_add name="_sys_agents_tools_popup_edit"><![CDATA[Edit tool]]></string_add>
+	<string_add name="_sys_agents_field_title"><![CDATA[Title]]></string_add>
+	<string_add name="_sys_agents_tools_field_params"><![CDATA[Parameters]]></string_add>
+	<string_add name="_sys_agents_tools_field_params_info"><![CDATA[Parameters for configuring the tool, specific to each tool]]></string_add>
+	<string_add name="_sys_agents_field_chat_history_context"><![CDATA[Chat history context window]]></string_add>
+	<string_add name="_sys_agents_field_chat_history_context_info"><![CDATA[Automatically cut the conversation history based on the size of the context window, set to '0' to disable chat history]]></string_add>
+	<string_add name="_sys_agents_models_txt_active"><![CDATA[Active]]></string_add>
+	<string_add name="_sys_agents_models_txt_name"><![CDATA[Name]]></string_add>
+	<string_add name="_sys_agents_models_txt_title"><![CDATA[Title]]></string_add>
+	<string_add name="_sys_agents_models_txt_key"><![CDATA[API Key]]></string_add>
+	<string_add name="_sys_agents_models_txt_params"><![CDATA[Parameters]]></string_add>
+	<string_add name="_sys_agents_models_txt_added"><![CDATA[Added]]></string_add>
+	<string_add name="_sys_agents_models_txt_capabilities"><![CDATA[Capabilities]]></string_add>
+	<string_add name="_sys_agents_models_txt_model"><![CDATA[Model]]></string_add>
+	<string_add name="_sys_agents_models_btn_add"><![CDATA[Add AI Provider]]></string_add>
+	<string_add name="_sys_agents_models_popup_edit"><![CDATA[Edit AI provider]]></string_add>
+	<string_add name="_sys_agents_models_field_title"><![CDATA[Title]]></string_add>
+	<string_add name="_sys_agents_models_field_title_info"><![CDATA[Display name for the AI provider.]]></string_add>
+	<string_add name="_sys_agents_models_field_model"><![CDATA[Model]]></string_add>
+	<string_add name="_sys_agents_models_field_model_info"><![CDATA[Model identifier used by the provider.]]></string_add>
+	<string_add name="_sys_agents_models_field_key"><![CDATA[API Key]]></string_add>
+	<string_add name="_sys_agents_models_field_key_info"><![CDATA[API key to authenticate with the provider.]]></string_add>
+	<string_add name="_sys_agents_models_field_params"><![CDATA[Parameters]]></string_add>
+	<string_add name="_sys_agents_models_field_params_info"><![CDATA[Additional configuration parameters in JSON format.]]></string_add>
+	<string_add name="_Duplicate"><![CDATA[Duplicate]]></string_add>
+	<string_add name="_sys_agents_vector_store_txt_embedding_provider"><![CDATA[Embedder]]></string_add>
+	<string_add name="_sys_agents_vector_store_txt_files_num"><![CDATA[Files]]></string_add>
+	<string_add name="_sys_agents_vector_store_popup_files"><![CDATA[Files]]></string_add>
+	<string_add name="_sys_agents_vector_store_popup_edit"><![CDATA[Edit vector store]]></string_add>
+	<string_add name="_sys_agents_vector_store_field_embedding_provider_id"><![CDATA[Embedding Provider]]></string_add>
+	<string_add name="_sys_agents_vector_store_field_embedding_provider_id_info"><![CDATA[Select the embedding provider for this vector store.]]></string_add>
+	<string_add name="_sys_agents_vector_store_field_topk"><![CDATA[Top K Results]]></string_add>
+	<string_add name="_sys_agents_vector_store_field_topk_info"><![CDATA[Number of top results to return from similarity search.]]></string_add>
+	<string_add name="_sys_agents_vector_store_field_params"><![CDATA[Parameters]]></string_add>
+	<string_add name="_sys_agents_vector_store_field_params_info"><![CDATA[Additional parameters in JSON format.]]></string_add>
+	<string_add name="_sys_agents_vector_store_popup_add_data"><![CDATA[Upload new files]]></string_add>
+	<string_add name="_sys_agents_vector_store_field_chunk_size"><![CDATA[Chunk Size]]></string_add>
+	<string_add name="_sys_agents_vector_store_field_chunk_size_info"><![CDATA[Number of characters in text chunks for embedding.]]></string_add>
+	<string_add name="_sys_agents_vector_store_field_delimeter"><![CDATA[Delimiter]]></string_add>
+	<string_add name="_sys_agents_vector_store_field_delimeter_info"><![CDATA[Character or sequence to split text into chunks.]]></string_add>
+	<string_add name="_sys_agents_vector_store_field_overlap"><![CDATA[Chunk Overlap]]></string_add>
+	<string_add name="_sys_agents_vector_store_field_overlap_info"><![CDATA[Number of overlapping elements between adjacent chunks, determined by the delimeter, for dot - it's bumber of sentences, for space - it's number of words.]]></string_add>
+	<string_add name="_sys_agents_vector_store_field_metadata"><![CDATA[Metadata]]></string_add>
+	<string_add name="_sys_agents_vector_store_field_metadata_info"><![CDATA[Additional metadata in JSON format for each chunk.]]></string_add>
+	<string_add name="_sys_agents_vector_store_field_files"><![CDATA[Files]]></string_add>
+	<string_add name="_sys_agents_vector_store_field_files_info"><![CDATA[Data files to upload to the vector store.]]></string_add>
+	<string_add name="_sys_agents_vector_store_data_queued"><![CDATA[Data queued for vector store processing]]></string_add>
+	<string_add name="_sys_agents_assistants_chat_dsc_studio"><![CDATA[Studio assistant]]></string_add>
+	<string_add name="_sys_agents_assistants_chat_dsc_block"><![CDATA['Ask AI' assistant]]></string_add>
+	<string_add name="_sys_agents_assistants_chat_dsc_live_search"><![CDATA[Live search assistant]]></string_add>
+	<string_add name="_sys_agents_agents_act_wipe_chat_history"><![CDATA[Wipe chat history]]></string_add>
+	<string_add name="_sys_agents_logs_popup"><![CDATA["{0}" agent logs]]></string_add>
+	<string_add name="_sys_agents_exception"><![CDATA[The AI encountered an error while completing your request. Please try again or rephrase your input.]]></string_add>
+	<string_add name="_sys_agents_agents_popup_edit"><![CDATA[Edit "{0}" agent]]></string_add>
+	<string_add name="_sys_conn_friends_done_initiator"><![CDATA[Request sent]]></string_add>
+	<string_add name="_sys_conn_friends_done_initiator_mutual"><![CDATA[Friends]]></string_add>
+	<string_add name="_sys_et_txt_body_welcome"><![CDATA[{email_header}
+<p>Hello {name},</p>
+<p>You are welcome to {site_name}</p>
+<p> </p>
+<p>You've confirmed your profile and is ready to use our site.</p>
+<p>Feel free to contact us if you need some help.</p>
+<p> </p>
+{email_footer}]]></string_add>
+	<string_add name="_sys_et_txt_name_system_welcome"><![CDATA[Welcome message]]></string_add>
+	<string_add name="_sys_et_txt_subject_welcome"><![CDATA[You are welcome to {site_name}]]></string_add>
+	<string_add name="_sys_form_input_textarea_editor"><![CDATA[Editor:]]></string_add>
+	<string_add name="_sys_skip_to_main_content"><![CDATA[Skip to main content]]></string_add>
+	<string_add name="_sys_txt_agent_inactive"><![CDATA[Agent isn't activated]]></string_add>
+
+	<string_upd name="_adm_bp_dsc_page_title"><![CDATA[This name is displayed in page header. Use at least 3 characters.]]></string_upd>
+	<string_upd name="_adm_bp_dsc_page_title_system"><![CDATA[This name is displayed in Studio only.]]></string_upd>
+	<string_upd name="_adm_bp_txt_block_title"><![CDATA[Display Name]]></string_upd>
+	<string_upd name="_adm_bp_txt_page_title"><![CDATA[Display Name]]></string_upd>
+	<string_upd name="_adm_form_dsc_field_caption"><![CDATA[This name is displayed on site.]]></string_upd>
+	<string_upd name="_adm_form_dsc_field_caption_system"><![CDATA[This name is displayed in Studio only.]]></string_upd>
+	<string_upd name="_adm_form_txt_field_caption"><![CDATA[Display Name]]></string_upd>
+	<string_upd name="_adm_form_txt_field_caption_system"><![CDATA[System Name]]></string_upd>
+	<string_upd name="_adm_form_txt_field_name"><![CDATA[Identifier]]></string_upd>
+	<string_upd name="_adm_nav_txt_items_title"><![CDATA[Display Name]]></string_upd>
+	<string_upd name="_adm_nav_txt_menus_title_public"><![CDATA[Display Name]]></string_upd>
+	<string_upd name="_adm_stg_cpt_category_agents_usage"><![CDATA[Assistants]]></string_upd>
+
+	<string_del name="_adm_stg_cpt_option_sys_account_activation_letter"><![CDATA[Enable account activation letter]]></string_del>
+	<string_del name="_adm_stg_inf_option_sys_embed_microlink_key"><![CDATA[Leave empty to use in Free mode.]]></string_del>
+	<string_del name="_adm_stg_cpt_option_sys_agents_api_key"><![CDATA[Default API key]]></string_del>
+	<string_del name="_adm_stg_cpt_option_sys_agents_model"><![CDATA[Default model]]></string_del>
+	<string_del name="_adm_stg_cpt_option_sys_agents_profile"><![CDATA[Profile]]></string_del>
+	<string_del name="_sys_agents_automators_popup_edit"><![CDATA[Edit automator]]></string_del>
+	<string_del name="_sys_agents_automators_field_name"><![CDATA[Name]]></string_del>
+	<string_del name="_sys_agents_automators_field_model_id"><![CDATA[Model]]></string_del>
+	<string_del name="_sys_agents_automators_field_alert_unit"><![CDATA[Event Type]]></string_del>
+	<string_del name="_sys_agents_automators_field_alert_action"><![CDATA[Event Action]]></string_del>
+	<string_del name="_sys_agents_automators_field_scheduler_time"><![CDATA[Scheduler Time]]></string_del>
+	<string_del name="_sys_conn_friends_do_initiator"><![CDATA[Friends]]></string_del>
+</resources>

+ 4486 - 0
modules/boonex/english/updates/15.0.2_15.0.3/source/data/langs/system/en.xml

@@ -0,0 +1,4486 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources name="en" flag="en" title="English">
+    <string name="_api_create_context"><![CDATA[Create {0}]]></string>
+    <string name="_ADM_PROFILE_SEND_MSG"><![CDATA[Message was successfully sent.]]></string>
+    <string name="_ATT_ACTIVE_E"><![CDATA[You are a full-featured member of our community. You can, however, suspend your profile to become temporarily unavailable for others.]]></string>
+    <string name="_ATT_APPROVAL_E"><![CDATA[Your profile activation is in progress. Usually it takes up to 24 hours. Thank you for your patience.]]></string>
+    <string name="_ATT_REJECTED_E"><![CDATA[Your profile was rejected by the system administrator because it contains illegal information or is missing some information. If you have any questions, please, <a target=_blank href="contact.php">contact us</a>, and don't forget to specify your profile ID.]]></string>
+    <string name="_ATT_SUSPENDED_E"><![CDATA[Your profile is temporarily out of {0} system services. You can activate it <a target=_blank href="change_status.php">here</a>. If you have any questions, please <a target=_blank href="contact.php">contact the administrators</a>.]]></string>
+    <string name="_ATT_UNCONFIRMED_E"><![CDATA[You will need to follow the link supplied in the e-mail to get your account submitted for approval. <br />Send me <a target=_blank href="activation_email.php">confirmation e-mail</a>.]]></string>
+    <string name="_Access denied"><![CDATA[Access denied]]></string>
+    <string name="_access_denied_page_title"><![CDATA[Page Not Available]]></string>
+    <string name="_access_denied_page_content"><![CDATA[Sorry, this content is no longer available. It may have been removed or is not accessible due to violation of our terms of service.]]></string>
+    <string name="_Action"><![CDATA[Action]]></string>
+    <string name="_all"><![CDATA[All]]></string>
+    <string name="_Allowed Since"><![CDATA[Allowed Since]]></string>
+    <string name="_Allowed Until"><![CDATA[Allowed Until]]></string>
+    <string name="_Allowed actions"><![CDATA[Allowed actions]]></string>
+    <string name="_anonymous"><![CDATA[anonymous]]></string>
+    <string name="_anonymous_f"><![CDATA[anonymous ({0})]]></string>
+        <string name="_Apply"><![CDATA[Apply]]></string>
+        <string name="_apps"><![CDATA[Apps]]></string>
+	<string name="_Are_you_sure"><![CDATA[Are you sure?]]></string>
+	<string name="_Auth type"><![CDATA[Auth type]]></string>
+        <string name="_by_author"><![CDATA[by]]></string>
+	<string name="_Basic"><![CDATA[Basic]]></string>
+	<string name="_CONTACT_H"><![CDATA[Contact us]]></string>
+	<string name="_CONTACT_H1"><![CDATA[Contact]]></string>
+	<string name="_Can not delete comments with replies"><![CDATA[Cannot delete comments with replies]]></string>
+	<string name="_Cancel"><![CDATA[Cancel]]></string>
+	<string name="_Content"><![CDATA[Content]]></string>
+        <string name="_Contents"><![CDATA[Contents]]></string>
+        <string name="_Context"><![CDATA[Context]]></string>
+	<string name="_Count"><![CDATA[Count]]></string>
+	<string name="_DELETE_SUCCESS"><![CDATA[You account was successfully deleted]]></string>
+	<string name="_DELETE_TEXT"><![CDATA[All your content will be deleted. Are you sure you want to delete your account?]]></string>
+	<string name="_Date"><![CDATA[Date]]></string>
+	<string name="_Delete"><![CDATA[Delete]]></string>
+	<string name="_Delete account"><![CDATA[Delete account]]></string>
+	<string name="_Description"><![CDATA[Description]]></string>
+	<string name="_EXPLANATION_H"><![CDATA[Explanation]]></string>
+	<string name="_Edit"><![CDATA[Edit]]></string>
+	<string name="_Email"><![CDATA[Email]]></string>
+	<string name="_Email sent failed"><![CDATA[Email send failed]]></string>
+	<string name="_Empty"><![CDATA[Empty]]></string>
+	<string name="_Enter_value_here"><![CDATA[Please, enter a value here]]></string>
+	<string name="_Error"><![CDATA[Error]]></string>
+	<string name="_Failed"><![CDATA[Failed]]></string>
+	<string name="_favorite_counter"><![CDATA[{0}]]></string>
+	<string name="_favorite_do_favorite"><![CDATA[Favorite]]></string>
+	<string name="_favorite_do_unfavorite"><![CDATA[Unfavorite]]></string>
+	<string name="_favorite_do_favorite_by"><![CDATA[Favorited by]]></string>
+	<string name="_favorite_err_cannot_perform_action"><![CDATA[Cannot perform the action.]]></string>
+	<string name="_favorite_err_duplicate_favorite"><![CDATA[You already favorited this item.]]></string>
+	<string name="_favorite_err_not_enabled"><![CDATA[The feature is not available right now. Please, try again later.]]></string>
+	<string name="_feature_do_feature"><![CDATA[Feature]]></string>
+        <string name="_feature_do_unfeature"><![CDATA[Unfeature]]></string>
+        <string name="_feature_err_cannot_perform_action"><![CDATA[Cannot perform the action.]]></string>
+        <string name="_feature_err_duplicate_feature"><![CDATA[The item was already added in featured list.]]></string>
+        <string name="_feature_err_not_enabled"><![CDATA[The feature is not available right now. Please, try again later.]]></string>
+	<string name="_Female"><![CDATA[Woman]]></string>
+        <string name="_free"><![CDATA[free]]></string>
+	<string name="_From"><![CDATA[From]]></string>
+        <string name="_Filters"><![CDATA[Filters]]></string>
+	<string name="_Header"><![CDATA[Header]]></string>
+	<string name="_Incorrect Captcha"><![CDATA[Incorrect Captcha]]></string>
+	<string name="_Incorrect Email"><![CDATA[Incorrect Email]]></string>
+	<string name="_Info"><![CDATA[Info]]></string>
+	<string name="_Keyword"><![CDATA[Keyword]]></string>
+	<string name="_Level"><![CDATA[Level]]></string>
+        <string name="_lifetime"><![CDATA[lifetime]]></string>
+        <string name="_Logs"><![CDATA[Logs]]></string>
+	<string name="_LookinFemale"><![CDATA[Woman]]></string>
+	<string name="_LookinMale"><![CDATA[Man]]></string>
+	<string name="_MEMBERSHIP_EXPIRES_IN_DAYS"><![CDATA[expires: in {0} day(s)]]></string>
+	<string name="_MEMBERSHIP_EXPIRES_NEVER"><![CDATA[expires: never]]></string>
+	<string name="_MEMBERSHIP_EXPIRES_TODAY"><![CDATA[expires: today at {0}. (Server time: {1})]]></string>
+	<string name="_MEMBERSHIP_STANDARD"><![CDATA[You are a standard member.]]></string>
+	<string name="_MEMBERSHIP_UPGRADE_FROM_STANDARD"><![CDATA[]]></string>
+	<string name="_Male"><![CDATA[Man]]></string>
+	<string name="_Manage"><![CDATA[Manage]]></string>
+	<string name="_Member"><![CDATA[Member]]></string>
+	<string name="_Member Login"><![CDATA[Login]]></string>
+	<string name="_Message text"><![CDATA[Message text]]></string>
+	<string name="_N_point"><![CDATA[<span>{0}</span> plus]]></string>
+	<string name="_N_points"><![CDATA[<span>{0}</span> pluses]]></string>
+	<string name="_Name"><![CDATA[Name]]></string>
+	<string name="_Name is required"><![CDATA[Name is required]]></string>
+        <string name="_never"><![CDATA[never]]></string>
+	<string name="_No"><![CDATA[No]]></string>
+	<string name="_None"><![CDATA[None]]></string>
+	<string name="_No actions allowed for this membership"><![CDATA[No actions allowed for this membership]]></string>
+	<string name="_No such comment"><![CDATA[No such comment]]></string>
+	<string name="_Ok"><![CDATA[OK]]></string>
+        <string name="_order_asc"><![CDATA[asc]]></string>
+        <string name="_order_desc"><![CDATA[desc]]></string>
+	<string name="_Period"><![CDATA[Period]]></string>
+	<string name="_Please Wait"><![CDATA[Please Wait]]></string>
+	<string name="_Please enter n1-n2 characters"><![CDATA[Please enter {0}-{1} characters]]></string>
+        <string name="_Please enter characters"><![CDATA[Please enter some number of characters]]></string>
+	<string name="_Please select value"><![CDATA[Please select a value from the list]]></string>
+        <string name="_polls_from"><![CDATA[Polls from: {0}]]></string>
+	<string name="_Preview"><![CDATA[Preview]]></string>
+        <string name="_price_recurring"><![CDATA[{0}/{1}]]></string>
+	<string name="_price_single"><![CDATA[{0}]]></string>
+        <string name="_report_comment"><![CDATA[reported as '{0}']]></string>
+        <string name="_report_comment_with_note"><![CDATA[reported as '{0}' with a note: {1}]]></string>
+        <string name="_report_comment_check_in"><![CDATA[check-in]]></string>
+        <string name="_report_comment_check_out"><![CDATA[check-out]]></string>
+        <string name="_report_status_new"><![CDATA[New]]></string>
+        <string name="_report_status_check_in"><![CDATA[In process]]></string>
+        <string name="_report_status_check_out"><![CDATA[Processed]]></string>
+        <string name="_report_status_all"><![CDATA[All]]></string>
+	<string name="_report_counter"><![CDATA[{0}]]></string>
+        <string name="_report_n_reports"><![CDATA[{0} reports]]></string>
+	<string name="_report_do_report"><![CDATA[Report]]></string>
+        <string name="_report_do_report_with_sample"><![CDATA[Report {0}]]></string>
+        <string name="_report_do_unreport"><![CDATA[Cancel report]]></string>
+        <string name="_report_do_unreport_confirm"><![CDATA[Are you sure, you want to cancel your report?]]></string>
+	<string name="_report_do_report_by"><![CDATA[Reported by]]></string>
+	<string name="_report_err_cannot_perform_action"><![CDATA[Cannot perform action.]]></string>
+	<string name="_report_err_duplicate_report"><![CDATA[You already reported this item.]]></string>
+	<string name="_report_err_not_enabled"><![CDATA[The feature is not available right now. Please, try again later.]]></string>
+	<string name="_report_err_wrong_type"><![CDATA[Wrong report type.]]></string>
+	<string name="_report_reported_as"><![CDATA[Reported as ]]></string>
+        <string name="_report_reported_by"><![CDATA[Reported by ]]></string>
+        <string name="_report_comments_count"><![CDATA[Comments ({0})]]></string>
+	<string name="_RSS_Feed_Title_Common"><![CDATA[{0} RSS]]></string>
+	<string name="_RSS_Feed_Title_Profile"><![CDATA[{0}'s Recent {1}]]></string>
+	<string name="_Rate"><![CDATA[Rate]]></string>
+	<string name="_Read"><![CDATA[Read]]></string>
+	<string name="_Read more"><![CDATA[Read more]]></string>
+	<string name="_Reset"><![CDATA[Reset]]></string>
+	<string name="_Search"><![CDATA[Search]]></string>
+  <string name="_search_in_all_section"><![CDATA[Search in all sections]]></string>
+  <string name="_Section"><![CDATA[Section]]></string>
+	<string name="_Select_one"><![CDATA[Select one...]]></string>
+	<string name="_Select_all"><![CDATA[Select all]]></string>
+	<string name="_Show"><![CDATA[Show]]></string>
+	<string name="_Sorry, your IP been banned"><![CDATA[Sorry, your IP has been banned]]></string>
+	<string name="_Subject"><![CDATA[Subject]]></string>
+	<string name="_Submit"><![CDATA[Submit]]></string>
+	<string name="_Success"><![CDATA[Success]]></string>
+	<string name="_Times allowed"><![CDATA[Times allowed]]></string>
+	<string name="_Title"><![CDATA[Title]]></string>
+	<string name="_To"><![CDATA[to]]></string>
+        <string name="_unlimited"><![CDATA[unlimited]]></string>
+	<string name="_VIEW_MEMBERSHIP_ACTIONS"><![CDATA[View Allowed Actions]]></string>
+	<string name="_View"><![CDATA[View]]></string>
+        <string name="_View_and_Join"><![CDATA[View & Join]]></string>
+	<string name="_Yes"><![CDATA[Yes]]></string>
+	<string name="_Your email"><![CDATA[Your email]]></string>
+	<string name="_Your name"><![CDATA[Your name]]></string>
+	<string name="__Afghanistan"><![CDATA[Afghanistan]]></string>
+	<string name="__Afrikaans"><![CDATA[Afrikaans]]></string>
+	<string name="__Aland_Islands"><![CDATA[Aland Islands]]></string>
+	<string name="__Albania"><![CDATA[Albania]]></string>
+	<string name="__Algeria"><![CDATA[Algeria]]></string>
+	<string name="__American Samoa"><![CDATA[American Samoa]]></string>
+	<string name="__Andorra"><![CDATA[Andorra]]></string>
+	<string name="__Angola"><![CDATA[Angola]]></string>
+	<string name="__Anguilla"><![CDATA[Anguilla]]></string>
+	<string name="__Antarctica"><![CDATA[Antarctica]]></string>
+	<string name="__Antigua and Barbuda"><![CDATA[Antigua and Barbuda]]></string>
+	<string name="__Arabic"><![CDATA[Arabic]]></string>
+	<string name="__Argentina"><![CDATA[Argentina]]></string>
+	<string name="__Armenia"><![CDATA[Armenia]]></string>
+	<string name="__Aruba"><![CDATA[Aruba]]></string>
+	<string name="__Australia"><![CDATA[Australia]]></string>
+	<string name="__Austria"><![CDATA[Austria]]></string>
+	<string name="__Azerbaijan"><![CDATA[Azerbaijan]]></string>
+	<string name="__Bahrain"><![CDATA[Bahrain]]></string>
+	<string name="__Bangladesh"><![CDATA[Bangladesh]]></string>
+	<string name="__Barbados"><![CDATA[Barbados]]></string>
+	<string name="__Belarus"><![CDATA[Belarus]]></string>
+	<string name="__Belgium"><![CDATA[Belgium]]></string>
+	<string name="__Belize"><![CDATA[Belize]]></string>
+	<string name="__Benin"><![CDATA[Benin]]></string>
+	<string name="__Bermuda"><![CDATA[Bermuda]]></string>
+	<string name="__Bhutan"><![CDATA[Bhutan]]></string>
+	<string name="__Bolivia"><![CDATA[Bolivia]]></string>
+	<string name="__Bosnia and Herzegovina"><![CDATA[Bosnia and Herzegovina]]></string>
+	<string name="__Botswana"><![CDATA[Botswana]]></string>
+	<string name="__Bouvet Island"><![CDATA[Bouvet Island]]></string>
+	<string name="__Brazil"><![CDATA[Brazil]]></string>
+	<string name="__British Indian Ocean Territory"><![CDATA[British Indian Ocean Territory]]></string>
+	<string name="__British Virgin Islands"><![CDATA[British Virgin Islands]]></string>
+	<string name="__Brunei Darussalam"><![CDATA[Brunei]]></string>
+	<string name="__Bulgaria"><![CDATA[Bulgaria]]></string>
+	<string name="__Bulgarian"><![CDATA[Bulgarian]]></string>
+	<string name="__Burkina Faso"><![CDATA[Burkina Faso]]></string>
+	<string name="__Burma"><![CDATA[Burma]]></string>
+	<string name="__Burmese"><![CDATA[Burmese]]></string>
+	<string name="__Burundi"><![CDATA[Burundi]]></string>
+	<string name="__Cambodia"><![CDATA[Cambodia]]></string>
+	<string name="__Cameroon"><![CDATA[Cameroon]]></string>
+	<string name="__Canada"><![CDATA[Canada]]></string>
+	<string name="__Cantonese"><![CDATA[Cantonese]]></string>
+	<string name="__Cape Verde"><![CDATA[Cape Verde]]></string>
+	<string name="__Cayman Islands"><![CDATA[Cayman Islands]]></string>
+	<string name="__Central African Republic"><![CDATA[Central African Republic]]></string>
+	<string name="__Chad"><![CDATA[Chad]]></string>
+	<string name="__Chile"><![CDATA[Chile]]></string>
+	<string name="__China"><![CDATA[China]]></string>
+	<string name="__Christmas Island"><![CDATA[Christmas Island]]></string>
+	<string name="__Cocos (Keeling) Islands"><![CDATA[Cocos (Keeling) Islands]]></string>
+	<string name="__Colombia"><![CDATA[Colombia]]></string>
+	<string name="__Comoros"><![CDATA[Comoros]]></string>
+	<string name="__Congo, Democratic Republic of the"><![CDATA[Congo, Democratic Republic of the]]></string>
+	<string name="__Congo, Republic of the"><![CDATA[Congo, Republic of the]]></string>
+	<string name="__Cook Islands"><![CDATA[Cook Islands]]></string>
+	<string name="__Costa Rica"><![CDATA[Costa Rica]]></string>
+	<string name="__Cote d'Ivoire"><![CDATA[Cote d'Ivoire]]></string>
+	<string name="__Croatia"><![CDATA[Croatia]]></string>
+	<string name="__Croatian"><![CDATA[Croatian]]></string>
+	<string name="__Cuba"><![CDATA[Cuba]]></string>
+	<string name="__Cyprus"><![CDATA[Cyprus]]></string>
+	<string name="__Czech Republic"><![CDATA[Czech Republic]]></string>
+	<string name="__Danish"><![CDATA[Danish]]></string>
+	<string name="__Denmark"><![CDATA[Denmark]]></string>
+	<string name="__Djibouti"><![CDATA[Djibouti]]></string>
+	<string name="__Dominica"><![CDATA[Dominica]]></string>
+	<string name="__Dominican Republic"><![CDATA[Dominican Republic]]></string>
+	<string name="__Dutch"><![CDATA[Dutch]]></string>
+	<string name="__East Timor"><![CDATA[East Timor]]></string>
+	<string name="__Ecuador"><![CDATA[Ecuador]]></string>
+	<string name="__Egypt"><![CDATA[Egypt]]></string>
+	<string name="__El Salvador"><![CDATA[El Salvador]]></string>
+	<string name="__English"><![CDATA[English]]></string>
+	<string name="__Equatorial Guinea"><![CDATA[Equatorial Guinea]]></string>
+	<string name="__Eritrea"><![CDATA[Eritrea]]></string>
+	<string name="__Esperanto"><![CDATA[Esperanto]]></string>
+	<string name="__Estonia"><![CDATA[Estonia]]></string>
+	<string name="__Estonian"><![CDATA[Estonian]]></string>
+	<string name="__Ethiopia"><![CDATA[Ethiopia]]></string>
+	<string name="__Falkland Islands (Islas Malvinas)"><![CDATA[Falkland Islands (Islas Malvinas)]]></string>
+	<string name="__Faroe Islands"><![CDATA[Faroe Islands]]></string>
+	<string name="__Fiji"><![CDATA[Fiji]]></string>
+	<string name="__Finland"><![CDATA[Finland]]></string>
+	<string name="__Finnish"><![CDATA[Finnish]]></string>
+	<string name="__France"><![CDATA[France]]></string>
+	<string name="__French"><![CDATA[French]]></string>
+	<string name="__French Guiana"><![CDATA[French Guiana]]></string>
+	<string name="__French Polynesia"><![CDATA[French Polynesia]]></string>
+	<string name="__French Southern and Antarctic Lands"><![CDATA[French Southern and Antarctic Lands]]></string>
+	<string name="__Gabon"><![CDATA[Gabon]]></string>
+	<string name="__Georgia"><![CDATA[Georgia]]></string>
+	<string name="__German"><![CDATA[German]]></string>
+	<string name="__Germany"><![CDATA[Germany]]></string>
+	<string name="__Ghana"><![CDATA[Ghana]]></string>
+	<string name="__Gibraltar"><![CDATA[Gibraltar]]></string>
+	<string name="__Greece"><![CDATA[Greece]]></string>
+	<string name="__Greek"><![CDATA[Greek]]></string>
+	<string name="__Greenland"><![CDATA[Greenland]]></string>
+	<string name="__Grenada"><![CDATA[Grenada]]></string>
+	<string name="__Guadeloupe"><![CDATA[Guadeloupe]]></string>
+	<string name="__Guam"><![CDATA[Guam]]></string>
+	<string name="__Guatemala"><![CDATA[Guatemala]]></string>
+	<string name="__Guernsey"><![CDATA[Guernsey]]></string>
+	<string name="__Guinea"><![CDATA[Guinea]]></string>
+	<string name="__Guinea-Bissau"><![CDATA[Guinea-Bissau]]></string>
+	<string name="__Gujrati"><![CDATA[Gujrati]]></string>
+	<string name="__Guyana"><![CDATA[Guyana]]></string>
+	<string name="__Haiti"><![CDATA[Haiti]]></string>
+	<string name="__Heard Island and McDonald Islands"><![CDATA[Heard Island and McDonald Islands]]></string>
+	<string name="__Hebrew"><![CDATA[Hebrew]]></string>
+	<string name="__Hindi"><![CDATA[Hindi]]></string>
+	<string name="__Holy See (Vatican City)"><![CDATA[Holy See (Vatican City)]]></string>
+	<string name="__Honduras"><![CDATA[Honduras]]></string>
+	<string name="__Hong Kong (SAR)"><![CDATA[Hong Kong (SAR)]]></string>
+	<string name="__Hungarian"><![CDATA[Hungarian]]></string>
+	<string name="__Hungary"><![CDATA[Hungary]]></string>
+	<string name="__Iceland"><![CDATA[Iceland]]></string>
+	<string name="__Icelandic"><![CDATA[Icelandic]]></string>
+	<string name="__India"><![CDATA[India]]></string>
+	<string name="__Indonesia"><![CDATA[Indonesia]]></string>
+	<string name="__Indonesian"><![CDATA[Indonesian]]></string>
+	<string name="__Iran"><![CDATA[Iran]]></string>
+	<string name="__Iraq"><![CDATA[Iraq]]></string>
+	<string name="__Ireland"><![CDATA[Ireland]]></string>
+	<string name="__Isle_of_Man"><![CDATA[Isle of Man]]></string>
+	<string name="__Israel"><![CDATA[Israel]]></string>
+	<string name="__Italian"><![CDATA[Italian]]></string>
+	<string name="__Italy"><![CDATA[Italy]]></string>
+	<string name="__Jamaica"><![CDATA[Jamaica]]></string>
+	<string name="__Japan"><![CDATA[Japan]]></string>
+	<string name="__Japanese"><![CDATA[Japanese]]></string>
+	<string name="__Jersey"><![CDATA[Jersey]]></string>
+	<string name="__Jordan"><![CDATA[Jordan]]></string>
+	<string name="__Kazakhstan"><![CDATA[Kazakhstan]]></string>
+	<string name="__Kenya"><![CDATA[Kenya]]></string>
+	<string name="__Kiribati"><![CDATA[Kiribati]]></string>
+	<string name="__Korea, North"><![CDATA[Korea, North]]></string>
+	<string name="__Korea, South"><![CDATA[Korea, South]]></string>
+	<string name="__Korean"><![CDATA[Korean]]></string>
+	<string name="__Kuwait"><![CDATA[Kuwait]]></string>
+	<string name="__Kyrgyzstan"><![CDATA[Kyrgyzstan]]></string>
+	<string name="__Laos"><![CDATA[Laos]]></string>
+	<string name="__Latvia"><![CDATA[Latvia]]></string>
+	<string name="__Latvian"><![CDATA[Latvian]]></string>
+	<string name="__Lebanon"><![CDATA[Lebanon]]></string>
+	<string name="__Lesotho"><![CDATA[Lesotho]]></string>
+	<string name="__Liberia"><![CDATA[Liberia]]></string>
+	<string name="__Libya"><![CDATA[Libya]]></string>
+	<string name="__Liechtenstein"><![CDATA[Liechtenstein]]></string>
+	<string name="__Lithuania"><![CDATA[Lithuania]]></string>
+	<string name="__Lithuanian"><![CDATA[Lithuanian]]></string>
+	<string name="__Luxembourg"><![CDATA[Luxembourg]]></string>
+	<string name="__Macao"><![CDATA[Macao]]></string>
+	<string name="__Macedonia, The Former Yugoslav Republic of"><![CDATA[Macedonia, The Former Yugoslav Republic of]]></string>
+	<string name="__Madagascar"><![CDATA[Madagascar]]></string>
+	<string name="__Malawi"><![CDATA[Malawi]]></string>
+	<string name="__Malay"><![CDATA[Malay]]></string>
+	<string name="__Malaysia"><![CDATA[Malaysia]]></string>
+	<string name="__Maldives"><![CDATA[Maldives]]></string>
+	<string name="__Mali"><![CDATA[Mali]]></string>
+	<string name="__Malta"><![CDATA[Malta]]></string>
+	<string name="__Mandarin"><![CDATA[Mandarin]]></string>
+	<string name="__Marathi"><![CDATA[Marathi]]></string>
+	<string name="__Marshall Islands"><![CDATA[Marshall Islands]]></string>
+	<string name="__Martinique"><![CDATA[Martinique]]></string>
+	<string name="__Mauritania"><![CDATA[Mauritania]]></string>
+	<string name="__Mauritius"><![CDATA[Mauritius]]></string>
+	<string name="__Mayotte"><![CDATA[Mayotte]]></string>
+	<string name="__Mexico"><![CDATA[Mexico]]></string>
+	<string name="__Micronesia, Federated States of"><![CDATA[Micronesia, Federated States of]]></string>
+	<string name="__Moldova"><![CDATA[Moldova]]></string>
+	<string name="__Moldovian"><![CDATA[Moldovian]]></string>
+	<string name="__Monaco"><![CDATA[Monaco]]></string>
+	<string name="__Mongolia"><![CDATA[Mongolia]]></string>
+	<string name="__Montenegro"><![CDATA[Montenegro]]></string>
+	<string name="__Montserrat"><![CDATA[Montserrat]]></string>
+	<string name="__Morocco"><![CDATA[Morocco]]></string>
+	<string name="__Mozambique"><![CDATA[Mozambique]]></string>
+	<string name="__Namibia"><![CDATA[Namibia]]></string>
+	<string name="__Nauru"><![CDATA[Nauru]]></string>
+	<string name="__Nepal"><![CDATA[Nepal]]></string>
+	<string name="__Nepalese"><![CDATA[Nepalese]]></string>
+	<string name="__Netherlands"><![CDATA[Netherlands]]></string>
+	<string name="__Netherlands Antilles"><![CDATA[Netherlands Antilles]]></string>
+	<string name="__New Caledonia"><![CDATA[New Caledonia]]></string>
+	<string name="__New Zealand"><![CDATA[New Zealand]]></string>
+	<string name="__Nicaragua"><![CDATA[Nicaragua]]></string>
+	<string name="__Niger"><![CDATA[Niger]]></string>
+	<string name="__Nigeria"><![CDATA[Nigeria]]></string>
+	<string name="__Niue"><![CDATA[Niue]]></string>
+	<string name="__Norfolk Island"><![CDATA[Norfolk Island]]></string>
+	<string name="__Northern Mariana Islands"><![CDATA[Northern Mariana Islands]]></string>
+	<string name="__Norway"><![CDATA[Norway]]></string>
+	<string name="__Norwegian"><![CDATA[Norwegian]]></string>
+	<string name="__Oman"><![CDATA[Oman]]></string>
+	<string name="__Pakistan"><![CDATA[Pakistan]]></string>
+	<string name="__Palau"><![CDATA[Palau]]></string>
+	<string name="__Palestinian Territory, Occupied"><![CDATA[Palestinian Territory, Occupied]]></string>
+	<string name="__Panama"><![CDATA[Panama]]></string>
+	<string name="__Papua New Guinea"><![CDATA[Papua New Guinea]]></string>
+	<string name="__Paraguay"><![CDATA[Paraguay]]></string>
+	<string name="__Persian"><![CDATA[Persian]]></string>
+	<string name="__Peru"><![CDATA[Peru]]></string>
+	<string name="__Philippines"><![CDATA[Philippines]]></string>
+	<string name="__Pitcairn Islands"><![CDATA[Pitcairn Islands]]></string>
+	<string name="__Poland"><![CDATA[Poland]]></string>
+	<string name="__Polish"><![CDATA[Polish]]></string>
+	<string name="__Portugal"><![CDATA[Portugal]]></string>
+	<string name="__Portuguese"><![CDATA[Portuguese]]></string>
+	<string name="__Puerto Rico"><![CDATA[Puerto Rico]]></string>
+	<string name="__Punjabi"><![CDATA[Punjabi]]></string>
+	<string name="__Qatar"><![CDATA[Qatar]]></string>
+	<string name="__Reunion"><![CDATA[Reunion]]></string>
+	<string name="__Romania"><![CDATA[Romania]]></string>
+	<string name="__Romanian"><![CDATA[Romanian]]></string>
+	<string name="__Russia"><![CDATA[Russia]]></string>
+	<string name="__Russian"><![CDATA[Russian]]></string>
+	<string name="__Rwanda"><![CDATA[Rwanda]]></string>
+	<string name="__Saint Helena"><![CDATA[Saint Helena]]></string>
+	<string name="__Saint Kitts and Nevis"><![CDATA[Saint Kitts and Nevis]]></string>
+	<string name="__Saint Lucia"><![CDATA[Saint Lucia]]></string>
+	<string name="__Saint Pierre and Miquelon"><![CDATA[Saint Pierre and Miquelon]]></string>
+	<string name="__Saint Vincent and the Grenadines"><![CDATA[Saint Vincent and the Grenadines]]></string>
+	<string name="__Saint_Barthelemy"><![CDATA[Saint Barthelemy]]></string>
+	<string name="__Saint_Martin_French_part"><![CDATA[Saint Martin (French part)]]></string>
+	<string name="__Samoa"><![CDATA[Samoa]]></string>
+	<string name="__San Marino"><![CDATA[San Marino]]></string>
+	<string name="__Sao Tome and Principe"><![CDATA[Sao Tome and Principe]]></string>
+	<string name="__Saudi Arabia"><![CDATA[Saudi Arabia]]></string>
+	<string name="__Senegal"><![CDATA[Senegal]]></string>
+	<string name="__Serbia"><![CDATA[Serbia]]></string>
+	<string name="__Serbian"><![CDATA[Serbian]]></string>
+	<string name="__Seychelles"><![CDATA[Seychelles]]></string>
+	<string name="__Sierra Leone"><![CDATA[Sierra Leone]]></string>
+	<string name="__Singapore"><![CDATA[Singapore]]></string>
+	<string name="__Slovakia"><![CDATA[Slovakia]]></string>
+	<string name="__Slovenia"><![CDATA[Slovenia]]></string>
+	<string name="__Solomon Islands"><![CDATA[Solomon Islands]]></string>
+	<string name="__Somalia"><![CDATA[Somalia]]></string>
+	<string name="__South Africa"><![CDATA[South Africa]]></string>
+	<string name="__South Georgia and the South Sandwich Islands"><![CDATA[South Georgia and the South Sandwich Islands]]></string>
+	<string name="__Spain"><![CDATA[Spain]]></string>
+	<string name="__Spanish"><![CDATA[Spanish]]></string>
+	<string name="__Sri Lanka"><![CDATA[Sri Lanka]]></string>
+	<string name="__Sudan"><![CDATA[Sudan]]></string>
+	<string name="__Suriname"><![CDATA[Suriname]]></string>
+	<string name="__Svalbard"><![CDATA[Svalbard]]></string>
+	<string name="__Swaziland"><![CDATA[Swaziland]]></string>
+	<string name="__Sweden"><![CDATA[Sweden]]></string>
+	<string name="__Swedish"><![CDATA[Swedish]]></string>
+	<string name="__Switzerland"><![CDATA[Switzerland]]></string>
+	<string name="__Syria"><![CDATA[Syria]]></string>
+	<string name="__Tagalog"><![CDATA[Tagalog]]></string>
+	<string name="__Taiwan"><![CDATA[Taiwan]]></string>
+	<string name="__Taiwanese"><![CDATA[Taiwanese]]></string>
+	<string name="__Tajikistan"><![CDATA[Tajikistan]]></string>
+	<string name="__Tamil"><![CDATA[Tamil]]></string>
+	<string name="__Tanzania"><![CDATA[Tanzania]]></string>
+	<string name="__Telugu"><![CDATA[Telugu]]></string>
+	<string name="__Thai"><![CDATA[Thai]]></string>
+	<string name="__Thailand"><![CDATA[Thailand]]></string>
+	<string name="__The Bahamas"><![CDATA[The Bahamas]]></string>
+	<string name="__The Gambia"><![CDATA[The Gambia]]></string>
+	<string name="__Togo"><![CDATA[Togo]]></string>
+	<string name="__Tokelau"><![CDATA[Tokelau]]></string>
+	<string name="__Tonga"><![CDATA[Tonga]]></string>
+	<string name="__Tongan"><![CDATA[Tongan]]></string>
+	<string name="__Trinidad and Tobago"><![CDATA[Trinidad and Tobago]]></string>
+	<string name="__Tunisia"><![CDATA[Tunisia]]></string>
+	<string name="__Turkey"><![CDATA[Turkey]]></string>
+	<string name="__Turkish"><![CDATA[Turkish]]></string>
+	<string name="__Turkmenistan"><![CDATA[Turkmenistan]]></string>
+	<string name="__Turks and Caicos Islands"><![CDATA[Turks and Caicos Islands]]></string>
+	<string name="__Tuvalu"><![CDATA[Tuvalu]]></string>
+	<string name="__Uganda"><![CDATA[Uganda]]></string>
+	<string name="__Ukraine"><![CDATA[Ukraine]]></string>
+	<string name="__Ukrainian"><![CDATA[Ukrainian]]></string>
+	<string name="__United Arab Emirates"><![CDATA[United Arab Emirates]]></string>
+	<string name="__United Kingdom"><![CDATA[United Kingdom]]></string>
+	<string name="__United States"><![CDATA[United States]]></string>
+	<string name="__United States Minor Outlying Islands"><![CDATA[United States Minor Outlying Islands]]></string>
+	<string name="__Urdu"><![CDATA[Urdu]]></string>
+	<string name="__Uruguay"><![CDATA[Uruguay]]></string>
+	<string name="__Uzbekistan"><![CDATA[Uzbekistan]]></string>
+	<string name="__Vanuatu"><![CDATA[Vanuatu]]></string>
+	<string name="__Venezuela"><![CDATA[Venezuela]]></string>
+	<string name="__Vietnam"><![CDATA[Vietnam]]></string>
+	<string name="__Vietnamese"><![CDATA[Vietnamese]]></string>
+	<string name="__Virgin Islands"><![CDATA[Virgin Islands]]></string>
+	<string name="__Visayan"><![CDATA[Visayan]]></string>
+	<string name="__Wallis and Futuna"><![CDATA[Wallis and Futuna]]></string>
+	<string name="__Western Sahara"><![CDATA[Western Sahara]]></string>
+	<string name="__Yemen"><![CDATA[Yemen]]></string>
+	<string name="__Zambia"><![CDATA[Zambia]]></string>
+	<string name="__Zimbabwe"><![CDATA[Zimbabwe]]></string>
+        <string name="__AUD"><![CDATA[AUD]]></string>
+        <string name="__CAD"><![CDATA[CAD]]></string>
+        <string name="__EUR"><![CDATA[EUR]]></string>
+        <string name="__GBP"><![CDATA[GBP]]></string>
+        <string name="__USD"><![CDATA[USD]]></string>
+        <string name="__YEN"><![CDATA[YEN]]></string>
+	<string name="_adm_act_err_failed_page_loading"><![CDATA[Cannot load the page]]></string>
+	<string name="_adm_action_cpt_checkout"><![CDATA[Checkout]]></string>
+	<string name="_adm_action_cpt_delete_all"><![CDATA[Delete All]]></string>
+	<string name="_adm_action_cpt_see_all"><![CDATA[See All]]></string>
+	<string name="_adm_admtools_Audit"><![CDATA[Audit]]></string>
+	<string name="_adm_admtools_Current_level"><![CDATA[Current status]]></string>
+	<string name="_adm_admtools_Desired_level"><![CDATA[Desired status]]></string>
+	<string name="_adm_admtools_Executable"><![CDATA[Executable]]></string>
+	<string name="_adm_admtools_Non_Executable"><![CDATA[Not executable]]></string>
+	<string name="_adm_admtools_Non_Writable"><![CDATA[Not writable]]></string>
+	<string name="_adm_admtools_Not_Exists"><![CDATA[Not exists]]></string>
+	<string name="_adm_admtools_Path"><![CDATA[Path]]></string>
+	<string name="_adm_admtools_Permissions"><![CDATA[Permissions]]></string>
+	<string name="_adm_admtools_Writable"><![CDATA[Writable]]></string>
+	<string name="_adm_admtools_title"><![CDATA[Admin Tools]]></string>
+	<string name="_adm_block_cpt_categories"><![CDATA[Categories]]></string>
+	<string name="_adm_block_cpt_category"><![CDATA[Category: {0}]]></string>
+	<string name="_adm_block_cpt_checkout"><![CDATA[Checkout]]></string>
+	<string name="_adm_block_cpt_checkout_by_vendor_ccode"><![CDATA[Products from {0} ({1} {2})]]></string>
+	<string name="_adm_block_cpt_checkout_by_vendor_csign"><![CDATA[Products from {0} ({1}{2})]]></string>
+	<string name="_adm_block_cpt_downloaded_modules"><![CDATA[Modules]]></string>
+	<string name="_adm_block_cpt_downloaded_updates"><![CDATA[Updates]]></string>
+	<string name="_adm_block_cpt_featured"><![CDATA[Featured]]></string>
+	<string name="_adm_block_cpt_goodies"><![CDATA[Storefront]]></string>
+	<string name="_adm_block_cpt_latest"><![CDATA[Latest]]></string>
+	<string name="_adm_block_cpt_modules_upload"><![CDATA[Add New Module]]></string>
+	<string name="_adm_block_cpt_popular"><![CDATA[Popular]]></string>
+	<string name="_adm_block_cpt_purchases"><![CDATA[Purchases]]></string>
+	<string name="_adm_block_cpt_search"><![CDATA[Search]]></string>
+	<string name="_adm_block_cpt_space"><![CDATA[Space Usage]]></string>
+	<string name="_adm_block_cpt_tag"><![CDATA[Hashtag: {0}]]></string>
+	<string name="_adm_block_cpt_tags"><![CDATA[Hashtags]]></string>
+	<string name="_adm_block_cpt_updates"><![CDATA[Updates]]></string>
+	<string name="_adm_block_cpt_versions"><![CDATA[Versions]]></string>
+	<string name="_adm_bp_btn_add_block"><![CDATA[Add Blocks]]></string>
+	<string name="_adm_bp_btn_block_add"><![CDATA[Add to Page]]></string>
+	<string name="_adm_bp_btn_block_cancel"><![CDATA[Cancel]]></string>
+	<string name="_adm_bp_btn_block_delete"><![CDATA[Delete]]></string>
+	<string name="_adm_bp_btn_block_save"><![CDATA[Save]]></string>
+	<string name="_adm_bp_btn_create_new"><![CDATA[Add New Page]]></string>
+	<string name="_adm_bp_btn_delete"><![CDATA[Delete]]></string>
+	<string name="_adm_bp_btn_page_apply"><![CDATA[Apply]]></string>
+	<string name="_adm_bp_btn_page_cancel"><![CDATA[Cancel]]></string>
+	<string name="_adm_bp_btn_page_create"><![CDATA[Create]]></string>
+	<string name="_adm_bp_btn_settings"><![CDATA[Settings]]></string>
+	<string name="_adm_bp_btn_view_page"><![CDATA[View Page]]></string>
+	<string name="_adm_bp_cpt_type_custom"><![CDATA[Custom Pages]]></string>
+	<string name="_adm_bp_cpt_type_modules"><![CDATA[Modules]]></string>
+	<string name="_adm_bp_cpt_type_system"><![CDATA[System Pages]]></string>
+	<string name="_adm_bp_dsc_block_content_image_file"><![CDATA[The image will be displayed in block]]></string>
+	<string name="_adm_bp_dsc_block_content_lang"><![CDATA[Enter the content in accordance with the selected language]]></string>
+	<string name="_adm_bp_dsc_block_content_raw"><![CDATA[Enter HTML content here]]></string>
+	<string name="_adm_bp_dsc_block_content_rss_length"><![CDATA[Enter a number of displayed items here]]></string>
+	<string name="_adm_bp_dsc_block_content_rss_url"><![CDATA[Enter URL to RSS resource here]]></string>
+        <string name="_adm_bp_dsc_block_content_empty"><![CDATA[Leave empty to use default one]]></string>
+        <string name="_adm_bp_dsc_block_description"><![CDATA[Short description for the block, visible in block header.]]></string>
+        <string name="_adm_bp_dsc_block_icon"><![CDATA[An icon (font icon, SVG or Emoji code) for the block, visible in block header.]]></string>
+	<string name="_adm_bp_dsc_block_title"><![CDATA[Short name for the block, visible in block header.]]></string>
+	<string name="_adm_bp_dsc_block_visible_for_levels"><![CDATA[Select user levels that can see this block]]></string>
+	<string name="_adm_bp_dsc_page_cache_lifetime"><![CDATA[Store page in cache for this number of seconds]]></string>
+        <string name="_adm_bp_dsc_page_inj_footer"><![CDATA[Just before BODY tag]]></string>
+        <string name="_adm_bp_dsc_page_inj_head"><![CDATA[In HEAD tag]]></string>
+	<string name="_adm_bp_dsc_page_meta_description"><![CDATA[Use 10-50 words to tell search engines what the page is about.]]></string>
+	<string name="_adm_bp_dsc_page_meta_keywords"><![CDATA[Use 5-10 keywords, separated by comma, associated with page content.]]></string>
+	<string name="_adm_bp_dsc_page_meta_robots"><![CDATA[Standard commands for search engine robots. Example: noindex, nofollow.]]></string>
+	<string name="_adm_bp_dsc_page_title"><![CDATA[This name is displayed in page header. Use at least 3 characters.]]></string>
+	<string name="_adm_bp_dsc_page_title_system"><![CDATA[This name is displayed in Studio only.]]></string>
+	<string name="_adm_bp_dsc_page_uri"><![CDATA[Page address used after 'youdomain.com/page/'. It must be unique and it can not be changed later.]]></string>
+	<string name="_adm_bp_dsc_page_url"><![CDATA[Page link to access the page.]]></string>
+	<string name="_adm_bp_dsc_page_visible_for_levels"><![CDATA[Select user levels that can see this page]]></string>
+	<string name="_adm_bp_err_block_added"><![CDATA[Cannot add block(s)]]></string>
+	<string name="_adm_bp_err_block_delete"><![CDATA[Cannot delete block]]></string>
+	<string name="_adm_bp_err_block_designbox"><![CDATA[Select a layout box for the block]]></string>
+	<string name="_adm_bp_err_block_edit"><![CDATA[Cannot update block]]></string>
+	<string name="_adm_bp_err_block_not_deletable"><![CDATA[The requested block cannot be deleted.]]></string>
+	<string name="_adm_bp_err_block_not_found"><![CDATA[The requested block cannot be found.]]></string>
+	<string name="_adm_bp_err_block_title"><![CDATA[Enter title, more than 3 characters]]></string>
+	<string name="_adm_bp_err_cannot_process_action"><![CDATA[Cannot process action. It does not have an associated handler.]]></string>
+	<string name="_adm_bp_err_nothing_changed"><![CDATA[Nothing was changed or an error occurred.]]></string>
+	<string name="_adm_bp_err_page_create"><![CDATA[Cannot create the page.]]></string>
+	<string name="_adm_bp_err_page_delete"><![CDATA[Cannot delete the page.]]></string>
+	<string name="_adm_bp_err_page_layout"><![CDATA[Please, select a page layout.]]></string>
+	<string name="_adm_bp_err_page_title"><![CDATA[A title with at least 3 characters is required.]]></string>
+	<string name="_adm_bp_err_page_title_system"><![CDATA[A name with at least 3 characters is required.]]></string>
+	<string name="_adm_bp_err_page_uri"><![CDATA[A unique URL with at least 3 characters is required.]]></string>
+	<string name="_adm_bp_err_page_visible_for_levels"><![CDATA[Visibility setting are determined by custom code or not applicable here.]]></string>
+	<string name="_adm_bp_err_save"><![CDATA[Cannot save or nothing was changed.]]></string>
+	<string name="_adm_bp_mi_page_cache"><![CDATA[Cache]]></string>
+	<string name="_adm_bp_mi_page_cover"><![CDATA[Cover]]></string>
+        <string name="_adm_bp_mi_page_injections"><![CDATA[Injections]]></string>
+	<string name="_adm_bp_mi_page_layout"><![CDATA[Layout]]></string>
+	<string name="_adm_bp_mi_page_options"><![CDATA[Options]]></string>
+	<string name="_adm_bp_mi_page_seo"><![CDATA[SEO]]></string>
+	<string name="_adm_bp_mi_page_visibility"><![CDATA[Visibility]]></string>
+	<string name="_adm_bp_scs_save"><![CDATA[The changes were successfully saved]]></string>
+	<string name="_adm_bp_txt_block_active"><![CDATA[Active]]></string>
+        <string name="_adm_bp_txt_block_active_api"><![CDATA[Active (for App)]]></string>
+	<string name="_adm_bp_txt_block_async"><![CDATA[Asynchronous Mode]]></string>
+	<string name="_adm_bp_txt_block_cache_lifetime"><![CDATA[Block Cache Lifetime (in seconds)]]></string>
+	<string name="_adm_bp_txt_block_content_attachments_html"><![CDATA[Attachments]]></string>
+	<string name="_adm_bp_txt_block_content_image_align"><![CDATA[Alignment]]></string>
+	<string name="_adm_bp_txt_block_content_image_align_center"><![CDATA[center]]></string>
+	<string name="_adm_bp_txt_block_content_image_align_empty"><![CDATA[Select alignment...]]></string>
+	<string name="_adm_bp_txt_block_content_image_align_left"><![CDATA[left]]></string>
+	<string name="_adm_bp_txt_block_content_image_align_right"><![CDATA[right]]></string>
+	<string name="_adm_bp_txt_block_content_image_file"><![CDATA[Image]]></string>
+	<string name="_adm_bp_txt_block_content_lang"><![CDATA[Content]]></string>
+	<string name="_adm_bp_txt_block_content_menu"><![CDATA[Menu]]></string>
+	<string name="_adm_bp_txt_block_content_menu_empty"><![CDATA[Select menu...]]></string>
+	<string name="_adm_bp_txt_block_content_raw"><![CDATA[Content]]></string>
+	<string name="_adm_bp_txt_block_content_rss_length"><![CDATA[Length]]></string>
+	<string name="_adm_bp_txt_block_content_rss_url"><![CDATA[URL]]></string>
+	<string name="_adm_bp_txt_block_content_service_method"><![CDATA[Method]]></string>
+	<string name="_adm_bp_txt_block_content_service_module"><![CDATA[Module]]></string>
+        <string name="_adm_bp_txt_block_content_empty"><![CDATA[Placeholder text for empty block]]></string>
+        <string name="_adm_bp_txt_block_description"><![CDATA[Description]]></string>
+	<string name="_adm_bp_txt_block_designbox"><![CDATA[Block Layout]]></string>
+	<string name="_adm_bp_txt_block_designbox_empty"><![CDATA[Select layout...]]></string>
+        <string name="_adm_bp_txt_block_class"><![CDATA[CSS Class]]></string>
+        <string name="_adm_bp_txt_block_help"><![CDATA[Help]]></string>
+	<string name="_adm_bp_txt_block_hidden_on"><![CDATA[Hidden on]]></string>
+	<string name="_adm_bp_txt_block_hidden_on_phone"><![CDATA[phone]]></string>
+	<string name="_adm_bp_txt_block_hidden_on_tablet"><![CDATA[tablet]]></string>
+	<string name="_adm_bp_txt_block_hidden_on_desktop"><![CDATA[desktop]]></string>
+        <string name="_adm_bp_txt_block_hidden_on_mobile"><![CDATA[mobile app]]></string>
+        <string name="_adm_bp_txt_block_icon"><![CDATA[Icon]]></string>
+	<string name="_adm_bp_txt_block_selected"><![CDATA[blocks selected]]></string>
+        <string name="_adm_bp_txt_block_submenu"><![CDATA[Block submenu]]></string>
+        <string name="_adm_bp_txt_block_tabs"><![CDATA[Use 'tabs' based block submenu]]></string>
+	<string name="_adm_bp_txt_block_title"><![CDATA[Display Name]]></string>
+	<string name="_adm_bp_txt_block_visible_for"><![CDATA[Visible For]]></string>
+	<string name="_adm_bp_txt_block_visible_for_all"><![CDATA[Anyone]]></string>
+	<string name="_adm_bp_txt_block_visible_for_levels"><![CDATA[Select Levels]]></string>
+	<string name="_adm_bp_txt_block_visible_for_selected"><![CDATA[Selected levels]]></string>
+	<string name="_adm_bp_txt_create_popup"><![CDATA[Create New Page]]></string>
+	<string name="_adm_bp_txt_edit_block_popup"><![CDATA[Edit "{0}" Block]]></string>
+	<string name="_adm_bp_txt_new_block_popup"><![CDATA[Add New Block]]></string>
+	<string name="_adm_bp_txt_page_cache_lifetime"><![CDATA[Cache]]></string>
+	<string name="_adm_bp_txt_page_cover"><![CDATA[Cover]]></string>
+	<string name="_adm_bp_txt_page_cover_image"><![CDATA[Custom Cover]]></string>
+        <string name="_adm_bp_txt_page_cover_title"><![CDATA[Custom Title]]></string>
+        <string name="_adm_bp_txt_page_cover_0"><![CDATA[Disabled]]></string>
+        <string name="_adm_bp_txt_page_cover_1"><![CDATA[Enabled for all]]></string>
+        <string name="_adm_bp_txt_page_cover_2"><![CDATA[Enabled for visitors only]]></string>
+        <string name="_adm_bp_txt_page_cover_3"><![CDATA[Enabled for members only]]></string>
+        <string name="_adm_bp_txt_page_inj_footer"><![CDATA[In Footer]]></string>
+        <string name="_adm_bp_txt_page_inj_head"><![CDATA[In Head]]></string>
+	<string name="_adm_bp_txt_page_layout"><![CDATA[Layout]]></string>
+	<string name="_adm_bp_txt_page_layout_empty"><![CDATA[Select Layout...]]></string>
+	<string name="_adm_bp_txt_page_meta_description"><![CDATA[Page (Meta) Description]]></string>
+	<string name="_adm_bp_txt_page_meta_keywords"><![CDATA[Keywords]]></string>
+        <string name="_adm_bp_txt_page_meta_title"><![CDATA[Page (Meta) Title]]></string>
+	<string name="_adm_bp_txt_page_meta_robots"><![CDATA[Meta Robots]]></string>
+        <string name="_adm_bp_txt_page_submenu"><![CDATA[Submenu]]></string>
+	<string name="_adm_bp_dsc_page_submenu"><![CDATA[Page submenu can be selected here]]></string>
+	<string name="_adm_bp_txt_page_title"><![CDATA[Display Name]]></string>
+	<string name="_adm_bp_txt_page_title_system"><![CDATA[System Name]]></string>
+	<string name="_adm_bp_txt_page_type_id"><![CDATA[Type]]></string>
+	<string name="_adm_bp_dsc_page_type_id"><![CDATA[Page display type. Default value can be changed in Studio -> Designer -> Settings.]]></string>
+	<string name="_adm_bp_txt_page_uri"><![CDATA[URL]]></string>
+	<string name="_adm_bp_txt_page_url"><![CDATA[Link]]></string>
+	<string name="_adm_bp_txt_page_visible_for_levels"><![CDATA[Select Levels]]></string>
+        <string name="_adm_bp_txt_page_sticky_columns"><![CDATA[Enable sticky blocks]]></string>
+        <string name="_adm_bp_txt_select_page"><![CDATA[Select Page...]]></string>
+	<string name="_adm_bp_txt_settings_popup"><![CDATA[Settings]]></string>
+	<string name="_adm_bp_txt_visible_for"><![CDATA[Visible for {0}]]></string>
+	<string name="_adm_bp_wrn_page_delete"><![CDATA[Are you sure you want to delete the page?]]></string>
+	<string name="_adm_bp_wrn_page_block_delete"><![CDATA[Are you sure you want to delete the block?]]></string>
+        <string name="_adm_bp_txt_inactive_blocks"><![CDATA[Inactive Blocks]]></string>
+	<string name="_adm_btn_cancel_submit"><![CDATA[Cancel]]></string>
+	<string name="_adm_btn_checkout_submit"><![CDATA[Checkout]]></string>
+	<string name="_adm_btn_delete_submit"><![CDATA[Delete]]></string>
+	<string name="_adm_btn_designer_submit"><![CDATA[Submit]]></string>
+	<string name="_adm_btn_download_submit"><![CDATA[Download]]></string>
+	<string name="_adm_btn_install_submit"><![CDATA[Install]]></string>
+	<string name="_adm_btn_installed_submit"><![CDATA[Installed]]></string>
+	<string name="_adm_btn_login_submit"><![CDATA[Sign in]]></string>
+	<string name="_adm_btn_queued_submit"><![CDATA[Queued]]></string>
+        <string name="_adm_btn_settings_export"><![CDATA[Export]]></string>
+	<string name="_adm_btn_settings_import"><![CDATA[Import]]></string>
+	<string name="_adm_btn_settings_save"><![CDATA[Save]]></string>
+	<string name="_adm_btn_settings_mix_create"><![CDATA[Add New Mix]]></string>
+	<string name="_adm_btn_settings_mix_import"><![CDATA[Import]]></string>
+	<string name="_adm_btn_settings_mix_export"><![CDATA[Export]]></string>
+	<string name="_adm_btn_settings_mix_delete"><![CDATA[Delete]]></string>
+        <string name="_adm_btn_settings_mix_hide"><![CDATA[Hide]]></string>
+        <string name="_adm_btn_settings_mix_publish"><![CDATA[Publish]]></string>
+	<string name="_adm_btn_store_search"><![CDATA[Search]]></string>
+	<string name="_adm_dbd_btn_update"><![CDATA[Update]]></string>
+        <string name="_adm_dbd_txt_available"><![CDATA[Available:]]></string>
+	<string name="_adm_dbd_txt_installed"><![CDATA[Installed:]]></string>
+	<string name="_adm_dbd_txt_updated"><![CDATA[Updated:]]></string>
+        <string name="_adm_dbd_msg_upgrade_started"><![CDATA[Site will be upgraded within a minute.<br />Don't forget to <a href="{0}store.php?page=updates">check for modules updates</a> after that.]]></string>
+	<string name="_adm_dbd_txt_su_database"><![CDATA[Database]]></string>
+	<string name="_adm_dbd_txt_su_system"><![CDATA[System]]></string>
+	<string name="_adm_dbd_txt_su_system_media"><![CDATA[System Media]]></string>
+        <string name="_adm_dbd_txt_c_select"><![CDATA[Select...]]></string>
+	<string name="_adm_dbd_txt_c_clear_all"><![CDATA[Clear all caches]]></string>
+	<string name="_adm_dbd_txt_c_content"><![CDATA[Content]]></string>
+	<string name="_adm_dbd_txt_c_clear_content"><![CDATA[Clear content cache]]></string>
+	<string name="_adm_dbd_txt_c_db"><![CDATA[DB]]></string>
+	<string name="_adm_dbd_txt_c_clear_db"><![CDATA[Clear DB cache]]></string>
+	<string name="_adm_dbd_txt_c_template"><![CDATA[Template]]></string>
+	<string name="_adm_dbd_txt_c_clear_template"><![CDATA[Clear Template cache]]></string>
+	<string name="_adm_dbd_txt_c_css"><![CDATA[CSS]]></string>
+	<string name="_adm_dbd_txt_c_clear_css"><![CDATA[Clear CSS cache]]></string>
+        <string name="_adm_dbd_txt_c_less"><![CDATA[LESS]]></string>
+        <string name="_adm_dbd_txt_c_clear_less"><![CDATA[Clear LESS cache]]></string>
+        <string name="_adm_dbd_txt_c_clear_purifier"><![CDATA[Clear Purifier cache]]></string>
+        <string name="_adm_dbd_txt_c_js"><![CDATA[JavaScript]]></string>
+        <string name="_adm_dbd_txt_c_clear_js"><![CDATA[Clear JavaScript cache]]></string>
+        <string name="_adm_dbd_txt_c_clear_custom"><![CDATA[Clear Custom cache]]></string>
+        <string name="_adm_dbd_txt_c_opcache"><![CDATA[Opcache]]></string>
+        <string name="_adm_dbd_txt_c_clear_opcache"><![CDATA[Clear Opcache]]></string>
+        <string name="_adm_dbd_err_c_clean_failed"><![CDATA[Failed to clear cache]]></string>
+        <string name="_adm_dbd_err_c_clean_unsupported"><![CDATA[Cache clearing is unsupported]]></string>
+        <string name="_adm_dbd_msg_c_clean_success"><![CDATA[Cache was successfully cleared]]></string>
+        <string name="_adm_dbd_msg_c_all_disabled"><![CDATA[All caches are disabled]]></string>
+        <string name="_adm_dsn_cnf_uninstall"><![CDATA[<h3>Uninstall "{0}" template?</h3><p>Uninstalling "{0}" template will also delete all of its data. Do you want to continue?</p>]]></string>
+	<string name="_adm_dsg_btn_delete"><![CDATA[Delete]]></string>
+	<string name="_adm_dsg_btn_make_default"><![CDATA[Make Default]]></string>
+	<string name="_adm_dsg_dsc_alt_text"><![CDATA[Serves as "ALT" text for logo image. Used as a logo when no logo image is uploaded.]]></string>
+	<string name="_adm_dsg_dsc_splash_warning"><![CDATA[Note, that improper use of HTML may break the site layout.]]></string>
+	<string name="_adm_dsg_err_cannot_process_action"><![CDATA[Cannot process action. It does not have an associated handler.]]></string>
+	<string name="_adm_dsg_err_deactivate_default"><![CDATA[You cannot deactivate template which was selected as Default]]></string>
+	<string name="_adm_dsg_err_last_active"><![CDATA[You need to have at least one active template.]]></string>
+	<string name="_adm_dsg_err_make_default"><![CDATA[Cannot make the template default.]]></string>
+	<string name="_adm_dsg_err_remove_old_cover"><![CDATA[Cannot remove current cover image.]]></string>
+	<string name="_adm_dsg_err_remove_old_icon"><![CDATA[Cannot remove current icon.]]></string>
+	<string name="_adm_dsg_err_save"><![CDATA[Cannot save: ]]></string>
+	<string name="_adm_dsg_err_save_changes"><![CDATA[Cannot save changes.]]></string>
+	<string name="_adm_dsg_scs_save"><![CDATA[The changes were successfully saved]]></string>
+        <string name="_adm_dsg_txt_logo_redefinition"><![CDATA[Note. All logo parameters can be overwritten in currently active Template app.]]></string>
+	<string name="_adm_dsg_txt_alt_text"><![CDATA[Logo Text]]></string>
+	<string name="_adm_dsg_txt_cover_common"><![CDATA[Default pages cover]]></string>
+	<string name="_adm_dsg_txt_cover_unit_profile"><![CDATA[Default profile unit cover]]></string>
+	<string name="_adm_dsg_txt_cover_disabled"><![CDATA[Disable pages covers]]></string>
+	<string name="_adm_dsg_txt_splash_enabled"><![CDATA[Enable splash page]]></string>
+	<string name="_adm_dsg_txt_default"><![CDATA[default]]></string>
+	<string name="_adm_dsg_txt_icon"><![CDATA[Favicon (32x32)]]></string>
+        <string name="_adm_dsg_txt_icon_svg"><![CDATA[SVG icon with light/dark styles]]></string>
+        <string name="_adm_dsg_txt_icon_apple"><![CDATA[Apple devices icon (180x180)]]></string>
+        <string name="_adm_dsg_txt_icon_android"><![CDATA[Android devices icon (192×192)]]></string>
+        <string name="_adm_dsg_txt_icon_android_splash"><![CDATA[Android devices splash (512×512)]]></string>
+	<string name="_adm_dsg_txt_upload_cover_common"><![CDATA[Upload new common pages cover]]></string>
+	<string name="_adm_dsg_txt_upload_cover_unit_profile"><![CDATA[Upload new profile unit cover]]></string>
+	<string name="_adm_dsg_txt_upload_icon"><![CDATA[favicon.ico]]></string>
+        <string name="_adm_dsg_txt_upload_icon_inf"><![CDATA[single 32×32 ico image file is recommended]]></string>
+        <string name="_adm_dsg_txt_upload_icon_svg"><![CDATA[SVG icon]]></string>
+        <string name="_adm_dsg_txt_upload_icon_svg_inf"><![CDATA[svg image with dark and light styles embedded is recommended]]></string>
+        <string name="_adm_dsg_txt_upload_icon_apple"><![CDATA[Apple devices icon]]></string>
+        <string name="_adm_dsg_txt_upload_icon_apple_inf"><![CDATA[padding and background color is recommended for this image]]></string>
+        <string name="_adm_dsg_txt_upload_icon_android"><![CDATA[Android devices icon]]></string>
+        <string name="_adm_dsg_txt_upload_icon_android_inf"><![CDATA[for Android home screen]]></string>
+        <string name="_adm_dsg_txt_upload_icon_android_splash"><![CDATA[Android devices splash]]></string>
+        <string name="_adm_dsg_txt_upload_icon_android_splash_inf"><![CDATA[for Android splash screen]]></string>
+	<string name="_adm_dsg_txt_upload_logo"><![CDATA[Logo Image]]></string>
+        <string name="_adm_dsg_txt_upload_logo_dark"><![CDATA[Logo Image (for Dark mode)]]></string>
+        <string name="_adm_dsg_txt_upload_logo_inline"><![CDATA[Logo Image (inline, low priority)]]></string>
+        <string name="_adm_dsg_txt_upload_mark"><![CDATA[Mark Image]]></string>
+        <string name="_adm_dsg_txt_upload_mark_dark"><![CDATA[Mark Image (for Dark mode)]]></string>
+        <string name="_adm_dsg_txt_upload_mark_inline"><![CDATA[Mark Image (inline, low priority)]]></string>
+	<string name="_adm_dsg_txt_inj_head"><![CDATA[&lt;HEAD&gt; injection]]></string>
+	<string name="_adm_dsg_txt_inj_head_inf"><![CDATA[Code to insert before closing HEAD tag]]></string>
+	<string name="_adm_dsg_txt_inj_body"><![CDATA[&lt;BODY&gt; injection]]></string>
+	<string name="_adm_dsg_txt_inj_body_inf"><![CDATA[Code to insert before closing BODY tag]]></string>
+	<string name="_adm_err_cannot_process_action"><![CDATA[Cannot process action. It does not have an associated handler.]]></string>
+	<string name="_adm_err_modules_already_disabled"><![CDATA[The module is already disabled.]]></string>
+	<string name="_adm_err_modules_already_enabled"><![CDATA[The module is already enabled.]]></string>
+	<string name="_adm_err_modules_already_installed"><![CDATA[The module was already installed.]]></string>
+	<string name="_adm_err_modules_already_uninstalled"><![CDATA[The module was already uninstalled.]]></string>
+	<string name="_adm_err_modules_cannot_add_to_cart"><![CDATA[Cannot add the product to shopping cart.]]></string>
+	<string name="_adm_err_modules_cannot_checkout_empty_vendor"><![CDATA[Cannot checkout. The vendor is unknown.]]></string>
+	<string name="_adm_err_modules_cannot_delete_from_cart"><![CDATA[Cannot delete the product(s) from shopping cart.]]></string>
+	<string name="_adm_err_modules_cannot_remove_package"><![CDATA[Cannot remove package.]]></string>
+	<string name="_adm_err_modules_cannot_subscribe"><![CDATA[Cannot initialize the subscription.]]></string>
+	<string name="_adm_err_modules_module_not_found"><![CDATA[Module not found]]></string>
+	<string name="_adm_err_modules_module_not_match"><![CDATA[Update is not suitable for this module.]]></string>
+	<string name="_adm_err_modules_module_not_installed"><![CDATA[Module not installed]]></string>
+	<string name="_adm_err_modules_module_was_modified"><![CDATA[Module was modified]]></string>
+	<string name="_adm_err_modules_pending_uninstall"><![CDATA[Module uninstall was postponed. Module will be uninstalled automatically after all its files are deleted.]]></string>
+	<string name="_adm_err_modules_pending_uninstall_already"><![CDATA[Module is pending uninstall already.]]></string>
+	<string name="_adm_err_modules_process_action_failed"><![CDATA[An error occurred. Contact with module's vendor]]></string>
+	<string name="_adm_err_modules_wrong_dependency_disable"><![CDATA[Failed to disable. The module has the following dependent modules. At least you need to disable them first.]]></string>
+	<string name="_adm_err_modules_wrong_dependency_install"><![CDATA[The following modules should be installed and activated first:]]></string>
+	<string name="_adm_err_modules_wrong_dependency_uninstall"><![CDATA[Failed to uninstall. The module has the following dependent modules. You need to uninstall them first.]]></string>
+	<string name="_adm_err_modules_wrong_mysql_query"><![CDATA[There are errors in the following MySQL queries:]]></string>
+	<string name="_adm_err_modules_wrong_mysql_query_msg"><![CDATA[Error: {0}]]></string>
+	<string name="_adm_err_modules_wrong_permissions_change"><![CDATA[Unable to change permissions automatically. You need to manually change them for the following files and folders and try again:]]></string>
+	<string name="_adm_err_modules_wrong_permissions_check"><![CDATA[You need to change permissions for the following files and folders:]]></string>
+	<string name="_adm_err_modules_wrong_permissions_msg"><![CDATA[{0} - {1}]]></string>
+	<string name="_adm_err_modules_wrong_version"><![CDATA[The module has incompatible version]]></string>
+	<string name="_adm_err_modules_wrong_version_script"><![CDATA[The module is not compatible with your version of UNA]]></string>
+	<string name="_adm_err_modules_wrong_version_script_update"><![CDATA[The new version of {0} module isn't compatible with your version of UNA. Please upgrade UNA first (Studio &gt; Dashboard &gt; Version) and then try to upgrade the module.]]></string>
+	<string name="_adm_err_oauth_cannot_get_token"><![CDATA[Cannot connect to <b>UNA</b>. Please try again later.]]></string>
+	<string name="_adm_err_oauth_cannot_read_answer"><![CDATA[Cannot get a valid answer from <b>UNA</b>. Please try again later.]]></string>
+	<string name="_adm_err_oauth_empty_key_secret"><![CDATA[You need to enter Key and Secret provided by <b>UNA</b> in Settings -> General.]]></string>
+	<string name="_adm_err_operation_failed"><![CDATA[Operation failed. Please report.]]></string>
+	<string name="_adm_form_btn_displays_cancel"><![CDATA[Cancel]]></string>
+	<string name="_adm_form_btn_displays_edit"><![CDATA[Edit display]]></string>
+	<string name="_adm_form_btn_displays_save"><![CDATA[Save]]></string>
+	<string name="_adm_form_btn_field_add"><![CDATA[Add]]></string>
+	<string name="_adm_form_btn_field_cancel"><![CDATA[Cancel]]></string>
+	<string name="_adm_form_btn_field_delete"><![CDATA[Delete field]]></string>
+	<string name="_adm_form_btn_field_edit"><![CDATA[Edit field]]></string>
+	<string name="_adm_form_btn_field_save"><![CDATA[Save]]></string>
+	<string name="_adm_form_btn_fields_create"><![CDATA[Add New Field]]></string>
+	<string name="_adm_form_btn_fields_visible"><![CDATA[Visible For]]></string>
+	<string name="_adm_form_btn_forms_cancel"><![CDATA[Cancel]]></string>
+	<string name="_adm_form_btn_forms_edit"><![CDATA[Edit form]]></string>
+	<string name="_adm_form_btn_forms_save"><![CDATA[Save]]></string>
+  <string name="_adm_form_btn_categories_cancel"><![CDATA[Cancel]]></string>
+  <string name="_adm_form_btn_categories_submit"><![CDATA[Submit]]></string>
+        <string name="_adm_form_btn_labels_add"><![CDATA[Add]]></string>
+        <string name="_adm_form_btn_labels_back"><![CDATA[Back]]></string>
+        <string name="_adm_form_btn_labels_cancel"><![CDATA[Cancel]]></string>
+        <string name="_adm_form_btn_labels_submit"><![CDATA[Submit]]></string>
+  <string name="_adm_form_btn_badges_add"><![CDATA[Add new badge]]></string>
+  <string name="_adm_form_btn_badges_delete"><![CDATA[Delete]]></string>
+  <string name="_adm_form_btn_categories_add"><![CDATA[Add]]></string>
+  <string name="_adm_form_btn_categories_delete"><![CDATA[Delete]]></string>
+	<string name="_adm_form_btn_pre_lists_add"><![CDATA[Add]]></string>
+	<string name="_adm_form_btn_pre_lists_cancel"><![CDATA[Cancel]]></string>
+	<string name="_adm_form_btn_pre_lists_create"><![CDATA[Add New List]]></string>
+	<string name="_adm_form_btn_pre_lists_delete"><![CDATA[Delete List]]></string>
+	<string name="_adm_form_btn_pre_lists_edit"><![CDATA[Edit List]]></string>
+	<string name="_adm_form_btn_pre_lists_save"><![CDATA[Save]]></string>
+	<string name="_adm_form_btn_pre_values_add"><![CDATA[Add]]></string>
+	<string name="_adm_form_btn_pre_values_cancel"><![CDATA[Cancel]]></string>
+	<string name="_adm_form_btn_pre_values_delete"><![CDATA[Delete]]></string>
+	<string name="_adm_form_btn_pre_values_create"><![CDATA[Add New Item]]></string>
+	<string name="_adm_form_btn_pre_values_delete_item"><![CDATA[Delete Item]]></string>
+	<string name="_adm_form_btn_pre_values_edit_item"><![CDATA[Edit Item]]></string>
+  
+  <string name="_adm_form_btn_reports_check_in"><![CDATA[Check in]]></string>
+  <string name="_adm_form_btn_reports_check_out"><![CDATA[Check out]]></string>
+  <string name="_adm_form_btn_reports_audit"><![CDATA[Audit]]></string>
+  <string name="_adm_form_btn_reports_hide"><![CDATA[Hide]]></string>
+  <string name="_adm_form_btn_reports_unhide"><![CDATA[Unhide]]></string>
+  
+    <string name="_adm_form_btn_search_forms_edit"><![CDATA[Edit search form]]></string>
+    <string name="_adm_form_btn_search_forms_fields_edit"><![CDATA[Edit search field]]></string>
+    <string name="_adm_form_btn_search_forms_fields_reset"><![CDATA[Reset]]></string>
+    <string name="_adm_form_btn_search_forms_sortable_fields_reset"><![CDATA[Reset]]></string>
+    <string name="_adm_form_btn_search_forms_save"><![CDATA[Save]]></string>
+    <string name="_adm_form_btn_search_forms_cancel"><![CDATA[Cancel]]></string>
+    <string name="_adm_form_dsc_displays_title"><![CDATA[Name of the form display mode. Displayed in Studio only.]]></string>
+    <string name="_adm_form_dsc_field_attrs_max"><![CDATA[Enter numeric value]]></string>
+    <string name="_adm_form_dsc_field_attrs_min"><![CDATA[Enter numeric value]]></string>
+    <string name="_adm_form_dsc_field_attrs_src"><![CDATA[Enter correct image URL]]></string>
+    <string name="_adm_form_dsc_field_attrs_step"><![CDATA[Enter numeric value]]></string>
+    <string name="_adm_form_dsc_field_caption"><![CDATA[This name is displayed on site.]]></string>
+    <string name="_adm_form_dsc_field_caption_block_header"><![CDATA[Title for the group of fields]]></string>
+    <string name="_adm_form_dsc_field_caption_system"><![CDATA[This name is displayed in Studio only.]]></string>
+    <string name="_adm_form_dsc_field_checker_error_captcha"><![CDATA[Error message to display if text doesn't match with text on the image]]></string>
+    <string name="_adm_form_dsc_field_checker_params_preg"><![CDATA[Use standard <a href="http://en.wikipedia.org/wiki/Regular_expression" target="_blank">regular expression</a>. Example: #^[A-Za-z0-9]{3,16}$#]]></string>
+    <string name="_adm_form_dsc_field_collapsed"><![CDATA[Pack down the group of this field by default]]></string>
+    <string name="_adm_form_dsc_field_html"><![CDATA[Select type of HTML editor]]></string>
+    <string name="_adm_form_dsc_field_icon"><![CDATA[You may use font icon, SVG or Emoji code here]]></string>
+    <string name="_adm_form_dsc_field_info"><![CDATA[Enter field description (optional)]]></string>
+    <string name="_adm_form_dsc_field_help"><![CDATA[Enter help information for the field (optional)]]></string>
+    <string name="_adm_form_dsc_field_privacy"><![CDATA[Check it if privacy settings can be changed for the field]]></string>
+    <string name="_adm_form_dsc_field_rateable"><![CDATA[Make this field rateable]]></string>
+    <string name="_adm_form_dsc_field_required"><![CDATA[Check it if the field should have value]]></string>
+    <string name="_adm_form_dsc_field_unique"><![CDATA[Check it if the field should have unique value]]></string>
+    <string name="_adm_form_dsc_field_value_button"><![CDATA[Enter button title here]]></string>
+    <string name="_adm_form_dsc_field_value_checkbox"><![CDATA[Send this data if checkbox is checked and form is submitted]]></string>
+    <string name="_adm_form_dsc_field_value_reset"><![CDATA[Button title (this button type is used to reset the form to its default state)]]></string>
+    <string name="_adm_form_dsc_field_value_submit"><![CDATA[Button title (this button type is used to send in the form data)]]></string>
+    <string name="_adm_form_dsc_field_visible_for_levels"><![CDATA[Select user levels that can see this menu item]]></string>
+    <string name="_adm_form_dsc_field_db_pass"><![CDATA[Select how field's data will be processed before saving in the database]]></string>
+    <string name="_adm_form_dsc_forms_title"><![CDATA[Name of the form. Displayed in Studio only.]]></string>
+    <string name="_adm_form_dsc_pre_lists_title"><![CDATA[List Name for Studio use only]]></string>
+    <string name="_adm_form_dsc_pre_values_empty"><![CDATA[You can use it for items like "Please select..." which can't be submitted.]]></string>
+    <string name="_adm_form_dsc_pre_values_lkey"><![CDATA[Item name displayed on site]]></string>
+    <string name="_adm_form_dsc_pre_values_icon"><![CDATA[Icon to show in a list (if supported)]]></string>
+    <string name="_adm_form_dsc_search_forms_fields_search_type"><![CDATA[The type of control element in search form]]></string>
+    <string name="_adm_form_dsc_search_forms_title"><![CDATA[Name of the search form. Displayed in Studio only.]]></string>
+    <string name="_adm_form_err_cannot_process_action"><![CDATA[Cannot process action. It does not have an associated handler.]]></string>
+    <string name="_adm_form_err_displays_edit"><![CDATA[Cannot update display]]></string>
+    <string name="_adm_form_err_displays_title"><![CDATA[Enter title, more than 3 characters]]></string>
+    <string name="_adm_form_err_field_add"><![CDATA[Cannot add new field]]></string>
+    <string name="_adm_form_err_field_add_already_exists"><![CDATA[Field with similar name already exists]]></string>
+    <string name="_adm_form_err_field_add_not_allowed"><![CDATA[Fields cannot be added in this form]]></string>
+    <string name="_adm_form_err_field_select_nested_form"><![CDATA[Nested form must be selected.]]></string>
+    <string name="_adm_form_err_field_caption"><![CDATA[A name with at least 3 characters is required.]]></string>
+    <string name="_adm_form_err_field_caption_system"><![CDATA[A name with at least 3 characters is required.]]></string>
+    <string name="_adm_form_err_field_checker_error"><![CDATA[You need to enter error message]]></string>
+    <string name="_adm_form_err_field_checker_func"><![CDATA[Check Function should be selected]]></string>
+    <string name="_adm_form_err_field_checker_params_length_max"><![CDATA[Enter Max Value, non-zero integer number]]></string>
+    <string name="_adm_form_err_field_checker_params_length_min"><![CDATA[Enter Min Value, non-zero integer number]]></string>
+    <string name="_adm_form_err_field_checker_params_preg"><![CDATA[Enter valid regular expression]]></string>
+    <string name="_adm_form_err_field_edit"><![CDATA[Cannot update field]]></string>
+    <string name="_adm_form_err_field_show_to"><![CDATA[Cannot update field]]></string>
+    <string name="_adm_form_err_field_value_doublerange"><![CDATA[Default value should be empty or looks like 12-23]]></string>
+    <string name="_adm_form_err_field_value_number"><![CDATA[Use numeric characters only]]></string>
+    <string name="_adm_form_err_field_values"><![CDATA[You need to select a data set from the list.]]></string>
+    <string name="_adm_form_err_forms_edit"><![CDATA[Cannot update form]]></string>
+    <string name="_adm_form_err_forms_title"><![CDATA[Enter name, more than 3 characters]]></string>
+    <string name="_adm_form_err_labels_add"><![CDATA[Cannot add label]]></string>
+    <string name="_adm_form_err_labels_edit"><![CDATA[Cannot update label]]></string>
+    <string name="_adm_form_err_labels_value"><![CDATA[Label should have unique non-empty value.]]></string>
+    <string name="_adm_form_err_missing_params"><![CDATA[The required parameters are missing.]]></string>
+    <string name="_adm_form_err_pre_lists_create"><![CDATA[Cannot add list]]></string>
+    <string name="_adm_form_err_pre_lists_edit"><![CDATA[Cannot update list]]></string>
+    <string name="_adm_form_err_pre_lists_title"><![CDATA[Enter title, more than 3 characters]]></string>
+    <string name="_adm_form_err_pre_values_create"><![CDATA[Cannot add item]]></string>
+    <string name="_adm_form_err_pre_values_create_forbidden"><![CDATA[This list is already used. It's impossible to add non-numeric, or less than 1, or more than {0} values in it.]]></string>
+    <string name="_adm_form_err_pre_values_delete"><![CDATA[Cannot delete item]]></string>
+    <string name="_adm_form_err_pre_values_edit"><![CDATA[Cannot update item]]></string>
+    <string name="_adm_form_err_pre_values_lkey"><![CDATA[Enter title, more than one character]]></string>
+    <string name="_adm_form_err_search_forms_essential"><![CDATA[The field is essential. Please fill in.]]></string>
+    <string name="_adm_form_err_search_forms_fields_edit"><![CDATA[Cannot update the search form field.]]></string>
+    <string name="_adm_from_err_search_forms_fields_reset"><![CDATA[Cannot reset the search form.]]></string>
+    <string name="_adm_from_err_search_forms_sortable_fields_reset"><![CDATA[Cannot reset the search form.]]></string>
+    <string name="_adm_form_err_search_forms_edit"><![CDATA[Cannot update the selected search form.]]></string>
+    <string name="_adm_form_err_search_forms_title"><![CDATA[Enter name, more than 3 characters]]></string>
+    <string name="_adm_form_txt_all_modules"><![CDATA[All Modules]]></string>
+    <string name="_adm_form_txt_confirm_delete"><![CDATA[Are you sure you want to delete this field? It will be deleted from all Displays! You may just turn it off instead.]]></string>
+    <string name="_adm_form_txt_audit_added"><![CDATA[Added]]></string>
+    <string name="_adm_form_txt_audit_profile"><![CDATA[Profile]]></string>
+    <string name="_adm_form_txt_audit_content"><![CDATA[Content]]></string>
+    <string name="_adm_form_txt_audit_module"><![CDATA[Module]]></string>
+    <string name="_adm_form_txt_audit_author_content"><![CDATA[Content's author]]></string>
+    <string name="_adm_pgt_txt_audit_context"><![CDATA[Context]]></string>
+    <string name="_adm_pgt_txt_audit_action"><![CDATA[Action]]></string>
+
+  <string name="_adm_form_txt_badges_text"><![CDATA[Text]]></string>
+  <string name="_adm_form_txt_badges_view"><![CDATA[View]]></string>
+  <string name="_adm_form_txt_badges_fontcolor"><![CDATA[Foreground color]]></string>
+  <string name="_adm_form_txt_badges_color"><![CDATA[Color]]></string>
+  <string name="_adm_form_dsc_badges_color"><![CDATA[Color]]></string>
+  <string name="_adm_form_txt_badges_is_icon_only"><![CDATA[Show icon only]]></string>
+  <string name="_adm_form_txt_badges_btn_current_icon_image_delete"><![CDATA[Delete]]></string>
+  <string name="_adm_form_txt_badges_icon"><![CDATA[Icon]]></string>
+  <string name="_adm_form_txt_badges_icon_image"><![CDATA[]]></string>
+  <string name="_adm_form_txt_badges_icon_image_new"><![CDATA[]]></string>
+  <string name="_adm_form_txt_badges_icon_image_old"><![CDATA[Current Icon]]></string>
+  <string name="_adm_form_dsc_badges_icon"><![CDATA[You may use: 1) font icon, 2) Inline SVG code, 3) Emoji]]></string>
+  <string name="_adm_form_dsc_badges_items_icon_image_current"><![CDATA[]]></string>
+  <string name="_adm_form_dsc_badges_icon_image"><![CDATA[or upload a small image to be displayed near the link.]]></string>
+  <string name="_adm_form_dsc_badges_icon_image_current"><![CDATA[No icon uploaded. Text is used in menu item.]]></string>
+  <string name="_adm_form_err_badges_icon"><![CDATA[You need to enter font icon name here.]]></string>
+  <string name="_adm_form_err_badges_icon_image"><![CDATA[Cannot process image: ]]></string>
+  <string name="_adm_form_err_badges_icon_image_remove"><![CDATA[Cannot remove icon image: ]]></string>
+  <string name="_adm_form_btn_badges_submit"><![CDATA[Submit]]></string>
+  <string name="_adm_form_btn_badges_cancel"><![CDATA[Cancel]]></string>
+  <string name="_adm_form_txt_badges_added"><![CDATA[Added]]></string>
+  <string name="_adm_form_txt_badges_module"><![CDATA[Module]]></string>
+  <string name="_adm_form_txt_badges_add_popup"><![CDATA[Add New Badge]]></string>
+  <string name="_adm_form_txt_badges_edit_popup"><![CDATA[Edit "{0}" badge]]></string>
+  <string name="_adm_pgt_txt_badges_text"><![CDATA[Text]]></string>
+  <string name="_adm_pgt_txt_badges_icon"><![CDATA[Icon]]></string>
+
+  <string name="_adm_form_txt_reports_object"><![CDATA[Object]]></string>
+  <string name="_adm_form_txt_reports_author"><![CDATA[Author]]></string>
+  <string name="_adm_form_txt_reports_type"><![CDATA[Type]]></string>
+  <string name="_adm_form_txt_reports_text"><![CDATA[Text]]></string>
+  <string name="_adm_form_txt_reports_date"><![CDATA[Date]]></string>
+  <string name="_adm_form_txt_reports_status"><![CDATA[Status]]></string>
+  <string name="_adm_form_txt_reports_checked_by"><![CDATA[Checked By]]></string>
+  <string name="_adm_form_txt_reports_notes"><![CDATA[Notes]]></string>
+  <string name="_adm_form_txt_reports_comments"><![CDATA[Comments]]></string>
+  <string name="_adm_form_txt_reports_action"><![CDATA[Actions]]></string>
+
+  <string name="_adm_form_txt_displays_edit_popup"><![CDATA[Edit "{0}" Display]]></string>
+	<string name="_adm_form_txt_displays_gl_fields"><![CDATA[Fields]]></string>
+	<string name="_adm_form_txt_displays_gl_form"><![CDATA[Form]]></string>
+	<string name="_adm_form_txt_displays_gl_module"><![CDATA[Module]]></string>
+	<string name="_adm_form_txt_displays_gl_title"><![CDATA[System Name]]></string>
+	<string name="_adm_form_txt_displays_manage_fields"><![CDATA[Manage fields]]></string>
+	<string name="_adm_form_txt_displays_title"><![CDATA[System Name]]></string>
+	<string name="_adm_form_txt_field_add_popup"><![CDATA[Add New Field]]></string>
+	<string name="_adm_form_txt_field_attrs_max"><![CDATA[Max Value]]></string>
+	<string name="_adm_form_txt_field_attrs_min"><![CDATA[Min Value]]></string>
+	<string name="_adm_form_txt_field_attrs_src"><![CDATA[Image Source]]></string>
+	<string name="_adm_form_txt_field_attrs_step"><![CDATA[Step]]></string>
+	<string name="_adm_form_txt_field_caption"><![CDATA[Display Name]]></string>
+	<string name="_adm_form_txt_field_caption_system"><![CDATA[System Name]]></string>
+	<string name="_adm_form_txt_field_checked"><![CDATA[Checked by default]]></string>
+	<string name="_adm_form_txt_field_checked_switcher"><![CDATA[Enabled by default]]></string>
+	<string name="_adm_form_txt_field_checker_avail"><![CDATA[Data Availability (something must be entered) ]]></string>
+	<string name="_adm_form_txt_field_checker_captcha"><![CDATA[Captcha (check for correct security image text input)]]></string>
+        <string name="_adm_form_txt_field_checker_custom"><![CDATA[Custom check]]></string>
+	<string name="_adm_form_txt_field_checker_date"><![CDATA[Date (check for correct date format)]]></string>
+        <string name="_adm_form_txt_field_checker_date_range"><![CDATA[Age's range]]></string>
+	<string name="_adm_form_txt_field_checker_date_time"><![CDATA[Date and Time (check for correct date and time format)]]></string>
+	<string name="_adm_form_txt_field_checker_email"><![CDATA[E-mail (correct email address format)]]></string>
+	<string name="_adm_form_txt_field_checker_empty"><![CDATA[Select...]]></string>
+	<string name="_adm_form_txt_field_checker_error"><![CDATA[Error message if check failed]]></string>
+	<string name="_adm_form_txt_field_checker_func"><![CDATA[Check for]]></string>
+        <string name="_adm_form_txt_field_checker_func_info_custom"><![CDATA[Note. It's not recommended to edit this field without absolute necessity.]]></string>
+	<string name="_adm_form_txt_field_checker_length"><![CDATA[Data Length (limit amount of characters)]]></string>
+        <string name="_adm_form_txt_field_checker_location"><![CDATA[Location Data (check for correct location data)]]></string>
+	<string name="_adm_form_txt_field_checker_no_spam"><![CDATA[Spam-Free (check if input is SPAM-free)]]></string>
+	<string name="_adm_form_txt_field_checker_params_length_max"><![CDATA[Max Value]]></string>
+	<string name="_adm_form_txt_field_checker_params_length_min"><![CDATA[Min Value]]></string>
+	<string name="_adm_form_txt_field_checker_params_required"><![CDATA[Required]]></string>
+	<string name="_adm_form_txt_field_checker_params_preg"><![CDATA[Expression]]></string>
+        <string name="_adm_form_txt_field_checker_password"><![CDATA[Password (correct password format with regular expression)]]></string>
+	<string name="_adm_form_txt_field_checker_preg"><![CDATA[Regular Expression (something specific must be entered)]]></string>
+	<string name="_adm_form_txt_field_collapsed"><![CDATA[Collapsed]]></string>
+	<string name="_adm_form_txt_field_edit_popup"><![CDATA[Edit "{0}" Field]]></string>
+	<string name="_adm_form_txt_field_html"><![CDATA[HTML Editor]]></string>
+	<string name="_adm_form_txt_field_html_full"><![CDATA[Full]]></string>
+	<string name="_adm_form_txt_field_html_mini"><![CDATA[Mini]]></string>
+	<string name="_adm_form_txt_field_html_none"><![CDATA[No Editor]]></string>
+	<string name="_adm_form_txt_field_html_standard"><![CDATA[Standard]]></string>
+        <string name="_adm_form_txt_field_icon"><![CDATA[Icon]]></string>
+        <string name="_adm_form_txt_field_icon_preview"><![CDATA[Current Icon]]></string>
+	<string name="_adm_form_txt_field_info"><![CDATA[Description]]></string>
+        <string name="_adm_form_txt_field_help"><![CDATA[Help]]></string>
+	<string name="_adm_form_txt_field_module"><![CDATA[Module]]></string>
+	<string name="_adm_form_txt_field_name"><![CDATA[Identifier]]></string>
+	<string name="_adm_form_txt_field_object"><![CDATA[Form]]></string>
+        <string name="_adm_form_txt_field_privacy"><![CDATA[Privacy]]></string>
+        <string name="_adm_form_txt_field_rateable"><![CDATA[Rateable]]></string>
+        <string name="_adm_form_txt_field_rateable_value_non"><![CDATA[Non-rateable]]></string>
+        <string name="_adm_form_txt_field_rateable_value_votes"><![CDATA[Use votes]]></string>
+        <string name="_adm_form_txt_field_rateable_value_reactions"><![CDATA[Use reactions]]></string>
+        <string name="_adm_form_txt_field_required"><![CDATA[Mandatory]]></string>
+        <string name="_adm_form_txt_field_select_nested_form"><![CDATA[Select nested form]]></string>
+	<string name="_adm_form_txt_field_show_to_popup"><![CDATA[Show "{0}" form field to: ]]></string>
+        <string name="_adm_form_txt_field_type_block_end"><![CDATA[block end]]></string>
+	<string name="_adm_form_txt_field_type_block_header"><![CDATA[block header]]></string>
+	<string name="_adm_form_txt_field_type_button"><![CDATA[button]]></string>
+	<string name="_adm_form_txt_field_type_captcha"><![CDATA[captcha]]></string>
+	<string name="_adm_form_txt_field_type_checkbox"><![CDATA[checkbox]]></string>
+	<string name="_adm_form_txt_field_type_checkbox_set"><![CDATA[checkbox set]]></string>
+	<string name="_adm_form_txt_field_type_custom"><![CDATA[custom]]></string>
+	<string name="_adm_form_txt_field_type_datepicker"><![CDATA[date]]></string>
+    <string name="_adm_form_txt_field_type_dateselect"><![CDATA[date select]]></string>
+	<string name="_adm_form_txt_field_type_datepicker_range"><![CDATA[date range]]></string>
+	<string name="_adm_form_txt_field_type_datepicker_range_age"><![CDATA[age range]]></string>
+	<string name="_adm_form_txt_field_type_datetime"><![CDATA[date time]]></string>
+	<string name="_adm_form_txt_field_type_datetime_range"><![CDATA[date time range]]></string>
+	<string name="_adm_form_txt_field_type_datetime_range_age"><![CDATA[age range]]></string>
+	<string name="_adm_form_txt_field_type_display"><![CDATA[Type]]></string>
+	<string name="_adm_form_txt_field_type_doublerange"><![CDATA[double range slider]]></string>
+	<string name="_adm_form_txt_field_type_file"><![CDATA[file]]></string>
+	<string name="_adm_form_txt_field_type_files"><![CDATA[files]]></string>
+	<string name="_adm_form_txt_field_type_hidden"><![CDATA[hidden]]></string>
+	<string name="_adm_form_txt_field_type_image"><![CDATA[image]]></string>
+	<string name="_adm_form_txt_field_type_input_set"><![CDATA[input set]]></string>
+	<string name="_adm_form_txt_field_type_location"><![CDATA[location]]></string>
+  <string name="_adm_form_txt_field_type_location_radius"><![CDATA[location radius]]></string>
+  <string name="_adm_form_txt_field_type_number"><![CDATA[number]]></string>
+  <string name="_adm_form_txt_field_type_price"><![CDATA[price]]></string>
+	<string name="_adm_form_txt_field_type_password"><![CDATA[password]]></string>
+	<string name="_adm_form_txt_field_type_radio_set"><![CDATA[radio set]]></string>
+	<string name="_adm_form_txt_field_type_reset"><![CDATA[reset]]></string>
+	<string name="_adm_form_txt_field_type_select"><![CDATA[select]]></string>
+	<string name="_adm_form_txt_field_type_select_multiple"><![CDATA[select (multiple)]]></string>
+	<string name="_adm_form_txt_field_type_slider"><![CDATA[slider]]></string>
+	<string name="_adm_form_txt_field_type_submit"><![CDATA[submit]]></string>
+	<string name="_adm_form_txt_field_type_switcher"><![CDATA[switcher]]></string>
+	<string name="_adm_form_txt_field_type_text"><![CDATA[text]]></string>
+        <string name="_adm_form_txt_field_type_text_range"><![CDATA[text (range)]]></string>
+	<string name="_adm_form_txt_field_type_text_auto"><![CDATA[auto text]]></string>
+	<string name="_adm_form_txt_field_type_textarea"><![CDATA[textarea]]></string>
+        <string name="_adm_form_txt_field_type_time"><![CDATA[time]]></string>
+	<string name="_adm_form_txt_field_type_value"><![CDATA[info]]></string>
+  <string name="_adm_form_txt_field_type_nested_form"><![CDATA[nested form]]></string>
+  <string name="_adm_form_txt_field_unique"><![CDATA[Unique]]></string>
+	<string name="_adm_form_txt_field_value_button"><![CDATA[Title]]></string>
+	<string name="_adm_form_txt_field_value_checkbox"><![CDATA[Value]]></string>
+	<string name="_adm_form_txt_field_value_custom_text"><![CDATA[Custom text]]></string>
+	<string name="_adm_form_txt_field_value_default"><![CDATA[Default value]]></string>
+	<string name="_adm_form_txt_field_value_files"><![CDATA[Enabled uploaders]]></string>
+	<string name="_adm_form_txt_field_value_select_value"><![CDATA[Select value...]]></string>
+	<string name="_adm_form_txt_field_values"><![CDATA[Values]]></string>
+	<string name="_adm_form_txt_field_values_manage"><![CDATA[Manage values]]></string>
+	<string name="_adm_form_txt_field_values_select_list"><![CDATA[Select list...]]></string>
+	<string name="_adm_form_txt_field_visible_for"><![CDATA[Visible For]]></string>
+	<string name="_adm_form_txt_field_visible_for_all"><![CDATA[Anyone]]></string>
+	<string name="_adm_form_txt_field_visible_for_levels"><![CDATA[Select Levels]]></string>
+	<string name="_adm_form_txt_field_visible_for_selected"><![CDATA[Selected levels]]></string>
+	<string name="_adm_form_txt_field_db_pass"><![CDATA[Process data as]]></string>
+	<string name="_adm_form_txt_field_db_pass_date"><![CDATA[Date]]></string>
+        <string name="_adm_form_txt_field_db_pass_date_ts"><![CDATA[Date as Unix Timestamp]]></string>
+        <string name="_adm_form_txt_field_db_pass_date_utc"><![CDATA[UTC Date as Unix Timestamp]]></string>
+	<string name="_adm_form_txt_field_db_pass_date_time"><![CDATA[Date/time]]></string>
+	<string name="_adm_form_txt_field_db_pass_date_time_ts"><![CDATA[Date/time as Unix Timestamp]]></string>
+	<string name="_adm_form_txt_field_db_pass_date_time_utc"><![CDATA[UTC Date/time as Unix Timestamp]]></string>
+        <string name="_adm_form_txt_field_db_pass_select_value"><![CDATA[Select value...]]></string>
+	<string name="_adm_form_txt_fields_caption_system"><![CDATA[System Name]]></string>
+	<string name="_adm_form_txt_fields_manage_visibility"><![CDATA[Manage visibility settings]]></string>
+	<string name="_adm_form_txt_fields_module"><![CDATA[Module]]></string>
+	<string name="_adm_form_txt_fields_type"><![CDATA[Type]]></string>
+	<string name="_adm_form_txt_fields_visible"><![CDATA[Visible For]]></string>
+	<string name="_adm_form_txt_forms_edit_popup"><![CDATA[Edit "{0}" Form]]></string>
+	<string name="_adm_form_txt_forms_gl_displays"><![CDATA[Displays]]></string>
+	<string name="_adm_form_txt_forms_gl_module"><![CDATA[Module]]></string>
+	<string name="_adm_form_txt_forms_gl_title"><![CDATA[System Name]]></string>
+	<string name="_adm_form_txt_forms_manage_displays"><![CDATA[Manage displays]]></string>
+	<string name="_adm_form_txt_forms_n_displays"><![CDATA[{0} displays]]></string>
+	<string name="_adm_form_txt_forms_n_fields"><![CDATA[{0} fields]]></string>
+	<string name="_adm_form_txt_forms_title"><![CDATA[System Name]]></string>
+        <string name="_adm_form_txt_labels_add_popup"><![CDATA[Add label]]></string>
+        <string name="_adm_form_txt_labels_edit_popup"><![CDATA[Edit "{0}" label]]></string>
+        <string name="_adm_form_txt_labels_items"><![CDATA[Items]]></string>
+        <string name="_adm_form_txt_labels_manage_items"><![CDATA[Manage child labels]]></string>
+        <string name="_adm_form_txt_labels_n_items"><![CDATA[{0} items]]></string>
+        <string name="_adm_form_txt_labels_parent"><![CDATA[Parent]]></string>
+        <string name="_adm_form_txt_labels_parent_empty"><![CDATA[No Parent]]></string>
+        <string name="_adm_form_txt_labels_grandparent_label"><![CDATA[Grandparent Label]]></string>
+        <string name="_adm_form_txt_labels_parent_label"><![CDATA[Parent Label]]></string>
+        <string name="_adm_form_txt_labels_sibling_labels"><![CDATA[Sibling Labels]]></string>
+        <string name="_adm_form_txt_labels_value"><![CDATA[Label]]></string>
+        <string name="_adm_form_txt_categories_author"><![CDATA[Author]]></string>
+        <string name="_adm_form_txt_categories_added"><![CDATA[Added]]></string>
+		<string name="_adm_form_txt_categories_module"><![CDATA[Module]]></string>
+        <string name="_adm_form_txt_categories_value"><![CDATA[Value]]></string>
+        <string name="_adm_form_txt_categories_add_popup"><![CDATA[Add category]]></string>
+        <string name="_adm_form_txt_categories_edit_popup"><![CDATA[Edit "{0}" category]]></string>
+        <string name="_adm_form_err_categories_value"><![CDATA[Category should have unique non-empty value.]]></string>
+      
+  
+    <string name="_adm_form_txt_pre_lists_country"><![CDATA[Country]]></string>
+    <string name="_adm_form_txt_pre_lists_create_popup"><![CDATA[Add New List]]></string>
+    <string name="_adm_form_txt_pre_lists_edit_popup"><![CDATA[Edit "{0}" List]]></string>
+    <string name="_adm_form_txt_pre_lists_gl_module"><![CDATA[Module]]></string>
+    <string name="_adm_form_txt_pre_lists_gl_title"><![CDATA[System Name]]></string>
+    <string name="_adm_form_txt_pre_lists_gl_use_for_sets"><![CDATA[Use For Sets]]></string>
+    <string name="_adm_form_txt_pre_lists_gl_values"><![CDATA[Values]]></string>
+    <string name="_adm_form_txt_pre_lists_language"><![CDATA[Language]]></string>
+    <string name="_adm_form_txt_pre_lists_currency"><![CDATA[Currency]]></string>
+    <string name="_adm_form_txt_pre_lists_manage_values"><![CDATA[Manage values]]></string>
+    <string name="_adm_form_txt_pre_lists_n_values"><![CDATA[{0} items]]></string>
+    <string name="_adm_form_txt_pre_lists_no"><![CDATA[No]]></string>
+    <string name="_adm_form_txt_pre_lists_sex"><![CDATA[Sex]]></string>
+    <string name="_adm_form_txt_pre_lists_title"><![CDATA[System Name]]></string>
+    <string name="_adm_form_txt_pre_lists_yes"><![CDATA[Yes]]></string>
+    <string name="_adm_form_txt_pre_values_create_popup"><![CDATA[Add New Item]]></string>
+    <string name="_adm_form_txt_pre_values_edit_popup"><![CDATA[Edit "{0}" Item]]></string>
+    <string name="_adm_form_txt_pre_values_empty"><![CDATA[Use empty value for this item]]></string>
+    <string name="_adm_form_txt_pre_values_gl_lkey"><![CDATA[Title]]></string>
+    <string name="_adm_form_txt_pre_values_lkey"><![CDATA[Title]]></string>
+    <string name="_adm_form_txt_pre_values_icon"><![CDATA[Icon]]></string>
+    <string name="_adm_form_txt_pre_values_icon_type"><![CDATA[Icon Type]]></string>
+    <string name="_adm_form_txt_pre_values_icon_type_emoji"><![CDATA[Emoji]]></string>
+    <string name="_adm_form_txt_pre_values_icon_type_icon"><![CDATA[Icon]]></string>
+    <string name="_adm_form_txt_pre_values_icon_type_image"><![CDATA[Image (inline SVG)]]></string>
+    <string name="_adm_form_txt_search_forms_edit_popup"><![CDATA[Edit "{0}" Search Form]]></string>
+    <string name="_adm_form_txt_search_forms_fields"><![CDATA[Fields]]></string>
+    <string name="_adm_form_txt_search_forms_sortable_fields"><![CDATA[Sortable Fields]]></string>
+    <string name="_adm_form_txt_search_forms_fields_type"><![CDATA[Type]]></string>
+    <string name="_adm_form_txt_search_forms_fields_caption"><![CDATA[Caption]]></string>
+    <string name="_adm_form_txt_search_forms_fields_info"><![CDATA[Description]]></string>
+    <string name="_adm_form_txt_search_forms_fields_search_type"><![CDATA[Search Type]]></string>
+    <string name="_adm_form_txt_search_forms_fields_select_object"><![CDATA[Select Form...]]></string>
+    <string name="_adm_form_txt_search_forms_fields_edit_popup"><![CDATA[Edit "{0}" Search Field]]></string>
+    <string name="_adm_form_txt_search_forms_sortable_fields_caption"><![CDATA[Caption]]></string>
+    <string name="_adm_form_txt_search_forms_sortable_fields_direction"><![CDATA[Direction]]></string>
+    <string name="_adm_form_txt_search_forms_manage_fields"><![CDATA[Manage fields]]></string>
+    <string name="_adm_form_txt_search_forms_module"><![CDATA[Module]]></string>
+    <string name="_adm_form_txt_search_forms_n_fields"><![CDATA[{0} fields]]></string>
+    <string name="_adm_form_txt_search_forms_title"><![CDATA[System Name]]></string>
+    <string name="_adm_form_txt_select_display"><![CDATA[Select Display...]]></string>
+    <string name="_adm_form_txt_select_form"><![CDATA[Select Form...]]></string>
+    <string name="_adm_form_txt_select_list"><![CDATA[Select List...]]></string>
+    <string name="_adm_from_err_field_delete"><![CDATA[Cannot delete field]]></string>
+    <string name="_adm_from_err_pre_lists_delete"><![CDATA[Cannot delete list]]></string>
+    <string name="_adm_ipbl_Date_of_finish"><![CDATA[Expiration date]]></string>
+    <string name="_adm_ipbl_IP_Role"><![CDATA[IP Role]]></string>
+    <string name="_adm_ipbl_Stored_members_caption"><![CDATA[Stored Logged Members IPs]]></string>
+    <string name="_adm_ipbl_Type0_desc"><![CDATA[IP List Type is 0 : disabled]]></string>
+    <string name="_adm_ipbl_Type1_desc"><![CDATA[IP List Type is 1 : All IPs allowed except listed]]></string>
+    <string name="_adm_ipbl_Type2_desc"><![CDATA[IP List Type is 2 : All IPs blocked except listed]]></string>
+    <string name="_adm_ipbl_sample"><![CDATA[sample]]></string>
+    <string name="_adm_lang_cnf_uninstall"><![CDATA[<h3>Uninstall "{0}" language?</h3><p>Uninstalling "{0}" language will also delete all of its data. Do you want to continue?</p>]]></string>
+    <string name="_adm_lmi_cpt_actions"><![CDATA[Actions]]></string>
+    <string name="_adm_lmi_cpt_api_config"><![CDATA[Configuration]]></string>
+    <string name="_adm_lmi_cpt_agents"><![CDATA[Agents]]></string>
+    <string name="_adm_lmi_cpt_ai_providers"><![CDATA[AI Providers]]></string>
+    <string name="_adm_lmi_cpt_tools"><![CDATA[Tools]]></string>
+    <string name="_adm_lmi_cpt_vector_store"><![CDATA[Vector Store]]></string>
+    <string name="_adm_lmi_cpt_assistants"><![CDATA[Assistants]]></string>
+    <string name="_adm_lmi_cpt_automators"><![CDATA[Automators]]></string>
+    <string name="_adm_lmi_cpt_helpers"><![CDATA[Helpers]]></string>
+    <string name="_adm_lmi_cpt_vector_store"><![CDATA[Vector Store]]></string>
+    <string name="_adm_lmi_cpt_badges"><![CDATA[Badges]]></string>
+    <string name="_adm_lmi_cpt_categories"><![CDATA[Categories]]></string>
+    <string name="_adm_lmi_cpt_checkout"><![CDATA[Checkout {checkout_counter}]]></string>
+    <string name="_adm_lmi_ttl_checkout"><![CDATA[Checkout]]></string>
+    <string name="_adm_lmi_cpt_cover"><![CDATA[Covers]]></string>
+    <string name="_adm_lmi_cpt_search"><![CDATA[Search]]></string>
+    <string name="_adm_lmi_cpt_search_forms"><![CDATA[Search Forms]]></string>
+    <string name="_adm_lmi_cpt_search_fields"><![CDATA[Search Fields]]></string>
+    <string name="_adm_lmi_cpt_search_sortable_fields"><![CDATA[Search Sortable Fields]]></string>
+    <string name="_adm_lmi_cpt_splash"><![CDATA[Welcome page]]></string>
+    <string name="_adm_lmi_cpt_displays"><![CDATA[Displays]]></string>
+    <string name="_adm_lmi_cpt_downloaded"><![CDATA[Downloaded]]></string>
+    <string name="_adm_lmi_cpt_etemplates_text"><![CDATA[Email Texts]]></string>
+    <string name="_adm_lmi_cpt_etemplates_html"><![CDATA[Email Template]]></string>
+    <string name="_adm_lmi_cpt_featured"><![CDATA[Featured]]></string>
+    <string name="_adm_lmi_cpt_fields"><![CDATA[Fields]]></string>
+    <string name="_adm_lmi_cpt_files"><![CDATA[Files]]></string>
+    <string name="_adm_lmi_cpt_forms"><![CDATA[Forms]]></string>
+    <string name="_adm_lmi_cpt_general"><![CDATA[General]]></string>
+    <string name="_adm_lmi_cpt_goodies"><![CDATA[Storefront]]></string>
+    <string name="_adm_lmi_cpt_icon"><![CDATA[Site Icon]]></string>
+    <string name="_adm_lmi_cpt_injections"><![CDATA[Injections]]></string>
+    <string name="_adm_lmi_cpt_images"><![CDATA[Images]]></string>
+    <string name="_adm_lmi_cpt_items"><![CDATA[Items]]></string>
+    <string name="_adm_lmi_cpt_keys"><![CDATA[Keys]]></string>
+    <string name="_adm_lmi_cpt_pgt_settings"><![CDATA[i18n Settings]]></string>
+    <string name="_adm_lmi_cpt_pgt_keys"><![CDATA[Text Keys]]></string>
+    <string name="_adm_lmi_cpt_labels"><![CDATA[Labels]]></string>
+    <string name="_adm_lmi_cpt_latest"><![CDATA[Latest]]></string>
+    <string name="_adm_lmi_cpt_levels"><![CDATA[Levels]]></string>
+    <string name="_adm_lmi_cpt_logo"><![CDATA[Logo]]></string>
+    <string name="_adm_lmi_cpt_menus"><![CDATA[Menus]]></string>
+    <string name="_adm_lmi_cpt_origins"><![CDATA[Origins]]></string>
+    <string name="_adm_lmi_cpt_pre_lists"><![CDATA[Data Lists]]></string>
+    <string name="_adm_lmi_cpt_pre_values"><![CDATA[Data Items]]></string>
+    <string name="_adm_lmi_cpt_providers"><![CDATA[Providers]]></string>
+    <string name="_adm_lmi_cpt_popular"><![CDATA[Popular]]></string>
+    <string name="_adm_lmi_cpt_purchases"><![CDATA[Purchases]]></string>
+    <string name="_adm_lmi_cpt_pwa"><![CDATA[Progressive Web App]]></string>
+    <string name="_adm_lmi_cpt_ractions"><![CDATA[Actions]]></string>
+    <string name="_adm_lmi_cpt_reports"><![CDATA[Reports]]></string>
+    <string name="_adm_lmi_cpt_rlevels"><![CDATA[Levels]]></string>
+    <string name="_adm_lmi_cpt_sets"><![CDATA[Sets]]></string>
+    <string name="_adm_lmi_cpt_settings"><![CDATA[Settings]]></string>
+    <string name="_adm_lmi_cpt_updates"><![CDATA[Updates]]></string>
+    <string name="_adm_mobile_page_homepage"><![CDATA[Homepage]]></string>
+    <string name="_adm_mobile_page_profile"><![CDATA[Profile]]></string>
+    <string name="_adm_mod_cnf_uninstall"><![CDATA[<h3>Uninstall "{0}" module?</h3><p>Uninstalling "{0}" module will also delete all of its data. Do you want to continue?</p>]]></string>
+    <string name="_adm_mod_err_cannot_process_action"><![CDATA[Cannot process action. It does not have an associated handler.]]></string>
+    <string name="_adm_mod_err_only_admin_can_perform_operations_with_modules"><![CDATA[Only admin can perform operations with modules]]></string>
+	<string name="_adm_mod_err_process_operation_failed"><![CDATA[Cannot {0} module from "{1}" directory]]></string>
+	<string name="_adm_mod_msg_process_operation_scheduled"><![CDATA[Operation was scheduled and will be performed in a few minutes. Please wait.]]></string>	
+	<string name="_adm_msg_modules_success_added_to_cart"><![CDATA[The product was successfully added to shopping cart.]]></string>
+	<string name="_adm_msg_modules_success_checkouted"><![CDATA[The payment was successfully accepted and should be processed automatically in a few minutes. Then the purchased product(s) will be available in Apps -> Purchases. If it doesn't happen for some reason, please contact product's vendor with your payment details.]]></string>
+	<string name="_adm_msg_modules_success_delete"><![CDATA[The package was deleted successfully]]></string>
+	<string name="_adm_msg_modules_success_disable"><![CDATA[The package was disabled successfully]]></string>
+	<string name="_adm_msg_modules_success_enable"><![CDATA[The package was enabled successfully]]></string>
+	<string name="_adm_msg_modules_success_install"><![CDATA[The package was installed successfully]]></string>
+	<string name="_adm_msg_modules_success_uninstall"><![CDATA[The package was uninstalled successfully]]></string>
+	<string name="_adm_msg_oauth_need_authorize"><![CDATA[You need to to login into your <b>UNA</b> account to get data. Click <a href="{0}">here</a> to login.]]></string>
+        <string name="_adm_msg_oauth_non_owner_logged"><![CDATA[WARNING: You are logged in to an <a href="{0}">UNA.IO</a> account which is different from the account that generated UNA Key & Secret for your domain.]]></string>
+	<string name="_adm_nav_btn_current_icon_image_delete"><![CDATA[Delete]]></string>
+	<string name="_adm_nav_btn_items_add"><![CDATA[Add]]></string>
+	<string name="_adm_nav_btn_items_cancel"><![CDATA[Cancel]]></string>
+	<string name="_adm_nav_btn_items_delete"><![CDATA[Delete item]]></string>
+	<string name="_adm_nav_btn_items_done"><![CDATA[Done]]></string>
+	<string name="_adm_nav_btn_items_edit"><![CDATA[Edit item]]></string>
+	<string name="_adm_nav_btn_items_gl_create"><![CDATA[Add New Item]]></string>
+	<string name="_adm_nav_btn_items_gl_import"><![CDATA[Import Items]]></string>
+	<string name="_adm_nav_btn_items_gl_visible"><![CDATA[Visible For]]></string>
+	<string name="_adm_nav_btn_items_import"><![CDATA[Import item]]></string>
+	<string name="_adm_nav_btn_items_save"><![CDATA[Save]]></string>
+	<string name="_adm_nav_btn_menus_add"><![CDATA[Add]]></string>
+	<string name="_adm_nav_btn_menus_cancel"><![CDATA[Cancel]]></string>
+	<string name="_adm_nav_btn_menus_create"><![CDATA[Add New Menu]]></string>
+	<string name="_adm_nav_btn_menus_delete"><![CDATA[Delete Menu]]></string>
+	<string name="_adm_nav_btn_menus_edit"><![CDATA[Edit Menu]]></string>
+	<string name="_adm_nav_btn_menus_save"><![CDATA[Save]]></string>
+	<string name="_adm_nav_btn_sets_add"><![CDATA[Add]]></string>
+	<string name="_adm_nav_btn_sets_cancel"><![CDATA[Cancel]]></string>
+	<string name="_adm_nav_btn_sets_create"><![CDATA[Add New Set]]></string>
+	<string name="_adm_nav_btn_sets_delete"><![CDATA[Delete set]]></string>
+	<string name="_adm_nav_btn_sets_edit"><![CDATA[Edit set]]></string>
+        <string name="_adm_nav_dsc_items_area_label"><![CDATA[Accessible name for the link. It is useful when the visible text content of the link is not descriptive enough or absent.]]></string>
+	<string name="_adm_nav_dsc_items_icon"><![CDATA[You may use font icon, SVG or Emoji code here]]></string>
+	<string name="_adm_nav_dsc_items_icon_image"><![CDATA[or upload a small image to be displayed near the link.]]></string>
+	<string name="_adm_nav_dsc_items_icon_image_current"><![CDATA[No icon uploaded. Text is used in menu item.]]></string>
+	<string name="_adm_nav_dsc_items_link"><![CDATA[Enter the link URL]]></string>
+	<string name="_adm_nav_dsc_items_onclick"><![CDATA[Enter a correct JavaScript code for the link]]></string>
+        <string name="_adm_nav_dsc_items_parent_id"><![CDATA[Use it to create multilevel menu inside one menu. Leave empty for one level menus.]]></string>
+	<string name="_adm_nav_dsc_items_submenu"><![CDATA[Select if you want the link to use another menu as submenu.]]></string>
+	<string name="_adm_nav_dsc_items_target"><![CDATA[Select if you want the link to open as a new page or within current page.]]></string>
+	<string name="_adm_nav_dsc_items_title"><![CDATA[Link name displayed in site menus. Use at least 3 characters.]]></string>
+        <string name="_adm_nav_dsc_items_title_attr"><![CDATA[A text which will be used in 'title' attribute of the link.]]></string>
+	<string name="_adm_nav_dsc_items_title_system"><![CDATA[Item name, displayed in Studio only.]]></string>
+        <string name="_adm_nav_dsc_items_info"><![CDATA[The value can be shown below the link name as short description.]]></string>
+	<string name="_adm_nav_dsc_items_visible_for_levels"><![CDATA[Select user levels that can see this menu item]]></string>
+	<string name="_adm_nav_dsc_menus_persistent"><![CDATA[Number of persistent menu items. Applicable for menus with 'Auto More' mechanism only.]]></string>
+        <string name="_adm_nav_dsc_menus_set_name"><![CDATA[Assign a Set of menu Items]]></string>
+	<string name="_adm_nav_dsc_menus_set_title"><![CDATA[Descriptive name displayed in Studio only. Use at least 3 characters.]]></string>
+	<string name="_adm_nav_dsc_menus_style"><![CDATA[Select presentation style - the way this menu will be displayed on site]]></string>
+	<string name="_adm_nav_dsc_menus_title"><![CDATA[Descriptive name displayed in Studio only. Use at least 3 characters.]]></string>
+	<string name="_adm_nav_dsc_sets_title"><![CDATA[Descriptive name displayed in Studio only. Use at least 3 characters.]]></string>
+	<string name="_adm_nav_err_cannot_process_action"><![CDATA[Cannot process action. It does not have an associated handler.]]></string>
+	<string name="_adm_nav_err_items_create"><![CDATA[Cannot create item]]></string>
+	<string name="_adm_nav_err_items_delete"><![CDATA[Cannot delete item]]></string>
+	<string name="_adm_nav_err_items_edit"><![CDATA[Cannot update item]]></string>
+	<string name="_adm_nav_err_items_icon"><![CDATA[You need to enter font icon name here.]]></string>
+	<string name="_adm_nav_err_items_icon_image"><![CDATA[Cannot process image: ]]></string>
+	<string name="_adm_nav_err_items_icon_image_remove"><![CDATA[Cannot remove icon image: ]]></string>
+	<string name="_adm_nav_err_items_import"><![CDATA[Cannot import item(s)]]></string>
+	<string name="_adm_nav_err_items_link"><![CDATA[You need to enter item URL]]></string>
+	<string name="_adm_nav_err_items_onclick"><![CDATA[You need to enter item OnClick]]></string>
+	<string name="_adm_nav_err_items_show_to"><![CDATA[Cannot update item]]></string>
+	<string name="_adm_nav_err_menus_create"><![CDATA[Cannot create menu]]></string>
+	<string name="_adm_nav_err_menus_delete"><![CDATA[Cannot delete menu]]></string>
+	<string name="_adm_nav_err_menus_edit"><![CDATA[Cannot update menu]]></string>
+	<string name="_adm_nav_err_menus_set_name"><![CDATA[Please, assign a Set.]]></string>
+	<string name="_adm_nav_err_menus_set_title"><![CDATA[A unique title with at least 3 characters is required.]]></string>
+	<string name="_adm_nav_err_menus_style"><![CDATA[Please, select a presentation style.]]></string>
+	<string name="_adm_nav_err_menus_title"><![CDATA[A title with at least 3 characters is required.]]></string>
+	<string name="_adm_nav_err_missing_params"><![CDATA[The required parameters are missing.]]></string>
+	<string name="_adm_nav_err_sets_create"><![CDATA[Cannot create set]]></string>
+	<string name="_adm_nav_err_sets_delete"><![CDATA[Cannot delete set]]></string>
+	<string name="_adm_nav_err_sets_delete_used"><![CDATA[Set can't be deleted because it is in use]]></string>
+	<string name="_adm_nav_err_sets_edit"><![CDATA[Cannot update set]]></string>
+	<string name="_adm_nav_err_sets_title"><![CDATA[A title with at least 3 characters is required.]]></string>
+	<string name="_adm_nav_txt_all_modules"><![CDATA[All Modules]]></string>
+        <string name="_adm_nav_txt_items_area_label"><![CDATA[Text for 'area-label' attribute]]></string>
+        <string name="_adm_nav_txt_items_collapsed"><![CDATA[Collapsed]]></string>
+    <string name="_adm_nav_txt_items_persistent"><![CDATA[Persistant]]></string>
+    
+	<string name="_adm_nav_txt_items_create_popup"><![CDATA[Add New Item]]></string>
+	<string name="_adm_nav_txt_items_edit_popup"><![CDATA[Edit {0} Item]]></string>
+	<string name="_adm_nav_txt_items_gl_icon"><![CDATA[Icon]]></string>
+	<string name="_adm_nav_txt_items_gl_link"><![CDATA[URL]]></string>
+	<string name="_adm_nav_txt_items_gl_link_custom"><![CDATA[Custom Action]]></string>
+	<string name="_adm_nav_txt_items_gl_link_menu"><![CDATA[Menu:]]></string>
+        <string name="_adm_nav_txt_items_gl_link_subitems"><![CDATA[Subitems:]]></string>
+	<string name="_adm_nav_txt_items_gl_module"><![CDATA[Module]]></string>
+	<string name="_adm_nav_txt_items_gl_title_system"><![CDATA[System Name]]></string>
+	<string name="_adm_nav_txt_items_gl_visible"><![CDATA[Visible For]]></string>
+	<string name="_adm_nav_txt_items_icon"><![CDATA[Icon]]></string>
+	<string name="_adm_nav_txt_items_icon_image"><![CDATA[]]></string>
+	<string name="_adm_nav_txt_items_icon_image_new"><![CDATA[]]></string>
+	<string name="_adm_nav_txt_items_icon_image_old"><![CDATA[Current Icon]]></string>
+        <string name="_adm_nav_txt_items_icon_only"><![CDATA[Icon only]]></string>
+	<string name="_adm_nav_txt_items_import_popup"><![CDATA[Import Items]]></string>
+	<string name="_adm_nav_txt_items_link"><![CDATA[URL]]></string>
+	<string name="_adm_nav_txt_items_onclick"><![CDATA[OnClick]]></string>
+        <string name="_adm_nav_txt_items_parent_id"><![CDATA[Parent Item]]></string>
+        <string name="_adm_nav_txt_items_parent_id_empty"><![CDATA[No Parent Item]]></string>
+        <string name="_adm_nav_txt_items_primary"><![CDATA[Primary]]></string>
+        <string name="_adm_nav_txt_items_active_api"><![CDATA[Active (for App)]]></string>
+	<string name="_adm_nav_txt_items_show_to_popup"><![CDATA[Show "{0}" menu item to: ]]></string>
+	<string name="_adm_nav_txt_items_submenu"><![CDATA[Submenu]]></string>
+	<string name="_adm_nav_txt_items_submenu_empty"><![CDATA[No Submenu]]></string>
+	<string name="_adm_nav_txt_items_submenu_popup"><![CDATA[Show submenu in popup]]></string>
+	<string name="_adm_nav_txt_items_target"><![CDATA[Target]]></string>
+	<string name="_adm_nav_txt_items_target_blank"><![CDATA[New Page]]></string>
+	<string name="_adm_nav_txt_items_target_self"><![CDATA[Same Page]]></string>
+	<string name="_adm_nav_txt_items_title"><![CDATA[Display Name]]></string>
+        <string name="_adm_nav_txt_items_title_attr"><![CDATA[Title]]></string>
+	<string name="_adm_nav_txt_items_title_system"><![CDATA[System Name]]></string>
+        <string name="_adm_nav_txt_items_info"><![CDATA[Info]]></string>
+	<string name="_adm_nav_txt_items_visible_for"><![CDATA[Visible For]]></string>
+	<string name="_adm_nav_txt_items_visible_for_all"><![CDATA[Anyone]]></string>
+	<string name="_adm_nav_txt_items_visible_for_levels"><![CDATA[Select Levels]]></string>
+	<string name="_adm_nav_txt_items_visible_for_selected"><![CDATA[Selected levels]]></string>
+	<string name="_adm_nav_txt_manage_items"><![CDATA[Manage items]]></string>
+	<string name="_adm_nav_txt_manage_visibility"><![CDATA[Manage visibility settings]]></string>
+	<string name="_adm_nav_txt_menus_create_popup"><![CDATA[Add New Menu]]></string>
+	<string name="_adm_nav_txt_menus_edit_popup"><![CDATA[Edit "{0}" Menu]]></string>
+	<string name="_adm_nav_txt_menus_gl_items"><![CDATA[Items]]></string>
+	<string name="_adm_nav_txt_menus_gl_module"><![CDATA[Module]]></string>
+	<string name="_adm_nav_txt_menus_gl_set_title"><![CDATA[Set]]></string>
+	<string name="_adm_nav_txt_menus_gl_template_title"><![CDATA[Style]]></string>
+	<string name="_adm_nav_txt_menus_gl_title"><![CDATA[System Name]]></string>
+        <string name="_adm_nav_txt_menus_persistent"><![CDATA[Persistent items]]></string>
+	<string name="_adm_nav_txt_menus_set_name"><![CDATA[Set]]></string>
+	<string name="_adm_nav_txt_menus_set_name_new"><![CDATA[Create New]]></string>
+	<string name="_adm_nav_txt_menus_set_name_select"><![CDATA[Select Set...]]></string>
+	<string name="_adm_nav_txt_menus_set_title"><![CDATA[Set Title]]></string>
+	<string name="_adm_nav_txt_menus_style"><![CDATA[Style]]></string>
+	<string name="_adm_nav_txt_menus_style_select"><![CDATA[Select Style...]]></string>
+	<string name="_adm_nav_txt_menus_title"><![CDATA[System Name]]></string>
+        <string name="_adm_nav_txt_menus_title_public"><![CDATA[Display Name]]></string>
+	<string name="_adm_nav_txt_n_items"><![CDATA[{0} items]]></string>
+	<string name="_adm_nav_txt_select_set"><![CDATA[Select Set...]]></string>
+	<string name="_adm_nav_txt_sets_create_popup"><![CDATA[Add New Set]]></string>
+	<string name="_adm_nav_txt_sets_edit_popup"><![CDATA[Edit "{0}" Set]]></string>
+	<string name="_adm_nav_txt_sets_gl_items"><![CDATA[Items]]></string>
+	<string name="_adm_nav_txt_sets_gl_module"><![CDATA[Module]]></string>
+	<string name="_adm_nav_txt_sets_gl_title"><![CDATA[System Name]]></string>
+	<string name="_adm_nav_txt_sets_title"><![CDATA[System Name]]></string>
+        <string name="_adm_nav_txt_block_hidden_on"><![CDATA[Hidden on]]></string>
+        <string name="_adm_nav_txt_block_hidden_on_phone"><![CDATA[phone]]></string>
+        <string name="_adm_nav_txt_block_hidden_on_tablet"><![CDATA[tablet]]></string>
+        <string name="_adm_nav_txt_block_hidden_on_desktop"><![CDATA[desktop]]></string>
+        <string name="_adm_nav_txt_block_hidden_on_mobile"><![CDATA[mobile app]]></string>
+        <string name="_adm_nav_txt_block_hidden_on_pt"><![CDATA[Hidden for page type]]></string>
+        <string name="_adm_nav_txt_block_hidden_on_col"><![CDATA[Hidden for column]]></string>
+        <string name="_adm_nav_txt_block_hidden_on_col_thin"><![CDATA[Thin]]></string>
+        <string name="_adm_nav_txt_block_hidden_on_col_half"><![CDATA[Half]]></string>
+        <string name="_adm_nav_txt_block_hidden_on_col_wide"><![CDATA[Wide]]></string>
+        <string name="_adm_nav_txt_block_hidden_on_col_full"><![CDATA[Full]]></string>
+        <string name="_adm_page_cpt_api"><![CDATA[API]]></string>
+        <string name="_adm_page_cpt_agents"><![CDATA[Agents]]></string>
+        <string name="_adm_page_cpt_audit"><![CDATA[Audit]]></string>
+        <string name="_adm_page_cpt_badges"><![CDATA[Badges]]></string>
+	<string name="_adm_page_cpt_builder_forms"><![CDATA[Forms]]></string>
+	<string name="_adm_page_cpt_builder_menus"><![CDATA[Navigation]]></string>
+	<string name="_adm_page_cpt_builder_mobile"><![CDATA[Mobile Builder]]></string>
+	<string name="_adm_page_cpt_builder_pages"><![CDATA[Pages]]></string>
+	<string name="_adm_page_cpt_builder_permissions"><![CDATA[Permissions]]></string>
+        <string name="_adm_page_cpt_builder_roles"><![CDATA[Roles]]></string>
+	<string name="_adm_page_cpt_dashboard"><![CDATA[Dashboard]]></string>
+	<string name="_adm_page_cpt_designer"><![CDATA[Designer]]></string>
+	<string name="_adm_page_cpt_home"><![CDATA[Studio]]></string>
+	<string name="_adm_page_cpt_login"><![CDATA[Login]]></string>
+	<string name="_adm_page_cpt_polyglot"><![CDATA[Polyglot]]></string>
+	<string name="_adm_page_cpt_settings"><![CDATA[Settings]]></string>
+	<string name="_adm_page_cpt_storages"><![CDATA[Storage]]></string>
+	<string name="_adm_page_cpt_store"><![CDATA[Apps]]></string>
+	<string name="_adm_pgt_btn_add_new_key"><![CDATA[Create New Key]]></string>
+	<string name="_adm_pgt_btn_delete"><![CDATA[Delete]]></string>
+	<string name="_adm_pgt_btn_delete_title"><![CDATA[Delete key]]></string>
+	<string name="_adm_pgt_btn_edit_title"><![CDATA[Edit key]]></string>
+	<string name="_adm_pgt_btn_etemplates_cancel"><![CDATA[Cancel]]></string>
+	<string name="_adm_pgt_btn_etemplates_gl_edit_title"><![CDATA[Edit template]]></string>
+	<string name="_adm_pgt_btn_etemplates_save"><![CDATA[Save]]></string>
+	<string name="_adm_pgt_btn_nkp_close"><![CDATA[Close]]></string>
+	<string name="_adm_pgt_btn_nkp_create"><![CDATA[Create]]></string>
+	<string name="_adm_pgt_btn_nkp_save"><![CDATA[Save]]></string>
+	<string name="_adm_pgt_dsc_etemplates_body"><![CDATA[Body of a message]]></string>
+	<string name="_adm_pgt_dsc_etemplates_name_system"><![CDATA[Name of the template. Displayed in Studio only.]]></string>
+	<string name="_adm_pgt_dsc_etemplates_subject"><![CDATA[Subject of a message]]></string>
+	<string name="_adm_pgt_err_cannot_process_action"><![CDATA[Cannot process action. It does not have an associated handler.]]></string>
+	<string name="_adm_pgt_err_cannot_recompile_lang"><![CDATA[Cannot recompile language(s).]]></string>
+	<string name="_adm_pgt_err_cannot_restore_lang"><![CDATA[Cannot restore language(s).]]></string>
+	<string name="_adm_pgt_err_create_key"><![CDATA[Cannot create key]]></string>
+	<string name="_adm_pgt_err_create_key_empty_fields"><![CDATA[You need to fill in the form.]]></string>
+	<string name="_adm_pgt_err_deactivate_default"><![CDATA[You cannot deactivate language which was selected as Default]]></string>
+	<string name="_adm_pgt_err_etemplates_body"><![CDATA[Enter body]]></string>
+	<string name="_adm_pgt_err_etemplates_edit"><![CDATA[Cannot update template]]></string>
+	<string name="_adm_pgt_err_etemplates_name_system"><![CDATA[Enter name, more than 3 characters]]></string>
+	<string name="_adm_pgt_err_etemplates_subject"><![CDATA[Enter subject]]></string>
+	<string name="_adm_pgt_err_last_active"><![CDATA[You need to have at least one active language.]]></string>
+	<string name="_adm_pgt_err_save"><![CDATA[Cannot save changes]]></string>
+	<string name="_adm_pgt_scs_recompiled"><![CDATA[Language(s) was successfully recompiled.]]></string>
+	<string name="_adm_pgt_scs_restored"><![CDATA[Language(s) was successfully restored.]]></string>
+	<string name="_adm_pgt_txt_all_modules"><![CDATA[All Modules]]></string>
+	<string name="_adm_pgt_txt_etemplates_body"><![CDATA[Body]]></string>
+	<string name="_adm_pgt_txt_etemplates_edit_popup"><![CDATA[Edit "{0}" Template]]></string>
+	<string name="_adm_pgt_txt_etemplates_gl_module"><![CDATA[Module]]></string>
+	<string name="_adm_pgt_txt_etemplates_gl_name_system"><![CDATA[System Title]]></string>
+	<string name="_adm_pgt_txt_etemplates_name_system"><![CDATA[System Name]]></string>
+	<string name="_adm_pgt_txt_etemplates_subject"><![CDATA[Subject]]></string>
+	<string name="_adm_pgt_txt_key"><![CDATA[Key]]></string>
+	<string name="_adm_pgt_txt_keyword"><![CDATA[Keyword...]]></string>
+	<string name="_adm_pgt_txt_languages"><![CDATA[Languages]]></string>
+	<string name="_adm_pgt_txt_module"><![CDATA[Module]]></string>
+	<string name="_adm_pgt_txt_nkp_add_popup"><![CDATA[Create New Key]]></string>
+	<string name="_adm_pgt_txt_nkp_edit_popup"><![CDATA[Edit "{0}" Key]]></string>
+	<string name="_adm_pgt_txt_nkp_key_name"><![CDATA[Key Name]]></string>
+	<string name="_adm_pgt_txt_nkp_module"><![CDATA[Module]]></string>
+	<string name="_adm_pgt_txt_text"><![CDATA[Text]]></string>
+        <string name="_adm_pgt_txt_et_c_content"><![CDATA[Message itself will be here.]]></string>
+	<string name="_adm_pgt_txt_et_hf_inf"><![CDATA[Note, that improper use of HTML may break the email message's layout. Also make sure that {unsubscribe} marker presents in at least one of the templates (header and/or footer).]]></string>
+        <string name="_adm_pgt_btn_et_hf_editor"><![CDATA[Use visual editor]]></string>
+	<string name="_adm_pgt_btn_et_hf_submit"><![CDATA[Submit]]></string>
+	<string name="_adm_pgt_scs_et_hf_save"><![CDATA[The changes were successfully saved.]]></string>
+	<string name="_adm_pgt_err_et_hf_save"><![CDATA[Cannot save changes.]]></string>
+	<string name="_adm_pgt_err_et_hf_save_unsubscribe"><![CDATA[Cannot save changes, because {unsubscribe} marker was removed from both templates, header and footer.]]></string>
+	<string name="_adm_prm_btn_actions_cancel"><![CDATA[Cancel]]></string>
+	<string name="_adm_prm_btn_actions_options"><![CDATA[Edit options]]></string>
+	<string name="_adm_prm_btn_actions_save"><![CDATA[Save]]></string>
+	<string name="_adm_prm_btn_add_level"><![CDATA[Add New Level]]></string>
+	<string name="_adm_prm_btn_add_price"><![CDATA[Add New Pricing Option]]></string>
+	<string name="_adm_prm_btn_level_add"><![CDATA[Add Level]]></string>
+	<string name="_adm_prm_btn_level_cancel"><![CDATA[Cancel]]></string>
+	<string name="_adm_prm_btn_level_delete"><![CDATA[Delete level]]></string>
+	<string name="_adm_prm_btn_level_edit"><![CDATA[Edit level]]></string>
+	<string name="_adm_prm_btn_level_save"><![CDATA[Save]]></string>
+	<string name="_adm_prm_btn_price_add"><![CDATA[Add]]></string>
+	<string name="_adm_prm_btn_price_cancel"><![CDATA[Cancel]]></string>
+	<string name="_adm_prm_btn_price_delete"><![CDATA[Delete pricing option]]></string>
+	<string name="_adm_prm_btn_price_edit"><![CDATA[Edit pricing option]]></string>
+	<string name="_adm_prm_btn_price_save"><![CDATA[Save]]></string>
+	<string name="_adm_prm_dsc_actions_avail"><![CDATA[Leave it blank if the action is always available]]></string>
+	<string name="_adm_prm_dsc_actions_number"><![CDATA[Leave it blank for unlimited actions]]></string>
+	<string name="_adm_prm_dsc_actions_reset"><![CDATA[In hours. Leave it blank if you don't want to reset counter]]></string>
+        <string name="_adm_prm_dsc_level_unavailable_to"><![CDATA[Select nothing if a level should be available to all profile types.]]></string>
+	<string name="_adm_prm_dsc_level_description"><![CDATA[Brief overview of terms and advantages of this level.]]></string>
+	<string name="_adm_prm_dsc_level_icon"><![CDATA[You may use font icon here]]></string>
+	<string name="_adm_prm_dsc_level_icon_image"><![CDATA[or upload an image.]]></string>
+	<string name="_adm_prm_dsc_level_name"><![CDATA[Short name for the membership level (i.e Premium, Gold, Newcomer, etc.)]]></string>
+	<string name="_adm_prm_dsc_level_quota_max_file_size"><![CDATA[Limit max file size for user with this level across all modules (0 - unlimited, other system limits may apply).]]></string>
+	<string name="_adm_prm_dsc_level_quota_number"><![CDATA[Limit  amount of files a user with this level can upload (0 - unlimited).]]></string>
+        <string name="_adm_prm_dsc_level_password_expired"><![CDATA[Period after which the password must be changed, in days (0 - unlimited).]]></string>
+        <string name="_adm_prm_dsc_level_password_expired_notify"><![CDATA[The period for which the notification of an expired password will be sent, in days (0 - unlimited).]]></string>    
+	<string name="_adm_prm_dsc_level_quota_size"><![CDATA[Limit how much space can be used by user with this level across all modules (0 - unlimited).]]></string>
+	<string name="_adm_prm_dsc_price_add_days"><![CDATA[Use 0 for life-time]]></string>
+	<string name="_adm_prm_err_action_edit"><![CDATA[Cannot update membership action's options]]></string>
+        <string name="_adm_prm_err_level_create"><![CDATA[Cannot create membership level]]></string>
+	<string name="_adm_prm_err_level_delete"><![CDATA[Cannot delete membership level]]></string>
+	<string name="_adm_prm_err_level_edit"><![CDATA[Cannot update membership level]]></string>
+	<string name="_adm_prm_err_level_icon"><![CDATA[You need to enter font icon name here.]]></string>
+	<string name="_adm_prm_err_level_icon_image"><![CDATA[Cannot upload icon: ]]></string>
+	<string name="_adm_prm_err_level_icon_image_remove"><![CDATA[Cannot remove icon]]></string>
+	<string name="_adm_prm_err_level_id"><![CDATA[Membership levels limit is reached.]]></string>
+	<string name="_adm_prm_err_level_name"><![CDATA[You need to enter name(3, 100) for all languages]]></string>
+	<string name="_adm_prm_err_level_quota_max_file_size"><![CDATA[You need to enter a numeric value, leave 0 for unlimited]]></string>
+	<string name="_adm_prm_err_level_quota_number"><![CDATA[You need to enter a numeric value, leave 0 for unlimited]]></string>
+        <string name="_adm_prm_err_level_password_expired"><![CDATA[You need to enter a numeric value, leave 0 for unlimited]]></string>
+        <string name="_adm_prm_err_level_password_expired_notify"><![CDATA[You need to enter a numeric value, leave 0 for unlimited]]></string>
+	<string name="_adm_prm_err_level_quota_size"><![CDATA[You need to enter a numeric value, leave 0 for unlimited]]></string>
+	<string name="_adm_prm_err_price_create"><![CDATA[Cannot create pricing option]]></string>
+	<string name="_adm_prm_err_price_duplicate"><![CDATA[The similar pricing option already exists for this level.]]></string>
+	<string name="_adm_prm_err_price_update"><![CDATA[Cannot update pricing option]]></string>
+	<string name="_adm_prm_txt_actions"><![CDATA[Actions]]></string>
+	<string name="_adm_prm_txt_actions_avail_end"><![CDATA[This action is available until]]></string>
+	<string name="_adm_prm_txt_actions_avail_start"><![CDATA[This action is available since]]></string>
+	<string name="_adm_prm_txt_actions_number"><![CDATA[Number of allowed actions]]></string>
+	<string name="_adm_prm_txt_actions_options_popup"><![CDATA[Edit "{0}" Action]]></string>
+	<string name="_adm_prm_txt_actions_reset"><![CDATA[Number of actions is reset every]]></string>
+	<string name="_adm_prm_txt_all_modules"><![CDATA[All Modules]]></string>
+	<string name="_adm_prm_txt_description"><![CDATA[Description]]></string>
+	<string name="_adm_prm_txt_enable"><![CDATA[Enable]]></string>
+	<string name="_adm_prm_txt_icon"><![CDATA[Icon]]></string>
+	<string name="_adm_prm_txt_level_account"><![CDATA[Account]]></string>
+	<string name="_adm_prm_txt_level_actions_copy"><![CDATA[Copy actions from]]></string>
+	<string name="_adm_prm_txt_level_administrator"><![CDATA[Administrator]]></string>
+        <string name="_adm_prm_txt_level_unavailable_to"><![CDATA[Unavailable for]]></string>
+	<string name="_adm_prm_txt_level_create_popup"><![CDATA[Add New Level]]></string>
+	<string name="_adm_prm_txt_level_description"><![CDATA[Description]]></string>
+	<string name="_adm_prm_txt_level_edit_popup"><![CDATA[Edit "{0}" Level]]></string>
+	<string name="_adm_prm_txt_level_icon"><![CDATA[Icon]]></string>
+	<string name="_adm_prm_txt_level_icon_image"><![CDATA[]]></string>
+	<string name="_adm_prm_txt_level_icon_image_new"><![CDATA[]]></string>
+	<string name="_adm_prm_txt_level_icon_image_old"><![CDATA[Current Icon]]></string>
+	<string name="_adm_prm_txt_level_moderator"><![CDATA[Moderator]]></string>
+	<string name="_adm_prm_txt_level_name"><![CDATA[Title]]></string>
+	<string name="_adm_prm_txt_level_pending"><![CDATA[Pending]]></string>
+	<string name="_adm_prm_txt_level_premium"><![CDATA[Premium]]></string>
+	<string name="_adm_prm_txt_level_quota_max_file_size"><![CDATA[Max File Size Limit(Mb)]]></string>
+	<string name="_adm_prm_txt_level_quota_number"><![CDATA[Max Files Limit]]></string>
+        <string name="_adm_prm_txt_level_password_expired"><![CDATA[Password Expired]]></string>
+        <string name="_adm_prm_txt_level_password_expired_notify"><![CDATA[Password Expired Notify]]></string>
+	<string name="_adm_prm_txt_level_quota_size"><![CDATA[Storage Limit(Mb)]]></string>
+	<string name="_adm_prm_txt_level_standard"><![CDATA[Standard]]></string>
+	<string name="_adm_prm_txt_level_suspended"><![CDATA[Suspended]]></string>
+	<string name="_adm_prm_txt_level_unauthenticated"><![CDATA[Unauthenticated]]></string>
+	<string name="_adm_prm_txt_level_unconfirmed"><![CDATA[Unconfirmed]]></string>
+	<string name="_adm_prm_txt_manage_actions"><![CDATA[Manage actions]]></string>
+	<string name="_adm_prm_txt_max_file_size"><![CDATA[Max File Size]]></string>
+	<string name="_adm_prm_txt_max_files"><![CDATA[Max Files]]></string>
+	<string name="_adm_prm_txt_module"><![CDATA[Module]]></string>
+	<string name="_adm_prm_txt_n_actions"><![CDATA[{0} actions]]></string>
+	<string name="_adm_prm_txt_price"><![CDATA[Price]]></string>
+	<string name="_adm_prm_txt_price_add_days"><![CDATA[Number of days]]></string>
+	<string name="_adm_prm_txt_price_add_popup"><![CDATA[Add New Pricing Option]]></string>
+	<string name="_adm_prm_txt_price_add_price"><![CDATA[Price]]></string>
+	<string name="_adm_prm_txt_price_edit_popup"><![CDATA[Edit "{0} days" Pricing Option]]></string>
+	<string name="_adm_prm_txt_select_level"><![CDATA[Select Level]]></string>
+	<string name="_adm_prm_txt_storage"><![CDATA[Storage]]></string>
+	<string name="_adm_prm_txt_term"><![CDATA[Term]]></string>
+	<string name="_adm_prm_txt_title"><![CDATA[Title]]></string>
+	<string name="_adm_prm_txt_visibility_items_anyone"><![CDATA[Anyone]]></string>
+	<string name="_adm_prm_txt_visibility_items_n_user_levels"><![CDATA[{0} User Levels]]></string>
+	<string name="_adm_prm_txt_visibility_items_nobody"><![CDATA[Nobody]]></string>
+        
+        <string name="_adm_rl_btn_role_add"><![CDATA[Add New Role]]></string>
+        <string name="_adm_rl_btn_role_edit"><![CDATA[Edit this role]]></string>
+        <string name="_adm_rl_btn_role_delete"><![CDATA[Delete this role]]></string>
+        <string name="_adm_rl_err_cannot_process_action"><![CDATA[Cannot process action. It does not have an associated handler.]]></string>
+        <string name="_adm_rl_err_role_create"><![CDATA[Cannot create role]]></string>
+        <string name="_adm_rl_err_role_edit"><![CDATA[Cannot update role]]></string>
+	<string name="_adm_rl_err_role_delete"><![CDATA[Cannot delete role]]></string>
+        <string name="_adm_rl_err_role_id"><![CDATA[Roles limit is reached.]]></string>
+        <string name="_adm_rl_txt_actions"><![CDATA[Actions]]></string>
+        <string name="_adm_rl_txt_description"><![CDATA[Description]]></string>
+        <string name="_adm_rl_txt_manage_actions"><![CDATA[Manage actions]]></string>
+        <string name="_adm_rl_txt_n_actions"><![CDATA[{0} actions]]></string>
+        <string name="_adm_rl_txt_select_role"><![CDATA[Select Role]]></string>
+        <string name="_adm_rl_txt_title"><![CDATA[Title]]></string>
+        <string name="_adm_rl_txt_role_create_popup"><![CDATA[Add New Role]]></string>
+	<string name="_adm_rl_txt_role_edit_popup"><![CDATA[Edit "{0}" Role]]></string>
+        <string name="_adm_rl_txt_role_master"><![CDATA[Master]]></string>
+        <string name="_adm_rl_txt_role_master_dsc"><![CDATA[]]></string>
+        <string name="_adm_rl_txt_role_operator"><![CDATA[Operator]]></string>
+        <string name="_adm_rl_txt_role_operator_dsc"><![CDATA[]]></string>
+        <string name="_adm_rl_txt_action_manage_roles"><![CDATA[Manage Roles]]></string>
+        <string name="_adm_rl_txt_action_manage_roles_dsc"><![CDATA[]]></string>
+        <string name="_adm_rl_txt_action_manage_apps"><![CDATA[Manage Apps]]></string>
+        <string name="_adm_rl_txt_action_manage_apps_dsc"><![CDATA[]]></string>
+        <string name="_adm_rl_txt_action_use_appearance"><![CDATA[Use 'Appearance' apps]]></string>
+        <string name="_adm_rl_txt_action_use_appearance_dsc"><![CDATA[]]></string>
+        <string name="_adm_rl_txt_action_use_structure"><![CDATA[Use 'Structure' apps]]></string>
+        <string name="_adm_rl_txt_action_use_structure_dsc"><![CDATA[]]></string>
+        <string name="_adm_rl_txt_action_use_content"><![CDATA[Use 'Content' apps]]></string>
+        <string name="_adm_rl_txt_action_use_content_dsc"><![CDATA[]]></string>
+        <string name="_adm_rl_txt_action_use_users"><![CDATA[Use 'Users' apps]]></string>
+        <string name="_adm_rl_txt_action_use_users_dsc"><![CDATA[]]></string>
+        <string name="_adm_rl_txt_action_use_configuration"><![CDATA[Use 'Configuration' apps]]></string>
+        <string name="_adm_rl_txt_action_use_configuration_dsc"><![CDATA[]]></string>
+        <string name="_adm_rl_txt_action_use_extensions"><![CDATA[Use 'Extensions' apps]]></string>
+        <string name="_adm_rl_txt_action_use_extensions_dsc"><![CDATA[]]></string>
+        <string name="_adm_rl_txt_action_use_integrations"><![CDATA[Use 'Integrations' apps]]></string>
+        <string name="_adm_rl_txt_action_use_integrations_dsc"><![CDATA[]]></string>
+        <string name="_adm_rl_txt_role_title"><![CDATA[Title]]></string>
+        <string name="_adm_rl_err_role_title"><![CDATA[You need to enter name(3, 100) for all languages]]></string>
+        <string name="_adm_rl_txt_role_description"><![CDATA[Description]]></string>
+        <string name="_adm_rl_txt_role_actions_copy"><![CDATA[Copy actions from]]></string>
+        <string name="_adm_rl_btn_role_create"><![CDATA[Create]]></string>
+	<string name="_adm_rl_btn_role_cancel"><![CDATA[Cancel]]></string>
+        <string name="_adm_rl_btn_role_save"><![CDATA[Save]]></string>
+        
+    <string name="_adm_scs_operation_done"><![CDATA[]]></string>
+    <string name="_adm_stg_cpt_category_account"><![CDATA[Account]]></string>
+    <string name="_adm_stg_cpt_category_acl"><![CDATA[ACL]]></string>
+    <string name="_adm_stg_cpt_category_audit"><![CDATA[Audit]]></string>
+    <string name="_adm_stg_cpt_category_notifications"><![CDATA[Notifications]]></string>
+    <string name="_adm_stg_cpt_category_notifications_push"><![CDATA[Push Notifications]]></string>
+    <string name="_adm_stg_cpt_category_cache"><![CDATA[Cache]]></string>
+    <string name="_adm_stg_cpt_category_general"><![CDATA[System]]></string>
+    <string name="_adm_stg_cpt_category_hidden"><![CDATA[Hidden]]></string>
+    <string name="_adm_stg_cpt_category_languages"><![CDATA[Languages]]></string>
+    <string name="_adm_stg_cpt_category_permalinks"><![CDATA[Permalinks]]></string>
+    <string name="_adm_stg_cpt_category_security"><![CDATA[Security]]></string>
+    <string name="_adm_stg_cpt_category_site_settings"><![CDATA[General]]></string>
+    <string name="_adm_stg_cpt_category_storage"><![CDATA[Storage]]></string>
+    <string name="_adm_stg_cpt_category_system"><![CDATA[System]]></string>
+    <string name="_adm_stg_cpt_category_templates"><![CDATA[Templates]]></string>
+    <string name="_adm_stg_cpt_category_sms"><![CDATA[SMS Sending]]></string>
+    <string name="_adm_stg_cpt_category_location"><![CDATA[Location]]></string>
+    <string name="_adm_stg_cpt_category_social_settings"><![CDATA[Social]]></string>
+    <string name="_adm_stg_cpt_category_api_general"><![CDATA[General]]></string>
+    <string name="_adm_stg_cpt_category_api_layout"><![CDATA[Layout]]></string>
+    <string name="_adm_stg_cpt_category_agents_general"><![CDATA[General]]></string>
+    <string name="_adm_stg_cpt_category_agents_usage"><![CDATA[Assistants]]></string>
+    <string name="_adm_stg_cpt_option_client_image_resize_width"><![CDATA[Image width to resize before upload (0 - disable)]]></string>
+    <string name="_adm_stg_cpt_option_client_image_resize_height"><![CDATA[Image height to resize before upload (0 - disable)]]></string>
+    <string name="_adm_stg_cpt_option_currency_code"><![CDATA[Currency code (for checkout system)]]></string>
+    <string name="_adm_stg_err_option_currency_code"><![CDATA[Cannot be empty.]]></string>
+    <string name="_adm_stg_cpt_option_currency_sign"><![CDATA[Currency sign (for display purposes only)]]></string>
+    <string name="_adm_stg_err_option_currency_sign"><![CDATA[Cannot be empty.]]></string>
+    <string name="_adm_stg_cpt_option_enable_gd"><![CDATA[Use GD library for image processing]]></string>
+    <string name="_adm_stg_cpt_option_enable_notification_account"><![CDATA[Notify about new accounts]]></string>
+    <string name="_adm_stg_cpt_option_enable_notification_pruning"><![CDATA[Notify about pruning results]]></string>
+    <string name="_adm_stg_cpt_option_expire_notification_days"><![CDATA[Number of days before membership expiration to notify members ( -1 = after expiration )]]></string>
+    <string name="_adm_stg_cpt_option_expire_notify_once"><![CDATA[Notify members about membership expiration only once (every day otherwise)]]></string>
+    <string name="_adm_stg_cpt_option_lang_default"><![CDATA[Default Language]]></string>
+    <string name="_adm_stg_cpt_option_lang_subst_from_en"><![CDATA[Substitute (during compilation) missing translations with english ones]]></string>	
+    <string name="_adm_stg_cpt_option_permalinks_modules"><![CDATA[Enable friendly permalinks for Modules]]></string>
+    <string name="_adm_stg_cpt_option_permalinks_pages"><![CDATA[Enable friendly permalinks for Pages]]></string>
+    <string name="_adm_stg_cpt_option_permalinks_storage"><![CDATA[Enable friendly permalinks for local Storage]]></string>
+    <string name="_adm_stg_cpt_option_permalinks_seo_links"><![CDATA[Enable SEO links]]></string>
+    <string name="_adm_stg_cpt_option_permalinks_seo_links_redirects"><![CDATA[Enable redirect from regular to SEO links]]></string>
+    <string name="_adm_stg_cpt_option_site_email"><![CDATA[Operator email]]></string>
+    <string name="_adm_stg_inf_option_site_email"><![CDATA[Email address to receive critical system notifications.]]></string>
+    <string name="_adm_stg_cpt_option_site_email_notify"><![CDATA["From" email]]></string>
+    <string name="_adm_stg_inf_option_site_email_notify"><![CDATA[Email address used as "sender" in transactional emails.]]></string>
+    <string name="_adm_stg_cpt_option_site_email_html_template_header"><![CDATA[Email template header]]></string>
+    <string name="_adm_stg_cpt_option_site_email_html_template_footer"><![CDATA[Email template footer]]></string>
+    <string name="_adm_stg_cpt_option_site_login_social_compact"><![CDATA[Enable compact view for social login]]></string>
+    <string name="_adm_stg_cpt_option_site_title"><![CDATA[Community name]]></string>
+    <string name="_adm_stg_inf_option_site_title"><![CDATA[The default name used to refer to your site in site texts, meta tags, emails and notifications.]]></string>
+    <string name="_adm_stg_cpt_option_site_tour_home"><![CDATA[User Tour]]></string>
+    <string name="_adm_stg_inf_option_site_tour_home"><![CDATA[You can edit steps and content of the User Tour <a href="/studio/polyglot.php?page=keys">here</a>.]]></string>
+    <string name="_adm_stg_cpt_option_site_tour_studio"><![CDATA[Studio Tour]]></string>
+    <string name="_adm_stg_inf_option_site_tour_studio"><![CDATA[You can edit steps and content of the Studio Tour <a href="/studio/polyglot.php?page=keys">here</a>.]]></string>
+    <string name="_adm_stg_cpt_option_smart_app_banner"><![CDATA[Smart App Banner]]></string>
+    <string name="_adm_stg_inf_option_smart_app_banner"><![CDATA[]]></string>
+    <string name="_adm_stg_cpt_option_smart_app_banner_ios_app_id"><![CDATA[iOS app ID for Smart App Banner]]></string>
+    <string name="_adm_stg_inf_option_smart_app_banner_ios_app_id"><![CDATA[]]></string>
+    <string name="_adm_stg_cpt_option_sys_account_welcome_letter"><![CDATA[Enable welcome letter]]></string>
+    <string name="_adm_stg_cpt_option_sys_account_confirmation_type"><![CDATA[Account is confirmed when]]></string>
+    <string name="_adm_stg_cpt_option_sys_account_hide_unconfirmed_accounts"><![CDATA[Hide profiles which have unconfirmed account]]></string>
+    <string name="_adm_stg_cpt_option_sys_account_2fa_enable"><![CDATA[Enable 2 Factor Authentication]]></string>
+    <string name="_adm_stg_cpt_option_sys_account_2fa_lifetime"><![CDATA[2FA code lifetime, in seconds (0 - send code upon each login)]]></string>
+    <string name="_adm_stg_cpt_option_sys_account_autoapproval"><![CDATA[Automatic account activation after creation]]></string>
+    <string name="_adm_stg_cpt_option_sys_account_auto_profile_creation"><![CDATA[Automatic profile creation from account name]]></string>
+    <string name="_adm_stg_cpt_option_sys_account_online_time"><![CDATA[Online status timeframe (minutes)]]></string>
+    <string name="_adm_stg_err_option_sys_account_online_time"><![CDATA[You need to enter a value greater than zero.]]></string>
+    <string name="_adm_stg_cpt_option_sys_account_default_profile_type"><![CDATA[Default profile type]]></string>
+    <string name="_adm_stg_cpt_option_sys_account_limit_profiles_number"><![CDATA[Limit number of profiles (0 - no limit)]]></string>
+    <string name="_adm_stg_cpt_option_sys_account_limit_incorrect_login_attempts"><![CDATA[Max number of logins attempts (0 - no limit)]]></string>
+    <string name="_adm_stg_cpt_option_sys_account_reset_password_key_lifetime"><![CDATA[Reset password key lifetime (in seconds)]]></string>
+    <string name="_adm_stg_cpt_option_sys_account_reset_password_redirect"><![CDATA[Redirect after reset password to]]></string>
+    <string name="_adm_stg_cpt_option_sys_account_disable_login_form"><![CDATA[Disable login form]]></string>
+    <string name="_adm_stg_cpt_option_sys_account_disable_join_form"><![CDATA[Disable join form]]></string>
+    <string name="_adm_stg_cpt_option_sys_allow_plus_in_email"><![CDATA[Allow to use plus sign ("+") in email address]]></string>
+    <string name="_adm_stg_cpt_option_sys_accounts_pruning"><![CDATA[Accounts pruning]]></string>
+    <string name="_adm_stg_cpt_option_sys_accounts_pruning_interval"><![CDATA[Accounts pruning period (in days)]]></string>
+    <string name="_adm_stg_cpt_option_sys_accounts_password_log_count"><![CDATA[Number of stored old passwords  (0 = do not store)]]></string>
+    <string name="_adm_stg_cpt_option_sys_accounts_force_password_change_after_expiration"><![CDATA[Force password change after password expiration]]></string>
+    
+    <string name="_adm_stg_cpt_option_sys_lock_from_unauthenticated"><![CDATA[Lock site from unauthenticated users]]></string>
+    <string name="_adm_stg_cpt_option_sys_lock_from_unauthenticated_exceptions"><![CDATA[Comma separated list of pages URIs, which are avalilable for unauthenticated users]]></string>
+    <string name="_adm_stg_cpt_option_value_sys_account_pruning_no_login_delete"><![CDATA[Delete accounts with no login within N days]]></string>
+    <string name="_adm_stg_cpt_option_value_sys_account_pruning_no_login_suspend"><![CDATA[Suspend accounts with no login within N days]]></string>
+    <string name="_adm_stg_cpt_option_value_sys_account_pruning_no_confirm_delete"><![CDATA[Delete accounts which didn't confirm email within N days]]></string>
+    <string name="_adm_stg_cpt_option_value_sys_account_pruning_no_profile_delete"><![CDATA[Delete accounts which didn't created any profiles within N days]]></string>
+    <string name="_adm_stg_cpt_option_value_sys_account_reset_password_redirect_home"><![CDATA[Home page]]></string>
+    <string name="_adm_stg_cpt_option_value_sys_account_reset_password_redirect_profile"><![CDATA[View profile page]]></string>
+    <string name="_adm_stg_cpt_option_value_sys_account_reset_password_redirect_profile_edit"><![CDATA[Edit profile page]]></string>
+    <string name="_adm_stg_cpt_option_value_sys_account_reset_password_redirect_custom"><![CDATA[Custom page]]></string>
+    <string name="_adm_stg_cpt_option_sys_account_reset_password_redirect_custom"><![CDATA[URL for 'Custom Page' redirect]]></string>
+    <string name="_adm_stg_cpt_option_sys_account_switch_to_profile_redirect"><![CDATA[Redirect after profile switch to]]></string>
+    <string name="_adm_stg_cpt_option_sys_account_switch_to_profile_redirect_custom"><![CDATA[URL for 'Custom Page' redirect]]></string>
+    <string name="_adm_stg_cpt_option_sys_account_remember_me"><![CDATA[Default value for 'Remember me' feature]]></string>
+    <string name="_adm_stg_cpt_option_value_sys_account_switch_to_profile_redirect_back"><![CDATA[Current page]]></string>
+    <string name="_adm_stg_cpt_option_value_sys_account_switch_to_profile_redirect_home"><![CDATA[Home page]]></string>
+    <string name="_adm_stg_cpt_option_value_sys_account_switch_to_profile_redirect_profile"><![CDATA[View profile page]]></string>
+    <string name="_adm_stg_cpt_option_value_sys_account_switch_to_profile_redirect_custom"><![CDATA[Custom page]]></string>
+    <string name="_adm_stg_cpt_option_sys_acl_expire_notification_days"><![CDATA[Number of days before membership expiration to notify members (-1 = after expiration)]]></string>
+    <string name="_adm_stg_cpt_option_sys_acl_expire_notify_once"><![CDATA[Notify members about membership expiration only once (every day otherwise)]]></string>
+    <string name="_adm_stg_cpt_option_sys_add_nofollow"><![CDATA[Add "nofollow" attribute for external links]]></string>
+    <string name="_adm_stg_cpt_option_sys_audit_enable"><![CDATA[Enable]]></string>
+    <string name="_adm_stg_cpt_option_sys_audit_max_records"><![CDATA[Number of log records]]></string>
+    <string name="_adm_stg_cpt_option_sys_audit_days_before_expire"><![CDATA[Delete logs older than (days)]]></string>
+    <string name="_adm_stg_cpt_option_sys_audit_acl_levels"><![CDATA[Enable for levels]]></string>
+    <string name="_adm_stg_cpt_option_sys_autoupdate_force_modified_files"><![CDATA[Force Automatic Updates]]></string>
+    <string name="_adm_stg_inf_option_sys_autoupdate_force_modified_files"><![CDATA[Update core system and modules even if modified files are detected.]]></string>
+    <string name="_adm_stg_cpt_option_sys_autoupdate"><![CDATA[Automatic System Updates]]></string>
+    <string name="_adm_stg_inf_option_sys_autoupdate"><![CDATA[Try to update core  system and modules automatically.]]></string>
+    <string name="_adm_stg_cpt_option_sys_cache_memcache_host"><![CDATA[Memcached server host]]></string>
+    <string name="_adm_stg_cpt_option_sys_cache_memcache_port"><![CDATA[Memcached server port]]></string>
+    <string name="_adm_stg_cpt_option_sys_cache_redis_connection_string"><![CDATA[Redis server connection string]]></string>
+    <string name="_adm_stg_cpt_option_sys_cache_redis_connection_string_info"><![CDATA[For example: redis://pwdhere@localhost:6379/2, where 2 is database number (0 by default)]]></string>
+    <string name="_adm_stg_cpt_option_sys_captcha_default"><![CDATA[Default Сaptcha]]></string>
+    <string name="_adm_stg_cpt_option_sys_cf_enable"><![CDATA[Enable content filters]]></string>
+    <string name="_adm_stg_cpt_option_sys_cf_enable_comments"><![CDATA[Enable content filters for comments]]></string>
+    <string name="_adm_stg_cpt_option_sys_cf_prohibited"><![CDATA[Prohibited content]]></string>
+    <string name="_adm_stg_cpt_option_sys_cf_unauthenticated"><![CDATA[Content visible to unauthenticated users]]></string>
+    <string name="_adm_stg_cpt_option_sys_confirmation_before_redirect"><![CDATA[Ask user confirmation before redirecting user to the external site]]></string>
+    <string name="_adm_stg_cpt_option_sys_email_attachable_email_templates"><![CDATA[Attachable email templates list]]></string>
+    <string name="_adm_stg_cpt_option_sys_db_cache_enable"><![CDATA[Enable DB cache]]></string>
+    <string name="_adm_stg_cpt_option_sys_db_cache_engine"><![CDATA[DB cache engine (other than File option may require custom server setup)]]></string>
+    <string name="_adm_stg_cpt_option_sys_content_cache_enable"><![CDATA[Enable content cache]]></string>
+    <string name="_adm_stg_cpt_option_sys_content_cache_engine"><![CDATA[DContent cache engine (other than File option may require custom server setup)]]></string>
+    <string name="_adm_stg_cpt_option_sys_default_payment"><![CDATA[Payment module]]></string>
+    <string name="_adm_stg_cpt_option_sys_editor_default"><![CDATA[Default HTML editor]]></string>
+    <string name="_adm_stg_cpt_option_sys_player_default"><![CDATA[Default Player]]></string>
+    <string name="_adm_stg_cpt_option_sys_player_default_quality"><![CDATA[Default video quality]]></string>
+    <string name="_adm_stg_cpt_option_sys_pt_default_visitor"><![CDATA[Default page type for visitor]]></string>
+    <string name="_adm_stg_cpt_option_sys_pt_default_member"><![CDATA[Default page type for member]]></string>
+    <string name="_adm_stg_cpt_option_sys_form_lpc_enable"><![CDATA[Enable leave page confirmation for pages with forms]]></string>
+    <string name="_adm_stg_cpt_option_sys_format_date"><![CDATA[<a target="_blank" href="https://momentjs.com/docs/#/displaying/format/">Date Format</a>]]></string>
+    <string name="_adm_stg_cpt_option_sys_format_datetime"><![CDATA[<a target="_blank" href="https://momentjs.com/docs/#/displaying/format/">Date And Time Format</a>]]></string>
+    <string name="_adm_stg_cpt_option_sys_format_time"><![CDATA[<a target="_blank" href="https://momentjs.com/docs/#/displaying/format/">Time Format</a>]]></string>
+    <string name="_adm_stg_cpt_option_sys_format_timeago"><![CDATA[Use 'time ago' format for dates less than this number of seconds]]></string>
+    <string name="_adm_stg_cpt_option_sys_format_input_24h"><![CDATA[Use 24h Format For Calendar Input]]></string>
+    <string name="_adm_stg_cpt_option_sys_ftp_dir"><![CDATA[Path to the script on FTP server]]></string>
+    <string name="_adm_stg_cpt_option_sys_ftp_login"><![CDATA[FTP server login]]></string>
+    <string name="_adm_stg_cpt_option_sys_ftp_password"><![CDATA[FTP server password]]></string>
+    <string name="_adm_stg_cpt_option_sys_cron_time"><![CDATA[Last cron execution time]]></string>
+    <string name="_adm_stg_cpt_option_sys_update_time"><![CDATA[Last update]]></string>
+    <string name="_adm_stg_cpt_option_sys_upgrade_channel"><![CDATA[Update channel]]></string>
+    <string name="_adm_stg_cpt_option_sys_live_updates_interval"><![CDATA[Live updates interval (in milliseconds)]]></string>
+    <string name="_adm_stg_cpt_option_sys_location_field_default"><![CDATA[Location field provider]]></string>
+    <string name="_adm_stg_cpt_option_sys_location_map_default"><![CDATA[Location map provider]]></string>
+    <string name="_adm_stg_cpt_option_sys_location_map_zoom_default"><![CDATA[Location map zoom]]></string>
+    <string name="_adm_stg_cpt_option_sys_location_leaflet_provider"><![CDATA[Leaflet tile layers provider]]></string>
+    <string name="_adm_stg_cpt_option_sys_location_normalize_names"><![CDATA[Normalize geographic names]]></string>
+    <string name="_adm_stg_cpt_option_sys_maps_api_key"><![CDATA[Google Maps API key]]></string>
+    <string name="_adm_stg_cpt_option_sys_embed_default"><![CDATA[Embeds provider]]></string>
+    <string name="_adm_stg_cpt_option_sys_embed_lifetime"><![CDATA[Generated embed lifetime in days (0 - do not track time)]]></string>
+    <string name="_adm_stg_cpt_option_sys_embed_system"><![CDATA[System]]></string>
+    <string name="_adm_stg_cpt_option_sys_embed_microlink"><![CDATA[Microlink]]></string>
+    <string name="_adm_stg_cpt_option_sys_embed_peekalink"><![CDATA[Peekalink]]></string>
+    <string name="_adm_stg_cpt_option_sys_embedly_api_key"><![CDATA[Embed.ly API key]]></string>
+    <string name="_adm_stg_cpt_option_sys_iframely_api_key"><![CDATA[Iframely API key]]></string>
+    <string name="_adm_stg_cpt_option_sys_embed_microlink_key"><![CDATA[Microlink API key]]></string>
+    <string name="_adm_stg_cpt_option_sys_embed_peekalink_api_key"><![CDATA[Peekalink API key]]></string>
+    <string name="_adm_stg_cpt_option_sys_eq_time"><![CDATA[Email queue execution flag]]></string>
+    <string name="_adm_stg_cpt_option_sys_eq_send_per_start"><![CDATA[Number of messages to send from mail queue per run]]></string>
+    <string name="_adm_stg_cpt_option_sys_eq_send_per_start_to_recipient"><![CDATA[Number of messages to send from mail queue per run to the same recipient]]></string>
+    <string name="_adm_stg_cpt_option_sys_oauth_key"><![CDATA[UNA account key]]></string>
+    <string name="_adm_stg_cpt_option_sys_oauth_secret"><![CDATA[UNA account secret]]></string>
+    <string name="_adm_stg_cpt_option_sys_page_cache_enable"><![CDATA[Enable Page cache]]></string>
+    <string name="_adm_stg_cpt_option_sys_page_cache_engine"><![CDATA[Page cache engine (other than File option may require custom server setup)]]></string>
+    <string name="_adm_stg_cpt_option_sys_pb_cache_enable"><![CDATA[Enable page blocks cache]]></string>
+    <string name="_adm_stg_cpt_option_sys_pb_cache_engine"><![CDATA[Page blocks cache engine (other than File option may require custom server setup)]]></string>
+    <string name="_adm_stg_cpt_option_sys_per_page_search_keyword_single"><![CDATA[Keyword Search Results]]></string>
+    <string name="_adm_stg_inf_option_sys_per_page_search_keyword_single"><![CDATA[Set the maximum number of results displayed per page in Keyword Search]]></string>
+    <string name="_adm_stg_cpt_option_sys_per_page_search_keyword_plural"><![CDATA[Site Search Results]]></string>
+    <string name="_adm_stg_inf_option_sys_per_page_search_keyword_plural"><![CDATA[Set the maximum number of results displayed per page in Site Search]]></string>
+    <string name="_adm_stg_cpt_option_sys_per_page_search_extended"><![CDATA[Extended Search Results]]></string>
+    <string name="_adm_stg_inf_option_sys_per_page_search_extended"><![CDATA[Set the maximum number of results displayed per page in Extended Search]]></string>
+    <string name="_adm_stg_cpt_option_sys_per_page_recommendations"><![CDATA[Browse Recommendations]]></string>
+    <string name="_adm_stg_inf_option_sys_per_page_recommendations"><![CDATA[Set the maximum number of results displayed per page]]></string>
+    <string name="_adm_stg_cpt_option_sys_per_page_recommendations_showcase"><![CDATA[Browse Recommendations in showcase view]]></string>
+    <string name="_adm_stg_inf_option_sys_per_page_recommendations_showcase"><![CDATA[Set the maximum number of results displayed per page in showcase view]]></string>
+    <string name="_adm_stg_cpt_option_sys_push_default"><![CDATA[Provider]]></string>
+    <string name="_adm_stg_cpt_option_sys_push_onesignal_app_id"><![CDATA[OneSignal: App ID]]></string>
+    <string name="_adm_stg_cpt_option_sys_push_onesignal_rest_api"><![CDATA[OneSignal: REST API Key]]></string>
+    <string name="_adm_stg_cpt_option_sys_push_onesignal_short_name"><![CDATA[OneSignal: Short name (required only for http sites. It must match the Subdomain you entered on the Web Push settings on the OneSignal dashboard)]]></string>
+    <string name="_adm_stg_cpt_option_sys_push_onesignal_safari_id"><![CDATA[OneSignal: Apple Safari Web ID on the Web Push settings]]></string>
+    <string name="_adm_stg_cpt_option_sys_push_wonderpush_app_id"><![CDATA[WonderPush: App ID]]></string>
+    <string name="_adm_stg_cpt_option_sys_push_wonderpush_access_token"><![CDATA[WonderPush: Access Token]]></string>
+    <string name="_adm_stg_cpt_option_sys_push_wonderpush_web_key"><![CDATA[WonderPush: Web Key]]></string>
+    <string name="_adm_stg_cpt_option_sys_push_queue_time"><![CDATA[Push queue execution flag]]></string>
+    <string name="_adm_stg_cpt_option_sys_push_queue_send_per_start"><![CDATA[Number of messages to send from Push queue per run]]></string>
+    <string name="_adm_stg_cpt_option_sys_push_queue_send_per_start_to_recipient"><![CDATA[Number of messages to send from Push queue per run to some recipient]]></string>
+    <string name="_adm_stg_cpt_option_sys_sms_default"><![CDATA[Provider]]></string>
+    <string name="_adm_stg_cpt_option_sys_sms_twilio_sid"><![CDATA[Twilio: Account SID]]></string>
+    <string name="_adm_stg_cpt_option_sys_sms_twilio_token"><![CDATA[Twilio: Auth token]]></string>
+    <string name="_adm_stg_cpt_option_sys_sms_twilio_from_number"><![CDATA[Twilio: Default 'From' number for SMS]]></string>
+    <string name="_adm_stg_cpt_option_sys_sms_smsru_api_id"><![CDATA[SMS.RU: API ID]]></string>
+    <string name="_adm_stg_cpt_option_sys_sms_smsru_from_number"><![CDATA[SMS.RU: Default 'From' number for SMS]]></string>
+    <string name="_adm_stg_cpt_option_sys_nominatim_server"><![CDATA[Nominatim server URL]]></string>    
+    <string name="_adm_stg_cpt_option_sys_nominatim_email"><![CDATA[Nominatim email to identify requests]]></string>
+    <string name="_adm_stg_cpt_option_sys_recaptcha_key_private"><![CDATA[reCAPTCHA/hCaptcha private key]]></string>
+    <string name="_adm_stg_cpt_option_sys_recaptcha_key_public"><![CDATA[reCAPTCHA/hCaptcha public key]]></string>
+    <string name="_adm_stg_cpt_option_sys_redirect_after_account_added"><![CDATA[Redirect after account creation to]]></string>
+    <string name="_adm_stg_cpt_option_sys_redirect_after_email_confirmation"><![CDATA[Redirect after email confirmation to]]></string>
+    <string name="_adm_stg_cpt_option_sys_relations_enable"><![CDATA[Enable relationships]]></string>
+    <string name="_adm_stg_cpt_option_sys_relations"><![CDATA[Allow relationships between]]></string>
+    <string name="_adm_stg_cpt_option_sys_revision"><![CDATA[Revision number]]></string>
+    <string name="_adm_stg_cpt_option_sys_security_form_token_enable"><![CDATA[Enable CSRF token in forms]]></string>
+    <string name="_adm_stg_cpt_option_sys_security_form_token_lifetime"><![CDATA[CSRF token lifetime in seconds(0 - do not track time)]]></string>
+    <string name="_adm_stg_cpt_option_sys_security_impact_threshold_block"><![CDATA[Total security impact threshold to send report and block aggressor]]></string>
+    <string name="_adm_stg_cpt_option_sys_security_impact_threshold_log"><![CDATA[Total security impact threshold to send report]]></string>
+    <string name="_adm_stg_cpt_option_sys_security_block_content_after_n_reports"><![CDATA[Block content after N reports (0 - do not block)]]></string>
+    <string name="_adm_stg_cpt_option_sys_site_logo_aspect_ratio"><![CDATA[Logo aspect ratio]]></string>
+    <string name="_adm_stg_cpt_option_sys_storage_default"><![CDATA[Default storage engine (other than Local may require custom/additional setup)]]></string>
+    <string name="_adm_stg_cpt_option_sys_storage_s3_access_key"><![CDATA[AWS access key]]></string>
+    <string name="_adm_stg_cpt_option_sys_storage_s3_bucket"><![CDATA[AWS bucket]]></string>
+    <string name="_adm_stg_cpt_option_sys_storage_s3_domain"><![CDATA[AWS custom domain (require custom DNS setup)]]></string>
+    <string name="_adm_stg_cpt_option_sys_storage_s3_secret_key"><![CDATA[AWS secret key]]></string>
+    <string name="_adm_stg_cpt_option_sys_storage_s3_endpoint"><![CDATA[Endpoint (specify if other than Amazon, such as storage.googleapis.com, s3.wasabisys.com)]]></string>
+    <string name="_adm_stg_cpt_option_sys_storage_s3_sig_ver"><![CDATA[Signature version (only S3v4alt storage supports both v2 and v4)]]></string>
+    <string name="_adm_stg_cpt_option_sys_storage_s3_region"><![CDATA[Region (for signature v4 only)]]></string>
+    <string name="_adm_stg_cpt_option_sys_storage_s3_amz_iam_role"><![CDATA[Authenticate using Amazon  IAM Role (S3v4alt storage only)]]></string>
+    <string name="_adm_stg_cpt_option_sys_storage_s3_acl_enable"><![CDATA[Enable ACLs (S3v4alt storage only)]]></string>
+    <string name="_adm_stg_cpt_option_sys_storage_s3_force_auth_urls"><![CDATA[Force authenticated URLs for specific storages]]></string>
+    <string name="_adm_stg_cpt_option_sys_storage_ghost_lifetime"><![CDATA[Lifetime for unused ghosts, which they will be automatically deleted after (in minutes, use 0 to disable).]]></string>
+    <string name="_adm_stg_cpt_option_sys_template_cache_image_enable"><![CDATA[Enable cache for images]]></string>
+    <string name="_adm_stg_cpt_option_sys_template_cache_image_max_size"><![CDATA[Cached image max size (in Kb)]]></string>
+    <string name="_adm_stg_cpt_option_sys_template_cache_image_max_size_err"><![CDATA[Use non-empty value less or equal to 10kb. Big values make no sense.]]></string>
+    <string name="_adm_stg_cpt_option_sys_template_cache_compress_enable"><![CDATA[Enable compression for JS/CSS files(cache should be enabled)]]></string>
+    <string name="_adm_stg_cpt_option_sys_template_cache_css_enable"><![CDATA[Enable cache for CSS files]]></string>
+    <string name="_adm_stg_cpt_option_sys_template_cache_enable"><![CDATA[Enable cache for HTML files]]></string>
+    <string name="_adm_stg_cpt_option_sys_template_cache_engine"><![CDATA[Template cache engine (other than FileHtml option may require custom server setup)]]></string>
+    <string name="_adm_stg_cpt_option_sys_template_cache_js_enable"><![CDATA[Enable cache for JS files]]></string>
+    <string name="_adm_stg_cpt_option_sys_template_cache_minify_css_enable"><![CDATA[Enable lessening for CSS files (cache should be enabled)]]></string>
+    <string name="_adm_stg_cpt_option_sys_template_cache_minify_js_enable"><![CDATA[Enable lessening for JS files (cache should be enabled)]]></string>
+    <string name="_adm_stg_cpt_option_sys_transcoder_queue_storage"><![CDATA[Remote video transcoding (requires special setup)]]></string>
+    <string name="_adm_stg_cpt_option_sys_live_search_limit"><![CDATA[Live Search Results]]></string>
+    <string name="_adm_stg_inf_option_sys_live_search_limit"><![CDATA[Set the maximum number of results displayed in Live Search suggestion box.]]></string>
+    <string name="_adm_stg_cpt_option_sys_profiles_search_limit"><![CDATA[Profile Search Results]]></string>
+    <string name="_adm_stg_inf_option_sys_profiles_search_limit"><![CDATA[Set the maximum number of results displayed per page in Profile Search.]]></string>
+    <string name="_adm_stg_cpt_option_sys_per_page_browse_showcase"><![CDATA[Number of items in showcase view]]></string>
+    <string name="_adm_stg_inf_option_sys_per_page_browse_showcase"><![CDATA[Set the maximum number of results displayed in horizontal carousel.]]></string>
+    <string name="_adm_stg_cpt_option_sys_session_lifetime_in_min"><![CDATA[Session lifetime (min)]]></string>
+    <string name="_adm_stg_cpt_option_sys_session_auth"><![CDATA[Session authentication]]></string>
+    <string name="_adm_stg_cpt_option_sys_default_curl_timeout"><![CDATA[cURL - default timeout]]></string>
+    <string name="_adm_stg_cpt_option_sys_default_socket_timeout"><![CDATA[HTTP context read timeout (in seconds, -1 - unlimit)]]></string>
+    <string name="_adm_stg_cpt_option_sys_ssl_allow_untrusted"><![CDATA[cURL - trust unsigned certificates or not verified hosts]]></string>
+    <string name="_adm_stg_cpt_option_sys_csp_frame_ancestors"><![CDATA['Content-Security-Policy: frame-ancestors' header value]]></string>
+    <string name="_adm_stg_cpt_option_sys_x_frame_options"><![CDATA['X-Frame-Options' header value (Off - don't send this header)]]></string>
+    <string name="_adm_stg_cpt_option_sys_samesite_cookies"><![CDATA[SameSite value for sensitive cookies]]></string>
+    <string name="_adm_stg_cpt_option_sys_notify_to_approve_by_role"><![CDATA[Notify context member with necessary role to approve content in the context]]></string>
+    <string name="_adm_stg_cpt_option_sys_fixed_header"><![CDATA[Fixed header]]></string>
+    <string name="_adm_stg_cpt_option_sys_css_media_classes"><![CDATA[CSS @media intervals]]></string>
+    <string name="_adm_stg_cpt_option_sys_css_tailwind_default"><![CDATA[Active Tailwind build]]></string>
+    <string name="_adm_stg_cpt_option_sys_css_tailwind_default_cdn"><![CDATA[Play CDN]]></string>
+    <string name="_adm_stg_cpt_option_sys_iconset_default"><![CDATA[Default iconset]]></string>
+    <string name="_adm_stg_cpt_option_sys_files_ext_images"><![CDATA[Allowed extensions for image's files]]></string>
+    <string name="_adm_stg_cpt_option_sys_files_ext_video"><![CDATA[Allowed extensions for video files]]></string>
+    <string name="_adm_stg_cpt_option_sys_files_ext_imagevideo"><![CDATA[Allowed extensions for image and video files]]></string>
+    <string name="_adm_stg_cpt_option_sys_files_ext_dangerous"><![CDATA[Disallowed extensions for files]]></string>
+    <string name="_adm_stg_cpt_option_sys_files_ext_audio"><![CDATA[Allowed extensions for audio files]]></string>
+    <string name="_adm_stg_cpt_option_template"><![CDATA[Default Template]]></string>
+    <string name="_adm_stg_err_option_template"><![CDATA[Template cannot be empty and must have a valid name.]]></string>
+    <string name="_adm_stg_cpt_option_use_like_operator"><![CDATA[Use operator LIKE for search (recommended for small content)]]></string>
+    <string name="_adm_stg_cpt_option_sys_quill_insert_as_plain_text"><![CDATA[Quill - paste as plain text]]></string>
+    <string name="_adm_stg_cpt_option_sys_quill_allow_empty_tags"><![CDATA[Quill - allow empty tags]]></string>
+    <string name="_adm_stg_cpt_option_sys_quill_allowed_tags_mini"><![CDATA[Quill - allowed formats for mini editor]]></string>
+    <string name="_adm_stg_cpt_option_sys_quill_allowed_tags_standard"><![CDATA[Quill - allowed formats for standard editor]]></string>
+    <string name="_adm_stg_cpt_option_sys_quill_allowed_tags_full"><![CDATA[Quill - allowed formats for full editor]]></string>
+    <string name="_adm_stg_cpt_option_sys_quill_toolbar_mini"><![CDATA[Quill buttons for mini editor]]></string>
+    <string name="_adm_stg_cpt_option_sys_quill_toolbar_standard"><![CDATA[Quill buttons for standard editor]]></string>
+    <string name="_adm_stg_cpt_option_sys_quill_toolbar_full"><![CDATA[Quill buttons for full editor]]></string>
+    <string name="_adm_stg_cpt_option_sys_metatags_hashtags_only"><![CDATA[Filter out labels from hashtag suggestion list]]></string>
+    <string name="_adm_stg_cpt_option_sys_metatags_hashtags_max"><![CDATA[Max number of hashtags per post]]></string>
+    <string name="_adm_stg_cpt_option_sys_metatags_mentions_max"><![CDATA[Max number of mentions per post]]></string>
+    <string name="_adm_stg_cpt_option_sys_attach_links_max"><![CDATA[Max number of attached links per post (0 - no limit)]]></string>
+    <string name="_adm_stg_cpt_option_sys_enable_post_to_context_for_privacy"><![CDATA[Allow to post to context using Privacy field]]></string>
+    <string name="_adm_stg_cpt_option_sys_hide_post_to_context_for_privacy"><![CDATA[Hide post to context for modules in Privacy field]]></string>
+    <string name="_adm_stg_cpt_option_sys_treat_cxt_in_cxt_as_cnt"><![CDATA[Treat context posted in context as content]]></string>
+    <string name="_adm_stg_cpt_option_sys_check_fan_in_parent_context"><![CDATA[Only parent group(space, event, etc) members can join]]></string>
+    <string name="_adm_stg_cpt_option_sys_search_keyword_min_len"><![CDATA[Keyword min length in site search]]></string>
+    <string name="_adm_stg_cpt_option_sys_profile_bot"><![CDATA[System Bot profile]]></string>
+    <string name="_adm_stg_inf_option_sys_profile_bot"><![CDATA[Choose profile which will be used as an author of system actions.]]></string>
+    <string name="_adm_stg_cpt_option_sys_logs_storage_default"><![CDATA[Default logs storage]]></string>
+    <string name="_adm_stg_cpt_option_sys_logs_level"><![CDATA[Log Level]]></string>
+    <string name="_adm_stg_cpt_option_sys_vote_reactions_quick_mode"><![CDATA[Enable 'Quick Reactions' mode - vote with default reaction when clicked]]></string>
+    <string name="_adm_stg_cpt_option_sys_cmts_enable_auto_approve"><![CDATA[Auto approve a comment after creation]]></string>
+    <string name="_adm_stg_cpt_option_sys_create_post_form_preloading_list"><![CDATA[Asynchronous forms preload in "Create Post" block]]></string>
+    <string name="_adm_stg_inf_option_sys_create_post_form_preloading_list"><![CDATA[]]></string>
+    <string name="_adm_stg_cpt_option_sys_a2a_enable"><![CDATA[Use Add2Any code instead of default sharing menu]]></string>
+    <string name="_adm_stg_cpt_option_sys_a2a_code"><![CDATA[Add2Any code]]></string>
+    <string name="_adm_stg_cpt_option_sys_api_enable"><![CDATA[Enable API]]></string>
+    <string name="_adm_stg_cpt_option_sys_api_access_by_origin"><![CDATA[Allow access by origin]]></string>
+    <string name="_adm_stg_cpt_option_sys_api_access_by_key"><![CDATA[Allow access with API key]]></string>
+    <string name="_adm_stg_cpt_option_sys_api_access_unsafe_services"><![CDATA[Access to unsafe services]]></string>
+    <string name="_adm_stg_cpt_option_sys_api_config"><![CDATA[]]></string>
+    <string name="_adm_stg_cpt_option_sys_api_cookie_path"><![CDATA[Cookies path]]></string>
+    <string name="_adm_stg_cpt_option_sys_api_cookie_secure"><![CDATA[Secure cookies]]></string>
+    <string name="_adm_stg_cpt_option_sys_api_cookie_samesite"><![CDATA[Cookies SameSite attribute]]></string>
+    <string name="_adm_stg_cpt_option_sys_api_menu_top"><![CDATA[Top Menu]]></string>
+    <string name="_adm_stg_cpt_option_sys_api_context_switcher"><![CDATA[Context switcher]]></string>
+    <string name="_adm_stg_cpt_option_sys_api_context_connection"><![CDATA[Context connection]]></string>
+    <string name="_adm_stg_cpt_option_sys_api_cnt_cnn_subscriptions"><![CDATA[following]]></string>
+    <string name="_adm_stg_cpt_option_sys_api_cnt_cnn_fans"><![CDATA[membership]]></string>
+    <string name="_adm_stg_cpt_option_sys_api_cnt_cnn_participants"><![CDATA[any participation]]></string>
+    <string name="_adm_stg_cpt_option_sys_api_comments_flat"><![CDATA[Flat comments]]></string>
+    <string name="_adm_stg_cpt_option_sys_api_search_sections"><![CDATA[Search sections]]></string>
+    <string name="_adm_stg_cpt_option_sys_api_extended_units"><![CDATA[Use extended units]]></string>
+    <string name="_adm_stg_cpt_option_sys_api_conn_in_prof_units"><![CDATA[Use connections lists in profiles/groups units]]></string>
+    <string name="_adm_stg_cpt_option_sys_api_root_page_guest"><![CDATA[Root page for non-logged user]]></string>
+    <string name="_adm_stg_cpt_option_sys_api_root_page_member"><![CDATA[Root page for logged user]]></string>
+    <string name="_adm_stg_cpt_option_sys_api_root_page_home"><![CDATA[Home]]></string>
+    <string name="_adm_stg_cpt_option_sys_api_root_page_dashboard"><![CDATA[Dashboard]]></string>
+    <string name="_adm_stg_cpt_option_sys_api_root_page_profile"><![CDATA[Profile]]></string>
+    <string name="_adm_stg_cpt_option_sys_api_root_page_splash"><![CDATA[Splash]]></string>
+    <string name="_adm_stg_cpt_option_sys_api_url_root_email"><![CDATA[Site main URL in email notifications]]></string>
+    <string name="_adm_stg_cpt_option_sys_api_url_root_push"><![CDATA[Site main URL in push notifications]]></string>
+    <string name="_adm_stg_cpt_option_sys_agents_inspector_key"><![CDATA[Inspector key]]></string>
+    <string name="_adm_stg_cpt_option_sys_agents_inspector_key_info"><![CDATA[Get key at https://app.inspector.dev/]]></string>
+    <string name="_adm_stg_cpt_option_sys_agents_asst_chats_trans_del"><![CDATA[Auto delete transient chats everyday]]></string>
+    <string name="_adm_stg_cpt_option_sys_agents_sa"><![CDATA[Assistant for Studio]]></string>
+    <string name="_adm_stg_cpt_option_sys_agents_lsa"><![CDATA[Assistant for Live search]]></string>
+    <string name="_adm_stg_cpt_option_sys_agents_aba"><![CDATA[Assistant for 'Ask AI' block]]></string>
+    <string name="_adm_stg_cpt_option_sys_viewport_meta_tag"><![CDATA[Viewport meta tag]]></string>
+
+    <string name="_adm_stg_cpt_category_pwa_manifest"><![CDATA[Manifest]]></string>
+    <string name="_adm_stg_cpt_option_sys_pwa_manifest_name"><![CDATA[Name]]></string>
+    <string name="_adm_stg_cpt_option_sys_pwa_manifest_short_name"><![CDATA[Short name]]></string>
+    <string name="_adm_stg_cpt_option_sys_pwa_manifest_description"><![CDATA[Description]]></string>
+    <string name="_adm_stg_cpt_option_sys_pwa_manifest_background_color"><![CDATA[Background color]]></string>
+    <string name="_adm_stg_cpt_option_sys_pwa_manifest_theme_color"><![CDATA[Theme color]]></string>
+
+    <string name="_adm_stg_cpt_category_pwa_sw"><![CDATA[Service Worker]]></string>
+    <string name="_adm_stg_cpt_option_sys_pwa_sw_enable"><![CDATA[Enable]]></string>
+    <string name="_adm_stg_cpt_option_sys_pwa_sw_cache"><![CDATA[URLs to cache on install (each in new line)]]></string>
+    <string name="_adm_stg_cpt_option_sys_pwa_sw_offline"><![CDATA[Offline page]]></string>
+
+    <string name="_adm_stg_cpt_category_sockets"><![CDATA[Sockets server]]></string>
+    <string name="_adm_stg_cpt_option_sys_sockets_type"><![CDATA[Type]]></string>
+    <string name="_adm_stg_cpt_option_sys_sockets_url"><![CDATA[Url]]></string>
+    <string name="_adm_stg_cpt_option_sys_sockets_app_id"><![CDATA[App id]]></string>
+    <string name="_adm_stg_cpt_option_sys_sockets_key"><![CDATA[App key]]></string>
+    <string name="_adm_stg_cpt_option_sys_sockets_secret"><![CDATA[App secret]]></string>
+    <string name="_adm_stg_cpt_option_sys_sockets_type_sys_sockets_disabled"><![CDATA[Disabled]]></string>
+    <string name="_adm_stg_cpt_option_sys_sockets_type_sys_sockets_soketi"><![CDATA[Soketi]]></string>
+    
+    <string name="_adm_stg_cpt_option_sys_std_show_header_left"><![CDATA[Studio: Show header left area]]></string>
+    <string name="_adm_stg_cpt_option_sys_std_show_header_left_search"><![CDATA[Studio: Show search in header left]]></string>
+    <string name="_adm_stg_cpt_option_sys_std_show_header_center"><![CDATA[Studio: Show header center area]]></string>
+    <string name="_adm_stg_cpt_option_sys_std_show_header_right"><![CDATA[Studio: Show header right area]]></string>
+    <string name="_adm_stg_cpt_option_sys_std_show_header_right_search"><![CDATA[Studio: Show search in header right]]></string>
+    <string name="_adm_stg_cpt_option_sys_std_show_header_right_site"><![CDATA[Studio: Show 'site' link in header]]></string>
+    <string name="_adm_stg_cpt_option_sys_std_show_launcher_left"><![CDATA[Studio: Show left area with menu in Launcher]]></string>
+    <string name="_adm_stg_cpt_option_sys_std_pgt_etemplates_editor"><![CDATA[Studio Polyglot: Enable visual editor]]></string>
+
+    <string name="_adm_stg_cpt_option_sys_bg_jobs_process_per_run"><![CDATA[Background jobs: Number of jobs to process per run]]></string>
+    <string name="_adm_stg_cpt_option_sys_bg_jobs_workers_limit"><![CDATA[Background jobs: Max number of parallel workers]]></string>
+    <string name="_adm_stg_cpt_option_sys_bg_jobs_cleanup_timeout"><![CDATA[Background jobs: Cleanup jobs with errors after (in days)]]></string>
+
+    <string name="_adm_stg_cpt_option_sys_maintenance_mode"><![CDATA[Maintenance mode]]></string>
+    <string name="_adm_stg_cpt_option_sys_maintenance_mode_html"><![CDATA[Maintenance mode custom HTML code]]></string>
+
+	<string name="_adm_stg_cpt_type_system"><![CDATA[Global]]></string>
+	<string name="_adm_stg_scs_save"><![CDATA[Settings were successfully saved]]></string>
+	<string name="_adm_stg_err_save_error_message"><![CDATA[Error in '{0}': {1}]]></string>
+	<string name="_adm_stg_err_cannot_perform"><![CDATA[Cannot perform the action.]]></string>
+	<string name="_adm_stg_err_mix_already_exists"><![CDATA[Mix with the same name already exists.]]></string>
+        <string name="_adm_stg_txt_import_popup"><![CDATA[Import Settings]]></string>
+        <string name="_adm_stg_msg_imported"><![CDATA[Import finished. {0} items were processed.]]></string>
+        <string name="_adm_stg_err_import_wrong_format"><![CDATA[Wrong file format.]]></string>
+	<string name="_adm_stg_txt_create_mix_popup"><![CDATA[Add New Mix]]></string>
+	<string name="_adm_stg_txt_import_mix_popup"><![CDATA[Import Mix]]></string>
+        <string name="_adm_stg_txt_mix_dark"><![CDATA[Dark mode]]></string>
+	<string name="_adm_stg_txt_mix_duplicate"><![CDATA[Duplicate from]]></string>
+	<string name="_adm_stg_txt_mix_duplicate_inf"><![CDATA[Use 'None' to duplicate System values]]></string>
+	<string name="_adm_stg_txt_mix_title"><![CDATA[Mix Title]]></string>
+        <string name="_adm_stg_txt_mix_title_inf"><![CDATA[Create a <b>_sys_template_mixed_[template_name]_[mix_name]</b> language key in Polyglot to customise the publicly-displayed name. <b>[template_name]</b> and <b>[mix_name]</b> are in lowercase, underscore instead of space.]]></string>
+	<string name="_adm_stg_txt_mix_title_err"><![CDATA[Title is essential. Please, fill in this field.]]></string>
+	<string name="_adm_stg_txt_mix_system"><![CDATA[System]]></string>
+	<string name="_adm_stg_err_remove_old_image"><![CDATA[Cannot remove current image.]]></string>
+	<string name="_adm_str_cpt_files_file"><![CDATA[File]]></string>
+	<string name="_adm_str_cpt_files_version"><![CDATA[Version]]></string>
+	<string name="_adm_str_err_cannot_connect_to_ftp"><![CDATA[Cannot connect to FTP server. Please check FTP access details in Settings -> General.]]></string>
+	<string name="_adm_str_err_cannot_unzip_package"><![CDATA[Cannot unarchive ZIP package.]]></string>
+	<string name="_adm_str_err_cannot_write"><![CDATA[Cannot save downloaded file.]]></string>
+	<string name="_adm_str_err_destination_not_valid"><![CDATA[Destination FTP folder doesn't look like a valid the script root folder.]]></string>
+	<string name="_adm_str_err_download_failed"><![CDATA[Download failed. Please report.]]></string>
+	<string name="_adm_str_err_files_copy_failed"><![CDATA[File transfer failed, please check write permissions.]]></string>
+	<string name="_adm_str_err_no_ftp_info"><![CDATA[FTP access info was not specified. You may enter it via Settings -> General.]]></string>
+	<string name="_adm_str_err_no_product_info"><![CDATA[Cannot load product info. Try again later.]]></string>
+	<string name="_adm_str_err_wrong_package_format"><![CDATA[Wrong package format.]]></string>
+	<string name="_adm_str_err_zip_not_available"><![CDATA[ZIP library is not available.]]></string>
+	<string name="_adm_str_msg_download_scheduled"><![CDATA[Download was scheduled, in a few minutes downloaded package will be available to install via Apps &gt; Downloaded]]></string>
+	<string name="_adm_str_msg_download_and_install_scheduled"><![CDATA[Download and subsequent installation were scheduled, it may take a few minutes]]></string>
+	<string name="_adm_str_msg_download_successfully"><![CDATA[Download was successfully finished, you may install it via Apps &gt; Downloaded]]></string>
+	<string name="_adm_str_msg_download_and_install_successfully"><![CDATA[Download and subsequent installation were successfully finished]]></string>
+	<string name="_adm_str_txt_discount_csign"><![CDATA[({0}{1} for Premium)]]></string>
+	<string name="_adm_str_txt_items_by"><![CDATA[item(s) by]]></string>
+	<string name="_adm_str_txt_or"><![CDATA[or]]></string>
+	<string name="_adm_str_txt_per_week"><![CDATA[week]]></string>
+    <string name="_adm_str_txt_per_week_short"><![CDATA[wk]]></string>
+    <string name="_adm_str_txt_per_month"><![CDATA[month]]></string>
+    <string name="_adm_str_txt_per_month_short"><![CDATA[mo]]></string>
+    <string name="_adm_str_txt_per_year"><![CDATA[year]]></string>
+    <string name="_adm_str_txt_per_year_short"><![CDATA[yr]]></string>
+	<string name="_adm_str_txt_price_free"><![CDATA[Free]]></string>
+	<string name="_adm_str_txt_price_recurring"><![CDATA[{0}{1}/{2}]]></string>
+	<string name="_adm_str_txt_price_single"><![CDATA[{0}{1}]]></string>
+	<string name="_adm_str_txt_pv_category"><![CDATA[Category]]></string>
+	<string name="_adm_str_txt_pv_created"><![CDATA[Created]]></string>
+	<string name="_adm_str_txt_pv_description"><![CDATA[Description]]></string>
+	<string name="_adm_str_txt_pv_discount"><![CDATA[Discount]]></string>
+	<string name="_adm_str_txt_pv_discount_off_csign"><![CDATA[{0}% ({1}{2}) off for Premium]]></string>
+	<string name="_adm_str_txt_pv_price"><![CDATA[Price]]></string>
+	<string name="_adm_str_txt_pv_rent"><![CDATA[Rent]]></string>
+	<string name="_adm_str_txt_pv_stats"><![CDATA[Stats]]></string>
+	<string name="_adm_str_txt_pv_stats_votes"><![CDATA[{0} votes]]></string>
+	<string name="_adm_str_txt_pv_stats_reviews"><![CDATA[{0} reviews]]></string>
+	<string name="_adm_str_txt_pv_stats_views"><![CDATA[{0} views]]></string>
+	<string name="_adm_str_txt_pv_tags"><![CDATA[Tags]]></string>
+	<string name="_adm_str_txt_pv_title"><![CDATA[Title]]></string>
+	<string name="_adm_str_txt_pv_updated"><![CDATA[Updated]]></string>
+	<string name="_adm_str_txt_pv_vendor"><![CDATA[Vendor]]></string>
+	<string name="_adm_str_txt_pv_version"><![CDATA[Version]]></string>
+	<string name="_adm_str_txt_pv_version_mask"><![CDATA[{0} ({1} is available)]]></string>
+	<string name="_adm_str_txt_update_from_to"><![CDATA[{0} - {1}]]></string>
+	<string name="_adm_strg_err_cannot_process_action"><![CDATA[Cannot process action. It does not have an associated handler.]]></string>
+	<string name="_adm_strg_err_files_delete"><![CDATA[Cannot delete file(s).]]></string>
+	<string name="_adm_strg_msg_files_delete"><![CDATA[Files were queued for deletion. They will be deleted a little bit later.]]></string>
+	<string name="_adm_strg_err_images_delete"><![CDATA[Cannot delete image(s).]]></string>
+	<string name="_adm_strg_msg_images_delete"><![CDATA[Images were queued for deletion. They will be deleted a little bit later.]]></string>
+	<string name="_adm_strg_err_images_resize"><![CDATA[Cannot resize image.]]></string>
+	<string name="_adm_strg_txt_file_name"><![CDATA[Name]]></string>
+	<string name="_adm_strg_txt_path"><![CDATA[URL]]></string>
+	<string name="_adm_strg_txt_mime_type"><![CDATA[Type]]></string>
+	<string name="_adm_strg_txt_added"><![CDATA[Date]]></string>
+	<string name="_adm_strg_btn_delete"><![CDATA[Delete]]></string>
+	<string name="_adm_strg_btn_add"><![CDATA[Add]]></string>
+	<string name="_adm_strg_btn_cancel"><![CDATA[Cancel]]></string>
+	<string name="_adm_strg_btn_done"><![CDATA[Done]]></string>
+	<string name="_adm_strg_btn_download"><![CDATA[Download]]></string>
+	<string name="_adm_strg_btn_resize"><![CDATA[Resize]]></string>
+	<string name="_adm_strg_txt_files_add_popup"><![CDATA[Add File]]></string>
+	<string name="_adm_strg_txt_images_add_popup"><![CDATA[Add Image]]></string>
+	<string name="_adm_strg_txt_images_resize_popup"><![CDATA[Resize Image]]></string>
+	<string name="_adm_strg_txt_size_mime_type"><![CDATA[{0}x{1}, {2}]]></string>
+	<string name="_adm_strg_txt_width"><![CDATA[Width]]></string>
+	<string name="_adm_strg_err_width"><![CDATA[Width is essential. Please, fill in this field.]]></string>
+	<string name="_adm_strg_txt_height"><![CDATA[Height]]></string>
+	<string name="_adm_strg_err_height"><![CDATA[Height is essential. Please, fill in this field.]]></string>
+        <string name="_adm_tmi_cpt_account"><![CDATA[Menu]]></string>
+        <string name="_adm_tmi_cpt_assistant"><![CDATA[Assistant]]></string>
+	<string name="_adm_tmi_cpt_site"><![CDATA[Go To Site]]></string>
+        <string name="_adm_tmi_cpt_search"><![CDATA[Search...]]></string>
+        <string name="_adm_tmi_cpt_scheme"><![CDATA[Color Scheme]]></string>
+	<string name="_adm_tmi_cpt_tour"><![CDATA[Tour]]></string>
+	<string name="_adm_tmi_cpt_launcher"><![CDATA[Launcher]]></string>
+        <string name="_adm_txt_active_api"><![CDATA[Available in App]]></string>
+        <string name="_adm_txt_assistant_popup_title"><![CDATA[How can I help?]]></string>
+	<string name="_adm_txt_confirm_cancel"><![CDATA[Cancel]]></string>
+	<string name="_adm_txt_confirm_ok"><![CDATA[OK]]></string>
+	<string name="_adm_txt_forgot_password"><![CDATA[Forgot password?]]></string>
+	<string name="_adm_txt_form_view_missing"><![CDATA[missing]]></string>
+	<string name="_adm_txt_login_password"><![CDATA[Password]]></string>
+        <string name="_adm_txt_login_password_placeholder"><![CDATA[your password]]></string>
+	<string name="_adm_txt_login_email"><![CDATA[Email address]]></string>
+        <string name="_adm_txt_login_email_placeholder"><![CDATA[operator@example.com]]></string>
+        <string name="_adm_txt_login_title"><![CDATA[Login]]></string>
+        <string name="_adm_txt_login_subtitle"><![CDATA[Enter your email and password to login to Studio.]]></string>
+	<string name="_adm_txt_module_custom"><![CDATA[Custom]]></string>
+	<string name="_adm_txt_module_skeletons"><![CDATA[Skeletons]]></string>
+	<string name="_adm_txt_module_system"><![CDATA[System]]></string>
+	<string name="_adm_txt_modules_check_dependencies"><![CDATA[Check module dependencies:]]></string>
+	<string name="_adm_txt_modules_check_module_exists"><![CDATA[Check module for existence:]]></string>
+	<string name="_adm_txt_modules_check_module_matches"><![CDATA[Check module to match:]]></string>
+	<string name="_adm_txt_modules_check_module_hash"><![CDATA[Check module hash:]]></string>
+	<string name="_adm_txt_modules_check_module_version"><![CDATA[Check module version:]]></string>
+	<string name="_adm_txt_modules_check_script_version"><![CDATA[Check the script version for compatibility:]]></string>
+	<string name="_adm_txt_modules_clear_db_cache"><![CDATA[Clear database cache:]]></string>
+	<string name="_adm_txt_modules_clear_template_cache"><![CDATA[Clear template cache:]]></string>
+	<string name="_adm_txt_modules_delete"><![CDATA[Delete]]></string>
+	<string name="_adm_txt_modules_disable"><![CDATA[Disable]]></string>
+        <string name="_adm_txt_modules_discontinued"><![CDATA[You have an unsupported UNA app installed. The "<a href='{0}'>{1}</a>" app is no longer receiving updates and is not compatible with latest version of UNA CMS.]]></string>
+	<string name="_adm_txt_modules_enable"><![CDATA[Enable]]></string>
+	<string name="_adm_txt_modules_executable"><![CDATA[Executable]]></string>
+	<string name="_adm_txt_modules_execute_sql"><![CDATA[Changing database:]]></string>
+	<string name="_adm_txt_modules_ftp_access"><![CDATA[FTP access]]></string>
+	<string name="_adm_txt_modules_install"><![CDATA[Install]]></string>
+	<string name="_adm_txt_modules_install_language"><![CDATA[Install language:]]></string>
+	<string name="_adm_txt_modules_login"><![CDATA[Login]]></string>
+	<string name="_adm_txt_modules_market"><![CDATA[UNA Market]]></string>
+	<string name="_adm_txt_modules_move_sources"><![CDATA[Move source files:]]></string>
+	<string name="_adm_txt_modules_operation_update"><![CDATA[Installation of update <b>{0}</b> from {1} up to {2}]]></string>
+	<string name="_adm_txt_modules_package_module"><![CDATA[Module]]></string>
+	<string name="_adm_txt_modules_package_to_upload"><![CDATA[Package to upload]]></string>
+	<string name="_adm_txt_modules_params_used"><![CDATA[A module with similar unique parameters is already installed.]]></string>
+	<string name="_adm_txt_modules_password"><![CDATA[Password]]></string>
+	<string name="_adm_txt_modules_process_action_success"><![CDATA[Done]]></string>
+	<string name="_adm_txt_modules_process_connections"><![CDATA[Process connections:]]></string>
+	<string name="_adm_txt_modules_process_deleted_profiles"><![CDATA[Process deleted profiles:]]></string>
+	<string name="_adm_txt_modules_process_menu_triggers"><![CDATA[Process menu triggers:]]></string>
+	<string name="_adm_txt_modules_process_page_triggers"><![CDATA[Process page triggers:]]></string>
+	<string name="_adm_txt_modules_process_storages"><![CDATA[Process storages:]]></string>
+	<string name="_adm_txt_modules_process_failed"><![CDATA[Failed]]></string>
+	<string name="_adm_txt_modules_process_success"><![CDATA[Done]]></string>
+	<string name="_adm_txt_modules_process_esearches"><![CDATA[Process search forms:]]></string>
+	<string name="_adm_txt_modules_register_transcoders"><![CDATA[Register transcoders:]]></string>
+	<string name="_adm_txt_modules_unregister_transcoders"><![CDATA[Unregister transcoders:]]></string>
+	<string name="_adm_txt_modules_show_conclusion"><![CDATA[Conclusion from vendor:]]></string>
+	<string name="_adm_txt_modules_show_introduction"><![CDATA[Introduction from vendor:]]></string>
+	<string name="_adm_txt_modules_update_files"><![CDATA[Update files:]]></string>
+	<string name="_adm_txt_modules_update_relations"><![CDATA[Update relations:]]></string>
+	<string name="_adm_txt_modules_update_relations_for_all"><![CDATA[Update relations for all dependent modules:]]></string>
+	<string name="_adm_txt_modules_update_languages"><![CDATA[Update languages:]]></string>
+	<string name="_adm_txt_modules_update_latest"><![CDATA[You have the most current version.]]></string>
+	<string name="_adm_txt_modules_update_text"><![CDATA[New version {0} is available.]]></string>
+	<string name="_adm_txt_modules_updates"><![CDATA[Available Updates]]></string>
+	<string name="_adm_txt_modules_upload"><![CDATA[Add New Module]]></string>
+	<string name="_adm_txt_modules_writable"><![CDATA[Writable]]></string>
+	<string name="_adm_txt_pca_active"><![CDATA[Active]]></string>
+        <string name="_adm_txt_pca_bookmark"><![CDATA[Bookmark]]></string>
+	<string name="_adm_txt_pca_featured"><![CDATA[Featured]]></string>
+        <string name="_adm_txt_pca_rearrange"><![CDATA[Move to]]></string>
+	<string name="_adm_txt_remember_me"><![CDATA[Remember me]]></string>
+	<string name="_adm_txt_select_module"><![CDATA[Select Module...]]></string>
+        <string name="_adm_txt_settings"><![CDATA[Settings]]></string>
+	<string name="_adm_txt_show_actions"><![CDATA[Actions]]></string>
+	<string name="_adm_txt_show_help"><![CDATA[Help]]></string>
+	<string name="_adm_txt_show_help_content_empty"><![CDATA[Help is not available]]></string>
+	<string name="_adm_txt_uninstall"><![CDATA[Uninstall]]></string>
+        <string name="_adm_wgt_cpt_api"><![CDATA[API]]></string>
+        <string name="_adm_wgt_cpt_agents"><![CDATA[Agents]]></string>
+        <string name="_adm_wgt_cpt_audit"><![CDATA[Audit]]></string>
+        <string name="_adm_wgt_cpt_badges"><![CDATA[Badges]]></string>
+	<string name="_adm_wgt_cpt_builder_forms"><![CDATA[Forms]]></string>
+	<string name="_adm_wgt_cpt_builder_menus"><![CDATA[Navigation]]></string>
+	<string name="_adm_wgt_cpt_builder_pages"><![CDATA[Pages]]></string>
+	<string name="_adm_wgt_cpt_builder_permissions"><![CDATA[Permissions]]></string>
+        <string name="_adm_wgt_cpt_builder_roles"><![CDATA[Roles]]></string>
+	<string name="_adm_wgt_cpt_dashboard"><![CDATA[Dashboard]]></string>
+	<string name="_adm_wgt_cpt_designer"><![CDATA[Designer]]></string>
+	<string name="_adm_wgt_cpt_polyglot"><![CDATA[Polyglot]]></string>
+	<string name="_adm_wgt_cpt_settings"><![CDATA[Settings]]></string>
+	<string name="_adm_wgt_cpt_storages"><![CDATA[Storage]]></string>
+	<string name="_adm_wgt_cpt_store"><![CDATA[App Store]]></string>
+        <string name="_cmt_err_not_enabled"><![CDATA[The feature is not available right now. Please, try again later.]]></string>
+	<string name="_cmt_block_comments_title"><![CDATA[Comments ({0})]]></string>
+	<string name="_cmt_browse_all"><![CDATA[All]]></string>
+	<string name="_cmt_browse_friends"><![CDATA[Friends]]></string>
+	<string name="_cmt_browse_head"><![CDATA[Oldest]]></string>
+	<string name="_cmt_browse_popular"><![CDATA[Popular]]></string>
+	<string name="_cmt_browse_subscriptions"><![CDATA[Subscriptions]]></string>
+	<string name="_cmt_browse_tail"><![CDATA[Newest]]></string>
+	<string name="_cmt_display_flat"><![CDATA[Flat]]></string>
+	<string name="_cmt_display_threaded"><![CDATA[Threaded]]></string>
+	<string name="_cmt_err_cannot_perform_action"><![CDATA[Cannot perform action. Please report.]]></string>
+	<string name="_cmt_msg_login_required"><![CDATA[<a href="{0}">Login</a> or <a href="{1}">Join</a> to comment.]]></string>
+	<string name="_cmt_page_view_header"><![CDATA[Comment '{comment_snippet}' to '{object_title}']]></string>
+	<string name="_cmt_page_view_title"><![CDATA[Comment to <a href="{object_url}">{object_title}</a>]]></string>
+        <string name="_cmt_page_view_title_author"><![CDATA[Comment author]]></string>
+        <string name="_cmt_page_view_title_content"><![CDATA[Comment content]]></string>
+	<string name="_cmt_download_attached_file"><![CDATA[Download file]]></string>
+	<string name="_cmt_view_attached_image"><![CDATA[View image]]></string>
+	<string name="_cmt_load_more_comments_head"><![CDATA[See newer comments...]]></string>
+	<string name="_cmt_load_more_comments_tail"><![CDATA[See older comments...]]></string>
+	<string name="_cmt_load_more_comments_popular"><![CDATA[See more comments...]]></string>
+	<string name="_cmt_load_more_replies_head"><![CDATA[See newer replies...]]></string>
+	<string name="_cmt_load_more_replies_tail"><![CDATA[See older replies...]]></string>
+	<string name="_cmt_load_more_replies_popular"><![CDATA[See more replies...]]></string>
+        <string name="_cmt_txt_new_content"><![CDATA[New content]]></string>
+	<string name="_cmt_txt_link_show"><![CDATA[Show]]></string>
+	<string name="_cmt_txt_link_reply"><![CDATA[Reply]]></string>
+        <string name="_cmt_txt_added_sample"><![CDATA[added a new comment]]></string>
+	<string name="_cmt_txt_or"><![CDATA[or]]></string>
+        <string name="_cmt_txt_pinned"><![CDATA[Pinned comment]]></string>
+	<string name="_cmt_txt_sample_comment_single"><![CDATA[comment]]></string>
+        <string name="_cmt_txt_sample_comment_single_with_article"><![CDATA[a comment]]></string>
+        <string name="_cmt_txt_sample_reaction_single"><![CDATA['{0}' reaction to comment]]></string>
+	<string name="_cmt_txt_sample_reply_to"><![CDATA[reply to comment]]></string>
+        <string name="_cmt_txt_sample_score_up_single"><![CDATA[score up vote to comment]]></string>
+        <string name="_cmt_txt_sample_score_down_single"><![CDATA[score down vote to comment]]></string>
+        <string name="_cmt_txt_sample_vote_single"><![CDATA[vote to comment]]></string>
+        <string name="_cmt_txt_added_sample_custom"><![CDATA[Added <a href="{sample_url}">{sample}</a> to <a href="{psample_url}">{psample}</a>]]></string>
+	<string name="_cmt_txt_n_comments"><![CDATA[{0} comments]]></string>
+        <string name="_cmt_txt_do"><![CDATA[Comment]]></string>
+        <string name="_cmt_txt_counter"><![CDATA[{0}]]></string>
+	<string name="_cmt_txt_counter_empty"><![CDATA[Comment]]></string>
+        <string name="_cmt_txt_min_form_placeholder"><![CDATA[{0}, leave your comment here.]]></string>
+        <string name="_cmt_txt_note_approve_pending"><![CDATA[Comment will be published as soon as it's approved by moderator]]></string>
+        <string name="_cmt_nts_popup_view_title"><![CDATA[Notes]]></string>
+        <string name="_cmt_nts_popup_view_title_rc"><![CDATA[Report's Comments]]></string>
+        <string name="_cmt_rvw_block_rating_title"><![CDATA[Reviews Rating]]></string>
+        <string name="_cmt_rvw_block_reviews_title"><![CDATA[Reviews ({0})]]></string>
+        <string name="_cmt_rvw_txt_min_form_placeholder"><![CDATA[{0}, leave your review here.]]></string>
+        <string name="_cmt_rvw_txt_sample_comment_single"><![CDATA[review]]></string>
+        <string name="_cmt_rvw_txt_sample_reaction_single"><![CDATA['{0}' reaction to review]]></string>
+        <string name="_cmt_rvw_txt_sample_score_up_single"><![CDATA[score up vote to review]]></string>
+        <string name="_cmt_rvw_txt_sample_score_down_single"><![CDATA[score down vote to review]]></string>
+        <string name="_cmt_rvw_txt_sample_vote_single"><![CDATA[vote to review]]></string>
+        <string name="_cmt_rvw_txt_empty"><![CDATA[No reviews yet]]></string>
+        <string name="_cmt_rvw_txt_do"><![CDATA[Review]]></string>
+        <string name="_copyright"><![CDATA[&copy; {0} Company]]></string>
+	<string name="_delete"><![CDATA[delete]]></string>
+        <string name="_duration_day"><![CDATA[day]]></string>
+        <string name="_duration_day_pl"><![CDATA[days]]></string>
+        <string name="_duration_week"><![CDATA[week]]></string>
+        <string name="_duration_week_pl"><![CDATA[week]]></string>
+        <string name="_duration_month"><![CDATA[month]]></string>
+        <string name="_duration_month_pl"><![CDATA[monthes]]></string>
+        <string name="_duration_year"><![CDATA[year]]></string>
+        <string name="_duration_year_pl"><![CDATA[year]]></string>
+	<string name="_error occured"><![CDATA[Error occurred]]></string>
+	<string name="_from"><![CDATA[from]]></string>
+	<string name="_hidden_comment"><![CDATA[Comment by <b>{0}</b> is hidden.]]></string>
+	<string name="_in_reply_to"><![CDATA[In reply to]]></string>
+        <string name="_in_reply_to_x"><![CDATA[In reply to {0}]]></string>
+	<string name="_item"><![CDATA[item]]></string>
+	<string name="_items"><![CDATA[items]]></string>
+	<string name="_member_banned"><![CDATA[Sorry, you've been banned]]></string>
+	<string name="_message_subject"><![CDATA[Message subject]]></string>
+	<string name="_mma_comments_edit_own"><![CDATA[comments edit own]]></string>
+	<string name="_mma_comments_post"><![CDATA[comments post]]></string>
+	<string name="_mma_comments_remove_own"><![CDATA[comments remove own]]></string>
+	<string name="_mma_comments_vote"><![CDATA[comments vote]]></string>
+	<string name="_mma_get_other_members_emails"><![CDATA[get other members emails]]></string>
+	<string name="_mma_send_greetings"><![CDATA[send greetings]]></string>
+	<string name="_mma_send_messages"><![CDATA[send messages]]></string>
+	<string name="_mma_view_profiles"><![CDATA[view profiles]]></string>
+	<string name="_mma_vote"><![CDATA[vote]]></string>
+	<string name="_month_next"><![CDATA[Next Month]]></string>
+	<string name="_month_prev"><![CDATA[Previous Month]]></string>
+	<string name="_no limit"><![CDATA[no limit]]></string>
+	<string name="_powered_by"><![CDATA[Powered by]]></string>
+	<string name="_see_more"><![CDATA[See more...]]></string>
+	<string name="_show_replacement"><![CDATA[Show]]></string>
+	<string name="_sys_accept"><![CDATA[Accept]]></string>
+	<string name="_sys_accounts"><![CDATA[Accounts]]></string>
+	<string name="_sys_access_denied_to_private_content"><![CDATA[Access denied. This is private content.]]></string>
+	<string name="_sys_actions"><![CDATA[Actions]]></string>
+	<string name="_sys_active"><![CDATA[Active]]></string>
+  <string name="_sys_account_settings_email_successfully_submitted"><![CDATA[Email settings were successfully saved]]></string>
+  <string name="_sys_account_settings_pwd_successfully_submitted"><![CDATA[Password was successfully changed]]></string>
+  <string name="_sys_account_settings_info_successfully_submitted"><![CDATA[Account settings were successfully saved]]></string>
+	<string name="_sys_acc_confirmation_type_none"><![CDATA[No confirmation]]></string>
+	<string name="_sys_acc_confirmation_type_email"><![CDATA[email is confirmed]]></string>
+	<string name="_sys_acc_confirmation_type_phone"><![CDATA[phone is confirmed]]></string>
+	<string name="_sys_acc_confirmation_type_email_and_phone"><![CDATA[email and phone are confirmed]]></string>
+  <string name="_sys_acc_confirmation_type_email_or_phone"><![CDATA[email or phone is confirmed]]></string>
+	<string name="_sys_acl_action_account"><![CDATA[You haven't created any profiles, so you can't '{1}'.]]></string>
+	<string name="_sys_acl_action_chart_view"><![CDATA[View charts]]></string>
+	<string name="_sys_acl_action_chart_view_desc"><![CDATA[View statistical charts]]></string>
+	<string name="_sys_acl_action_comments_edit_all"><![CDATA[Comments Edit All]]></string>
+	<string name="_sys_acl_action_comments_edit_own"><![CDATA[Comments Edit Own]]></string>
+        <string name="_sys_acl_action_comments_pin"><![CDATA[Comments Pin]]></string>
+	<string name="_sys_acl_action_comments_post"><![CDATA[Comments Post]]></string>
+	<string name="_sys_acl_action_comments_remove_all"><![CDATA[Comments Remove All]]></string>
+  <string name="_sys_acl_action_comments_remove_in_own_content"><![CDATA[Comments Remove All In Own Content]]></string>
+  <string name="_sys_acl_action_comments_remove_in_group_context"><![CDATA[Comments Remove All In Context for Context's admins]]></string>
+	<string name="_sys_acl_action_comments_remove_own"><![CDATA[Comments Remove Own]]></string>
+	<string name="_sys_acl_action_connect"><![CDATA[Connect (befriend, follow, etc)]]></string>
+	<string name="_sys_acl_action_create_account"><![CDATA[Create Account]]></string>
+	<string name="_sys_acl_action_create_account_desc"><![CDATA[It make sense for guests only, you can temporary disable it or set limit by time for example.]]></string>
+	<string name="_sys_acl_action_delete_account"><![CDATA[Delete Account]]></string>
+	<string name="_sys_acl_action_delete_account_desc"><![CDATA[Delete account also deletes account's content.]]></string>
+	<string name="_sys_acl_action_every_period"><![CDATA[ every {4} hours, new period begins {8}]]></string>
+	<string name="_sys_acl_action_favorite"><![CDATA[Favorite]]></string>
+	<string name="_sys_acl_action_favorite_view"><![CDATA[View favorites]]></string>
+	<string name="_sys_acl_action_feature"><![CDATA[Feature]]></string>
+	<string name="_sys_acl_action_view_view"><![CDATA[View views]]></string>
+	<string name="_sys_acl_action_view_view_viewers_own"><![CDATA[View viewers for own content]]></string>
+	<string name="_sys_acl_action_limit_reached"><![CDATA[You have reached your limit for now. Your current membership ({2}) allows you to {1} no more than {3} times]]></string>
+	<string name="_sys_acl_action_not_allowed"><![CDATA[Your current membership ({2}) doesn't allow you to '{1}'.]]></string>
+	<string name="_sys_acl_action_not_allowed_after"><![CDATA[Your current membership ({2}) stopped to allow you to '{1}' {5}.]]></string>
+	<string name="_sys_acl_action_not_allowed_before"><![CDATA[Your current membership ({2}) will allow you to '{1}' {6}.]]></string>
+        <string name="_sys_acl_action_pending"><![CDATA[You are currently not an active member. Please, ask the site <a href="mailto:{7}">administrator</a> to make you an active member so you would be able to <b>{1}</b>.]]></string>
+	<string name="_sys_acl_action_post_links"><![CDATA[Post links]]></string>
+	<string name="_sys_acl_action_post_links_desc"><![CDATA[Post links in text and textarea form fields]]></string>
+	<string name="_sys_acl_action_use_macros"><![CDATA[Use Macros]]></string>
+        <string name="_sys_acl_action_use_macros_desc"><![CDATA[Use special constructions to insert dynamic content almost anywhere]]></string>
+	<string name="_sys_acl_action_set_acl_level"><![CDATA[Set membership level]]></string>
+	<string name="_sys_acl_action_set_acl_level_desc"><![CDATA[Set membership level for profiles]]></string>
+        <string name="_sys_acl_action_show_membership_levels_in_privacy_groups"><![CDATA[Use membership level(s) in privacy fields]]></string>
+        <string name="_sys_acl_action_show_membership_levels_in_privacy_groups_desc"><![CDATA[Allow to limit access by membership level(s) in privacy fields]]></string>
+        <string name="_sys_acl_action_show_membership_private_info"><![CDATA[Show membership private info]]></string>
+        <string name="_sys_acl_action_show_membership_private_info_desc"><![CDATA[Show membership private info]]></string>
+        <string name="_sys_acl_action_set_badge"><![CDATA[Set badge]]></string>
+        <string name="_sys_acl_action_set_badge_desc"><![CDATA[Set badge for content]]></string>
+        <string name="_sys_acl_action_switch_to_any_profile"><![CDATA[Switch to any profile]]></string>
+        <string name="_sys_acl_action_switch_to_any_profile_desc"><![CDATA[Allow switch to any profile]]></string>
+        <string name="_sys_acl_action_set_acl_as_privacy"><![CDATA[Choose membership level as privacy]]></string>
+	<string name="_sys_acl_action_set_acl_as_privacy_desc"><![CDATA[Choose membership level as privacy in add content forms]]></string>
+        <string name="_sys_acl_action_set_form_fields_privacy"><![CDATA[Set form fields privacy]]></string>
+	<string name="_sys_acl_action_set_form_fields_privacy_desc"><![CDATA[Allow to set privacy for form fields]]></string>
+	<string name="_sys_acl_action_suspended"><![CDATA[You can't '{1}' because your profile was suspended, if you don't know why - try to send message to <a href="mailto:{7}">administrator</a>.]]></string>
+	<string name="_sys_acl_action_unauthenticated"><![CDATA[Not logged in users can't '{1}'.]]></string>
+	<string name="_sys_acl_action_unconfirmed"><![CDATA[You didn't confirm your profile. Please check your email with profile activation link. Unconfirmed members can't <b>{1}</b>.]]></string>
+	<string name="_sys_acl_action_vote"><![CDATA[Vote]]></string>
+        <string name="_sys_acl_action_vote_view"><![CDATA[View votes]]></string>
+        <string name="_sys_acl_action_vote_view_voters"><![CDATA[View voters]]></string>
+	<string name="_sys_acl_action_report"><![CDATA[Report]]></string>
+	<string name="_sys_acl_action_report_view"><![CDATA[View reports]]></string>
+	<string name="_sys_acl_action_add_block"><![CDATA[Wiki: Add Block]]></string>
+	<string name="_sys_acl_action_edit_block"><![CDATA[Wiki: Edit Block]]></string>
+	<string name="_sys_acl_action_translate_block"><![CDATA[Wiki: Translate Block]]></string>
+	<string name="_sys_acl_action_delete_version"><![CDATA[Wiki: Delete Version]]></string>
+	<string name="_sys_acl_action_delete_block"><![CDATA[Wiki: Delete Block]]></string>
+	<string name="_sys_acl_action_history"><![CDATA[Wiki: History]]></string>
+	<string name="_sys_acl_action_unsafe"><![CDATA[Wiki: Unsafe HTML]]></string>
+	<string name="_sys_acl_start"><![CDATA[Started: ]]></string>
+	<string name="_sys_acl_expire"><![CDATA[Expires: ]]></string>
+	<string name="_sys_acl_expire_never"><![CDATA[never]]></string>
+    <string name="_sys_acl_state"><![CDATA[State: ]]></string>
+    <string name="_sys_acl_state_trial"><![CDATA[Trial]]></string>
+    <string name="_sys_acl_downgrade"><![CDATA[Downgrade]]></string>
+
+    <string name="_sys_agents_form_field_err_enter"><![CDATA[This field is essential. Please enter something here.]]></string>
+    <string name="_sys_agents_form_field_err_select"><![CDATA[This field is essential. Please select something here.]]></string>
+    <string name="_sys_agents_form_field_err_profile_has_agent"><![CDATA[This profile is already used in another agent({0}) with the same 'message' trigger.]]></string>
+    <string name="_sys_agents_json_field_err"><![CDATA[Invalid JSON format.]]></string>
+    <string name="_sys_agents_automators_txt_active"><![CDATA[Active]]></string>
+    <string name="_sys_agents_automators_txt_name"><![CDATA[Name]]></string>
+    <string name="_sys_agents_automators_txt_type"><![CDATA[Type]]></string>
+    <string name="_sys_agents_automators_txt_alert_unit"><![CDATA[Unit]]></string>
+    <string name="_sys_agents_automators_txt_alert_action"><![CDATA[Action]]></string>
+    <string name="_sys_agents_automators_txt_scheduler_time"><![CDATA[Time]]></string>
+    <string name="_sys_agents_automators_txt_model_id"><![CDATA[Model]]></string>
+    <string name="_sys_agents_automators_txt_profile_id"><![CDATA[Profile]]></string>
+    <string name="_sys_agents_automators_txt_message_id"><![CDATA[Prompt]]></string>
+    <string name="_sys_agents_automators_txt_messages"><![CDATA[Messages]]></string>
+    <string name="_sys_agents_automators_txt_code"><![CDATA[Code]]></string>
+    <string name="_sys_agents_automators_txt_added"><![CDATA[Added]]></string>
+    <string name="_sys_agents_automators_txt_status"><![CDATA[Status]]></string>
+    
+    <string name="_sys_agents_agents_txt_name"><![CDATA[Name]]></string>
+    <string name="_sys_agents_agents_txt_trigger"><![CDATA[Trigger]]></string>
+    <string name="_sys_agents_agents_txt_profile_id"><![CDATA[Profile]]></string>
+    <string name="_sys_agents_agents_popup_add"><![CDATA[Add agent]]></string>
+    
+    <string name="_Run"><![CDATA[Run]]></string>
+    
+    <string name="_sys_agents_automators_btn_add"><![CDATA[Add]]></string>
+    <string name="_sys_agents_automators_btn_tune"><![CDATA[Tune]]></string>
+    <string name="_sys_agents_automators_btn_approve"><![CDATA[Approve]]></string>
+    <string name="_sys_agents_automators_popup_add"><![CDATA[Add automator]]></string>
+    <string name="_sys_agents_count_today"><![CDATA[{0} calls today]]></string>
+    <string name="_sys_agents_count_per_req"><![CDATA[{0} calls per request]]></string>
+    <string name="_sys_agents_field_async"><![CDATA[Delayed execution]]></string>
+    <string name="_sys_agents_field_async_inf"><![CDATA[Run agent later to not block/delay normal code execution. Not applicable for 'manual' and 'scheduler'. For 'alert' - overriding values will not work. For 'messenger' - messages will not appear automatically.]]></string>
+    <string name="_sys_agents_popup_edit"><![CDATA[Edit automator]]></string>
+    <string name="_sys_agents_field_name"><![CDATA[Name]]></string>
+    <string name="_sys_agents_field_name_info"><![CDATA[Uniq agent name]]></string>
+    <string name="_sys_agents_field_model_id"><![CDATA[Model]]></string>
+    <string name="_sys_agents_field_model_id_info"><![CDATA[AI model to use for this agent.]]></string>
+    <string name="_sys_agents_automators_field_profile_id"><![CDATA[Profile]]></string>
+    <string name="_sys_agents_automators_field_profile_id_inf"><![CDATA[Leave empty to use default.]]></string>
+    <string name="_sys_agents_field_profile_id"><![CDATA[Profile]]></string>
+    <string name="_sys_agents_field_profile_id_inf"><![CDATA[AI agent will perform actions under this profile]]></string>
+    <string name="_sys_agents_automators_field_type"><![CDATA[Type]]></string>
+    <string name="_sys_agents_automators_field_type_event"><![CDATA[Event]]></string>
+    <string name="_sys_agents_automators_field_type_scheduler"><![CDATA[Scheduler]]></string>
+    <string name="_sys_agents_automators_field_type_webhook"><![CDATA[Webhook]]></string>
+    <string name="_sys_agents_field_trigger"><![CDATA[Trigger]]></string>
+    <string name="_sys_agents_field_trigger_info"><![CDATA[Trigger which will initiate agent to run. Alert — system event notification. Scheduler — time-based scheduled execution. Webhook — external HTTP trigger. Manual — user-initiated run. Agent — triggered by another agent. Message — triggered by chat message.]]></string>
+    <string name="_sys_agents_field_alert_sample"><![CDATA[Alert: payload]]></string>
+    <string name="_sys_agents_waiting_for_sample_data_alert"><![CDATA[Please select an alert to see its payload.]]></string>
+    <string name="_sys_agents_waiting_for_sample_data_webhook"><![CDATA[Trigger webhook to see its payload.]]></string>
+    <string name="_sys_agents_field_alert"><![CDATA[Alert: event name]]></string>
+    <string name="_sys_agents_field_alert_info"><![CDATA[Event that triggers the agent. Usually starts with system or module_name. Only events that have occurred at least once are shown.]]></string>
+    <string name="_sys_agents_field_scheduler_cron"><![CDATA[Scheduler (CRON)]]></string>
+    <string name="_sys_agents_field_scheduler_cron_info"><![CDATA[CRON expression for scheduling the agent.]]></string>
+    <string name="_sys_agents_field_webhook_key"><![CDATA[Webhook: key]]></string>
+    <string name="_sys_agents_field_webhook_key_info"><![CDATA[Unique key for webhook endpoint, used as Bearer Authentication header.]]></string>
+    <string name="_sys_agents_field_webhook_sample"><![CDATA[Webhook: sample payload]]></string>
+    <string name="_sys_agents_field_message_profile"><![CDATA[Message: profile for communication with agent]]></string>
+    <string name="_sys_agents_field_message_profile_info"><![CDATA[Profile to use for sending messages to the agent, messages from other users are ignored.]]></string>
+    <string name="_sys_agents_field_vector_store_id"><![CDATA[Knowledge]]></string>
+    <string name="_sys_agents_field_vector_store_id_info"><![CDATA[Vector store for knowledge retrieval.]]></string>
+    <string name="_sys_agents_field_tools"><![CDATA[Tools]]></string>
+    <string name="_sys_agents_field_tools_info"><![CDATA[Tools available for the agent to use.]]></string>
+    <string name="_sys_agents_field_tools_max_run"><![CDATA[Max tool calls]]></string>
+    <string name="_sys_agents_field_tools_max_run_info"><![CDATA[Limits how many times the AI can call external tools (such as search or actions) while completing a task. Higher values may increase execution time.]]></string>
+    <string name="_sys_agents_field_prompt_system"><![CDATA[System Prompt]]></string>
+    <string name="_sys_agents_field_prompt_system_info"><![CDATA[System prompt for the agent.]]></string>
+    <string name="_sys_agents_field_prompt_steps"><![CDATA[Steps Prompt]]></string>
+    <string name="_sys_agents_field_prompt_steps_info"><![CDATA[Instructions for executing agent steps.]]></string>
+    <string name="_sys_agents_field_prompt_output"><![CDATA[Output Prompt]]></string>
+    <string name="_sys_agents_field_prompt_output_info"><![CDATA[Instructions for formatting the output.]]></string>
+    <string name="_sys_agents_field_prompt_tools"><![CDATA[Tools Prompt]]></string>
+    <string name="_sys_agents_field_prompt_tools_info"><![CDATA[Instructions for using available tools.]]></string>
+    <string name="_sys_agents_tools_popup_edit"><![CDATA[Edit tool]]></string>
+    <string name="_sys_agents_field_title"><![CDATA[Title]]></string>
+    <string name="_sys_agents_tools_field_params"><![CDATA[Parameters]]></string>
+    <string name="_sys_agents_tools_field_params_info"><![CDATA[Parameters for configuring the tool, specific to each tool]]></string>
+    <string name="_sys_agents_field_chat_history_context"><![CDATA[Chat history context window]]></string>
+    <string name="_sys_agents_field_chat_history_context_info"><![CDATA[Automatically cut the conversation history based on the size of the context window, set to '0' to disable chat history]]></string>
+    <string name="_sys_agents_automators_field_providers"><![CDATA[Providers]]></string>
+    <string name="_sys_agents_automators_field_providers_add"><![CDATA[Add]]></string>
+    <string name="_sys_agents_automators_field_helpers"><![CDATA[Helpers]]></string>
+    <string name="_sys_agents_automators_field_helpers_add"><![CDATA[Add]]></string>
+    <string name="_sys_agents_automators_field_assistants"><![CDATA[Assistants]]></string>
+    <string name="_sys_agents_automators_field_assistants_add"><![CDATA[Add]]></string>
+    <string name="_sys_agents_automators_field_message"><![CDATA[Prompt]]></string>
+    <string name="_sys_agents_automators_field_message_err"><![CDATA[Prompt is essential. Please type something here.]]></string>
+    <string name="_sys_agents_automators_field_status_auto"><![CDATA[Auto]]></string>
+    <string name="_sys_agents_automators_field_status_manual"><![CDATA[Manual]]></string>
+    <string name="_sys_agents_automators_field_status_ready"><![CDATA[Ready]]></string>
+    <string name="_sys_agents_automators_err_event_not_found"><![CDATA[Event isn't found, please rephrase your prompt.]]></string>
+    <string name="_sys_agents_automators_err_cannot_get_code"><![CDATA[Can't generate code, please rephrase your prompt.]]></string>
+    <string name="_sys_agents_automators_txt_eval_response"><![CDATA[Response:<br />]]></string>
+    <string name="_sys_agents_providers_txt_active"><![CDATA[Active]]></string>
+    <string name="_sys_agents_providers_txt_provider_name"><![CDATA[Name]]></string>
+    <string name="_sys_agents_providers_txt_provider_type"><![CDATA[Type]]></string>
+    <string name="_sys_agents_providers_txt_added"><![CDATA[Added]]></string>
+    <string name="_sys_agents_providers_btn_add"><![CDATA[Add Provider]]></string>
+    <string name="_sys_agents_providers_btn_info"><![CDATA[Info]]></string>
+    <string name="_sys_agents_providers_btn_edit"><![CDATA[Edit]]></string>
+    <string name="_sys_agents_providers_btn_delete"><![CDATA[Delete]]></string>
+    <string name="_sys_agents_providers_popup_add"><![CDATA[Add provider]]></string>
+    <string name="_sys_agents_providers_popup_edit"><![CDATA[Edit provider]]></string>
+    <string name="_sys_agents_providers_popup_view"><![CDATA[View provider]]></string>
+    <string name="_sys_agents_providers_field_type_id"><![CDATA[Type]]></string>
+    <string name="_sys_agents_providers_field_type_id_err"><![CDATA[Type is essential. Please select a value.]]></string>
+    <string name="_sys_agents_providers_field_name"><![CDATA[Name]]></string>        
+    <string name="_sys_agents_pvd_cpt_shopify_admin"><![CDATA[Shopify (Admin API)]]></string>
+    <string name="_sys_agents_pvd_opt_cpt_active"><![CDATA[Active]]></string>
+    <string name="_sys_agents_pvd_opt_dsc_active"><![CDATA[Activate(Deactivate) source]]></string>
+    <string name="_sys_agents_pvd_opt_cpt_shop_domain"><![CDATA[Shop domain]]></string>
+    <string name="_sys_agents_pvd_opt_dsc_shop_domain"><![CDATA[]]></string>
+    <string name="_sys_agents_pvd_opt_cpt_access_token"><![CDATA[Access token]]></string>
+    <string name="_sys_agents_pvd_opt_dsc_access_token"><![CDATA[]]></string>
+    <string name="_sys_agents_pvd_opt_cpt_secret_key"><![CDATA[Secret key]]></string>
+    <string name="_sys_agents_pvd_opt_dsc_secret_key"><![CDATA[]]></string>
+    <string name="_sys_agents_pvd_opt_cpt_webhook_url"><![CDATA[Webhook URL]]></string>
+    <string name="_sys_agents_pvd_opt_dsc_webhook_url"><![CDATA[]]></string>
+    <string name="_sys_agents_helpers_txt_active"><![CDATA[Active]]></string>
+    <string name="_sys_agents_helpers_txt_name"><![CDATA[Name]]></string>
+    <string name="_sys_agents_helpers_txt_model_id"><![CDATA[Model]]></string>
+    <string name="_sys_agents_helpers_txt_profile_id"><![CDATA[Profile]]></string>
+    <string name="_sys_agents_helpers_txt_prompt"><![CDATA[Prompt]]></string>
+    <string name="_sys_agents_helpers_txt_added"><![CDATA[Added]]></string>
+    <string name="_sys_agents_helpers_btn_add"><![CDATA[Add Helper]]></string>
+    <string name="_sys_agents_helpers_btn_tune"><![CDATA[Tune]]></string>
+    <string name="_sys_agents_helpers_field_name"><![CDATA[Name]]></string>
+    <string name="_sys_agents_helpers_field_model_id"><![CDATA[Model]]></string>
+    <string name="_sys_agents_helpers_field_profile_id"><![CDATA[Profile]]></string>
+    <string name="_sys_agents_helpers_field_profile_id_inf"><![CDATA[Leave empty to use default.]]></string>
+    <string name="_sys_agents_helpers_field_description"><![CDATA[Description]]></string>
+    <string name="_sys_agents_helpers_field_prompt"><![CDATA[Prompt]]></string>
+    <string name="_sys_agents_helpers_field_prompt_err"><![CDATA[Prompt is essential. Please type something here.]]></string>
+    <string name="_sys_agents_helpers_field_message"><![CDATA[Message]]></string>
+    <string name="_sys_agents_helpers_field_message_err"><![CDATA[Message is essential. Please type something here.]]></string>
+    <string name="_sys_agents_helpers_field_result"><![CDATA[Result]]></string>
+    <string name="_sys_agents_helpers_popup_add"><![CDATA[Add helper]]></string>
+    <string name="_sys_agents_helpers_popup_edit"><![CDATA[Edit helper]]></string>
+    <string name="_sys_agents_models_txt_active"><![CDATA[Active]]></string>
+    <string name="_sys_agents_models_txt_name"><![CDATA[Name]]></string>
+    <string name="_sys_agents_models_txt_title"><![CDATA[Title]]></string>
+    <string name="_sys_agents_models_txt_key"><![CDATA[API Key]]></string>
+    <string name="_sys_agents_models_txt_params"><![CDATA[Parameters]]></string>
+    <string name="_sys_agents_models_txt_added"><![CDATA[Added]]></string>
+    <string name="_sys_agents_models_txt_capabilities"><![CDATA[Capabilities]]></string>
+    <string name="_sys_agents_models_txt_model"><![CDATA[Model]]></string>
+    <string name="_sys_agents_models_btn_add"><![CDATA[Add AI Provider]]></string>
+    <string name="_sys_agents_models_popup_edit"><![CDATA[Edit AI provider]]></string>
+    <string name="_sys_agents_models_field_title"><![CDATA[Title]]></string>
+    <string name="_sys_agents_models_field_title_info"><![CDATA[Display name for the AI provider.]]></string>
+    <string name="_sys_agents_models_field_model"><![CDATA[Model]]></string>
+    <string name="_sys_agents_models_field_model_info"><![CDATA[Model identifier used by the provider.]]></string>
+    <string name="_sys_agents_models_field_key"><![CDATA[API Key]]></string>
+    <string name="_sys_agents_models_field_key_info"><![CDATA[API key to authenticate with the provider.]]></string>
+    <string name="_sys_agents_models_field_params"><![CDATA[Parameters]]></string>
+    <string name="_sys_agents_models_field_params_info"><![CDATA[Additional configuration parameters in JSON format.]]></string>
+    <string name="_Duplicate"><![CDATA[Duplicate]]></string>
+    
+    <string name="_sys_agents_vector_store_txt_embedding_provider"><![CDATA[Embedder]]></string>
+    <string name="_sys_agents_vector_store_txt_files_num"><![CDATA[Files]]></string>
+    <string name="_sys_agents_vector_store_popup_files"><![CDATA[Files]]></string>
+    <string name="_sys_agents_vector_store_popup_edit"><![CDATA[Edit vector store]]></string>
+    <string name="_sys_agents_vector_store_field_embedding_provider_id"><![CDATA[Embedding Provider]]></string>
+    <string name="_sys_agents_vector_store_field_embedding_provider_id_info"><![CDATA[Select the embedding provider for this vector store.]]></string>
+    <string name="_sys_agents_vector_store_field_topk"><![CDATA[Top K Results]]></string>
+    <string name="_sys_agents_vector_store_field_topk_info"><![CDATA[Number of top results to return from similarity search.]]></string>
+    <string name="_sys_agents_vector_store_field_params"><![CDATA[Parameters]]></string>
+    <string name="_sys_agents_vector_store_field_params_info"><![CDATA[Additional parameters in JSON format.]]></string>
+    <string name="_sys_agents_vector_store_popup_add_data"><![CDATA[Upload new files]]></string>
+    <string name="_sys_agents_vector_store_field_chunk_size"><![CDATA[Chunk Size]]></string>
+    <string name="_sys_agents_vector_store_field_chunk_size_info"><![CDATA[Number of characters in text chunks for embedding.]]></string>
+    <string name="_sys_agents_vector_store_field_delimeter"><![CDATA[Delimiter]]></string>
+    <string name="_sys_agents_vector_store_field_delimeter_info"><![CDATA[Character or sequence to split text into chunks.]]></string>
+    <string name="_sys_agents_vector_store_field_overlap"><![CDATA[Chunk Overlap]]></string>
+    <string name="_sys_agents_vector_store_field_overlap_info"><![CDATA[Number of overlapping elements between adjacent chunks, determined by the delimeter, for dot - it's bumber of sentences, for space - it's number of words.]]></string>
+    <string name="_sys_agents_vector_store_field_metadata"><![CDATA[Metadata]]></string>
+    <string name="_sys_agents_vector_store_field_metadata_info"><![CDATA[Additional metadata in JSON format for each chunk.]]></string>
+    <string name="_sys_agents_vector_store_field_files"><![CDATA[Files]]></string>
+    <string name="_sys_agents_vector_store_field_files_info"><![CDATA[Data files to upload to the vector store.]]></string>
+    <string name="_sys_agents_vector_store_data_queued"><![CDATA[Data queued for vector store processing]]></string>
+    
+    <string name="_sys_agents_assistants_txt_active"><![CDATA[Active]]></string>
+    <string name="_sys_agents_assistants_txt_name"><![CDATA[Name]]></string>
+    <string name="_sys_agents_assistants_txt_model_id"><![CDATA[Model]]></string>
+    <string name="_sys_agents_assistants_txt_profile_id"><![CDATA[Profile]]></string>
+    <string name="_sys_agents_assistants_txt_prompt"><![CDATA[Prompt]]></string>
+    <string name="_sys_agents_assistants_txt_added"><![CDATA[Added]]></string>
+    <string name="_sys_agents_assistants_txt_assistant"><![CDATA[Assistant]]></string>
+    <string name="_sys_agents_assistants_txt_codes_onclick"><![CDATA[onClick code for a link]]></string>
+    <string name="_sys_agents_assistants_txt_codes_button"><![CDATA[Button HTML code]]></string>
+    <string name="_sys_agents_assistants_txt_add_knowledge"><![CDATA[Add knowledge]]></string>
+    <string name="_sys_agents_assistants_txt_ask"><![CDATA[Ask]]></string>
+    <string name="_sys_agents_assistants_btn_add"><![CDATA[Add Assistant]]></string>
+    <string name="_sys_agents_assistants_btn_chats"><![CDATA[Chats]]></string>
+    <string name="_sys_agents_assistants_btn_files"><![CDATA[Files]]></string>
+    <string name="_sys_agents_assistants_btn_codes"><![CDATA[Get codes]]></string>
+    <string name="_sys_agents_assistants_field_name"><![CDATA[Name]]></string>
+    <string name="_sys_agents_assistants_field_model_id"><![CDATA[Model]]></string>
+    <string name="_sys_agents_assistants_field_profile_id"><![CDATA[Profile]]></string>
+    <string name="_sys_agents_assistants_field_profile_id_inf"><![CDATA[Leave empty to use default.]]></string>
+    <string name="_sys_agents_assistants_field_description"><![CDATA[Description]]></string>
+    <string name="_sys_agents_assistants_field_prompt"><![CDATA[Prompt]]></string>
+    <string name="_sys_agents_assistants_field_prompt_err"><![CDATA[Prompt is essential. Please type something here.]]></string>
+    <string name="_sys_agents_assistants_field_result"><![CDATA[Result]]></string>
+    <string name="_sys_agents_assistants_popup_add"><![CDATA[Add assistant]]></string>
+    <string name="_sys_agents_assistants_popup_edit"><![CDATA[Edit assistant]]></string>
+    <string name="_sys_agents_assistants_chat_dsc_studio"><![CDATA[Studio assistant]]></string>
+    <string name="_sys_agents_assistants_chat_dsc_block"><![CDATA['Ask AI' assistant]]></string>
+    <string name="_sys_agents_assistants_chat_dsc_live_search"><![CDATA[Live search assistant]]></string>
+    <string name="_sys_agents_assistants_chats_txt_name"><![CDATA[Name]]></string>
+    <string name="_sys_agents_assistants_chats_txt_type"><![CDATA[Type]]></string>
+    <string name="_sys_agents_assistants_chats_txt_type_1"><![CDATA[Permanent]]></string>
+    <string name="_sys_agents_assistants_chats_txt_type_10"><![CDATA[Transient]]></string>
+    <string name="_sys_agents_assistants_chats_txt_description"><![CDATA[Description]]></string>
+    <string name="_sys_agents_assistants_chats_txt_messages"><![CDATA[Messages]]></string>
+    <string name="_sys_agents_assistants_chats_txt_added"><![CDATA[Added]]></string>
+    <string name="_sys_agents_assistants_chats_txt_stored"><![CDATA[Stored]]></string>
+    <string name="_sys_agents_assistants_chats_txt_chat"><![CDATA[Chat]]></string>
+    <string name="_sys_agents_assistants_chats_btn_add"><![CDATA[Add Chat]]></string>
+    <string name="_sys_agents_assistants_chats_btn_chat"><![CDATA[Chat]]></string>
+    <string name="_sys_agents_assistants_chats_btn_store"><![CDATA[Store for future usage]]></string>
+    <string name="_sys_agents_assistants_chats_btn_unstore"><![CDATA[Remove from store]]></string>
+    <string name="_sys_agents_agents_act_wipe_chat_history"><![CDATA[Wipe chat history]]></string>
+    <string name="_sys_agents_assistants_chats_field_name"><![CDATA[Name]]></string>
+    <string name="_sys_agents_assistants_chats_field_description"><![CDATA[Description]]></string>
+    <string name="_sys_agents_assistants_chats_popup_add"><![CDATA[Add chat]]></string>
+    <string name="_sys_agents_assistants_chats_popup_edit"><![CDATA[Edit chat]]></string>
+    <string name="_sys_agents_assistants_chats_msg_loading"><![CDATA[I'm thinking. Please wait.]]></string>
+    <string name="_sys_agents_assistants_chats_err_no_response"><![CDATA[Cannot get response. Check log file for more info.]]></string>
+    <string name="_sys_agents_assistants_files_txt_name"><![CDATA[Name]]></string>
+    <string name="_sys_agents_assistants_files_txt_size"><![CDATA[Size]]></string>
+    <string name="_sys_agents_assistants_files_txt_status"><![CDATA[Status]]></string>
+    <string name="_sys_agents_assistants_files_txt_status_in_progress"><![CDATA[In progress]]></string>
+    <string name="_sys_agents_assistants_files_txt_status_completed"><![CDATA[Completed]]></string>
+    <string name="_sys_agents_assistants_files_txt_status_failed"><![CDATA[Failed]]></string>
+    <string name="_sys_agents_assistants_files_txt_status_cancelled"><![CDATA[Cancelled]]></string>
+    <string name="_sys_agents_assistants_files_txt_added"><![CDATA[Added]]></string>
+    <string name="_sys_agents_assistants_files_btn_add"><![CDATA[Add File]]></string>
+    <string name="_sys_agents_assistants_files_btn_sync"><![CDATA[Sync]]></string>
+    <string name="_sys_agents_assistants_files_btn_delete"><![CDATA[Delete file]]></string>
+    <string name="_sys_agents_assistants_files_field_file"><![CDATA[File]]></string>
+    <string name="_sys_agents_assistants_files_popup_add"><![CDATA[Add File]]></string>
+    <string name="_sys_agents_assistants_field_kwg_type"><![CDATA[Type]]></string>
+    <string name="_sys_agents_assistants_field_kwg_type_text"><![CDATA[Text]]></string>
+    <string name="_sys_agents_assistants_field_kwg_type_faq"><![CDATA[Question with answer]]></string>
+    <string name="_sys_agents_assistants_field_kwg_text"><![CDATA[Text]]></string>
+    <string name="_sys_agents_assistants_field_kwg_faq_q"><![CDATA[Question]]></string>
+    <string name="_sys_agents_assistants_field_kwg_faq_a"><![CDATA[Answer]]></string>
+    <string name="_sys_agents_assistants_popup_add_knowledge"><![CDATA[Add Knowledge]]></string>
+    <string name="_sys_agents_assistants_popup_ask"><![CDATA[Ask Assistant]]></string>
+    <string name="_sys_agents_assistants_msg_knowledge_added"><![CDATA[Knowledge was added.]]></string>
+    <string name="_sys_agents_logs_popup"><![CDATA["{0}" agent logs]]></string>
+    <string name="_sys_agents_err_failed"><![CDATA[Error occurred. Try to check log file for more info.]]></string>
+    <string name="_sys_agents_exception"><![CDATA[The AI encountered an error while completing your request. Please try again or rephrase your input.]]></string>
+
+  <string name="_sys_audit_content_info_popup_title"><![CDATA[Information]]></string>
+  <string name="_sys_audit_action_edit_content"><![CDATA[Content edited]]></string>
+  <string name="_sys_audit_action_add_content"><![CDATA[Content added]]></string>
+  <string name="_sys_audit_action_detete_content"><![CDATA[Content removed]]></string>
+  <string name="_sys_audit_action_edit_comment"><![CDATA[Comment edited]]></string>
+  <string name="_sys_audit_action_add_comment"><![CDATA[Comment added]]></string>
+  <string name="_sys_audit_action_delete_comment"><![CDATA[Comment removed]]></string>
+  <string name="_sys_audit_action_feature"><![CDATA[Featured]]></string>
+  <string name="_sys_audit_action_unfeature"><![CDATA[Unfeatured]]></string>
+  <string name="_sys_audit_action_resolve"><![CDATA[Marked as resolved]]></string>
+  <string name="_sys_audit_action_group_to_admins"><![CDATA[Added to group admins]]></string>
+  <string name="_sys_audit_action_group_from_admins"><![CDATA[Removed from group admins]]></string>
+  <string name="_sys_audit_action_group_role_changed"><![CDATA[Group role was changed]]></string>
+  <string name="_sys_audit_action_group_join_request_accepted"><![CDATA[Join request accepted]]></string>
+  <string name="_sys_audit_action_account_change_role_to_3"><![CDATA[Made operator]]></string>
+  <string name="_sys_audit_action_account_change_role_to_1"><![CDATA[Unmade operator]]></string>
+  <string name="_sys_audit_action_account_unlock"><![CDATA[Unlocked]]></string>
+  <string name="_sys_audit_action_account_login"><![CDATA[Login]]></string>
+  <string name="_sys_audit_action_account_failed_login_attempt"><![CDATA[Failed login attempt]]></string>
+  <string name="_sys_audit_action_account_logout"><![CDATA[Logout]]></string>
+  <string name="_sys_audit_action_account_reset_password"><![CDATA[Password reseted]]></string>
+  <string name="_sys_audit_action_account_resend_confirmation_email"><![CDATA[Confirmation email re-sended]]></string>
+  <string name="_sys_audit_action_account_deleted_with_content"><![CDATA[Removed with content]]></string>
+  <string name="_sys_audit_action_account_deleted"><![CDATA[Removed]]></string>
+  <string name="_sys_audit_action_account_email_changed"><![CDATA[Email changed]]></string>
+  <string name="_sys_audit_action_account_activated"><![CDATA[Activated]]></string>
+  <string name="_sys_audit_action_account_suspended"><![CDATA[Suspended]]></string>
+  <string name="_sys_audit_action_content_enabled"><![CDATA[Enabled]]></string>
+  <string name="_sys_audit_action_content_disabled"><![CDATA[Disabled]]></string>
+  <string name="_sys_audit_action_set_membership"><![CDATA[Membership set]]></string>
+  <string name="_sys_audit_action_set_status_approve"><![CDATA[Approved]]></string>
+  <string name="_sys_audit_action_set_status_active"><![CDATA[Activated]]></string>
+  <string name="_sys_audit_action_set_status_disapprove"><![CDATA[Disapproved]]></string>
+  <string name="_sys_audit_action_set_status_suspended"><![CDATA[Suspended]]></string>
+  <string name="_sys_audit_action_report"><![CDATA[Reported]]></string>
+  <string name="_sys_audit_action_report_comment"><![CDATA[Comment Reported]]></string>
+  <string name="_sys_audit_action_lock"><![CDATA[Locked]]></string>
+  <string name="_sys_audit_action_unlock"><![CDATA[Unlocked]]></string>
+  <string name="_sys_audit_action_stick"><![CDATA[Sticked]]></string>
+  <string name="_sys_audit_action_unstick"><![CDATA[Unsticked]]></string>
+  <string name="_sys_audit_action_promote"><![CDATA[Promoted]]></string>
+  <string name="_sys_audit_action_unpromote"><![CDATA[Unpromoted]]></string>
+
+  <string name="_sys_add_friend"><![CDATA[Add friend]]></string>
+        <string name="_sys_add_relation"><![CDATA[Add relationship]]></string>
+	<string name="_sys_adm_installed"><![CDATA[Installed]]></string>
+	<string name="_sys_admin_apply"><![CDATA[Apply]]></string>
+	<string name="_sys_admin_filter"><![CDATA[Filter:]]></string>
+  <string name="_sys_audit_filter_profile_select"><![CDATA[Select Profile]]></string>
+  <string name="_sys_audit_filter_action_select"><![CDATA[Select Action]]></string>
+	<string name="_sys_audit_cron_jobs"><![CDATA[Cron jobs]]></string>
+	<string name="_sys_audit_cron_jobs_exec_time"><![CDATA[Last cron jobs execution]]></string>
+	<string name="_sys_audit_header_manual_audit"><![CDATA[Manual Server Audit]]></string>
+	<string name="_sys_audit_header_requirements"><![CDATA[Requirements]]></string>
+	<string name="_sys_audit_header_site_optimization"><![CDATA[Site optimization]]></string>
+	<string name="_sys_audit_header_site_setup"><![CDATA[Site setup]]></string>
+	<string name="_sys_audit_mail_sending"><![CDATA[Mail sending]]></string>
+	<string name="_sys_audit_msg_apache_module_fail"><![CDATA[you will need to install {0} for Apache]]></string>
+	<string name="_sys_audit_msg_cron_jobs"><![CDATA[<pre class="code">{0}</pre> if you are unsure if output is correct then <a href="#manual_audit">manual server audit</a> may be required]]></string>
+	<string name="_sys_audit_msg_optimization_fail"><![CDATA[please enable this cache in Studio &gt; Settings &gt; Cache]]></string>
+	<string name="_sys_audit_msg_optimization_warn"><![CDATA[installing PHP accelerator will speed-up file cache]]></string>
+	<string name="_sys_audit_msg_x_based_cache_engine"><![CDATA[ ({0} based cache engine)]]></string>
+	<string name="_sys_audit_msg_ffmpeg"><![CDATA[<pre class="code">{0}</pre>if you don't know if output is correct then <a href="#manual_audit">manual server audit</a> may be required.]]></string>
+	<string name="_sys_audit_msg_hardware_requirements"><![CDATA[Hardware requirements can not be determined automatically - <a href="#manual_audit">manual server audit</a> may be required.]]></string>
+	<string name="_sys_audit_msg_mail_send_failed"><![CDATA[mail send failed]]></string>
+	<string name="_sys_audit_msg_mail_sending"><![CDATA[<span id="bx-sys-adm-audit-test-email"><a href="javascript:void(0);" onclick="bx_sys_adm_audit_test_email()">click here</a> to send test email</span>]]></string>
+	<string name="_sys_audit_msg_mail_sent"><![CDATA[test mail was send, please check {0} mailbox]]></string>
+	<string name="_sys_audit_msg_manual_audit"><![CDATA[<p>
+Some things can not be determined automatically, manual server audit is required to check it. 
+If you don't know how to do it by yourself you can submit <a target="_blank" href="mailto:team@unacms.com?subject=Server Audit Request">Server Audit Request</a>.
+</p>]]></string>
+	<string name="_sys_audit_msg_must_be"><![CDATA[must be {0} {1}]]></string>
+	<string name="_sys_audit_msg_optimization_apache_module"><![CDATA[To apply this optimization you need to have <b>{0}</b> - {1}]]></string>
+	<string name="_sys_audit_msg_permissions"><![CDATA[please <a href="javascript:void(0);" onclick="oBxDolStudioDashboard.permissions()">click here</a> to find out if permissions are correct.]]></string>
+	<string name="_sys_audit_msg_php_accelerator_missing"><![CDATA[The script can be much faster if you install some PHP accelerator]]></string>
+	<string name="_sys_audit_msg_php_setup_inefficient"><![CDATA[your PHP setup maybe very inefficient, <a href="javascript:void(0)" onclick="bx_sys_adm_audit_phpinfo()">please check it for sure</a> and try to switch to mod_php, apache dso module or FastCGI]]></string>
+	<string name="_sys_audit_msg_serverside_compression"><![CDATA[
+can be checked <a href="#manual_audit">manually</a> or in "Page Speed" tool build-in into browser.<br />
+If it is not enabled then please consider implement this optimization, since it improve perceived site speed and save the bandwidth.<br />{0}]]></string>
+	<string name="_sys_audit_msg_should_be"><![CDATA[should be {0} {1}]]></string>
+	<string name="_sys_audit_msg_userside_caching"><![CDATA[
+<a href="{0}">click here to check it in Google Page Speed</a><br />
+If it is not enabled then please consider implement this optimization, since it improve perceived site speed and save the bandwidth.<br />{1}]]></string>
+	<string name="_sys_audit_msg_value_checking_failed"><![CDATA[value checking failed]]></string>
+	<string name="_sys_audit_msg_version_is_incompatible"><![CDATA[your version is incompatible with UNA, must be at least {0}]]></string>
+	<string name="_sys_audit_msg_version_is_outdated"><![CDATA[your version is outdated, upgrade to the latest {0} maybe required]]></string>
+	<string name="_sys_audit_permissions"><![CDATA[Files and folders permissions]]></string>
+	<string name="_sys_audit_php_accelerator"><![CDATA[PHP accelerator]]></string>
+	<string name="_sys_audit_php_setup"><![CDATA[PHP setup]]></string>
+	<string name="_sys_audit_section_hardware"><![CDATA[Hardware]]></string>
+	<string name="_sys_audit_section_os"><![CDATA[OS]]></string>
+	<string name="_sys_audit_section_webserver"><![CDATA[Web-server]]></string>
+	<string name="_sys_audit_serverside_compression"><![CDATA[Server-side content compression]]></string>
+	<string name="_sys_audit_title_fail"><![CDATA[FAIL]]></string>
+	<string name="_sys_audit_title_ok"><![CDATA[OK]]></string>
+	<string name="_sys_audit_title_undef"><![CDATA[UNDEFINED]]></string>
+	<string name="_sys_audit_title_warn"><![CDATA[WARNING]]></string>
+	<string name="_sys_audit_userside_caching"><![CDATA[User-side caching for static content]]></string>
+	<string name="_sys_audit_version"><![CDATA[version]]></string>
+	<string name="_sys_audit_version_script"><![CDATA[UNA version]]></string>
+
+	<string name="_sys_agents_agents_popup_edit"><![CDATA[Edit "{0}" agent]]></string>
+
+        <string name="_sys_block_type_custom"><![CDATA[custom]]></string>
+	<string name="_sys_block_type_html"><![CDATA[html]]></string>
+	<string name="_sys_block_type_image"><![CDATA[image]]></string>
+	<string name="_sys_block_type_lang"><![CDATA[lang]]></string>
+        <string name="_sys_block_type_creative"><![CDATA[creative]]></string>
+        <string name="_sys_block_type_bento_grid"><![CDATA[bento grid]]></string>
+	<string name="_sys_block_type_menu"><![CDATA[menu]]></string>
+	<string name="_sys_block_type_raw"><![CDATA[raw]]></string>
+	<string name="_sys_block_type_rss"><![CDATA[rss]]></string>
+        <string name="_sys_block_type_wiki"><![CDATA[wiki]]></string>
+	<string name="_sys_block_type_service"><![CDATA[service]]></string>
+	<string name="_sys_block_types_custom"><![CDATA[Custom]]></string>
+	<string name="_sys_block_types_skeletons"><![CDATA[Skeletons]]></string>
+	<string name="_sys_block_types_system"><![CDATA[System]]></string>
+
+    <string name="_sys_cmts"><![CDATA[Comments]]></string>
+    <string name="_sys_cmts_administration_grid_column_title_adm_active"><![CDATA[Active]]></string>
+    <string name="_sys_cmts_administration_grid_column_title_adm_cmt_module"><![CDATA[Module]]></string>
+    <string name="_sys_cmts_administration_grid_column_title_adm_cmt_text"><![CDATA[Text]]></string>
+    <string name="_sys_cmts_administration_grid_column_title_adm_cmt_time"><![CDATA[Added]]></string>
+    <string name="_sys_cmts_administration_grid_column_title_adm_cmt_author_id"><![CDATA[Author]]></string>
+    <string name="_sys_cmts_administration_grid_action_title_adm_delete"><![CDATA[Delete]]></string>
+  
+    <string name="_sys_chart_growth_object"><![CDATA[Display]]></string>
+    <string name="_sys_chart_growth_date_from"><![CDATA[From]]></string>
+    <string name="_sys_chart_growth_date_to"><![CDATA[To]]></string>
+    <string name="_sys_chart_accounts_growth"><![CDATA[Accounts: Growth]]></string>
+    <string name="_sys_chart_accounts_growth_speed"><![CDATA[Accounts: Growth Speed]]></string>
+    <string name="_sys_close"><![CDATA[Close]]></string>
+    <string name="_sys_confirm"><![CDATA[Confirm]]></string>
+    <string name="_sys_confirmed"><![CDATA[Confirmed]]></string>
+    <string name="_sys_conn_do_by"><![CDATA[Connected by]]></string>
+    <string name="_sys_conn_friends_counter"><![CDATA[{0} friends]]></string>
+    <string name="_sys_conn_friends_done_initiator"><![CDATA[Request sent]]></string>
+    <string name="_sys_conn_friends_done_initiator_mutual"><![CDATA[Friends]]></string>
+    <string name="_sys_conn_friends_do_content"><![CDATA[Respond]]></string>
+    <string name="_sys_conn_subscriptions_do_initiator"><![CDATA[Following]]></string>
+    <string name="_sys_conn_subscriptions_counter"><![CDATA[{0} followers]]></string>
+    <string name="_sys_conn_relations_do_initiator"><![CDATA[Add Relationship]]></string>
+    <string name="_sys_conn_relations_do_initiator_done"><![CDATA[Relations]]></string>
+    <string name="_sys_conn_relations_do_initiator_undo"><![CDATA[Remove Relationship]]></string>
+    <string name="_sys_conn_err_connection_already_exists"><![CDATA[Connection already exists]]></string>
+    <string name="_sys_conn_err_connection_does_not_exists"><![CDATA[Connection doesn't exist]]></string>
+    <string name="_sys_conn_err_connection_is_awaiting_confirmation"><![CDATA[Connection request is awaiting confirmation]]></string>
+    <string name="_sys_conn_err_input_data_is_not_defined"><![CDATA[Input data isn't defined]]></string>
+    <string name="_sys_conn_msg_success"><![CDATA[Operation has beed successfully completed]]></string>
+
+    <string name="_sys_connect_information"><![CDATA[Configuration info]]></string>
+    <string name="_sys_connect_error_join_unavailable"><![CDATA[Sorry but join is unavailable now. Please try again later.]]></string>
+    <string name="_sys_connect_profile_error_info"><![CDATA[Can't define your profile information]]></string>
+    <string name="_sys_connect_state_invalid"><![CDATA[State parameter isn't matching]]></string>
+    <string name="_sys_connect_adm_stg_cpt_category_general"><![CDATA[General]]></string>
+    <string name="_sys_connect_option_redirect"><![CDATA[Redirect page after first sign in]]></string>
+    <string name="_sys_connect_option_module"><![CDATA[Module to create profile in]]></string>
+    <string name="_sys_connect_option_confirm_email"><![CDATA[Always confirm emails when joined using this module]]></string>
+    <string name="_sys_connect_option_approve"><![CDATA[Always approve profiles when joined using this module]]></string>
+    <string name="_sys_connect_option_privacy"><![CDATA[Default privacy for created profiles]]></string>
+
+    <string name="_sys_currency"><![CDATA[{0}{1}]]></string>
+    <string name="_sys_decline"><![CDATA[Decline]]></string>
+    <string name="_sys_designbox_0"><![CDATA[Content]]></string>
+    <string name="_sys_designbox_1"><![CDATA[Content + Title + Background]]></string>
+    <string name="_sys_designbox_10"><![CDATA[Content + Padding]]></string>
+    <string name="_sys_designbox_11"><![CDATA[Content + Title + Background + Padding]]></string>
+    <string name="_sys_designbox_13"><![CDATA[Content + Background + Padding]]></string>
+    <string name="_sys_designbox_14"><![CDATA[Content + Title + Padding]]></string>
+    <string name="_sys_designbox_2"><![CDATA[Empty box]]></string>
+    <string name="_sys_designbox_3"><![CDATA[Content + Background]]></string>
+    <string name="_sys_designbox_4"><![CDATA[Content + Title]]></string>
+    <string name="_sys_done"><![CDATA[Done]]></string>    
+    <string name="_sys_et_txt_about_us"><![CDATA[About us]]></string>
+    <string name="_sys_et_txt_body_admin_email"><![CDATA[{email_header}
+<p>Message from <a href="{site_url}">{site_name}</a> admin:</p>
+<p> </p>
+<p>{MessageText}</p>
+<p> </p>
+{email_footer}]]></string>
+    <string name="_sys_et_txt_body_comment_replied"><![CDATA[{email_header}
+<p>User {sender_display_name} posted reply to your comment: </p>
+<p> </p>
+<p>{reply_text}</p>
+<p> </p>
+<p>View and reply here: <a href="{page_url}">{page_title}</a>.</p>
+<p> </p>
+{email_footer}]]></string>
+    <string name="_sys_et_txt_body_system_reported"><![CDATA[{email_header}
+<p>New <b>{report_type}</b> report received:</p>
+<p> </p>
+<p>{report_text}</p>
+<p> </p>
+<p><a href="{report_url}">View report</a>.</p>
+<p> </p>
+{email_footer}]]></string>
+    <string name="_sys_et_txt_body_confirmation"><![CDATA[{email_header}
+<p>Hello {name} ({email}),</p>
+<p>Please confirm your email address by clicking the link below:</p>
+<p> </p>
+<p><a href="{conf_link}">{conf_link}</a></p>
+<p> </p>
+<p>or use the code:</p>
+<p><span class="h3">{conf_code}</span></p>
+<p> </p>
+{email_footer}]]></string>
+    <string name="_sys_et_txt_body_welcome"><![CDATA[{email_header}
+<p>Hello {name},</p>
+<p>You are welcome to {site_name}</p>
+<p> </p>
+<p>You've confirmed your profile and is ready to use our site.</p>
+<p>Feel free to contact us if you need some help.</p>
+<p> </p>
+{email_footer}]]></string>
+    <string name="_sys_et_txt_body_delayed_module_uninstall"><![CDATA[{email_header}
+<p>Module: <b>{Module}</b></p>
+<p>Uninstallation result: {Result}</p>
+<p> </p>
+<p>{Message}</p>
+<p> </p>
+{email_footer}]]></string>
+    <string name="_sys_et_txt_body_forgot"><![CDATA[{email_header}
+<p>Hello {name} ({email})</p>,
+<p>Click the link below to reset your password, please:</p>
+<p> </p>
+<p><a href="{forgot_password_url}">Reset my password</a>.</p>
+<p> </p>
+{email_footer}]]></string>
+    <string name="_sys_et_txt_body_mem_changed"><![CDATA[{email_header}
+<p><b>{profile_name}</b> profile membership level is now <b>{membership_level}</b>.</p>
+<p> </p>
+{email_footer}]]></string>
+    <string name="_sys_et_txt_body_mem_prolonged"><![CDATA[{email_header}
+<p><b>{profile_name}</b> profile membership level (<b>{membership_level}</b>) was prolonged.</p>
+<p> </p>
+{email_footer}]]></string>
+    <string name="_sys_et_txt_body_mem_expiration"><![CDATA[{email_header}
+<p>Your {membership_name} membership will expire in {expire_days} days (-1 means already expired).</p>
+<p>Click the link below to renew your membership:</p>
+<p> </p>
+<p><a href="{page_url}">Renew my membership</a></p>
+<p> </p>
+{email_footer}]]></string>
+    <string name="_sys_et_txt_body_profile_change_status_active"><![CDATA[{email_header}
+<p>Your {site_name} account details:</p>
+<p> </p>
+<p>Name: {account_name}</p>
+<p>Email: {account_email}</p>
+<p>URL: <a href="{site_url}">{site_url}</a></p>
+<p></p>
+{email_footer}]]></string>
+    <string name="_sys_et_txt_body_profile_change_status_pending"><![CDATA[{email_header}
+<p>Your profile is pending review. We will send you the review result shortly.</p>
+<p> </p>
+{email_footer}]]></string>
+    <string name="_sys_et_txt_body_profile_change_status_suspended"><![CDATA[{email_header}
+<p>Your profile is currently suspended.</p>
+<p> </p>
+{email_footer}]]></string>
+    <string name="_sys_et_txt_body_account_change_status_activate"><![CDATA[{email_header}
+<p>Your account and all your related profiles are currently activated.</p>
+<p></p>
+{email_footer}]]></string>
+    <string name="_sys_et_txt_body_account_change_status_suspended"><![CDATA[{email_header}
+<p>Your account and all your related profiles are currently suspended.</p>
+<p> </p>
+{email_footer}]]></string>
+    <string name="_sys_et_txt_body_account"><![CDATA[{email_header}
+<p>{account_output}</p>
+{email_footer}]]></string>
+     <string name="_sys_et_txt_body_account_password_expired"><![CDATA[{email_header}
+<p>Your password will expire {expired_date}</p>
+<p>Please, sign-in and change password</p>
+{email_footer}]]></string>
+    <string name="_sys_et_txt_body_pruning"><![CDATA[{email_header}
+<p>{pruning_output}</p>
+{email_footer}]]></string>
+    <string name="_sys_et_txt_body_upgrade_failed"><![CDATA[{email_header}
+<p>Upgrade failed due to the following error:</p>
+<p> </p>
+<p>{error_msg}</p>
+<p> </p>
+{email_footer}]]></string>
+    <string name="_sys_et_txt_body_upgrade_modules_failed"><![CDATA[{email_header}
+<p>The following errors appeared during modules upgrade:</p>
+<p> </p>
+<p>{conclusion}</p>
+<p> </p>
+{email_footer}]]></string>
+    <string name="_sys_et_txt_body_upgrade_success"><![CDATA[{email_header}
+<p>Site was successfully upgraded to {new_version}.</p>
+<p>Please go to <b>Studio &gt; App Store &gt; Updates</b> to check for modules updates.</p>
+<p> </p>
+{conclusion}
+<p> </p>
+{email_footer}]]></string>
+    <string name="_sys_et_txt_body_upgrade_modules_success"><![CDATA[{email_header}
+<p>The following modules were successfully upgraded.</p>
+<p> </p>
+{conclusion}
+<p> </p>
+{email_footer}]]></string>
+    <string name="_sys_et_txt_body_bg_operation_failed"><![CDATA[{email_header}
+<p>Background operation failed with the following message.</p>
+<p> </p>
+{conclusion}
+<p> </p>
+{email_footer}]]></string>
+    <string name="_sys_et_txt_body_manage_approve"><![CDATA[{email_header}
+<p>Moderation team has a question for you about '{content_title}':</p>
+<p> </p>
+<p>{notes}</p>
+<p> </p>
+{email_footer}]]></string>
+	<string name="_sys_et_txt_body_modules_upgrade_success"><![CDATA[<b>{0}</b> module: up to {1} version.<br />]]></string>
+	<string name="_sys_et_txt_body_modules_upgrade_failed"><![CDATA[<b>{0}</b> module: {1}<br />]]></string>
+	<string name="_sys_et_txt_name_system_admin_email"><![CDATA[Message sending from the Admin Panel]]></string>
+	<string name="_sys_et_txt_name_system_comment_replied"><![CDATA[The letter is sent to members whose comment was replied]]></string>
+	<string name="_sys_et_txt_name_system_reported"><![CDATA[New report notification]]></string>
+	<string name="_sys_et_txt_name_system_confirmation"><![CDATA[Profile e-mail confirmation message]]></string>
+        <string name="_sys_et_txt_name_system_welcome"><![CDATA[Welcome message]]></string>
+	<string name="_sys_et_txt_name_system_delayed_module_uninstall"><![CDATA[Delayed module uninstall notification]]></string>
+	<string name="_sys_et_txt_name_system_forgot"><![CDATA[Reset password message]]></string>
+	<string name="_sys_et_txt_name_system_mem_changed"><![CDATA[The letter is sent to members whose membership level was changed]]></string>
+        <string name="_sys_et_txt_name_system_mem_prolonged"><![CDATA[The letter is sent to members whose membership level was prolonged]]></string>
+	<string name="_sys_et_txt_name_system_mem_expiration"><![CDATA[Membership expiration letter sent to members whose membership level expires]]></string>
+	<string name="_sys_et_txt_name_profile_change_status_active"><![CDATA[Profile status changed to active]]></string>
+	<string name="_sys_et_txt_name_profile_change_status_pending"><![CDATA[Profile status changed to pending]]></string>
+	<string name="_sys_et_txt_name_profile_change_status_suspended"><![CDATA[Profile status changed to suspended]]></string>
+        <string name="_sys_et_txt_name_account_change_status_activate"><![CDATA[Account status changed to active]]></string>
+        <string name="_sys_et_txt_name_account_change_status_suspended"><![CDATA[Account status changed to suspended]]></string>
+        <string name="_sys_et_txt_name_manage_approve"><![CDATA[Approve: Contact content's author]]></string>
+	<string name="_sys_et_txt_name_system_account"><![CDATA[New Accounts]]></string>
+        <string name="_sys_et_txt_name_system_account_password_expired"><![CDATA[Password will expire]]></string>
+	<string name="_sys_et_txt_name_system_pruning"><![CDATA[Pruning result]]></string>
+	<string name="_sys_et_txt_name_upgrade_failed"><![CDATA[Upgrade failed]]></string>
+	<string name="_sys_et_txt_name_upgrade_modules_failed"><![CDATA[Modules upgrade failed]]></string>
+	<string name="_sys_et_txt_name_upgrade_success"><![CDATA[Site upgrade success]]></string>
+	<string name="_sys_et_txt_name_upgrade_modules_success"><![CDATA[Modules upgrade success]]></string>
+	<string name="_sys_et_txt_name_bg_operation_failed"><![CDATA[Background operation failed]]></string>
+	<string name="_sys_et_txt_subject_admin_email"><![CDATA[Message from <SiteName> Admin: <MessageSubject>]]></string>
+	<string name="_sys_et_txt_subject_comment_replied"><![CDATA[User {sender_display_name} replied to your comment.]]></string>
+	<string name="_sys_et_txt_subject_system_reported"><![CDATA[New report notification]]></string>
+	<string name="_sys_et_txt_subject_confirmation"><![CDATA[Confirm your email address]]></string>
+        <string name="_sys_et_txt_subject_welcome"><![CDATA[You are welcome to {site_name}]]></string>
+	<string name="_sys_et_txt_subject_delayed_module_uninstall"><![CDATA[Delayed {Module} module uninstall: {Result}]]></string>
+	<string name="_sys_et_txt_subject_forgot"><![CDATA[Reset your password]]></string>
+	<string name="_sys_et_txt_subject_mem_changed"><![CDATA[Your membership level was changed]]></string>
+        <string name="_sys_et_txt_subject_mem_prolonged"><![CDATA[Your membership level was prolonged]]></string>
+	<string name="_sys_et_txt_subject_mem_expiration"><![CDATA[Your membership is about to expire]]></string>
+	<string name="_sys_et_txt_subject_profile_change_status_active"><![CDATA[Profile activated]]></string>
+	<string name="_sys_et_txt_subject_profile_change_status_pending"><![CDATA[Profile pending review]]></string>
+	<string name="_sys_et_txt_subject_profile_change_status_suspended"><![CDATA[Profile suspended]]></string>
+        <string name="_sys_et_txt_subject_account_change_status_activate"><![CDATA[Account activated]]></string>
+        <string name="_sys_et_txt_subject_account_change_status_suspended"><![CDATA[Account suspended]]></string>
+        <string name="_sys_et_txt_subject_manage_approve"><![CDATA[Approvement. A question about '{content_title}'.]]></string>
+	<string name="_sys_et_txt_subject_account"><![CDATA[{site_name} {account_count} accounts created yesterday]]></string>
+        <string name="_sys_et_txt_subject_account_password_expired"><![CDATA[Your password will expire soon]]></string>
+	<string name="_sys_et_txt_subject_pruning"><![CDATA[{site_name} pruning result]]></string>
+	<string name="_sys_et_txt_subject_upgrade_failed"><![CDATA[{site_name} upgrade failed]]></string>
+	<string name="_sys_et_txt_subject_upgrade_modules_failed"><![CDATA[Modules upgrade failed on {site_name}]]></string>
+	<string name="_sys_et_txt_subject_upgrade_success"><![CDATA[{site_name} upgrade success]]></string>
+	<string name="_sys_et_txt_subject_upgrade_modules_success"><![CDATA[Modules upgrade success on {site_name}]]></string>
+	<string name="_sys_et_txt_subject_bg_operation_failed"><![CDATA[Background operation failed]]></string>
+        <string name="_sys_et_txt_unsubscribe"><![CDATA[Unsubscribe]]></string>
+	<string name="_sys_file_handlers_ms_viewer"><![CDATA[Microsoft Office Viewer]]></string>
+	<string name="_sys_file_handlers_google_viewer"><![CDATA[Google Viewer]]></string>
+	<string name="_sys_file_handlers_images_viewer"><![CDATA[Images Viewer]]></string>
+	<string name="_sys_file_handlers_code_viewer"><![CDATA[Code Viewer]]></string>
+        <string name="_sys_file_handlers_sounds_viewer"><![CDATA[Sounds Player]]></string>
+        <string name="_sys_file_handlers_videos_viewer"><![CDATA[Videos Player]]></string>
+	<string name="_sys_form_account"><![CDATA[Account]]></string>
+	<string name="_sys_form_account_input_agreement"><![CDATA[]]></string>
+	<string name="_sys_form_account_input_agreement_value"><![CDATA[By signing up, you agree to the <a href="{0}">Terms of Service</a> and <a href="{1}">Privacy Policy</a>.]]></string>
+	<string name="_sys_form_account_input_captcha"><![CDATA[Security Image]]></string>
+	<string name="_sys_form_account_input_captcha_error"><![CDATA[Security image input failed. Please, try again.]]></string>
+	<string name="_sys_form_account_input_captcha_label_text_image"><![CDATA[Type the text:]]></string>
+	<string name="_sys_form_account_input_captcha_label_text_audio"><![CDATA[Type the text you hear:]]></string>
+	<string name="_sys_form_account_input_captcha_action_refresh"><![CDATA[refresh]]></string>
+	<string name="_sys_form_account_input_captcha_action_title_refresh"><![CDATA[Get another CAPTCHA]]></string>
+	<string name="_sys_form_account_input_captcha_action_audio"><![CDATA[audio]]></string>
+	<string name="_sys_form_account_input_captcha_action_title_audio"><![CDATA[Get an audio CAPTCHA]]></string>
+	<string name="_sys_form_account_input_captcha_action_image"><![CDATA[image]]></string>
+	<string name="_sys_form_account_input_captcha_action_title_image"><![CDATA[Get an image CAPTCHA]]></string>
+	<string name="_sys_form_account_input_captcha_action_help"><![CDATA[help]]></string>
+	<string name="_sys_form_account_input_captcha_action_title_help"><![CDATA[Get Help]]></string>
+	<string name="_sys_form_account_input_delete_confirm"><![CDATA[I'm sure that I want to delete the account and data.]]></string>
+        <string name="_sys_form_account_input_delete_confirm_wo_content"><![CDATA[I'm sure that I want to delete the account.]]></string>
+	<string name="_sys_form_account_input_delete_confirm_error"><![CDATA[Please check this checkbox if you really want to delete account.]]></string>
+	<string name="_sys_form_account_input_delete_confirm_info"><![CDATA[This action can not be undone.]]></string>
+	<string name="_sys_form_account_input_email"><![CDATA[Email]]></string>
+	<string name="_sys_form_account_input_email_error"><![CDATA[Email is not valid]]></string>
+	<string name="_sys_form_account_input_email_uniq_error"><![CDATA[This email address is already registered. Please, use <a href="{0}">Forgot password</a> to restore access to your account.]]></string>
+	<string name="_sys_form_account_input_email_uniq_error_loggedin"><![CDATA[This email is already used by someone.]]></string>
+        <string name="_sys_form_account_input_phone_uniq_error_loggedin"><![CDATA[This phone number is already used by someone.]]></string>
+	<string name="_sys_form_account_input_name"><![CDATA[Account name]]></string>
+	<string name="_sys_form_account_input_name_error"><![CDATA[Account name is mandatory and and cannot start with @]]></string>
+	<string name="_sys_form_account_input_password"><![CDATA[Create a password]]></string>
+	<string name="_sys_form_account_input_password_confirm"><![CDATA[Confirm a password]]></string>
+	<string name="_sys_form_account_input_password_confirm_error"><![CDATA[Password confirmation failed]]></string>
+	<string name="_sys_form_account_input_password_current"><![CDATA[Current Password]]></string>
+        <string name="_sys_form_account_input_password_error_old_used"><![CDATA[This password has already been used before, use a different one]]></string>
+	<string name="_sys_form_account_input_password_current_error"><![CDATA[Current password isn't correct, please enter password you are using to login to this site.]]></string>
+	<string name="_sys_form_account_input_password_error"><![CDATA[The password must at least 8 characters long and contain at least 1 uppercase letter, 1 lowercase letter and 1 digit.]]></string>
+	<string name="_sys_form_account_input_receive_news"><![CDATA[Receive Newsletters]]></string>
+	<string name="_sys_form_account_input_receive_updates"><![CDATA[Receive Site Updates]]></string>
+	<string name="_sys_form_account_input_submit"><![CDATA[Submit]]></string>
+        <string name="_sys_form_account_input_publish"><![CDATA[Create new account]]></string>
+        <string name="_sys_form_account_input_caption_system_picture"><![CDATA[Account Picture]]></string>
+        <string name="_sys_form_account_input_picture"><![CDATA[Upload an account picture]]></string>
+        <string name="_sys_form_agents_comment"><![CDATA[Agents: Message]]></string>
+        <string name="_sys_form_display_agents_comment_post"><![CDATA[Agents: Message Send]]></string>
+        <string name="_sys_form_agents_comment_input_caption_system_action"><![CDATA[Action]]></string>
+        <string name="_sys_form_agents_comment_input_caption_system_cmt_image"><![CDATA[Image]]></string>
+	<string name="_sys_form_agents_comment_input_caption_system_cmt_parent_id"><![CDATA[Parent ID]]></string>
+	<string name="_sys_form_agents_comment_input_caption_system_cmt_submit"><![CDATA[Send]]></string>
+        <string name="_sys_form_agents_comment_input_caption_cmt_submit"><![CDATA[Send]]></string>
+	<string name="_sys_form_agents_comment_input_caption_system_cmt_text"><![CDATA[Text]]></string>
+        <string name="_sys_form_agents_comment_input_caption_cmt_text_error"><![CDATA[Empty message isn't allowed. Write something to send to assistant.]]></string>
+        <string name="_sys_form_agents_comment_input_caption_system_id"><![CDATA[Object ID]]></string>
+        <string name="_sys_form_agents_comment_input_caption_system_sys"><![CDATA[Object Type]]></string>
+	<string name="_sys_form_checkbox_value_off"><![CDATA[No]]></string>
+	<string name="_sys_form_checkbox_value_on"><![CDATA[Yes]]></string>
+        <string name="_sys_form_input_caption_author"><![CDATA[Author]]></string>
+	<string name="_sys_form_comment"><![CDATA[Comment]]></string>
+	<string name="_sys_form_comment_input_caption_cmt_author_id"><![CDATA[Author]]></string>
+	<string name="_sys_form_comment_input_caption_cmt_text"><![CDATA[Text]]></string>
+	<string name="_sys_form_comment_input_caption_system_action"><![CDATA[Action]]></string>
+        <string name="_sys_form_comment_input_caption_system_cmt_author_id"><![CDATA[Author]]></string>
+        <string name="_sys_form_comment_input_caption_system_cmt_cancel"><![CDATA[Cancel]]></string>
+	<string name="_sys_form_comment_input_caption_system_cmt_id"><![CDATA[Comment ID]]></string>
+	<string name="_sys_form_comment_input_caption_system_cmt_image"><![CDATA[Image]]></string>
+	<string name="_sys_form_comment_input_caption_system_cmt_parent_id"><![CDATA[Parent ID]]></string>
+	<string name="_sys_form_comment_input_caption_system_cmt_submit"><![CDATA[Post]]></string>
+	<string name="_sys_form_comment_input_caption_system_cmt_text"><![CDATA[Text]]></string>
+	<string name="_sys_form_comment_input_caption_system_id"><![CDATA[Object ID]]></string>
+	<string name="_sys_form_comment_input_caption_system_sys"><![CDATA[Object Type]]></string>
+        <string name="_sys_form_comment_input_cancel"><![CDATA[Cancel]]></string>
+	<string name="_sys_form_comment_input_submit"><![CDATA[Post]]></string>
+	<string name="_sys_form_confirm_email"><![CDATA[Email Confirmation]]></string>
+	<string name="_sys_form_confirm_email_input_caption_system_code"><![CDATA[Verification Code]]></string>
+	<string name="_sys_form_confirm_email_input_caption_system_do_submit"><![CDATA[Submit]]></string>
+	<string name="_sys_form_confirm_email_input_code"><![CDATA[Verification Code]]></string>
+	<string name="_sys_form_confirm_email_input_code_error"><![CDATA[Verification code is invalid or expired, please login to your account and resend verification email.]]></string>
+	<string name="_sys_form_confirm_email_input_submit"><![CDATA[Submit]]></string>
+	<string name="_sys_form_confirm_phone"><![CDATA[Phone Confirmation]]></string>
+	<string name="_sys_form_confirm_phone_input_caption_system_phone"><![CDATA[Phone]]></string>
+	<string name="_sys_form_confirm_phone_input_phone"><![CDATA[Phone]]></string>
+        <string name="_sys_form_confirm_phone_input_phone_info"><![CDATA[Enter your phone with country code]]></string>
+	<string name="_sys_form_confirm_phone_input_phone_error_format"><![CDATA[Wrong phone number, allowed digits only and start from '+']]></string>
+	<string name="_sys_form_confirm_phone_input_phone_error_not_unique"><![CDATA[This phone is already used by someone.]]></string>
+	<string name="_sys_form_confirm_phone_input_caption_system_code"><![CDATA[Code]]></string>
+	<string name="_sys_form_confirm_phone_confirmation_input_code"><![CDATA[Code]]></string>
+	<string name="_sys_form_confirm_phone_input_submit"><![CDATA[Submit]]></string>
+	<string name="_sys_form_confirm_phone_input_caption_system_do_submit"><![CDATA[Submit]]></string>
+	<string name="_sys_form_confirm_phone_input_sendsms"><![CDATA[Send SMS]]></string>
+	<string name="_sys_form_confirm_phone_input_caption_system_do_sendsms"><![CDATA[Send SMS]]></string>
+	<string name="_sys_form_confirm_phone_input_code_error_empty"><![CDATA[Cannot be empty.]]></string>
+	<string name="_sys_form_confirm_phone_input_code_error_invalid"><![CDATA[Wrong verification code. Please, repeat code or <a href="{0}">change the phone number and repeat from the beginning</a>.]]></string>
+	<string name="_sys_form_account_input_phone_error"><![CDATA[Phone is not valid]]></string>
+	<string name="_sys_form_display_account_create"><![CDATA[Create Account]]></string>
+	<string name="_sys_form_display_account_settings_delete"><![CDATA[Delete Account]]></string>
+	<string name="_sys_form_display_account_settings_email"><![CDATA[Email Settings]]></string>
+	<string name="_sys_form_display_account_settings_info"><![CDATA[Edit Account]]></string>
+	<string name="_sys_form_display_account_settings_password"><![CDATA[Change Password]]></string>
+	<string name="_sys_form_display_comment_edit"><![CDATA[Comment Edit Form]]></string>
+	<string name="_sys_form_display_comment_post"><![CDATA[Comment Post Form]]></string>
+	<string name="_sys_form_display_confirm_email"><![CDATA[Email Confirmation]]></string>
+	<string name="_sys_form_display_confirm_phone_set_phone"><![CDATA[Set phone]]></string>
+	<string name="_sys_form_display_confirm_phone_confirmation"><![CDATA[Phone confirmation]]></string>
+	<string name="_sys_form_display_forgot_password"><![CDATA[Forgot Password]]></string>
+        <string name="_sys_form_display_forgot_password_reset"><![CDATA[Reset Password]]></string>
+	<string name="_sys_form_display_login"><![CDATA[Log in]]></string>
+	<string name="_sys_form_display_login_step2"><![CDATA[Log in - step 2]]></string>
+	<string name="_sys_form_display_login_step3"><![CDATA[Log in - step 3]]></string>
+	<string name="_sys_form_display_report_post"><![CDATA[Report From Post]]></string>
+	<string name="_sys_form_display_unsubscribe_news"><![CDATA[Unsubscribe From Newsletters]]></string>
+	<string name="_sys_form_display_unsubscribe_updates"><![CDATA[Unsubscribe From Updates]]></string>
+	<string name="_sys_form_forgot_password"><![CDATA[Forgot Password]]></string>
+	<string name="_sys_form_forgot_password_email_not_recognized"><![CDATA[This email doesn't belong to any account. Please make sure that it is typed correctly.]]></string>
+	<string name="_sys_form_forgot_password_phone_not_recognized"><![CDATA[This phone doesn't belong to any account. Please make sure that it is typed correctly.]]></string>
+	<string name="_sys_form_forgot_password_phone_error_format"><![CDATA[Wrong phone number, allowed digits only and start from '+']]></string>
+	<string name="_sys_form_forgot_password_phone_and_email_empty_error"><![CDATA[Please, fill phone or email field]]></string>
+	<string name="_sys_form_forgot_password_input_caption_system_do_submit"><![CDATA[Submit]]></string>
+	<string name="_sys_form_forgot_password_input_caption_system_email"><![CDATA[Email]]></string>
+        <string name="_sys_form_forgot_password_input_caption_system_key"><![CDATA[Key]]></string>
+        <string name="_sys_form_forgot_password_input_caption_system_password"><![CDATA[Password]]></string>
+        <string name="_sys_form_forgot_password_input_caption_password"><![CDATA[Password]]></string>
+        <string name="_sys_form_forgot_password_input_caption_system_password_reset"><![CDATA[Password]]></string>
+        <string name="_sys_form_forgot_password_input_caption_password_reset"><![CDATA[Type your new password]]></string>
+	<string name="_sys_form_forgot_password_input_email"><![CDATA[Email]]></string>
+	<string name="_sys_form_forgot_password_input_caption_system_phone"><![CDATA[Phone]]></string>
+	<string name="_sys_form_forgot_password_input_phone"><![CDATA[Phone]]></string>
+	<string name="_sys_form_forgot_password_input_submit"><![CDATA[Submit]]></string>
+	<string name="_sys_form_input_age"><![CDATA[Age]]></string>
+	<string name="_sys_form_input_sys_location"><![CDATA[Location]]></string>
+	<string name="_sys_form_input_location"><![CDATA[Location]]></string>
+        <string name="_sys_form_input_location_radius_label"><![CDATA[Radius (in km)]]></string>
+        <string name="_sys_form_input_nested_form_button_add_new_item"><![CDATA[Add new item]]></string>
+        <string name="_sys_form_input_nested_form_button_delete_item"><![CDATA[Delete item]]></string>
+	<string name="_sys_form_input_sys_anonymous"><![CDATA[Post as anonymous]]></string>
+	<string name="_sys_form_input_anonymous"><![CDATA[Post as anonymous]]></string>
+        <string name="_sys_form_input_sys_cancel"><![CDATA[Cancel]]></string>
+        <string name="_sys_form_input_cancel"><![CDATA[Cancel]]></string>
+        <string name="_sys_form_input_sys_controls"><![CDATA[Controls]]></string>
+        <string name="_sys_form_input_sys_labels"><![CDATA[Labels]]></string>
+        <string name="_sys_form_input_labels"><![CDATA[Labels]]></string>
+        <string name="_sys_form_input_labels_placeholder"><![CDATA[Add Label]]></string>
+        <string name="_sys_form_input_password_show"><![CDATA[Show password]]></string>
+        <string name="_sys_form_input_password_hide"><![CDATA[Hide password]]></string>
+        <string name="_sys_form_input_textarea_editor"><![CDATA[Editor:]]></string>
+        <string name="_sys_form_labels"><![CDATA[Labels]]></string>
+        <string name="_sys_form_labels_display_select"><![CDATA[Select labels display]]></string>
+        <string name="_sys_form_labels_input_caption_system_name"><![CDATA[Name]]></string>
+        <string name="_sys_form_labels_input_caption_system_action"><![CDATA[Action]]></string>
+        <string name="_sys_form_labels_input_caption_system_search"><![CDATA[Search]]></string>
+        <string name="_sys_form_labels_input_caption_search"><![CDATA[Search]]></string>
+        <string name="_sys_form_labels_input_caption_system_list"><![CDATA[List]]></string>
+        <string name="_sys_form_labels_input_caption_list"><![CDATA[or select from general labels]]></string>
+        <string name="_sys_form_labels_input_caption_system_list_context"><![CDATA[List from contexts]]></string>
+        <string name="_sys_form_labels_input_caption_list_context"><![CDATA[from contexts' labels]]></string>
+        <string name="_sys_form_labels_input_caption_do_submit"><![CDATA[Submit]]></string>
+        <string name="_sys_form_labels_input_caption_system_do_submit"><![CDATA[Submit]]></string>
+        <string name="_sys_form_labels_input_caption_do_cancel"><![CDATA[Cancel]]></string>
+        <string name="_sys_form_labels_input_caption_system_do_cancel"><![CDATA[Cancel]]></string>
+	<string name="_sys_form_login"><![CDATA[Log in]]></string>
+	<string name="_sys_form_login_input_caption_system_agreement"><![CDATA[Agreement]]></string>
+	<string name="_sys_form_login_input_caption_system_captcha"><![CDATA[Captcha]]></string>
+	<string name="_sys_form_login_input_caption_system_checkcode"><![CDATA[Submit]]></string>
+	<string name="_sys_form_login_input_caption_system_code"><![CDATA[Code from SMS]]></string>
+	<string name="_sys_form_login_input_caption_system_back"><![CDATA[Resend SMS code]]></string>
+	<string name="_sys_form_login_input_caption_system_delete_confirm"><![CDATA[Confirm Delete]]></string>
+	<string name="_sys_form_login_input_caption_system_delete_content"><![CDATA[Delete with Content]]></string>
+	<string name="_sys_form_login_input_caption_system_do_submit"><![CDATA[Submit]]></string>
+        <string name="_sys_form_login_input_caption_system_do_publish"><![CDATA[Sign up]]></string>
+	<string name="_sys_form_login_input_caption_system_email"><![CDATA[Email]]></string>
+	<string name="_sys_form_login_input_caption_system_id"><![CDATA[ID]]></string>
+	<string name="_sys_form_login_input_caption_system_name"><![CDATA[Account name]]></string>
+	<string name="_sys_form_login_input_caption_system_password"><![CDATA[Password]]></string>
+	<string name="_sys_form_login_input_caption_system_password_confirm"><![CDATA[Confirm Password]]></string>
+	<string name="_sys_form_login_input_caption_system_phone"><![CDATA[Phone]]></string>
+	<string name="_sys_form_login_input_caption_system_password_current"><![CDATA[Current Password]]></string>
+	<string name="_sys_form_login_input_caption_system_receive_news"><![CDATA[Receive News]]></string>
+	<string name="_sys_form_login_input_caption_system_receive_updates"><![CDATA[Receive Updates]]></string>
+	<string name="_sys_form_login_input_caption_system_relocate"><![CDATA[Relocate]]></string>
+	<string name="_sys_form_login_input_caption_system_remember_me"><![CDATA[Remember me]]></string>
+	<string name="_sys_form_login_input_caption_system_role"><![CDATA[Role]]></string>
+	<string name="_sys_form_login_input_caption_system_sendsms"><![CDATA[Send SMS]]></string>
+	<string name="_sys_form_login_input_caption_system_submit"><![CDATA[Submit]]></string>
+	<string name="_sys_form_login_input_caption_system_submit_text"><![CDATA[Submit Text]]></string>
+        <string name="_sys_form_login_input_agreement_value"><![CDATA[By logging in, you agree to the <a href="{0}">Terms of Service</a> and <a href="{1}">Privacy Policy</a>.]]></string>
+	<string name="_sys_form_login_input_code"><![CDATA[Code from SMS]]></string>
+	<string name="_sys_form_login_input_back"><![CDATA[You didn't receive an SMS? <a href="{0}">Send SMS again</a>.]]></string>
+	<string name="_sys_form_login_input_checkcode"><![CDATA[Submit]]></string>
+	<string name="_sys_form_login_input_email"><![CDATA[Email]]></string>
+	<string name="_sys_form_login_input_password"><![CDATA[Password]]></string>
+	<string name="_sys_form_login_input_phone"><![CDATA[Phone]]></string>
+        <string name="_sys_form_login_input_phone_info"><![CDATA[Enter your phone with country code]]></string>
+	<string name="_sys_form_login_input_remember_me"><![CDATA[Remember me]]></string>
+	<string name="_sys_form_login_input_sendsms"><![CDATA[Send SMS]]></string>
+	<string name="_sys_form_login_input_submit"><![CDATA[Log in]]></string>
+	<string name="_sys_form_login_input_code_error_empty"><![CDATA[Cannot be empty.]]></string>
+	<string name="_sys_form_login_input_phone_error_format"><![CDATA[Wrong phone number, allowed digits only and start from '+']]></string>
+	<string name="_sys_form_login_input_phone_error_not_unique"><![CDATA[This phone is already used by someone.]]></string>
+	<string name="_sys_form_login_input_code_error_invalid"><![CDATA[Wrong verification code. Please, repeat code or <a href="{0}">change the phone number and repeat from the beginning</a>.]]></string>
+        <string name="_sys_form_manage"><![CDATA[Manage form]]></string>
+        <string name="_sys_form_display_manage_approve"><![CDATA[Manage form: Approve]]></string>
+        <string name="_sys_form_manage_input_sys_content_id"><![CDATA[Content ID]]></string>
+        <string name="_sys_form_manage_input_sys_notes"><![CDATA[Notes]]></string>
+        <string name="_sys_form_manage_input_notes"><![CDATA[Notes]]></string>
+        <string name="_sys_form_manage_input_sys_do_send"><![CDATA[Send]]></string>
+        <string name="_sys_form_manage_input_do_send"><![CDATA[Send]]></string>
+        <string name="_sys_form_manage_input_sys_do_submit"><![CDATA[Submit]]></string>
+        <string name="_sys_form_manage_input_do_submit"><![CDATA[Submit]]></string>
+        <string name="_sys_form_manage_input_do_submit_approve"><![CDATA[Approve]]></string>
+        <string name="_sys_form_manage_input_sys_do_cancel"><![CDATA[Cancel]]></string>
+        <string name="_sys_form_manage_input_do_cancel"><![CDATA[Cancel]]></string>
+        <string name="_sys_form_acl"><![CDATA[ACL form]]></string>
+        <string name="_sys_form_display_acl_set"><![CDATA[ACL form: Set]]></string>
+        <string name="_sys_form_popup_acl_set"><![CDATA[Set Membership]]></string>
+        <string name="_sys_form_acl_input_sys_level_id"><![CDATA[Level]]></string>
+        <string name="_sys_form_acl_input_level_id"><![CDATA[Level]]></string>
+        <string name="_sys_form_acl_input_sys_duration"><![CDATA[Duration]]></string>
+        <string name="_sys_form_acl_input_duration"><![CDATA[Duration]]></string>
+        <string name="_sys_form_acl_input_duration_inf"><![CDATA[In days. Leave empty for lifetime]]></string>
+        <string name="_sys_form_acl_input_sys_do_submit"><![CDATA[Submit]]></string>
+        <string name="_sys_form_acl_input_do_submit"><![CDATA[Submit]]></string>
+        <string name="_sys_form_acl_input_sys_do_cancel"><![CDATA[Cancel]]></string>
+        <string name="_sys_form_acl_input_do_cancel"><![CDATA[Cancel]]></string>
+        <string name="_sys_form_entry_input_sys_cf"><![CDATA[Content Filter]]></string>
+        <string name="_sys_form_entry_input_cf"><![CDATA[Select audience]]></string>
+	<string name="_sys_form_paceholder_profiles_suggestions"><![CDATA[Type name here...]]></string>
+        <string name="_sys_form_profile"><![CDATA[Profile]]></string>
+        <string name="_sys_form_display_profile_cf_set"><![CDATA[Configure Content Filter]]></string>
+        <string name="_sys_form_display_profile_cf_manage"><![CDATA[Manage Content Filter]]></string>
+        <string name="_sys_form_profile_input_sys_cfw_value"><![CDATA[Content Filter Value]]></string>
+        <string name="_sys_form_profile_input_cfw_value"><![CDATA[Show me a content marked with]]></string>
+        <string name="_sys_form_profile_input_sys_cfu_items"><![CDATA[Content Filter Items]]></string>
+        <string name="_sys_form_profile_input_cfu_items"><![CDATA[Available content filter categories]]></string>
+        <string name="_sys_form_profile_input_sys_cfu_locked"><![CDATA[Lock Content Filter]]></string>
+        <string name="_sys_form_profile_input_cfu_locked"><![CDATA[Lock content filter categories]]></string>
+        <string name="_sys_form_profile_input_sys_do_submit"><![CDATA[Submit]]></string>
+        <string name="_sys_form_profile_input_do_submit"><![CDATA[Submit]]></string>
+        <string name="_sys_form_profile_input_sys_do_cancel"><![CDATA[Cancel]]></string>
+        <string name="_sys_form_profile_input_do_cancel"><![CDATA[Cancel]]></string>
+        <string name="_sys_profile_cf_set_successfully_submitted"><![CDATA[Content Filter was successfully updated]]></string>
+        <string name="_sys_profile_cf_manage_successfully_submitted"><![CDATA[Content Filter was successfully updated]]></string>
+        <string name="_sys_profile_cf_manage_popup"><![CDATA[Manage Content Filter]]></string>
+        <string name="_sys_form_ps_group_custom"><![CDATA[Privacy: Custom group]]></string>
+        <string name="_sys_form_display_ps_gc_members"><![CDATA[Privacy: Profiles based custom group display]]></string>
+        <string name="_sys_form_display_ps_gc_memberships"><![CDATA[Privacy: Memberships based custom group display]]></string>
+        <string name="_sys_form_ps_gc_input_caption_system_profile_id"><![CDATA[Profile ID]]></string>
+        <string name="_sys_form_ps_gc_input_caption_system_content_id"><![CDATA[Content ID]]></string>
+        <string name="_sys_form_ps_gc_input_caption_system_object"><![CDATA[Object]]></string>
+        <string name="_sys_form_ps_gc_input_caption_system_action"><![CDATA[Action]]></string>
+        <string name="_sys_form_ps_gc_input_caption_system_group_id"><![CDATA[Group ID]]></string>
+        <string name="_sys_form_ps_gc_input_caption_system_search"><![CDATA[Search]]></string>
+        <string name="_sys_form_ps_gc_input_caption_search"><![CDATA[Search]]></string>
+        <string name="_sys_form_ps_gc_input_caption_system_list"><![CDATA[List]]></string>
+        <string name="_sys_form_ps_gc_input_caption_list"><![CDATA[or select]]></string>
+        <string name="_sys_form_ps_gc_input_caption_system_memberships"><![CDATA[Memberships List]]></string>
+        <string name="_sys_form_ps_gc_input_caption_memberships"><![CDATA[Select]]></string>
+        <string name="_sys_form_ps_gc_input_caption_system_do_submit"><![CDATA[Submit]]></string>
+        <string name="_sys_form_ps_gc_input_caption_do_submit"><![CDATA[Submit]]></string>
+        <string name="_sys_form_ps_gc_input_caption_system_do_cancel"><![CDATA[Cancel]]></string>
+        <string name="_sys_form_ps_gc_input_caption_do_cancel"><![CDATA[Cancel]]></string>
+  <string name="_sys_form_favorite"><![CDATA[Favorite]]></string>
+  <string name="_sys_form_display_favorite_add"><![CDATA[Add to favorite list]]></string>
+  <string name="_sys_form_display_favorite_list_edit"><![CDATA[Edit favorite list]]></string>
+  <string name="_sys_form_favorite_input_caption_system_sys"><![CDATA[Object Type]]></string>
+  <string name="_sys_form_favorite_input_caption_system_list_id"><![CDATA[List Id]]></string>
+  <string name="_sys_form_favorite_input_caption_system_object_id"><![CDATA[Object ID]]></string>
+  <string name="_sys_form_favorite_input_caption_system_action"><![CDATA[Action]]></string>
+  <string name="_sys_form_favorite_input_caption_system_id"><![CDATA[System ID]]></string>
+  <string name="_sys_form_favorite_input_caption_system_list"><![CDATA[Add to list]]></string>
+  <string name="_sys_form_favorite_input_caption_list"><![CDATA[Add to list]]></string>
+  <string name="_sys_form_favorite_input_caption_system_title"><![CDATA[Title]]></string>
+  <string name="_sys_form_favorite_input_caption_title"><![CDATA[Title]]></string>
+  <string name="_sys_form_favorite_input_caption_system_allow_view_to"><![CDATA[Visibility]]></string>
+  <string name="_sys_form_favorite_input_caption_allow_view_to"><![CDATA[Visibility]]></string>
+  <string name="_sys_form_favorite_input_caption_submit"><![CDATA[Save]]></string>
+  <string name="_sys_form_favorite_input_caption_system_submit"><![CDATA[Submit]]></string>
+  <string name="_sys_form_favorite_input_caption_button_new_list"><![CDATA[<i class="sys-icon folder-plus"></i>]]></string>
+  <string name="_sys_form_favorite_list_title_count"><![CDATA[Number of videos]]></string>
+  <string name="_sys_form_favorite_list_title_created"><![CDATA[Created]]></string>
+  <string name="_sys_form_favorite_list_title_updated"><![CDATA[Updated]]></string>
+  <string name="_sys_form_favorite_list_title_visibility"><![CDATA[Visibility]]></string>
+  <string name="_sys_txt_default_favorite_list"><![CDATA[Default]]></string>
+  
+	<string name="_sys_form_report"><![CDATA[Report]]></string>
+	<string name="_sys_form_report_input_caption_submit"><![CDATA[Post]]></string>
+	<string name="_sys_form_report_input_caption_text"><![CDATA[Report Text]]></string>
+	<string name="_sys_form_report_input_caption_type"><![CDATA[Report Type]]></string>
+	<string name="_sys_form_report_input_caption_system_action"><![CDATA[Action]]></string>
+	<string name="_sys_form_report_input_caption_system_object_id"><![CDATA[Object ID]]></string>	
+	<string name="_sys_form_report_input_caption_system_id"><![CDATA[Report ID]]></string>
+	<string name="_sys_form_report_input_caption_system_submit"><![CDATA[Post Report]]></string>
+	<string name="_sys_form_report_input_caption_system_text"><![CDATA[Report Text]]></string>
+	<string name="_sys_form_report_input_caption_system_type"><![CDATA[Report Type]]></string>
+	<string name="_sys_form_report_input_caption_system_sys"><![CDATA[Object Type]]></string>
+        <string name="_sys_form_review"><![CDATA[Review]]></string>
+        <string name="_sys_form_review_display_edit"><![CDATA[Review Edit Form]]></string>
+	<string name="_sys_form_review_display_post"><![CDATA[Review Post Form]]></string>
+	<string name="_sys_form_review_input_caption_cmt_author_id"><![CDATA[Author]]></string>
+	<string name="_sys_form_review_input_caption_cmt_text"><![CDATA[Text]]></string>
+	<string name="_sys_form_review_input_caption_system_action"><![CDATA[Action]]></string>
+        <string name="_sys_form_review_input_caption_system_cmt_author_id"><![CDATA[Author]]></string>
+	<string name="_sys_form_review_input_caption_system_cmt_id"><![CDATA[ID]]></string>
+	<string name="_sys_form_review_input_caption_system_cmt_image"><![CDATA[Image]]></string>
+	<string name="_sys_form_review_input_caption_system_cmt_parent_id"><![CDATA[Parent ID]]></string>
+	<string name="_sys_form_review_input_caption_system_cmt_submit"><![CDATA[Post]]></string>
+	<string name="_sys_form_review_input_caption_system_cmt_text"><![CDATA[Text]]></string>
+        <string name="_sys_form_review_input_caption_system_cmt_mood"><![CDATA[Rating]]></string>
+	<string name="_sys_form_review_input_caption_system_id"><![CDATA[Object ID]]></string>
+	<string name="_sys_form_review_input_caption_system_sys"><![CDATA[Object Type]]></string>
+	<string name="_sys_form_review_input_submit"><![CDATA[Post]]></string>
+	<string name="_sys_form_unsubscribe"><![CDATA[Unsubscribe]]></string>
+	<string name="_sys_form_unsubscribe_input_caption_system_code"><![CDATA[Security Code]]></string>
+	<string name="_sys_form_unsubscribe_input_caption_system_do_submit"><![CDATA[Submit]]></string>
+	<string name="_sys_form_unsubscribe_input_caption_system_id"><![CDATA[Account ID]]></string>
+	<string name="_sys_form_unsubscribe_input_caption_system_receive_news"><![CDATA[Receive Newsletters]]></string>
+	<string name="_sys_form_unsubscribe_input_caption_system_receive_updates"><![CDATA[Receive Site Updates]]></string>
+	<string name="_sys_form_unsubscribe_input_receive_news"><![CDATA[Receive Newsletters]]></string>
+	<string name="_sys_form_unsubscribe_input_receive_updates"><![CDATA[Receive Site Updates]]></string>
+	<string name="_sys_form_unsubscribe_input_submit"><![CDATA[Submit]]></string>
+	<string name="_sys_form_err_not_unique_value"><![CDATA[The field should have unique value]]></string>
+	<string name="_sys_form_txt_select_file"><![CDATA[Select a file]]></string>
+	<string name="_sys_form_wiki"><![CDATA[Wiki]]></string>
+	<string name="_sys_form_display_wiki_edit"><![CDATA[Wiki Edit]]></string>
+	<string name="_sys_form_display_wiki_translate"><![CDATA[Wiki Translate]]></string>
+	<string name="_sys_form_wiki_input_caption_block_id"><![CDATA[Block ID]]></string>
+	<string name="_sys_form_wiki_input_caption_lang"><![CDATA[Language]]></string>
+	<string name="_sys_form_wiki_input_caption_lang_info"><![CDATA[★ - main(original) language, red - outdated or missing translation]]></string>
+	<string name="_sys_form_wiki_input_caption_lang_err"><![CDATA[Please select value]]></string>
+	<string name="_sys_form_wiki_input_caption_content"><![CDATA[Content]]></string>
+	<string name="_sys_form_wiki_input_caption_content_info"><![CDATA[Markdown syntax and macros are supported.]]></string>
+	<string name="_sys_form_wiki_input_caption_content_main"><![CDATA[Main(original) Content]]></string>
+	<string name="_sys_form_wiki_input_caption_notes"><![CDATA[Notes]]></string>
+	<string name="_sys_form_wiki_input_caption_submit"><![CDATA[Submit]]></string>
+	<string name="_sys_form_wiki_input_caption_close"><![CDATA[Close]]></string>
+	<string name="_sys_form_wiki_input_caption_files"><![CDATA[Images]]></string>
+	<string name="_sys_form_wiki_buttons"><![CDATA[Buttons]]></string>
+	<string name="_sys_format_size_b"><![CDATA[{0} bytes]]></string>
+	<string name="_sys_format_size_gb"><![CDATA[{0} GB]]></string>
+	<string name="_sys_format_size_kb"><![CDATA[{0} KB]]></string>
+	<string name="_sys_format_size_mb"><![CDATA[{0} MB]]></string>
+	<string name="_sys_format_size_tb"><![CDATA[{0} TB]]></string>
+	<string name="_sys_grid_confirmation"><![CDATA[Are you sure?]]></string>
+	<string name="_sys_grid_delete_failed"><![CDATA[Delete failed]]></string>
+  <string name="_sys_grid_search"><![CDATA[Search...]]></string>
+  <string name="_sys_grid_total_count"><![CDATA[Сount: {0}]]></string>
+  <string name="_sys_grid_txt_account_manager"><![CDATA[Redirect to manage account.]]></string>
+	<string name="_sys_inst_conf_desc"><![CDATA[{0}{1}<br />Example: {2}]]></string>
+	<string name="_sys_inst_conf_desc_admin_email"><![CDATA[Admin user e-mail address.]]></string>
+	<string name="_sys_inst_conf_desc_admin_pwd"><![CDATA[Admin user password here.]]></string>
+	<string name="_sys_inst_conf_desc_admin_username"><![CDATA[Admin user name here.]]></string>
+	<string name="_sys_inst_conf_desc_db_host"><![CDATA[Your MySQL database host name here.]]></string>
+	<string name="_sys_inst_conf_desc_db_name"><![CDATA[Your MySQL database name here.]]></string>
+	<string name="_sys_inst_conf_desc_db_port"><![CDATA[Leave blank or specify custom MySQL database host port number.]]></string>
+	<string name="_sys_inst_conf_desc_db_pwd"><![CDATA[Your MySQL database password here.]]></string>
+	<string name="_sys_inst_conf_desc_db_sock"><![CDATA[Leave blank or specify MySQL database socket path.]]></string>
+	<string name="_sys_inst_conf_desc_db_user"><![CDATA[Your MySQL database user name with read/write access.]]></string>
+	<string name="_sys_inst_conf_desc_db_engine"><![CDATA[MySQL database engine, some DB engines may require custom MYSQL configuration.]]></string>
+	<string name="_sys_inst_conf_desc_language"><![CDATA[Language to install by default.]]></string>
+	<string name="_sys_inst_conf_desc_profiles"><![CDATA[Profiles module to install by default.]]></string>
+	<string name="_sys_inst_conf_desc_oauth_key_secret"><![CDATA[<a target="_blank" href="http://www.una.io/page/kands-manage">Get UNA Key & Secret</a>]]></string>
+	<string name="_sys_inst_conf_desc_path_to_binary"><![CDATA[If '{0}' binary doesn't exist, you need to install <a target="_blank" href="http://www.imagemagick.org/">ImageMagick</a>.]]></string>
+	<string name="_sys_inst_conf_desc_root_dir"><![CDATA[Path to directory where UNA files are stored.]]></string>
+	<string name="_sys_inst_conf_desc_site_email"><![CDATA[Email to send site messages from.]]></string>
+	<string name="_sys_inst_conf_desc_site_title"><![CDATA[The name of your site.]]></string>
+	<string name="_sys_inst_conf_desc_site_url"><![CDATA[Your site URL here (slash at the end is required).]]></string>
+	<string name="_sys_inst_conf_desc_template"><![CDATA[Template to install by default.]]></string>
+	<string name="_sys_inst_conf_error"><![CDATA[Please, input valid data here.]]></string>
+	<string name="_sys_inst_conf_field_admin_email"><![CDATA[Admin e-mail]]></string>
+	<string name="_sys_inst_conf_field_admin_pwd"><![CDATA[Admin password]]></string>
+	<string name="_sys_inst_conf_field_admin_username"><![CDATA[Admin user name]]></string>
+	<string name="_sys_inst_conf_field_db_host"><![CDATA[Database host name]]></string>
+	<string name="_sys_inst_conf_field_db_name"><![CDATA[Database name]]></string>
+	<string name="_sys_inst_conf_field_db_port"><![CDATA[Database host port number]]></string>
+	<string name="_sys_inst_conf_field_db_pwd"><![CDATA[Database password]]></string>
+	<string name="_sys_inst_conf_field_db_sock"><![CDATA[Database socket path]]></string>
+	<string name="_sys_inst_conf_field_db_user"><![CDATA[Database user]]></string>
+	<string name="_sys_inst_conf_field_db_engine"><![CDATA[Database engine]]></string>
+	<string name="_sys_inst_conf_field_language"><![CDATA[Language]]></string>
+	<string name="_sys_inst_conf_field_profiles"><![CDATA[Profiles]]></string>
+	<string name="_sys_inst_conf_field_oauth_key"><![CDATA[UNA key]]></string>
+	<string name="_sys_inst_conf_field_oauth_secret"><![CDATA[UNA secret]]></string>
+	<string name="_sys_inst_conf_field_path_to_binary"><![CDATA[Path to '{0}' binary]]></string>
+	<string name="_sys_inst_conf_field_root_dir"><![CDATA[Site directory]]></string>
+	<string name="_sys_inst_conf_field_site_email"><![CDATA[Site e-mail]]></string>
+	<string name="_sys_inst_conf_field_site_title"><![CDATA[Site title]]></string>
+	<string name="_sys_inst_conf_field_site_url"><![CDATA[Site URL]]></string>
+	<string name="_sys_inst_conf_field_template"><![CDATA[Template]]></string>
+	<string name="_sys_inst_conf_found"><![CDATA[<span style="color:green">Found</span>]]></string>
+	<string name="_sys_inst_conf_no_example"><![CDATA[no example]]></string>
+	<string name="_sys_inst_conf_not_found"><![CDATA[<span style="color:red">Not found</span>]]></string>
+	<string name="_sys_inst_conf_section_db_config"><![CDATA[DB config]]></string>
+	<string name="_sys_inst_conf_section_link_with_market"><![CDATA[Link with UNA market]]></string>
+	<string name="_sys_inst_conf_section_modules"><![CDATA[Modules]]></string>
+	<string name="_sys_inst_conf_section_paths"><![CDATA[Site paths]]></string>
+	<string name="_sys_inst_conf_section_site_info"><![CDATA[Site info]]></string>
+	<string name="_sys_inst_continue"><![CDATA[Continue]]></string>
+	<string name="_sys_inst_finish"><![CDATA[Installation has been successfully completed]]></string>
+	<string name="_sys_inst_help_finish"><![CDATA[Help with cron jobs]]></string>
+	<string name="_sys_inst_help_permissions"><![CDATA[Setting permissions help]]></string>
+	<string name="_sys_inst_help_site_config"><![CDATA[Creating database help]]></string>
+	<string name="_sys_inst_hosting_fails"><![CDATA[Your hosting doesn't meet minimal requirements:]]></string>
+	<string name="_sys_inst_hosting_warnings"><![CDATA[Your hosting setup has some warnings, for the complete report go to <a href="?action=audit">server audit page</a>.]]></string>
+	<string name="_sys_inst_msg_admin_account_not_found"><![CDATA[Admin account wasn't found by email - {0}]]></string>
+	<string name="_sys_inst_msg_db_err_connect"><![CDATA[Database connect failed]]></string>
+	<string name="_sys_inst_msg_db_err_select"><![CDATA[Database select failed]]></string>
+	<string name="_sys_inst_msg_file_read_failed"><![CDATA[File read failed: {0}]]></string>
+	<string name="_sys_inst_msg_file_write_failed"><![CDATA[File write failed: {0}]]></string>
+	<string name="_sys_inst_msg_finish"><![CDATA[But some additional manual steps are required:]]></string>
+	<string name="_sys_inst_msg_finish_cron_jobs"><![CDATA[Setup the following cron jobs command:]]></string>
+	<string name="_sys_inst_msg_finish_delete_install_folder"><![CDATA[Remove <b>/install/</b> folder from the script root folder.]]></string>
+	<string name="_sys_inst_msg_finish_goto_studio"><![CDATA[<a href="{0}studio/">Go to Studio</a> to add additional modules and customize the site.]]></string>
+	<string name="_sys_inst_msg_form_error"><![CDATA[Please fix form errors.]]></string>
+	<string name="_sys_inst_msg_module_error"><![CDATA[{0} - {1}]]></string>
+	<string name="_sys_inst_msg_permissions_wrong"><![CDATA[Some files or folders rights aren't correct, please set necessary permissions then click "Continue".]]></string>
+	<string name="_sys_inst_msg_remove_install"><![CDATA[Please, remove INSTALL directory from your server and reload this page to activate your site.<br />After deletion you can safely go <a href="../studio/">to the site Studio</a> to add additional modules and customize the site.]]></string>
+	<string name="_sys_inst_msg_script_isnt_installed"><![CDATA[Script isn't installed]]></string>
+	<string name="_sys_inst_refresh"><![CDATA[Refresh]]></string>
+	<string name="_sys_inst_server_audit"><![CDATA[Server audit]]></string>
+	<string name="_sys_inst_site_config"><![CDATA[Site configuration]]></string>
+	<string name="_sys_inst_start_installation"><![CDATA[Start installation]]></string>
+	<string name="_sys_inst_title"><![CDATA[UNA {0} Installation]]></string>
+	<string name="_sys_layout_1_column"><![CDATA[1 column]]></string>
+        <string name="_sys_layout_1_column_thin"><![CDATA[1 column (thin)]]></string>
+        <string name="_sys_layout_1_column_half"><![CDATA[1 column (half)]]></string>
+        <string name="_sys_layout_1_column_wiki"><![CDATA[1 column (wiki)]]></string>
+	<string name="_sys_layout_2_columns"><![CDATA[2 columns]]></string>
+	<string name="_sys_layout_3_columns"><![CDATA[3 columns]]></string>
+	<string name="_sys_layout_bar_left"><![CDATA[With left bar]]></string>
+	<string name="_sys_layout_bar_content_bar"><![CDATA[With left and right bars]]></string>
+	<string name="_sys_layout_bar_right"><![CDATA[With right bar]]></string>
+	<string name="_sys_layout_bottom_area_2_columns"><![CDATA[Bottom area with 2 columns at top]]></string>
+	<string name="_sys_layout_top_area_2_columns"><![CDATA[Top area with 2 columns]]></string>
+	<string name="_sys_layout_top_area_3_columns"><![CDATA[Top area with 3 columns]]></string>
+	<string name="_sys_layout_top_area_bar_left"><![CDATA[Top area with left bar]]></string>
+	<string name="_sys_layout_top_area_bar_content_bar"><![CDATA[Top area with left and right bars]]></string>
+	<string name="_sys_layout_top_area_bar_right"><![CDATA[Top area with right bar]]></string>
+	<string name="_sys_layout_topbottom_area_2_columns"><![CDATA[Top&bottom areas with 2 columns in the middle]]></string>
+	<string name="_sys_layout_topbottom_area_bar_left"><![CDATA[Top&bottom areas with left bar in the middle]]></string>
+	<string name="_sys_layout_topbottom_area_bar_right"><![CDATA[Top&bottom areas with right bar in the middle]]></string>	
+        <string name="_sys_layout_topbottom_area_col1_col3_col2"><![CDATA[Top&bottom areas with 3 columns (1:3:2) in the middle]]></string>
+        <string name="_sys_layout_topbottom_area_col1_col5"><![CDATA[Top&bottom areas with 2 columns (1:5) in the middle]]></string>
+        <string name="_sys_layout_topbottom_area_col2_col5_col3"><![CDATA[Top&bottom areas with 3 columns (2:5:3) in the middle]]></string>
+	<string name="_sys_loading"><![CDATA[Loading...]]></string>
+	<string name="_sys_location_country"><![CDATA[<i class="sys-icon location-arrow"></i> {0}]]></string>
+	<string name="_sys_location_country_city"><![CDATA[<i class="sys-icon location-arrow"></i> {2}, {1}, {0}]]></string>
+        <string name="_sys_location_country_city_street"><![CDATA[<i class="sys-icon location-arrow"></i> {4} {3}, {2}, {1}, {0} ]]></string>
+	<string name="_sys_location_determining"><![CDATA[Determining location...]]></string>
+	<string name="_sys_location_geolocation_not_supported_by_browser"><![CDATA[Geolocation is not supported by this browser]]></string>
+	<string name="_sys_location_undefined"><![CDATA[Location undefined]]></string>
+	<string name="_sys_location_map_google_static"><![CDATA[Google Maps (Static)]]></string>
+	<string name="_sys_location_map_leaflet"><![CDATA[Leaflet (various free map providers)]]></string>
+	<string name="_sys_location_field_google"><![CDATA[Google autocomplete for addresses]]></string>
+	<string name="_sys_location_field_plain"><![CDATA[Plain address fields with Nominatim OSM geocoding]]></string>
+        <string name="_sys_location_field_label"><![CDATA[Show location]]></string>
+    <string name="_sys_location_ph_number"><![CDATA[Number]]></string>
+    <string name="_sys_location_ph_street"><![CDATA[Street]]></string>
+    <string name="_sys_location_ph_city"><![CDATA[City / District]]></string>
+    <string name="_sys_location_ph_state"><![CDATA[State / Province]]></string>
+    <string name="_sys_location_ph_zip"><![CDATA[Postal Code]]></string>
+    <string name="_sys_location_status_undef"><![CDATA[Address is undefined]]></string>
+    <string name="_sys_location_status_ok"><![CDATA[Address found]]></string>
+    <string name="_sys_location_status_fail"><![CDATA[Address not found]]></string>
+    <string name="_sys_log_debug"><![CDATA[System: debug]]></string>
+    <string name="_sys_log_sms"><![CDATA[System: SMS]]></string>
+    <string name="_sys_log_push"><![CDATA[System: PUSH]]></string>
+    <string name="_sys_log_payments"><![CDATA[System: Payments]]></string>
+    <string name="_sys_log_cron_jobs"><![CDATA[System: Cron jobs]]></string>
+    <string name="_sys_log_transcoder"><![CDATA[System: Transcoder]]></string>
+    <string name="_sys_macros_malformed"><![CDATA[Error: malformed macros]]></string>
+    <string name="_sys_macros_unsafe"><![CDATA[Error: unsafe macros]]></string>
+    <string name="_sys_macros_output_not_displayable"><![CDATA[Error: output isn't displayable]]></string>
+    <string name="_sys_macros_method_or_class_not_found"><![CDATA[Error: no such macros]]></string>
+    <string name="_sys_macros_required_args_missing"><![CDATA[Error: required arguments are missing]]></string>
+    <string name="_sys_macros_too_many_args"><![CDATA[Error: too many arguments]]></string>
+    <string name="_sys_manage_popup_approve_title"><![CDATA[Approve]]></string>
+    <string name="_sys_manage_txt_approved"><![CDATA[The content was approved.]]></string>
+    <string name="_sys_manage_txt_sent"><![CDATA[Message was sent.]]></string>
+    <string name="_sys_manage_err_cannot_perform_action"><![CDATA[Cannot perform the action. Please report.]]></string>
+    <string name="_sys_menu_item_info_audit_administration"><![CDATA[For content moderation activity.]]></string>
+    <string name="_sys_menu_item_title_about"><![CDATA[About]]></string>
+    <string name="_sys_menu_item_title_copyright"><![CDATA[Copyright]]></string>
+    <string name="_sys_menu_item_title_privacy"><![CDATA[Privacy]]></string>
+    <string name="_sys_menu_item_title_search"><![CDATA[Search]]></string>
+    <string name="_sys_menu_item_title_switch_language"><![CDATA[Language]]></string>
+    <string name="_sys_menu_item_title_switch_language_mask"><![CDATA[{1} {0}]]></string>
+    <string name="_sys_menu_item_title_switch_template"><![CDATA[Design]]></string>
+    <string name="_sys_menu_item_title_switch_template_mask"><![CDATA[{0}]]></string>
+    <string name="_sys_menu_item_title_terms"><![CDATA[Terms]]></string>
+    <string name="_sys_menu_item_title_account_menu"><![CDATA[{member_display_name}]]></string>
+    <string name="_sys_menu_item_title_account_profile_context"><![CDATA[Profiles]]></string>
+    <string name="_sys_menu_item_title_account_dashboard"><![CDATA[Dashboard]]></string>
+    <string name="_sys_menu_item_title_account_dashboard_administration"><![CDATA[Administration]]></string>
+    <string name="_sys_menu_item_title_account_settings"><![CDATA[Settings]]></string>
+    <string name="_sys_menu_item_title_account_settings_delete"><![CDATA[Delete]]></string>
+    <string name="_sys_menu_item_title_account_settings_email"><![CDATA[Email]]></string>
+    <string name="_sys_menu_item_title_account_settings_info"><![CDATA[Account]]></string>
+    <string name="_sys_menu_item_title_account_settings_pwd"><![CDATA[Password]]></string>
+    <string name="_sys_menu_item_title_profile_settings_cfilter"><![CDATA[Content Filter]]></string>
+    <string name="_sys_menu_item_title_add_content"><![CDATA[Add...]]></string>
+    <string name="_sys_menu_item_title_cart"><![CDATA[Shopping Cart]]></string>
+    <string name="_sys_menu_item_title_cmts_administration"><![CDATA[Comments]]></string>
+    <string name="_sys_menu_item_title_audit_administration"><![CDATA[Audit]]></string>
+    <string name="_sys_menu_item_title_cmts_item_delete"><![CDATA[Delete]]></string>
+    <string name="_sys_menu_item_title_cmts_item_edit"><![CDATA[Edit]]></string>
+    <string name="_sys_menu_item_title_cmts_item_pin"><![CDATA[Pin]]></string>
+    <string name="_sys_menu_item_title_cmts_item_unpin"><![CDATA[Unpin]]></string>
+    <string name="_sys_menu_item_title_cmts_item_quote"><![CDATA[Quote]]></string>
+    <string name="_sys_menu_item_title_cmts_item_reaction"><![CDATA[]]></string>
+    <string name="_sys_menu_item_title_cmts_item_reply"><![CDATA[Reply]]></string>
+    <string name="_sys_menu_item_title_cmts_item_score"><![CDATA[]]></string>
+    <string name="_sys_menu_item_title_cmts_item_vote"><![CDATA[]]></string>
+    <string name="_sys_menu_item_title_cmts_item_more"><![CDATA[]]></string>
+    <string name="_sys_menu_item_title_connections"><![CDATA[Connections]]></string>
+    <string name="_sys_menu_item_title_dashboard"><![CDATA[Dash]]></string>
+    <string name="_sys_menu_item_title_home"><![CDATA[Home]]></string>
+    <string name="_sys_menu_item_title_invoices"><![CDATA[Invoices]]></string>
+    <string name="_sys_menu_item_title_logout"><![CDATA[Sign out]]></string>
+    <string name="_sys_menu_item_title_more"><![CDATA[More]]></string>
+    <string name="_sys_menu_item_title_more_auto"><![CDATA[]]></string>
+    <string name="_sys_menu_item_title_orders"><![CDATA[Orders]]></string>
+    <string name="_sys_menu_item_title_profile"><![CDATA[Profile]]></string>
+    <string name="_sys_menu_item_title_set_acl_level"><![CDATA[Set membership]]></string>
+    <string name="_sys_menu_item_title_set_badges"><![CDATA[Set badges]]></string>
+    <string name="_sys_menu_item_title_studio"><![CDATA[Studio]]></string>
+    <string name="_sys_menu_item_title_subscriptions"><![CDATA[Subscriptions]]></string>
+    <string name="_sys_menu_item_title_social_sharing_facebook"><![CDATA[Share in Facebook]]></string>
+    <string name="_sys_menu_item_title_social_sharing_twitter"><![CDATA[Share in Twitter]]></string>
+    <string name="_sys_menu_item_title_social_sharing_pinterest"><![CDATA[Share in Pinterest]]></string>
+    <string name="_sys_menu_item_title_social_sharing_linked_in"><![CDATA[Share in LinkedIn]]></string>
+    <string name="_sys_menu_item_title_system_social_sharing_linked_in"><![CDATA[Share in LinkedIn]]></string>
+    <string name="_sys_menu_item_title_social_sharing_whatsapp"><![CDATA[Share in Whatsapp]]></string>
+    <string name="_sys_menu_item_title_system_social_sharing_whatsapp"><![CDATA[Share in Whatsapp]]></string>
+    
+    <string name="_sys_menu_item_title_sm_in_reply_to"><![CDATA[In reply to]]></string>
+    <string name="_sys_menu_item_title_sm_author"><![CDATA[Author]]></string>
+    <string name="_sys_menu_item_title_sm_date"><![CDATA[Date]]></string>
+    <string name="_sys_menu_item_title_sm_category"><![CDATA[Category]]></string>
+    <string name="_sys_menu_item_title_sm_tags"><![CDATA[Tags]]></string>
+    <string name="_sys_menu_item_title_sm_views"><![CDATA[Views]]></string>
+    <string name="_sys_menu_item_title_sm_votes"><![CDATA[Votes]]></string>
+    <string name="_sys_menu_item_title_sm_reactions"><![CDATA[Reactions]]></string>
+    <string name="_sys_menu_item_title_sm_scores"><![CDATA[Votes (for/against)]]></string>
+    <string name="_sys_menu_item_title_sm_rating"><![CDATA[Rating]]></string>
+    <string name="_sys_menu_item_title_sm_comments"><![CDATA[Comments]]></string>
+    <string name="_sys_menu_item_title_sm_actions"><![CDATA[Actions]]></string>
+    <string name="_sys_menu_item_title_sm_befriend"><![CDATA[Add friend]]></string>
+    <string name="_sys_menu_item_title_sm_befriend_sent"><![CDATA[Add friend (requested)]]></string>
+    <string name="_sys_menu_item_title_sm_befriend_confirm"><![CDATA[Accept friend request]]></string>
+    <string name="_sys_menu_item_title_sm_unfriend"><![CDATA[Unfriend]]></string>
+    <string name="_sys_menu_item_title_sm_unfriend_cancel"><![CDATA[Cancel request]]></string>
+    <string name="_sys_menu_item_title_sm_unfriend_reject"><![CDATA[Reject friend request]]></string>
+    <string name="_sys_menu_item_title_sm_join_paid"><![CDATA[Pay & Join]]></string>
+    <string name="_sys_menu_item_title_sm_join"><![CDATA[Join]]></string>
+    <string name="_sys_menu_item_title_sm_join_confirm"><![CDATA[Accept join request]]></string>
+    <string name="_sys_menu_item_title_sm_leave"><![CDATA[Leave]]></string>
+    <string name="_sys_menu_item_title_sm_leave_cancel"><![CDATA[Cancel join request]]></string>
+    <string name="_sys_menu_item_title_sm_leave_reject"><![CDATA[Reject join request]]></string>
+    <string name="_sys_menu_item_title_sm_nl"><![CDATA[New line]]></string>
+    <string name="_sys_menu_item_title_sm_subscribe"><![CDATA[Follow]]></string>
+    <string name="_sys_menu_item_title_sm_unsubscribe"><![CDATA[Unfollow]]></string>
+    <string name="_sys_menu_item_title_sm_friends"><![CDATA[{0} friends]]></string>
+    <string name="_sys_menu_item_title_sm_friends_mutual"><![CDATA[{0} mutual friends]]></string>
+    <string name="_sys_menu_item_title_sm_members"><![CDATA[{0} members]]></string>
+    <string name="_sys_menu_item_title_sm_fans"><![CDATA[Members]]></string>
+    <string name="_sys_menu_item_title_sm_fans_respond"><![CDATA[Respond a fan]]></string>
+    <string name="_sys_menu_item_title_sm_subscribers"><![CDATA[{0} followers]]></string>
+    <string name="_sys_menu_item_title_sm_relations"><![CDATA[{0} relations]]></string>
+    <string name="_sys_menu_item_title_sm_country"><![CDATA[Country]]></string>
+    <string name="_sys_menu_item_title_sm_country_city"><![CDATA[Country and City]]></string>
+    <string name="_sys_menu_item_title_sm_ignore"><![CDATA[Remove]]></string>
+    <string name="_sys_menu_item_title_vm_membership"><![CDATA[Membership]]></string>
+    <string name="_sys_menu_item_title_vm_badges"><![CDATA[Badges]]></string>
+    <string name="_sys_menu_item_title_system_about"><![CDATA[About]]></string>
+    <string name="_sys_menu_item_title_system_copyright"><![CDATA[Copyright]]></string>
+    <string name="_sys_menu_item_title_system_privacy"><![CDATA[Privacy]]></string>
+    <string name="_sys_menu_item_title_system_switch_language"><![CDATA[Language]]></string>
+    <string name="_sys_menu_item_title_system_switch_template"><![CDATA[Template]]></string>
+    <string name="_sys_menu_item_title_system_terms"><![CDATA[Terms]]></string>
+    <string name="_sys_menu_item_title_system_account_menu"><![CDATA[Account]]></string>
+    <string name="_sys_menu_item_title_system_account_profile_context"><![CDATA[Profiles]]></string>
+    <string name="_sys_menu_item_title_system_account_dashboard"><![CDATA[Dashboard]]></string>
+    <string name="_sys_menu_item_title_system_account_dashboard_administration"><![CDATA[Administration]]></string>
+
+    <string name="_sys_menu_item_title_system_account_dashboard_content"><![CDATA[Content]]></string>
+    <string name="_sys_menu_item_title_account_dashboard_content"><![CDATA[Content]]></string>
+    <string name="_sys_menu_item_title_system_account_dashboard_reports"><![CDATA[Reports]]></string>
+    <string name="_sys_menu_item_title_account_dashboard_reports"><![CDATA[Reports]]></string>
+    <string name="_sys_menu_item_title_system_account_dashboard_audit"><![CDATA[Audit]]></string>
+    <string name="_sys_menu_item_title_account_dashboard_audit"><![CDATA[Audit]]></string>
+
+    <string name="_sys_menu_item_title_system_ap_profile_active"><![CDATA[Active Profile]]></string>
+    <string name="_sys_menu_item_title_system_ap_profile_notifications"><![CDATA[Notifications Menu]]></string>
+    <string name="_sys_menu_item_title_system_ap_profile_switcher"><![CDATA[Profile Switcher]]></string>
+    <string name="_sys_menu_item_title_system_ap_profile_create"><![CDATA[Create Profile]]></string>
+    <string name="_sys_menu_item_title_system_account_settings"><![CDATA[Settings]]></string>
+    <string name="_sys_menu_item_title_system_account_settings_delete"><![CDATA[Delete]]></string>
+    <string name="_sys_menu_item_title_system_account_settings_email"><![CDATA[Email]]></string>
+    <string name="_sys_menu_item_title_system_account_settings_info"><![CDATA[Account]]></string>
+    <string name="_sys_menu_item_title_system_account_settings_pwd"><![CDATA[Password]]></string>
+    <string name="_sys_menu_item_title_system_profile_settings_cfilter"><![CDATA[Content Filter]]></string>
+    <string name="_sys_menu_item_title_system_add_content"><![CDATA[Add Content]]></string>
+    <string name="_sys_menu_item_title_system_apps"><![CDATA[Apps]]></string>
+    <string name="_sys_menu_item_title_system_cart"><![CDATA[Shopping Cart]]></string>
+    <string name="_sys_menu_item_title_system_cmts_administration"><![CDATA[Comments]]></string>
+    <string name="_sys_menu_item_title_system_audit_administration"><![CDATA[Audit]]></string>
+    <string name="_sys_menu_item_title_system_cmts_item_delete"><![CDATA[Delete]]></string>
+    <string name="_sys_menu_item_title_system_cmts_item_edit"><![CDATA[Edit]]></string>
+    <string name="_sys_menu_item_title_system_cmts_item_pin"><![CDATA[Pin]]></string>
+    <string name="_sys_menu_item_title_system_cmts_item_unpin"><![CDATA[Unpin]]></string>
+    <string name="_sys_menu_item_title_system_cmts_item_quote"><![CDATA[Quote]]></string>
+    <string name="_sys_menu_item_title_system_cmts_item_reaction"><![CDATA[Reaction]]></string>
+    <string name="_sys_menu_item_title_system_cmts_item_reply"><![CDATA[Reply]]></string>
+    <string name="_sys_menu_item_title_system_cmts_item_report"><![CDATA[Report]]></string>
+    <string name="_sys_menu_item_title_system_cmts_item_score"><![CDATA[Score]]></string>
+    <string name="_sys_menu_item_title_system_cmts_item_vote"><![CDATA[Plus]]></string>
+    <string name="_sys_menu_item_title_system_cmts_item_more"><![CDATA[More]]></string>
+    <string name="_sys_menu_item_title_system_connections"><![CDATA[Connections]]></string>
+    <string name="_sys_menu_item_title_system_dashboard"><![CDATA[Dashboard]]></string>
+    <string name="_sys_menu_item_title_system_home"><![CDATA[Home]]></string>
+    <string name="_sys_menu_item_title_system_invoices"><![CDATA[Invoices]]></string>
+    <string name="_sys_menu_item_title_system_login"><![CDATA[Log in]]></string>
+    <string name="_sys_menu_item_title_system_logout"><![CDATA[Log out]]></string>
+    <string name="_sys_menu_item_title_system_main_menu"><![CDATA[Main Menu]]></string>
+    <string name="_sys_menu_item_title_system_member_avatar"><![CDATA[Member Avatar]]></string>
+    <string name="_sys_menu_item_title_system_member_followings"><![CDATA[Member Following]]></string>
+    <string name="_sys_menu_item_title_system_member_menu"><![CDATA[Member Menu]]></string>
+    <string name="_sys_menu_item_title_system_more"><![CDATA[More]]></string>
+    <string name="_sys_menu_item_title_system_more_auto"><![CDATA[More]]></string>
+    <string name="_sys_menu_item_title_system_orders"><![CDATA[Orders]]></string>
+    <string name="_sys_menu_item_title_system_powered_by"><![CDATA[Powered By]]></string>
+    <string name="_sys_menu_item_title_system_profile"><![CDATA[Profile]]></string>
+    <string name="_sys_menu_item_title_system_public_menu"><![CDATA[Public Menu]]></string>
+    <string name="_sys_menu_item_title_system_search"><![CDATA[Search]]></string>
+    <string name="_sys_menu_item_title_system_set_acl_level"><![CDATA[Set membership]]></string>
+    <string name="_sys_menu_item_title_system_set_badges"><![CDATA[Set badges]]></string>
+    <string name="_sys_menu_item_title_system_studio"><![CDATA[Studio]]></string>
+    <string name="_sys_menu_item_title_system_subscriptions"><![CDATA[Subscriptions]]></string>
+    <string name="_sys_menu_title_view_actions"><![CDATA[View Actions]]></string>
+    <string name="_sys_menu_set_title_view_actions"><![CDATA[View Actions]]></string>
+    <string name="_sys_menu_item_title_system_va_approve"><![CDATA[Approve]]></string>
+    <string name="_sys_menu_item_title_system_va_comment"><![CDATA[Comment]]></string>
+    <string name="_sys_menu_item_title_system_va_view"><![CDATA[View]]></string>
+    <string name="_sys_menu_item_title_system_va_vote"><![CDATA[Vote (for)]]></string>
+    <string name="_sys_menu_item_title_system_va_score"><![CDATA[Vote (for/against)]]></string>
+    <string name="_sys_menu_item_title_system_va_favorite"><![CDATA[Favorite]]></string>
+    <string name="_sys_menu_item_title_system_va_feature"><![CDATA[Feature]]></string>
+    <string name="_sys_menu_item_title_system_va_reaction"><![CDATA[Reaction]]></string>
+    <string name="_sys_menu_item_title_system_va_rate"><![CDATA[Rate]]></string>
+    <string name="_sys_menu_item_title_system_va_repost"><![CDATA[Repost]]></string>
+    <string name="_sys_menu_item_title_system_va_repost_with_text"><![CDATA[Repost with Text]]></string>
+    <string name="_sys_menu_item_title_system_va_repost_to_context"><![CDATA[Repost to Context]]></string>
+    <string name="_sys_menu_item_title_system_va_report"><![CDATA[Report]]></string>
+    <string name="_sys_menu_item_title_system_va_notes"><![CDATA[Notes]]></string>
+    <string name="_sys_menu_item_title_system_va_audit"><![CDATA[Audit]]></string>
+    <string name="_sys_menu_item_title_system_va_more_auto"><![CDATA[More]]></string>
+    <string name="_sys_menu_item_title_va_approve"><![CDATA[Approve]]></string>
+    <string name="_sys_menu_item_title_va_notes"><![CDATA[Notes]]></string>
+    <string name="_sys_menu_item_title_va_audit"><![CDATA[Audit]]></string>
+    <string name="_sys_menu_item_title_va_more_auto"><![CDATA[More]]></string>
+    <string name="_sys_menu_item_title_va_more_auto_empty"><![CDATA[]]></string>
+    <string name="_sys_menu_item_title_social_sharing"><![CDATA[Share]]></string>
+    <string name="_sys_menu_item_title_system_social_sharing"><![CDATA[Share]]></string>
+    <string name="_sys_menu_item_title_system_social_sharing_facebook"><![CDATA[Share in Facebook]]></string>
+    <string name="_sys_menu_item_title_system_social_sharing_twitter"><![CDATA[Share in Twitter]]></string>
+    <string name="_sys_menu_item_title_system_social_sharing_pinterest"><![CDATA[Share in Pinterest]]></string>
+    <string name="_sys_menu_item_title_system_sm_in_reply_to"><![CDATA[In reply to]]></string>
+    <string name="_sys_menu_item_title_system_sm_author"><![CDATA[Author]]></string>
+    <string name="_sys_menu_item_title_system_sm_date"><![CDATA[Date]]></string>
+    <string name="_sys_menu_item_title_system_sm_category"><![CDATA[Category]]></string>
+    <string name="_sys_menu_item_title_system_sm_tags"><![CDATA[Tags]]></string>
+    <string name="_sys_menu_item_title_system_sm_views"><![CDATA[Views]]></string>
+    <string name="_sys_menu_item_title_system_sm_votes"><![CDATA[Votes]]></string>
+    <string name="_sys_menu_item_title_system_sm_reactions"><![CDATA[Reactions]]></string>
+    <string name="_sys_menu_item_title_system_sm_scores"><![CDATA[Votes (for/against)]]></string>
+    <string name="_sys_menu_item_title_system_sm_rating"><![CDATA[Rating]]></string>
+    <string name="_sys_menu_item_title_system_sm_comments"><![CDATA[Comments]]></string>
+    <string name="_sys_menu_item_title_system_sm_actions"><![CDATA[Actions]]></string>
+    <string name="_sys_menu_item_title_system_sm_befriend"><![CDATA[Add Friend]]></string>
+    <string name="_sys_menu_item_title_system_sm_unfriend"><![CDATA[Remove Friend]]></string>
+    <string name="_sys_menu_item_title_system_sm_join_paid"><![CDATA[Pay & Join]]></string>
+    <string name="_sys_menu_item_title_system_sm_join"><![CDATA[Join]]></string>
+    <string name="_sys_menu_item_title_system_sm_leave"><![CDATA[Leave]]></string>
+    <string name="_sys_menu_item_title_system_sm_nl"><![CDATA[New Line]]></string>
+    <string name="_sys_menu_item_title_system_sm_subscribe"><![CDATA[Follow]]></string>
+    <string name="_sys_menu_item_title_system_sm_unsubscribe"><![CDATA[Unfollow]]></string>
+    <string name="_sys_menu_item_title_system_sm_friends"><![CDATA[Friends]]></string>
+    <string name="_sys_menu_item_title_system_sm_friends_mutual"><![CDATA[Mutual Friends]]></string>
+    <string name="_sys_menu_item_title_system_sm_members"><![CDATA[Members]]></string>
+    <string name="_sys_menu_item_title_system_sm_membership"><![CDATA[Membership]]></string>
+    <string name="_sys_menu_item_title_system_sm_subscribers"><![CDATA[Followers]]></string>
+    <string name="_sys_menu_item_title_system_sm_subscriptions"><![CDATA[Following]]></string>
+    <string name="_sys_menu_item_title_system_sm_relations"><![CDATA[Relations]]></string>
+    <string name="_sys_menu_item_title_system_sm_country"><![CDATA[Country]]></string>
+    <string name="_sys_menu_item_title_system_sm_country_city"><![CDATA[Country and City]]></string>
+    <string name="_sys_menu_item_title_system_sm_ignore"><![CDATA[Ignore Recommendation]]></string>
+    <string name="_sys_menu_item_title_system_sm_ignore_befriend"><![CDATA[Ignore Recommendation: Befriend]]></string>
+    <string name="_sys_menu_item_title_system_sm_ignore_subscribe"><![CDATA[Ignore Recommendation: Subscribe]]></string>
+    <string name="_sys_menu_item_title_system_vm_membership"><![CDATA[Membership]]></string>
+    <string name="_sys_menu_item_title_system_vm_badges"><![CDATA[Badges]]></string>
+    
+    <string name="_sys_menu_set_title_account_dashboard"><![CDATA[Account Dashboard]]></string>
+    <string name="_sys_menu_set_title_account_dashboard_manage_tools"><![CDATA[Account Dashboard Manage Tools]]></string>
+    <string name="_sys_menu_set_title_account_settings"><![CDATA[Account Settings]]></string>
+    <string name="_sys_menu_set_title_account_popup"><![CDATA[Account Popup]]></string>
+    <string name="_sys_menu_set_title_account_notifications"><![CDATA[Account Notifications]]></string>
+    <string name="_sys_menu_set_title_add_content"><![CDATA[Add Content]]></string>
+    <string name="_sys_menu_set_title_create_post"><![CDATA[Create Post]]></string>
+    <string name="_sys_menu_set_title_dashboard_content_manage"><![CDATA[Content Manage]]></string>
+    <string name="_sys_menu_set_title_dashboard_reports_manage"><![CDATA[Reports Manage]]></string>
+    <string name="_sys_menu_set_title_add_profile"><![CDATA[Add Profile]]></string>
+    <string name="_sys_menu_set_title_cmts_item_actions"><![CDATA[Comment Actions]]></string>
+    <string name="_sys_menu_set_title_cmts_item_counters"><![CDATA[Comment Сounters]]></string>
+    <string name="_sys_menu_set_title_cmts_item_manage"><![CDATA[Manage Comment]]></string>
+    <string name="_sys_menu_set_title_cmts_item_meta"><![CDATA[Comment Meta Info]]></string>
+    <string name="_sys_menu_set_title_switch_language"><![CDATA[Switch Language]]></string>
+    <string name="_sys_menu_set_title_switch_template"><![CDATA[Switch Template]]></string>
+    <string name="_sys_menu_set_title_sys_social_sharing"><![CDATA[Social Sharing]]></string>
+    <string name="_sys_menu_set_title_footer"><![CDATA[Footer]]></string>
+    <string name="_sys_menu_set_title_profile_create_links"><![CDATA[Create Profile Links]]></string>
+    <string name="_sys_menu_set_title_profile_followings"><![CDATA[Followed Contexts]]></string>
+    <string name="_sys_menu_set_title_profile_stats"><![CDATA[Profile Stats]]></string>
+    <string name="_sys_menu_set_title_site"><![CDATA[Site]]></string>
+    <string name="_sys_menu_set_title_application"><![CDATA[Application]]></string>
+    <string name="_sys_menu_set_title_panel"><![CDATA[Panel]]></string>
+    <string name="_sys_menu_set_title_homepage"><![CDATA[Content modules]]></string>
+    <string name="_sys_menu_set_title_toolbar_member"><![CDATA[Toolbar Member]]></string>
+    <string name="_sys_menu_set_title_toolbar_site"><![CDATA[Toolbar Site]]></string>
+    <string name="_sys_menu_set_title_snippet_meta"><![CDATA[Snippet Meta Info]]></string>
+    <string name="_sys_menu_template_title_add_content"><![CDATA[Add Content Menu]]></string>
+    <string name="_sys_menu_template_title_block_submenu_hor"><![CDATA[Horizontal Block Submenu]]></string>
+    <string name="_sys_menu_template_title_block_submenu_ver"><![CDATA[Vertical Block Submenu]]></string>
+    <string name="_sys_menu_template_title_buttons_hor"><![CDATA[Horizontal Buttons]]></string>
+    <string name="_sys_menu_template_title_buttons_icon_hor"><![CDATA[Horizontal Buttons (icons only)]]></string>
+    <string name="_sys_menu_template_title_buttons_ver"><![CDATA[Vertical Buttons]]></string>
+    <string name="_sys_menu_template_title_floating_blocks"><![CDATA[Floating Blocks]]></string>
+    <string name="_sys_menu_template_title_floating_blocks_wide"><![CDATA[Wide Floating Blocks with Notifications]]></string>
+    <string name="_sys_menu_template_title_floating_blocks_big"><![CDATA[Floating Blocks Big]]></string>
+    <string name="_sys_menu_template_title_floating_blocks_dash"><![CDATA[Floating Blocks with icons & captions]]></string>
+    <string name="_sys_menu_template_title_footer"><![CDATA[Footer Links]]></string>
+    <string name="_sys_menu_template_title_hor"><![CDATA[Horizontal Links]]></string>
+    <string name="_sys_menu_template_title_inline"><![CDATA[Inline]]></string>
+    <string name="_sys_menu_template_title_inline_sbtn"><![CDATA[Inline ('special' buttons)]]></string>
+    <string name="_sys_menu_template_title_interactive"><![CDATA[Interactive Horizontal Links]]></string>
+    <string name="_sys_menu_template_title_interactive_vertical"><![CDATA[Interactive Vertical Links]]></string>
+    <string name="_sys_menu_template_title_empty"><![CDATA[Empty Menu]]></string>
+    <string name="_sys_menu_template_title_main"><![CDATA[Site Navigation Menu]]></string>
+    <string name="_sys_menu_template_title_main_submenu"><![CDATA[Site Navigation Submenu]]></string>
+    <string name="_sys_menu_template_title_main_submenu_more_auto"><![CDATA[Site Navigation Submenu (with Auto More)]]></string>
+    <string name="_sys_menu_template_title_panel"><![CDATA[Site Panel Menu]]></string>
+    <string name="_sys_menu_template_title_main_in_panel"><![CDATA[Site Navigation Menu in Panel]]></string>
+    <string name="_sys_menu_template_title_multilevel"><![CDATA[Multilevel Menu]]></string>
+    <string name="_sys_menu_template_title_toolbar"><![CDATA[Toolbar Buttons]]></string>
+    <string name="_sys_menu_template_title_toolbar_left"><![CDATA[Toolbar Buttons (left)]]></string>
+    <string name="_sys_menu_template_title_toolbar_right"><![CDATA[Toolbar Buttons (right)]]></string>
+    <string name="_sys_menu_template_title_ver"><![CDATA[Vertical Links]]></string>
+    <string name="_sys_menu_template_title_ver_lite"><![CDATA[Vertical Links (lite)]]></string>
+    <string name="_sys_menu_template_title_account_notifications"><![CDATA[Account notifications]]></string>
+    <string name="_sys_menu_template_title_account_popup"><![CDATA[Account popup]]></string>
+    <string name="_sys_menu_template_title_custom_hor"><![CDATA[Horizontal menu with custom items]]></string>
+    <string name="_sys_menu_template_title_custom_ver"><![CDATA[Vertical menu with custom items]]></string>
+    <string name="_sys_menu_template_title_profile_followings"><![CDATA[Profile Following Menu]]></string>
+    <string name="_sys_menu_template_title_vertical_more_less"><![CDATA[Vertical menu with more/less]]></string>
+    <string name="_sys_menu_template_title_profile_stats"><![CDATA[Profile Stats Menu]]></string>
+    <string name="_sys_menu_title_account_dashboard"><![CDATA[Account Dashboard Menu]]></string>
+    <string name="_sys_menu_title_public_account_dashboard"><![CDATA[Dashboard]]></string>
+    <string name="_sys_menu_title_account_dashboard_manage_tools"><![CDATA[Account Dashboard Manage Tools Menu]]></string>
+    <string name="_sys_menu_title_account_notifications"><![CDATA[Account Notifications]]></string>
+    <string name="_sys_menu_title_account_popup"><![CDATA[Account Popup]]></string>
+    <string name="_sys_menu_title_account_settings"><![CDATA[Account Settings Menu]]></string>
+    <string name="_sys_menu_title_public_account_settings"><![CDATA[Settings]]></string>
+    <string name="_sys_menu_title_add_content"><![CDATA[Add Content Menu]]></string>
+    <string name="_sys_menu_title_add_profile"><![CDATA[Add Profile Menu]]></string>
+    <string name="_sys_menu_title_add_profile_vertical"><![CDATA[Add Profile Menu (vertical)]]></string>
+    <string name="_sys_menu_title_cmts_item_actions"><![CDATA[Comment Actions]]></string>
+    <string name="_sys_menu_title_cmts_item_counters"><![CDATA[Comment Counters]]></string>
+    <string name="_sys_menu_title_cmts_item_manage"><![CDATA[Manage Comment]]></string>
+    <string name="_sys_menu_title_cmts_item_meta"><![CDATA[Comment Meta Info]]></string>
+    <string name="_sys_menu_title_footer"><![CDATA[Footer Links]]></string>
+    <string name="_sys_menu_title_main"><![CDATA[Site Navigation]]></string>
+    <string name="_sys_menu_title_main_in_panel"><![CDATA[Site Navigation in Panel]]></string>
+    <string name="_sys_menu_title_application"><![CDATA[Application Navigation]]></string>
+    <string name="_sys_menu_title_homepage"><![CDATA[Homepage Menu]]></string>
+    <string name="_sys_menu_title_homepage_submenu"><![CDATA[Homepage Submenu]]></string>
+    <string name="_sys_menu_title_public_homepage_submenu"><![CDATA[Explore]]></string>
+    <string name="_sys_menu_set_title_homepage_submenu"><![CDATA[Homepage Submenu]]></string>
+    <string name="_sys_menu_item_title_system_explore"><![CDATA[Explore]]></string>
+    <string name="_sys_menu_item_title_explore"><![CDATA[Explore]]></string>
+    <string name="_sys_menu_item_title_system_updates"><![CDATA[Updates]]></string>
+    <string name="_sys_menu_item_title_updates"><![CDATA[Updates]]></string>
+    <string name="_sys_menu_item_title_system_trends"><![CDATA[Trends]]></string>
+    <string name="_sys_menu_item_title_trends"><![CDATA[Trends]]></string>
+    <string name="_sys_menu_title_profiles_create"><![CDATA[Create Profiles]]></string>
+    <string name="_sys_menu_title_profile_followings"><![CDATA[Profile Following]]></string>
+    <string name="_sys_menu_title_profile_stats"><![CDATA[Profile Stats]]></string>
+    <string name="_sys_menu_title_tags_cloud"><![CDATA[Tags Cloud]]></string>
+    <string name="_sys_menu_title_rss"><![CDATA[RSS]]></string>
+    <string name="_sys_menu_title_set_acl_level"><![CDATA[ACL Levels]]></string>
+    <string name="_sys_menu_title_set_badges"><![CDATA[Badges]]></string>
+    <string name="_sys_menu_title_social_sharing"><![CDATA[Social Sharing]]></string>
+    <string name="_sys_menu_title_create_post"><![CDATA[Create Post Menu]]></string>
+  
+    <string name="_sys_menu_title_dashboard_content_manage"><![CDATA[Dashboard content manage]]></string>
+    <string name="_sys_menu_title_dashboard_reports_manage"><![CDATA[Dashboard reports manage]]></string>
+  
+    <string name="_sys_menu_title_add_relation"><![CDATA[Add Relationship Menu]]></string>
+    <string name="_sys_menu_title_manage"><![CDATA[Manage Submenu]]></string>
+    <string name="_sys_menu_title_panel"><![CDATA[Site Panel]]></string>
+    <string name="_sys_menu_title_submenu"><![CDATA[Site Submenu]]></string>
+    <string name="_sys_menu_title_toolbar_member"><![CDATA[Member Toolbar]]></string>
+    <string name="_sys_menu_title_toolbar_site"><![CDATA[Site Toolbar]]></string>
+    <string name="_sys_menu_title_switch_language_popup"><![CDATA[Language Switcher (popup)]]></string>
+    <string name="_sys_menu_title_switch_language_inline"><![CDATA[Language Switch (inline)]]></string>
+    <string name="_sys_menu_title_switch_template"><![CDATA[Switch Template]]></string>
+    <string name="_sys_menu_title_snippet_meta"><![CDATA[Snippet Meta Info]]></string>
+    <string name="_sys_menu_title_vote_reactions_do"><![CDATA[Do Reaction Vote]]></string>
+    <string name="_sys_menu_title_wiki"><![CDATA[Wiki]]></string>
+    <string name="_sys_menu_set_title_sys_wiki"><![CDATA[Wiki]]></string>
+    <string name="_sys_menu_item_title_wiki_edit"><![CDATA[Edit]]></string>
+    <string name="_sys_menu_item_title_wiki_delete_version"><![CDATA[Delete Version]]></string>
+    <string name="_sys_menu_item_title_wiki_delete_block"><![CDATA[Delete Block]]></string>
+    <string name="_sys_menu_item_title_wiki_translate"><![CDATA[Translate]]></string>
+    <string name="_sys_menu_item_title_wiki_history"><![CDATA[History]]></string>
+    <string name="_sys_menu_title_favorite_list"><![CDATA[Favorite list]]></string>
+    <string name="_sys_menu_set_title_sys_favorite_list"><![CDATA[Favorite list]]></string>
+    <string name="_sys_menu_item_title_favorite_list_edit"><![CDATA[Edit]]></string>
+    <string name="_sys_menu_item_title_wiki_favorite_list_delete"><![CDATA[Delete]]></string>        
+    <string name="_sys_menu_dashboard_manage_tools_addon_counter1_caption_default"><![CDATA[hidden]]></string>
+    <string name="_sys_menu_dashboard_manage_tools_addon_counter1_caption_profile_default"><![CDATA[unapproved]]></string>
+    <string name="_sys_menu_dashboard_manage_tools_addon_counter2_caption_default"><![CDATA[reported]]></string>
+    <string name="_sys_menu_title_studio_account_popup"><![CDATA[Account Popup (Studio)]]></string>
+    <string name="_sys_menu_set_title_studio_account_popup"><![CDATA[Account Popup (Studio)]]></string>
+    <string name="_sys_menu_item_title_system_sa_account"><![CDATA[Account]]></string>
+    <string name="_sys_menu_item_title_sa_account"><![CDATA[{member_display_name}]]></string>
+    <string name="_sys_menu_item_title_system_sa_site"><![CDATA[Go To Site]]></string>
+    <string name="_sys_menu_item_title_sa_site"><![CDATA[Go To Site]]></string>
+    <string name="_sys_menu_item_title_system_sa_edit"><![CDATA[Manage Apps]]></string>
+    <string name="_sys_menu_item_title_sa_edit"><![CDATA[Manage Apps]]></string>
+    <string name="_sys_menu_item_title_system_sa_language"><![CDATA[Language]]></string>
+    <string name="_sys_menu_item_title_sa_language"><![CDATA[Language]]></string>
+    <string name="_sys_menu_item_title_sa_scheme_auto"><![CDATA[System]]></string>
+    <string name="_sys_menu_item_title_sa_scheme_light"><![CDATA[Light Mode]]></string>
+    <string name="_sys_menu_item_title_sa_scheme_dark"><![CDATA[Dark Mode]]></string>
+    <string name="_sys_menu_item_title_system_sa_logout"><![CDATA[Sign out]]></string>
+    <string name="_sys_menu_item_title_sa_logout"><![CDATA[Sign out]]></string>
+    <string name="_sys_menu_item_title_inherited"><![CDATA[Inherited]]></string>
+    <string name="_sys_menu_item_title_disabled"><![CDATA[Disabled]]></string>
+    <string name="_sys_menu_title_con_submenu"><![CDATA[Connections]]></string>
+    <string name="_sys_menu_title_public_con_submenu"><![CDATA[Connections]]></string>
+    <string name="_sys_menu_set_title_con_submenu"><![CDATA[Connections]]></string>
+    <string name="_sys_menu_item_title_con_friends"><![CDATA[All Friends]]></string>
+    <string name="_sys_menu_item_title_con_friend_requests"><![CDATA[Friend Requests]]></string>
+    <string name="_sys_menu_item_title_con_friend_requested"><![CDATA[Sent Requests]]></string>
+    <string name="_sys_menu_item_title_con_following"><![CDATA[Following]]></string>
+    <string name="_sys_menu_item_title_con_followers"><![CDATA[Followers]]></string>
+    <string name="_sys_menu_item_title_recom_friends"><![CDATA[Suggestions]]></string>
+    <string name="_sys_menu_item_title_recom_subscriptions"><![CDATA[Who to follow]]></string>    
+    <string name="_sys_menu_title_ntfs_submenu"><![CDATA[Notifications]]></string>
+    <string name="_sys_menu_title_public_ntfs_submenu"><![CDATA[Notifications]]></string>
+    <string name="_sys_menu_set_title_ntfs_submenu"><![CDATA[Notifications]]></string>
+    <string name="_sys_menu_item_title_system_ntfs_context_invitations"><![CDATA[Notifications: Context Invitations]]></string>
+    <string name="_sys_menu_item_title_ntfs_context_invitations"><![CDATA[Invitations]]></string>
+    <string name="_sys_metatags_mention_added"><![CDATA[<b class="bx-ntfs-content-profile">{owner_name}</b> mentioned <b class="bx-ntfs-content-entry">{entry_caption}</b>]]></string>
+    <string name="_sys_mobile_friends"><![CDATA[Friends]]></string>
+    <string name="_sys_mobile_info"><![CDATA[Info]]></string>
+    <string name="_sys_mobile_mail"><![CDATA[Messages]]></string>
+    <string name="_sys_mobile_profile_contact"><![CDATA[Contact]]></string>
+    <string name="_sys_mobile_profile_friends"><![CDATA[Friends]]></string>
+    <string name="_sys_mobile_profile_info"><![CDATA[Profile Info]]></string>
+    <string name="_sys_mobile_search"><![CDATA[Search]]></string>
+    <string name="_sys_mobile_status"><![CDATA[Status]]></string>
+    <string name="_sys_name"><![CDATA[Name]]></string>
+    <string name="_sys_added"><![CDATA[Added]]></string>
+    <string name="_sys_next"><![CDATA[Next]]></string>
+    <string name="_sys_notification_account"><![CDATA[Accounts created in the last 24 hours:]]></string>
+    <string name="_sys_no_menu"><![CDATA[No menu]]></string>
+    <string name="_sys_no_async"><![CDATA[Asynchronous mode disabled]]></string>
+    <string name="_sys_not_available"><![CDATA[n/a]]></string>
+    <string name="_sys_not_specified"><![CDATA[Not Specified]]></string>
+    <string name="_sys_on"><![CDATA[on]]></string>
+    <string name="_sys_off"><![CDATA[off]]></string>
+    <string name="_sys_pages"><![CDATA[Pages]]></string>
+    <string name="_sys_page_content_ph_loading_indicator"><![CDATA[With loading indicator]]></string>
+    <string name="_sys_page_content_ph_text"><![CDATA[With text placeholder]]></string>
+    <string name="_sys_page_content_ph_image"><![CDATA[With image placeholder]]></string>
+    <string name="_sys_page_content_ph_create_post"><![CDATA[With create post placeholder]]></string>
+    <string name="_sys_page_content_ph_profile_units"><![CDATA[With profile units placeholder]]></string>
+    <string name="_sys_page_content_ph_text_units_list"><![CDATA[With text units list placeholder]]></string>
+    <string name="_sys_page_content_ph_text_units_gallery"><![CDATA[With text units gallery placeholder]]></string>
+    <string name="_sys_page_block_title_about"><![CDATA[About]]></string>
+    <string name="_sys_page_block_title_account_profile_create"><![CDATA[Create a profile...]]></string>
+    <string name="_sys_page_block_title_account_profile_switcher"><![CDATA[Use site as ...]]></string>
+    <string name="_sys_page_block_title_account_settings_delete"><![CDATA[Delete Account]]></string>
+    <string name="_sys_page_block_title_account_settings_email"><![CDATA[Email Settings]]></string>
+    <string name="_sys_page_block_title_account_settings_info"><![CDATA[Edit Account]]></string>
+    <string name="_sys_page_block_title_account_settings_menu"><![CDATA[Account Settings]]></string>
+    <string name="_sys_page_block_title_account_settings_pwd"><![CDATA[Change Password]]></string>
+    <string name="_sys_page_block_title_profile_settings_cfilter"><![CDATA[Content Filter]]></string>
+    <string name="_sys_page_block_title_add_content"><![CDATA[Add Content]]></string>
+    <string name="_sys_page_block_title_chart_growth"><![CDATA[Growth Charts]]></string>
+    <string name="_sys_page_block_title_chart_stats"><![CDATA[Content]]></string>
+    <string name="_sys_page_block_title_cmts_administration"><![CDATA[Manage Comments]]></string>
+    <string name="_sys_page_block_title_audit_administration"><![CDATA[Audit]]></string>
+    <string name="_sys_page_block_title_confirm_email"><![CDATA[Email Confirmation]]></string>
+    <string name="_sys_page_block_title_confirm_phone"><![CDATA[Phone Confirmation]]></string>
+    <string name="_sys_page_block_title_create_account"><![CDATA[Sign up]]></string>
+    <string name="_sys_page_block_title_sys_author"><![CDATA[Author]]></string>
+    <string name="_sys_page_block_title_author"><![CDATA[Author]]></string>
+    <string name="_sys_page_block_title_sys_ask_aqssistant"><![CDATA[Ask AI]]></string>
+    <string name="_sys_page_block_title_ask_aqssistant"><![CDATA[Ask AI]]></string>
+    <string name="_sys_page_block_title_con_friends"><![CDATA[Friends]]></string>
+    <string name="_sys_page_block_title_con_friend_requests"><![CDATA[Friend Requests]]></string>
+    <string name="_sys_page_block_title_con_friend_requested"><![CDATA[Sent Friend Requests]]></string>
+    <string name="_sys_page_block_title_con_following"><![CDATA[Following]]></string>
+    <string name="_sys_page_block_title_con_followers"><![CDATA[Followers]]></string>
+    <string name="_sys_page_block_title_sys_recom_friends"><![CDATA[Recommended Friends]]></string>
+    <string name="_sys_page_block_title_recom_friends"><![CDATA[Friend Suggestions]]></string>
+    <string name="_sys_page_block_title_sys_recom_subscriptions"><![CDATA[Recommended Subscriptions]]></string>
+    <string name="_sys_page_block_title_recom_subscriptions"><![CDATA[Who to follow]]></string>
+    <string name="_sys_page_block_title_ntfs_context_invitations"><![CDATA[Invitations]]></string>
+    <string name="_sys_page_block_title_sys_invitations"><![CDATA[Invitations]]></string>
+    <string name="_sys_page_block_title_invitations"><![CDATA[Invitations]]></string>
+    <string name="_sys_page_block_title_sys_create_post"><![CDATA[Create Post]]></string>
+    <string name="_sys_page_block_title_create_post"><![CDATA[Add new...]]></string>
+    <string name="_sys_page_block_title_sys_create_post_context"><![CDATA[Create Post (Context)]]></string>
+    <string name="_sys_page_block_title_create_post_context"><![CDATA[Post to {display_name}]]></string>
+    <string name="_sys_page_block_title_sys_create_post_public"><![CDATA[Create Post (Public)]]></string>
+    <string name="_sys_page_block_title_create_post_public"><![CDATA[Add new...]]></string>
+    <string name="_sys_page_block_title_dashboard"><![CDATA[Dashboard]]></string>
+    <string name="_sys_page_block_title_dashboard_api"><![CDATA[Dashboard (for App only)]]></string>
+    <string name="_sys_page_block_title_homepage_menu"><![CDATA[Content modules menu]]></string>
+    <string name="_sys_page_block_title_homepage_splash"><![CDATA[Splash]]></string>
+    <string name="_sys_page_block_title_forgot_password"><![CDATA[Forgot Password]]></string>
+    <string name="_sys_page_block_title_search_keyword_form"><![CDATA[Search Form]]></string>
+    <string name="_sys_page_block_title_search_keyword_result"><![CDATA[Search Result]]></string>
+    <string name="_sys_page_block_title_membership_stats"><![CDATA[Membership Limits]]></string>
+    <string name="_sys_page_block_system_title_login"><![CDATA[Log in with Sign up link]]></string>
+    <string name="_sys_page_block_system_title_login_step2"><![CDATA[Log in - step2]]></string>
+    <string name="_sys_page_block_system_title_login_step3"><![CDATA[Log in - step3]]></string>
+    <string name="_sys_page_block_system_title_login_only"><![CDATA[Log in]]></string>
+    <string name="_sys_page_block_title_dashboard_content"><![CDATA[Dashboard - Content]]></string>
+    <string name="_sys_page_block_title_dashboard_audit"><![CDATA[Dashboard - Audit]]></string>
+    <string name="_sys_page_block_title_dashboard_reports"><![CDATA[Dashboard - Reports]]></string>
+    <string name="_sys_page_block_title_system_cmts_view"><![CDATA[View Comment]]></string>
+    <string name="_sys_page_block_title_system_cmts_view_author"><![CDATA[Comment Author]]></string>
+    <string name="_sys_page_block_title_system_cmts_view_content"><![CDATA[Commented Content]]></string>
+    <string name="_sys_page_block_title_system_cmts_administration"><![CDATA[Manage Comments]]></string>
+    <string name="_sys_page_block_title_system_audit_administration"><![CDATA[Audit]]></string>
+    <string name="_sys_page_block_title_logout"><![CDATA[Log out]]></string>
+    <string name="_sys_page_block_title_login"><![CDATA[Log in]]></string>
+    <string name="_sys_page_block_title_login_step2"><![CDATA[Log in - step 2]]></string>
+    <string name="_sys_page_block_title_login_step3"><![CDATA[Log in - step 3]]></string>
+    <string name="_sys_page_block_title_manage_tools"><![CDATA[Manage]]></string>
+    <string name="_sys_page_block_title_privacy"><![CDATA[Privacy Policy]]></string>
+    <string name="_sys_page_block_title_profile_stats"><![CDATA[Profile stats]]></string>
+    <string name="_sys_page_block_title_profile_avatar"><![CDATA[Profile avatar]]></string>
+    <string name="_sys_page_block_title_profile_menu"><![CDATA[Profile menu]]></string>
+    <string name="_sys_page_block_title_profile_followings"><![CDATA[Profile followings]]></string>
+    <string name="_sys_page_block_title_profile_membership"><![CDATA[Membership]]></string>
+    <string name="_sys_page_block_title_unsubscribe_news"><![CDATA[Unsubscribe From Site Newsletters]]></string>
+    <string name="_sys_page_block_title_unsubscribe_notifications"><![CDATA[Unsubscribe From Site Notifications]]></string>
+    <string name="_sys_page_block_title_std_dash_version"><![CDATA[Version]]></string>
+    <string name="_sys_page_block_title_std_dash_space"><![CDATA[Space Usage]]></string>
+    <string name="_sys_page_block_title_std_dash_host_tools"><![CDATA[Host Tools]]></string>
+    <string name="_sys_page_block_title_std_dash_cache"><![CDATA[Cache]]></string>
+    <string name="_sys_page_block_title_std_dash_queues"><![CDATA[Queues]]></string>
+    <string name="_sys_page_block_title_terms"><![CDATA[Terms of Service]]></string>
+    <string name="_sys_page_block_title_sys_std_site_submenu"><![CDATA[Site submenu]]></string>
+    <string name="_sys_page_block_title_std_site_submenu"><![CDATA[Site submenu]]></string>
+    <string name="_sys_page_block_title_wiki_pages_list"><![CDATA[Pages List]]></string>
+    <string name="_sys_page_block_title_wiki_page_contents"><![CDATA[Page Contents]]></string>
+
+    <string name="_sys_page_description_hashtag"><![CDATA[Hashtag "{0}" search results]]></string>
+    <string name="_sys_page_description_hashtag_in_section"><![CDATA[Hashtag "{0}" search results in "{1}" section]]></string>
+    <string name="_sys_page_description_keyword"><![CDATA[Keyword "{0}" search results]]></string>
+    <string name="_sys_page_description_keyword_in_section"><![CDATA[Keyword "{0}" search results in "{1}" section]]></string>
+    <string name="_sys_page_description_category"><![CDATA[Category "{0}" search results]]></string>
+    <string name="_sys_page_description_category_in_section"><![CDATA[Category "{0}" search results in "{1}" section]]></string>
+    <string name="_sys_page_description_location"><![CDATA[Location "{0}" search results]]></string>
+    <string name="_sys_page_description_location_in_section"><![CDATA[Location "{0}" search results in "{1}" section]]></string>
+    <string name="_sys_page_description_mention"><![CDATA[Mentions of "{0}" search results]]></string>
+    <string name="_sys_page_description_mention_in_section"><![CDATA[Mentions of "{0}" in "{1}" section search results]]></string>
+
+    <string name="_sys_page_lang_block_about"><![CDATA[This site is powered by UNA. The rest is a mystery.]]></string>
+    <string name="_sys_page_lang_block_terms"><![CDATA[Our terms of use.]]></string>
+    <string name="_sys_page_lang_block_privacy"><![CDATA[Our privacy policy.]]></string>
+    <string name="_sys_page_title_about"><![CDATA[About]]></string>
+    <string name="_sys_page_title_account_profile_switcher"><![CDATA[My Profiles]]></string>
+    <string name="_sys_page_title_account_settings_delete"><![CDATA[Delete Account]]></string>
+    <string name="_sys_page_title_account_settings_email"><![CDATA[Email Settings]]></string>
+    <string name="_sys_page_title_account_settings_info"><![CDATA[Edit Account]]></string>
+    <string name="_sys_page_title_account_settings_pwd"><![CDATA[Change Password]]></string>
+    <string name="_sys_page_title_profile_settings_cfilter"><![CDATA[Content Filter]]></string>
+    <string name="_sys_page_title_add_content"><![CDATA[Add Content]]></string>
+    <string name="_sys_page_title_cmts_administration"><![CDATA[Manage Comments]]></string>
+    <string name="_sys_page_title_audit_administration"><![CDATA[Audit]]></string>
+    <string name="_sys_page_title_confirm_email"><![CDATA[Email Confirmation]]></string>
+    <string name="_sys_page_title_confirm_phone"><![CDATA[Phone Confirmation]]></string>
+    <string name="_sys_page_title_create_account"><![CDATA[Sign up]]></string>
+    <string name="_sys_page_title_dashboard"><![CDATA[Dashboard]]></string>
+    <string name="_sys_page_title_forgot_password"><![CDATA[Forgot Password]]></string>
+    <string name="_sys_page_title_forgot_password_reset"><![CDATA[Choose New Password]]></string>
+    <string name="_sys_page_title_home"><![CDATA[{site_title} :: Homepage]]></string>
+    <string name="_sys_page_title_logout"><![CDATA[Log out]]></string>
+    <string name="_sys_page_title_login"><![CDATA[Log in]]></string>
+    <string name="_sys_page_title_login_step2"><![CDATA[Log in - step 2]]></string>
+    <string name="_sys_page_title_login_step3"><![CDATA[Log in - step 3]]></string>
+    <string name="_sys_page_title_privacy"><![CDATA[Privacy Policy]]></string>
+    <string name="_sys_page_title_explore"><![CDATA[Explore]]></string>
+    <string name="_sys_page_title_updates"><![CDATA[Updates]]></string>
+    <string name="_sys_page_title_trends"><![CDATA[Trends]]></string>
+    <string name="_sys_page_title_terms"><![CDATA[Terms of Service]]></string>
+    <string name="_sys_page_title_system_about"><![CDATA[Info - About]]></string>
+    <string name="_sys_page_title_system_account_profile_switcher"><![CDATA[Account - My Profiles]]></string>
+    <string name="_sys_page_title_system_account_settings_delete"><![CDATA[Account - Delete]]></string>
+    <string name="_sys_page_title_system_account_settings_email"><![CDATA[Account - Email Settings]]></string>
+    <string name="_sys_page_title_system_account_settings_info"><![CDATA[Account - Edit]]></string>
+    <string name="_sys_page_title_system_account_settings_pwd"><![CDATA[Account - Change Password]]></string>
+    <string name="_sys_page_title_system_profile_settings_cfilter"><![CDATA[Content Filter]]></string>
+    <string name="_sys_page_title_system_add_content"><![CDATA[Add Content]]></string>
+    <string name="_sys_page_title_system_cmts_view"><![CDATA[Comments - View Comment]]></string>
+    <string name="_sys_page_title_system_cmts_administration"><![CDATA[Comments - Manage]]></string>
+    <string name="_sys_page_title_system_audit_administration"><![CDATA[Audit]]></string>
+    <string name="_sys_page_title_system_confirm_email"><![CDATA[Account Create - Email Confirmation]]></string>
+    <string name="_sys_page_title_system_confirm_phone"><![CDATA[Account Create - Phone Confirmation]]></string>
+    <string name="_sys_page_title_system_create_account"><![CDATA[Account - Create]]></string>
+    <string name="_sys_page_title_system_dashboard"><![CDATA[Dashboard]]></string>
+    <string name="_sys_page_title_system_dashboard_content"><![CDATA[Dashboard - Content]]></string>
+    <string name="_sys_page_title_dashboard_content"><![CDATA[Content]]></string>
+    <string name="_sys_page_title_system_dashboard_reports"><![CDATA[Dashboard - Reports]]></string>
+    <string name="_sys_page_title_dashboard_reports"><![CDATA[Reports]]></string>
+    <string name="_sys_page_title_system_dashboard_audit"><![CDATA[Dashboard - Audit]]></string>
+    <string name="_sys_page_title_dashboard_audit"><![CDATA[Audit]]></string>
+    <string name="_sys_page_title_system_forgot_password"><![CDATA[Log in - Forgot Password]]></string>
+    <string name="_sys_page_title_system_search_keyword"><![CDATA[Search by Keyword]]></string>
+    <string name="_sys_page_title_search_keyword"><![CDATA[Search by Keyword]]></string>
+    <string name="_sys_page_title_system_home"><![CDATA[Homepage]]></string>
+    <string name="_sys_page_title_system_login"><![CDATA[Log in - Step 1]]></string>
+    <string name="_sys_page_title_system_login_step2"><![CDATA[Log in - Step 2]]></string>
+    <string name="_sys_page_title_system_login_step3"><![CDATA[Log in - Step 3]]></string>
+    <string name="_sys_page_title_system_privacy"><![CDATA[Info - Privacy Policy]]></string>
+    <string name="_sys_page_title_sys_explore"><![CDATA[Info - Explore]]></string>
+    <string name="_sys_page_title_sys_updates"><![CDATA[Info - Updates]]></string>
+    <string name="_sys_page_title_sys_trends"><![CDATA[Info - Trends]]></string>
+    <string name="_sys_page_title_system_terms"><![CDATA[Info - Terms of Service]]></string>
+    <string name="_sys_page_title_system_unsubscribe_news"><![CDATA[Unsubscribe From Newsletters]]></string>
+    <string name="_sys_page_title_system_unsubscribe_notifications"><![CDATA[Unsubscribe From Notifications]]></string>
+    <string name="_sys_page_title_system_studio_dashboard"><![CDATA[Studio Dashboard]]></string>
+    <string name="_sys_page_title_unsubscribe_news"><![CDATA[Unsubscribe From Site Newsletters]]></string>
+    <string name="_sys_page_title_unsubscribe_notifications"><![CDATA[Unsubscribe From Site Notifications]]></string>
+    <string name="_sys_page_title_studio_dashboard"><![CDATA[Studio Dashboard]]></string>
+    <string name="_sys_page_title_wiki_pages_list"><![CDATA[Subpage: Pages List]]></string>
+    <string name="_sys_page_title_wiki_page_contents"><![CDATA[Subpage: Page Contents]]></string>
+    <string name="_sys_page_title_system_con_friends"><![CDATA[Connections - Friends]]></string>
+    <string name="_sys_page_title_con_friends"><![CDATA[Friends]]></string>
+    <string name="_sys_page_title_system_con_friend_requests"><![CDATA[Connections - Friend Requests]]></string>
+    <string name="_sys_page_title_con_friend_requests"><![CDATA[Friend Requests]]></string>
+    <string name="_sys_page_title_system_con_friend_requested"><![CDATA[Connections - Sent Friend Requests]]></string>
+    <string name="_sys_page_title_con_friend_requested"><![CDATA[Sent Friend Requests]]></string>
+    <string name="_sys_page_title_system_con_following"><![CDATA[Connections - Following]]></string>
+    <string name="_sys_page_title_con_following"><![CDATA[Following]]></string>
+    <string name="_sys_page_title_system_con_followers"><![CDATA[Connections - Followers]]></string>
+    <string name="_sys_page_title_con_followers"><![CDATA[Followers]]></string>
+    <string name="_sys_page_title_system_recom_friends"><![CDATA[Recommendations - Friends]]></string>
+    <string name="_sys_page_title_recom_friends"><![CDATA[Friend Suggestions]]></string>
+    <string name="_sys_page_title_system_recom_subscriptions"><![CDATA[Recommendations - Subscriptions]]></string>
+    <string name="_sys_page_title_recom_subscriptions"><![CDATA[Who to follow]]></string>
+    <string name="_sys_page_title_system_ntfs_context_invitations"><![CDATA[Notifications - Context Invitations]]></string>
+    <string name="_sys_page_title_ntfs_context_invitations"><![CDATA[Invitations]]></string>
+    <string name="_sys_page_type_application"><![CDATA[Application]]></string>
+    <string name="_sys_page_type_default"><![CDATA[Default]]></string>
+    <string name="_sys_page_type_standard"><![CDATA[Standard]]></string>
+    <string name="_sys_page_type_wo_hf"><![CDATA[Without header/footer]]></string>
+    <string name="_sys_paginate_info"><![CDATA[{0}-{1}]]></string>
+    <string name="_sys_paginate_total"><![CDATA[{0}-{1} of {2}]]></string>
+    <string name="_sys_paginate_view_all"><![CDATA[View All]]></string>
+    <string name="_sys_payments_err_no_payments"><![CDATA[There is no installed payment processing module.]]></string>
+    <string name="_sys_payments_err_not_accept_payments"><![CDATA[You need to activate at least one payment provider. You may do it via My Account menu -> Settings page -> <a href="{0}">Payments</a> tab.]]></string>
+    <string name="_sys_please_select"><![CDATA[Please select...]]></string>
+
+    <string name="_sys_pre_lists_colors"><![CDATA[Colors]]></string>
+    <string name="_sys_pre_lists_color_slate"><![CDATA[Slate]]></string>
+    <string name="_sys_pre_lists_color_gray"><![CDATA[Gray]]></string>
+    <string name="_sys_pre_lists_color_zinc"><![CDATA[Zinc]]></string>
+    <string name="_sys_pre_lists_color_neutral"><![CDATA[Neutral]]></string>
+    <string name="_sys_pre_lists_color_stone"><![CDATA[Stone]]></string>
+    <string name="_sys_pre_lists_color_red"><![CDATA[Red]]></string>
+    <string name="_sys_pre_lists_color_orange"><![CDATA[Orange]]></string>
+    <string name="_sys_pre_lists_color_amber"><![CDATA[Amber]]></string>
+    <string name="_sys_pre_lists_color_yellow"><![CDATA[Yellow]]></string>
+    <string name="_sys_pre_lists_color_lime"><![CDATA[Lime]]></string>
+    <string name="_sys_pre_lists_color_green"><![CDATA[Green]]></string>
+    <string name="_sys_pre_lists_color_emerald"><![CDATA[Emerald]]></string>
+    <string name="_sys_pre_lists_color_teal"><![CDATA[Teal]]></string>
+    <string name="_sys_pre_lists_color_cyan"><![CDATA[Cyan]]></string>
+    <string name="_sys_pre_lists_color_sky"><![CDATA[Sky]]></string>
+    <string name="_sys_pre_lists_color_blue"><![CDATA[Blue]]></string>
+    <string name="_sys_pre_lists_color_indigo"><![CDATA[Indigo]]></string>
+    <string name="_sys_pre_lists_color_violet"><![CDATA[Violet]]></string>
+    <string name="_sys_pre_lists_color_purple"><![CDATA[Purple]]></string>
+    <string name="_sys_pre_lists_color_fuchsia"><![CDATA[Fuchsia]]></string>
+    <string name="_sys_pre_lists_color_pink"><![CDATA[Pink]]></string>
+    <string name="_sys_pre_lists_color_rose"><![CDATA[Rose]]></string>
+    
+        <string name="_sys_pre_lists_content_filter"><![CDATA[Content filter]]></string>
+        <string name="_sys_pre_lists_content_filter_g"><![CDATA[G]]></string>
+        <string name="_sys_pre_lists_content_filter_pg"><![CDATA[PG]]></string>
+        <string name="_sys_pre_lists_content_filter_pg13"><![CDATA[PG-13]]></string>
+        <string name="_sys_pre_lists_content_filter_r"><![CDATA[R]]></string>
+        <string name="_sys_pre_lists_content_filter_x"><![CDATA[X]]></string>
+        <string name="_sys_pre_lists_relations"><![CDATA[Relationships]]></string>
+        <string name="_sys_pre_lists_relations_husband"><![CDATA[husband]]></string>
+        <string name="_sys_pre_lists_relations_wife"><![CDATA[wife]]></string>
+        <string name="_sys_pre_lists_relations_father"><![CDATA[father]]></string>
+        <string name="_sys_pre_lists_relations_mother"><![CDATA[mother]]></string>
+        <string name="_sys_pre_lists_relations_son"><![CDATA[son]]></string>
+        <string name="_sys_pre_lists_relations_daughter"><![CDATA[daughter]]></string>
+        <string name="_sys_pre_lists_relations_brother"><![CDATA[brother]]></string>
+        <string name="_sys_pre_lists_relations_sister"><![CDATA[sister]]></string>
+	<string name="_sys_pre_lists_report_types"><![CDATA[Report Types]]></string>
+	<string name="_sys_pre_lists_report_types_spam"><![CDATA[spam]]></string>
+	<string name="_sys_pre_lists_report_types_scam"><![CDATA[scam]]></string>
+	<string name="_sys_pre_lists_report_types_fraud"><![CDATA[fraud]]></string>
+	<string name="_sys_pre_lists_report_types_nude"><![CDATA[nude]]></string>
+	<string name="_sys_pre_lists_report_types_other"><![CDATA[other]]></string>
+        <string name="_sys_pre_lists_vote_reactions"><![CDATA[Reactions]]></string>
+        <string name="_sys_pre_lists_vote_reactions_default"><![CDATA[React]]></string>
+        <string name="_sys_pre_lists_vote_reactions_like"><![CDATA[Like]]></string>
+        <string name="_sys_pre_lists_vote_reactions_love"><![CDATA[Love]]></string>
+        <string name="_sys_pre_lists_vote_reactions_joy"><![CDATA[Haha]]></string>
+        <string name="_sys_pre_lists_vote_reactions_surprise"><![CDATA[Wow]]></string>
+        <string name="_sys_pre_lists_vote_reactions_sadness"><![CDATA[Sad]]></string>
+        <string name="_sys_pre_lists_vote_reactions_anger"><![CDATA[Angry]]></string>
+        <string name="_sys_pre_lists_studio_widget_types"><![CDATA[App Types]]></string>
+        <string name="_sys_pre_lists_studio_widget_types_library"><![CDATA[Apps Library]]></string>
+        <string name="_sys_pre_lists_studio_widget_types_appearance"><![CDATA[Appearance]]></string>
+        <string name="_sys_pre_lists_studio_widget_types_structure"><![CDATA[Structure]]></string>
+        <string name="_sys_pre_lists_studio_widget_types_content"><![CDATA[Content]]></string>
+        <string name="_sys_pre_lists_studio_widget_types_users"><![CDATA[Users]]></string>
+        <string name="_sys_pre_lists_studio_widget_types_configuration"><![CDATA[Configuration]]></string>
+        <string name="_sys_pre_lists_studio_widget_types_extensions"><![CDATA[Extensions]]></string>
+        <string name="_sys_pre_lists_studio_widget_types_integrations"><![CDATA[Integrations]]></string>
+        <string name="_sys_pre_lists_studio_widget_types_favorites"><![CDATA[Favorites]]></string>
+	<string name="_sys_profile_sample_single"><![CDATA[profile]]></string>
+	<string name="_sys_profile_with_type"><![CDATA[{0} ({1})]]></string>
+        <string name="_sys_profile_friend_request_added"><![CDATA[<b class="bx-ntfs-content-profile">{owner_name}</b> befriended <b class="bx-ntfs-content-entry">{entry_caption}</b>]]></string>
+	<string name="_sys_profile_friendship_added"><![CDATA[Now <b class="bx-ntfs-content-profile">{owner_name}</b> and <b class="bx-ntfs-content-entry">{entry_caption}</b> are friends]]></string>
+	<string name="_sys_profile_subscription_added"><![CDATA[<b class="bx-ntfs-content-profile">{owner_name}</b> followed <b class="bx-ntfs-content-entry">{entry_caption}</b>]]></string>
+	<string name="_sys_profile_status_active"><![CDATA[Active]]></string>
+	<string name="_sys_profile_status_pending"><![CDATA[Pending]]></string>
+	<string name="_sys_profile_status_suspended"><![CDATA[Suspended]]></string>
+        <string name="_sys_profile_storage_quota_size"><![CDATA[Storage]]></string>
+        <string name="_sys_profile_storage_quota_number"><![CDATA[Number of files]]></string>
+	<string name="_sys_private"><![CDATA[Private]]></string>
+        <string name="_sys_privacy_forms_input_allow_view_to"><![CDATA[Visibility]]></string>
+        <string name="_sys_privacy_groups_acl"><![CDATA[Membership Levels]]></string>
+        <string name="_sys_pruning_db"><![CDATA[<h3>Database pruning:</h3>
+        <ul>
+            <li><b>{0}</b> deleted expired membership levels</li>
+            <li><b>{1}</b> deleted expired sessions</li>
+            <li><b>{2}</b> deleted expired keys</li>
+            <li><b>{3}</b> deleted expired storage tokens</li>
+            <li><b>{4}</b> deleted outdated transcoded images</li>
+            <li><b>{5}</b> deleted/suspended accounts</li>
+            <li><b>{6}</b> deleted view tracks</li>
+            <li><b>{7}</b> deleted vote tracks</li>
+            <li><b>{8}</b> deleted score tracks</li>
+            <li><b>{9}</b> deleted favorite tracks</li>
+            <li><b>{10}</b> deleted report tracks</li>
+        </ul>]]></string>
+    <string name="_sys_pruning_files"><![CDATA[<h3>Files pruning:</h3>
+        <ul>
+            <li><b>{0}</b> total</li>
+            <li><b>{1}</b> deleted</li>
+        </ul>]]></string>
+    <string name="_sys_ps_group_title_memberships_selected"><![CDATA[Specific membership levels...]]></string>
+    <string name="_sys_ps_group_title_custom"><![CDATA[Custom]]></string>
+    <string name="_sys_ps_group_title_followers"><![CDATA[Followers]]></string>
+    <string name="_sys_ps_group_title_friends"><![CDATA[Friends]]></string>
+    <string name="_sys_ps_group_title_friends_selected"><![CDATA[Specific friends...]]></string>
+    <string name="_sys_ps_group_title_relations"><![CDATA[Relationships]]></string>
+    <string name="_sys_ps_group_title_relations_selected"><![CDATA[Specific relationships...]]></string>
+    <string name="_sys_ps_group_title_me_only"><![CDATA[Only me]]></string>
+    <string name="_sys_ps_group_title_members"><![CDATA[Members]]></string>
+    <string name="_sys_ps_group_title_public"><![CDATA[Public]]></string>
+    <string name="_sys_ps_group_title_participants"><![CDATA[Participants]]></string>
+    <string name="_sys_ps_group_title_closed"><![CDATA[Closed]]></string>
+    <string name="_sys_ps_group_title_secret"><![CDATA[Secret]]></string>
+    <string name="_sys_ps_group_title_unknown"><![CDATA[Unknown]]></string>
+    <string name="_sys_ps_ferr_incorrect_gc_not_allowed"><![CDATA[Custom privacy groups aren't allowed.]]></string>
+    <string name="_sys_ps_ferr_incorrect_gc_owner"><![CDATA[You are not an owner of the content.]]></string>
+    <string name="_sys_ps_ferr_incorrect_select"><![CDATA[You need to select some value]]></string>
+    <string name="_sys_ps_space_title_friend"><![CDATA[friend]]></string>
+    <string name="_sys_push_notification_request"><![CDATA[Would you like to get notifications from {0}?]]></string>  
+    <string name="_sys_push_notification_request_yes"><![CDATA[Yes]]></string>  
+    <string name="_sys_push_notification_request_no"><![CDATA[No, thanks]]></string>
+    <string name="_sys_read_more"><![CDATA[Continue reading "{0}"]]></string>
+    <string name="_sys_relation"><![CDATA[Relationship]]></string>
+    <string name="_sys_request_module_not_found_cpt"><![CDATA[Module was not found]]></string>
+    <string name="_sys_request_module_not_found_cnt"><![CDATA[Module({0}) was not found]]></string>
+    <string name="_sys_request_page_not_found_cpt"><![CDATA[Page was not found]]></string>
+    <string name="_sys_request_page_not_found_cnt"><![CDATA[Page({0}) was not found in module({1})]]></string>
+    <string name="_sys_request_method_not_found_cpt"><![CDATA[Method was not found]]></string>
+    <string name="_sys_request_method_not_found_cnt"><![CDATA[Method({0}) was not found in module({1})]]></string>
+    <string name="_sys_score_counter"><![CDATA[{0}]]></string>
+    <string name="_sys_score_counter_empty"><![CDATA[Vote]]></string>
+    <string name="_sys_score_n_score"><![CDATA[{0} score]]></string>
+    <string name="_sys_score_do_up"><![CDATA[Up]]></string>
+    <string name="_sys_score_do_down"><![CDATA[Down]]></string>
+    <string name="_sys_score_do_by"><![CDATA[Voted by]]></string>
+    <string name="_sys_score_err_not_enabled"><![CDATA[The feature is not available right now. Please, try again later.]]></string>
+    <string name="_sys_score_err_duplicate_vote"><![CDATA[Duplicate vote]]></string>
+    <string name="_sys_search_main_title"><![CDATA[Search Home]]></string>
+    <string name="_sys_select"><![CDATA[Select]]></string>
+    <string name="_sys_send"><![CDATA[Send]]></string>
+    <string name="_sys_search_placeholder"><![CDATA[Search...]]></string>
+    <string name="_sys_search_or_ask_placeholder"><![CDATA[Search or ask...]]></string>
+    <string name="_sys_show_less"><![CDATA[Show less]]></string>    
+    <string name="_sys_show_more"><![CDATA[Show more]]></string>
+    <string name="_sys_skip_to_main_content"><![CDATA[Skip to main content]]></string>
+    <string name="_sys_spam_detected"><![CDATA[Your activity triggered automated block]]></string>
+    <string name="_sys_spam_detected_contact"><![CDATA[Your activity triggered automated block, please contact us to investigate: {0}]]></string>
+    <string name="_sys_splash_btn_start"><![CDATA[Start]]></string>
+    <string name="_sys_splash_err_domain_incorrect"><![CDATA[Domain is essential. Please, fill in this field, for example, my-first-site.]]></string>
+    <string name="_sys_splash_err_domain_is_used"><![CDATA[The domain name is already used. Try to select another one.]]></string>
+    <string name="_sys_splash_err_service_not_available"><![CDATA[The service is currently not available. Try it later, please.]]></string>
+    <string name="_sys_splash_inp_placeholder"><![CDATA[site address]]></string>
+    <string name="_sys_splash_inp_postfix"><![CDATA[.online.me]]></string>
+    <string name="_sys_splash_slogan"><![CDATA[The easiest way to create your own social website.]]></string>
+    <string name="_sys_status"><![CDATA[Status]]></string>
+    <string name="_sys_status_awaiting"><![CDATA[awaiting]]></string>
+    <string name="_sys_status_failed"><![CDATA[failed]]></string>
+    <string name="_sys_status_pending"><![CDATA[pending]]></string>
+    <string name="_sys_status_suspended"><![CDATA[suspended]]></string>
+    <string name="_sys_storage_err_db"><![CDATA[database error]]></string>
+    <string name="_sys_storage_err_engine_add"><![CDATA[error occurred]]></string>
+    <string name="_sys_storage_err_engine_get"><![CDATA[error occurred]]></string>
+    <string name="_sys_storage_err_file_not_found"><![CDATA[file not found]]></string>
+    <string name="_sys_storage_err_file_too_big"><![CDATA[file is too big]]></string>
+    <string name="_sys_storage_err_filesystem_perm"><![CDATA[permissions error]]></string>
+    <string name="_sys_storage_err_no_file"><![CDATA[no file to upload]]></string>
+    <string name="_sys_storage_err_no_input_method"><![CDATA[so such input method available]]></string>
+    <string name="_sys_storage_err_object_quota_exceeded"><![CDATA[quota exceeded]]></string>
+    <string name="_sys_storage_err_permission_denied"><![CDATA[permission denied]]></string>
+    <string name="_sys_storage_err_site_quota_exceeded"><![CDATA[quota exceeded]]></string>
+    <string name="_sys_storage_err_unlink"><![CDATA[file deletion failed]]></string>
+    <string name="_sys_storage_err_user_quota_exceeded"><![CDATA[user quota exceeded]]></string>
+    <string name="_sys_storage_err_wrong_ext"><![CDATA[wrong file extension]]></string>
+    <string name="_sys_storage_files"><![CDATA[file(s)]]></string>
+    <string name="_sys_storage_invalid_file"><![CDATA[file is invalid]]></string>
+    <string name="_sys_storage_restriction_ext_all_allowed"><![CDATA[Wow, files of all types are allowed!]]></string>
+    <string name="_sys_storage_restriction_ext_all_denied"><![CDATA[Sorry, adding all file types is currently restricted.]]></string>
+    <string name="_sys_storage_restriction_ext_allowed"><![CDATA[Please, upload only files of these types: {0}]]></string>
+    <string name="_sys_storage_restriction_ext_denied"><![CDATA[You may upload any types of files except for {0}]]></string>
+    <string name="_sys_storage_restriction_size"><![CDATA[Maximum file size limit is {0}]]></string>
+    <string name="_sys_switch_profile"><![CDATA[Switch profile]]></string>
+    <string name="_sys_submit"><![CDATA[Submit]]></string>
+    <string name="_sys_subscribe"><![CDATA[Follow]]></string>
+    <string name="_sys_template_mixed_mask"><![CDATA[{0} ({1})]]></string>
+
+    <string name="_sys_tour_launcher_welcome_title"><![CDATA[Welcome to UNA Studio!]]></string>
+    <string name="_sys_tour_launcher_welcome_txt"><![CDATA[Studio is where you customise your site; add and manage apps; control languages and design; set membership levels and permissions; build pages and navigation, and a lot more. You are now in Studio Launcher.]]></string>
+    <string name="_sys_tour_launcher_apps_title"><![CDATA[Add and manage Apps]]></string>
+    <string name="_sys_tour_launcher_apps_txt"><![CDATA[Apps are modules, languages, tools, templates - all the bits and pieces that make your site unique. You can download and install Apps and they will appear in Studio Launcher. Apps add and change functionality of your site.]]></string>
+    <string name="_sys_tour_launcher_designer_title"><![CDATA[Start making your site special]]></string>
+    <string name="_sys_tour_launcher_designer_txt"><![CDATA[Designer is the best place to start customisation. Change the site logo, choose design template and manage the “Cover Page”. Your site now shows Cover Page to all guest visitors. You can either customise it to turn it off to display a full homepage with content of your choice.]]></string>
+    <string name="_sys_tour_launcher_accounts_title"><![CDATA[You are more than Admin]]></string>
+    <string name="_sys_tour_launcher_accounts_txt"><![CDATA[UNA content and profiles are controlled by Admins and Moderators right on the site front-end, so you don’t have to worry about that in Studio. You do need to appoint your Admins and Moderators, though. And this is where you do it. If you also want to be the site Admin, just create your profile use “Set Membership” to upgrade it.]]></string>
+    <string name="_sys_tour_launcher_dashboard_title"><![CDATA[One look and you know it]]></string>
+    <string name="_sys_tour_launcher_dashboard_txt"><![CDATA[Dashboard gives a quick overview of the site status. UNA version, space usage, hosting tools and cache.  Different Apps will add their blocks to Dashboard.]]></string>
+    <string name="_sys_tour_launcher_builder_page_title"><![CDATA[Build your site the way you want it]]></string>
+    <string name="_sys_tour_launcher_builder_page_txt"><![CDATA[Pages allow you to edit the site by rearranging, adding and removing blocks on site pages. You can even create new custom pages of different types. You can also control visibility settings, SEO data, cacheing and page layouts.]]></string>
+    <string name="_sys_tour_launcher_builder_permissions_title"><![CDATA[Define who can do what]]></string>
+    <string name="_sys_tour_launcher_builder_permissions_txt"><![CDATA[Create and edit Membership Levels and associated Actions permissions.]]></string>
+    <string name="_sys_tour_launcher_builder_forms_title"><![CDATA[Form and re-form your forms]]></string>
+    <string name="_sys_tour_launcher_builder_forms_txt"><![CDATA[Forms builder is a powerful tool that allows deep customisation of site database and forms. You can create and manage data lists, form fields and even display types (like Add/Edit/Delete). Your Forms will define the structure and theme of the site.]]></string>
+    <string name="_sys_tour_launcher_builder_menus_title"><![CDATA[Show them around]]></string>
+    <string name="_sys_tour_launcher_builder_menus_txt"><![CDATA[Add and manage site navigation menus. You can edit links, re-order them, add new ones, change icons and control visibility according to membership permissions.]]></string>
+    <string name="_sys_tour_launcher_polyglot_title"><![CDATA[Speak their language]]></string>
+    <string name="_sys_tour_launcher_polyglot_txt"><![CDATA["If you talk to a man in a language he understands, that goes to his head. If you talk to him in his language, that goes to his heart." Polyglot allows you to set site language and data format, edit site texts in all installed languages and even translate email templates.]]></string>
+    <string name="_sys_tour_launcher_reorganize_title"><![CDATA[Move the Apps around]]></string>
+    <string name="_sys_tour_launcher_reorganize_txt"><![CDATA[Activate reorganisation mode to rearrange Apps in Launcher or delete inactive ones altogether.]]></string>
+    <string name="_sys_tour_launcher_favourites_title"><![CDATA[Choose wisely]]></string>
+    <string name="_sys_tour_launcher_favourites_txt"><![CDATA[Your Studio may have hundreds of installed Apps. Choose the ones you access most often and use the Star to bring them up.]]></string>
+    <string name="_sys_tour_launcher_add_apps_title"><![CDATA[Now DO add new Apps!]]></string>
+    <string name="_sys_tour_launcher_add_apps_txt"><![CDATA[UNA comes with only a handful of core Apps. Choose, download and install Apps to add profiles types, modules, system tools, plugins, languages and design templates. You can activate and deactivate installed Apps. UNA is super-modular and incredibly flexible, letting you choose your own combination of functionality, settings and database structure to make the social site of your dreams real. Even without changing anything you will have the perfectly functioning social site!]]></string>
+
+    <string name="_sys_tour_homepage_welcome_title"><![CDATA[This is the Homepage]]></string>
+    <string name="_sys_tour_homepage_welcome_txt"><![CDATA[At first there isn't much here. Install more Apps via Studio, add more blocks via Studio > Pages > Homepage, create profiles, appoint admins, post some content and your site will come alive!]]></string>
+    <string name="_sys_tour_homepage_account_menu_title"><![CDATA[Get to know your Account Menu]]></string>
+    <string name="_sys_tour_homepage_account_menu_txt"><![CDATA[Add and manage profiles, check notifications, access account settings. Admins and Moderators can use it to access Dash with links to site content and profiles management.]]></string>
+
+    <string name="_sys_txt_api_key"><![CDATA[API Key]]></string>
+    <string name="_sys_txt_access_denied"><![CDATA[Access denied]]></string>
+    <string name="_sys_txt_account_pending"><![CDATA[Your account is pending approval, please wait until it is activated.]]></string>
+    <string name="_sys_txt_account_profile_context_change_suggestion"><![CDATA[This is your profile, you can <a href="{0}">change your current profile</a> to this profile]]></string>
+    <string name="_sys_txt_account_profile_context_change_to_another_suggestion"><![CDATA[You can <a href="{0}">change your current profile</a> to this profile]]></string>
+    <string name="_sys_txt_account_profile_context_changed_success"><![CDATA[Current profile has been successfully changed to: <b>{0}</b>]]></string>
+    <string name="_sys_txt_account_suspended"><![CDATA[Your account is suspended.]]></string>
+    <string name="_sys_txt_account_unconfirmed_email"><![CDATA[Your email address is unconfirmed. Please, check your email ({1}) for a confirmation letter and click email confirmation link or use confirmation code (6 digit) to <a href="{2}">confirm your email</a>. Can't find the letter? Check your SPAM folder or <a href="{0}">send the verification letter again</a>.]]></string>
+    <string name="_sys_txt_account_unconfirmed_phone"><![CDATA[Your phone is unconfirmed. Please, confirm it on <a href="{0}">verification page</a>.]]></string>
+    <string name="_sys_txt_account_profile_system"><![CDATA[Please <a href="{0}">create a profile</a> to start using the site.]]></string>
+    <string name="_sys_txt_account_need_to_change_password"><![CDATA[Your password has been expired. Please <a href="{0}">change your password</a>.]]></string>
+    <string name="_sys_txt_account_cannot_delete"><![CDATA[Cannot delete the only Operator account]]></string>
+    <string name="_sys_txt_account_deletion_scheduled"><![CDATA[Account deletion was scheduled and would be done in a few minutes.]]></string>
+    
+    <string name="_sys_txt_agent_inactive"><![CDATA[Agent isn't activated]]></string>
+    <string name="_sys_txt_captcha_not_available"><![CDATA[CAPTCHA not available]]></string>
+    <string name="_sys_txt_categories_button_caption_add"><![CDATA[Add]]></string>
+    <string name="_sys_txt_categories_button_caption_addnew"><![CDATA[Create own category]]></string>
+    <string name="_sys_txt_change_image"><![CDATA[Change Picture]]></string>
+    <string name="_sys_txt_cmt_loading"><![CDATA[Loading...]]></string>
+    <string name="_sys_txt_confirm_email_already_confirmed"><![CDATA[Your email address is already confirmed.]]></string>
+    <string name="_sys_txt_confirm_email_desc"><![CDATA[Please enter confirmation code which was sent to your email address, or just click confirmation link in the same email message.]]></string>
+    <string name="_sys_txt_confirm_email_error_occured"><![CDATA[Error occurred, please try to login to your account and resend verification email.]]></string>
+    <string name="_sys_txt_confirm_email_sent"><![CDATA[Email verification letter was sent, please check your inbox.]]></string>
+    <string name="_sys_txt_confirm_email_sent_failed"><![CDATA[Error occurred, please report error to site administrator.]]></string>
+    <string name="_sys_txt_confirm_email_success"><![CDATA[You email address was successfully confirmed.]]></string>
+
+    <string name="_sys_txt_confirm_phone_already_confirmed"><![CDATA[Your phone is already confirmed.]]></string>
+    <string name="_sys_txt_confirm_phone_set_phone_error_occured"><![CDATA[Error occurred, please try to login to your account and repeat verification.]]></string>
+    <string name="_sys_txt_confirm_phone_send_sms_error_occured"><![CDATA[Error occurred, please report error to site administrator.]]></string>
+    <string name="_sys_txt_confirm_phone_sms_text"><![CDATA[Your phone's verification code is {0}.]]></string>
+    <string name="_sys_txt_confirm_phone_confirm_success"><![CDATA[Your phone number has been confirmed.]]></string>
+    <string name="_sys_txt_confirm_phone_set_phone_desc_set_phone"><![CDATA[Please enter a phone number for sending verification SMS.]]></string>
+    <string name="_sys_txt_confirm_phone_set_phone_desc_phone_confirmation"><![CDATA[Please enter verification code from the SMS.]]></string>
+
+    <string name="_sys_txt_create_post_placeholder"><![CDATA[Write here, {0}...]]></string>
+    <string name="_sys_txt_err_attach_links"><![CDATA[The maximum allowed number of attached links has been reached.]]></string>
+
+    <string name="_sys_txt_current_picture"><![CDATA[Current Picture]]></string>
+    <string name="_sys_txt_data_successfully_submitted"><![CDATA[Done]]></string>
+    <string name="_sys_txt_delete"><![CDATA[Delete]]></string>
+    <string name="_sys_txt_discard"><![CDATA[Discard]]></string>
+    <string name="_sys_txt_empty"><![CDATA[Empty]]></string>
+    <string name="_sys_txt_error_account_creation"><![CDATA[Account creation failed]]></string>
+    <string name="_sys_txt_error_account_delete"><![CDATA[Account delete failed]]></string>
+    <string name="_sys_txt_error_account_is_not_defined"><![CDATA[Account is not defined]]></string>
+    <string name="_sys_txt_error_account_update"><![CDATA[Account update failed]]></string>
+    <string name="_sys_txt_error_entry_creation"><![CDATA[Entry creation error]]></string>
+    <string name="_sys_txt_error_entry_delete"><![CDATA[Entry delete failed]]></string>
+    <string name="_sys_txt_error_entry_is_not_defined"><![CDATA[Requested resource doesn't exist]]></string>
+    <string name="_sys_txt_error_entry_update"><![CDATA[Entry update failed]]></string>
+    <string name="_sys_txt_error_occured"><![CDATA[Error Occurred]]></string>
+    <string name="_sys_txt_error_profile_is_not_defined"><![CDATA[Profile is not defined]]></string>
+    <string name="_sys_txt_error_profile_update"><![CDATA[Profile update failed]]></string>
+    <string name="_sys_txt_err_sound_not_transcoded_yet"><![CDATA[Sound file isn't transcoded yet]]></string>
+    <string name="_sys_txt_forms_unknown_field_err"><![CDATA['{0}' field is unknown]]></string>
+    <string name="_sys_txt_field_created"><![CDATA[Created:]]></string>
+    <string name="_sys_txt_field_updated"><![CDATA[Updated:]]></string>
+    <string name="_sys_txt_forgot_pasword"><![CDATA[Forgot password?]]></string>
+    <string name="_sys_txt_forgot_pasword_check_email"><![CDATA[Email was sent, please follow instructions in the email message.]]></string>
+    <string name="_sys_txt_forgot_pasword_check_phone"><![CDATA[SMS was sent, please follow instructions in the SMS.]]></string>
+    <string name="_sys_txt_forgot_pasword_desc"><![CDATA[Enter your account email address to get a password-reset link.]]></string>
+    <string name="_sys_txt_forgot_pasword_by_both_desc"><![CDATA[Enter your account email address or phone to get a password-reset link.]]></string>
+    <string name="_sys_txt_forgot_pasword_by_phone_desc"><![CDATA[Enter your account phone to get a password-reset link.]]></string>
+    <string name="_sys_txt_forgot_pasword_email_send_failed"><![CDATA[Email send failed, please try again later.]]></string>
+    <string name="_sys_txt_forgot_pasword_error_occured"><![CDATA[Error occurred, please report error to the site administrator.]]></string>
+    <string name="_sys_txt_forgot_pasword_sms_text"><![CDATA[Click the link below to reset your password {0}]]></string>
+    <string name="_sys_txt_forgot_pasword_logged_in"><![CDATA[You are already logged in. If you still wish to reset your password, please log out first and then initiate the password recovery process.]]></string>
+
+    <string name="_sys_txt_form_entry_input_picture_copy"><![CDATA[Copy URL]]></string>
+    <string name="_sys_txt_form_entry_input_picture_delete"><![CDATA[Delete]]></string>
+    <string name="_sys_txt_form_entry_input_picture_insert"><![CDATA[Insert to Post]]></string>
+    <string name="_sys_txt_form_entry_input_picture_pic_url"><![CDATA[Attachment URL:]]></string>
+    <string name="_sys_txt_form_entry_input_picture_use_as_thumb"><![CDATA[Use as Thumbnail]]></string>
+    <string name="_sys_txt_form_submission_error"><![CDATA[Incorrect info. Please, check your inputs and try to submit again.]]></string>
+    <string name="_sys_txt_form_submission_error_csrf_expired"><![CDATA[Token expired. Please try again.]]></string> 
+
+    <string name="_sys_txt_homepage_cover"><![CDATA[Unity is strength... when there is teamwork and collaboration, wonderful things can be achieved.<br /><button class="bx-btn bx-hide-when-logged-in bx-def-margin-top" onclick="document.location='{0}'">Join Now!</button>]]></string>
+    <string name="_sys_txt_login_2fa_description"><![CDATA[Two-factor authentication is enabled, please specify the phone number to send verification code to.]]></string>
+	
+    <string name="_sys_txt_login_2fa_sms_text"><![CDATA[Your verification code is {0}.]]></string>
+    <string name="_sys_txt_login_2fa_sms_error_occured"><![CDATA[An error occurred, please report error to the site administrator.]]></string>
+    <string name="_sys_txt_join_description_action"><![CDATA[Log in]]></string>
+    <string name="_sys_txt_login_description_action"><![CDATA[Create New Account]]></string>
+    <string name="_sys_txt_login_error"><![CDATA[Entered email or password is incorrect. Please try again.]]></string>
+    <string name="_sys_txt_login_locked"><![CDATA[Your account is locked and needs to be unlocked using <a href="{0}">forgot password page</a>.]]></string>
+  
+    <string name="_sys_txt_following_counter"><![CDATA[Following: {0}]]></string>
+    <string name="_sys_txt_followers_counter"><![CDATA[Followers: {0}]]></string>
+    <string name="_sys_txt_friends_counter"><![CDATA[Friends: {0}]]></string>
+    <string name="_sys_txt_login_invalid_role"><![CDATA[Access denied]]></string>
+    <string name="_sys_txt_my_profiles"><![CDATA[Create a new profile]]></string>
+    <string name="_sys_txt_switch_profiles"><![CDATA[Switch to]]></string>
+    <string name="_sys_txt_new_picture"><![CDATA[New Picture]]></string>
+    <string name="_sys_txt_not_found"><![CDATA[Not found]]></string>
+    <string name="_sys_txt_no_picture_uploaded"><![CDATA[No picture uploaded]]></string>
+    <string name="_sys_txt_no_title"><![CDATA[No title]]></string>
+    <string name="_sys_txt_n_by"><![CDATA[{0} by]]></string>
+    <string name="_sys_txt_n_friends"><![CDATA[{0} friends]]></string>
+    <string name="_sys_txt_n_mutual_friends"><![CDATA[{0} mutual friends]]></string>
+    <string name="_sys_txt_one_mutual_friend"><![CDATA[<a href="{0}">{1}</a> mutual friend]]></string>
+    <string name="_sys_txt_powered_by"><![CDATA[Powered by UNA Community Management System]]></string>
+  <string name="_sys_txt_report_status_0"><![CDATA[New]]></string>
+  <string name="_sys_txt_report_status_1"><![CDATA[In-process]]></string>
+  <string name="_sys_txt_report_status_2"><![CDATA[Processed]]></string>
+  <string name="_sys_txt_report_status_3"><![CDATA[Hided]]></string>
+	<string name="_sys_txt_reset_pasword_success"><![CDATA[Your password was reset. You are welcome to login to your account.]]></string>
+        <string name="_sys_txt_reset_pasword_error_invalid_key"><![CDATA[Reset password link was expired or already used. Please <a href="{0}">try again</a>.]]></string>
+        <string name="_sys_txt_reset_pasword_error_not_found"><![CDATA[Account with specified email wasn't found. Please <a href="{0}">try again</a>.]]></string>
+	<string name="_sys_txt_reset_pasword_error_occured"><![CDATA[Error occurred, please <a href="{0}">try again</a>.]]></string>
+        <string name="_sys_txt_splash_btn_join"><![CDATA[Join Now]]></string>
+	<string name="_sys_txt_splash_slide01_title"><![CDATA[Connect with people that share your passion.]]></string>
+	<string name="_sys_txt_splash_slide01_desc"><![CDATA[Stories, ideas, photos, videos, questions, jokes, discussions, anything.<br />Follow inspiring people and inspire your followers.]]></string>
+	<string name="_sys_txt_splash_slide02_txt"><![CDATA["Pull up a chair. Take a taste.<br />Come join us. Life is so endlessly<br />delicious."]]></string>
+	<string name="_sys_txt_splash_slide03_txt"><![CDATA["The only way to have a friend is to be one."]]></string>
+	<string name="_sys_txt_splash_slide04_txt"><![CDATA[Already one of us?]]></string>
+	<string name="_sys_txt_splash_title"><![CDATA[Connect. Share. Create.]]></string>
+	<string name="_sys_txt_splash_slogan"><![CDATA[Join our community now to connect with like-minded people, share exciting news and create inspiring content.]]></string>
+        <string name="_sys_txt_splash_login"><![CDATA[Login]]></string>
+        <string name="_sys_txt_splash_join"><![CDATA[Join]]></string>
+        <string name="_sys_txt_splash_connect"><![CDATA[Connect]]></string>
+        <string name="_sys_txt_splash_connect_text"><![CDATA[Find like-minded people, make new friends, follow interesting authors and stay in touch anywhere.]]></string>
+        <string name="_sys_txt_splash_share"><![CDATA[Share]]></string>
+        <string name="_sys_txt_splash_share_text"><![CDATA[Bring up the latest news, share interesting articles, exciting websites, cool photos and awesome videos.]]></string>
+        <string name="_sys_txt_splash_create"><![CDATA[Create]]></string>
+        <string name="_sys_txt_splash_create_text"><![CDATA[Build your social profile, post status updates, write notes, create polls and upload media albums.]]></string>
+	<string name="_sys_txt_switch_profile_context"><![CDATA[Switch]]></string>
+	<string name="_sys_txt_unsubscribe_email_settings_update_success"><![CDATA[Your email preferences have been updated.]]></string>
+	<string name="_sys_txt_unsubscribe_error_occured"><![CDATA[Error occurred, please login to your account and update email references there or contact site administrator to unsubscribe you manually.]]></string>
+	<string name="_sys_txt_unsubscribe_info"><![CDATA[Update email preferences for <b>{0}</b>]]></string>
+        <string name="_sys_txt_unsubscribe_wrong_link"><![CDATA[Unsubscribe link is wrong.]]></string>
+        <string name="_sys_txt_url"><![CDATA[URL]]></string>
+        <string name="_sys_txt_user_n"><![CDATA[User #{0}]]></string>
+        <string name="_sys_txt_reports_title"><![CDATA[Reports]]></string>
+        <string name="_sys_txt_reports_grid_view_notes"><![CDATA[View notes]]></string>
+        <string name="_sys_txt_share_popup_header"><![CDATA[Share]]></string>
+        <string name="_sys_txt_share_popup_url"><![CDATA[URL]]></string>
+        <string name="_sys_txt_share_popup_copy_to_clipboard_text"><![CDATA[Click for copy to the clipboard]]></string>
+        <string name="_sys_txt_share_popup_embeded_code"><![CDATA[Embeded code]]></string>
+    
+        <string name="_sys_txt_search_sort_by"><![CDATA[Sort by]]></string>
+        <string name="_sys_txt_search_sort_by_default"><![CDATA[Default]]></string>
+    
+        <string name="_sys_unconfirmed"><![CDATA[Unconfirmed]]></string>
+	<string name="_sys_upgrade_conclusion"><![CDATA[<h3>Important info:</h3><p>{0}</p>]]></string>
+	<string name="_sys_upgrade_db_and_files_versions_different"><![CDATA[Database and files versions are different, probably previous patch wasn't applied correctly.]]></string>
+	<string name="_sys_upgrade_files_checksum_failed"><![CDATA[Can't apply upgrade because the following files were modified: {0}]]></string>
+	<string name="_sys_upgrade_files_checksum_failed_too_many"><![CDATA[Can't apply upgrade because too many files({0}%) were modified]]></string>
+	<string name="_sys_upgrade_files_checksum_failed_too_many_module"><![CDATA[Can't apply upgrade because too many files({0}%) were modified in {1} module]]></string>
+	<string name="_sys_upgrade_get_version_info_failed"><![CDATA[Get version info failed, please check internet connection on the web-server or web-server firewall]]></string>
+        <string name="_sys_upgrade_modules_upgrade_first"><![CDATA[You have outdated modules. Upgrade them first in Studio &gt; App Store &gt; Updates.]]></string>
+	<string name="_sys_upgrade_patch_checksum_failed"><![CDATA[Downloaded patch file checksum is invalid]]></string>
+	<string name="_sys_upgrade_patch_download_failed"><![CDATA[Patch download failed, or downloaded file can't be saved]]></string>
+	<string name="_sys_upgrade_patch_invalid"><![CDATA[Invalid patch, it can't be applied to your version or incorrect files structure in the patch.]]></string>
+	<string name="_sys_upgrade_patch_unpack_failed"><![CDATA[Patch unpack failed]]></string>
+	<string name="_sys_uploader_button_name_single"><![CDATA[Upload File]]></string>
+	<string name="_sys_uploader_close"><![CDATA[Close]]></string>
+	<string name="_sys_uploader_confirm_close_popup"><![CDATA[Oh no! Are you sure? This may discard uploading files, seriously.]]></string>
+    <string name="_sys_uploader_confirm_leaving_page"><![CDATA[Upload is in progress! Stay cool and don't close this page, or it will cut off half-way.]]></string>
+    <string name="_sys_uploader_crop_button_name"><![CDATA[Upload and Crop]]></string>
+    <string name="_sys_uploader_crop_rotate_left"><![CDATA[Rotate Left]]></string>
+	<string name="_sys_uploader_crop_rotate_right"><![CDATA[Rotate Right]]></string>
+	<string name="_sys_uploader_crop_submit_button"><![CDATA[Upload]]></string>
+    <string name="_sys_uploader_crop_title"><![CDATA[Crop Image]]></string>
+    <string name="_sys_uploader_crop_err_upload"><![CDATA[Error Uploading.]]></string>
+    <string name="_sys_uploader_crop_wrong_ext"><![CDATA[Wrong file extension, only images with the following extensions are allowed: jpg, jpeg, png, gif.]]></string>
+	<string name="_sys_uploader_err_msg"><![CDATA[Oops! An error occurred with {0} file: {1}]]></string>
+	<string name="_sys_uploader_html5_button_name"><![CDATA[Multiple Upload]]></string>
+	<string name="_sys_uploader_html5_drop_area"><![CDATA[Drag and Drop files here to upload]]></string>
+	<string name="_sys_uploader_html5_shoose_file"><![CDATA[Select a file]]></string>
+    <string name="_sys_uploader_html5_title"><![CDATA[Multiple Upload]]></string>
+    <string name="_sys_uploader_html5_default_message"><![CDATA[Drop files here to upload or click here to select files]]></string>
+    <string name="_sys_uploader_html5_file_is_too_big"><![CDATA[File is too big - {{filesize}} MB, max filesize is {{maxFilesize}} MB.]]></string>
+    <string name="_sys_uploader_html5_number_of_files_exceeded"><![CDATA[You can not upload any more files.]]></string>
+    <string name="_sys_uploader_html5_invalid_file_type"><![CDATA[You can't upload files of this type.]]></string>
+	<string name="_sys_uploader_simple_attach_one_more_file"><![CDATA[+ Add more files]]></string>
+	<string name="_sys_uploader_simple_button_name"><![CDATA[Simple Upload]]></string>
+	<string name="_sys_uploader_simple_submit_button"><![CDATA[Upload]]></string>
+	<string name="_sys_uploader_record_video_button_name"><![CDATA[Record]]></string>
+	<string name="_sys_uploader_record_video_submit_button"><![CDATA[Upload]]></string>
+	<string name="_sys_uploader_record_video_title"><![CDATA[Record Video]]></string>
+	<string name="_sys_uploader_record_video_start_button"><![CDATA[Start Recording]]></string>
+	<string name="_sys_uploader_record_video_stop_button"><![CDATA[Stop Recording]]></string>
+	<string name="_sys_uploader_record_video_mb"><![CDATA[Mb]]></string>
+	<string name="_sys_uploader_record_video_switch_camera"><![CDATA[Switch camera]]></string>
+	<string name="_sys_uploader_upload_canceled"><![CDATA[Too bad. Upload canceled.]]></string>
+	<string name="_sys_uploader_camera_capture_failed"><![CDATA[We were unable to initialize your camera.]]></string>
+	<string name="_sys_uploader_unsupported_browser"><![CDATA[Your browser doesn't support video recording. You can try <strong>Google Chrome</strong> or <strong>Mozilla FireFox</strong> instead.]]></string>
+    <string name="_sys_uploader_image_reposition"><![CDATA[Change position]]></string>
+    <string name="_sys_uploader_image_reposition_save"><![CDATA[Save]]></string>
+    <string name="_sys_uploader_image_reposition_cancel"><![CDATA[Cancel]]></string>
+    <string name="_sys_uploader_image_upload"><![CDATA[Upload new]]></string>
+    <string name="_sys_uploader_image_reposition_info"><![CDATA[Drag to reposition]]></string>
+	<string name="_sys_edit_profile"><![CDATA[Edit profile]]></string>    
+	<string name="_sys_exit"><![CDATA[Exit]]></string>    
+	<string name="_sys_warn"><![CDATA[warning]]></string>
+	<string name="_sys_x_days"><![CDATA[{0} days]]></string>
+	<string name="_to"><![CDATA[to]]></string>
+	<string name="_top"><![CDATA[Top]]></string>
+	<string name="_uknown"><![CDATA[unknown]]></string>
+	<string name="_undefined"><![CDATA[undefined]]></string>
+	<string name="_view_counter"><![CDATA[{0}]]></string>
+	<string name="_view_do_view"><![CDATA[View]]></string>
+	<string name="_view_do_view_by"><![CDATA[Viewed by]]></string>
+	<string name="_view_do_view_by_counter"><![CDATA[{0} views]]></string>
+	<string name="_view_n_views"><![CDATA[{0} views]]></string>
+	<string name="_vote_counter"><![CDATA[{0}]]></string>
+	<string name="_vote_do_like"><![CDATA[Like]]></string>
+	<string name="_vote_do_unlike"><![CDATA[Like]]></string>
+	<string name="_vote_do_by"><![CDATA[Liked by]]></string>
+        <string name="_vote_do_by_reactions"><![CDATA[Reacted by]]></string>
+        <string name="_vote_do_by_x_reaction"><![CDATA["{0}" by]]></string>
+        <string name="_vote_do_by_summary"><![CDATA[All]]></string>
+	<string name="_vote_err_not_enabled"><![CDATA[The feature is not available right now. Please, try again later.]]></string>
+	<string name="_vote_err_duplicate_vote"><![CDATA[Duplicate vote]]></string>
+        <string name="_vote_n_votes"><![CDATA[{0} votes]]></string>
+	<string name="_week_fri"><![CDATA[Friday]]></string>
+	<string name="_week_mon"><![CDATA[Monday]]></string>
+	<string name="_week_sat"><![CDATA[Saturday]]></string>
+	<string name="_week_sun"><![CDATA[Sunday]]></string>
+	<string name="_week_thu"><![CDATA[Thursday]]></string>
+	<string name="_week_tue"><![CDATA[Tuesday]]></string>
+	<string name="_week_wed"><![CDATA[Wednesday]]></string>
+	<string name="_sys_option_labels"><![CDATA[Labels]]></string>
+	<string name="_sys_option_per_page_browse_showcase"><![CDATA[Number of items in showcase view]]></string>
+	<string name="_sys_option_per_page_browse_recommended"><![CDATA[Number of items in recommended view]]></string>
+	<string name="_sys_javascript_requred"><![CDATA[This site requires JavaScript! Please, enable it in the browser!]]></string>
+	<string name="_sys_wiki_system_title"><![CDATA[System WIKI]]></string>
+	<string name="_sys_wiki_error_page_exists"><![CDATA[Page with such name({0}) already exists]]></string>
+	<string name="_sys_wiki_error_no_rev"><![CDATA[There is no {0} revision exist for {1} language]]></string>
+	<string name="_sys_wiki_error_no_revs"><![CDATA[There are no revisions available for this block]]></string>
+	<string name="_sys_wiki_error_missing_wiki_object"><![CDATA[Wiki object ({0}) wasn't found]]></string>
+    <string name="_sys_wiki_error_action_not_allowed"><![CDATA[Wiki object ({1}) action ({0}) isn't allowed]]></string>
+    <string name="_sys_wiki_error_incorrect_page_uri"><![CDATA["{0}" isn't correct page URI]]></string>
+    <string name="_sys_wiki_error_no_such_lang"><![CDATA[No sucn language]]></string>
+    <string name="_sys_wiki_error_occured"><![CDATA[Error occured (code:{0})]]></string>
+    <string name="_sys_wiki_view_rev"><![CDATA[Version <b>{0}</b> by <a href="{1}">{2}</a>, {3}]]></string>
+    <string name="_sys_wiki_lang_mask"><![CDATA[{0} {1} <span class="bx-def-font-grayed bx-def-font-small">{2}</span>]]></string>
+    <string name="_sys_wiki_lang_mask_warn"><![CDATA[{0} {1} <span class="bx-def-font-small" style="color:red;">{2}</span>]]></string>
+    <string name="_sys_wiki_lang_missing"><![CDATA[missing]]></string>
+    <string name="_sys_wiki_revisions_deleted"><![CDATA[{0} revisions were deleted]]></string>
+    <string name="_sys_wiki_confirm_block_deletion"><![CDATA[Are you sure you want to permanently delete this block with all revisions and translations?]]></string>
+    <string name="_sys_wiki_block_deleted"><![CDATA[Block was successfully deleted]]></string>
+    <string name="_sys_wiki_add_block"><![CDATA[Add Block]]></string>
+	<string name="_sys_wiki_add_page"><![CDATA[Add Page]]></string>
+	<string name="_sys_wiki_add_page_text"><![CDATA[Such wiki page doesn't exists.]]></string>
+	<string name="_sys_wiki_no_missing_translations"><![CDATA[No missing translations for {0} language.]]></string>
+	<string name="_sys_wiki_all_translations_up_to_date"><![CDATA[All translations are up to date for {0} language.]]></string>
+    <string name="_sys_wiki_title_title"><![CDATA[Page]]></string>
+    <string name="_sys_wiki_title_lang_missing"><![CDATA[Missing Lang]]></string>
+    <string name="_sys_wiki_title_lang_outated"><![CDATA[Outdated Lang]]></string>
+    <string name="_sys_wiki_title_author"><![CDATA[{0} author]]></string>
+    <string name="_sys_wiki_title_content"><![CDATA[{0} content]]></string>
+    <string name="_sys_wiki_title_time"><![CDATA[{0} updated]]></string>
+    <string name="_sys_wiki_orig"><![CDATA[Orig.]]></string>
+    <string name="_sys_wiki_copy"><![CDATA[Copy to clipboard]]></string>
+    <string name="_sys_wiki_open_in_editor"><![CDATA[Open in editor]]></string>
+    <string name="_sys_wiki_external_editor_references_comment"><![CDATA[NOTE: don't modify this comment and lines below]]></string>
+
+	<string name="_adm_lmi_cpt_groups_roles"><![CDATA[Roles]]></string>
+	<string name="_adm_form_txt_groups_roles_add_popup"><![CDATA[Create role]]></string>
+	<string name="_adm_form_txt_groups_role_value"><![CDATA[Role name]]></string>
+	<string name="_adm_form_txt_groups_role_value_err"><![CDATA[Role name is required]]></string>
+	<string name="_adm_form_txt_groups_roles_edit_popup"><![CDATA[Edit role]]></string>
+	<string name="_adm_form_txt_groups_role_manage_fans"><![CDATA[Manage fans]]></string>
+	<string name="_adm_form_txt_groups_role_manage_roles"><![CDATA[Manage roles]]></string>
+	<string name="_adm_form_txt_groups_role_edit"><![CDATA[Edit]]></string>
+	<string name="_adm_form_txt_groups_role_invite"><![CDATA[Invite]]></string>
+	<string name="_adm_form_txt_groups_role_change_cover"><![CDATA[Change cover]]></string>
+	<string name="_adm_form_txt_groups_role_post"><![CDATA[Post]]></string>
+	<string name="_adm_form_txt_groups_role_edit_any"><![CDATA[Edit any entry]]></string>
+	<string name="_adm_form_txt_groups_role_delete_any"><![CDATA[Delete any entry]]></string>
+	<string name="_adm_form_txt_groups_role_pin"><![CDATA[Pin entry]]></string>
+    
+    <string name="_sys_txt_quill_tooltip_bold"><![CDATA[Add bold text <cmd+b>]]></string>
+    <string name="_sys_txt_quill_tooltip_italic"><![CDATA[Add italic text <cmd+i>]]></string>
+    <string name="_sys_txt_quill_tooltip_underline"><![CDATA[Add underline text <cmd+u>]]></string>
+    <string name="_sys_txt_quill_tooltip_clean"><![CDATA[Clear format]]></string>
+    <string name="_sys_txt_quill_tooltip_list_ordered"><![CDATA[Numbered list]]></string>
+    <string name="_sys_txt_quill_tooltip_list_bullet"><![CDATA[Bulleted list]]></string>
+    <string name="_sys_txt_quill_tooltip_indent_1"><![CDATA[Decrease indent]]></string>
+    <string name="_sys_txt_quill_tooltip_indent_2"><![CDATA[Increase indent]]></string>
+    <string name="_sys_txt_quill_tooltip_blockquote"><![CDATA[Add blockquote]]></string>
+    <string name="_sys_txt_quill_tooltip_direction"><![CDATA[Text direction]]></string>
+    <string name="_sys_txt_quill_tooltip_script_sub"><![CDATA[Subscript]]></string>
+    <string name="_sys_txt_quill_tooltip_script_super"><![CDATA[Superscript]]></string>
+    <string name="_sys_txt_quill_tooltip_link"><![CDATA[Insert a link]]></string>
+    <string name="_sys_txt_quill_tooltip_image"><![CDATA[Insert an image]]></string>
+    <string name="_sys_txt_quill_tooltip_code_block"><![CDATA[Add code]]></string>
+    
+    <string name="_sys_txt_quill_tooltip_color"><![CDATA[Select a text color]]></string>
+    <string name="_sys_txt_quill_tooltip_background"><![CDATA[Select a background color]]></string>
+    <string name="_sys_txt_quill_tooltip_align"><![CDATA[Text alignment]]></string>
+    <string name="_sys_txt_quill_tooltip_header"><![CDATA[Select the text style]]></string>
+    <string name="_sys_txt_quill_tooltip_embed"><![CDATA[Insert an embed]]></string>
+    <string name="_sys_txt_quill_tooltip_embed_popup_header"><![CDATA[Paste an URL for embed]]></string>
+    <string name="_sys_txt_quill_tooltip_link_popup_header"><![CDATA[Paste an URL]]></string>
+    <string name="_sys_queue_emails"><![CDATA[Emails]]></string>
+    <string name="_sys_queue_push"><![CDATA[PUSH]]></string>
+    <string name="_sys_queue_transcoding"><![CDATA[Video transcoding]]></string>
+    <string name="_sys_queue_storage"><![CDATA[Files storage]]></string>    
+    <string name="_sys_page_title_redirect"><![CDATA[Redirect Confirmation]]></string>
+    <string name="_sys_page_block_title_redirect"><![CDATA[Confirm redirect]]></string>
+    <string name="_sys_redirect_confirmation"><![CDATA[<div class="bx-def-font-h2 bx-def-margin-sec-bottom">You're going to a link outside {1}</div><div class="bx-def-font-small">Link: {0}</div><div class="bx-def-margin-sec-top">Are you sure you want to follow this link?</div>]]></string>
+    <string name="_sys_redirect_confirmation_harmful"><![CDATA[<div class="bx-def-font-h2 bx-def-margin-sec-bottom">You're going to a potentially <b>harmful</b> link {1}</div><div class="bx-def-font-small">Link: {0}</div><div class="bx-def-margin-sec-top">Are you sure you want to follow this link?</div>]]></string>
+    <string name="_sys_leave_page_confirmation"><![CDATA[<div class="bx-def-font-h2">Leave the page?</div><div class="bx-def-margin-sec-top">If you do it, your changes will not be saved.</div>]]></string>
+</resources>

+ 71 - 0
modules/boonex/english/updates/15.0.2_15.0.3/source/install/config.php

@@ -0,0 +1,71 @@
+<?php
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    English English language
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+$aConfig = array(
+    /**
+     * Main Section.
+     */
+    'type' => BX_DOL_MODULE_TYPE_LANGUAGE,
+    'name' => 'bx_en',
+    'title' => 'English',
+    'note' => 'Language file',
+    'version' => '15.0.3',
+    'vendor' => 'UNA INC',
+    'help_url' => 'http://feed.una.io/?section={module_name}',
+
+    'compatible_with' => array(
+        '15.0.0-B2'
+    ),
+
+    /**
+     * 'home_dir' and 'home_uri' - should be unique. Don't use spaces in 'home_uri' and the other special chars.
+     */
+    'home_dir' => 'boonex/english/',
+    'home_uri' => 'en',
+
+    'db_prefix' => 'bx_eng_',
+    'class_prefix' => 'BxEng',
+
+    /**
+     * Category for language keys.
+     */
+    'language_category' => 'BoonEx English',
+
+    /**
+     * Installation/Uninstallation Section.
+     * NOTE. The sequence of actions is critical. Don't change the order.
+     */
+    'install' => array(
+        'execute_sql' => 1,
+        'update_languages' => 1,
+        'install_language' => 1,
+    	'clear_db_cache' => 1
+    ),
+    'uninstall' => array (
+        'update_languages' => 1,
+        'execute_sql' => 1,
+    	'clear_db_cache' => 1
+    ),
+    'enable' => array(
+        'execute_sql' => 1
+    ),
+    'disable' => array(
+        'execute_sql' => 1
+    ),
+
+    /**
+     * Dependencies Section
+     */
+    'dependencies' => array(),
+
+);
+
+/** @} */

+ 51 - 0
modules/boonex/lucid/updates/15.0.2_15.0.3/install/config.php

@@ -0,0 +1,51 @@
+<?php
+/**
+ * Copyright (c) BoonEx Pty Limited - http://www.boonex.com/
+ * CC-BY License - http://creativecommons.org/licenses/by/3.0/
+ */
+
+$aConfig = array(
+    /**
+     * Main Section.
+     */
+    'title' => 'Lucid',
+    'version_from' => '15.0.2',
+    'version_to' => '15.0.3',
+    'vendor' => 'UNA INC',
+
+    'compatible_with' => array(
+        '15.0.0-B2'
+    ),
+
+    /**
+     * 'home_dir' and 'home_uri' - should be unique. Don't use spaces in 'home_uri' and the other special chars.
+     */
+    'home_dir' => 'boonex/lucid/updates/update_15.0.2_15.0.3/',
+    'home_uri' => 'lucid_update_1502_1503',
+
+    'module_dir' => 'boonex/lucid/',
+    'module_uri' => 'lucid',
+
+    'db_prefix' => 'bx_lucid_',
+    'class_prefix' => 'BxLucid',
+
+    /**
+     * Installation/Uninstallation Section.
+     */
+    'install' => array(
+        'execute_sql' => 0,
+        'update_files' => 1,
+        'update_languages' => 0,
+        'clear_db_cache' => 0,
+    ),
+
+    /**
+     * Category for language keys.
+     */
+    'language_category' => 'Boonex Lucid Template',
+
+    /**
+     * Files Section
+     */
+    'delete_files' => array(),
+);

+ 26 - 0
modules/boonex/lucid/updates/15.0.2_15.0.3/install/installer.php

@@ -0,0 +1,26 @@
+<?php
+/**
+ * Copyright (c) BoonEx Pty Limited - http://www.boonex.com/
+ * CC-BY License - http://creativecommons.org/licenses/by/3.0/
+ */
+
+class BxLucidUpdater extends BxDolStudioUpdater
+{
+    function __construct($aConfig)
+    {
+        parent::__construct($aConfig);
+    }
+
+    public function update($aParams)
+    {
+        $aResult = parent::update($aParams);
+        if(!$aResult['result'])
+            return $aResult;
+
+        $oCacheUtilities = BxDolCacheUtilities::getInstance();
+        $oCacheUtilities->clear('css');
+        $oCacheUtilities->clear('template');
+
+        return $aResult;
+    }
+}

+ 43 - 0
modules/boonex/lucid/updates/15.0.2_15.0.3/source/data/template/system/_sub_footer.html

@@ -0,0 +1,43 @@
+						
+						                <bx_injection:injection_content_after />
+						
+						                <div class="bx-clear"></div>
+						
+						            <bx_injection:banner_bottom />
+						
+						        </main> <!-- #bx-content-main -->
+						
+						        <bx_injection:injection_between_content_footer />
+						
+						    </div> <!-- #bx-content-container -->
+						
+						</div>
+				
+					</div> <!-- #bx-content-wrapper -->
+	
+                            <div id="bx-footer-wrapper" class="bx-footer-wrapper bx-def-image-bg-footer bx-def-color-bg-footer bx-def-border-footer bx-shadow-footer">    
+                                <div class="bx-def-centered bx-def-padding-sec-leftright bx-def-box-sizing">
+                                    <footer id="bx-footer" class="bx-footer bx-def-padding-sec-left bx-def-padding-sec-right bx-clearfix">
+                                        <div class="bx-footer-cnt bx-content-padding-footer">
+                                            <bx_injection:injection_footer_before />
+                                            <div id="bx-menu-bottom" class="bx-def-margin-sec-top-auto">
+                                                <bx_menu:sys_footer />
+                                            </div>
+                                            <bx_injection:injection_footer_after />
+                                        </div>
+                                    </footer>
+                                </div>
+                            </div>
+	
+		        </div> <!-- .content-wrapper -->
+	
+	        </div> <!-- .content-wrapper-wrp -->
+	
+	    </div> <!-- .cd-main-content -->
+
+    </div> <!-- .cd-main-content-wrp -->
+
+    <bx_menu:sys_site_action />
+</div>
+
+<bx_include_auto:_footer.html />

+ 61 - 0
modules/boonex/lucid/updates/15.0.2_15.0.3/source/data/template/system/_sub_header.html

@@ -0,0 +1,61 @@
+<bx_include_auto:_header.html />
+
+<div class="bx-main <bx_injection:injection_main_class />">
+        <bx_injection:top />
+
+        <div id="bx-toolbar" class="bx-header bx-def-image-bg-header bx-def-color-bg-header bx-def-border-header bx-shadow-header bx-def-z-index-nav cd-main-header">
+            <div class="bx-toolbar-content-hgap bx-def-padding-sec-leftright bx-def-box-sizing">
+                <div class="bx-toolbar-content-wrapper bx-content-padding-header">
+                    <div id="bx-toolbar-content" class="bx-toolbar-content bx-clearfix">
+                        <bx_menu:sys_toolbar_site />
+                        <div id="bx-logo-container" class="bx-toolbar-item bx-ti-logo">
+                            <bx_injection:injection_logo_before />
+                                __main_logo__
+                            <bx_injection:injection_logo_after />
+                        </div>
+                        <div id="bx-menu-main-container" class="bx-toolbar-item bx-ti-menu bx-ti-stretcher">
+                            <bx_menu:sys_site />
+                        </div>
+                        <bx_menu:sys_toolbar_member />
+                    </div>
+                </div>
+            </div>
+        </div>
+
+	<div class="cd-main-content-wrp">
+            <div class="cd-main-content bx-clearfix">
+            <div class="content-wrapper-wrp">
+                <div class="content-wrapper bx-def-box-sizing">
+                    <bx_injection:injection_between_cover_logo />
+                    __cover__
+                    <bx_injection:injection_between_cover_top_menu />
+
+                    <div class="bx-menu-main-bar-gap bx-def-centered bx-def-padding-leftright bx-def-page-width bx-def-box-sizing __site_submenu_hidden__">
+                        <div id="bx-menu-main-bar-wrapper" class="bx-menu-main-bar-wrapper bx-def-color-bg-sec">
+                            <div id="bx-menu-main-bar" class="bx-menu-main-bar __site_submenu_class__">
+                                <div class="bx-menu-main-bar-cnt px-4">
+                                    <bx_injection:injection_top_menu_before />
+                                    <div class="flex items-center h-full text-center">
+                                        <div class="relative flex-1 h-full">
+                                            <div class="absolute w-full h-full">
+                                                <bx_menu:sys_site_submenu />
+                                            </div>
+                                        </div>
+                                        <div class="flex-none">
+                                            <bx_menu:sys_site_manage />
+                                        </div>
+                                    </div>
+                                    <bx_injection:injection_top_menu_after />
+                                </div>
+                            </div>
+                        </div>
+                    </div>
+
+                    <bx_injection:injection_between_content_menu />
+
+                    <div id="bx-content-wrapper" class="bx-content-wrapper">
+                        __informer__
+                        <div class="bx-page-wrapper bx-def-centered bx-def-padding-sec-leftright bx-def-page-width bx-def-box-sizing">
+                            <div id="bx-content-container" class="bx-def-padding-sec-left bx-def-padding-sec-right">
+                                <bx_injection:injection_content_before />
+                                <main role="main" id="bx-content-main" class=" my-4 lg:my-6">

+ 116 - 0
modules/boonex/lucid/updates/15.0.2_15.0.3/source/data/template/system/pt_application.html

@@ -0,0 +1,116 @@
+<bx_include_auto:_header.html />
+<div class="bx-main bx-pt-application <bx_injection:injection_main_class />">
+    <bx_injection:top />
+    <div id="bx-toolbar" class="bx-header bx-def-image-bg-header bx-def-color-bg-header bx-def-border-header bx-shadow-header bx-def-z-index-nav cd-main-header">
+        <div class="bx-toolbar-content-hgap bx-def-padding-sec-leftright bx-def-box-sizing">
+            <div class="bx-toolbar-content-wrapper bx-content-padding-header">
+                <div id="bx-toolbar-content" class="bx-toolbar-content bx-clearfix">
+                    <div class="bx-toolbar-item">
+                        <!-- Sidebar Toggler -->
+                        <button id="toggleSidebar" aria-expanded="true" aria-controls="sidebar" class="hidden p-2 mr-6 text-gray-600 rounded cursor-pointer xl:inline hover:text-gray-900 hover:bg-gray-100 dark:text-gray-400 dark:hover:text-white dark:hover:bg-gray-700">
+                          <svg class="w-6 h-6" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M3 5a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1zM3 10a1 1 0 011-1h6a1 1 0 110 2H4a1 1 0 01-1-1zM3 15a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1z" clip-rule="evenodd"></path></svg>
+                        </button>
+                        <button id="toggleSidebarMobile" aria-expanded="true" aria-controls="sidebar" class="p-2 mr-2 text-gray-600 rounded cursor-pointer xl:hidden hover:text-gray-900 hover:bg-gray-100 focus:bg-gray-100 dark:focus:bg-gray-700 focus:ring-2 focus:ring-gray-100 dark:focus:ring-gray-700 dark:text-gray-400 dark:hover:bg-gray-700 dark:hover:text-white">
+                          <svg id="toggleSidebarMobileHamburger" class="w-6 h-6" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M3 5a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1zM3 10a1 1 0 011-1h6a1 1 0 110 2H4a1 1 0 01-1-1zM3 15a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1z" clip-rule="evenodd"></path></svg>
+                          <svg id="toggleSidebarMobileClose" class="hidden w-6 h-6" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" clip-rule="evenodd"></path></svg>
+                        </button>
+                    </div>
+                    <div id="bx-logo-container" class="bx-toolbar-item bx-ti-logo flex-2 xl:flex-none">
+                        <bx_injection:injection_logo_before />
+                            __main_logo__
+                        <bx_injection:injection_logo_after />
+                    </div>
+                    <div id="bx-menu-main-container" class="bx-toolbar-item bx-ti-menu bx-ti-stretcher flex-2 ml-4">
+                        <div class="bx-ti-cmt w-full">
+                            <bx_menu:sys_application />
+                        </div>
+                    </div>
+                    <bx_menu:sys_toolbar_member />
+                </div>
+            </div>
+        </div>
+    </div>
+    <div class="bx-main-content flex overflow-hidden">
+        <!-- BEG: Sidebar -->
+        <div id="sidebar" class="bx-main-column narrow fixed top-0 left-0 z-20 hidden xl:flex flex-col flex-shrink-0 w-64 h-full pt-14 duration-75 transition-width">
+            <div class="bx-mc-border relative flex flex-col flex-1 min-h-0 max-h-full pt-0 bg-white border-r border-gray-200 dark:bg-gray-800 dark:border-gray-700">
+                <div class="flex flex-col flex-1 py-2 overflow-y-auto">
+                    <div class="bx-mc-cnt flex-1 px-4 space-y-1 bg-white divide-y divide-gray-200 dark:bg-gray-800 dark:divide-gray-700">
+                        <bx_menu:sys_site_panel />
+                    </div>
+                </div>
+                <div class="absolute bottom-0 left-0 justify-center hidden w-full p-4 space-x-4 xl:flex" sidebar-bottom-menu>
+                    <!-- Some button based menu may be here -->
+                </div>
+            </div>
+        </div>
+        <div class="fixed inset-0 z-10 hidden bg-gray-900/50 dark:bg-gray-900/90" id="sidebarBackdrop"></div>
+        <!-- END: Sidebar -->
+        
+        <!-- BEG: Main Content -->
+        <div id="main-content" class="bx-main-column wide relative w-full h-full overflow-y-auto xl:ml-64">
+            <div class="cd-main-content-wrp">
+                <div class="cd-main-content bx-clearfix">
+                    <div class="content-wrapper-wrp">
+                        <div class="content-wrapper bx-def-box-sizing">
+                            <bx_injection:injection_between_cover_logo />
+                            __cover__
+                            <bx_injection:injection_between_cover_top_menu />
+                            <div class="bx-menu-main-bar-gap bx-def-centered bx-def-padding-leftright bx-def-page-width bx-def-box-sizing __site_submenu_hidden__">
+                                <div id="bx-menu-main-bar-wrapper" class="bx-menu-main-bar-wrapper bx-def-color-bg-sec">
+                                    <div id="bx-menu-main-bar" class="bx-menu-main-bar __site_submenu_class__">
+                                        <div class="bx-menu-main-bar-cnt px-4">
+                                            <bx_injection:injection_top_menu_before />
+                                            <div class="flex items-center h-full text-center">
+                                                <div class="relative flex-1 h-full">
+                                                    <div class="absolute w-full h-full">
+                                                        <bx_menu:sys_site_submenu />
+                                                    </div>
+                                                </div>
+                                                <div class="flex-none">
+                                                    <bx_menu:sys_site_manage />
+                                                </div>
+                                            </div>
+                                            <bx_injection:injection_top_menu_after />
+                                        </div>
+                                    </div>
+                                </div>
+                            </div>
+                            <bx_injection:injection_between_content_menu />
+                            <div id="bx-content-wrapper" class="bx-content-wrapper">
+                                __informer__
+                                <div class="bx-page-wrapper bx-def-centered bx-def-padding-sec-leftright bx-def-page-width bx-def-box-sizing">
+                                    <div id="bx-content-container" class="bx-def-padding-sec-left bx-def-padding-sec-right">
+                                        <main role="main" id="bx-content-main" class="bx-def-margin-sec-topbottom">
+                                            <bx_injection:injection_content_before />
+                                            __page_main_code__
+                                            <bx_injection:injection_content_after />
+                                            <div class="bx-clear"></div>
+                                            <bx_injection:banner_bottom />
+                                        </main> <!-- #bx-content-main -->
+                                        <bx_injection:injection_between_content_footer />
+                                    </div> <!-- #bx-content-container -->
+                                </div>
+                            </div> <!-- #bx-content-wrapper -->
+                        </div> <!-- .content-wrapper -->
+                    </div> <!-- .content-wrapper-wrp -->
+                </div> <!-- .cd-main-content -->
+            </div> <!-- .cd-main-content-wrp -->
+        </div> <!-- .bx-main-column -->
+    </div> <!-- .bx-main-content -->
+    <div id="bx-footer-wrapper" class="bx-footer-wrapper bx-def-image-bg-footer bx-def-color-bg-footer bx-def-border-footer bx-shadow-footer">    
+        <div class="bx-def-centered bx-def-padding-sec-leftright bx-def-box-sizing">
+            <footer id="bx-footer" class="bx-footer bx-def-padding-sec-left bx-def-padding-sec-right bx-clearfix">
+                <div class="bx-footer-cnt bx-content-padding-footer">
+                    <bx_injection:injection_footer_before />
+                    <div id="bx-menu-bottom" class="bx-def-margin-sec-top-auto">
+                        <bx_menu:sys_footer />
+                    </div>
+                    <bx_injection:injection_footer_after />
+                </div>
+            </footer>
+        </div>
+    </div>
+    <bx_menu:sys_site_action />
+</div>
+<bx_include_auto:_footer.html />

+ 68 - 0
modules/boonex/lucid/updates/15.0.2_15.0.3/source/install/config.php

@@ -0,0 +1,68 @@
+<?php
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Lucid Lucid template
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+$aConfig = array(
+    /**
+     * Main Section.
+     */
+    'type' => BX_DOL_MODULE_TYPE_TEMPLATE,
+    'name' => 'bx_lucid',
+    'title' => 'Lucid',
+    'note' => 'Design template',
+    'version' => '15.0.3',
+    'vendor' => 'UNA INC',
+    'help_url' => 'http://feed.una.io/?section={module_name}',
+
+    'compatible_with' => array(
+        '15.0.0-B2'
+    ),
+
+    /**
+     * 'home_dir' and 'home_uri' - should be unique. Don't use spaces in 'home_uri' and the other special chars.
+     */
+    'home_dir' => 'boonex/lucid/',
+    'home_uri' => 'lucid',
+
+    'db_prefix' => 'bx_lucid_',
+    'class_prefix' => 'BxLucid',
+
+    /**
+     * Category for language keys.
+     */
+    'language_category' => 'Boonex Lucid Template',
+
+    /**
+     * Installation/Uninstallation Section.
+     */
+    'install' => array(
+        'execute_sql' => 1,
+        'update_languages' => 1,
+    	'clear_db_cache' => 1
+    ),
+    'uninstall' => array (
+        'execute_sql' => 1,
+        'update_languages' => 1,
+    	'clear_db_cache' => 1
+    ),
+    'enable' => array(
+        'execute_sql' => 1
+    ),
+    'disable' => array(
+        'execute_sql' => 1
+    ),
+
+    /**
+     * Dependencies Section
+     */
+    'dependencies' => array(),
+);
+
+/** @} */

+ 51 - 0
modules/boonex/notifications/updates/15.0.2_15.0.3/install/config.php

@@ -0,0 +1,51 @@
+<?php
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ */
+
+$aConfig = array(
+    /**
+     * Main Section.
+     */
+    'title' => 'Notifications',
+    'version_from' => '15.0.2',
+    'version_to' => '15.0.3',
+    'vendor' => 'UNA INC',
+
+    'compatible_with' => array(
+        '15.0.0-B2'
+    ),
+
+    /**
+     * 'home_dir' and 'home_uri' - should be unique. Don't use spaces in 'home_uri' and the other special chars.
+     */
+    'home_dir' => 'boonex/notifications/updates/update_15.0.2_15.0.3/',
+    'home_uri' => 'notifications_update_1502_1503',
+
+    'module_dir' => 'boonex/notifications/',
+    'module_uri' => 'notifications',
+
+    'db_prefix' => 'bx_notifications_',
+    'class_prefix' => 'BxNtfs',
+
+    /**
+     * Installation/Uninstallation Section.
+     */
+    'install' => array(
+        'execute_sql' => 1,
+        'update_files' => 1,
+        'update_languages' => 1,
+        'clear_db_cache' => 1,
+    ),
+
+    /**
+     * Category for language keys.
+     */
+    'language_category' => 'Notifications',
+
+    /**
+     * Files Section
+     */
+    'delete_files' => array(),
+);

+ 13 - 0
modules/boonex/notifications/updates/15.0.2_15.0.3/install/installer.php

@@ -0,0 +1,13 @@
+<?php
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ */
+
+class BxNtfsUpdater extends BxDolStudioUpdater
+{
+    function __construct($aConfig)
+    {
+        parent::__construct($aConfig);
+    }
+}

+ 40 - 0
modules/boonex/notifications/updates/15.0.2_15.0.3/install/langs/en.xml

@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources name="en" flag="gb" title="English">
+	<string_add name="_bx_ntfs_form_etemplate"><![CDATA[Email Template]]></string_add>
+	<string_add name="_bx_ntfs_form_etemplate_display_add"><![CDATA[Add Email Template]]></string_add>
+	<string_add name="_bx_ntfs_form_etemplate_display_edit"><![CDATA[Edit Email Template]]></string_add>
+	<string_add name="_bx_ntfs_form_etemplate_input_controls"><![CDATA[Controls]]></string_add>
+	<string_add name="_bx_ntfs_form_etemplate_input_sys_do_submit"><![CDATA[Submit]]></string_add>
+	<string_add name="_bx_ntfs_form_etemplate_input_do_submit"><![CDATA[Submit]]></string_add>
+	<string_add name="_bx_ntfs_form_etemplate_input_sys_do_cancel"><![CDATA[Cancel]]></string_add>
+	<string_add name="_bx_ntfs_form_etemplate_input_do_cancel"><![CDATA[Cancel]]></string_add>
+	<string_add name="_bx_ntfs_form_etemplate_input_sys_type"><![CDATA[Type]]></string_add>
+	<string_add name="_bx_ntfs_form_etemplate_input_type"><![CDATA[Type]]></string_add>
+	<string_add name="_bx_ntfs_form_etemplate_input_sys_action"><![CDATA[Action]]></string_add>
+	<string_add name="_bx_ntfs_form_etemplate_input_action"><![CDATA[Action]]></string_add>
+	<string_add name="_bx_ntfs_form_etemplate_input_sys_subject"><![CDATA[Subject]]></string_add>
+	<string_add name="_bx_ntfs_form_etemplate_input_subject"><![CDATA[Subject]]></string_add>
+	<string_add name="_bx_ntfs_form_etemplate_input_sys_body"><![CDATA[Body]]></string_add>
+	<string_add name="_bx_ntfs_form_etemplate_input_body"><![CDATA[Body]]></string_add>
+	<string_add name="_bx_ntfs_form_etemplate_input_err_select"><![CDATA[This field is essential. Please select a value.]]></string_add>
+	<string_add name="_bx_ntfs_form_etemplate_input_err_enter"><![CDATA[This field is essential. Please fill it in.]]></string_add>
+	<string_add name="_bx_ntfs_lmi_cpt_etemplates_text"><![CDATA[Email Texts]]></string_add>
+	<string_add name="_bx_ntfs_option_delivery_timeout_inf"><![CDATA[Positive value other than '0' means that notifications will be send via Internal queue.]]></string_add>
+	<string_add name="_bx_ntfs_option_queue_add_threshold"><![CDATA[Threshold to add to Internal queue]]></string_add>
+	<string_add name="_bx_ntfs_option_queue_add_threshold_inf"><![CDATA['0' means that adding in the queue will be performed only when the queue is empty.]]></string_add>
+	<string_add name="_bx_ntfs_option_queue_add_limit"><![CDATA[Number of notifications to process and add to queue (Internal or System) per execution]]></string_add>
+	<string_add name="_bx_ntfs_option_queue_add_limit_inf"><![CDATA['0' means that all available notifications will be processed at once.]]></string_add>
+	<string_add name="_bx_ntfs_txt_et_preview_subject"><![CDATA[Subject:]]></string_add>
+	<string_add name="_bx_ntfs_txt_et_preview_body"><![CDATA[Body:]]></string_add>
+	<string_add name="_bx_ntfs_grid_column_title_ett_active"><![CDATA[Active]]></string_add>
+	<string_add name="_bx_ntfs_grid_column_title_ett_type"><![CDATA[Type]]></string_add>
+	<string_add name="_bx_ntfs_grid_column_title_ett_action"><![CDATA[Action]]></string_add>
+	<string_add name="_bx_ntfs_grid_column_title_ett_subject"><![CDATA[Subject]]></string_add>
+	<string_add name="_bx_ntfs_grid_action_title_ett_add"><![CDATA[Add]]></string_add>
+	<string_add name="_bx_ntfs_grid_action_title_ett_preview"><![CDATA[Preview]]></string_add>
+	<string_add name="_bx_ntfs_grid_action_title_ett_edit"><![CDATA[Edit]]></string_add>
+	<string_add name="_bx_ntfs_grid_action_title_ett_delete"><![CDATA[Delete]]></string_add>
+	<string_add name="_bx_ntfs_grid_popup_title_ett_add"><![CDATA[Add Email Template]]></string_add>
+	<string_add name="_bx_ntfs_grid_popup_title_ett_edit"><![CDATA[Edit Email Template]]></string_add>
+	<string_add name="_bx_ntfs_grid_popup_title_ett_preview"><![CDATA[Preview Email Template]]></string_add>
+</resources>

+ 32 - 0
modules/boonex/notifications/updates/15.0.2_15.0.3/install/sql/enable.sql

@@ -0,0 +1,32 @@
+SET @sName = 'bx_notifications';
+
+
+-- SETTINGS
+UPDATE `sys_options` SET `info`='_bx_ntfs_option_delivery_timeout_inf' WHERE `name`='bx_notifications_delivery_timeout';
+
+SET @iCategId = (SELECT `id` FROM `sys_options_categories` WHERE `name`=@sName LIMIT 1);
+DELETE FROM `sys_options` WHERE `name` IN ('bx_notifications_queue_add_threshold', 'bx_notifications_queue_add_limit');
+INSERT INTO `sys_options` (`name`, `value`, `category_id`, `caption`, `info`, `type`, `check`, `check_params`, `check_error`, `extra`, `order`) VALUES
+('bx_notifications_queue_add_threshold', '0', @iCategId, '_bx_ntfs_option_queue_add_threshold', '_bx_ntfs_option_queue_add_threshold_inf', 'digit', '', '', '', '', 21),
+('bx_notifications_queue_add_limit', '200', @iCategId, '_bx_ntfs_option_queue_add_limit', '_bx_ntfs_option_queue_add_limit_inf', 'digit', '', '', '', '', 22);
+
+
+-- GRIDS
+DELETE FROM `sys_objects_grid` WHERE `object`='bx_notifications_etemplates';
+INSERT INTO `sys_objects_grid` (`object`, `source_type`, `source`, `table`, `field_id`, `field_order`, `field_active`, `paginate_url`, `paginate_per_page`, `paginate_simple`, `paginate_get_start`, `paginate_get_per_page`, `filter_fields`, `filter_fields_translatable`, `filter_mode`, `sorting_fields`, `visible_for_levels`, `override_class_name`, `override_class_file`) VALUES
+('bx_notifications_etemplates', 'Sql', 'SELECT * FROM `bx_notifications_etemplates` WHERE 1 ', 'bx_notifications_etemplates', 'id', '', 'active', '', 100, NULL, 'start', '', '', 'type,action,subject,content', 'auto', '', 2147483647, 'BxNtfsGridEtemplates', 'modules/boonex/notifications/classes/BxNtfsGridEtemplates.php');
+
+DELETE FROM `sys_grid_fields` WHERE `object`='bx_notifications_etemplates';
+INSERT INTO `sys_grid_fields` (`object`, `name`, `title`, `width`, `translatable`, `chars_limit`, `params`, `order`) VALUES
+('bx_notifications_etemplates', 'switcher', '_bx_ntfs_grid_column_title_ett_active', '10%', 0, '', '', 10),
+('bx_notifications_etemplates', 'type', '_bx_ntfs_grid_column_title_ett_type', '15%', 0, '', '', 20),
+('bx_notifications_etemplates', 'action', '_bx_ntfs_grid_column_title_ett_action', '15%', 0, '', '', 30),
+('bx_notifications_etemplates', 'subject', '_bx_ntfs_grid_column_title_ett_subject', '40%', 0, '', '', 40),
+('bx_notifications_etemplates', 'actions', '', '20%', 0, '', '', 50);
+
+DELETE FROM `sys_grid_actions` WHERE `object`='bx_notifications_etemplates';
+INSERT INTO `sys_grid_actions` (`object`, `type`, `name`, `title`, `icon`, `icon_only`, `confirm`, `order`) VALUES
+('bx_notifications_etemplates', 'independent', 'add', '_bx_ntfs_grid_action_title_ett_add', '', 0, 0, 1),
+('bx_notifications_etemplates', 'single', 'preview', '_bx_ntfs_grid_action_title_ett_preview', 'eye', 1, 0, 1),
+('bx_notifications_etemplates', 'single', 'edit', '_bx_ntfs_grid_action_title_ett_edit', 'pencil-alt', 1, 0, 2),
+('bx_notifications_etemplates', 'single', 'delete', '_bx_ntfs_grid_action_title_ett_delete', 'remove', 1, 1, 3);

+ 51 - 0
modules/boonex/notifications/updates/15.0.2_15.0.3/install/sql/install.sql

@@ -0,0 +1,51 @@
+SET @sName = 'bx_notifications';
+
+
+-- TABLES
+CREATE TABLE IF NOT EXISTS `bx_notifications_etemplates` (
+  `id` int(11) NOT NULL auto_increment,
+  `type` varchar(255) NOT NULL,
+  `action` varchar(255) NOT NULL,
+  `subject` varchar(255) NOT NULL default '',
+  `body` text NOT NULL,
+  `active` tinyint(4) NOT NULL default '0',
+  PRIMARY KEY (`id`),
+  UNIQUE KEY `etemplate` (`type`(32), `action`(127))
+);
+
+
+-- FORMS
+DELETE FROM `sys_objects_form` WHERE `object`='bx_notifications_etemplate';
+INSERT INTO `sys_objects_form` (`object`, `module`, `title`, `action`, `form_attrs`, `submit_name`, `table`, `key`, `uri`, `uri_title`, `params`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES
+('bx_notifications_etemplate', @sName, '_bx_ntfs_form_etemplate', '', '', 'do_submit', 'bx_notifications_etemplates', 'id', '', '', '', 0, 1, '', '');
+
+DELETE FROM `sys_form_displays` WHERE `object`='bx_notifications_etemplate';
+INSERT INTO `sys_form_displays` (`display_name`, `module`, `object`, `title`, `view_mode`) VALUES
+('bx_notifications_etemplate_add', @sName, 'bx_notifications_etemplate', '_bx_ntfs_form_etemplate_display_add', 0),
+('bx_notifications_etemplate_edit', @sName, 'bx_notifications_etemplate', '_bx_ntfs_form_etemplate_display_edit', 0);
+
+DELETE FROM `sys_form_inputs` WHERE `object`='bx_notifications_etemplate';
+INSERT INTO `sys_form_inputs` (`object`, `module`, `name`, `value`, `values`, `checked`, `type`, `caption_system`, `caption`, `info`, `required`, `collapsed`, `html`, `attrs`, `attrs_tr`, `attrs_wrapper`, `checker_func`, `checker_params`, `checker_error`, `db_pass`, `db_params`, `editable`, `deletable`) VALUES
+('bx_notifications_etemplate', @sName, 'type', '', '', 0, 'select', '_bx_ntfs_form_etemplate_input_sys_type', '_bx_ntfs_form_etemplate_input_type', '', 1, 0, 0, '', '', '', 'Avail', '', '_bx_ntfs_form_etemplate_input_err_select', 'Xss', '', 0, 0),
+('bx_notifications_etemplate', @sName, 'action', '', '', 0, 'select', '_bx_ntfs_form_etemplate_input_sys_action', '_bx_ntfs_form_etemplate_input_action', '', 1, 0, 0, '', '', '', 'Avail', '', '_bx_ntfs_form_etemplate_input_err_select', 'Xss', '', 0, 0),
+('bx_notifications_etemplate', @sName, 'subject', '', '', 0, 'text', '_bx_ntfs_form_etemplate_input_sys_subject', '_bx_ntfs_form_etemplate_input_subject', '', 1, 0, 0, '', '', '', 'Avail', '', '_bx_ntfs_form_etemplate_input_err_enter', 'Xss', '', 0, 0),
+('bx_notifications_etemplate', @sName, 'body', '', '', 0, 'textarea', '_bx_ntfs_form_etemplate_input_sys_body', '_bx_ntfs_form_etemplate_input_body', '', 1, 0, 0, '', '', '', 'Avail', '', '_bx_ntfs_form_etemplate_input_err_enter', 'XssHtml', '', 0, 0),
+('bx_notifications_etemplate', @sName, 'controls', '', 'do_submit,do_cancel', 0, 'input_set', '_bx_ntfs_form_etemplate_input_controls', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 0, 0),
+('bx_notifications_etemplate', @sName, 'do_submit', '_bx_ntfs_form_etemplate_input_do_submit', '', 0, 'submit', '_bx_ntfs_form_etemplate_input_sys_do_submit', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 0, 0),
+('bx_notifications_etemplate', @sName, 'do_cancel', '_bx_ntfs_form_etemplate_input_do_cancel', '', 0, 'button', '_bx_ntfs_form_etemplate_input_do_cancel', '', '', 0, 0, 0, 'a:2:{s:7:"onclick";s:45:"$(''.bx-popup-applied:visible'').dolPopupHide()";s:5:"class";s:22:"bx-def-margin-sec-left";}', '', '', '', '', '', '', '', 0, 0);
+
+DELETE FROM `sys_form_display_inputs` WHERE `display_name` IN ('bx_notifications_etemplate_add', 'bx_notifications_etemplate_edit');
+INSERT INTO `sys_form_display_inputs` (`display_name`, `input_name`, `visible_for_levels`, `active`, `order`) VALUES
+('bx_notifications_etemplate_add', 'type', 2147483647, 1, 1),
+('bx_notifications_etemplate_add', 'action', 2147483647, 1, 2),
+('bx_notifications_etemplate_add', 'subject', 2147483647, 1, 3),
+('bx_notifications_etemplate_add', 'body', 2147483647, 1, 4),
+('bx_notifications_etemplate_add', 'controls', 2147483647, 1, 5),
+('bx_notifications_etemplate_add', 'do_submit', 2147483647, 1, 6),
+('bx_notifications_etemplate_add', 'do_cancel', 2147483647, 1, 7),
+
+('bx_notifications_etemplate_edit', 'subject', 2147483647, 1, 1),
+('bx_notifications_etemplate_edit', 'body', 2147483647, 1, 2),
+('bx_notifications_etemplate_edit', 'controls', 2147483647, 1, 3),
+('bx_notifications_etemplate_edit', 'do_submit', 2147483647, 1, 4),
+('bx_notifications_etemplate_edit', 'do_cancel', 2147483647, 1, 5);

+ 323 - 0
modules/boonex/notifications/updates/15.0.2_15.0.3/source/classes/BxNtfsConfig.php

@@ -0,0 +1,323 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Notifications Notifications
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+bx_import('BxDolPrivacy');
+
+class BxNtfsConfig extends BxBaseModNotificationsConfig
+{
+    protected $_iSummaryMaxLen;
+    protected $_iOwnerNameMaxLen;
+    protected $_iContentMaxLen;
+    protected $_iPushMaxLen;
+    protected $_iEmailSubjectMaxLen;
+
+    protected $_aHandlersHiddenEmail;
+    protected $_aHandlersHiddenPush;
+
+    /**
+     * Group settings by action. Enabled by default.
+     */
+    protected $_bSettingsGrouped;
+    protected $_aSettingsTypes;
+    protected $_aDeliveryTypes;
+
+    protected $_aModulesProfiles;
+    protected $_aModulesContexts;
+
+    protected $_iDeliveryTimeout;
+
+    protected $_bEventsGrouped;
+
+    protected $_bClickedIndicator;
+
+    /**
+     * Constructor
+     */
+    public function __construct($aModule)
+    {
+        parent::__construct($aModule);
+
+        $this->CNF = array (
+            // page URIs
+            'URL_HOME' => 'page.php?i=notifications-view',
+
+            // some params
+            'PARAM_QUEUE_ADD_THRESHOLD' => 'bx_notifications_queue_add_threshold',
+            'PARAM_QUEUE_ADD_LIMIT' => 'bx_notifications_queue_add_limit',
+            'PARAM_COMMENT_POST_EXT' => 'bx_notifications_enable_comment_post_ext',
+            'PARAM_REPLY_AS_COMMENT' => 'bx_notifications_enable_reply_as_comment',
+            'PARAM_PROCESSED_EVENT' => 'bx_notifications_processed_event',
+
+            // objects
+            'OBJECT_FORM_ETEMPLATE' => 'bx_notifications_etemplate',
+            'OBJECT_FORM_ETEMPLATE_DISPLAY_ADD' => 'bx_notifications_etemplate_add',
+            'OBJECT_FORM_ETEMPLATE_DISPLAY_EDIT' => 'bx_notifications_etemplate_edit',
+            'OBJECT_MENU_SUBMENU' => 'bx_notifications_submenu', // main module submenu
+            'OBJECT_MENU_SETTINGS' => 'bx_notifications_settings', // settings submenu
+            'OBJECT_GRID_SETTINGS_ADMINISTRATION' => 'bx_notifications_settings_administration',
+            'OBJECT_GRID_SETTINGS_COMMON' => 'bx_notifications_settings_common',
+            'OBJECT_GRID_ETEMPLATES' => 'bx_notifications_etemplates',
+
+            // some language keys
+            'T' => array(
+                'setting_personal' => '_bx_ntfs_setting_type_personal',
+                'setting_follow_member' => '_bx_ntfs_setting_type_follow_member',
+                'setting_follow_context' => '_bx_ntfs_setting_type_follow_context',
+                'setting_other' => '_bx_ntfs_setting_type_other',
+            )
+        );
+
+        $this->_aPrefixes = array(
+            'style' => 'bx-ntfs',
+            'language' => '_bx_ntfs',
+            'option' => 'bx_notifications_'
+        );
+
+        $this->_iSummaryMaxLen = 0;
+        $this->_iOwnerNameMaxLen = 0;
+        $this->_iContentMaxLen = 0;
+        $this->_iEmailSubjectMaxLen = 0;
+        $this->_iPushMaxLen = 0;
+
+        $this->_aHandlerDescriptor = array('module_name' => '', 'module_method' => '', 'module_class' => '');
+        $this->_sHandlersMethod = 'get_notifications_data';
+        $this->_aHandlersHiddenEmail = array();
+        $this->_aHandlersHiddenPush = array();
+
+        $this->_bSettingsGrouped = true;
+        $this->_aSettingsTypes = array(
+            BX_NTFS_STYPE_PERSONAL,
+            BX_NTFS_STYPE_FOLLOW_MEMBER,
+            BX_NTFS_STYPE_FOLLOW_CONTEXT,
+            //BX_NTFS_STYPE_OTHER           //TODO: May be it can be removed, because there is no events(alerts) for this type.
+        );
+
+        $this->_aDeliveryTypes = [
+            BX_NTFS_DTYPE_SITE,
+            BX_NTFS_DTYPE_EMAIL,
+            BX_NTFS_DTYPE_PUSH
+        ];
+
+        $this->_aModulesProfiles = false;
+        $this->_aModulesContexts = false;
+
+        $this->_aJsClasses = array(
+            'main' => 'BxNtfsMain',
+            'view' => 'BxNtfsView',
+        );
+        $this->_aJsObjects = array(
+            'main' => 'oBxNtfsMain',
+            'view' => 'oBxNtfsView',
+        );
+
+        $sHtmlPrefix = str_replace('_', '-', $this->_sName);
+        $this->_aHtmlIds = [
+            'main' => [
+                'field_action' => $sHtmlPrefix . '-field-action',
+            ],
+            'view' => [
+                'block' => $sHtmlPrefix,
+                'events' => $sHtmlPrefix . '-events',
+                'event' => $sHtmlPrefix . '-event-',
+                'add_etemplate_popup' => $sHtmlPrefix . '-etemplate-add',
+                'edit_etemplate_popup' => $sHtmlPrefix . '-etemplate-edit',
+                'preview_etemplate_popup' => $sHtmlPrefix . '-etemplate-preview',
+            ]
+        ];
+    }
+
+    public function init(&$oDb)
+    {
+    	parent::init($oDb);
+
+    	$sOptionPrefix = $this->getPrefix('option');
+    	$this->_aPerPage = array(
+            'default' => (int)getParam($sOptionPrefix . 'events_per_page'),
+    	    'preview' => (int)getParam($sOptionPrefix . 'events_per_preview')
+    	);
+
+        $this->_bSettingsGrouped = getParam($sOptionPrefix . 'enable_group_settings') == 'on';
+
+    	$aSettings = array(
+    	    'site' => '',
+    	    'email' => 'Email',
+    	    'push' => 'Push'
+    	);
+    	foreach($aSettings as $sSetting => $sVariable) {
+    	    $sHideTimeline = getParam($sOptionPrefix . 'events_hide_' . $sSetting);
+            if(!empty($sHideTimeline))
+                $this->{'_aHandlersHidden' . $sVariable} = explode(',', $sHideTimeline);
+    	}
+
+        $this->_iDeliveryTimeout = (int)getParam($sOptionPrefix . 'delivery_timeout');
+
+        $this->_bEventsGrouped = getParam($sOptionPrefix . 'enable_group_events') == 'on';
+
+        $this->_bClickedIndicator = getParam($sOptionPrefix . 'enable_clicked_indicator') == 'on';
+
+        $this->_iSummaryMaxLen = (int)getParam($sOptionPrefix . 'summary_chars');
+        $this->_iOwnerNameMaxLen = (int)getParam($sOptionPrefix . 'owner_name_chars');
+        $this->_iContentMaxLen = (int)getParam($sOptionPrefix . 'content_chars');
+        $this->_iEmailSubjectMaxLen = (int)getParam($sOptionPrefix . 'email_subject_chars');
+        $this->_iPushMaxLen = (int)getParam($sOptionPrefix . 'push_message_chars');
+    }
+
+    public function getSummaryMaxLen()
+    {
+        return $this->_iSummaryMaxLen;
+    }
+
+    public function getOwnerNameMaxLen()
+    {
+        return $this->_iOwnerNameMaxLen;
+    }
+
+    public function getContentMaxLen()
+    {
+        return $this->_iContentMaxLen;
+    }
+
+    public function getPushMaxLen()
+    {
+        return $this->_iPushMaxLen;
+    }
+
+    public function getEmailSubjectMaxLen()
+    {
+        return $this->_iEmailSubjectMaxLen;
+    }
+
+    public function getHandlersHidden($sType = '')
+    {
+        if(!in_array($sType, array('', 'email', 'push')))
+            return array();
+
+        return $this->{'_aHandlersHidden' . ucfirst($sType)};
+    }
+
+    public function isSettingsGrouped()
+    {
+        return $this->_bSettingsGrouped;
+    }
+
+    public function getSettingsTypes()
+    {
+        return $this->_aSettingsTypes;
+    }
+    
+    public function getDeliveryTypes()
+    {
+        return $this->_aDeliveryTypes;
+    }
+
+    public function getDeliveryTimeout()
+    {
+        return $this->_iDeliveryTimeout;
+    }
+
+    public function isEventsGrouped()
+    {
+        return $this->_bEventsGrouped;
+    }
+
+    public function isClickedIndicator()
+    {
+        return $this->_bClickedIndicator;
+    }
+
+    public function getProcessedEvent()
+    {
+        return (int)getParam($this->CNF['PARAM_PROCESSED_EVENT'], false);
+    }
+
+    public function setProcessedEvent($iEvent)
+    {
+        setParam($this->CNF['PARAM_PROCESSED_EVENT'], $iEvent);
+    }
+
+    /**
+     * Ancillary functions
+     */
+    public function getViewUrl()
+    {
+        return bx_absolute_url(BxDolPermalinks::getInstance()->permalink('page.php?i=notifications-view'));
+    }
+
+    public function getContentModule(&$aEvent)
+    {
+        $sModule = $aEvent['type'];
+        if($this->_oDb->isEnabledByName($sModule))
+            return $sModule;
+
+        $sModule = str_replace(array('_media', '_reactions'), array('', ''), $sModule);
+        if($this->_oDb->isEnabledByName($sModule))
+            return $sModule;
+
+        return '';
+    }
+
+    public function getContentObjectId(&$aEvent)
+    {
+        $bContentObjectId = !empty($aEvent['content']['object_id']);
+        if(!$bContentObjectId) {
+            if(in_array($aEvent['action'], ['replyPost']))
+                return false;
+
+            if(strpos($aEvent['type'], '_media') !== false && in_array($aEvent['action'], ['commentPost', 'doVote', 'doVoteUp', 'doVoteDown']))
+                return false;
+        }
+
+        return $bContentObjectId ? (int)$aEvent['content']['object_id'] : (int)$aEvent['object_id'];
+    }
+
+    public function getProfileBasedModules() 
+    {
+        if ($this->_aModulesProfiles !== false && $this->_aModulesContexts !== false)
+            return array($this->_aModulesProfiles, $this->_aModulesContexts);
+
+        if (getParam('sys_db_cache_enable')) {
+            $oDb = BxDolDb::getInstance();
+            $oCache = $oDb->getDbCacheObject();
+            $sCacheKey = $oDb->genDbCacheKey('bx_ntfs_profile_based_modules');
+            $aData = $oCache->getData($sCacheKey);
+            if (null === $aData) {
+                $aData = $this->_getProfileBasedModulesData();
+                $oCache->setData ($sCacheKey, $aData);
+            }
+        } 
+        else {
+            $aData = $this->_getProfileBasedModulesData();
+        }
+
+        return $aData;
+    }
+
+    protected function _getProfileBasedModulesData() 
+    {
+        $this->_aModulesProfiles = [];
+        $this->_aModulesContexts = [];
+
+        $aModules = BxDolModuleQuery::getInstance()->getModulesBy(['type' => 'modules']);
+        foreach($aModules as $aModule) {
+            if(!bx_is_srv($aModule['name'], 'act_as_profile'))
+                continue;
+
+            if(bx_srv($aModule['name'], 'act_as_profile'))
+                $this->_aModulesProfiles[] = $aModule['name'];
+            else
+                $this->_aModulesContexts[] = $aModule['name'];
+        }
+
+        return [$this->_aModulesProfiles, $this->_aModulesContexts];
+    }
+}
+
+/** @} */

+ 183 - 0
modules/boonex/notifications/updates/15.0.2_15.0.3/source/classes/BxNtfsCronNotify.php

@@ -0,0 +1,183 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Notifications Notifications
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+/**
+ * Get notifications list and retrieve recipients for each notification. Put emails in:
+ * a) internal queue, if Delivery Timeout is set,
+ * b) system queue otherwise
+ */
+class BxNtfsCronNotify extends BxDolCron
+{
+    protected $_sModule;
+    protected $_oModule;
+
+    protected $_bDeliveryTimeout;
+
+    public function __construct()
+    {
+    	$this->_sModule = 'bx_notifications';
+    	$this->_oModule = BxDolModule::getInstance($this->_sModule);
+
+        parent::__construct();
+
+        $this->_bDeliveryTimeout = $this->_oModule->_oConfig->getDeliveryTimeout() > 0;
+    }
+
+    public function processing()
+    {
+        $CNF = &$this->_oModule->_oConfig->CNF;
+
+        if($this->_bDeliveryTimeout) {
+            $iCount = (int)$this->_oModule->_oDb->queueGet(['type' => 'count']);
+            if($iCount > (int)getParam($CNF['PARAM_QUEUE_ADD_THRESHOLD']))
+                return;
+        }
+
+        $aEvents = $this->_oModule->_oDb->getEventsToProcess((int)getParam($CNF['PARAM_QUEUE_ADD_LIMIT']));
+
+        foreach($aEvents as $aEvent) {
+            if(!empty($aEvent['content']) && is_string($aEvent['content']))
+                $aEvent['content'] = unserialize($aEvent['content']);
+
+            $this->_sendNotifications($aEvent);
+        }
+    }
+
+    protected function _sendNotifications(&$aEvent)
+    {
+        $aHandler = $this->_oModule->_oConfig->getHandlers($aEvent['type'] . '_' . $aEvent['action']);
+        if(empty($aHandler) || !is_array($aHandler))
+            return;
+
+        $aDeliveryTypes = array();
+
+        $iId = (int)$aEvent['id'];
+        $iSilentMode = $this->_oModule->getSilentMode($aEvent['content']);
+        switch($iSilentMode) {
+            case BX_BASE_MOD_NTFS_SLTMODE_ABSOLUTE:
+            case BX_NTFS_SLTMODE_ABSOLUTE:
+            case BX_NTFS_SLTMODE_SITE:
+                return;
+
+            case BX_NTFS_SLTMODE_SITE_EMAIL:
+                $aDeliveryTypes[] = BX_BASE_MOD_NTFS_DTYPE_EMAIL;
+                break;
+
+            case BX_NTFS_SLTMODE_SITE_PUSH:
+                $aDeliveryTypes[] = BX_BASE_MOD_NTFS_DTYPE_PUSH;
+                break;
+
+            default:
+                $aDeliveryTypes = array(BX_BASE_MOD_NTFS_DTYPE_EMAIL, BX_BASE_MOD_NTFS_DTYPE_PUSH);
+        }
+
+        $aSendUsing = array();
+        foreach($aDeliveryTypes as $sDeliveryType) {
+            $aHidden = $this->_oModule->_oConfig->getHandlersHidden($sDeliveryType);
+            if(in_array($aHandler['id'], $aHidden))
+                continue;
+
+            $sMethodPostfix = bx_gen_method_name($sDeliveryType);
+            $sMethodGet = 'getNotification' . $sMethodPostfix;
+            $sMethodSend = 'sendNotification' . $sMethodPostfix;
+            if(!$this->_oModule->_oTemplate->isMethodExists($sMethodGet) || !method_exists($this->_oModule, $sMethodSend))
+                continue;
+
+            $aSendUsing[$sDeliveryType] = array(
+                'method_get' => $sMethodGet,
+            	'method_send' => $sMethodSend,
+            );
+        }
+
+        if(empty($aSendUsing) || !is_array($aSendUsing))
+            return;
+
+        $iOwner = (int)$aEvent['owner_id'];
+        $aRecipients = array();
+
+        //--- Get recipients: Subscribers.
+        $oConnection = BxDolConnection::getObjectInstance($this->_oModule->_oConfig->getObject('conn_subscriptions'));
+        $aSubscribers = $oConnection->getConnectedInitiators($iOwner);
+        if(!empty($aSubscribers) && is_array($aSubscribers)) {
+            $oOwner = BxDolProfile::getInstance($iOwner);
+            if(!empty($oOwner)) {
+                $sSettingType = bx_srv($oOwner->getModule(), 'act_as_profile') ? BX_NTFS_STYPE_FOLLOW_MEMBER : BX_NTFS_STYPE_FOLLOW_CONTEXT;
+
+                foreach($aSubscribers as $iSubscriber) 
+                    $this->_addRecipient($iSubscriber, $sSettingType, $aRecipients);
+            }
+        }
+
+        //--- Get recipients: Content owner.
+        $iObjectOwner = (int)$aEvent['object_owner_id'];
+        if($iOwner != $iObjectOwner)
+            $this->_addRecipient($iObjectOwner, BX_NTFS_STYPE_PERSONAL, $aRecipients);
+
+        //--- Check recipients and send notifications.
+        list($aModulesProfiles) = $this->_oModule->_oConfig->getProfileBasedModules();
+        $aRecipientsId = $this->_oModule->_oDb->filterProfileIdsByModule(array_keys($aRecipients), $aModulesProfiles);
+        $aRecipients = array_intersect_key($aRecipients, array_flip($aRecipientsId));
+
+        $oPrivacyInt = BxDolPrivacy::getObjectInstance($this->_oModule->_oConfig->getObject('privacy_view'));
+        $oPrivacyExt = $this->_oModule->_oConfig->getPrivacyObject($aEvent['type'] . '_' . $aEvent['action']);
+        foreach($aRecipients as $iRecipient => $aSettingTypes) {
+            $iIdRead = $this->_oModule->_oDb->getLastRead($iRecipient);
+            if($iIdRead >= $iId)
+                continue;
+
+            if($oPrivacyExt !== false && !$oPrivacyExt->check($aEvent['id'], $iRecipient)) 
+                continue;
+
+            if($oPrivacyInt !== false && !$oPrivacyInt->check($aEvent['id'], $iRecipient))
+                continue;
+
+            foreach($aSendUsing as $sDeliveryType => $aDeliveryType)
+                foreach($aSettingTypes as $sSettingType) {
+                    $aSetting = $this->_oModule->_oDb->getSetting(array('by' => 'tsu_allowed', 'handler_id' => $aHandler['id'], 'delivery' => $sDeliveryType, 'type' => $sSettingType, 'user_id' => $iRecipient));
+                    if(empty($aSetting) || !is_array($aSetting))
+                        continue;
+
+                    if((int)$aSetting['active_adm'] == 0 || (int)$aSetting['active_pnl'] == 0)
+                        continue;
+
+                    $mixedNotification = $this->_oModule->_oTemplate->{$aDeliveryType['method_get']}($iRecipient, $aEvent);
+                    if($mixedNotification === false)
+                        continue;
+            
+                    /**
+                     * 'break' is essential in the next two conditions to avoid 
+                     * duplicate sending to the same recipient.
+                     */
+                    if($this->_bDeliveryTimeout && $this->_oModule->_oDb->queueAdd(array(
+                        'profile_id' => $iRecipient, 
+                        'event_id' => $aEvent['id'], 
+                        'delivery' => $sDeliveryType,
+                        'content' => serialize($mixedNotification),
+                        'date' => time()
+                    )) !== false)
+                        break;
+
+                    if($this->_oModule->{$aDeliveryType['method_send']}($iRecipient, $mixedNotification) !== false)
+                        break;
+                }
+        }
+    }
+
+    protected function _addRecipient($iUser, $sSettingType, &$aRecipients)
+    {
+        if(!isset($aRecipients[$iUser]))
+            $aRecipients[$iUser] = array();
+
+        $aRecipients[$iUser][] = $sSettingType;
+    }
+}
+
+/** @} */

+ 48 - 0
modules/boonex/notifications/updates/15.0.2_15.0.3/source/classes/BxNtfsCronQueue.php

@@ -0,0 +1,48 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Notifications Notifications
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+/**
+ * Send notifications from internal queue by moving them to system one.
+ * Is working if Delivery Timeout is set.
+ */
+class BxNtfsCronQueue extends BxDolCron
+{
+    protected $_sModule;
+    protected $_oModule;
+
+    public function __construct()
+    {
+    	$this->_sModule = 'bx_notifications';
+    	$this->_oModule = BxDolModule::getInstance($this->_sModule);
+
+        parent::__construct();
+    }
+
+    public function processing()
+    {
+        $iDeliveryTimeout = $this->_oModule->_oConfig->getDeliveryTimeout();
+        if($iDeliveryTimeout == 0)
+            return;
+
+        $aItems = $this->_oModule->_oDb->queueGet(array('type' => 'all_to_send', 'timeout' => $iDeliveryTimeout));
+        if(empty($aItems) || !is_array($aItems))
+            return;
+
+        $this->_oModule->_oDb->queueDeleteByIds(array_keys($aItems));
+
+        $aSent = array();
+        foreach($aItems as $aItem)
+            if($this->_oModule->{'sendNotification' . bx_gen_method_name($aItem['delivery'])}($aItem['profile_id'], unserialize($aItem['content'])) !== false)
+                $aSent[] = $aItem['id'];
+    }
+}
+
+/** @} */

+ 618 - 0
modules/boonex/notifications/updates/15.0.2_15.0.3/source/classes/BxNtfsDb.php

@@ -0,0 +1,618 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Notifications Notifications
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+class BxNtfsDb extends BxBaseModNotificationsDb
+{
+    protected $_sTableEvt2Usr;
+    protected $_sTableQueue;
+    protected $_sTableRead;
+    protected $_sTableEtemplates;
+
+    /*
+     * Constructor.
+     */
+    function __construct(&$oConfig)
+    {
+        parent::__construct($oConfig);
+
+        $this->_aDeliveryTypes = array(
+            BX_BASE_MOD_NTFS_DTYPE_SITE, 
+            BX_BASE_MOD_NTFS_DTYPE_EMAIL, 
+            BX_BASE_MOD_NTFS_DTYPE_PUSH
+        );
+
+        $this->_sTableEvt2Usr = $this->_sPrefix . 'events2users';
+        $this->_sTableQueue = $this->_sPrefix . 'queue';
+        $this->_sTableRead = $this->_sPrefix . 'read';
+        $this->_sTableEtemplates = $this->_sPrefix . 'etemplates';
+    }
+
+    public function getHandlerTypes()
+    {
+        return $this->getColumn("SELECT DISTINCT `alert_unit` FROM `{$this->_sTableHandlers}` WHERE `type`='insert'");
+    }
+
+    public function getHandlerActions($sUnit = '')
+    {
+        $aBindings = [];
+        $sWhereClause = "";
+
+        if($sUnit) {
+            $aBindings['alert_unit'] = $sUnit;
+            $sWhereClause .= " AND `alert_unit`=:alert_unit";
+        }
+
+        return $this->getColumn("SELECT DISTINCT `alert_action` FROM `{$this->_sTableHandlers}` WHERE `type`='insert'" . $sWhereClause, $aBindings);
+    }
+
+    public function markAsClicked($iUserId, $iEventId)
+    {
+        return $this->query("INSERT INTO `" . $this->_sTableEvt2Usr . "` (`user_id`, `event_id`, `clicked`) VALUES (:user_id, :event_id, 1) ON DUPLICATE KEY UPDATE `clicked`=1", [
+            'user_id' => $iUserId,
+            'event_id' => $iEventId
+        ]);
+    }
+
+    public function markAsRead($iUserId, $iEventId)
+    {
+        $this->queueDeleteByProfile($iUserId, $iEventId);
+
+        return $this->query("INSERT INTO `" . $this->_sTableRead . "` (`user_id`, `event_id`) VALUES (:user_id, :event_id) ON DUPLICATE KEY UPDATE `event_id`=:event_id", array(
+            'user_id' => $iUserId,
+            'event_id' => $iEventId
+        ));
+    }
+
+    public function getLastRead($iUserId)
+    {
+        return (int)$this->getOne("SELECT `event_id` FROM `" . $this->_sTableRead . "` WHERE `user_id`=:user_id LIMIT 1", array(
+            'user_id' => (int)$iUserId
+        ));
+    }
+
+    public function deleteEvent($aParams, $sWhereAddon = "")
+    {
+        $aEvents = $this->getAll("SELECT * FROM `{$this->_sTable}` WHERE " . $this->arrayToSQL($aParams, " AND ") . $sWhereAddon);
+        if(!empty($aEvents) && is_array($aEvents)) 
+            foreach($aEvents as $aEvent)
+                $this->queueDelete(array('event_id' => $aEvent['id']));
+
+        return parent::deleteEvent($aParams, $sWhereAddon);
+    }
+
+    public function getEvents($aParams, $bReturnCount = false)
+    {
+        /**
+         * @hooks
+         * @hookdef hook-bx_notifications-get_events_before 'bx_notifications', 'get_events_before' - hook to override params which are used to get events
+         * - $unit_name - equals `bx_notifications`
+         * - $action - equals `get_events_before`
+         * - $object_id - not used
+         * - $sender_id - not used
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `params` - [array] by ref, params array as key&value pairs, can be overridden in hook processing
+         * @hook @ref hook-bx_notifications-get_events_before
+         */
+        bx_alert($this->_oConfig->getName(), 'get_events_before', 0, 0, [
+            'params' => &$aParams,
+            'params_ref' => &$aParams,
+        ]);
+
+        if($aParams['browse'] != 'list' || $aParams['type'] != BX_NTFS_TYPE_OBJECT_OWNER_AND_CONNECTIONS)
+            return parent::getEvents($aParams);
+
+        $bClickedIndicator = $this->_oConfig->isClickedIndicator();
+        $bCountOnly = !empty($aParams['count_only']);
+        $bViewerId = !empty($aParams['viewer_id']);
+
+        $sSelectClauseClicked = ", 0 AS `clicked`";
+        $sLimitClause = isset($aParams['per_page']) ? "LIMIT 0, " . ($aParams['start'] + $aParams['per_page']) : "";
+
+        //--- Get query for 'Object Owner' notifications
+        $aParams['type'] = BX_BASE_MOD_NTFS_TYPE_OBJECT_OWNER;
+        list($sMethod, $sSelectClause, $sJoinClausePo, $sWhereClausePo, $sOrderClausePo) = $this->_getSqlPartsEvents($aParams);       
+
+        if($bClickedIndicator && $bViewerId) {
+            $sSelectClauseClicked = ", IF(ISNULL(`{$this->_sTableEvt2Usr}`.`clicked`) OR `{$this->_sTableEvt2Usr}`.`clicked`=0, 0, 1) AS `clicked`";
+            $sJoinClausePo .= $this->prepareAsString(" LEFT JOIN `{$this->_sTableEvt2Usr}` ON `{$this->_sTable}`.`id`=`{$this->_sTableEvt2Usr}`.`event_id` AND `{$this->_sTableEvt2Usr}`.`user_id`=?", $aParams['viewer_id']);
+        }
+
+        $sQueryOwner = "SELECT {select}
+            FROM `{$this->_sTable}`
+            LEFT JOIN `{$this->_sTableHandlers}` ON `{$this->_sTable}`.`type`=`{$this->_sTableHandlers}`.`alert_unit` AND `{$this->_sTable}`.`action`=`{$this->_sTableHandlers}`.`alert_action` " . $sJoinClausePo . "
+            WHERE 1 " . $sWhereClausePo . (!$bCountOnly ? " " . $sOrderClausePo . " " . $sLimitClause : "");
+
+        //--- Get query for 'Connections based' notifications
+        $aParams['type'] = BX_BASE_MOD_NTFS_TYPE_CONNECTIONS;
+        list($sMethod, $sSelectClause, $sJoinClausePc, $sWhereClausePc, $sOrderClausePc) = $this->_getSqlPartsEvents($aParams);
+
+        if($bClickedIndicator && $bViewerId) {
+            $sSelectClauseClicked = ", IF(ISNULL(`{$this->_sTableEvt2Usr}`.`clicked`) OR `{$this->_sTableEvt2Usr}`.`clicked`=0, 0, 1) AS `clicked`";
+            $sJoinClausePc .= $this->prepareAsString(" LEFT JOIN `{$this->_sTableEvt2Usr}` ON `{$this->_sTable}`.`id`=`{$this->_sTableEvt2Usr}`.`event_id` AND `{$this->_sTableEvt2Usr}`.`user_id`=?", $aParams['viewer_id']);
+        }
+
+        $sQueryConnections = "SELECT {select}
+            FROM `{$this->_sTable}`
+            LEFT JOIN `{$this->_sTableHandlers}` ON `{$this->_sTable}`.`type`=`{$this->_sTableHandlers}`.`alert_unit` AND `{$this->_sTable}`.`action`=`{$this->_sTableHandlers}`.`alert_action` " . $sJoinClausePc . "
+            WHERE 1 " . $sWhereClausePc . (!$bCountOnly ? " " . $sOrderClausePc . " " . $sLimitClause : "");
+
+        $sSelectClause .= $sSelectClauseClicked;
+
+        //--- Combine both queries in one
+        $bStartFromItem = isset($aParams['start_from_item']) && $aParams['start_from_item'] === true;
+
+        $sUnionMethod = 'getColumn';
+        $sUnionOrderClause = $sUnionLimitClause = '';
+        if(!$bCountOnly) {
+            $sUnionMethod = $sMethod;
+            $sUnionOrderClause = "ORDER BY `date` DESC, `id` DESC";
+            $sUnionLimitClause = isset($aParams['per_page']) ? "LIMIT " . (!$bStartFromItem ? $aParams['start'] : 0) . ", " . $aParams['per_page'] : "";
+        }
+
+        $aAlertParams = $aParams;
+        unset($aAlertParams['browse']);
+
+        /**
+         * Parts: 
+         * PO - notifications related to Owner's content
+         * PC - notifications related to Connections' content
+         */
+        /**
+         * @hooks
+         * @hookdef hook-bx_notifications-get_events 'bx_notifications', 'get_events' - hook to override events list which will be received from database
+         * - $unit_name - equals `bx_notifications`
+         * - $action - equals `get_events`
+         * - $object_id - not used
+         * - $sender_id - not used
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `browse` - [string] browsing type
+         *      - `params` - [array] browse params array as key&value pairs
+         *      - `table` - [string] datatbase table name
+         *      - `method` - [string] by ref, database class method name, @see BxDolDb, can be overridden in hook processing
+         *      - `select_clause` - [string] by ref, 'select' part of SQL query, can be overridden in hook processing
+         *      - `join_clause_po` - [string] by ref, 'join' part of Owner's SQL query, can be overridden in hook processing
+         *      - `join_clause_pc` - [string] by ref, 'join' part of Connections' SQL query, can be overridden in hook processing
+         *      - `where_clause_po` - [string] by ref, 'where' part of Owner's SQL query, can be overridden in hook processing
+         *      - `where_clause_pc` - [string] by ref, 'where' part of Connections' SQL query, can be overridden in hook processing
+         *      - `order_clause_po` - [string] by ref, 'order' part of Owner's SQL query, can be overridden in hook processing
+         *      - `order_clause_pc` - [string] by ref, 'order' part of Connections' SQL query, can be overridden in hook processing
+         *      - `order_clause` - [string] by ref, 'order' part of SQL query, can be overridden in hook processing
+         *      - `limit_clause` - [string] by ref, 'limit' part of SQL query, can be overridden in hook processing
+         *      - `query_po` - [string] by ref, Owner's SQL query, can be overridden in hook processing
+         *      - `query_pc` - [string] by ref, Connections' SQL query, can be overridden in hook processing
+         * @hook @ref hook-bx_notifications-get_events
+         */
+        bx_alert($this->_oConfig->getName(), 'get_events', 0, 0, [
+            'browse' => $aParams['browse'],
+            'params' => $aAlertParams,
+            'table' => $this->_sTable,
+
+            'method' => &$sUnionMethod,
+            'select_clause' => &$sSelectClause,
+            'join_clause_po' => &$sJoinClausePo,
+            'join_clause_pc' => &$sJoinClausePc,
+            'where_clause_po' => &$sWhereClausePo,
+            'where_clause_pc' => &$sWhereClausePc,
+            'order_clause_po' => &$sOrderClausePo,
+            'order_clause_pc' => &$sOrderClausePc,
+            'order_clause' => &$sUnionOrderClause,
+            'limit_clause' => &$sUnionLimitClause,
+            'query_po' => &$sQueryOwner,
+            'query_pc' => &$sQueryConnections,
+
+            'method_ref' => &$sUnionMethod,
+            'select_clause_ref' => &$sSelectClause,
+            'join_clause_po_ref' => &$sJoinClausePo,
+            'join_clause_pc_ref' => &$sJoinClausePc,
+            'where_clause_po_ref' => &$sWhereClausePo,
+            'where_clause_pc_ref' => &$sWhereClausePc,
+            'order_clause_po_ref' => &$sOrderClausePo,
+            'order_clause_pc_ref' => &$sOrderClausePc,
+            'order_clause_ref' => &$sUnionOrderClause,
+            'limit_clause_ref' => &$sUnionLimitClause,
+            'query_po_ref' => &$sQueryOwner,
+            'query_pc_ref' => &$sQueryConnections,
+        ]);
+
+        $sQuery = "(" . $sQueryOwner . ") UNION (" . $sQueryConnections . ") {order} {limit}";
+        $sQuery = str_replace(['{select}', '{order}', '{limit}'], [$sSelectClause, $sUnionOrderClause, $sUnionLimitClause], $sQuery);
+        $aEntries = $this->$sUnionMethod($sQuery);
+
+        if($bCountOnly)
+            $aEntries = (int)array_sum($aEntries);
+
+        return $aEntries;
+    }
+
+    protected function _getSqlPartsEvents($aParams)
+    {
+        list($sMethod, $sSelectClause, $sJoinClause, $sWhereClause, $sOrderClause, $sLimitClause) = parent::_getSqlPartsEvents($aParams);
+
+        switch($aParams['browse']) {
+            case 'descriptor':
+                $sMethod = 'getRow';
+                $sWhereClause = "";
+
+                if(isset($aParams['type']))
+                    $sWhereClause .= $this->prepareAsString("AND `" . $this->_sTable . "`.`type`=? ", $aParams['type']);
+                if(isset($aParams['action']))
+                    $sWhereClause .= $this->prepareAsString("AND `" . $this->_sTable . "`.`action`=? ", $aParams['action']);
+                if(isset($aParams['object_id']))
+                    $sWhereClause .= $this->prepareAsString("AND `" . $this->_sTable . "`.`object_id`=? ", $aParams['object_id']);
+
+                $sLimitClause = "LIMIT 1";
+                break;
+
+            case 'first':
+                $sWhereClause .= $this->prepareAsString("AND `" . $this->_sTable . "`.`date` <= ? ", time());
+                break;
+
+            case 'list':
+                if(!empty($aParams['count_only'])) {
+                    $sMethod = 'getOne';
+                    $sSelectClause = 'COUNT(DISTINCT `' . $this->_sTable . '`.`id`)';
+                }
+                else {
+                    $sSelectClause .= ", `{$this->_sTableHandlers}`.`priority` AS `priority`";
+
+                    if(in_array($aParams['type'], array(BX_BASE_MOD_NTFS_TYPE_CONNECTIONS, BX_NTFS_TYPE_OBJECT_OWNER_AND_CONNECTIONS)))
+                        $sSelectClause = 'DISTINCT ' . $sSelectClause;
+                }
+
+                $sWhereClause .= $this->prepareAsString("AND `" . $this->_sTable . "`.`date` <= ? ", time());
+                break;
+        }
+
+        return array($sMethod, $sSelectClause, $sJoinClause, $sWhereClause, $sOrderClause, $sLimitClause);
+    }
+
+    protected function _getSqlPartsEventsList($aParams)
+    {
+        $sJoinClause = $sWhereClause = "";
+
+        //--- Apply 'start from'  filter
+        $sWhereClauseStartFrom = '';
+        if(isset($aParams['start_from_item']) && $aParams['start_from_item'] === true && $aParams['start'] != 0)
+            $sWhereClauseStartFrom = $this->prepareAsString("AND `{$this->_sTable}`.`id`<? ", (int)$aParams['start']);
+
+        //--- Apply status filter
+        $sWhereClauseStatus = '';
+        if(isset($aParams['active']))
+            $sWhereClauseStatus = $this->prepareAsString("AND `{$this->_sTable}`.`active`=? ", (int)$aParams['active']);
+
+        //--- Apply modules or handlers filter
+        $sWhereClauseModules = '';
+        if(!empty($aParams['modules']) && is_array($aParams['modules']))
+            $sWhereClauseModules = "AND `" . $this->_sTable . "`.`type` IN (" . $this->implode_escape($aParams['modules']) . ") ";
+
+        if($sWhereClauseModules == '') {
+            $aHidden = $this->_oConfig->getHandlersHidden();
+            $sWhereClauseModules = !empty($aHidden) && is_array($aHidden) ? "AND `" . $this->_sTableHandlers . "`.`id` NOT IN (" . $this->implode_escape($aHidden) . ") " : "";
+        }
+
+        //--- Check flag 'New'
+        $sWhereClauseNew = '';
+        if(!empty($aParams['new']) && !empty($aParams['owner_id']))
+            $sWhereClauseNew = $this->prepareAsString("AND `{$this->_sTable}`.`id`>? ", $this->getLastRead((int)$aParams['owner_id']));
+
+        //--- Check type
+        $sWhereClauseSettings = $sWhereClauseType = '';
+        if(!empty($aParams['owner_id']))
+            switch($aParams['type']) {
+                /*
+                 * Note. It isn't used for now and outdated.
+                 */
+                case BX_BASE_MOD_NTFS_TYPE_OWNER:
+                    $sWhereClauseType = $this->prepareAsString("AND `{$this->_sTable}`.`owner_id`=? ", $aParams['owner_id']);
+                    break;
+
+                case BX_BASE_MOD_NTFS_TYPE_OBJECT_OWNER:
+                    $sJoinClause .= $this->prepareAsString(" INNER JOIN `{$this->_sTableSettings}` ON `{$this->_sTableHandlers}`.`id`=`{$this->_sTableSettings}`.`handler_id` AND `{$this->_sTableSettings}`.`delivery`='" . BX_BASE_MOD_NTFS_DTYPE_SITE . "' AND `{$this->_sTableSettings}`.`active`='1' AND `{$this->_sTableSettings}`.`type`=?", BX_NTFS_STYPE_PERSONAL);
+
+                    $sJoinClauseS2U = " LEFT JOIN `{$this->_sTableSettings2Users}` ON `{$this->_sTableSettings}`.`id`=`{$this->_sTableSettings2Users}`.`setting_id` ";
+                    if(!empty($aParams['owner_id']))
+                        $sJoinClauseS2U .= $this->prepareAsString("AND `{$this->_sTableSettings2Users}`.`user_id`=? ", $aParams['owner_id']);
+
+                    $sJoinClause .= $sJoinClauseS2U;
+                    $sWhereClauseSettings = "AND ((ISNULL(`{$this->_sTableSettings2Users}`.`active`) AND `{$this->_sTableSettings}`.`value`='1') OR (NOT ISNULL(`{$this->_sTableSettings2Users}`.`active`) AND `{$this->_sTableSettings2Users}`.`active`='1')) ";
+
+                    $sWhereClauseType = $this->prepareAsString("AND `{$this->_sTable}`.`owner_id`<>`{$this->_sTable}`.`object_owner_id` AND ((`{$this->_sTable}`.`owner_id`=? AND `{$this->_sTable}`.`object_privacy_view`<0 AND `{$this->_sTable}`.`owner_id`=ABS(`{$this->_sTable}`.`object_privacy_view`)) OR `{$this->_sTable}`.`object_owner_id`=?) ", $aParams['owner_id'], $aParams['owner_id']);
+                    break;
+
+                case BX_BASE_MOD_NTFS_TYPE_CONNECTIONS:
+                    $oConnection = BxDolConnection::getObjectInstance($this->_oConfig->getObject('conn_subscriptions'));
+                    $aQueryParts = $oConnection->getConnectedContentAsSQLParts($this->_sTable, 'owner_id', $aParams['owner_id']);
+                    if(empty($aQueryParts) || !is_array($aQueryParts) || empty($aQueryParts['join']))
+                        break;
+
+                    //--- Show notifications from connected contexts (using INNER JOIN)
+                    $sJoinClause .= " LEFT JOIN `sys_profiles` AS `tsp` ON `{$this->_sTable}`.`owner_id`=`tsp`.`id` " . $aQueryParts['join'];
+
+                    $sWhereClauseType = '';
+                    //--- Don't show notifications about own posts to connected contexts
+                    $sWhereClauseType .= $this->prepareAsString("AND `{$this->_sTable}`.`object_owner_id` <> ? ", $aParams['owner_id']);
+                    //--- Don't show notifications about posts created before the connection was established
+                    if(!empty($aQueryParts['fields']['added']))
+                        $sWhereClauseType .= "AND `{$this->_sTable}`.`date` >= " . $aQueryParts['fields']['added'];
+
+                    list($aModulesProfiles, $aModulesContexts) = $this->_oConfig->getProfileBasedModules();
+                    $sJoinClause .= $this->prepareAsString(" INNER JOIN `{$this->_sTableSettings}` ON `{$this->_sTableHandlers}`.`id`=`{$this->_sTableSettings}`.`handler_id` AND `{$this->_sTableSettings}`.`delivery`='" . BX_BASE_MOD_NTFS_DTYPE_SITE . "' AND `{$this->_sTableSettings}`.`active`='1' AND ((`{$this->_sTableSettings}`.`type`=? AND `tsp`.`type` IN (" . $this->implode_escape($aModulesProfiles) . ")) || (`{$this->_sTableSettings}`.`type`=? AND `tsp`.`type` IN (" . $this->implode_escape($aModulesContexts) . ")))", BX_NTFS_STYPE_FOLLOW_MEMBER, BX_NTFS_STYPE_FOLLOW_CONTEXT);
+
+                    $sJoinClauseS2U = " LEFT JOIN `{$this->_sTableSettings2Users}` ON `{$this->_sTableSettings}`.`id`=`{$this->_sTableSettings2Users}`.`setting_id` ";
+                    if(!empty($aParams['owner_id']))
+                        $sJoinClauseS2U .= $this->prepareAsString("AND `{$this->_sTableSettings2Users}`.`user_id`=? ", $aParams['owner_id']);
+
+                    $sJoinClause .= $sJoinClauseS2U;
+                    $sWhereClauseSettings = "AND ((ISNULL(`{$this->_sTableSettings2Users}`.`active`) AND `{$this->_sTableSettings}`.`value`='1') OR (NOT ISNULL(`{$this->_sTableSettings2Users}`.`active`) AND `{$this->_sTableSettings2Users}`.`active`='1')) ";
+                    break;
+
+                case BX_NTFS_TYPE_OBJECT_OWNER_AND_CONNECTIONS:
+                    /**
+                     * 'personal' notifications are taken by: 
+                     * 1. 'owner_id', in case of somebody performed an action in requested profile's context
+                     * 'object_privacy_view' < 0 AND 'owner_id' == ABS('object_privacy_view'))
+                     * Currently it happens when somebody posted a Direct Timeline post in requested profile.
+                     * 2. 'object_owner_id', in case of somebody performed an action with content 
+                     * owned by the requested profile.
+                     */
+                    $sWhereClauseObjectOwner = $this->prepareAsString("`{$this->_sTable}`.`owner_id` <> `{$this->_sTable}`.`object_owner_id` AND ((`{$this->_sTable}`.`owner_id`=? AND `{$this->_sTable}`.`object_privacy_view`<0 AND `{$this->_sTable}`.`owner_id`=ABS(`{$this->_sTable}`.`object_privacy_view`)) OR `{$this->_sTable}`.`object_owner_id`=?) ", $aParams['owner_id'], $aParams['owner_id']);
+
+                    /**
+                     * 'follow' notifications are taken by connection with `owner_id`
+                     */
+                    $sWhereClauseConnections = '0';
+                    $oConnection = BxDolConnection::getObjectInstance($this->_oConfig->getObject('conn_subscriptions'));
+                    $aQueryParts = $oConnection->getConnectedContentAsSQLPartsExt($this->_sTable, 'owner_id', $aParams['owner_id']);
+                    if(!empty($aQueryParts) && is_array($aQueryParts) && !empty($aQueryParts['join'])) {
+                        $sJoinClause .= " LEFT JOIN `sys_profiles` AS `tsp` ON `{$this->_sTable}`.`owner_id`=`tsp`.`id`";
+                        $sJoinClause .= " LEFT JOIN `" . $aQueryParts['join']['table'] . "` AS `" . $aQueryParts['join']['table_alias'] . "` ON (" . $aQueryParts['join']['condition'] . ")";
+
+                        //--- Show notifications from connected contexts
+                        $sWhereClauseConnections = "NOT ISNULL(`c`.`content`) ";
+                        //--- Don't show notifications about own posts to connected contexts
+                        $sWhereClauseConnections .= $this->prepareAsString("AND `{$this->_sTable}`.`object_owner_id` <> ? ", $aParams['owner_id']);
+                        //--- Don't show notifications about posts created before the connection was established
+                        if(!empty($aQueryParts['fields']['added']))
+                            $sWhereClauseConnections .= "AND `{$this->_sTable}`.`date` >= `" . $aQueryParts['fields']['added']['table_alias'] . "`.`" . $aQueryParts['fields']['added']['name'] . "` ";
+                    }
+
+                    list($aModulesProfiles, $aModulesContexts) = $this->_oConfig->getProfileBasedModules();
+                    $sJoinClause .= $this->prepareAsString(" INNER JOIN `{$this->_sTableSettings}` ON `{$this->_sTableHandlers}`.`id`=`{$this->_sTableSettings}`.`handler_id` AND `{$this->_sTableSettings}`.`delivery`='" . BX_BASE_MOD_NTFS_DTYPE_SITE . "' AND `{$this->_sTableSettings}`.`active`='1' AND (`{$this->_sTableSettings}`.`type`=? OR ((`{$this->_sTableSettings}`.`type`=? AND `tsp`.`type` IN (" . $this->implode_escape($aModulesProfiles) . ")) || (`{$this->_sTableSettings}`.`type`=? AND `tsp`.`type` IN (" . $this->implode_escape($aModulesContexts) . "))))", BX_NTFS_STYPE_PERSONAL, BX_NTFS_STYPE_FOLLOW_MEMBER, BX_NTFS_STYPE_FOLLOW_CONTEXT);
+
+                    $sJoinClauseS2U = " LEFT JOIN `{$this->_sTableSettings2Users}` ON `{$this->_sTableSettings}`.`id`=`{$this->_sTableSettings2Users}`.`setting_id` ";
+                    if(!empty($aParams['owner_id']))
+                        $sJoinClauseS2U .= $this->prepareAsString("AND `{$this->_sTableSettings2Users}`.`user_id`=? ", $aParams['owner_id']);
+
+                    $sJoinClause .= $sJoinClauseS2U;
+                    $sWhereClauseSettings = "AND ((ISNULL(`{$this->_sTableSettings2Users}`.`active`) AND `{$this->_sTableSettings}`.`value`='1') OR (NOT ISNULL(`{$this->_sTableSettings2Users}`.`active`) AND `{$this->_sTableSettings2Users}`.`active`='1')) ";
+
+                    $sWhereClauseType = "AND ((" . $sWhereClauseObjectOwner . ") OR (" . $sWhereClauseConnections . ")) ";
+                    break;
+            }
+
+        $aAlertParams = $aParams;
+        unset($aAlertParams['type'], $aAlertParams['owner_id']);
+
+        /**
+         * @hooks
+         * @hookdef hook-bx_notifications-get_list_by_type 'bx_notifications', 'get_list_by_type' - hook to override SQL query parts which are used to get events list
+         * - $unit_name - equals `bx_notifications`
+         * - $action - equals `get_list_by_type`
+         * - $object_id - not used
+         * - $sender_id - not used
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `type` - [string] a type of events list
+         *      - `owner_id` - [int] owner profile id
+         *      - `params` - [array] browse params array as key&value pairs
+         *      - `table` - [string] datatbase table name
+         *      - `join_clause` - [string] by ref, 'join' part of SQL query, can be overridden in hook processing
+         *      - `where_clause` - [string] by ref, 'where' part of SQL query, can be overridden in hook processing
+         *      - `where_clause_start_from` - [string] by ref, 'start_from' condition in 'where' part of SQL query, can be overridden in hook processing
+         *      - `where_clause_status` - [string] by ref, 'status' condition in 'where' part of SQL query, can be overridden in hook processing
+         *      - `where_clause_modules` - [string] by ref, 'modules' condition in 'where' part of SQL query, can be overridden in hook processing
+         *      - `where_clause_new` - [string] by ref, 'new' condition in 'where' part of SQL query, can be overridden in hook processing
+         *      - `where_clause_settings` - [string] by ref, 'settings' conditions in 'where' part of SQL query, can be overridden in hook processing
+         *      - `where_clause_type` - [string] by ref, 'type' condition in 'where' part of SQL query, can be overridden in hook processing
+         * @hook @ref hook-bx_notifications-get_list_by_type
+         */
+        bx_alert($this->_oConfig->getName(), 'get_list_by_type', 0, 0, [
+            'type' => $aParams['type'],
+            'owner_id' => $aParams['owner_id'],
+            'params' => $aAlertParams,
+            'table' => $this->_sTable,
+
+            'join_clause' => &$sJoinClause,
+            'where_clause' => &$sWhereClause,
+            'where_clause_start_from' => &$sWhereClauseStartFrom,
+            'where_clause_status' => &$sWhereClauseStatus,
+            'where_clause_modules' => &$sWhereClauseModules,
+            'where_clause_new' => &$sWhereClauseNew,
+            'where_clause_settings' => &$sWhereClauseSettings,
+            'where_clause_type' => &$sWhereClauseType,
+
+            'join_clause_ref' => &$sJoinClause,
+            'where_clause_ref' => &$sWhereClause,
+            'where_clause_start_from_ref' => &$sWhereClauseStartFrom,
+            'where_clause_status_ref' => &$sWhereClauseStatus,
+            'where_clause_modules_ref' => &$sWhereClauseModules,
+            'where_clause_new_ref' => &$sWhereClauseNew,
+            'where_clause_settings_ref' => &$sWhereClauseSettings,
+            'where_clause_type_ref' => &$sWhereClauseType,
+        ]);
+
+        $sWhereClause .= $sWhereClauseStartFrom;
+        $sWhereClause .= $sWhereClauseStatus;
+        $sWhereClause .= $sWhereClauseModules;
+        $sWhereClause .= $sWhereClauseNew;
+        $sWhereClause .= $sWhereClauseSettings;
+        $sWhereClause .= $sWhereClauseType;
+
+        return [$sJoinClause, $sWhereClause];
+    }
+
+    public function getEventsToProcess($iLimit = 0)
+    {
+        $aEvents = $this->getAll("SELECT * FROM `" . $this->_sTable . "` WHERE `id`>:id ORDER BY `id` ASC" . ($iLimit != 0 ? ' LIMIT ' . $iLimit : ''), array(
+            'id' => $this->_oConfig->getProcessedEvent()
+        ));
+
+        if(!empty($aEvents) && is_array($aEvents)) {
+            $aEventEnd = end($aEvents);
+
+            $this->_oConfig->setProcessedEvent($aEventEnd['id']);
+
+            reset($aEvents);
+        }
+
+        return $aEvents;
+    }
+
+    public function queueGet($aParams)
+    {
+    	$aMethod = array('name' => 'getAll', 'params' => array(0 => 'query'));
+
+    	$sSelectClause = "*";
+    	$sWhereClause = $sOrderClause = $sLimitClause = "";
+
+        switch($aParams['type']) {
+            case 'count':
+            	$aMethod['name'] = 'getOne';
+
+                $sSelectClause = "COUNT(*)";
+                break;
+
+            case 'id':
+            	$aMethod['name'] = 'getRow';
+            	$aMethod['params'][1] = array(
+                    'id' => $aParams['id']
+                );
+
+                $sWhereClause = " AND `id`=:id";
+                break;
+
+            case 'all_to_send':
+                $aMethod['name'] = 'getAllWithKey';
+                $aMethod['params'][1] = 'id';
+                $aMethod['params'][2] = array(
+                    'timeout' => $aParams['timeout']
+                );
+
+                $sWhereClause = " AND `date`+:timeout < UNIX_TIMESTAMP()";
+                $sOrderClause = "`date` ASC";
+                break;
+        }
+
+        $sOrderClause = !empty($sOrderClause) ? "ORDER BY " . $sOrderClause : $sOrderClause;
+        $sLimitClause = !empty($sLimitClause) ? "LIMIT " . $sLimitClause : $sLimitClause;
+
+        $aMethod['params'][0] = "SELECT
+                " . $sSelectClause . "
+            FROM `" . $this->_sTableQueue . "`
+            WHERE 1" . $sWhereClause . " " . $sOrderClause . " " . $sLimitClause;
+
+        return call_user_func_array(array($this, $aMethod['name']), $aMethod['params']);
+    }
+
+    public function queueAdd($aSet)
+    {
+        if(empty($aSet))
+            return false;
+
+        return (int)$this->query("INSERT INTO `" . $this->_sTableQueue . "` SET " . $this->arrayToSQL($aSet)) > 0;
+    }
+
+    public function queueDelete($aWhere)
+    {
+    	if(empty($aWhere))
+            return false;
+
+        return (int)$this->query("DELETE FROM `" . $this->_sTableQueue . "` WHERE " . $this->arrayToSQL($aWhere, ' AND ')) > 0;
+    }
+
+    public function queueDeleteByProfile($iProfileId, $iEventId)
+    {
+        return (int)$this->query("DELETE FROM `" . $this->_sTableQueue . "` WHERE `profile_id`=:profile_id AND `event_id`<=:event_id", array(
+            'profile_id' => $iProfileId,
+            'event_id' => $iEventId
+        )) > 0;
+    }
+
+    public function queueDeleteByIds($mixedId)
+    {
+        if(empty($mixedId))
+            return false;
+
+        if(!is_array($mixedId))
+            $mixedId = array($mixedId);
+
+        return (int)$this->query("DELETE FROM `" . $this->_sTableQueue . "` WHERE `id` IN (" . $this->implode_escape($mixedId) . ")") > 0;
+    }
+    
+    public function getEtemplates($aParams)
+    {
+    	$aMethod = ['name' => 'getAll', 'params' => [0 => 'query']];
+
+    	$sSelectClause = "*";
+    	$sWhereClause = $sOrderClause = $sLimitClause = "";
+
+        switch($aParams['sample']) {
+            case 'id':
+            	$aMethod['name'] = 'getRow';
+            	$aMethod['params'][1] = [
+                    'id' => $aParams['id']
+                ];
+
+                $sWhereClause = " AND `id`=:id";
+                break;
+
+            case 'type_action':
+            	$aMethod['name'] = 'getRow';
+            	$aMethod['params'][1] = [
+                    'type' => $aParams['type'],
+                    'action' => $aParams['action']
+                ];
+
+                $sWhereClause = " AND `type`=:type AND `action`=:action";
+
+                if(isset($aParams['active'])) {
+                    $aMethod['params'][1]['active'] = (int)$aParams['active'];
+
+                    $sWhereClause .= " AND `active`=:active";
+                }
+                break;
+        }
+
+        $sOrderClause = !empty($sOrderClause) ? "ORDER BY " . $sOrderClause : $sOrderClause;
+        $sLimitClause = !empty($sLimitClause) ? "LIMIT " . $sLimitClause : $sLimitClause;
+
+        $aMethod['params'][0] = "SELECT
+                " . $sSelectClause . "
+            FROM `" . $this->_sTableEtemplates . "`
+            WHERE 1" . $sWhereClause . " " . $sOrderClause . " " . $sLimitClause;
+
+        return call_user_func_array([$this, $aMethod['name']], $aMethod['params']);
+    }
+    
+    public function cleanEvents($iClearIntervalInDays)
+    {
+        $this->query("DELETE FROM `{$this->_sTable}` WHERE `date` < :date", array('date' => time() - $iClearIntervalInDays * 86400));
+    }   
+
+    public function filterProfileIdsByModule($aIds, $mixedModule)
+    {
+        if(!is_array($mixedModule))
+            $mixedModule = array($mixedModule);
+
+        return $this->getColumn("SELECT `id` FROM `sys_profiles` WHERE `id` IN (" . $this->implode_escape($aIds) . ") AND `type` IN (" . $this->implode_escape($mixedModule) . ")");
+    }
+}
+
+/** @} */

+ 180 - 0
modules/boonex/notifications/updates/15.0.2_15.0.3/source/classes/BxNtfsGridEtemplates.php

@@ -0,0 +1,180 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Notifications Notifications
+ * @ingroup     UnaModules
+ * 
+ * @{
+ */
+
+class BxNtfsGridEtemplates extends BxTemplGrid
+{
+    protected $_sModule;
+    protected $_oModule;
+
+    public function __construct ($aOptions, $oTemplate = false)
+    {
+        parent::__construct ($aOptions, $oTemplate);
+
+        $this->_sModule = 'bx_notifications';
+        $this->_oModule = BxDolModule::getInstance($this->_sModule);
+    }
+
+    public function getCode($isDisplayHeader = true)
+    {
+        $sResult = parent::getCode($isDisplayHeader);
+        if(!$sResult)
+            return $sResult;
+
+        return $sResult . $this->_oModule->_oTemplate->getJsCode('main');
+    }
+
+    public function performActionAdd()
+    {
+        $sAction = 'add';
+
+        $oForm = $this->_getFormObject($sAction);
+        $oForm->initChecker();
+        if($oForm->isSubmittedAndValid()) {
+            if(($iId = $oForm->insert()) !== false)
+                $aRes = ['grid' => $this->getCode(false), 'blink' => $iId];
+            else
+                $aRes = ['msg' => _t('_bx_ntfs_txt_err_cannot_perform')];
+
+            echoJson($aRes);
+        }
+        else {
+            $sContent = BxTemplFunctions::getInstance()->popupBox($this->_oModule->_oConfig->getHtmlIds('view', 'add_etemplate_popup'), _t('_bx_ntfs_grid_popup_title_ett_add'), $this->_oModule->_oTemplate->parseHtmlByName('etemplate_form.html', [
+                'style_prefix' => $this->_oModule->_oConfig->getPrefix('style'),
+                'form_id' => $oForm->aFormAttrs['id'],
+                'form' => $oForm->getCode(true),
+                'object' => $this->_sObject,
+                'action' => $sAction
+            ]));
+
+            echoJson(['popup' => ['html' => $sContent, 'options' => ['closeOnOuterClick' => false, 'removeOnClose' => true]]]);
+        }
+    }
+
+    public function performActionEdit()
+    {
+        $sAction = 'edit';
+
+        $iId = $this->_getId();
+        $aEtemplate = $this->_oModule->_oDb->getEtemplates(['sample' => 'id', 'id' => $iId]);
+        if(empty($aEtemplate) || !is_array($aEtemplate))
+            return echoJson([]);
+
+        $oForm = $this->_getFormObject($sAction, $aEtemplate);
+        $oForm->initChecker($aEtemplate);
+        if($oForm->isSubmittedAndValid()) {
+            if($oForm->update($iId) !== false)
+                $aRes = ['grid' => $this->getCode(false), 'blink' => $iId];
+            else
+                $aRes = ['msg' => _t('_bx_ntfs_txt_err_cannot_perform')];
+
+            echoJson($aRes);
+        }
+        else {
+            $sContent = BxTemplFunctions::getInstance()->popupBox($this->_oModule->_oConfig->getHtmlIds('view', 'edit_etemplate_popup'), _t('_bx_ntfs_grid_popup_title_ett_edit'), $this->_oModule->_oTemplate->parseHtmlByName('etemplate_form.html', [
+                'style_prefix' => $this->_oModule->_oConfig->getPrefix('style'),
+                'form_id' => $oForm->aFormAttrs['id'],
+                'form' => $oForm->getCode(true),
+                'object' => $this->_sObject,
+                'action' => $sAction
+            ]));
+
+            echoJson(['popup' => ['html' => $sContent, 'options' => ['closeOnOuterClick' => false, 'removeOnClose' => true]]]);
+        }
+    }
+
+    public function performActionPreview()
+    {
+        $iId = $this->_getId();
+        $aEtemplate = $this->_oModule->_oDb->getEtemplates(['sample' => 'id', 'id' => $iId]);
+        if(empty($aEtemplate) || !is_array($aEtemplate))
+            return echoJson([]);
+
+        $aTemplate = BxDolEmailTemplates::getInstance()->parseTemplate('bx_notifications_new_event', [
+            'subject' => !empty($aEtemplate['subject']) ? $aEtemplate['subject'] : _t('_bx_ntfs_txt_new_event_subject', getParam('site_title')),
+            'content' => $aEtemplate['body']
+        ]);
+
+        $sContent = BxTemplFunctions::getInstance()->popupBox($this->_oModule->_oConfig->getHtmlIds('view', 'preview_etemplate_popup'), _t('_bx_ntfs_grid_popup_title_ett_preview'), $this->_oModule->_oTemplate->parseHtmlByName('etemplate_preview.html', [
+            'style_prefix' => $this->_oModule->_oConfig->getPrefix('style'),
+            'subject' => $aTemplate['Subject'],
+            'body' => $aTemplate['Body']
+        ]));
+
+        echoJson(['popup' => ['html' => $sContent, 'options' => ['closeOnOuterClick' => true, 'removeOnClose' => true]]]);
+    }
+
+    protected function _getCellType($mixedValue, $sKey, $aField, $aRow)
+    {
+        return parent::_getCellDefault($this->_oModule->_oTemplate->getTypeTitle($mixedValue), $sKey, $aField, $aRow);
+    }
+
+    protected function _getCellAction($mixedValue, $sKey, $aField, $aRow)
+    {
+        return parent::_getCellDefault($this->_oModule->_oTemplate->getActionTitle($mixedValue), $sKey, $aField, $aRow);
+    }
+
+    protected function _getActionsDisabledBehavior($aRow)
+    {
+        return false;
+    }
+
+    protected function _getFormObject($sAction, $aItem = [])
+    {
+        $CNF = &$this->_oModule->_oConfig->CNF;
+
+        $oForm = BxDolForm::getObjectInstance($CNF['OBJECT_FORM_ETEMPLATE'], $CNF['OBJECT_FORM_ETEMPLATE_DISPLAY_' . strtoupper($sAction)]);
+        $oForm->aFormAttrs['action'] = BX_DOL_URL_ROOT . 'grid.php?o=' . $this->_sObject . '&a=' . $sAction;
+        if(!empty($aItem['id']))
+            $oForm->aFormAttrs['action'] .= '&id=' . $aItem['id'];
+
+        if(($sK = 'type') && isset($oForm->aInputs[$sK])) {
+            $oForm->aInputs[$sK] = array_merge($oForm->aInputs[$sK], [
+                'attrs' => [
+                    'onchange' => $this->_oModule->_oConfig->getJsObject('main') . '.onChangeType(this)',
+                ],
+                'values' => [
+                    ['key' => '', 'value' => _t('_sys_please_select')]
+                ]
+            ]);
+
+            $aTypes = $this->_oModule->_oDb->getHandlerTypes();
+            foreach($aTypes as $sType)
+                $oForm->aInputs[$sK]['values'][] = ['key' => $sType, 'value' => $this->_oModule->_oTemplate->getTypeTitle($sType)];
+        }
+
+        if(($sK = 'action') && isset($oForm->aInputs[$sK])) {
+            $oForm->aInputs[$sK] = array_merge($oForm->aInputs[$sK], [
+                'attrs' => [
+                    'id' => $this->_oModule->_oConfig->getHtmlIds('main', 'field_action'),
+                    'disabled' => 'disabled'
+                ],
+                'values' => [
+                    ['key' => '', 'value' => _t('_sys_please_select')]
+                ]
+            ]);
+        }
+
+        if(($sK = 'body') && isset($oForm->aInputs[$sK]))
+            $oForm->aInputs[$sK]['code'] = 1;
+
+        return $oForm;
+    }
+
+    protected function _getId()
+    {
+        if(($aIds = bx_get('ids')) && is_array($aIds)) 
+            return array_shift($aIds);
+
+        return ($iId = bx_get('id')) !== false ? (int)$iId : false;
+    }
+}
+
+/** @} */

+ 332 - 0
modules/boonex/notifications/updates/15.0.2_15.0.3/source/classes/BxNtfsGridSettingsAdministration.php

@@ -0,0 +1,332 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Notifications Notifications
+ * @ingroup     UnaModules
+ * 
+ * @{
+ */
+
+require_once(BX_DOL_DIR_STUDIO_INC . 'utils.inc.php');
+
+class BxNtfsGridSettingsAdministration extends BxTemplGrid
+{
+    protected $_sModule;
+    protected $_oModule;
+
+    protected $_bAdministration;
+
+    protected $_bGrouped;
+    protected $_sDeliveryType;
+    protected $_sTitleMask;
+
+    protected $_sSource;
+
+    public function __construct ($aOptions, $oTemplate = false)
+    {
+        parent::__construct ($aOptions, $oTemplate);
+
+        $this->_sModule = 'bx_notifications';
+        $this->_oModule = BxDolModule::getInstance($this->_sModule);
+
+        $CNF = &$this->_oModule->_oConfig->CNF;
+
+        $this->_bAdministration = true;      
+
+        $this->_bGrouped = $this->_oModule->_oConfig->isSettingsGrouped();
+        if($this->_bGrouped)
+            $this->_aOptions['show_total_count'] = 0;
+
+        $this->_sDeliveryType = BX_BASE_MOD_NTFS_DTYPE_SITE;
+        $this->_sTitleMask = _t('_bx_ntfs_setting_title_mask', '%s', '%s');
+
+        $this->_sSource = '';
+
+        $sDeliveryType = bx_get('delivery_type');
+        if(!empty($sDeliveryType))
+            $this->setDeliveryType($sDeliveryType);
+
+        $this->init();
+    }
+
+    public function init()
+    {
+        if(!$this->_bGrouped && !isset($this->_aOptions['fields']['unit'], $this->_aOptions['fields']['type']))
+            $this->_aOptions['fields'] = bx_array_insert_after(array(
+                'unit' => array('title' => _t('_bx_ntfs_grid_column_title_unit'), 'width' => '10%', 'translatable' => 0 ,'chars_limit' => 0),
+                'type' => array('title' => _t('_bx_ntfs_grid_column_title_type'), 'width' => '20%', 'translatable' => 0 ,'chars_limit' => 0),
+            ), $this->_aOptions['fields'], 'switcher');
+    }
+
+    public function setGrouped($bGrouped)
+    {
+        $bReinit = $this->_bGrouped !== (bool)$bGrouped;
+
+        $this->_bGrouped = $bGrouped;
+
+        if($bReinit)
+            $this->init();
+    }
+
+    public function setDeliveryType($sType)
+    {
+        $this->_sDeliveryType = bx_process_input($sType);
+        $this->_aQueryAppend['delivery_type'] = $this->_sDeliveryType;
+    }
+
+    public function performActionActivate()
+    {
+        parent::performActionEnable(1);
+    }
+
+    public function performActionDeactivate()
+    {
+        parent::performActionEnable(0);
+    }
+    
+    public function performActionChangeValue()
+    {
+        $aIds = bx_get('ids');
+        if(empty($aIds) || !is_array($aIds))
+            return echoJson(array());
+
+        $iId = array_shift($aIds);
+        $iValue = $this->_switcherChecked2State((int)bx_get('checked'));
+
+        if(!$this->_bGrouped)
+            $mixedResult = $this->_oModule->_oDb->updateSetting(array('value' => $iValue), array('id' => $iId));
+        else 
+            $mixedResult = $this->_oModule->changeSettingsValueLike($iId, 'value', $iValue, $this->_bAdministration);
+
+        $aResult = array();
+        if($mixedResult === false)
+            $aResult = array('msg' => _t('_bx_ntfs_txt_err_cannot_perform'));
+        else if((int)$mixedResult == 0)
+            $aResult = array('msg' => _t('_bx_ntfs_txt_err_nothing_changed'));
+
+        return echoJson($aResult);
+    }
+
+    protected function _enable ($mixedId, $isChecked)
+    {
+        if(!$this->_bGrouped)
+            return parent::_enable($mixedId, $isChecked);
+
+        return $this->_oModule->enableSettingsLike($mixedId, $isChecked, $this->_bAdministration);
+    }
+
+    protected function _isCheckboxDisabled($aRow)
+    {
+        return false;
+    }
+
+    protected function _getFilterControls()
+    {
+        if($this->_bGrouped)
+            return '';
+
+        return parent::_getFilterControls();
+    }
+
+    protected function _getCellValue($mixedValue, $sKey, $aField, $aRow)
+    {
+        $sAttr = $this->_convertAttrs(
+            $aField, 'attr_cell',
+            'bx-def-padding-sec-bottom bx-def-padding-sec-top',
+            isset($aField['width']) ? 'width:' . $aField['width'] : false
+        );
+
+        $oForm = new BxTemplFormView(array(), $this->_oTemplate);
+        $oForm->addCssJs();
+        $aInput = array(
+            'type' => 'switcher',
+            'name' => $this->_sObject . '_change_value_' . $aRow[$this->_aOptions['field_id']],
+            'caption' => '',
+            'attrs' => array (
+                'bx_grid_action_single' => 'change_value',
+                'bx_grid_action_confirm' => '',
+                'bx_grid_action_data' => $aRow[$this->_aOptions['field_id']],
+            ),
+            'value' => $aRow[$this->_aOptions['field_id']],
+            'checked' => $this->_isSwitcherOn($mixedValue, $sKey, $aField, $aRow),
+        );
+        $sSwitcher = $oForm->genInput($aInput);
+        return '<td ' . $sAttr . '>' . $sSwitcher . '</td>';
+    }
+
+    protected function _getCellUnit($mixedValue, $sKey, $aField, $aRow)
+    {
+        return parent::_getCellDefault(_t($this->_oModule->_oConfig->getHandlersUnitTitle($mixedValue)), $sKey, $aField, $aRow);
+    }
+
+    protected function _getCellType($mixedValue, $sKey, $aField, $aRow)
+    {
+        $CNF = &$this->_oModule->_oConfig->CNF;
+
+        return parent::_getCellDefault(_t($CNF['T']['setting_' . $mixedValue]), $sKey, $aField, $aRow);
+    }
+
+    protected function _getCellTitle($mixedValue, $sKey, $aField, $aRow)
+    {
+        if(empty($mixedValue)) {
+            $mixedValueKey = $this->_oModule->_oConfig->getHandlersActionTitle($aRow['unit'], $aRow['action'], $aRow['type']);
+            $mixedValue = _t($mixedValueKey);
+
+            if(strcmp($mixedValueKey, $mixedValue) !== 0)
+                $this->_updateSettingTitle($mixedValueKey, $aRow);
+        }
+
+        $sTitle = $mixedValue;
+        if($this->_bGrouped) {
+            if(($sKey = '_bx_ntfs_alert_action_group_' . $aRow['group']) && ($_sKey = _t($sKey)) && strcmp($sKey, $_sKey) !== 0)
+                $sTitle = $_sKey;
+            else if($aRow['type'] == BX_NTFS_STYPE_OTHER)
+                $sTitle = sprintf($this->_sTitleMask, _t($this->_oModule->_oConfig->getHandlersUnitTitle($aRow['unit'])), $sTitle);
+        }
+
+        if(!$this->_bIsApi) {
+            $iInfo = '';
+            if(($sKey = '_bx_ntfs_alert_action_group_info_' . $aRow['group']) && ($_sKey = _t($sKey)) && strcmp($sKey, $_sKey) !== 0)
+                $iInfo = $_sKey;
+            else if(($sKey = '_bx_ntfs_alert_action_group_info_' . $aRow['group'] . '_' . $aRow['type']) && ($_sKey = _t($sKey)) && strcmp($sKey, $_sKey) !== 0)
+                $iInfo = $_sKey;
+            else
+                $iInfo = $this->_oModule->_oConfig->getHandlersActionInfo($aRow['unit'], $aRow['action'], $aRow['type'], true);
+
+            $sStylePrefix = $this->_oModule->_oConfig->getPrefix('style');
+            $mixedValue = $this->_oModule->_oTemplate->parseHtmlByName('setting_title.html', [
+                'style_prefix' => $sStylePrefix,
+                'bx_if:show_warning' => [
+                    'condition' => $this->_bGrouped && !$this->_isSettingsGroupValid($aRow),
+                    'content' => [
+                        'style_prefix' => $sStylePrefix
+                    ]
+                ],
+                'title' => $sTitle,
+                'info' => $iInfo
+            ]);
+        }
+        else
+            $mixedValue = $sTitle;
+
+        return parent::_getCellDefault($mixedValue, $sKey, $aField, $aRow);
+    }
+
+    protected function _getActionActivate($sType, $sKey, $a, $isSmall = false, $isDisabled = false, $aRow = array())
+    {
+    	return $this->_getActionDefault ($sType, $sKey, $a, $isSmall, $isDisabled, $aRow);
+    }
+
+    protected function _getActionDeactivate($sType, $sKey, $a, $isSmall = false, $isDisabled = false, $aRow = array())
+    {
+    	return $this->_getActionDefault ($sType, $sKey, $a, $isSmall, $isDisabled, $aRow);
+    }
+
+    protected function _getData ($sFilter, $sOrderField, $sOrderDir, $iStart, $iPerPage)
+    {
+        if(!$this->_bIsApi)
+            return parent::_getData($sFilter, $sOrderField, $sOrderDir, $iStart, $iPerPage);
+        
+        $sSource = $this->_aOptions['source'];
+
+        $aData = [];
+        $aDeliveryTypes = $this->_oModule->_oConfig->getDeliveryTypes();
+        foreach($aDeliveryTypes as $sDeliveryType) {
+            $this->_sDeliveryType = $sDeliveryType;
+            $this->_aOptions['source'] = $sSource;
+
+            $aData[] = [
+                'delivery' => $sDeliveryType,
+                'items' => parent::_getData($sFilter, $sOrderField, $sOrderDir, $iStart, $iPerPage)
+            ];
+        }
+
+        return $aData;
+    }
+
+    protected function _getDataSql($sFilter, $sOrderField, $sOrderDir, $iStart, $iPerPage)
+    {
+        $this->_aOptions['source'] .= $this->_oModule->_oDb->prepareAsString(" AND `ts`.`delivery`=?", $this->_sDeliveryType);
+        if(!$this->_bGrouped)
+            return parent::_getDataSql($sFilter, $sOrderField, $sOrderDir, $iStart, $iPerPage);
+
+        $CNF = &$this->_oModule->_oConfig->CNF;
+
+        $aResult = array();
+        $this->_sSource = $this->_aOptions['source'];
+
+        $aTypes = $this->_oModule->_oConfig->getSettingsTypes();
+        foreach($aTypes as $sType) {
+            $this->_aOptions['source'] = $this->_sSource . $this->_oModule->_oDb->prepareAsString(" AND `ts`.`type`=?", $sType) . " GROUP BY `ts`.`group`";
+
+            $aRows = parent::_getDataSql($sFilter, $sOrderField, $sOrderDir, $iStart, $iPerPage);
+            if(empty($aRows) || !is_array($aRows)) 
+                continue;
+
+            $aResult[] = _t($CNF['T']['setting_' . $sType]);
+            $aResult = array_merge($aResult, $aRows);
+        }
+
+        return $aResult;
+    }
+
+    protected function _updateSettingTitle($sTitle, &$aRow)
+    {
+        return $this->_oModule->_oDb->updateSetting(array('title' => $sTitle), array('id' => $aRow['id']));
+    }
+    
+    protected function _isSettingsGroupValid(&$aRow)
+    {
+        if(!$this->_bGrouped)
+            return true;
+
+        $iEnabled = $iDisabled = 0;
+
+        $sSql = $this->_sSource . $this->_oModule->_oDb->prepareAsString(" AND `ts`.`group`=? AND `ts`.`type`=?", $aRow['group'], $aRow['type']);
+        $aItems = $this->_oModule->_oDb->getAll($sSql);
+        foreach($aItems as $aItem) 
+            if((int)$aItem['active'] != 0)
+                $iEnabled += 1;
+            else 
+                $iDisabled += 1;
+
+        return $iEnabled == 0 || $iDisabled == 0;
+    }
+    
+    public function decodeDataAPI($aData)
+    {
+        $sKeyId = $this->_aOptions['field_id'];
+        $sMethodDefault = '_getCellDefault';
+
+        $aDataR = [];
+        foreach($aData as $aDataItem) {
+            $aDataS = [];
+            foreach($aDataItem['items'] as $iKey => $aRow) {
+                if(!is_string($aRow)) {
+                    $aDataS[$iKey] = [$sKeyId => $aRow[$sKeyId]];
+
+                    foreach($this->_aOptions['fields'] as $sKey => $aField) {
+                        $sMethod = '_getCell' . $this->_genMethodName($sKey);
+                        if(!method_exists($this, $sMethod))
+                            $sMethod = $sMethodDefault;
+
+                        $aDataS[$iKey][$sKey] = $this->$sMethod(isset($aRow[$sKey]) ? $aRow[$sKey] : _t('_undefined'), $sKey, $aField, $aRow);
+                    }
+                }
+                else
+                    $aDataS[$iKey] = $aRow;
+            }
+
+            $aDataR[] = [
+                'delivery' => $aDataItem['delivery'],
+                'items' => $aDataS
+            ];
+        }
+
+        return $aDataR;
+    }
+}
+
+/** @} */

+ 860 - 0
modules/boonex/notifications/updates/15.0.2_15.0.3/source/classes/BxNtfsModule.php

@@ -0,0 +1,860 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Notifications Notifications
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+bx_import('BxBaseModNotificationsModule');
+
+define('BX_NTFS_TYPE_OBJECT_OWNER_AND_CONNECTIONS', 'obj_own_and_con');
+define('BX_NTFS_TYPE_DEFAULT', BX_NTFS_TYPE_OBJECT_OWNER_AND_CONNECTIONS);
+
+/**
+ * STYPE - Setting Type:
+ * 1. personal - related to you;
+ * 2. follow_member - related to members you follow;
+ * 3. follow_context - related to contexts you follow;
+ * 4. other - others.
+ */
+define('BX_NTFS_STYPE_PERSONAL', 'personal');
+define('BX_NTFS_STYPE_FOLLOW_MEMBER', 'follow_member');
+define('BX_NTFS_STYPE_FOLLOW_CONTEXT', 'follow_context');
+define('BX_NTFS_STYPE_OTHER', 'other');
+
+/**
+ * DTYPE - Delivery Type
+ */
+define('BX_NTFS_DTYPE_SITE', 'site');
+define('BX_NTFS_DTYPE_EMAIL', 'email');
+define('BX_NTFS_DTYPE_PUSH', 'push');
+
+/**
+ * SLTMODE - Silent mode:
+ * It is needed for alert sending module to tell that the alert should be ignored 
+ * with Notifications module completely or partially. Available values: 
+ * 1. disabled (global, value = 0) - all notifications are available;
+ * 2. absolute (global, value = 1) - alert isn't registered which means that there is no notifications at all;
+ * 3. absolute (for Notifications only, value = 11) - the same as global absolute.
+ * 3. on-site only (value = 12) - alert is registered. It means that on-site notification is available while the others are disabled.
+ * 4. on-site + email (value = 13) - alert is registered (on-site) and notification via 'email' is enabled.
+ * 5. on-site + push (value = 14) - alert is registered (on-site) and notification via 'push' is enabled.
+ * 
+ * @see BxNtfsResponse::response - 'silent_mode' parameter in Alerts Extras array.
+ */
+define('BX_NTFS_SLTMODE_ABSOLUTE', 11);
+define('BX_NTFS_SLTMODE_SITE', 12);
+define('BX_NTFS_SLTMODE_SITE_EMAIL', 13);
+define('BX_NTFS_SLTMODE_SITE_PUSH', 14);
+
+class BxNtfsModule extends BxBaseModNotificationsModule
+{
+    /**
+     * Constructor
+     */
+    function __construct($aModule)
+    {
+        parent::__construct($aModule);
+
+        $this->_iOwnerId = $this->getUserId();
+    }
+
+    /**
+     * ACTION METHODS
+     */
+    public function actionGetAction($sType)
+    {
+        $aActions = $this->_oDb->getHandlerActions($sType);
+        if(empty($aActions) || !is_array($aActions))
+            return echoJson(['code' => 1]);
+
+        echoJson([
+            'code' => 0, 
+            'content' => $this->_oTemplate->getSelectActions($aActions)
+        ]);
+    }
+
+    function actionMarkAsClicked()
+    {
+        $iId = bx_process_input(bx_get('id'), BX_DATA_INT);
+        $aEvent = $this->_oDb->getEvents(['browse' => 'id', 'value' => $iId]);
+        if(empty($aEvent) || !is_array($aEvent))
+            return echoJson(['code' => 1]);
+
+        $aParams = $this->_prepareParamsGet();
+        if($this->_oDb->markAsClicked($aParams['viewer_id'], $iId) === false)
+            return echoJson(['code' => 2]);
+
+        echoJson([
+            'code' => 0, 
+            'id' => $iId
+        ]);
+    }
+
+    function actionGetPosts()
+    {
+        $aParams = $this->_prepareParamsGet();
+        if(empty($aParams['owner_id']) || (int)$aParams['owner_id'] != $this->_iOwnerId)
+            return echoJson([]);
+
+        echoJson([
+            'events' => $this->_oTemplate->getPosts($aParams)
+        ]);
+    }
+
+    /**
+     * SERVICE METHODS
+     */
+
+    public function serviceGetSafeServices()
+    {
+        return [
+            'GetBlockView' => '',
+            'GetData' => '',
+            'GetUnreadNotificationsNum' => '',
+            'GetUnreadNotificationsNumEx' => '',
+            'MarkAsRead' => '',
+            'EnableSetting' => '',
+            'ChangeSetting' => '',
+        ];
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_notifications Invitations
+     * @subsection bx_notifications-other Other
+     * @subsubsection bx_notifications-get_include get_include
+     * 
+     * @code bx_srv('bx_notifications', 'get_include', [...]); @endcode
+     * 
+     * Get all necessary CSS and JS files to include in a page.
+     *
+     * @return string with all necessary CSS and JS files.
+     * 
+     * @see BxInvModule::serviceGetInclude
+     */
+    /** 
+     * @ref bx_notifications-get_include "get_include"
+     */
+    public function serviceGetInclude($bIncludeCss = true, $mixedIncludeJs = false)
+    {
+        return $this->_oTemplate->getInclude($bIncludeCss, $mixedIncludeJs);
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_notifications Notifications
+     * @subsection bx_notifications-page_blocks Page Blocks
+     * @subsubsection bx_notifications-get_block_settings get_block_settings
+     * 
+     * @code bx_srv('bx_notifications', 'get_block_settings', [...]); @endcode
+     * 
+     * Get Settings block for a separate page.
+     *
+     * @return a string with block content to display on the site. All necessary CSS and JS files are automatically added to the HEAD section of the site HTML.
+     * 
+     * @see BxNtfsModule::serviceGetBlockSettings
+     */
+    /** 
+     * @ref bx_notifications-get_block_settings "get_block_settings"
+     */
+    public function serviceGetBlockSettings($sDeliveryType = '', $aParams = array())
+    {
+        if(!isLogged())
+            return '';
+
+        if(empty($sDeliveryType) && bx_get('delivery') !== false)
+            $sDeliveryType = bx_process_input(bx_get('delivery'));
+
+        if(empty($sDeliveryType))
+            $sDeliveryType = BX_BASE_MOD_NTFS_DTYPE_SITE;
+
+        $iUserId = bx_get_logged_profile_id();
+        if(!empty($aParams['user_id']))
+            $iUserId = (int)$aParams['user_id'];
+        else
+            $aParams['user_id'] = $iUserId;
+
+        $this->_oDb->initSettingUser($iUserId);
+
+        return array(
+            'content' => $this->getBlockSettings($sDeliveryType, $aParams),
+        );
+    }
+
+    
+    /**
+     * @page service Service Calls
+     * @section bx_notifications Notifications
+     * @subsection bx_notifications-page_blocks Page Blocks
+     * @subsubsection bx_notifications-get_data get_data
+     * 
+     * @code bx_srv('bx_notifications', 'get_data', [...]); @endcode
+     * 
+     * Get data for app
+     *
+     * @return an array .
+     * 
+     * @see BxNtfsModule::serviceGetData
+     */
+     /** 
+     * @ref bx_notifications-get_data "get_data"
+     * @api @ref bx_notifications-get_data "get_data"
+     */
+    public function serviceGetData($aParams)
+    {
+        if(is_string($aParams))
+            $aParams = bx_api_get_browse_params($aParams, true);
+
+        return call_user_func_array([$this, 'serviceGetBlockView'], [
+            isset($aParams['type']) ? $aParams['type'] : '',
+            isset($aParams['start']) ? (int)$aParams['start'] : -1,
+            isset($aParams['per_page']) ? (int)$aParams['per_page'] : -1,
+            isset($aParams['modules']) ? $aParams['modules'] : [],
+        ]);
+    }
+    
+    /**
+     * @page service Service Calls
+     * @section bx_notifications Notifications
+     * @subsection bx_notifications-page_blocks Page Blocks
+     * @subsubsection bx_notifications-get_block_view get_block_view
+     * 
+     * @code bx_srv('bx_notifications', 'get_block_view', [...]); @endcode
+     * 
+     * Get View block for a separate page. Will return a block with "Empty" message if nothing found.
+     *
+     * @return an array describing a block to display on the site. All necessary CSS and JS files are automatically added to the HEAD section of the site HTML.
+     * 
+     * @see BxNtfsModule::serviceGetBlockView
+     */
+    /** 
+     * @ref bx_notifications-get_block_view "get_block_view"
+     */
+    public function serviceGetBlockView($sType = '', $iStart = -1, $iPerPage = -1, $aModules = [])
+    {
+    	$aBrowseTypes = [BX_NTFS_TYPE_OBJECT_OWNER_AND_CONNECTIONS, BX_BASE_MOD_NTFS_TYPE_CONNECTIONS, BX_BASE_MOD_NTFS_TYPE_OBJECT_OWNER];
+
+    	if(empty($sType)) {
+            $mixedType = bx_get('type');
+            if($mixedType !== false && in_array($mixedType, $aBrowseTypes))
+                $sType = $mixedType;
+
+            if(empty($sType))
+                $sType = BX_NTFS_TYPE_DEFAULT;
+    	}
+
+    	$iOwnerId = $this->getUserId();
+        if(!$iOwnerId) {
+            $sResult = _t('_bx_ntfs_txt_msg_no_results');
+            return $this->_bIsApi ? [bx_api_get_msg($sResult)] : ['content' => MsgBox($sResult)];
+        }
+
+        $aParams = $this->_prepareParams($sType, $iOwnerId, $iStart, $iPerPage, $aModules);
+
+        if($this->_bIsApi) {
+            $aParams['start_from_item'] = true;
+
+            $aContent = defined('BX_API_PAGE') ? [] : $this->_oTemplate->getPosts($aParams);
+            if(!empty($aContent) && is_array($aContent)) {
+                $iContent = count($aContent);
+                if($iContent > $aParams['per_page'])
+                    $aContent = array_slice($aContent, 0, -($iContent - $aParams['per_page']));
+
+                $aParams['start'] = end($aContent)['id'];
+            }
+
+            //if($aParams['start'] == 0)
+            //    $this->markAsRead($iOwnerId, $aParams);
+
+            return [bx_api_get_block('browse', [
+                'unit' => 'notifications',  
+                'request_url' => '/api.php?r=bx_notifications/get_data/&params[]=',
+                'params' => $aParams,
+                'id' => $iOwnerId,
+                'data' => $aContent]),
+            ];
+        }
+
+        $sContent = $this->_oTemplate->getViewBlock($aParams);
+
+        $this->markAsRead($iOwnerId, $aParams);
+
+        return ['content' => $sContent]; 
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_notifications Notifications
+     * @subsection bx_notifications-browsing Browsing
+     * @subsubsection bx_notifications-get_event_by_id get_event_by_id
+     * 
+     * @code bx_srv('bx_notifications', 'get_event_by_id', [...]); @endcode
+     * 
+     * Get event's data by event ID.
+     *
+     * @return an array with event's data.
+     * 
+     * @see BxNtfsModule::serviceGetEventById
+     */
+    /** 
+     * @ref bx_notifications-get_event_by_id "get_event_by_id"
+     */
+    public function serviceGetEventById($iId)
+    {
+        $aParams = array(
+            'browse' => 'id',
+            'value' => $iId,
+        );
+    	return $this->_oDb->getEvents($aParams);
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_notifications Notifications
+     * @subsection bx_notifications-other Other
+     * @subsubsection bx_notifications-get_notifications get_notifications
+     * 
+     * @code bx_srv('bx_notifications', 'get_notifications', [...]); @endcode
+     * 
+     * Get notifications by params.
+     *
+     * @return array with notifications.
+     * 
+     * @see BxNtfsModule::serviceGetNotifications
+     */
+    /** 
+     * @ref bx_notifications-get_notifications "get_notifications"
+     */
+    public function serviceGetNotifications($iOwnerId = 0, $aBrowseParams = array())
+    {
+        if(!$iOwnerId)
+            $iOwnerId = $this->getUserId();
+
+        if(!$iOwnerId)
+            return 0;
+
+        $aParams = $this->_prepareParams(BX_NTFS_TYPE_DEFAULT, $iOwnerId);
+        if(!empty($aBrowseParams) && is_array($aBrowseParams))
+            $aParams = array_merge($aParams, $aBrowseParams);
+
+        $aEvents = $this->_oDb->getEvents($aParams);
+
+        if($this->_oConfig->isEventsGrouped())
+            $this->groupEvents($aEvents);
+
+        // returns parsed content for React Jot
+        if (!is_array($aBrowseParams) && $aBrowseParams === 'return_parsed_content')
+            foreach ($aEvents as &$aContent)
+                $this->_oTemplate->getPost($aContent, array('return_parsed_content'));
+
+        return $aEvents;
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_notifications Notifications
+     * @subsection bx_notifications-other Other
+     * @subsubsection bx_notifications-get_unread_notifications get_unread_notifications
+     * 
+     * @code bx_srv('bx_notifications', 'get_unread_notifications', [...]); @endcode
+     * 
+     * Get unread notifications.
+     *
+     * @return array with unread notifications.
+     * 
+     * @see BxNtfsModule::serviceGetUnreadNotifications
+     */
+    /** 
+     * @ref bx_notifications-get_unread_notifications "get_unread_notifications"
+     */
+    public function serviceGetUnreadNotifications($iOwnerId = 0)
+    {
+        return $this->serviceGetNotifications($iOwnerId, array('new' => 1));
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_notifications Notifications
+     * @subsection bx_notifications-other Other
+     * @subsubsection bx_notifications-get_unread_notifications_num get_unread_notifications_num
+     * 
+     * @code bx_srv('bx_notifications', 'get_unread_notifications_num', [...]); @endcode
+     * 
+     * Get number of unread notifications.
+     *
+     * @return integer value with number of unread notifications.
+     * 
+     * @see BxNtfsModule::serviceGetUnreadNotificationsNum
+     */
+    /** 
+     * @ref bx_notifications-get_unread_notifications_num "get_unread_notifications_num"
+     */
+    public function serviceGetUnreadNotificationsNum($iOwnerId = 0)
+    {
+        if(!$iOwnerId)
+            $iOwnerId = $this->getUserId();
+
+        if(!$iOwnerId)
+            return 0;
+
+        $sModule = $this->_oConfig->getName();
+        $aBrowseParams = $this->_prepareParams(BX_NTFS_TYPE_DEFAULT, $iOwnerId, 0, PHP_INT_MAX);
+
+        $sParamCheck = 'perform_privacy_check';
+        $sParamCheckFor = 'perform_privacy_check_for';
+
+        $iEvents = 0;
+        if($this->_oConfig->isEventsGrouped()) {
+            $aEvents = $this->_oDb->getEvents($aBrowseParams);
+
+            $this->groupEvents($aEvents);
+
+            $iCount = 0;
+            $iLastRead = $this->_oDb->getLastRead((int)$aBrowseParams['owner_id']);
+            foreach($aEvents as $aEvent)
+                if($aEvent['id'] > $iLastRead)
+                    $iCount++;
+
+            $aEvents = array_slice($aEvents, 0, $iCount);
+        }
+        else {
+            $aBrowseParams = array_merge($aBrowseParams, [
+                'new' => 1,
+            ]);
+
+            $aEvents = $this->_oDb->getEvents($aBrowseParams);
+        }
+
+        foreach($aEvents as $aEvent) {
+            if(isset($aBrowseParams[$sParamCheck]) && $aBrowseParams[$sParamCheck] !== true) 
+                continue;
+
+            $iViewerId = !empty($aBrowseParams[$sParamCheckFor]) ? (int)$aBrowseParams[$sParamCheckFor] : 0;
+
+            $oPrivacyInt = BxDolPrivacy::getObjectInstance($this->_oConfig->getObject('privacy_view'));
+            if(!$oPrivacyInt->check($aEvent['id'], $iViewerId))
+                continue;
+
+            $oPrivacyExt = $this->_oConfig->getPrivacyObject($aEvent['type'] . '_' . $aEvent['action']);
+            if($oPrivacyExt !== false && !$oPrivacyExt->check($aEvent['id'], $iViewerId))
+                continue;
+
+            $iContentObjectId = $this->_oConfig->getContentObjectId($aEvent);
+            if($iContentObjectId === false) {
+                $this->_oTemplate->getPost($aEvent, $aBrowseParams);
+                $iContentObjectId = $this->_oConfig->getContentObjectId($aEvent);
+            }
+
+            $sSrvModule = $this->_oConfig->getContentModule($aEvent);
+            $sSrvMethod = 'check_allowed_with_content_for_profile';
+            if($sSrvModule && bx_is_srv($sSrvModule, $sSrvMethod) && bx_srv($sSrvModule, $sSrvMethod, ['view', $iContentObjectId, $iViewerId]) !== CHECK_ACTION_RESULT_ALLOWED)
+                continue;
+
+            $bEventCanceled = false;
+            
+            /**
+             * @hooks
+             * @hookdef hook-bx_notifications-is_notification 'bx_notifications', 'is_notification' - hook to override checking if an event is available or not
+             * - $unit_name - equals `bx_notifications`
+             * - $action - equals `is_notification`
+             * - $object_id - not used
+             * - $sender_id - not used
+             * - $extra_params - array of additional params with the following array keys:
+             *      - `browse_params` - [array] browse params array as key&value pairs
+             *      - `event` - [array] by ref, array with event data as key&value pairs, can be overridden in hook processing
+             *      - `event_canceled` - [boolean] by ref, if event is canceled (not available) or not, can be overridden in hook processing
+             * @hook @ref hook-bx_notifications-is_notification
+             */
+            bx_alert($sModule, 'is_notification', 0, 0, [
+                'browse_params' => $aBrowseParams,
+                'event' => &$aEvent, 
+                'event_canceled' => &$bEventCanceled,
+                'event_ref' => &$aEvent, 
+                'event_canceled_ref' => &$bEventCanceled
+            ]);
+
+            if($bEventCanceled)
+                continue;
+
+            $iEvents++;
+        }
+
+        return $iEvents;
+    }
+    
+    public function serviceGetUnreadNotificationsNumEx($iOwnerId, $iCount)
+    {
+         header('Content-Type: text/event-stream');
+         header('Cache-Control: no-cache');
+         $iTmp = $this->serviceGetUnreadNotificationsNum($iOwnerId);
+         if ($iCount != $iTmp){
+             $time = date('r');
+             echo "id: " . time() . "\n";
+             echo "data: $iTmp\n\n";
+             flush();
+         }
+         exit();
+            
+     }
+
+    /**
+     * @page service Service Calls
+     * @section bx_notifications Notifications
+     * @subsection bx_notifications-other Other
+     * @subsubsection bx_notifications-get_live_updates get_live_updates
+     * 
+     * @code bx_srv('bx_notifications', 'get_live_updates', [...]); @endcode
+     * 
+     * Get data for Live Updates system.
+     *
+     * @return an array with special format.
+     * 
+     * @see BxNtfsModule::serviceGetLiveUpdates
+     */
+    /** 
+     * @ref bx_notifications-get_live_updates "get_live_updates"
+     */
+    public function serviceGetLiveUpdates($aMenuItemParent, $aMenuItemChild, $iCount = 0)
+    {
+        $iOwnerId = $this->getUserId();
+        $iCountNew = $this->serviceGetUnreadNotificationsNum($iOwnerId);
+        if($iCountNew == $iCount)
+			return false;
+
+        return array(
+    		'count' => $iCountNew, // required
+    		'method' => 'bx_menu_show_live_update(oData)', // required
+    		'data' => array(
+    			'code' => BxDolTemplate::getInstance()->parseHtmlByTemplateName('menu_item_addon', array(
+    				'content' => '{count}'
+                )),
+                'mi_parent' => $aMenuItemParent,
+                'mi_child' => $aMenuItemChild
+    		),  // optional, may have some additional data to be passed in JS method provided using 'method' param above.
+    	);
+    }
+
+    /*
+     * COMMON METHODS
+     */
+    public function getBlockSettings($sDeliveryType, $aParams = array())
+    {
+        return $this->_oTemplate->getSettingsBlock($sDeliveryType, $aParams);
+    }
+
+    public function setSubmenu($sSelected)
+    {
+    	$oSubmenuSystem = BxDolMenu::getObjectInstance('sys_site_submenu');
+        if(!$oSubmenuSystem)
+            return;
+
+        $CNF = &$this->_oConfig->CNF;
+
+        $oSubmenuSystem->setObjectSubmenu($CNF['OBJECT_MENU_SUBMENU'], array (
+            'title' => _t('_bx_ntfs'),
+            'link' => bx_absolute_url(BxDolPermalinks::getInstance()->permalink($CNF['URL_HOME'])),
+            'icon' => '',
+        ));
+
+        $oSubmenuModule = BxDolMenu::getObjectInstance($CNF['OBJECT_MENU_SUBMENU']);
+        if($oSubmenuModule)
+            $oSubmenuModule->setSelected($this->_oConfig->getName(), $sSelected);
+    }
+
+    public function onPost($iId)
+    {
+    	//--- Event -> Post for Alerts Engine ---//
+        $oAlert = new BxDolAlerts($this->_oConfig->getObject('alert'), 'post', $iId);
+        $oAlert->alert();
+        //--- Event -> Post for Alerts Engine ---//
+    }
+
+    public function enableSettingsLike($iId, $bValue, $bAdministration = false)
+    {
+        return $this->_changeSettingsLike($iId, 'activate', [$bValue], $bAdministration);
+    }
+
+    public function changeSettingsValueLike($iId, $sField, $mixedValue, $bAdministration = false)
+    {
+        return $this->_changeSettingsLike($iId, 'change', [$sField, $mixedValue], $bAdministration);
+    }
+
+    public function sendNotificationEmail($iProfile, $aNotification)
+    {
+        if(!$iProfile)
+            return false;
+
+        $aSettings = &$aNotification['settings'];
+
+        $sTemplate = !empty($aSettings['template']) ? $aSettings['template'] : 'bx_notifications_new_event';
+        $aTemplateMarkers = [
+            'subject' => !empty($aNotification['subject']) ? $aNotification['subject'] : _t('_bx_ntfs_txt_new_event_subject', getParam('site_title')),
+            'content' => $aNotification['content']
+        ];
+        if(!empty($aSettings['markers']) && is_array($aSettings['markers']))
+            $aTemplateMarkers = array_merge($aTemplateMarkers, $aSettings['markers']);              
+
+        $aTemplate = null;
+        /**
+         * @hooks
+         * @hookdef hook-bx_notifications-before_parse_email_template 'bx_notifications', 'before_parse_email_template' - hook to override email template
+         * - $unit_name - equals `bx_notifications`
+         * - $action - equals `before_parse_email_template`
+         * - $object_id - not used
+         * - $sender_id - not used
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `profile_id` - [int] recipient profile id
+         *      - `template` - [string] email template name
+         *      - `markers` - [array] parsable variables array as key&value pairs
+         *      - `notification` - [array] notification data array as key&value pairs
+         *      - `override_result` - [array] by ref, email template (subject and body), if null, then default one will be used, can be overridden in hook processing
+         * @hook @ref hook-bx_notifications-before_parse_email_template
+         */
+        bx_alert($this->_aModule['name'], 'before_parse_email_template', 0, 0, [
+            'profile_id' => $iProfile, 
+            'template' => $sTemplate, 
+            'markers' => $aTemplateMarkers, 
+            'notification' => $aNotification, 
+            'override_result' => &$aTemplate
+        ]);
+        if(is_null($aTemplate))
+            $aTemplate = BxDolEmailTemplates::getInstance()->parseTemplate($sTemplate, $aTemplateMarkers, 0, $iProfile);
+        if(!$aTemplate)
+            return false;
+
+        $sEmail = BxDolProfileQuery::getInstance()->getEmailById($iProfile);
+        $sSubject = !empty($aSettings['subject']) ? $aSettings['subject'] : $aTemplate['Subject'];
+        return sendMail($sEmail, $sSubject, $aTemplate['Body'], $iProfile, array(), BX_EMAIL_NOTIFY, 'html', false, array(), true);
+    }
+
+    public function sendNotificationPush($iProfile, $aNotification)
+    {
+        if(!$iProfile)
+            return false;
+        
+        $oPush = BxDolPush::getObjectInstance();
+        if(!$oPush)
+            return false;
+        
+
+        $aContent = &$aNotification['content'];
+        $aSettings = &$aNotification['settings'];
+        
+        /**
+         * @hooks
+         * @hookdef hook-bx_notifications-before_send_notification_push 'bx_notifications', 'before_send_notification_push' - hook to override push message
+         * - $unit_name - equals `bx_notifications`
+         * - $action - equals `before_send_notification_push`
+         * - $object_id - not used
+         * - $sender_id - not used
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `profile_id` - [int] recipient profile id
+         *      - `content` - [array] by ref, push message params array as key&value pairs, can be overridden in hook processing
+         *      - `setting` - [array] by ref, push settings array as key&value pairs, can be overridden in hook processing
+         *      - `subject` - [string] by ref, push message subject, can be overridden in hook processing
+         * @hook @ref hook-bx_notifications-before_send_notification_push
+         */
+        bx_alert($this->_aModule['name'], 'before_send_notification_push', 0, 0, [
+            'profile_id' => $iProfile, 
+
+            'content' => &$aContent, 
+            'setting' => &$aSettings, 
+            'subject' => &$sSubject,
+
+            'content_ref' => &$aContent, 
+            'setting_ref' => &$aSettings, 
+            'subject_ref' => &$sSubject,
+        ]);
+        
+        if (!$aContent)
+            return false;
+
+        $sSubject = !empty($aSettings['subject']) ? $aSettings['subject'] : _t('_bx_ntfs_txt_new_event_subject', getParam('site_title'));
+
+        return $oPush->send($iProfile, [
+            'contents' => [
+                'en' => $aContent['message']
+            ],
+            'headings' => [
+                'en' => $sSubject
+            ],
+            'url' => $aContent['url'],
+            'icon' => $aContent['icon']
+        ], true);
+    }
+
+    public function groupEvents(&$aEvents)
+    {
+        //--- Check for Visual Grouping
+        $aGroups = [];
+        foreach($aEvents as $iIndex => $aEvent) {
+            if(empty($aEvent['source']))
+                continue;
+
+            $sSource = $aEvent['source'];
+            if(!isset($aGroups[$sSource]))
+               $aGroups[$sSource] = [];
+
+            $aGroups[$sSource][$iIndex] = $aEvent['priority'];
+        }
+
+        //--- Perform Visual Grouping
+        foreach($aGroups as $sSource => $aGroup) {
+            if(!is_array($aGroup) || count($aGroup) < 2)
+                continue;
+
+            arsort($aGroup);
+            $iPriorityMax = reset($aGroup);
+
+            foreach($aGroup as $iIndex => $iPriority)
+                if($iPriority != $iPriorityMax)
+                    unset($aEvents[$iIndex]);
+        }
+    }
+    
+    public function serviceMarkAsRead()
+    {
+        $iOwnerId = bx_get_logged_profile_id();
+        $aParams = $this->_prepareParams(BX_NTFS_TYPE_OBJECT_OWNER_AND_CONNECTIONS, $iOwnerId);
+        $this->markAsRead($iOwnerId, $aParams);
+    }
+
+    public function markAsRead($iOwnerId, $aParams)
+    {
+        $aParams['browse'] = 'first';
+    	$aEvent = $this->_oDb->getEvents($aParams);
+    	if(empty($aEvent) || !is_array($aEvent))
+            return false;
+
+        return $this->_oDb->markAsRead($iOwnerId, $aEvent['id']) !== false;
+    }
+
+    public function serviceEnableSetting($mixedParams)
+    {
+        if(!is_array($mixedParams))
+            $mixedParams = json_decode($mixedParams, true);
+
+        if(!isset($mixedParams['id'], $mixedParams['value']))
+            return false;
+
+        $iId = (int)$mixedParams['id'];
+        $iValue = (int)$mixedParams['value'];
+        $bAdministration = isset($mixedParams['admin']) && $mixedParams['admin'];
+
+        if(!$this->_oConfig->isSettingsGrouped())
+            $mixedResult = $this->_oDb->updateSetting(['active' => $iValue], ['id' => $iId]);
+        else 
+            $mixedResult = $this->enableSettingsLike($iId, $iValue, $bAdministration);
+
+        return $mixedResult !== false;
+    }
+            
+    public function serviceChangeSetting($mixedParams)
+    {
+        if(!is_array($mixedParams))
+            $mixedParams = json_decode($mixedParams, true);
+
+        if(!isset($mixedParams['id'], $mixedParams['value']))
+            return false;
+
+        $iId = (int)$mixedParams['id'];
+        $iValue = (int)$mixedParams['value'];
+
+        if(!$this->_oConfig->isSettingsGrouped())
+            $mixedResult = $this->_oDb->updateSetting(['value' => $iValue], ['id' => $iId]);
+        else 
+            $mixedResult = $this->changeSettingsValueLike($iId, 'value', $iValue, true);
+
+        return $mixedResult !== false;
+    }
+
+    /*
+     * INTERNAL METHODS
+     */
+    protected function _changeSettingsLike($iId, $sAction, $aArgs, $bAdministration = false)
+    {
+        $aSetting = $this->_oDb->getSetting(array(
+            'by' => $bAdministration ? 'id' : 'tsu_id', 
+            'id' => (int)$iId
+        ));
+        if(empty($aSetting) || !is_array($aSetting))
+            return false;
+
+        $aSettingsIds = $this->_oDb->getSetting(array(
+            'by' => 'group_type_delivery', 
+            'group' => $aSetting['group'], 
+            'delivery' => $aSetting['delivery'], 
+            'type' => $aSetting['type'], 
+            'active' => !$bAdministration
+        ));
+        if(empty($aSettingsIds) || !is_array($aSettingsIds))
+            return false;
+
+        $sMethod = $sAction . 'SettingById' . (!$bAdministration ? 'User' : '');
+
+        if(!$bAdministration)
+            $aArgs[] = bx_get_logged_profile_id();
+        $aArgs[] = $aSettingsIds;
+
+        return call_user_func_array([$this->_oDb, $sMethod], $aArgs);
+    }
+
+    protected function _prepareParams($sType = '', $iOwnerId = 0, $iStart = -1, $iPerPage = -1, $aModules = [])
+    {
+        $iUserId = $this->getUserId();
+        $iOwnerId = (int)$iOwnerId != 0 ? $iOwnerId : $iUserId;
+
+        $aParams = [
+            'browse' => 'list',
+            'type' => !empty($sType) ? $sType : BX_NTFS_TYPE_DEFAULT,
+            'owner_id' => $iOwnerId,
+            'start' => (int)$iStart > 0 ? $iStart : 0,
+            'start_from_item' => false,
+            'per_page' => (int)$iPerPage > 0 ? $iPerPage : $this->_oConfig->getPerPage(),
+            'modules' => is_array($aModules) && !empty($aModules) ? $aModules : [],
+            'last_read' => $this->_oDb->getLastRead($iOwnerId),
+            'viewer_id' => $iUserId,
+            'active' => 1
+        ];
+
+        return $aParams;
+    }
+
+    protected function _prepareParamsGet()
+    {
+        $aParams = [];
+        $aParams['browse'] = 'list';
+
+        $sType = bx_get('type');
+        $aParams['type'] = $sType !== false ? bx_process_input($sType, BX_DATA_TEXT) : BX_NTFS_TYPE_DEFAULT;
+
+        $aParams['owner_id'] = $sType !== false ? bx_process_input(bx_get('owner_id'), BX_DATA_INT) : $this->getUserId();
+
+        $iStart = bx_get('start');
+        $aParams['start'] = $iStart !== false ? bx_process_input($iStart, BX_DATA_INT) : 0;
+        $aParams['start_from_item'] = false;
+
+        $iPerPage = bx_get('per_page');
+        $aParams['per_page'] = $iPerPage !== false ? bx_process_input($iPerPage, BX_DATA_INT) : $this->_oConfig->getPerPage();
+
+        $aModules = bx_get('modules');
+        $aParams['modules'] = $aModules !== false ? bx_process_input($aModules, BX_DATA_TEXT) : [];
+
+        $iViewerId = $this->getUserId();
+        if(($aParams['viewer_id'] = bx_get('viewer_id')) !== false)
+            $aParams['viewer_id'] = bx_process_input($aParams['viewer_id'], BX_DATA_INT);
+        if(!$aParams['viewer_id'] || $aParams['viewer_id'] != $iViewerId)
+            $aParams['viewer_id'] = $iViewerId;
+
+        $aParams['active'] = 1;
+
+        return $aParams;
+    }
+}
+
+/** @} */

+ 64 - 0
modules/boonex/notifications/updates/15.0.2_15.0.3/source/classes/BxNtfsStudioPage.php

@@ -0,0 +1,64 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Notifications Notifications
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+define('BX_DOL_STUDIO_MOD_TYPE_ETEMPLATES', 'etemplates_text');
+
+class BxNtfsStudioPage extends BxBaseModNotificationsStudioPage
+{
+    public function __construct($sModule, $mixedPageName, $sPage = "")
+    {
+    	$this->_sModule = 'bx_notifications';
+
+        parent::__construct($sModule, $mixedPageName, $sPage);
+
+        $this->aMenuItems = array_merge($this->aMenuItems, array(
+            BX_BASE_MOD_NTFS_DTYPE_SITE => array('name' => BX_BASE_MOD_NTFS_DTYPE_SITE, 'icon' => 'globe', 'title' => '_bx_ntfs_lmi_cpt_site'),
+            BX_BASE_MOD_NTFS_DTYPE_EMAIL => array('name' => BX_BASE_MOD_NTFS_DTYPE_EMAIL, 'icon' => 'envelope', 'title' => '_bx_ntfs_lmi_cpt_email'),
+            BX_BASE_MOD_NTFS_DTYPE_PUSH => array('name' => BX_BASE_MOD_NTFS_DTYPE_PUSH, 'icon' => 'bullhorn', 'title' => '_bx_ntfs_lmi_cpt_push'),
+            BX_DOL_STUDIO_MOD_TYPE_ETEMPLATES => array('name' => BX_DOL_STUDIO_MOD_TYPE_ETEMPLATES, 'icon' => 'file-word', 'title' => '_bx_ntfs_lmi_cpt_etemplates_text'),
+        ));
+    }
+
+    protected function getSite()
+    {
+        return $this->_getDeliveryType(BX_BASE_MOD_NTFS_DTYPE_SITE);
+    }
+
+    protected function getEmail()
+    {
+        return $this->_getDeliveryType(BX_BASE_MOD_NTFS_DTYPE_EMAIL);
+    }
+
+    protected function getPush()
+    {
+        return $this->_getDeliveryType(BX_BASE_MOD_NTFS_DTYPE_PUSH);
+    }
+    
+    protected function getEtemplatesText()
+    {
+        $oGrid = BxDolGrid::getObjectInstance($this->_oModule->_oConfig->CNF['OBJECT_GRID_ETEMPLATES'], BxDolStudioTemplate::getInstance());
+        if(!$oGrid)
+            return '';
+
+        $this->_oModule->_oTemplate->addStudioJs(['main.js']);
+        return $oGrid->getCode();
+    }
+
+    protected function _getDeliveryType($sDeliveryType)
+    {
+        return $this->_oModule->getBlockSettings($sDeliveryType, array(
+            'grid' => $this->_oModule->_oConfig->CNF['OBJECT_GRID_SETTINGS_ADMINISTRATION'],
+            'template' => BxDolStudioTemplate::getInstance()
+        ));
+    }
+}
+
+/** @} */

+ 633 - 0
modules/boonex/notifications/updates/15.0.2_15.0.3/source/classes/BxNtfsTemplate.php

@@ -0,0 +1,633 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Notifications Notifications
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+require_once(BX_DIRECTORY_PATH_INC . "design.inc.php");
+
+class BxNtfsTemplate extends BxBaseModNotificationsTemplate
+{
+    function __construct(&$oConfig, &$oDb)
+    {
+        parent::__construct($oConfig, $oDb);
+    }
+
+    public function getInclude($bIncludeCss = true, $mixedIncludeJs = false)
+    {
+        if($bIncludeCss)
+            $this->getAddedCss();
+
+        $sResult = '';
+        if(is_string($mixedIncludeJs) && !empty($mixedIncludeJs)) {
+            $this->getAddedJs();
+            
+            $sResult = $this->getJsCode($mixedIncludeJs);
+        }
+            
+        return $sResult;
+    }
+
+    public function getViewBlock($aParams)
+    {
+        return $this->parseHtmlByName('block_view.html', array(
+            'html_id_view_block' => $this->_oConfig->getHtmlIds('view', 'block'),
+            'html_id_events' => $this->_oConfig->getHtmlIds('view', 'events'),
+            'style_prefix' => $this->_oConfig->getPrefix('style'),
+            'content' => $this->getPosts($aParams),
+            'js_content' => $this->getJsCode('view', array(
+                'oRequestParams' => array(
+                    'type' => $aParams['type'],
+                    'owner_id' => $aParams['owner_id'],
+                    'start' => $aParams['start'],
+                    'per_page' => $aParams['per_page'],
+                    'modules' => $aParams['modules']
+                )
+            ))
+        ));
+    }
+
+    public function getSettingsBlock($sDeliveryType, $aParams = array())
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $iUserId = !empty($aParams['user_id']) ? (int)$aParams['user_id'] : bx_get_logged_profile_id();
+        $sGrid = !empty($aParams['grid']) ? $aParams['grid'] : $CNF['OBJECT_GRID_SETTINGS_COMMON'];
+        $oTemplate = !empty($aParams['template']) ? $aParams['template'] : $this;
+
+        $oGrid = BxDolGrid::getObjectInstance($sGrid, $oTemplate);
+        if(!$oGrid)
+            return '';
+
+        $oGrid->setDeliveryType($sDeliveryType);
+        if(method_exists($oGrid, 'setUserId'))
+            $oGrid->setUserId($iUserId);
+
+        return !$this->_bIsApi ? $oGrid->getCode() : [
+            bx_api_get_block('notifications_settings', $oGrid->getCodeApi(true), ['ext' => ['request_url' => '/api.php?r=' . $this->_oConfig->getName() . '/enable_setting/&params[]=']])
+        ];
+    }
+
+    public function getPosts($aParams)
+    {
+    	$sJsObject = $this->_oConfig->getJsObject('view');
+
+    	$aParamsDb = $aParams;
+    	$aParamsDb['per_page'] = 3 * $aParamsDb['per_page'];
+
+        $aEvents = $this->_oDb->getEvents($aParamsDb);
+        if(empty($aEvents))
+            return bx_is_api() ? [] : $this->getEmpty();
+
+        if($this->_oConfig->isEventsGrouped())
+            $this->_oModule->groupEvents($aEvents);
+
+        $aTmplVarsEvents = array();
+
+        foreach($aEvents as $aEvent) {
+            $sEvent = $this->getPost($aEvent, $aParams);
+            if(empty($sEvent))
+                continue;
+
+            if($this->_bIsApi){
+                if(!isset($sEvent['author_data']))
+                    $sEvent['author_data'] = BxDolProfile::getData($sEvent['owner_id']);
+
+                $aTmplVarsEvents[] = $sEvent;
+            }
+            else
+                $aTmplVarsEvents[] = ['event' => $sEvent];
+
+            if(count($aTmplVarsEvents) >= ($aParams['per_page'] + 1))
+            	break;
+        }
+
+        if($this->_bIsApi)
+            return $aTmplVarsEvents;
+
+        $oPaginate = new BxTemplPaginate(array(
+            'start' => $aParams['start'],
+            'per_page' => $aParams['per_page'],
+            'page_url' => $this->_oConfig->getViewUrl(),
+            'on_change_page' => $sJsObject . ".changePage(this, {start}, {per_page})"
+        ));
+        $oPaginate->setNumFromDataArray($aTmplVarsEvents);
+
+        return $this->parseHtmlByName('events.html', array(
+            'style_prefix' => $this->_oConfig->getPrefix('style'),
+            'bx_repeat:events' => $aTmplVarsEvents,
+            'paginate' => $oPaginate->getSimplePaginate()
+        ));
+    }
+
+    /**
+     * Enter description here ...
+     * @example Available keys are:
+     * 1. owner_name and owner_link
+     * 2. entry_caption and entry_url
+     * 3. subentry_url and subentry_sample
+     * 
+     */
+    public function getPost(&$aEvent, $aBrowseParams = array())
+    {
+    	$oModule = $this->getModule();
+
+        if(!empty($aEvent['content']) && is_string($aEvent['content']))
+            $aEvent['content'] = unserialize($aEvent['content']);
+
+    	if((int)$aEvent['processed'] == 0)
+            $this->_processContent($aEvent);
+
+        if((int)$aEvent['processed'] == 0 || empty($aEvent['content']))
+            return '';
+
+        $sParamCheck = 'perform_privacy_check';
+        if(!isset($aBrowseParams[$sParamCheck]) || $aBrowseParams[$sParamCheck] === true) {
+            $sParamCheckFor = 'perform_privacy_check_for';
+            $iViewerId = !empty($aBrowseParams[$sParamCheckFor]) ? (int)$aBrowseParams[$sParamCheckFor] : 0;
+
+            $oPrivacyInt = BxDolPrivacy::getObjectInstance($this->_oConfig->getObject('privacy_view'));
+            if(!$oPrivacyInt->check($aEvent['id'], $iViewerId))
+                return '';
+
+            $oPrivacyExt = $this->_oConfig->getPrivacyObject($aEvent['type'] . '_' . $aEvent['action']);
+            if($oPrivacyExt !== false && !$oPrivacyExt->check($aEvent['id'], $iViewerId))
+                return '';
+
+            $sSrvModule = $this->_oConfig->getContentModule($aEvent);
+            $sSrvMethod = 'check_allowed_with_content_for_profile';
+            if($sSrvModule && bx_is_srv($sSrvModule, $sSrvMethod) && bx_srv($sSrvModule, $sSrvMethod, ['view', $this->_oConfig->getContentObjectId($aEvent), $iViewerId]) !== CHECK_ACTION_RESULT_ALLOWED)
+                return '';
+        }
+
+        $bShowRealProfile = !isset($aBrowseParams['show_real_profile']) || $aBrowseParams['show_real_profile'] === true;
+
+        $oOwner = $oModule->getObjectUser($aEvent['owner_id']);
+        if(!$bShowRealProfile && $oOwner instanceof BxDolProfileAnonymous)
+            $oOwner->setShowRealProfile($bShowRealProfile);
+
+        $aEvent['content']['owner_name'] = strmaxtextlen($oOwner->getDisplayName(), $this->_oConfig->getOwnerNameMaxLen());
+        $aEvent['content']['owner_link'] = $oOwner->getUrl();
+        $aEvent['content']['owner_icon'] = $oOwner->getThumb();
+
+        if(!empty($aEvent['content']['entry_caption'])) {
+            $sEntryCaption = bx_process_output($aEvent['content']['entry_caption'], BX_DATA_TEXT);
+            if(get_mb_substr($sEntryCaption, 0, 1) == '_')
+                $sEntryCaption = _t($sEntryCaption);
+
+            $aEvent['content']['entry_caption'] = strmaxtextlen($sEntryCaption, $this->_oConfig->getContentMaxLen());
+        }
+
+        $iObjectOwner = (int)$aEvent['object_owner_id'];
+        if(empty($iObjectOwner) && !empty($aEvent['content']['entry_author']))
+            $iObjectOwner = (int)$aEvent['content']['entry_author'];
+
+        $oObjectOwner = $oModule->getObjectUser($iObjectOwner);
+        if($oObjectOwner) {
+            if(!$bShowRealProfile && $oObjectOwner instanceof BxDolProfileAnonymous)
+                $oObjectOwner->setShowRealProfile($bShowRealProfile);
+
+            $aEvent['content']['object_owner_name'] = strmaxtextlen($oObjectOwner->getDisplayName(), $this->_oConfig->getOwnerNameMaxLen());
+            $aEvent['content']['object_owner_link'] = $oObjectOwner->getUrl();
+            $aEvent['content']['object_owner_icon'] = $oObjectOwner->getThumb();
+        }
+
+        foreach($aEvent['content'] as $sKey => $sValue) {
+            if(!is_string($sValue) || substr($sValue, 0, 1) != '_') 
+                continue;
+
+            $aCallParams = array($sValue);
+
+            $sKeyParams = $sKey . '_params';
+            if(isset($aEvent['content'][$sKeyParams]) && is_array($aEvent['content'][$sKeyParams])) {
+                foreach($aEvent['content'][$sKeyParams] as $iParamIndex => $sParamValue)
+                    if(is_string($sParamValue) && substr($sParamValue, 0, 1) == '_')
+                        $aEvent['content'][$sKeyParams][$iParamIndex] = _t($sParamValue);
+
+                $aCallParams = array_merge($aCallParams, $aEvent['content'][$sKeyParams]);
+                unset($aEvent['content'][$sKeyParams]);
+            }
+
+            $aEvent['content'][$sKey] = call_user_func_array('_t', $aCallParams);
+        }
+
+        $sOwnerUnit = $oOwner->getUnit(0, ['template' => 'unit_wo_info_links']);
+
+        $bEventParsed = false;
+        $bEventCanceled = false;
+        
+        /**
+         * @hooks
+         * @hookdef hook-bx_notifications-get_notification 'bx_notifications', 'get_notification' - hook to override notification or even cancel it
+         * - $unit_name - equals `bx_notifications`
+         * - $action - equals `get_notification`
+         * - $object_id - not used
+         * - $sender_id - not used
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `browse_params` - [array] browse params array as key&value pairs
+         *      - `event` - [array] by ref, event data array, can be overridden in hook processing        
+         *      - `event_parsed` - [boolean] by ref, if event was already parsed (ready to display), can be overridden in hook processing
+         *      - `event_canceled` - [boolean] by ref, if event was canceled, can be overridden in hook processing
+         *      - `owner` - [object] by ref, an instance of owner profile, @see BxDolProfile, can be overridden in hook processing
+         *      - `owner_unit` - [string] by ref, profile unit HTML code, can be overridden in hook processing
+         * @hook @ref hook-bx_notifications-get_notification
+         */
+        bx_alert($this->_oConfig->getName(), 'get_notification', 0, 0, [
+            'browse_params' => $aBrowseParams,
+
+            'event' => &$aEvent, 
+            'event_parsed' => &$bEventParsed, 
+            'event_canceled' => &$bEventCanceled,
+            'owner' => &$oOwner, 
+            'owner_unit' => &$sOwnerUnit,
+
+            'event_ref' => &$aEvent, 
+            'event_parsed_ref' => &$bEventParsed, 
+            'event_canceled_ref' => &$bEventCanceled,
+            'owner_ref' => &$oOwner, 
+            'owner_unit_ref' => &$sOwnerUnit,
+        ]);
+        
+        if ($bEventCanceled)
+            return '';
+
+        if(!$bEventParsed) {
+            $mLk = '';
+            if(!empty($aEvent['content']['lang_key'])) {
+                $mLk = $aEvent['content']['lang_key'];
+                if(!is_string($mLk) && !(is_array($mLk) && isset($mLk['site'], $mLk['email'], $mLk['push'])))
+                    $mLk = '';
+            }
+
+            if(empty($mLk))
+                $mLk = $this->_getContentLangKey($aEvent);
+
+            if(is_array($mLk))
+                foreach($mLk as $sDeliveryType => $sLangKey)
+                    $aEvent['content_parsed'][$sDeliveryType] = $this->_parseContentLangKey($sLangKey, $aEvent);
+            else
+                $aEvent['content_parsed'] = $this->_parseContentLangKey($mLk, $aEvent);
+        }
+
+        // returns parsed content for React Jot
+        if(isset($aBrowseParams['return_parsed_content']))
+            return $aEvent;
+
+        $bClickedIndicator = $this->_oConfig->isClickedIndicator();
+        $sJsObject = $this->_oConfig->getJsObject('view');
+
+        if($this->_bIsApi) {
+            $aLinks = [
+                'owner_link' => $aEvent['content']['owner_link'],
+                'object_owner_link' => $aEvent['content']['object_owner_link']
+            ];
+
+            foreach(['entry_url', 'entry_url_api', 'subentry_url', 'subentry_url_api'] as $sKey)
+                if(!empty($aEvent['content'][$sKey]))
+                    $aLinks[$sKey] = $this->_getLink($aEvent['content'][$sKey]);
+
+            array_walk($aLinks, function(&$sValue, $sKey) {
+                $sValue = bx_api_get_relative_url($sValue);
+            });
+
+            $aEvent['module'] = $aEvent['type'];
+            if(!$this->_oDb->isModuleByName($aEvent['module'])) {
+                if(!isset($aEvent['content']['module'])) {
+                    if(($s = $aEvent['source'] ?: '') || ($s = $aEvent['type']))
+                        $aEvent['module'] = substr($s, 0, strrpos($s, '_'));
+                }
+                else
+                    $aEvent['module'] = $aEvent['content']['module'];
+            }
+
+            $aEvent['content'] = array_merge($aEvent['content'], $aLinks);
+            $aEvent['content'] = array_intersect_key($aEvent['content'], array_flip([
+                'entry_url', 'entry_url_api', 'subentry_url', 'subentry_url_api'
+            ]));
+
+            if(($sKey = 'content_parsed') && is_array($aEvent[$sKey])) {
+                foreach($aEvent[$sKey] as $sDeliveryType => $sContentParsed)
+                    $aEvent[$sKey][$sDeliveryType] = html_entity_decode($sContentParsed);
+            }
+            else    
+                $aEvent[$sKey] = html_entity_decode($aEvent[$sKey]);
+
+            return array_intersect_key($aEvent, array_flip([
+                'id', 'owner_id', 'module', 'type', 'content', 'content_parsed', 'date', 'author_data'
+            ]));
+        }
+
+        return $this->parseHtmlByName('event.html', [
+            'html_id' => $this->_oConfig->getHtmlIds('view', 'event') . $aEvent['id'],
+            'style_prefix' => $this->_oConfig->getPrefix('style'),
+            'js_object' => $sJsObject,
+            'class' => !empty($aBrowseParams['last_read']) && $aEvent['id'] > $aBrowseParams['last_read'] ? ' bx-def-color-bg-box-active' : '', 
+            'id' => $aEvent['id'],
+            'author_unit' => $sOwnerUnit,
+            'link' => $this->_getContentLink($aEvent),
+            'content' => is_array($aEvent['content_parsed']) && isset($aEvent['content_parsed']['site']) ? $aEvent['content_parsed']['site'] : $aEvent['content_parsed'],
+            'date' => bx_time_js($aEvent['date']),
+            'bx_if:show_onclick' => [
+                'condition' => $bClickedIndicator,
+                'content' => [
+                    'js_object' => $sJsObject,
+                    'id' => $aEvent['id']
+                ]
+            ],
+            'bx_if:show_clicked_indicator' => [
+                'condition' => $bClickedIndicator && (!isset($aEvent['clicked']) || (int)$aEvent['clicked'] == 0),
+                'content' => []
+            ],
+        ]);
+    }
+
+    public function getNotificationEmail($iRecipient, &$aEvent)
+    {
+        $sEvent = $this->getPost($aEvent, ['perform_privacy_check_for' => $iRecipient, 'show_real_profile' => false]);
+        if(empty($sEvent) || empty($aEvent['content_parsed']))
+            return false;
+
+        $aContent = &$aEvent['content'];
+
+        $sIconUrl = !empty($aContent['owner_icon']) ? $aContent['owner_icon'] : $this->getIconUrl('std-icon.svg');
+        $sContentUrl = bx_absolute_url($this->_getContentLink($aEvent, getParam('sys_api_url_root_email') != ''));
+        $sContent = is_array($aEvent['content_parsed']) && isset($aEvent['content_parsed']['email']) ? $aEvent['content_parsed']['email'] : $aEvent['content_parsed'];
+        $sSummary = (($sK = 'subentry_summary') && ($sV = $aContent[$sK] ?? false)) || (($sK = 'entry_summary') && ($sV = $aContent[$sK] ?? false)) ? $sV : '';
+        $sDate = bx_process_output($aEvent['date'], BX_DATA_DATE_TS);
+
+        $aEtemplate = $this->_oDb->getEtemplates([
+            'sample' => 'type_action', 
+            'type' => $aEvent['type'], 
+            'action' => $aEvent['action'], 
+            'active' => 1
+        ]);
+
+        $sSubject = $sBody = '';
+        if(!empty($aEtemplate) && is_array($aEtemplate)) {
+            $aEtParams = array_diff_key($aContent, array_flip(['lang_key', 'settings']));
+            $aEtParams = array_merge($aEtParams, [
+                'icon_url' => $sIconUrl,
+                'content_url' => $sContentUrl,
+                'content' => $sContent,
+                'summary' => $sSummary,
+                'date' => $sDate
+            ]);
+
+            $sSubject = bx_replace_markers($aEtemplate['subject'], $aEtParams);
+            $sBody = bx_replace_markers($aEtemplate['body'], $aEtParams);
+        }
+        else {
+            $sSubject = $sContent;
+            $sBody = $this->parseHtmlByName('et_new_event.html', [
+                'icon_url' => $sIconUrl,
+                'content_url' => $sContentUrl,
+                'content' => $sContent,
+                'date' => $sDate,
+                'bx_if:show_summary' => [
+                    'condition' => !empty($sSummary),
+                    'content' => [
+                        'summary' => $sSummary
+                    ]
+                ]
+            ]);
+        }
+
+        if(($iEmailSubjectMaxLen = $this->_oConfig->getEmailSubjectMaxLen()) !== 0)
+            $sSubject = strmaxtextlen($sSubject, $iEmailSubjectMaxLen);
+        else 
+            $sSubject = trim(strip_tags($sSubject));
+
+        return [
+            'subject' => $sSubject,
+            'content' => $sBody,
+            'settings' => !empty($aContent['settings']['email']) ? $aContent['settings']['email'] : []
+        ];
+    }
+
+    public function getNotificationPush($iRecipient, &$aEvent)
+    {
+        $sEvent = $this->getPost($aEvent, array('perform_privacy_check_for' => $iRecipient, 'show_real_profile' => false));
+        if(empty($sEvent) || empty($aEvent['content_parsed']))
+            return false;
+
+        $sMessage = is_array($aEvent['content_parsed']) && isset($aEvent['content_parsed']['push']) ? $aEvent['content_parsed']['push'] : $aEvent['content_parsed'];
+        $sMessage = preg_replace('/<\/?[a-zA-Z0-9=\'":;\(\)\s_-]+>/i', ($sChar = getParam("bx_ntfs_option_tag_to_char_push")) !== false ? $sChar : '"', $sMessage);
+        if($sMessage)
+            $sMessage = BxTemplFunctions::getInstance()->getStringWithLimitedLength(html_entity_decode($sMessage), $this->_oConfig->getPushMaxLen());
+
+        if(empty($sMessage))
+            return false;
+
+        $aContent = &$aEvent['content'];
+        return array(
+            'content' => array(
+                'url' => bx_absolute_url($this->_getContentLink($aEvent, getParam('sys_api_url_root_push') != '')),
+                'message' => $sMessage,
+                'icon' => !empty($aContent['owner_icon']) ? $aContent['owner_icon'] : ''
+            ),
+            'settings' => !empty($aContent['settings']['push']) ? $aContent['settings']['push'] : array()
+        );
+    }
+
+    public function getEmpty($bVisible = true)
+    {
+        return $this->parseHtmlByName('empty.html', array(
+            'style_prefix' => $this->_oConfig->getPrefix('style'),
+            'visible' => $bVisible ? 'block' : 'none',
+            'content' => MsgBox(_t('_bx_ntfs_txt_msg_no_results'))
+        ));
+    }
+
+    public function getSelectActions($aActions)
+    {
+        $aTmplVarsActions = [
+            ['value' => '', 'title' => _t('_sys_please_select')]
+        ];
+
+        foreach($aActions as $sAction)
+            $aTmplVarsActions[] = ['value' => $sAction, 'title' => $this->getActionTitle($sAction)];
+
+        return $this->parseHtmlByName('field_actions.html', [
+            'bx_repeat:actions' => $aTmplVarsActions
+        ]);
+    }
+
+    public function getTypeTitle($sType)
+    {
+        $sResult = '';
+        if(($sKey = '_bx_ntfs_alert_module_' . $sType) && ($_sKey = _t($sKey)) && strcmp($sKey, $_sKey) != 0)
+            $sResult = $_sKey;
+        else if(($sKey = '_' . $sType) && ($_sKey = _t($sKey)) && strcmp($sKey, $_sKey) != 0)
+            $sResult = $_sKey;
+        else if(($aModule = $this->_oDb->getModuleByName($sType)) && is_array($aModule) && ($_sKey = $aModule['title'] ?? false))
+            $sResult = $_sKey;
+        else
+            $sResult = $sType;
+
+        return $sResult;
+    }
+
+    public function getActionTitle($sAction)
+    {
+        $sResult = '';
+        if(($sKey = '_bx_ntfs_alert_action_' . $sAction) && ($_sKey = _t($sKey)) && strcmp($sKey, $_sKey) != 0)
+            $sResult = $_sKey;
+        else if(($sKey .= '_personal') && ($_sKey = _t($sKey)) && strcmp($sKey, $_sKey) != 0)
+            $sResult = $_sKey;
+        else
+            $sResult = $sAction;
+
+        return $sResult;
+    }
+
+    protected function _processContent(&$aEvent)
+    {
+    	$aContent = $this->_getContent($aEvent);
+        if(empty($aContent) || !is_array($aContent)) 
+            return;
+
+        /**
+         * @hooks
+         * @hookdef hook-bx_notifications-get_content 'bx_notifications', 'get_content' - hook to override notification content
+         * - $unit_name - equals `bx_notifications`
+         * - $action - equals `get_content`
+         * - $object_id - not used
+         * - $sender_id - not used
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `event` - [array] by ref, event data array, can be overridden in hook processing        
+         *      - `override_result` - [array] by ref, event content array, can be overridden in hook processing
+         * @hook @ref hook-bx_notifications-get_content
+         */
+        bx_alert($this->_oConfig->getName(), 'get_content', 0, 0, [
+            'event' => $aEvent,
+            'override_result' => &$aContent
+        ]);
+
+        $aSet = array();
+        if(!empty($aContent['entry_author'])) {
+            $aSet['object_owner_id'] = (int)$aContent['entry_author'];
+            unset($aContent['entry_author']);
+        }
+
+        if(!empty($aContent['entry_privacy'])) {
+            $aSet['allow_view_event_to'] = $aContent['entry_privacy'];
+            $aEvent['allow_view_event_to'] = $aContent['entry_privacy'];
+            unset($aContent['entry_privacy']);
+        }
+
+        foreach(['entry_summary', 'subentry_summary'] as $sKey) {
+            if(empty($aContent[$sKey]))
+                continue;
+
+            $sSummary = nl2br(strip_tags($aContent[$sKey]));
+            $aContent[$sKey] = strmaxtextlen($sSummary, $this->_oConfig->getSummaryMaxLen());
+        }
+
+        if(!empty($aEvent['content'])) {
+            if(is_string($aEvent['content']))
+                $aEvent['content'] = unserialize($aEvent['content']);
+
+            if(is_array($aEvent['content']))
+                $aEvent['content'] = array_merge($aEvent['content'], $aContent);
+        }
+        else
+            $aEvent['content'] = $aContent;
+
+        $aEvent['processed'] = 1;
+
+        $aSet = array_merge($aSet, array(
+            'content' => serialize($aEvent['content']), 
+            'processed' => 1
+        ));
+
+        $this->_oDb->updateEvent($aSet, array('id' => $aEvent['id']));
+        return;
+    }
+
+    protected function _getContent(&$aEvent)
+    {
+        $sHandler = $aEvent['type'] . '_' . $aEvent['action'];
+        if(!$this->_oConfig->isHandler($sHandler))
+            return array();
+
+        $aHandler = $this->_oConfig->getHandlers($sHandler);
+        if(!empty($aHandler['module_name']) && !empty($aHandler['module_class']) && !empty($aHandler['module_method']))
+            return BxDolService::call($aHandler['module_name'], $aHandler['module_method'], array($aEvent), $aHandler['module_class']);
+
+        $sMethod = 'display' . bx_gen_method_name($aHandler['alert_unit'] . '_' . $aHandler['alert_action']);
+        if(!method_exists($this, $sMethod))
+            return array();
+
+        return $this->$sMethod($aEvent);
+    }
+
+    protected function _getContentLangKey(&$aEvent)
+    {
+        $bInContext = $this->_isInContext($aEvent);
+
+        if(!empty($aEvent['subobject_id']))
+            return '_bx_ntfs_txt_subobject_added' . ($bInContext ? '_in_context' : '');
+
+        $sKey = '';
+        switch($aEvent['action']) {
+            case 'pending_approval':
+                $sKey = '_bx_ntfs_txt_object_pending_approval';
+                break;
+
+            case 'reported_content':
+                $sKey = '_bx_ntfs_txt_object_reported_content';
+                break;
+
+            case 'publish_failed':
+                $sKey = '_bx_ntfs_txt_object_publish_failed';
+                break;
+
+            case 'publish_succeeded':
+                $sKey = '_bx_ntfs_txt_object_publish_succeeded';
+                break;
+
+            default:
+                $sKey = '_bx_ntfs_txt_object_' . $aEvent['action'] . ($bInContext ? '_in_context' : '');
+        }
+
+    	return $sKey;
+    }
+
+    protected function _parseContentLangKey($sLangKey, &$aEvent)
+    {
+        $aExclude = array(
+            'lang_key' => 1,
+            'settings' => 1
+        );
+
+        return $this->parseHtmlByContent(_t($sLangKey), array_diff_key($aEvent['content'], $aExclude), array('{', '}'));
+    }
+
+    protected function _getContentLink($aEvent, $bForApi = false)
+    {
+        $sLink = $aEvent['content']['entry_url' . ($bForApi ? '_api' : '')] ?? $aEvent['content']['entry_url'];
+        if(!empty($aEvent['subobject_id']) && !empty($aEvent['content']['subentry_url'])) 
+            $sLink = $aEvent['content']['subentry_url' . ($bForApi ? '_api' : '')] ?? $aEvent['content']['subentry_url'];
+
+        return $this->_getLink($sLink);
+    }
+
+    protected function _getLink($sLink)
+    {
+        return bx_replace_markers($sLink, [
+            'bx_url_root' => BX_DOL_URL_ROOT
+        ]);
+    }
+
+    protected function _isInContext(&$aEvent)
+    {
+        return (int)$aEvent['object_privacy_view'] < 0;
+    }
+}
+
+/** @} */

+ 82 - 0
modules/boonex/notifications/updates/15.0.2_15.0.3/source/install/config.php

@@ -0,0 +1,82 @@
+<?php
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Notifications Notifications
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+$aConfig = array(
+    /**
+     * Main Section.
+     */
+    'type' => BX_DOL_MODULE_TYPE_MODULE,
+    'name' => 'bx_notifications',
+    'title' => 'Notifications',
+    'note' => 'Notifications module.',
+    'version' => '15.0.3',
+    'vendor' => 'UNA INC',
+    'help_url' => 'http://feed.una.io/?section={module_name}',
+
+    'compatible_with' => array(
+        '15.0.0-B2'
+    ),
+
+    /**
+     * 'home_dir' and 'home_uri' - should be unique. Don't use spaces in 'home_uri' and the other special chars.
+     */
+    'home_dir' => 'boonex/notifications/',
+    'home_uri' => 'notifications',
+
+    'db_prefix' => 'bx_notifications_',
+    'class_prefix' => 'BxNtfs',
+
+    /**
+     * Category for language keys.
+     */
+    'language_category' => 'Notifications',
+
+    /**
+     * Installation/Uninstallation Section.
+     */
+    'install' => array(
+        'execute_sql' => 1,
+        'update_languages' => 1,
+        'clear_db_cache' => 1,
+    ),
+    'uninstall' => array (
+        'execute_sql' => 1,
+        'update_languages' => 1,
+        'clear_db_cache' => 1,
+    ),
+    'enable' => array(
+        'execute_sql' => 1,
+    	'update_relations_for_all' => 1,
+        'clear_db_cache' => 1,
+    ),
+    'disable' => array (
+        'execute_sql' => 1,
+    	'update_relations_for_all' => 1,
+        'clear_db_cache' => 1,
+    ),
+
+    /**
+     * Dependencies Section
+     */
+    'dependencies' => array(),
+
+    /**
+     * Relations Section
+     */
+    'relation_handlers' => array(
+    	'on_install' => '',
+    	'on_uninstall' => 'delete_module_events',
+	    'on_enable' => 'add_handlers',
+	    'on_disable' => 'delete_handlers',
+    ),
+);
+
+/** @} */

+ 223 - 0
modules/boonex/notifications/updates/15.0.2_15.0.3/source/install/langs/en.xml

@@ -0,0 +1,223 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources name="en" flag="gb" title="English">
+    <string name="_bx_ntfs"><![CDATA[Notifications]]></string>
+    <string name="_bx_notifications"><![CDATA[Notifications]]></string>
+
+    <string name="_bx_ntfs_form_etemplate"><![CDATA[Email Template]]></string>
+    <string name="_bx_ntfs_form_etemplate_display_add"><![CDATA[Add Email Template]]></string>
+    <string name="_bx_ntfs_form_etemplate_display_edit"><![CDATA[Edit Email Template]]></string>
+    <string name="_bx_ntfs_form_etemplate_input_controls"><![CDATA[Controls]]></string>
+    <string name="_bx_ntfs_form_etemplate_input_sys_do_submit"><![CDATA[Submit]]></string>
+    <string name="_bx_ntfs_form_etemplate_input_do_submit"><![CDATA[Submit]]></string>
+    <string name="_bx_ntfs_form_etemplate_input_sys_do_cancel"><![CDATA[Cancel]]></string>
+    <string name="_bx_ntfs_form_etemplate_input_do_cancel"><![CDATA[Cancel]]></string>
+    <string name="_bx_ntfs_form_etemplate_input_sys_type"><![CDATA[Type]]></string>
+    <string name="_bx_ntfs_form_etemplate_input_type"><![CDATA[Type]]></string>
+    <string name="_bx_ntfs_form_etemplate_input_sys_action"><![CDATA[Action]]></string>
+    <string name="_bx_ntfs_form_etemplate_input_action"><![CDATA[Action]]></string>
+    <string name="_bx_ntfs_form_etemplate_input_sys_subject"><![CDATA[Subject]]></string>
+    <string name="_bx_ntfs_form_etemplate_input_subject"><![CDATA[Subject]]></string>
+    <string name="_bx_ntfs_form_etemplate_input_sys_body"><![CDATA[Body]]></string>
+    <string name="_bx_ntfs_form_etemplate_input_body"><![CDATA[Body]]></string>
+    <string name="_bx_ntfs_form_etemplate_input_err_select"><![CDATA[This field is essential. Please select a value.]]></string>
+    <string name="_bx_ntfs_form_etemplate_input_err_enter"><![CDATA[This field is essential. Please fill it in.]]></string>
+
+    <string name="_bx_ntfs_page_title_system_view"><![CDATA[Notifications]]></string>
+    <string name="_bx_ntfs_page_title_view"><![CDATA[Notifications]]></string>
+    <string name="_bx_ntfs_page_block_title_view"><![CDATA[Notifications]]></string>
+    <string name="_bx_ntfs_page_title_system_settings"><![CDATA[Notifications Settings]]></string>
+    <string name="_bx_ntfs_page_title_settings"><![CDATA[Notifications Settings]]></string>
+    <string name="_bx_ntfs_page_block_title_delivery"><![CDATA[Receive via]]></string>
+    <string name="_bx_ntfs_page_block_title_settings"><![CDATA[Notifications]]></string>
+
+    <string name="_bx_ntfs_menu_title_submenu"><![CDATA[Notifications Submenu]]></string>
+    <string name="_bx_ntfs_menu_title_public_submenu"><![CDATA[Notifications]]></string>
+    <string name="_bx_ntfs_menu_set_title_submenu"><![CDATA[Notifications Submenu]]></string>
+    <string name="_bx_ntfs_menu_item_title_system_notifications_all"><![CDATA[All Notifications]]></string>
+    <string name="_bx_ntfs_menu_item_title_notifications_all"><![CDATA[All Notifications]]></string>
+    <string name="_bx_ntfs_menu_title_settings"><![CDATA[Settings Submenu]]></string>
+    <string name="_bx_ntfs_menu_set_title_settings"><![CDATA[Settings Submenu]]></string>
+    <string name="_bx_ntfs_menu_item_title_system_notifications_site"><![CDATA[On Site]]></string>
+    <string name="_bx_ntfs_menu_item_title_notifications_site"><![CDATA[On Site]]></string>
+    <string name="_bx_ntfs_menu_item_title_system_notifications_email"><![CDATA[Email]]></string>
+    <string name="_bx_ntfs_menu_item_title_notifications_email"><![CDATA[Email]]></string>
+    <string name="_bx_ntfs_menu_item_title_system_notifications_push"><![CDATA[Push]]></string>
+    <string name="_bx_ntfs_menu_item_title_notifications_push"><![CDATA[Push]]></string>
+    <string name="_bx_ntfs_menu_item_title_system_notifications"><![CDATA[Notifications]]></string>
+    <string name="_bx_ntfs_menu_item_title_notifications"><![CDATA[Notifications]]></string>
+    <string name="_bx_ntfs_menu_item_title_system_preview"><![CDATA[Notifications]]></string>
+    <string name="_bx_ntfs_menu_item_title_preview"><![CDATA[]]></string>
+
+    <string name="_bx_ntfs_menu_title_preview"><![CDATA[Notifications Preview]]></string>
+    <string name="_bx_ntfs_menu_set_title_preview"><![CDATA[Notifications Preview]]></string>
+    <string name="_bx_ntfs_menu_item_title_system_more"><![CDATA[See all notifications]]></string>
+    <string name="_bx_ntfs_menu_item_title_more"><![CDATA[See all notifications]]></string>
+    <string name="_bx_ntfs_lmi_cpt_site"><![CDATA[On Site]]></string>
+    <string name="_bx_ntfs_lmi_cpt_email"><![CDATA[Email]]></string>
+    <string name="_bx_ntfs_lmi_cpt_push"><![CDATA[Push]]></string>
+    <string name="_bx_ntfs_lmi_cpt_etemplates_text"><![CDATA[Email Texts]]></string>
+
+    <string name="_bx_ntfs_options_category_system"><![CDATA[System]]></string>
+    <string name="_bx_ntfs_option_events_per_page"><![CDATA[Number of items per page]]></string>
+    <string name="_bx_ntfs_option_events_per_preview"><![CDATA[Number of items in preview]]></string>
+    <string name="_bx_ntfs_option_events_hide_site"><![CDATA[Onsite notifications]]></string>
+    <string name="_bx_ntfs_option_events_hide_email"><![CDATA[Email notifications]]></string>
+    <string name="_bx_ntfs_option_events_hide_push"><![CDATA[Push notifications]]></string>
+    <string name="_bx_ntfs_option_enable_group_settings"><![CDATA[Group settings by category]]></string>
+    <string name="_bx_ntfs_option_enable_group_events"><![CDATA[Group notifications by event]]></string>
+    <string name="_bx_ntfs_option_enable_clicked_indicator"><![CDATA[Enable 'clicked' indicator]]></string>
+    <string name="_bx_ntfs_option_delivery_timeout"><![CDATA[Delay before sending Email and/or Push notifications (in seconds)]]></string>
+    <string name="_bx_ntfs_option_delivery_timeout_inf"><![CDATA[Positive value other than '0' means that notifications will be send via Internal queue.]]></string>
+    <string name="_bx_ntfs_option_queue_add_threshold"><![CDATA[Threshold to add to Internal queue]]></string>
+    <string name="_bx_ntfs_option_queue_add_threshold_inf"><![CDATA['0' means that adding in the queue will be performed only when the queue is empty.]]></string>
+    <string name="_bx_ntfs_option_queue_add_limit"><![CDATA[Number of notifications to process and add to queue (Internal or System) per execution]]></string>
+    <string name="_bx_ntfs_option_queue_add_limit_inf"><![CDATA['0' means that all available notifications will be processed at once.]]></string>
+    <string name="_bx_ntfs_option_processed_event"><![CDATA[The last processed event upon notifications sending]]></string>
+    <string name="_bx_ntfs_option_clear_interval"><![CDATA[Notification lifetime, in days (0 - no limit)]]></string>
+    <string name="_bx_ntfs_option_enable_comment_post_ext"><![CDATA[Notify a user about new comments for a content he's previously commented]]></string>
+    <string name="_bx_ntfs_option_enable_reply_as_comment"><![CDATA[Treat replies as comments in 'New comments' notification.]]></string>
+    <string name="_bx_ntfs_option_summary_chars"><![CDATA[Number of characters in auto-cropped summary (applied before saving a notification)]]></string>
+    <string name="_bx_ntfs_option_owner_name_chars"><![CDATA[Number of characters in auto-cropped author name in notification text]]></string>
+    <string name="_bx_ntfs_option_content_chars"><![CDATA[Number of characters in auto-cropped content title in notification text]]></string>
+    <string name="_bx_ntfs_option_email_subject_chars"><![CDATA[Number of characters in auto-cropped email notification subject (0 - no limit)]]></string>
+    <string name="_bx_ntfs_option_push_message_chars"><![CDATA[Number of characters in auto-cropped push notification message]]></string>
+
+    <string name="_bx_ntfs_privacy_view"><![CDATA[View event]]></string>
+
+    <string name="_bx_ntfs_alert_action_group_comment"><![CDATA[New comments]]></string>
+    <string name="_bx_ntfs_alert_action_group_content_updated"><![CDATA[Content was updated]]></string>
+    <string name="_bx_ntfs_alert_action_group_action_required"><![CDATA[Your action required]]></string>    
+    <string name="_bx_ntfs_alert_action_group_info_mention"><![CDATA[A member mentioned your name in a post or comment.]]></string>
+    <string name="_bx_ntfs_alert_action_group_info_friendship"><![CDATA[A member became your friend.]]></string>
+    <string name="_bx_ntfs_alert_action_group_info_subscription"><![CDATA[A member is now following your profile.]]></string>
+    <string name="_bx_ntfs_alert_action_group_info_comment_personal"><![CDATA[Someone posted a new comment on your content.]]></string>
+    <string name="_bx_ntfs_alert_action_group_info_comment_follow_member"><![CDATA[Someone you follow posted a new comment.]]></string>
+    <string name="_bx_ntfs_alert_action_group_info_comment_follow_context"><![CDATA[New comments were posted in a space you follow.]]></string>
+    <string name="_bx_ntfs_alert_action_group_info_reply"><![CDATA[A member replied to one of your comments.]]></string>
+    <string name="_bx_ntfs_alert_action_group_info_vote_personal"><![CDATA[A member liked one of your posts or comments.]]></string>
+    <string name="_bx_ntfs_alert_action_group_info_vote_follow_member"><![CDATA[Someone you follow liked a post or comment.]]></string>
+    <string name="_bx_ntfs_alert_action_group_info_vote_follow_context"><![CDATA[Someone liked content in a space you follow.]]></string>
+    <string name="_bx_ntfs_alert_action_group_info_score_up_personal"><![CDATA[A member gave your content an 'Up' vote.]]></string>
+    <string name="_bx_ntfs_alert_action_group_info_score_up_follow_member"><![CDATA[Someone you follow gave an 'Up' vote to some content.]]></string>
+    <string name="_bx_ntfs_alert_action_group_info_score_up_follow_context"><![CDATA[Someone gave an 'Up' vote to content in a space you follow.]]></string>
+    <string name="_bx_ntfs_alert_action_group_info_score_down_personal"><![CDATA[A member gave your content a 'Down' vote.]]></string>
+    <string name="_bx_ntfs_alert_action_group_info_score_down_follow_member"><![CDATA[Someone you follow gave a 'Down' vote to some content.]]></string>
+    <string name="_bx_ntfs_alert_action_group_info_score_down_follow_context"><![CDATA[Someone gave a 'Down' vote to content in a space you follow.]]></string>
+    <string name="_bx_ntfs_alert_action_group_info_fan_personal"><![CDATA[Someone became a fan of your profile, page, or group.]]></string>
+    <string name="_bx_ntfs_alert_action_group_info_fan_follow_member"><![CDATA[Someone you follow gained new fans.]]></string>
+    <string name="_bx_ntfs_alert_action_group_info_fan_follow_context"><![CDATA[A space you follow gained new fans.]]></string>
+    <string name="_bx_ntfs_alert_action_group_info_invite"><![CDATA[You have been invited to join a space (group, event, etc.).]]></string>
+    <string name="_bx_ntfs_alert_action_group_info_join_personal"><![CDATA[Someone requested to join your space (group, event, etc.).]]></string>
+    <string name="_bx_ntfs_alert_action_group_info_join_follow_member"><![CDATA[Someone you follow received a new join request for their space.]]></string>
+    <string name="_bx_ntfs_alert_action_group_info_join_follow_context"><![CDATA[A space you follow received a new join request.]]></string>
+    <string name="_bx_ntfs_alert_action_group_info_content_personal"><![CDATA[A new post, article, or update relevant to you was published.]]></string>
+    <string name="_bx_ntfs_alert_action_group_info_content_follow_member"><![CDATA[Someone you follow published new content.]]></string>
+    <string name="_bx_ntfs_alert_action_group_info_content_follow_context"><![CDATA[New content was published in a space you follow.]]></string>
+    <string name="_bx_ntfs_alert_action_group_info_action_required"><![CDATA[There is an item or request that needs your attention.]]></string>
+    <string name="_bx_ntfs_alert_action_group_info_content_updated"><![CDATA[Your previously posted content was edited or updated.]]></string>
+    <string name="_bx_ntfs_alert_action_group_info_timeline_post_personal"><![CDATA[New posts have been added to your timeline.]]></string>
+    <string name="_bx_ntfs_alert_action_group_info_timeline_post_follow_member"><![CDATA[Someone you follow shared a new post on their timeline.]]></string>
+    <string name="_bx_ntfs_alert_action_group_info_timeline_post_follow_context"><![CDATA[New posts were shared on the timeline of a space you follow.]]></string>
+
+    <string name="_bx_ntfs_alert_action_added"><![CDATA[add]]></string>
+    <string name="_bx_ntfs_alert_action_commentPost"><![CDATA[add comment]]></string>
+    <string name="_bx_ntfs_alert_action_replyPost"><![CDATA[reply to own comment]]></string>
+    <string name="_bx_ntfs_alert_action_doVote"><![CDATA[add vote]]></string>
+    <string name="_bx_ntfs_alert_action_timeline_post_common"><![CDATA[post to timeline]]></string>
+    <string name="_bx_ntfs_alert_action_mention_added_personal"><![CDATA[Someone mentions you]]></string>
+    <string name="_bx_ntfs_alert_action_friendship_added_personal"><![CDATA[You get a new friend]]></string>
+    <string name="_bx_ntfs_alert_action_subscription_added_personal"><![CDATA[You get a new follower]]></string>
+    <string name="_bx_ntfs_alert_action_comment_added_personal"><![CDATA[Someone adds a comment on a content you've already commented]]></string>
+    <string name="_bx_ntfs_alert_action_added_follow_member"><![CDATA[New content]]></string>
+    <string name="_bx_ntfs_alert_action_added_follow_context"><![CDATA[New content]]></string>
+    <string name="_bx_ntfs_alert_action_commentPost_personal"><![CDATA[Someone adds a comment on your content]]></string>
+    <string name="_bx_ntfs_alert_action_commentPost_follow_member"><![CDATA[New comments]]></string>
+    <string name="_bx_ntfs_alert_action_commentPost_follow_context"><![CDATA[New comments]]></string>
+    <string name="_bx_ntfs_alert_action_replyPost_personal"><![CDATA[Someone adds a reply to your comment]]></string>
+    <string name="_bx_ntfs_alert_action_doVote_personal"><![CDATA[Someone adds a like to your content]]></string>
+    <string name="_bx_ntfs_alert_action_doVote_follow_member"><![CDATA[New likes]]></string>
+    <string name="_bx_ntfs_alert_action_doVote_follow_context"><![CDATA[New likes]]></string>
+    <string name="_bx_ntfs_alert_action_doVoteUp_personal"><![CDATA[Someone adds an 'Up' vote to your content]]></string>
+    <string name="_bx_ntfs_alert_action_doVoteUp_follow_member"><![CDATA[New 'Up' votes]]></string>
+    <string name="_bx_ntfs_alert_action_doVoteUp_follow_context"><![CDATA[New 'Up' votes]]></string>
+    <string name="_bx_ntfs_alert_action_doVoteDown_personal"><![CDATA[Someone adds a 'Down' vote to your content]]></string>
+    <string name="_bx_ntfs_alert_action_doVoteDown_follow_member"><![CDATA[New 'Down' votes]]></string>
+    <string name="_bx_ntfs_alert_action_doVoteDown_follow_context"><![CDATA[New 'Down' votes]]></string>
+    <string name="_bx_ntfs_alert_action_fan_added_personal"><![CDATA[New fans]]></string>
+    <string name="_bx_ntfs_alert_action_fan_added_follow_member"><![CDATA[New fans]]></string>
+    <string name="_bx_ntfs_alert_action_fan_added_follow_context"><![CDATA[New fans]]></string>
+    <string name="_bx_ntfs_alert_action_join_request_personal"><![CDATA[New join requests]]></string>
+    <string name="_bx_ntfs_alert_action_join_request_follow_member"><![CDATA[New join requests]]></string>
+    <string name="_bx_ntfs_alert_action_join_request_follow_context"><![CDATA[New join requests]]></string>
+    <string name="_bx_ntfs_alert_action_join_invitation_notif_personal"><![CDATA[New join invitation]]></string>
+    <string name="_bx_ntfs_alert_action_timeline_post_common_personal"><![CDATA[New posts on Timeline]]></string>
+    <string name="_bx_ntfs_alert_action_timeline_post_common_follow_member"><![CDATA[New posts on Timeline]]></string>
+    <string name="_bx_ntfs_alert_action_timeline_post_common_follow_context"><![CDATA[New posts on Timeline]]></string>
+    <string name="_bx_ntfs_alert_action_publish_failed_personal"><![CDATA[Delayed publishing failed]]></string>
+    <string name="_bx_ntfs_alert_action_publish_succeeded_personal"><![CDATA[Delayed publishing succeeded]]></string>
+    <string name="_bx_ntfs_alert_action_pending_approval_personal"><![CDATA[New pending approval content]]></string>
+    <string name="_bx_ntfs_alert_action_approved_personal"><![CDATA[Your content was approved]]></string>
+    <string name="_bx_ntfs_alert_action_reported_content_personal"><![CDATA[New report]]></string>
+
+    <string name="_bx_ntfs_setting_title_mask"><![CDATA[{0}: {1}]]></string>
+    <string name="_bx_ntfs_setting_type_personal"><![CDATA[Activity related to you]]></string>
+    <string name="_bx_ntfs_setting_type_follow_member"><![CDATA[Activity by members you follow]]></string>
+    <string name="_bx_ntfs_setting_type_follow_context"><![CDATA[Activity in spaces (groups, events, etc.) you follow]]></string>
+    <string name="_bx_ntfs_setting_type_other"><![CDATA[Other Activity]]></string>
+
+    <string name="_bx_ntfs_alert_module_comment"><![CDATA[Comments]]></string>
+    <string name="_bx_ntfs_alert_module_sys_cmts"><![CDATA[Comments]]></string>
+    <string name="_bx_ntfs_alert_module_sys_cmts_reactions"><![CDATA[Comments' Reactions]]></string>
+    <string name="_bx_ntfs_alert_module_meta_mention"><![CDATA[Profiles Mentions]]></string>
+    <string name="_bx_ntfs_alert_module_sys_profiles_subscriptions"><![CDATA[Profiles Subscriptions]]></string>
+    <string name="_bx_ntfs_alert_module_sys_profiles_friends"><![CDATA[Profiles Friends]]></string>
+    <string name="_bx_ntfs_alert_action_connection_added"><![CDATA[add connection]]></string>
+
+    <string name="_bx_ntfs_txt_msg_no_results"><![CDATA[Empty]]></string>
+    <string name="_bx_ntfs_txt_err_nothing_changed"><![CDATA[Nothing was changed.]]></string>
+    <string name="_bx_ntfs_txt_err_cannot_perform"><![CDATA[Cannot perform the action.]]></string>
+    <string name="_bx_ntfs_txt_object_added"><![CDATA[<b class="bx-ntfs-content-profile">{owner_name}</b> added a {entry_sample} <b class="bx-ntfs-content-entry">{entry_caption}</b>]]></string>
+    <string name="_bx_ntfs_txt_object_added_in_context"><![CDATA[<b class="bx-ntfs-content-profile">{owner_name}</b> has got a {entry_sample} <b class="bx-ntfs-content-entry">{entry_caption}</b> added by <b class="bx-ntfs-content-profile">{object_owner_name}</b>]]></string>
+    <string name="_bx_ntfs_txt_object_post_common"><![CDATA[<b class="bx-ntfs-content-profile">{owner_name}</b> added a {entry_sample} <b class="bx-ntfs-content-entry">{entry_caption}</b>]]></string>
+    <string name="_bx_ntfs_txt_object_post_common_in_context"><![CDATA[<b class="bx-ntfs-content-profile">{owner_name}</b> has got a {entry_sample} <b class="bx-ntfs-content-entry">{entry_caption}</b> added by <b class="bx-ntfs-content-profile">{object_owner_name}</b>]]></string>
+    <string name="_bx_ntfs_txt_object_approved"><![CDATA[<b class="bx-ntfs-content-profile">{owner_name}</b> approved {entry_sample} <b class="bx-ntfs-content-entry">{entry_caption}</b>]]></string>
+    <string name="_bx_ntfs_txt_object_approved_in_context"><![CDATA[<b class="bx-ntfs-content-entry">{entry_caption}</b> {entry_sample} was approved in <b class="bx-ntfs-content-profile">{owner_name}</b>]]></string>
+    <string name="_bx_ntfs_txt_object_publish_failed"><![CDATA[Failed to publish your {entry_sample} <b class="bx-ntfs-content-entry">{entry_caption}</b>]]></string>
+    <string name="_bx_ntfs_txt_object_publish_succeeded"><![CDATA[Your {entry_sample} <b class="bx-ntfs-content-entry">{entry_caption}</b> was published successfully]]></string>
+    <string name="_bx_ntfs_txt_object_pending_approval"><![CDATA[<b class="bx-ntfs-content-profile">{owner_name}</b> added a pending approval {entry_sample} <b class="bx-ntfs-content-entry">{entry_caption}</b>]]></string>
+    <string name="_bx_ntfs_txt_object_reported_content"><![CDATA[<b class="bx-ntfs-content-profile">{owner_name}</b> reported a {entry_sample} <b class="bx-ntfs-content-entry">{entry_caption}</b>]]></string>
+    <string name="_bx_ntfs_txt_subobject_added"><![CDATA[<b class="bx-ntfs-content-profile">{owner_name}</b> added a {subentry_sample} <b class="bx-ntfs-content-entry">{entry_caption}</b>]]></string>
+    <string name="_bx_ntfs_txt_subobject_added_in_context"><![CDATA[<b class="bx-ntfs-content-profile">{owner_name}</b> has got a {subentry_sample} <b class="bx-ntfs-content-entry">{entry_caption}</b>]]></string>
+    <string name="_bx_ntfs_txt_new_event_subject"><![CDATA[New on "{0}"]]></string>
+    <string name="_bx_ntfs_txt_et_preview_subject"><![CDATA[Subject:]]></string>
+    <string name="_bx_ntfs_txt_et_preview_body"><![CDATA[Body:]]></string>
+
+    <string name="_bx_ntfs_email_new_event"><![CDATA[New notification]]></string>
+    <string name="_bx_ntfs_email_new_event_subject"><![CDATA[{subject}]]></string>
+    <string name="_bx_ntfs_email_new_event_body"><![CDATA[{email_header}
+<p> </p>
+{content}
+<p> </p>
+{email_footer}]]></string>
+
+    <string name="_bx_ntfs_grid_column_title_active"><![CDATA[Active]]></string>
+    <string name="_bx_ntfs_grid_column_title_unit"><![CDATA[Module]]></string>
+    <string name="_bx_ntfs_grid_column_title_type"><![CDATA[Type]]></string>
+    <string name="_bx_ntfs_grid_column_title_title"><![CDATA[Notification]]></string>
+    <string name="_bx_ntfs_grid_column_title_title_warning"><![CDATA[The setting's value is corrupted. It is recommended to enable/disable it and reload the page.]]></string>
+    <string name="_bx_ntfs_grid_column_title_value"><![CDATA[Default value]]></string>
+    <string name="_bx_ntfs_grid_action_title_activate"><![CDATA[Activate]]></string>
+    <string name="_bx_ntfs_grid_action_title_deactivate"><![CDATA[Deactivate]]></string>
+
+    <string name="_bx_ntfs_grid_column_title_ett_active"><![CDATA[Active]]></string>
+    <string name="_bx_ntfs_grid_column_title_ett_type"><![CDATA[Type]]></string>
+    <string name="_bx_ntfs_grid_column_title_ett_action"><![CDATA[Action]]></string>
+    <string name="_bx_ntfs_grid_column_title_ett_subject"><![CDATA[Subject]]></string>
+    <string name="_bx_ntfs_grid_action_title_ett_add"><![CDATA[Add]]></string>
+    <string name="_bx_ntfs_grid_action_title_ett_preview"><![CDATA[Preview]]></string>
+    <string name="_bx_ntfs_grid_action_title_ett_edit"><![CDATA[Edit]]></string>
+    <string name="_bx_ntfs_grid_action_title_ett_delete"><![CDATA[Delete]]></string>
+    <string name="_bx_ntfs_grid_popup_title_ett_add"><![CDATA[Add Email Template]]></string>
+    <string name="_bx_ntfs_grid_popup_title_ett_edit"><![CDATA[Edit Email Template]]></string>
+    <string name="_bx_ntfs_grid_popup_title_ett_preview"><![CDATA[Preview Email Template]]></string>
+</resources>

+ 205 - 0
modules/boonex/notifications/updates/15.0.2_15.0.3/source/install/sql/enable.sql

@@ -0,0 +1,205 @@
+SET @sName = 'bx_notifications';
+
+
+-- PAGES & BLOCKS
+INSERT INTO `sys_objects_page`(`object`, `title_system`, `title`, `module`, `layout_id`, `visible_for_levels`, `visible_for_levels_editable`, `uri`, `url`, `meta_description`, `meta_keywords`, `meta_robots`, `cache_lifetime`, `cache_editable`, `deletable`, `override_class_name`, `override_class_file`) VALUES 
+('bx_notifications_view', '_bx_ntfs_page_title_system_view', '_bx_ntfs_page_title_view', @sName, 5, 2147483647, 1, 'notifications-view', 'page.php?i=notifications-view', '', '', '', 0, 1, 0, 'BxNtfsPageView', 'modules/boonex/notifications/classes/BxNtfsPageView.php');
+
+INSERT INTO `sys_pages_blocks` (`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES
+('bx_notifications_view', 1, @sName, '_bx_ntfs_page_block_title_view', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:16:"bx_notifications";s:6:"method";s:14:"get_block_view";}', 0, 1, 1);
+
+INSERT INTO `sys_objects_page`(`object`, `title_system`, `title`, `module`, `layout_id`, `visible_for_levels`, `visible_for_levels_editable`, `uri`, `url`, `meta_description`, `meta_keywords`, `meta_robots`, `cache_lifetime`, `cache_editable`, `deletable`, `override_class_name`, `override_class_file`) VALUES 
+('bx_notifications_settings', '_bx_ntfs_page_title_system_settings', '_bx_ntfs_page_title_settings', @sName, 1, 2147483647, 1, 'notifications-settings', 'page.php?i=notifications-settings', '', '', '', 0, 1, 0, 'BxNtfsPageSettings', 'modules/boonex/notifications/classes/BxNtfsPageSettings.php');
+
+INSERT INTO `sys_pages_blocks` (`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES
+('bx_notifications_settings', 1, @sName, '_bx_ntfs_page_block_title_delivery', 13, 2147483644, 'menu', 'bx_notifications_settings', 0, 0, 1),
+('bx_notifications_settings', 2, @sName, '_bx_ntfs_page_block_title_settings', 13, 2147483644, 'service', 'a:2:{s:6:"module";s:16:"bx_notifications";s:6:"method";s:18:"get_block_settings";}', 0, 1, 1);
+
+-- PAGES: add page block on dashboard
+SET @iPBCellDashboard = 3;
+SET @iPBOrderDashboard = 4; --(SELECT IFNULL(MAX(`order`), 0) FROM `sys_pages_blocks` WHERE `object` = 'sys_dashboard' AND `cell_id` = @iPBCellDashboard LIMIT 1);
+INSERT INTO `sys_pages_blocks` (`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `active`, `order`) VALUES
+('sys_dashboard', @iPBCellDashboard, @sName, '_bx_ntfs_page_block_title_view', 11, 2147483644, 'service', 'a:2:{s:6:"module";s:16:"bx_notifications";s:6:"method";s:14:"get_block_view";}', 0, 0, 0, @iPBOrderDashboard);
+
+
+-- MENU: module sub-menu
+INSERT INTO `sys_objects_menu`(`object`, `title`, `title_public`, `set_name`, `module`, `template_id`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES 
+('bx_notifications_submenu', '_bx_ntfs_menu_title_submenu', '_bx_ntfs_menu_title_public_submenu', 'bx_notifications_submenu', @sName, 8, 0, 1, '', '');
+
+INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+('bx_notifications_submenu', @sName, '_bx_ntfs_menu_set_title_submenu', 0);
+
+INSERT INTO `sys_menu_items`(`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `submenu_object`, `visible_for_levels`, `active`, `copyable`, `order`) VALUES 
+('bx_notifications_submenu', @sName, 'notifications-all', '_bx_ntfs_menu_item_title_system_notifications_all', '_bx_ntfs_menu_item_title_notifications_all', 'page.php?i=notifications-view', '', '', '', '', 2147483647, 1, 0, 1);
+
+-- MENU: preview popup
+INSERT INTO `sys_objects_menu`(`object`, `title`, `set_name`, `module`, `template_id`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES 
+('bx_notifications_preview', '_bx_ntfs_menu_title_preview', 'bx_notifications_preview', @sName, 20, 0, 1, 'BxNtfsMenuPreview', 'modules/boonex/notifications/classes/BxNtfsMenuPreview.php');
+
+INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+('bx_notifications_preview', @sName, '_bx_ntfs_menu_set_title_preview', 0);
+
+INSERT INTO `sys_menu_items`(`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `submenu_object`, `visible_for_levels`, `active`, `copyable`, `order`) VALUES 
+('bx_notifications_preview', @sName, 'more', '_bx_ntfs_menu_item_title_system_more', '_bx_ntfs_menu_item_title_more', 'page.php?i=notifications-view', '', '', '', '', 2147483647, 1, 0, 1);
+
+-- MENU: settings sub-menu
+INSERT INTO `sys_objects_menu`(`object`, `title`, `set_name`, `module`, `template_id`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES 
+('bx_notifications_settings', '_bx_ntfs_menu_title_settings', 'bx_notifications_settings', @sName, 6, 0, 1, '', '');
+
+INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+('bx_notifications_settings', @sName, '_bx_ntfs_menu_set_title_settings', 0);
+
+INSERT INTO `sys_menu_items`(`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `submenu_object`, `visible_for_levels`, `active`, `copyable`, `order`) VALUES 
+('bx_notifications_settings', @sName, 'notifications-site', '_bx_ntfs_menu_item_title_system_notifications_site', '_bx_ntfs_menu_item_title_notifications_site', 'page.php?i=notifications-settings&delivery=site', '', '', '', '', 2147483647, 1, 0, 10),
+('bx_notifications_settings', @sName, 'notifications-email', '_bx_ntfs_menu_item_title_system_notifications_email', '_bx_ntfs_menu_item_title_notifications_email', 'page.php?i=notifications-settings&delivery=email', '', '', '', '', 2147483647, 1, 0, 20),
+('bx_notifications_settings', @sName, 'notifications-push', '_bx_ntfs_menu_item_title_system_notifications_push', '_bx_ntfs_menu_item_title_notifications_push', 'page.php?i=notifications-settings&delivery=push', '', '', '', '', 2147483647, 1, 0, 30);
+
+-- MENU: member toolbar
+SET @iMenuToolbarMenuOrder = (SELECT IFNULL(MAX(`order`), 0) FROM `sys_menu_items` WHERE `set_name`='sys_toolbar_member' LIMIT 1);
+INSERT INTO `sys_menu_items`(`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `addon`, `markers`, `submenu_object`, `submenu_popup`, `visible_for_levels`, `hidden_on`, `active`, `copyable`, `order`) VALUES 
+('sys_toolbar_member', @sName, 'notifications-preview', '_bx_ntfs_menu_item_title_system_preview', '_bx_ntfs_menu_item_title_preview', 'javascript:void(0)', 'bx_menu_slide(''bx_notifications_preview'', $(this).parents(''ul:first''), ''site'', {id:{value:''bx_notifications_preview'', force:1}, pointer:{align:''right''}, cssClass: ''''});', '', 'bell', 'a:2:{s:6:"module";s:16:"bx_notifications";s:6:"method";s:28:"get_unread_notifications_num";}', '', 'bx_notifications_preview', 1, 2147483646, 9, 1, 1, 0);
+
+-- MENU: notifications
+SET @iMIOrder = (SELECT IFNULL(MAX(`order`), 0) FROM `sys_menu_items` WHERE `set_name` = 'sys_ntfs_submenu' AND `order` < 9999);
+INSERT INTO `sys_menu_items` (`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `addon`, `markers`, `submenu_object`, `submenu_popup`, `visible_for_levels`, `hidden_on`, `active`, `copyable`, `order`) VALUES
+('sys_ntfs_submenu', @sName, 'notifications-view', '_bx_ntfs_menu_item_title_system_notifications', '_bx_ntfs_menu_item_title_notifications', 'page.php?i=notifications-view', '', '', 'bell', 'a:2:{s:6:"module";s:16:"bx_notifications";s:6:"method";s:28:"get_unread_notifications_num";}', '', 'bx_notifications_preview', 1, 2147483646, 0, 1, 1, @iMIOrder + 1);
+
+-- MENU: account notifications
+SET @iMIOrder = (SELECT IFNULL(MAX(`order`), 0) FROM `sys_menu_items` WHERE `set_name` = 'sys_account_notifications' AND `order` < 9999);
+INSERT INTO `sys_menu_items` (`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `addon`, `markers`, `submenu_object`, `submenu_popup`, `visible_for_levels`, `hidden_on`, `active`, `copyable`, `order`) VALUES
+('sys_account_notifications', @sName, 'notifications-notifications', '_bx_ntfs_menu_item_title_system_notifications', '_bx_ntfs_menu_item_title_notifications', 'javascript:void(0)', 'bx_menu_slide(''bx_notifications_preview'', this, ''site'', {id:{value:''bx_notifications_preview'', force:1}});', '', 'bell', 'a:2:{s:6:"module";s:16:"bx_notifications";s:6:"method";s:28:"get_unread_notifications_num";}', '', 'bx_notifications_preview', 1, 2147483646, 6, 1, 1, @iMIOrder + 1);
+
+-- MENU: account settings menu
+SET @iMoAccountSettings = (SELECT IFNULL(MAX(`order`), 0) FROM `sys_menu_items` WHERE `set_name`='sys_account_settings' AND `order` < 9999 LIMIT 1);
+INSERT INTO `sys_menu_items` (`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `addon`, `submenu_object`, `visible_for_levels`, `active`, `copyable`, `editable`, `order`) VALUES
+('sys_account_settings', @sName, 'notifications-settings', '_bx_ntfs_menu_item_title_system_notifications', '_bx_ntfs_menu_item_title_notifications', 'page.php?i=notifications-settings', '', '', 'bell', '', '', 2147483646, 1, 0, 1, @iMoAccountSettings + 1);
+
+
+-- SETTINGS
+SET @iTypeOrder = (SELECT IFNULL(MAX(`order`), 0) FROM `sys_options_types` WHERE `group` = 'modules');
+INSERT INTO `sys_options_types`(`group`, `name`, `caption`, `icon`, `order`) VALUES 
+('modules', @sName, '_bx_ntfs', 'bx_notifications@modules/boonex/notifications/|std-icon.svg', @iTypeOrder + 1);
+SET @iTypeId = LAST_INSERT_ID();
+
+INSERT INTO `sys_options_categories` (`type_id`, `name`, `caption`, `hidden`, `order`) VALUES (@iTypeId, 'bx_notifications_system', '_bx_ntfs_options_category_system', 1, 1);
+SET @iCategId = LAST_INSERT_ID();
+
+INSERT INTO `sys_options` (`name`, `value`, `category_id`, `caption`, `type`, `check`, `check_params`, `check_error`, `extra`, `order`) VALUES
+('bx_notifications_events_hide_site', '', @iCategId, '_bx_ntfs_option_events_hide_site', 'rlist', '', '', '', 'a:2:{s:6:"module";s:16:"bx_notifications";s:6:"method";s:21:"get_actions_checklist";}', 1),
+('bx_notifications_events_hide_email', '', @iCategId, '_bx_ntfs_option_events_hide_email', 'rlist', '', '', '', 'a:2:{s:6:"module";s:16:"bx_notifications";s:6:"method";s:21:"get_actions_checklist";}', 2),
+('bx_notifications_events_hide_push', '', @iCategId, '_bx_ntfs_option_events_hide_push', 'rlist', '', '', '', 'a:2:{s:6:"module";s:16:"bx_notifications";s:6:"method";s:21:"get_actions_checklist";}', 3),
+('bx_notifications_processed_event', '', @iCategId, '_bx_ntfs_option_processed_event', 'digit', '', '', '', '', 10);
+
+INSERT INTO `sys_options_categories` (`type_id`, `name`, `caption`, `hidden`, `order`) VALUES (@iTypeId, @sName, '_bx_ntfs', 0, 1);
+SET @iCategId = LAST_INSERT_ID();
+
+INSERT INTO `sys_options` (`name`, `value`, `category_id`, `caption`, `info`, `type`, `check`, `check_params`, `check_error`, `extra`, `order`) VALUES
+('bx_notifications_events_per_page', '24', @iCategId, '_bx_ntfs_option_events_per_page', '', 'digit', '', '', '', '', 1),
+('bx_notifications_events_per_preview', '5', @iCategId, '_bx_ntfs_option_events_per_preview', '', 'digit', '', '', '', '', 5),
+('bx_notifications_enable_group_settings', 'on', @iCategId, '_bx_ntfs_option_enable_group_settings', '', 'checkbox', '', '', '', '', 10), 
+('bx_notifications_enable_group_events', 'on', @iCategId, '_bx_ntfs_option_enable_group_events', '', 'checkbox', '', '', '', '', 11), 
+('bx_notifications_enable_clicked_indicator', '', @iCategId, '_bx_ntfs_option_enable_clicked_indicator', '', 'checkbox', '', '', '', '', 15),
+('bx_notifications_delivery_timeout', '120', @iCategId, '_bx_ntfs_option_delivery_timeout', '_bx_ntfs_option_delivery_timeout_inf', 'digit', '', '', '', '', 20),
+('bx_notifications_queue_add_threshold', '0', @iCategId, '_bx_ntfs_option_queue_add_threshold', '_bx_ntfs_option_queue_add_threshold_inf', 'digit', '', '', '', '', 21),
+('bx_notifications_queue_add_limit', '200', @iCategId, '_bx_ntfs_option_queue_add_limit', '_bx_ntfs_option_queue_add_limit_inf', 'digit', '', '', '', '', 22),
+('bx_notifications_clear_interval', '90', @iCategId, '_bx_ntfs_option_clear_interval', '', 'digit', '', '', '', '', 30),
+('bx_notifications_enable_comment_post_ext', '', @iCategId, '_bx_ntfs_option_enable_comment_post_ext', '', 'checkbox', '', '', '', '', 40),
+('bx_notifications_enable_reply_as_comment', 'on', @iCategId, '_bx_ntfs_option_enable_reply_as_comment', '', 'checkbox', '', '', '', '', 42),
+('bx_notifications_summary_chars', '200', @iCategId, '_bx_ntfs_option_summary_chars', '', 'digit', '', '', '', '', 50),
+('bx_notifications_owner_name_chars', '21', @iCategId, '_bx_ntfs_option_owner_name_chars', '', 'digit', '', '', '', '', 51),
+('bx_notifications_content_chars', '32', @iCategId, '_bx_ntfs_option_content_chars', '', 'digit', '', '', '', '', 52),
+('bx_notifications_email_subject_chars', '30', @iCategId, '_bx_ntfs_option_email_subject_chars', '', 'digit', '', '', '', '', 53),
+('bx_notifications_push_message_chars', '190', @iCategId, '_bx_ntfs_option_push_message_chars', '', 'digit', '', '', '', '', 54);
+
+
+-- PRIVACY 
+INSERT INTO `sys_objects_privacy` (`object`, `module`, `action`, `title`, `default_group`, `table`, `table_field_id`, `table_field_author`, `override_class_name`, `override_class_file`) VALUES
+('bx_notifications_privacy_view', @sName, 'view', '_bx_notifications_privacy_view', '3', 'bx_notifications_events', 'id', 'owner_id', 'BxNtfsPrivacy', 'modules/boonex/notifications/classes/BxNtfsPrivacy.php');
+
+
+-- LIVE UPDATES
+INSERT INTO `sys_objects_live_updates`(`name`, `frequency`, `service_call`, `active`) VALUES
+(@sName, 1, 'a:3:{s:6:"module";s:16:"bx_notifications";s:6:"method";s:16:"get_live_updates";s:6:"params";a:3:{i:0;a:2:{s:11:"menu_object";s:18:"sys_toolbar_member";s:9:"menu_item";s:7:"account";}i:1;a:2:{s:11:"menu_object";s:25:"sys_account_notifications";s:9:"menu_item";s:27:"notifications-notifications";}i:2;s:7:"{count}";}}', 1),
+('bx_notifications_toolbar', 1, 'a:3:{s:6:"module";s:16:"bx_notifications";s:6:"method";s:16:"get_live_updates";s:6:"params";a:3:{i:0;a:0:{}i:1;a:2:{s:11:"menu_object";s:18:"sys_toolbar_member";s:9:"menu_item";s:21:"notifications-preview";}i:2;s:7:"{count}";}}', 1);
+
+
+-- ALERTS
+INSERT INTO `sys_alerts_handlers`(`name`, `class`, `file`, `service_call`) VALUES 
+(@sName, 'BxNtfsResponse', 'modules/boonex/notifications/classes/BxNtfsResponse.php', '');
+SET @iHandler := LAST_INSERT_ID();
+
+INSERT INTO `sys_alerts` (`unit`, `action`, `handler_id`) VALUES
+('profile', 'delete', @iHandler),
+
+('comment', 'added', @iHandler),
+('comment', 'deleted', @iHandler),
+
+('meta_mention', 'added', @iHandler),
+
+('sys_profiles_friends', 'connection_added', @iHandler),
+('sys_profiles_friends', 'connection_removed', @iHandler),
+
+('sys_profiles_subscriptions', 'connection_added', @iHandler),
+('sys_profiles_subscriptions', 'connection_removed', @iHandler),
+
+('sys_cmts', 'doVote', @iHandler),
+('sys_cmts', 'undoVote', @iHandler),
+
+('sys_cmts_reactions', 'doVote', @iHandler),
+('sys_cmts_reactions', 'undoVote', @iHandler),
+
+('sys_cmts', 'doVoteUp', @iHandler),
+('sys_cmts', 'doVoteDown', @iHandler),
+
+('sys_cmts', 'reported_content', @iHandler);
+
+
+-- EMAIL TEMPLATES
+INSERT INTO `sys_email_templates` (`Module`, `NameSystem`, `Name`, `Subject`, `Body`) VALUES
+(@sName, '_bx_ntfs_email_new_event', 'bx_notifications_new_event', '_bx_ntfs_email_new_event_subject', '_bx_ntfs_email_new_event_body');
+
+
+-- GRIDS
+INSERT INTO `sys_objects_grid` (`object`, `source_type`, `source`, `table`, `field_id`, `field_order`, `field_active`, `paginate_url`, `paginate_per_page`, `paginate_simple`, `paginate_get_start`, `paginate_get_per_page`, `filter_fields`, `filter_fields_translatable`, `filter_mode`, `sorting_fields`, `visible_for_levels`, `override_class_name`, `override_class_file`) VALUES
+('bx_notifications_settings_administration', 'Sql', 'SELECT `ts`.*, `th`.`alert_unit` AS `unit`, `th`.`alert_action` AS `action` FROM `bx_notifications_settings` AS `ts` LEFT JOIN `bx_notifications_handlers` AS `th` ON `ts`.`handler_id`=`th`.`id` WHERE 1 ', 'bx_notifications_settings', 'id', 'order', 'active', '', 100, NULL, 'start', '', '', 'ts`.`title', 'auto', '', 192, 'BxNtfsGridSettingsAdministration', 'modules/boonex/notifications/classes/BxNtfsGridSettingsAdministration.php'),
+('bx_notifications_settings_common', 'Sql', 'SELECT `tsu`.`id` AS `id`, `ts`.`group` AS `group`, `ts`.`id` AS `setting_id`, `ts`.`type` AS `type`, `ts`.`delivery` AS `delivery`, `ts`.`title` AS `title`, `tsu`.`active` AS `active`, `ts`.`order` AS `order`, `th`.`alert_unit` AS `unit`, `th`.`alert_action` AS `action` FROM `bx_notifications_settings` AS `ts` LEFT JOIN `bx_notifications_handlers` AS `th` ON `ts`.`handler_id`=`th`.`id` LEFT JOIN `bx_notifications_settings2users` AS `tsu` ON `ts`.`id`=`tsu`.`setting_id` WHERE `ts`.`active`=''1'' ', 'bx_notifications_settings2users', 'id', 'order', 'active', '', 100, NULL, 'start', '', '', 'ts`.`title', 'auto', '', 2147483647, 'BxNtfsGridSettingsCommon', 'modules/boonex/notifications/classes/BxNtfsGridSettingsCommon.php');
+
+INSERT INTO `sys_grid_fields` (`object`, `name`, `title`, `width`, `translatable`, `chars_limit`, `params`, `order`) VALUES
+('bx_notifications_settings_administration', 'checkbox', '', '1%', 0, '', '', 1),
+('bx_notifications_settings_administration', 'switcher', '_bx_ntfs_grid_column_title_active', '10%', 0, '', '', 2),
+('bx_notifications_settings_administration', 'title', '_bx_ntfs_grid_column_title_title', '79%', 1, '', '', 10),
+('bx_notifications_settings_administration', 'value', '_bx_ntfs_grid_column_title_value', '10%', 0, '', '', 20),
+
+('bx_notifications_settings_common', 'checkbox', '', '1%', 0, '', '', 1),
+('bx_notifications_settings_common', 'switcher', '', '10%', 0, '', '', 2),
+('bx_notifications_settings_common', 'title', '_bx_ntfs_grid_column_title_title', '89%', 1, '', '', 10);
+
+INSERT INTO `sys_grid_actions` (`object`, `type`, `name`, `title`, `icon`, `confirm`, `order`) VALUES
+('bx_notifications_settings_administration', 'bulk', 'activate', '_bx_ntfs_grid_action_title_activate', '', 1, 1),
+('bx_notifications_settings_administration', 'bulk', 'deactivate', '_bx_ntfs_grid_action_title_deactivate', '', 1, 2),
+
+('bx_notifications_settings_common', 'bulk', 'activate', '_bx_ntfs_grid_action_title_activate', '', 1, 1),
+('bx_notifications_settings_common', 'bulk', 'deactivate', '_bx_ntfs_grid_action_title_deactivate', '', 1, 2);
+
+INSERT INTO `sys_objects_grid` (`object`, `source_type`, `source`, `table`, `field_id`, `field_order`, `field_active`, `paginate_url`, `paginate_per_page`, `paginate_simple`, `paginate_get_start`, `paginate_get_per_page`, `filter_fields`, `filter_fields_translatable`, `filter_mode`, `sorting_fields`, `visible_for_levels`, `override_class_name`, `override_class_file`) VALUES
+('bx_notifications_etemplates', 'Sql', 'SELECT * FROM `bx_notifications_etemplates` WHERE 1 ', 'bx_notifications_etemplates', 'id', '', 'active', '', 100, NULL, 'start', '', '', 'type,action,subject,content', 'auto', '', 2147483647, 'BxNtfsGridEtemplates', 'modules/boonex/notifications/classes/BxNtfsGridEtemplates.php');
+
+INSERT INTO `sys_grid_fields` (`object`, `name`, `title`, `width`, `translatable`, `chars_limit`, `params`, `order`) VALUES
+('bx_notifications_etemplates', 'switcher', '_bx_ntfs_grid_column_title_ett_active', '10%', 0, '', '', 10),
+('bx_notifications_etemplates', 'type', '_bx_ntfs_grid_column_title_ett_type', '15%', 0, '', '', 20),
+('bx_notifications_etemplates', 'action', '_bx_ntfs_grid_column_title_ett_action', '15%', 0, '', '', 30),
+('bx_notifications_etemplates', 'subject', '_bx_ntfs_grid_column_title_ett_subject', '40%', 0, '', '', 40),
+('bx_notifications_etemplates', 'actions', '', '20%', 0, '', '', 50);
+
+INSERT INTO `sys_grid_actions` (`object`, `type`, `name`, `title`, `icon`, `icon_only`, `confirm`, `order`) VALUES
+('bx_notifications_etemplates', 'independent', 'add', '_bx_ntfs_grid_action_title_ett_add', '', 0, 0, 1),
+('bx_notifications_etemplates', 'single', 'preview', '_bx_ntfs_grid_action_title_ett_preview', 'eye', 1, 0, 1),
+('bx_notifications_etemplates', 'single', 'edit', '_bx_ntfs_grid_action_title_ett_edit', 'pencil-alt', 1, 0, 2),
+('bx_notifications_etemplates', 'single', 'delete', '_bx_ntfs_grid_action_title_ett_delete', 'remove', 1, 1, 3);
+
+
+-- CRON
+INSERT INTO `sys_cron_jobs` (`name`, `time`, `class`, `file`, `service_call`) VALUES
+('bx_notifications_queue', '* * * * *', 'BxNtfsCronQueue', 'modules/boonex/notifications/classes/BxNtfsCronQueue.php', ''),
+('bx_notifications_notify', '* * * * *', 'BxNtfsCronNotify', 'modules/boonex/notifications/classes/BxNtfsCronNotify.php', ''),
+('bx_notifications_clean', '0 0 * * *', 'BxNtfsCronClean', 'modules/boonex/notifications/classes/BxNtfsCronClean.php', '');

+ 279 - 0
modules/boonex/notifications/updates/15.0.2_15.0.3/source/install/sql/install.sql

@@ -0,0 +1,279 @@
+SET @sName = 'bx_notifications';
+
+
+-- TABLES
+CREATE TABLE IF NOT EXISTS `bx_notifications_events` (
+  `id` int(11) NOT NULL auto_increment,
+  `owner_id` int(11) NOT NULL default '0',
+  `type` varchar(255) NOT NULL,
+  `action` varchar(255) NOT NULL,
+  `object_id` text NOT NULL,
+  `object_owner_id` int(11) NOT NULL default '0',
+  `object_privacy_view` varchar(32) NOT NULL default '3',
+  `subobject_id` int(11) NOT NULL default '0',
+  `content` text NOT NULL,
+  `source` varchar(32) NOT NULL default '',
+  `allow_view_event_to` varchar(32) NOT NULL default '3',
+  `date` int(11) NOT NULL default '0',
+  `processed` tinyint(4) NOT NULL default '0',
+  `active` tinyint(4) NOT NULL default '1',
+  PRIMARY KEY  (`id`),
+  KEY `owner_id` (`owner_id`),
+  KEY `object_owner_id` (`object_owner_id`)
+);
+
+CREATE TABLE IF NOT EXISTS `bx_notifications_events2users` (
+  `id` int(11) NOT NULL auto_increment,
+  `user_id` int(11) NOT NULL DEFAULT '0',
+  `event_id` int(11) NOT NULL DEFAULT '0',
+  `clicked` tinyint(4) NOT NULL default '0',
+  PRIMARY KEY (`id`),
+  UNIQUE `event` (`user_id`, `event_id`)
+);
+
+CREATE TABLE IF NOT EXISTS `bx_notifications_read` (
+  `user_id` int(11) NOT NULL DEFAULT '0',
+  `event_id` int(11) NOT NULL DEFAULT '0',
+  PRIMARY KEY (`user_id`)
+);
+
+CREATE TABLE IF NOT EXISTS `bx_notifications_handlers` (
+  `id` int(11) NOT NULL auto_increment,
+  `group` varchar(64) NOT NULL default '',
+  `type` enum('insert','update','delete') NOT NULL DEFAULT 'insert',
+  `alert_unit` varchar(64) NOT NULL default '',
+  `alert_action` varchar(64) NOT NULL default '',
+  `content` text NOT NULL,
+  `privacy` varchar(64) NOT NULL default '',
+  `priority` int(11) NOT NULL default '0',
+  PRIMARY KEY  (`id`),
+  UNIQUE `handler` (`group`, `type`),
+  UNIQUE `alert` (`alert_unit`, `alert_action`)
+);
+
+CREATE TABLE IF NOT EXISTS `bx_notifications_settings` (
+  `id` int(11) NOT NULL auto_increment,
+  `group` varchar(64) NOT NULL default '',
+  `handler_id` int(11) NOT NULL DEFAULT '0',
+  `delivery` enum('site','email','push') NOT NULL DEFAULT 'site',
+  `type` enum('personal','follow_member','follow_context','other') NOT NULL DEFAULT 'personal',
+  `title` varchar(64) NOT NULL default '',
+  `value` tinyint(4) NOT NULL default '1',
+  `active` tinyint(4) NOT NULL default '1',
+  `order` int(11) NOT NULL default '0',
+  PRIMARY KEY (`id`),
+  UNIQUE `setting` (`handler_id`, `type`, `delivery`)
+);
+
+CREATE TABLE IF NOT EXISTS `bx_notifications_settings2users` (
+  `id` int(11) NOT NULL auto_increment,
+  `user_id` int(11) NOT NULL DEFAULT '0',
+  `setting_id` int(11) NOT NULL DEFAULT '0',
+  `active` tinyint(4) NOT NULL default '1',
+  PRIMARY KEY (`id`),
+  UNIQUE `setting` (`setting_id`, `user_id`)
+);
+
+INSERT INTO `bx_notifications_handlers`(`group`, `type`, `alert_unit`, `alert_action`, `content`) VALUES 
+('profile', 'delete', 'profile', 'delete', '');
+
+-- Mentions
+INSERT INTO `bx_notifications_handlers`(`group`, `type`, `alert_unit`, `alert_action`, `content`, `privacy`, `priority`) VALUES 
+('mention', 'insert', 'meta_mention', 'added', 'a:3:{s:11:"module_name";s:6:"system";s:13:"module_method";s:30:"get_notifications_post_mention";s:12:"module_class";s:20:"TemplServiceMetatags";}', '', 1);
+SET @iHandlerId = LAST_INSERT_ID();
+
+INSERT INTO `bx_notifications_settings`(`group`, `handler_id`, `delivery`, `type`, `title`, `order`) VALUES
+('mention', @iHandlerId, 'site', 'personal', '_bx_ntfs_alert_action_mention_added_personal', 1),
+('mention', @iHandlerId, 'email', 'personal', '_bx_ntfs_alert_action_mention_added_personal', 1),
+('mention', @iHandlerId, 'push', 'personal', '_bx_ntfs_alert_action_mention_added_personal', 1);
+
+-- Friendship
+INSERT INTO `bx_notifications_handlers`(`group`, `type`, `alert_unit`, `alert_action`, `content`) VALUES 
+('friendship', 'insert', 'sys_profiles_friends', 'connection_added', 'a:3:{s:11:"module_name";s:6:"system";s:13:"module_method";s:33:"get_notifications_post_friendship";s:12:"module_class";s:23:"TemplServiceConnections";}');
+SET @iHandlerId = LAST_INSERT_ID();
+
+INSERT INTO `bx_notifications_settings`(`group`, `handler_id`, `delivery`, `type`, `title`, `order`) VALUES
+('friendship', @iHandlerId, 'site', 'personal', '_bx_ntfs_alert_action_friendship_added_personal', 2),
+('friendship', @iHandlerId, 'email', 'personal', '_bx_ntfs_alert_action_friendship_added_personal', 2),
+('friendship', @iHandlerId, 'push', 'personal', '_bx_ntfs_alert_action_friendship_added_personal', 2);
+
+INSERT INTO `bx_notifications_handlers`(`group`, `type`, `alert_unit`, `alert_action`, `content`) VALUES 
+('friendship', 'delete', 'sys_profiles_friends', 'connection_removed', '');
+
+-- Subscription
+INSERT INTO `bx_notifications_handlers`(`group`, `type`, `alert_unit`, `alert_action`, `content`) VALUES 
+('subscription', 'insert', 'sys_profiles_subscriptions', 'connection_added', 'a:3:{s:11:"module_name";s:6:"system";s:13:"module_method";s:22:"get_notifications_post";s:12:"module_class";s:23:"TemplServiceConnections";}');
+SET @iHandlerId = LAST_INSERT_ID();
+
+INSERT INTO `bx_notifications_settings`(`group`, `handler_id`, `delivery`, `type`, `title`, `order`) VALUES
+('subscription', @iHandlerId, 'site', 'personal', '_bx_ntfs_alert_action_subscription_added_personal', 3),
+('subscription', @iHandlerId, 'email', 'personal', '_bx_ntfs_alert_action_subscription_added_personal', 3),
+('subscription', @iHandlerId, 'push', 'personal', '_bx_ntfs_alert_action_subscription_added_personal', 3);
+
+INSERT INTO `bx_notifications_handlers`(`group`, `type`, `alert_unit`, `alert_action`, `content`) VALUES 
+('subscription', 'delete', 'sys_profiles_subscriptions', 'connection_removed', '');
+
+-- Comments
+INSERT INTO `bx_notifications_handlers`(`group`, `type`, `alert_unit`, `alert_action`, `content`) VALUES 
+('comment', 'insert', 'comment', 'added', 'a:3:{s:11:"module_name";s:6:"system";s:13:"module_method";s:31:"get_notifications_comment_added";s:12:"module_class";s:17:"TemplCmtsServices";}');
+SET @iHandlerId = LAST_INSERT_ID();
+
+INSERT INTO `bx_notifications_settings`(`group`, `handler_id`, `delivery`, `type`, `title`, `order`) VALUES
+('comment', @iHandlerId, 'site', 'personal', '_bx_ntfs_alert_action_comment_added_personal', 1),
+('comment', @iHandlerId, 'email', 'personal', '_bx_ntfs_alert_action_comment_added_personal', 1),
+('comment', @iHandlerId, 'push', 'personal', '_bx_ntfs_alert_action_comment_added_personal', 1);
+
+INSERT INTO `bx_notifications_handlers`(`group`, `type`, `alert_unit`, `alert_action`, `content`) VALUES 
+('comment', 'delete', 'comment', 'deleted', '');
+
+-- Comments Actions (Like, Reaction, Score Up\Down)
+INSERT INTO `bx_notifications_handlers`(`group`, `type`, `alert_unit`, `alert_action`, `content`, `privacy`) VALUES 
+('sys_cmts_vote', 'insert', 'sys_cmts', 'doVote', 'a:3:{s:11:"module_name";s:6:"system";s:13:"module_method";s:22:"get_notifications_vote";s:12:"module_class";s:17:"TemplCmtsServices";}', '');
+SET @iHandlerId = LAST_INSERT_ID();
+
+INSERT INTO `bx_notifications_settings`(`group`, `handler_id`, `delivery`, `type`, `title`, `order`) VALUES
+('vote', @iHandlerId, 'site', 'personal', '_bx_ntfs_alert_action_doVote_personal', 4),
+('vote', @iHandlerId, 'email', 'personal', '_bx_ntfs_alert_action_doVote_personal', 4),
+('vote', @iHandlerId, 'push', 'personal', '_bx_ntfs_alert_action_doVote_personal', 4),
+
+('vote', @iHandlerId, 'site', 'follow_member', '_bx_ntfs_alert_action_doVote_follow_member', 1),
+('vote', @iHandlerId, 'email', 'follow_member', '_bx_ntfs_alert_action_doVote_follow_member', 1),
+('vote', @iHandlerId, 'push', 'follow_member', '_bx_ntfs_alert_action_doVote_follow_member', 1),
+
+('vote', @iHandlerId, 'site', 'follow_context', '_bx_ntfs_alert_action_doVote_follow_context', 1),
+('vote', @iHandlerId, 'email', 'follow_context', '_bx_ntfs_alert_action_doVote_follow_context', 1),
+('vote', @iHandlerId, 'push', 'follow_context', '_bx_ntfs_alert_action_doVote_follow_context', 1);
+
+INSERT INTO `bx_notifications_handlers`(`group`, `type`, `alert_unit`, `alert_action`, `content`) VALUES 
+('sys_cmts_vote', 'delete', 'sys_cmts', 'undoVote', '');
+
+INSERT INTO `bx_notifications_handlers`(`group`, `type`, `alert_unit`, `alert_action`, `content`, `privacy`) VALUES 
+('sys_cmts_reaction', 'insert', 'sys_cmts_reactions', 'doVote', 'a:3:{s:11:"module_name";s:6:"system";s:13:"module_method";s:26:"get_notifications_reaction";s:12:"module_class";s:17:"TemplCmtsServices";}', '');
+SET @iHandlerId = LAST_INSERT_ID();
+
+INSERT INTO `bx_notifications_settings`(`group`, `handler_id`, `delivery`, `type`, `title`, `order`) VALUES
+('vote', @iHandlerId, 'site', 'personal', '_bx_ntfs_alert_action_doVote_personal', 5),
+('vote', @iHandlerId, 'email', 'personal', '_bx_ntfs_alert_action_doVote_personal', 5),
+('vote', @iHandlerId, 'push', 'personal', '_bx_ntfs_alert_action_doVote_personal', 5),
+
+('vote', @iHandlerId, 'site', 'follow_member', '_bx_ntfs_alert_action_doVote_follow_member', 2),
+('vote', @iHandlerId, 'email', 'follow_member', '_bx_ntfs_alert_action_doVote_follow_member', 2),
+('vote', @iHandlerId, 'push', 'follow_member', '_bx_ntfs_alert_action_doVote_follow_member', 2),
+
+('vote', @iHandlerId, 'site', 'follow_context', '_bx_ntfs_alert_action_doVote_follow_context', 2),
+('vote', @iHandlerId, 'email', 'follow_context', '_bx_ntfs_alert_action_doVote_follow_context', 2),
+('vote', @iHandlerId, 'push', 'follow_context', '_bx_ntfs_alert_action_doVote_follow_context', 2);
+
+INSERT INTO `bx_notifications_handlers`(`group`, `type`, `alert_unit`, `alert_action`, `content`) VALUES 
+('sys_cmts_reaction', 'delete', 'sys_cmts_reactions', 'undoVote', '');
+
+INSERT INTO `bx_notifications_handlers`(`group`, `type`, `alert_unit`, `alert_action`, `content`, `privacy`) VALUES 
+('sys_cmts_score_up', 'insert', 'sys_cmts', 'doVoteUp', 'a:3:{s:11:"module_name";s:6:"system";s:13:"module_method";s:26:"get_notifications_score_up";s:12:"module_class";s:17:"TemplCmtsServices";}', '');
+SET @iHandlerId = LAST_INSERT_ID();
+
+INSERT INTO `bx_notifications_settings`(`group`, `handler_id`, `delivery`, `type`, `title`, `order`) VALUES
+('score_up', @iHandlerId, 'site', 'personal', '_bx_ntfs_alert_action_doVoteUp_personal', 6),
+('score_up', @iHandlerId, 'email', 'personal', '_bx_ntfs_alert_action_doVoteUp_personal', 6),
+('score_up', @iHandlerId, 'push', 'personal', '_bx_ntfs_alert_action_doVoteUp_personal', 6),
+
+('score_up', @iHandlerId, 'site', 'follow_member', '_bx_ntfs_alert_action_doVoteUp_follow_member', 3),
+('score_up', @iHandlerId, 'email', 'follow_member', '_bx_ntfs_alert_action_doVoteUp_follow_member', 3),
+('score_up', @iHandlerId, 'push', 'follow_member', '_bx_ntfs_alert_action_doVoteUp_follow_member', 3),
+
+('score_up', @iHandlerId, 'site', 'follow_context', '_bx_ntfs_alert_action_doVoteUp_follow_context', 3),
+('score_up', @iHandlerId, 'email', 'follow_context', '_bx_ntfs_alert_action_doVoteUp_follow_context', 3),
+('score_up', @iHandlerId, 'push', 'follow_context', '_bx_ntfs_alert_action_doVoteUp_follow_context', 3);
+
+INSERT INTO `bx_notifications_handlers`(`group`, `type`, `alert_unit`, `alert_action`, `content`, `privacy`) VALUES 
+('sys_cmts_score_down', 'insert', 'sys_cmts', 'doVoteDown', 'a:3:{s:11:"module_name";s:6:"system";s:13:"module_method";s:28:"get_notifications_score_down";s:12:"module_class";s:17:"TemplCmtsServices";}', '');
+SET @iHandlerId = LAST_INSERT_ID();
+
+INSERT INTO `bx_notifications_settings`(`group`, `handler_id`, `delivery`, `type`, `title`, `order`) VALUES
+('score_down', @iHandlerId, 'site', 'personal', '_bx_ntfs_alert_action_doVoteDown_personal', 7),
+('score_down', @iHandlerId, 'email', 'personal', '_bx_ntfs_alert_action_doVoteDown_personal', 7),
+('score_down', @iHandlerId, 'push', 'personal', '_bx_ntfs_alert_action_doVoteDown_personal', 7),
+
+('score_down', @iHandlerId, 'site', 'follow_member', '_bx_ntfs_alert_action_doVoteDown_follow_member', 4),
+('score_down', @iHandlerId, 'email', 'follow_member', '_bx_ntfs_alert_action_doVoteDown_follow_member', 4),
+('score_down', @iHandlerId, 'push', 'follow_member', '_bx_ntfs_alert_action_doVoteDown_follow_member', 4),
+
+('score_down', @iHandlerId, 'site', 'follow_context', '_bx_ntfs_alert_action_doVoteDown_follow_context', 4),
+('score_down', @iHandlerId, 'email', 'follow_context', '_bx_ntfs_alert_action_doVoteDown_follow_context', 4),
+('score_down', @iHandlerId, 'push', 'follow_context', '_bx_ntfs_alert_action_doVoteDown_follow_context', 4);
+
+INSERT INTO `bx_notifications_handlers`(`group`, `type`, `alert_unit`, `alert_action`, `content`, `privacy`) VALUES 
+('sys_cmts_object_reported', 'insert', 'sys_cmts', 'reported_content', 'a:3:{s:11:"module_name";s:6:"system";s:13:"module_method";s:34:"get_notifications_comment_reported";s:12:"module_class";s:17:"TemplCmtsServices";}', '');
+SET @iHandlerId = LAST_INSERT_ID();
+
+INSERT INTO `bx_notifications_settings`(`group`, `handler_id`, `delivery`, `type`, `title`, `order`) VALUES
+('action_required', @iHandlerId, 'site', 'personal', '_bx_ntfs_alert_action_reported_content_personal', 8),
+('action_required', @iHandlerId, 'email', 'personal', '_bx_ntfs_alert_action_reported_content_personal', 8),
+('action_required', @iHandlerId, 'push', 'personal', '_bx_ntfs_alert_action_reported_content_personal', 8);
+
+
+CREATE TABLE IF NOT EXISTS `bx_notifications_queue` (
+  `id` int(11) NOT NULL auto_increment,
+  `profile_id` int(11) NOT NULL DEFAULT '0',
+  `event_id` int(11) NOT NULL DEFAULT '0',
+  `delivery` varchar(64) NOT NULL default '',
+  `content` text NOT NULL,
+  `date` int(11) NOT NULL default '0',
+  PRIMARY KEY  (`id`)
+);
+
+CREATE TABLE IF NOT EXISTS `bx_notifications_etemplates` (
+  `id` int(11) NOT NULL auto_increment,
+  `type` varchar(255) NOT NULL,
+  `action` varchar(255) NOT NULL,
+  `subject` varchar(255) NOT NULL default '',
+  `body` text NOT NULL,
+  `active` tinyint(4) NOT NULL default '0',
+  PRIMARY KEY (`id`),
+  UNIQUE KEY `etemplate` (`type`(32), `action`(127))
+);
+
+
+-- FORMS: etemplate
+INSERT INTO `sys_objects_form` (`object`, `module`, `title`, `action`, `form_attrs`, `submit_name`, `table`, `key`, `uri`, `uri_title`, `params`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES
+('bx_notifications_etemplate', @sName, '_bx_ntfs_form_etemplate', '', '', 'do_submit', 'bx_notifications_etemplates', 'id', '', '', '', 0, 1, '', '');
+
+INSERT INTO `sys_form_displays` (`display_name`, `module`, `object`, `title`, `view_mode`) VALUES
+('bx_notifications_etemplate_add', @sName, 'bx_notifications_etemplate', '_bx_ntfs_form_etemplate_display_add', 0),
+('bx_notifications_etemplate_edit', @sName, 'bx_notifications_etemplate', '_bx_ntfs_form_etemplate_display_edit', 0);
+
+INSERT INTO `sys_form_inputs` (`object`, `module`, `name`, `value`, `values`, `checked`, `type`, `caption_system`, `caption`, `info`, `required`, `collapsed`, `html`, `attrs`, `attrs_tr`, `attrs_wrapper`, `checker_func`, `checker_params`, `checker_error`, `db_pass`, `db_params`, `editable`, `deletable`) VALUES
+('bx_notifications_etemplate', @sName, 'type', '', '', 0, 'select', '_bx_ntfs_form_etemplate_input_sys_type', '_bx_ntfs_form_etemplate_input_type', '', 1, 0, 0, '', '', '', 'Avail', '', '_bx_ntfs_form_etemplate_input_err_select', 'Xss', '', 0, 0),
+('bx_notifications_etemplate', @sName, 'action', '', '', 0, 'select', '_bx_ntfs_form_etemplate_input_sys_action', '_bx_ntfs_form_etemplate_input_action', '', 1, 0, 0, '', '', '', 'Avail', '', '_bx_ntfs_form_etemplate_input_err_select', 'Xss', '', 0, 0),
+('bx_notifications_etemplate', @sName, 'subject', '', '', 0, 'text', '_bx_ntfs_form_etemplate_input_sys_subject', '_bx_ntfs_form_etemplate_input_subject', '', 1, 0, 0, '', '', '', 'Avail', '', '_bx_ntfs_form_etemplate_input_err_enter', 'Xss', '', 0, 0),
+('bx_notifications_etemplate', @sName, 'body', '', '', 0, 'textarea', '_bx_ntfs_form_etemplate_input_sys_body', '_bx_ntfs_form_etemplate_input_body', '', 1, 0, 0, '', '', '', 'Avail', '', '_bx_ntfs_form_etemplate_input_err_enter', 'XssHtml', '', 0, 0),
+('bx_notifications_etemplate', @sName, 'controls', '', 'do_submit,do_cancel', 0, 'input_set', '_bx_ntfs_form_etemplate_input_controls', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 0, 0),
+('bx_notifications_etemplate', @sName, 'do_submit', '_bx_ntfs_form_etemplate_input_do_submit', '', 0, 'submit', '_bx_ntfs_form_etemplate_input_sys_do_submit', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 0, 0),
+('bx_notifications_etemplate', @sName, 'do_cancel', '_bx_ntfs_form_etemplate_input_do_cancel', '', 0, 'button', '_bx_ntfs_form_etemplate_input_do_cancel', '', '', 0, 0, 0, 'a:2:{s:7:"onclick";s:45:"$(''.bx-popup-applied:visible'').dolPopupHide()";s:5:"class";s:22:"bx-def-margin-sec-left";}', '', '', '', '', '', '', '', 0, 0);
+
+INSERT INTO `sys_form_display_inputs` (`display_name`, `input_name`, `visible_for_levels`, `active`, `order`) VALUES
+('bx_notifications_etemplate_add', 'type', 2147483647, 1, 1),
+('bx_notifications_etemplate_add', 'action', 2147483647, 1, 2),
+('bx_notifications_etemplate_add', 'subject', 2147483647, 1, 3),
+('bx_notifications_etemplate_add', 'body', 2147483647, 1, 4),
+('bx_notifications_etemplate_add', 'controls', 2147483647, 1, 5),
+('bx_notifications_etemplate_add', 'do_submit', 2147483647, 1, 6),
+('bx_notifications_etemplate_add', 'do_cancel', 2147483647, 1, 7),
+
+('bx_notifications_etemplate_edit', 'subject', 2147483647, 1, 1),
+('bx_notifications_etemplate_edit', 'body', 2147483647, 1, 2),
+('bx_notifications_etemplate_edit', 'controls', 2147483647, 1, 3),
+('bx_notifications_etemplate_edit', 'do_submit', 2147483647, 1, 4),
+('bx_notifications_etemplate_edit', 'do_cancel', 2147483647, 1, 5);
+
+
+-- STUDIO PAGE & WIDGET
+INSERT INTO `sys_std_pages`(`index`, `name`, `header`, `caption`, `icon`) VALUES
+(3, @sName, '_bx_ntfs', '_bx_ntfs', 'bx_notifications@modules/boonex/notifications/|std-icon.svg');
+SET @iPageId = LAST_INSERT_ID();
+
+SET @iParentPageId = (SELECT `id` FROM `sys_std_pages` WHERE `name` = 'home');
+SET @iParentPageOrder = (SELECT MAX(`order`) FROM `sys_std_pages_widgets` WHERE `page_id` = @iParentPageId);
+INSERT INTO `sys_std_widgets` (`page_id`, `module`, `type`, `url`, `click`, `icon`, `caption`, `cnt_notices`, `cnt_actions`) VALUES
+(@iPageId, @sName, 'extensions', '{url_studio}module.php?name=bx_notifications', '', 'bx_notifications@modules/boonex/notifications/|std-icon.svg', '_bx_ntfs', '', 'a:4:{s:6:"module";s:6:"system";s:6:"method";s:11:"get_actions";s:6:"params";a:0:{}s:5:"class";s:18:"TemplStudioModules";}');
+INSERT INTO `sys_std_pages_widgets` (`page_id`, `widget_id`, `order`) VALUES
+(@iParentPageId, LAST_INSERT_ID(), IF(ISNULL(@iParentPageOrder), 1, @iParentPageOrder + 1));

+ 19 - 0
modules/boonex/notifications/updates/15.0.2_15.0.3/source/install/sql/uninstall.sql

@@ -0,0 +1,19 @@
+SET @sName = 'bx_notifications';
+
+
+DROP TABLE IF EXISTS `bx_notifications_events`, `bx_notifications_events2users`, `bx_notifications_read`;
+DROP TABLE IF EXISTS `bx_notifications_handlers`, `bx_notifications_settings`, `bx_notifications_settings2users`;
+DROP TABLE IF EXISTS `bx_notifications_queue`, `bx_notifications_etemplates`;
+
+
+-- FORMS
+DELETE FROM `sys_objects_form` WHERE `module` = @sName;
+DELETE FROM `sys_form_displays` WHERE `module` = @sName;
+DELETE FROM `sys_form_inputs` WHERE `module` = @sName;
+DELETE FROM `sys_form_display_inputs` WHERE `display_name` LIKE 'bx_notifications_%';
+
+
+-- STUDIO PAGE & WIDGET
+DELETE FROM `tp`, `tw`, `twb`, `tpw` 
+USING `sys_std_pages` AS `tp` LEFT JOIN `sys_std_widgets` AS `tw` ON `tp`.`id` = `tw`.`page_id` LEFT JOIN `sys_std_widgets_bookmarks` AS `twb` ON `tw`.`id` = `twb`.`widget_id` LEFT JOIN `sys_std_pages_widgets` AS `tpw` ON `tw`.`id` = `tpw`.`widget_id`
+WHERE  `tp`.`name` = @sName;

+ 54 - 0
modules/boonex/notifications/updates/15.0.2_15.0.3/source/js/main.js

@@ -0,0 +1,54 @@
+function BxNtfsMain(oOptions) {
+    this._sActionsUri = oOptions.sActionUri;
+    this._sActionsUrl = oOptions.sActionUrl;
+    this._sAnimationEffect = oOptions.sAnimationEffect == undefined ? 'slide' : oOptions.sAnimationEffect;
+    this._iAnimationSpeed = oOptions.iAnimationSpeed == undefined ? 'slow' : oOptions.iAnimationSpeed;
+    this._aHtmlIds = oOptions.aHtmlIds == undefined ? {} : oOptions.aHtmlIds;
+    this._oRequestParams = oOptions.oRequestParams == undefined ? {} : oOptions.oRequestParams;
+}
+
+BxNtfsMain.prototype.onChangeType = function(oElement) {
+    var $this = this;
+    var oData = this._getDefaultData();
+
+    jQuery.get(
+        this._sActionsUrl + 'get_action/' + $(oElement).val(),
+        oData,
+        function(oData) {
+            if(!oData || oData.code != 0)
+                return;
+
+            $('#' + $this._aHtmlIds['field_action']).html(oData.content).removeAttr('disabled');
+        },
+        'json'
+    );
+
+    return false;
+};
+
+BxNtfsMain.prototype.loadingInButton = function(e, bShow) {
+    if($(e).length)
+        bx_loading_btn($(e), bShow);
+    else
+        bx_loading($('body'), bShow);	
+};
+
+BxNtfsMain.prototype.loadingInItem = function(e, bShow) {
+    var oParent = $(e).length ? $(e).parents('.bx-ntfs-item:first') : $('body'); 
+    bx_loading(oParent, bShow);
+};
+
+BxNtfsMain.prototype.loadingInBlock = function(e, bShow) {
+    var oParent = $(e).length ? $(e).parents('.bx-db-container:first') : $('body'); 
+    bx_loading(oParent, bShow);
+};
+
+BxNtfsMain.prototype._loading = function(e, bShow) {
+    var oParent = $(e).length ? $(e) : $('body'); 
+    bx_loading(oParent, bShow);
+};
+
+BxNtfsMain.prototype._getDefaultData = function () {
+    var oDate = new Date();
+    return jQuery.extend({}, this._oRequestParams, {_t:oDate.getTime()});
+};

+ 19 - 0
modules/boonex/notifications/updates/15.0.2_15.0.3/source/template/etemplate_form.html

@@ -0,0 +1,19 @@
+<div class="__style_prefix__-etemplate-form">
+    <div class="__style_prefix__-etemplate-form-cnt">
+        __form__
+        <script language="javascript">
+            $(document).ready(function () {
+                $("#__form_id__").ajaxForm({ 
+                    dataType: "json",
+                    beforeSubmit: function (formData, jqForm, options) {
+                        bx_loading($("#__form_id__"), true);
+                    },
+                    success: function (data) {
+                        $(".bx-popup-applied:visible").dolPopupHide();
+                        glGrids.__object__.processJson(data, '__action__');
+                    }
+                });
+            });
+        </script>
+    </div>
+</div>

+ 12 - 0
modules/boonex/notifications/updates/15.0.2_15.0.3/source/template/etemplate_preview.html

@@ -0,0 +1,12 @@
+<div class="__style_prefix__-etemplate-preview">
+    <div class="__style_prefix__-etemplate-preview-cnt">
+        <div class="__style_prefix__-etp-row">
+            <div class="font-bold"><bx_text:_bx_ntfs_txt_et_preview_subject /></div>
+            <div>__subject__</div>
+        </div>
+        <div class="__style_prefix__-etp-row mt-4">
+            <div class="font-bold"><bx_text:_bx_ntfs_txt_et_preview_body /></div>
+            <div>__body__</div>
+        </div>
+    </div>
+</div>

+ 1 - 0
modules/boonex/notifications/updates/15.0.2_15.0.3/source/template/field_actions.html

@@ -0,0 +1 @@
+<bx_repeat:actions><option value="__value__">__title__</option></bx_repeat:actions>

+ 58 - 0
modules/boonex/organizations/updates/15.0.2_15.0.3/install/config.php

@@ -0,0 +1,58 @@
+<?php
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ */
+
+$aConfig = array(
+    /**
+     * Main Section.
+     */
+    'title' => 'Organizations',
+    'version_from' => '15.0.2',
+    'version_to' => '15.0.3',
+    'vendor' => 'UNA INC',
+
+    'compatible_with' => array(
+        '15.0.0-B2'
+    ),
+
+    /**
+     * 'home_dir' and 'home_uri' - should be unique. Don't use spaces in 'home_uri' and the other special chars.
+     */
+    'home_dir' => 'boonex/organizations/updates/update_15.0.2_15.0.3/',
+    'home_uri' => 'orgs_update_1502_1503',
+
+    'module_dir' => 'boonex/organizations/',
+    'module_uri' => 'orgs',
+
+    'db_prefix' => 'bx_organizations_',
+    'class_prefix' => 'BxOrgs',
+
+    /**
+      * Transcoders.
+      */
+    'transcoders' => array(
+        'bx_organizations_badge'
+    ),
+
+    /**
+     * Installation/Uninstallation Section.
+     */
+    'install' => array(
+        'execute_sql' => 0,
+        'update_files' => 1,
+        'update_languages' => 0,
+        'clear_db_cache' => 0,
+    ),
+
+    /**
+     * Category for language keys.
+     */
+    'language_category' => 'Organizations',
+
+    /**
+     * Files Section
+     */
+    'delete_files' => array(),
+);

+ 13 - 0
modules/boonex/organizations/updates/15.0.2_15.0.3/install/installer.php

@@ -0,0 +1,13 @@
+<?php
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ */
+
+class BxOrgsUpdater extends BxDolStudioUpdater
+{
+    function __construct($aConfig)
+    {
+        parent::__construct($aConfig);
+    }
+}

+ 153 - 0
modules/boonex/organizations/updates/15.0.2_15.0.3/source/install/config.php

@@ -0,0 +1,153 @@
+<?php
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Organizations Organizations
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+$aConfig = array(
+
+    /**
+     * Main Section.
+     */
+    'type' => BX_DOL_MODULE_TYPE_MODULE,
+    'name' => 'bx_organizations',
+    'title' => 'Organizations',
+    'note' => 'Basic organization profiles functionality.',
+    'version' => '15.0.3',
+    'vendor' => 'UNA INC',
+    'help_url' => 'http://feed.una.io/?section={module_name}',
+
+    'compatible_with' => array(
+        '15.0.0-B2'
+    ),
+
+    /**
+     * 'home_dir' and 'home_uri' - should be unique. Don't use spaces in 'home_uri' and the other special chars.
+     */
+    'home_dir' => 'boonex/organizations/',
+    'home_uri' => 'orgs',
+
+    'db_prefix' => 'bx_organizations_',
+    'class_prefix' => 'BxOrgs',
+
+    /**
+     * Category for language keys.
+     */
+    'language_category' => 'Organizations',
+
+    /**
+     * Connections.
+     */
+    'connections' => array(
+    	'sys_profiles_friends' => array ('type' => 'profiles'),
+        'sys_profiles_subscriptions' => array ('type' => 'profiles'),
+        'sys_profiles_relations' => array ('type' => 'profiles'),
+    ),
+
+    /**
+     * Menu triggers.
+     */
+    'menu_triggers' => array(
+        'trigger_profile_view_submenu',
+        'trigger_profile_snippet_meta',
+        'trigger_profile_view_actions',
+    ),
+
+    /**
+     * Page triggers.
+     */
+    'page_triggers' => array (
+    	'trigger_page_profile_view_entry', 
+    ),
+
+    /**
+     * Storage objects to automatically delete files from upon module uninstallation.
+     * Note. Don't add storage objects used in transcoder objects.
+     */
+    'storages' => array(
+    	'bx_organizations_pics'
+    ),
+
+    /**
+     * Transcoders.
+     */
+    'transcoders' => array(
+    	'bx_organizations_icon', 
+    	'bx_organizations_thumb', 
+    	'bx_organizations_avatar', 
+        'bx_organizations_avatar_big', 
+    	'bx_organizations_picture', 
+    	'bx_organizations_cover', 
+    	'bx_organizations_cover_thumb',
+    	'bx_organizations_gallery',
+        'bx_organizations_badge'
+    ),
+
+    /**
+     * Extended Search Forms.
+     */
+    'esearches' => array(
+        'bx_organizations',
+    	'bx_organizations_cmts',
+    ),
+
+    /**
+     * Installation/Uninstallation Section.
+     */
+    'install' => array(
+        'execute_sql' => 1,
+        'update_languages' => 1,
+        'clear_db_cache' => 1,
+    ),
+    'uninstall' => array (
+    	'process_esearches' => 1,
+        'execute_sql' => 1,
+        'update_languages' => 1,
+    	'process_connections' => 1,
+    	'process_deleted_profiles' => 1,
+    	'update_relations' => 1,
+        'clear_db_cache' => 1,
+    ),
+    'enable' => array(
+        'execute_sql' => 1,
+    	'update_relations' => 1,
+        'clear_db_cache' => 1,
+    ),
+    'enable_success' => array(
+    	'process_menu_triggers' => 1,
+    	'process_page_triggers' => 1,
+    	'process_esearches' => 1,
+    	'register_transcoders' => 1,
+        'clear_db_cache' => 1,
+    ),
+    'disable' => array (
+        'execute_sql' => 1,
+    	'unregister_transcoders' => 1,
+    	'update_relations' => 1,
+        'clear_db_cache' => 1,
+    ),
+    'disable_failed' => array (
+    	'register_transcoders' => 1,
+    	'clear_db_cache' => 1,
+    ),
+
+    /**
+     * Dependencies Section
+     */
+    'dependencies' => array(),
+
+    /**
+     * Connections Section
+     */
+    'relations' => array(
+        'bx_timeline',
+        'bx_notifications',
+    ),
+);
+
+/** @} */

+ 59 - 0
modules/boonex/organizations/updates/15.0.2_15.0.3/source/install/sql/uninstall.sql

@@ -0,0 +1,59 @@
+
+-- TABLES
+DROP TABLE IF EXISTS `bx_organizations_data`, `bx_organizations_pics`, `bx_organizations_pics_resized`, `bx_organizations_cmts`, `bx_organizations_cmts_notes`, `bx_organizations_views_track`, `bx_organizations_votes`, `bx_organizations_votes_track`, `bx_organizations_reactions`, `bx_organizations_reactions_track`, `bx_organizations_favorites_track`, `bx_organizations_favorites_lists`, `bx_organizations_reports`, `bx_organizations_reports_track`, `bx_organizations_meta_keywords`, `bx_organizations_meta_locations`, `bx_organizations_meta_mentions`, `bx_organizations_invites`, `bx_organizations_fans`, `bx_organizations_admins`, `bx_organizations_scores`, `bx_organizations_scores_track`, `bx_organizations_prices`;
+
+-- PROFILES
+DELETE FROM sys_profiles WHERE `type` = 'bx_organizations';
+
+-- STORAGES & TRANSCODERS
+DELETE FROM `sys_objects_storage` WHERE `object` IN('bx_organizations_pics', 'bx_organizations_pics_resized');
+DELETE FROM `sys_storage_tokens` WHERE `object` IN('bx_organizations_pics', 'bx_organizations_pics_resized');
+
+DELETE FROM `sys_objects_transcoder` WHERE `object` IN('bx_organizations_icon', 'bx_organizations_thumb', 'bx_organizations_avatar', 'bx_organizations_avatar_big', 'bx_organizations_picture', 'bx_organizations_cover', 'bx_organizations_cover_thumb', 'bx_organizations_gallery', 'bx_organizations_badge');
+DELETE FROM `sys_transcoder_filters` WHERE `transcoder_object` IN('bx_organizations_icon', 'bx_organizations_thumb', 'bx_organizations_avatar', 'bx_organizations_avatar_big', 'bx_organizations_picture', 'bx_organizations_cover', 'bx_organizations_cover_thumb', 'bx_organizations_gallery', 'bx_organizations_badge');
+DELETE FROM `sys_transcoder_images_files` WHERE `transcoder_object` IN('bx_organizations_icon', 'bx_organizations_thumb', 'bx_organizations_avatar', 'bx_organizations_avatar_big', 'bx_organizations_picture', 'bx_organizations_cover', 'bx_organizations_cover_thumb', 'bx_organizations_gallery', 'bx_organizations_badge');
+
+-- FORMS
+DELETE FROM `sys_objects_form` WHERE `module` = 'bx_organizations';
+DELETE FROM `sys_form_displays` WHERE `module` = 'bx_organizations';
+DELETE FROM `sys_form_inputs` WHERE `module` = 'bx_organizations';
+DELETE FROM `sys_form_display_inputs` WHERE `display_name` IN('bx_organization_add', 'bx_organization_delete', 'bx_organization_edit', 'bx_organization_edit_cover', 'bx_organization_edit_badge', 'bx_organization_view', 'bx_organization_view_full', 'bx_organization_invite', 'bx_organizations_price_add', 'bx_organizations_price_edit');
+
+-- PRE-VALUES
+DELETE FROM `sys_form_pre_lists` WHERE `module` = 'bx_organizations';
+
+DELETE FROM `sys_form_pre_values` WHERE `Key` LIKE 'bx_organizations%';
+
+-- COMMENTS
+DELETE FROM `sys_objects_cmts` WHERE `Name` LIKE 'bx_organizations%';
+
+-- VIEWS
+DELETE FROM `sys_objects_view` WHERE `name` = 'bx_organizations';
+
+-- VOTES
+DELETE FROM `sys_objects_vote` WHERE `Name` IN ('bx_organizations', 'bx_organizations_reactions');
+
+-- SCORES
+DELETE FROM `sys_objects_score` WHERE `name` = 'bx_organizations';
+
+-- FAFORITES
+DELETE FROM `sys_objects_favorite` WHERE `name` = 'bx_organizations';
+
+-- FEATURED
+DELETE FROM `sys_objects_feature` WHERE `name` = 'bx_organizations';
+
+-- REPORTS
+DELETE FROM `sys_objects_report` WHERE `name` = 'bx_organizations';
+
+-- CONTENT INFO
+DELETE FROM `sys_objects_content_info` WHERE `name` IN ('bx_organizations', 'bx_organizations_cmts');
+
+DELETE FROM `sys_content_info_grids` WHERE `object` IN ('bx_organizations');
+
+-- SEARCH EXTENDED
+DELETE FROM `sys_objects_search_extended` WHERE `module` = 'bx_organizations';
+
+-- STUDIO PAGE & WIDGET
+DELETE FROM `tp`, `tw`, `twb`, `tpw` 
+USING `sys_std_pages` AS `tp` LEFT JOIN `sys_std_widgets` AS `tw` ON `tp`.`id` = `tw`.`page_id` LEFT JOIN `sys_std_widgets_bookmarks` AS `twb` ON `tw`.`id` = `twb`.`widget_id` LEFT JOIN `sys_std_pages_widgets` AS `tpw` ON `tw`.`id` = `tpw`.`widget_id`
+WHERE  `tp`.`name` = 'bx_organizations';

+ 51 - 0
modules/boonex/payment/updates/15.0.1_15.0.2/install/config.php

@@ -0,0 +1,51 @@
+<?php
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ */
+
+$aConfig = array(
+    /**
+     * Main Section.
+     */
+    'title' => 'Payment',
+    'version_from' => '15.0.1',
+    'version_to' => '15.0.2',
+    'vendor' => 'UNA INC',
+
+    'compatible_with' => array(
+        '15.0.0-B2'
+    ),
+
+    /**
+     * 'home_dir' and 'home_uri' - should be unique. Don't use spaces in 'home_uri' and the other special chars.
+     */
+    'home_dir' => 'boonex/payment/updates/update_15.0.1_15.0.2/',
+    'home_uri' => 'payment_update_1501_1502',
+
+    'module_dir' => 'boonex/payment/',
+    'module_uri' => 'payment',
+
+    'db_prefix' => 'bx_payment_',
+    'class_prefix' => 'BxPayment',
+
+    /**
+     * Installation/Uninstallation Section.
+     */
+    'install' => array(
+        'execute_sql' => 1,
+        'update_files' => 1,
+        'update_languages' => 1,
+        'clear_db_cache' => 1,
+    ),
+
+    /**
+     * Category for language keys.
+     */
+    'language_category' => 'Payment',
+
+    /**
+     * Files Section
+     */
+    'delete_files' => array(),
+);

+ 25 - 0
modules/boonex/payment/updates/15.0.1_15.0.2/install/installer.php

@@ -0,0 +1,25 @@
+<?php
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ */
+
+class BxPaymentUpdater extends BxDolStudioUpdater
+{
+    function __construct($aConfig)
+    {
+        parent::__construct($aConfig);
+    }
+
+    public function actionExecuteSql($sOperation)
+    {
+        if($sOperation == 'install') {
+            if(!$this->oDb->isFieldExists('bx_payment_providers_options', 'value'))
+                $this->oDb->query("ALTER TABLE `bx_payment_providers_options` ADD `value` varchar(255) NOT NULL default '' AFTER `type`");
+            if(!$this->oDb->isFieldExists('bx_payment_providers_options', 'extended'))
+                $this->oDb->query("ALTER TABLE `bx_payment_providers_options` ADD `extended` tinyint(4) NOT NULL default '0' AFTER `check_error`");
+        }
+
+        return parent::actionExecuteSql($sOperation);
+    }
+}

+ 30 - 0
modules/boonex/payment/updates/15.0.1_15.0.2/install/langs/en.xml

@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+	<string_add name="_bx_payment_option_extended_mode"><![CDATA[Extended mode (Allows sellers to use Test mode, etc).]]></string_add>
+	<string_add name="_bx_payment_option_sbs_cancel_survey"><![CDATA[Enable 'Your reason to cancel subscription' survey.]]></string_add>
+	<string_add name="_bx_payment_grid_column_title_sbs_items"><![CDATA[Products]]></string_add>
+	<string_add name="_bx_payment_grid_column_title_sbs_item_id"><![CDATA[Product]]></string_add>
+	<string_add name="_bx_payment_form_cs_input_items"><![CDATA[Why do you want to cancel?]]></string_add>
+	<string_add name="_bx_payment_form_cs_input_other"><![CDATA[Your variant]]></string_add>
+	<string_add name="_bx_payment_form_cs_input_submit"><![CDATA[Submit]]></string_add>
+	<string_add name="_bx_payment_form_cs_input_cancel"><![CDATA[Cancel]]></string_add>
+	<string_add name="_bx_payment_form_input_err"><![CDATA[This field is essential. Please, fill it in.]]></string_add>
+	<string_add name="_bx_payment_pre_lists_reasons_cancel"><![CDATA[Reasons to cancel subscription]]></string_add>
+	<string_add name="_bx_payment_pre_values_rc_0"><![CDATA[Other]]></string_add>
+	<string_add name="_bx_payment_pre_values_rc_1"><![CDATA[Cost & Budgeting]]></string_add>
+	<string_add name="_bx_payment_pre_values_rc_2"><![CDATA[Hidden Fees & Billing Issues]]></string_add>
+	<string_add name="_bx_payment_pre_values_rc_3"><![CDATA[Low Usage]]></string_add>
+	<string_add name="_bx_payment_pre_values_rc_4"><![CDATA[Loss of Interest]]></string_add>
+	<string_add name="_bx_payment_pre_values_rc_5"><![CDATA[Poor User Experience]]></string_add>
+	<string_add name="_bx_payment_pre_values_rc_6"><![CDATA[Better Alternatives]]></string_add>
+	<string_add name="_bx_payment_txt_customer_id"><![CDATA[Customer ID]]></string_add>
+	<string_add name="_bx_payment_txt_subscription"><![CDATA[Subscription]]></string_add>
+	<string_add name="_bx_payment_txt_deleted"><![CDATA[Date cancel]]></string_add>
+	<string_add name="_bx_payment_txt_deleted_reason"><![CDATA[Reason to cancel]]></string_add>
+	<string_add name="_bx_payment_txt_status_cancel"><![CDATA[Canceled]]></string_add>
+
+	<string_del name="_bx_payment_grid_column_title_sbs_customer_id"><![CDATA[Customer ID]]></string_del>
+	<string_del name="_bx_payment_grid_column_title_sbs_subscription_id"><![CDATA[Subscription]]></string_del>
+	<string_del name="_bx_payment_grid_column_title_sbs_transaction"><![CDATA[Transaction]]></string_del>
+	<string_del name="_bx_payment_grid_column_title_sbs_license"><![CDATA[License]]></string_del>
+	<string_del name="_bx_payment_grid_column_title_sbs_provider"><![CDATA[Provider]]></string_del>
+</resources>

+ 13 - 0
modules/boonex/payment/updates/15.0.1_15.0.2/install/sql/enable.sql

@@ -0,0 +1,13 @@
+SET @sName = 'bx_payment';
+
+
+-- OPTIONS
+SET @iCategoryId = (SELECT `id` FROM `sys_options_categories` WHERE `name`='bx_payment_general' LIMIT 1);
+DELETE FROM `sys_options` WHERE `name` IN ('bx_payment_extended_mode', 'bx_payment_sbs_cancel_survey');
+INSERT INTO `sys_options` (`name`, `value`, `category_id`, `caption`, `type`, `check`, `check_params`, `check_error`, `extra`, `order`) VALUES
+('bx_payment_extended_mode', '', @iCategoryId, '_bx_payment_option_extended_mode', 'checkbox', '', '', '', '', 9),
+('bx_payment_sbs_cancel_survey', '', @iCategoryId, '_bx_payment_option_sbs_cancel_survey', 'checkbox', '', '', '', '', 20);
+
+
+-- MENUS
+UPDATE `sys_menu_items` SET `onclick`='{js_object}.cancel(this, {id}, \'{grid}\', 1)' WHERE `set_name`='bx_payment_menu_sbs_actions' AND `name`='sbs-cancel';

+ 50 - 0
modules/boonex/payment/updates/15.0.1_15.0.2/install/sql/install.sql

@@ -0,0 +1,50 @@
+SET @sName = 'bx_payment';
+
+
+-- TABLES
+ALTER TABLE `bx_payment_subscriptions_deleted` MODIFY `reason` varchar(255) NOT NULL default '';
+
+UPDATE `bx_payment_providers_options` SET `value`='on', `extended`='2' WHERE `name`='strp_v3_active';
+UPDATE `bx_payment_providers_options` SET `value`='', `extended`='1' WHERE `name`='strp_v3_hidden';
+UPDATE `bx_payment_providers_options` SET `value`='1', `extended`='2' WHERE `name`='strp_v3_mode';
+UPDATE `bx_payment_providers_options` SET `value`='', `extended`='1' WHERE `name`='strp_v3_test_pub_key';
+UPDATE `bx_payment_providers_options` SET `value`='', `extended`='1' WHERE `name`='strp_v3_test_sec_key';
+UPDATE `bx_payment_providers_options` SET `value`='', `extended`='1' WHERE `name`='strp_v3_check_amount';
+UPDATE `bx_payment_providers_options` SET `value`='on', `extended`='1' WHERE `name`='strp_v3_ssl';
+UPDATE `bx_payment_providers_options` SET `value`='', `extended`='1' WHERE `name`='strp_v3_expiration_email';
+
+UPDATE `bx_payment_providers_options` SET `value`='', `extended`='1' WHERE `name`='strp_cnnt_test_account_id';
+
+
+-- GRIDS
+UPDATE `sys_objects_grid` SET `source`='SELECT `ttp`.`id` AS `id`, `ttp`.`client_id` AS `client_id`, `ttp`.`seller_id` AS `seller_id`, `ttp`.`items` AS `items`, `ts`.`date_add` AS `date_add`, `ts`.`date_next` AS `date_next`, `ts`.`status` AS `status`, `ts`.`reason` AS `reason` FROM (SELECT `id`, `pending_id`, `customer_id`, `subscription_id`, `date_add`, `date_next`, `status`, '''' AS `reason` FROM `bx_payment_subscriptions` UNION SELECT `id`, `pending_id`, `customer_id`, `subscription_id`, `date_add`, `date_next`, ''canceled'' AS `status`, `reason` FROM `bx_payment_subscriptions_deleted`) AS `ts` LEFT JOIN `bx_payment_transactions_pending` AS `ttp` ON `ts`.`pending_id`=`ttp`.`id` WHERE 1 AND `ttp`.`type`=''recurring'' ' WHERE `object`='bx_payment_grid_sbs_list_my';
+UPDATE `sys_objects_grid` SET `source`='SELECT `ttp`.`id` AS `id`, `ttp`.`client_id` AS `client_id`, `tac`.`email` AS `client_email`, `ttp`.`seller_id` AS `seller_id`, `ttp`.`items` AS `items`, `ts`.`date_add` AS `date_add`, `ts`.`date_next` AS `date_next`, `ts`.`status` AS `status`, `ts`.`reason` AS `reason` FROM (SELECT `id`, `pending_id`, `customer_id`, `subscription_id`, `date_add`, `date_next`, `status`, '''' AS `reason` FROM `bx_payment_subscriptions` UNION SELECT `id`, `pending_id`, `customer_id`, `subscription_id`, `date_add`, `date_next`, ''canceled'' AS `status`, `reason` FROM `bx_payment_subscriptions_deleted`) AS `ts` LEFT JOIN `bx_payment_transactions_pending` AS `ttp` ON `ts`.`pending_id`=`ttp`.`id` LEFT JOIN `sys_profiles` AS `tpc` ON `ttp`.`client_id`=`tpc`.`id` LEFT JOIN `sys_accounts` AS `tac` ON `tpc`.`account_id`=`tac`.`id` WHERE 1 AND `ttp`.`type`=''recurring'' ' WHERE `object`='bx_payment_grid_sbs_list_all';
+UPDATE `sys_objects_grid` SET `source`='SELECT `tt`.`id` AS `id`, `ttp`.`client_id` AS `client_id`, `tt`.`seller_id` AS `seller_id`, `tt`.`module_id` AS `module_id`, `tt`.`item_id` AS `item_id`, `tt`.`item_count` AS `item_count`, `tt`.`amount` AS `amount`, `tt`.`currency` AS `currency`, `tt`.`date` AS `date` FROM `bx_payment_transactions` AS `tt` LEFT JOIN `bx_payment_transactions_pending` AS `ttp` ON `tt`.`pending_id`=`ttp`.`id` WHERE 1 AND `ttp`.`type`=''recurring'' ' WHERE `object`='bx_payment_grid_sbs_history';
+
+DELETE FROM `sys_grid_fields` WHERE `object`='bx_payment_grid_sbs_list_my' AND `name` IN ('customer_id', 'subscription_id', 'provider', 'items');
+INSERT INTO `sys_grid_fields` (`object`, `name`, `title`, `width`, `translatable`, `chars_limit`, `params`, `order`) VALUES
+('bx_payment_grid_sbs_list_my', 'items', '_bx_payment_grid_column_title_sbs_items', '30%', 0, '', '', 3);
+
+DELETE FROM `sys_grid_fields` WHERE `object`='bx_payment_grid_sbs_list_all' AND `name` IN ('customer_id', 'subscription_id', 'provider', 'items');
+INSERT INTO `sys_grid_fields` (`object`, `name`, `title`, `width`, `translatable`, `chars_limit`, `params`, `order`) VALUES
+('bx_payment_grid_sbs_list_all', 'items', '_bx_payment_grid_column_title_sbs_items', '15%', 0, '', '', 4);
+
+DELETE FROM `sys_grid_fields` WHERE `object`='bx_payment_grid_sbs_history' AND `name` IN ('transaction', 'license', 'item_id');
+INSERT INTO `sys_grid_fields` (`object`, `name`, `title`, `width`, `translatable`, `chars_limit`, `params`, `order`) VALUES
+('bx_payment_grid_sbs_history', 'item_id', '_bx_payment_grid_column_title_sbs_item_id', '44%', 0, '', '', 2);
+
+
+-- PRE VALUES
+DELETE FROM `sys_form_pre_lists` WHERE `key`='bx_payment_reasons_cancel';
+INSERT INTO `sys_form_pre_lists`(`key`, `title`, `module`, `use_for_sets`, `extendable`) VALUES
+('bx_payment_reasons_cancel', '_bx_payment_pre_lists_reasons_cancel', 'bx_payment', '0', '1');
+
+DELETE FROM `sys_form_pre_values` WHERE `key`='bx_payment_reasons_cancel';
+INSERT INTO `sys_form_pre_values`(`Key`, `Value`, `Order`, `LKey`, `LKey2`) VALUES
+('bx_payment_reasons_cancel', 'rc_0', 7, '_bx_payment_pre_values_rc_0', ''),
+('bx_payment_reasons_cancel', 'rc_1', 1, '_bx_payment_pre_values_rc_1', ''),
+('bx_payment_reasons_cancel', 'rc_2', 2, '_bx_payment_pre_values_rc_2', ''),
+('bx_payment_reasons_cancel', 'rc_3', 3, '_bx_payment_pre_values_rc_3', ''),
+('bx_payment_reasons_cancel', 'rc_4', 4, '_bx_payment_pre_values_rc_4', ''),
+('bx_payment_reasons_cancel', 'rc_5', 5, '_bx_payment_pre_values_rc_5', ''),
+('bx_payment_reasons_cancel', 'rc_6', 6, '_bx_payment_pre_values_rc_6', '');

+ 423 - 0
modules/boonex/payment/updates/15.0.1_15.0.2/source/classes/BxPaymentCart.php

@@ -0,0 +1,423 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Payment Payment
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+class BxPaymentCart extends BxBaseModPaymentCart
+{
+    function __construct()
+    {
+    	$this->MODULE = 'bx_payment';
+
+    	parent::__construct();
+    }
+
+    /*
+     * Service methods
+     */
+    
+    /**
+     * @page service Service Calls
+     * @section bx_payment Payment
+     * @subsection bx_payment-page_blocks Page Blocks
+     * @subsubsection bx_payment-get_block_carts get_block_carts
+     * 
+     * @code bx_srv('bx_payment', 'get_block_carts', [...], 'Cart'); @endcode
+     * 
+     * Get page block with shopping carts by vendors.
+     *
+     * @return an array describing a block to display on the site or an empty string if something is wrong. All necessary CSS and JS files are automatically added to the HEAD section of the site HTML.
+     * 
+     * @see BxPaymentCart::serviceGetBlockCarts
+     */
+    /** 
+     * @ref bx_payment-get_block_carts "get_block_carts"
+     */
+    public function serviceGetBlockCarts()
+    {
+    	$CNF = &$this->_oModule->_oConfig->CNF;
+
+        $iUserId = $this->_oModule->getProfileId();
+        if(empty($iUserId))
+            return MsgBox(_t($CNF['T']['ERR_REQUIRED_LOGIN']));
+
+        if($this->_oModule->_oConfig->isSingleSeller())
+            return MsgBox(_t($CNF['T']['MSG_SINGLE_SELLER_MODE'], $this->serviceGetCartUrl()));
+
+    	if(bx_get('seller_id') !== false)
+            return '';
+
+        $mixedContent = $this->_oModule->_oTemplate->displayBlockCarts($iUserId);
+
+        if($this->_bIsApi)
+            return [
+                bx_api_get_block('grid', $mixedContent)
+            ];
+
+        return [
+            'content' => $mixedContent
+        ];
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_payment Payment
+     * @subsection bx_payment-page_blocks Page Blocks
+     * @subsubsection bx_payment-get_block_cart get_block_cart
+     * 
+     * @code bx_srv('bx_payment', 'get_block_cart', [...], 'Cart'); @endcode
+     * 
+     * Get page block with content of selected shopping cart.
+     *
+     * @return an array describing a block to display on the site or an empty string if something is wrong. All necessary CSS and JS files are automatically added to the HEAD section of the site HTML.
+     * 
+     * @see BxPaymentCart::serviceGetBlockCart
+     */
+    /** 
+     * @ref bx_payment-get_block_cart "get_block_cart"
+     */
+    public function serviceGetBlockCart()
+    {
+        $CNF = &$this->_oModule->_oConfig->CNF;
+
+    	if(!$this->_bSingleSeller && bx_get('seller_id') === false)
+            return $this->_bIsApi ? [bx_api_get_msg('')] : '';
+
+    	$iUserId = $this->_oModule->getProfileId();
+        if(empty($iUserId))
+            return $this->_bIsApi ? [bx_api_get_msg(_t($CNF['T']['ERR_REQUIRED_LOGIN']))] : [
+            	'content' => MsgBox(_t($CNF['T']['ERR_REQUIRED_LOGIN']))
+            ];
+
+    	$iSellerId = !$this->_bSingleSeller ? bx_process_input(bx_get('seller_id'), BX_DATA_INT) : $this->_oModule->_oConfig->getSiteAdmin();
+    	if(empty($iSellerId))
+            return $this->_bIsApi ? [bx_api_get_msg(_t($CNF['T']['ERR_UNKNOWN_VENDOR']))] : [
+                'content' => MsgBox(_t($CNF['T']['ERR_UNKNOWN_VENDOR']))
+            ];
+
+        $aSeller = $this->_oModule->getProfileInfo($iSellerId);
+
+        $sTitle = _t($CNF['T']['BLOCK_TITLE_CART'], $aSeller['name']);
+        $mixedContent = $this->_oModule->_oTemplate->displayBlockCart($iUserId, $iSellerId);
+
+        if($this->_bIsApi)
+            return [
+                'title' => $sTitle,
+                'content' => [bx_api_get_block('grid', $mixedContent)]
+            ];
+
+        return [
+            'title' => $sTitle,
+            'content' => $mixedContent
+        ];
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_payment Payment
+     * @subsection bx_payment-page_blocks Page Blocks
+     * @subsubsection bx_payment-get_block_cart_history get_block_cart_history
+     * 
+     * @code bx_srv('bx_payment', 'get_block_cart_history', [...], 'Cart'); @endcode
+     * 
+     * Get page block with shopping cart history.
+     *
+     * @return an array describing a block to display on the site or an empty string if something is wrong. All necessary CSS and JS files are automatically added to the HEAD section of the site HTML.
+     * 
+     * @see BxPaymentCart::serviceGetBlockCartHistory
+     */
+    /** 
+     * @ref bx_payment-get_block_cart_history "get_block_cart_history"
+     */
+    public function serviceGetBlockCartHistory()
+    {
+        $CNF = &$this->_oModule->_oConfig->CNF;
+
+        $iSellerId = bx_get('vendor') !== false ? (int)bx_get('vendor') : 0;
+        $iUserId = $this->_oModule->getProfileId();
+        if(empty($iUserId))
+            return $this->_bIsApi ? [] : [
+                'content' => MsgBox(_t($CNF['T']['ERR_REQUIRED_LOGIN']))
+            ];
+
+        $mixedBlockContent = $this->_oModule->_oTemplate->displayBlockHistory($iUserId, $iSellerId);
+
+        if($this->_bIsApi)
+            return !$mixedBlockContent ? [] : [
+                bx_api_get_block('grid', $mixedBlockContent)
+            ];
+
+        return [
+            'content' => $mixedBlockContent,
+        ];
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_payment Payment
+     * @subsection bx_payment-purchase_processing Purchase Processing
+     * @subsubsection bx_payment-add_to_cart add_to_cart
+     * 
+     * @code bx_srv('bx_payment', 'add_to_cart', [...], 'Cart'); @endcode
+     * 
+     * Add an item described with method's params to shopping cart.
+     *
+     * @param $iSellerId integer value with seller ID.
+     * @param $mixedModuleId mixed value (ID, Name or URI) determining a module from which the action was initiated.
+     * @param $iItemId integer value with item ID.
+     * @param $iItemCount integer value with a number of items for purchasing.
+     * @param $aCustom array with custom data.
+     * @return an array with special format which describes the result of operation.
+     * 
+     * @see BxPaymentCart::serviceAddToCart
+     */
+    /** 
+     * @ref bx_payment-add_to_cart "add_to_cart"
+     */
+    public function serviceAddToCart($iSellerId, $mixedModuleId, $iItemId, $iItemCount, $aCustom = array())
+    {
+    	$CNF = &$this->_oModule->_oConfig->CNF;
+
+    	$iModuleId = $this->_oModule->_oConfig->getModuleId($mixedModuleId);
+    	$iClientId = $this->_oModule->getProfileId();
+
+    	$mixedResult = $this->_oModule->checkData($iClientId, $iSellerId, $iModuleId, $iItemId, $iItemCount, $aCustom);
+    	if($mixedResult !== true)
+    		return $mixedResult;
+
+        $aSellerProviders = $this->_oModule->_oDb->getVendorInfoProvidersSingle($iSellerId);
+        if(empty($aSellerProviders))
+            return array('code' => 5, 'message' => _t($CNF['T']['ERR_NOT_ACCEPT_PAYMENTS']));
+
+        $aCart = $this->_oModule->_oDb->getCartContent($iClientId);
+        $sCartItems = !empty($aCart['items']) ? $aCart['items'] : '';
+
+        $sCartItemsResult = false;
+        $this->_oModule->alert('before_add_to_cart', 0, $iClientId, [
+            'client_id' => $iClientId,
+            'seller_id' => $iSellerId, 
+            'module_id' => $iModuleId,
+            'item_id' => $iItemId,
+            'item_count' => $iItemCount,
+
+            'cart' => &$aCart,
+            'cart_items' => &$sCartItems,
+
+            'cart_ref' => &$aCart,
+            'cart_items_ref' => &$sCartItems,
+
+            'override_result' => &$sCartItemsResult,
+        ]);
+
+        $sCiDsc = $this->_oModule->_oConfig->descriptorA2S(array($iSellerId, $iModuleId, $iItemId));
+        if($sCartItemsResult === false) {            
+        if(strpos($sCartItems, $sCiDsc) !== false)
+                $sCartItemsResult = preg_replace_callback(
+                "/" . $this->_oModule->_oConfig->descriptorA2S(array(preg_quote($iSellerId, '/'), preg_quote($iModuleId, '/'), preg_quote($iItemId, '/'), '([0-9]+)')) . "/", function($aMatches) use($iSellerId, $iModuleId, $iItemId, $iItemCount) {
+                    return $this->_oModule->_oConfig->descriptorA2S(array($iSellerId, $iModuleId, $iItemId, $aMatches[1] + $iItemCount));
+                },
+            	$sCartItems
+            );
+        else {
+            $sCartItem = $this->_oModule->_oConfig->descriptorA2S(array($iSellerId, $iModuleId, $iItemId, $iItemCount));
+                $sCartItemsResult = empty($sCartItems) ? $sCartItem : $sCartItems . $this->_oModule->_oConfig->getDivider('DIVIDER_DESCRIPTORS') . $sCartItem;
+            }
+        }
+
+        $aCartCustom = $aCart['customs'];
+        if(!empty($aCustom) && is_array($aCustom))
+            $aCartCustom[$sCiDsc] = !empty($aCartCustom[$sCiDsc]) && is_array($aCartCustom[$sCiDsc]) ? array_merge($aCartCustom[$sCiDsc], $aCustom) : $aCustom;
+
+        $this->_oModule->_oDb->setCartItems($iClientId, $sCartItemsResult, $aCartCustom);
+
+        $aInfo = $this->getInfo(BX_PAYMENT_TYPE_SINGLE, $iClientId);
+        $iTotalQuantity = 0;
+        foreach($aInfo as $aCart)
+           $iTotalQuantity += $aCart['items_count'];
+
+        return array(
+        	'code' => 0, 
+        	'message' => _t($CNF['T']['MSG_ITEM_ADDED']), 
+        	'total_quantity' => $iTotalQuantity,
+	        //TODO: Update account submenu if it's needed.  
+        	'content' => '' //$this->_oModule->_oTemplate->displayToolbarSubmenu($aInfo)
+        );
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_payment Payment
+     * @subsection bx_payment-purchase_processing Purchase Processing
+     * @subsubsection bx_payment-delete_from_cart delete_from_cart
+     * 
+     * @code bx_srv('bx_payment', 'delete_from_cart', [...], 'Cart'); @endcode
+     * 
+     * Delete an item(s) from shopping cart.
+     *
+     * @param $iSellerId integer value with seller ID. The items owned by this seller will be removed only.
+     * @param $iModuleId (optional) integer value with module ID. If specified, the items related to this module will be removed only.
+     * @param $iItemId (optional) integer value with item ID. If specified, the item with this ID will be removed only.
+     * @return an array with special format which describes the result of operation.
+     * 
+     * @see BxPaymentCart::serviceDeleteFromCart
+     */
+    /** 
+     * @ref bx_payment-delete_from_cart "delete_from_cart"
+     */
+    public function serviceDeleteFromCart($iSellerId, $iModuleId = 0, $iItemId = 0)
+    {
+        $CNF = &$this->_oModule->_oConfig->CNF;
+
+        if($iSellerId == BX_PAYMENT_EMPTY_ID)
+            return array('code' => 1, 'message' => _t($CNF['T']['ERR_WRONG_DATA']));
+
+        $iClientId = $this->_oModule->getProfileId();
+        if(empty($iClientId))
+            return array('code' => 2, 'message' => _t($CNF['T']['ERR_REQUIRED_LOGIN']));
+
+        $aCart = $this->_oModule->_oDb->getCartContent($iClientId);
+
+        $aCartCustom = $aCart['customs'];
+        if(!empty($iModuleId) && !empty($iItemId)) {
+            $sCiDsc = $this->_oModule->_oConfig->descriptorA2S(array($iSellerId, $iModuleId, $iItemId));
+            if(!empty($aCartCustom[$sCiDsc]))
+                unset($aCartCustom[$sCiDsc]);
+        }
+        else {
+            $aCiDscs = array_keys($aCartCustom);
+            foreach($aCiDscs as $sCiDsc)
+                if(strpos($sCiDsc, $iSellerId . '_') === 0)
+                    unset($aCartCustom[$sCiDsc]);
+
+            $iModuleId = $iItemId = '[0-9\-]+';
+        }
+
+        $aCart['items'] = trim(preg_replace("'" . $this->_oModule->_oConfig->descriptorA2S(array(preg_quote($iSellerId, "'"), preg_quote($iModuleId, "'"), preg_quote($iItemId, "'"), '[0-9]+:?')) . "'", "", $aCart['items']), ":");
+        $this->_oModule->_oDb->setCartItems($iClientId, $aCart['items'], $aCartCustom);
+
+        $this->_oModule->alert('delete_from_cart', 0, 0, array(
+            'seller_id' => $iSellerId,
+            'module_id' => $iModuleId,
+            'item_id' => $iItemId,
+        ));
+
+        return array('code' => 0, 'message' => _t($CNF['T']['MSG_ITEM_DELETED']));
+    }
+
+    public function getInfo($sType, $iUserId, $iSellerId = BX_PAYMENT_EMPTY_ID, $aItems = array())
+    {
+        if($iSellerId != BX_PAYMENT_EMPTY_ID && !empty($aItems))
+            return $this->_getInfo($sType, $iUserId, $iSellerId, $this->_oModule->_oConfig->descriptorsM2A($aItems));
+
+        $aContent = $this->_parseByVendor($iUserId);
+        if($iSellerId != BX_PAYMENT_EMPTY_ID)
+            return $this->_getInfo($sType, $iUserId, $iSellerId, (isset($aContent[$iSellerId]) ? $aContent[$iSellerId] : []));
+
+        $aResult = array();
+        foreach($aContent as $iSellerId => $aSellerItems)
+            $aResult[$iSellerId] = $this->_getInfo($sType, $iUserId, $iSellerId, $aSellerItems);
+
+        return $aResult;
+    }
+
+    /**
+     * Enter description here...
+     *
+     * @param  integer $iClientId client's ID
+     * @param  integer $iSellerId vendor's ID
+     * @param  array   $aItems    item descriptors(quaternions) from shopping cart.
+     * @return array   with full info about vendor and items.
+     */
+    protected function _getInfo($sType, $iClientId, $iSellerId, $aItems)
+    {
+        $bTypeSingle = $sType == BX_PAYMENT_TYPE_SINGLE;
+
+        $iItemsCount = 0;
+        $fItemsPrice = 0;
+        $aItemsInfo = array();
+        foreach($aItems as $aItem) {
+            $aCustom = isset($aItem['custom']) ? $aItem['custom'] : [];
+
+            //--- Get item main info
+            $aItemInfo = $this->_oModule->callGetCartItem((int)$aItem['module_id'], array($aItem['item_id'], $iClientId, $aCustom));
+            if(empty($aItemInfo) || !is_array($aItemInfo)) {
+                if($bTypeSingle) {
+                    $sCartItems = $this->_oModule->_oDb->getCartItems($iClientId);
+                    $sCartItems = trim(preg_replace("'" . preg_quote($this->_oModule->_oConfig->descriptorA2S($aItem), "'") . ":?'", "", $sCartItems), ":");
+                    $this->_oModule->_oDb->setCartItems($iClientId, $sCartItems);
+                }
+
+                continue;
+            }
+
+            $aItemInfo['module_id'] = (int)$aItem['module_id'];
+            $aItemInfo['quantity'] = (int)$aItem['item_count'];
+
+            //--- Get item addons' info
+            $aItemAddons = array();
+            if(!empty($aItem['item_addons'])) {
+                $aAddons = $this->_oModule->_oConfig->s2a($aItem['item_addons']);
+                foreach($aAddons as $sAddon) {
+                    if(isset($aItemAddons[$sAddon])) {
+                        $aItemAddons[$sAddon]['quantity'] += 1;
+                        continue;
+                    }
+
+                    $aAddonInfo = $this->_oModule->callGetCartItem((int)$aItem['module_id'], array($sAddon, $iClientId, $aCustom));
+                    if(empty($aAddonInfo) || !is_array($aAddonInfo))
+                        continue;
+
+                    $aAddonInfo['module_id'] = (int)$aItem['module_id'];
+                    $aAddonInfo['quantity'] = 1;
+
+                    $aItemAddons[$sAddon] = $aAddonInfo;
+                }
+            }
+
+            $aItemInfo['addons'] = $aItemAddons;
+            $aItemsInfo[] = $aItemInfo;
+
+            //--- Update items' summary
+            $fAddonsPrice = 0;
+            foreach($aItemInfo['addons'] as $aAddonInfo)
+                $fAddonsPrice += $aAddonInfo['quantity'] * $this->_oModule->_oConfig->getPrice($sType, $aAddonInfo);
+
+            $iItemsCount += $aItemInfo['quantity'];
+            $fItemsPrice += $aItemInfo['quantity'] * ($this->_oModule->_oConfig->getPrice($sType, $aItemInfo) + $fAddonsPrice);
+        }
+
+        $aSeller = $this->_oModule->getVendorInfo((int)$iSellerId);
+        $aResult = array(
+            'client_id' => $iClientId,
+            'vendor_id' => $aSeller['id'],
+            'vendor_name' => $aSeller['name'],
+            'vendor_link' => $aSeller['link'],
+            'vendor_icon' => $aSeller['icon'],
+            'vendor_thumb' => $aSeller['thumb'],
+            'vendor_avatar' => $aSeller['avatar'],
+            'vendor_currency_code' => $aSeller['currency_code'],
+            'vendor_currency_sign' => $aSeller['currency_sign'],
+            'items_count' => $iItemsCount,
+            'items_price' => $fItemsPrice,
+            'items' => $aItemsInfo
+        );
+
+        $this->_oModule->alert('get_cart_info', 0, 0, array(
+           'type' => $sType,
+           'client_id' => $iClientId,
+           'seller_id' => $iSellerId,
+           'items' => $aItems,
+           'override_result' => &$aResult
+        ));
+
+        return $aResult;
+    }
+}
+
+/** @} */

+ 384 - 0
modules/boonex/payment/updates/15.0.1_15.0.2/source/classes/BxPaymentConfig.php

@@ -0,0 +1,384 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Payment Payment
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+class BxPaymentConfig extends BxBaseModPaymentConfig
+{
+    protected $_bExtendedMode;
+    protected $_bCreditsOnly;
+
+    protected $_iPayAttemptsMax;
+    protected $_iPayAttemptsInterval;
+
+    function __construct($aModule)
+    {
+        parent::__construct($aModule);
+
+        $sBaseUrl = BX_DOL_URL_ROOT . $this->getBaseUri();
+
+        $this->CNF = array_merge($this->CNF, [
+            // module icon
+            'ICON' => 'credit-card',
+
+            // database tables
+            'TABLE_COMMISSIONS' => $aModule['db_prefix'] . 'commissions',
+            'TABLE_INVOICES' => $aModule['db_prefix'] . 'invoices',
+
+            // page URIs
+            'URL_JOIN' => 'page.php?i=payment-join',
+            'URL_CARTS' => 'page.php?i=payment-carts',
+            'URL_CART' => 'page.php?i=payment-cart',
+            'URL_CART_CHECKOUT' => $sBaseUrl . 'initialize_checkout/' . BX_PAYMENT_TYPE_SINGLE . '/',
+            'URL_AUTHORIZE' => $sBaseUrl . 'authorize_checkout/',
+            'URL_SUBSCRIBE' => $sBaseUrl . 'subscribe/',
+            'URL_SUBSCRIBE_JSON' => $sBaseUrl . 'subscribe_json/',
+            'URL_SUBSCRIPTIONS' => 'page.php?i=payment-sbs-list-my',
+            'URL_HISTORY' => 'page.php?i=payment-history',
+            'URL_ORDERS' => 'page.php?i=payment-orders',
+            'URL_INVOICES' => 'page.php?i=payment-invoices',
+            'URL_DETAILS' => 'page.php?i=payment-details',
+            'URL_RETURN' => 'page.php?i=payment-cart-thank-you',
+            'URL_RETURN_DATA' => $sBaseUrl . 'finalize_checkout/',
+            'URL_NOTIFY' => $sBaseUrl . 'notify/',
+            'URL_CHECKOUT_OFFLINE' => 'page.php?i=payment-checkout-offline',
+
+            'KEY_ARRAY_PRICE_SINGLE' => 'price_single',
+            'KEY_ARRAY_PRICE_RECURRING' => 'price_recurring',
+            'KEY_ARRAY_PERIOD_RECURRING' => 'period_recurring',
+            'KEY_ARRAY_PERIOD_UNIT_RECURRING' => 'period_unit_recurring',
+            'KEY_ARRAY_TRIAL_RECURRING' => 'trial_recurring',
+
+            // some params
+            'PARAM_SBS_CANCEL_SURVEY' => 'bx_payment_sbs_cancel_survey',
+            'PARAM_CURRENCY_EXCHANGE_API' => 'bx_payment_currency_exchange_api',
+            'PARAM_CMSN_ENABLE' => 'bx_payment_commissions',
+            'PARAM_CMSN_INVOICE_ISSUE_DAY' => 'bx_payment_inv_issue_day', //some day of month
+            'PARAM_CMSN_INVOICE_LIFETIME' => 'bx_payment_inv_lifetime', //in days
+            'PARAM_CMSN_INVOICE_EXPIRATION_NOTIFY' => 'bx_payment_inv_expiraction_notify', //in days, before expiration date
+
+            // objects
+            'OBJECT_FORM_PRELISTS_CURRENCIES' => 'bx_payment_currencies',
+            'OBJECT_FORM_PRELISTS_REASONS_CANCEL' => 'bx_payment_reasons_cancel',
+            'OBJECT_PP_OFFLINE' => 'offline', //Offline payment provider
+            'OBJECT_PP_CREDITS' => 'credits', //Credits payment provider
+
+            'MODULE_CREDITS' => 'bx_credits',
+
+            // some language keys
+            'T' => [
+                'MSG_ITEM_ADDED' => '_bx_payment_msg_item_added',
+                'MSG_ITEM_DELETED' => '_bx_payment_msg_item_deleted',
+                'MSG_SINGLE_SELLER_MODE' => '_bx_payment_msg_single_seller',
+                'ERR_WRONG_DATA' => '_bx_payment_err_wrong_data',
+                'ERR_REQUIRED_LOGIN' => '_bx_payment_err_required_login',
+                'ERR_NOT_ACCEPT_PAYMENTS' => '_bx_payment_err_not_accept_payments',
+                'ERR_SELF_PURCHASE' => '_bx_payment_err_self_purchase',
+                'ERR_INACTIVE_VENDOR' => '_bx_payment_err_inactive_vendor',
+                'ERR_UNKNOWN_VENDOR' => '_bx_payment_err_unknown_vendor',
+
+                'BLOCK_TITLE_CART' => '_bx_payment_page_block_title_cart',
+
+                'POPUP_PROVIDERS_SELECT' => '_bx_payment_popup_title_crd_providers_select', 
+
+                'TXT_CART_PROVIDER' => '_bx_payment_txt_cart_'
+            ]
+        ]);
+
+        $this->_aHtmlIds = array(
+            'cart' => array(
+                'providers_select' => $this->_sName . '-cart-providers-select-',
+            ),
+            'history' => array(
+                'order_history_view' => $this->_sName . '-order-view-history',
+            ),
+            'subscription' => array(
+                'order_subscription_view' => $this->_sName . '-order-view-subscription',
+                'order_subscription_get_details' => $this->_sName . '-order-get-details-subscription',
+                'order_subscription_change_details' => $this->_sName . '-order-change-details-subscription',
+                'order_subscription_get_billing' => $this->_sName . '-order-get-billing-subscription',
+                'order_subscription_change_billing' => $this->_sName . '-order-change-billing-subscription',
+                'form_subscription_change_billing' => $this->_sName . '-form-change-billing-subscription',
+                'form_subscription_change_details' => $this->_sName . '-form-change-details-subscription',
+                'form_subscription_cancel_survay' => $this->_sName . '-form-cancel-subscription-survay-',
+                'popup_subscription_cancel_survay' => $this->_sName . '-popup-cancel-subscription-survay-',
+            ),
+            'pending' => array(
+                'order_pending_view' => $this->_sName . '-order-view-pending',
+                'order_pending_process' => $this->_sName . '-order-process',
+            ),
+            'processed' => array(
+                'order_processed_view' => $this->_sName . '-order-view-processed',
+                'order_processed_add' => $this->_sName . '-order-add',
+                'order_processed_client_id' => $this->_sName . '-oa-client-id',
+                'order_processed_client' => $this->_sName . '-oa-client',
+                'order_processed_items' => $this->_sName . '-oa-items',	
+            ),
+            'commission' => array(
+                'popup_add' => $this->_sName . '-commission-popup-add',
+                'popup_edit' => $this->_sName . '-commission-popup-edit',
+            ),
+            'invoice' => array(
+                'popup_edit' => $this->_sName . '-invoice-popup-edit',
+            )
+        );
+
+        $this->_aPerPage = array(
+            'orders' => 10,
+            'history' => 10
+        );
+
+        $this->_aJsClasses = array(
+            'cart' => 'BxPaymentCart',
+            'history' => 'BxPaymentOrders',
+            'subscription' => 'BxPaymentSubscriptions',
+            'pending' => 'BxPaymentOrders',
+            'processed' => 'BxPaymentOrders',
+            'chargebee_v3' => 'BxPaymentProviderChargebeeV3',
+            'stripe' => 'BxPaymentProviderStripe',
+            'stripe_v3' => 'BxPaymentProviderStripeV3'
+        );
+
+        $this->_aJsObjects = array(
+            'cart' => 'oPaymentCart',
+            'history' => 'oPaymentOrders',
+            'subscription' => 'oBxPaymentSubscriptions',
+            'pending' => 'oPaymentOrders',
+            'processed' => 'oPaymentOrders',
+            'chargebee_v3' => 'oPaymentProviderChargebeeV3',
+            'stripe' => 'oPaymentProviderStripe',
+            'stripe_v3' => 'oPaymentProviderStripeV3'
+        );
+
+        $this->_bExtendedMode = false;
+        $this->_bCreditsOnly = false;
+
+        $this->_iPayAttemptsMax = 3;
+        $this->_iPayAttemptsInterval = 86400; //--- in sec
+    }
+
+    public function init(&$oDb)
+    {
+        parent::init($oDb);
+
+        $sPrefix = $this->getPrefix('options');
+
+        $this->_bExtendedMode = $this->_oDb->getParam($sPrefix . 'extended_mode') == 'on';
+        $this->_bCreditsOnly = $this->_oDb->getParam($sPrefix . 'credits_only') == 'on';
+    }
+
+    public function isExtendedMode()
+    {
+        return $this->_bExtendedMode;
+    }
+
+    public function isCreditsOnly()
+    {
+        return $this->_bCreditsOnly;
+    }
+
+    public function getPayAttemptsMax()
+    {
+        return $this->_iPayAttemptsMax;
+    }
+
+    public function getPayAttemptsInterval()
+    {
+        return $this->_iPayAttemptsInterval;
+    }
+
+    public function getPrice($sType, $aItem, $iPrecision = 2)
+    {
+    	$fPrice = 0;
+
+        switch($sType) {
+            case BX_PAYMENT_TYPE_SINGLE:
+                $fPrice = $aItem[$this->getKey('KEY_ARRAY_PRICE_SINGLE')];
+                break;
+
+            case BX_PAYMENT_TYPE_RECURRING:
+                $fPrice = $aItem[$this->getKey('KEY_ARRAY_PRICE_RECURRING')];
+                break;
+        }
+
+        return round((float)$fPrice, $iPrecision);
+    }
+
+    public function getPeriod($sType, $aItem)
+    {
+        $mixedResult = false;
+
+        switch($sType) {
+            case BX_PAYMENT_TYPE_SINGLE:
+                break;
+
+            case BX_PAYMENT_TYPE_RECURRING:
+                $mixedResult = [$aItem[$this->getKey('KEY_ARRAY_PERIOD_RECURRING')], $aItem[$this->getKey('KEY_ARRAY_PERIOD_UNIT_RECURRING')]];
+                break;
+        }
+
+        return $mixedResult;
+    }
+
+    public function getTrial($sType, $aItem)
+    {
+        $iTrial = 0;
+
+        switch($sType) {
+            case BX_PAYMENT_TYPE_RECURRING:
+                $iTrial = $aItem[$this->getKey('KEY_ARRAY_TRIAL_RECURRING')];
+                break;
+        }
+
+        return (int)$iTrial;
+    }
+
+    public function getModuleId($mixedId)
+    {
+        if(is_numeric($mixedId))
+            return (int)$mixedId;
+
+        if(is_string($mixedId)) {
+            $aInfo = $this->_oDb->getModuleByName($mixedId);
+            if(!is_array($aInfo) || empty($aInfo['id']))
+                $aInfo = $this->_oDb->getModuleByUri($mixedId);
+
+            if(is_array($aInfo) && !empty($aInfo['id']))
+                return (int)$aInfo['id'];
+        } 
+
+        return 0;
+    }
+
+    public function a2s($a, $bEncodeString = true)
+    {
+        $s = json_encode($a);
+
+        return $bEncodeString ? base64_encode($s) : $s;
+    }
+
+    public function s2a($s, $bDecodeString = true)
+    {
+        if($bDecodeString)
+            $s = base64_decode($s);
+
+        return json_decode($s, true);
+    }
+
+    public function urlEncode($s)
+    {
+        return urlencode(base64_encode($s));
+    }
+
+    public function urlDecode($s)
+    {
+        return base64_decode(urldecode($s));
+    }
+
+    public function descriptorA2S($a) 
+    {
+    	return implode($this->getDivider('DIVIDER_DESCRIPTOR'), $a);
+    }
+
+    public function descriptorS2A($s) 
+    {
+    	return explode($this->getDivider('DIVIDER_DESCRIPTOR'), $s);
+    }
+
+    public function descriptorsA2S($a) 
+    {
+    	return implode($this->getDivider('DIVIDER_DESCRIPTORS'), $a);
+    }
+
+    /**
+     * Conver items to array with necessary structure.
+     *
+     * @param  string/array $mixed - string with cart items divided with (:) or an array of cart items.
+     * @return array        with items.
+     */
+    public function descriptorsM2A($mixed)
+    {
+        $aResults = array();
+
+        if(is_string($mixed))
+           $aItems = explode($this->getDivider('DIVIDER_DESCRIPTORS'), $mixed);
+        else if(is_array($mixed))
+           $aItems = $mixed;
+        else
+            $aItems = array();
+
+        foreach($aItems as $mixedItem) {
+            $aItem = is_array($mixedItem) ? $mixedItem : $this->descriptorS2A($mixedItem);
+
+            $aResult = array('vendor_id' => $aItem[0], 'module_id' => $aItem[1], 'item_id' => $aItem[2], 'item_count' => $aItem[3]);
+            if(isset($aItem[4]))
+                $aResult['item_addons'] = $aItem[4];
+
+            $aResults[] = $aResult;
+        }
+
+        return $aResults;
+    }
+
+    public function putCustom($mDsc, $aCustom, &$aCustoms)
+    {
+        if(empty($aCustom) || !is_array($aCustom))
+            return;
+
+        if(is_array($mDsc))
+            $mDsc = $this->descriptorA2S(array_slice($mDsc, 0, 3));
+
+        $aCustoms[$mDsc] = !empty($aCustoms[$mDsc]) && is_array($aCustoms[$mDsc]) ? array_merge($aCustoms[$mDsc], $aCustom) : $aCustom;
+    }
+
+    public function getCustom($mDsc, &$aCustoms)
+    {
+        if(is_array($mDsc))
+            $mDsc = $this->descriptorA2S(array_slice($mDsc, 0, 3));
+
+        if(empty($aCustoms) || !is_array($aCustoms) || empty($aCustoms[$mDsc]))
+            return array();
+
+        return $aCustoms[$mDsc];
+    }
+
+    public function pullCustom($mDsc, &$aCustoms)
+    {
+        if(is_array($mDsc))
+            $mDsc = $this->descriptorA2S(array_slice($mDsc, 0, 3));
+
+        if(empty($aCustoms) || !is_array($aCustoms) || empty($aCustoms[$mDsc]))
+            return array();
+
+        $aResult = $aCustoms[$mDsc];
+        unset($aCustoms[$mDsc]);           
+
+        return $aResult;
+    }
+
+    public function http2https($s)
+    {
+    	if(strncmp($s, 'https://', 8) === 0)
+    		return $s;
+
+        return 'https://' . bx_ltrim_str($s, 'http://');
+    }
+
+    public function sortByColumn($sColumn, &$aValues)
+    {
+        return usort($aValues, function($aV1, $aV2) use ($sColumn) {
+            if($aV1[$sColumn] == $aV2[$sColumn])
+                return 0;
+
+            return $aV1[$sColumn] < $aV2[$sColumn] ? -1 : 1;
+        });
+    }
+}
+
+/** @} */

+ 912 - 0
modules/boonex/payment/updates/15.0.1_15.0.2/source/classes/BxPaymentDb.php

@@ -0,0 +1,912 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Payment Payment
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+class BxPaymentDb extends BxBaseModPaymentDb
+{
+    function __construct(&$oConfig)
+    {
+        parent::__construct($oConfig);
+    }
+
+    public function getModulesWithPayments()
+    {
+    	$sQuery = $this->prepare("SELECT `name` FROM `" . $this->_sPrefix . "modules`");
+        return $this->getColumn($sQuery);
+    }
+
+    /**
+     * Payment details methods
+     */
+    public function getForm($sPaymentProvider = '')
+    {
+        $sWhereClause = '';
+
+        if(!empty($sPaymentProvider))
+            $sWhereClause .= $this->prepareAsString(" AND `tp`.`name`=?", $sPaymentProvider);
+        
+        $sQuery = "SELECT
+                `tp`.`id` AS `provider_id`,
+                `tp`.`name` AS `provider_name`,
+                `tp`.`caption` AS `provider_caption`,
+                `tp`.`description` AS `provider_description`,
+                `tp`.`option_prefix` AS `provider_option_prefix`,
+                `tp`.`for_owner_only` AS `provider_for_owner_only`,
+                `tp`.`single_seller` AS `provider_single_seller`,
+                `tpo`.`id` AS `id`,
+                `tpo`.`name` AS `name`,
+                `tpo`.`type` AS `type`,
+                `tpo`.`value` AS `value`,
+                `tpo`.`caption` AS `caption`,
+                `tpo`.`description` AS `description`,
+                `tpo`.`extra` AS `extra`,
+                `tpo`.`check_type` AS `check_type`,
+                `tpo`.`check_params` AS `check_params`,
+                `tpo`.`check_error` AS `check_error`,
+                `tpo`.`extended` AS `extended`
+            FROM `" . $this->_sPrefix . "providers` AS `tp`
+            LEFT JOIN `" . $this->_sPrefix . "providers_options` AS `tpo` ON `tp`.`id`=`tpo`.`provider_id`
+            WHERE `tp`.`active`='1'" . $sWhereClause . "
+            ORDER BY `tp`.`order` ASC, `tpo`.`order` ASC";
+
+        return $this->getAll($sQuery);
+    }
+
+    public function getProviders($aParams = array())
+    {
+    	$aMethod = array('name' => 'getAll', 'params' => array(0 => 'query'));
+
+        $sWhereClause = $sOrderClause = "";
+        if(!empty($aParams['type']))
+            switch($aParams['type']) {
+                case 'by_name':
+                    $aMethod['name'] = 'getRow';
+                    $aMethod['params'][1] = array(
+                        'name' => $aParams['name']
+                    );
+
+                    $sWhereClause = " AND `tp`.`name`=:name";
+                    break;
+
+                case 'for_single':
+                    $aMethod['name'] = 'getAllWithKey';
+                    $aMethod['params'][1] = 'name';
+
+                    $sWhereClause = " AND `tp`.`for_single`='1'";
+                    if(!empty($aParams['active'])) 
+                        $sWhereClause .= " AND `tp`.`active`='1'";
+
+                    if(isset($aParams['order']) && $aParams['order'] === true)
+                        $sOrderClause = "`tp`.`order` ASC";
+                    break;
+
+                case 'for_recurring':
+                    $aMethod['name'] = 'getAllWithKey';
+                    $aMethod['params'][1] = 'name';
+
+                    $sWhereClause = " AND `tp`.`for_recurring`='1'";
+                    if(!empty($aParams['active'])) 
+                        $sWhereClause .= " AND `tp`.`active`='1'";
+
+                    if(isset($aParams['order']) && $aParams['order'] === true)
+                        $sOrderClause = "`tp`.`order` ASC";
+                    break;
+
+                case 'all':
+                    $aMethod['name'] = 'getAllWithKey';
+                    $aMethod['params'][1] = 'name';
+
+                    if(!empty($aParams['active'])) 
+                        $sWhereClause = " AND `tp`.`active`='1'";
+
+                    if(isset($aParams['order']) && $aParams['order'] === true)
+                        $sOrderClause = "`tp`.`order` ASC";
+                    break;
+            }
+
+        if(!empty($sOrderClause))
+            $sOrderClause = " ORDER BY " . $sOrderClause;
+                
+        $aMethod['params'][0] = "SELECT
+                `tp`.`id` AS `id`,
+                `tp`.`name` AS `name`,
+                `tp`.`caption` AS `caption`,
+                `tp`.`description` AS `description`,
+                `tp`.`option_prefix` AS `option_prefix`,
+                `tp`.`for_visitor` AS `for_visitor`,
+                `tp`.`for_single` AS `for_single`,
+                `tp`.`for_recurring` AS `for_recurring`,
+                `tp`.`class_name` AS `class_name`,
+                `tp`.`class_file` AS `class_file`
+            FROM `" . $this->_sPrefix . "providers` AS `tp`
+            WHERE 1" . $sWhereClause . $sOrderClause;
+
+        return call_user_func_array(array($this, $aMethod['name']), $aMethod['params']);
+    }
+
+    public function getOption($aParams)
+    {
+        $aMethod = array('name' => 'getAll', 'params' => array(0 => 'query'));
+
+        $sSelectClause = "`tpo`.*";
+        $sJoinClause = $sWhereClause = "";
+        if(!empty($aParams['type']))
+	        switch($aParams['type']) {
+                    case 'by_pid_and_name':
+                        $aMethod['name'] = 'getRow';
+                        $aMethod['params'][1] = array(
+                            'provider_id' => $aParams['provider_id'],
+                            'name' => $aParams['name'],
+                        );
+
+                        $sWhereClause = " AND `tpo`.`provider_id`=:provider_id AND `tpo`.`name`=:name";
+                        break;
+                }
+
+        $aMethod['params'][0] = "SELECT " . $sSelectClause . " FROM `" . $this->_sPrefix . "providers_options` AS `tpo` " . $sJoinClause . " WHERE 1" . $sWhereClause;
+
+        return call_user_func_array(array($this, $aMethod['name']), $aMethod['params']);
+    }
+
+    public function getOptions($iUserId = BX_PAYMENT_EMPTY_ID, $iProviderId = 0)
+    {
+        $aBinding = [
+            'user_id' => $iUserId
+        ];
+
+        if($iUserId == BX_PAYMENT_EMPTY_ID && empty($iProviderId))
+           return $this->getAll("SELECT `id`, `name`, `type` FROM `" . $this->_sPrefix . "providers_options`");
+
+        $sWhereAddon = "";
+        if(!empty($iProviderId)) {
+            $aBinding['provider_id'] = $iProviderId;
+
+            $sWhereAddon = " AND `tpo`.`provider_id`=:provider_id";
+        }
+
+        $sQuery = "SELECT
+               `tpo`.`name` AS `name`,
+               `tuv`.`value` AS `value`
+            FROM `" . $this->_sPrefix . "providers_options` AS `tpo`
+            LEFT JOIN `" . $this->_sPrefix . "user_values` AS `tuv` ON `tpo`.`id`=`tuv`.`option_id`
+            WHERE 1" . $sWhereAddon . " AND `tuv`.`user_id`=:user_id ORDER BY `tpo`.`order`";
+
+        return $this->getAllWithKey($sQuery, 'name', $aBinding);
+    }
+
+    public function getOptionsByProvider($mixedProvider)
+    {
+        $aBindings = [
+            'provider' => $mixedProvider
+        ];
+
+        $sJoinClause = $sWhereClause = '';
+        if(!is_numeric($mixedProvider)) {
+            $sJoinClause = " LEFT JOIN `" . $this->_sPrefix . "providers` AS `tp` ON `tpo`.`provider_id`=`tp`.`id`";
+            $sWhereClause = " AND `tp`.`name`=:provider";
+        }
+        else
+            $sWhereClause = " AND `tpo`.`provider_id`=:provider";
+
+        return $this->getAll("SELECT `tpo`.`id`, `tpo`.`name`, `tpo`.`type` FROM `" . $this->_sPrefix . "providers_options` AS `tpo`" . $sJoinClause . " WHERE 1" . $sWhereClause, $aBindings);
+    }
+
+    public function updateOption($iUserId, $iOptionId, $sValue)
+    {
+        $sQuery = $this->prepare("REPLACE INTO `" . $this->_sPrefix . "user_values` SET `user_id`=?, `option_id`=?, `value`=?", $iUserId, $iOptionId, $sValue);
+        return $this->query($sQuery);
+    }
+
+    public function getCurrencyExchangeRate($sCode)
+    {
+        return $this->getOne("SELECT `rate` FROM `" . $this->_sPrefix . "currencies` WHERE `code`=:code LIMIT 1", [
+            'code' => $sCode
+        ]);
+    }
+
+    public function updateCurrencyExchangeRate($sCode, $fRate)
+    {
+        return $this->query("INSERT INTO `" . $this->_sPrefix . "currencies`(`code`, `rate`) VALUES(:code, :rate) ON DUPLICATE KEY UPDATE `rate`=:rate", [
+            'code' => $sCode,
+            'rate' => $fRate
+        ]);
+    }
+
+    public function deleteCurrencyExchangeRate($sCode)
+    {
+        return $this->query("DELETE FROM `" . $this->_sPrefix . "currencies` WHERE `code`=:code", [
+            'code' => $sCode
+        ]) !== false;
+    }
+
+    /**
+     * Shopping cart methods.
+     */
+    public function getCartItems($iId)
+    {
+    	$sQuery = $this->prepare("SELECT `items` FROM `" . $this->_sPrefix . "cart` WHERE `client_id`=? LIMIT 1", $iId);
+        return $this->getOne($sQuery);
+    }
+
+    public function getCartContent($iId)
+    {
+        $aCart = $this->getRow("SELECT * FROM `" . $this->_sPrefix . "cart` WHERE `client_id`=:client_id LIMIT 1", [
+            'client_id' => $iId
+        ]);
+
+        if(empty($aCart) || !is_array($aCart))
+            $aCart = ['items' => '', 'customs' => []];
+
+        if(!empty($aCart['customs']))
+            $aCart['customs'] = is_string($aCart['customs']) ? $this->_oConfig->s2a($aCart['customs'], false) : $aCart['customs'];
+        else 
+            $aCart['customs'] = [];
+
+        return $aCart;
+    }
+
+    public function setCartItems($iId, $sItems, $aCustoms = array())
+    {
+        $sItems = trim($sItems, ":");
+        if(empty($sItems))
+            return $this->query("DELETE FROM `" . $this->_sPrefix . "cart` WHERE `client_id`=:client_id LIMIT 1", array(
+                'client_id' => $iId
+            ));
+
+        return $this->query("REPLACE INTO `" . $this->_sPrefix . "cart` SET `client_id`=:client_id, `items`=:items, `customs`=:customs", array(
+            'client_id' => $iId,
+            'items' => $sItems,
+            'customs' => !empty($aCustoms) && is_array($aCustoms) ? $this->_oConfig->a2s($aCustoms, false) : ''
+        ));
+    }
+
+    public function getVendorInfoProvidersSingle($iVendorId, $bActiveOnly = false)
+    {
+        $aParams = ['type' => 'for_single', 'order' => true];
+        if($bActiveOnly)
+            $aParams['active'] = true;
+        
+    	return $this->getVendorInfoProviders($iVendorId, $aParams);
+    }
+
+    public function getVendorInfoProvidersRecurring($iVendorId, $bActiveOnly = false)
+    {
+        $aParams = ['type' => 'for_recurring', 'order' => true];
+        if($bActiveOnly)
+            $aParams['active'] = true;
+        
+    	return $this->getVendorInfoProviders($iVendorId, $aParams);
+    }
+
+    public function getVendorInfoProviders($iVendorId, $aParams = [])
+    {
+        if(empty($aParams))
+            $aParams = ['type' => 'all', 'order' => true];
+
+        $aProviders = $this->getProviders($aParams);
+        $aOptions = $this->getOptions($iVendorId);
+
+        $aResult = [];
+        foreach($aProviders as $sProvider => $aProvider) {
+            if(!isset($aOptions[$aProvider['option_prefix'] . 'active']) || !in_array($aOptions[$aProvider['option_prefix'] . 'active']['value'], ['on', 1]))
+                continue;
+
+            if(isset($aOptions[$aProvider['option_prefix'] . 'hidden']) && in_array($aOptions[$aProvider['option_prefix'] . 'hidden']['value'], ['on', 1]))
+                continue;
+
+            foreach($aOptions as $sName => $aOption)
+                if(strpos($sName, $aProvider['option_prefix']) !== false)
+                    $aProvider['options'][$sName] = $aOption;
+
+            $aResult[$sProvider] = $aProvider;
+        }
+
+        return $aResult;
+    }
+
+    public function getAdminsIds()
+    {
+        $sQuery = "SELECT 
+        		`tp`.`id` AS `id`,
+        		`tp`.`type` AS `type`  
+        	FROM `sys_profiles` AS `tp` 
+        	INNER JOIN `sys_accounts` AS `ta` ON `tp`.`account_id`=`ta`.`id` AND `ta`.`role`&" . BX_DOL_ROLE_ADMIN . " 
+        	WHERE 
+        		`tp`.`type`<>'system' AND `tp`.`status`='active' 
+        	ORDER BY `tp`.`id` ASC";
+
+        $aAdmins = $this->getAllWithKey($sQuery, 'id');
+        foreach($aAdmins as $iId => $aAdmin)
+            if(!BxDolService::call($aAdmin['type'], 'act_as_profile'))
+                unset($aAdmins[$iId]);
+
+        return array_keys($aAdmins);
+    }
+
+
+	/*
+     * Pending Orders methods
+     */
+    public function getOrderPending($aParams)
+    {
+    	$aMethod = array('name' => 'getRow', 'params' => array(0 => 'query'));
+
+    	$sWhereClause = $sLimitClause = '';
+        switch($aParams['type']) {
+            case 'id':
+            	$aMethod['params'][1] = array(
+                	'id' => $aParams['id']
+                );
+
+                $sWhereClause = " AND `id`=:id";
+                $sLimitClause = " LIMIT 1";
+                break;
+
+            case 'order':
+            	$aMethod['params'][1] = array(
+                	'order' => $aParams['order']
+                );
+
+            	$sWhereClause = " AND `order`=:order";
+                $sLimitClause = " LIMIT 1";
+                break;
+
+            case 'mixed':
+                $aMethod['name'] = 'getAll';
+
+                $sWhereClause = ' AND ' . $this->arrayToSQL($aParams['conditions'], ' AND ');
+                break;
+        }
+
+        $aMethod['params'][0] = "SELECT * FROM `" . $this->_sPrefix . "transactions_pending` WHERE 1 " . $sWhereClause . $sLimitClause;
+        return call_user_func_array(array($this, $aMethod['name']), $aMethod['params']);
+    }
+
+    public function insertOrderPending($iClientId, $sType, $sProvider, $aCartInfo, $aCustom = [])
+    {
+        $sItems = "";
+        foreach($aCartInfo['items'] as $aItem) {
+            $sItems .= $this->_oConfig->descriptorA2S(array($aItem['author_id'], $aItem['module_id'], $aItem['id'], $aItem['quantity'])) . ':';
+
+            if(empty($aItem['addons']) || !is_array($aItem['addons']))
+                continue;
+
+            foreach($aItem['addons'] as $sAddon => $aAddon)
+                $sItems .= $this->_oConfig->descriptorA2S(array($aAddon['author_id'], $aAddon['module_id'], $aAddon['id'], $aAddon['quantity'])) . ':';
+        }
+
+        $sCurrency = $aCartInfo['vendor_currency_code'];
+        $sCurrencyDefault = $this->_oConfig->getDefaultCurrencyCode();
+
+        $aData = ['cur_def' => $sCurrencyDefault];
+        if(strcmp($sCurrency, $sCurrencyDefault) != 0)
+            $aData['cur_rate'] = $this->getCurrencyExchangeRate($sCurrency);
+
+        $aSet = [
+            'client_id' => $iClientId,
+            'seller_id' => $aCartInfo['vendor_id'],
+            'type' => $sType, 
+            'provider' => $sProvider,
+            'items' => trim($sItems, ':'),
+            'customs' => !empty($aCustom) && is_array($aCustom) ? $this->_oConfig->a2s($aCustom, false) : '',
+            'amount' => $aCartInfo['items_price'],
+            'currency' => $sCurrency,
+            'data' => !empty($aData) ? serialize($aData) : ''
+        ];
+
+        return (int)$this->query("INSERT INTO `" . $this->_sPrefix . "transactions_pending` SET " . $this->arrayToSQL($aSet) . ", `date`=UNIX_TIMESTAMP()") > 0 ? $this->lastId() : 0;
+    }
+
+    public function updateOrderPending($iId, $aValues)
+    {
+        $sQuery = $this->prepare("UPDATE `" . $this->_sPrefix . "transactions_pending` SET " . $this->arrayToSQL($aValues) . " WHERE `id`=?", $iId);
+        return (int)$this->query($sQuery) > 0;
+    }
+
+    public function deleteOrderPending($mixedId)
+    {
+    	if(!is_array($mixedId))
+    		$mixedId = array($mixedId);
+
+        return (int)$this->query("DELETE FROM `" . $this->_sPrefix . "transactions_pending` WHERE `id` IN (" . $this->implode_escape($mixedId) . ")") > 0;
+    }
+
+    /*
+     * Processed Orders
+     */
+    public function getOrderProcessed($aParams)
+    {
+    	$aMethod = array('name' => 'getRow', 'params' => array(0 => 'query'));
+
+        $sSelectClause = "`tt`.`id`, `tt`.`license`, `ttp`.`type`, `tt`.`client_id`, `tt`.`seller_id`, `tt`.`author_id`, `tt`.`module_id`, `tt`.`item_id`, `tt`.`item_count`, `tt`.`amount`, `tt`.`date`, `ttp`.`order`, `ttp`.`error_msg`, `ttp`.`provider`";
+        $sWhereClause = $sGroupClause = "";
+
+        switch($aParams['type']) {
+            case 'id':
+            	$aMethod['params'][1] = array(
+                    'id' => $aParams['id']
+                );
+
+                $sWhereClause = " AND `tt`.`id`=:id";
+                break;
+
+            case 'new':
+                $aMethod['name'] = 'getAll';
+                $aMethod['params'][1] = array(
+                    'seller_id' => $aParams['seller_id']
+                );
+
+                $sWhereClause = " AND `tt`.`seller_id`=:seller_id AND `tt`.`new`='1'";
+                break;
+
+            case 'pending_id':
+                if(empty($aParams['with_key'])) {
+                    $aMethod['name'] = 'getAll';
+                    $aMethod['params'][1] = array(
+                        'pending_id' => $aParams['pending_id']
+                    );
+                }
+                else {
+                    $aMethod['name'] = 'getAllWithKey';
+                    $aMethod['params'][1] = $aParams['with_key'];
+                    $aMethod['params'][2] = array(
+                        'pending_id' => $aParams['pending_id']
+                    );
+                }
+
+                $sWhereClause = " AND `tt`.`pending_id`=:pending_id";
+                break;
+
+            case 'clients':
+                $aMethod['name'] = 'getColumn';
+                $aMethod['params'][1] = array(
+                    'seller_id' => $aParams['seller_id']
+                );
+
+                $sSelectClause = "DISTINCT `tt`.`client_id`";
+                $sWhereClause = " AND `tt`.`seller_id`=:seller_id";
+                break;
+
+            case 'authors':
+                $aMethod['name'] = 'getColumn';
+                $aMethod['params'][1] = array(
+                    'seller_id' => $aParams['seller_id']
+                );
+
+                $sSelectClause = "DISTINCT `tt`.`author_id`";
+                $sWhereClause = " AND `tt`.`seller_id`=:seller_id";
+                break;
+
+            case 'license':
+                $aMethod['name'] = 'getAll';
+                $aMethod['params'][1] = array(
+                    'license' => $aParams['license']
+                );
+
+                $sWhereClause = " AND `tt`.`license`=:license";
+                break;
+            
+            case 'income':
+                $aMethod['name'] = 'getAll';
+                $aMethod['params'][1] = array(
+                    'period_start' => $aParams['period_start'],
+                    'period_end' => $aParams['period_end']
+                );
+
+                $sSelectClause = '`tt`.`author_id` AS `id`, SUM(`tt`.`amount`) AS `amount`';
+                $sWhereClause = ' AND `tt`.`date`>=:period_start AND `tt`.`date`<=:period_end';
+                $sGroupClause = '`tt`.`author_id`';
+                break;
+
+            case 'mixed':
+                $aMethod['name'] = 'getAll';
+
+                $sWhereClause = ' AND ' . $this->arrayToSQL($aParams['conditions'], ' AND ');
+                break;
+
+        }
+
+        if(!empty($sGroupClause))
+            $sGroupClause = ' GROUP BY ' . $sGroupClause;
+
+        $aMethod['params'][0] = "SELECT
+                " . $sSelectClause . "
+            FROM `" . $this->_sPrefix . "transactions` AS `tt`
+            LEFT JOIN `" . $this->_sPrefix . "transactions_pending` AS `ttp` ON `tt`.`pending_id`=`ttp`.`id`
+            WHERE 1" . $sWhereClause . $sGroupClause;
+
+        return call_user_func_array(array($this, $aMethod['name']), $aMethod['params']);
+    }
+
+    public function insertOrderProcessed($aValues)
+    {
+        return $this->query("INSERT INTO `" . $this->_sPrefix . "transactions` SET " . $this->arrayToSQL($aValues) . ", `date`=UNIX_TIMESTAMP()");
+    }
+
+    public function updateOrderProcessed($iId, $aValues)
+    {        
+        return $this->updateOrdersProcessed($aValues, array('id' => $iId));
+    }
+
+    public function updateOrdersProcessed($aValues, $aWhere)
+    {
+        if(empty($aValues) || !is_array($aValues) || empty($aWhere) || !is_array($aWhere))
+            return false;
+
+        return (int)$this->query("UPDATE `" . $this->_sPrefix . "transactions` SET " . $this->arrayToSQL($aValues) . " WHERE " . $this->arrayToSQL($aWhere, ' AND ')) > 0;
+    }
+
+    public function deleteOrderProcessed($mixedId)
+    {
+    	if(!is_array($mixedId))
+            $mixedId = array($mixedId);
+
+        return (int)$this->query("DELETE FROM `" . $this->_sPrefix . "transactions` WHERE `id` IN (" . $this->implode_escape($mixedId) . ")") > 0;
+    }
+
+    public function getOrderHistory($aParams)
+    {
+        return $this->getOrderProcessed($aParams);
+    }
+
+    /*
+     * Subscriptions methods
+     */
+    public function getOrderSubscription($aParams)
+    {
+        $aResult = $this->getOrderPending($aParams);
+
+        if(($iPendingId = $aParams['id'] ?? 0)) {
+            $aSubscription = $this->getSubscription(['type' => 'pending_id', 'pending_id' => $iPendingId]);
+            if(!$aSubscription || !is_array($aSubscription))
+                $aSubscription = $this->getSubscription(['type' => 'pending_id', 'pending_id' => $iPendingId, 'from_deleted' => true]);
+
+            if($aSubscription && is_array($aSubscription))
+                $aResult = array_merge($aResult, [
+                    'customer_id' => $aSubscription['customer_id'],
+                    'deleted' => $aSubscription['deleted'] ?? false,
+                    'deleted_reason' => $aSubscription['reason'] ?? '',
+                ]);
+        }
+
+        return $aResult;
+    }
+
+    public function getSubscription($aParams)
+    {
+    	$aMethod = array('name' => 'getAll', 'params' => array(0 => 'query'));
+
+        $sTable = $this->_sPrefix . 'subscriptions';
+        if(($sK = 'from_deleted') && isset($aParams[$sK]) && $aParams[$sK])
+            $sTable .= '_deleted';
+
+        $sSelectClause = "`ts`.*";
+    	$sJoinClause = $sWhereClause = $sLimitClause = '';
+        switch($aParams['type']) {
+            case 'pending_id':
+                $aMethod['name'] = 'getRow';
+            	$aMethod['params'][1] = array(
+                    'pending_id' => $aParams['pending_id']
+                );
+
+                $sWhereClause = " AND `ts`.`pending_id`=:pending_id";
+                $sLimitClause = " LIMIT 1";
+                break;
+
+            case 'mixed':
+                $sWhereClause = " AND " . $this->arrayToSQL($aParams['conditions'], ' AND ');
+                break;
+
+            case 'mixed_ext':
+                $sSelectClause .= ", `ttp`.`client_id`, `ttp`.`seller_id`, `ttp`.`type`, `ttp`.`provider`, `ttp`.`order`";
+                $sJoinClause = "LEFT JOIN `" . $this->_sPrefix . "transactions_pending` AS `ttp` ON `ts`.`pending_id`=`ttp`.`id`";
+                $sWhereClause = " AND " . $this->arrayToSQL($aParams['conditions'], ' AND ');
+                break;
+
+            case 'time_tracker':
+                $aMethod['params'][1] = array(
+                    'status_active' => $aParams['status_active'],
+                    'status_trial' => $aParams['status_trial'],
+                    'status_unpaid' => $aParams['status_unpaid'],
+                    'pay_attempts_max' => $aParams['pay_attempts_max'],
+                    'pay_attempts_interval' => $aParams['pay_attempts_interval']
+                );
+
+                $sSelectClause .= ", `ttp`.`client_id`, `ttp`.`seller_id`, `ttp`.`type`, `ttp`.`provider`, `ttp`.`amount`, `ttp`.`order`";
+                $sJoinClause = "LEFT JOIN `" . $this->_sPrefix . "transactions_pending` AS `ttp` ON `ts`.`pending_id`=`ttp`.`id` INNER JOIN `" . $this->_sPrefix . "providers` AS `tp` ON `ttp`.`provider`=`tp`.`name` AND `tp`.`time_tracker`='1'";
+                $sWhereClause = " AND `ts`.`date_next`<>0 AND `ts`.`date_next`<=UNIX_TIMESTAMP() AND (`ts`.`status`=:status_active OR `ts`.`status`=:status_trial OR (`ts`.`status`=:status_unpaid AND `ts`.`pay_attempts`<:pay_attempts_max AND DATE_ADD(FROM_UNIXTIME(`ts`.`date_next`), INTERVAL `ts`.`pay_attempts`*:pay_attempts_interval SECOND)<=NOW()))";
+                break;
+        }
+
+        $aMethod['params'][0] = "SELECT " . $sSelectClause . " FROM `" . $sTable . "` AS `ts` " . $sJoinClause . " WHERE 1 " . $sWhereClause . $sLimitClause;
+        return call_user_func_array(array($this, $aMethod['name']), $aMethod['params']);
+    }
+
+    public function isSubscriptionByPending($iPending)
+    {
+    	$aSubscription = $this->getSubscription(array(
+            'type' => 'pending_id', 
+            'pending_id' => $iPending
+    	));
+
+    	return !empty($aSubscription) && is_array($aSubscription);
+    }
+
+    public function insertSubscription($aValues)
+    {
+        if(empty($aValues) || !is_array($aValues))
+            return false;
+
+        $sSetClause = $this->arrayToSQL($aValues);
+        if(empty($aValues['date_add']))
+            $sSetClause .= ", `date_add`=UNIX_TIMESTAMP()";
+
+        return (int)$this->query("INSERT INTO `" . $this->_sPrefix . "subscriptions` SET " . $sSetClause) > 0;
+    }
+
+    public function updateSubscription($aValues, $aWhere)
+    {
+        if(empty($aValues) || !is_array($aValues) || empty($aWhere) || !is_array($aWhere))
+            return false;
+
+        return (int)$this->query("UPDATE `" . $this->_sPrefix . "subscriptions` SET " . $this->arrayToSQL($aValues) . " WHERE " . $this->arrayToSQL($aWhere, ' AND ')) > 0;
+    }
+
+    public function deleteSubscription($mixedId, $sReason)
+    {
+    	if(!is_array($mixedId))
+            $mixedId = array($mixedId);
+
+        //--- Move to deleted subscriptions table.   
+    	$sQuery = "INSERT IGNORE INTO `" . $this->_sPrefix . "subscriptions_deleted` SELECT *, :reason AS `reason`, UNIX_TIMESTAMP() AS `deleted` FROM `" . $this->_sPrefix . "subscriptions` WHERE `id` IN (" . $this->implode_escape($mixedId) . ")";
+        $this->query($sQuery, array(
+            'reason' => $sReason
+        ));
+
+        return (int)$this->query("DELETE FROM `" . $this->_sPrefix . "subscriptions` WHERE `id` IN (" . $this->implode_escape($mixedId) . ")") > 0;
+    }
+
+    //--- Order Administration ---//
+    public function onProfileDelete($iId)
+    {
+    	$sQuery = $this->prepare("DELETE FROM `" . $this->_sPrefix . "cart` WHERE `client_id`=?", $iId);
+    	$this->query($sQuery);
+
+    	$sQuery = $this->prepare("DELETE FROM `" . $this->_sPrefix . "user_values` WHERE `user_id`=?", $iId);
+    	$this->query($sQuery);
+    }
+
+
+    /*
+     * Commissions methods
+     */
+    public function getCommissions($aParams = array())
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+    	$aMethod = array('name' => 'getAll', 'params' => array(0 => 'query'));
+
+        $sSelectClause = "`tc`.*";
+        $sWhereClause = $sOrderClause = "";
+        if(!empty($aParams['type']))
+            switch($aParams['type']) {
+                case 'max_order':
+                    $aMethod['name'] = 'getOne';
+                    $aMethod['params'][1] = array();
+
+                    $sSelectClause = "IFNULL(MAX(`tc`.`order`), 0)";
+                    break;
+
+                case 'id':
+                    $aMethod['name'] = 'getRow';
+                    $aMethod['params'][1] = array(
+                        'id' => $aParams['id']
+                    );
+
+                    $sWhereClause = " AND `tc`.`id`=:id";
+                    break;
+
+                case 'acl_id':
+                    $aMethod['name'] = 'getAll';
+                    $aMethod['params'][1] = array(
+                        'acl_id' => $aParams['acl_id']
+                    );
+
+                    $sWhereClause = " AND (`tc`.`acl_id`=:acl_id OR `tc`.`acl_id`=0)";
+                    $sOrderClause = "`tc`.`order` ASC";
+                    break;
+
+                case 'all':
+                    if(!empty($aParams['active'])) 
+                        $sWhereClause = " AND `tc`.`active`='1'";
+                    break;
+            }
+
+        if(!empty($sOrderClause))
+            $sOrderClause = " ORDER BY " . $sOrderClause;
+
+        $aMethod['params'][0] = "SELECT " . $sSelectClause . "
+            FROM `" . $CNF['TABLE_COMMISSIONS'] . "` AS `tc`
+            WHERE 1" . $sWhereClause . $sOrderClause;
+
+        return call_user_func_array(array($this, $aMethod['name']), $aMethod['params']);
+    }
+
+    public function getInvoices($aParams = array())
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+    	$aMethod = array('name' => 'getAll', 'params' => array(0 => 'query'));
+
+        $sSelectClause = "`ti`.*";
+        $sWhereClause = "";
+        if(!empty($aParams['type']))
+            switch($aParams['type']) {
+                case 'index':
+                    $aMethod['name'] = 'getOne';
+                    $aMethod['params'][1] = array(
+                        'commissionaire_id' => $aParams['commissionaire_id'],
+                        'committent_id' => $aParams['committent_id'],
+                    );
+
+                    $sSelectClause = "COUNT(`ti`.`id`) + 1";
+                    $sWhereClause = " AND `ti`.`commissionaire_id`=:commissionaire_id AND `ti`.`committent_id`=:committent_id";
+                    break;
+
+                case 'id':
+                    $aMethod['name'] = 'getRow';
+                    $aMethod['params'][1] = array(
+                        'id' => $aParams['id']
+                    );
+
+                    $sWhereClause = " AND `ti`.`id`=:id";
+                    break;
+
+                case 'commissionaire_id':
+                    $aMethod['params'][1] = array(
+                        'commissionaire_id' => $aParams['commissionaire_id']
+                    );
+
+                    $sWhereClause = " AND `ti`.`commissionaire_id`=:commissionaire_id";
+                    break;
+
+                case 'committent_id':
+                    $aMethod['params'][1] = array(
+                        'committent_id' => $aParams['committent_id']
+                    );
+
+                    $sWhereClause = " AND `ti`.`committent_id`=:committent_id";
+
+                    if(!empty($aParams['period_start'])) {
+                        $aMethod['params'][1]['period_start'] = (int)$aParams['period_start'];
+
+                        $sWhereClause .= " AND `ti`.`period_start`=:period_start";
+                    }
+
+                    if(!empty($aParams['period_end'])) {
+                        $aMethod['params'][1]['period_end'] = (int)$aParams['period_end'];
+
+                        $sWhereClause .= " AND `ti`.`period_end`=:period_end";
+                    }
+                    break;
+
+                case 'expiring':
+                    $aMethod['params'][1] = array(
+                        'notify_days' => $this->_oConfig->getInvoiceExpirationNotify(),
+                        'status' => BX_PAYMENT_INV_STATUS_UNPAID
+                    );
+
+                    $sWhereClause = " AND DATE_SUB(FROM_UNIXTIME(`ti`.`date_due`), INTERVAL :notify_days DAY) < NOW() AND DATE_SUB(FROM_UNIXTIME(`ti`.`date_due`), INTERVAL (:notify_days - 1) DAY) > NOW() AND `ti`.`status`=:status";
+                    break;
+
+                case 'overdue':
+                    $aMethod['params'][1] = array(
+                        'status_unpaid' => BX_PAYMENT_INV_STATUS_UNPAID,
+                        'status_overdue' => BX_PAYMENT_INV_STATUS_OVERDUE
+                    );
+
+                    $sWhereClause = " AND `ti`.`date_due` < UNIX_TIMESTAMP() AND (`ti`.`status`=:status_unpaid OR (`ti`.`status`=:status_overdue AND `ti`.`ntf_due`='0'))";
+                    break;
+
+                case 'status':
+                    $aMethod['params'][1] = array(
+                        'status' => $aParams['status']
+                    );
+
+                    $sWhereClause = " AND `ti`.`status`=:status";
+                    
+                    if(isset($aParams['count']) && $aParams['count'] === true) {
+                        $sSelectClause = "COUNT(`ti`.`id`)";
+                        $aMethod['name'] = 'getOne';
+                    }
+
+                    if(isset($aParams['committent_id'])) {
+                        $aMethod['params'][1]['committent_id'] = $aParams['committent_id'];
+
+                        $sWhereClause .= " AND `ti`.`committent_id`=:committent_id";
+                    }
+                    break;
+
+                case 'all_count':
+                    $sSelectClause = "COUNT(`ti`.`id`)";
+                    $aMethod['name'] = 'getOne';
+                    break;
+                
+                case 'all':
+                    break;
+            }
+
+        $aMethod['params'][0] = "SELECT " . $sSelectClause . "
+            FROM `" . $CNF['TABLE_INVOICES'] . "` AS `ti`
+            WHERE 1" . $sWhereClause;
+
+        return call_user_func_array(array($this, $aMethod['name']), $aMethod['params']);
+    }
+
+    public function insertInvoice($aValues)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        return $this->query("INSERT INTO `" . $CNF['TABLE_INVOICES'] . "` SET " . $this->arrayToSQL($aValues));
+    }
+
+    public function updateInvoice($mixedId, $aValues)
+    {
+        $CNF = &$this->_oConfig->CNF;
+        
+        if(!is_array($mixedId))
+            $mixedId = array($mixedId);
+
+        return (int)$this->query("UPDATE `" . $CNF['TABLE_INVOICES'] . "` SET " . $this->arrayToSQL($aValues) . " WHERE `id` IN (" . $this->implode_escape($mixedId) . ')') > 0;
+    }
+
+    public function deleteInvoice($mixedId)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+    	if(!is_array($mixedId))
+            $mixedId = array($mixedId);
+
+        return (int)$this->query("DELETE FROM `" . $CNF['TABLE_INVOICES'] . "` WHERE `id` IN (" . $this->implode_escape($mixedId) . ")") > 0;
+    }
+    
+    /**
+     * For Stripe integration only
+     */
+    public function getStrpPaymentPending($sSubscriptionId)
+    {
+        $aResult = $this->getRow("SELECT * FROM `" . $this->_sPrefix . "stripe_payments_pending` WHERE `subscription_id`=:subscription_id", [
+            'subscription_id' => $sSubscriptionId
+        ]);
+
+        if(!empty($aResult) && is_array($aResult))
+            $this->deleteStrpPaymentPending($sSubscriptionId);
+
+        return $aResult;
+    }
+
+    public function insertStrpPaymentPending($sSubscriptionId, $fAmount, $sCurrency)
+    {
+        return $this->query("INSERT IGNORE INTO `" . $this->_sPrefix . "stripe_payments_pending` SET " . $this->arrayToSQL([
+            'subscription_id' => $sSubscriptionId,
+            'amount' => $fAmount,
+            'currency' => $sCurrency
+        ])) !== false;
+    }
+
+    public function deleteStrpPaymentPending($sSubscriptionId)
+    {
+        return $this->query("DELETE FROM `" . $this->_sPrefix . "stripe_payments_pending` WHERE `subscription_id`=:subscription_id", [
+            'subscription_id' => $sSubscriptionId
+        ]) !== false;
+    }
+}
+
+/** @} */

+ 130 - 0
modules/boonex/payment/updates/15.0.1_15.0.2/source/classes/BxPaymentDetails.php

@@ -0,0 +1,130 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Payment Payment
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+class BxPaymentDetails extends BxBaseModPaymentDetails
+{
+    protected $_bIsApi;
+    protected $_sLangsPrefix;
+
+    function __construct()
+    {
+        $this->MODULE = 'bx_payment';
+
+        parent::__construct();
+
+        $this->_bIsApi = bx_is_api();
+        $this->_sLangsPrefix = $this->_oModule->_oConfig->getPrefix('langs');
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_payment Payment
+     * @subsection bx_payment-page_blocks Page Blocks
+     * @subsubsection bx_payment-get_block_details get_block_details
+     * 
+     * @code bx_srv('bx_payment', 'get_block_details', [...], 'Details'); @endcode
+     * 
+     * Get page block with payment providers' configuration settings represented as subforms.
+     *
+     * @return an array describing a block to display on the site. All necessary CSS and JS files are automatically added to the HEAD section of the site HTML.
+     * 
+     * @see BxPaymentDetails::serviceGetBlockDetails
+     */
+    /** 
+     * @ref bx_payment-get_block_details "get_block_details"
+     */
+    public function serviceGetBlockDetails($iUserId = BX_PAYMENT_EMPTY_ID, $mixedPaymentProvider = false)
+    {
+        if(!$this->_oModule->isLogged())
+            return ($sMsg = $this->_sLangsPrefix . 'err_required_login') && $this->_bIsApi ? [bx_api_get_msg($sMsg)] : MsgBox(_t($sMsg));
+
+        $iUserId = $iUserId != BX_PAYMENT_EMPTY_ID ? $iUserId : $this->_oModule->getProfileId();
+
+        $aPaymentProviders = [];
+        if(!$mixedPaymentProvider) {
+            $aPaymentProviders = $this->_oModule->_oDb->getProviders([
+                'type' => 'all', 
+                'active' => true, 
+                'order' => true
+            ]);
+
+            if(!empty($aPaymentProviders) && is_array($aPaymentProviders))
+                $aPaymentProviders = array_keys($aPaymentProviders);
+        }
+        else {
+            if(is_array($mixedPaymentProvider))
+                $aPaymentProviders = $mixedPaymentProvider;
+            else if(is_string($mixedPaymentProvider))
+                $aPaymentProviders = [$mixedPaymentProvider];
+        }
+
+        if(!$aPaymentProviders)
+            return ($sMsg = $this->_sLangsPrefix . 'msg_no_results') && $this->_bIsApi ? [bx_api_get_msg($sMsg)] : MsgBox(_t($sMsg));
+
+        $mixedContent = $this->_bIsApi ? [] : '';
+        foreach($aPaymentProviders as $iIndex => $sPaymentProvider) {
+            $mixedForm = $this->getForm($iUserId, $sPaymentProvider);
+
+            if($this->_bIsApi)
+                $mixedContent[] = bx_api_get_block('form', $mixedForm, [
+                    'id' => $iIndex + 1,
+                    'ext' => [
+                        'name' => $mixedForm['attrs']['name'] ?? $this->MODULE,
+                        'request' => ['url' => '/api.php?r=' . $this->MODULE . '/get_block_details/Details', 'immutable' => true]
+                    ]
+                ]);
+            else
+                $mixedContent .= $this->_oModule->_oTemplate->parseHtmlByName('details_form.html', [
+                    'provider' => str_replace('_', '-', $sPaymentProvider),
+                    'form' => $mixedForm
+                ]);
+        }
+
+        if(empty($mixedContent))
+            return ($sMsg = $this->_sLangsPrefix . 'msg_no_results') && $this->_bIsApi ? [bx_api_get_msg($sMsg)] : MsgBox(_t($sMsg));
+
+        return $this->_bIsApi ? $mixedContent : $mixedContent;
+    }
+
+    public function getForm($iProfileId, $sPaymentProvider)
+    {
+        $CNF = &$this->_oModule->_oConfig->CNF;
+
+        $oForm = BxTemplFormView::getObjectInstance($CNF['OBJECT_FORM_DETAILES'], $CNF['OBJECT_FORM_DETAILES_EDIT']);
+        $oForm->initWithParams($iProfileId, $sPaymentProvider);
+        $oForm->initChecker();
+        if($oForm->isSubmitted()) {
+            if($oForm->isValid()) {
+                $aOptions = $this->_oModule->_oDb->getOptionsByProvider($sPaymentProvider);
+                foreach($aOptions as $aOption) {
+                    $sValue = bx_get($aOption['name']) !== false ? bx_get($aOption['name']) : '';
+                    $this->_oModule->_oDb->updateOption($iProfileId, $aOption['id'], bx_process_input($sValue));
+                }
+
+                if(!$this->_bIsApi) {
+                    header('Location: ' . bx_absolute_url(BxDolPermalinks::getInstance()->permalink('page.php?i=payment-details', ['pp' => $sPaymentProvider])));
+                    return;
+                }
+            }
+            else
+                foreach($oForm->aInputs as $aInput)
+                    if(!empty($aInput['error']) && !empty($aInput['attrs']['bx-data-provider'])) {
+                        $sProviderBlock = 'provider_' . (int)$aInput['attrs']['bx-data-provider'] . '_begin';
+                        if(!empty($oForm->aInputs[$sProviderBlock]))
+                            $oForm->aInputs[$sProviderBlock]['collapsed'] = false;
+                    }
+        }
+
+        return $this->_bIsApi ? $oForm->getCodeAPI() : $oForm->getCode();
+    }
+}
+
+/** @} */

+ 210 - 0
modules/boonex/payment/updates/15.0.1_15.0.2/source/classes/BxPaymentFormDetails.php

@@ -0,0 +1,210 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Payment Payment
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+class BxPaymentDetailsFormCheckerHelper extends BxDolFormCheckerHelper
+{
+    function checkHttps ($s)
+    {
+        return empty($s) || substr(BX_DOL_URL_ROOT, 0, 5) == 'https';
+    }
+}
+
+class BxPaymentFormDetails extends BxTemplFormView
+{
+    protected $_sModule;
+    protected $_oModule;
+
+    protected $_sLangsPrefix;
+    protected $_bCollapseFirst;
+    
+    protected $_iProfileId;
+    protected $_sPaymentProvider;
+
+    function __construct($aInfo, $oTemplate = false)
+    {
+        parent::__construct($aInfo, $oTemplate);
+
+        $this->_sModule = 'bx_payment';
+        $this->_oModule = BxDolModule::getInstance($this->_sModule);
+
+        $this->_sLangsPrefix = $this->_oModule->_oConfig->getPrefix('langs');
+        $this->_bCollapseFirst = true;
+        
+        $this->_iProfileId = $this->_oModule->getProfileId();
+        $this->_sPaymentProvider = '';
+    }
+
+    public function setProfileId($iProfileId = BX_PAYMENT_EMPTY_ID)
+    {
+        if($iProfileId != BX_PAYMENT_EMPTY_ID)
+            $this->_iProfileId = $iProfileId;
+    }
+
+    public function setPaymentProvider($sPaymentProvider)
+    {
+        $this->_sPaymentProvider = $sPaymentProvider;
+
+        $this->aParams['db']['submit_name'] = $this->_getSubmitName();
+
+        $sName = $this->_getName();
+        $this->setId($sName);
+        $this->setName($sName);
+    }
+
+    public function init()
+    {
+        $this->aInputs = [];
+                
+        $aInputs = $this->_oModule->_oDb->getForm($this->_sPaymentProvider);
+        if(empty($aInputs))
+            return false;
+
+        $bSiteAdmin = $this->_oModule->_oConfig->isSiteAdmin();
+        $bExtendedMode = $this->_oModule->_oConfig->isExtendedMode();
+        $bSingleSeller = $this->_oModule->_oConfig->isSingleSeller();
+
+        $bCollapsed = $this->_bCollapseFirst;
+        $iProvider = 0;
+        $sProvider = "";
+        $oProvider = null;
+        foreach($aInputs as $aInput) {
+            if((int)$aInput['provider_for_owner_only'] != 0 && !$bSiteAdmin)
+                continue;
+
+            if((int)$aInput['provider_single_seller'] == 0 && $bSingleSeller)
+                continue;
+
+            if($iProvider != $aInput['provider_id']) {
+                $sBlockHeaderName = 'provider_' . $aInput['provider_id'] . '_begin';
+                $this->aInputs[$sBlockHeaderName] = array(
+                    'type' => 'block_header',
+                    'name' => $sBlockHeaderName,
+                    'caption' => _t($aInput['provider_caption']),
+                    'info' => _t($aInput['provider_description']),
+                    'collapsable' => true,
+                    'collapsed' => ($sSelected = bx_get('pp')) !== false && $sSelected == $aInput['provider_name'] ? false : $bCollapsed
+                );
+
+                $iProvider = $aInput['provider_id'];
+                $sProvider = $aInput['provider_name'];
+                $oProvider = $this->_oModule->getObjectProvider($sProvider, $this->_iProfileId);
+                $bCollapsed = true;
+            }
+
+            $mixedValue = $oProvider->getOption($aInput['name']);
+            if(!$bExtendedMode && ($iInpExt = (int)$aInput['extended']) != BX_PAYMENT_POPT_EXT_NONE)
+                $this->aInputs[$aInput['name']] = [
+                    'type' => 'hidden',
+                    'name' => $aInput['name'],
+                    'value' => $mixedValue !== false && $iInpExt == BX_PAYMENT_POPT_EXT_SAVE ? $mixedValue : $aInput['value'],
+                    'attrs' => [
+                        'bx-data-provider' => $iProvider
+                    ]
+                ];
+            else
+                $this->aInputs[$aInput['name']] = [
+                    'type' => $aInput['type'],
+                    'name' => $aInput['name'],
+                    'caption' => _t($aInput['caption']),
+                    'value' => $mixedValue !== false ? $mixedValue : '',
+                    'info' => _t($aInput['description']),
+                    'attrs' => [
+                        'bx-data-provider' => $iProvider
+                    ],
+                    'checker' => [
+                        'func' => $aInput['check_type'],
+                        'params' => $aInput['check_params'],
+                        'error' => _t($aInput['check_error']),
+                    ]
+                ];
+
+            //--- Make some field dependent actions ---//
+            $aAddon = [];
+            switch($this->aInputs[$aInput['name']]['type']) {
+                case 'select':
+                    if(empty($aInput['extra']))
+                       break;
+
+                    $aAddon = ['values' => []];
+
+                    if(BxDolService::isSerializedService($aInput['extra']))
+                        $aAddon['values'] = BxDolService::callSerialized($aInput['extra']);
+                    else {
+                        $aPairs = explode(',', $aInput['extra']);
+                        foreach($aPairs as $sPair) {
+                            $aPair = explode('|', $sPair);
+                            $aAddon['values'][] = ['key' => $aPair[0], 'value' => _t($aPair[1])];
+                        }
+                    }
+                    break;
+
+                case 'checkbox':
+                    if(in_array($this->aInputs[$aInput['name']]['value'], ['on', 1]))
+                        $aAddon = ['checked' => true];
+
+                    $this->aInputs[$aInput['name']]['value'] = $this->_bIsApi ? 1 : 'on';
+                    break;
+
+                case 'value':
+                       $sMethod = 'get' . bx_gen_method_name(str_replace($aInput['provider_option_prefix'], '', $aInput['name']));
+                       if(method_exists($oProvider, $sMethod))
+                            $this->aInputs[$aInput['name']]['value'] = $oProvider->$sMethod($this->_iProfileId);
+                       break;
+
+                case 'custom':
+                    $sMethod = 'get' . bx_gen_method_name(str_replace($aInput['provider_option_prefix'], '', $aInput['name']));
+                    if(method_exists($oProvider, $sMethod)) {
+                        $mixedContent = $oProvider->$sMethod($this->_iProfileId);
+                        if(is_array($mixedContent))
+                            $this->aInputs[$aInput['name']] = array_merge($this->aInputs[$aInput['name']], $mixedContent);
+                        else
+                            $this->aInputs[$aInput['name']]['content'] = $mixedContent;
+                    }
+                    break;
+            }
+
+            if(!empty($aAddon) && is_array($aAddon))
+                $this->aInputs[$aInput['name']] = array_merge($this->aInputs[$aInput['name']], $aAddon);
+        }
+
+        $sSubmitName = $this->_getSubmitName();
+        $this->aInputs[$sSubmitName] = [
+            'type' => 'submit',
+            'name' => $sSubmitName,
+            'value' => _t($this->_sLangsPrefix . 'form_details_input_do_submit'),
+        ];
+
+        $this->aInputs['provider_' . $iProvider . '_end'] = [
+            'type' => 'block_end'
+        ];
+
+        return true;
+    }
+
+    public function initWithParams($iProfileId, $sPaymentProvider)
+    {
+        $this->setProfileId($iProfileId);
+        $this->setPaymentProvider($sPaymentProvider);
+        $this->init();
+    }
+
+    protected function _getName()
+    {
+        return $this->_sModule . '_form_details' . ($this->_sPaymentProvider ? '_' . $this->_sPaymentProvider : '');
+    }
+
+    protected function _getSubmitName()
+    {
+        return 'submit' . ($this->_sPaymentProvider ? '_' . $this->_sPaymentProvider : '');
+    }
+}
+
+/** @} */

+ 334 - 0
modules/boonex/payment/updates/15.0.1_15.0.2/source/classes/BxPaymentGridCart.php

@@ -0,0 +1,334 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Payment Payment
+ * @ingroup     UnaModules
+ * 
+ * @{
+ */
+
+
+class BxPaymentGridCart extends BxBaseModPaymentGridCarts
+{
+    public function __construct ($aOptions, $oTemplate = false)
+    {
+    	$this->MODULE = 'bx_payment';
+
+        parent::__construct ($aOptions, $oTemplate);
+
+        $this->_bSelectAll = true;
+    }
+    
+    public function getCodeAPI($bForceReturn = false)
+    {
+        $aData = parent::getCodeAPI($bForceReturn);
+        $aData['settings']['field_id'] = 'id';
+        foreach ($aData['data'] as &$aRow){
+            $aRow['id'] = $aRow['checkbox']['data'];
+            $aRow['title']['value'] = strip_tags($aRow['title']['value']);
+            $aRow['price_single']['value'] = str_replace('&#36; ','$', $aRow['price_single']['value']);
+            
+        }
+        return $aData;
+    }
+
+    public function performActionQuantitySub()
+    {
+        $sId = $this->_getItemId();
+        list($iVendorId, $iModuleId, $iItemId, $iItemCount) = $this->_oModule->_oConfig->descriptorS2A($sId);
+
+        if($iItemCount == 1)
+            return echoJson([]);
+        
+        $aResult = $this->_oModule->getObjectCart()->serviceAddToCart($iVendorId, $iModuleId, $iItemId, -1);
+        if($aResult['code'] != 0 && isset($aResult['message']))
+            return echoJson(['msg' => $aResult['message']]);
+
+        return echoJson(['grid' => $this->getCode(false), 'blink' => $sId]);
+    }
+
+    public function performActionQuantityAdd()
+    {
+        $sId = $this->_getItemId();
+        list($iVendorId, $iModuleId, $iItemId, $iItemCount) = $this->_oModule->_oConfig->descriptorS2A($sId);
+
+        $aResult = $this->_oModule->getObjectCart()->serviceAddToCart($iVendorId, $iModuleId, $iItemId, 1);
+        if($aResult['code'] != 0 && isset($aResult['message']))
+            return echoJson(['msg' => $aResult['message']]);
+
+        return echoJson(['grid' => $this->getCode(false), 'blink' => $sId]);
+    }
+
+    public function performActionCheckout()
+    {
+    	$aParams = array(
+            'seller_id' => bx_process_input(bx_get('seller_id'), BX_DATA_INT), 
+            'provider' => bx_process_input(bx_get('provider')), 
+            'items' => bx_process_input(bx_get('ids'))
+    	);
+
+    	if(empty($aParams['seller_id']) || empty($aParams['provider']))
+            return echoJson(array());
+
+        if(empty($aParams['items']) || !is_array($aParams['items'])) 
+            return echoJson(array('msg' => _t('_bx_payment_err_nothing_selected')));
+
+        $oProvider = $this->_oModule->getObjectProvider($aParams['provider'], $aParams['seller_id']);
+        if($oProvider !== false) {
+            if(method_exists($oProvider, 'overwriteCheckoutParamsSingle'))
+                return echoJson($oProvider->overwriteCheckoutParamsSingle($aParams, $this));
+
+            if(method_exists($oProvider, 'getCheckoutParamsSingle'))
+                $aParams = $oProvider->getCheckoutParamsSingle($aParams, $this);
+        }
+
+        echoJson(array(
+            'eval' => $this->_oModule->_oConfig->getJsObject('cart') . '.onCartCheckout(oData);', 
+            'link' => bx_append_url_params($this->_oModule->_oConfig->getUrl('URL_CART_CHECKOUT'), $aParams)
+        ));
+    }
+
+    protected function _getCellTitle($mixedValue, $sKey, $aField, $aRow)
+    {
+        if(!$this->_bIsApi)
+            $mixedValue = $this->_oModule->_oTemplate->displayLink('link', array(
+                'href' => $aRow['url'],
+                'title' => bx_html_attribute($aRow['title']),
+                'content' => $aRow['title']
+            ));
+
+    	return parent::_getCellDefault($mixedValue, $sKey, $aField, $aRow);
+    }
+
+    protected function _getCellPriceSingle($mixedValue, $sKey, $aField, $aRow)
+    {
+        return parent::_getCellDefault(_t_format_currency_ext($mixedValue, ['sign' => $this->_sCurrencySign]), $sKey, $aField, $aRow);
+    }
+
+    protected function _getCellQuantity($mixedValue, $sKey, $aField, $aRow)
+    {
+        if(!$this->_bIsApi)
+            $mixedValue = $this->_oModule->_oTemplate->parseHtmlByName('cart_quantity.html', [
+                'sub' => $this->_getActionQuantity('sub', $aRow),
+                'quantity' => $mixedValue,
+                'add' => $this->_getActionQuantity('add', $aRow)
+            ]);
+
+        return parent::_getCellDefault($mixedValue, $sKey, $aField, $aRow);
+    }
+
+    protected function _getActionQuantitySub ($sType, $sKey, $a, $isSmall = false, $isDisabled = false, $aRow = array())
+    {
+        return '';
+    }
+
+    protected function _getActionQuantityAdd ($sType, $sKey, $a, $isSmall = false, $isDisabled = false, $aRow = array())
+    {
+        return '';
+    }
+
+    protected function _getActionQuantity($sAction, &$aRow)
+    {
+        $sAction = 'quantity_' . $sAction;
+        $aAction = array_merge($this->_aOptions['actions_single'][$sAction], ['attr' => [
+            'bx_grid_action_single' => $sAction,
+            'bx_grid_action_data' => $aRow[$this->_aOptions['field_id']],
+            'bx_grid_action_confirm' => $this->_aOptions['actions_single'][$sAction]['confirm'],
+            'bx_grid_action_reset_paginate' => 0
+        ]]);
+
+        return $this->_getActionDefault('single', $sAction, $aAction, false, false, $aRow);
+    }
+
+    protected function _getActionCheckout ($sType, $sKey, $a, $isSmall = false, $isDisabled = false, $aRow = array())
+    {
+        return '';
+    }
+
+    protected function _getActions ($sType, $sActionData = false, $isSmall = false, $isDisabled = false, $isPermanentState = false, $aRow = array())
+    {
+    	$CNF = &$this->_oModule->_oConfig->CNF;
+
+    	$sActions = '';
+    	if($sType == 'bulk' && !empty($this->_aQueryAppend['seller_id'])) {
+            $sActionName = 'checkout';
+
+            $iClientId = (int)$this->_aQueryAppend['client_id'];
+            $iSellerId = (int)$this->_aQueryAppend['seller_id'];
+            $aCartInfo = $this->_oModule->getObjectCart()->getInfo(BX_PAYMENT_TYPE_SINGLE, $iClientId, $iSellerId);
+
+            $bCreditsOnly = $this->_oModule->_oConfig->isCreditsOnly();
+
+            $bPayForCredits = true;
+            if(!empty($aCartInfo['items']) && is_array($aCartInfo['items']))
+                foreach($aCartInfo['items'] as $aItem) {
+                    $aModule = $this->_oModule->_oDb->getModuleById((int)$aItem['module_id']);
+                    if($aModule['name'] != $CNF['MODULE_CREDITS']) {
+                        $bPayForCredits = false;
+                        break;
+                    }
+                }
+
+            $aProviders = $this->_oModule->_oDb->getVendorInfoProvidersSingle($iSellerId);
+            foreach($aProviders as $aProvider) {
+                $bProviderCredits = $aProvider['name'] == $CNF['OBJECT_PP_CREDITS'];
+
+                /*
+                 * Hide all non-Credits payment providers when 'credits only' mode is enabled 
+                 * and purchasing items aren't credits.
+                 */
+                if($bCreditsOnly && !$bProviderCredits && !$bPayForCredits)
+                    continue;
+
+                /*
+                 * Hide Credits payment provider when paying for credits.
+                 */
+                if($bProviderCredits && $bPayForCredits)
+                    continue;
+
+                $sAction = $this->_getActionDefault($sType, $sActionName, array(
+                    'title'=> _t('_bx_payment_grid_action_title_crt_checkout', _t($CNF['T']['TXT_CART_PROVIDER'] . $aProvider['name'])),
+                    'icon' => '',
+                    'icon_only' => 0,
+                    'confirm' => 0,
+                    'attr' => array(
+                        'bx_grid_action_' . $sType => $sActionName,
+                        'bx_grid_action_append' => json_encode(array('provider' => $aProvider['name'])),
+                        'bx_grid_action_confirm' => 0,
+                        'bx_grid_action_reset_paginate' => 0,
+                    )
+                ), $isSmall, $isDisabled, $aRow);
+
+                $oProvider = $this->_oModule->getObjectProvider($aProvider['name'], $iSellerId);
+                if($oProvider !== false && method_exists($oProvider, 'getButtonSingle')) {
+                    $aParams = array(
+                        'sObjNameGrid' => $this->getObject(),
+                        'aCartInfo' => $aCartInfo,
+                        'sAction' => $sAction
+                    );
+
+                    if(!empty($aCartInfo['items_price']) && !empty($aCartInfo['items']) && is_array($aCartInfo['items'])) {
+                        $aTitles = array();
+                        foreach ($aCartInfo['items'] as $aItem)
+                            $aTitles[] = $aItem['title'];
+
+                        $aParams = array_merge($aParams, array(
+                            'iAmount' => (int)round(100 * (float)$aCartInfo['items_price']),
+                            'sItemTitle' => implode(', ', $aTitles)
+                        ));
+                    }
+
+                    $mixedButton = $oProvider->getButtonSingle($iClientId, $iSellerId, $aParams);
+                    if($mixedButton !== false)
+                        $sAction = $mixedButton;
+                }
+
+                $sActions .= $sAction;
+            }
+    	}else{
+           if (bx_is_api())
+               return parent::_getActions ($sType, $sActionData, $isSmall, $isDisabled, $isPermanentState, $aRow);
+        }
+
+        
+    	return $sActions . parent::_getActions ($sType, $sActionData, $isSmall, $isDisabled, $isPermanentState, $aRow);
+    }
+
+    protected function _getActionsAPI($sType)
+    {
+        if($sType != 'bulk' || empty($this->_aQueryAppend['seller_id']))
+            return parent::_getActionsAPI($sType);
+
+        $CNF = &$this->_oModule->_oConfig->CNF;
+
+        $iClientId = (int)$this->_aQueryAppend['client_id'];
+        $iSellerId = (int)$this->_aQueryAppend['seller_id'];
+        $aCartInfo = $this->_oModule->getObjectCart()->getInfo(BX_PAYMENT_TYPE_SINGLE, $iClientId, $iSellerId);
+
+        $bCreditsOnly = $this->_oModule->_oConfig->isCreditsOnly();
+
+        $bPayForCredits = true;
+        if(!empty($aCartInfo['items']) && is_array($aCartInfo['items']))
+            foreach($aCartInfo['items'] as $aItem) {
+                $aModule = $this->_oModule->_oDb->getModuleById((int)$aItem['module_id']);
+                if($aModule['name'] != $CNF['MODULE_CREDITS']) {
+                    $bPayForCredits = false;
+                    break;
+                }
+            }
+
+        $aActions = [];
+        $aProviders = $this->_oModule->_oDb->getVendorInfoProvidersSingle($iSellerId);
+        foreach($aProviders as $aProvider) {
+            $bProviderCredits = $aProvider['name'] == $CNF['OBJECT_PP_CREDITS'];
+
+            /*
+             * Hide all non-Credits payment providers when 'credits only' mode is enabled 
+             * and purchasing items aren't credits.
+             */
+            if($bCreditsOnly && !$bProviderCredits && !$bPayForCredits)
+                continue;
+
+            /*
+             * Hide Credits payment provider when paying for credits.
+             */
+            if($bProviderCredits && $bPayForCredits)
+                continue;
+
+            $aActions[$aProvider['name']] = [
+                'name' => $aProvider['name'],
+                'title'=> _t('_bx_payment_grid_action_title_crt_checkout', _t($CNF['T']['TXT_CART_PROVIDER'] . $aProvider['name'])),
+                'icon' => '',
+                'icon_only' => 0,
+                'confirm' => 0,
+            ];
+        }
+        return $aActions;
+    }    
+
+    protected function _getDataArray($sFilter, $sOrderField, $sOrderDir, $iStart, $iPerPage)
+    {
+        if(empty($this->_aQueryAppend['client_id']) || empty($this->_aQueryAppend['seller_id']))
+            return array();
+
+        $aCart = $this->_oCart->getInfo(BX_PAYMENT_TYPE_SINGLE, $this->_aQueryAppend['client_id'], $this->_aQueryAppend['seller_id']);
+        if(empty($aCart) || empty($aCart['items']) || !is_array($aCart['items']))
+            return array();
+
+        $this->_aOptions['source'] = array();
+        foreach($aCart['items'] as $aCartItem) {
+            $this->_aOptions['source'][] = array_merge($aCartItem, [
+                'descriptor' => $this->_oModule->_oConfig->descriptorA2S(array($aCartItem['author_id'], $aCartItem['module_id'], $aCartItem['id'], $aCartItem['quantity'])),
+                'description' => strip_tags($aCartItem['description']),
+                'currency_code' => $aCart['vendor_currency_code'],
+                'currency_sign' => $aCart['vendor_currency_sign']
+            ]);
+        }
+
+        return parent::_getDataArray($sFilter, $sOrderField, $sOrderDir, $iStart, $iPerPage);
+    }
+
+    protected function _delete($mixedId)
+    {
+    	list($iVendorId, $iModuleId, $iItemId) = $this->_oModule->_oConfig->descriptorS2A($mixedId);
+    	if(!$this->_oModule->isSingleSeller() && (int)$iVendorId != (int)$this->_aQueryAppend['seller_id'])
+            return false;
+
+    	return $this->_oCart->serviceDeleteFromCart($iVendorId, $iModuleId, $iItemId);
+    }
+
+    protected function _getItemId()
+    {
+        if(($aIds = bx_get('ids')) && is_array($aIds)) 
+            return array_shift($aIds);
+
+        if(($sId = bx_get('id')))
+            return $sId;
+
+        return false;
+    }
+}
+
+/** @} */

+ 115 - 0
modules/boonex/payment/updates/15.0.1_15.0.2/source/classes/BxPaymentGridSbsAdministration.php

@@ -0,0 +1,115 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Payment Payment
+ * @ingroup     UnaModules
+ * 
+ * @{
+ */
+
+
+class BxPaymentGridSbsAdministration extends BxBaseModPaymentGridTransactions
+{
+    protected $_iNow;
+    protected $_sManageType;
+
+    public function __construct ($aOptions, $oTemplate = false)
+    {
+    	$this->MODULE = 'bx_payment';
+
+        parent::__construct ($aOptions, $oTemplate);
+
+        $this->_iNow = time();
+        $this->_sOrdersType = BX_PAYMENT_ORDERS_TYPE_SUBSCRIPTION;
+        $this->_sManageType = 'administration';
+    }
+
+    public function performActionCancel()
+    {
+    	$aIds = bx_get('ids');
+        if(!$aIds || !is_array($aIds)) 
+            return echoJson(array());
+
+        $oSubscriptions = $this->_oModule->getObjectSubscriptions();
+
+        $iAffected = 0;
+        $aAffected = array();
+        foreach($aIds as $iId)
+            if($oSubscriptions->cancel($iId)) {
+                $aAffected[] = $iId;
+            	$iAffected++;
+            }
+
+        echoJson($iAffected ? array('grid' => $this->getCode(false), 'blink' => $aAffected) : array('msg' => _t($this->_sLangsPrefix . 'err_cannot_perform')));
+    }
+
+    protected function _getCellProvider($mixedValue, $sKey, $aField, $aRow)
+    {
+        return parent::_getCellDefault(_t('_bx_payment_txt_name_' . $mixedValue), $sKey, $aField, $aRow);
+    }
+
+    protected function _getCellSubscriptionId($mixedValue, $sKey, $aField, $aRow)
+    {
+        $aItems = $this->_oModule->_oConfig->descriptorsM2A($aRow['items']);
+        if(!is_array($aItems) || count($aItems) != 1)
+            return parent::_getCellDefault($mixedValue, $sKey, $aField, $aRow);
+
+        $aItem = array_shift($aItems);
+        $aInfo = BxDolService::call((int)$aItem['module_id'], 'get_payment_data');
+        if(!empty($aInfo['url_browse_order_' . $this->_sManageType]))
+            $mixedValue = $this->_oModule->_oTemplate->displayLink('link', array(
+                'href' => bx_replace_markers($aInfo['url_browse_order_' . $this->_sManageType], array(
+                    'order' => $mixedValue
+                )),
+                'title' => bx_html_attribute($mixedValue),
+                'content' => $mixedValue
+            ));
+
+        return parent::_getCellDefault($mixedValue, $sKey, $aField, $aRow);
+    }
+
+    protected function _getCellDateAdd($mixedValue, $sKey, $aField, $aRow)
+    {
+        return $this->_getCellDefaultDateTime($mixedValue, $sKey, $aField, $aRow);
+    }
+
+    protected function _getCellDateNext($mixedValue, $sKey, $aField, $aRow)
+    {
+        if(empty($mixedValue))
+            return parent::_getCellDefault(_t('_never'), $sKey, $aField, $aRow);
+        else if(is_numeric($mixedValue) && (int)$mixedValue < $this->_iNow)
+            return parent::_getCellDefault(_t('_uknown'), $sKey, $aField, $aRow);
+
+        return $this->_getCellDefaultDateTime($mixedValue, $sKey, $aField, $aRow);
+    }
+
+    protected function _getCellStatus($mixedValue, $sKey, $aField, $aRow)
+    {
+        return parent::_getCellDefault(_t('_bx_payment_txt_status_' . $mixedValue), $sKey, $aField, $aRow);
+    }
+
+    protected function _addJsCss()
+    {
+        parent::_addJsCss();
+
+        $this->_oTemplate->addJsTranslation(array(
+            '_bx_payment_form_input_err',
+            '_bx_payment_msg_confirm_cancelation',
+            '_bx_payment_txt_unsubscribe_yes',
+            '_bx_payment_txt_unsubscribe_no'
+        ));
+    }
+
+    protected function _delete ($mixedId)
+    {
+        $aSubscription = $this->_oModule->_oDb->getSubscription(array('type' => 'pending_id', 'pending_id' => $mixedId));
+        if(empty($aSubscription) || !is_array($aSubscription))
+            return false;
+
+        return $this->_oModule->_oDb->deleteSubscription($aSubscription['id'], 'delete');
+    }
+}
+
+/** @} */

+ 30 - 0
modules/boonex/payment/updates/15.0.1_15.0.2/source/classes/BxPaymentGridSbsHistory.php

@@ -0,0 +1,30 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Payment Payment
+ * @ingroup     UnaModules
+ * 
+ * @{
+ */
+
+
+require_once('BxPaymentGridHistory.php');
+
+class BxPaymentGridSbsHistory extends BxPaymentGridHistory
+{
+    public function __construct ($aOptions, $oTemplate = false)
+    {
+        parent::__construct ($aOptions, $oTemplate);
+    }
+
+    protected function _getCellItemId($mixedValue, $sKey, $aField, $aRow)
+    {
+        $mixedValue = $this->_oModule->_oConfig->descriptorA2S([$aRow['seller_id'], $aRow['module_id'], $mixedValue, $aRow['item_count']]);
+
+        return parent::_getCellItems($mixedValue, $sKey, $aField, $aRow);
+    }
+}
+
+/** @} */

+ 82 - 0
modules/boonex/payment/updates/15.0.1_15.0.2/source/classes/BxPaymentGridSbsList.php

@@ -0,0 +1,82 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Payment Payment
+ * @ingroup     UnaModules
+ * 
+ * @{
+ */
+
+require_once('BxPaymentGridSbsAdministration.php');
+
+class BxPaymentGridSbsList extends BxPaymentGridSbsAdministration
+{
+    protected $_aProvidersAttached;
+
+    public function __construct ($aOptions, $oTemplate = false)
+    {
+        parent::__construct ($aOptions, $oTemplate);
+
+        $this->_sManageType = 'common';
+        $this->_aProvidersAttached = array();
+    }
+
+    public function getCode ($isDisplayHeader = true)
+    {
+        if(empty($this->_aQueryAppend['client_id']) || $this->_aQueryAppend['client_id'] != bx_get_logged_profile_id())
+            return '';
+
+        return parent::getCode($isDisplayHeader);
+    }
+
+    protected function _getActionActions ($sType, $sKey, $a, $isSmall = false, $isDisabled = false, $aRow = array())
+    {
+        if(in_array($aRow['status'], ['cancel', 'canceled']))
+            return '';
+
+        $sMenuObject = $this->_oModule->_oConfig->getObject('menu_sbs_actions');
+
+        if($this->_bIsApi) {
+            $aParams = [];
+            if($sType == 'single' && ($sFieldId = $this->_aOptions['field_id']) && isset($aRow[$sFieldId]))
+                $aParams['pending_id'] = (int)$aRow[$sFieldId];
+
+            return array_merge($a, ['name' => $sKey, 'type' => 'menu', 'action' => $sKey, 'params' => $aParams, 'object' => $sMenuObject]);
+        }
+
+        $sJsCode = '';
+        if(!empty($aRow['seller_id']) && !empty($aRow['provider']) && !in_array($aRow['provider'], $this->_aProvidersAttached)) {
+            $oProvider = $this->_oModule->getObjectProvider($aRow['provider'], $aRow['seller_id']);
+            if($oProvider) {
+                $oProvider->addJsCss();
+
+                $sMethodName = 'getJsCode';
+                if(method_exists($oProvider, $sMethodName))
+                    $sJsCode = $oProvider->$sMethodName();
+
+                $this->_aProvidersAttached[] = $aRow['provider'];
+            }
+        }
+
+        unset($a['attr']['bx_grid_action_single']);
+        $a['attr'] = array_merge($a['attr'], [
+            "onclick" => "bx_menu_popup('" . $sMenuObject . "', this, {id: 'bx-payment-subscription-" . $aRow['id'] . "'}, {id: " . $aRow['id'] . ", grid: '" . $this->_sObject . "'});"
+        ]);
+
+        return $sJsCode . parent::_getActionDefault($sType, $sKey, $a, false, $isDisabled, $aRow);
+    }
+
+    protected function _getDataSql($sFilter, $sOrderField, $sOrderDir, $iStart, $iPerPage)
+    {
+        if(empty($this->_aQueryAppend['client_id']))
+            return array();
+
+        $this->_aOptions['source'] .= $this->_oModule->_oDb->prepareAsString(" AND `client_id`=?", $this->_aQueryAppend['client_id']);
+
+        return parent::_getDataSql($sFilter, $sOrderField, $sOrderDir, $iStart, $iPerPage);
+    }
+}
+
+/** @} */

+ 95 - 0
modules/boonex/payment/updates/15.0.1_15.0.2/source/classes/BxPaymentMenuSbsActions.php

@@ -0,0 +1,95 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Payment Payment
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+
+class BxPaymentMenuSbsActions extends BxTemplMenu
+{
+    protected $_sModule;
+    protected $_oModule;
+
+    protected $_iPendingId;
+
+    public function __construct($aObject, $oTemplate = false)
+    {
+        $this->_sModule = 'bx_payment';
+        $this->_oModule = BxDolModule::getInstance($this->_sModule);
+
+        parent::__construct($aObject, $oTemplate);
+
+        if(($iPendingId = bx_get('id')) !== false && ($iPendingId = bx_process_input($iPendingId, BX_DATA_INT)))
+            $this->setPendingId($iPendingId);
+    }
+
+    public function setContentParams($aParams)
+    {
+        parent::setContentParams($aParams);
+
+        if(($iPendingId = $aParams['pending_id'] ?? false))
+            $this->setPendingId($iPendingId);
+    }
+
+    public function setPendingId($iPendingId)
+    {
+        $this->_iPendingId = $iPendingId;
+
+        $aPending = $this->_oModule->_oDb->getOrderPending(['type' => 'id', 'id' => $this->_iPendingId]);
+        if(empty($aPending) || !is_array($aPending))
+            return;
+
+        $sMethod = 'getMenuItemsActionsRecurring';
+        $oProvider = $this->_oModule->getObjectProvider($aPending['provider'], $aPending['seller_id']);
+        if($oProvider === false || !$oProvider->isActive() || !method_exists($oProvider, $sMethod))
+            return;
+
+        $this->_aObject['menu_items'] = array_merge($oProvider->$sMethod($aPending['client_id'], $aPending['seller_id'], [
+            'id' => $aPending['id'],
+            'order' => $aPending['order']
+        ]), $this->getMenuItemsRaw());
+
+        $aMarkers = [
+            'js_object' => $this->_oModule->_oConfig->getJsObject('subscription'),
+            'id' => $this->_iPendingId
+        ];
+
+        if(($sGrid = bx_get('grid')) !== false)
+            $aMarkers['grid'] = bx_process_input($sGrid);
+
+        $this->addMarkers($aMarkers);
+    }
+
+    public function getCode()
+    {
+        if(empty($this->_aObject['menu_items']) || !is_array($this->_aObject['menu_items']))
+            return MsgBox(_t('_Empty'));
+
+        return parent::getCode();
+    }
+
+    protected function _getMenuCallbackDataAPI($a)
+    {
+        $aResult = [];
+
+        switch($a['name']) {
+            case 'sbs-cancel':
+                $aResult = [
+                    'confirm' => 1,
+                    'request_url' => $this->_sModule . '/cancel_by_pending_id/Subscriptions&params[]=' . $this->_iPendingId . '&params[]=1', 
+                    'on_callback' => 'hide_row',
+                    'id' => $this->_iPendingId
+                ];
+                break;
+        }
+
+        return $aResult;
+    }
+}
+
+/** @} */

+ 2129 - 0
modules/boonex/payment/updates/15.0.1_15.0.2/source/classes/BxPaymentModule.php

@@ -0,0 +1,2129 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Payment Payment
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+define('BX_PAYMENT_ORDERS_TYPE_PENDING', 'pending');
+define('BX_PAYMENT_ORDERS_TYPE_PROCESSED', 'processed');
+define('BX_PAYMENT_ORDERS_TYPE_SUBSCRIPTION', 'subscription');
+define('BX_PAYMENT_ORDERS_TYPE_HISTORY', 'history');
+
+define('BX_PAYMENT_RESULT_SUCCESS', 0);
+
+/*
+ * Subscriptions: statuses.
+ */
+define('BX_PAYMENT_SBS_STATUS_SCHEDULED', 'scheduled');
+define('BX_PAYMENT_SBS_STATUS_TRIAL', 'trial');
+define('BX_PAYMENT_SBS_STATUS_ACTIVE', 'active');
+define('BX_PAYMENT_SBS_STATUS_UNPAID', 'unpaid');
+define('BX_PAYMENT_SBS_STATUS_PAUSED', 'paused');
+define('BX_PAYMENT_SBS_STATUS_CANCELED', 'canceled');
+define('BX_PAYMENT_SBS_STATUS_UNKNOWN', 'unknown');
+
+/*
+ * Subscriptions: period units.
+ */
+define('BX_PAYMENT_SBS_PU_YEAR', 'year');
+define('BX_PAYMENT_SBS_PU_MONTH', 'month');
+define('BX_PAYMENT_SBS_PU_WEEK', 'week');
+define('BX_PAYMENT_SBS_PU_DAY', 'day');
+define('BX_PAYMENT_SBS_PU_HOUR', 'hour');
+define('BX_PAYMENT_SBS_PU_MINUTE', 'minute');
+
+/*
+ * Invoice: statuses.
+ */
+define('BX_PAYMENT_INV_STATUS_UNPAID', 'unpaid');
+define('BX_PAYMENT_INV_STATUS_PAID', 'paid');
+define('BX_PAYMENT_INV_STATUS_OVERDUE', 'overdue');
+
+/*
+ * Provider options: extended mode.
+ */
+define('BX_PAYMENT_POPT_EXT_NONE', 0);
+define('BX_PAYMENT_POPT_EXT_SAVE', 1);
+define('BX_PAYMENT_POPT_EXT_RESET', 2);
+
+/**
+ * Payment module by BoonEx
+ *
+ * This module is needed to work with payment providers and organize the process
+ * of some item purchasing. Shopping Cart and Orders Manager are included.
+ *
+ * Integration notes:
+ * To integrate your module with this one, you need:
+ * 1. Get 'Add To Cart' button using serviceGetAddToCartLink service.
+ * 2. Add info about your module in the 'bx_pmt_modules' table.
+ * 3. Realize the following service methods in your Module class.
+ *   a. serviceGetItems($iSellerId) - Is used in Orders Administration to get all products of the requested seller(vendor).
+ *   b. serviceGetCartItem($iClientId, $iItemId) - Is used in Shopping Cart to get one product by specified id.
+ *   c. serviceRegisterCartItem($iClientId, $iSellerId, $iItemId, $iItemCount, $sOrderId) - Register purchased product.
+ *   d. serviceUnregisterCartItem($iClientId, $iSellerId, $iItemId, $iItemCount, $sOrderId) - Unregister the product purchased earlier.
+ * @see You may see an example of integration in Membership module.
+ *
+ *
+ * Profile's Wall:
+ * no spy events
+ *
+ *
+ *
+ * Spy:
+ * no spy events
+ *
+ *
+ *
+ * Memberships/ACL:
+ * Doesn't depend on user's membership.
+ *
+ *
+ *
+ * Service methods:
+ *
+ * Is used to get "Add to cart" link for some item(s) in your module.
+ * @see BxPmtModule::serviceGetAddToCartLink
+ * BxDolService::call('payment', 'get_add_to_cart_link', array($iSellerId, $mixedModuleId, $iItemId, $iItemCount));
+ *
+ * Check transaction(s) in database which satisty all conditions.
+ * @see BxPmtModule::serviceGetOrdersInfo
+ * BxDolService::call('payment', 'get_orders_info', array($aConditions), 'Orders');
+ *
+ * Get total count of items in Shopping Cart.
+ * @see BxPmtModule::serviceGetCartItemsCount
+ * BxDolService::call('payment', 'get_cart_items_count', array($iUserId, $iOldCount));
+ * @note is needed for internal usage(integration with member tool bar).
+ *
+ * Get Shopping cart content.
+ * @see BxPmtModule::serviceGetCartItems
+ * BxDolService::call('payment', 'get_cart_items');
+ * @note is needed for internal usage(integration with member tool bar).
+ *
+ *
+ * Alerts:
+ * no alerts available
+ *
+ */
+class BxPaymentModule extends BxBaseModPaymentModule
+{
+    protected $_iUserId;
+
+    protected $_aOrderTypes;
+
+    function __construct($aModule)
+    {
+        parent::__construct($aModule);
+
+        $this->_iUserId = $this->getProfileId();
+
+        $this->_aOrderTypes = array(
+            BX_PAYMENT_ORDERS_TYPE_PENDING, 
+            BX_PAYMENT_ORDERS_TYPE_PROCESSED, 
+            BX_PAYMENT_ORDERS_TYPE_SUBSCRIPTION, 
+            BX_PAYMENT_ORDERS_TYPE_HISTORY
+        );
+    }
+
+    /**
+     * Manage Orders Methods
+     */
+    public function actionGetClients()
+    {
+        $sTerm = bx_get('term');
+
+        $aResult = BxDolService::call('system', 'profiles_search', array($sTerm), 'TemplServiceProfiles');
+
+        echoJson($aResult);
+    }
+
+    public function actionGetItems($sType, $iModuleId)
+    {
+    	$iSellerId = $this->getProfileId();
+        $aItems = $this->callGetCartItems((int)$iModuleId, array($iSellerId));
+        $aParams = [
+            'filter' => bx_get('filter')
+        ];
+
+        echoJson([
+            'code' => 0, 
+            'eval' => $this->_oConfig->getJsObject('processed') . '.onSelectModule(oData);', 
+            'data' => $this->_oTemplate->displayItems($iSellerId, $sType, $aItems, $aParams)
+        ]);
+    }
+
+    public function actionGetFilterValuesItem($iSellerId, $iModuleId)
+    {
+        $sItems = '<option value="">' . _t('_bx_payment_txt_all_items') . '</option>';
+
+        if(empty($iSellerId) || empty($iModuleId))
+            return echoJson(array('code' => 1, 'content' => $sItems));
+
+        $aItems = $this->callGetCartItems((int)$iModuleId, array($iSellerId));
+
+        $this->_oConfig->sortByColumn('title', $aItems);
+
+        foreach($aItems as $aItem)
+            $sItems .= '<option value="' . $aItem['id'] . '">' . $aItem['title'] . '</option>';
+
+        echoJson(array('code' => 0, 'content' => $sItems));
+    }
+
+    public function serviceGetSafeServices()
+    {
+        return array_merge(parent::serviceGetSafeServices(), [
+            'GetBlockJoin' => 'BxPaymentJoin',
+
+            'GetBlockCarts' => 'BxPaymentCart',
+            'GetBlockCart' => 'BxPaymentCart',
+            'GetBlockCartHistory' => 'BxPaymentCart',
+            
+            'GetBlockListMy' => 'BxPaymentSubscriptions',
+            'GetBlockHistory' => 'BxPaymentSubscriptions',
+            'Cancel' => 'BxPaymentSubscriptions',
+            'CancelByPendingId' => 'BxPaymentSubscriptions',
+
+            'GetProviderOptions' => '',
+            'InitializeCheckoutApi' => '',
+            'StripeV3CreateSessionApi' => ''
+        ]);
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_payment Payment
+     * @subsection bx_payment-purchase_processing Purchase Processing
+     * @subsubsection bx_payment-get_modules_with_payments get_modules_with_payments
+     * 
+     * @code bx_srv('bx_payment', 'get_modules_with_payments', []); @endcode
+     * 
+     * Get modules with payments functionality
+     *
+     * @return array with modules names
+     * 
+     * @see BxPaymentModule::serviceGetModulesWithPayments
+     */
+    /** 
+     * @ref bx_payment-get_modules_with_payments "get_modules_with_payments"
+     */
+    public function serviceGetModulesWithPayments()
+    {
+        return $this->_oDb->getModulesWithPayments();
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_payment Payment
+     * @subsection bx_payment-purchase_processing Purchase Processing
+     * @subsubsection bx_payment-is_credits_only is_credits_only
+     * 
+     * @code bx_srv('bx_payment', 'is_credits_only'); @endcode
+     * 
+     * Check whether the 'Credits Only' mode is enabled or not.
+     *
+     * @return boolean value determining the result of checking.
+     * 
+     * @see BxPaymentModule::serviceIsCreditsOnly
+     */
+    /** 
+     * @ref bx_payment-is_credits_only "is_credits_only"
+     */
+    public function serviceIsCreditsOnly()
+    {
+        return $this->_oConfig->isCreditsOnly();
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_payment Payment
+     * @subsection bx_payment-purchase_processing Purchase Processing
+     * @subsubsection bx_payment-is_accepting_payments is_accepting_payments
+     * 
+     * @code bx_srv('bx_payment', 'is_accepting_payments', [...]); @endcode
+     * 
+     * Check whether the specified vendor has a configured payment provider or not.
+     *
+     * @param $iVendorId integer value with vendor ID.
+     * @param $sPaymentType (optional) string value with payment type. If specified then the vendor will be checked for having the payment provider of the requested type.
+     * @return boolean value determining the result of checking.
+     * 
+     * @see BxPaymentModule::serviceIsAcceptingPayments
+     */
+    /** 
+     * @ref bx_payment-is_accepting_payments "is_accepting_payments"
+     */
+    public function serviceIsAcceptingPayments($iVendorId, $sPaymentType = '')
+    {
+    	$bResult = false;
+
+    	switch($sPaymentType) {
+            case BX_PAYMENT_TYPE_SINGLE:
+                $aProvidersCart = $this->_oDb->getVendorInfoProvidersSingle($iVendorId);
+                $bResult = !empty($aProvidersCart);
+                break;
+
+            case BX_PAYMENT_TYPE_RECURRING:
+                $aProvidersSubscription = $this->_oDb->getVendorInfoProvidersRecurring($iVendorId);
+                $bResult = !empty($aProvidersSubscription);
+                break;
+
+            default:
+                $aProviders = $this->_oDb->getVendorInfoProviders($iVendorId);
+                $bResult = !empty($aProviders);
+    	}
+
+        return $bResult;
+    }
+
+    /** 
+     * @deprecated since version 11.0.0
+     * 
+     * @see BxPaymentModule::serviceIsProviderOptions
+     */
+    public function serviceIsPaymentProvider($iVendorId, $sVendorProvider, $sPaymentType = '')
+    {
+    	return $this->serviceIsProviderOptions($iVendorId, $sVendorProvider, $sPaymentType);
+    }
+
+    /** 
+     * @deprecated since version 11.0.0
+     * 
+     * @see BxPaymentModule::serviceGetProviderOptions
+     */
+    public function serviceGetPaymentProvider($iVendorId, $sVendorProvider, $sPaymentType = '')
+    {
+    	return $this->serviceGetProviderOptions($iVendorId, $sVendorProvider, $sPaymentType);
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_payment Payment
+     * @subsection bx_payment-purchase_processing Purchase Processing
+     * @subsubsection bx_payment-is_provider_options is_provider_options
+     * 
+     * @code bx_srv('bx_payment', 'is_provider_options', [...]); @endcode
+     * 
+     * Check whether the specified vendor has configured the specified payment provider or not.
+     *
+     * @param $iVendorId integer value with vendor ID.
+     * @param $sVendorProvider string value with payment provider name.
+     * @param $sPaymentType (optional) string value with payment type. If specified then the vendor will be checked for having the payment provider of the requested type.
+     * @return boolean value determining the result of checking.
+     * 
+     * @see BxPaymentModule::serviceIsProviderOptions
+     */
+    /** 
+     * @ref bx_payment-is_provider_options "is_provider_options"
+     */
+    public function serviceIsProviderOptions($iVendorId, $sVendorProvider, $sPaymentType = '')
+    {
+    	$aProvider = $this->serviceGetProviderOptions($iVendorId, $sVendorProvider, $sPaymentType);
+    	return $aProvider !== false;
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_payment Payment
+     * @subsection bx_payment-purchase_processing Purchase Processing
+     * @subsubsection bx_payment-get_provider_options get_provider_options
+     * 
+     * @code bx_srv('bx_payment', 'get_provider_options', [...]); @endcode
+     * 
+     * Get configuration settings for the payment provider entered by the specified vendor.
+     *
+     * @param $iVendorId integer value with vendor ID.
+     * @param $sVendorProvider string value with payment provider name.
+     * @param $sPaymentType (optional) string value with payment type. If specified then the vendor will be checked for having the payment provider of the requested type.
+     * @return an array with special format describing the payment provider or false value if something is wrong.
+     * 
+     * @see BxPaymentModule::serviceGetProviderOptions
+     */
+    /** 
+     * @ref bx_payment-get_provider_options "get_provider_options"
+     */
+    public function serviceGetProviderOptions($iVendorId, $sVendorProvider, $sPaymentType = '')
+    {
+    	$aProviders = array();
+    	switch($sPaymentType) {
+            case BX_PAYMENT_TYPE_SINGLE:
+                $aProviders = $this->_oDb->getVendorInfoProvidersSingle($iVendorId);
+                break;
+
+            case BX_PAYMENT_TYPE_RECURRING:
+                $aProviders = $this->_oDb->getVendorInfoProvidersRecurring($iVendorId);
+                break;
+
+            default:
+                $aProviders = $this->_oDb->getVendorInfoProviders($iVendorId);
+    	}
+
+    	return !empty($aProviders) && !empty($aProviders[$sVendorProvider]) && is_array(($aProviders[$sVendorProvider])) ? $aProviders[$sVendorProvider] : false;
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_payment Payment
+     * @subsection bx_payment-other Other
+     * @subsubsection bx_payment-get_options_default_currency_code get_options_default_currency_code
+     * 
+     * @code bx_srv('bx_payment', 'get_options_default_currency_code', [...]); @endcode
+     * 
+     * Get an array with available currencies. Is used in forms.
+     *
+     * @return an array with available currencies represented as key => value pairs.
+     * 
+     * @see BxPaymentModule::serviceGetOptionsDefaultCurrencyCode
+     */
+    /** 
+     * @ref bx_payment-get_options_default_currency_code "get_options_default_currency_code"
+     */
+    public function serviceGetOptionsDefaultCurrencyCode()
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $aCurrencies = BxDolForm::getDataItems($CNF['OBJECT_FORM_PRELISTS_CURRENCIES']);
+
+        $aResult = array();
+        foreach($aCurrencies as $sKey => $sValue)
+            $aResult[] = array(
+                'key' => $sKey,
+                'value' => $sValue
+            );
+
+        return $aResult;
+    }
+
+    public function serviceGetOptionsPersonalCurrencyCode()
+    {
+        return array_merge([[
+            'key' => '',
+            'value' => _t('_bx_payment_gc_currency_code_default')
+        ]], $this->serviceGetOptionsDefaultCurrencyCode());
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_payment Payment
+     * @subsection bx_payment-other Other
+     * @subsubsection bx_payment-get_options_site_admin get_options_site_admin
+     * 
+     * @code bx_srv('bx_payment', 'get_options_site_admin', [...]); @endcode
+     * 
+     * Get an array with profiles which can be used as 'Site Admin (Owner)'. 'Site Admin' is a person who will be displayed to buyers when something is selling on behalf of the site.
+     *
+     * @return an array with profiles represented as key => value pairs.
+     * 
+     * @see BxPaymentModule::serviceGetOptionsSiteAdmin
+     */
+    /** 
+     * @ref bx_payment-get_options_site_admin "get_options_site_admin"
+     */
+    public function serviceGetOptionsSiteAdmin()
+    {
+        $aResult = array(
+            array('key' => '', 'value' => _t('_Select_one'))
+        );
+
+        $aIds = $this->_oDb->getAdminsIds();
+        foreach($aIds as $iId) {
+            $aUser = $this->getProfileInfo($iId);
+
+            $aResult[] = array(
+                'key' => $iId,
+                'value' => $aUser['name']
+            );
+        }
+
+        return $aResult;
+    }
+
+    public function serviceGetMenuAddonManageTools()
+    {
+        return array(
+            'counter1_value' => (int)$this->_oDb->getInvoices(array('type' => 'status', 'status' => BX_PAYMENT_INV_STATUS_PAID, 'count' => true)), 
+            'counter1_caption' => _t('_bx_payment_menu_item_title_admt_addon_counter1_caption'), 
+            'counter2_value' => (int)$this->_oDb->getInvoices(array('type' => 'status', 'status' => BX_PAYMENT_INV_STATUS_OVERDUE, 'count' => true)), 
+            'counter2_caption' => _t('_bx_payment_menu_item_title_admt_addon_counter2_caption'), 
+            'counter3_value' => (int)$this->_oDb->getInvoices(array('type' => 'all_count'))
+        );
+    }
+
+    public function serviceGetBlockCheckoutOffline()
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $oBuyer = BxDolProfile::getInstance();
+        if(!$oBuyer)
+            return MsgBox(_t('_bx_payment_err_required_login'));
+        
+        $iSeller = (int)bx_get('seller');
+        $oSeller = BxDolProfile::getInstance($iSeller);
+        if(!$oSeller)
+            return MsgBox(_t('_bx_payment_err_unknown_vendor'));
+
+        $aData = array(
+            'seller' => $iSeller,
+            'currency' => array(
+                'code' => bx_process_input(bx_get('currency_code')),
+                'sign' => bx_process_input(bx_get('currency_sign')),
+            ),
+            'amount' => (float)bx_get('amount'),
+            'return_url' => bx_process_input(bx_get('return_url')),
+        );
+
+        if(empty($aData['currency']['code']))
+            $aData['currency']['code'] = $this->_oConfig->getDefaultCurrencyCode();
+
+        if(empty($aData['currency']['sign']))
+            $aData['currency']['sign'] = $this->_oConfig->getDefaultCurrencySign();
+
+        $sItems = '';
+        $iItemsCount = (int)bx_get('items_count');
+        for($i = 0; $i < $iItemsCount; $i++) {
+            $aItem = array(
+                'title' => bx_process_input(bx_get('item_title_' . $i)),
+                'quantity' => (int)bx_get('item_quantity_' . $i)
+            );
+
+            $sItems .= _t('_bx_payment_txt_checkout_item', $aItem['title'], $aItem['quantity']);
+            $aData['items'][] = $aItem;
+        }
+
+        $aTemplate = BxDolEmailTemplates::getInstance()->parseTemplate($this->_oConfig->getPrefix('general') . 'checkout_offline', array(
+            'profile_name' => $oBuyer->getDisplayName(),
+            'profile_link' => $oBuyer->getUrl(),
+            'items' => $sItems,
+            'amount' => $aData['currency']['sign'] . sprintf("%.2f", (float)($aData['amount'])),
+            'date' => bx_time_js(time(), BX_FORMAT_DATE, true),
+            'pending_orders_link' => $this->getObjectOrders()->serviceGetPendingOrdersUrl()
+        ), 0, $iSeller);
+
+        $sEmail = '';
+        $oProvider = $this->getObjectProvider($CNF['OBJECT_PP_OFFLINE'], $iSeller);
+        if($oProvider !== false && $oProvider->isActive())
+            $sEmail = $oProvider->getOption('checkout_email');
+
+        if(empty($sEmail))
+            $sEmail = $oBuyer->getAccountObject()->getEmail();
+
+        if(!sendMail($sEmail, $aTemplate['Subject'], $aTemplate['Body'], 0, array(), BX_EMAIL_SYSTEM))
+            return MsgBox(_t('_bx_payment_err_cannot_perform'));
+
+        return $this->_oTemplate->displayBlockCheckoutOffline($oBuyer, $oSeller, $aData);
+    }
+
+    /**
+     * Cart Processing Methods
+     */
+    public function actionAddToCart($iSellerId, $iModuleId, $iItemId, $iItemCount, $sCustom = '')
+    {
+        if(empty($sCustom) && ($sCustom = bx_get('custom')) !== false)
+            $sCustom = bx_process_input($sCustom);
+
+        $aCustom = [];
+        if(!empty($sCustom)) {
+            $aCustom = $this->_oConfig->s2a($sCustom);
+            if(empty($aCustom) || !is_array($aCustom))
+                $aCustom = [];
+        }
+
+        $aResult = $this->getObjectCart()->serviceAddToCart($iSellerId, $iModuleId, $iItemId, $iItemCount, $aCustom);
+        echoJson($aResult);
+    }
+
+    /**
+     * Isn't used yet.
+     */
+    public function actionDeleteFromCart($iSellerId, $iModuleId, $iItemId)
+    {
+        echoJson($this->getObjectCart()->serviceDeleteFromCart($iSellerId, $iModuleId, $iItemId));
+    }
+
+    /**
+     * Isn't used yet.
+     */
+    public function actionEmptyCart($iSellerId)
+    {
+        echoJson($this->getObjectCart()->serviceDeleteFromCart($iSellerId));
+    }
+
+    public function actionSubscribe()
+    {
+    	$iSellerId = bx_process_input(bx_get('seller_id'), BX_DATA_INT);
+    	$sSellerProvider = bx_process_input(bx_get('seller_provider'));
+    	$iModuleId = bx_process_input(bx_get('module_id'), BX_DATA_INT);
+    	$iItemId = bx_process_input(bx_get('item_id'), BX_DATA_INT);
+    	$iItemCount = bx_process_input(bx_get('item_count'), BX_DATA_INT);
+    	if(empty($iItemCount))
+    		$iItemCount = 1;
+
+        $sRedirect = bx_process_input(bx_get('redirect'));
+        $sCustom = bx_process_input(bx_get('custom'));
+
+        $aCustom = array();
+        if(!empty($sCustom)) {
+            $aCustom = json_decode(base64_decode($sCustom), true);
+            if(empty($aCustom) || !is_array($aCustom))
+                $aCustom = array();
+        }
+
+        $aResult = $this->getObjectSubscriptions()->serviceSubscribe($iSellerId, $sSellerProvider, $iModuleId, $iItemId, $iItemCount, $sRedirect, $aCustom);
+        $bRedirect = !empty($aResult['redirect']);
+
+        if(!empty($aResult['popup'])) {
+            $sContent = '';
+            $sContent .= $this->_oTemplate->displayCartJs(BX_PAYMENT_TYPE_RECURRING, $iSellerId);
+            $sContent .= !empty($aResult['popup']['html']) ? $aResult['popup']['html'] : $aResult['popup'];
+
+			return $this->_oTemplate->displayPageCodeResponse($sContent, false, true);
+        }
+
+		if(!empty($aResult['code']))
+			return $this->_oTemplate->displayPageCodeError($aResult['message']);
+
+		if(!empty($aResult['message']) && !$bRedirect)
+			return $this->_oTemplate->displayPageCodeResponse($aResult['message']);
+
+        if($bRedirect) {
+            header('Location: ' . $aResult['redirect']);
+            exit;
+        }
+    }
+
+    public function actionSubscribeJson()
+    {
+    	$iSellerId = bx_process_input(bx_get('seller_id'), BX_DATA_INT);
+    	$sSellerProvider = bx_process_input(bx_get('seller_provider'));
+    	$iModuleId = bx_process_input(bx_get('module_id'), BX_DATA_INT);
+    	$iItemId = bx_process_input(bx_get('item_id'), BX_DATA_INT);
+
+    	$iItemCount = bx_process_input(bx_get('item_count'), BX_DATA_INT);
+    	if(empty($iItemCount))
+            $iItemCount = 1;
+
+        $sItemAddons = '';
+        if(bx_get('item_addons') !== false) {
+            $sItemAddons = bx_process_input(bx_get('item_addons'));
+            if(is_array($sItemAddons))
+                $sItemAddons = $this->_oConfig->a2s($sItemAddons);
+        }
+
+        $sRedirect = bx_process_input(bx_get('redirect'));
+        $sCustom = bx_process_input(bx_get('custom'));
+
+        $aCustom = array();
+        if(!empty($sCustom)) {
+            $aCustom = $this->_oConfig->s2a($sCustom);
+            if(empty($aCustom) || !is_array($aCustom))
+                $aCustom = [];
+        }
+
+        echoJson($this->getObjectSubscriptions()->serviceSubscribeWithAddons($iSellerId, $sSellerProvider, $iModuleId, $iItemId, $iItemCount, $sItemAddons, $sRedirect, $aCustom));
+    }
+
+    public function actionSubscriptionGetDetails($iId)
+    {
+        echoJson($this->_oTemplate->displaySubscriptionGetDetails($iId));
+    }
+
+    public function actionSubscriptionChangeDetails($iId)
+    {
+        echoJson($this->_oTemplate->displaySubscriptionChangeDetails($iId));
+    }
+
+    public function actionSubscriptionGetBilling($iId)
+    {
+        echoJson($this->_oTemplate->displaySubscriptionGetBilling($iId));
+    }
+
+    public function actionSubscriptionChangeBilling($iId)
+    {
+        echoJson($this->_oTemplate->displaySubscriptionChangeBilling($iId));
+    }
+
+    public function actionSubscriptionCancelation($iId)
+    {
+        $aResult = array('code' => 1, 'message' => _t('_bx_payment_err_cannot_perform'));
+
+        $aPending = $this->_oDb->getOrderPending(array('type' => 'id', 'id' => $iId));
+        if(empty($aPending) || !is_array($aPending))
+            return echoJson($aResult);
+
+        $aSubscription = $this->_oDb->getSubscription(array('type' => 'pending_id', 'pending_id' => $iId));
+        if(empty($aSubscription) || !is_array($aSubscription))
+            return echoJson($aResult);
+
+        $oRecipient = BxDolProfile::getInstance((int)$aPending['seller_id']);
+        if(!$oRecipient)
+            return echoJson($aResult);
+
+        $mixedResult = $this->isAllowedManage($aPending);
+        if($mixedResult !== true)
+            return echoJson(array('code' => 2, 'message' => $mixedResult));
+
+        $aTemplate = BxDolEmailTemplates::getInstance()->parseTemplate($this->_oConfig->getPrefix('general') . 'cancelation_request', array(
+            'subscription_id' => $aSubscription['subscription_id'],
+            'subscription_customer' => $aSubscription['customer_id'],
+            'subscription_date' => bx_time_js($aSubscription['date_add'], BX_FORMAT_DATE, true)
+        ), 0, (int)$aPending['client_id']);
+
+        $sEmail = '';
+        $oProvider = $this->getObjectProvider($aPending['provider'], $aPending['seller_id']);
+        if($oProvider !== false && $oProvider->isActive())
+            $sEmail = $oProvider->getOption('cancellation_email');
+
+        if(empty($sEmail))
+            $sEmail = $oRecipient->getAccountObject()->getEmail();
+
+        if(!sendMail($sEmail, $aTemplate['Subject'], $aTemplate['Body'], 0, array(), BX_EMAIL_SYSTEM))
+            return echoJson($aResult);
+
+        echoJson(array('code' => 0, 'message' => _t('_bx_payment_msg_cancelation_request_sent')));
+    }
+
+    public function actionSubscriptionCancel($iId, $mixedGridObject = false)
+    {
+        $CNF = &$this->_oConfig->CNF;
+        $aResult = ['code' => 1, 'message' => _t('_bx_payment_err_cannot_perform')];
+
+        $aPending = $this->_oDb->getOrderPending(['type' => 'id', 'id' => $iId]);
+        if(empty($aPending) || !is_array($aPending))
+            return echoJson($aResult);
+
+        $mixedResult = $this->isAllowedManage($aPending);
+        if($mixedResult !== true)
+            return echoJson(['code' => 2, 'message' => $mixedResult]);
+
+        $oSubscriptions = $this->getObjectSubscriptions();
+        
+        $sReason = '';
+        if(getParam($CNF['PARAM_SBS_CANCEL_SURVEY']) == 'on') {
+            $aCsResult = $oSubscriptions->getPopupCancelSurvey($iId);
+            if($aCsResult['code'] != 0)
+                return echoJson($aCsResult);
+
+            $sReason = $aCsResult['msg'];
+        }
+
+        if(!$oSubscriptions->cancel($iId, $sReason))
+            return echoJson($aResult);
+
+        if(empty($mixedGridObject) && bx_get('grid') !== false)
+            $mixedGridObject = bx_process_input(bx_get('grid'));
+
+        if(!empty($mixedGridObject) && $aPending['client_id'] == $this->getProfileId()) {
+            $oGrid = BxDolGrid::getObjectInstance($mixedGridObject, $this->_oTemplate);
+            $oGrid->addQueryParam('client_id', $aPending['client_id']);
+
+            return echoJson(['object' => $mixedGridObject, 'grid' => $oGrid->getCode(false), 'blink' => array($iId)]);
+        }
+        else
+            return echoJson(['code' => 0, 'message' => _t('_bx_payment_msg_successfully_performed')]);
+    }
+
+    /**
+     * Payment Processing Methods
+     */
+    public function actionAuthorizeCheckout($sType)
+    {
+    	if(!$this->isLogged())
+            return $this->_oTemplate->displayPageCodeError($this->_sLangsPrefix . 'err_required_login');
+
+        if(bx_get('seller_id') === false || bx_get('provider') === false || bx_get('items') === false)
+            return $this->_oTemplate->displayPageCodeError($this->_sLangsPrefix . 'err_wrong_data');
+
+        $iSellerId = bx_process_input(bx_get('seller_id'), BX_DATA_INT);
+        $sProvider = bx_process_input(bx_get('provider'));
+        $aItems = bx_process_input(bx_get('items'));
+
+        $mixedResult = $this->serviceAuthorizeCheckout($sType, $iSellerId, $sProvider, $aItems);
+        if(is_string($mixedResult))
+            return $this->_oTemplate->displayPageCodeError($mixedResult);
+
+        if(is_array($mixedResult) && !empty($mixedResult['redirect'])) {
+            header('Location: ' . $mixedResult['redirect']);
+            exit;
+        }
+
+        return $this->_oTemplate->displayPageCodeResponse($this->_sLangsPrefix . 'msg_successfully_performed');
+    }
+
+    public function actionCaptureAuthorizedCheckout($sType)
+    {
+        $iProfileId = bx_get_logged_profile_id();
+    	if(!$iProfileId)
+            return $this->_oTemplate->displayPageCodeError($this->_sLangsPrefix . 'err_required_login');
+
+        $sOrderAuth = '';
+        if(($sOrderAuth = bx_get('order')) !== false) 
+            $sOrderAuth = bx_process_input($sOrderAuth);
+
+        if(empty($sOrderAuth))
+            return $this->_oTemplate->displayPageCodeError($this->_sLangsPrefix . 'err_empty_order');
+
+        $aPending = $this->_oDb->getOrderPending(['type' => 'order', 'order' => $sOrderAuth]);
+        if(empty($aPending) || !is_array($aPending))
+            return $this->_oTemplate->displayPageCodeError($this->_sLangsPrefix . 'err_empty_order');
+
+        if((int)$aPending['seller_id'] != $iProfileId)
+            return $this->_oTemplate->displayPageCodeError($this->_sLangsPrefix . 'err_wrong_vendor');
+
+        $mixedResult = $this->serviceCaptureAuthorizedCheckout($sType, $sOrderAuth);
+        if(is_string($mixedResult))
+            return $this->_oTemplate->displayPageCodeError($mixedResult);
+
+        if(!empty($mixedResult['redirect'])) {
+            header('Location: ' . base64_decode(urldecode($mixedResult['redirect'])));
+            exit;
+        }
+
+        return $this->_oTemplate->displayPageCodeResponse($mixedResult['message']);
+    }
+
+    public function actionInitializeCheckout($sType)
+    {
+    	if(!$this->isLogged())
+            return $this->_oTemplate->displayPageCodeError($this->_sLangsPrefix . 'err_required_login');
+
+        if(bx_get('seller_id') !== false && bx_get('provider') !== false && bx_get('items') !== false) {
+            $iSellerId = bx_process_input(bx_get('seller_id'), BX_DATA_INT);
+            $sProvider = bx_process_input(bx_get('provider'));
+            $aItems = bx_process_input(bx_get('items'));
+
+            $mixedResult = $this->serviceInitializeCheckout(BX_PAYMENT_TYPE_SINGLE, $iSellerId, $sProvider, $aItems);
+            if($mixedResult !== true)
+                return $this->_oTemplate->displayPageCodeError($mixedResult);
+        }
+
+        header('Location: ' . $this->_oConfig->getUrl('URL_CART'));
+        exit;
+    }
+
+    public function actionInitializeCheckoutJson($sType)
+    {
+    	if(!$this->isLogged())
+            return echoJson(['code' => 1, 'message' => _t($this->_sLangsPrefix . 'err_required_login')]);
+
+        if(bx_get('seller_id') !== false && bx_get('provider') !== false && bx_get('items') !== false) {
+            $iSellerId = bx_process_input(bx_get('seller_id'), BX_DATA_INT);
+            $sProvider = bx_process_input(bx_get('provider'));
+            $aItems = bx_process_input(bx_get('items'));
+
+            $mixedResult = $this->serviceInitializeCheckout(BX_PAYMENT_TYPE_SINGLE, $iSellerId, $sProvider, $aItems);
+            if($mixedResult === false)
+                return echoJson(['code' => 2, 'message' => _t($this->_sLangsPrefix . 'err_cannot_perform')]);
+            if(is_string($mixedResult))
+                return echoJson(['code' => 3, 'message' => $mixedResult]);
+            else if(is_array($mixedResult))
+                return echoJson($mixedResult);
+        }
+
+        return echoJson(['code' => 0, 'redirect' => $this->_oConfig->getUrl('URL_CART')]);
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_payment Payment
+     * @subsection bx_payment-purchase_processing Purchase Processing
+     * @subsubsection bx_payment-authorize_checkout authorize_checkout
+     * 
+     * @code bx_srv('bx_payment', 'authorize_checkout', [...]); @endcode
+     * 
+     * Authorize order for future checkout.
+     * 
+     * @param $sType string value with payment type (single or recurring). 
+     * @param $iSellerId integer value with seller ID. 
+     * @param $sProvider string value with payment provider name. 
+     * @param $aItems (optional) an array with items to be purchased. 
+     * @param $sRedirect (optional) string value with redirect URL if it's needed.
+     * @return the result depends on the payment provider which is used for processing or represented as string value with error message if something is wrong.
+     * 
+     * @see BxPaymentModule::serviceAuthorizeCheckout
+     */
+    /** 
+     * @ref bx_payment-authorize_checkout "authorize_checkout"
+     */
+    public function serviceAuthorizeCheckout($sType, $iSellerId, $sProvider, $aItems = [], $sRedirect = '')
+    {
+        $bTypeSingle = $sType == BX_PAYMENT_TYPE_SINGLE;
+        $bTypeRecurring = $sType == BX_PAYMENT_TYPE_RECURRING;
+
+        if(!is_array($aItems))
+            $aItems = [$aItems];
+
+        $iSellerId = (int)$iSellerId;
+        if($iSellerId == BX_PAYMENT_EMPTY_ID)
+            return $this->_sLangsPrefix . 'err_unknown_vendor';
+
+        $oProvider = $this->getObjectProvider($sProvider, $iSellerId);
+        if($oProvider === false || !$oProvider->isActive())
+            return $this->_sLangsPrefix . 'err_incorrect_provider';
+
+        $aInfo = $this->getObjectCart()->getInfo($sType, $this->_iUserId, $iSellerId, $aItems);
+        if(empty($aInfo) || $aInfo['vendor_id'] == BX_PAYMENT_EMPTY_ID || empty($aInfo['items']))
+            return $this->_sLangsPrefix . 'err_empty_order';
+
+        $this->alert('before_authorize', 0, $this->_iUserId, array(
+            'client_id' => $this->_iUserId,
+            'seller_id' => $iSellerId, 
+
+            'type' => &$sType,
+            'provider' => &$sProvider,
+            'cart_info' => &$aInfo,
+
+            'type_ref' => &$sType,
+            'provider_ref' => &$sProvider,
+            'cart_info_ref' => &$aInfo,
+        ));
+
+        $iPendingId = $this->_oDb->insertOrderPending($this->_iUserId, $sType, $sProvider, $aInfo);
+        if(empty($iPendingId))
+            return $this->_sLangsPrefix . 'err_access_db';
+
+        return $oProvider->authorizeCheckout($iPendingId, $aInfo, $sRedirect);
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_payment Payment
+     * @subsection bx_payment-purchase_processing Purchase Processing
+     * @subsubsection bx_payment-capture_authorized_checkout capture_authorized_checkout
+     * 
+     * @code bx_srv('bx_payment', 'capture_authorized_checkout', [...]); @endcode
+     * 
+     * Capture funds for previously authorized order.
+     * 
+     * @param $sType string value with payment type (single or recurring). 
+     * @param $sOrderAuth string value with order's authorization ID. 
+     * @return the result depends on the payment provider which is used for processing or represented as string value with error message if something is wrong.
+     * 
+     * @see BxPaymentModule::serviceCaptureAuthorizedCheckout
+     */
+    /** 
+     * @ref bx_payment-capture_authorized_checkout "capture_authorized_checkout"
+     */
+    public function serviceCaptureAuthorizedCheckout($sType, $sOrderAuth, $sRedirect = '')
+    {
+        $aPending = $this->_oDb->getOrderPending(['type' => 'order', 'order' => $sOrderAuth]);
+        if(empty($aPending) || !is_array($aPending))
+            return $this->_sLangsPrefix . 'err_empty_order';
+
+        if((int)$aPending['processed'] != 0)
+            return $this->_sLangsPrefix . 'err_already_processed';
+
+        $iClientId = (int)$aPending['client_id'];
+        $iSellerId = (int)$aPending['seller_id'];
+        $sProvider = $aPending['provider'];
+
+        $oProvider = $this->getObjectProvider($sProvider, $iSellerId);
+        if($oProvider === false || !$oProvider->isActive())
+            return $this->_sLangsPrefix . 'err_incorrect_provider';
+
+        $aInfo = $this->getObjectCart()->getInfo($sType, $iClientId, $iSellerId, $aPending['items']);
+        if(empty($aInfo) || $aInfo['vendor_id'] == BX_PAYMENT_EMPTY_ID || empty($aInfo['items']))
+            return $this->_sLangsPrefix . 'err_empty_order';
+
+        $this->alert('before_capture_authorized', 0, $iClientId, array(
+            'order_auth' => $sOrderAuth,
+            'client_id' => $iClientId,
+            'seller_id' => $iSellerId, 
+
+            'type' => &$sType,
+            'provider' => &$sProvider,
+            'cart_info' => &$aInfo,
+
+            'type_ref' => &$sType,
+            'provider_ref' => &$sProvider,
+            'cart_info_ref' => &$aInfo,
+        ));
+
+        $aResult = $oProvider->captureAuthorizedCheckout($sOrderAuth, $aPending, $aInfo, $sRedirect);
+        if((int)$aResult['code'] != BX_PAYMENT_RESULT_SUCCESS) 
+            return $aResult['message'];
+
+        //--- Get updated pending order
+        $aPending = $this->_oDb->getOrderPending(['type' => 'id', 'id' => $aResult['pending_id']]);
+
+        //--- Register payment for purchased items in associated modules 
+        if(isset($aResult['paid']) && $aResult['paid'])
+            $this->registerPayment($aPending);
+
+        $this->alert('finalize_checkout', 0, bx_get_logged_profile_id(), array(
+            'pending' => $aPending,
+            'transactions' => $this->_oDb->getOrderProcessed(array('type' => 'pending_id', 'pending_id' => (int)$aPending['id'])),
+            'provider' => $oProvider,
+
+            'message' => &$aResult['message'],
+            'result' => &$aResult,
+
+            'message_ref' => &$aResult['message'],
+            'result_ref' => &$aResult,
+        ));
+
+        if(empty($aResult['redirect']) && $oProvider->needRedirect())
+            $aResult['redirect'] = $oProvider->getReturnUrl();
+
+        return $aResult;
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_payment Payment
+     * @subsection bx_payment-purchase_processing Purchase Processing
+     * @subsubsection bx_payment-initialize_checkout initialize_checkout
+     * 
+     * @code bx_srv('bx_payment', 'initialize_checkout', [...]); @endcode
+     * 
+     * Initialize the checkout process.
+     * 
+     * @param $sType string value with payment type (single or recurring). 
+     * @param $iSellerId integer value with seller ID. 
+     * @param $sProvider string value with payment provider name. 
+     * @param $aItems (optional) an array with items to be purchased. 
+     * @param $sRedirect (optional) string value with redirect URL if it's needed.
+     * @param $aCustom (optional) array with custom data to attach to a payment.
+     * @return the result depends on the payment provider which is used for processing or represented as string value with error message if something is wrong.
+     * 
+     * @see BxPaymentModule::serviceInitializeCheckout
+     */
+    /** 
+     * @ref bx_payment-initialize_checkout "initialize_checkout"
+     */
+    public function serviceInitializeCheckout($sType, $iSellerId, $sProvider, $aItems = array(), $sRedirect = '', $aCustoms = array())
+    {
+        $bTypeSingle = $sType == BX_PAYMENT_TYPE_SINGLE;
+        $bTypeRecurring = $sType == BX_PAYMENT_TYPE_RECURRING;
+
+        if(!is_array($aItems))
+            $aItems = array($aItems);
+
+        $iSellerId = (int)$iSellerId;
+        if($iSellerId == BX_PAYMENT_EMPTY_ID)
+            return $this->_sLangsPrefix . 'err_unknown_vendor';
+
+        $oProvider = $this->getObjectProvider($sProvider, $iSellerId);
+        if($oProvider === false || !$oProvider->isActive())
+            return $this->_sLangsPrefix . 'err_incorrect_provider';
+
+        $aInfo = $this->getObjectCart()->getInfo($sType, $this->_iUserId, $iSellerId, $aItems);
+        if(empty($aInfo) || $aInfo['vendor_id'] == BX_PAYMENT_EMPTY_ID || empty($aInfo['items']))
+            return $this->_sLangsPrefix . 'err_empty_order';
+
+        /*
+         * Process FREE (price = 0) items for LOGGED IN members
+         * WITHOUT processing via payment provider.
+         * Note. This section isn't used for now!
+         */
+        $bProcessedFree = false;
+        $sKeyPriceSingle = $this->_oConfig->getKey('KEY_ARRAY_PRICE_SINGLE');
+        $sKeyPriceRecurring = $this->_oConfig->getKey('KEY_ARRAY_PRICE_RECURRING');
+        foreach($aInfo['items'] as $iIndex => $aItem) {
+            if((int)$aInfo['client_id'] == 0)
+                continue;
+
+            //--- For Single time payments.
+            if($bTypeSingle && (float)$aItem[$sKeyPriceSingle] == 0) {
+                $aCart = $this->_oDb->getCartContent($aInfo['client_id']);
+                $aCartCustoms = $aCart['customs'];
+
+                $aCartItem = array($aInfo['vendor_id'], $aItem['module_id'], $aItem['id'], $aItem['quantity']);
+                $aCartItemCustom = $this->_oConfig->pullCustom($aCartItem, $aCartCustoms);
+
+                $aItemInfo = $this->callRegisterCartItem((int)$aItem['module_id'], array($aInfo['client_id'], $aInfo['vendor_id'], $aItem['id'], $aItem['quantity'], $this->_oConfig->getLicense(), $aCartItemCustom));
+                if(!empty($aItemInfo) && is_array($aItemInfo)) {
+                    if(!empty($aItemInfo['addons']) && is_array($aItemInfo['addons']))
+                        foreach($aItemInfo['addons'] as $sAddon => $aAddon)
+                            $this->callRegisterCartItem((int)$aAddon['module_id'], array($aInfo['client_id'], $aInfo['vendor_id'], $aAddon['id'], $aAddon['quantity'], $this->_oConfig->getLicense(), $aCartItemCustom));
+
+                    $bProcessedFree = true;
+                }
+
+                $aInfo['items_count'] -= 1;
+                unset($aInfo['items'][$iIndex]);
+
+                $aCart['items'] = trim(preg_replace("'" . $this->_oConfig->descriptorA2S($aCartItem) . ":?'", "", $aCart['items']), ":");
+                $this->_oDb->setCartItems($aInfo['client_id'], $aCart['items'], $aCartCustoms);
+            }
+
+            //--- For Recurring payments.
+            if($bTypeRecurring && (float)$aItem[$sKeyPriceRecurring] == 0) {
+                //TODO: Process FREE subscription here, if such situation will be possible.
+            }
+        }
+
+        if(empty($aInfo['items']))
+            return $this->_sLangsPrefix . ($bProcessedFree ? 'msg_successfully_processed_free' : 'err_empty_order');
+
+        if($bTypeSingle && (empty($aCustoms) || !is_array($aCustoms))) {
+            $aCart = $this->_oDb->getCartContent($aInfo['client_id']);
+            $aCartCustoms = $aCart['customs'];
+
+            $aCustoms = array();
+            foreach($aInfo['items'] as $aItem) {
+                $sCartItem = $this->_oConfig->descriptorA2S(array($aItem['author_id'], $aItem['module_id'], $aItem['id']));
+                $aCartItemCustom = $this->_oConfig->getCustom($sCartItem, $aCartCustoms);
+                $this->_oConfig->putCustom($sCartItem, $aCartItemCustom, $aCustoms);
+            }
+        }
+
+        $this->alert('before_pending', 0, bx_get_logged_profile_id(), array(
+            'client_id' => $this->_iUserId,
+            'seller_id' => $iSellerId, 
+
+            'type' => &$sType,
+            'provider' => &$sProvider,
+            'cart_info' => &$aInfo,
+            'custom' => &$aCustoms,
+
+            'type_ref' => &$sType,
+            'provider_ref' => &$sProvider,
+            'cart_info_ref' => &$aInfo,
+            'custom_ref' => &$aCustoms,
+        ));
+
+        $iPendingId = $this->_oDb->insertOrderPending($this->_iUserId, $sType, $sProvider, $aInfo, $aCustoms);
+        if(empty($iPendingId))
+            return $this->_sLangsPrefix . 'err_access_db';
+
+        /*
+         * Perform Join WITHOUT processing via payment provider
+         * if a client ISN'T logged in and has only ONE FREE item in the card.
+         * Note. This section isn't used for now because only a member can purchase!
+         */
+        if((int)$aInfo['client_id'] == 0 && (int)$aInfo['items_count'] == 1) {
+            reset($aInfo['items']);
+            $aItem = current($aInfo['items']);
+
+            if(!empty($aItem) && $this->_oConfig->getPrice($sType, $aItem)) {
+                $this->_oDb->updateOrderPending($iPendingId, array(
+                    'order' => $this->_oConfig->getLicense(),
+                    'error_code' => '1',
+                    'error_msg' => ''
+                ));
+
+                $this->getObjectJoin()->performJoin($iPendingId);
+            }
+        }
+
+        return $oProvider->initializeCheckout($iPendingId, $aInfo, $sRedirect);
+    }
+
+    public function serviceInitializeCheckoutApi($sType, $iSellerId, $sProvider, $aItems = [], $sRedirect = '', $aCustoms = [])
+    {
+        $mixedResult = $this->serviceInitializeCheckout($sType, $iSellerId, $sProvider, $aItems, $sRedirect, $aCustoms);
+        if(is_string($mixedResult))
+            return [bx_api_get_msg($mixedResult)];
+        
+        if(is_array($mixedResult)) {
+            if(isset($mixedResult['redirect'])) {
+                header('Location: ' . bx_api_get_relative_url($mixedResult['redirect']));
+                exit;
+            }
+
+            if(isset($mixedResult['message']))
+                return [bx_api_get_msg($mixedResult['message'])];
+        }
+
+        return [];
+    }
+
+    public function actionFinalizeCheckout($sProvider, $mixedVendorId = "")
+    {
+        $aData = &$_REQUEST;
+
+        $aResult = $this->serviceFinalizeCheckout($sProvider, $mixedVendorId, $aData);
+        if(isset($aResult['error']))
+            return $this->_oTemplate->displayPageCodeError($aResult['error']);
+        else if(isset($aResult['redirect'])) {
+            header('Location: ' . $aResult['redirect']);
+            exit;
+        }
+        else
+            $this->_oTemplate->displayPageCodeResponse($aResult['message']);
+    }
+    
+    public function serviceFinalizeCheckout($sProvider, $mixedVendorId = "", $aData = [])
+    {
+        $oProvider = $this->getObjectProvider($sProvider, $mixedVendorId);
+        if($oProvider === false || !$oProvider->isActive())
+            return ['error' => $this->_sLangsPrefix . 'err_incorrect_provider'];
+
+        $aResult = $oProvider->finalizeCheckout($aData);
+        if((int)$aResult['code'] != BX_PAYMENT_RESULT_SUCCESS) 
+            return ['error' => $aResult['message']];
+
+        $aPending = $this->_oDb->getOrderPending(['type' => 'id', 'id' => (int)$aResult['pending_id']]);
+        $bTypeRecurring = $aPending['type'] == BX_PAYMENT_TYPE_RECURRING;
+        $bAuthorized = isset($aResult['authorized']) && $aResult['authorized'];
+        $bPaid = isset($aResult['paid']) && $aResult['paid'];
+        $bTrial = isset($aResult['trial']) && $aResult['trial'];
+
+        //--- Register subscription
+        if($bTypeRecurring) {
+            $sStatus = BX_PAYMENT_SBS_STATUS_UNPAID;
+            if($bPaid)
+                $sStatus = BX_PAYMENT_SBS_STATUS_ACTIVE;
+            else if($bTrial)
+                $sStatus = BX_PAYMENT_SBS_STATUS_TRIAL;
+
+            $aSubscription = array(
+                'customer_id' => $aResult['customer_id'], 
+                'subscription_id' => $aResult['subscription_id'],
+                'status' => $sStatus
+            );
+
+            if(!$this->getObjectSubscriptions()->register($aPending, $aSubscription))
+                return ['error' => $this->_sLangsPrefix . 'err_already_registered'];
+        }
+
+        $this->onPaymentRegisterBefore($aPending);
+
+        //--- Check "Pay Before Join" situation
+        if((int)$aPending['client_id'] == 0)
+            $this->getObjectJoin()->performJoin((int)$aPending['id'], isset($aResult['client_name']) ? $aResult['client_name'] : '', isset($aResult['client_email']) ? $aResult['client_email'] : '');
+
+        //--- Authorize order for selected items in associated modules 
+        if($bAuthorized)
+            $this->authorizePayment($aPending);
+
+        //--- Register payment for purchased items in associated modules 
+        if($bPaid || ($bTypeRecurring && $bTrial))
+            $this->registerPayment($aPending);
+
+        //--- Get updated pending order
+        $aPending = $this->_oDb->getOrderPending(['type' => 'id', 'id' => $aPending['id']]);
+
+        $this->alert('finalize_checkout', 0, bx_get_logged_profile_id(), array(
+            'pending' => $aPending,
+            'transactions' => $this->_oDb->getOrderProcessed(array('type' => 'pending_id', 'pending_id' => (int)$aPending['id'])),
+            'provider' => $oProvider,
+
+            'message' => &$aResult['message'],
+            'result' => &$aResult,
+
+            'message_ref' => &$aResult['message'],
+            'result_ref' => &$aResult,
+        ));
+
+        if($oProvider->needRedirect()) 
+            return ['redirect' => $oProvider->getReturnUrl()];
+
+        if(!empty($aResult['redirect'])) 
+            return ['redirect' => $this->_oConfig->urlDecode($aResult['redirect'])];
+
+        return ['message' => $aResult['message']];
+    }
+
+    public function actionFinalizedCheckout($sProvider, $mixedVendorId = "")
+    {
+        $oProvider = $this->getObjectProvider($sProvider, $mixedVendorId);
+        if($oProvider === false || !$oProvider->isActive())
+            return $this->_oTemplate->displayPageCodeError($this->_sLangsPrefix . 'err_incorrect_provider');
+
+        $aResult = $oProvider->finalizedCheckout();
+        $this->_oTemplate->displayPageCodeResponse($aResult['message']);
+    }
+
+    public function actionNotify($sProvider, $mixedVendorId = "")
+    {
+    	$oProvider = $this->getObjectProvider($sProvider, $mixedVendorId);
+        if($oProvider === false || !$oProvider->isActive())
+            return $this->_oTemplate->displayPageCodeError($this->_sLangsPrefix . 'err_incorrect_provider');
+
+        $oProvider->notify();
+    }
+    
+    /**
+     * The method is needed to pass direct action calls to necessary Payment Provider.
+     */
+    public function actionCall($sProvider, $sAction, $mixedVendorId = BX_PAYMENT_EMPTY_ID)
+    {
+        $oProvider = $this->getObjectProvider($sProvider, $mixedVendorId);
+        if($oProvider === false)
+            BxDolRequest::methodNotFound($sAction, $this->getName());
+
+         $sMethod = 'action' . bx_gen_method_name($sAction);
+         if(!method_exists($oProvider, $sMethod))
+             BxDolRequest::methodNotFound($sAction, $this->getName());
+
+        return call_user_func_array(array($oProvider, $sMethod), array_slice(func_get_args(), 2));
+    }
+
+    public function onProfileJoin($iProfileId)
+    {
+    	$this->getObjectJoin()->onProfileJoin($iProfileId);
+    }
+
+    public function onProfileDelete($iProfileId)
+    {
+        //--- Cancel subscriptions
+        $aSubscriptions = $this->_oDb->getSubscription(['type' => 'mixed_ext', 'conditions' => ['client_id' => $iProfileId]]);
+        if(!empty($aSubscriptions) && is_array($aSubscriptions)) 
+            foreach($aSubscriptions as $aSubscription)
+                $this->getObjectSubscriptions()->cancel($aSubscription['pending_id']);
+
+        //--- Clean DB
+        $this->_oDb->onProfileDelete($iProfileId);
+    }
+
+    public function isAllowedPurchase($aItem, $bPerform = false)
+    {
+        $iUserId = (int)$this->getProfileId();
+
+        $aItemInfo = $this->callGetCartItem((int)$aItem['module_id'], array($aItem['item_id'], $iUserId, isset($aItem['custom']) ? $aItem['custom'] : array()));
+        if(empty($aItemInfo))
+            return false;
+
+        if(isAdmin())
+            return true;
+
+        $aCheckResult = checkActionModule($iUserId, 'purchase', $this->getName(), $bPerform);
+        if($aCheckResult[CHECK_ACTION_RESULT] == CHECK_ACTION_RESULT_ALLOWED)
+            return true;
+
+        return $aCheckResult[CHECK_ACTION_MESSAGE];
+    }
+
+    public function isAllowedSell($aItem, $bPerform = false)
+    {
+        $iUserId = (int)$this->getProfileId();
+        if(!$iUserId)
+            return false;
+
+        $aItemInfo = $this->callGetCartItem((int)$aItem['module_id'], array($aItem['item_id'], $iUserId));
+        if(empty($aItemInfo))
+            return false;
+
+        if(isAdmin())
+            return true;
+
+        $aCheckResult = checkActionModule($iUserId, 'sell', $this->getName(), $bPerform);
+        if((int)$aItemInfo['author_id'] == $iUserId && $aCheckResult[CHECK_ACTION_RESULT] == CHECK_ACTION_RESULT_ALLOWED)
+            return true;
+
+        return $aCheckResult[CHECK_ACTION_MESSAGE];
+    }
+
+    public function isAllowedManage($aPending, $bPerform = false)
+    {
+        $iUserId = (int)$this->getProfileId();
+
+        if($iUserId == $aPending['client_id'] || $iUserId == $aPending['seller_id'] || isAdmin())
+            return true;
+
+        $aCheckResult = checkActionModule($iUserId, 'manage any purchase', $this->getName(), $bPerform);
+        if($aCheckResult[CHECK_ACTION_RESULT] == CHECK_ACTION_RESULT_ALLOWED)
+            return true;
+
+        return $aCheckResult[CHECK_ACTION_MESSAGE];
+    }
+
+    public function isAllowedManageInvoices($bPerform = false)
+    {
+        if($this->_isModerator())
+            return true;
+
+        return _t('_sys_txt_access_denied');
+    }
+
+    public function checkData($iClientId, $iSellerId, $iModuleId, $iItemId, $iItemCount, $aCustom = array())
+    {
+    	$CNF = &$this->_oConfig->CNF;
+
+        if($iSellerId == BX_PAYMENT_EMPTY_ID || empty($iModuleId) || empty($iItemId) || empty($iItemCount))
+            return array('code' => 1, 'message' => _t($CNF['T']['ERR_WRONG_DATA']));
+
+        $iClientId = $this->getProfileId();
+        if(empty($iClientId)) {
+            $sLoginUrl = BxDolPermalinks::getInstance()->permalink('page.php?i=login');
+            return array('code' => 2, 'eval' => 'window.open("' . $sLoginUrl . '", "_self");');
+        }
+
+        $mixedResult = $this->isAllowedPurchase(array('module_id' => $iModuleId, 'item_id' => $iItemId, 'custom' => $aCustom));
+        if($mixedResult !== true) {
+            if(is_string($mixedResult) && !empty($mixedResult))
+                return array('code' => 2, 'message' => $mixedResult);
+            else 
+                return array('code' => 1, 'message' => _t($CNF['T']['ERR_WRONG_DATA']));
+        }
+
+        if($iClientId == $iSellerId)
+            return array('code' => 3, 'message' => _t($CNF['T']['ERR_SELF_PURCHASE']));
+
+        $aSeller = $this->getVendorInfo($iSellerId);
+        if(!$aSeller['active'])
+            return array('code' => 4, 'message' => _t($CNF['T']['ERR_INACTIVE_VENDOR']));
+
+		return true;
+    }
+
+    public function authorizePayment($mixedPending)
+    {
+        $aPending = is_array($mixedPending) ? $mixedPending : $this->_oDb->getOrderPending(['type' => 'id', 'id' => (int)$mixedPending]);
+    	if(empty($aPending) || !is_array($aPending))
+            return false;
+
+        $sType = $aPending['type'];
+        $bTypeSingle = $sType == BX_PAYMENT_TYPE_SINGLE;
+
+        if((int)$aPending['authorized'] == 1)
+            return true;
+
+        $iClientId = (int)$aPending['client_id'];
+
+        $aCart = array();
+        if($bTypeSingle)
+            $aCart = $this->_oDb->getCartContent($iClientId);
+        
+        $bResult = false;
+        $aItems = $this->_oConfig->descriptorsM2A($aPending['items']);
+        foreach($aItems as $aItem) {
+            $sItem = $this->_oConfig->descriptorA2S([$aItem['vendor_id'], $aItem['module_id'], $aItem['item_id']]);
+            
+            $sMethod = $bTypeSingle ? 'callAuthorizeCartItem' : 'callAuthorizeSubscriptionItem';
+            $aItemInfo = $this->$sMethod((int)$aItem['module_id'], [$aPending['client_id'], $aPending['seller_id'], $aItem['item_id'], $aItem['item_count'], $aPending['order']]);
+            if(empty($aItemInfo) || !is_array($aItemInfo))
+                continue;
+
+            if($bTypeSingle)
+            	$aCart['items'] = trim(preg_replace("'" . $this->_oConfig->descriptorA2S($aItem) . ":?'", "", $aCart['items']), ":");
+
+            $bResult = true;
+        }
+
+        if($bResult) {
+            $this->_oDb->updateOrderPending($aPending['id'], ['authorized' => 1]);
+
+            $this->onPaymentAuthorize($aPending);
+        }
+
+        return $bResult;
+    }
+    
+    public function registerPayment($mixedPending)
+    {
+    	$aPending = is_array($mixedPending) ? $mixedPending : $this->_oDb->getOrderPending(['type' => 'id', 'id' => (int)$mixedPending]);
+    	if(empty($aPending) || !is_array($aPending))
+            return false;
+
+        $sType = $aPending['type'];
+        $bTypeSingle = $sType == BX_PAYMENT_TYPE_SINGLE;
+
+        if($bTypeSingle && (int)$aPending['processed'] == 1)
+            return true;
+
+        $iClientId = (int)$aPending['client_id'];
+        $iSellerId = (int)$aPending['seller_id'];
+        $sLicense = $this->_oConfig->getLicense();
+        $aCustoms = !empty($aPending['customs']) ? $this->_oConfig->s2a($aPending['customs'], false) : [];
+        $aCart = $bTypeSingle ? $this->_oDb->getCartContent($iClientId) : [];
+
+        $bResult = false;
+        $aItems = $this->_oConfig->descriptorsM2A($aPending['items']);
+        foreach($aItems as $aItem) {
+            $sItem = $this->_oConfig->descriptorA2S([$aItem['vendor_id'], $aItem['module_id'], $aItem['item_id']]);
+            $aItemCustom = $this->_oConfig->getCustom($sItem, $aCustoms);
+
+            $sMethod = $bTypeSingle ? 'callRegisterCartItem' : 'callRegisterSubscriptionItem';
+            $aItemInfo = $this->$sMethod((int)$aItem['module_id'], [$iClientId, $iSellerId, $aItem['item_id'], $aItem['item_count'], $aPending['order'], $sLicense, $aItemCustom]);
+            if(empty($aItemInfo) || !is_array($aItemInfo))
+                continue;
+
+            $this->_oDb->insertOrderProcessed([
+                'pending_id' => $aPending['id'],
+                'client_id' => $iClientId,
+                'seller_id' => $iSellerId,
+                'author_id' => (int)$aItem['vendor_id'],
+                'module_id' => (int)$aItem['module_id'],
+                'item_id' => (int)$aItem['item_id'],
+                'item_count' => (int)$aItem['item_count'],
+                'amount' => (int)$aItem['item_count'] * $this->_oConfig->getPrice($sType, $aItemInfo),
+                'currency' => !empty($aPending['currency']) ? $aPending['currency'] : $this->getVendorCurrencyCode($iSellerId),
+            	'license' => $sLicense,
+            ]);
+
+            if($bTypeSingle) {
+                $this->_oConfig->pullCustom($sItem, $aCart['customs']);
+
+            	$aCart['items'] = trim(preg_replace("'" . $this->_oConfig->descriptorA2S($aItem) . ":?'", "", $aCart['items']), ":");
+            }
+
+            $bResult = true;
+        }
+
+        if($bTypeSingle)
+            $this->_oDb->setCartItems($iClientId, $aCart['items'], $aCart['customs']);
+
+        if($bResult) {
+            $this->_oDb->updateOrderPending($aPending['id'], ['processed' => 1]);
+
+            $this->onPaymentRegister($aPending);
+        }
+
+        return $bResult;
+    }
+
+    public function refundPayment($mixedPending)
+    {
+        $aPending = is_array($mixedPending) ? $mixedPending : $this->_oDb->getOrderPending(array('type' => 'id', 'id' => (int)$mixedPending));
+        if(empty($aPending) || !is_array($aPending))
+            return false;
+
+        $bTypeSingle = $aPending['type'] == BX_PAYMENT_TYPE_SINGLE;
+
+        $iCanceled = 0;
+        $aOrders = $this->_oDb->getOrderProcessed(array('type' => 'pending_id', 'pending_id' => (int)$aPending['id']));
+        foreach($aOrders as $aOrder) {
+            $sMethod = $bTypeSingle ? 'callUnregisterCartItem' : 'callUnregisterSubscriptionItem';
+            $bResult = $this->$sMethod((int)$aOrder['module_id'], array($aOrder['client_id'], $aOrder['seller_id'], $aOrder['item_id'], $aOrder['item_count'], $aPending['order'], $aOrder['license']));
+            if(!$bResult)
+                continue;
+
+            if($this->_oDb->deleteOrderProcessed($aOrder['id']))
+                $iCanceled++;
+        }
+
+        if($iCanceled != count($aOrders))
+                return false;
+
+        $bResult = $this->_oDb->deleteOrderPending($aPending['id']);
+        if($bResult)
+                $this->onPaymentRefund($aPending);
+
+        return $bResult;
+    }
+
+    /**
+     * @deprecated since version 12.0.0
+     * 
+     * @use BxPaymentSubscriptions::register instead.
+     */
+    public function registerSubscription($aPending, $aParams = array())
+    {
+        return $this->getObjectSubscriptions()->register($aPending, $aParams);
+    }
+
+    /**
+     * @deprecated since version 12.0.0
+     * 
+     * @use BxPaymentSubscriptions::cancelLocal instead.
+     */
+    public function cancelSubscription($mixedPending)
+    {
+        return $this->getObjectSubscriptions()->cancelLocal($mixedPending);
+    }
+
+    public function processCommissions()
+    {
+        if(!defined('BX_DOL_CRON_EXECUTE'))
+            return;
+
+        if(!$this->_oConfig->isCommissions())
+            return;
+
+        if((int)date('j') == $this->_oConfig->getInvoiceIssueDay())
+            $this->_invoicesIssue();
+
+        $this->_invoicesCheck();
+    }
+
+    protected function _invoicesIssue()
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $sInvoiceNameMask = 'INV-%d-%d-%d';
+
+        $iMonth = date('m');
+        $iYear = date('Y');
+        $iPeriodStart = mktime(0, 0, 0, $iMonth-1, 1, $iYear);
+        $iPeriodEnd = mktime(23, 59, 59, $iMonth, 0, $iYear);
+        $iDateIssue = time();
+        $iDateDue = $iDateIssue + 86400 * $this->_oConfig->getInvoiceLifetime();
+
+        $aCommissionsInfo = array();
+        $aAclLevels = BxDolAcl::getInstance()->getMemberships(false, true, false, true);
+        foreach($aAclLevels as $iAclLevelId => $sAclLevelTitle)
+            $aCommissionsInfo[$iAclLevelId] = $this->_oDb->getCommissions(['type' => 'acl_id', 'acl_id' => $iAclLevelId]);
+
+        $iMainSellerId = $this->_oConfig->getSiteAdmin();
+
+        $aVendors = $this->_oDb->getOrderProcessed(['type' => 'income', 'period_start' => $iPeriodStart, 'period_end' => $iPeriodEnd]);
+        foreach($aVendors as $aVendor) {
+            $iVendorId = (int)$aVendor['id'];
+            if($iVendorId == $iMainSellerId)
+                continue;
+
+            $aInvoice = $this->_oDb->getInvoices(['type' => 'committent_id', 'committent_id' => $iVendorId, 'period_start' => $iPeriodStart, 'period_end' => $iPeriodEnd]);
+            if(!empty($aInvoice) && is_array($aInvoice))
+                continue;
+
+            $aVendorAcl = BxDolAcl::getInstance()->getMemberMembershipInfo($iVendorId);
+            $aCommissions = $aCommissionsInfo[$aVendorAcl['id']];
+
+            $fCommission = 0;
+            foreach($aCommissions as $aCommission) {
+                if((float)$aCommission['percentage'] > 0)
+                    $fCommission += (float)$aVendor['amount'] * (float)$aCommission['percentage'] / 100;
+
+                if((float)$aCommission['installment'] > 0)
+                    $fCommission += (float)$aCommission['installment'];
+            }
+
+            $this->alert('calculate_commission', 0, 0, [
+                'vendor' => $aVendor,
+                'commissions' => $aCommissions,
+                'override_result' => &$fCommission,
+            ]);
+
+            if($fCommission > 0)
+                $this->_oDb->insertInvoice([
+                    'name' => sprintf($sInvoiceNameMask, $iMainSellerId, $iVendorId, $this->_oDb->getInvoices([
+                        'type' => 'index', 
+                        'commissionaire_id' => $iMainSellerId, 
+                        'committent_id' => $iVendorId
+                    ])),
+                    'commissionaire_id' => $iMainSellerId, 
+                    'committent_id' => $iVendorId,
+                    'amount' => $fCommission,
+                    'period_start' => $iPeriodStart,
+                    'period_end' => $iPeriodEnd,
+                    'date_issue' => $iDateIssue,
+                    'date_due' => $iDateDue,
+                    'status' => BX_PAYMENT_INV_STATUS_UNPAID
+                ]);
+        }
+    }
+
+    protected function _invoicesCheck()
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $sPrefix = $this->_oConfig->getPrefix('general');
+        $oEmailTemplates = BxDolEmailTemplates::getInstance();
+
+        //--- Process expiring invoices.
+        $aInvoices = $this->_oDb->getInvoices(array('type' => 'expiring'));
+        if(!empty($aInvoices) && is_array($aInvoices))
+            foreach($aInvoices as $aInvoice) {
+                if((int)$aInvoice['ntf_exp'] > 0)
+                    continue;
+
+                $oCommittent = BxDolProfile::getInstance($aInvoice['committent_id']);
+                if(!$oCommittent)
+                    continue;
+
+                $bResult = sendMailTemplate($sPrefix . 'expiring_notification_committent', 0, (int)$aInvoice['committent_id'], array(
+                    'invoice' => $aInvoice['name'],
+                    'days' => $this->_oConfig->getInvoiceExpirationNotify(),
+                    'period_start' => $this->_oConfig->formatDate($aInvoice['period_start']),
+                    'period_end' => $this->_oConfig->formatDate($aInvoice['period_end']),
+                    'date_issue' => $this->_oConfig->formatDateTime($aInvoice['date_issue']),
+                    'date_due' => $this->_oConfig->formatDateTime($aInvoice['date_due']),
+                ), BX_EMAIL_NOTIFY, true);
+
+                if($bResult)
+                    $this->_oDb->updateInvoice($aInvoice['id'], array('ntf_exp' => 1));
+            }
+
+        //--- Process overdue invoices.
+        $aInvoices = $this->_oDb->getInvoices(array('type' => 'overdue'));
+        if(!empty($aInvoices) && is_array($aInvoices))
+            foreach($aInvoices as $aInvoice) {
+                if((int)$aInvoice['ntf_due'] > 0 && $aInvoice['status'] == BX_PAYMENT_INV_STATUS_OVERDUE)
+                    continue;
+
+                $oCommittent = BxDolProfile::getInstance($aInvoice['committent_id']);
+                if(!$oCommittent)
+                    continue;
+
+                $bResult = sendMailTemplate($sPrefix . 'overdue_notification_committent', 0, (int)$aInvoice['committent_id'], array(
+                    'invoice' => $aInvoice['name'],
+                    'period_start' => $this->_oConfig->formatDate($aInvoice['period_start']),
+                    'period_end' => $this->_oConfig->formatDate($aInvoice['period_end']),
+                    'date_issue' => $this->_oConfig->formatDateTime($aInvoice['date_issue']),
+                    'date_due' => $this->_oConfig->formatDateTime($aInvoice['date_due']),
+                ), BX_EMAIL_NOTIFY, true);
+
+                $this->_oDb->updateInvoice($aInvoice['id'], array(
+                    'status' => BX_PAYMENT_INV_STATUS_OVERDUE, 
+                    'ntf_due' => $bResult ? 1 : 0
+                ));
+            }
+    }
+
+    public function processTimeTracker()
+    {
+        if(!defined('BX_DOL_CRON_EXECUTE'))
+            return;
+
+        $aSubscriptions = $this->_oDb->getSubscription(array(
+            'type' => 'time_tracker',
+            'status_active' => BX_PAYMENT_SBS_STATUS_ACTIVE,
+            'status_trial' => BX_PAYMENT_SBS_STATUS_TRIAL,
+            'status_unpaid' => BX_PAYMENT_SBS_STATUS_UNPAID,
+            'pay_attempts_max' => $this->_oConfig->getPayAttemptsMax(),
+            'pay_attempts_interval' => $this->_oConfig->getPayAttemptsInterval()
+        ));
+
+        if(empty($aSubscriptions) || !is_array($aSubscriptions))
+            return;
+
+        foreach($aSubscriptions as $aSubscription) {
+            $aPending = $this->_oDb->getOrderPending(array('type' => 'id', 'id' => (int)$aSubscription['pending_id']));
+            if(empty($aPending) || !is_array($aPending) || $aPending['type'] != BX_PAYMENT_TYPE_RECURRING) {
+                $this->log($aSubscription, 'Time Tracker', 'Cannot process subscription.', BX_LOG_ERR);
+                continue;
+            }
+
+            $oProvider = $this->getObjectProvider($aPending['provider'], $aPending['seller_id']);
+            if($oProvider === false || !$oProvider->isActive() || !method_exists($oProvider, 'makePayment')) {
+                $this->log($aSubscription, 'Time Tracker', 'Payment provider unavailable or incorrect.', BX_LOG_ERR);
+                continue;
+            }
+
+            $this->_oDb->updateSubscription(['pay_attempts' => (int)$aSubscription['pay_attempts'] + 1], ['id' => $aSubscription['id']]);
+
+            if(($mixedResult = $oProvider->makePayment($aPending)) !== true) {
+                $this->_oDb->updateSubscription(['status' => BX_PAYMENT_SBS_STATUS_UNPAID], ['id' => $aSubscription['id']]);
+
+                $this->log($aSubscription, 'Time Tracker', 'Payment cannot be processed (code: ' . (!empty($mixedResult['code']) ? (int)$mixedResult['code'] : 0) . ').', BX_LOG_ERR);
+                continue;
+            }
+
+            if(!$this->getObjectSubscriptions()->prolong($aPending)) {
+                $this->log($aSubscription, 'Time Tracker', 'Cannot prolong subscription.', BX_LOG_ERR);
+                continue;
+            }
+
+            if(!$this->registerPayment($aPending)) {
+                $this->log($aSubscription, 'Time Tracker', 'Cannot register payment.', BX_LOG_ERR);
+                continue;
+            }
+        }
+    }
+
+    public function onPaymentRegisterBefore($aPending, $aResult = [])
+    {
+        $this->alert('before_register_payment', 0, $aPending['client_id'], array('pending' => $aPending));
+    }
+
+    public function onPaymentAuthorize($aPending, $aResult = [])
+    {
+        $this->alert('authorize_payment', 0, $aPending['client_id'], ['pending' => $aPending]);
+    }
+
+    public function onPaymentRegister($aPending, $aResult = [])
+    {
+        $bTypeSingle = $aPending['type'] == BX_PAYMENT_TYPE_SINGLE;
+
+        if($bTypeSingle) {
+            $aItems = $this->_oConfig->descriptorsM2A($aPending['items']);
+            foreach($aItems as $aItem)
+                $this->isAllowedPurchase(['module_id' => $aItem['module_id'], 'item_id' => $aItem['item_id']], true);
+        }
+
+        $this->alert('register_payment', 0, $aPending['client_id'], ['pending' => $aPending]);
+    }
+
+    public function onPaymentRefund($aPending, $aResult = [])
+    {
+        $this->alert('refund_payment', 0, $aPending['client_id'], ['pending' => $aPending]);
+    }
+
+    public function onSubscriptionCreate($aPending, $aSubscription, $aResult = [])
+    {
+        $aItems = $this->_oConfig->descriptorsM2A($aPending['items']);
+        $this->isAllowedPurchase(['module_id' => $aItems[0]['module_id'], 'item_id' => $aItems[0]['item_id']], true);
+
+        $this->alert('create_subscription', 0, $aPending['client_id'], [
+            'pending' => $aPending,
+            'subscription' => $aSubscription
+        ]);
+    }
+
+    public function onSubscriptionProlong($aPending, $aSubscription, $aResult = [])
+    {
+        $this->alert('prolong_subscription', 0, $aPending['client_id'], [
+            'pending' => $aPending,
+            'subscription' => $aSubscription
+        ]);
+    }
+
+    public function onSubscriptionOverdue($aPending, $aSubscription, $aResult = [])
+    {
+        $this->alert('overdue_subscription', 0, $aPending['client_id'], [
+            'pending' => $aPending,
+            'subscription' => $aSubscription
+        ]);
+    }
+
+    public function onSubscriptionCancel($aPending, $aSubscription, $aResult = [])
+    {
+        $this->alert('cancel_subscription', 0, $aPending['client_id'], [
+            'pending' => $aPending,
+            'subscription' => $aSubscription
+        ]);
+    }
+
+    public function setSiteSubmenu($sSubmenu, $sSelModule, $sSelName)
+    {
+        $oSiteSubmenu = BxDolMenu::getObjectInstance('sys_site_submenu');
+        if(!$oSiteSubmenu)
+            return;
+
+        $sModuleSubmenu = $this->_oConfig->getObject($sSubmenu);
+        $oModuleSubmenu = BxDolMenu::getObjectInstance($sModuleSubmenu);
+        if(!$oModuleSubmenu) 
+            return;
+
+        $oSiteSubmenu->setObjectSubmenu($sModuleSubmenu);
+        $oModuleSubmenu->setSelected($sSelModule, $sSelName);
+    }
+
+    public function getProviderButtonJs($aCartItem, $aProvider, $sRedirect = '', $aCustom = array())
+    {
+        $aButtonJs = array();
+        $iClientId = $this->getProfileId();
+
+        $sItemAddons = '';
+        if(count($aCartItem) == 5)
+            $sItemAddons = array_pop($aCartItem);
+
+        list($iSellerId, $iModuleId, $iItemId, $iItemCount) = $aCartItem;
+
+        $oProvider = $this->getObjectProvider($aProvider['name'], $iSellerId);
+        if($oProvider !== false && method_exists($oProvider, 'getButtonRecurring')) {
+            $aParams = array(
+                'sObjNameCart' => $this->_oConfig->getJsObject('cart'),
+                'iSellerId' => $iSellerId,
+                'iModuleId' => $iModuleId,
+                'iItemId' => $iItemId,
+                'iItemCount' => $iItemCount,
+                'sItemAddons' => $sItemAddons,
+                'sRedirect' => $sRedirect,
+                'sCustom' => base64_encode(json_encode($aCustom))
+            );
+
+            $aCartInfo = $this->getObjectCart()->getInfo(BX_PAYMENT_TYPE_RECURRING, $iClientId, $iSellerId, $this->_oConfig->descriptorA2S($aCartItem));
+            if(!empty($aCartInfo['items_price']) && !empty($aCartInfo['items']) && is_array($aCartInfo['items'])) {
+                $aItem = array_shift($aCartInfo['items']);
+
+                $aParams = array_merge($aParams, array(
+                    'iAmount' => (int)round(100 * (float)$aCartInfo['items_price']),
+                    'sItemName' => $aItem['name'],
+                    'sItemTitle' => $aItem['title']
+                ));
+            }
+
+            $aButtonJs = $oProvider->getButtonRecurringJs($iClientId, $iSellerId, $aParams);
+        }
+
+        if(empty($aButtonJs) || !is_array($aButtonJs))
+            $aButtonJs = $this->getObjectSubscriptions()->serviceGetSubscribeJs($iSellerId, $aProvider['name'], $iModuleId, $iItemId, $iItemCount, $sRedirect, $aCustom);
+
+        return $aButtonJs;
+    }
+
+    /**
+     * Integration with itslef which is needed to pay an invoice.
+     */
+
+    /**
+     * @page service Service Calls
+     * @section bx_payment Payment
+     * @subsection bx_payment-payments Payments
+     * @subsubsection bx_payment-get_payment_data get_payment_data
+     * 
+     * @code bx_srv('bx_payment', 'get_payment_data', [...]); @endcode
+     * 
+     * Get an array with module's description. Is needed for payments processing module.
+     * 
+     * @return an array with module's description.
+     * 
+     * @see BxPaymentModule::serviceGetPaymentData
+     */
+    /** 
+     * @ref bx_payment-get_payment_data "get_payment_data"
+     */
+    public function serviceGetPaymentData()
+    {
+        return $this->_aModule;
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_payment Payment
+     * @subsection bx_payment-payments Payments
+     * @subsubsection bx_payment-get_cart_item get_cart_item
+     * 
+     * @code bx_srv('bx_payment', 'get_cart_item', [...]); @endcode
+     * 
+     * Get an array with prodict's description. Is used in Shopping Cart in payments processing module.
+     * 
+     * @param $mixedItemId product's ID or Unique Name.
+     * @return an array with prodict's description. Empty array is returned if something is wrong.
+     * 
+     * @see BxPaymentModule::serviceGetCartItem
+     */
+    /** 
+     * @ref bx_payment-get_cart_item "get_cart_item"
+     */
+    public function serviceGetCartItem($mixedItemId)
+    {
+    	$CNF = &$this->_oConfig->CNF;
+
+        if(!$mixedItemId)
+            return array();
+
+        if(is_numeric($mixedItemId))
+            $aItem = $this->_oDb->getInvoices(array('type' => 'id', 'id' => (int)$mixedItemId));
+        else 
+            $aItem = $this->_oDb->getInvoices(array('type' => 'name', 'name' => $mixedItemId));
+
+        if(empty($aItem) || !is_array($aItem))
+            return array();
+
+        $oCommissionaire = BxDolProfile::getInstanceMagic($aItem['commissionaire_id']);
+
+        return array (
+            'id' => $aItem['id'],
+            'author_id' => $aItem['commissionaire_id'],
+            'name' => $aItem['name'],
+            'title' => _t('_bx_payment_txt_invoice_title', $aItem['name'], $oCommissionaire->getDisplayName()),
+            'description' => _t('_bx_payment_txt_invoice_description', bx_process_output($aItem['period_start'], BX_DATA_DATE_TS_UTC), bx_process_output($aItem['period_end'], BX_DATA_DATE_TS_UTC)),
+            'url' => '',
+            'price_single' => $aItem['amount'],
+            'price_recurring' => '',
+            'period_recurring' => 0,
+            'period_unit_recurring' => '',
+            'trial_recurring' => ''
+        );
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_payment Payment
+     * @subsection bx_payment-payments Payments
+     * @subsubsection bx_payment-get_cart_items get_cart_items
+     * 
+     * @code bx_srv('bx_payment', 'get_cart_items', [...]); @endcode
+     * 
+     * Get an array with prodicts' descriptions by seller. Is used in Manual Order Processing in payments processing module.
+     * 
+     * @param $iCommissionaireId commissionaire ID.
+     * @return an array with prodicts' descriptions. Empty array is returned if something is wrong or seller doesn't have any products.
+     * 
+     * @see BxPaymentModule::serviceGetCartItems
+     */
+    /** 
+     * @ref bx_payment-get_cart_items "get_cart_items"
+     */
+    public function serviceGetCartItems($iCommissionaireId)
+    {
+    	$CNF = &$this->_oConfig->CNF;
+
+        $iCommissionaireId = (int)$iCommissionaireId;
+        if(empty($iCommissionaireId))
+            return array();
+
+        $sCommissionaireName = BxDolProfile::getInstanceMagic($iCommissionaireId)->getDisplayName();
+
+        $aItems = $this->_oDb->getInvoices(array('type' => 'commissionaire_id', 'commissionaire_id' => $iCommissionaireId));      
+
+        $aResult = array();
+        foreach($aItems as $aItem)
+            $aResult[] = array(
+                'id' => $aItem['id'],
+                'author_id' => $aItem['commissionaire_id'],
+                'name' => $aItem['name'],
+                'title' => _t('_bx_payment_txt_invoice_title', $aItem['name'], $sCommissionaireName),
+                'description' => _t('_bx_payment_txt_invoice_description', bx_process_output($aItem['period_start'], BX_DATA_DATE_TS_UTC), bx_process_output($aItem['period_end'], BX_DATA_DATE_TS_UTC)),
+                'url' => '',
+                'price_single' => $aItem['amount'],
+                'price_recurring' => '',
+                'period_recurring' => 0,
+                'period_unit_recurring' => '',
+                'trial_recurring' => ''
+            );
+
+        return $aResult;
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_payment Payment
+     * @subsection bx_payment-payments Payments
+     * @subsubsection bx_payment-register_cart_item register_cart_item
+     * 
+     * @code bx_srv('bx_payment', 'register_cart_item', [...]); @endcode
+     * 
+     * Register a processed single time payment inside the Payment module. Is called with payment processing module after the payment was registered there.
+     * 
+     * @param $iClientId client ID.
+     * @param $iSellerId seller ID
+     * @param $iItemId item ID.
+     * @param $iItemCount the number of purchased items.
+     * @param $sOrder order number received from payment provider (PayPal, Stripe, etc)
+     * @param $sLicense license number genereted with payment processing module for internal usage
+     * @return an array with purchased prodict's description. Empty array is returned if something is wrong.
+     * 
+     * @see BxPaymentModule::serviceRegisterCartItem
+     */
+    /** 
+     * @ref bx_payment-register_cart_item "register_cart_item"
+     */
+    public function serviceRegisterCartItem($iClientId, $iSellerId, $iItemId, $iItemCount, $sOrder, $sLicense)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+    	$aItem = $this->serviceGetCartItem($iItemId);
+        if(empty($aItem) || !is_array($aItem))
+            return array();
+
+        if(!$this->_oDb->updateInvoice($iItemId, array('status' => BX_PAYMENT_INV_STATUS_PAID)))
+            return array();
+
+        $this->alert('invoice_marked_as_paid', 0, false, array(
+            'product_id' => $iItemId,
+            'profile_id' => $iClientId,
+            'order' => $sOrder,
+            'license' => $sLicense,
+            'type' => BX_PAYMENT_TYPE_SINGLE,
+            'count' => $iItemCount,
+            'duration' => '',
+            'trial' => ''
+        ));
+
+        return $aItem;
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_payment Payment
+     * @subsection bx_payment-payments Payments
+     * @subsubsection bx_payment-unregister_cart_item unregister_cart_item
+     * 
+     * @code bx_srv('bx_payment', 'unregister_cart_item', [...]); @endcode
+     * 
+     * Unregister an earlier processed single time payment inside the Payment module. Is called with payment processing module after the payment was unregistered there.
+     * 
+     * @param $iClientId client ID.
+     * @param $iSellerId seller ID
+     * @param $iItemId item ID.
+     * @param $iItemCount the number of purchased items.
+     * @param $sOrder order number received from payment provider (PayPal, Stripe, etc)
+     * @param $sLicense license number genereted with payment processing module for internal usage
+     * @return boolean value determining where the payment was unregistered or not.
+     * 
+     * @see BxPaymentModule::serviceUnregisterCartItem
+     */
+    /** 
+     * @ref bx_payment-unregister_cart_item "unregister_cart_item"
+     */
+    public function serviceUnregisterCartItem($iClientId, $iSellerId, $iItemId, $iItemCount, $sOrder, $sLicense)
+    {
+        if(!$this->_oDb->updateInvoice($iItemId, array('status' => BX_PAYMENT_INV_STATUS_UNPAID)))
+            return false;
+
+        $this->alert('invoice_marked_as_unpaid', 0, false, array(
+            'product_id' => $iItemId,
+            'profile_id' => $iClientId,
+            'order' => $sOrder,
+            'license' => $sLicense,
+            'type' => BX_PAYMENT_TYPE_SINGLE,
+            'count' => $iItemCount
+        ));
+
+    	return true;
+    }
+
+    public function serviceStripeV3CreateSessionApi($mixedParams)
+    {
+        $aParams = is_array($mixedParams) ? $mixedParams : json_decode($mixedParams, true);
+        if(!isset($aParams['type'], $aParams['seller_id'], $aParams['items']))
+            return [bx_api_get_msg(_t($this->_sLangsPrefix . 'err_wrong_data'))];
+
+        $sType = $aParams['type'];
+        $sProvider = 'stripe_v3';
+        $iClientId = $this->getProfileId();
+        $iSellerId = (int)$aParams['seller_id'];
+        $sItems = $aParams['items'];
+
+        $oProvider = $this->getObjectProvider($sProvider, $iSellerId);
+        if($oProvider === false || !$oProvider->isActive())
+            return [bx_api_get_msg(_t($this->_sLangsPrefix . 'err_incorrect_provider'))];
+
+        $aSessionParams = [];
+        if(!empty($aParams['return_url'])) {
+            $sRedirect = $this->_oConfig->urlEncode($this->_oConfig->getUrl('URL_' . ($sType == BX_PAYMENT_TYPE_RECURRING ? 'SUBSCRIPTIONS' : 'HISTORY')));
+
+            $aSessionParams['return_url'] = $aParams['return_url'] . '/api.php?r=' . $this->getName() . '/initialize_checkout_api&params[]=' . implode('&params[]=', [$sType, $iSellerId, $sProvider, $sItems, $sRedirect]);
+        }
+        
+        $minxedSession = $oProvider->createSessionPaymentEmbedded($sType, $iClientId, $iSellerId, $sItems, $aSessionParams);
+        if($minxedSession === false)
+            return [bx_api_get_msg(_t($this->_sLangsPrefix . 'err_cannot_perform'))];
+
+        return [
+            'clientSecret' => $minxedSession
+        ];
+    }
+
+    public function serviceConvert($fAmount, $sCurrencyFrom, $sCurrencyTo, $fRate = false)
+    {
+        $sCurrencyDefault = $this->_oConfig->getDefaultCurrencyCode();
+        $bFromDefault = strcmp($sCurrencyFrom, $sCurrencyDefault) == 0;
+        $bToDefault = strcmp($sCurrencyTo, $sCurrencyDefault) == 0;
+
+        if(!$bFromDefault && !$bToDefault)
+            return false;
+
+        if($fRate === false)
+            $fRate = $this->_oDb->getCurrencyExchangeRate($bFromDefault ? $sCurrencyTo : $sCurrencyFrom);
+        if($fRate === false)
+            return false;
+
+        $fRate = (float)$fRate;
+        if($bToDefault)
+            $fRate = 1/$fRate;
+
+        return $fAmount * $fRate;
+    }
+
+    public function updateCurrencyExchangeRates()
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $sApiKey = getParam($CNF['PARAM_CURRENCY_EXCHANGE_API']);
+        if(empty($sApiKey))
+            return;
+
+        $sCurrency = $this->_oDb->getParam($CNF['PARAM_CURRENCY_CODE'], false);
+        $aCurrencies = BxDolForm::getDataItems($CNF['OBJECT_FORM_PRELISTS_CURRENCIES'], false, BX_DATA_VALUES_ADDITIONAL);
+        unset($aCurrencies[$sCurrency]);
+
+        $sApiEndpoint = 'https://api.apilayer.com/exchangerates_data/latest';
+        $aApiParams = [
+            'symbols' => implode(',', array_keys($aCurrencies)), 
+            'base' => $sCurrency
+        ];
+        $sResponse = bx_file_get_contents($sApiEndpoint, $aApiParams, 'get', [
+            'apikey: ' . $sApiKey
+        ]);
+
+        $aResponse = json_decode($sResponse, true);
+        if(empty($aResponse['rates']) || !is_array($aResponse['rates']))
+            return;
+
+        $this->_oDb->deleteCurrencyExchangeRate($sCurrency);
+
+        foreach($aResponse['rates'] as $sCode => $fRate)
+            $this->_oDb->updateCurrencyExchangeRate($sCode, $fRate);
+    }
+}
+
+/** @} */

+ 444 - 0
modules/boonex/payment/updates/15.0.1_15.0.2/source/classes/BxPaymentProviderChargebeeV3.php

@@ -0,0 +1,444 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Payment Payment
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+require_once('BxPaymentProviderChargebee.php');
+
+use ChargeBee\ChargeBee\Environment;
+use ChargeBee\ChargeBee\Models\PortalSession;
+
+class BxPaymentProviderChargebeeV3 extends BxPaymentProviderChargebee
+{
+    function __construct($aConfig)
+    {
+        $this->MODULE = 'bx_payment';
+
+        parent::__construct($aConfig);
+
+        $this->_aIncludeJs = array(
+            'https://js.chargebee.com/v2/chargebee.js',
+            'main.js',
+            'chargebee_v3.js'
+        );
+
+        $this->_aIncludeCss = array(
+            'chargebee_v3.css'
+        );
+    }
+
+    public function actionGetHostedPageSingle($iClientId, $iVendorId)
+    {
+        $this->initOptionsByVendor($iVendorId);
+
+        $aCartInfo = $this->_oModule->getObjectCart()->getInfo(BX_PAYMENT_TYPE_SINGLE, $iClientId, $iVendorId);
+
+        $aItem = [
+            'amount' => 100 * $aCartInfo['items_price'], 
+            'description' => _t($this->_sLangsPrefix . 'txt_payment_to', $aCartInfo['vendor_name'])
+        ];
+
+        $mixedItemAddons = bx_process_input(bx_get('addons'));
+        if(!empty($mixedItemAddons)) {
+            $aItemAddons = is_array($mixedItemAddons) ? $mixedItemAddons : $this->_oModule->_oConfig->s2a($mixedItemAddons);
+
+            foreach($aItemAddons as $sItemAddon)
+                if(!isset($aItem['addons'][$sItemAddon]))
+                    $aItem['addons'][$sItemAddon] = array(
+                        'id' => $sItemAddon,
+                        'quantity' => 1
+                    );
+                else 
+                    $aItem['addons'][$sItemAddon]['quantity'] += 1;
+
+            $aItem['addons'] = array_values($aItem['addons']);
+        }
+
+        $aClient = $this->_oModule->getProfileInfo($iClientId);
+
+        $oPage = $this->createHostedPageSingle($aItem, $aClient);
+        if($oPage === false)
+            return echoJson(array());
+
+        header('Content-type: text/html; charset=utf-8');
+        echo $oPage->toJson();
+    }
+
+    public function actionGetHostedPageRecurring($iClientId, $iVendorId, $sItemName)
+    {
+        $this->initOptionsByVendor($iVendorId);
+
+        $aItem = array('name' => $sItemName);
+
+        $mixedItemAddons = bx_process_input(bx_get('addons'));
+        if(!empty($mixedItemAddons)) {
+            $aItemAddons = is_array($mixedItemAddons) ? $mixedItemAddons : $this->_oModule->_oConfig->s2a($mixedItemAddons);
+
+            foreach($aItemAddons as $sItemAddon)
+                if(!isset($aItem['addons'][$sItemAddon]))
+                    $aItem['addons'][$sItemAddon] = array(
+                        'id' => $sItemAddon,
+                        'quantity' => 1
+                    );
+                else 
+                    $aItem['addons'][$sItemAddon]['quantity'] += 1;
+
+            $aItem['addons'] = array_values($aItem['addons']);
+        }
+        $aClient = $this->_oModule->getProfileInfo($iClientId);
+
+        $oPage = $this->createHostedPageRecurring($aItem, $aClient);
+        if($oPage === false)
+            return echoJson(array());
+
+        header('Content-type: text/html; charset=utf-8');
+        echo $oPage->toJson();
+    }
+
+    public function actionGetPortal($iPendingId)
+    {
+    	if(!isLogged())
+            return echoJson(array());
+
+    	$aPending = $this->_oModule->_oDb->getOrderPending(array('type' => 'id', 'id' => $iPendingId));
+    	if(empty($aPending) || !is_array($aPending))
+            return echoJson(array());
+
+    	$this->initOptionsByVendor((int)$aPending['seller_id']);
+
+    	$aSubscription = $this->_oModule->_oDb->getSubscription(array('type' => 'pending_id', 'pending_id' => $iPendingId));
+    	if(empty($aSubscription) || !is_array($aSubscription))
+            return echoJson(array());
+
+    	$oPortal = $this->getPortal($aSubscription['customer_id'], $aSubscription['subscription_id']);
+    	if($oPortal === false)
+            return echoJson(array());
+
+    	header('Content-type: text/html; charset=utf-8');
+    	echo $oPortal->toJson();
+    }
+
+    public function addJsCss()
+    {
+    	if(!$this->isActive())
+            return;
+
+        $this->_oModule->_oTemplate->addJs($this->_aIncludeJs);
+        $this->_oModule->_oTemplate->addCss($this->_aIncludeCss);
+    }
+
+    public function getJsObject($aParams = array())
+    {
+        $sJsObject = $this->_oModule->_oConfig->getJsObject($this->_sName);
+        if(isset($aParams['iModuleId'], $aParams['iSellerId'], $aParams['iItemId']))
+            $sJsObject .= '_' . md5($aParams['iModuleId'] . '-' . $aParams['iSellerId'] . '-' . $aParams['iItemId']);
+        
+        return $sJsObject;
+    }
+
+    public function initializeCheckout($iPendingId, $aCartInfo, $sRedirect = '')
+    {
+        $sPageId = bx_process_input(bx_get('page_id'));
+        if(empty($sPageId) || empty($iPendingId))
+            return $this->_sLangsPrefix . 'err_wrong_data';
+
+    	$aItem = array_shift($aCartInfo['items']);
+    	if(empty($aItem) || !is_array($aItem))
+            return $this->_sLangsPrefix . 'err_empty_items';
+
+        $aClient = $this->_oModule->getProfileInfo();
+        $aVendor = $this->_oModule->getProfileInfo($aCartInfo['vendor_id']);
+
+        $oPage = $this->retreiveHostedPage($sPageId);
+        if($oPage === false)
+            return $this->_sLangsPrefix . 'err_cannot_perform';
+
+        $aPending = $this->_oModule->_oDb->getOrderPending(array('type' => 'id', 'id' => $iPendingId));
+        if(!empty($aPending['order']) || !empty($aPending['error_code']) || !empty($aPending['error_msg']) || (int)$aPending['processed'] != 0)
+            return $this->_sLangsPrefix . 'err_already_processed';
+
+        $aResult = [];
+        switch($aPending['type']) {
+            case BX_PAYMENT_TYPE_SINGLE:
+                $oInvoice = $oPage->content()->invoice();
+
+                $aResult = [
+                    'code' => 0,
+                    'eval' => $this->_oModule->_oConfig->getJsObject('cart') . '.onCartCheckout(oData);',
+                    'link' => $this->getReturnDataUrl($aVendor['id'], [
+                        'order_id' => $oInvoice->id,
+                        'customer_id' => $oInvoice->customerId,
+                        'pending_id' => $aPending['id'],
+                        'redirect' => $sRedirect
+                    ])
+                ];
+                break;
+
+            case BX_PAYMENT_TYPE_RECURRING:
+                $aResult = [
+                    'code' => 0,
+                    'eval' => $this->_oModule->_oConfig->getJsObject('cart') . '.onSubscribeSubmit(oData);',
+                    'redirect' => $this->getReturnDataUrl($aVendor['id'], [
+                        'order_id' => $oPage->content()->subscription()->id,
+                        'customer_id' => $oPage->content()->customer()->id,
+                        'pending_id' => $aPending['id'],
+                        'redirect' => $sRedirect
+                    ])
+                ];
+                break;
+        }
+
+        return $aResult;
+    }
+
+    public function finalizeCheckout(&$aData)
+    {
+        $sOrderId = bx_process_input($aData['order_id']);
+    	$sCustomerId = bx_process_input($aData['customer_id']);
+        $iPendingId = bx_process_input($aData['pending_id'], BX_DATA_INT);
+        if(empty($iPendingId))
+            return array('code' => 1, 'message' => $this->_sLangsPrefix . 'err_wrong_data');
+
+        $sRedirect = bx_process_input($aData['redirect']);
+
+        $aPending = $this->_oModule->_oDb->getOrderPending(array('type' => 'id', 'id' => $iPendingId));
+        if(!empty($aPending['order']) || !empty($aPending['error_code']) || !empty($aPending['error_msg']) || (int)$aPending['processed'] != 0)
+            return array('code' => 3, 'message' => $this->_sLangsPrefix . 'err_already_processed');
+
+        $oCustomer = $this->retrieveCustomer($sCustomerId);
+        if($oCustomer === false)
+            return array('code' => 4, 'message' => $this->_sLangsPrefix . 'err_cannot_perform');
+
+        $sOrder = '';
+        $aResult = [
+            'code' => BX_PAYMENT_RESULT_SUCCESS,
+            'message' => '',
+            'pending_id' => $iPendingId,
+            'client_name' => _t($this->_sLangsPrefix . 'txt_buyer_name_mask', $oCustomer->firstName, $oCustomer->lastName),
+            'client_email' => $oCustomer->email,
+            'paid' => false,
+            'redirect' => $sRedirect
+        ];
+
+        switch($aPending['type']) {
+            case BX_PAYMENT_TYPE_SINGLE:
+                $oInvoice = $this->retrieveInvoice($sOrderId);
+                if($oInvoice === false || empty($oInvoice->linkedPayments))
+                    return ['code' => 4, 'message' => $this->_sLangsPrefix . 'err_cannot_perform'];
+
+                $sOrder = $oInvoice->linkedPayments[0]->txnId;
+                $aResult = array_merge($aResult, [
+                    'message' => $this->_sLangsPrefix . 'cbee_msg_charged',
+                    'paid' => $oInvoice->status == 'paid',
+                ]);
+                break;
+
+            case BX_PAYMENT_TYPE_RECURRING:
+                $oSubscription = $this->retrieveSubscription($sOrderId);
+                if($oSubscription === false)
+                    return ['code' => 4, 'message' => $this->_sLangsPrefix . 'err_cannot_perform'];
+
+                $sOrder = $oSubscription->id;
+                $aResult = array_merge($aResult, [
+                    'message' => $this->_sLangsPrefix . 'cbee_msg_subscribed',
+                    'customer_id' => $oCustomer->id,
+                    'subscription_id' => $oSubscription->id,
+                    'trial' => $oSubscription->status == 'in_trial',
+                ]);
+
+                break;
+        }
+
+        //--- Update pending transaction ---//
+        $this->_oModule->_oDb->updateOrderPending($iPendingId, [
+            'order' => $sOrder,
+            'error_code' => $aResult['code'],
+            'error_msg' => _t($aResult['message'])
+        ]);
+
+        return $aResult;
+    }
+
+    public function getPortal($sCustomerId, $sSubscriptionId)
+    {
+    	$oPortal = false;
+
+    	try {
+            Environment::configure($this->_getSite(), $this->_getApiKey());
+            $oResult = PortalSession::create(array(
+                'customer' => array(
+                    'id' => $sCustomerId
+                )
+            ));
+
+            $oPortal = $oResult->portalSession();
+    	}
+    	catch (Exception $oException) {
+            $iError = $oException->getCode();
+            $sError = $oException->getMessage();
+
+            $this->log('Get Portal Error: ' . $sError . '(' . $iError . ')', '', BX_LOG_ERR);
+
+            return false;
+    	}
+
+    	return $oPortal;
+    }
+
+    public function getJsCode($aParams = array())
+    {
+    	$sSite = '';
+        /**
+         * @hooks
+         * @hookdef hook-bx_payment-chargebee_v3_get_js_code 'bx_payment', 'chargebee_v3_get_js_code' - hook to override JavaScript code
+         * - $unit_name - equals `bx_payment`
+         * - $action - equals `chargebee_v3_get_js_code`
+         * - $object_id - not used
+         * - $sender_id - not used
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `site` - [string] by ref, site name from ChargeBee account, can be overridden in hook processing
+         *      - `params` - [array] by ref, params array as key&value pairs, can be overridden in hook processing
+         * @hook @ref hook-bx_payment-chargebee_v3_get_js_code
+         */
+    	bx_alert($this->_oModule->_oConfig->getName(), $this->_sName . '_get_js_code', 0, 0, [
+            'site' => &$sSite,
+            'params' => &$aParams,
+
+            'site_ref' => &$sSite,
+            'param_ref' => &$aParams
+    	]);
+
+    	return $this->_oModule->_oTemplate->getJsCode($this->_sName, array_merge(array(
+            'sProvider' => $this->_sName,
+            'sSite' => !empty($sSite) ? $sSite : $this->_getSite()
+    	), $aParams));
+    }
+
+    public function getButtonSingle($iClientId, $iVendorId, $aParams = [])
+    {
+        $oCart = $this->_oModule->getObjectCart();
+        $aCartInfo = $oCart->getInfo(BX_PAYMENT_TYPE_SINGLE, $iClientId, (int)$iVendorId);
+        if(empty($aCartInfo) || !is_array($aCartInfo))
+            return '';
+
+        $aItems = [];
+        $aCartItems = $oCart->getCartItems($iClientId, $iVendorId);
+        foreach($aCartItems as $aCartItem)
+            $aItems[] = $this->_oModule->_oConfig->descriptorA2S($aCartItem);
+
+    	return $this->_getButton(BX_PAYMENT_TYPE_SINGLE, $iClientId, $iVendorId, array_merge($aParams, [
+            'iSellerId' => $iVendorId,
+            'aItems' => $aItems
+    	]));
+    }
+
+    public function getButtonSingleJs($iClientId, $iVendorId, $aParams = [])
+    {
+        $oCart = $this->_oModule->getObjectCart();
+        $aCartInfo = $oCart->getInfo(BX_PAYMENT_TYPE_SINGLE, $iClientId, (int)$iVendorId);
+        if(empty($aCartInfo) || !is_array($aCartInfo))
+            return '';
+
+        $aItems = [];
+        $aCartItems = $oCart->getCartItems($iClientId, $iVendorId);
+        foreach($aCartItems as $aCartItem)
+            $aItems[] = $this->_oModule->_oConfig->descriptorA2S($aCartItem);
+
+    	return $this->_getButtonJs(BX_PAYMENT_TYPE_SINGLE, $iClientId, $iVendorId, array_merge($aParams, [
+            'iSellerId' => $iVendorId,
+            'aItems' => $aItems
+    	]));
+    }
+
+    public function getButtonRecurring($iClientId, $iVendorId, $aParams = array())
+    {
+        return $this->_getButton(BX_PAYMENT_TYPE_RECURRING, $iClientId, $iVendorId, $aParams);
+    }
+
+    public function getButtonRecurringJs($iClientId, $iVendorId, $aParams = array())
+    {
+        return $this->_getButtonJs(BX_PAYMENT_TYPE_RECURRING, $iClientId, $iVendorId, $aParams);
+    }
+
+    protected function _getButton($sType, $iClientId, $iVendorId, $aParams = array())
+    {
+        list($sJsCode, $sJsMethod) = $this->_getButtonJs($sType, $iClientId, $iVendorId, $aParams);        
+
+        return $this->_oModule->_oTemplate->parseHtmlByName('cbee_v3_button_' . $sType . '.html', array(
+            'type' => $sType,
+            'link' => 'javascript:void(0)',
+            'caption' => _t($this->_sLangsPrefix . 'cbee_txt_checkout_with_' . $sType, $this->_sCaption),
+            'onclick' => $sJsMethod,
+            'js_object' => $this->_oModule->_oConfig->getJsObject($this->_sName),
+            'js_code' => $sJsCode
+        ));
+    }
+    
+    protected function _getButtonJs($sType, $iClientId, $iVendorId, $aParams = array())
+    {
+        $sSite = '';
+
+        /**
+         * @hooks
+         * @hookdef hook-bx_payment-chargebee_v3_get_button 'bx_payment', 'chargebee_v3_get_button' - hook to override checkout/subscibe button
+         * - $unit_name - equals `bx_payment`
+         * - $action - equals `chargebee_v3_get_button`
+         * - $object_id - not used
+         * - $sender_id - client (buyer) profile id
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `type` - [string] by ref, payment type ('single' or 'recurring'), can be overridden in hook processing
+         *      - `site` - [string] by ref, site name from ChargeBee account, can be overridden in hook processing
+         *      - `params` - [array] by ref, params array as key&value pairs, can be overridden in hook processing
+         * @hook @ref hook-bx_payment-chargebee_v3_get_button
+         */
+        bx_alert($this->_oModule->_oConfig->getName(), $this->_sName . '_get_button', 0, $iClientId, [
+            'type' => &$sType, 
+            'site' => &$sSite,
+            'params' => &$aParams,
+
+            'type_ref' => &$sType, 
+            'site_ref' => &$sSite,
+            'params_ref' => &$aParams,
+        ]);
+
+        $sJsMethod = '';
+        $sJsObject = $this->getJsObject($aParams);
+        switch($sType) {
+            case BX_PAYMENT_TYPE_SINGLE:
+                $sJsMethod = $sJsObject . '.checkout(this)';
+                break;
+
+            case BX_PAYMENT_TYPE_RECURRING:
+                $sJsMethod = $sJsObject . '.subscribe(this)';
+                break;
+        }
+
+        return array($this->_oModule->_oTemplate->getJsCode($this->_sName, array_merge(array(
+            'js_object' => $sJsObject,
+            'sProvider' => $this->_sName,
+            'sSite' => !empty($sSite) ? $sSite : $this->_getSite(),
+            'iClientId' => $iClientId
+        ), $aParams)), $sJsMethod);
+    }
+
+    public function getMenuItemsActionsRecurring($iClientId, $iVendorId, $aParams = array())
+    {
+        if(empty($aParams['id']))
+            return array();
+
+        $sPrefix = 'bx-payment-strp-';
+        $sJsObject = $this->_oModule->_oConfig->getJsObject($this->_sName);
+
+        return array(
+            array('id' => $sPrefix . 'manager', 'name' => $sPrefix . 'manager', 'class' => '', 'link' => 'javascript:void(0)', 'onclick' => "javascript:return " . $sJsObject . ".manage(this, '" . $aParams['id'] . "')", 'target' => '_self', 'title' => _t('_bx_payment_cbee_menu_item_title_manager'))
+        );
+    }
+}
+
+/** @} */

+ 310 - 0
modules/boonex/payment/updates/15.0.1_15.0.2/source/classes/BxPaymentProviderPayPal.php

@@ -0,0 +1,310 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Payment Payment
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+/**
+ * Usefull links related to the integration:
+ * 
+ * HTML Form Basics for PayPal Payments Standard
+ * https://developer.paypal.com/docs/classic/paypal-payments-standard/integration-guide/formbasics/
+ * 
+ * HTML Variables for PayPal Payments Standard
+ * https://developer.paypal.com/docs/classic/paypal-payments-standard/integration-guide/Appx_websitestandard_htmlvariables/
+ * 
+ */
+
+define('PP_MODE_LIVE', 1);
+define('PP_MODE_TEST', 2);
+
+define('PP_PRC_TYPE_DIRECT', 1);
+define('PP_PRC_TYPE_PDT', 2);
+define('PP_PRC_TYPE_IPN', 3);
+
+class BxPaymentProviderPayPal extends BxBaseModPaymentProvider implements iBxBaseModPaymentProvider
+{
+    function __construct($aConfig)
+    {
+    	$this->MODULE = 'bx_payment';
+
+        parent::__construct($aConfig);
+    }
+
+    public function initializeCheckout($iPendingId, $aCartInfo, $bRecurring = false, $iRecurringDays = 0)
+    {
+        $iMode = (int)$this->getOption('mode');
+        $sItemName = _t($this->_sLangsPrefix . 'txt_payment_to_for', $aCartInfo['vendor_name']);
+        $sActionURL = $iMode == PP_MODE_LIVE ? 'https://www.paypal.com/cgi-bin/webscr' : 'https://www.sandbox.paypal.com/cgi-bin/webscr';
+
+        if($bRecurring) {
+            $aFormData = array(
+                'cmd' => '_xclick-subscriptions',
+                'a3' => sprintf("%.2f", (float)$aCartInfo['items_price']),
+                'p3' => $iRecurringDays,
+                't3' => 'D',
+                'src' => '1', // repeat billings unles member cancels subscription
+                'sra' => '1' // reattempt on failure
+            );
+
+            foreach($aCartInfo['items'] as $aItem)
+                $sItemName .= ' ' . $aItem['title'] . ',';
+		    $sItemName = trim($sItemName, ', ');
+        }
+        else {
+            $aFormData = array(
+                'cmd' => '_cart',
+                'upload' => '1',
+                'item_name' => $sItemName,
+                'amount' => sprintf( "%.2f", (float)$aCartInfo['items_price'])
+            );
+
+            foreach($aCartInfo['items'] as $iIndex => $aItem) {
+                $i = $iIndex + 1; 
+
+                $aFormData['item_name_' . $i] = bx_process_output($aItem['title']);
+			    $aFormData['quantity_' . $i] = $aItem['quantity'];
+			    $aFormData['amount_' . $i] = $this->_oModule->_oConfig->getPrice(BX_PAYMENT_TYPE_SINGLE, $aItem);
+            }
+        }
+
+        $aFormData = array_merge($aFormData, array(
+            'business' => $iMode == PP_MODE_LIVE ? $this->getOption('business') : $this->getOption('sandbox'),
+            'currency_code' => $aCartInfo['vendor_currency_code'],
+            'no_note' => '1',
+            'no_shipping' => '1',
+            'custom' => $this->_constructCustomData($aCartInfo['vendor_id'], $iPendingId),
+        	'item_name' => $sItemName,
+            'item_number' => $iPendingId,
+        ));
+
+        switch($this->getOption('prc_type')) {
+            case PP_PRC_TYPE_PDT:
+            case PP_PRC_TYPE_DIRECT:
+                $aFormData = array_merge($aFormData, array(
+                    'return' => $this->getReturnDataUrl($aCartInfo['vendor_id']),
+                    'rm' => '2'
+                ));
+                break;
+            case PP_PRC_TYPE_IPN:
+                $aFormData = array_merge($aFormData, array(
+                    'return' => $this->getReturnUrl(),
+                    'notify_url' => $this->getReturnDataUrl($aCartInfo['vendor_id']),
+                    'rm' => '1'
+                ));
+                break;
+        }
+
+        $this->log('Initialize Checkout:', '', BX_LOG_INFO);
+        $this->log($aFormData, '', BX_LOG_INFO);
+
+        $this->_oModule->_oTemplate->displayPageCodeRedirect($sActionURL, $aFormData);
+        exit;
+    }
+
+    public function finalizeCheckout(&$aData)
+    {
+        $aResult = $this->_registerCheckout($aData);
+        if(!isset($aResult['code']) || (int)$aResult['code'] != BX_PAYMENT_RESULT_SUCCESS) {
+            $this->log('Finalize Checkout: Failed', '', BX_LOG_ERR);
+            $this->log($aData, '', BX_LOG_ERR);
+            $this->log($aResult, '', BX_LOG_ERR);
+        }
+
+        return $aResult;
+    }
+
+    /**
+     *
+     * @param $aData - data from payment provider.
+     * @return array with results.
+     */
+    protected function _registerCheckout(&$aData)
+    {
+        if(empty($this->_aOptions) && !empty($aData['item_number']))
+            $this->_aOptions = $this->getOptionsByPending((int)$aData['item_number']);
+
+        if(empty($this->_aOptions))
+            return array('code' => 1, 'message' => $this->_sLangsPrefix . 'err_incorrect_provider');
+
+        $iPrcType = (int)$this->getOption('prc_type');
+        if((in_array($iPrcType, array(PP_PRC_TYPE_DIRECT, PP_PRC_TYPE_IPN)) && !isset($aData['txn_id'])) || ($iPrcType == PP_PRC_TYPE_PDT && !isset($aData['tx'])))
+            return array('code' => 2, 'message' => $this->_sLangsPrefix . 'pp_err_no_data_given');
+
+        $aPending = array();
+        $aResult = $this->_validateCheckout($aData, $aPending);
+
+        if(empty($aPending) || !is_array($aPending))
+            return $aResult;
+
+        if(!empty($aPending['order']) || !empty($aPending['error_code']) || !empty($aPending['error_msg']) || (int)$aPending['processed'] != 0)
+            return array('code' => 11, 'message' => $this->_sLangsPrefix . 'err_already_processed');
+
+        //--- Update pending transaction
+        $this->_oModule->_oDb->updateOrderPending($aPending['id'], array(
+            'order' => $aData['txn_id'],
+            'error_code' => $aResult['code'],
+            'error_msg' => _t($aResult['message'])
+        ));
+
+        $aResult['pending_id'] = $aPending['id'];
+        $aResult['client_name'] = _t($this->_sLangsPrefix . 'txt_buyer_name_mask', bx_process_input($aData['first_name']), bx_process_input($aData['last_name'])); 
+		$aResult['client_email'] = bx_process_input($aData['payer_email']);
+		$aResult['paid'] = true;
+        return $aResult;
+    }
+
+    protected function _validateCheckout(&$aData, &$aPending)
+    {
+        $iMode = (int)$this->getOption('mode');
+        if($iMode == PP_MODE_LIVE) {
+           $sBusiness = $this->getOption('business');
+           $sConnectionUrl = 'www.paypal.com';
+        } else {
+            $sBusiness = $this->getOption('sandbox');
+            $sConnectionUrl = 'www.sandbox.paypal.com';
+        }
+
+        $iPrcType = $this->getOption('prc_type');
+        if($iPrcType == PP_PRC_TYPE_DIRECT || $iPrcType == PP_PRC_TYPE_IPN) {
+            if($aData['payment_status'] != 'Completed' )
+                return array('code' => 3, 'message' => $this->_sLangsPrefix . 'pp_err_not_completed');
+
+            if($aData['business'] != $sBusiness)
+                return array('code' => 4, 'message' => $this->_sLangsPrefix . 'pp_err_wrong_business');
+
+            $sRequest = 'cmd=_notify-validate';
+            foreach($aData as $sKey => $sValue) {
+                if(in_array($sKey, array('cmd', 'r')))
+                    continue;
+
+                $sRequest .= '&' . urlencode($sKey) . '=' . urlencode(bx_process_pass($sValue));
+            }
+
+            $aResponse = $this->_readValidationData($sConnectionUrl, $sRequest);
+            if((int)$aResponse['code'] !== 0)
+               return $aResponse;
+
+            foreach($aResponse['content'] as $iLine => $sLine)
+                $aResponse['content'][$iLine] = trim($sLine);
+
+            if(strcmp($aResponse['content'][0], "INVALID") === 0)
+                return array('code' => 6, 'message' => $this->_sLangsPrefix . 'pp_err_wrong_transaction');
+            else if(strcmp($aResponse['content'][0], "VERIFIED") !== 0)
+                return array('code' => 7, 'message' => $this->_sLangsPrefix . 'pp_err_wrong_verification_status');
+        }
+         else if($iPrcType == PP_PRC_TYPE_PDT) {
+            $sRequest = "cmd=_notify-synch&tx=" . $aData['tx'] . "&at=" . $this->getOption('token');
+            $aResponse = $this->_readValidationData($sConnectionUrl, $sRequest);
+
+            if((int)$aResponse['code'] !== 0)
+               return $aResponse;
+
+            if(strcmp($aResponse['content'][0], "FAIL") === 0)
+                return array('code' => 6, 'message' => $this->_sLangsPrefix . 'pp_err_wrong_transaction');
+            else if(strcmp($aResponse['content'][0], "SUCCESS") !== 0)
+                return array('code' => 7, 'message' => $this->_sLangsPrefix . 'pp_err_wrong_verification_status');
+
+            $aKeys = array();
+            foreach($aResponse['content'] as $sLine) 
+                if(strpos($sLine, '=') !== false) {
+                    list($sKey, $sValue) = explode('=', $sLine);
+                    $aKeys[urldecode($sKey)] = urldecode($sValue);
+                }
+
+            $aData = array_merge($aData, $aKeys);
+
+            if($aData['payment_status'] != 'Completed' )
+                return array('code' => 3, 'message' => $this->_sLangsPrefix . 'pp_err_not_completed');
+
+            if($aData['business'] != $sBusiness)
+                return array('code' => 4, 'message' => $this->_sLangsPrefix . 'pp_err_wrong_business');
+        }
+
+        if(empty($aData['custom']))
+            return array('code' => 8, 'message' => $this->_sLangsPrefix . 'pp_err_wrong_custom_data');
+
+        list($iVendorId, $iPendingId) = $this->_deconstructCustomData($aData['custom']);
+        if(empty($iVendorId) || empty($iPendingId))
+            return array('code' => 8, 'message' => $this->_sLangsPrefix . 'pp_err_wrong_custom_data');
+
+        $aPending = $this->_oModule->_oDb->getOrderPending(array('type' => 'id', 'id' => $iPendingId));
+        if((int)$iVendorId != (int)$aPending['seller_id'])
+            return array('code' => 9, 'message' => $this->_sLangsPrefix . 'pp_err_wrong_vendor');
+
+        $aVendor = $this->_oModule->getVendorInfo($iVendorId);
+        $fAmount = (float)$this->_getReceivedAmount($aVendor['currency_code'], $aData);
+        if($fAmount != (float)$aPending['amount'])
+            return array('code' => 10, 'message' => $this->_sLangsPrefix . 'pp_err_wrong_amount');
+
+        return array('code' => BX_PAYMENT_RESULT_SUCCESS, 'message' => $this->_sLangsPrefix . 'pp_msg_verified');
+    }
+
+    protected function _readValidationData($sConnectionUrl, $sRequest)
+    {
+        $this->log('Validation Request: ', '', BX_LOG_INFO);
+        $this->log($sRequest, '', BX_LOG_INFO);
+
+		$rConnect = curl_init('https://' . $sConnectionUrl . '/cgi-bin/webscr');
+		curl_setopt($rConnect, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
+		curl_setopt($rConnect, CURLOPT_POST, 1);
+		curl_setopt($rConnect, CURLOPT_RETURNTRANSFER,1);
+		curl_setopt($rConnect, CURLOPT_POSTFIELDS, $sRequest);
+		curl_setopt($rConnect, CURLOPT_SSL_VERIFYPEER, 1);
+		curl_setopt($rConnect, CURLOPT_SSL_VERIFYHOST, 2);
+		curl_setopt($rConnect, CURLOPT_FORBID_REUSE, 1);
+		curl_setopt($rConnect, CURLOPT_HTTPHEADER, array('Connection: Close'));
+
+		$sResponse = curl_exec($rConnect);
+    	if(curl_errno($rConnect) == 60) { // CURLE_SSL_CACERT
+            curl_setopt($rConnect, CURLOPT_CAINFO, BX_DIRECTORY_PATH_PLUGINS . 'curl/cacert/cacert.pem');
+            $sResponse = curl_exec($rConnect);
+        }
+
+		if(!$sResponse) {
+		    $this->log('Validation Data: ' . curl_error($rConnect), '', BX_LOG_ERR);
+            $this->log($sResponse, '', BX_LOG_ERR);
+
+			return array('code' => 5, 'message' => $this->_sLangsPrefix . 'err_cannot_validate');
+		}
+
+		$aResponse = explode("\n", $sResponse);
+
+		$this->log('Validation Response: ', '', BX_LOG_INFO);
+        $this->log($aResponse, '', BX_LOG_INFO);
+		return array('code' => 0, 'content' => $aResponse);
+    }
+
+    protected function _getReceivedAmount($sCurrencyCode, &$aResultData)
+    {
+        $fAmount = 0.00;
+        $fTax = isset($aResultData['tax']) ? (float)$aResultData['tax'] : 0.00;
+
+        if($aResultData['mc_currency'] == $sCurrencyCode && isset($aResultData['payment_gross']) && !empty($aResultData['payment_gross']))
+            $fAmount = (float)$aResultData['payment_gross'] - $fTax;
+        else if($aResultData['mc_currency'] == $sCurrencyCode && isset($aResultData['mc_gross']) && !empty($aResultData['mc_gross']))
+            $fAmount = (float)$aResultData['mc_gross'] - $fTax;
+        else if($aResultData['settle_currency'] == $sCurrencyCode && isset($aResultData['settle_amount']) && !empty($aResultData['settle_amount']))
+            $fAmount = (float)$aResultData['settle_amount'] - $fTax;
+
+        return $fAmount;
+    }
+
+	protected function _constructCustomData()
+	{
+		$aParams = func_get_args();
+		return urlencode(base64_encode(implode('|', $aParams)));
+	}
+
+	protected function _deconstructCustomData($data)
+	{
+		return explode('|', base64_decode(urldecode($data)));
+	}
+}
+
+/** @} */

+ 588 - 0
modules/boonex/payment/updates/15.0.1_15.0.2/source/classes/BxPaymentProviderStripe.php

@@ -0,0 +1,588 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Payment Payment
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+require_once('BxPaymentProviderStripeBasic.php');
+
+class BxPaymentProviderStripe extends BxPaymentProviderStripeBasic implements iBxBaseModPaymentProvider
+{
+    function __construct($aConfig)
+    {
+        parent::__construct($aConfig);
+
+        $this->_aIncludeJs = array(
+            'https://checkout.stripe.com/checkout.js',
+            'stripe.js'
+        );
+    }
+
+    public function initializeCheckout($iPendingId, $aCartInfo, $sRedirect = '')
+    {
+    	$sToken = bx_process_input(bx_get('token'));
+
+    	if(empty($aCartInfo['items']) || !is_array($aCartInfo['items']))
+            return $this->_sLangsPrefix . 'err_empty_items';
+
+        $aClient = $this->_oModule->getProfileInfo();
+        $aVendor = $this->_oModule->getProfileInfo($aCartInfo['vendor_id']);
+
+        $aPending = $this->_oModule->_oDb->getOrderPending(array('type' => 'id', 'id' => $iPendingId));
+        if(!empty($aPending['order']) || !empty($aPending['error_code']) || !empty($aPending['error_msg']) || (int)$aPending['processed'] != 0)
+            return $this->_sLangsPrefix . 'err_already_processed';
+
+        switch($aPending['type']) {
+            case BX_PAYMENT_TYPE_SINGLE:
+                $aCartInfo['items_title'] = '';
+                foreach($aCartInfo['items'] as $aItem)
+                    $aCartInfo['items_title'] .= ' ' . $aItem['title'] . ',';
+                $aCartInfo['items_title'] = trim($aCartInfo['items_title'], ', ');
+
+                $mixedResult = $this->_createCharge($sToken, $iPendingId, $aClient, $aCartInfo);
+                if($mixedResult === false)
+                    return $this->_sLangsPrefix . 'err_cannot_perform';
+
+                header("Location: " . $this->getReturnDataUrl($aVendor['id'], array(
+                    'order_id' => $mixedResult['order'],
+                    'customer_id' => $mixedResult['customer'], 
+                    'pending_id' => $aPending['id'],
+                    'redirect' => $sRedirect
+                )));
+                exit;
+
+            case BX_PAYMENT_TYPE_RECURRING:
+                $mixedResult = $this->_createSubscription($sToken, $iPendingId, $aClient, $aCartInfo);
+                if($mixedResult === false)
+                    return $this->_sLangsPrefix . 'err_cannot_perform';
+
+                return array(
+                    'code' => 0,
+                    'eval' => $this->_oModule->_oConfig->getJsObject('cart') . '.onSubscribeSubmit(oData);',
+                    'redirect' => $this->getReturnDataUrl($aVendor['id'], array(
+                        'order_id' => $mixedResult['order'],
+                        'customer_id' => $mixedResult['customer'],
+                        'pending_id' => $aPending['id'],
+                        'redirect' => $sRedirect
+                    ))
+                );
+        }
+    }
+
+    public function finalizeCheckout(&$aData)
+    {
+    	$sOrderId = bx_process_input($aData['order_id']);
+    	$sCustomerId = bx_process_input($aData['customer_id']);
+        $iPendingId = bx_process_input($aData['pending_id'], BX_DATA_INT);
+        if(empty($iPendingId))
+            return array('code' => 1, 'message' => $this->_sLangsPrefix . 'err_wrong_data');
+
+        $sRedirect = bx_process_input($aData['redirect']);
+
+        $aPending = $this->_oModule->_oDb->getOrderPending(array('type' => 'id', 'id' => $iPendingId));
+        if(!empty($aPending['order']) || !empty($aPending['error_code']) || !empty($aPending['error_msg']) || (int)$aPending['processed'] != 0)
+            return array('code' => 3, 'message' => $this->_sLangsPrefix . 'err_already_processed');
+
+        $aResult = array(
+            'code' => BX_PAYMENT_RESULT_SUCCESS,
+            'message' => '',
+            'pending_id' => $iPendingId,
+            'customer_id' => '',
+            'subscription_id' => '',
+            'client_name' => '',
+            'client_email' => '',
+            'paid' => false,
+            'trial' => false,
+            'redirect' => $sRedirect
+        );
+
+        switch($aPending['type']) {
+            case BX_PAYMENT_TYPE_SINGLE:
+                $oCustomer = $this->_retrieveCustomer(BX_PAYMENT_TYPE_SINGLE, $sCustomerId);
+                $oCharge = $this->_retrieveCharge($sOrderId);
+                if($oCustomer === false || $oCharge === false)
+                    return array('code' => 4, 'message' => $this->_sLangsPrefix . 'err_cannot_perform');
+
+                $aCustomer = $oCustomer->jsonSerialize();
+                $aCharge = $oCharge->jsonSerialize();
+                if(empty($aCustomer) || !is_array($aCustomer) || empty($aCharge) || !is_array($aCharge))
+                    return array('code' => 4, 'message' => $this->_sLangsPrefix . 'err_cannot_perform');
+
+                $aResult = array_merge($aResult, array(
+                    'message' => $this->_sLangsPrefix . 'strp_msg_charged',
+                    'client_email' => $aCustomer['email'],
+                    'paid' => (bool)$aCharge['paid']
+                ));
+                break;
+
+            case BX_PAYMENT_TYPE_RECURRING:
+                $oCustomer = $this->_retrieveCustomer(BX_PAYMENT_TYPE_RECURRING, $sCustomerId);
+                $oSubscription = $this->_retrieveSubscription($sCustomerId, $sOrderId);
+                if($oCustomer === false || $oSubscription === false)
+                    return array('code' => 4, 'message' => $this->_sLangsPrefix . 'err_cannot_perform');
+
+                $aCustomer = $oCustomer->jsonSerialize();
+                $aSubscription = $oSubscription->jsonSerialize();
+                if(empty($aCustomer) || !is_array($aCustomer) || empty($aSubscription) || !is_array($aSubscription))
+                    return array('code' => 4, 'message' => $this->_sLangsPrefix . 'err_cannot_perform');
+
+                $aResult = array_merge($aResult, array(
+                    'message' => $this->_sLangsPrefix . 'strp_msg_subscribed',
+                    'customer_id' => $sCustomerId,
+                    'subscription_id' => $sOrderId,
+                    'client_email' => $aCustomer['email'],
+                    'trial' => $aSubscription['status'] == 'trialing'
+                ));
+                break;
+        }
+
+        //--- Update pending transaction ---//
+        $this->_oModule->_oDb->updateOrderPending($iPendingId, array(
+            'order' => $sOrderId,
+            'error_code' => $aResult['code'],
+            'error_msg' => _t($aResult['message'])
+        ));
+
+        return $aResult;
+    }
+
+    public function getCheckoutParamsSingle($aParams, &$oGrid)
+    {
+    	if(bx_get('token') !== false)
+            $aParams['token'] = bx_process_input(bx_get('token'));
+
+    	return $aParams;
+    }
+
+    public function getVerificationCodeCharge($iVendorId, $iCustomerId, $fAmount, $sCurrency)
+    {
+        $sCode = $this->_getVerificationCodeCharge($iVendorId, $iCustomerId, $fAmount, $sCurrency);
+
+        /**
+         * @hooks
+         * @hookdef hook-bx_payment-stripe_get_code_charge 'bx_payment', 'stripe_get_code_charge' - hook to override verification code for 'charge' action
+         * - $unit_name - equals `bx_payment`
+         * - $action - equals `stripe_get_code_charge`
+         * - $object_id - not used
+         * - $sender_id - not used
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `provider` - [object] an instance of provider, @see BxBaseModPaymentProvider
+         *      - `vendor_id` - [int] vendor (seller) profile id
+         *      - `customer_id` - [int] customer (buyer) profile id
+         *      - `amount` - [float] charge amount
+         *      - `currency` - [string] charge currency code
+         *      - `override_result` - [string] by ref, verification code, can be overridden in hook processing
+         * @hook @ref hook-bx_payment-stripe_get_code_charge
+         */
+        bx_alert($this->_oModule->_oConfig->getName(), $this->_sName . '_get_code_charge', 0, false, [
+            'provider' => $this,
+            'vendor_id' => $iVendorId, 
+            'customer_id' => $iCustomerId,
+            'amount' => $fAmount,
+            'currency' => $sCurrency,
+            'override_result' => &$sCode
+        ]);
+
+        return $sCode;
+    }
+
+    public function checkVerificationCodeCharge($iVendorId, $iCustomerId, $aResult)
+    {
+        $bCheckResult = $this->_checkVerificationCodeCharge($iVendorId, $iCustomerId, $aResult);
+
+        /**
+         * @hooks
+         * @hookdef hook-bx_payment-stripe_verify_charge 'bx_payment', 'stripe_verify_charge' - hook to override code verification for 'charge' action
+         * - $unit_name - equals `bx_payment`
+         * - $action - equals `stripe_verify_charge`
+         * - $object_id - not used
+         * - $sender_id - not used
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `provider` - [object] an instance of provider, @see BxBaseModPaymentProvider
+         *      - `vendor_id` - [int] vendor (seller) profile id
+         *      - `customer_id` - [int] customer (buyer) profile id
+         *      - `result` - [array] results array received from payment provider
+         *      - `override_result` - [boolean] by ref, is verification passed or not, can be overridden in hook processing
+         * @hook @ref hook-bx_payment-stripe_verify_charge
+         */
+        bx_alert($this->_oModule->_oConfig->getName(), $this->_sName . '_verify_charge', 0, false, array(
+            'provider' => $this,
+            'vendor_id' => $iVendorId, 
+            'customer_id' => $iCustomerId,
+            'result' => $aResult,
+            'override_result' => &$bCheckResult
+        ));
+
+        return $bCheckResult;
+    }
+
+    public function getVerificationCodeSubscription($iVendorId, $iCustomerId, $sSubscription, $sCurrency)
+    {
+        $sCode = $this->_getVerificationCodeSubscription($iVendorId, $iCustomerId, $sSubscription, $sCurrency);
+
+        /**
+         * @hooks
+         * @hookdef hook-bx_payment-stripe_get_code_subscription 'bx_payment', 'stripe_get_code_subscription' - hook to override verification code for 'subscribe' action
+         * - $unit_name - equals `bx_payment`
+         * - $action - equals `stripe_get_code_subscription`
+         * - $object_id - not used
+         * - $sender_id - not used
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `provider` - [object] an instance of provider, @see BxBaseModPaymentProvider
+         *      - `vendor_id` - [int] vendor (seller) profile id
+         *      - `customer_id` - [int] customer (buyer) profile id
+         *      - `subscription` - [string] unique subscription id
+         *      - `currency` - [string] charge currency code
+         *      - `override_result` - [string] by ref, verification code, can be overridden in hook processing
+         * @hook @ref hook-bx_payment-stripe_get_code_subscription
+         */
+        bx_alert($this->_oModule->_oConfig->getName(), $this->_sName . '_get_code_subscription', 0, false, [
+            'provider' => $this,
+            'vendor_id' => $iVendorId, 
+            'customer_id' => $iCustomerId,
+            'subscription' => $sSubscription,
+            'currency' => $sCurrency,
+            'override_result' => &$sCode
+        ]);
+
+        return $sCode;
+    }
+    
+    public function checkVerificationCodeSubscription($iVendorId, $iCustomerId, $aResult)
+    {
+        $bCheckResult = $this->_checkVerificationCodeSubscription($iVendorId, $iCustomerId, $aResult);
+
+        /**
+         * @hooks
+         * @hookdef hook-bx_payment-stripe_verify_subscription 'bx_payment', 'stripe_verify_subscription' - hook to override code verification for 'subscribe' action
+         * It's equivalent to @ref hook-bx_payment-stripe_verify_charge
+         * @hook @ref hook-bx_payment-stripe_verify_subscription
+         */
+        bx_alert($this->_oModule->_oConfig->getName(), $this->_sName . '_verify_subscription', 0, false, array(
+            'provider' => $this,
+            'vendor_id' => $iVendorId, 
+            'customer_id' => $iCustomerId,
+            'result' => $aResult,
+            'override_result' => &$bCheckResult
+        ));
+
+        return $bCheckResult;
+    }
+
+    protected function _createToken($aCard)
+    {
+        try {
+            $oToken = Stripe\Token::create(array('card' => $aCard));
+        }
+        catch (Stripe\Error\Base $oException) {
+            return $this->_processException('Create Token Error: ', $oException);
+        }
+
+        return $oToken->jsonSerialize();
+    }
+
+    protected function _createCustomer($sType, $sToken, $aClient)
+    {
+        $oCustomer = null;
+        $aCustomer = array(
+            'card' => $sToken,
+            'email' => !empty($aClient['email']) ? $aClient['email'] : ''
+        );
+
+        /**
+         * @hooks
+         * @hookdef hook-bx_payment-stripe_create_customer 'bx_payment', 'stripe_create_customer' - hook to override customer data redurned by payment provider
+         * - $unit_name - equals `bx_payment`
+         * - $action - equals `stripe_create_customer`
+         * - $object_id - not used
+         * - $sender_id - client (buyer) profile id
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `type` - [string] payment type: single or recurring
+         *      - `customer_object` - [object] by ref, an instance of customer, redurned by payment provider, can be overridden in hook processing
+         *      - `customer_params` - [array] by ref, array with customer parameters, can be overridden in hook processing
+         * @hook @ref hook-bx_payment-stripe_create_customer
+         */
+        bx_alert($this->_oModule->_oConfig->getName(), $this->_sName . '_create_customer', 0, $aClient['id'], [
+            'type' => $sType,
+
+            'customer_object' => &$oCustomer, 
+            'customer_params' => &$aCustomer,
+
+            'customer_object_ref' => &$oCustomer, 
+            'customer_params_ref' => &$aCustomer,
+        ]);
+
+        try {
+            $this->_oCustomer = !empty($oCustomer) ? $oCustomer : \Stripe\Customer::create($aCustomer);
+        }
+        catch (Exception $oException) {
+            return $this->_processException('Create Customer Error: ', $oException);
+        }
+
+        return $this->_oCustomer->jsonSerialize();
+    }
+
+    protected function _createCharge($sToken, $iPendingId, &$aClient, &$aCartInfo)
+    {
+        if(empty($this->_oCustomer))
+            $this->_createCustomer(BX_PAYMENT_TYPE_SINGLE, $sToken, $aClient);
+
+        if(empty($this->_oCustomer))
+            return false;
+
+        $fAmount = 100 * (float)$aCartInfo['items_price'];
+
+        $oCharge = null;
+        $aCharge = array(
+            'customer' => $this->_oCustomer->id,
+            'amount' => $fAmount,
+            'currency' => $aCartInfo['vendor_currency_code'],
+            'description' => $aCartInfo['items_title'],
+            'metadata' => array(
+                'vendor' => $aCartInfo['vendor_id'],
+                'client' => $aClient['id'],
+                'product' => $iPendingId,
+                'verification' => $this->getVerificationCodeCharge($aCartInfo['vendor_id'], $aClient['id'], $fAmount, $aCartInfo['vendor_currency_code'])
+            )
+        );
+
+        /**
+         * @hooks
+         * @hookdef hook-bx_payment-stripe_create_charge 'bx_payment', 'stripe_create_charge' - hook to override charge data redurned by payment provider
+         * - $unit_name - equals `bx_payment`
+         * - $action - equals `stripe_create_charge`
+         * - $object_id - pending transaction id
+         * - $sender_id - not used
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `charge_object` - [object] by ref, an instance of charge, redurned by payment provider, can be overridden in hook processing
+         *      - `charge_params` - [array] by ref, array with charge parameters, can be overridden in hook processing
+         * @hook @ref hook-bx_payment-stripe_create_charge
+         */
+        bx_alert($this->_oModule->_oConfig->getName(), $this->_sName . '_create_charge', $iPendingId, false, [
+            'charge_object' => &$oCharge, 
+            'charge_params' => &$aCharge,
+            'charge_params_ref' => &$aCharge,
+        ]);
+
+        try {
+            if(empty($oCharge))
+                $oCharge = \Stripe\Charge::create($aCharge);
+        }
+        catch (Exception $oException) {
+            return $this->_processException('Create Charge Error: ', $oException);
+        }
+
+        $aResult = $oCharge->jsonSerialize();
+        if(empty($aResult) || !is_array($aResult) || empty($aResult['paid']))
+            return false;
+
+        $aMetadata = $aResult['metadata'];
+        if(!$this->checkVerificationCodeCharge($aCartInfo['vendor_id'], $aClient['id'], $aResult))
+            return false;
+
+        return array(
+            'pending' => $iPendingId,
+            'amount' =>(float)$aResult['amount'] / 100,
+            'customer' => $this->_oCustomer->id,
+            'order' => $aResult['id']
+        );
+    }
+
+    protected function _createSubscription($sToken, $iPendingId, &$aClient, &$aCartInfo)
+    {
+        if(empty($this->_oCustomer))
+            $this->_createCustomer(BX_PAYMENT_TYPE_RECURRING, $sToken, $aClient);
+
+        if(empty($this->_oCustomer))
+            return false;
+
+        $aItem = array_shift($aCartInfo['items']);
+        if(empty($aItem) || !is_array($aItem))
+            return false;
+
+        $iTrial = $this->_oModule->_oConfig->getTrial(BX_PAYMENT_TYPE_RECURRING, $aItem);
+        $bTrial = !empty($iTrial);
+
+        $oSubscription = null;
+        $aSubscription = array(
+            'plan' => $aItem['name'],
+            'metadata' => array(
+                'vendor' => $aCartInfo['vendor_id'],
+                'client' => $aClient['id'],
+                'product' => $iPendingId,
+                'verification' => $this->getVerificationCodeSubscription($aCartInfo['vendor_id'], $aClient['id'], $aItem['name'], $aCartInfo['vendor_currency_code'])
+            )
+        );
+
+        /**
+         * @hooks
+         * @hookdef hook-bx_payment-stripe_create_subscription 'bx_payment', 'stripe_create_subscription' - hook to override subscription data redurned by payment provider
+         * - $unit_name - equals `bx_payment`
+         * - $action - equals `stripe_create_subscription`
+         * - $object_id - pending transaction id
+         * - $sender_id - not used
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `customer` - [object] by ref, an instance of customer, can be overridden in hook processing
+         *      - `subscription_object` - [object] by ref, an instance of subscription, redurned by payment provider, can be overridden in hook processing
+         *      - `subscription_params` - [array] by ref, array with subscription parameters, can be overridden in hook processing
+         * @hook @ref hook-bx_payment-stripe_create_subscription
+         */
+        bx_alert($this->_oModule->_oConfig->getName(), $this->_sName . '_create_subscription', $iPendingId, false, [
+            'customer' => &$this->_oCustomer,
+
+            'subscription_object' => &$oSubscription, 
+            'subscription_params' => &$aSubscription,
+
+            'subscription_object_ref' => &$oSubscription, 
+            'subscription_params_ref' => &$aSubscription,
+        ]);
+
+        try {
+            if(empty($oSubscription))
+                $oSubscription = \Stripe\Subscription::create(['customer' => $this->_oCustomer->id, 'items' => [['price' => $aItem['name']]], 'metadata' => $aSubscription['metadata']]);				
+        }
+        catch (Exception $oException) {
+            return $this->_processException('Create Subscription Error: ', $oException);
+        }
+
+        $aResult = $oSubscription->jsonSerialize();
+        if(empty($aResult) || !is_array($aResult) || (!$bTrial && $aResult['status'] != 'active') || ($bTrial && !in_array($aResult['status'], array('active', 'trialing'))))
+            return false;
+
+        if(!$this->checkVerificationCodeSubscription($aCartInfo['vendor_id'], $aClient['id'], $aResult))
+            return false;
+
+        return array(
+            'pending' => $iPendingId,
+            'amount' =>(float)$aCartInfo['items_price'],
+            'customer' => $this->_oCustomer->id, 
+            'order' => $aResult['id'],
+            'trial' => $bTrial
+        );
+    }
+
+    protected function _createCard($sType, $sCustomerId, $sToken)
+    {
+        try {
+            $oCard = $this->_retrieveCustomer($sType, $sCustomerId)->sources->create(array(
+                'source' => $sToken
+            ));
+        }
+        catch (Stripe\Error\Base $oException) {
+            return $this->_processException('Create Card Error: ', $oException);
+        }
+
+        return $oCard->jsonSerialize();
+    }
+
+    protected function _retrieveCard($sCustomerId, $sCardId = '') {
+        try {
+            $oCustomer = \Stripe\Customer::retrieve($sCustomerId);
+            $oCard = $oCustomer->sources->retrieve(!empty($sCardId) ? $sCardId : $oCustomer->default_source);
+        }
+        catch (Exception $oException) {
+            return $this->_processException('Retrieve Card Error: ', $oException);
+        }
+
+        return $oCard;
+    }
+
+    protected function _retrieveCoupon($sId) {
+        try {
+            $oCoupon = \Stripe\Coupon::retrieve($sId);
+        }
+        catch (Exception $oException) {
+            return $this->_processException('Retrieve Coupon Error: ', $oException);
+        }
+
+        return $oCoupon;
+    }
+
+    protected function _getButtonJs($sType, $iClientId, $iVendorId, $aParams = array())
+    {
+        $sClientEmail = '';
+    	if(!empty($iClientId) && ($oClient = BxDolProfile::getInstance($iClientId)) !== false)
+            $sClientEmail = $oClient->getAccountObject()->getEmail();
+
+        $sPublicKey = '';
+        
+        /**
+         * @hooks
+         * @hookdef hook-bx_payment-stripe_get_button 'bx_payment', 'stripe_get_button' - hook to override checkout/subscibe button
+         * - $unit_name - equals `bx_payment`
+         * - $action - equals `stripe_get_button`
+         * - $object_id - not used
+         * - $sender_id - client (buyer) profile id
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `type` - [string] by ref, payment type ('single' or 'recurring'), can be overridden in hook processing
+         *      - `public_key` - [string] by ref, Stripe public key, can be overridden in hook processing
+         * @hook @ref hook-bx_payment-stripe_get_button
+         */
+    	bx_alert($this->_oModule->_oConfig->getName(), $this->_sName . '_get_button', 0, $iClientId, [
+            'type' => &$sType, 
+            'public_key' => &$sPublicKey,
+
+            'type_ref' => &$sType, 
+            'public_key_ref' => &$sPublicKey,
+        ]);
+
+        $sJsMethod = '';
+        $sJsObject = $this->getJsObject($aParams);
+        switch($sType) {
+            case BX_PAYMENT_TYPE_SINGLE:
+                $sJsMethod = $sJsObject . '.checkout(this)';
+                break;
+
+            case BX_PAYMENT_TYPE_RECURRING:
+                $sJsMethod = $sJsObject . '.subscribe(this)';
+                break;
+        }
+
+        return array($this->_oModule->_oTemplate->getJsCode($this->_sName, array_merge(array(
+            'js_object' => $sJsObject,
+            'sProvider' => $this->_sName,
+            'sPublicKey' => !empty($sPublicKey) ? $sPublicKey : $this->_getPublicKey(),
+            'sVendorName' => '',
+            'sVendorCurrency' => '',
+            'sVendorIcon' => '',
+            'sClientEmail' => $sClientEmail,
+        ), $aParams)), $sJsMethod);
+    }
+    
+    protected function _getVerificationCodeCharge($iVendorId, $iCustomerId, $fAmount, $sCurrency)
+    {
+        return md5(implode('#-#', array(
+            (int)$iVendorId,
+            (int)$iCustomerId,
+            (float)$fAmount,
+            strtoupper($sCurrency)
+        )));
+    }
+
+    protected function _checkVerificationCodeCharge($iVendorId, $iCustomerId, $aResult)
+    {
+        return !empty($aResult['metadata']['verification']) && $aResult['metadata']['verification'] == $this->getVerificationCodeCharge($iVendorId, $iCustomerId, $aResult['amount'], $aResult['currency']);
+    }
+
+    protected function _getVerificationCodeSubscription($iVendorId, $iCustomerId, $sSubscription, $sCurrency)
+    {
+        return md5(implode('#-#', array(
+            (int)$iVendorId,
+            (int)$iCustomerId,
+            strtoupper($sSubscription),
+            strtoupper($sCurrency)
+        )));
+    }
+
+    protected function _checkVerificationCodeSubscription($iVendorId, $iCustomerId, $aResult)
+    {
+        return !empty($aResult['metadata']['verification']) && $aResult['metadata']['verification'] == $this->getVerificationCodeSubscription($iVendorId, $iCustomerId, $aResult['plan']['id'], $aResult['plan']['currency']);
+    }
+}
+
+/** @} */

+ 757 - 0
modules/boonex/payment/updates/15.0.1_15.0.2/source/classes/BxPaymentProviderStripeBasic.php

@@ -0,0 +1,757 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Payment Payment
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+define('STRP_MODE_LIVE', 1);
+define('STRP_MODE_TEST', 2);
+
+class BxPaymentProviderStripeBasic extends BxBaseModPaymentProvider
+{
+    protected $_sFormDetails;
+    protected $_sFormDisplayDetailsEdit;
+
+    protected $_sFormCard;
+    protected $_sFormDisplayCardAdd;
+
+    protected $_iMode;
+    protected $_bCheckAmount;
+    protected $_bProrate;
+
+    protected $_oCustomer;
+
+
+    function __construct($aConfig)
+    {
+    	$this->MODULE = 'bx_payment';
+
+        parent::__construct($aConfig);
+
+        $this->_aSbsStatuses = array(
+            'incomplete' => BX_PAYMENT_SBS_STATUS_UNPAID, 
+            'incomplete_expired' => BX_PAYMENT_SBS_STATUS_UNPAID, 
+            'trialing' => BX_PAYMENT_SBS_STATUS_TRIAL, 
+            'active' => BX_PAYMENT_SBS_STATUS_ACTIVE, 
+            'past_due' => BX_PAYMENT_SBS_STATUS_UNPAID,
+            'unpaid' => BX_PAYMENT_SBS_STATUS_UNPAID,
+            'canceled' => BX_PAYMENT_SBS_STATUS_CANCELED,
+        );
+
+        $this->_sFormDetails = 'bx_payment_form_strp_details';
+        $this->_sFormDisplayDetailsEdit = 'bx_payment_form_strp_details_edit';
+
+        $this->_sFormCard = 'bx_payment_form_strp_card';
+        $this->_sFormDisplayCardAdd = 'bx_payment_form_strp_card_add';
+
+        $this->_bProrate = false;
+
+        $this->_aIncludeJs = array(
+            'main.js',
+        );
+
+        $this->_aIncludeCss = array(
+            'stripe.css'
+        );
+
+        $this->_oCustomer = null;
+
+        \Stripe\Stripe::setApiKey($this->_getSecretKey());
+    }
+
+    public function initOptions($aOptions)
+    {
+    	parent::initOptions($aOptions);
+
+    	$this->_iMode = (int)$this->getOption('mode');
+    	$this->_bCheckAmount = $this->getOption('check_amount') == 'on';
+    	$this->_bUseSsl = $this->getOption('ssl') == 'on';
+    }
+
+    public function addJsCss()
+    {
+    	if(!$this->isActive())
+    		return;
+
+        $this->_oModule->_oTemplate->addJs($this->_aIncludeJs);
+        $this->_oModule->_oTemplate->addCss($this->_aIncludeCss);
+    }
+
+    public function getJsObject($aParams = array())
+    {
+        $sJsObject = $this->_oModule->_oConfig->getJsObject($this->_sName);
+        if(isset($aParams['iModuleId'], $aParams['iSellerId'], $aParams['iItemId']))
+            $sJsObject .= '_' . md5($aParams['iModuleId'] . '-' . $aParams['iSellerId'] . '-' . $aParams['iItemId']);
+        
+        return $sJsObject;
+    }
+
+    public function notify()
+    {
+        $iResult = $this->_processEvent();
+        http_response_code($iResult);
+    }
+
+    public function getButtonSingle($iClientId, $iVendorId, $aParams = array())
+    {
+        $aItems = array();
+        $aCartInfo = $this->_oModule->getObjectCart()->getInfo(BX_PAYMENT_TYPE_SINGLE, $iClientId, (int)$iVendorId, $aItems);
+        if(empty($aCartInfo) || !is_array($aCartInfo))
+            return '';
+
+    	return $this->_getButton(BX_PAYMENT_TYPE_SINGLE, $iClientId, $iVendorId, array_merge($aParams, array(
+            'sVendorName' => _t($this->_sLangsPrefix . 'txt_payment_to', $aCartInfo['vendor_name']),
+            'sVendorCurrency' => $aCartInfo['vendor_currency_code'],
+            'sVendorIcon' => $aCartInfo['vendor_avatar'],
+    	)));
+    }
+
+    public function getButtonSingleJs($iClientId, $iVendorId, $aParams = array())
+    {
+        $aItems = array();
+        $aCartInfo = $this->_oModule->getObjectCart()->getInfo(BX_PAYMENT_TYPE_SINGLE, $iClientId, (int)$iVendorId, $aItems);
+        if(empty($aCartInfo) || !is_array($aCartInfo))
+            return '';
+
+    	return $this->_getButtonJs(BX_PAYMENT_TYPE_SINGLE, $iClientId, $iVendorId, array_merge($aParams, array(
+            'sVendorName' => _t($this->_sLangsPrefix . 'txt_payment_to', $aCartInfo['vendor_name']),
+            'sVendorCurrency' => $aCartInfo['vendor_currency_code'],
+            'sVendorIcon' => $aCartInfo['vendor_avatar'],
+    	)));
+    }
+
+    public function getButtonRecurring($iClientId, $iVendorId, $aParams = array())
+    {
+    	$aVendor = $this->_oModule->getVendorInfo((int)$iVendorId);
+
+        return $this->_getButton(BX_PAYMENT_TYPE_RECURRING, $iClientId, $iVendorId, array_merge($aParams, array(
+            'sVendorName' => _t($this->_sLangsPrefix . 'txt_payment_to', $aVendor['name']),
+            'sVendorCurrency' => $aVendor['currency_code'],
+            'sVendorIcon' => $aVendor['avatar'],
+        )));
+    }
+    
+    public function getButtonRecurringJs($iClientId, $iVendorId, $aParams = array())
+    {
+    	$aVendor = $this->_oModule->getVendorInfo((int)$iVendorId);
+
+        return $this->_getButtonJs(BX_PAYMENT_TYPE_RECURRING, $iClientId, $iVendorId, array_merge($aParams, array(
+            'sVendorName' => _t($this->_sLangsPrefix . 'txt_payment_to', $aVendor['name']),
+            'sVendorCurrency' => $aVendor['currency_code'],
+            'sVendorIcon' => $aVendor['avatar'],
+        )));
+    }
+
+    public function getMenuItemsActionsRecurring($iClientId, $iVendorId, $aParams = array())
+    {
+        if($this->_bIsApi || empty($aParams['order']))
+            return [];
+
+        $sJsObject = $this->_oModule->_oConfig->getJsObject(BX_PAYMENT_ORDERS_TYPE_SUBSCRIPTION);
+
+        $sPrefix = 'bx-payment-strp-';
+        return array(
+            array('id' => $sPrefix . 'details', 'name' => $sPrefix . 'details', 'class' => '', 'link' => 'javascript:void(0)', 'onclick' => "javascript:" . $sJsObject . ".getDetails(this, '" . $aParams['id'] . "')", 'target' => '_self', 'title' => _t('_bx_payment_strp_menu_item_title_details')),
+            array('id' => $sPrefix . 'details_change', 'name' => $sPrefix . 'details_change', 'class' => '', 'link' => 'javascript:void(0)', 'onclick' => "javascript:" . $sJsObject . ".changeDetails(this, '" . $aParams['id'] . "')", 'target' => '_self', 'title' => _t('_bx_payment_strp_menu_item_title_details_change')),
+            array('id' => $sPrefix . 'billing', 'name' => $sPrefix . 'billing', 'class' => '', 'link' => 'javascript:void(0)', 'onclick' => "javascript:" . $sJsObject . ".getBilling(this, '" . $aParams['id'] . "')", 'target' => '_self', 'title' => _t('_bx_payment_strp_menu_item_title_billing')),
+            array('id' => $sPrefix . 'billing_change', 'name' => $sPrefix . 'billing_change', 'class' => '', 'link' => 'javascript:void(0)', 'onclick' => "javascript:" . $sJsObject . ".changeBilling(this, '" . $aParams['id'] . "')", 'target' => '_self', 'title' => _t('_bx_payment_strp_menu_item_title_billing_change')),
+        );
+    }
+
+    public function getDetailsRecurring($iPendingId, $sCustomerId, $sSubscriptionId)
+    {
+        $oSubscription = $this->_retrieveSubscription($sCustomerId, $sSubscriptionId);
+        if($oSubscription === false)
+            return '';
+
+        $aSubscription = $oSubscription->jsonSerialize();
+        if(empty($aSubscription) || !is_array($aSubscription))
+            return '';
+
+        $sName = '';
+        if(!empty($aSubscription['plan']['name']))
+            $sName = $aSubscription['plan']['name'];
+        else if(!empty($aSubscription['plan']['product'])){
+            $oProduct = $this->_retrieveProduct($aSubscription['plan']['product']);
+            if($oProduct !== false) 
+                $sName = $oProduct->name;
+        }
+
+        $sNone = _t('_bx_payment_txt_none');
+        return $this->_oModule->_oTemplate->parseHtmlByName('strp_details_recurring.html', array(
+            'plan' => $sName,
+            'cost' => _t('_bx_payment_strp_txt_cost_mask', (int)$aSubscription['plan']['amount'] / 100, $aSubscription['plan']['currency'], $aSubscription['plan']['interval']),
+            'status' => $aSubscription['status'],
+            'created' => bx_time_js($aSubscription['created'], BX_FORMAT_DATE_TIME, true),
+            'started' => !empty($aSubscription['start']) ? bx_time_js($aSubscription['start'], BX_FORMAT_DATE_TIME, true) : $sNone,
+            'trial_start' => !empty($aSubscription['trial_start']) ? bx_time_js($aSubscription['trial_start'], BX_FORMAT_DATE_TIME, true) : $sNone,
+            'trial_end' => !empty($aSubscription['trial_end']) ? bx_time_js($aSubscription['trial_end'], BX_FORMAT_DATE_TIME, true) : $sNone,
+            'cperiod_start' => !empty($aSubscription['current_period_start']) ? bx_time_js($aSubscription['current_period_start'], BX_FORMAT_DATE_TIME, true) : $sNone,
+            'cperiod_end' => !empty($aSubscription['current_period_end']) ? bx_time_js($aSubscription['current_period_end'], BX_FORMAT_DATE_TIME, true) : $sNone,
+        ));
+    }
+
+    public function changeDetailsRecurring($iPendingId, $sCustomerId, $sSubscriptionId)
+    {
+        $oForm = BxDolForm::getObjectInstance($this->_sFormDetails, $this->_sFormDisplayDetailsEdit, $this->_oModule->_oTemplate);
+        $oForm->aFormAttrs['id'] = $this->_oModule->_oConfig->getHtmlIds('subscription', 'form_subscription_change_details');
+        $oForm->aFormAttrs['action'] = BX_DOL_URL_ROOT . $this->_oModule->_oConfig->getBaseUri() . 'subscription_change_details/' . $iPendingId;
+
+        $oForm->aInputs['item_id']['values'] = $this->_getDataChangeDetailsRecurring($iPendingId);
+
+        $oForm->initChecker();
+        if($oForm->isSubmittedAndValid()) {
+            $aResultError = array('code' => 1, 'message' => _t('_bx_payment_strp_err_details_changed'));
+
+            $aPending = $this->_oModule->_oDb->getOrderPending(array('type' => 'id', 'id' => $iPendingId));
+            list($iVendorId, $iModuleId, $iItemId, $iItemCount) = $this->_oModule->_oConfig->descriptorS2A($aPending['items']);
+
+            $aItem = $this->_oModule->callGetCartItem($iModuleId, array($oForm->getCleanValue('item_id'), $aPending['client_id']));
+    		if(empty($aItem) || !is_array($aItem))
+    			return $aResultError;
+
+            $oSubscription = $this->_retrieveSubscription($sCustomerId, $sSubscriptionId);
+            if($oSubscription === false)
+                return $aResultError;
+
+            $oSubscription->plan = $aItem['name'];
+            $oSubscription->prorate = $this->_bProrate;
+            $oSubscription = $oSubscription->save();
+            if(strcmp($oSubscription->plan->id, $aItem['name']) !== 0)
+                return $aResultError;
+
+            $sItems = $this->_oModule->_oConfig->descriptorA2S(array($iVendorId, $iModuleId, $aItem['id'], $iItemCount));
+            if(!$this->_oModule->_oDb->updateOrderPending($iPendingId, array('items' => $sItems)))
+                return $aResultError;
+
+            $this->_oModule->callReregisterSubscriptionItem($iModuleId, array($aPending['client_id'], $aPending['seller_id'], $iItemId, $aItem['id'], $aPending['order']));
+
+            return array('code' => 0, 'message' => _t('_bx_payment_strp_msg_details_changed'));
+        }
+
+        return $this->_oModule->_oTemplate->parseHtmlByName('strp_details_change_recuring.html', array(
+            'object' => $this->_oModule->_oConfig->getJsObject('subscription'),
+            'form' => $oForm->getCode(),
+            'form_id' => $oForm->aFormAttrs['id'],
+        ));
+    }
+
+    public function getBillingRecurring($iPendingId, $sCustomerId, $sSubscriptionId)
+    {
+        $aCard = ['brand' => '', 'country' => '', 'funding' => '', 'last4' => '', 'exp_month' => '', 'exp_year' => '', 'cvc_check' => ''];
+
+        $oCard = $this->_retrieveCard($sCustomerId);
+        if($oCard === false && ($oSubscription = $this->_retrieveSubscription($sCustomerId, $sSubscriptionId)) !== false) {
+            $sPaymentMethodId = $oSubscription->default_payment_method;
+            if(!empty($sPaymentMethodId) && ($oPaymentMethod = $this->_retrievePaymentMethod($sPaymentMethodId)) !== false)
+                $oCard = $oPaymentMethod->card;
+        }
+
+        if(!empty($oCard))
+            $aCard = $oCard->jsonSerialize();
+
+        return $this->_oModule->_oTemplate->parseHtmlByName('strp_billing_recurring.html', array(
+            'brand' => $aCard['brand'],
+            'origin' => $aCard['country'],
+            'type' => $aCard['funding'],
+            'number' => _t('_bx_payment_strp_txt_card_number_mask', $aCard['last4']),
+            'expires' => _t('_bx_payment_strp_txt_card_expires_mask', $aCard['exp_month'], $aCard['exp_year']),
+            'cvc' => _t(!empty($aCard['cvc_check']) && strcmp($aCard['cvc_check'], 'pass') === 0 ? '_bx_payment_strp_txt_card_cvc_passed' : '_bx_payment_txt_none'),
+        ));
+    }
+
+    public function changeBillingRecurring($iPendingId, $sCustomerId, $sSubscriptionId)
+    {
+        $oForm = BxDolForm::getObjectInstance($this->_sFormCard, $this->_sFormDisplayCardAdd, $this->_oModule->_oTemplate);
+        $oForm->aFormAttrs['id'] = $this->_oModule->_oConfig->getHtmlIds('subscription', 'form_subscription_change_billing');
+        $oForm->aFormAttrs['action'] = BX_DOL_URL_ROOT . $this->_oModule->_oConfig->getBaseUri() . 'subscription_change_billing/' . $iPendingId;
+
+        $oForm->initChecker();
+        if($oForm->isSubmittedAndValid()) {
+            $aResultError = array('code' => 1, 'message' => _t('_bx_payment_strp_err_billing_changed'));
+
+            $aMatch = array();
+            if(!preg_match('/^([0-9]{2})\D([0-9]{4})$/i', $oForm->getCleanValue('card_expire'), $aMatch))
+                return $aResultError;
+
+            list($iMonth, $iYear) = array_slice($aMatch, 1);
+
+        	$aToken = $this->_createToken(array(
+                'number' => $oForm->getCleanValue('card_number'),
+                'exp_month' => $iMonth,
+                'exp_year' => $iYear,
+                'cvc' => $oForm->getCleanValue('card_cvv')
+            ));
+            if(empty($aToken) || !is_array($aToken))
+                return $aResultError;
+
+            $aCard = $this->_createCard(BX_PAYMENT_TYPE_RECURRING, $sCustomerId, $aToken['id']);
+            if(empty($aCard) || !is_array($aCard))
+                return $aResultError;
+
+            $oCustomer = $this->_retrieveCustomer(BX_PAYMENT_TYPE_RECURRING, $sCustomerId);
+            if($oCustomer === false)
+                return $aResultError;
+
+            $oCustomer->default_source = $aCard['id'];
+            $oCustomer->save();
+
+            return array('code' => 0, 'message' => _t('_bx_payment_strp_msg_billing_changed'));
+        }
+
+        return $this->_oModule->_oTemplate->parseHtmlByName('strp_billing_change_recuring.html', array(
+            'object' => $this->_oModule->_oConfig->getJsObject('subscription'),
+            'form' => $oForm->getCode(),
+            'form_id' => $oForm->aFormAttrs['id'],
+        ));
+    }
+
+    public function cancelRecurring($iPendingId, $sCustomerId, $sSubscriptionId)
+    {
+        $oSubscription = $this->_cancelSubscription($sCustomerId, $sSubscriptionId);
+        if($oSubscription === false)
+            return false;
+
+        return true;
+    }
+
+    public function getSubscription($iPendingId, $sCustomerId, $sSubscriptionId)
+    {
+        $oSubscription = $this->_retrieveSubscription($sCustomerId, $sSubscriptionId);
+        if($oSubscription === false)
+            return array();
+
+        $aSubscription = $oSubscription->jsonSerialize();
+        if(empty($aSubscription) || !is_array($aSubscription))
+            return array();
+
+        $sStatus = isset($this->_aSbsStatuses[$aSubscription['status']]) ? $this->_aSbsStatuses[$aSubscription['status']] : BX_PAYMENT_SBS_STATUS_UNKNOWN;
+
+        return array(
+            'status' => $sStatus,
+            'created' => $aSubscription['created'],
+            'started' => !empty($aSubscription['start']) ? $aSubscription['start'] : 0,
+            'trial_start' => !empty($aSubscription['trial_start']) ? $aSubscription['trial_start'] : 0,
+            'trial_end' => !empty($aSubscription['trial_end']) ? $aSubscription['trial_end'] : 0,
+            'cperiod_start' => !empty($aSubscription['current_period_start']) ? $aSubscription['current_period_start'] : 0,
+            'cperiod_end' => !empty($aSubscription['current_period_end']) ? $aSubscription['current_period_end'] : 0,
+        );
+    }
+
+    protected function _getPublicKey()
+    {
+        return $this->_iMode == STRP_MODE_LIVE ? $this->getOption('live_pub_key') : $this->getOption('test_pub_key');
+    }
+
+    protected function _getSecretKey()
+    {
+        return $this->_iMode == STRP_MODE_LIVE ? $this->getOption('live_sec_key') : $this->getOption('test_sec_key');
+    }
+
+    protected function _retrieveCustomer($sType, $sId)
+    {
+        $oCustomer = null;
+        
+        /**
+         * @hooks
+         * @hookdef hook-bx_payment-stripe_retrieve_customer 'bx_payment', 'stripe_retrieve_customer' - hook to override customer data retrieved from payment provider
+         * - $unit_name - equals `bx_payment`
+         * - $action - equals `stripe_retrieve_customer`
+         * - $object_id - not used
+         * - $sender_id - not used
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `type` - [string] payment type: single or recurring
+         *      - `customer_id` - [string] by ref, unique customer id, can be overridden in hook processing
+         *      - `customer_object` - [object] by ref, an instance of customer, redurned by payment provider, can be overridden in hook processing
+         * @hook @ref hook-bx_payment-stripe_retrieve_customer
+         */
+        bx_alert($this->_oModule->_oConfig->getName(), $this->_sName . '_retrieve_customer', 0, false, [
+            'type' => $sType,
+
+            'customer_id' => &$sId,
+            'customer_object' => &$oCustomer,
+
+            'customer_id_ref' => &$sId,
+            'customer_object_ref' => &$oCustomer,
+        ]);
+
+        try {
+            if(empty($oCustomer))
+                $oCustomer = \Stripe\Customer::retrieve($sId);
+        }
+        catch (Exception $oException) {
+            return $this->_processException('Retrieve Customer Error: ', $oException);
+        }
+
+        return $oCustomer;
+    }
+
+    protected function _retrieveCharge($sId)
+    {
+        $oCharge = null;
+        
+        /**
+         * @hooks
+         * @hookdef hook-bx_payment-stripe_retrieve_charge 'bx_payment', 'stripe_retrieve_charge' - hook to override charge data retrieved from payment provider
+         * - $unit_name - equals `bx_payment`
+         * - $action - equals `stripe_retrieve_charge`
+         * - $object_id - not used
+         * - $sender_id - not used
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `type` - [string] payment type: single or recurring
+         *      - `charge_id` - [string] by ref, unique charge id, can be overridden in hook processing
+         *      - `charge_object` - [object] by ref, an instance of charge, redurned by payment provider, can be overridden in hook processing
+         * @hook @ref hook-bx_payment-stripe_retrieve_charge
+         */
+        /**
+         * @hooks
+         * @hookdef hook-bx_payment-stripe_v3_retrieve_charge 'bx_payment', 'stripe_v3_retrieve_charge' - hook to override charge data retrieved from payment provider
+         * It's equivalent to @ref hook-bx_payment-stripe_retrieve_charge
+         * @hook @ref hook-bx_payment-stripe_v3_retrieve_charge
+         */
+        bx_alert($this->_oModule->_oConfig->getName(), $this->_sName . '_retrieve_charge', 0, false, [
+            'charge_id' => &$sId,
+            'charge_object' => &$oCharge,
+
+            'charge_id_ref' => &$sId,
+            'charge_object_ref' => &$oCharge,
+        ]);
+
+        try {
+            if(empty($oCharge))
+                $oCharge = \Stripe\Charge::retrieve($sId);
+        }
+        catch (Exception $oException) {
+            return $this->_processException('Retrieve Charge Error: ', $oException);
+        }
+
+        return $oCharge;
+    }
+
+    protected function _retrieveSubscription($sCustomerId, $sSubscriptionId)
+    {
+        try {
+            $oCustomer = $this->_retrieveCustomer(BX_PAYMENT_TYPE_RECURRING, $sCustomerId);
+            $oSubscription = \Stripe\Subscription::retrieve($sSubscriptionId);
+        }
+        catch (Exception $oException) {
+            return $this->_processException('Retrieve Subscription Error: ', $oException);
+        }
+
+        return $oSubscription;
+    }
+
+    protected function _cancelSubscription($sCustomerId, $sSubscriptionId)
+    {
+        try {
+            $oSubscription = $this->_retrieveSubscription($sCustomerId, $sSubscriptionId);
+            $oSubscription = $oSubscription->cancel();
+        }
+        catch (Exception $oException) {
+                return $this->_processException('Cancel Subscription Error: ', $oException);
+        }
+
+        /**
+         * @hooks
+         * @hookdef hook-bx_payment-stripe_cancel_subscription 'bx_payment', 'stripe_cancel_subscription' - hook after a subscription was canceled
+         * - $unit_name - equals `bx_payment`
+         * - $action - equals `stripe_cancel_subscription`
+         * - $object_id - not used
+         * - $sender_id - not used
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `subscription_id` - [string] unique subscription id
+         *      - `subscription_object` - [object] an instance of subscription, redurned by payment provider
+         * @hook @ref hook-bx_payment-stripe_cancel_subscription
+         */
+        /**
+         * @hooks
+         * @hookdef hook-bx_payment-stripe_v3_cancel_subscription 'bx_payment', 'stripe_v3_cancel_subscription' - hook after a subscription was canceled
+         * It's equivalent to @ref hook-bx_payment-stripe_cancel_subscription
+         * @hook @ref hook-bx_payment-stripe_v3_cancel_subscription
+         */
+        bx_alert($this->_oModule->_oConfig->getName(), $this->_sName . '_cancel_subscription', 0, false, [
+            'subscription_id' => $sSubscriptionId,
+            'subscription_object' => &$oSubscription
+        ]);
+
+        return $oSubscription;
+    }
+
+    protected function _retrievePaymentMethod($sPaymentMethodId)
+    {
+        return false;
+    }
+
+    protected function _retrieveProduct($sId)
+    {
+        $oProduct = null;
+
+        /**
+         * @hooks
+         * @hookdef hook-bx_payment-stripe_retrieve_product 'bx_payment', 'stripe_retrieve_product' - hook to override product data retrieved from payment provider
+         * - $unit_name - equals `bx_payment`
+         * - $action - equals `stripe_retrieve_product`
+         * - $object_id - not used
+         * - $sender_id - not used
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `product_id` - [string] by ref, unique product id, can be overridden in hook processing
+         *      - `product_object` - [object] by ref, an instance of product, redurned by payment provider, can be overridden in hook processing
+         * @hook @ref hook-bx_payment-stripe_retrieve_product
+         */
+        /**
+         * @hooks
+         * @hookdef hook-bx_payment-stripe_v3_retrieve_product 'bx_payment', 'stripe_v3_retrieve_product' - hook to override product data retrieved from payment provider
+         * It's equivalent to @ref hook-bx_payment-stripe_retrieve_product
+         * @hook @ref hook-bx_payment-stripe_v3_retrieve_product
+         */
+        bx_alert($this->_oModule->_oConfig->getName(), $this->_sName . '_retrieve_product', 0, false, [
+            'product_id' => &$sId,
+            'product_object' => &$oProduct
+        ]);
+
+        if(!empty($oProduct))
+            return $oProduct;
+
+        try {
+            $oProduct = \Stripe\Product::retrieve($sId);
+        }
+        catch (Exception $oException) {
+            return $this->_processException('Retrieve Product Error: ', $oException);
+        }
+
+        return $oProduct;
+    }
+
+    protected function _listPlans($iLimit = 100)
+    {
+        if($iLimit <= 0)
+            $iLimit = 1;
+        if($iLimit > 100)
+            $iLimit = 100;
+
+        try {
+            $oPlans = \Stripe\Plan::all(array('limit' => $iLimit));
+        }
+        catch (Exception $oException) {
+            return $this->_processException('List Plans Error: ', $oException);
+        }
+
+        return $oPlans;
+    }
+
+    protected function _retrieveEvent($sId) {
+        try {
+            $oEvent = \Stripe\Event::retrieve($sId);
+        }
+        catch (Exception $oException) {
+            return $this->_processException('Retrieve Event Error: ', $oException);
+        }
+
+        return $oEvent;
+    }
+
+    protected function _processEvent()
+    {
+        $sInput = @file_get_contents("php://input");
+        $aEvent = json_decode($sInput, true);
+        if(empty($aEvent) || !is_array($aEvent)) 
+            return 404;
+
+        $sType = $aEvent['type'];
+        if(!in_array($sType, array('invoice.payment_succeeded', 'charge.refunded', 'customer.subscription.deleted')))
+            return 200;
+
+        $this->log('Webhooks: ' . (!empty($sType) ? $sType : ''), '', BX_LOG_INFO);
+        $this->log($aEvent, '', BX_LOG_INFO);
+
+        $sMethod = '_processEvent' . bx_gen_method_name($sType, array('.', '_', '-'));
+    	if(!method_exists($this, $sMethod))
+            return 200;
+
+    	return $this->$sMethod($aEvent) ? 200 : 403;
+    }
+
+    protected function _processEventInvoicePaymentSucceeded(&$aEvent)
+    {
+        $mixedResult = $this->_getDataInvoicePaymentSucceeded($aEvent);
+        if($mixedResult === false)
+            return false;
+
+        list($mixedPending, $aPaid) = $mixedResult;
+        if(empty($mixedPending) || empty($aPaid))
+            return false;
+
+        $fChargeAmount = (float)$aPaid['amount'] / 100;
+        $sChargeCurrency = strtoupper($aPaid['currency']);
+
+        if(is_string($mixedPending))
+            return $this->_oModule->_oDb->insertStrpPaymentPending($mixedPending, $fChargeAmount, $sChargeCurrency);
+
+        if($this->_bCheckAmount && ((float)$mixedPending['amount'] != $fChargeAmount || strcasecmp($this->_oModule->_oConfig->getDefaultCurrencyCode(), $sChargeCurrency) !== 0))
+            return false;
+
+        if($mixedPending['type'] == BX_PAYMENT_TYPE_RECURRING)
+            $this->_oModule->getObjectSubscriptions()->prolong($mixedPending);
+
+        return $this->_oModule->registerPayment($mixedPending);
+    }
+
+    protected function _processEventChargeRefunded(&$aEvent)
+    {
+        $mixedResult = $this->_getData($aEvent);
+        if($mixedResult === false)
+            return false;
+
+        list($aPending) = $mixedResult;
+        if(empty($aPending) || !is_array($aPending))
+            return false;
+
+        return $this->_oModule->refundPayment($aPending);
+    }
+
+    protected function _processEventCustomerSubscriptionDeleted(&$aEvent)
+    {
+        $mixedResult = $this->_getData($aEvent);
+        if($mixedResult === false)
+            return false;
+
+        list($aPending) = $mixedResult;
+        if(empty($aPending) || !is_array($aPending))
+            return true;
+
+        return $this->_oModule->getObjectSubscriptions()->cancelLocal($aPending);
+    }
+
+    protected function _processException($sMessage, &$oException)
+    {
+        $aError = $oException->getJsonBody();
+
+        $sMessage = $aError['error']['message'];
+        if(empty($sMessage))
+            $sMessage = $oException->getMessage();
+
+        $this->log($sMessage . $aError['error']['message'], '', BX_LOG_ERR);
+        $this->log($aError, '', BX_LOG_ERR);
+
+        return false;
+    }
+
+    protected function _getData(&$aEvent, $bRetrieve = true)
+    {
+        if($bRetrieve)
+            $oEvent = $this->_retrieveEvent($aEvent['id']);
+        else 
+            $oEvent = \Stripe\Util\Util::convertToStripeObject($aEvent, array());
+
+        if(empty($oEvent))
+            return false;
+
+        $aPending = $this->_oModule->_oDb->getOrderPending(array('type' => 'order', 'order' => $oEvent->data->object->subscription));
+        $oCharge = $this->_retrieveCharge($oEvent->data->object->charge);
+
+        return array($aPending, $oCharge);
+    }
+
+    protected function _getDataInvoicePaymentSucceeded(&$aEvent, $bRetrieve = true)
+    {
+        if($bRetrieve)
+            $oEvent = $this->_retrieveEvent($aEvent['id']);
+        else 
+            $oEvent = \Stripe\Util\Util::convertToStripeObject($aEvent, array());
+
+        if(empty($oEvent))
+            return false;
+
+        /**
+         * Note. $oEvent->data->object->subscription and $oEvent->data->object->charge 
+         * are checked for backward compatibility.
+         */
+        $sSubscriptionId = '';
+        if(!empty($oEvent->data->object->subscription))
+            $sSubscriptionId = $oEvent->data->object->subscription;
+        else if(!empty($oEvent->data->object->parent) && $oEvent->data->object->parent->type == 'subscription_details')
+            $sSubscriptionId = $oEvent->data->object->parent->subscription_details->subscription;
+        if(!$sSubscriptionId)
+            return false;
+
+        $aPending = $this->_oModule->_oDb->getOrderPending(['type' => 'order', 'order' => $sSubscriptionId]);
+
+        $aPaid = ['amount' => 0, 'currency' => ''];
+        if(!empty($oEvent->data->object->charge)) {
+            $oCharge = $this->_retrieveCharge($oEvent->data->object->charge);
+            if($oCharge)
+                $aPaid = [
+                    'amount' => $oCharge->amount,
+                    'currency' => $oCharge->currency
+                ];
+        }
+        else {
+            if(!empty($oEvent->data->object->amount_paid)) 
+                $aPaid['amount'] = $oEvent->data->object->amount_paid;
+            if(!empty($oEvent->data->object->currency))
+                $aPaid['currency'] = $oEvent->data->object->currency;
+        }
+
+        return [!empty($aPending) && is_array($aPending) ? $aPending : $sSubscriptionId, $aPaid];
+    }
+
+    protected function _getDataChangeDetailsRecurring($iPendingId)
+    {
+        $aResult = array();
+
+        $aPending = $this->_oModule->_oDb->getOrderPending(array('type' => 'id', 'id' => $iPendingId));
+        list($iVendorId, $iModuleId, $iItemId) = $this->_oModule->_oConfig->descriptorS2A($aPending['items']);
+        if(empty($iModuleId) || empty($iVendorId) || (int)$iVendorId != (int)$aPending['seller_id'])
+            return $aResult;
+
+        $aItems = $this->_oModule->callGetCartItems((int)$iModuleId, array($iVendorId));
+        if(empty($aItems) || !is_array($aItems))
+            return $aResult;
+
+        $oPlans = $this->_listPlans();
+        if($oPlans === false)
+            return $aResult;
+
+        $aPlans = $oPlans->jsonSerialize();
+        if(empty($aPlans) || !is_array($aPlans) || empty($aPlans['data']) || !is_array($aPlans['data']))
+            return $aResult;
+
+        $aPlans = $aPlans['data'];
+
+        $aPlanNames = array();
+        foreach($aPlans as $aPlan)
+            $aPlanNames[] = $aPlan['id'];
+        if(empty($aPlanNames) || !is_array($aPlanNames))
+            return $aResult;
+
+        foreach($aItems as $aItem) {
+            $fPrice = $this->_oModule->_oConfig->getPrice(BX_PAYMENT_TYPE_RECURRING, $aItem);
+            if($fPrice == 0 || (int)$aItem['id'] == (int)$iItemId || !in_array($aItem['name'], $aPlanNames))
+                continue;
+
+            $aResult[] = array('key' => $aItem['id'], 'value' => $aItem['title']);
+        }
+
+        return $aResult;
+    }
+
+    protected function _getButton($sType, $iClientId, $iVendorId, $aParams = array())
+    {
+        list($sJsCode, $sJsMethod) = $this->_getButtonJs($sType, $iClientId, $iVendorId, $aParams);
+
+    	return $this->_oModule->_oTemplate->parseHtmlByName('strp_button_' . $sType . '.html', array(
+            'type' => $sType,
+            'caption' => _t($this->_sLangsPrefix . 'strp_txt_checkout_with_' . $sType, $this->_sCaption),  
+            'onclick' => $sJsMethod,
+            'js_object' => $this->_oModule->_oConfig->getJsObject($this->_sName),
+            'js_code' => $sJsCode,
+    	));
+    }
+}
+
+/** @} */

+ 1192 - 0
modules/boonex/payment/updates/15.0.1_15.0.2/source/classes/BxPaymentProviderStripeV3.php

@@ -0,0 +1,1192 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Payment Payment
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+require_once('BxPaymentProviderStripeBasic.php');
+
+class BxPaymentProviderStripeV3 extends BxPaymentProviderStripeBasic implements iBxBaseModPaymentProvider
+{
+    protected $_oStripe;
+
+    protected $_iAmountPrecision;
+
+    function __construct($aConfig)
+    {
+        parent::__construct($aConfig);
+
+        $this->_aIncludeJs = array(
+            'stripe_v3.js'
+        );
+
+        $this->_oStripe = null;
+
+        $this->_iAmountPrecision = 2;
+    }
+
+    public function actionGetSessionRecurring()
+    {
+        $aClient = $this->_oModule->getProfileInfo();
+
+        $aParams = array(
+            'seller_id' => (int)bx_get('seller_id'),
+            'seller_provider' => bx_process_input(bx_get('seller_provider')),
+            'module_id' => (int)bx_get('module_id'),
+            'item_id' => (int)bx_get('item_id'),
+            'item_count' => (int)bx_get('item_count'),
+            'item_addons' => '',
+            'redirect' => bx_process_input(bx_get('redirect')),
+            'custom' => bx_process_input(bx_get('custom')),
+        );
+        
+        if(($mixedItemAddons = bx_get('item_addons')) !== false) {
+            $mixedItemAddons = bx_process_input($mixedItemAddons);
+            if(!is_array($mixedItemAddons))
+                $mixedItemAddons = strpos($mixedItemAddons, ',') !== false ? explode(',', $mixedItemAddons) : [$mixedItemAddons];
+
+            $aParams['item_addons'] = $this->_oModule->_oConfig->a2s($mixedItemAddons);
+        }
+
+        $aItems = array($this->_oModule->_oConfig->descriptorA2S(array(
+            'seller_id' => $aParams['seller_id'],
+            'module_id' => $aParams['module_id'],
+            'item_id' => $aParams['item_id'],
+            'item_count' => $aParams['item_count'],
+            'item_addons' => $aParams['item_addons'],
+        )));
+
+        $oCart = $this->_oModule->getObjectCart();
+        $aCartInfo = $oCart->getInfo(BX_PAYMENT_TYPE_RECURRING, $aClient['id'], $aParams['seller_id'], $aItems);
+        if(empty($aCartInfo) || !is_array($aCartInfo))
+            return echoJson(array('msg' => _t('_bx_payment_err_nothing_selected')));
+
+        $aItem = reset($aCartInfo['items']);
+
+        $aSessionParams = array(
+            'cancel_url' => $aItem['url'],
+            'success_url' => bx_append_url_params($this->_oModule->_oConfig->getUrl('URL_SUBSCRIBE_JSON'), array_merge($aParams, array(
+                'session_id' => '{CHECKOUT_SESSION_ID}'
+            )), false)
+        );
+
+        $mixedSession = $this->_createSession(BX_PAYMENT_TYPE_RECURRING, $aSessionParams, $aClient, $aCartInfo);
+        if($mixedSession === false)
+            return echoJson(array('msg' => _t('_bx_payment_err_cannot_perform')));
+
+        $sJsObject = $this->getJsObject(array(
+            'iModuleId' => $aParams['module_id'],
+            'iSellerId' => $aParams['seller_id'],
+            'iItemId' => $aParams['item_id']
+        ));
+
+        return echoJson(array(
+            'code' => 0, 
+            'session_id' => $mixedSession['id'],
+            'eval' => $sJsObject . '.onSubscribe(oData);'
+        ));
+    }
+
+    public function authorizeCheckout($iPendingId, $aCartInfo, $sRedirect = '')
+    {
+        $sSessionId = bx_process_input(bx_get('session_id'));
+
+    	if(empty($aCartInfo['items']) || !is_array($aCartInfo['items']))
+            return $this->_sLangsPrefix . 'err_empty_items';
+
+        $aClient = $this->_oModule->getProfileInfo();
+        $aVendor = $this->_oModule->getProfileInfo($aCartInfo['vendor_id']);
+
+        $aPending = $this->_oModule->_oDb->getOrderPending(array('type' => 'id', 'id' => $iPendingId));
+        if(!empty($aPending['order']) || !empty($aPending['error_code']) || !empty($aPending['error_msg']) || (int)$aPending['processed'] != 0)
+            return $this->_sLangsPrefix . 'err_already_processed';
+
+        switch($aPending['type']) {
+            case BX_PAYMENT_TYPE_SINGLE:
+                $mixedResult = $this->_getSession(BX_PAYMENT_TYPE_SINGLE, $sSessionId);
+                if($mixedResult === false)
+                    return $this->_sLangsPrefix . 'err_cannot_perform';
+
+                return [
+                    'code' => BX_PAYMENT_RESULT_SUCCESS,
+                    'redirect' => $this->getReturnDataUrl($aVendor['id'], array(
+                        'mode' => $mixedResult['mode'],
+                        'order_id' => $mixedResult['order_id'],
+                        'customer_id' => $mixedResult['customer_id'], 
+                        'pending_id' => $aPending['id'],
+                        'redirect' => $sRedirect
+                    ))
+                ];
+
+            case BX_PAYMENT_TYPE_RECURRING:
+                return $this->_sLangsPrefix . 'err_not_supported';
+        }
+    }
+
+    public function captureAuthorizedCheckout($sOrderAuth, $mixedPending, $aInfo)
+    {
+        $aPending = is_array($mixedPending) ? $mixedPending : $this->_oModule->_oDb->getOrderPending(['type' => 'id', 'id' => (int)$mixedPending]);
+        if(empty($aPending) || !is_array($aPending))
+            return ['code' => 2, 'message' => $this->_sLangsPrefix . 'err_empty_order'];
+
+        $bPaid = false;
+        $sOrder = '';
+        switch($aPending['type']) {
+            case BX_PAYMENT_TYPE_SINGLE:
+                $oPaymentIntent = $this->_createPaymentIntent($sOrderAuth, $aInfo['items_price'], $aInfo['vendor_currency_code']);
+                if($oPaymentIntent === false)
+                    return ['code' => 3, 'message' => $this->_sLangsPrefix . 'err_cannot_perform'];
+
+                $aPaymentIntent = $oPaymentIntent->jsonSerialize();
+                if(empty($aPaymentIntent) || !is_array($aPaymentIntent))
+                    return ['code' => 3, 'message' => $this->_sLangsPrefix . 'err_cannot_perform'];
+
+                $bPaid = $aPaymentIntent['status'] == 'succeeded';
+                $sOrder = $aPaymentIntent['id'];
+                break;
+
+            case BX_PAYMENT_TYPE_RECURRING:
+                return ['code' => 1, 'message' => $this->_sLangsPrefix . 'err_not_supported'];
+        }
+
+        $aResult = [
+            'code' => BX_PAYMENT_RESULT_SUCCESS,
+            'message' => $this->_sLangsPrefix . 'strp_msg_charged',
+            'pending_id' => $aPending['id'],
+            'paid' => $bPaid
+        ];
+
+        //--- Update pending transaction
+        $this->_oModule->_oDb->updateOrderPending($aResult['pending_id'], [
+            'order' => $sOrder,
+            'error_code' => $aResult['code'],
+            'error_msg' => _t($aResult['message']),
+        ]);
+
+        return $aResult;
+    }
+
+    public function initializeCheckout($iPendingId, $aCartInfo, $sRedirect = '')
+    {
+        $sSessionId = bx_process_input(bx_get('session_id'));
+
+    	if(empty($aCartInfo['items']) || !is_array($aCartInfo['items']))
+            return $this->_sLangsPrefix . 'err_empty_items';
+
+        $aClient = $this->_oModule->getProfileInfo();
+        $aVendor = $this->_oModule->getProfileInfo($aCartInfo['vendor_id']);
+
+        $aPending = $this->_oModule->_oDb->getOrderPending(array('type' => 'id', 'id' => $iPendingId));
+        if(!empty($aPending['order']) || !empty($aPending['error_code']) || !empty($aPending['error_msg']) || (int)$aPending['processed'] != 0)
+            return $this->_sLangsPrefix . 'err_already_processed';
+
+        switch($aPending['type']) {
+            case BX_PAYMENT_TYPE_SINGLE:
+                $mixedResult = $this->_getSession(BX_PAYMENT_TYPE_SINGLE, $sSessionId);
+                if($mixedResult === false || $mixedResult['status'] != 'paid')
+                    return $this->_sLangsPrefix . 'err_cannot_perform';
+                break;
+
+            case BX_PAYMENT_TYPE_RECURRING:
+                $mixedResult = $this->_getSession(BX_PAYMENT_TYPE_RECURRING, $sSessionId);
+                if($mixedResult === false)
+                    return $this->_sLangsPrefix . 'err_cannot_perform';
+                break;
+        }
+
+        $aProcessed = $this->_oModule->_oDb->getOrderPending(['type' => 'order', 'order' => $mixedResult['order_id']]);
+        if(!empty($aProcessed) && is_array($aProcessed) && (int)$aProcessed['processed'] != 0 && $aProcessed['id'] != $iPendingId)
+            return $this->_sLangsPrefix . 'err_already_processed';
+
+        $aData = [
+            'mode' => $mixedResult['mode'],
+            'order_id' => $mixedResult['order_id'],
+            'customer_id' => $mixedResult['customer_id'], 
+            'pending_id' => $aPending['id'],
+            'redirect' => $sRedirect
+        ];
+
+        if(bx_is_api())
+            return $this->_oModule->serviceFinalizeCheckout($this->_sName, $aVendor['id'], $aData);
+
+        header("Location: " . $this->getReturnDataUrl($aVendor['id'], $aData));
+        exit;
+    }
+
+    public function finalizeCheckout(&$aData)
+    {
+        $sMode = bx_process_input($aData['mode']);
+    	$sOrderId = bx_process_input($aData['order_id']);
+    	$sCustomerId = bx_process_input($aData['customer_id']);
+        $iPendingId = bx_process_input($aData['pending_id'], BX_DATA_INT);
+        if(empty($iPendingId))
+            return array('code' => 1, 'message' => $this->_sLangsPrefix . 'err_wrong_data');
+
+        $sRedirect = bx_process_input($aData['redirect']);
+
+        $aPending = $this->_oModule->_oDb->getOrderPending(array('type' => 'id', 'id' => $iPendingId));
+        if(!empty($aPending['order']) || !empty($aPending['error_code']) || !empty($aPending['error_msg']) || (int)$aPending['processed'] != 0)
+            return array('code' => 3, 'message' => $this->_sLangsPrefix . 'err_already_processed');
+
+        $aResult = array(
+            'code' => BX_PAYMENT_RESULT_SUCCESS,
+            'message' => '',
+            'pending_id' => $iPendingId,
+            'customer_id' => '',
+            'subscription_id' => '',
+            'client_name' => '',
+            'client_email' => '',
+            'authorized' => false,
+            'paid' => false,
+            'trial' => false,
+            'redirect' => $sRedirect
+        );
+
+        switch($aPending['type']) {
+            case BX_PAYMENT_TYPE_SINGLE:
+                $oCustomer = $this->_retrieveCustomer(BX_PAYMENT_TYPE_SINGLE, $sCustomerId);
+                if($oCustomer === false)
+                    return array('code' => 4, 'message' => $this->_sLangsPrefix . 'err_cannot_perform');
+
+                $aCustomer = $oCustomer->jsonSerialize();
+                if(empty($aCustomer) || !is_array($aCustomer))
+                    return array('code' => 4, 'message' => $this->_sLangsPrefix . 'err_cannot_perform');
+
+                $sMessage = '';
+                $bPaid = $bAuthorized = false;
+                switch($sMode) {
+                    case 'setup':
+                        $oSetupIntent = $this->_retrieveSetupIntent($sOrderId);
+                        if($oSetupIntent === false)
+                            return array('code' => 4, 'message' => $this->_sLangsPrefix . 'err_cannot_perform');
+                        
+                        $aSetupIntent = $oSetupIntent->jsonSerialize();
+                        if(empty($aSetupIntent) || !is_array($aSetupIntent))
+                            return array('code' => 4, 'message' => $this->_sLangsPrefix . 'err_cannot_perform');
+                                
+                        $sMessage = $this->_sLangsPrefix . 'strp_msg_authorized';
+                        $bAuthorized = $aSetupIntent['status'] == 'succeeded';
+                        break;
+
+                    case 'payment':
+                        $oPaymentIntent = $this->_retrievePaymentIntent($sOrderId);
+                        if($oPaymentIntent === false)
+                            return array('code' => 4, 'message' => $this->_sLangsPrefix . 'err_cannot_perform');
+
+                        $aPaymentIntent = $oPaymentIntent->jsonSerialize();
+                        if(empty($aPaymentIntent) || !is_array($aPaymentIntent))
+                            return array('code' => 4, 'message' => $this->_sLangsPrefix . 'err_cannot_perform');
+
+                        $sMessage = $this->_sLangsPrefix . 'strp_msg_charged';
+                        $bPaid = $aPaymentIntent['status'] == 'succeeded';
+                        break;
+                }
+
+                $aResult = array_merge($aResult, array(
+                    'message' => $sMessage,
+                    'client_email' => $aCustomer['email'],
+                    'authorized' => $bAuthorized,
+                    'paid' => $bPaid,
+                ));
+                break;
+
+            case BX_PAYMENT_TYPE_RECURRING:
+                $oCustomer = $this->_retrieveCustomer(BX_PAYMENT_TYPE_RECURRING, $sCustomerId);
+                $oSubscription = $this->_retrieveSubscription($sCustomerId, $sOrderId);
+                if($oCustomer === false || $oSubscription === false)
+                    return array('code' => 4, 'message' => $this->_sLangsPrefix . 'err_cannot_perform');
+
+                $aCustomer = $oCustomer->jsonSerialize();
+                $aSubscription = $oSubscription->jsonSerialize();
+                if(empty($aCustomer) || !is_array($aCustomer) || empty($aSubscription) || !is_array($aSubscription))
+                    return array('code' => 4, 'message' => $this->_sLangsPrefix . 'err_cannot_perform');
+
+                $aResult = array_merge($aResult, [
+                    'message' => $this->_sLangsPrefix . 'strp_msg_subscribed',
+                    'customer_id' => $sCustomerId,
+                    'subscription_id' => $sOrderId,
+                    'client_email' => $aCustomer['email'],
+                    'trial' => $this->isSubscriptionStatus(BX_PAYMENT_SBS_STATUS_TRIAL, $aSubscription)
+                ]);
+
+                $aPaymentPending = $this->_oModule->_oDb->getStrpPaymentPending($sOrderId);
+                if(empty($aPaymentPending) || !is_array($aPaymentPending)) 
+                    break;
+
+                if($this->_bCheckAmount && ((float)$aPending['amount'] != (float)$aPaymentPending['amount'] || strcasecmp($this->_oModule->_oConfig->getDefaultCurrencyCode(), $aPaymentPending['currency']) !== 0))
+                    break;
+
+                $aResult['paid'] = true;
+                break;
+        }
+
+        //--- Update pending transaction ---//
+        $this->_oModule->_oDb->updateOrderPending($iPendingId, array(
+            'order' => $sOrderId,
+            'error_code' => $aResult['code'],
+            'error_msg' => _t($aResult['message'])
+        ));
+
+        return $aResult;
+    }
+
+    public function getButtonSingle($iClientId, $iVendorId, $aParams = array())
+    {
+        if(!isset($aParams['sAction']))
+            return '';
+
+        return $aParams['sAction'] . parent::getButtonSingle($iClientId, $iVendorId, $aParams);
+    }
+
+    public function overwriteCheckoutParamsSingle($aParams, &$oGrid)
+    {
+        $aClient = $this->_oModule->getProfileInfo();
+
+        $oCart = $this->_oModule->getObjectCart();
+        $aCartInfo = $oCart->getInfo(BX_PAYMENT_TYPE_SINGLE, $aClient['id'], $aParams['seller_id'], $aParams['items']);
+        if(empty($aCartInfo) || !is_array($aCartInfo))
+            return array('msg' => _t('_bx_payment_err_nothing_selected'));
+
+        $aSessionParams = array(
+            'cancel_url' => $oCart->serviceGetCartUrl($aParams['seller_id']),
+            'success_url' => bx_append_url_params($this->_oModule->_oConfig->getUrl('URL_CART_CHECKOUT'), array_merge($aParams, array(
+                'session_id' => '{CHECKOUT_SESSION_ID}'
+            )), false)
+        );
+
+        $mixedSession = $this->_createSession(BX_PAYMENT_TYPE_SINGLE, $aSessionParams, $aClient, $aCartInfo);
+        if($mixedSession === false)
+            return array('msg' => _t('_bx_payment_err_cannot_perform'));
+
+        return array(
+            'eval' => $this->_oModule->_oConfig->getJsObject($this->_sName) . '.onCartCheckout(oData);', 
+            'session_id' => $mixedSession['id']
+        );
+    }
+
+    /**
+     * Note. Isn't used for now in default version.
+     */
+    public function createSessionAuthorize($sType, $iClientId, $iSellerId, $sItems, $aSessionParams = [])
+    {
+        $aClient = $this->_oModule->getProfileInfo($iClientId);
+
+        $oCart = $this->_oModule->getObjectCart();
+        $aCartInfo = $oCart->getInfo($sType, $aClient['id'], $iSellerId, $sItems);
+        if(empty($aCartInfo) || !is_array($aCartInfo))
+            return false;
+
+        $aSessionParams = array_merge([
+            'cancel_url' => $oCart->serviceGetCartUrl($iSellerId),
+            'success_url' => bx_append_url_params($this->_oModule->_oConfig->getUrl('URL_AUTHORIZE') . $sType . '/', [
+                'provider' => $this->_sName,
+                'seller_id' => $iSellerId,
+                'items' => $sItems,
+                'session_id' => '{CHECKOUT_SESSION_ID}'
+            ], false)
+        ], $aSessionParams);
+
+        $mixedSession = $this->_createSession('authorize', $aSessionParams, $aClient, $aCartInfo);
+        if($mixedSession === false)
+            return false;
+
+        return $mixedSession['id'];
+    }
+
+    /*
+     * https://stripe.com/docs/checkout/embedded/quickstart?client=react&lang=php
+     */
+    public function createSessionPaymentEmbedded($sType, $iClientId, $iSellerId, $sItems, $aSessionParams = [])
+    {
+        $aClient = $this->_oModule->getProfileInfo($iClientId);
+
+        $oCart = $this->_oModule->getObjectCart();
+        $aCartInfo = $oCart->getInfo($sType, $aClient['id'], $iSellerId, $sItems);
+        if(empty($aCartInfo) || !is_array($aCartInfo))
+            return false;
+
+        $aSessionParams = array_merge([
+            'ui_mode' => 'embedded',
+            'return_url' => bx_append_url_params($this->_oModule->_oConfig->getUrl('URL_CART_CHECKOUT'), [
+                'provider' => $this->_sName,
+                'seller_id' => $iSellerId,
+                'items' => $sItems,
+                'session_id' => '{CHECKOUT_SESSION_ID}'
+            ], false)
+        ], $aSessionParams);
+
+        if(strpos($aSessionParams['return_url'], 'session_id') === false)
+            $aSessionParams['return_url'] .= '&session_id={CHECKOUT_SESSION_ID}';
+
+        $mixedSession = $this->_createSession($sType, $aSessionParams, $aClient, $aCartInfo);
+        if($mixedSession === false)
+            return false;
+
+        return $mixedSession['client_secret'];
+    }
+
+    public function createTax($sName, $fPercentage, $bInclusive = false)
+    {
+        $oTax = null;
+        $aTax = [
+            'display_name' => $sName,
+            'percentage' => $fPercentage,
+            'inclusive' => $bInclusive,
+        ];
+
+        /**
+         * @hooks
+         * @hookdef hook-bx_payment-stripe_v3_create_tax 'bx_payment', 'stripe_v3_create_tax' - hook to override tax data redurned by payment provider
+         * - $unit_name - equals `bx_payment`
+         * - $action - equals `stripe_v3_create_tax`
+         * - $object_id - pending transaction id
+         * - $sender_id - not used
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `tax_object` - [object] by ref, an instance of tax, redurned by payment provider, can be overridden in hook processing
+         *      - `tax_params` - [array] by ref, array with tax parameters, can be overridden in hook processing
+         * @hook @ref hook-bx_payment-stripe_v3_create_tax
+         */
+        bx_alert($this->_oModule->_oConfig->getName(), $this->_sName . '_create_tax', 0, false, [
+            'tax_object' => &$oTax, 
+            'tax_params' => &$aTax,
+            'tax_params_ref' => &$aTax,
+        ]);
+
+        try {
+            if(empty($oTax))
+                $oTax = $this->_getStripe()->taxRates->create($aTax);
+        }
+        catch (Exception $oException) {
+            return $this->_processException('Create Tax Error: ', $oException);
+        }
+
+        $aResult = $oTax->jsonSerialize();
+        if(empty($aResult) || !is_array($aResult))
+            return false;
+
+        return $aResult['id'];
+    }
+
+    public function retrieveTax($sId)
+    {
+        $oTax = null;
+        
+        /**
+         * @hooks
+         * @hookdef hook-bx_payment-stripe_v3_retrieve_tax 'bx_payment', 'stripe_v3_retrieve_tax' - hook to override tax data retrieved from payment provider
+         * - $unit_name - equals `bx_payment`
+         * - $action - equals `stripe_v3_retrieve_tax`
+         * - $object_id - not used
+         * - $sender_id - not used
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `tax_id` - [string] by ref, unique tax id, can be overridden in hook processing
+         *      - `tax_object` - [object] by ref, an instance of tax, redurned by payment provider, can be overridden in hook processing
+         * @hook @ref hook-bx_payment-stripe_v3_retrieve_tax
+         */
+        bx_alert($this->_oModule->_oConfig->getName(), $this->_sName . '_retrieve_tax', 0, false, [
+            'tax_id' => &$sId,
+            'tax_object' => &$oTax
+        ]);
+
+        try {
+            if(empty($oTax))
+                $oTax = $this->_getStripe()->taxRates->retrieve($sId);
+        }
+        catch (Exception $oException) {
+            return $this->_processException('Retrieve Tax Error: ', $oException);
+        }
+
+        return $oTax;
+    }
+
+    public function getVerificationCodeSession($iVendorId, $iCustomerId, $fAmount, $sCurrency)
+    {
+        $sCode = $this->_getVerificationCodeSession($iVendorId, $iCustomerId, $fAmount, $sCurrency);
+
+        /**
+         * @hooks
+         * @hookdef hook-bx_payment-stripe_v3_get_code_session 'bx_payment', 'stripe_v3_get_code_session' - hook to override session verification code
+         * - $unit_name - equals `bx_payment`
+         * - $action - equals `stripe_v3_get_code_session`
+         * - $object_id - not used
+         * - $sender_id - not used
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `provider` - [object] an instance of provider, @see BxBaseModPaymentProvider
+         *      - `vendor_id` - [int] vendor (seller) profile id
+         *      - `customer_id` - [int] customer (buyer) profile id
+         *      - `amount` - [float] session amount
+         *      - `currency` - [string] session currency code
+         *      - `override_result` - [string] by ref, verification code, can be overridden in hook processing
+         * @hook @ref hook-bx_payment-stripe_v3_get_code_session
+         */        
+        bx_alert($this->_oModule->_oConfig->getName(), $this->_sName . '_get_code_session', 0, false, [
+            'provider' => $this,
+            'vendor_id' => $iVendorId, 
+            'customer_id' => $iCustomerId,
+            'amount' => $fAmount,
+            'currency' => $sCurrency,
+            'override_result' => &$sCode
+        ]);
+
+        return $sCode;
+    }
+
+    public function checkVerificationCodeSession($iVendorId, $iCustomerId, $aResult)
+    {
+        $bCheckResult = $this->_checkVerificationCodeSession($iVendorId, $iCustomerId, $aResult);
+
+        /**
+         * @hooks
+         * @hookdef hook-bx_payment-stripe_v3_verify_session 'bx_payment', 'stripe_v3_verify_session' - hook to override checking of session verification code
+         * - $unit_name - equals `bx_payment`
+         * - $action - equals `stripe_v3_verify_session`
+         * - $object_id - not used
+         * - $sender_id - not used
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `provider` - [object] an instance of provider, @see BxBaseModPaymentProvider
+         *      - `vendor_id` - [int] vendor (seller) profile id
+         *      - `customer_id` - [int] customer (buyer) profile id
+         *      - `result` - [array] results array received from payment provider
+         *      - `override_result` - [boolean] by ref, is verification passed or not, can be overridden in hook processing
+         * @hook @ref hook-bx_payment-stripe_v3_verify_session
+         */
+        bx_alert($this->_oModule->_oConfig->getName(), $this->_sName . '_verify_session', 0, false, [
+            'provider' => $this,
+            'vendor_id' => $iVendorId, 
+            'customer_id' => $iCustomerId,
+            'result' => $aResult,
+            'override_result' => &$bCheckResult
+        ]);
+
+        return $bCheckResult;
+    }
+
+    protected function _getStripe()
+    {
+        if(empty($this->_oStripe))
+            $this->_oStripe = new \Stripe\StripeClient($this->_getSecretKey());
+
+        return $this->_oStripe;
+    }
+
+    /*
+     * Related Docs: https://stripe.com/docs/api/customers/retrieve
+     */
+    protected function _retrieveCustomer($sType, $sId)
+    {
+        $oCustomer = null;
+        
+        /**
+         * @hooks
+         * @hookdef hook-bx_payment-stripe_v3_retrieve_customer 'bx_payment', 'stripe_v3_retrieve_customer' - hook to override customer data retrieved from payment provider
+         * It's equivalent to @ref hook-bx_payment-stripe_retrieve_customer
+         * @hook @ref hook-bx_payment-stripe_v3_retrieve_customer
+         */
+        bx_alert($this->_oModule->_oConfig->getName(), $this->_sName . '_retrieve_customer', 0, false, [
+            'type' => $sType,
+            'customer_id' => &$sId,
+            'customer_object' => &$oCustomer
+        ]);
+
+        try {
+            if(empty($oCustomer))
+                $oCustomer = $this->_getStripe()->customers->retrieve($sId);
+        }
+        catch (Exception $oException) {
+            return $this->_processException('Retrieve Customer Error: ', $oException);
+        }
+
+        return $oCustomer;
+    }
+
+    /*
+     * Related Docs: https://stripe.com/docs/api/checkout/sessions/create
+     */
+    protected function _createSession($sType, $aParams, &$aClient, &$aCartInfo)
+    {
+        $sMode = '';
+        $aLineItems = $aMetaItems = [];
+        $bVerify = true;
+
+        switch($sType) {
+            case 'authorize':
+                $sMode = 'setup';
+                $bVerify = false;
+
+                foreach($aCartInfo['items'] as $aItem) {
+                    $aMetaItems[] = $this->_oModule->_oConfig->descriptorA2S([$aItem['module_id'], $aItem['id']]);
+                    if(!empty($aItem['addons']) && is_array($aItem['addons']))
+                        foreach($aItem['addons'] as $aAddon)
+                            $aMetaItems[] = $this->_oModule->_oConfig->descriptorA2S([$aAddon['module_id'], $aAddon['id']]);
+                }
+
+                $aParams['customer_creation'] = 'always';
+                break;
+
+            case BX_PAYMENT_TYPE_SINGLE:
+                $sMode = 'payment';
+
+                foreach($aCartInfo['items'] as $aItem) {
+                    list($_aLineItems, $_aMetaItems) = $this->_getLineItems($sType, $aItem, [
+                        'vendor_currency_code' => $aCartInfo['vendor_currency_code']
+                    ]);
+
+                    $aLineItems = array_merge($aLineItems, $_aLineItems);
+                    $aMetaItems = array_merge($aMetaItems, $_aMetaItems);
+                }
+
+                $aParams['customer_creation'] = 'always';
+                break;
+
+            case BX_PAYMENT_TYPE_RECURRING:
+                $sMode = 'subscription';
+                $iTrial = 0;
+
+                foreach($aCartInfo['items'] as $aItem) {
+                    list($_aLineItems, $_aMetaItems) = $this->_getLineItems($sType, $aItem, [
+                        'vendor_currency_code' => $aCartInfo['vendor_currency_code']
+                    ]);
+
+                    $aLineItems = array_merge($aLineItems, $_aLineItems);
+                    $aMetaItems = array_merge($aMetaItems, $_aMetaItems);
+
+                    if((int)$aItem['trial_recurring'] > 0)
+                        $iTrial = (int)$aItem['trial_recurring'];
+                }
+
+                if($iTrial > 0) {
+                    $bVerify = false;
+
+                    $aParams['subscription_data'] = [
+                        'trial_period_days' => $iTrial
+                    ];
+                }
+
+                break;
+        }
+
+        $oSession = null;
+        $aSession = array_merge([
+            'mode' => $sMode,
+            'payment_method_types' => ['card'],
+            'customer_email' => !empty($aClient['email']) ? $aClient['email'] : ''
+        ], $aParams);
+
+        $bLineItems = !empty($aLineItems);
+        $aSession['line_items'] = $aLineItems;
+
+        $bMetaData = !empty($aMetaItems);
+        if($bMetaData) {
+            $aSession['metadata'] = [
+                'vendor' => $aCartInfo['vendor_id'],
+                'client' => $aClient['id'],
+                'type' => $sType, 
+                'items' => $this->_oModule->_oConfig->descriptorsA2S($aMetaItems)
+            ];
+
+            if($bVerify) {
+                $fAmount = 100 * round((float)$aCartInfo['items_price'], $this->_iAmountPrecision);
+                $aSession['metadata']['verification'] = $this->getVerificationCodeSession($aCartInfo['vendor_id'], $aClient['id'], $fAmount, $aCartInfo['vendor_currency_code']);
+            }
+        }
+
+        /**
+         * @hooks
+         * @hookdef hook-bx_payment-stripe_v3_create_session 'bx_payment', 'stripe_v3_create_session' - hook to override session data redurned by payment provider
+         * - $unit_name - equals `bx_payment`
+         * - $action - equals `stripe_v3_create_session`
+         * - $object_id - pending transaction id
+         * - $sender_id - not used
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `session_object` - [object] by ref, an instance of session, redurned by payment provider, can be overridden in hook processing
+         *      - `session_params` - [array] by ref, array with session parameters, can be overridden in hook processing
+         * @hook @ref hook-bx_payment-stripe_v3_create_session
+         */
+        bx_alert($this->_oModule->_oConfig->getName(), $this->_sName . '_create_session', 0, false, [
+            'session_object' => &$oSession, 
+            'session_params' => &$aSession
+        ]);
+
+        try {
+            if(empty($oSession))
+                $oSession = $this->_getStripe()->checkout->sessions->create($aSession);
+        }
+        catch (Exception $oException) {
+            return $this->_processException('Create Session Error: ', $oException);
+        }
+
+        $aResult = $oSession->jsonSerialize();
+        if(empty($aResult) || !is_array($aResult))
+            return false;
+
+        if($bVerify && !$this->checkVerificationCodeSession($aCartInfo['vendor_id'], $aClient['id'], $aResult))
+            return false;
+
+        return $aResult;
+    }
+
+    protected function _getSession($sType, $sId)
+    {
+        $oSession = $this->_retrieveSession($sId);
+        if($oSession === false)
+            return false;
+
+        $aSession = $oSession->jsonSerialize();
+        if(empty($aSession) || !is_array($aSession))
+            return array();
+
+        $sMode = 'payment';
+        if(!empty($aSession['mode']))
+            $sMode = $aSession['mode'];
+        
+        $aResult = array(
+            'id' => $aSession['id'],
+            'mode' => $sMode,
+            'order_id' => '',
+            'customer_id' => $aSession['customer'],
+            'status' => $aSession['payment_status']
+        );
+
+        switch($sType) {
+            case BX_PAYMENT_TYPE_SINGLE:
+                $aResult['order_id'] = $aSession[($sMode == 'setup' ? 'setup' : 'payment') . '_intent'];
+                break;
+
+            case BX_PAYMENT_TYPE_RECURRING:
+                $aResult['order_id'] = $aSession['subscription'];
+                break;
+        }
+
+        return $aResult;
+    }
+
+    /*
+     * Related Docs: https://stripe.com/docs/api/checkout/sessions/retrieve
+     */
+    protected function _retrieveSession($sId)
+    {
+        $oSession = null;
+        
+        /**
+         * @hooks
+         * @hookdef hook-bx_payment-stripe_v3_retrieve_session 'bx_payment', 'stripe_v3_retrieve_session' - hook to override session data retrieved from payment provider
+         * - $unit_name - equals `bx_payment`
+         * - $action - equals `stripe_v3_retrieve_session`
+         * - $object_id - not used
+         * - $sender_id - not used
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `session_id` - [string] by ref, unique session id, can be overridden in hook processing
+         *      - `session_object` - [object] by ref, an instance of session, redurned by payment provider, can be overridden in hook processing
+         * @hook @ref hook-bx_payment-stripe_v3_retrieve_session
+         */
+        bx_alert($this->_oModule->_oConfig->getName(), $this->_sName . '_retrieve_session', 0, false, [
+            'session_id' => &$sId,
+            'session_object' => &$oSession
+        ]);
+
+        try {
+            if(empty($oSession))
+                $oSession = $this->_getStripe()->checkout->sessions->retrieve($sId);
+        }
+        catch (Exception $oException) {
+            return $this->_processException('Retrieve Session Error: ', $oException);
+        }
+
+        return $oSession;
+    }
+    
+    
+    /*
+     * Related Docs: https://stripe.com/docs/api/setup_intents/retrieve
+     */
+    protected function _retrieveSetupIntent($sId)
+    {
+        $oSetupIntent = null;
+
+        /**
+         * @hooks
+         * @hookdef hook-bx_payment-stripe_v3_retrieve_setup_intent 'bx_payment', 'stripe_v3_retrieve_setup_intent' - hook to override SetupIntent data retrieved from payment provider
+         * - $unit_name - equals `bx_payment`
+         * - $action - equals `stripe_v3_retrieve_setup_intent`
+         * - $object_id - not used
+         * - $sender_id - not used
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `setup_intent_id` - [string] by ref, unique SetupIntent id, can be overridden in hook processing
+         *      - `setup_intent_object` - [object] by ref, an instance of SetupIntent, redurned by payment provider, can be overridden in hook processing
+         * @hook @ref hook-bx_payment-stripe_v3_retrieve_setup_intent
+         */
+        bx_alert($this->_oModule->_oConfig->getName(), $this->_sName . '_retrieve_setup_intent', 0, false, [
+            'setup_intent_id' => &$sId,
+            'setup_intent_object' => &$oSetupIntent
+        ]);
+
+        try {
+            if(empty($oSetupIntent))
+                $oSetupIntent = $this->_getStripe()->setupIntents->retrieve($sId);
+        }
+        catch (Exception $oException) {
+            return $this->_processException('Retrieve Setup Intent Error: ', $oException);
+        }
+
+        return $oSetupIntent;
+    }
+
+    /*
+     * Related Docs: https://stripe.com/docs/api/payment_intents/create
+     */
+    protected function _createPaymentIntent($sSetupIntentId, $fAmount, $sCurrency, $bConfirm = true)
+    {
+        $oPaymentIntent = null;
+
+        /**
+         * @hooks
+         * @hookdef hook-bx_payment-stripe_v3_create_payment_intent 'bx_payment', 'stripe_v3_create_payment_intent' - hook to override PaymentIntent data redurned by payment provider
+         * - $unit_name - equals `bx_payment`
+         * - $action - equals `stripe_v3_create_payment_intent`
+         * - $object_id - not used
+         * - $sender_id - not used
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `setup_intent_id` - [string] by ref, unique SetupIntent id, can be overridden in hook processing
+         *      - `payment_intent_object` - [object] by ref, an instance of PaymentIntent, redurned by payment provider, can be overridden in hook processing
+         * @hook @ref hook-bx_payment-stripe_v3_create_payment_intent
+         */
+        bx_alert($this->_oModule->_oConfig->getName(), $this->_sName . '_create_payment_intent', 0, false, [
+            'setup_intent_id' => &$sSetupIntentId,
+            'payment_intent_object' => &$oPaymentIntent
+        ]);
+
+        try {
+            if(empty($oPaymentIntent)) {
+                $oSetupIntent = $this->_retrieveSetupIntent($sSetupIntentId);
+                if($oSetupIntent === false)
+                    return false;
+
+                $aSetupIntent = $oSetupIntent->jsonSerialize();
+                if(empty($aSetupIntent) || !is_array($aSetupIntent))
+                    return false;
+
+                $oPaymentIntent = $this->_getStripe()->paymentIntents->create([
+                    'amount' => 100 * round($fAmount, $this->_iAmountPrecision),
+                    'currency' => strtolower($sCurrency),
+                    'customer' => $aSetupIntent['customer'],
+                    'payment_method' => $aSetupIntent['payment_method'],
+                    'confirm' => $bConfirm
+                ]);
+            }
+        }
+        catch (Exception $oException) {
+            return $this->_processException('Retrieve Payment Intent Error: ', $oException);
+        }
+
+        return $oPaymentIntent;
+    }
+
+    /*
+     * Related Docs: https://stripe.com/docs/api/payment_intents/retrieve
+     */
+    protected function _retrievePaymentIntent($sId)
+    {
+        $oPaymentIntent = null;
+
+        /**
+         * @hooks
+         * @hookdef hook-bx_payment-stripe_v3_retrieve_payment_intent 'bx_payment', 'stripe_v3_retrieve_payment_intent' - hook to override PaymentIntent data retrieved from payment provider
+         * - $unit_name - equals `bx_payment`
+         * - $action - equals `stripe_v3_retrieve_payment_intent`
+         * - $object_id - not used
+         * - $sender_id - not used
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `payment_intent_id` - [string] by ref, unique PaymentIntent id, can be overridden in hook processing
+         *      - `payment_intent_object` - [object] by ref, an instance of PaymentIntent, redurned by payment provider, can be overridden in hook processing
+         * @hook @ref hook-bx_payment-stripe_v3_retrieve_payment_intent
+         */
+        bx_alert($this->_oModule->_oConfig->getName(), $this->_sName . '_retrieve_payment_intent', 0, false, [
+            'payment_intent_id' => &$sId,
+            'payment_intent_object' => &$oPaymentIntent
+        ]);
+
+        try {
+            if(empty($oPaymentIntent))
+                $oPaymentIntent = $this->_getStripe()->paymentIntents->retrieve($sId);
+        }
+        catch (Exception $oException) {
+            return $this->_processException('Retrieve Payment Intent Error: ', $oException);
+        }
+
+        return $oPaymentIntent;
+    }
+    
+    /*
+     * Related Docs: https://stripe.com/docs/api/subscriptions/retrieve
+     */
+    protected function _retrieveSubscription($sCustomerId, $sSubscriptionId)
+    {
+        $oSubscription = null;
+        
+        /**
+         * @hooks
+         * @hookdef hook-bx_payment-stripe_v3_retrieve_subscription 'bx_payment', 'stripe_v3_retrieve_subscription' - hook to override subscription data retrieved from payment provider
+         * - $unit_name - equals `bx_payment`
+         * - $action - equals `stripe_v3_retrieve_subscription`
+         * - $object_id - not used
+         * - $sender_id - not used
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `subscription_id` - [string] by ref, unique subscription id, can be overridden in hook processing
+         *      - `subscription_object` - [object] by ref, an instance of subscription, redurned by payment provider, can be overridden in hook processing
+         * @hook @ref hook-bx_payment-stripe_v3_retrieve_subscription
+         */
+        bx_alert($this->_oModule->_oConfig->getName(), $this->_sName . '_retrieve_subscription', 0, false, [
+            'subscription_id' => &$sSubscriptionId,
+            'subscription_object' => &$oSubscription
+        ]);
+
+        try {
+            if(empty($oSubscription))
+                $oSubscription = $this->_getStripe()->subscriptions->retrieve($sSubscriptionId);
+        }
+        catch (Exception $oException) {
+            return $this->_processException('Retrieve Subscription Error: ', $oException);
+        }
+
+        return $oSubscription;
+    }
+
+    /*
+     * Related Docs: https://stripe.com/docs/api/tokens/create_card
+     */
+    protected function _createToken($aCard)
+    {
+        try {
+            $oToken = $this->_getStripe()->tokens->create(['card' => $aCard]);
+        }
+        catch (Stripe\Error\Base $oException) {
+            return $this->_processException('Create Token Error: ', $oException);
+        }
+
+        return $oToken->jsonSerialize();
+    }
+
+    /*
+     * Related Docs: https://stripe.com/docs/api/cards/create
+     */
+    protected function _createCard($sType, $sCustomerId, $sToken)
+    {
+        try {
+            $oCard = $this->_getStripe()->customers->createSource($sCustomerId, [
+                'source' => $sToken
+            ]);
+        }
+        catch (Stripe\Error\Base $oException) {
+            return $this->_processException('Create Card Error: ', $oException);
+        }
+
+        return $oCard->jsonSerialize();
+    }
+
+    protected function _retrieveCard($sCustomerId, $sCardId = '')
+    {
+        try {
+            $oCustomer = $this->_getStripe()->customers->retrieve($sCustomerId);
+
+            if(empty($sCardId))
+                $sCardId = $oCustomer->default_source;
+            if(empty($sCardId))
+                return false;
+
+            $oCard = $this->_getStripe()->customers->retrieveSource($sCustomerId, $sCardId);
+        }
+        catch (Exception $oException) {
+            return $this->_processException('Retrieve Card Error: ', $oException);
+        }
+
+        return $oCard;
+    }
+
+    /*
+     * Related Docs: https://stripe.com/docs/api/payment_methods/retrieve
+     */
+    protected function _retrievePaymentMethod($sPaymentMethodId)
+    {
+        try {
+            $oPaymentMethod = $this->_getStripe()->paymentMethods->retrieve($sPaymentMethodId);
+        }
+        catch (Exception $oException) {
+            return $this->_processException('Retrieve Payment Method Error: ', $oException);
+        }
+
+        return $oPaymentMethod;
+    }
+
+    protected function _getButton($sType, $iClientId, $iVendorId, $aParams = array())
+    {
+        list($sJsCode, $sJsMethod) = $this->_getButtonJs($sType, $iClientId, $iVendorId, $aParams);
+
+    	if($sType == BX_PAYMENT_TYPE_SINGLE)
+            return $sJsCode;
+
+        return parent::_getButton($sType, $iClientId, $iVendorId);
+    }
+
+    protected function _getButtonJs($sType, $iClientId, $iVendorId, $aParams = array())
+    {
+        $sClientEmail = '';
+    	if(!empty($iClientId) && ($oClient = BxDolProfile::getInstance($iClientId)) !== false)
+            $sClientEmail = $oClient->getAccountObject()->getEmail();
+
+        $sPublicKey = '';
+        $sConnectedAccountId = '';
+        
+        /**
+         * @hooks
+         * @hookdef hook-bx_payment-stripe_v3_get_button 'bx_payment', 'stripe_v3_get_button' - hook to override checkout/subscibe button
+         * - $unit_name - equals `bx_payment`
+         * - $action - equals `stripe_v3_get_button`
+         * - $object_id - not used
+         * - $sender_id - client (buyer) profile id
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `type` - [string] by ref, payment type ('single' or 'recurring'), can be overridden in hook processing
+         *      - `public_key` - [string] by ref, public key from Stripe account, can be overridden in hook processing
+         * @hook @ref hook-bx_payment-stripe_v3_get_button
+         */
+    	bx_alert($this->_oModule->_oConfig->getName(), $this->_sName . '_get_button', 0, $iClientId, [
+            'client_id' => $iClientId,
+            'vendor_id' => $iVendorId,
+
+            'type' => &$sType, 
+            'public_key' => &$sPublicKey,
+            'connected_account_id' => &$sConnectedAccountId,
+
+            'type_ref' => &$sType, 
+            'public_key_ref' => &$sPublicKey,
+            'connected_account_id_ref' => &$sConnectedAccountId,
+        ]);
+
+        $sJsMethod = '';
+        $sJsObject = $this->getJsObject($aParams);
+        switch($sType) {
+            case BX_PAYMENT_TYPE_SINGLE:
+                $sJsMethod = 'void(0)';
+                break;
+
+            case BX_PAYMENT_TYPE_RECURRING:
+                $sJsMethod = $sJsObject . '.subscribe(this)';
+                break;
+        }
+
+        return [$this->_oModule->_oTemplate->getJsCode($this->_sName, array_merge([
+            'js_object' => $sJsObject,
+            'sProvider' => $this->_sName,
+            'sPublicKey' => !empty($sPublicKey) ? $sPublicKey : $this->_getPublicKey(),
+            'sConnectedAccountId' => $sConnectedAccountId,
+            'sVendorName' => '',
+            'sVendorCurrency' => '',
+            'sVendorIcon' => '',
+            'sClientEmail' => $sClientEmail,
+        ], $aParams)), $sJsMethod];
+    }
+
+    protected function _getVerificationCodeSession($iVendorId, $iCustomerId, $fAmount, $sCurrency)
+    {
+        return md5(implode('#-#', array(
+            (int)$iVendorId,
+            (int)$iCustomerId,
+            (float)$fAmount,
+            strtoupper($sCurrency)
+        )));
+    }
+
+    protected function _checkVerificationCodeSession($iVendorId, $iCustomerId, $aResult)
+    {
+        return !empty($aResult['metadata']['verification']) && $aResult['metadata']['verification'] == $this->getVerificationCodeSession($iVendorId, $iCustomerId, $aResult['amount_total'], $aResult['currency']);
+    }
+
+    protected function _getLineItems($sType, $aItem, $aParams = [])
+    {
+        $aLineItems = $aMetaItems = [];
+
+        $bRecurring = $sType == BX_PAYMENT_TYPE_RECURRING;
+        $sCurrency = ($sKey = 'vendor_currency_code') && !empty($aParams[$sKey]) ? $aParams[$sKey] : $this->_oModule->_oConfig->getDefaultCurrencyCode();
+
+        $aProductData = [
+            'name' => $aItem['title']
+        ];
+        if(!empty($aItem['description']))
+            $aProductData['description'] = strmaxtextlen(strip_tags($aItem['description']), 60, '...');
+
+        $aLineItem = [
+            'price_data' => [
+                'currency' => $sCurrency,
+                'product_data' => $aProductData,
+                'unit_amount' => 100 * $this->_oModule->_oConfig->getPrice($sType, $aItem, $this->_iAmountPrecision),
+            ],
+            'quantity' => $aItem['quantity'],
+        ];
+        
+        if($bRecurring && ($mixedPeriod = $this->_oModule->_oConfig->getPeriod($sType, $aItem)) !== false) {
+            list($iPeriod, $sPeriodUnit) = $mixedPeriod;
+            $aLineItem['price_data']['recurring'] = [
+                'interval' => $sPeriodUnit,
+                'interval_count' => $iPeriod
+            ];
+        }
+
+        $aLineItems[] = $aLineItem;
+        $aMetaItems[] = $this->_oModule->_oConfig->descriptorA2S([$aItem['module_id'], $aItem['id']]);
+
+        if(!empty($aItem['addons']) && is_array($aItem['addons']))
+            foreach($aItem['addons'] as $aAddon) {
+                $aAddonData = [
+                    'name' => $aAddon['title']
+                ];
+                if(!empty($aAddon['description']))
+                    $aAddonData['description'] = strmaxtextlen(strip_tags($aAddon['description']), 60, '...');
+
+                $aLineItem = [
+                    'price_data' => [
+                        'currency' => $sCurrency,
+                        'product_data' => $aAddonData,
+                        'unit_amount' => 100 * $this->_oModule->_oConfig->getPrice($sType, $aAddon, $this->_iAmountPrecision),
+                    ],
+                    'quantity' => $aAddon['quantity'],
+                ];
+                
+                if($bRecurring && ($mixedPeriod = $this->_oModule->_oConfig->getPeriod($sType, $aAddon)) !== false) {
+                    list($iPeriod, $sPeriodUnit) = $mixedPeriod;
+                    $aLineItem['price_data']['recurring'] = [
+                        'interval' => $sPeriodUnit,
+                        'interval_count' => $iPeriod
+                    ];
+                }
+
+                $aLineItems[] = $aLineItem;
+                $aMetaItems[] = $this->_oModule->_oConfig->descriptorA2S([$aAddon['module_id'], $aAddon['id']]);
+            }
+
+        return [$aLineItems, $aMetaItems];
+    }
+
+    protected function _processException($sMessage, &$oException)
+    {
+        if(method_exists($oException, 'getError') && ($oError = $oException->getError())) {
+            $sError = $oError->message;
+            $aError = $oError->toArray();
+        }
+        else { 
+            $sError = $oException->getMessage();
+            $aError = array();
+        }
+
+        $this->log($sMessage . $sError, '', BX_LOG_ERR);
+        if(!empty($aError))
+            $this->log($aError, '', BX_LOG_ERR);
+
+        return false;
+    }
+}
+
+/** @} */

+ 689 - 0
modules/boonex/payment/updates/15.0.1_15.0.2/source/classes/BxPaymentSubscriptions.php

@@ -0,0 +1,689 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Payment Payment
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+class BxPaymentSubscriptions extends BxBaseModPaymentSubscriptions
+{
+    function __construct()
+    {
+    	$this->MODULE = 'bx_payment';
+
+    	parent::__construct();
+    }
+
+    /*
+     * Service methods
+     */
+    
+    /**
+     * @page service Service Calls
+     * @section bx_payment Payment
+     * @subsection bx_payment-page_blocks Page Blocks
+     * @subsubsection bx_payment-get_block_list_my get_block_list_my
+     * 
+     * @code bx_srv('bx_payment', 'get_block_list_my', [...], 'Subscriptions'); @endcode
+     * 
+     * Get page block with a list of currently logged in member's subscriptions.
+     *
+     * @return an array describing a block to display on the site. All necessary CSS and JS files are automatically added to the HEAD section of the site HTML.
+     * 
+     * @see BxPaymentSubscriptions::serviceGetBlockListMy
+     */
+    /** 
+     * @ref bx_payment-get_block_list_my "get_block_list_my"
+     */
+    public function serviceGetBlockListMy()
+    {
+        return $this->_getBlock('list_my');
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_payment Payment
+     * @subsection bx_payment-page_blocks Page Blocks
+     * @subsubsection bx_payment-get_block_list_all get_block_list_all
+     * 
+     * @code bx_srv('bx_payment', 'get_block_list_all', [...], 'Subscriptions'); @endcode
+     * 
+     * Get page block with a list of all subscriptions. It's available for authorized members only.
+     *
+     * @return an array describing a block to display on the site. All necessary CSS and JS files are automatically added to the HEAD section of the site HTML.
+     * 
+     * @see BxPaymentSubscriptions::serviceGetBlockListAll
+     */
+    /** 
+     * @ref bx_payment-get_block_list_all "get_block_list_all"
+     */
+    public function serviceGetBlockListAll()
+    {
+        return $this->_getBlock('list_all');
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_payment Payment
+     * @subsection bx_payment-page_blocks Page Blocks
+     * @subsubsection bx_payment-get_block_history get_block_history
+     * 
+     * @code bx_srv('bx_payment', 'get_block_history', [...], 'Subscriptions'); @endcode
+     * 
+     * Get page block with a list of payments related to subscriptions of currently logged in member.
+     *
+     * @return an array describing a block to display on the site. All necessary CSS and JS files are automatically added to the HEAD section of the site HTML.
+     * 
+     * @see BxPaymentSubscriptions::serviceGetBlockHistory
+     */
+    /** 
+     * @ref bx_payment-get_block_history "get_block_history"
+     */
+    public function serviceGetBlockHistory()
+    {
+        return $this->_getBlock('history');
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_payment Payment
+     * @subsection bx_payment-other Other
+     * @subsubsection bx_payment-get_subscription_orders_info get_subscription_orders_info
+     * 
+     * @code bx_srv('bx_payment', 'get_subscription_orders_info', [...], 'Subscriptions'); @endcode
+     * 
+     * Get subscription transaction(s) which meets all requirements.
+     *
+     * @param $aConditions an array of pears('key' => 'value'). The most useful keys are the following:
+     * a. client_id - client's ID (integer)
+     * b. seller_id - seller's ID (integer)
+     * c. type - transaction type: single or recurring (string)
+     * d. amount - transaction amount (float)
+     * e. order - order ID received from payment provider (string)
+     * f. provider - payment provider name (string)
+     * g. date - the date when the payment was established(UNIXTIME STAMP)
+     * h. processed - whether the payment was processed or not (integer, 0 or 1)
+     * @return an array of transactions. Each transaction has full info(client ID, seller ID, external transaction ID, date and so on)
+     * 
+     * @see BxPaymentSubscriptions::serviceGetSubscriptionOrdersInfo
+     */
+    /** 
+     * @ref bx_payment-get_subscription_orders_info "get_subscription_orders_info"
+     */
+    public function serviceGetSubscriptionOrdersInfo($aConditions)
+    {
+        if(empty($aConditions) || !is_array($aConditions))
+            return array();
+
+        return $this->_oModule->_oDb->getOrderSubscription(array('type' => 'mixed', 'conditions' => $aConditions));
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_payment Payment
+     * @subsection bx_payment-other Other
+     * @subsubsection bx_payment-get_subscriptions_info get_subscriptions_info
+     * 
+     * @code bx_srv('bx_payment', 'get_subscriptions_info', [...], 'Subscriptions'); @endcode
+     * 
+     * Get subscription(s) which meets all requirements.
+     *
+     * @param $aConditions an array of pears('key' => 'value'). The most useful keys are the following:
+     * a. pending_id - pending transaction ID (integer)
+     * b. customer_id - customer ID from payment provider (string)
+     * c. subscription_id - subscription ID from payment provider (string)
+     * d. paid - flag determining whether the subscription paid or not (integer)
+     * e. date - the date when the subscription was established(UNIXTIME STAMP)
+     * @param $bCheckInProvider boolean value determining whether the subscription should be checked in associated payment provider.
+     * @return an array of subscriptions. Each subscription has full info(pending ID, customer ID, subscription ID and so on)
+     * 
+     * @see BxPaymentSubscriptions::serviceGetSubscriptionsInfo
+     */
+    /** 
+     * @ref bx_payment-get_subscriptions_info "get_subscriptions_info"
+     */
+    public function serviceGetSubscriptionsInfo($aConditions, $bCheckInProvider = false)
+    {
+        if(empty($aConditions) || !is_array($aConditions))
+            return array();
+
+        $aSubscriptions = $this->_oModule->_oDb->getSubscription(array('type' => 'mixed_ext', 'conditions' => $aConditions));
+        if(empty($aSubscriptions) || !is_array($aSubscriptions) || !$bCheckInProvider)
+            return $aSubscriptions;
+
+        foreach($aSubscriptions as $iKey => $aSubscription) {
+            if(empty($aSubscription['provider']) || $aSubscription['provider'] == 'manual')
+                continue;
+
+            $oProvider = $this->_oModule->getObjectProvider($aSubscription['provider'], $aSubscription['seller_id']);
+            if(!$oProvider)
+                continue;
+
+            $aSubscriptions[$iKey]['data'] = $oProvider->getSubscription($aSubscription['pending_id'], $aSubscription['customer_id'], $aSubscription['subscription_id']);
+        }
+
+        return $aSubscriptions;
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_payment Payment
+     * @subsection bx_payment-purchase_processing Purchase Processing
+     * @subsubsection bx_payment-subscribe subscribe
+     * 
+     * @code bx_srv('bx_payment', 'subscribe', [...], 'Subscriptions'); @endcode
+     * 
+     * Initialize subscription for specified item.
+     *
+     * @param $iSellerId integer value with seller ID.
+     * @param $sSellerProvider string value with a name of payment provider to be used for processing. Empty value means that payment provider selector should be shown.
+     * @param $iModuleId integer value with module ID.
+     * @param $iItemId integer value with item ID.
+     * @param $iItemCount integer value with a number of items for purchasing. It's equal to 1 in case of subscription.
+     * @param $sRedirect (optional) string value with redirect URL, if it's needed. 
+     * @return an array with special format which describes the result of operation.
+     * 
+     * @see BxPaymentSubscriptions::serviceSubscribe
+     */
+    /** 
+     * @ref bx_payment-subscribe "subscribe"
+     */
+    public function serviceSubscribe($iSellerId, $sSellerProvider, $iModuleId, $iItemId, $iItemCount, $sRedirect = '', $aCustom = array())
+    {
+        return $this->serviceSubscribeWithAddons($iSellerId, $sSellerProvider, $iModuleId, $iItemId, $iItemCount, '', $sRedirect, $aCustom);
+    }
+    
+    /**
+     * @page service Service Calls
+     * @section bx_payment Payment
+     * @subsection bx_payment-purchase_processing Purchase Processing
+     * @subsubsection bx_payment-subscribe_with_addons subscribe_with_addons
+     * 
+     * @code bx_srv('bx_payment', 'subscribe_with_addons', [...], 'Subscriptions'); @endcode
+     * 
+     * Initialize subscription for specified item.
+     *
+     * @param $iSellerId integer value with seller ID.
+     * @param $sSellerProvider string value with a name of payment provider to be used for processing. Empty value means that payment provider selector should be shown.
+     * @param $iModuleId integer value with module ID.
+     * @param $iItemId integer value with item ID.
+     * @param $iItemCount integer value with a number of items for purchasing. It's equal to 1 in case of subscription.
+     * @param $sItemAddons (optional) string with attached addons.
+     * @param $sRedirect (optional) string value with redirect URL, if it's needed. 
+     * @return an array with special format which describes the result of operation.
+     * 
+     * @see BxPaymentSubscriptions::serviceSubscribeWithAddons
+     */
+    /** 
+     * @ref bx_payment-subscribe_with_addons "subscribe_with_addons"
+     */
+    public function serviceSubscribeWithAddons($iSellerId, $sSellerProvider, $mixedModuleId, $iItemId, $iItemCount, $sItemAddons = '', $sRedirect = '', $aCustom = array())
+    {
+    	$CNF = &$this->_oModule->_oConfig->CNF;
+
+        $iModuleId = $this->_oModule->_oConfig->getModuleId($mixedModuleId);
+    	$iClientId = $this->_oModule->getProfileId();
+
+    	$mixedResult = $this->_oModule->checkData($iClientId, $iSellerId, $iModuleId, $iItemId, $iItemCount);
+    	if($mixedResult !== true)
+            return $mixedResult;
+
+        $aSellerProviders = $this->_oModule->_oDb->getVendorInfoProvidersRecurring($iSellerId, true);
+        if(empty($aSellerProviders))
+            return array('code' => 5, 'message' => _t($CNF['T']['ERR_NOT_ACCEPT_PAYMENTS']));
+
+        $aCartItem = array($iSellerId, $iModuleId, $iItemId, $iItemCount, $sItemAddons);
+
+        if(empty($sSellerProvider)) {
+            $sId = $this->_oModule->_oConfig->getHtmlIds('cart', 'providers_select') . BX_PAYMENT_TYPE_RECURRING;
+            $sTitle = _t($CNF['T']['POPUP_PROVIDERS_SELECT']);
+            return array('popup' => array(
+                'html' => BxTemplFunctions::getInstance()->popupBox($sId, $sTitle, $this->_oModule->_oTemplate->displayProvidersSelector($aCartItem, $aSellerProviders, $sRedirect, $aCustom)), 
+                'options' => array('closeOnOuterClick' => true)
+            ));
+        }
+
+        $aCustoms = array();
+        $this->_oModule->_oConfig->putCustom($aCartItem, $aCustom, $aCustoms);
+
+        $sCartItem = $this->_oModule->_oConfig->descriptorA2S($aCartItem);
+        $mixedResult = $this->_oModule->serviceInitializeCheckout(BX_PAYMENT_TYPE_RECURRING, $iSellerId, $aSellerProviders[$sSellerProvider]['name'], array($sCartItem), $sRedirect, $aCustoms);
+        if(is_string($mixedResult))
+            return array('code' => 6, 'message' => _t($mixedResult));
+
+        return $mixedResult;
+    }
+
+    public function serviceCancel($sOrder, $bForce = true)
+    {
+        $aPending = $this->_oModule->_oDb->getOrderPending(['type' => 'order', 'order' => $sOrder]);
+        if(empty($aPending) || !is_array($aPending))
+            return ['code' => 1, 'message' => _t('_bx_payment_err_not_found_pending')];
+
+        if(!(bool)$bForce && ($mixedResult = $this->_oModule->isAllowedManage($aPending)) !== true)
+            return ['code' => 2, 'message' => $mixedResult];
+
+        if(!$this->cancel((int)$aPending['id']))
+            return ['code' => 3, 'message' => _t('_bx_payment_err_cannot_perform')];
+
+        return ['code' => 0, 'message' => _t('_bx_payment_msg_successfully_performed')];
+    }
+
+    public function serviceCancelByPendingId($iId, $bForce = true)
+    {
+        $aPending = $this->_oModule->_oDb->getOrderPending(['type' => 'id', 'id' => $iId]);
+        if(empty($aPending) || !is_array($aPending))
+            return ['code' => 1, 'message' => _t('_bx_payment_err_not_found_pending')];
+
+        if(!(bool)$bForce && ($mixedResult = $this->_oModule->isAllowedManage($aPending)) !== true)
+            return ['code' => 2, 'message' => $mixedResult];
+
+        if(!$this->cancel((int)$aPending['id']))
+            return ['code' => 3, 'message' => _t('_bx_payment_err_cannot_perform')];
+
+        return ['code' => 0, 'message' => _t('_bx_payment_msg_successfully_performed')];
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_payment Payment
+     * @subsection bx_payment-purchase_processing Purchase Processing
+     * @subsubsection bx_payment-send_subscription_expiration_letters send_subscription_expiration_letters
+     * 
+     * @code bx_srv('bx_payment', 'send_subscription_expiration_letters', [...], 'Subscriptions'); @endcode
+     * 
+     * Send subscription expiration letters.
+     *
+     * @param $iPendingId integer value with pending transaction ID.
+     * @param $sOrderId string value with order ID.
+     * 
+     * @see BxPaymentSubscriptions::serviceSendSubscriptionExpirationLetters
+     */
+    /** 
+     * @ref bx_payment-send_subscription_expiration_letters "send_subscription_expiration_letters"
+     */
+    public function serviceSendSubscriptionExpirationLetters($iPendingId, $sOrderId)
+    {
+    	$CNF = &$this->_oModule->_oConfig->CNF;
+        $sPrefix = $this->_oModule->_oConfig->getPrefix('general');
+
+        $aSubscription = $this->serviceGetSubscriptionsInfo(array('subscription_id' => $sOrderId));
+        if(empty($aSubscription) || !is_array($aSubscription))
+            return;
+
+        $aSubscription = array_shift($aSubscription);
+
+        $oSeller = BxDolProfile::getInstance((int)$aSubscription['seller_id']);
+        $oClient = BxDolProfile::getInstance((int)$aSubscription['client_id']);
+
+        $aEtParams = array(
+            'subscription_id' => $aSubscription['subscription_id'],
+            'subscription_customer' => $aSubscription['customer_id'],
+            'subscription_date' => bx_time_js($aSubscription['date_add'], BX_FORMAT_DATE, true)
+        );
+
+        /**
+         * Notify seller.
+         */
+        if($oSeller !== false) {
+            $sEmail = '';
+            $oProvider = $this->_oModule->getObjectProvider($aSubscription['provider'], $aSubscription['seller_id']);
+            if($oProvider !== false && $oProvider->isActive())
+                $sEmail = $oProvider->getOption('expiration_email');
+
+            if(empty($sEmail))
+                $sEmail = $oSeller->getAccountObject()->getEmail();
+
+            $aTemplate = BxDolEmailTemplates::getInstance()->parseTemplate($sPrefix . 'expiration_notification_seller', $aEtParams, 0, (int)$aSubscription['client_id']);
+
+            sendMail($sEmail, $aTemplate['Subject'], $aTemplate['Body'], 0, array(), BX_EMAIL_SYSTEM);
+        }
+
+        /**
+         * Notify client.
+         */
+        if($oClient !== false) {
+            $sEmail = $oClient->getAccountObject()->getEmail();
+            $aTemplate = BxDolEmailTemplates::getInstance()->parseTemplate($sPrefix . 'expiration_notification_client', $aEtParams, 0, (int)$aSubscription['seller_id']);
+
+            sendMail($sEmail, $aTemplate['Subject'], $aTemplate['Body'], 0, array(), BX_EMAIL_SYSTEM);
+        }
+    }
+
+    public function register($aPending, $aParams = array())
+    {
+        if($this->_oModule->_oDb->isSubscriptionByPending($aPending['id']) || empty($aPending['items']))
+            return false;
+
+        $aInfo = $this->_oModule->getObjectCart()->getInfo(BX_PAYMENT_TYPE_RECURRING, $aPending['client_id'], $aPending['seller_id'], $aPending['items']);
+        if(empty($aInfo['items']) || !is_array($aInfo['items']))
+            return false;
+
+        $aItem = array_shift($aInfo['items']);
+
+        $iPeriod = (int)$aItem['period_recurring'];
+        $iTrial = (int)$aItem['trial_recurring'];
+
+        $oDate = date_create();
+        $iNow = $iNext = date_format($oDate, 'U');
+
+        if((!empty($aParams['status']) && $aParams['status'] == BX_PAYMENT_SBS_STATUS_ACTIVE) || $iTrial > 0) {
+            $sInterval = $this->_getInterval($iPeriod, $aItem['period_unit_recurring'], $iTrial);
+            date_add($oDate, new DateInterval($sInterval));
+            $iNext = date_format($oDate, 'U');
+        }
+
+        $sUnique = genRndPwd(9, false);
+
+        $aSubscription = array(
+            'pending_id' => $aPending['id'],
+            'customer_id' => !empty($aParams['customer_id']) ? $aParams['customer_id'] : 'bx_cus_' . $sUnique,
+            'subscription_id' => !empty($aParams['subscription_id']) ? $aParams['subscription_id'] : 'bx_sub_' . $sUnique,
+            'period' => $iPeriod,
+            'period_unit' => $aItem['period_unit_recurring'],
+            'trial' => $iTrial,
+            'date_add' => $iNow,
+            'date_next' => $iNext,
+            'status' => !empty($aParams['status']) ? $aParams['status'] : ($iTrial > 0 ? BX_PAYMENT_SBS_STATUS_TRIAL : BX_PAYMENT_SBS_STATUS_UNPAID)
+        );
+
+        if(!$this->_oModule->_oDb->insertSubscription($aSubscription))
+            return false;
+
+        $this->_oModule->onSubscriptionCreate($aPending, $aSubscription);
+
+        return true;
+    }
+
+    public function prolong($aPending, $aParams = array())
+    {
+        if(empty($aPending['items']))
+            return false;
+
+        $aSubscription = $this->_oModule->_oDb->getSubscription(array('type' => 'pending_id', 'pending_id' => $aPending['id']));
+        if(empty($aSubscription) || !is_array($aSubscription))
+            return false;
+
+        $aInfo = $this->_oModule->getObjectCart()->getInfo(BX_PAYMENT_TYPE_RECURRING, $aPending['client_id'], $aPending['seller_id'], $aPending['items']);
+        if(empty($aInfo['items']) || !is_array($aInfo['items']))
+            return false;
+
+        $aItem = array_shift($aInfo['items']);
+        $iItemPeriod = (int)$aItem['period_recurring'];
+        $sItemPeriodUnit = $aItem['period_unit_recurring'];
+
+        $iDateNext = 0;
+        if(!empty($iItemPeriod) && !empty($sItemPeriodUnit)) {
+            $sInterval = $this->_getInterval($iItemPeriod, $sItemPeriodUnit);
+            if(empty($sInterval))
+                return false;
+
+            $oDate = date_create('@' . $aSubscription['date_next']);
+            date_add($oDate, new DateInterval($sInterval));
+            $iDateNext = date_format($oDate, 'U');
+        }
+
+        $this->_oModule->_oDb->updateSubscription(array_merge(array(
+            'date_next' => $iDateNext,
+            'pay_attempts' => 0,
+            'status' => BX_PAYMENT_SBS_STATUS_ACTIVE
+        ), $aParams), array(
+            'id' => $aSubscription['id']
+        ));
+
+        $this->_oModule->onSubscriptionProlong($aPending, $aSubscription);
+
+        return true;
+    }
+
+    public function overdue($aPending, $aParams = array())
+    {
+        $aSubscription = $this->_oModule->_oDb->getSubscription(array('type' => 'pending_id', 'pending_id' => $aPending['id']));
+        if(empty($aSubscription) || !is_array($aSubscription))
+            return false;
+
+        $this->_oModule->_oDb->updateSubscription(array_merge(array(
+            'status' => BX_PAYMENT_SBS_STATUS_UNPAID
+        ), $aParams), array(
+            'id' => $aSubscription['id']
+        ));
+
+        $this->_oModule->onSubscriptionOverdue($aPending, $aSubscription);
+
+        return true;
+    }
+
+    public function cancel($iPendingId, $sReason = '')
+    {
+        if(!$this->cancelRemote($iPendingId))
+            return false;
+
+        if(!$this->cancelLocal($iPendingId, $sReason))
+            return false;
+
+        return true;
+    }
+
+    public function cancelRemote($mixedPending)
+    {
+        $aPending = is_array($mixedPending) ? $mixedPending : $this->_oModule->_oDb->getOrderPending(array('type' => 'id', 'id' => (int)$mixedPending));
+        if(empty($aPending) || !is_array($aPending) || $aPending['type'] != BX_PAYMENT_TYPE_RECURRING)
+            return false;
+
+        $aSubscription = $this->_oModule->_oDb->getSubscription(array('type' => 'pending_id', 'pending_id' => $aPending['id']));
+        if(empty($aSubscription) || !is_array($aSubscription))
+            return false;
+
+        $iSellerId = (int)$aPending['seller_id'];
+        $oProvider = $this->_oModule->getObjectProvider($aPending['provider'], $iSellerId);
+        if($oProvider === false || !$oProvider->isActive())
+            return false;
+
+        if(!$oProvider->cancelRecurring($aPending['id'], $aSubscription['customer_id'], $aSubscription['subscription_id']))
+            return false;
+
+        return true;
+    }
+
+    public function cancelLocal($mixedPending, $sReason = 'cancel')
+    {
+        $aPending = is_array($mixedPending) ? $mixedPending : $this->_oModule->_oDb->getOrderPending(array('type' => 'id', 'id' => (int)$mixedPending));
+        if(empty($aPending) || !is_array($aPending) || $aPending['type'] != BX_PAYMENT_TYPE_RECURRING)
+            return false;
+
+        $aSubscription = $this->_oModule->_oDb->getSubscription(array('type' => 'pending_id', 'pending_id' => $aPending['id']));
+        if(empty($aSubscription) || !is_array($aSubscription))
+            return false;
+
+        $aItems = $this->_oModule->_oConfig->descriptorsM2A($aPending['items']);
+        foreach($aItems as $aItem)
+            $this->_oModule->callCancelSubscriptionItem((int)$aItem['module_id'], array($aPending['client_id'], $aPending['seller_id'], $aItem['item_id'], $aItem['item_count'], $aPending['order']));
+
+        if(!$this->_oModule->_oDb->deleteSubscription($aSubscription['id'], $sReason))
+            return false;
+
+        $this->_oModule->onSubscriptionCancel($aPending, $aSubscription);
+
+        return true;
+    }
+
+    public function getPopupCancelSurvey($iId)
+    {
+        $CNF = &$this->_oModule->_oConfig->CNF;
+
+        $oForm = $this->_getFormCancelSurvey($iId);
+        $oForm->initChecker();
+        if($oForm->isSubmittedAndValid()) {
+            $aReasons = BxDolForm::getDataItems($CNF['OBJECT_FORM_PRELISTS_REASONS_CANCEL']);
+
+            return [
+                'code' => 0,
+                'msg' => ($sOther = $oForm->getCleanValue('other')) ? $sOther : $aReasons[$oForm->getCleanValue('items')]
+            ];
+        }
+
+        $sPopupId = $this->_oModule->_oConfig->getHtmlIds('subscription', 'popup_subscription_cancel_survay') . $iId;
+        $sPopupContent = BxTemplFunctions::getInstance()->transBox($sPopupId, $this->_oModule->_oTemplate->parseHtmlByName('subscription_form.html', [
+            'form_id' => $oForm->aFormAttrs['id'],
+            'form' => $oForm->getCode(true)
+        ]));
+
+        return ['code' => 1, 'popup' => ['html' => $sPopupContent, 'options' => ['closeOnOuterClick' => false]]];
+    }
+
+    protected function _getBlock($sType)
+    {
+        $CNF = &$this->_oModule->_oConfig->CNF;
+
+        $sMethod = 'displayBlockSbs' . bx_gen_method_name($sType);
+        if(!$this->_oModule->_oTemplate->isMethodExists($sMethod))
+            return $this->_bIsApi ? [] : [
+                'content' => MsgBox(_t('_Empty'))
+            ];
+
+        $iUserId = $this->_oModule->getProfileId();
+        if(empty($iUserId))
+            return $this->_bIsApi ? [] : [
+                'content' => MsgBox(_t($CNF['T']['ERR_REQUIRED_LOGIN']))
+            ];
+
+        $mixedBlockContent = $this->_oModule->_oTemplate->$sMethod($iUserId);
+
+        if($this->_bIsApi)
+            return !$mixedBlockContent ? [] : [
+                bx_api_get_block('grid', $mixedBlockContent)
+            ];
+
+        $this->_oModule->setSiteSubmenu('menu_dashboard', 'system', 'dashboard-subscriptions');
+
+        $sBlockSubmenu = $this->_oModule->_oConfig->getObject('menu_sbs_submenu');
+        $oBlockSubmenu = BxDolMenu::getObjectInstance($sBlockSubmenu);
+        if($oBlockSubmenu) 
+            $oBlockSubmenu->setSelected($this->MODULE, 'sbs-' . str_replace('_', '-', $sType));     
+
+        return [
+            'content' => $mixedBlockContent,
+            'menu' => $this->_oModule->_oConfig->getObject('menu_sbs_submenu')
+        ];
+    }
+
+    private function _getInterval($iPeriod, $sPeriodUnit, $iTrial = 0)
+    {
+        if((int)$iTrial > 0)
+            return 'P' . $iTrial . 'D';
+
+        $sInterval = '';
+        switch($sPeriodUnit) {
+            case BX_PAYMENT_SBS_PU_YEAR:
+                $sInterval = 'P' . $iPeriod . 'Y';
+                break;
+
+            case BX_PAYMENT_SBS_PU_MONTH:
+                $sInterval = 'P' . $iPeriod . 'M';
+                break;
+
+            case BX_PAYMENT_SBS_PU_WEEK:
+                $sInterval = 'P' . (7 * $iPeriod) . 'D';
+                break;
+
+            case BX_PAYMENT_SBS_PU_DAY:
+                $sInterval = 'P' . $iPeriod . 'D';
+                break;
+
+            case BX_PAYMENT_SBS_PU_HOUR:
+                $sInterval = 'PT' . $iPeriod . 'H';
+                break;
+
+            case BX_PAYMENT_SBS_PU_MINUTE:
+                $sInterval = 'PT' . $iPeriod . 'I';
+                break;
+        }
+
+        return $sInterval;
+    }
+
+    protected function _getFormCancelSurvey($iId)
+    {
+        $CNF = &$this->_oModule->_oConfig->CNF;
+        $sJsObject = $this->_oModule->_oConfig->getJsObject('subscription');
+
+        $aReasons = BxDolForm::getDataItems($CNF['OBJECT_FORM_PRELISTS_REASONS_CANCEL']);
+        
+        $aForm = [
+            'form_attrs' => [
+                'id' => $this->_oModule->_oConfig->getHtmlIds('subscription', 'form_subscription_cancel_survay') . $iId,
+                'action' => BX_DOL_URL_ROOT . $this->_oModule->_oConfig->getBaseUri() . 'subscription_cancel/' . $iId,
+                'method' => BX_DOL_FORM_METHOD_DEFAULT,
+                'onsubmit' => 'return ' . $sJsObject . '.onSubmitCancelationReason(this)'
+            ],
+            'params' => [
+                'db' => [
+                    'table' => '',
+                    'key' => '',
+                    'uri' => '',
+                    'uri_title' => '',
+                    'submit_name' => 'do_submit'
+                ],
+            ],
+            'inputs' => [
+                'items' => [
+                    'type' => 'radio_set',
+                    'name' => 'items',
+                    'caption' => _t('_bx_payment_form_cs_input_items'),
+                    'values' => $aReasons,
+                    'value' => key($aReasons),
+                    'required' => '1',
+                    'attrs' => [
+                        'onchange' => $sJsObject . '.onChangeCancelationReason(this)'
+                    ],
+                    'db' => [
+                        'pass' => 'Xss',
+                    ],
+                    'checker' => [
+                        'func' => 'Avail',
+                        'params' => [],
+                        'error' => _t('_bx_payment_form_input_err'),
+                    ],
+                ],
+                'other' => [
+                    'type' => 'text',
+                    'name' => 'other',
+                    'caption' => _t('_bx_payment_form_cs_input_other'),
+                    'value' => '',
+                    'required' => '1',
+                    'tr_attrs' => [
+                        'class' => 'bx-payment-cs-other bx-payment-cs-hidden'
+                    ],
+                    'db' => [
+                        'pass' => 'Xss',
+                    ],
+                ],
+                'controls' => [
+                    'name' => 'controls',
+                    'type' => 'input_set',
+                    [
+                        'type' => 'submit',
+                        'name' => 'do_submit',
+                        'value' => _t('_bx_payment_form_cs_input_submit'),
+                    ], [
+                        'type' => 'reset',
+                        'name' => 'do_cancel',
+                        'value' => _t('_bx_payment_form_cs_input_cancel'),
+                        'attrs' => [
+                            'onclick' => "$('.bx-popup-applied:visible').dolPopupHide()",
+                            'class' => 'bx-def-margin-sec-left',
+                        ],
+                    ]
+                ]
+            ]
+        ];
+
+        return new BxTemplFormView($aForm);
+    }
+}
+
+/** @} */

+ 649 - 0
modules/boonex/payment/updates/15.0.1_15.0.2/source/classes/BxPaymentTemplate.php

@@ -0,0 +1,649 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Payment Payment
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+class BxPaymentTemplate extends BxBaseModPaymentTemplate
+{
+    protected $_sLangsPrefix;
+
+    function __construct(&$oConfig, &$oDb)
+    {
+    	$this->MODULE = 'bx_payment';
+
+        parent::__construct($oConfig, $oDb);
+
+        $this->_sLangsPrefix = $this->_oConfig->getPrefix('langs');
+    }
+
+    public function addJsCssOrders()
+    {
+    	$this->addJs(array(
+            'jquery-ui/jquery-ui.min.js',
+            'jquery.form.min.js', 
+            'jquery.anim.js', 
+            'jquery.webForms.js',
+            'orders.js'
+    	));
+    	$this->addCss(array('orders.css'));
+    }
+
+    public function addJsCssSubscriptions()
+    {
+        $this->addJs(array('jquery.form.min.js', 'jquery.anim.js', 'jquery.webForms.js', 'main.js', 'subscriptions.js'));
+        $this->addCss(array('orders.css', 'subscriptions.css'));
+    }
+
+    public function addJsCssCart($sType = '', $iVendorId = 0)
+    {
+    	$this->addJsTranslation(array('_bx_payment_err_nothing_selected'));
+    	$this->addJs(array('jquery.anim.js', 'main.js', 'cart.js'));
+    	$this->addCss(array('orders.css', 'cart.css'));
+
+    	$oModule = $this->getModule();
+    	if(!empty($iVendorId)) {
+            $sMethod = 'getVendorInfoProviders' . bx_gen_method_name($sType);
+            $aProviders = $this->_oDb->$sMethod($iVendorId);
+            foreach($aProviders as $sProvider => $aProvider)
+                $oModule->getObjectProvider($sProvider, $iVendorId)->addJsCss();
+    	}
+    }
+
+    public function addJsCssInvoices()
+    {
+    	$this->addCss(array('invoices.css'));
+    }
+
+    public function displayBlockCheckoutOffline($oBuyer, $oSeller, $aData)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $sTxtQt = _t('_bx_payment_txt_checkout_qt');
+
+        $aTmplVarsItems = array();
+        foreach($aData['items'] as $iIndex => $aItem)
+            $aTmplVarsItems[] = array(
+                'item_index' => $iIndex + 1,
+                'item_title' => $aItem['title'],
+                'item_quantity' => $aItem['quantity'] . $sTxtQt
+            );
+
+        $this->addCss(array('checkout.css'));
+        return $this->parseHtmlByName('checkout_offline.html', array(
+            'message' => _t('_bx_payment_txt_checkout_for', $oSeller->getDisplayName()),
+            'bx_repeat:items' => $aTmplVarsItems,
+            'amount' => $aData['currency']['sign'] . sprintf("%.2f", (float)($aData['amount'])),
+            'redirect_url' => $aData['return_url']
+        ));
+    }
+
+    public function displayCartJs($sType = '', $iVendorId = 0)
+    {
+        $this->addJsCssCart($sType, $iVendorId);
+        return $this->displayJsCode('cart');
+    }
+
+    public function displayAddToCartJs($iVendorId, $iModuleId, $iItemId, $iItemCount, $bNeedRedirect = false, $aCustom = array())
+    {
+        $sJsCode = $this->displayCartJs(BX_PAYMENT_TYPE_SINGLE, $iVendorId);
+        $sJsMethod = $this->parseHtmlByName('add_to_cart_js.html', array(
+            'js_object' => $this->_oConfig->getJsObject('cart'),
+            'vendor_id' => $iVendorId,
+            'module_id' => $iModuleId,
+            'item_id' => $iItemId,
+            'item_count' => $iItemCount,
+            'need_redirect' => (int)$bNeedRedirect,
+            'custom' => !empty($aCustom) && is_array($aCustom) ? base64_encode(json_encode($aCustom)) : ''
+        ));
+
+        return array($sJsCode, $sJsMethod);
+    }
+
+    public function displayAddToCartLink($iVendorId, $iModuleId, $iItemId, $iItemCount, $bNeedRedirect = false, $aCustom = array())
+    {
+        $this->addJsCssCart(BX_PAYMENT_TYPE_SINGLE, $iVendorId);
+        return $this->parseHtmlByName('add_to_cart.html', array(
+            'js_object' => $this->_oConfig->getJsObject('cart'),
+            'js_content' => $this->displayJsCode('cart'),
+            'txt_add_to_cart' => _t($this->_sLangsPrefix . 'txt_add_to_cart'),
+            'vendor_id' => $iVendorId,
+            'module_id' => $iModuleId,
+            'item_id' => $iItemId,
+            'item_count' => $iItemCount,
+            'need_redirect' => (int)$bNeedRedirect,
+            'custom' => !empty($aCustom) && is_array($aCustom) ? base64_encode(json_encode($aCustom)) : ''
+        ));
+    }
+
+    public function displaySubscribeJs($iVendorId, $sVendorProvider, $iModuleId, $iItemId, $iItemCount = 1, $sRedirect = '', $aCustom = array())
+    {
+        return $this->displaySubscribeJsWithAddons($iVendorId, $sVendorProvider, $iModuleId, $iItemId, $iItemCount, '', $sRedirect, $aCustom);
+    }
+
+    public function displaySubscribeJsWithAddons($iVendorId, $sVendorProvider, $iModuleId, $iItemId, $iItemCount = 1, $sItemAddons = '', $sRedirect = '', $aCustom = array())
+    {
+        $aSellerProviders = $this->_oDb->getVendorInfoProvidersRecurring($iVendorId);
+        if(empty($sVendorProvider) && count($aSellerProviders) == 1) {
+            $aCartItem = array($iVendorId, $iModuleId, $iItemId, $iItemCount, $sItemAddons);
+
+            $this->addJsCssCart(BX_PAYMENT_TYPE_RECURRING, $iVendorId);
+            return $this->getModule()->getProviderButtonJs($aCartItem, array_shift($aSellerProviders), $sRedirect, $aCustom);
+        }
+
+        return array(
+            $this->displayCartJs(BX_PAYMENT_TYPE_RECURRING, $iVendorId),
+            $this->parseHtmlByName('subscribe_js.html', array(
+                'js_object' => $this->_oConfig->getJsObject('cart'),
+                'vendor_id' => $iVendorId,
+                'vendor_provider' => $sVendorProvider,
+                'module_id' => $iModuleId,
+                'item_id' => $iItemId,
+                'item_count' => $iItemCount,
+                'redirect' => !empty($sRedirect) ? $sRedirect : '',
+                'custom' => !empty($aCustom) && is_array($aCustom) ? base64_encode(json_encode($aCustom)) : ''
+            ))
+        );
+    }
+
+    public function displaySubscribeLink($iVendorId, $sVendorProvider, $iModuleId, $iItemId, $iItemCount = 1, $sRedirect = '', $aCustom = array())
+    {
+        $this->addJsCssCart(BX_PAYMENT_TYPE_RECURRING, $iVendorId);
+        return $this->parseHtmlByName('subscribe.html', array(
+            'js_object' => $this->_oConfig->getJsObject('cart'),
+            'js_content' => $this->displayJsCode('cart'),
+            'txt_add_to_cart' => _t($this->_sLangsPrefix . 'txt_subscribe'),
+            'vendor_id' => $iVendorId,
+            'vendor_provider' => $sVendorProvider,
+            'module_id' => $iModuleId,
+            'item_id' => $iItemId,
+            'item_count' => $iItemCount,
+            'redirect' => !empty($sRedirect) ? $sRedirect : '',
+            'custom' => !empty($aCustom) && is_array($aCustom) ? base64_encode(json_encode($aCustom)) : ''
+        ));
+    }
+
+    public function displaySubscriptionGetDetails($iId)
+    {
+    	return $this->_displaySubscriptionData('get_details', $iId);
+    }
+
+    public function displaySubscriptionChangeDetails($iId)
+    {
+    	return $this->_displaySubscriptionData('change_details', $iId);
+    }
+
+    public function displaySubscriptionGetBilling($iId)
+    {
+    	return $this->_displaySubscriptionData('get_billing', $iId);
+    }
+
+    public function displaySubscriptionChangeBilling($iId)
+    {
+    	return $this->_displaySubscriptionData('change_billing', $iId);
+    }
+
+    public function displayBlockCarts($iClientId)
+    {
+    	$oGrid = BxDolGrid::getObjectInstance($this->_oConfig->getObject('grid_carts'));
+        if(!$oGrid)
+            return MsgBox(_t($this->_sLangsPrefix . 'msg_no_results'));
+
+        $oGrid->addQueryParam('client_id', $iClientId);
+        
+        if($this->_bIsApi)
+            return $oGrid->getCodeAPI();
+
+        $this->addJsCssCart(BX_PAYMENT_TYPE_SINGLE);
+        return $this->displayJsCode('cart') . $oGrid->getCode();
+    }
+
+    public function displayBlockCart($iClientId, $iSellerId = 0)
+    {
+    	$oGrid = BxDolGrid::getObjectInstance($this->_oConfig->getObject('grid_cart'));
+        if(!$oGrid || empty($iSellerId))
+            return MsgBox(_t($this->_sLangsPrefix . 'msg_no_results'));
+
+        $oGrid->addQueryParam('client_id', $iClientId);
+        $oGrid->addQueryParam('seller_id', $iSellerId);
+
+        if($this->_bIsApi)
+            return $oGrid->getCodeAPI();
+
+        $this->addJsCssCart(BX_PAYMENT_TYPE_SINGLE, $iSellerId);
+        return $this->displayJsCode('cart') . $oGrid->getCode();
+    }
+
+    public function displayBlockHistory($iClientId, $iSellerId)
+    {
+        return $this->_displayBlockHistory('grid_history', $iClientId, $iSellerId);
+    }
+
+    public function displayBlockSbsListMy($iClientId)
+    {
+        $oGrid = BxDolGrid::getObjectInstance($this->_oConfig->getObject('grid_sbs_list_my'), $this->getModule()->_oTemplate);
+        if(!$oGrid || empty($iClientId))
+            return $this->_bIsApi ? false : MsgBox(_t($this->_sLangsPrefix . 'msg_no_results'));
+
+        $oGrid->addQueryParam('client_id', $iClientId);
+
+        if($this->_bIsApi)
+            return $oGrid->getCodeAPI(true);
+
+        $this->addJsCssSubscriptions();
+        return $this->displayJsCode(BX_PAYMENT_ORDERS_TYPE_SUBSCRIPTION) . $oGrid->getCode();
+    }
+
+    public function displayBlockSbsListAll()
+    {
+        $oGrid = BxDolGrid::getObjectInstance($this->_oConfig->getObject('grid_sbs_list_all'), $this->getModule()->_oTemplate);
+        if(!$oGrid)
+            return $this->_bIsApi ? false : MsgBox(_t($this->_sLangsPrefix . 'msg_no_results'));
+
+        if($this->_bIsApi)
+            return $oGrid->getCodeAPI(true);
+
+        $this->addJsCssSubscriptions();
+        return $this->displayJsCode(BX_PAYMENT_ORDERS_TYPE_SUBSCRIPTION) . $oGrid->getCode();
+    }
+
+    public function displayBlockSbsHistory($iClientId)
+    {
+        return $this->_displayBlockHistory('grid_sbs_history', $iClientId);
+    }
+
+    public function displayBlockSbsDetails($iClientId)
+    {
+        return 'Details would be here';
+    }
+
+    public function displayBlockOrders($sType, $iSellerId)
+    {
+        $sGrid = $this->_oConfig->getObject('grid_' . $sType);
+        $oGrid = BxDolGrid::getObjectInstance($sGrid);
+        if(!$oGrid || empty($iSellerId))
+            return MsgBox(_t($this->_sLangsPrefix . 'msg_no_results'));
+
+        $oGrid->addQueryParam('seller_id', $iSellerId);
+
+        $this->addJsCssOrders();
+        return $this->displayJsCode($sType, array(
+            'sObjNameGrid' => $sGrid,
+            'sParamsDivider' => $this->_oConfig->getDivider('DIVIDER_GRID_FILTERS'),
+            'sTextSearchInput' => _t('_sys_grid_search')
+        )) . $oGrid->getCode();
+    }
+
+    public function displayOrder($sType, $iId)
+    {
+        $sMethodName = 'getOrder' . bx_gen_method_name($sType);
+        $aOrder = $this->_oDb->$sMethodName(array('type' => 'id', 'id' => $iId));
+
+        if($this->_bIsApi)
+            return $this->displayOrderAPI($sType, $aOrder);
+
+        $oModule = $this->getModule();
+        $aSeller = $oModule->getVendorInfo((int)$aOrder['seller_id']);
+        $aClient = $oModule->getProfileInfo((int)$aOrder['client_id']);
+
+        if(in_array($sType, [BX_PAYMENT_ORDERS_TYPE_PENDING, BX_PAYMENT_ORDERS_TYPE_SUBSCRIPTION]))
+            $aItems = $this->_oConfig->descriptorsM2A($aOrder['items']);
+        else
+            $aItems = $this->_oConfig->descriptorsM2A($this->_oConfig->descriptorA2S([$aOrder['seller_id'], $aOrder['module_id'], $aOrder['item_id'], $aOrder['item_count']]));
+
+        $aTmplVarsLicense = array();
+        if(in_array($sType, array(BX_PAYMENT_ORDERS_TYPE_PROCESSED, BX_PAYMENT_ORDERS_TYPE_HISTORY)))
+            $aTmplVarsLicense = array(
+                'txt_license' => _t($this->_sLangsPrefix . 'txt_license'),
+                'license' => $aOrder['license']
+            );
+
+        $bTmplVarsShowSlrAtr = !empty($aOrder['author_id']) && $aOrder['seller_id'] != $aOrder['author_id'];
+
+        $aTmplVarsAuthor = array();
+        if($bTmplVarsShowSlrAtr) {
+            $aAuthor = $oModule->getProfileInfo((int)$aOrder['author_id']);
+
+            $aTmplVarsAuthor = array(
+                'txt_author' => _t($this->_sLangsPrefix . 'txt_author'),
+                'author_name' => $aAuthor['name'],
+                'author_url' => $aAuthor['link'],
+            );
+        }
+
+        $aTmplVarsSeller = array(
+            'txt_seller' => _t($this->_sLangsPrefix . 'txt_seller'),
+            'bx_if:show_link' => array(
+                'condition' => !empty($aSeller['link']),
+                'content' => array(
+                    'seller_name' => $aSeller['name'],
+                    'seller_url' => $aSeller['link'],
+                )
+            ),
+            'bx_if:show_text' => array(
+                'condition' => empty($aSeller['link']),
+                'content' => array(
+                    'seller_name' => $aSeller['name']
+                )
+            ),
+        );
+
+        $aTmplVarsCustom = [];
+        if(in_array($sType, [BX_PAYMENT_ORDERS_TYPE_SUBSCRIPTION])) {
+            $sOrder = $aOrder['order'];
+            if($oModule->_isModerator() && ($aItem = reset($aItems))) {
+                $aItemModule = bx_srv((int)$aItem['module_id'], 'get_payment_data');
+                if(($sUrlBrowse = $aItemModule['url_browse_order_administration'] ?? false)) 
+                    $sOrder = $this->displayLink('link', [
+                        'href' => bx_replace_markers($sUrlBrowse, [
+                            'order' => $sOrder
+                        ]),
+                        'title' => bx_html_attribute($sOrder),
+                        'content' => $sOrder
+                    ]);
+            }
+
+            $aTmplVarsCustom = [
+                'txt_order' => _t($this->_sLangsPrefix . 'txt_subscription'),
+                'order' => $sOrder,
+                'txt_customer_id' => _t($this->_sLangsPrefix . 'txt_customer_id'),
+                'customer_id' => $aOrder['customer_id'] ?? '',
+                'bx_if:show_deleted' => [
+                    'condition' => false,
+                    'content' => [
+                        'txt_deleted' => _t($this->_sLangsPrefix . 'txt_deleted'),
+                        'txt_deleted_reason' => _t($this->_sLangsPrefix . 'txt_deleted_reason'),
+                        'deleted' => 0,
+                        'deleted_reason' => ''
+                    ]
+                ]
+            ];
+
+            if(($sK = 'deleted') && isset($aOrder[$sK]) && $aOrder[$sK]) {
+                $aTmplVarsCustom['bx_if:show_deleted']['condition'] = true;
+                $aTmplVarsCustom['bx_if:show_deleted']['content'] = array_merge($aTmplVarsCustom['bx_if:show_deleted']['content'], [
+                    'deleted' => bx_time_js($aOrder[$sK], BX_FORMAT_DATE_TIME, true),
+                    'deleted_reason' => $aOrder['deleted_reason'] ?? ''
+                ]);
+            }
+        }
+
+        $aResult = array_merge(array(
+            'txt_client' => _t($this->_sLangsPrefix . 'txt_client'),
+            'txt_order' => _t($this->_sLangsPrefix . 'txt_order'),
+            'txt_processed_with' => _t($this->_sLangsPrefix . 'txt_processed_with'),
+            'txt_message' => _t($this->_sLangsPrefix . 'txt_message'),
+            'txt_date' => _t($this->_sLangsPrefix . 'txt_date'),
+            'txt_products' => _t($this->_sLangsPrefix . 'txt_products'),
+            'client_name' => $aClient['name'],
+            'client_url' => $aClient['link'],
+            'bx_if:show_seller' => array(
+                'condition' => $bTmplVarsShowSlrAtr,
+                'content' => $aTmplVarsSeller
+            ),
+            'bx_if:show_license' => array(
+                'condition' => !empty($aTmplVarsLicense),
+                'content' => $aTmplVarsLicense
+            ),
+            'order' => $aOrder['order'],
+            'provider' => _t('_bx_payment_txt_name_' . $aOrder['provider']),
+            'error' => $aOrder['error_msg'],
+            'date' => bx_time_js($aOrder['date'], BX_FORMAT_DATE_TIME, true),
+            'bx_if:show_author' => array(
+                'condition' => $bTmplVarsShowSlrAtr,
+                'content' => $aTmplVarsAuthor
+            ),
+            'bx_repeat:items' => array()
+        ), $aTmplVarsSeller, $aTmplVarsCustom);
+
+        foreach($aItems as $aItem) {
+            $aInfo = $oModule->callGetCartItem((int)$aItem['module_id'], array($aItem['item_id'], $aOrder['client_id']));
+            if(!empty($aInfo) && is_array($aInfo))
+                $aResult['bx_repeat:items'][] = array(
+                    'bx_if:link' => array(
+                        'condition' => !empty($aInfo['url']),
+                        'content' => array(
+                            'title' => $aInfo['title'],
+                            'url' => $aInfo['url']
+                        )
+                    ),
+                    'bx_if:text' => array(
+                        'condition' => empty($aInfo['url']),
+                        'content' => array(
+                            'title' => $aInfo['title'],
+                        )
+                    ),
+                    'quantity' => $aItem['item_count'],
+                    'price' => $this->_oConfig->getPrice($aOrder['type'], $aInfo),
+                    'currency_code' => $aSeller['currency_code']
+                );
+        }
+
+        return $this->parseHtmlByName('order_' . $sType . '.html', $aResult);
+    }
+    
+    public function displayOrderAPI($sType, $aOrder)
+    {
+        $oModule = $this->getModule();
+        $aSeller = $oModule->getVendorInfo((int)$aOrder['seller_id']);
+        $bSubscription = in_array($sType, [BX_PAYMENT_ORDERS_TYPE_SUBSCRIPTION]);
+
+        $aResult = [
+            [_t($this->_sLangsPrefix . 'txt_seller'), $aSeller['name']],
+            [_t($this->_sLangsPrefix . 'txt_' . ($bSubscription ? 'subscription' : 'order')), $aOrder['order']],           
+        ];
+
+        if($bSubscription)
+            $aResult[] = [_t($this->_sLangsPrefix . 'txt_customer_id'), $aOrder['customer_id']];
+
+        if(in_array($sType, [BX_PAYMENT_ORDERS_TYPE_PROCESSED, BX_PAYMENT_ORDERS_TYPE_HISTORY]))
+            $aResult[] = [_t($this->_sLangsPrefix . 'txt_license'), $aOrder['license']];
+
+        $aResult[] = [_t($this->_sLangsPrefix . 'txt_date'), $aOrder['date']];
+
+        if(in_array($sType, [BX_PAYMENT_ORDERS_TYPE_PENDING, BX_PAYMENT_ORDERS_TYPE_SUBSCRIPTION]))
+            $aItems = $this->_oConfig->descriptorsM2A($aOrder['items']);
+        else
+            $aItems = $this->_oConfig->descriptorsM2A($this->_oConfig->descriptorA2S(array($aOrder['seller_id'], $aOrder['module_id'], $aOrder['item_id'], $aOrder['item_count'])));
+
+        $sProducts = '';
+        foreach($aItems as $aItem) {
+            $aInfo = $oModule->callGetCartItem((int)$aItem['module_id'], array($aItem['item_id'], $aOrder['client_id']));
+            if(empty($aInfo) || !is_array($aInfo))
+                continue;
+
+            $sProducts .= $aInfo['title'] . ' (' . $aItem['item_count'] . ') - ' . $this->_oConfig->getPrice($aOrder['type'], $aInfo) . $aSeller['currency_code'] . ', ';
+        }
+
+        $aResult[] = [_t($this->_sLangsPrefix . 'txt_products'), trim($sProducts, ", ")];
+
+        return $aResult;
+    }
+
+    public function displayBlockInvoices()
+    {
+        $sGrid = $this->_oConfig->getObject('grid_invoices');
+        $oGrid = BxDolGrid::getObjectInstance($sGrid);
+        if(!$oGrid)
+            return MsgBox(_t($this->_sLangsPrefix . 'msg_no_results'));
+
+        $this->addJsCssInvoices();
+        return $oGrid->getCode();
+    }
+
+    public function displayItems($iSellerId, $sType, $aItems = [], $aParams = [])
+    {
+        $oModule = $this->getModule();
+        $oForm = new BxTemplFormView([]);
+
+        $sSign = !$this->_oConfig->isSingleSeller() ? $oModule->getVendorCurrencySign($iSellerId) : $this->_oConfig->getDefaultCurrencySign();
+
+        $bFilter = !empty($aParams['filter']);
+        $sFilter = $bFilter ? $aParams['filter'] : '';
+        
+        $aTmplVarsItems = [];
+        if(!empty($aItems) && is_array($aItems))
+            foreach($aItems as $aItem) {
+                if($bFilter && stripos($aItem['title'], $sFilter) === false)
+                    continue;
+
+                $fPrice = $this->_oConfig->getPrice($sType, $aItem);
+
+                $aInputCheckbox = array(
+                    'type' => 'checkbox',
+                    'name' => 'items[]',
+                    'value' => $aItem['id']
+                );
+                $aInputPrice = array(
+                    'type' => 'text',
+                    'name' => 'item-price-' . $aItem['id'],
+                    'value' => $fPrice
+                );
+                $aInputQuantity = array(
+                    'type' => 'text',
+                    'name' => 'item-quantity-' . $aItem['id'],
+                    'value' => 1
+                );
+
+                $aTmplVarsItems[$aItem['name']] = array(
+                    'id' => $aItem['id'],
+                    'price' => $fPrice,
+                    'price_f' => _t_format_currency_ext($fPrice, ['sign' => $sSign]),
+                    'bx_if:link' => array(
+                        'condition' => !empty($aItem['url']),
+                        'content' => array(
+                            'url' => $aItem['url'],
+                            'title' => $aItem['title']
+                        )
+                    ),
+                    'bx_if:text' => array(
+                        'condition' => empty($aItem['url']),
+                        'content' => array(
+                            'title' => $aItem['title']
+                        )
+                    ),
+                    'input_checkbox' => $oForm->genInput($aInputCheckbox),
+                    'input_price' => $oForm->genInput($aInputPrice),
+                    'input_quantity' => $oForm->genInput($aInputQuantity),
+                );
+            }
+
+        
+        $bTmplVarsItems = !empty($aTmplVarsItems) && is_array($aTmplVarsItems);
+        if($bTmplVarsItems) {
+            ksort($aTmplVarsItems);
+            $aTmplVarsItems = array_values($aTmplVarsItems);
+        }
+        else 
+            $aTmplVarsItems = MsgBox(_t($this->_sLangsPrefix . 'msg_no_results'));
+
+        $sInputFilter = '';
+        if($bFilter || $bTmplVarsItems) {
+            $sJsMethod = 'javascript:' . $this->_oModule->_oConfig->getJsObject('processed') . '.filterItems(event, this);';
+            $aInputFilter = [
+                'type' => 'text',
+                'name' => 'filter',
+                'value' => $sFilter,
+                'attrs' => [
+                    'placeholder' => _t('_sys_search_placeholder'),
+                    'onkeydown' => $sJsMethod,
+                    'onpaste' => $sJsMethod
+                ]
+            ];
+            $sInputFilter = $oForm->genInput($aInputFilter);
+        }       
+
+        return $this->parseHtmlByName('items.html', array(
+            'html_id' => $this->_oConfig->getHtmlIds('processed', 'order_processed_items'),
+            'input_filter' => $sInputFilter,
+            'bx_repeat:items' => $aTmplVarsItems
+        ));
+    }
+
+    public function displayProvidersSelector($aCartItem, $aProviders, $sRedirect = '', $aCustom = array())
+    {
+    	$oModule = $this->getModule();
+
+        $aTmplVarsProviders = array();
+        foreach($aProviders as $sProvider => $aProvider) {
+            list($sJsCode, $sJsOnclick) = $oModule->getProviderButtonJs($aCartItem, $aProvider, $sRedirect, $aCustom);
+
+            $sCaptionKey = '_bx_payment_txt_subscribe_' . $aProvider['name'];
+            $sCaptionValue = _t($sCaptionKey);
+            if(strcmp($sCaptionKey, $sCaptionValue) == 0)
+                $sCaptionValue = _t($aProvider['caption']);
+
+            $aTmplVarsProviders[] = array(
+                'button' => $this->parseHtmlByName('providers_select_button.html', array(
+                    'onclick' => $sJsOnclick,
+                    'title' => _t('_bx_payment_txt_checkout_with', $sCaptionValue),
+                    'js_code' => $sJsCode
+                ))
+            );
+        }
+
+        return $this->parseHtmlByName('providers_select.html', array(
+            'bx_repeat:providers' => $aTmplVarsProviders
+        ));
+    }
+
+    protected function _displayBlockHistory($sObject, $iClientId, $iSellerId = 0)
+    {
+    	$oGrid = BxDolGrid::getObjectInstance($this->_oConfig->getObject($sObject), $this->getModule()->_oTemplate);
+        if(!$oGrid || empty($iClientId))
+            return $this->_bIsApi ? false : MsgBox(_t($this->_sLangsPrefix . 'msg_no_results'));
+
+        $oGrid->addQueryParam('client_id', $iClientId);
+        if(!empty($iSellerId))
+            $oGrid->addQueryParam('seller_id', $iSellerId);
+
+        if($this->_bIsApi)
+            return $oGrid->getCodeAPI();
+
+        $this->addJsCssOrders();
+        return $this->displayJsCode(BX_PAYMENT_ORDERS_TYPE_HISTORY) . $oGrid->getCode();
+    }
+
+    protected function _displaySubscriptionData($sType, $iId)
+    {
+        $aResult = array('code' => 1, 'message' => _t('_bx_payment_err_cannot_perform'));
+
+        $aPending = $this->_oDb->getOrderPending(array('type' => 'id', 'id' => $iId));
+        if(empty($aPending) || !is_array($aPending))
+            return $aResult;
+
+        $aSubscription = $this->_oDb->getSubscription(array('type' => 'pending_id', 'pending_id' => $iId));
+        if(empty($aSubscription) || !is_array($aSubscription))
+            return $aResult;
+
+        $mixedResult = $this->getModule()->isAllowedManage($aPending);
+        if($mixedResult !== true)
+            return array('code' => 2, 'message' => $mixedResult);
+            
+        $sMethod = bx_gen_method_name($sType) . 'Recurring';
+        $oProvider = $this->getModule()->getObjectProvider($aPending['provider'], $aPending['seller_id']);
+        if($oProvider === false || !$oProvider->isActive() || !method_exists($oProvider, $sMethod))
+        	return $aResult;
+
+        $mixedContent = $oProvider->$sMethod($iId, $aSubscription['customer_id'], $aSubscription['subscription_id']);
+        if(empty($mixedContent))
+            return $aResult;
+        else if(is_array($mixedContent))
+            return $mixedContent;
+
+        $sKey = 'order_' . BX_PAYMENT_ORDERS_TYPE_SUBSCRIPTION . '_' . $sType;
+    	$sId = $this->_oConfig->getHtmlIds(BX_PAYMENT_ORDERS_TYPE_SUBSCRIPTION, $sKey);
+    	$sTitle = _t($this->_sLangsPrefix . 'popup_title_ods_' . $sKey);
+    	return array('popup' => array(
+    		'html' => BxTemplFunctions::getInstance()->popupBox($sId, $sTitle, $mixedContent), 
+    		'options' => array('closeOnOuterClick' => 1)
+    	));
+    }
+}
+
+/** @} */

+ 70 - 0
modules/boonex/payment/updates/15.0.1_15.0.2/source/install/config.php

@@ -0,0 +1,70 @@
+<?php
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Payment Payment
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+$aConfig = array(
+    /**
+     * Main Section.
+     */
+    'type' => BX_DOL_MODULE_TYPE_MODULE,
+    'name' => 'bx_payment',
+    'title' => 'Payment',
+    'note' => 'Payment module.',
+    'version' => '15.0.2',
+    'vendor' => 'UNA INC',
+    'help_url' => 'http://feed.una.io/?section={module_name}',
+
+    'compatible_with' => array(
+        '15.0.0-B2'
+    ),
+
+    /**
+     * 'home_dir' and 'home_uri' - should be unique. Don't use spaces in 'home_uri' and the other special chars.
+     */
+    'home_dir' => 'boonex/payment/',
+    'home_uri' => 'payment',
+
+    'db_prefix' => 'bx_payment_',
+    'class_prefix' => 'BxPayment',
+
+    /**
+     * Category for language keys.
+     */
+    'language_category' => 'Payment',
+
+    /**
+     * Installation/Uninstallation Section.
+     */
+    'install' => array(
+        'execute_sql' => 1,
+        'update_languages' => 1,
+        'clear_db_cache' => 1,
+    ),
+	'uninstall' => array (
+        'execute_sql' => 1,
+        'update_languages' => 1,
+        'clear_db_cache' => 1,
+    ),
+    'enable' => array(
+        'execute_sql' => 1,
+        'clear_db_cache' => 1,
+    ),
+    'disable' => array (
+        'execute_sql' => 1,
+        'clear_db_cache' => 1,
+    ),
+
+    /**
+     * Dependencies Section
+     */
+    'dependencies' => array(),
+);
+
+/** @} */

+ 715 - 0
modules/boonex/payment/updates/15.0.1_15.0.2/source/install/langs/en.xml

@@ -0,0 +1,715 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources name="en" flag="gb" title="English">
+    <string name="_bx_payment"><![CDATA[Payments]]></string>
+
+    <!-- OPTIONS -->
+    <string name="_bx_payment_options_category_general"><![CDATA[General]]></string>
+    <string name="_bx_payment_options_category_currency"><![CDATA[Сurrency]]></string>
+    <string name="_bx_payment_options_category_commissions"><![CDATA[Commissions]]></string>
+    <string name="_bx_payment_option_default_currency_code"><![CDATA[Currency]]></string>
+    <string name="_bx_payment_option_err_default_currency_code"><![CDATA[Currency code cannot be empty.]]></string>
+    <string name="_bx_payment_option_currency_exchange_api"><![CDATA[Exchange currency API key (by exchangeratesapi.io)]]></string>
+    <string name="_bx_payment_option_site_admin"><![CDATA[Main seller (To sell on behalf of the site)]]></string>
+    <string name="_bx_payment_option_extended_mode"><![CDATA[Extended mode (Allows sellers to use Test mode, etc).]]></string>
+    <string name="_bx_payment_option_credits_only"><![CDATA[Pay with Credits only mode ('Credits' app should be installed).]]></string>
+    <string name="_bx_payment_option_single_seller"><![CDATA[Single seller mode (To sell everything on behalf of the 'Main seller').]]></string>
+    <string name="_bx_payment_option_sbs_cancel_survey"><![CDATA[Enable 'Your reason to cancel subscription' survey.]]></string>
+    <string name="_bx_payment_option_commissions"><![CDATA[Enable commissions calculation]]></string>
+    <string name="_bx_payment_option_inv_issue_day"><![CDATA[Day of month when invoices are automatically generated (1, 2, 3, etc)]]></string>
+    <string name="_bx_payment_option_inv_lifetime"><![CDATA[Due date - days after invoice date]]></string>
+    <string name="_bx_payment_option_inv_expiraction_notify"><![CDATA[Number of days before invoice expiration to notify payer]]></string>
+
+    <!-- PAGES and BLOCKS -->
+    <string name="_bx_payment_page_title_sys_carts"><![CDATA[Shopping Cart]]></string>
+    <string name="_bx_payment_page_title_carts"><![CDATA[Shopping Cart]]></string>
+    <string name="_bx_payment_page_title_sys_cart"><![CDATA[Shopping Cart]]></string>
+    <string name="_bx_payment_page_title_cart"><![CDATA[Shopping Cart]]></string>
+    <string name="_bx_payment_page_title_sys_cart_thank_you"><![CDATA[Thank you!]]></string>
+    <string name="_bx_payment_page_title_cart_thank_you"><![CDATA[Thank you!]]></string>
+    <string name="_bx_payment_page_block_title_carts"><![CDATA[Shopping Cart]]></string>
+    <string name="_bx_payment_page_block_title_cart"><![CDATA[{0}'s Shopping Cart]]></string>
+    <string name="_bx_payment_page_block_title_cart_thank_you"><![CDATA[Thank you!]]></string>
+    <string name="_bx_payment_page_block_content_cart_thank_you"><![CDATA[Thank you! Payment was successfully performed. The data will be processed shortly. Please wait.]]></string>
+
+    <string name="_bx_payment_page_title_sys_sbs_list_my"><![CDATA[My Subscriptions]]></string>
+    <string name="_bx_payment_page_title_sbs_list_my"><![CDATA[My Subscriptions]]></string>
+    <string name="_bx_payment_page_block_title_sbs_list_my"><![CDATA[My Subscriptions]]></string>
+
+    <string name="_bx_payment_page_title_sys_sbs_list_all"><![CDATA[All Subscriptions]]></string>
+    <string name="_bx_payment_page_title_sbs_list_all"><![CDATA[All Subscriptions]]></string>
+    <string name="_bx_payment_page_block_title_sbs_list_all"><![CDATA[All Subscriptions]]></string>
+
+    <string name="_bx_payment_page_title_sys_sbs_history"><![CDATA[My Payments]]></string>
+    <string name="_bx_payment_page_title_sbs_history"><![CDATA[My Payments]]></string>
+    <string name="_bx_payment_page_block_title_sbs_history"><![CDATA[My Payments]]></string>
+
+    <string name="_bx_payment_page_title_sys_history"><![CDATA[Shopping History]]></string>
+    <string name="_bx_payment_page_title_history"><![CDATA[Shopping History]]></string>
+    <string name="_bx_payment_page_block_title_history"><![CDATA[Shopping History]]></string>
+
+    <string name="_bx_payment_page_title_sys_orders"><![CDATA[Orders]]></string>
+    <string name="_bx_payment_page_title_orders"><![CDATA[Orders]]></string>
+    <string name="_bx_payment_page_block_title_orders"><![CDATA[Orders]]></string>
+
+    <string name="_bx_payment_page_title_sys_details"><![CDATA[Payments Details]]></string>
+    <string name="_bx_payment_page_title_details"><![CDATA[Payments Details]]></string>
+    <string name="_bx_payment_page_block_title_details"><![CDATA[Payments Details]]></string>
+
+    <string name="_bx_payment_page_block_title_orders_processed"><![CDATA[Processed Orders]]></string>
+    <string name="_bx_payment_page_block_title_orders_pending"><![CDATA[Pending Orders]]></string>
+
+    <string name="_bx_payment_page_title_response"><![CDATA[Payment Response]]></string>
+    <string name="_bx_payment_page_title_error"><![CDATA[Payment Error]]></string>
+
+    <string name="_bx_payment_page_title_sys_join"><![CDATA[Join]]></string>
+    <string name="_bx_payment_page_title_join"><![CDATA[Join]]></string>
+    <string name="_bx_payment_page_block_title_join"><![CDATA[Join]]></string>
+
+    <string name="_bx_payment_page_title_sys_invoices"><![CDATA[Invoices]]></string>
+    <string name="_bx_payment_page_title_invoices"><![CDATA[Invoices]]></string>
+    <string name="_bx_payment_page_block_title_invoices"><![CDATA[Invoices]]></string>
+    
+    <string name="_bx_payment_page_title_sys_checkout_offline"><![CDATA[Offline Checkout]]></string>
+    <string name="_bx_payment_page_title_checkout_offline"><![CDATA[Offline Checkout]]></string>
+    <string name="_bx_payment_page_block_title_sys_checkout_offline"><![CDATA[Offline Checkout]]></string>
+    <string name="_bx_payment_page_block_title_checkout_offline"><![CDATA[]]></string>
+
+    <!-- MENUS -->
+    <string name="_bx_payment_lmi_cpt_providers"><![CDATA[Providers]]></string>
+    <string name="_bx_payment_lmi_cpt_commissions"><![CDATA[Commissions]]></string>
+
+    <string name="_bx_payment_menu_title_orders_submenu"><![CDATA[Orders Submenu]]></string>
+    <string name="_bx_payment_menu_set_title_orders_submenu"><![CDATA[Orders Submenu]]></string>
+    <string name="_bx_payment_menu_item_title_system_orders_processed"><![CDATA[Processed Orders]]></string>
+    <string name="_bx_payment_menu_item_title_orders_processed"><![CDATA[Processed]]></string>
+    <string name="_bx_payment_menu_item_title_system_orders_pending"><![CDATA[Pending Orders]]></string>
+    <string name="_bx_payment_menu_item_title_orders_pending"><![CDATA[Pending]]></string>
+    <string name="_bx_payment_menu_item_title_system_details"><![CDATA[Payments Details]]></string>
+    <string name="_bx_payment_menu_item_title_details"><![CDATA[Payments]]></string>
+    <string name="_bx_payment_menu_item_title_system_admt_invoices"><![CDATA[Invoices]]></string>
+    <string name="_bx_payment_menu_item_title_admt_invoices"><![CDATA[Invoices]]></string>
+    <string name="_bx_payment_menu_item_title_admt_addon_counter1_caption"><![CDATA[paid]]></string>
+    <string name="_bx_payment_menu_item_title_admt_addon_counter2_caption"><![CDATA[overdue]]></string>
+
+    <string name="_bx_payment_menu_title_cart_submenu"><![CDATA[Cart Submenu]]></string>
+    <string name="_bx_payment_menu_title_public_cart_submenu"><![CDATA[Carts]]></string>
+    <string name="_bx_payment_menu_set_title_cart_submenu"><![CDATA[Cart Submenu]]></string>
+    <string name="_bx_payment_menu_item_title_system_cart"><![CDATA[Checkout]]></string>
+    <string name="_bx_payment_menu_item_title_cart"><![CDATA[Checkout]]></string>
+    <string name="_bx_payment_menu_item_title_system_cart_history"><![CDATA[Payment History]]></string>
+    <string name="_bx_payment_menu_item_title_cart_history"><![CDATA[Payment History]]></string>
+
+    <string name="_bx_payment_menu_title_sbs_submenu"><![CDATA[Subscriptions Submenu]]></string>
+    <string name="_bx_payment_menu_set_title_sbs_submenu"><![CDATA[Subscriptions Submenu]]></string>
+    <string name="_bx_payment_menu_item_title_system_sbs_list_my"><![CDATA[My Subscriptions List]]></string>
+    <string name="_bx_payment_menu_item_title_sbs_list_my"><![CDATA[My Subscriptions]]></string>
+    <string name="_bx_payment_menu_item_title_system_sbs_list_all"><![CDATA[All Subscriptions List]]></string>
+    <string name="_bx_payment_menu_item_title_sbs_list_all"><![CDATA[All Subscriptions]]></string>
+    <string name="_bx_payment_menu_item_title_system_sbs_history"><![CDATA[My Payments History]]></string>
+    <string name="_bx_payment_menu_item_title_sbs_history"><![CDATA[My Payments]]></string>
+
+    <string name="_bx_payment_menu_title_sbs_actions"><![CDATA[Subscription Actions]]></string>
+    <string name="_bx_payment_menu_set_title_sbs_actions"><![CDATA[Subscription Actions]]></string>
+    <string name="_bx_payment_menu_item_title_system_sbs_request_cancelation"><![CDATA[Request Cancellation]]></string>
+    <string name="_bx_payment_menu_item_title_sbs_request_cancelation"><![CDATA[Request Cancellation]]></string>
+    <string name="_bx_payment_menu_item_title_system_sbs_cancel"><![CDATA[Cancel Subscription]]></string>
+    <string name="_bx_payment_menu_item_title_sbs_cancel"><![CDATA[Cancel Subscription]]></string>
+
+    <!-- GRIDS -->
+    <string name="_bx_payment_grid_column_title_pdrs_caption"><![CDATA[Caption]]></string>
+    <string name="_bx_payment_grid_column_title_pdrs_description"><![CDATA[Description]]></string>
+    <string name="_bx_payment_grid_column_title_pdrs_for_visitor"><![CDATA[For visitors]]></string>
+    <string name="_bx_payment_grid_column_title_pdrs_for_single"><![CDATA[One Time]]></string>
+    <string name="_bx_payment_grid_column_title_pdrs_for_recurring"><![CDATA[Recurring]]></string>
+    <string name="_bx_payment_grid_column_title_pdrs_single_seller"><![CDATA[Single Seller]]></string>
+    <string name="_bx_payment_grid_column_title_pdrs_time_tracker"><![CDATA[Time Tracker]]></string>
+    <string name="_bx_payment_grid_column_title_ods_client_id"><![CDATA[Client]]></string>
+    <string name="_bx_payment_grid_column_title_ods_seller_id"><![CDATA[Seller]]></string>
+    <string name="_bx_payment_grid_column_title_ods_author_id"><![CDATA[Author]]></string>
+    <string name="_bx_payment_grid_column_title_ods_transaction"><![CDATA[Transaction]]></string>
+    <string name="_bx_payment_grid_column_title_ods_license"><![CDATA[License]]></string>
+    <string name="_bx_payment_grid_column_title_ods_item"><![CDATA[Product]]></string>
+    <string name="_bx_payment_grid_column_title_ods_amount"><![CDATA[Amount]]></string>
+    <string name="_bx_payment_grid_column_title_ods_date"><![CDATA[Date]]></string>
+    <string name="_bx_payment_grid_column_title_sbs_seller_id"><![CDATA[Seller]]></string>
+    <string name="_bx_payment_grid_column_title_sbs_client_id"><![CDATA[Client]]></string>
+    <string name="_bx_payment_grid_column_title_sbs_client_email"><![CDATA[Email]]></string>
+    <string name="_bx_payment_grid_column_title_sbs_items"><![CDATA[Products]]></string>
+    <string name="_bx_payment_grid_column_title_sbs_item_id"><![CDATA[Product]]></string>
+    <string name="_bx_payment_grid_column_title_sbs_amount"><![CDATA[Amount]]></string>
+    <string name="_bx_payment_grid_column_title_sbs_status"><![CDATA[Status]]></string>
+    <string name="_bx_payment_grid_column_title_sbs_date"><![CDATA[Date]]></string>
+    <string name="_bx_payment_grid_column_title_sbs_date_add"><![CDATA[Created]]></string>
+    <string name="_bx_payment_grid_column_title_sbs_date_next"><![CDATA[Next Payment]]></string>
+    <string name="_bx_payment_grid_column_title_crts_vendor_id"><![CDATA[Vendor]]></string>
+    <string name="_bx_payment_grid_column_title_crts_items_count"><![CDATA[Count]]></string>
+    <string name="_bx_payment_grid_column_title_crts_items_price"><![CDATA[Price]]></string>
+    <string name="_bx_payment_grid_column_title_crt_title"><![CDATA[Product]]></string>
+    <string name="_bx_payment_grid_column_title_crt_description"><![CDATA[Description]]></string>
+    <string name="_bx_payment_grid_column_title_crt_quantity"><![CDATA[Quantity]]></string>
+    <string name="_bx_payment_grid_column_title_crt_price"><![CDATA[Price]]></string>
+    <string name="_bx_payment_grid_column_title_cms_caption"><![CDATA[Caption]]></string>
+    <string name="_bx_payment_grid_column_title_cms_description"><![CDATA[Description]]></string>
+    <string name="_bx_payment_grid_column_title_cms_acl_id"><![CDATA[Membership]]></string>
+    <string name="_bx_payment_grid_column_title_cms_percentage"><![CDATA[Percentage]]></string>
+    <string name="_bx_payment_grid_column_title_cms_installment"><![CDATA[Fixed fee]]></string>
+    <string name="_bx_payment_grid_column_title_inv_commissionaire_id"><![CDATA[Payee]]></string>
+    <string name="_bx_payment_grid_column_title_inv_committent_id"><![CDATA[Payer]]></string>
+    <string name="_bx_payment_grid_column_title_inv_name"><![CDATA[Name]]></string>
+    <string name="_bx_payment_grid_column_title_inv_period_start"><![CDATA[Period start]]></string>
+    <string name="_bx_payment_grid_column_title_inv_period_end"><![CDATA[Period end]]></string>
+    <string name="_bx_payment_grid_column_title_inv_amount"><![CDATA[Amount]]></string>
+    <string name="_bx_payment_grid_column_title_inv_date_issue"><![CDATA[Issue date]]></string>
+    <string name="_bx_payment_grid_column_title_inv_date_due"><![CDATA[Due date]]></string>
+    <string name="_bx_payment_grid_column_title_inv_status"><![CDATA[Status]]></string>
+
+    <string name="_bx_payment_grid_action_title_ods_add"><![CDATA[Manual Order]]></string>
+    <string name="_bx_payment_grid_action_title_ods_cancel"><![CDATA[Cancel]]></string>
+    <string name="_bx_payment_grid_action_title_ods_process"><![CDATA[Process]]></string>
+    <string name="_bx_payment_grid_action_title_ods_view_order"><![CDATA[View]]></string>
+    <string name="_bx_payment_grid_action_title_sbs_actions"><![CDATA[Actions]]></string>
+    <string name="_bx_payment_grid_action_title_sbs_view_order"><![CDATA[View]]></string>
+    <string name="_bx_payment_grid_action_title_sbs_cancel"><![CDATA[Cancel]]></string>
+    <string name="_bx_payment_grid_action_title_sbs_delete"><![CDATA[Remove]]></string>
+    <string name="_bx_payment_grid_action_title_crts_delete"><![CDATA[Delete]]></string>
+    <string name="_bx_payment_grid_action_title_crts_continue"><![CDATA[Continue to checkout]]></string>
+    <string name="_bx_payment_grid_action_title_crt_checkout"><![CDATA[Checkout with {0}]]></string>
+    <string name="_bx_payment_grid_action_title_crt_delete"><![CDATA[Delete]]></string>
+    <string name="_bx_payment_grid_action_title_crt_quantity_sub"><![CDATA[Decrease quantity]]></string>
+    <string name="_bx_payment_grid_action_title_crt_quantity_add"><![CDATA[Increase quantity]]></string>
+    <string name="_bx_payment_grid_action_title_cms_add"><![CDATA[Add]]></string>
+    <string name="_bx_payment_grid_action_title_cms_edit"><![CDATA[Edit]]></string>
+    <string name="_bx_payment_grid_action_title_cms_delete"><![CDATA[Delete]]></string>
+    <string name="_bx_payment_grid_action_title_inv_edit"><![CDATA[Edit]]></string>
+    <string name="_bx_payment_grid_action_title_inv_delete"><![CDATA[Delete]]></string>
+    <string name="_bx_payment_grid_action_title_inv_pay"><![CDATA[Pay]]></string>
+
+    <string name="_bx_payment_popup_title_ods_order_subscription_view"><![CDATA[Subscription]]></string>
+    <string name="_bx_payment_popup_title_ods_order_subscription_get_details"><![CDATA[Subscription Details]]></string>
+    <string name="_bx_payment_popup_title_ods_order_subscription_change_details"><![CDATA[Change Subscription Details]]></string>
+    <string name="_bx_payment_popup_title_ods_order_subscription_get_billing"><![CDATA[Billing Information]]></string>
+    <string name="_bx_payment_popup_title_ods_order_subscription_change_billing"><![CDATA[Change Billing Information]]></string>
+    <string name="_bx_payment_popup_title_ods_order_history_view"><![CDATA[Order]]></string>
+    <string name="_bx_payment_popup_title_ods_order_pending_view"><![CDATA[Pending Order]]></string>
+    <string name="_bx_payment_popup_title_ods_order_pending_process"><![CDATA[Process Pending Order]]></string>
+    <string name="_bx_payment_popup_title_ods_order_processed_view"><![CDATA[Processed Order]]></string>
+    <string name="_bx_payment_popup_title_ods_order_processed_add"><![CDATA[Manual Order]]></string>
+    <string name="_bx_payment_popup_title_crd_providers_select"><![CDATA[Select Payment Method]]></string>
+    <string name="_bx_payment_popup_title_cms_add"><![CDATA[Add Monthly Commission]]></string>
+    <string name="_bx_payment_popup_title_cms_edit"><![CDATA[Edit Monthly Commission]]></string>
+    <string name="_bx_payment_popup_title_inv_edit"><![CDATA[Edit Invoice]]></string>
+
+    <!-- FORMS -->
+    <string name="_bx_payment_form_cart_input_do_delete"><![CDATA[Delete]]></string>
+    <string name="_bx_payment_form_cart_input_do_checkout"><![CDATA[Checkout]]></string>
+    <string name="_bx_payment_form_details_input_do_submit"><![CDATA[Save]]></string>
+
+    <string name="_bx_payment_form_details_form"><![CDATA[Details Form]]></string>
+    <string name="_bx_payment_form_details_display_edit"><![CDATA[Edit Details Display]]></string>
+
+    <string name="_bx_payment_form_pendings_form"><![CDATA[Pendings Form]]></string>
+    <string name="_bx_payment_form_processed_form"><![CDATA[Processed Form]]></string>
+    <string name="_bx_payment_form_pendings_display_process"><![CDATA[Process Pending Display]]></string>
+    <string name="_bx_payment_form_processed_display_add"><![CDATA[Add Processed Display]]></string>
+    <string name="_bx_payment_form_pendings_input_id_sys"><![CDATA[ID]]></string>
+    <string name="_bx_payment_form_pendings_input_seller_id_sys"><![CDATA[Seller ID]]></string>
+    <string name="_bx_payment_form_pendings_input_order_sys"><![CDATA[Order]]></string>
+    <string name="_bx_payment_form_pendings_input_order"><![CDATA[Order]]></string>
+    <string name="_bx_payment_form_pendings_input_order_err"><![CDATA[You need to fill in order number here.]]></string>
+    <string name="_bx_payment_form_pendings_input_process_sys"><![CDATA[Process]]></string>
+    <string name="_bx_payment_form_pendings_input_process"><![CDATA[Process]]></string>
+    <string name="_bx_payment_form_pendings_input_cancel_sys"><![CDATA[Cancel]]></string>
+    <string name="_bx_payment_form_pendings_input_cancel"><![CDATA[Cancel]]></string>
+    <string name="_bx_payment_form_processed_input_seller_id_sys"><![CDATA[Seller ID]]></string>
+    <string name="_bx_payment_form_processed_input_client_id_sys"><![CDATA[Client ID]]></string>
+    <string name="_bx_payment_form_processed_input_client_sys"><![CDATA[Client]]></string>
+    <string name="_bx_payment_form_processed_input_client"><![CDATA[Client]]></string>
+    <string name="_bx_payment_form_processed_input_client_err"><![CDATA[You need to enter a name of an existed member here.]]></string>
+    <string name="_bx_payment_form_processed_input_order_sys"><![CDATA[Order]]></string>
+    <string name="_bx_payment_form_processed_input_order"><![CDATA[Order]]></string>
+    <string name="_bx_payment_form_processed_input_order_err"><![CDATA[You need to fill in order number here.]]></string>
+    <string name="_bx_payment_form_processed_input_module_id_sys"><![CDATA[Module]]></string>
+    <string name="_bx_payment_form_processed_input_module_id"><![CDATA[Module]]></string>
+    <string name="_bx_payment_form_processed_input_module_id_err"><![CDATA[You need to select a module here.]]></string>
+    <string name="_bx_payment_form_processed_input_items_sys"><![CDATA[Items]]></string>
+    <string name="_bx_payment_form_processed_input_items"><![CDATA[]]></string>
+    <string name="_bx_payment_form_processed_input_items_err"><![CDATA[You need to select at least one item from the list here.]]></string>
+    <string name="_bx_payment_form_processed_input_add"><![CDATA[Add]]></string>
+    <string name="_bx_payment_form_processed_input_add_sys"><![CDATA[Add]]></string>
+    <string name="_bx_payment_form_processed_input_cancel"><![CDATA[Cancel]]></string>
+    <string name="_bx_payment_form_processed_input_cancel_sys"><![CDATA[Cancel]]></string>
+    
+    <string name="_bx_payment_form_commissions_form"><![CDATA[Commissions Form]]></string>
+    <string name="_bx_payment_form_commissions_display_add"><![CDATA[Add Commission Display]]></string>
+    <string name="_bx_payment_form_commissions_display_edit"><![CDATA[Edit Commission Display]]></string>
+    <string name="_bx_payment_form_commissions_input_caption_sys"><![CDATA[Caption]]></string>
+    <string name="_bx_payment_form_commissions_input_caption"><![CDATA[Caption]]></string>
+    <string name="_bx_payment_form_commissions_input_caption_err"><![CDATA[This field is essential. Please, fill it in.]]></string>
+    <string name="_bx_payment_form_commissions_input_description_sys"><![CDATA[Description]]></string>
+    <string name="_bx_payment_form_commissions_input_description"><![CDATA[Description]]></string>
+    <string name="_bx_payment_form_commissions_input_acl_id_sys"><![CDATA[Membership Level]]></string>
+    <string name="_bx_payment_form_commissions_input_acl_id"><![CDATA[Membership Level]]></string>
+    <string name="_bx_payment_form_commissions_input_percentage_sys"><![CDATA[Percentage]]></string>
+    <string name="_bx_payment_form_commissions_input_percentage"><![CDATA[Percentage]]></string>
+    <string name="_bx_payment_form_commissions_input_installment_sys"><![CDATA[Fixed fee]]></string>
+    <string name="_bx_payment_form_commissions_input_installment"><![CDATA[Fixed fee]]></string>
+    <string name="_bx_payment_form_commissions_input_submit_sys"><![CDATA[Submit]]></string>
+    <string name="_bx_payment_form_commissions_input_submit"><![CDATA[Submit]]></string>
+    <string name="_bx_payment_form_commissions_input_cancel_sys"><![CDATA[Cancel]]></string>
+    <string name="_bx_payment_form_commissions_input_cancel"><![CDATA[Cancel]]></string>
+    
+    <string name="_bx_payment_form_invoices_form"><![CDATA[Invoices Form]]></string>
+    <string name="_bx_payment_form_invoices_display_edit"><![CDATA[Edit Invoice Display]]></string>
+    <string name="_bx_payment_form_invoices_input_amount_sys"><![CDATA[Amount]]></string>
+    <string name="_bx_payment_form_invoices_input_amount"><![CDATA[Amount]]></string>
+    <string name="_bx_payment_form_invoices_input_amount_err"><![CDATA[This field is essential. Please, fill it in.]]></string>
+    <string name="_bx_payment_form_invoices_input_date_due_sys"><![CDATA[Due date]]></string>
+    <string name="_bx_payment_form_invoices_input_date_due"><![CDATA[Due date]]></string>
+    <string name="_bx_payment_form_invoices_input_date_due_err"><![CDATA[This field is essential. Please, fill it in.]]></string>
+    <string name="_bx_payment_form_invoices_input_status_sys"><![CDATA[Status]]></string>
+    <string name="_bx_payment_form_invoices_input_status"><![CDATA[Status]]></string>
+    <string name="_bx_payment_form_invoices_input_submit_sys"><![CDATA[Submit]]></string>
+    <string name="_bx_payment_form_invoices_input_submit"><![CDATA[Submit]]></string>
+    <string name="_bx_payment_form_invoices_input_cancel_sys"><![CDATA[Cancel]]></string>
+    <string name="_bx_payment_form_invoices_input_cancel"><![CDATA[Cancel]]></string>
+    
+    <string name="_bx_payment_form_cs_input_items"><![CDATA[Why do you want to cancel?]]></string>
+    <string name="_bx_payment_form_cs_input_other"><![CDATA[Your variant]]></string>
+    <string name="_bx_payment_form_cs_input_submit"><![CDATA[Submit]]></string>
+    <string name="_bx_payment_form_cs_input_cancel"><![CDATA[Cancel]]></string>
+
+    <string name="_bx_payment_form_input_err"><![CDATA[This field is essential. Please, fill it in.]]></string>
+    <string name="_bx_payment_form_input_email_err_cor_or_emp"><![CDATA[Use correct email address or leave empty.]]></string>
+
+    <!-- Predefined Values -->
+    <string name="_bx_payment_pre_lists_currencies"><![CDATA[Currencies]]></string>
+    
+    <string name="_bx_payment_pre_lists_reasons_cancel"><![CDATA[Reasons to cancel subscription]]></string>
+    <string name="_bx_payment_pre_values_rc_0"><![CDATA[Other]]></string>
+    <string name="_bx_payment_pre_values_rc_1"><![CDATA[Cost & Budgeting]]></string>
+    <string name="_bx_payment_pre_values_rc_2"><![CDATA[Hidden Fees & Billing Issues]]></string>
+    <string name="_bx_payment_pre_values_rc_3"><![CDATA[Low Usage]]></string>
+    <string name="_bx_payment_pre_values_rc_4"><![CDATA[Loss of Interest]]></string>
+    <string name="_bx_payment_pre_values_rc_5"><![CDATA[Poor User Experience]]></string>
+    <string name="_bx_payment_pre_values_rc_6"><![CDATA[Better Alternatives]]></string>
+
+    <!-- ACL -->
+    <string name="_bx_payment_acl_action_purchase"><![CDATA[Purchase]]></string>
+    <string name="_bx_payment_acl_action_sell"><![CDATA[Sell]]></string>
+    <string name="_bx_payment_acl_action_manage_any_purchase"><![CDATA[Manage Any Purchase]]></string>
+
+    <!-- EMAIL TEMPLATES -->
+    <string name="_bx_payment_et_txt_name_paid_need_join"><![CDATA[Paid and need to join.]]></string>
+    <string name="_bx_payment_et_txt_subject_paid_need_join"><![CDATA[Payment was processed.]]></string>
+    <string name="_bx_payment_et_txt_body_paid_need_join"><![CDATA[{email_header}
+<p>Hello, {RealName}.</p>
+<p>Your payment was processed. If you did not fill in the join form yet, then you may do it using the following link.</p>
+<p><a href="{JoinLink}">Join Now</a></p>
+{email_footer}]]></string>
+
+    <string name="_bx_payment_et_txt_name_cancelation_request"><![CDATA[Subscription cancellation request.]]></string>
+    <string name="_bx_payment_et_txt_subject_cancelation_request"><![CDATA[Subscription cancellation request.]]></string>
+    <string name="_bx_payment_et_txt_body_cancelation_request"><![CDATA[{email_header}
+<p>Hello,</p>
+<p>A user with {profile_name} profile name requested cancellation for a subscription.</p>
+<p>Subscription info:<br />ID: {subscription_id}<br />Customer: {subscription_customer}<br />Date: {subscription_date}</p>
+{email_footer}]]></string>
+
+    <string name="_bx_payment_et_txt_name_expiration_notification_seller"><![CDATA[Subscription expiration notification (for seller).]]></string>
+    <string name="_bx_payment_et_txt_subject_expiration_notification_seller"><![CDATA[Subscription expiration notification.]]></string>
+    <string name="_bx_payment_et_txt_body_expiration_notification_seller"><![CDATA[{email_header}
+<p>Hello,</p>
+<p>A subscription purchased by '{profile_name}' expired.</p>
+<p>Subscription info:<br />ID: {subscription_id}<br />Customer: {subscription_customer}<br />Date: {subscription_date}</p>
+<p><b>Note</b>. An associated data will be removed shortly.</p>
+{email_footer}]]></string>
+
+    <string name="_bx_payment_et_txt_name_expiration_notification_client"><![CDATA[Subscription expiration notification (for client).]]></string>
+    <string name="_bx_payment_et_txt_subject_expiration_notification_client"><![CDATA[Subscription expiration notification.]]></string>
+    <string name="_bx_payment_et_txt_body_expiration_notification_client"><![CDATA[{email_header}
+<p>Hello,</p>
+<p>Your subscription purchased from '{profile_name}' expired.</p>
+<p>Subscription info:<br />ID: {subscription_id}<br />Customer: {subscription_customer}<br />Date: {subscription_date}</p>
+<p><b>Note</b>. An associated data will be removed shortly.</p>
+{email_footer}]]></string>
+
+    <string name="_bx_payment_et_txt_name_expiring_notification_committent"><![CDATA[Invoice expiring notification.]]></string>
+    <string name="_bx_payment_et_txt_subject_expiring_notification_committent"><![CDATA[Invoice expiring notification.]]></string>
+    <string name="_bx_payment_et_txt_body_expiring_notification_committent"><![CDATA[{email_header}
+<p>Hello,</p>
+<p>Your invoice '{invoice}' is expiring in '{days}' day(s).</p>
+<p>Invoice info:<br />Period start: {period_start}<br />Period end: {period_end}<br />Issue date: {date_issue}<br />Due date: {date_due}</p>
+{email_footer}]]></string>
+
+    <string name="_bx_payment_et_txt_name_overdue_notification_committent"><![CDATA[Overdue invoice notification.]]></string>
+    <string name="_bx_payment_et_txt_subject_overdue_notification_committent"><![CDATA[Overdue invoice notification.]]></string>
+    <string name="_bx_payment_et_txt_body_overdue_notification_committent"><![CDATA[{email_header}
+<p>Hello,</p>
+<p>Your invoice '{invoice}' is overdue '{date_due}'.</p>
+<p>Invoice info:<br />Period start: {period_start}<br />Period end: {period_end}<br />Issue date: {date_issue}<br />Due date: {date_due}</p>
+{email_footer}]]></string>
+
+    <string name="_bx_payment_et_txt_name_checkout_offline"><![CDATA[Offline checkout attempt.]]></string>
+    <string name="_bx_payment_et_txt_subject_checkout_offline"><![CDATA[An attempt to pay with cash.]]></string>
+    <string name="_bx_payment_et_txt_body_checkout_offline"><![CDATA[{email_header}
+<p>Hello,</p>
+<p>A site member <a href="{profile_link}">{profile_name}</a> wanted to pay you with cash for:</p>
+<p>{items}</p>
+<p>Amount: {amount}<br />Date: {date}</p>
+<p>Go to the <a href="{pending_orders_link}">pending orders page</a> to process the order once the payment is received.</p>
+{email_footer}]]></string>
+
+    <string name="_bx_payment_et_txt_name_wrong_balance"><![CDATA[Insufficient funds to write off.]]></string>
+    <string name="_bx_payment_et_txt_subject_wrong_balance"><![CDATA[Insufficient funds to write off.]]></string>
+    <string name="_bx_payment_et_txt_body_wrong_balance"><![CDATA[{email_header}
+<p>Hello,</p>
+<p>You have insufficient funds to write off for paying a subscription.</p>
+<p>Subscription info:<br />ID: {subscription_id}<br />Customer: {subscription_customer}<br />Payment provider: {subscription_provider}<br />Date: {subscription_date}</p>
+{email_footer}]]></string>
+
+    <!-- MESSAGES, WARNINGS and ERRORS -->
+    <string name="_bx_payment_msg_no_results"><![CDATA[Empty]]></string>
+    <string name="_bx_payment_msg_redirecting"><![CDATA[Redirecting... Please wait.]]></string>
+    <string name="_bx_payment_msg_item_added"><![CDATA[The item was successfully added to your shopping cart.]]></string>
+    <string name="_bx_payment_msg_item_deleted"><![CDATA[The item was successfully deleted from your shopping cart.]]></string>
+    <string name="_bx_payment_msg_successfully_performed"><![CDATA[The action was successfully performed.]]></string>
+    <string name="_bx_payment_msg_successfully_processed_free"><![CDATA[Free item was successfully processed]]></string>
+    <string name="_bx_payment_msg_cancelation_request_sent"><![CDATA[Cancellation request was sent. Please wait.]]></string>
+    <string name="_bx_payment_msg_confirm_cancelation"><![CDATA[Are you sure you want to cancel your subscription?]]></string>
+    <string name="_bx_payment_msg_single_seller"><![CDATA[Single seller mode is enabled. <a href="{0}">Got to</a> single shopping cart.]]></string>
+    <string name="_bx_payment_err_access_db"><![CDATA[Database access error.]]></string>
+    <string name="_bx_payment_err_cannot_validate"><![CDATA[Can't connect to remote host for validation.]]></string>
+    <string name="_bx_payment_err_empty_items"><![CDATA[There are no items selected.]]></string>
+    <string name="_bx_payment_err_empty_order"><![CDATA[The order is empty.]]></string>
+    <string name="_bx_payment_err_inactive_vendor"><![CDATA[The vendor status is not active.]]></string>
+    <string name="_bx_payment_err_incorrect_provider"><![CDATA[Incorrect or unavailable payment provider.]]></string>
+    <string name="_bx_payment_err_not_accept_payments"><![CDATA[The vendor does not accept payments.]]></string>
+    <string name="_bx_payment_err_nothing_selected"><![CDATA[You need to select at least one item.]]></string>
+    <string name="_bx_payment_err_self_purchase"><![CDATA[Buying from your own store is not permitted.]]></string>
+    <string name="_bx_payment_err_required_login"><![CDATA[You need to login.]]></string>
+    <string name="_bx_payment_err_unknown_vendor"><![CDATA[Unknown vendor.]]></string>
+    <string name="_bx_payment_err_wrong_vendor"><![CDATA[Incorrect vendor.]]></string>
+    <string name="_bx_payment_err_wrong_data"><![CDATA[Incorrect input data.]]></string>
+    <string name="_bx_payment_err_not_found_pending"><![CDATA[Pending order was not found.]]></string>
+    <string name="_bx_payment_err_cannot_perform"><![CDATA[Cannot perform the action. Please report.]]></string>
+    <string name="_bx_payment_err_wrong_quantity"><![CDATA[Incorrect quantity specified.]]></string>
+    <string name="_bx_payment_err_already_processed"><![CDATA[This payment has already processed.]]></string>
+    <string name="_bx_payment_err_already_registered"><![CDATA[Subscription with the same data was already registered.]]></string>
+    <string name="_bx_payment_err_not_supported"><![CDATA[Operation isn't supported.]]></string>
+
+    <!-- Other -->
+    <string name="_bx_payment_txt_add_to_cart"><![CDATA[Add to Cart]]></string>
+    <string name="_bx_payment_txt_subscribe"><![CDATA[Subscribe]]></string>
+    <string name="_bx_payment_txt_payment_to"><![CDATA[Payment to {0}]]></string>
+    <string name="_bx_payment_txt_payment_to_for"><![CDATA[Payment to {0} for:]]></string>
+    <string name="_bx_payment_txt_checkout_to"><![CDATA[Continue checkouting to {0}]]></string>
+    <string name="_bx_payment_txt_checkout_with"><![CDATA[Checkout with {0}]]></string>
+    <string name="_bx_payment_txt_checkout_with_cash"><![CDATA[Checkout with cash]]></string>
+    <string name="_bx_payment_txt_checkout_for"><![CDATA[A message was sent to the seller ({0}), that you want to pay with cash for the following items. He should contact you shortly.]]></string>
+    <string name="_bx_payment_txt_checkout_qt"><![CDATA[qt.]]></string>
+    <string name="_bx_payment_txt_checkout_item"><![CDATA[{0} ({1}qt.)<br />]]></string>
+    <string name="_bx_payment_txt_client"><![CDATA[Client]]></string>
+    <string name="_bx_payment_txt_license"><![CDATA[License]]></string>
+    <string name="_bx_payment_txt_seller"><![CDATA[Seller]]></string>
+    <string name="_bx_payment_txt_author"><![CDATA[Author]]></string>
+    <string name="_bx_payment_txt_item"><![CDATA[Product]]></string>
+    <string name="_bx_payment_txt_quantity"><![CDATA[Qt.]]></string>
+    <string name="_bx_payment_txt_order"><![CDATA[Order ID]]></string>
+    <string name="_bx_payment_txt_customer_id"><![CDATA[Customer ID]]></string>
+    <string name="_bx_payment_txt_subscription"><![CDATA[Subscription]]></string>
+    <string name="_bx_payment_txt_price"><![CDATA[Price]]></string>
+    <string name="_bx_payment_txt_price_sold"><![CDATA[Sold Price]]></string>
+    <string name="_bx_payment_txt_processed_with"><![CDATA[Processed with]]></string>
+    <string name="_bx_payment_txt_message"><![CDATA[Result]]></string>
+    <string name="_bx_payment_txt_date"><![CDATA[Date]]></string>
+    <string name="_bx_payment_txt_deleted"><![CDATA[Date cancel]]></string>
+    <string name="_bx_payment_txt_deleted_reason"><![CDATA[Reason to cancel]]></string>
+    <string name="_bx_payment_txt_products"><![CDATA[Products]]></string>
+    <string name="_bx_payment_txt_buyer_name_mask"><![CDATA[{0} {1}]]></string>
+    <string name="_bx_payment_txt_none"><![CDATA[none]]></string>
+    <string name="_bx_payment_txt_name_manual"><![CDATA[Manually]]></string>
+    <string name="_bx_payment_txt_yes"><![CDATA[Yes]]></string>
+    <string name="_bx_payment_txt_no"><![CDATA[No]]></string>
+    <string name="_bx_payment_txt_unsubscribe_yes"><![CDATA[Cancel automatically]]></string>
+    <string name="_bx_payment_txt_unsubscribe_no"><![CDATA[Do not cancel]]></string>
+    <string name="_bx_payment_txt_all_authors"><![CDATA[All Authors]]></string>
+    <string name="_bx_payment_txt_all_clients"><![CDATA[All Clients]]></string>
+    <string name="_bx_payment_txt_all_modules"><![CDATA[All Modules]]></string>
+    <string name="_bx_payment_txt_all_items"><![CDATA[All Items]]></string>
+    <string name="_bx_payment_txt_status_scheduled"><![CDATA[Scheduled]]></string>
+    <string name="_bx_payment_txt_status_trial"><![CDATA[Trial]]></string>
+    <string name="_bx_payment_txt_status_active"><![CDATA[Active]]></string>
+    <string name="_bx_payment_txt_status_paid"><![CDATA[Paid]]></string>
+    <string name="_bx_payment_txt_status_unpaid"><![CDATA[Unpaid]]></string>
+    <string name="_bx_payment_txt_status_overdue"><![CDATA[Overdue]]></string>
+    <string name="_bx_payment_txt_status_paused"><![CDATA[Paused]]></string>
+    <string name="_bx_payment_txt_status_cancel"><![CDATA[Canceled]]></string>
+    <string name="_bx_payment_txt_status_canceled"><![CDATA[Canceled]]></string>
+    <string name="_bx_payment_txt_status_unknown"><![CDATA[Unknown]]></string>
+    <string name="_bx_payment_txt_invoice_title"><![CDATA[Invoice {0} from {1}]]></string>
+    <string name="_bx_payment_txt_invoice_description"><![CDATA[For a period between {0} and {1}]]></string>
+    <string name="_bx_payment_txt_payment_description"><![CDATA[Payment on {0} site.]]></string>
+
+    <!-- Generic payment provider -->
+    <string name="_bx_payment_gc_cpt"><![CDATA[Generic]]></string>
+    <string name="_bx_payment_gc_dsc"><![CDATA[Isn't used to process payments directly. Is needed to store personal settings for usage in the other providers.]]></string>
+    <string name="_bx_payment_gc_currency_code_cpt"><![CDATA[Currency]]></string>
+    <string name="_bx_payment_gc_currency_code_dsc"><![CDATA[Select your own currency instead the default one]]></string>
+    <string name="_bx_payment_gc_currency_code_default"><![CDATA[Default]]></string>
+    <string name="_bx_payment_gc_err_not_available"><![CDATA[Generic payment provider isn't available for payments.]]></string>
+
+    <!-- Offline payment provider -->
+    <string name="_bx_payment_off_cpt"><![CDATA[Offline]]></string>
+    <string name="_bx_payment_off_dsc"><![CDATA[For offline payments like cash, etransfer, etc.]]></string>
+    <string name="_bx_payment_off_active_cpt"><![CDATA[Active]]></string>
+    <string name="_bx_payment_off_active_dsc"><![CDATA[Activate(Deactivate) provider]]></string>
+    <string name="_bx_payment_off_checkout_email_cpt"><![CDATA[Email]]></string>
+    <string name="_bx_payment_off_checkout_email_dsc"><![CDATA[Email to send notifications about checkout attempts to. Leave empty to receive notifications on your profile email.]]></string>
+    <string name="_bx_payment_off_err_not_available"><![CDATA[Offline payment provider isn't available for online payments.]]></string>
+    <string name="_bx_payment_txt_name_offline"><![CDATA[Cash]]></string>
+    <string name="_bx_payment_txt_cart_offline"><![CDATA[Cash]]></string>
+
+    <!-- Credits payment provider -->
+    <string name="_bx_payment_cdt_cpt"><![CDATA[Credits]]></string>
+    <string name="_bx_payment_cdt_dsc"><![CDATA[Credits payment provider]]></string>
+    <string name="_bx_payment_cdt_active_cpt"><![CDATA[Active]]></string>
+    <string name="_bx_payment_cdt_active_dsc"><![CDATA[Activate(Deactivate) provider]]></string>
+    <string name="_bx_payment_cdt_msg_charged"><![CDATA[Payment was successfully processed.]]></string>
+    <string name="_bx_payment_cdt_msg_subscribed"><![CDATA[Thank you! Subscription created. Please, check your email for further instructions.]]></string>
+    <string name="_bx_payment_cdt_err_not_available"><![CDATA[Checkout with Credits isn't available now.]]></string>
+    <string name="_bx_payment_cdt_err_wrong_balance"><![CDATA[Insufficient funds to write off.]]></string>
+    <string name="_bx_payment_cdt_err_wrong_transaction"><![CDATA[Transaction verification failed.]]></string>
+    <string name="_bx_payment_txt_name_credits"><![CDATA[Credits]]></string>
+    <string name="_bx_payment_txt_cart_credits"><![CDATA[Credits]]></string>
+
+    <!-- PayPal payment provider -->
+    <string name="_bx_payment_pp_cpt"><![CDATA[PayPal]]></string>
+    <string name="_bx_payment_pp_dsc"><![CDATA[PayPal payment provider]]></string>
+    <string name="_bx_payment_pp_active_cpt"><![CDATA[Active]]></string>
+    <string name="_bx_payment_pp_active_dsc"><![CDATA[Activate(Deactivate) provider]]></string>
+    <string name="_bx_payment_pp_mode_cpt"><![CDATA[Mode]]></string>
+    <string name="_bx_payment_pp_mode_dsc"><![CDATA[Mode to process payments]]></string>
+    <string name="_bx_payment_pp_mode_live"><![CDATA[live]]></string>
+    <string name="_bx_payment_pp_mode_test"><![CDATA[test]]></string>
+    <string name="_bx_payment_pp_business_cpt"><![CDATA[Business]]></string>
+    <string name="_bx_payment_pp_business_dsc"><![CDATA[Business email address]]></string>
+    <string name="_bx_payment_pp_prc_type_cpt"><![CDATA[Process type]]></string>
+    <string name="_bx_payment_pp_prc_type_dsc"><![CDATA[The type in which data is to be processed]]></string>
+    <string name="_bx_payment_pp_prc_type_direct"><![CDATA[direct]]></string>
+    <string name="_bx_payment_pp_prc_type_pdt"><![CDATA[PDT]]></string>
+    <string name="_bx_payment_pp_prc_type_ipn"><![CDATA[IPN]]></string>
+    <string name="_bx_payment_pp_token_cpt"><![CDATA[Identity token]]></string>
+    <string name="_bx_payment_pp_token_dsc"><![CDATA[Identity token]]></string>
+    <string name="_bx_payment_pp_sandbox_cpt"><![CDATA[Sandbox]]></string>
+    <string name="_bx_payment_pp_sandbox_dsc"><![CDATA[Sandbox email address]]></string>
+    <string name="_bx_payment_pp_return_data_url_cpt"><![CDATA[Data return URL]]></string>
+    <string name="_bx_payment_pp_err_no_data_given"><![CDATA[No data given.]]></string>
+    <string name="_bx_payment_pp_err_not_completed"><![CDATA[Payment is not completed.]]></string>
+    <string name="_bx_payment_pp_err_wrong_vendor"><![CDATA[Wrong vendor.]]></string>
+    <string name="_bx_payment_pp_err_wrong_business"><![CDATA[Wrong receiver email.]]></string>
+    <string name="_bx_payment_pp_err_wrong_transaction"><![CDATA[Transaction verification failed.]]></string>
+    <string name="_bx_payment_pp_err_wrong_verification_status"><![CDATA[No verification status received.]]></string>
+    <string name="_bx_payment_pp_err_wrong_amount"><![CDATA[Wrong amount.]]></string>
+    <string name="_bx_payment_pp_err_wrong_custom_data"><![CDATA[Incorrect custom data.]]></string>
+    <string name="_bx_payment_pp_msg_verified"><![CDATA[Payment was successfully processed.]]></string>
+    <string name="_bx_payment_txt_name_paypal"><![CDATA[PayPal]]></string>
+    <string name="_bx_payment_txt_cart_paypal"><![CDATA[PayPal]]></string>
+
+    <!-- PayPal API payment provider -->
+    <string name="_bx_payment_pp_api_cpt"><![CDATA[PayPal API]]></string>
+    <string name="_bx_payment_pp_api_dsc"><![CDATA[PayPal payment provider (API based integration)]]></string>
+    <string name="_bx_payment_pp_api_active_cpt"><![CDATA[Active]]></string>
+    <string name="_bx_payment_pp_api_active_dsc"><![CDATA[Activate(Deactivate) provider]]></string>
+    <string name="_bx_payment_pp_api_hidden_cpt"><![CDATA[Hidden]]></string>
+    <string name="_bx_payment_pp_api_hidden_dsc"><![CDATA[Hide provider if you don't want to accept new payments but already have active subscriptions.]]></string>
+    <string name="_bx_payment_pp_api_mode_cpt"><![CDATA[Mode]]></string>
+    <string name="_bx_payment_pp_api_mode_dsc"><![CDATA[Mode to process payments]]></string>
+    <string name="_bx_payment_pp_api_mode_live"><![CDATA[live]]></string>
+    <string name="_bx_payment_pp_api_mode_test"><![CDATA[test]]></string>
+    <string name="_bx_payment_pp_api_live_account_cpt"><![CDATA[Account (live)]]></string>
+    <string name="_bx_payment_pp_api_live_account_dsc"><![CDATA[Email address which is used to access your PayPal account.]]></string>
+    <string name="_bx_payment_pp_api_live_client_id_cpt"><![CDATA[Client ID (live)]]></string>
+    <string name="_bx_payment_pp_api_live_client_id_dsc"><![CDATA[A part of application's credentials.]]></string>
+    <string name="_bx_payment_pp_api_live_secret_cpt"><![CDATA[Secret (live)]]></string>
+    <string name="_bx_payment_pp_api_live_secret_dsc"><![CDATA[A part of application's credentials.]]></string>
+    <string name="_bx_payment_pp_api_test_account_cpt"><![CDATA[Account (test)]]></string>
+    <string name="_bx_payment_pp_api_test_account_dsc"><![CDATA[Email address which is used to access your PayPal account.]]></string>
+    <string name="_bx_payment_pp_api_test_client_id_cpt"><![CDATA[Client ID (test)]]></string>
+    <string name="_bx_payment_pp_api_test_client_id_dsc"><![CDATA[A part of application's credentials.]]></string>
+    <string name="_bx_payment_pp_api_test_secret_cpt"><![CDATA[Secret (test)]]></string>
+    <string name="_bx_payment_pp_api_test_secret_dsc"><![CDATA[A part of application's credentials.]]></string>
+    <string name="_bx_payment_pp_api_return_data_url_cpt"><![CDATA[Data return URL]]></string>
+    <string name="_bx_payment_pp_api_notify_url_cpt"><![CDATA[Webhooks URL]]></string>
+    <string name="_bx_payment_pp_api_err_cannot_authorize"><![CDATA[Can't authorize the approved order.]]></string>
+    <string name="_bx_payment_pp_api_err_cannot_capture"><![CDATA[Can't finalize checkout.]]></string>
+    <string name="_bx_payment_pp_api_err_no_item"><![CDATA[There is nothing to subscribe.]]></string>
+    <string name="_bx_payment_pp_api_err_wrong_item"><![CDATA[The product you want to subscribe to has incorrect data on PayPal end. Please report.]]></string>
+    <string name="_bx_payment_pp_api_err_no_subscription"><![CDATA[The subscription data isn't available or incorrect.]]></string>
+    <string name="_bx_payment_pp_api_err_subscription_not_confirmed"><![CDATA[Subscription wasn't confirmed.]]></string>
+    <string name="_bx_payment_pp_api_msg_authorized"><![CDATA[The order was successfully authorized.]]></string>
+    <string name="_bx_payment_pp_api_msg_captured"><![CDATA[Payment was successfully processed.]]></string>
+    <string name="_bx_payment_pp_api_msg_subscribed"><![CDATA[Thank you! Subscription created. Please, check your email for further instructions.]]></string>
+    <string name="_bx_payment_txt_name_paypal_api"><![CDATA[PayPal]]></string>
+    <string name="_bx_payment_txt_cart_paypal_api"><![CDATA[PayPal]]></string>
+    <string name="_bx_payment_txt_subscribe_paypal_api"><![CDATA[PayPal]]></string>
+
+    <!-- Chargebee payment provider -->
+    <string name="_bx_payment_cbee_cpt"><![CDATA[Chargebee]]></string>
+    <string name="_bx_payment_cbee_dsc"><![CDATA[If enabled, users can checkout using Chargebee's hosted pages.]]></string>
+    <string name="_bx_payment_cbee_v3_cpt"><![CDATA[Chargebee]]></string>
+    <string name="_bx_payment_cbee_v3_dsc"><![CDATA[If enabled, users can checkout using Chargebee's drop-in script.]]></string>
+    <string name="_bx_payment_cbee_active_cpt"><![CDATA[Active]]></string>
+    <string name="_bx_payment_cbee_active_dsc"><![CDATA[Activate(Deactivate) provider. Note. It's recommended to use SSL for better payment processing.]]></string>
+    <string name="_bx_payment_cbee_hidden_cpt"><![CDATA[Hidden]]></string>
+    <string name="_bx_payment_cbee_hidden_dsc"><![CDATA[Hide provider if you don't want to accept new payments but already have active subscriptions.]]></string>
+    <string name="_bx_payment_cbee_mode_cpt"><![CDATA[Mode]]></string>
+    <string name="_bx_payment_cbee_mode_dsc"><![CDATA[Mode to process payments]]></string>
+    <string name="_bx_payment_cbee_mode_live"><![CDATA[live]]></string>
+    <string name="_bx_payment_cbee_mode_test"><![CDATA[test]]></string>
+    <string name="_bx_payment_cbee_live_site_cpt"><![CDATA[Site (live)]]></string>
+    <string name="_bx_payment_cbee_live_site_dsc"><![CDATA[Your site name registered in Chargebee for 'live' mode]]></string>
+    <string name="_bx_payment_cbee_live_api_key_cpt"><![CDATA[API Key (live)]]></string>
+    <string name="_bx_payment_cbee_live_api_key_dsc"><![CDATA[Your Chargebee API Access key for 'live' mode]]></string>
+    <string name="_bx_payment_cbee_test_site_cpt"><![CDATA[Site (test)]]></string>
+    <string name="_bx_payment_cbee_test_site_dsc"><![CDATA[Your site name registered in Chargebee for 'test' mode]]></string>
+    <string name="_bx_payment_cbee_test_api_key_cpt"><![CDATA[API Key (test)]]></string>
+    <string name="_bx_payment_cbee_test_api_key_dsc"><![CDATA[Your Chargebee API Access key for 'test' mode]]></string>
+    <string name="_bx_payment_cbee_check_amount_cpt"><![CDATA[Enable amount checking]]></string>
+    <string name="_bx_payment_cbee_check_amount_dsc"><![CDATA[Enable amount checking for Chargebee Webhooks (recomended). However checking should be disabled when discounts and coupons are used.]]></string>
+    <string name="_bx_payment_cbee_ssl_cpt"><![CDATA[Enable SSL]]></string>
+    <string name="_bx_payment_cbee_ssl_dsc"><![CDATA[Enable SSL connection to communicate with Chargebee. Note. URLs below will be updated after saving.]]></string>
+    <string name="_bx_payment_cbee_cancellation_email_cpt"><![CDATA[Cancellation Email]]></string>
+    <string name="_bx_payment_cbee_expiration_email_cpt"><![CDATA[Expiration Email]]></string>
+    <string name="_bx_payment_cbee_return_data_url_cpt"><![CDATA[Data return URL]]></string>
+    <string name="_bx_payment_cbee_notify_url_cpt"><![CDATA[Webhooks URL]]></string>
+    <string name="_bx_payment_cbee_msg_charged"><![CDATA[Payment was successfully processed.]]></string>
+    <string name="_bx_payment_cbee_msg_subscribed"><![CDATA[Thank you! Subscription created. Please, check your email for further instructions.]]></string>
+    <string name="_bx_payment_cbee_txt_checkout_with_single"><![CDATA[Checkout with {0}]]></string>
+    <string name="_bx_payment_cbee_txt_checkout_with_recurring"><![CDATA[Checkout with {0}]]></string>
+    <string name="_bx_payment_cbee_menu_item_title_manager"><![CDATA[Self-serve Portal]]></string>
+    <string name="_bx_payment_txt_name_chargebee"><![CDATA[Chargebee]]></string>
+    <string name="_bx_payment_txt_name_chargebee_v3"><![CDATA[Chargebee]]></string>
+    <string name="_bx_payment_txt_cart_chargebee"><![CDATA[Chargebee]]></string>
+    <string name="_bx_payment_txt_cart_chargebee_v3"><![CDATA[Chargebee]]></string>
+
+    <!-- Stripe payment provider -->
+    <string name="_bx_payment_strp_cpt"><![CDATA[Stripe]]></string>
+    <string name="_bx_payment_strp_dsc"><![CDATA[Stripe payment provider]]></string>
+    <string name="_bx_payment_strp_v3_cpt"><![CDATA[Stripe]]></string>
+    <string name="_bx_payment_strp_v3_dsc"><![CDATA[Stripe payment provider with 3D Secure authentication for Strong Customer Authentication (SCA) support. Note, it doesn't allow to use recurring payments with trial period.]]></string>
+    <string name="_bx_payment_strp_active_cpt"><![CDATA[Active]]></string>
+    <string name="_bx_payment_strp_active_dsc"><![CDATA[Activate(Deactivate) provider. Note. It's recommended to use SSL for better payment processing.]]></string>
+    <string name="_bx_payment_strp_hidden_cpt"><![CDATA[Hidden]]></string>
+    <string name="_bx_payment_strp_hidden_dsc"><![CDATA[Hide provider if you don't want to accept new payments but already have active subscriptions.]]></string>
+    <string name="_bx_payment_strp_mode_cpt"><![CDATA[Mode]]></string>
+    <string name="_bx_payment_strp_mode_dsc"><![CDATA[Mode to process payments]]></string>
+    <string name="_bx_payment_strp_mode_live"><![CDATA[live]]></string>
+    <string name="_bx_payment_strp_mode_test"><![CDATA[test]]></string>
+    <string name="_bx_payment_strp_live_pub_key_cpt"><![CDATA[Public Key (live)]]></string>
+    <string name="_bx_payment_strp_live_pub_key_dsc"><![CDATA[Your Public Key generated in Stripe for 'live' mode]]></string>
+    <string name="_bx_payment_strp_live_sec_key_cpt"><![CDATA[Secret Key (live)]]></string>
+    <string name="_bx_payment_strp_live_sec_key_dsc"><![CDATA[Your Stripe Secret Key for 'live' mode]]></string>
+    <string name="_bx_payment_strp_test_pub_key_cpt"><![CDATA[Public Key (test)]]></string>
+    <string name="_bx_payment_strp_test_pub_key_dsc"><![CDATA[Your Public Key generated in Stripe for 'test' mode]]></string>
+    <string name="_bx_payment_strp_test_sec_key_cpt"><![CDATA[Secret Key (test)]]></string>
+    <string name="_bx_payment_strp_test_sec_key_dsc"><![CDATA[Your Stripe Secret Key for 'test' mode]]></string>
+    <string name="_bx_payment_strp_check_amount_cpt"><![CDATA[Enable amount checking]]></string>
+    <string name="_bx_payment_strp_check_amount_dsc"><![CDATA[Enable amount checking for Stripe Webhooks (recomended). However checking should be disabled when discounts and coupons are used.]]></string>
+    <string name="_bx_payment_strp_ssl_cpt"><![CDATA[Enable SSL]]></string>
+    <string name="_bx_payment_strp_ssl_dsc"><![CDATA[Enable SSL connection to communicate with Stripe. Note. URLs below will be updated after saving.]]></string>
+    <string name="_bx_payment_strp_notify_url_cpt"><![CDATA[Webhooks URL]]></string>
+    <string name="_bx_payment_strp_cancellation_email_cpt"><![CDATA[Cancellation Email]]></string>
+    <string name="_bx_payment_strp_expiration_email_cpt"><![CDATA[Expiration Email]]></string>
+    <string name="_bx_payment_strp_msg_authorized"><![CDATA[The order was successfully authorized.]]></string>
+    <string name="_bx_payment_strp_msg_charged"><![CDATA[Payment was successfully processed.]]></string>
+    <string name="_bx_payment_strp_msg_subscribed"><![CDATA[Thank you! Subscription created. Please, check your email for further instructions.]]></string>
+    <string name="_bx_payment_strp_msg_details_changed"><![CDATA[Subscription details were changed.]]></string>
+    <string name="_bx_payment_strp_err_details_changed"><![CDATA[Cannot change subscription details. Recheck provided data and try again.]]></string>
+    <string name="_bx_payment_strp_msg_billing_changed"><![CDATA[Billing information was changed.]]></string>
+    <string name="_bx_payment_strp_err_billing_changed"><![CDATA[Cannot change billing information. Recheck provided data and try again.]]></string>
+    <string name="_bx_payment_strp_txt_checkout_with_single"><![CDATA[Checkout with {0}]]></string>
+    <string name="_bx_payment_strp_txt_checkout_with_recurring"><![CDATA[Checkout with {0}]]></string>
+    <string name="_bx_payment_strp_menu_item_title_details"><![CDATA[Details]]></string>
+    <string name="_bx_payment_strp_menu_item_title_details_change"><![CDATA[Change Details]]></string>
+    <string name="_bx_payment_strp_menu_item_title_billing"><![CDATA[Billing Info]]></string>
+    <string name="_bx_payment_strp_menu_item_title_billing_change"><![CDATA[Change Billing Info]]></string>
+    <string name="_bx_payment_strp_txt_plan"><![CDATA[Plan]]></string>
+    <string name="_bx_payment_strp_txt_cost"><![CDATA[Cost]]></string>
+    <string name="_bx_payment_strp_txt_cost_mask"><![CDATA[{0} {1} / {2}]]></string>
+    <string name="_bx_payment_strp_txt_status"><![CDATA[Status]]></string>
+    <string name="_bx_payment_strp_txt_created"><![CDATA[Created]]></string>
+    <string name="_bx_payment_strp_txt_started"><![CDATA[Started]]></string>
+    <string name="_bx_payment_strp_txt_trial_start"><![CDATA[Trial start]]></string>
+    <string name="_bx_payment_strp_txt_trial_end"><![CDATA[Trial end]]></string>
+    <string name="_bx_payment_strp_txt_cperiod_start"><![CDATA[Current period start]]></string>
+    <string name="_bx_payment_strp_txt_cperiod_end"><![CDATA[Current period end]]></string>
+    <string name="_bx_payment_strp_txt_card_brand"><![CDATA[Brand]]></string>
+    <string name="_bx_payment_strp_txt_card_origin"><![CDATA[Origin]]></string>
+    <string name="_bx_payment_strp_txt_card_type"><![CDATA[Type]]></string>
+    <string name="_bx_payment_strp_txt_card_number"><![CDATA[Number]]></string>
+    <string name="_bx_payment_strp_txt_card_number_mask"><![CDATA[....{0}]]></string>
+    <string name="_bx_payment_strp_txt_card_expires"><![CDATA[Expires]]></string>
+    <string name="_bx_payment_strp_txt_card_expires_mask"><![CDATA[{0} / {1}]]></string>
+    <string name="_bx_payment_strp_txt_card_cvc"><![CDATA[CVC check]]></string>
+    <string name="_bx_payment_strp_txt_card_cvc_passed"><![CDATA[passed]]></string>
+
+    <string name="_bx_payment_form_strp_details"><![CDATA[Stripe: Details Form]]></string>
+    <string name="_bx_payment_form_strp_details_display_edit"><![CDATA[Stripe: Edit Details Display]]></string>
+    <string name="_bx_payment_form_strp_details_input_item_id_sys"><![CDATA[Plan]]></string>
+    <string name="_bx_payment_form_strp_details_input_item_id"><![CDATA[Plan]]></string>
+    <string name="_bx_payment_form_strp_details_input_item_id_err"><![CDATA[You need to select some plan here]]></string>
+    <string name="_bx_payment_form_strp_details_input_submit_sys"><![CDATA[Submit]]></string>
+    <string name="_bx_payment_form_strp_details_input_submit"><![CDATA[Submit]]></string>
+    <string name="_bx_payment_form_strp_details_input_cancel_sys"><![CDATA[Cancel]]></string>
+    <string name="_bx_payment_form_strp_details_input_cancel"><![CDATA[Cancel]]></string>
+
+    <string name="_bx_payment_form_strp_card"><![CDATA[Stripe: Card Form]]></string>
+    <string name="_bx_payment_form_strp_card_display_add"><![CDATA[Stripe: Add Card Display]]></string>
+    <string name="_bx_payment_form_strp_card_input_card_number_sys"><![CDATA[Card Number]]></string>
+    <string name="_bx_payment_form_strp_card_input_card_number"><![CDATA[Card Number]]></string>
+    <string name="_bx_payment_form_strp_card_input_card_number_inf"><![CDATA[16 digits without spaces describing your card number]]></string>
+    <string name="_bx_payment_form_strp_card_input_card_number_err"><![CDATA[You need to enter card number here]]></string>
+    <string name="_bx_payment_form_strp_card_input_card_expire_sys"><![CDATA[Expiry Date]]></string>
+    <string name="_bx_payment_form_strp_card_input_card_expire"><![CDATA[Expiry Date]]></string>
+    <string name="_bx_payment_form_strp_card_input_card_expire_month"><![CDATA[Month]]></string>
+    <string name="_bx_payment_form_strp_card_input_card_expire_year"><![CDATA[Year]]></string>
+    <string name="_bx_payment_form_strp_card_input_card_expire_inf"><![CDATA[Use 'mm yyyy' format]]></string>
+    <string name="_bx_payment_form_strp_card_input_card_expire_err"><![CDATA[You need to enter expiry date in specified format here]]></string>
+    <string name="_bx_payment_form_strp_card_input_card_cvv_sys"><![CDATA[CVV]]></string>
+    <string name="_bx_payment_form_strp_card_input_card_cvv"><![CDATA[CVV]]></string>
+    <string name="_bx_payment_form_strp_card_input_card_cvv_inf"><![CDATA[Three digits from the back side of your card.]]></string>
+    <string name="_bx_payment_form_strp_card_input_card_cvv_err"><![CDATA[You need to enter card CVV here]]></string>
+    <string name="_bx_payment_form_strp_card_input_submit_sys"><![CDATA[Submit]]></string>
+    <string name="_bx_payment_form_strp_card_input_submit"><![CDATA[Submit]]></string>
+    <string name="_bx_payment_form_strp_card_input_cancel_sys"><![CDATA[Cancel]]></string>
+    <string name="_bx_payment_form_strp_card_input_cancel"><![CDATA[Cancel]]></string>
+
+    <string name="_bx_payment_txt_name_stripe"><![CDATA[Stripe]]></string>
+    <string name="_bx_payment_txt_cart_stripe"><![CDATA[Stripe]]></string>
+    <string name="_bx_payment_txt_name_stripe_v3"><![CDATA[Stripe]]></string>
+    <string name="_bx_payment_txt_cart_stripe_v3"><![CDATA[Stripe]]></string>
+
+    <!-- Stripe Connect payment provider -->
+    <string name="_bx_payment_strp_cnnt_cpt"><![CDATA[Stripe Connect]]></string>
+    <string name="_bx_payment_strp_cnnt_dsc"><![CDATA[Payment provider which is working in pairs with Stripe Connect app.]]></string>
+    <string name="_bx_payment_strp_cnnt_active_dsc"><![CDATA[Activate(Deactivate) provider.]]></string>
+    <string name="_bx_payment_strp_cnnt_connect_cpt"><![CDATA[Connected account]]></string>
+    <string name="_bx_payment_strp_cnnt_live_account_id_cpt"><![CDATA[Account ID (live)]]></string>
+    <string name="_bx_payment_strp_cnnt_test_account_id_cpt"><![CDATA[Account ID (test)]]></string>   
+
+    <!-- _bx_payment_aina_mode_live payment provider -->
+    <string name="_bx_payment_aina_cpt"><![CDATA[Apple In-App]]></string>
+    <string name="_bx_payment_aina_dsc"><![CDATA[Apple In-App payment provider]]></string>
+    <string name="_bx_payment_aina_active_cpt"><![CDATA[Active]]></string>
+    <string name="_bx_payment_aina_active_dsc"><![CDATA[Activate(Deactivate) provider.]]></string>
+    <string name="_bx_payment_aina_hidden_cpt"><![CDATA[Hidden]]></string>
+    <string name="_bx_payment_aina_hidden_dsc"><![CDATA[Recommended. The provider should be hidden in WEB because it can be used in mobile app only.]]></string>
+    <string name="_bx_payment_aina_secret_cpt"><![CDATA[Shared Secret]]></string>
+    <string name="_bx_payment_aina_secret_dsc"><![CDATA[It's the app-specific unique code to receive receipts for auto-renewable subscriptions.]]></string>
+    <string name="_bx_payment_aina_notify_url_cpt"><![CDATA[URL for App Store Server Notifications]]></string>
+    <string name="_bx_payment_aina_menu_item_title_cancel"><![CDATA[Cancel]]></string>
+    <string name="_bx_payment_aina_msg_charged"><![CDATA[Payment was successfully processed.]]></string>
+    <string name="_bx_payment_aina_msg_subscribed"><![CDATA[Thank you! Subscription created. Please, check your email for further instructions.]]></string>
+    <string name="_bx_payment_txt_name_apple_in_app"><![CDATA[Apple In-App]]></string>
+    <string name="_bx_payment_txt_cart_apple_in_app"><![CDATA[Apple In-App]]></string>
+</resources>

+ 213 - 0
modules/boonex/payment/updates/15.0.1_15.0.2/source/install/sql/enable.sql

@@ -0,0 +1,213 @@
+SET @sName = 'bx_payment';
+
+
+-- OPTIONS
+SET @iTypeOrder = (SELECT IFNULL(MAX(`order`), 0) FROM `sys_options_types` WHERE `group` = 'modules');
+INSERT INTO `sys_options_types`(`group`, `name`, `caption`, `icon`, `order`) VALUES 
+('modules', @sName, '_bx_payment', 'bx_payment@modules/boonex/payment/|std-icon.svg', @iTypeOrder + 1);
+SET @iTypeId = LAST_INSERT_ID();
+
+INSERT INTO `sys_options_categories` (`type_id`, `name`, `caption`, `order`)
+VALUES (@iTypeId, 'bx_payment_general', '_bx_payment_options_category_general', 1);
+SET @iCategoryId = LAST_INSERT_ID();
+
+INSERT INTO `sys_options` (`name`, `value`, `category_id`, `caption`, `type`, `check`, `check_params`, `check_error`, `extra`, `order`) VALUES
+('bx_payment_site_admin', '', @iCategoryId, '_bx_payment_option_site_admin', 'select', '', '', '', 'a:2:{s:6:"module";s:10:"bx_payment";s:6:"method";s:22:"get_options_site_admin";}', 1),
+('bx_payment_extended_mode', '', @iCategoryId, '_bx_payment_option_extended_mode', 'checkbox', '', '', '', '', 11),
+('bx_payment_credits_only', '', @iCategoryId, '_bx_payment_option_credits_only', 'checkbox', '', '', '', '', 13),
+('bx_payment_single_seller', '', @iCategoryId, '_bx_payment_option_single_seller', 'checkbox', '', '', '', '', 15),
+('bx_payment_sbs_cancel_survey', '', @iCategoryId, '_bx_payment_option_sbs_cancel_survey', 'checkbox', '', '', '', '', 20);
+
+INSERT INTO `sys_options_categories` (`type_id`, `name`, `caption`, `order`)
+VALUES (@iTypeId, 'bx_payment_currency', '_bx_payment_options_category_currency', 5);
+SET @iCategoryId = LAST_INSERT_ID();
+
+INSERT INTO `sys_options` (`name`, `value`, `category_id`, `caption`, `type`, `check`, `check_params`, `check_error`, `extra`, `order`) VALUES
+('bx_payment_default_currency_code', 'USD', @iCategoryId, '_bx_payment_option_default_currency_code', 'select', 'Avail', '', '_bx_payment_option_err_default_currency_code', 'a:2:{s:6:"module";s:10:"bx_payment";s:6:"method";s:33:"get_options_default_currency_code";}', 1),
+('bx_payment_currency_exchange_api', '', @iCategoryId, '_bx_payment_option_currency_exchange_api', 'digit', '', '', '', '', 10);
+
+INSERT INTO `sys_options_categories` (`type_id`, `name`, `caption`, `order`)
+VALUES (@iTypeId, 'bx_payment_commissions', '_bx_payment_options_category_commissions', 10);
+SET @iCategoryId = LAST_INSERT_ID();
+
+INSERT INTO `sys_options` (`name`, `value`, `category_id`, `caption`, `type`, `check`, `check_params`, `check_error`, `extra`, `order`) VALUES
+('bx_payment_commissions', '', @iCategoryId, '_bx_payment_option_commissions', 'checkbox', '', '', '', '', 0),
+('bx_payment_inv_issue_day', '1', @iCategoryId, '_bx_payment_option_inv_issue_day', 'digit', '', '', '', '', 1),
+('bx_payment_inv_lifetime', '4', @iCategoryId, '_bx_payment_option_inv_lifetime', 'digit', '', '', '', '', 2),
+('bx_payment_inv_expiraction_notify', '1', @iCategoryId, '_bx_payment_option_inv_expiraction_notify', 'digit', '', '', '', '', 3);
+
+
+-- PAGES & BLOCKS
+INSERT INTO `sys_objects_page`(`object`, `title_system`, `title`, `module`, `layout_id`, `visible_for_levels`, `visible_for_levels_editable`, `uri`, `url`, `meta_description`, `meta_keywords`, `meta_robots`, `cache_lifetime`, `cache_editable`, `deletable`, `override_class_name`, `override_class_file`) VALUES
+('bx_payment_join', '_bx_payment_page_title_sys_join', '_bx_payment_page_title_join', @sName, 5, 2147483647, 1, 'payment-join', 'page.php?i=payment-join', '', '', '', 0, 1, 0, 'BxPaymentPageJoin', 'modules/boonex/payment/classes/BxPaymentPageJoin.php'),
+
+('bx_payment_carts', '_bx_payment_page_title_sys_carts', '_bx_payment_page_title_carts', @sName, 5, 2147483647, 1, 'payment-carts', 'page.php?i=payment-carts', '', '', '', 0, 1, 0, 'BxPaymentPageCart', 'modules/boonex/payment/classes/BxPaymentPageCart.php'),
+('bx_payment_cart', '_bx_payment_page_title_sys_cart', '_bx_payment_page_title_cart', @sName, 5, 2147483647, 1, 'payment-cart', 'page.php?i=payment-cart', '', '', '', 0, 1, 0, 'BxPaymentPageCart', 'modules/boonex/payment/classes/BxPaymentPageCart.php'),
+('bx_payment_cart_thank_you', '_bx_payment_page_title_sys_cart_thank_you', '_bx_payment_page_title_cart_thank_you', @sName, 5, 2147483647, 1, 'payment-cart-thank-you', 'page.php?i=payment-cart-thank-you', '', '', '', 0, 1, 0, 'BxPaymentPageCart', 'modules/boonex/payment/classes/BxPaymentPageCart.php'),
+('bx_payment_history', '_bx_payment_page_title_sys_history', '_bx_payment_page_title_history', @sName, 5, 2147483647, 1, 'payment-history', 'page.php?i=payment-history', '', '', '', 0, 1, 0, 'BxPaymentPageHistory', 'modules/boonex/payment/classes/BxPaymentPageHistory.php'),
+
+('bx_payment_sbs_list_my', '_bx_payment_page_title_sys_sbs_list_my', '_bx_payment_page_title_sbs_list_my', @sName, 5, 2147483647, 1, 'payment-sbs-list-my', 'page.php?i=payment-sbs-list-my', '', '', '', 0, 1, 0, 'BxPaymentPageSubscriptions', 'modules/boonex/payment/classes/BxPaymentPageSubscriptions.php'),
+('bx_payment_sbs_list_all', '_bx_payment_page_title_sys_sbs_list_all', '_bx_payment_page_title_sbs_list_all', @sName, 5, 192, 1, 'payment-sbs-list-all', 'page.php?i=payment-sbs-list-all', '', '', '', 0, 1, 0, 'BxPaymentPageSubscriptions', 'modules/boonex/payment/classes/BxPaymentPageSubscriptions.php'),
+('bx_payment_sbs_history', '_bx_payment_page_title_sys_sbs_history', '_bx_payment_page_title_sbs_history', @sName, 5, 2147483647, 1, 'payment-sbs-history', 'page.php?i=payment-sbs-history', '', '', '', 0, 1, 0, 'BxPaymentPageSubscriptions', 'modules/boonex/payment/classes/BxPaymentPageSubscriptions.php'),
+
+('bx_payment_orders', '_bx_payment_page_title_sys_orders', '_bx_payment_page_title_orders', @sName, 5, 2147483647, 1, 'payment-orders', 'page.php?i=payment-orders', '', '', '', 0, 1, 0, 'BxPaymentPageOrders', 'modules/boonex/payment/classes/BxPaymentPageOrders.php'),
+('bx_payment_details', '_bx_payment_page_title_sys_details', '_bx_payment_page_title_details', @sName, 5, 2147483647, 1, 'payment-details', 'page.php?i=payment-details', '', '', '', 0, 1, 0, 'BxPaymentPageDetails', 'modules/boonex/payment/classes/BxPaymentPageDetails.php'),
+
+('bx_payment_invoices', '_bx_payment_page_title_sys_invoices', '_bx_payment_page_title_invoices', @sName, 5, 2147483647, 1, 'payment-invoices', 'page.php?i=payment-invoices', '', '', '', 0, 1, 0, 'BxPaymentPageInvoices', 'modules/boonex/payment/classes/BxPaymentPageInvoices.php');
+
+INSERT INTO `sys_pages_blocks` (`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES
+('bx_payment_join', 1, @sName, '_bx_payment_page_block_title_join', 11, 2147483647, 'service', 'a:4:{s:6:"module";s:10:"bx_payment";s:6:"method";s:14:"get_block_join";s:6:"params";a:0:{}s:5:"class";s:4:"Join";}', 0, 0, 1),
+
+('bx_payment_carts', 1, @sName, '_bx_payment_page_block_title_carts', 11, 2147483647, 'service', 'a:4:{s:6:"module";s:10:"bx_payment";s:6:"method";s:15:"get_block_carts";s:6:"params";a:0:{}s:5:"class";s:4:"Cart";}', 0, 0, 1),
+('bx_payment_cart', 1, @sName, '_bx_payment_page_block_title_cart', 11, 2147483647, 'service', 'a:4:{s:6:"module";s:10:"bx_payment";s:6:"method";s:14:"get_block_cart";s:6:"params";a:0:{}s:5:"class";s:4:"Cart";}', 0, 0, 1),
+('bx_payment_cart_thank_you', 1, @sName, '_bx_payment_page_block_title_cart_thank_you', 11, 2147483647, 'lang', '_bx_payment_page_block_content_cart_thank_you', 0, 0, 1),
+('bx_payment_history', 1, @sName, '_bx_payment_page_block_title_history', 11, 2147483647, 'service', 'a:4:{s:6:"module";s:10:"bx_payment";s:6:"method";s:22:"get_block_cart_history";s:6:"params";a:0:{}s:5:"class";s:4:"Cart";}', 0, 0, 1),
+
+('bx_payment_sbs_list_my', 1, @sName, '_bx_payment_page_block_title_sbs_list_my', 11, 2147483647, 'service', 'a:4:{s:6:"module";s:10:"bx_payment";s:6:"method";s:17:"get_block_list_my";s:6:"params";a:0:{}s:5:"class";s:13:"Subscriptions";}', 0, 0, 1),
+('bx_payment_sbs_list_all', 1, @sName, '_bx_payment_page_block_title_sbs_list_all', 11, 192, 'service', 'a:4:{s:6:"module";s:10:"bx_payment";s:6:"method";s:18:"get_block_list_all";s:6:"params";a:0:{}s:5:"class";s:13:"Subscriptions";}', 0, 0, 1),
+('bx_payment_sbs_history', 1, @sName, '_bx_payment_page_block_title_sbs_history', 11, 2147483647, 'service', 'a:4:{s:6:"module";s:10:"bx_payment";s:6:"method";s:17:"get_block_history";s:6:"params";a:0:{}s:5:"class";s:13:"Subscriptions";}', 0, 0, 1),
+
+('bx_payment_orders', 1, @sName, '_bx_payment_page_block_title_orders', 11, 2147483647, 'service', 'a:4:{s:6:"module";s:10:"bx_payment";s:6:"method";s:16:"get_block_orders";s:6:"params";a:0:{}s:5:"class";s:6:"Orders";}', 0, 0, 1),
+('bx_payment_details', 1, @sName, '_bx_payment_page_block_title_details', 11, 2147483647, 'service', 'a:4:{s:6:"module";s:10:"bx_payment";s:6:"method";s:17:"get_block_details";s:6:"params";a:0:{}s:5:"class";s:7:"Details";}', 0, 0, 1),
+
+('bx_payment_invoices', 1, @sName, '_bx_payment_page_block_title_invoices', 11, 2147483647, 'service', 'a:4:{s:6:"module";s:10:"bx_payment";s:6:"method";s:18:"get_block_invoices";s:6:"params";a:0:{}s:5:"class";s:11:"Commissions";}', 0, 0, 1);
+
+-- PAGE: offline checkout
+INSERT INTO `sys_objects_page`(`object`, `uri`, `title_system`, `title`, `module`, `type_id`, `layout_id`, `visible_for_levels`, `visible_for_levels_editable`, `url`, `meta_description`, `meta_keywords`, `meta_robots`, `cache_lifetime`, `cache_editable`, `deletable`, `override_class_name`, `override_class_file`) VALUES 
+('bx_payment_checkout_offline', 'payment-checkout-offline', '_bx_payment_page_title_sys_checkout_offline', '_bx_payment_page_title_checkout_offline', 'bx_payment', 2, 5, 2147483647, 1, 'page.php?i=payment-checkout-offline', '', '', '', 0, 1, 0, '', '');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title_system`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `active`, `order`) VALUES 
+('bx_payment_checkout_offline', 1, 'bx_payment', '_bx_payment_page_block_title_sys_checkout_offline', '_bx_payment_page_block_title_checkout_offline', 0, 2147483647, 'service', 'a:2:{s:6:"module";s:10:"bx_payment";s:6:"method";s:26:"get_block_checkout_offline";}', 0, 0, 1, 0);
+
+
+-- MENU: cart submenu
+INSERT INTO `sys_objects_menu`(`object`, `title`, `title_public`, `set_name`, `module`, `template_id`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES 
+('bx_payment_menu_cart_submenu', '_bx_payment_menu_title_cart_submenu', '_bx_payment_menu_title_public_cart_submenu', 'bx_payment_menu_cart_submenu', 'bx_payment', 8, 0, 1, '', '');
+
+INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+('bx_payment_menu_cart_submenu', 'bx_payment', '_bx_payment_menu_set_title_cart_submenu', 0);
+
+INSERT INTO `sys_menu_items`(`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `addon`, `submenu_object`, `visible_for_levels`, `active`, `copyable`, `editable`, `order`) VALUES 
+('bx_payment_menu_cart_submenu', 'bx_payment', 'cart', '_bx_payment_menu_item_title_system_cart', '_bx_payment_menu_item_title_cart', 'page.php?i=payment-carts', '', '_self', '', '', '', 2147483647, 1, 0, 1, 1),
+('bx_payment_menu_cart_submenu', 'bx_payment', 'cart-history', '_bx_payment_menu_item_title_system_cart_history', '_bx_payment_menu_item_title_cart_history', 'page.php?i=payment-history', '', '_self', '', '', '', 2147483647, 1, 0, 1, 2);
+
+-- MENU: subscriptions submenu
+INSERT INTO `sys_objects_menu`(`object`, `title`, `set_name`, `module`, `template_id`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES 
+('bx_payment_menu_sbs_submenu', '_bx_payment_menu_title_sbs_submenu', 'bx_payment_menu_sbs_submenu', 'bx_payment', 6, 0, 1, '', '');
+
+INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+('bx_payment_menu_sbs_submenu', 'bx_payment', '_bx_payment_menu_set_title_sbs_submenu', 0);
+
+INSERT INTO `sys_menu_items`(`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `addon`, `submenu_object`, `visible_for_levels`, `active`, `copyable`, `editable`, `order`) VALUES 
+('bx_payment_menu_sbs_submenu', 'bx_payment', 'sbs-list-all', '_bx_payment_menu_item_title_system_sbs_list_all', '_bx_payment_menu_item_title_sbs_list_all', 'page.php?i=payment-sbs-list-all', '', '_self', '', '', '', 192, 1, 0, 1, 1),
+('bx_payment_menu_sbs_submenu', 'bx_payment', 'sbs-list-my', '_bx_payment_menu_item_title_system_sbs_list_my', '_bx_payment_menu_item_title_sbs_list_my', 'page.php?i=payment-sbs-list-my', '', '_self', '', '', '', 2147483646, 1, 0, 1, 2),
+('bx_payment_menu_sbs_submenu', 'bx_payment', 'sbs-history', '_bx_payment_menu_item_title_system_sbs_history', '_bx_payment_menu_item_title_sbs_history', 'page.php?i=payment-sbs-history', '', '_self', '', '', '', 2147483646, 1, 0, 1, 3);
+
+-- MENU: subscription actions
+INSERT INTO `sys_objects_menu`(`object`, `title`, `set_name`, `module`, `template_id`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES 
+('bx_payment_menu_sbs_actions', '_bx_payment_menu_title_sbs_actions', 'bx_payment_menu_sbs_actions', 'bx_payment', 6, 0, 1, 'BxPaymentMenuSbsActions', 'modules/boonex/payment/classes/BxPaymentMenuSbsActions.php');
+
+INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+('bx_payment_menu_sbs_actions', 'bx_payment', '_bx_payment_menu_set_title_sbs_actions', 0);
+
+INSERT INTO `sys_menu_items`(`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `addon`, `submenu_object`, `visible_for_levels`, `active`, `copyable`, `editable`, `order`) VALUES 
+('bx_payment_menu_sbs_actions', 'bx_payment', 'sbs-request-cancelation', '_bx_payment_menu_item_title_system_sbs_request_cancelation', '_bx_payment_menu_item_title_sbs_request_cancelation', 'javascript:void(0)', '{js_object}.requestCancelation(this, {id})', '_self', '', '', '', 2147483647, 1, 0, 1, 1),
+('bx_payment_menu_sbs_actions', 'bx_payment', 'sbs-cancel', '_bx_payment_menu_item_title_system_sbs_cancel', '_bx_payment_menu_item_title_sbs_cancel', 'javascript:void(0)', '{js_object}.cancel(this, {id}, \'{grid}\', 1)', '_self', '', '', '', 2147483647, 0, 0, 1, 2);
+
+-- MENU: orders submenu
+INSERT INTO `sys_objects_menu`(`object`, `title`, `set_name`, `module`, `template_id`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES 
+('bx_payment_menu_orders_submenu', '_bx_payment_menu_title_orders_submenu', 'bx_payment_menu_orders_submenu', 'bx_payment', 6, 0, 1, '', '');
+
+INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+('bx_payment_menu_orders_submenu', 'bx_payment', '_bx_payment_menu_set_title_orders_submenu', 0);
+
+INSERT INTO `sys_menu_items`(`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `addon`, `submenu_object`, `visible_for_levels`, `active`, `copyable`, `editable`, `order`) VALUES 
+('bx_payment_menu_orders_submenu', 'bx_payment', 'orders-processed', '_bx_payment_menu_item_title_system_orders_processed', '_bx_payment_menu_item_title_orders_processed', 'page.php?i=payment-orders&type=processed', '', '_self', '', '', '', 2147483647, 1, 0, 1, 1),
+('bx_payment_menu_orders_submenu', 'bx_payment', 'orders-pending', '_bx_payment_menu_item_title_system_orders_pending', '_bx_payment_menu_item_title_orders_pending', 'page.php?i=payment-orders&type=pending', '', '_self', '', '', '', 2147483647, 1, 0, 1, 2);
+
+-- MENU: account settings menu
+SET @iMoAccountSettings = (SELECT IFNULL(MAX(`order`), 0) FROM `sys_menu_items` WHERE `set_name`='sys_account_settings' AND `order` < 9999 LIMIT 1);
+INSERT INTO `sys_menu_items` (`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `addon`, `submenu_object`, `visible_for_levels`, `active`, `copyable`, `editable`, `order`) VALUES
+('sys_account_settings', 'bx_payment', 'payment-details', '_bx_payment_menu_item_title_system_details', '_bx_payment_menu_item_title_details', 'page.php?i=payment-details', '', '_self', 'credit-card', '', '', 2147483646, 1, 0, 1, @iMoAccountSettings + 1);
+
+-- MENU: dashboard manage tools
+SET @iManageMenuOrder = (SELECT IFNULL(MAX(`order`), 0) FROM `sys_menu_items` WHERE `set_name`='sys_account_dashboard_manage_tools' LIMIT 1);
+INSERT INTO `sys_menu_items`(`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `addon`, `submenu_object`, `visible_for_levels`, `active`, `copyable`, `order`) VALUES 
+('sys_account_dashboard_manage_tools', 'bx_payment', 'payment-invoices', '_bx_payment_menu_item_title_system_admt_invoices', '_bx_payment_menu_item_title_admt_invoices', 'page.php?i=payment-invoices', '', '_self', 'credit-card', 'a:2:{s:6:"module";s:10:"bx_payment";s:6:"method";s:27:"get_menu_addon_manage_tools";}', '', 192, 1, 0, @iManageMenuOrder + 1);
+
+
+-- ALERTS
+INSERT INTO `sys_alerts_handlers`(`name`, `class`, `file`, `service_call`) VALUES 
+(@sName, 'BxPaymentResponse', 'modules/boonex/payment/classes/BxPaymentResponse.php', '');
+SET @iHandler := LAST_INSERT_ID();
+
+INSERT INTO `sys_alerts` (`unit`, `action`, `handler_id`) VALUES
+('system', 'save_setting', @iHandler),
+('profile', 'join', @iHandler),
+('profile', 'delete', @iHandler);
+
+
+-- ACL
+INSERT INTO `sys_acl_actions` (`Module`, `Name`, `AdditionalParamName`, `Title`, `Desc`, `Countable`, `DisabledForLevels`) VALUES
+(@sName, 'purchase', NULL, '_bx_payment_acl_action_purchase', '', 1, 3);
+SET @iIdActionPurchase = LAST_INSERT_ID();
+
+INSERT INTO `sys_acl_actions` (`Module`, `Name`, `AdditionalParamName`, `Title`, `Desc`, `Countable`, `DisabledForLevels`) VALUES
+(@sName, 'sell', NULL, '_bx_payment_acl_action_sell', '', 1, 3);
+SET @iIdActionSell = LAST_INSERT_ID();
+
+INSERT INTO `sys_acl_actions` (`Module`, `Name`, `AdditionalParamName`, `Title`, `Desc`, `Countable`, `DisabledForLevels`) VALUES
+(@sName, 'manage any purchase', NULL, '_bx_payment_acl_action_manage_any_purchase', '', 1, 3);
+SET @iIdActionManageAnyPurchase = LAST_INSERT_ID();
+
+SET @iUnauthenticated = 1;
+SET @iAccount = 2;
+SET @iStandard = 3;
+SET @iUnconfirmed = 4;
+SET @iPending = 5;
+SET @iSuspended = 6;
+SET @iModerator = 7;
+SET @iAdministrator = 8;
+SET @iPremium = 9;
+
+INSERT INTO `sys_acl_matrix` (`IDLevel`, `IDAction`) VALUES
+
+-- purchase
+(@iStandard, @iIdActionPurchase),
+(@iModerator, @iIdActionPurchase),
+(@iAdministrator, @iIdActionPurchase),
+(@iPremium, @iIdActionPurchase),
+
+-- sell
+(@iStandard, @iIdActionSell),
+(@iModerator, @iIdActionSell),
+(@iAdministrator, @iIdActionSell),
+(@iPremium, @iIdActionSell),
+
+-- manage any purchase
+(@iModerator, @iIdActionManageAnyPurchase),
+(@iAdministrator, @iIdActionManageAnyPurchase);
+
+
+-- EMAIL TEMPLATES
+INSERT INTO `sys_email_templates` (`Module`, `NameSystem`, `Name`, `Subject`, `Body`) VALUES 
+(@sName, '_bx_payment_et_txt_name_paid_need_join', 'bx_payment_paid_need_join', '_bx_payment_et_txt_subject_paid_need_join', '_bx_payment_et_txt_body_paid_need_join'),
+(@sName, '_bx_payment_et_txt_name_cancelation_request', 'bx_payment_cancelation_request', '_bx_payment_et_txt_subject_cancelation_request', '_bx_payment_et_txt_body_cancelation_request'),
+(@sName, '_bx_payment_et_txt_name_expiration_notification_seller', 'bx_payment_expiration_notification_seller', '_bx_payment_et_txt_subject_expiration_notification_seller', '_bx_payment_et_txt_body_expiration_notification_seller'),
+(@sName, '_bx_payment_et_txt_name_expiration_notification_client', 'bx_payment_expiration_notification_client', '_bx_payment_et_txt_subject_expiration_notification_client', '_bx_payment_et_txt_body_expiration_notification_client'),
+(@sName, '_bx_payment_et_txt_name_expiring_notification_committent', 'bx_payment_expiring_notification_committent', '_bx_payment_et_txt_subject_expiring_notification_committent', '_bx_payment_et_txt_body_expiring_notification_committent'),
+(@sName, '_bx_payment_et_txt_name_overdue_notification_committent', 'bx_payment_overdue_notification_committent', '_bx_payment_et_txt_subject_overdue_notification_committent', '_bx_payment_et_txt_body_overdue_notification_committent'),
+(@sName, '_bx_payment_et_txt_name_checkout_offline', 'bx_payment_checkout_offline', '_bx_payment_et_txt_subject_checkout_offline', '_bx_payment_et_txt_body_checkout_offline'),
+(@sName, '_bx_payment_et_txt_name_wrong_balance', 'bx_payment_wrong_balance', '_bx_payment_et_txt_subject_wrong_balance', '_bx_payment_et_txt_body_wrong_balance');
+
+
+-- CRON
+INSERT INTO `sys_cron_jobs` (`name`, `time`, `class`, `file`, `service_call`) VALUES
+('bx_payment_commissions', '0 * * * *', 'BxPaymentCronCommissions', 'modules/boonex/payment/classes/BxPaymentCronCommissions.php', ''),
+('bx_payment_currency', '0 0 * * *', 'BxPaymentCronCurrency', 'modules/boonex/payment/classes/BxPaymentCronCurrency.php', ''),
+('bx_payment_time_tracker', '* * * * *', 'BxPaymentCronTimeTracker', 'modules/boonex/payment/classes/BxPaymentCronTimeTracker.php', '');
+
+
+-- PAYMENTS
+INSERT INTO `sys_objects_payments` (`object`, `title`, `uri`) VALUES
+(@sName, '_bx_payment', 'payment');

+ 701 - 0
modules/boonex/payment/updates/15.0.1_15.0.2/source/install/sql/install.sql

@@ -0,0 +1,701 @@
+SET @sName = 'bx_payment';
+
+
+-- TABLES
+CREATE TABLE IF NOT EXISTS `bx_payment_currencies` (
+  `id` int(11) NOT NULL auto_increment,
+  `code` varchar(4) NOT NULL default '',
+  `rate` float NOT NULL default '0',
+  PRIMARY KEY(`id`),
+  UNIQUE KEY `code`(`code`)
+);
+
+CREATE TABLE IF NOT EXISTS `bx_payment_providers` (
+  `id` int(11) NOT NULL auto_increment,
+  `name` varchar(64) NOT NULL default '',
+  `caption` varchar(128) NOT NULL default '',
+  `description` varchar(128) NOT NULL default '',
+  `option_prefix` varchar(32) NOT NULL default '',
+  `for_visitor` tinyint(4) NOT NULL default '0',
+  `for_owner_only` tinyint(4) NOT NULL default '0',
+  `for_single` tinyint(4) NOT NULL default '0',
+  `for_recurring` tinyint(4) NOT NULL default '0',
+  `single_seller` tinyint(4) NOT NULL default '0',
+  `time_tracker` tinyint(4) NOT NULL default '0',
+  `active` tinyint(4) NOT NULL default '0',
+  `order` tinyint(4) NOT NULL default '0',
+  `class_name` varchar(128) NOT NULL default '',
+  `class_file` varchar(255) NOT NULL  default '',
+  PRIMARY KEY(`id`)
+);
+
+CREATE TABLE IF NOT EXISTS `bx_payment_providers_options` (
+  `id` int(11) NOT NULL auto_increment,
+  `provider_id` varchar(64) NOT NULL default '',
+  `name` varchar(64) NOT NULL default '',
+  `type` varchar(64) NOT NULL default 'text',
+  `value` varchar(255) NOT NULL default '',
+  `caption` varchar(255) NOT NULL default '',
+  `description` text NOT NULL default '',
+  `extra` varchar(255) NOT NULL default '',
+  `check_type` varchar(64) NOT NULL default '',
+  `check_params` varchar(128) NOT NULL default '',
+  `check_error` varchar(128) NOT NULL default '',
+  `extended` tinyint(4) NOT NULL default '0',
+  `order` tinyint(4) NOT NULL default '0',
+  PRIMARY KEY(`id`),
+  UNIQUE KEY `name`(`name`)
+);
+
+CREATE TABLE IF NOT EXISTS `bx_payment_user_values` (
+  `id` int(11) NOT NULL auto_increment,
+  `user_id` int(11) NOT NULL default '0',
+  `option_id` int(11) NOT NULL default '0',  
+  `value` varchar(255) NOT NULL default '',
+  PRIMARY KEY(`id`),
+  UNIQUE KEY `value`(`user_id`, `option_id`)
+);
+
+CREATE TABLE IF NOT EXISTS `bx_payment_cart` (
+  `client_id` int(11) NOT NULL default '0',
+  `items` text NOT NULL default '',
+  `customs` text NOT NULL default '',
+  PRIMARY KEY(`client_id`)
+);
+
+CREATE TABLE IF NOT EXISTS `bx_payment_transactions` (
+  `id` int(11) NOT NULL auto_increment,
+  `pending_id` int(11) NOT NULL default '0',
+  `client_id` int(11) NOT NULL default '0',
+  `seller_id` int(11) NOT NULL default '0',
+  `author_id` int(11) NOT NULL default '0',
+  `module_id` int(11) NOT NULL default '0',  
+  `item_id` int(11) NOT NULL default '0',
+  `item_count` int(11) NOT NULL default '0',
+  `amount` float NOT NULL default '0',
+  `currency` varchar(4) NOT NULL default '',
+  `license` varchar(16) NOT NULL default '',
+  `date` int(11) NOT NULL default '0',
+  `new` tinyint(1) NOT NULL default '1',
+  PRIMARY KEY(`id`)
+);
+
+CREATE TABLE IF NOT EXISTS `bx_payment_subscriptions` (
+  `id` int(11) NOT NULL auto_increment,
+  `pending_id` int(11) NOT NULL default '0',
+  `customer_id` varchar(32) NOT NULL default '',
+  `subscription_id` varchar(32) NOT NULL default '',
+  `period` int(11) unsigned NOT NULL default '1',
+  `period_unit` varchar(32) NOT NULL default '',
+  `trial` int(11) unsigned NOT NULL default '0',
+  `date_add` int(11) NOT NULL default '0',
+  `date_next` int(11) NOT NULL default '0',
+  `pay_attempts` tinyint(4) NOT NULL default '0',
+  `status` varchar(32) NOT NULL default 'unpaid',
+  PRIMARY KEY(`id`),
+  UNIQUE KEY `pending_id` (`pending_id`)
+);
+
+CREATE TABLE IF NOT EXISTS `bx_payment_subscriptions_deleted` (
+  `id` int(11) NOT NULL auto_increment,
+  `pending_id` int(11) NOT NULL default '0',
+  `customer_id` varchar(32) NOT NULL default '',
+  `subscription_id` varchar(32) NOT NULL default '',
+  `period` int(11) unsigned NOT NULL default '1',
+  `period_unit` varchar(32) NOT NULL default '',
+  `trial` int(11) unsigned NOT NULL default '0',
+  `date_add` int(11) NOT NULL default '0',
+  `date_next` int(11) NOT NULL default '0',
+  `pay_attempts` tinyint(4) NOT NULL default '0',
+  `status` varchar(32) NOT NULL default 'unpaid',
+  `reason` varchar(255) NOT NULL default '',
+  `deleted` int(11) NOT NULL default '0',
+  PRIMARY KEY(`id`),
+  UNIQUE KEY `pending_id` (`pending_id`)
+);
+
+CREATE TABLE IF NOT EXISTS `bx_payment_transactions_pending` (
+  `id` int(10) unsigned NOT NULL auto_increment,
+  `client_id` int(11) NOT NULL default '0',
+  `seller_id` int(11) NOT NULL default '0',
+  `type` varchar(16) NOT NULL default 'single',
+  `provider` varchar(32) NOT NULL default '',
+  `items` text NOT NULL default '',
+  `customs` text NOT NULL default '',
+  `amount` float NOT NULL default '0',
+  `currency` varchar(4) NOT NULL default '',
+  `order` varchar(32) NOT NULL default '',
+  `data` text NOT NULL,
+  `error_code` varchar(16) NOT NULL default '',
+  `error_msg` varchar(255) NOT NULL default '',
+  `date` int(11) NOT NULL default '0',
+  `authorized` tinyint(4) NOT NULL default '0',
+  `processed` tinyint(4) NOT NULL default '0',
+  PRIMARY KEY(`id`)
+);
+
+CREATE TABLE IF NOT EXISTS `bx_payment_modules` (
+  `id` int(11) NOT NULL auto_increment,
+  `name` varchar(32) NOT NULL default '',
+  PRIMARY KEY(`id`),
+  UNIQUE KEY `uri`(`name`)
+);
+
+INSERT INTO `bx_payment_modules`(`name`) VALUES
+(@sName);
+
+CREATE TABLE IF NOT EXISTS `bx_payment_commissions` (
+  `id` int(11) NOT NULL auto_increment,
+  `name` varchar(64) NOT NULL default '',
+  `caption` varchar(128) NOT NULL default '',
+  `description` varchar(128) NOT NULL default '',
+  `acl_id` int(11) NOT NULL default '0',
+  `percentage` float NOT NULL default '0',
+  `installment` float NOT NULL default '0',
+  `active` tinyint(4) NOT NULL default '0',
+  `order` tinyint(4) NOT NULL default '0',
+  PRIMARY KEY(`id`),
+  UNIQUE KEY `name`(`name`)
+);
+
+CREATE TABLE IF NOT EXISTS `bx_payment_invoices` (
+  `id` int(11) NOT NULL auto_increment,
+  `name` varchar(64) NOT NULL default '',
+  `commissionaire_id` varchar(32) NOT NULL default '',
+  `committent_id` varchar(32) NOT NULL default '',
+  `amount` float NOT NULL default '0',
+  `currency` varchar(4) NOT NULL default '',
+  `period_start` int(11) NOT NULL default '0',
+  `period_end` int(11) NOT NULL default '0',
+  `date_issue` int(11) NOT NULL default '0',
+  `date_due` int(11) NOT NULL default '0',
+  `status` varchar(32) NOT NULL default 'unpaid',
+  `ntf_exp` tinyint(4) NOT NULL default '0',
+  `ntf_due` tinyint(4) NOT NULL default '0',
+  PRIMARY KEY(`id`),
+  UNIQUE KEY `name`(`name`)
+);
+
+CREATE TABLE IF NOT EXISTS `bx_payment_stripe_payments_pending` (
+  `id` int(11) NOT NULL auto_increment,
+  `subscription_id` varchar(32) NOT NULL default '',
+  `amount` float NOT NULL default '0',
+  `currency` varchar(4) NOT NULL default '',
+  PRIMARY KEY(`id`),
+  UNIQUE KEY `subscription_id` (`subscription_id`)
+);
+
+-- Generic payment provider
+INSERT INTO `bx_payment_providers`(`name`, `caption`, `description`, `option_prefix`, `for_visitor`, `for_single`, `for_recurring`, `single_seller`, `time_tracker`, `active`, `order`, `class_name`) VALUES
+('generic', '_bx_payment_gc_cpt', '_bx_payment_gc_dsc', 'gc_', 0, 0, 0, 0, 0, 0, 0, 'BxPaymentProviderGeneric');
+SET @iProviderId = LAST_INSERT_ID();
+
+INSERT INTO `bx_payment_providers_options`(`provider_id`, `name`, `type`, `caption`, `description`, `extra`, `check_type`, `check_params`, `check_error`, `order`) VALUES
+(@iProviderId, 'gc_currency_code', 'select', '_bx_payment_gc_currency_code_cpt', '_bx_payment_gc_currency_code_dsc', 'a:2:{s:6:"module";s:10:"bx_payment";s:6:"method";s:34:"get_options_personal_currency_code";}', '', '', '', 1);
+
+-- Offline payment provider
+INSERT INTO `bx_payment_providers`(`name`, `caption`, `description`, `option_prefix`, `for_visitor`, `for_single`, `for_recurring`, `single_seller`, `time_tracker`, `active`, `order`, `class_name`) VALUES
+('offline', '_bx_payment_off_cpt', '_bx_payment_off_dsc', 'off_', 0, 1, 0, 0, 0, 1, 5, 'BxPaymentProviderOffline');
+SET @iProviderId = LAST_INSERT_ID();
+
+INSERT INTO `bx_payment_providers_options`(`provider_id`, `name`, `type`, `caption`, `description`, `extra`, `check_type`, `check_params`, `check_error`, `order`) VALUES
+(@iProviderId, 'off_active', 'checkbox', '_bx_payment_off_active_cpt', '_bx_payment_off_active_dsc', '', '', '', '', 1),
+(@iProviderId, 'off_checkout_email', 'text', '_bx_payment_off_checkout_email_cpt', '_bx_payment_off_checkout_email_dsc', '', 'EmailOrEmpty', '', '_sys_form_account_input_email_error', 2);
+
+
+-- Credits payment provider
+INSERT INTO `bx_payment_providers`(`name`, `caption`, `description`, `option_prefix`, `for_visitor`, `for_single`, `for_recurring`, `single_seller`, `time_tracker`, `active`, `order`, `class_name`) VALUES
+('credits', '_bx_payment_cdt_cpt', '_bx_payment_cdt_dsc', 'cdt_', 0, 1, 1, 1, 1, 1, 6, 'BxPaymentProviderCredits');
+SET @iProviderId = LAST_INSERT_ID();
+
+INSERT INTO `bx_payment_providers_options`(`provider_id`, `name`, `type`, `caption`, `description`, `extra`, `check_type`, `check_params`, `check_error`, `order`) VALUES
+(@iProviderId, 'cdt_active', 'checkbox', '_bx_payment_cdt_active_cpt', '_bx_payment_cdt_active_dsc', '', '', '', '', 1);
+
+
+-- PayPal payment provider
+INSERT INTO `bx_payment_providers`(`name`, `caption`, `description`, `option_prefix`, `for_visitor`, `for_single`, `for_recurring`, `single_seller`, `active`, `order`, `class_name`) VALUES
+('paypal', '_bx_payment_pp_cpt', '_bx_payment_pp_dsc', 'pp_', 1, 1, 0, 1, 1, 10, 'BxPaymentProviderPayPal');
+SET @iProviderId = LAST_INSERT_ID();
+
+INSERT INTO `bx_payment_providers_options`(`provider_id`, `name`, `type`, `caption`, `description`, `extra`, `check_type`, `check_params`, `check_error`, `order`) VALUES
+(@iProviderId, 'pp_active', 'checkbox', '_bx_payment_pp_active_cpt', '_bx_payment_pp_active_dsc', '', '', '', '', 1),
+(@iProviderId, 'pp_mode', 'select', '_bx_payment_pp_mode_cpt', '_bx_payment_pp_mode_dsc', '1|_bx_payment_pp_mode_live,2|_bx_payment_pp_mode_test', '', '', '', 2),
+(@iProviderId, 'pp_business', 'text', '_bx_payment_pp_business_cpt', '_bx_payment_pp_business_dsc', '', 'EmailOrEmpty', '', '_bx_payment_form_input_email_err_cor_or_emp', 3),
+(@iProviderId, 'pp_prc_type', 'select', '_bx_payment_pp_prc_type_cpt', '_bx_payment_pp_prc_type_dsc', '1|_bx_payment_pp_prc_type_direct,2|_bx_payment_pp_prc_type_pdt,3|_bx_payment_pp_prc_type_ipn', '', '', '', 4),
+(@iProviderId, 'pp_token', 'text', '_bx_payment_pp_token_cpt', '_bx_payment_pp_token_dsc', '', '', '', '', 5),
+(@iProviderId, 'pp_sandbox', 'text', '_bx_payment_pp_sandbox_cpt', '_bx_payment_pp_sandbox_dsc', '', 'EmailOrEmpty', '', '_bx_payment_form_input_email_err_cor_or_emp', 6),
+(@iProviderId, 'pp_return_data_url', 'value', '_bx_payment_pp_return_data_url_cpt', '', '', '', '', '', 7);
+
+-- PayPal API payment provider
+INSERT INTO `bx_payment_providers`(`name`, `caption`, `description`, `option_prefix`, `for_visitor`, `for_single`, `for_recurring`, `single_seller`, `active`, `order`, `class_name`) VALUES
+('paypal_api', '_bx_payment_pp_api_cpt', '_bx_payment_pp_api_dsc', 'pp_api_', 1, 1, 1, 1, 1, 15, 'BxPaymentProviderPayPalApi');
+SET @iProviderId = LAST_INSERT_ID();
+
+INSERT INTO `bx_payment_providers_options`(`provider_id`, `name`, `type`, `caption`, `description`, `extra`, `check_type`, `check_params`, `check_error`, `order`) VALUES
+(@iProviderId, 'pp_api_active', 'checkbox', '_bx_payment_pp_api_active_cpt', '_bx_payment_pp_api_active_dsc', '', '', '', '', 1),
+(@iProviderId, 'pp_api_hidden', 'checkbox', '_bx_payment_pp_api_hidden_cpt', '_bx_payment_pp_api_hidden_dsc', '', '', '', '', 2),
+(@iProviderId, 'pp_api_mode', 'select', '_bx_payment_pp_api_mode_cpt', '_bx_payment_pp_api_mode_dsc', '1|_bx_payment_pp_api_mode_live,2|_bx_payment_pp_api_mode_test', '', '', '', 3),
+(@iProviderId, 'pp_api_live_account', 'text', '_bx_payment_pp_api_live_account_cpt', '_bx_payment_pp_api_live_account_dsc', '', 'EmailOrEmpty', '', '_bx_payment_form_input_email_err_cor_or_emp', 4),
+(@iProviderId, 'pp_api_live_client_id', 'text', '_bx_payment_pp_api_live_client_id_cpt', '_bx_payment_pp_api_live_client_id_dsc', '', '', '', '', 5),
+(@iProviderId, 'pp_api_live_secret', 'text', '_bx_payment_pp_api_live_secret_cpt', '_bx_payment_pp_api_live_secret_dsc', '', '', '', '', 6),
+(@iProviderId, 'pp_api_test_account', 'text', '_bx_payment_pp_api_test_account_cpt', '_bx_payment_pp_api_test_account_dsc', '', 'EmailOrEmpty', '', '_bx_payment_form_input_email_err_cor_or_emp', 7),
+(@iProviderId, 'pp_api_test_client_id', 'text', '_bx_payment_pp_api_test_client_id_cpt', '_bx_payment_pp_api_test_client_id_dsc', '', '', '', '', 8),
+(@iProviderId, 'pp_api_test_secret', 'text', '_bx_payment_pp_api_test_secret_cpt', '_bx_payment_pp_api_test_secret_dsc', '', '', '', '', 9),
+(@iProviderId, 'pp_api_return_data_url', 'value', '_bx_payment_pp_api_return_data_url_cpt', '', '', '', '', '', 10),
+(@iProviderId, 'pp_api_notify_url', 'value', '_bx_payment_pp_api_notify_url_cpt', '', '', '', '', '', 11);
+
+-- Chargebee payment provider
+INSERT INTO `bx_payment_providers`(`name`, `caption`, `description`, `option_prefix`, `for_visitor`, `for_single`, `for_recurring`, `active`, `order`, `class_name`) VALUES
+('chargebee', '_bx_payment_cbee_cpt', '_bx_payment_cbee_dsc', 'cbee_', 1, 0, 1, 1, 40, 'BxPaymentProviderChargebee');
+SET @iProviderId = LAST_INSERT_ID();
+
+INSERT INTO `bx_payment_providers_options`(`provider_id`, `name`, `type`, `caption`, `description`, `extra`, `check_type`, `check_params`, `check_error`, `order`) VALUES
+(@iProviderId, 'cbee_active', 'checkbox', '_bx_payment_cbee_active_cpt', '_bx_payment_cbee_active_dsc', '', '', '', '', 1),
+(@iProviderId, 'cbee_hidden', 'checkbox', '_bx_payment_cbee_hidden_cpt', '_bx_payment_cbee_hidden_dsc', '', '', '', '', 2),
+(@iProviderId, 'cbee_mode', 'select', '_bx_payment_cbee_mode_cpt', '_bx_payment_cbee_mode_dsc', '1|_bx_payment_cbee_mode_live,2|_bx_payment_cbee_mode_test', '', '', '', 3),
+(@iProviderId, 'cbee_live_site', 'text', '_bx_payment_cbee_live_site_cpt', '_bx_payment_cbee_live_site_dsc', '', '', '', '', 4),
+(@iProviderId, 'cbee_live_api_key', 'text', '_bx_payment_cbee_live_api_key_cpt', '_bx_payment_cbee_live_api_key_dsc', '', '', '', '', 5),
+(@iProviderId, 'cbee_test_site', 'text', '_bx_payment_cbee_test_site_cpt', '_bx_payment_cbee_test_site_dsc', '', '', '', '', 6),
+(@iProviderId, 'cbee_test_api_key', 'text', '_bx_payment_cbee_test_api_key_cpt', '_bx_payment_cbee_test_api_key_dsc', '', '', '', '', 7),
+(@iProviderId, 'cbee_check_amount', 'checkbox', '_bx_payment_cbee_check_amount_cpt', '_bx_payment_cbee_check_amount_dsc', '', '', '', '', 8),
+(@iProviderId, 'cbee_ssl', 'checkbox', '_bx_payment_cbee_ssl_cpt', '_bx_payment_cbee_ssl_dsc', '', '', '', '', 9),
+(@iProviderId, 'cbee_cancellation_email', 'text', '_bx_payment_cbee_cancellation_email_cpt', '', '', 'EmailOrEmpty', '', '_bx_payment_form_input_email_err_cor_or_emp', 10),
+(@iProviderId, 'cbee_expiration_email', 'text', '_bx_payment_cbee_expiration_email_cpt', '', '', 'EmailOrEmpty', '', '_bx_payment_form_input_email_err_cor_or_emp', 11),
+(@iProviderId, 'cbee_return_data_url', 'value', '_bx_payment_cbee_return_data_url_cpt', '', '', '', '', '', 12),
+(@iProviderId, 'cbee_notify_url', 'value', '_bx_payment_cbee_notify_url_cpt', '', '', '', '', '', 13);
+
+-- Chargebee V3 payment provider
+INSERT INTO `bx_payment_providers`(`name`, `caption`, `description`, `option_prefix`, `for_visitor`, `for_single`, `for_recurring`, `active`, `order`, `class_name`) VALUES
+('chargebee_v3', '_bx_payment_cbee_v3_cpt', '_bx_payment_cbee_v3_dsc', 'cbee_v3_', 1, 1, 1, 1, 41, 'BxPaymentProviderChargebeeV3');
+SET @iProviderId = LAST_INSERT_ID();
+
+INSERT INTO `bx_payment_providers_options`(`provider_id`, `name`, `type`, `caption`, `description`, `extra`, `check_type`, `check_params`, `check_error`, `order`) VALUES
+(@iProviderId, 'cbee_v3_active', 'checkbox', '_bx_payment_cbee_active_cpt', '_bx_payment_cbee_active_dsc', '', '', '', '', 1),
+(@iProviderId, 'cbee_v3_hidden', 'checkbox', '_bx_payment_cbee_hidden_cpt', '_bx_payment_cbee_hidden_dsc', '', '', '', '', 2),
+(@iProviderId, 'cbee_v3_mode', 'select', '_bx_payment_cbee_mode_cpt', '_bx_payment_cbee_mode_dsc', '1|_bx_payment_cbee_mode_live,2|_bx_payment_cbee_mode_test', '', '', '', 3),
+(@iProviderId, 'cbee_v3_live_site', 'text', '_bx_payment_cbee_live_site_cpt', '_bx_payment_cbee_live_site_dsc', '', '', '', '', 4),
+(@iProviderId, 'cbee_v3_live_api_key', 'text', '_bx_payment_cbee_live_api_key_cpt', '_bx_payment_cbee_live_api_key_dsc', '', '', '', '', 5),
+(@iProviderId, 'cbee_v3_test_site', 'text', '_bx_payment_cbee_test_site_cpt', '_bx_payment_cbee_test_site_dsc', '', '', '', '', 6),
+(@iProviderId, 'cbee_v3_test_api_key', 'text', '_bx_payment_cbee_test_api_key_cpt', '_bx_payment_cbee_test_api_key_dsc', '', '', '', '', 7),
+(@iProviderId, 'cbee_v3_check_amount', 'checkbox', '_bx_payment_cbee_check_amount_cpt', '_bx_payment_cbee_check_amount_dsc', '', '', '', '', 8),
+(@iProviderId, 'cbee_v3_ssl', 'checkbox', '_bx_payment_cbee_ssl_cpt', '_bx_payment_cbee_ssl_dsc', '', '', '', '', 9),
+(@iProviderId, 'cbee_v3_cancellation_email', 'text', '_bx_payment_cbee_cancellation_email_cpt', '', '', 'EmailOrEmpty', '', '_bx_payment_form_input_email_err_cor_or_emp', 10),
+(@iProviderId, 'cbee_v3_expiration_email', 'text', '_bx_payment_cbee_expiration_email_cpt', '', '', 'EmailOrEmpty', '', '_bx_payment_form_input_email_err_cor_or_emp', 11),
+(@iProviderId, 'cbee_v3_return_data_url', 'value', '_bx_payment_cbee_return_data_url_cpt', '', '', '', '', '', 12),
+(@iProviderId, 'cbee_v3_notify_url', 'value', '_bx_payment_cbee_notify_url_cpt', '', '', '', '', '', 13);
+
+-- Stripe payment provider
+INSERT INTO `bx_payment_providers`(`name`, `caption`, `description`, `option_prefix`, `for_visitor`, `for_single`, `for_recurring`, `active`, `order`, `class_name`) VALUES
+('stripe', '_bx_payment_strp_cpt', '_bx_payment_strp_dsc', 'strp_', 1, 1, 1, 1, 60, 'BxPaymentProviderStripe');
+SET @iProviderId = LAST_INSERT_ID();
+
+INSERT INTO `bx_payment_providers_options`(`provider_id`, `name`, `type`, `caption`, `description`, `extra`, `check_type`, `check_params`, `check_error`, `order`) VALUES
+(@iProviderId, 'strp_active', 'checkbox', '_bx_payment_strp_active_cpt', '_bx_payment_strp_active_dsc', '', '', '', '', 1),
+(@iProviderId, 'strp_hidden', 'checkbox', '_bx_payment_strp_hidden_cpt', '_bx_payment_strp_hidden_dsc', '', '', '', '', 2),
+(@iProviderId, 'strp_mode', 'select', '_bx_payment_strp_mode_cpt', '_bx_payment_strp_mode_dsc', '1|_bx_payment_strp_mode_live,2|_bx_payment_strp_mode_test', '', '', '', 3),
+(@iProviderId, 'strp_live_pub_key', 'text', '_bx_payment_strp_live_pub_key_cpt', '_bx_payment_strp_live_pub_key_dsc', '', '', '', '', 4),
+(@iProviderId, 'strp_live_sec_key', 'text', '_bx_payment_strp_live_sec_key_cpt', '_bx_payment_strp_live_sec_key_dsc', '', '', '', '', 5),
+(@iProviderId, 'strp_test_pub_key', 'text', '_bx_payment_strp_test_pub_key_cpt', '_bx_payment_strp_test_pub_key_dsc', '', '', '', '', 6),
+(@iProviderId, 'strp_test_sec_key', 'text', '_bx_payment_strp_test_sec_key_cpt', '_bx_payment_strp_test_sec_key_dsc', '', '', '', '', 7),
+(@iProviderId, 'strp_check_amount', 'checkbox', '_bx_payment_strp_check_amount_cpt', '_bx_payment_strp_check_amount_dsc', '', '', '', '', 8),
+(@iProviderId, 'strp_ssl', 'checkbox', '_bx_payment_strp_ssl_cpt', '_bx_payment_strp_ssl_dsc', '', '', '', '', 9),
+(@iProviderId, 'strp_cancellation_email', 'text', '_bx_payment_strp_cancellation_email_cpt', '', '', 'EmailOrEmpty', '', '_bx_payment_form_input_email_err_cor_or_emp', 10),
+(@iProviderId, 'strp_expiration_email', 'text', '_bx_payment_strp_expiration_email_cpt', '', '', 'EmailOrEmpty', '', '_bx_payment_form_input_email_err_cor_or_emp', 11),
+(@iProviderId, 'strp_notify_url', 'value', '_bx_payment_strp_notify_url_cpt', '', '', '', '', '', 12);
+
+-- Stripe V3 payment provider (with 3D Secure authentication for Strong Customer Authentication (SCA) support)
+INSERT INTO `bx_payment_providers`(`name`, `caption`, `description`, `option_prefix`, `for_visitor`, `for_single`, `for_recurring`, `active`, `order`, `class_name`) VALUES
+('stripe_v3', '_bx_payment_strp_v3_cpt', '_bx_payment_strp_v3_dsc', 'strp_v3_', 1, 1, 1, 1, 61, 'BxPaymentProviderStripeV3');
+SET @iProviderId = LAST_INSERT_ID();
+
+INSERT INTO `bx_payment_providers_options`(`provider_id`, `name`, `type`, `value`, `caption`, `description`, `extra`, `check_type`, `check_params`, `check_error`, `extended`, `order`) VALUES
+(@iProviderId, 'strp_v3_active', 'checkbox', 'on', '_bx_payment_strp_active_cpt', '_bx_payment_strp_active_dsc', '', '', '', '', 2, 1),
+(@iProviderId, 'strp_v3_hidden', 'checkbox', '', '_bx_payment_strp_hidden_cpt', '_bx_payment_strp_hidden_dsc', '', '', '', '', 1, 2),
+(@iProviderId, 'strp_v3_mode', 'select', '1', '_bx_payment_strp_mode_cpt', '_bx_payment_strp_mode_dsc', '1|_bx_payment_strp_mode_live,2|_bx_payment_strp_mode_test', '', '', '', 2, 3),
+(@iProviderId, 'strp_v3_live_pub_key', 'text', '', '_bx_payment_strp_live_pub_key_cpt', '_bx_payment_strp_live_pub_key_dsc', '', '', '', '', 0, 4),
+(@iProviderId, 'strp_v3_live_sec_key', 'text', '', '_bx_payment_strp_live_sec_key_cpt', '_bx_payment_strp_live_sec_key_dsc', '', '', '', '', 0, 5),
+(@iProviderId, 'strp_v3_test_pub_key', 'text', '', '_bx_payment_strp_test_pub_key_cpt', '_bx_payment_strp_test_pub_key_dsc', '', '', '', '', 1, 6),
+(@iProviderId, 'strp_v3_test_sec_key', 'text', '', '_bx_payment_strp_test_sec_key_cpt', '_bx_payment_strp_test_sec_key_dsc', '', '', '', '', 1, 7),
+(@iProviderId, 'strp_v3_check_amount', 'checkbox', '', '_bx_payment_strp_check_amount_cpt', '_bx_payment_strp_check_amount_dsc', '', '', '', '', 1, 8),
+(@iProviderId, 'strp_v3_ssl', 'checkbox', 'on', '_bx_payment_strp_ssl_cpt', '_bx_payment_strp_ssl_dsc', '', '', '', '', 1, 9),
+(@iProviderId, 'strp_v3_cancellation_email', 'text', '', '_bx_payment_strp_cancellation_email_cpt', '', '', 'EmailOrEmpty', '', '_bx_payment_form_input_email_err_cor_or_emp', 0, 10),
+(@iProviderId, 'strp_v3_expiration_email', 'text', '', '_bx_payment_strp_expiration_email_cpt', '', '', 'EmailOrEmpty', '', '_bx_payment_form_input_email_err_cor_or_emp', 1, 11),
+(@iProviderId, 'strp_v3_notify_url', 'value', '', '_bx_payment_strp_notify_url_cpt', '', '', '', '', '', 0, 12);
+
+-- Stripe Connect payment provider
+INSERT INTO `bx_payment_providers`(`name`, `caption`, `description`, `option_prefix`, `for_visitor`, `for_single`, `for_recurring`, `active`, `order`, `class_name`) VALUES
+('stripe_connect', '_bx_payment_strp_cnnt_cpt', '_bx_payment_strp_cnnt_dsc', 'strp_cnnt_', 1, 1, 1, 1, 65, 'BxPaymentProviderStripeConnect');
+SET @iProviderId = LAST_INSERT_ID();
+
+INSERT INTO `bx_payment_providers_options`(`provider_id`, `name`, `type`, `value`, `caption`, `description`, `extra`, `check_type`, `check_params`, `check_error`, `extended`, `order`) VALUES
+(@iProviderId, 'strp_cnnt_mode', 'value', '', '_bx_payment_strp_mode_cpt', '', '', '', '', '', 0, 1),
+(@iProviderId, 'strp_cnnt_connect', 'custom', '', '_bx_payment_strp_cnnt_connect_cpt', '', '', '', '', '', 0, 2),
+(@iProviderId, 'strp_cnnt_live_account_id', 'value', '', '_bx_payment_strp_cnnt_live_account_id_cpt', '', '', '', '', '', 0, 3),
+(@iProviderId, 'strp_cnnt_test_account_id', 'value', '', '_bx_payment_strp_cnnt_test_account_id_cpt', '', '', '', '', '', 1, 4);
+
+-- Apple In-App payment provider
+INSERT INTO `bx_payment_providers`(`name`, `caption`, `description`, `option_prefix`, `for_visitor`, `for_owner_only`, `for_single`, `for_recurring`, `active`, `order`, `class_name`) VALUES
+('apple_in_app', '_bx_payment_aina_cpt', '_bx_payment_aina_dsc', 'aina_', 0, 1, 1, 1, 1, 70, 'BxPaymentProviderAppleInApp');
+SET @iProviderId = LAST_INSERT_ID();
+
+INSERT INTO `bx_payment_providers_options`(`provider_id`, `name`, `type`, `caption`, `description`, `extra`, `check_type`, `check_params`, `check_error`, `order`) VALUES
+(@iProviderId, 'aina_active', 'checkbox', '_bx_payment_aina_active_cpt', '_bx_payment_aina_active_dsc', '', '', '', '', 1),
+(@iProviderId, 'aina_hidden', 'checkbox', '_bx_payment_aina_hidden_cpt', '_bx_payment_aina_hidden_dsc', '', '', '', '', 2),
+(@iProviderId, 'aina_secret', 'text', '_bx_payment_aina_secret_cpt', '_bx_payment_aina_secret_dsc', '', '', '', '', 3),
+(@iProviderId, 'aina_notify_url', 'value', '_bx_payment_aina_notify_url_cpt', '', '', '', '', '', 4);
+
+-- GRIDS
+INSERT INTO `sys_objects_grid` (`object`, `source_type`, `source`, `table`, `field_id`, `field_order`, `field_active`, `paginate_url`, `paginate_per_page`, `paginate_simple`, `paginate_get_start`, `paginate_get_per_page`, `filter_fields`, `filter_fields_translatable`, `filter_mode`, `sorting_fields`, `sorting_fields_translatable`, `visible_for_levels`, `show_total_count`, `override_class_name`, `override_class_file`) VALUES
+('bx_payment_grid_providers', 'Sql', 'SELECT * FROM `bx_payment_providers` WHERE 1 ', 'bx_payment_providers', 'id', 'order', 'active', '', 100, NULL, 'start', '', 'name', 'caption,description', 'auto', '', '', 192, 0, 'BxPaymentGridProviders', 'modules/boonex/payment/classes/BxPaymentGridProviders.php'),
+
+('bx_payment_grid_carts', 'Array', '', '', 'vendor_id', '', '', '', 20, NULL, 'start', '', '', '', 'like', '', '', 2147483647, 1, 'BxPaymentGridCarts', 'modules/boonex/payment/classes/BxPaymentGridCarts.php'),
+('bx_payment_grid_cart', 'Array', '', '', 'descriptor', '', '', '', 20, NULL, 'start', '', 'title,description', '', 'like', '', '', 2147483647, 1, 'BxPaymentGridCart', 'modules/boonex/payment/classes/BxPaymentGridCart.php'),
+
+('bx_payment_grid_sbs_list_my', 'Sql', 'SELECT `ttp`.`id` AS `id`, `ttp`.`client_id` AS `client_id`, `ttp`.`seller_id` AS `seller_id`, `ttp`.`items` AS `items`, `ts`.`date_add` AS `date_add`, `ts`.`date_next` AS `date_next`, `ts`.`status` AS `status`, `ts`.`reason` AS `reason` FROM (SELECT `id`, `pending_id`, `customer_id`, `subscription_id`, `date_add`, `date_next`, `status`, '''' AS `reason` FROM `bx_payment_subscriptions` UNION SELECT `id`, `pending_id`, `customer_id`, `subscription_id`, `date_add`, `date_next`, ''canceled'' AS `status`, `reason` FROM `bx_payment_subscriptions_deleted`) AS `ts` LEFT JOIN `bx_payment_transactions_pending` AS `ttp` ON `ts`.`pending_id`=`ttp`.`id` WHERE 1 AND `ttp`.`type`=''recurring'' ', 'bx_payment_subscriptions', 'id', 'date_add', '', '', 100, NULL, 'start', '', 'ts`.`customer_id,ts`.`subscription_id,ts`.`date_add', '', 'auto', '', '', 2147483647, 0, 'BxPaymentGridSbsList', 'modules/boonex/payment/classes/BxPaymentGridSbsList.php'),
+('bx_payment_grid_sbs_list_all', 'Sql', 'SELECT `ttp`.`id` AS `id`, `ttp`.`client_id` AS `client_id`, `tac`.`email` AS `client_email`, `ttp`.`seller_id` AS `seller_id`, `ttp`.`items` AS `items`, `ts`.`date_add` AS `date_add`, `ts`.`date_next` AS `date_next`, `ts`.`status` AS `status`, `ts`.`reason` AS `reason` FROM (SELECT `id`, `pending_id`, `customer_id`, `subscription_id`, `date_add`, `date_next`, `status`, '''' AS `reason` FROM `bx_payment_subscriptions` UNION SELECT `id`, `pending_id`, `customer_id`, `subscription_id`, `date_add`, `date_next`, ''canceled'' AS `status`, `reason` FROM `bx_payment_subscriptions_deleted`) AS `ts` LEFT JOIN `bx_payment_transactions_pending` AS `ttp` ON `ts`.`pending_id`=`ttp`.`id` LEFT JOIN `sys_profiles` AS `tpc` ON `ttp`.`client_id`=`tpc`.`id` LEFT JOIN `sys_accounts` AS `tac` ON `tpc`.`account_id`=`tac`.`id` WHERE 1 AND `ttp`.`type`=''recurring'' ', 'bx_payment_subscriptions', 'id', 'date_add', '', '', 100, NULL, 'start', '', 'tac`.`email,ts`.`customer_id,ts`.`subscription_id,ts`.`date_add', '', 'auto', '', '', 192, 0, 'BxPaymentGridSbsAdministration', 'modules/boonex/payment/classes/BxPaymentGridSbsAdministration.php'),
+('bx_payment_grid_sbs_history', 'Sql', 'SELECT `tt`.`id` AS `id`, `ttp`.`client_id` AS `client_id`, `tt`.`seller_id` AS `seller_id`, `tt`.`module_id` AS `module_id`, `tt`.`item_id` AS `item_id`, `tt`.`item_count` AS `item_count`, `tt`.`amount` AS `amount`, `tt`.`currency` AS `currency`, `tt`.`date` AS `date` FROM `bx_payment_transactions` AS `tt` LEFT JOIN `bx_payment_transactions_pending` AS `ttp` ON `tt`.`pending_id`=`ttp`.`id` WHERE 1 AND `ttp`.`type`=''recurring'' ', 'bx_payment_transactions', 'id', 'date', '', '', 100, NULL, 'start', '', 'ttp`.`order,tt`.`license,tt`.`amount,tt`.`date', '', 'auto', '', '', 2147483647, 0, 'BxPaymentGridSbsHistory', 'modules/boonex/payment/classes/BxPaymentGridSbsHistory.php'),
+
+('bx_payment_grid_orders_history', 'Sql', 'SELECT `tt`.`id` AS `id`, `tt`.`seller_id` AS `seller_id`, `tt`.`module_id` AS `module_id`, `tt`.`item_id` AS `item_id`, `ttp`.`order` AS `transaction`, `tt`.`license` AS `license`, `tt`.`amount` AS `amount`, `tt`.`currency` AS `currency`, `tt`.`date` AS `date` FROM `bx_payment_transactions` AS `tt` LEFT JOIN `bx_payment_transactions_pending` AS `ttp` ON `tt`.`pending_id`=`ttp`.`id` WHERE 1 AND `ttp`.`type`=''single'' ', 'bx_payment_transactions', 'id', 'date', '', '', 100, NULL, 'start', '', 'ttp`.`order,tt`.`license,tt`.`amount,tt`.`date', '', 'auto', '', '', 2147483647, 0, 'BxPaymentGridHistory', 'modules/boonex/payment/classes/BxPaymentGridHistory.php'),
+('bx_payment_grid_orders_processed', 'Sql', 'SELECT `tt`.`id` AS `id`, `tt`.`client_id` AS `client_id`, `tt`.`seller_id` AS `seller_id`, `tt`.`author_id` AS `author_id`, `tt`.`module_id` AS `module_id`, `tt`.`item_id` AS `item_id`, `tt`.`item_count` AS `item_count`, `ttp`.`order` AS `transaction`, `ttp`.`error_msg` AS `error_msg`, `ttp`.`provider` AS `provider`, `tt`.`license` AS `license`, `tt`.`amount` AS `amount`, `tt`.`currency` AS `currency`, `tt`.`date` AS `date` FROM `bx_payment_transactions` AS `tt` LEFT JOIN `bx_payment_transactions_pending` AS `ttp` ON `tt`.`pending_id`=`ttp`.`id` LEFT JOIN `sys_profiles` AS `tup` ON `tt`.`client_id`=`tup`.`id` LEFT JOIN `sys_accounts` AS `tua` ON `tup`.`account_id`=`tua`.`id` WHERE 1 ', 'bx_payment_transactions', 'id', 'date', '', '', 100, NULL, 'start', '', 'ttp`.`order,tt`.`license,tt`.`amount,tt`.`date,tua`.`name,tua`.`email', '', 'auto', '', '', 2147483647, 0, 'BxPaymentGridProcessed', 'modules/boonex/payment/classes/BxPaymentGridProcessed.php'),
+('bx_payment_grid_orders_pending', 'Sql', 'SELECT `tt`.`id` AS `id`, `tt`.`client_id` AS `client_id`, `tt`.`seller_id` AS `seller_id`, `tt`.`items` AS `items`, `tt`.`amount` AS `amount`, `tt`.`currency` AS `currency`, `tt`.`order` AS `transaction`, `tt`.`error_msg` AS `error_msg`, `tt`.`provider` AS `provider`, `tt`.`date` AS `date` FROM `bx_payment_transactions_pending` AS `tt` LEFT JOIN `sys_profiles` AS `tup` ON `tt`.`client_id`=`tup`.`id` LEFT JOIN `sys_accounts` AS `tua` ON `tup`.`account_id`=`tua`.`id` WHERE 1 AND (ISNULL(`tt`.`order`) OR (NOT ISNULL(`tt`.`order`) AND `tt`.`error_code`<>''0'')) ', 'bx_payment_transactions_pending', 'id', 'date', '', '', 100, NULL, 'start', '', 'tt`.`order,tt`.`amount,tt`.`date,tua`.`name,tua`.`email', '', 'auto', '', '', 2147483647, 0, 'BxPaymentGridPending', 'modules/boonex/payment/classes/BxPaymentGridPending.php'),
+
+('bx_payment_grid_commissions', 'Sql', 'SELECT * FROM `bx_payment_commissions` WHERE 1 ', 'bx_payment_commissions', 'id', 'order', 'active', '', 100, NULL, 'start', '', 'name', 'caption,description', 'auto', '', '', 192, 1, 'BxPaymentGridCommissions', 'modules/boonex/payment/classes/BxPaymentGridCommissions.php'),
+('bx_payment_grid_invoices', 'Sql', 'SELECT * FROM `bx_payment_invoices` WHERE 1 ', 'bx_payment_invoices', 'id', '', '', '', 100, NULL, 'start', '', '', '', 'auto', '', '', 2147483647, 1, 'BxPaymentGridInvoices', 'modules/boonex/payment/classes/BxPaymentGridInvoices.php');
+
+INSERT INTO `sys_grid_fields` (`object`, `name`, `title`, `width`, `translatable`, `chars_limit`, `params`, `order`) VALUES
+('bx_payment_grid_providers', 'order', '', '2%', 0, '0', '', 1),
+('bx_payment_grid_providers', 'switcher', '', '8%', 0, '0', '', 2),
+('bx_payment_grid_providers', 'caption', '_bx_payment_grid_column_title_pdrs_caption', '20%', 1, '16', '', 3),
+('bx_payment_grid_providers', 'description', '_bx_payment_grid_column_title_pdrs_description', '30%', 1, '32', '', 4),
+('bx_payment_grid_providers', 'for_visitor', '_bx_payment_grid_column_title_pdrs_for_visitor', '8%', 0, '8', '', 5),
+('bx_payment_grid_providers', 'for_single', '_bx_payment_grid_column_title_pdrs_for_single', '8%', 0, '8', '', 6),
+('bx_payment_grid_providers', 'for_recurring', '_bx_payment_grid_column_title_pdrs_for_recurring', '8%', 0, '8', '', 7),
+('bx_payment_grid_providers', 'single_seller', '_bx_payment_grid_column_title_pdrs_single_seller', '8%', 0, '8', '', 8),
+('bx_payment_grid_providers', 'time_tracker', '_bx_payment_grid_column_title_pdrs_time_tracker', '8%', 0, '8', '', 9),
+
+('bx_payment_grid_carts', 'checkbox', '', '2%', 0, '', '', 1),
+('bx_payment_grid_carts', 'vendor_id', '_bx_payment_grid_column_title_crts_vendor_id', '40%', 0, '36', '', 2),
+('bx_payment_grid_carts', 'items_count', '_bx_payment_grid_column_title_crts_items_count', '20%', 0, '16', '', 3),
+('bx_payment_grid_carts', 'items_price', '_bx_payment_grid_column_title_crts_items_price', '20%', 0, '16', '', 4),
+('bx_payment_grid_carts', 'actions', '', '18%', 0, '', '', 5),
+
+('bx_payment_grid_cart', 'checkbox', '', '2%', 0, '', '', 1),
+('bx_payment_grid_cart', 'title', '_bx_payment_grid_column_title_crt_title', '25%', 0, '24', '', 2),
+('bx_payment_grid_cart', 'description', '_bx_payment_grid_column_title_crt_description', '35%', 0, '48', '', 3),
+('bx_payment_grid_cart', 'quantity', '_bx_payment_grid_column_title_crt_quantity', '10%', 0, '16', '', 4),
+('bx_payment_grid_cart', 'price_single', '_bx_payment_grid_column_title_crt_price', '10%', 0, '16', '', 5),
+('bx_payment_grid_cart', 'actions', '', '18%', 0, '', '', 6),
+
+('bx_payment_grid_sbs_list_my', 'checkbox', '', '2%', 0, '0', '', 1),
+('bx_payment_grid_sbs_list_my', 'seller_id', '_bx_payment_grid_column_title_sbs_seller_id', '16%', 0, '0', '', 2),
+('bx_payment_grid_sbs_list_my', 'items', '_bx_payment_grid_column_title_sbs_items', '30%', 0, '', '', 3),
+('bx_payment_grid_sbs_list_my', 'date_add', '_bx_payment_grid_column_title_sbs_date_add', '14%', 0, '10', '', 4),
+('bx_payment_grid_sbs_list_my', 'date_next', '_bx_payment_grid_column_title_sbs_date_next', '14%', 0, '10', '', 5),
+('bx_payment_grid_sbs_list_my', 'status', '_bx_payment_grid_column_title_sbs_status', '6%', 0, '8', '', 6),
+('bx_payment_grid_sbs_list_my', 'actions', '', '18%', 0, '0', '', 7),
+
+('bx_payment_grid_sbs_list_all', 'seller_id', '_bx_payment_grid_column_title_sbs_seller_id', '12%', 0, '0', '', 1),
+('bx_payment_grid_sbs_list_all', 'client_id', '_bx_payment_grid_column_title_sbs_client_id', '12%', 0, '0', '', 2),
+('bx_payment_grid_sbs_list_all', 'client_email', '_bx_payment_grid_column_title_sbs_client_email', '15%', 0, '24', '', 3),
+('bx_payment_grid_sbs_list_all', 'items', '_bx_payment_grid_column_title_sbs_items', '15%', 0, '', '', 4),
+('bx_payment_grid_sbs_list_all', 'date_add', '_bx_payment_grid_column_title_sbs_date_add', '12%', 0, '10', '', 5),
+('bx_payment_grid_sbs_list_all', 'date_next', '_bx_payment_grid_column_title_sbs_date_next', '12%', 0, '10', '', 6),
+('bx_payment_grid_sbs_list_all', 'status', '_bx_payment_grid_column_title_sbs_status', '6%', 0, '8', '', 7),
+('bx_payment_grid_sbs_list_all', 'actions', '', '16%', 0, '0', '', 8),
+
+('bx_payment_grid_sbs_history', 'seller_id', '_bx_payment_grid_column_title_sbs_seller_id', '24%', 0, '0', '', 1),
+('bx_payment_grid_sbs_history', 'item_id', '_bx_payment_grid_column_title_sbs_item_id', '44%', 0, '', '', 2),
+('bx_payment_grid_sbs_history', 'amount', '_bx_payment_grid_column_title_sbs_amount', '10%', 1, '10', '', 3),
+('bx_payment_grid_sbs_history', 'date', '_bx_payment_grid_column_title_sbs_date', '10%', 0, '10', '', 4),
+('bx_payment_grid_sbs_history', 'actions', '', '12%', 0, '', '', 5),
+
+('bx_payment_grid_orders_history', 'seller_id', '_bx_payment_grid_column_title_ods_seller_id', '24%', 0, '0', '', 1),
+('bx_payment_grid_orders_history', 'transaction', '_bx_payment_grid_column_title_ods_transaction', '22%', 0, '18', '', 2),
+('bx_payment_grid_orders_history', 'item', '_bx_payment_grid_column_title_ods_item', '22%', 0, '18', '', 3),
+('bx_payment_grid_orders_history', 'amount', '_bx_payment_grid_column_title_ods_amount', '10%', 1, '10', '', 4),
+('bx_payment_grid_orders_history', 'date', '_bx_payment_grid_column_title_ods_date', '10%', 0, '10', '', 5),
+('bx_payment_grid_orders_history', 'actions', '', '12%', 0, '', '', 6),
+
+('bx_payment_grid_orders_processed', 'checkbox', '', '2%', 0, '0', '', 1),
+('bx_payment_grid_orders_processed', 'client_id', '_bx_payment_grid_column_title_ods_client_id', '16%', 0, '0', '', 2),
+('bx_payment_grid_orders_processed', 'author_id', '_bx_payment_grid_column_title_ods_author_id', '16%', 0, '0', '', 3),
+('bx_payment_grid_orders_processed', 'transaction', '_bx_payment_grid_column_title_ods_transaction', '10%', 0, '8', '', 4),
+('bx_payment_grid_orders_processed', 'item', '_bx_payment_grid_column_title_ods_item', '20%', 0, '', '', 5),
+('bx_payment_grid_orders_processed', 'amount', '_bx_payment_grid_column_title_ods_amount', '10%', 1, '10', '', 6),
+('bx_payment_grid_orders_processed', 'date', '_bx_payment_grid_column_title_ods_date', '10%', 0, '10', '', 7),
+('bx_payment_grid_orders_processed', 'actions', '', '16%', 0, '0', '', 8),
+
+('bx_payment_grid_orders_pending', 'checkbox', '', '2%', 0, '', '', 1),
+('bx_payment_grid_orders_pending', 'client_id', '_bx_payment_grid_column_title_ods_client_id', '25%', 0, '0', '', 2),
+('bx_payment_grid_orders_pending', 'transaction', '_bx_payment_grid_column_title_ods_transaction', '25%', 0, '25', '', 3),
+('bx_payment_grid_orders_pending', 'amount', '_bx_payment_grid_column_title_ods_amount', '14%', 1, '14', '', 4),
+('bx_payment_grid_orders_pending', 'date', '_bx_payment_grid_column_title_ods_date', '14%', 0, '14', '', 5),
+('bx_payment_grid_orders_pending', 'actions', '', '20%', 0, '', '', 6),
+
+('bx_payment_grid_commissions', 'order', '', '2%', 0, '0', '', 1),
+('bx_payment_grid_commissions', 'switcher', '', '8%', 0, '0', '', 2),
+('bx_payment_grid_commissions', 'caption', '_bx_payment_grid_column_title_cms_caption', '15%', 1, '16', '', 3),
+('bx_payment_grid_commissions', 'description', '_bx_payment_grid_column_title_cms_description', '20%', 1, '16', '', 4),
+('bx_payment_grid_commissions', 'acl_id', '_bx_payment_grid_column_title_cms_acl_id', '15%', 0, '16', '', 5),
+('bx_payment_grid_commissions', 'percentage', '_bx_payment_grid_column_title_cms_percentage', '10%', 0, '0', '', 6),
+('bx_payment_grid_commissions', 'installment', '_bx_payment_grid_column_title_cms_installment', '10%', 0, '0', '', 7),
+('bx_payment_grid_commissions', 'actions', '', '20%', 0, '0', '', 8),
+
+('bx_payment_grid_invoices', 'checkbox', '', '2%', 0, '0', '', 1),
+('bx_payment_grid_invoices', 'commissionaire_id', '_bx_payment_grid_column_title_inv_commissionaire_id', '10%', 1, '0', '', 2),
+('bx_payment_grid_invoices', 'committent_id', '_bx_payment_grid_column_title_inv_committent_id', '10%', 1, '0', '', 3),
+('bx_payment_grid_invoices', 'name', '_bx_payment_grid_column_title_inv_name', '8%', 1, '0', '', 4),
+('bx_payment_grid_invoices', 'period_start', '_bx_payment_grid_column_title_inv_period_start', '10%', 0, '0', '', 5),
+('bx_payment_grid_invoices', 'period_end', '_bx_payment_grid_column_title_inv_period_end', '10%', 0, '0', '', 6),
+('bx_payment_grid_invoices', 'amount', '_bx_payment_grid_column_title_inv_amount', '6%', 0, '0', '', 7),
+('bx_payment_grid_invoices', 'date_issue', '_bx_payment_grid_column_title_inv_date_issue', '10%', 0, '0', '', 8),
+('bx_payment_grid_invoices', 'date_due', '_bx_payment_grid_column_title_inv_date_due', '10%', 0, '0', '', 9),
+('bx_payment_grid_invoices', 'status', '_bx_payment_grid_column_title_inv_status', '6%', 0, '8', '', 10),
+('bx_payment_grid_invoices', 'actions', '', '18%', 0, '0', '', 11);
+
+INSERT INTO `sys_grid_actions` (`object`, `type`, `name`, `title`, `icon`, `icon_only`, `confirm`, `order`) VALUES
+('bx_payment_grid_carts', 'bulk', 'delete', '_bx_payment_grid_action_title_crts_delete', '', 0, 1, 1),
+('bx_payment_grid_carts', 'single', 'continue', '_bx_payment_grid_action_title_crts_continue', 'far credit-card', 1, 0, 1),
+('bx_payment_grid_carts', 'single', 'delete', '_bx_payment_grid_action_title_crts_delete', 'remove', 1, 1, 2),
+
+('bx_payment_grid_cart', 'bulk', 'checkout', '_bx_payment_grid_action_title_crt_checkout', '', 0, 0, 1),
+('bx_payment_grid_cart', 'single', 'delete', '_bx_payment_grid_action_title_crt_delete', 'remove', 1, 1, 1),
+('bx_payment_grid_cart', 'single', 'quantity_sub', '_bx_payment_grid_action_title_crt_quantity_sub', 'minus', 1, 0, 2),
+('bx_payment_grid_cart', 'single', 'quantity_add', '_bx_payment_grid_action_title_crt_quantity_add', 'plus', 1, 0, 3),
+
+('bx_payment_grid_sbs_list_my', 'single', 'view_order', '_bx_payment_grid_action_title_sbs_view_order', 'ellipsis-h', 1, 0, 1),
+('bx_payment_grid_sbs_list_my', 'single', 'actions', '_bx_payment_grid_action_title_sbs_actions', 'cog', 1, 0, 2),
+
+('bx_payment_grid_sbs_list_all', 'single', 'view_order', '_bx_payment_grid_action_title_sbs_view_order', 'ellipsis-h', 1, 0, 1),
+('bx_payment_grid_sbs_list_all', 'single', 'cancel', '_bx_payment_grid_action_title_sbs_cancel', 'ban', 1, 1, 2),
+('bx_payment_grid_sbs_list_all', 'single', 'delete', '_bx_payment_grid_action_title_sbs_delete', 'times', 1, 1, 3),
+
+('bx_payment_grid_sbs_history', 'single', 'view_order', '_bx_payment_grid_action_title_sbs_view_order', 'ellipsis-h', 1, 0, 1),
+
+('bx_payment_grid_orders_history', 'single', 'view_order', '_bx_payment_grid_action_title_ods_view_order', 'ellipsis-h', 1, 0, 1),
+
+('bx_payment_grid_orders_processed', 'independent', 'add', '_bx_payment_grid_action_title_ods_add', '', 0, 0, 1),
+('bx_payment_grid_orders_processed', 'bulk', 'cancel', '_bx_payment_grid_action_title_ods_cancel', '', 0, 1, 1),
+('bx_payment_grid_orders_processed', 'single', 'view_order', '_bx_payment_grid_action_title_ods_view_order', 'ellipsis-h', 1, 0, 1),
+('bx_payment_grid_orders_processed', 'single', 'cancel', '_bx_payment_grid_action_title_ods_cancel', 'times', 1, 1, 2),
+
+('bx_payment_grid_orders_pending', 'bulk', 'cancel', '_bx_payment_grid_action_title_ods_cancel', '', 0, 1, 1),
+('bx_payment_grid_orders_pending', 'single', 'view_order', '_bx_payment_grid_action_title_ods_view_order', 'ellipsis-h', 1, 0, 1),
+('bx_payment_grid_orders_pending', 'single', 'process', '_bx_payment_grid_action_title_ods_process', 'sync', 1, 0, 2),
+('bx_payment_grid_orders_pending', 'single', 'cancel', '_bx_payment_grid_action_title_ods_cancel', 'times', 1, 1, 3),
+
+('bx_payment_grid_commissions', 'independent', 'add', '_bx_payment_grid_action_title_cms_add', '', 0, 0, 1),
+('bx_payment_grid_commissions', 'bulk', 'delete', '_bx_payment_grid_action_title_cms_delete', '', 0, 1, 1),
+('bx_payment_grid_commissions', 'single', 'edit', '_bx_payment_grid_action_title_cms_edit', 'pencil-alt', 1, 0, 1),
+('bx_payment_grid_commissions', 'single', 'delete', '_bx_payment_grid_action_title_cms_delete', 'remove', 1, 1, 2),
+
+('bx_payment_grid_invoices', 'bulk', 'delete', '_bx_payment_grid_action_title_inv_delete', '', 0, 1, 1),
+('bx_payment_grid_invoices', 'single', 'pay', '_bx_payment_grid_action_title_inv_pay', 'credit-card', 1, 0, 1),
+('bx_payment_grid_invoices', 'single', 'edit', '_bx_payment_grid_action_title_inv_edit', 'pencil-alt', 1, 0, 2),
+('bx_payment_grid_invoices', 'single', 'delete', '_bx_payment_grid_action_title_inv_delete', 'remove', 1, 1, 3);
+
+
+-- FORMS
+INSERT INTO `sys_objects_form` (`object`, `module`, `title`, `action`, `form_attrs`, `submit_name`, `table`, `key`, `uri`, `uri_title`, `params`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES
+('bx_payment_form_details', @sName, '_bx_payment_form_details_form', '', '', 'submit', '', 'id', '', '', 'a:1:{s:14:"checker_helper";s:33:"BxPaymentDetailsFormCheckerHelper";}', 0, 1, 'BxPaymentFormDetails', 'modules/boonex/payment/classes/BxPaymentFormDetails.php'),
+
+('bx_payment_form_pendings', @sName, '_bx_payment_form_pendings_form', '', '', 'do_submit', 'bx_payment_transactions_pending', 'id', '', '', '', 0, 1, 'BxPaymentFormView', 'modules/boonex/payment/classes/BxPaymentFormView.php'),
+('bx_payment_form_processed', @sName, '_bx_payment_form_processed_form', '', '', 'do_submit', 'bx_payment_transactions', 'id', '', '', '', 0, 1, 'BxPaymentFormView', 'modules/boonex/payment/classes/BxPaymentFormView.php'),
+
+('bx_payment_form_commissions', @sName, '_bx_payment_form_commissions_form', '', '', 'do_submit', 'bx_payment_commissions', 'id', '', '', '', 0, 1, 'BxPaymentFormCommissions', 'modules/boonex/payment/classes/BxPaymentFormCommissions.php'),
+('bx_payment_form_invoices', @sName, '_bx_payment_form_invoices_form', '', '', 'do_submit', 'bx_payment_invoices', 'id', '', '', '', 0, 1, 'BxPaymentFormInvoices', 'modules/boonex/payment/classes/BxPaymentFormInvoices.php'),
+
+-- FORMS: Recurly
+('bx_payment_form_rcrl_card', @sName, '_bx_payment_form_rcrl_card', '', '', 'do_submit', '', '', '', '', '', 0, 1, '', ''),
+
+-- FORMS: Stripe
+('bx_payment_form_strp_details', @sName, '_bx_payment_form_strp_details', '', '', 'do_submit', '', '', '', '', '', 0, 1, '', ''),
+('bx_payment_form_strp_card', @sName, '_bx_payment_form_strp_card', '', '', 'do_submit', '', '', '', '', '', 0, 1, '', '');
+
+
+INSERT INTO `sys_form_displays` (`display_name`, `module`, `object`, `title`, `view_mode`) VALUES
+('bx_payment_form_details_edit', @sName, 'bx_payment_form_details', '_bx_payment_form_details_display_edit', 0),
+
+('bx_payment_form_pendings_process', @sName, 'bx_payment_form_pendings', '_bx_payment_form_pendings_display_process', 0),
+('bx_payment_form_processed_add', @sName, 'bx_payment_form_processed', '_bx_payment_form_processed_display_add', 0),
+
+('bx_payment_form_commissions_add', @sName, 'bx_payment_form_commissions', '_bx_payment_form_commissions_display_add', 0),
+('bx_payment_form_commissions_edit', @sName, 'bx_payment_form_commissions', '_bx_payment_form_commissions_display_edit', 0),
+
+('bx_payment_form_invoices_edit', @sName, 'bx_payment_form_invoices', '_bx_payment_form_invoices_display_edit', 0),
+
+-- FORMS: Recurly
+('bx_payment_form_rcrl_card_add', @sName, 'bx_payment_form_rcrl_card', '_bx_payment_form_rcrl_card_display_add', 0),
+
+-- FORMS: Stripe
+('bx_payment_form_strp_details_edit', @sName, 'bx_payment_form_strp_details', '_bx_payment_form_strp_details_display_edit', 0),
+('bx_payment_form_strp_card_add', @sName, 'bx_payment_form_strp_card', '_bx_payment_form_strp_card_display_add', 0);
+
+INSERT INTO `sys_form_inputs` (`object`, `module`, `name`, `value`, `values`, `checked`, `type`, `caption_system`, `caption`, `info`, `required`, `collapsed`, `html`, `attrs`, `attrs_tr`, `attrs_wrapper`, `checker_func`, `checker_params`, `checker_error`, `db_pass`, `db_params`, `editable`, `deletable`) VALUES
+('bx_payment_form_pendings', @sName, 'id', '0', '', 0, 'hidden', '_bx_payment_form_pendings_input_id_sys', '', '', 0, 0, 0, '', '', '', '', '', '', 'Int', '', 0, 0),
+('bx_payment_form_pendings', @sName, 'seller_id', '0', '', 0, 'hidden', '_bx_payment_form_pendings_input_seller_id_sys', '', '', 0, 0, 0, '', '', '', '', '', '', 'Int', '', 0, 0),
+('bx_payment_form_pendings', @sName, 'order', '', '', 0, 'text', '_bx_payment_form_pendings_input_order_sys', '_bx_payment_form_pendings_input_order', '', 1, 0, 0, '', '', '', 'Avail', '', '_bx_payment_form_pendings_input_order_err', 'Xss', '', 0, 0),
+('bx_payment_form_pendings', @sName, 'controls', '', 'do_submit,do_cancel', 0, 'input_set', '', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 0, 0),
+('bx_payment_form_pendings', @sName, 'do_submit', '_bx_payment_form_pendings_input_process', '', 0, 'submit', '_bx_payment_form_pendings_input_process_sys', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 0, 0),
+('bx_payment_form_pendings', @sName, 'do_cancel', '_bx_payment_form_pendings_input_cancel', '', 0, 'button', '_bx_payment_form_pendings_input_cancel_sys', '', '', 0, 0, 0, 'a:2:{s:7:"onclick";s:45:"$(''.bx-popup-applied:visible'').dolPopupHide()";s:5:"class";s:22:"bx-def-margin-sec-left";}', '', '', '', '', '', '', '', 0, 0),
+
+('bx_payment_form_processed', @sName, 'seller_id', '0', '', 0, 'hidden', '_bx_payment_form_processed_input_seller_id_sys', '', '', 0, 0, 0, '', '', '', '', '', '', 'Int', '', 0, 0),
+('bx_payment_form_processed', @sName, 'client_id', '0', '', 0, 'hidden', '_bx_payment_form_processed_input_client_id_sys', '', '', 0, 0, 0, '', '', '', '', '', '', 'Int', '', 0, 0),
+('bx_payment_form_processed', @sName, 'client', '0', '', 0, 'custom', '_bx_payment_form_processed_input_client_sys', '_bx_payment_form_processed_input_client', '', 0, 0, 0, '', '', '', 'Avail', '', '_bx_payment_form_processed_input_client_err', 'Xss', '', 0, 0),
+('bx_payment_form_processed', @sName, 'order', '0', '', 0, 'text', '_bx_payment_form_processed_input_order_sys', '_bx_payment_form_processed_input_order', '', 0, 0, 0, '', '', '', 'Avail', '', '_bx_payment_form_processed_input_order_err', 'Xss', '', 0, 0),
+('bx_payment_form_processed', @sName, 'module_id', '0', '', 0, 'select', '_bx_payment_form_processed_input_module_id_sys', '_bx_payment_form_processed_input_module_id', '', 0, 0, 0, '', '', '', 'Avail', '', '_bx_payment_form_processed_input_module_id_err', 'Int', '', 0, 0),
+('bx_payment_form_processed', @sName, 'items', '0', '', 0, 'custom', '_bx_payment_form_processed_input_items_sys', '_bx_payment_form_processed_input_items', '', 0, 0, 0, '', '', '', '', '', '_bx_payment_form_processed_input_items_err', '', '', 0, 0),
+('bx_payment_form_processed', @sName, 'controls', '', 'do_submit,do_cancel', 0, 'input_set', '', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 0, 0),
+('bx_payment_form_processed', @sName, 'do_submit', '_bx_payment_form_processed_input_add', '', 0, 'submit', '_bx_payment_form_processed_input_add_sys', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 0, 0),
+('bx_payment_form_processed', @sName, 'do_cancel', '_bx_payment_form_processed_input_cancel', '', 0, 'button', '_bx_payment_form_processed_input_cancel_sys', '', '', 0, 0, 0, 'a:2:{s:7:"onclick";s:45:"$(''.bx-popup-applied:visible'').dolPopupHide()";s:5:"class";s:22:"bx-def-margin-sec-left";}', '', '', '', '', '', '', '', 0, 0),
+
+('bx_payment_form_commissions', @sName, 'caption', '0', '', 0, 'text_translatable', '_bx_payment_form_commissions_input_caption_sys', '_bx_payment_form_commissions_input_caption', '', 1, 0, 0, '', '', '', 'AvailTranslatable', 'a:1:{i:0;s:7:"caption";}', '_bx_payment_form_commissions_input_caption_err', 'Xss', '', 0, 0),
+('bx_payment_form_commissions', @sName, 'description', '0', '', 0, 'textarea_translatable', '_bx_payment_form_commissions_input_description_sys', '_bx_payment_form_commissions_input_description', '', 0, 0, 0, '', '', '', '', '', '', 'Xss', '', 0, 0),
+('bx_payment_form_commissions', @sName, 'acl_id', '0', '', 0, 'select', '_bx_payment_form_commissions_input_acl_id_sys', '_bx_payment_form_commissions_input_acl_id', '', 0, 0, 0, '', '', '', '', '', '', 'Int', '', 0, 0),
+('bx_payment_form_commissions', @sName, 'percentage', '0', '', 0, 'text', '_bx_payment_form_commissions_input_percentage_sys', '_bx_payment_form_commissions_input_percentage', '', 0, 0, 0, '', '', '', '', '', '', 'Float', '', 0, 0),
+('bx_payment_form_commissions', @sName, 'installment', '0', '', 0, 'text', '_bx_payment_form_commissions_input_installment_sys', '_bx_payment_form_commissions_input_installment', '', 0, 0, 0, '', '', '', '', '', '', 'Float', '', 0, 0),
+('bx_payment_form_commissions', @sName, 'controls', '', 'do_submit,do_cancel', 0, 'input_set', '', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 0, 0),
+('bx_payment_form_commissions', @sName, 'do_submit', '_bx_payment_form_commissions_input_submit', '', 0, 'submit', '_bx_payment_form_commissions_input_submit_sys', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 0, 0),
+('bx_payment_form_commissions', @sName, 'do_cancel', '_bx_payment_form_commissions_input_cancel', '', 0, 'button', '_bx_payment_form_commissions_input_cancel_sys', '', '', 0, 0, 0, 'a:2:{s:7:"onclick";s:45:"$(''.bx-popup-applied:visible'').dolPopupHide()";s:5:"class";s:22:"bx-def-margin-sec-left";}', '', '', '', '', '', '', '', 0, 0),
+
+('bx_payment_form_invoices', @sName, 'amount', '0', '', 0, 'text', '_bx_payment_form_invoices_input_amount_sys', '_bx_payment_form_invoices_input_amount', '', 1, 0, 0, '', '', '', 'Avail', '', '_bx_payment_form_invoices_input_amount_err', 'Float', '', 0, 0),
+('bx_payment_form_invoices', @sName, 'date_due', '', '', 0, 'datepicker', '_bx_payment_form_invoices_input_date_due_sys', '_bx_payment_form_invoices_input_date_due', '', 1, 0, 0, '', '', '', 'Avail', '', '_bx_payment_form_invoices_input_date_due_err', 'DateUtc', '', 0, 0),
+('bx_payment_form_invoices', @sName, 'status', '', '', 0, 'select', '_bx_payment_form_invoices_input_status_sys', '_bx_payment_form_invoices_input_status', '', 0, 0, 0, '', '', '', '', '', '', 'Xss', '', 0, 0),
+('bx_payment_form_invoices', @sName, 'controls', '', 'do_submit,do_cancel', 0, 'input_set', '', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 0, 0),
+('bx_payment_form_invoices', @sName, 'do_submit', '_bx_payment_form_invoices_input_submit', '', 0, 'submit', '_bx_payment_form_invoices_input_submit_sys', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 0, 0),
+('bx_payment_form_invoices', @sName, 'do_cancel', '_bx_payment_form_invoices_input_cancel', '', 0, 'button', '_bx_payment_form_invoices_input_cancel_sys', '', '', 0, 0, 0, 'a:2:{s:7:"onclick";s:45:"$(''.bx-popup-applied:visible'').dolPopupHide()";s:5:"class";s:22:"bx-def-margin-sec-left";}', '', '', '', '', '', '', '', 0, 0),
+
+-- FORMS: Recurly
+('bx_payment_form_rcrl_card', @sName, 'pending_id', '0', '', 0, 'hidden', '_bx_payment_form_rcrl_card_input_pending_id_sys', '', '', 0, 0, 0, '', '', '', '', '', '', 'Int', '', 0, 0),
+('bx_payment_form_rcrl_card', @sName, 'item', '', '', 0, 'hidden', '_bx_payment_form_rcrl_card_input_item_sys', '', '', 0, 0, 0, '', '', '', '', '', '', 'Xss', '', 0, 0),
+('bx_payment_form_rcrl_card', @sName, 'token', '', '', 0, 'hidden', '_bx_payment_form_rcrl_card_input_token_sys', '', '', 0, 0, 0, 'a:1:{s:12:"data-recurly";s:5:"token";}', '', '', '', '', '', 'Xss', '', 0, 0),
+('bx_payment_form_rcrl_card', @sName, 'first_name', '', '', 0, 'text', '_bx_payment_form_rcrl_card_input_first_name_sys', '_bx_payment_form_rcrl_card_input_first_name', '', 1, 0, 0, 'a:1:{s:12:"data-recurly";s:10:"first_name";}', '', '', 'Avail', '', '_bx_payment_form_rcrl_card_input_first_name_err', 'Xss', '', 0, 0),
+('bx_payment_form_rcrl_card', @sName, 'last_name', '', '', 0, 'text', '_bx_payment_form_rcrl_card_input_last_name_sys', '_bx_payment_form_rcrl_card_input_last_name', '', 1, 0, 0, 'a:1:{s:12:"data-recurly";s:9:"last_name";}', '', '', 'Avail', '', '_bx_payment_form_rcrl_card_input_last_name_err', 'Xss', '', 0, 0),
+('bx_payment_form_rcrl_card', @sName, 'email', '', '', 0, 'text', '_bx_payment_form_rcrl_card_input_email_sys', '_bx_payment_form_rcrl_card_input_email', '', 1, 0, 0, '', '', '', 'Email', '', '', 'Xss', '', 0, 0),
+('bx_payment_form_rcrl_card', @sName, 'card_number', '', '', 0, 'custom', '_bx_payment_form_rcrl_card_input_card_number_sys', '_bx_payment_form_rcrl_card_input_card_number', '_bx_payment_form_rcrl_card_input_card_number_inf', 1, 0, 0, 'a:1:{s:12:"data-recurly";s:6:"number";}', '', '', '', '', '', 'Xss', '', 0, 0),
+('bx_payment_form_rcrl_card', @sName, 'card_expire', '', '', 0, 'custom', '_bx_payment_form_rcrl_card_input_card_expire_sys', '_bx_payment_form_rcrl_card_input_card_expire', '_bx_payment_form_rcrl_card_input_card_expire_inf', 1, 0, 0, '', '', '', '', '', '', 'Xss', '', 0, 0),
+('bx_payment_form_rcrl_card', @sName, 'card_cvv', '', '', 0, 'custom', '_bx_payment_form_rcrl_card_input_card_cvv_sys', '_bx_payment_form_rcrl_card_input_card_cvv', '_bx_payment_form_rcrl_card_input_card_cvv_inf', 1, 0, 0, 'a:1:{s:12:"data-recurly";s:3:"cvv";}', '', '', '', '', '', 'Xss', '', 0, 0),
+('bx_payment_form_rcrl_card', @sName, 'controls', '', 'do_submit,do_cancel', 0, 'input_set', '', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 0, 0),
+('bx_payment_form_rcrl_card', @sName, 'do_submit', '_bx_payment_form_rcrl_card_input_submit', '', 0, 'submit', '_bx_payment_form_rcrl_card_input_submit_sys', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 0, 0),
+('bx_payment_form_rcrl_card', @sName, 'do_cancel', '_bx_payment_form_rcrl_card_input_cancel', '', 0, 'button', '_bx_payment_form_rcrl_card_input_cancel_sys', '', '', 0, 0, 0, 'a:2:{s:7:"onclick";s:45:"$(''.bx-popup-applied:visible'').dolPopupHide()";s:5:"class";s:22:"bx-def-margin-sec-left";}', '', '', '', '', '', '', '', 0, 0),
+
+-- FORMS: Stripe
+('bx_payment_form_strp_details', @sName, 'item_id', '', '', 0, 'select', '_bx_payment_form_strp_details_input_item_id_sys', '_bx_payment_form_strp_details_input_item_id', '', 1, 0, 0, '', '', '', 'Avail', '', '_bx_payment_form_strp_details_input_item_id_err', 'Int', '', 0, 0),
+('bx_payment_form_strp_details', @sName, 'controls', '', 'do_submit,do_cancel', 0, 'input_set', '', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 0, 0),
+('bx_payment_form_strp_details', @sName, 'do_submit', '_bx_payment_form_strp_details_input_submit', '', 0, 'submit', '_bx_payment_form_strp_details_input_submit_sys', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 0, 0),
+('bx_payment_form_strp_details', @sName, 'do_cancel', '_bx_payment_form_strp_details_input_cancel', '', 0, 'button', '_bx_payment_form_strp_details_input_cancel_sys', '', '', 0, 0, 0, 'a:2:{s:7:"onclick";s:45:"$(''.bx-popup-applied:visible'').dolPopupHide()";s:5:"class";s:22:"bx-def-margin-sec-left";}', '', '', '', '', '', '', '', 0, 0),
+
+('bx_payment_form_strp_card', @sName, 'card_number', '', '', 0, 'text', '_bx_payment_form_strp_card_input_card_number_sys', '_bx_payment_form_strp_card_input_card_number', '_bx_payment_form_strp_card_input_card_number_inf', 1, 0, 0, '', '', '', 'Avail', '', '_bx_payment_form_strp_card_input_card_number_err', 'Xss', '', 0, 0),
+('bx_payment_form_strp_card', @sName, 'card_expire', '', '', 0, 'text', '_bx_payment_form_strp_card_input_card_expire_sys', '_bx_payment_form_strp_card_input_card_expire', '_bx_payment_form_strp_card_input_card_expire_inf', 1, 0, 0, '', '', '', 'Avail', '', '_bx_payment_form_strp_card_input_card_expire_err', 'Xss', '', 0, 0),
+('bx_payment_form_strp_card', @sName, 'card_cvv', '', '', 0, 'text', '_bx_payment_form_strp_card_input_card_cvv_sys', '_bx_payment_form_strp_card_input_card_cvv', '_bx_payment_form_strp_card_input_card_cvv_inf', 1, 0, 0, '', '', '', 'Avail', '', '_bx_payment_form_strp_card_input_card_cvv_err', 'Xss', '', 0, 0),
+('bx_payment_form_strp_card', @sName, 'controls', '', 'do_submit,do_cancel', 0, 'input_set', '', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 0, 0),
+('bx_payment_form_strp_card', @sName, 'do_submit', '_bx_payment_form_strp_card_input_submit', '', 0, 'submit', '_bx_payment_form_strp_card_input_submit_sys', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 0, 0),
+('bx_payment_form_strp_card', @sName, 'do_cancel', '_bx_payment_form_strp_card_input_cancel', '', 0, 'button', '_bx_payment_form_strp_card_input_cancel_sys', '', '', 0, 0, 0, 'a:2:{s:7:"onclick";s:45:"$(''.bx-popup-applied:visible'').dolPopupHide()";s:5:"class";s:22:"bx-def-margin-sec-left";}', '', '', '', '', '', '', '', 0, 0);
+
+
+INSERT INTO `sys_form_display_inputs` (`display_name`, `input_name`, `visible_for_levels`, `active`, `order`) VALUES
+('bx_payment_form_pendings_process', 'id', 2147483647, 1, 1),
+('bx_payment_form_pendings_process', 'seller_id', 2147483647, 1, 2),
+('bx_payment_form_pendings_process', 'order', 2147483647, 1, 3),
+('bx_payment_form_pendings_process', 'controls', 2147483647, 1, 4),
+('bx_payment_form_pendings_process', 'do_submit', 2147483647, 1, 5),
+('bx_payment_form_pendings_process', 'do_cancel', 2147483647, 1, 6),
+
+('bx_payment_form_processed_add', 'seller_id', 2147483647, 1, 2),
+('bx_payment_form_processed_add', 'client_id', 2147483647, 1, 3),
+('bx_payment_form_processed_add', 'client', 2147483647, 1, 4),
+('bx_payment_form_processed_add', 'order', 2147483647, 1, 5),
+('bx_payment_form_processed_add', 'module_id', 2147483647, 1, 6),
+('bx_payment_form_processed_add', 'items', 2147483647, 1, 7),
+('bx_payment_form_processed_add', 'controls', 2147483647, 1, 8),
+('bx_payment_form_processed_add', 'do_submit', 2147483647, 1, 9),
+('bx_payment_form_processed_add', 'do_cancel', 2147483647, 1, 10),
+
+('bx_payment_form_commissions_add', 'caption', 2147483647, 1, 1),
+('bx_payment_form_commissions_add', 'description', 2147483647, 1, 2),
+('bx_payment_form_commissions_add', 'acl_id', 2147483647, 1, 3),
+('bx_payment_form_commissions_add', 'percentage', 2147483647, 1, 4),
+('bx_payment_form_commissions_add', 'installment', 2147483647, 1, 5),
+('bx_payment_form_commissions_add', 'controls', 2147483647, 1, 6),
+('bx_payment_form_commissions_add', 'do_submit', 2147483647, 1, 7),
+('bx_payment_form_commissions_add', 'do_cancel', 2147483647, 1, 8),
+
+('bx_payment_form_commissions_edit', 'caption', 2147483647, 1, 1),
+('bx_payment_form_commissions_edit', 'description', 2147483647, 1, 2),
+('bx_payment_form_commissions_edit', 'acl_id', 2147483647, 1, 3),
+('bx_payment_form_commissions_edit', 'percentage', 2147483647, 1, 4),
+('bx_payment_form_commissions_edit', 'installment', 2147483647, 1, 5),
+('bx_payment_form_commissions_edit', 'controls', 2147483647, 1, 6),
+('bx_payment_form_commissions_edit', 'do_submit', 2147483647, 1, 7),
+('bx_payment_form_commissions_edit', 'do_cancel', 2147483647, 1, 8),
+
+('bx_payment_form_invoices_edit', 'amount', 2147483647, 1, 1),
+('bx_payment_form_invoices_edit', 'date_due', 2147483647, 1, 2),
+('bx_payment_form_invoices_edit', 'status', 2147483647, 1, 3),
+('bx_payment_form_invoices_edit', 'controls', 2147483647, 1, 4),
+('bx_payment_form_invoices_edit', 'do_submit', 2147483647, 1, 5),
+('bx_payment_form_invoices_edit', 'do_cancel', 2147483647, 1, 6),
+
+-- FORMS: Recurly
+('bx_payment_form_rcrl_card_add', 'pending_id', 2147483647, 1, 1),
+('bx_payment_form_rcrl_card_add', 'item', 2147483647, 1, 2),
+('bx_payment_form_rcrl_card_add', 'token', 2147483647, 1, 3),
+('bx_payment_form_rcrl_card_add', 'first_name', 2147483647, 1, 4),
+('bx_payment_form_rcrl_card_add', 'last_name', 2147483647, 1, 5),
+('bx_payment_form_rcrl_card_add', 'email', 2147483647, 1, 6),
+('bx_payment_form_rcrl_card_add', 'card_number', 2147483647, 1, 7),
+('bx_payment_form_rcrl_card_add', 'card_expire', 2147483647, 1, 8),
+('bx_payment_form_rcrl_card_add', 'card_cvv', 2147483647, 1, 9),
+('bx_payment_form_rcrl_card_add', 'controls', 2147483647, 1, 10),
+('bx_payment_form_rcrl_card_add', 'do_submit', 2147483647, 1, 11),
+('bx_payment_form_rcrl_card_add', 'do_cancel', 2147483647, 1, 12),
+
+-- FORMS: Stripe
+('bx_payment_form_strp_details_edit', 'item_id', 2147483647, 1, 1),
+('bx_payment_form_strp_details_edit', 'controls', 2147483647, 1, 2),
+('bx_payment_form_strp_details_edit', 'do_submit', 2147483647, 1, 3),
+('bx_payment_form_strp_details_edit', 'do_cancel', 2147483647, 1, 4),
+
+('bx_payment_form_strp_card_add', 'card_number', 2147483647, 1, 1),
+('bx_payment_form_strp_card_add', 'card_expire', 2147483647, 1, 2),
+('bx_payment_form_strp_card_add', 'card_cvv', 2147483647, 1, 3),
+('bx_payment_form_strp_card_add', 'controls', 2147483647, 1, 4),
+('bx_payment_form_strp_card_add', 'do_submit', 2147483647, 1, 5),
+('bx_payment_form_strp_card_add', 'do_cancel', 2147483647, 1, 6);
+
+
+-- PRE-VALUES
+INSERT INTO `sys_form_pre_lists`(`key`, `title`, `module`, `use_for_sets`, `extendable`) VALUES
+('bx_payment_currencies', '_bx_payment_pre_lists_currencies', 'bx_payment', '0', '0');
+
+INSERT INTO `sys_form_pre_values`(`Key`, `Value`, `Order`, `LKey`, `LKey2`) VALUES
+('bx_payment_currencies', 'AUD', 1, 'AUD', 'A&#36;'),
+('bx_payment_currencies', 'CAD', 2, 'CAD', 'C&#36;'),
+('bx_payment_currencies', 'EUR', 3, 'EUR', '&#8364;'),
+('bx_payment_currencies', 'GBP', 4, 'GBP', '&#163;'),
+('bx_payment_currencies', 'USD', 5, 'USD', '&#36;'),
+('bx_payment_currencies', 'JPY', 6, 'YEN', '&#165;');
+
+INSERT INTO `sys_form_pre_lists`(`key`, `title`, `module`, `use_for_sets`, `extendable`) VALUES
+('bx_payment_reasons_cancel', '_bx_payment_pre_lists_reasons_cancel', 'bx_payment', '0', '1');
+
+INSERT INTO `sys_form_pre_values`(`Key`, `Value`, `Order`, `LKey`, `LKey2`) VALUES
+('bx_payment_reasons_cancel', 'rc_0', 7, '_bx_payment_pre_values_rc_0', ''),
+('bx_payment_reasons_cancel', 'rc_1', 1, '_bx_payment_pre_values_rc_1', ''),
+('bx_payment_reasons_cancel', 'rc_2', 2, '_bx_payment_pre_values_rc_2', ''),
+('bx_payment_reasons_cancel', 'rc_3', 3, '_bx_payment_pre_values_rc_3', ''),
+('bx_payment_reasons_cancel', 'rc_4', 4, '_bx_payment_pre_values_rc_4', ''),
+('bx_payment_reasons_cancel', 'rc_5', 5, '_bx_payment_pre_values_rc_5', ''),
+('bx_payment_reasons_cancel', 'rc_6', 6, '_bx_payment_pre_values_rc_6', '');
+
+-- STUDIO PAGE & WIDGET
+INSERT INTO `sys_std_pages`(`index`, `name`, `header`, `caption`, `icon`) VALUES
+(3, @sName, '_bx_payment', '_bx_payment', 'bx_payment@modules/boonex/payment/|std-icon.svg');
+SET @iPageId = LAST_INSERT_ID();
+
+SET @iParentPageId = (SELECT `id` FROM `sys_std_pages` WHERE `name` = 'home');
+SET @iParentPageOrder = (SELECT MAX(`order`) FROM `sys_std_pages_widgets` WHERE `page_id` = @iParentPageId);
+INSERT INTO `sys_std_widgets` (`page_id`, `module`, `type`, `url`, `click`, `icon`, `caption`, `cnt_notices`, `cnt_actions`) VALUES
+(@iPageId, @sName, 'extensions', '{url_studio}module.php?name=bx_payment', '', 'bx_payment@modules/boonex/payment/|std-icon.svg', '_bx_payment', '', 'a:4:{s:6:"module";s:6:"system";s:6:"method";s:11:"get_actions";s:6:"params";a:0:{}s:5:"class";s:18:"TemplStudioModules";}');
+INSERT INTO `sys_std_pages_widgets` (`page_id`, `widget_id`, `order`) VALUES
+(@iParentPageId, LAST_INSERT_ID(), IF(ISNULL(@iParentPageOrder), 1, @iParentPageOrder + 1));

+ 110 - 0
modules/boonex/payment/updates/15.0.1_15.0.2/source/js/subscriptions.js

@@ -0,0 +1,110 @@
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Payment Payment
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+function BxPaymentSubscriptions(oOptions) {
+    this.init(oOptions);
+}
+
+BxPaymentSubscriptions.prototype = new BxPaymentMain();
+
+BxPaymentSubscriptions.prototype.init = function(oOptions) {
+    if($.isEmptyObject(oOptions))
+        return;
+
+    this._sActionsUrl = oOptions.sActionUrl;
+    this._sObjName = oOptions.sObjName == undefined ? 'oPmtSubscriptions' : oOptions.sObjName;
+    this._sAnimationEffect = oOptions.sAnimationEffect == undefined ? 'fade' : oOptions.sAnimationEffect;
+    this._iAnimationSpeed = oOptions.iAnimationSpeed == undefined ? 'slow' : oOptions.iAnimationSpeed;
+};
+
+BxPaymentSubscriptions.prototype.getDetails = function(oLink, iId) {
+    this._performRequest(oLink, iId, 'subscription_get_details');
+};
+
+BxPaymentSubscriptions.prototype.changeDetails = function(oLink, iId) {
+    this._performRequest(oLink, iId, 'subscription_change_details');
+};
+
+BxPaymentSubscriptions.prototype.getBilling = function(oLink, iId) {
+    this._performRequest(oLink, iId, 'subscription_get_billing');
+};
+
+BxPaymentSubscriptions.prototype.changeBilling = function(oLink, iId) {
+    this._performRequest(oLink, iId, 'subscription_change_billing');
+};
+
+BxPaymentSubscriptions.prototype.requestCancelation = function(oLink, iId) {
+    this._performRequest(oLink, iId, 'subscription_cancelation');
+};
+
+BxPaymentSubscriptions.prototype.onSubmitCancelationReason = function(oForm) {
+    oForm = $(oForm);
+
+    if(oForm.find("[name = 'items']:checked").val() == 'rc_0' && oForm.find("[name = 'other']").val() == '') {
+        oForm.find(".bx-payment-cs-other .bx-form-warn").html(_t('_bx_payment_form_input_err')).show();
+        return false;
+    }
+
+    return true;
+};
+
+BxPaymentSubscriptions.prototype.onChangeCancelationReason = function(oElement) {
+    var bOther = $(oElement).val() == 'rc_0';
+    var oOther = $(oElement).parents('.bx-form-element-wrapper:first').siblings('.bx-payment-cs-other');
+    oOther.toggleClass('bx-payment-cs-hidden', !bOther);
+    if(!bOther)
+        oOther.find("[name = 'other']").val('');
+};
+
+BxPaymentSubscriptions.prototype.cancel = function(oLink, iId, sGrid, iConfirm) {
+    var $this = this;
+
+    var oParams = {};
+    if(sGrid != undefined)
+        oParams.grid = sGrid;
+
+    var fPerformYes = function() {
+        $this._performRequest(oLink, iId, 'subscription_cancel', oParams);
+    };
+
+    if(iConfirm != undefined && parseInt(iConfirm) == 0)
+        fPerformYes();
+    else
+        bx_confirm(_t('_bx_payment_msg_confirm_cancelation'), fPerformYes, function() {}, {
+            yes: {
+                title: _t('_bx_payment_txt_unsubscribe_yes')
+            },
+            no: {
+                title: _t('_bx_payment_txt_unsubscribe_no')
+            }
+        });
+};
+
+BxPaymentSubscriptions.prototype._performRequest = function(oLink, iId, sUri, oParams) {
+    var $this = this;
+    var oDate = new Date();
+
+    this.loadingInPopup(oLink, true);
+
+    $.post(
+        this._sActionsUrl + sUri + '/' + iId,
+        $.extend({}, {_t:oDate.getTime()}, oParams),
+        function(oData){
+            $this.loadingInPopup(oLink, false);
+
+            $(".bx-popup-applied:visible").dolPopupHide();
+
+            processJsonData(oData);
+        },
+        'json'
+    );
+};
+
+/** @} */

+ 34 - 0
modules/boonex/payment/updates/15.0.1_15.0.2/source/template/css/subscriptions.css

@@ -0,0 +1,34 @@
+/*--- Actions Menu ---*/
+.bx-menu-object-bx_payment_menu_sbs_actions .bx-loading-ajax-btn {
+	vertical-align: middle;
+	max-width: 20px;
+	max-height: 20px;
+}
+
+/*--- Actions Menu ---*/
+div.bx-payment-cs-hidden {
+    display: none;
+}
+
+/*--- View Details ---*/
+div.bx-payment-view-details {
+    border-top-width: 0px;
+}
+div.bx-payment-vd-row {
+	white-space: nowrap;
+}
+div.bx-payment-vd-caption,
+div.bx-payment-vd-content,
+div.bx-payment-vd-items {
+    position: relative;
+    display: inline-block;
+	vertical-align: top;
+
+    overflow: hidden;
+}
+div.bx-payment-vd-caption {
+    width: 40%;
+}
+div.bx-payment-vd-content {
+    width: 60%;
+}

+ 45 - 0
modules/boonex/payment/updates/15.0.1_15.0.2/source/template/order_subscription.html

@@ -0,0 +1,45 @@
+<div class="bx-payment-view-order-popup">
+    <div class="bx-payment-view-order-popup-cnt">
+        <div class="bx-payment-view-order bx-def-border">
+            <div class="bx-payment-vo-row bx-def-padding-thd bx-def-border-top bx-clearfix">
+                <div class="bx-payment-vo-caption">__txt_seller__</div><div class="bx-payment-vo-content">
+                    <bx_if:show_link>
+                        <a href="__seller_url__" target="_blank">__seller_name__</a>
+                    </bx_if:show_link>
+                    <bx_if:show_text>__seller_name__</bx_if:show_text>
+                </div>
+            </div>
+            <div class="bx-payment-vo-row bx-def-padding-thd bx-def-border-top bx-clearfix">
+                <div class="bx-payment-vo-caption">__txt_customer_id__</div><div class="bx-payment-vo-content">__customer_id__</div>
+            </div>
+            <div class="bx-payment-vo-row bx-def-padding-thd bx-def-border-top bx-clearfix">
+                <div class="bx-payment-vo-caption">__txt_order__</div><div class="bx-payment-vo-content">__order__</div>
+            </div>
+            <div class="bx-payment-vo-row bx-def-padding-thd bx-def-border-top bx-clearfix">
+                <div class="bx-payment-vo-caption">__txt_processed_with__</div><div class="bx-payment-vo-content">__provider__</div>
+            </div>
+            <div class="bx-payment-vo-row bx-def-padding-thd bx-def-border-top bx-clearfix">
+                <div class="bx-payment-vo-caption">__txt_date__</div><div class="bx-payment-vo-content">__date__</div>
+            </div>
+            <div class="bx-payment-vo-row bx-def-padding-thd bx-def-border-top bx-clearfix">
+                <div class="bx-payment-vo-caption">__txt_products__</div><div class="bx-payment-vo-items">
+                    <bx_repeat:items>
+                        <bx_if:link>
+                            <a href="__url__" target="_blank">__title__</a>
+                        </bx_if:link>
+                        <bx_if:text>__title__</bx_if:text>
+                        (__quantity__) - __price__ __currency_code__<br />
+                    </bx_repeat:items>
+                </div>
+            </div> 
+            <bx_if:show_deleted>
+                <div class="bx-payment-vo-row bx-def-padding-thd bx-def-border-top bx-clearfix">
+                    <div class="bx-payment-vo-caption">__txt_deleted__</div><div class="bx-payment-vo-content">__deleted__</div>
+                </div>
+                <div class="bx-payment-vo-row bx-def-padding-thd bx-def-border-top bx-clearfix">
+                    <div class="bx-payment-vo-caption">__txt_deleted_reason__</div><div class="bx-payment-vo-content">__deleted_reason__</div>
+                </div>
+            </bx_if:show_deleted>
+        </div>
+    </div>
+</div>

+ 19 - 0
modules/boonex/payment/updates/15.0.1_15.0.2/source/template/subscription_form.html

@@ -0,0 +1,19 @@
+<div class="bx-payment-subscription">
+    <div class="bx-payment-subscription-cnt p-4">
+        __form__
+        <script language="javascript">
+            $(document).ready(function () {
+                $("#__form_id__").ajaxForm({ 
+                    dataType: "json",
+                    beforeSubmit: function (formData, jqForm, options) {
+                        bx_loading($("#__form_id__"), true);
+                    },
+                    success: function (data) {
+                        $(".bx-popup-applied:visible").dolPopupHide();
+                        processJsonData(data);
+                    }
+                });
+            });
+        </script>
+    </div>
+</div>

+ 51 - 0
modules/boonex/persons/updates/15.0.2_15.0.3/install/config.php

@@ -0,0 +1,51 @@
+<?php
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ */
+
+$aConfig = array(
+    /**
+     * Main Section.
+     */
+    'title' => 'Persons',
+    'version_from' => '15.0.2',
+    'version_to' => '15.0.3',
+    'vendor' => 'UNA INC',
+
+    'compatible_with' => array(
+        '15.0.0-B2'
+    ),
+
+    /**
+     * 'home_dir' and 'home_uri' - should be unique. Don't use spaces in 'home_uri' and the other special chars.
+     */
+    'home_dir' => 'boonex/persons/updates/update_15.0.2_15.0.3/',
+    'home_uri' => 'persons_update_1502_1503',
+
+    'module_dir' => 'boonex/persons/',
+    'module_uri' => 'persons',
+
+    'db_prefix' => 'bx_persons_',
+    'class_prefix' => 'BxPersons',
+
+    /**
+     * Installation/Uninstallation Section.
+     */
+    'install' => array(
+        'execute_sql' => 0,
+        'update_files' => 1,
+        'update_languages' => 1,
+        'clear_db_cache' => 0,
+    ),
+
+    /**
+     * Category for language keys.
+     */
+    'language_category' => 'Persons',
+
+    /**
+     * Files Section
+     */
+    'delete_files' => array(),
+);

+ 13 - 0
modules/boonex/persons/updates/15.0.2_15.0.3/install/installer.php

@@ -0,0 +1,13 @@
+<?php
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ */
+
+class BxPersonsUpdater extends BxDolStudioUpdater
+{
+    function __construct($aConfig)
+    {
+        parent::__construct($aConfig);
+    }
+}

+ 4 - 0
modules/boonex/persons/updates/15.0.2_15.0.3/install/langs/en.xml

@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources name="en" flag="gb" title="English">
+	<string_add name="_bx_persons_reactions"><![CDATA[Persons' Reactions]]></string_add>
+</resources>

+ 153 - 0
modules/boonex/persons/updates/15.0.2_15.0.3/source/install/config.php

@@ -0,0 +1,153 @@
+<?php
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Persons Persons
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+$aConfig = array(
+
+    /**
+     * Main Section.
+     */
+    'type' => BX_DOL_MODULE_TYPE_MODULE,
+    'name' => 'bx_persons',
+    'title' => 'Persons',
+    'note' => 'Basic person profiles functionality.',
+    'version' => '15.0.3',
+    'vendor' => 'UNA INC',
+    'help_url' => 'http://feed.una.io/?section={module_name}',
+
+    'compatible_with' => array(
+        '15.0.0-B2'
+    ),
+
+    /**
+     * 'home_dir' and 'home_uri' - should be unique. Don't use spaces in 'home_uri' and the other special chars.
+     */
+    'home_dir' => 'boonex/persons/',
+    'home_uri' => 'persons',
+
+    'db_prefix' => 'bx_persons_',
+    'class_prefix' => 'BxPersons',
+
+    /**
+     * Category for language keys.
+     */
+    'language_category' => 'Persons',
+
+    /**
+     * Connections.
+     */
+    'connections' => array(
+        'sys_profiles_friends' => array ('type' => 'profiles'),
+        'sys_profiles_subscriptions' => array ('type' => 'profiles'),
+        'sys_profiles_relations' => array ('type' => 'profiles'),
+    ),
+
+    /**
+     * Menu triggers.
+     */
+    'menu_triggers' => array(
+        'trigger_profile_view_submenu',
+        'trigger_profile_snippet_meta',
+    	'trigger_profile_view_actions',
+    ),
+
+	/**
+     * Page triggers.
+     */
+    'page_triggers' => array (
+    	'trigger_page_profile_view_entry', 
+    ),
+
+	/**
+     * Storage objects to automatically delete files from upon module uninstallation.
+     * Note. Don't add storage objects used in transcoder objects.
+     */
+    'storages' => array(
+    	'bx_persons_pictures'
+    ),
+
+	/**
+     * Transcoders.
+     */
+    'transcoders' => array(
+    	'bx_persons_icon',
+    	'bx_persons_thumb',
+    	'bx_persons_avatar',
+        'bx_persons_avatar_big',
+    	'bx_persons_picture',
+    	'bx_persons_cover',
+    	'bx_persons_cover_thumb',
+        'bx_persons_gallery',
+        'bx_persons_badge'
+    ),
+
+    /**
+     * Extended Search Forms.
+     */
+    'esearches' => array(
+        'bx_persons',
+    	'bx_persons_cmts',
+    ),
+
+    /**
+     * Installation/Uninstallation Section.
+     */
+    'install' => array(
+        'execute_sql' => 1,
+        'update_languages' => 1,
+        'clear_db_cache' => 1,
+    ),
+    'uninstall' => array (
+    	'process_esearches' => 1,
+        'execute_sql' => 1,
+        'update_languages' => 1,
+    	'process_connections' => 1,
+    	'process_deleted_profiles' => 1,
+    	'update_relations' => 1,
+        'clear_db_cache' => 1,
+    ),
+    'enable' => array(
+        'execute_sql' => 1,
+    	'update_relations' => 1,
+        'clear_db_cache' => 1,
+    ),
+	'enable_success' => array(
+    	'process_menu_triggers' => 1,
+    	'process_page_triggers' => 1,
+    	'process_esearches' => 1,
+    	'register_transcoders' => 1,
+        'clear_db_cache' => 1,
+    ),
+    'disable' => array (
+        'execute_sql' => 1,
+    	'unregister_transcoders' => 1,
+    	'update_relations' => 1,
+        'clear_db_cache' => 1,
+    ),
+    'disable_failed' => array (
+    	'register_transcoders' => 1,
+    	'clear_db_cache' => 1,
+    ),
+
+    /**
+     * Dependencies Section
+     */
+    'dependencies' => array(),
+
+    /**
+     * Connections Section
+     */
+    'relations' => array(
+    	'bx_timeline',
+        'bx_notifications',
+    ),
+);
+
+/** @} */

+ 374 - 0
modules/boonex/persons/updates/15.0.2_15.0.3/source/install/langs/en.xml

@@ -0,0 +1,374 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources name="en" flag="gb" title="English">
+
+    <string name="_bx_persons"><![CDATA[Persons]]></string>
+    <string name="_bx_persons_cmts"><![CDATA[Persons' Comments]]></string>
+    <string name="_bx_persons_reactions"><![CDATA[Persons' Reactions]]></string>
+
+    <string name="_bx_persons_option_autoapproval"><![CDATA[Activate all persons automatically]]></string>
+    <string name="_bx_persons_option_default_acl_level"><![CDATA[Default member's level to assign after person's profile creation]]></string>
+    <string name="_bx_persons_option_enable_profile_activation_letter"><![CDATA[Enable profile activation letter]]></string>
+    <string name="_bx_persons_option_redirect_aadd"><![CDATA[Redirect after person's profile creation to]]></string>
+    <string name="_bx_persons_option_redirect_aadd_profile"><![CDATA[Profile Page]]></string>
+    <string name="_bx_persons_option_redirect_aadd_last"><![CDATA[Last Page]]></string>
+    <string name="_bx_persons_option_redirect_aadd_custom"><![CDATA[Custom Page]]></string>
+    <string name="_bx_persons_option_redirect_aadd_homepage"><![CDATA[Homepage]]></string>
+    <string name="_bx_persons_option_redirect_aadd_custom_url"><![CDATA[URL for 'Custom Page' redirect]]></string>
+    <string name="_bx_persons_option_activation_on"><![CDATA[After creation & after editing]]></string>
+    <string name="_bx_persons_option_activation_add"><![CDATA[After creation only]]></string>
+    <string name="_bx_persons_option_activation_edit"><![CDATA[After editing only]]></string>
+    <string name="_bx_persons_option_activation_off"><![CDATA[Manual activation]]></string>
+    <string name="_bx_persons_option_num_connections_quick"><![CDATA[Number of items in friends block]]></string>
+    <string name="_bx_persons_option_per_page_browse"><![CDATA[Number of items per page]]></string>
+    <string name="_bx_persons_option_num_rss"><![CDATA[Number of items in RSS feed]]></string>
+    <string name="_bx_persons_option_searchable_fields"><![CDATA[Searchable fields for keyword search]]></string>
+    <string name="_bx_persons_option_friends"><![CDATA[Friendship]]></string>
+    <string name="_bx_persons_option_public_subscriptions"><![CDATA[Public following list]]></string>
+    <string name="_bx_persons_option_public_subscribed_me"><![CDATA[Public followers list]]></string>
+
+    <string name="_bx_persons_form_profile"><![CDATA[Persons]]></string>
+    <string name="_bx_persons_form_profile_display_add"><![CDATA[Add Person]]></string>
+    <string name="_bx_persons_form_profile_display_edit"><![CDATA[Edit Person]]></string>
+    <string name="_bx_persons_form_profile_display_edit_cover"><![CDATA[Edit Cover]]></string>
+    <string name="_bx_persons_form_profile_display_edit_badge"><![CDATA[Edit Badge]]></string>
+    <string name="_bx_persons_form_profile_display_delete"><![CDATA[Delete Person]]></string>
+    <string name="_bx_persons_form_profile_display_view"><![CDATA[View Person]]></string>
+    <string name="_bx_persons_form_profile_display_view_full"><![CDATA[Full View Person]]></string>
+    <string name="_bx_persons_form_profile_input_sys_do_submit"><![CDATA[Submit]]></string>
+    <string name="_bx_persons_form_profile_input_submit"><![CDATA[Submit]]></string>
+    <string name="_bx_persons_form_profile_input_sys_allow_view_to"><![CDATA[Visible to]]></string>
+    <string name="_bx_persons_form_profile_input_allow_view_to"><![CDATA[Visible to]]></string>
+    <string name="_bx_persons_form_profile_input_sys_allow_post_to"><![CDATA[Who can post to my profile]]></string>
+    <string name="_bx_persons_form_profile_input_allow_post_to"><![CDATA[Who can post to my profile]]></string>
+    <string name="_bx_persons_form_profile_input_sys_allow_contact_to"><![CDATA[Who can contact me]]></string>
+    <string name="_bx_persons_form_profile_input_allow_contact_to"><![CDATA[Who can contact me]]></string>
+    <string name="_bx_persons_form_profile_input_sys_fullname"><![CDATA[Name]]></string>
+    <string name="_bx_persons_form_profile_input_fullname"><![CDATA[Name]]></string>
+    <string name="_bx_persons_form_profile_input_sys_last_name"><![CDATA[Last Name]]></string>
+    <string name="_bx_persons_form_profile_input_last_name"><![CDATA[Last Name]]></string>
+    <string name="_bx_persons_form_profile_input_fullname_err"><![CDATA[Profile name is mandatory and and cannot start with @]]></string>
+    <string name="_bx_persons_form_profile_input_sys_desc"><![CDATA[Description]]></string>
+    <string name="_bx_persons_form_profile_input_desc"><![CDATA[Description]]></string>
+    <string name="_bx_persons_form_profile_input_sys_picture"><![CDATA[Profile Picture]]></string>
+    <string name="_bx_persons_form_profile_input_picture"><![CDATA[Upload a profile picture]]></string>
+    <string name="_bx_persons_form_profile_input_picture_err"><![CDATA[Profile picture is mandatory.]]></string>
+    <string name="_bx_persons_form_profile_input_picture_search"><![CDATA[With photo]]></string>
+    <string name="_bx_persons_form_profile_input_online_search"><![CDATA[Online only]]></string>
+    <string name="_bx_persons_form_profile_input_sys_cover"><![CDATA[Cover Picture]]></string>
+    <string name="_bx_persons_form_profile_input_cover"><![CDATA[Upload New Cover Picture]]></string>
+    <string name="_bx_persons_form_profile_input_sys_badge"><![CDATA[Badge Image]]></string>
+    <string name="_bx_persons_form_profile_input_badge"><![CDATA[Upload New Badge Image]]></string>
+    <string name="_bx_persons_form_profile_input_sys_badge_link_custom"><![CDATA[Badge Custom Link]]></string>
+    <string name="_bx_persons_form_profile_input_badge_link_custom"><![CDATA[Badge Custom Link]]></string>
+    <string name="_bx_persons_form_profile_input_badge_link_custom_placeholder"><![CDATA[or enter your own here]]></string>
+    <string name="_bx_persons_form_profile_input_sys_badge_link_select"><![CDATA[Badge Link Select]]></string>
+    <string name="_bx_persons_form_profile_input_badge_link_select"><![CDATA[Badge Link]]></string>
+    <string name="_bx_persons_form_profile_input_sys_delete_confirm"><![CDATA[Delete confirmation]]></string>
+    <string name="_bx_persons_form_profile_input_delete_confirm"><![CDATA[I am sure I want to delete this profile]]></string>
+    <string name="_bx_persons_form_profile_input_delete_confirm_info"><![CDATA[This action can not be undone.]]></string>
+    <string name="_bx_persons_form_profile_input_delete_confirm_error"><![CDATA[Please check this checkbox if you really want to delete your profile.]]></string>
+    <string name="_bx_persons_form_profile_input_sys_birthday"><![CDATA[Birthday]]></string>
+    <string name="_bx_persons_form_profile_input_birthday_err"><![CDATA[Age between 18 and 99]]></string>
+    <string name="_bx_persons_form_profile_input_birthday"><![CDATA[Birthday]]></string>
+    <string name="_bx_persons_form_profile_input_sys_gender"><![CDATA[Gender]]></string>
+    <string name="_bx_persons_form_profile_input_gender"><![CDATA[Gender]]></string>
+    <string name="_bx_persons_form_profile_input_sys_profile_email"><![CDATA[Email]]></string>
+    <string name="_bx_persons_form_profile_input_profile_email"><![CDATA[Email]]></string>
+    <string name="_bx_persons_form_profile_input_sys_profile_status"><![CDATA[Status]]></string>
+    <string name="_bx_persons_form_profile_input_profile_status"><![CDATA[Status]]></string>
+    <string name="_bx_persons_form_profile_input_sys_profile_ip"><![CDATA[IP]]></string>
+    <string name="_bx_persons_form_profile_input_profile_ip"><![CDATA[IP]]></string>
+    <string name="_bx_persons_form_profile_input_sys_profile_last_active"><![CDATA[Last account activity]]></string>
+    <string name="_bx_persons_form_profile_input_profile_last_active"><![CDATA[Last account activity]]></string>
+    <string name="_bx_persons_form_profile_input_sys_skills"><![CDATA[Skills]]></string>
+    <string name="_bx_persons_form_profile_input_skills"><![CDATA[Skills]]></string>
+    <string name="_bx_persons_form_profile_input_sys_date_added"><![CDATA[Added]]></string>
+    <string name="_bx_persons_form_profile_input_date_added"><![CDATA[Added]]></string>
+    <string name="_bx_persons_form_profile_input_sys_date_changed"><![CDATA[Updated]]></string>
+    <string name="_bx_persons_form_profile_input_date_changed"><![CDATA[Updated]]></string>
+    <string name="_bx_persons_form_profile_input_sys_friends_count"><![CDATA[Friends count]]></string>
+    <string name="_bx_persons_form_profile_input_friends_count"><![CDATA[Friends count]]></string>
+    <string name="_bx_persons_form_profile_input_sys_followers_count"><![CDATA[Followers count]]></string>
+    <string name="_bx_persons_form_profile_input_followers_count"><![CDATA[Followers count]]></string>
+
+    <string name="_bx_persons_skills_form_profile"><![CDATA[Skills]]></string>
+    <string name="_bx_persons_skills_form_profile_display_add"><![CDATA[Add Skill]]></string>
+    <string name="_bx_persons_skills_form_profile_display_view"><![CDATA[View Skill]]></string>
+    <string name="_bx_persons_skills_form_profile_input_sys_skill_name"><![CDATA[Name]]></string>
+    <string name="_bx_persons_skills_form_profile_input_skill_name"><![CDATA[Name]]></string>
+    <string name="_bx_persons_skills_form_profile_input_skill_name_err"><![CDATA[This information is essential. Please, fill in this field.]]></string>
+
+    <string name="_bx_persons_acl_action_create_profile"><![CDATA[Create Person's Profile]]></string>
+    <string name="_bx_persons_acl_action_delete_profile"><![CDATA[Delete Person's Profile]]></string>
+    <string name="_bx_persons_acl_action_view_profile"><![CDATA[View Person's Profile]]></string>
+    <string name="_bx_persons_acl_action_change_badge"><![CDATA[Change Person's Profile Badge]]></string>
+    <string name="_bx_persons_acl_action_edit_any_profile"><![CDATA[Edit Any Person's Profile]]></string>
+    <string name="_bx_persons_acl_action_delete_any_profile"><![CDATA[Delete Any Person's Profile]]></string>
+
+    <string name="_bx_persons_page_title_sys_create_profile"><![CDATA[Create a Profile - Person]]></string>
+    <string name="_bx_persons_page_title_create_profile"><![CDATA[Create a Profile - Person]]></string>
+    <string name="_bx_persons_page_title_sys_edit_profile"><![CDATA[Edit Profile]]></string>
+    <string name="_bx_persons_page_title_edit_profile"><![CDATA[Edit Profile]]></string>
+    <string name="_bx_persons_page_title_sys_edit_profile_cover"><![CDATA[Edit Cover]]></string>
+    <string name="_bx_persons_page_title_edit_profile_cover"><![CDATA[Edit Cover]]></string>
+    <string name="_bx_persons_page_title_sys_edit_profile_badge"><![CDATA[Edit Badge]]></string>
+    <string name="_bx_persons_page_title_edit_profile_badge"><![CDATA[Edit Badge]]></string>
+    <string name="_bx_persons_page_title_sys_delete_profile"><![CDATA[Delete Profile]]></string>
+    <string name="_bx_persons_page_title_delete_profile"><![CDATA[Delete Profile]]></string>
+    <string name="_bx_persons_page_title_sys_view_profile"><![CDATA[View Profile]]></string>
+    <string name="_bx_persons_page_title_sys_view_profile_closed"><![CDATA[View Profile with Limited Visibility]]></string>
+    <string name="_bx_persons_page_title_view_profile"><![CDATA[{display_name}]]></string>
+    <string name="_bx_persons_page_title_browse"><![CDATA[People]]></string>
+    <string name="_bx_persons_page_title_browse_featured"><![CDATA[Featured People]]></string>
+    <string name="_bx_persons_page_title_browse_active"><![CDATA[Active People]]></string>
+    <string name="_bx_persons_page_title_browse_online"><![CDATA[Online People]]></string>
+    <string name="_bx_persons_page_title_browse_recent"><![CDATA[New People]]></string>
+    <string name="_bx_persons_page_title_browse_connections"><![CDATA[{0} connections]]></string>
+    <string name="_bx_persons_page_title_browse_connections_mutual"><![CDATA[{0} and {1} mutual connections]]></string>
+    <string name="_bx_persons_page_title_browse_familiar"><![CDATA[People You May Know]]></string>
+    <string name="_bx_persons_page_title_browse_favorites"><![CDATA[{0} favorites]]></string>
+    <string name="_bx_persons_page_title_browse_by_acl"><![CDATA[{0} People]]></string>
+    <string name="_bx_persons_page_title_browse_by_cmts"><![CDATA[People's Comments]]></string>
+    <string name="_bx_persons_page_title_sys_profile_favorites"><![CDATA[Favorite persons]]></string>
+    <string name="_bx_persons_page_title_profile_favorites"><![CDATA[Favorite persons]]></string>
+    <string name="_bx_persons_page_title_sys_profile_friends"><![CDATA[Friends]]></string>
+    <string name="_bx_persons_page_title_profile_friends"><![CDATA[Friends]]></string>
+    <string name="_bx_persons_page_title_sys_friend_requests"><![CDATA[Friend Requests]]></string>
+    <string name="_bx_persons_page_title_friend_requests"><![CDATA[Friend Requests]]></string>
+    <string name="_bx_persons_page_title_sys_profile_subscriptions"><![CDATA[Following]]></string>
+    <string name="_bx_persons_page_title_profile_subscriptions"><![CDATA[Following & Followers]]></string>
+    <string name="_bx_persons_page_title_sys_profile_relations"><![CDATA[Relationships]]></string>
+    <string name="_bx_persons_page_title_profile_relations"><![CDATA[Relationships]]></string>
+    <string name="_bx_persons_page_title_sys_profile_comments"><![CDATA[Comments]]></string>
+    <string name="_bx_persons_page_title_profile_comments"><![CDATA[Comments]]></string>
+    <string name="_bx_persons_page_title_sys_profile_info"><![CDATA[Profile Info]]></string>
+    <string name="_bx_persons_page_title_profile_info"><![CDATA[Info about {display_name}]]></string>
+    <string name="_bx_persons_page_title_sys_recent"><![CDATA[New People]]></string>
+    <string name="_bx_persons_page_title_recent"><![CDATA[New People]]></string>
+    <string name="_bx_persons_page_title_sys_manage"><![CDATA[Manage Own People]]></string>
+    <string name="_bx_persons_page_title_sys_manage_administration"><![CDATA[Manage All People]]></string>
+    <string name="_bx_persons_page_title_manage"><![CDATA[Manage People]]></string>
+    <string name="_bx_persons_page_title_sys_active"><![CDATA[Active People]]></string>
+    <string name="_bx_persons_page_title_active"><![CDATA[Active People]]></string>
+    <string name="_bx_persons_page_title_sys_online"><![CDATA[Online People]]></string>
+    <string name="_bx_persons_page_title_online"><![CDATA[Online People]]></string>
+    <string name="_bx_persons_page_title_sys_entries_search"><![CDATA[Search]]></string>
+    <string name="_bx_persons_page_title_entries_search"><![CDATA[Search]]></string>
+
+    <string name="_bx_persons_page_block_title_profile_private"><![CDATA[Private Profile]]></string>
+    <string name="_bx_persons_page_block_title_choose_type"><![CDATA[Choose Profile Type]]></string>
+    <string name="_bx_persons_page_block_title_create_profile"><![CDATA[Create a Profile - Person]]></string>
+    <string name="_bx_persons_page_block_title_edit_profile"><![CDATA[Edit Profile]]></string>
+    <string name="_bx_persons_page_block_title_edit_profile_cover"><![CDATA[Edit Cover]]></string>
+    <string name="_bx_persons_page_block_title_edit_profile_badge"><![CDATA[Edit Badge]]></string>
+    <string name="_bx_persons_page_block_title_delete_profile"><![CDATA[Delete Profile]]></string>
+    <string name="_bx_persons_page_block_title_profile_all_actions"><![CDATA[All Actions]]></string>
+    <string name="_bx_persons_page_block_title_profile_info_link"><![CDATA[About <a href="{profile_link}">{display_name}</a>]]></string>
+    <string name="_bx_persons_page_block_title_profile_info"><![CDATA[Info]]></string>
+    <string name="_bx_persons_page_block_title_system_profile_info"><![CDATA[Info]]></string>
+    <string name="_bx_persons_page_block_title_profile_membership"><![CDATA[Membership]]></string>
+    <string name="_bx_persons_page_block_title_system_profile_membership"><![CDATA[Membership]]></string>
+    <string name="_bx_persons_page_block_title_profile_description"><![CDATA[Description]]></string>
+    <string name="_bx_persons_page_block_title_profile_favorites"><![CDATA[Favorite persons]]></string>
+    <string name="_bx_persons_page_block_title_system_profile_favorites"><![CDATA[Favorite persons]]></string>
+    <string name="_bx_persons_page_block_title_profile_friends_link"><![CDATA[Friends of <a href="{profile_link}">{display_name}</a>]]></string>
+    <string name="_bx_persons_page_block_title_profile_friends"><![CDATA[Friends]]></string>
+    <string name="_bx_persons_page_block_title_profile_friends_mutual"><![CDATA[Mutual Friends]]></string>
+    <string name="_bx_persons_page_block_title_system_profile_friends"><![CDATA[Friends]]></string>
+    <string name="_bx_persons_page_block_title_friend_requests_link"><![CDATA[Friend Requests for <a href="{profile_link}">{display_name}</a>]]></string>
+    <string name="_bx_persons_page_block_title_system_friend_requests"><![CDATA[Friend Requests]]></string>
+    <string name="_bx_persons_page_block_title_profile_location"><![CDATA[Location]]></string>
+    <string name="_bx_persons_page_block_title_system_profile_subscriptions"><![CDATA[Following]]></string>
+    <string name="_bx_persons_page_block_title_profile_subscriptions"><![CDATA[Following]]></string>
+    <string name="_bx_persons_page_block_title_system_profile_subscribed_me"><![CDATA[Followers]]></string>
+    <string name="_bx_persons_page_block_title_profile_subscribed_me"><![CDATA[Followers]]></string>
+    <string name="_bx_persons_page_block_title_system_profile_relations"><![CDATA[Relationships]]></string>
+    <string name="_bx_persons_page_block_title_profile_relations"><![CDATA[Relationships]]></string>
+    <string name="_bx_persons_page_block_title_system_profile_related_me"><![CDATA[Relationships with Me]]></string>
+    <string name="_bx_persons_page_block_title_profile_related_me"><![CDATA[Relationships with Me]]></string>
+    <string name="_bx_persons_page_block_title_profile_comments"><![CDATA[Comments]]></string>
+    <string name="_bx_persons_page_block_title_entry_reports"><![CDATA[Reports]]></string>
+    <string name="_bx_persons_page_block_title_profile_comments_link"><![CDATA[Comments to <a href="{entry_link}">{title}</a>]]></string>
+    <string name="_bx_persons_page_block_title_featured_profiles"><![CDATA[Featured People]]></string>
+    <string name="_bx_persons_page_block_title_profile_actions"><![CDATA[Actions]]></string>
+    <string name="_bx_persons_page_block_title_profile_calendar"><![CDATA[Calendar]]></string>
+    <string name="_bx_persons_page_block_title_latest_profiles"><![CDATA[New People]]></string>
+    <string name="_bx_persons_page_block_title_system_manage"><![CDATA[Manage Own People]]></string>
+    <string name="_bx_persons_page_block_title_system_manage_administration"><![CDATA[Manage All People]]></string>
+    <string name="_bx_persons_page_block_title_manage"><![CDATA[Manage People]]></string>
+    <string name="_bx_persons_page_block_title_sys_active_profiles"><![CDATA[Active People]]></string>
+    <string name="_bx_persons_page_block_title_active_profiles"><![CDATA[Active People]]></string>
+    <string name="_bx_persons_page_block_title_online_profiles"><![CDATA[Online People]]></string>
+    <string name="_bx_persons_page_block_title_sys_familiar_profiles"><![CDATA[Familiar People]]></string>
+    <string name="_bx_persons_page_block_title_familiar_profiles"><![CDATA[People You May Know]]></string>
+    <string name="_bx_persons_page_block_title_search_form"><![CDATA[Search Form]]></string>
+    <string name="_bx_persons_page_block_title_search_results"><![CDATA[Search Results]]></string>
+    <string name="_bx_persons_page_block_title_search_form_cmts"><![CDATA[Comments Search Form]]></string>
+    <string name="_bx_persons_page_block_title_search_results_cmts"><![CDATA[Comments Search Results]]></string>
+    <string name="_bx_persons_page_block_title_sys_featured_entries_view_showcase"><![CDATA[Featured People (Showcase View)]]></string>
+    <string name="_bx_persons_page_block_title_featured_entries_view_showcase"><![CDATA[Featured People]]></string>
+    <string name="_bx_persons_page_block_title_sys_recommended_entries_view_showcase"><![CDATA[Recommended People (Showcase View)]]></string>
+    <string name="_bx_persons_page_block_title_recommended_entries_view_showcase"><![CDATA[Recommended People]]></string>
+    <string name="_bx_persons_page_block_title_sys_active_entries_view_showcase"><![CDATA[Active People (Showcase View)]]></string>
+    <string name="_bx_persons_page_block_title_active_entries_view_showcase"><![CDATA[Active People]]></string>
+    <string name="_bx_persons_page_block_title_sys_cover_block"><![CDATA[Cover]]></string>
+    <string name="_bx_persons_page_block_title_cover_block"><![CDATA[Cover]]></string>
+
+    <string name="_bx_persons_menu_title_submenu"><![CDATA[Persons Submenu]]></string>
+    <string name="_bx_persons_menu_title_public_submenu"><![CDATA[Persons]]></string>
+    <string name="_bx_persons_menu_set_title_submenu"><![CDATA[Persons Submenu]]></string>
+    <string name="_bx_persons_menu_set_title_view_profile_actions"><![CDATA[Person Actions]]></string>
+    <string name="_bx_persons_menu_title_view_profile_actions"><![CDATA[Person Actions]]></string>
+    <string name="_bx_persons_menu_set_title_view_profile_actions_more"><![CDATA[Person More Actions]]></string>
+    <string name="_bx_persons_menu_title_view_profile_actions_more"><![CDATA[Person More Actions]]></string>
+    <string name="_bx_persons_menu_title_view_profile_meta"><![CDATA[Person Meta]]></string>
+    <string name="_bx_persons_menu_set_title_view_profile_meta"><![CDATA[Person Meta]]></string>
+    <string name="_bx_persons_menu_set_title_view_profile_submenu"><![CDATA[View Person Submenu]]></string>
+    <string name="_bx_persons_menu_title_view_profile_submenu"><![CDATA[View Person Submenu]]></string>
+    <string name="_bx_persons_menu_set_title_manage_tools"><![CDATA[Manage Tools Submenu]]></string>
+    <string name="_bx_persons_menu_title_manage_tools"><![CDATA[Manage Tools Submenu]]></string>
+    <string name="_bx_persons_menu_item_title_system_delete_with_content"><![CDATA[Delete with Data]]></string>
+    <string name="_bx_persons_menu_item_title_delete_with_content"><![CDATA[Delete with Data]]></string>
+    <string name="_bx_persons_menu_item_title_system_clear_reports"><![CDATA[Clear reports]]></string>
+    <string name="_bx_persons_menu_item_title_clear_reports"><![CDATA[Clear reports]]></string>
+    <string name="_bx_persons_menu_item_title_system_manage_cf"><![CDATA[Manage audience]]></string>
+    <string name="_bx_persons_menu_item_title_manage_cf"><![CDATA[Manage audience]]></string>
+    <string name="_bx_persons_menu_item_title_system_edit_cover"><![CDATA[Edit Cover]]></string>
+    <string name="_bx_persons_menu_item_title_edit_cover"><![CDATA[Edit Cover]]></string>
+    <string name="_bx_persons_menu_item_title_system_edit_profile"><![CDATA[Edit Person]]></string>
+    <string name="_bx_persons_menu_item_title_edit_profile"><![CDATA[Edit Profile]]></string>
+    <string name="_bx_persons_menu_item_title_system_edit_badge"><![CDATA[Edit Badge]]></string>
+    <string name="_bx_persons_menu_item_title_edit_badge"><![CDATA[Edit Badge]]></string>
+    <string name="_bx_persons_menu_item_title_system_delete_profile"><![CDATA[Delete Profile and Data]]></string>
+    <string name="_bx_persons_menu_item_title_delete_profile"><![CDATA[Delete Profile and Data]]></string>
+    <string name="_bx_persons_menu_item_title_system_delete_account"><![CDATA[Delete Account]]></string>
+    <string name="_bx_persons_menu_item_title_delete_account"><![CDATA[Delete Account]]></string>
+    <string name="_bx_persons_menu_item_title_system_delete_account_content"><![CDATA[Delete Account and Data]]></string>
+    <string name="_bx_persons_menu_item_title_delete_account_content"><![CDATA[Delete Account and Data]]></string>
+    <string name="_bx_persons_menu_item_title_system_profile_type"><![CDATA[Person]]></string>
+    <string name="_bx_persons_menu_item_title_profile_type"><![CDATA[Person]]></string>
+    <string name="_bx_persons_menu_item_title_system_create_profile"><![CDATA[Person]]></string>
+    <string name="_bx_persons_menu_item_title_create_profile"><![CDATA[Person]]></string>
+    <string name="_bx_persons_menu_item_title_system_view_profile_friends"><![CDATA[Friends]]></string>
+    <string name="_bx_persons_menu_item_title_view_profile_friends"><![CDATA[Friends]]></string>
+    <string name="_bx_persons_menu_item_title_system_view_profile_relations"><![CDATA[Relationships]]></string>
+    <string name="_bx_persons_menu_item_title_view_profile_relations"><![CDATA[Relationships]]></string>
+    <string name="_bx_persons_menu_item_title_system_view_profile_subscriptions"><![CDATA[Following]]></string>
+    <string name="_bx_persons_menu_item_title_view_profile_subscriptions"><![CDATA[Following]]></string>
+    <string name="_bx_persons_menu_item_title_system_view_profile_comments"><![CDATA[Comments]]></string>
+    <string name="_bx_persons_menu_item_title_view_profile_comments"><![CDATA[Comments]]></string>
+    <string name="_bx_persons_menu_item_title_system_view_profile_info"><![CDATA[Info]]></string>
+    <string name="_bx_persons_menu_item_title_view_profile_info"><![CDATA[Info]]></string>
+    <string name="_bx_persons_menu_item_title_system_view_profile_view"><![CDATA[Profile]]></string>
+    <string name="_bx_persons_menu_item_title_view_profile_view"><![CDATA[Profile]]></string>
+    <string name="_bx_persons_menu_item_title_system_view_profile_more_auto"><![CDATA[More]]></string>
+    <string name="_bx_persons_menu_item_title_view_profile_more_auto"><![CDATA[More]]></string>
+    <string name="_bx_persons_menu_item_title_system_befriend"><![CDATA[Add friend]]></string>
+    <string name="_bx_persons_menu_item_title_befriend"><![CDATA[Add friend]]></string>
+    <string name="_bx_persons_menu_item_title_befriend_sent"><![CDATA[Add friend (requested)]]></string>
+    <string name="_bx_persons_menu_item_title_befriend_confirm"><![CDATA[Accept friend request]]></string>
+    <string name="_bx_persons_menu_item_title_system_unfriend"><![CDATA[Unfriend]]></string>
+    <string name="_bx_persons_menu_item_title_unfriend"><![CDATA[Unfriend]]></string>
+    <string name="_bx_persons_menu_item_title_unfriend_cancel_request"><![CDATA[Cancel friend request]]></string>
+    <string name="_bx_persons_menu_item_title_unfriend_reject_request"><![CDATA[Reject friend request]]></string>
+    <string name="_bx_persons_menu_item_title_system_subscribe"><![CDATA[Follow]]></string>
+    <string name="_bx_persons_menu_item_title_subscribe"><![CDATA[Follow]]></string>
+    <string name="_bx_persons_menu_item_title_system_unsubscribe"><![CDATA[Unfollow]]></string>
+    <string name="_bx_persons_menu_item_title_unsubscribe"><![CDATA[Unfollow]]></string>
+    <string name="_bx_persons_menu_item_title_system_relation_add"><![CDATA[Add Relationship]]></string>
+    <string name="_bx_persons_menu_item_title_relation_add"><![CDATA[Add Relationship]]></string>
+    <string name="_bx_persons_menu_item_title_system_relation_delete"><![CDATA[Remove Relationship]]></string>
+    <string name="_bx_persons_menu_item_title_relation_delete"><![CDATA[Remove Relationship]]></string>
+    <string name="_bx_persons_menu_item_title_system_more_actions"><![CDATA[More Actions]]></string>
+    <string name="_bx_persons_menu_item_title_more_actions"><![CDATA[]]></string>
+    <string name="_bx_persons_menu_item_title_system_friends"><![CDATA[Friends]]></string>
+    <string name="_bx_persons_menu_item_title_friends"><![CDATA[Friends]]></string>
+    <string name="_bx_persons_menu_item_title_system_relations"><![CDATA[Relationships]]></string>
+    <string name="_bx_persons_menu_item_title_relations"><![CDATA[Relationships]]></string>
+    <string name="_bx_persons_menu_item_title_system_friend_requests"><![CDATA[Friend requests number]]></string>
+    <string name="_bx_persons_menu_item_title_friend_requests"><![CDATA[Friend requests]]></string>
+    <string name="_bx_persons_menu_item_title_system_manage_my_profiles"><![CDATA[My profiles]]></string>
+    <string name="_bx_persons_menu_item_title_manage_my_profiles"><![CDATA[Profiles]]></string>
+    <string name="_bx_persons_menu_item_title_system_favorites"><![CDATA[Favorite Persons]]></string>
+    <string name="_bx_persons_menu_item_title_favorites"><![CDATA[Favorite persons]]></string>    
+    <string name="_bx_persons_menu_item_title_system_subscriptions"><![CDATA[Following]]></string>
+    <string name="_bx_persons_menu_item_title_subscriptions"><![CDATA[Following]]></string>
+    <string name="_bx_persons_menu_item_title_system_subscribed_me"><![CDATA[Followers]]></string>
+    <string name="_bx_persons_menu_item_title_subscribed_me"><![CDATA[Followers]]></string>
+    <string name="_bx_persons_menu_item_title_system_relations"><![CDATA[Relationships]]></string>
+    <string name="_bx_persons_menu_item_title_relations"><![CDATA[Relationships]]></string>
+    <string name="_bx_persons_menu_item_title_system_related_me"><![CDATA[Relationships with Me]]></string>
+    <string name="_bx_persons_menu_item_title_related_me"><![CDATA[Relationships with Me]]></string>
+    <string name="_bx_persons_menu_item_title_system_followings"><![CDATA[Persons]]></string>
+    <string name="_bx_persons_menu_item_title_followings"><![CDATA[Persons]]></string>
+    <string name="_bx_persons_menu_item_title_system_entries_recent"><![CDATA[New]]></string>
+    <string name="_bx_persons_menu_item_title_entries_recent"><![CDATA[New]]></string>
+    <string name="_bx_persons_menu_item_title_system_entries_search"><![CDATA[Search]]></string>
+    <string name="_bx_persons_menu_item_title_entries_search"><![CDATA[Search]]></string>
+    <string name="_bx_persons_menu_item_title_system_entries_manage"><![CDATA[Manage]]></string>
+    <string name="_bx_persons_menu_item_title_entries_manage"><![CDATA[Manage]]></string>
+    <string name="_bx_persons_menu_item_title_system_entries_home"><![CDATA[Persons]]></string>
+    <string name="_bx_persons_menu_item_title_entries_home"><![CDATA[People]]></string>
+	<string name="_bx_persons_menu_item_title_system_admt_persons"><![CDATA[Profiles]]></string>
+	<string name="_bx_persons_menu_item_title_admt_persons"><![CDATA[Profiles]]></string>
+	<string name="_bx_persons_menu_item_title_manage_my"><![CDATA[My Profiles]]></string>
+	<string name="_bx_persons_menu_item_title_manage_all"><![CDATA[All Profiles]]></string>   
+	<string name="_bx_persons_menu_item_title_system_entries_active"><![CDATA[Active]]></string>
+	<string name="_bx_persons_menu_item_title_entries_active"><![CDATA[Active]]></string>
+	<string name="_bx_persons_menu_item_title_system_entries_online"><![CDATA[Online]]></string>
+	<string name="_bx_persons_menu_item_title_entries_online"><![CDATA[Online]]></string>
+
+    <string name="_bx_persons_grid_filter_item_title_adm_select_one_filter1"><![CDATA[All Statuses]]></string>
+    <string name="_bx_persons_grid_filter_item_title_adm_select_one_filter2"><![CDATA[All]]></string>
+    <string name="_bx_persons_grid_filter_item_title_adm_active"><![CDATA[Active]]></string>
+    <string name="_bx_persons_grid_filter_item_title_adm_pending"><![CDATA[Pending]]></string>
+    <string name="_bx_persons_grid_filter_item_title_adm_suspended"><![CDATA[Suspended]]></string>
+    <string name="_bx_persons_grid_filter_item_title_adm_unconfirmed"><![CDATA[Unconfirmed]]></string>
+    <string name="_bx_persons_grid_column_title_adm_active"><![CDATA[Active]]></string>
+    <string name="_bx_persons_grid_column_title_adm_fullname"><![CDATA[Name]]></string>
+    <string name="_bx_persons_grid_column_title_adm_last_online"><![CDATA[Last Logged]]></string>
+    <string name="_bx_persons_grid_column_title_adm_account"><![CDATA[Account]]></string>
+    <string name="_bx_persons_grid_action_title_adm_delete_with_content"><![CDATA[Delete With Content]]></string>
+    <string name="_bx_persons_grid_action_title_adm_clear_reports"><![CDATA[Clear reports]]></string>
+    <string name="_bx_persons_grid_action_title_adm_set_acl_level"><![CDATA[Set Membership]]></string>
+    <string name="_bx_persons_grid_action_title_adm_more_actions"><![CDATA[More Actions]]></string>
+    <string name="_bx_persons_grid_action_title_adm_audit_content"><![CDATA[Audit actions with profile]]></string>
+    <string name="_bx_persons_grid_action_title_adm_audit_profile"><![CDATA[Audit profile actions]]></string>
+    <string name="_bx_persons_grid_action_title_adm_manage_cf"><![CDATA[Manage audience]]></string>
+    
+    <string name="_bx_persons_grid_action_err_delete"><![CDATA[Cannot delete the selected person(s).]]></string>
+    <string name="_bx_persons_grid_txt_account_manager"><![CDATA[Redirect to manage account.]]></string>
+
+    <string name="_bx_persons_chart_growth"><![CDATA[Persons: Growth]]></string>
+    <string name="_bx_persons_chart_growth_speed"><![CDATA[Persons: Growth Speed]]></string>
+
+    <string name="_bx_persons_search_extended"><![CDATA[Persons Search]]></string>
+    <string name="_bx_persons_search_extended_cmts"><![CDATA[Persons Comments Search]]></string>
+
+    <string name="_bx_persons_alert_action_profile_cover_changed"><![CDATA[cover changed]]></string>
+    <string name="_bx_persons_alert_action_profile_picture_changed"><![CDATA[picture changed]]></string>
+
+    <string name="_bx_persons_txt_account_pending"><![CDATA[This profile is pending approval, please wait until it is activated.]]></string>
+    <string name="_bx_persons_txt_account_pending_moderation"><![CDATA[This <a href="{0}">profile</a> is pending approval.]]></string>
+    <string name="_bx_persons_txt_account_suspended"><![CDATA[This profile is suspended.]]></string>
+    <string name="_bx_persons_txt_account_suspended_moderation"><![CDATA[This <a href="{0}">profile</a> is suspended.]]></string>
+    <string name="_bx_persons_txt_N_friends"><![CDATA[{0} friends]]></string>
+    <string name="_bx_persons_txt_ntfs_timeline_post_common"><![CDATA[New post <b class="bx-ntfs-content-entry">{subentry_sample}</b> in <b class="bx-ntfs-content-profile">{owner_name}</b> profile timeline]]></string>
+    <string name="_bx_persons_txt_sample_single"><![CDATA[person]]></string>
+    <string name="_bx_persons_txt_sample_comment_single"><![CDATA[comment to person]]></string>
+    <string name="_bx_persons_txt_sample_vote_single"><![CDATA[vote to person]]></string>
+    <string name="_bx_persons_txt_sample_score_up_single"><![CDATA[score up vote to person]]></string>
+    <string name="_bx_persons_txt_sample_score_down_single"><![CDATA[score down vote to person]]></string>
+    <string name="_bx_persons_txt_sample_pp_single"><![CDATA[profile picture]]></string>
+    <string name="_bx_persons_txt_sample_pp_single_with_article"><![CDATA[a profile picture]]></string>
+    <string name="_bx_persons_txt_sample_pc_single"><![CDATA[profile cover]]></string>
+    <string name="_bx_persons_txt_sample_pc_single_with_article"><![CDATA[a profile cover]]></string>
+    <string name="_bx_persons_txt_sample_pi_action"><![CDATA[changed {0}]]></string>
+    <string name="_bx_persons_txt_sample_pi_action_user"><![CDATA[{0} changed {1}]]></string>
+
+    <string name="_bx_persons_email_friend_request"><![CDATA[Friend request]]></string>
+    <string name="_bx_persons_email_friend_request_subject"><![CDATA[Friendship Request]]></string>
+    <string name="_bx_persons_email_friend_request_body"><![CDATA[{email_header}
+<p><a href="{SenderUrl}">{SenderDisplayName}</a> wants to be friends with you. <a href="{FriendsLink}">Respond</a>.</p>
+{email_footer}]]></string>
+</resources>

+ 51 - 0
modules/boonex/posts/updates/15.0.2_15.0.3/install/config.php

@@ -0,0 +1,51 @@
+<?php
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ */
+
+$aConfig = array(
+    /**
+     * Main Section.
+     */
+    'title' => 'Posts',
+    'version_from' => '15.0.2',
+    'version_to' => '15.0.3',
+    'vendor' => 'UNA INC',
+
+    'compatible_with' => array(
+        '15.0.0-B2'
+    ),
+
+    /**
+     * 'home_dir' and 'home_uri' - should be unique. Don't use spaces in 'home_uri' and the other special chars.
+     */
+    'home_dir' => 'boonex/posts/updates/update_15.0.2_15.0.3/',
+    'home_uri' => 'posts_update_1502_1503',
+
+    'module_dir' => 'boonex/posts/',
+    'module_uri' => 'posts',
+
+    'db_prefix' => 'bx_posts_',
+    'class_prefix' => 'BxPosts',
+
+    /**
+     * Installation/Uninstallation Section.
+     */
+    'install' => array(
+        'execute_sql' => 1,
+        'update_files' => 1,
+        'update_languages' => 1,
+        'clear_db_cache' => 1,
+    ),
+
+    /**
+     * Category for language keys.
+     */
+    'language_category' => 'Posts',
+
+    /**
+     * Files Section
+     */
+    'delete_files' => array(),
+);

+ 13 - 0
modules/boonex/posts/updates/15.0.2_15.0.3/install/installer.php

@@ -0,0 +1,13 @@
+<?php
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ */
+
+class BxPostsUpdater extends BxDolStudioUpdater
+{
+    function __construct($aConfig)
+    {
+        parent::__construct($aConfig);
+    }
+}

+ 4 - 0
modules/boonex/posts/updates/15.0.2_15.0.3/install/langs/en.xml

@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources name="en" flag="gb" title="English">
+	<string_upd name="_bx_posts_form_entry_input_title_err"><![CDATA[Title is essential min 3 max 160.]]></string_upd>
+</resources>

+ 2 - 0
modules/boonex/posts/updates/15.0.2_15.0.3/install/sql/install.sql

@@ -0,0 +1,2 @@
+-- FORMS
+UPDATE `sys_form_inputs` SET `checker_func`='Length', `checker_params`='a:2:{s:3:"min";i:3;s:3:"max";i:160;}' WHERE `object`='bx_posts' AND `name`='title';

+ 137 - 0
modules/boonex/posts/updates/15.0.2_15.0.3/source/classes/BxPostsSearchResult.php

@@ -0,0 +1,137 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Posts Posts
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+class BxPostsSearchResult extends BxBaseModTextSearchResult
+{
+    function __construct($sMode = '', $aParams = array())
+    {
+        parent::__construct($sMode, $aParams);
+
+        $this->aCurrent = array(
+            'name' => 'bx_posts',
+            'module_name' => 'bx_posts',
+            'object_metatags' => 'bx_posts',
+            'title' => _t('_bx_posts_page_title_browse'),
+            'table' => 'bx_posts_posts',
+            'ownFields' => array('id', 'title', 'abstract', 'text', 'thumb', 'thumb_data', 'author', 'added', 'labels', 'location'),
+            'searchFields' => array(),
+            'restriction' => array(
+                'author' => array('value' => '', 'field' => 'author', 'operator' => '='),
+                'featured' => array('value' => '', 'field' => 'featured', 'operator' => '<>'),
+                'status' => array('value' => 'active', 'field' => 'status', 'operator' => '='),
+                'statusAdmin' => array('value' => 'active', 'field' => 'status_admin', 'operator' => '='),
+            ),
+            'paginate' => array('perPage' => getParam('bx_posts_per_page_browse'), 'start' => 0),
+            'sorting' => 'last',
+            'rss' => array(
+                'title' => '',
+                'link' => '',
+                'image' => '',
+                'profile' => 0,
+                'fields' => array (
+                    'Guid' => 'link',
+                    'Link' => 'link',
+                    'Title' => 'title',
+                    'DateTimeUTS' => 'added',
+                    'Desc' => 'text',
+                    'Image' => 'thumb'
+                ),
+            ),
+            'ident' => 'id',
+        );
+
+        $this->sFilterName = 'bx_posts_filter';
+        $this->oModule = $this->getMain();
+
+        $CNF = &$this->oModule->_oConfig->CNF;
+
+        $sSearchFields = getParam($CNF['PARAM_SEARCHABLE_FIELDS']);
+        $this->aCurrent['searchFields'] = !empty($sSearchFields) ? explode(',', $sSearchFields) : '';
+
+        $oProfileAuthor = null;
+
+        switch ($sMode) {
+            case 'author':
+                if(!$this->_updateCurrentForAuthor($sMode, $aParams, $oProfileAuthor))
+                    $this->isError = true;
+                break;
+
+            case 'context':
+                if(!$this->_updateCurrentForContext($sMode, $aParams, $oProfileAuthor))
+                    $this->isError = true;
+                break;
+
+            case 'followed_contexts':
+                if(!$this->_updateCurrentForFollowedContexts($sMode, $aParams, $oProfileAuthor))
+                    $this->isError = true;
+                break;
+
+            case 'favorite':
+                if(!$this->_updateCurrentForFavorite($sMode, $aParams, $oProfileAuthor))
+                    $this->isError = true;
+                break;
+			
+            case 'recent':
+            case 'public':
+                $this->sBrowseUrl = BxDolPermalinks::getInstance()->permalink($CNF['URL_HOME']);
+                $this->aCurrent['title'] = _t('_bx_posts_page_title_browse_recent');
+                $this->aCurrent['rss']['link'] = 'modules/?r=posts/rss/' . $sMode;
+                break;
+
+            case 'featured':
+                $this->sBrowseUrl = BxDolPermalinks::getInstance()->permalink($CNF['URL_HOME']);
+                $this->aCurrent['title'] = _t('_bx_posts_page_title_browse_featured');
+                $this->aCurrent['restriction']['featured']['value'] = '0';
+                $this->aCurrent['rss']['link'] = 'modules/?r=posts/rss/' . $sMode;
+                $this->aCurrent['sorting'] = 'featured';
+                break;
+
+            case 'popular':
+                $this->sBrowseUrl = BxDolPermalinks::getInstance()->permalink($CNF['URL_TOP']);
+                $this->aCurrent['title'] = _t('_bx_posts_page_title_browse_popular');
+                $this->aCurrent['rss']['link'] = 'modules/?r=posts/rss/' . $sMode;
+                $this->aCurrent['sorting'] = 'popular';
+                break;
+
+            case 'top':
+                $this->sBrowseUrl = BxDolPermalinks::getInstance()->permalink($CNF['URL_POPULAR']);
+                $this->aCurrent['title'] = _t('_bx_posts_page_title_browse_top');
+                $this->aCurrent['rss']['link'] = 'modules/?r=posts/rss/' . $sMode;
+                $this->aCurrent['sorting'] = 'top';
+                break;
+
+            case 'updated':
+                $this->sBrowseUrl = BxDolPermalinks::getInstance()->permalink($CNF['URL_UPDATED']);
+                $this->aCurrent['title'] = _t('_bx_posts_page_title_browse_updated');
+                $this->aCurrent['rss']['link'] = 'modules/?r=posts/rss/' . $sMode;
+                $this->aCurrent['sorting'] = 'updated';
+                break;
+
+            case '': // search results
+                $this->checkRestrictionsForContext($sMode, $aParams, $oProfileAuthor);
+                $this->sBrowseUrl = BX_DOL_SEARCH_KEYWORD_PAGE;
+                $this->aCurrent['title'] = _t('_bx_posts');
+                unset($this->aCurrent['paginate']['perPage'], $this->aCurrent['rss']);
+                break;
+
+            default:
+                $sMode = '';
+                $this->isError = true;
+        }
+
+        $this->processReplaceableMarkers($oProfileAuthor);
+
+        $this->addConditionsForPrivateContent($CNF, $oProfileAuthor);
+        $this->addCustomConditions($CNF, $oProfileAuthor, $sMode, $aParams);
+    }
+}
+
+/** @} */

+ 155 - 0
modules/boonex/posts/updates/15.0.2_15.0.3/source/install/config.php

@@ -0,0 +1,155 @@
+<?php
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Posts Posts
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+$aConfig = array(
+
+    /**
+     * Main Section.
+     */
+    'type' => BX_DOL_MODULE_TYPE_MODULE,
+    'name' => 'bx_posts',
+    'title' => 'Posts',
+    'note' => 'Basic blogging module.',
+    'version' => '15.0.3',
+    'vendor' => 'UNA INC',
+    'help_url' => 'http://feed.una.io/?section={module_name}',
+
+    'compatible_with' => array(
+        '15.0.0-B2'
+    ),
+
+    /**
+     * 'home_dir' and 'home_uri' - should be unique. Don't use spaces in 'home_uri' and the other special chars.
+     */
+    'home_dir' => 'boonex/posts/',
+    'home_uri' => 'posts',
+
+    'db_prefix' => 'bx_posts_',
+    'class_prefix' => 'BxPosts',
+
+    /**
+     * Category for language keys.
+     */
+    'language_category' => 'Posts',
+
+    /**
+     * List of page triggers.
+     */
+    'page_triggers' => array (
+    	'trigger_page_profile_view_entry',
+    ),
+    
+    /**
+     * Menu triggers.
+     */
+    'menu_triggers' => array(
+        'trigger_profile_view_submenu',
+        'trigger_group_view_submenu',
+    ),
+
+    /**
+     * Storage objects to automatically delete files from upon module uninstallation.
+     * Note. Don't add storage objects used in transcoder objects.
+     */
+    'storages' => array(
+        'bx_posts_covers',
+        'bx_posts_photos',
+        'bx_posts_videos',
+        'bx_posts_files'
+    ),
+
+    /**
+     * Transcoders.
+     */
+    'transcoders' => array(
+        'bx_posts_preview',
+        'bx_posts_miniature',
+        'bx_posts_gallery',
+        'bx_posts_cover',
+
+        'bx_posts_preview_photos',
+        'bx_posts_miniature_photos',
+        'bx_posts_gallery_photos',
+        'bx_posts_view_photos',
+
+        'bx_posts_videos_poster',
+        'bx_posts_videos_poster_preview',
+        'bx_posts_videos_mp4',
+        'bx_posts_videos_mp4_hd',
+        
+        'bx_posts_sounds_mp3',
+
+        'bx_posts_preview_files',
+        'bx_posts_gallery_files'
+    ),
+
+    /**
+     * Extended Search Forms.
+     */
+    'esearches' => array(
+        'bx_posts',
+    	'bx_posts_cmts'
+    ),
+
+    /**
+     * Installation/Uninstallation Section.
+     */
+    'install' => array(
+        'execute_sql' => 1,
+        'update_languages' => 1,
+        'clear_db_cache' => 1,
+    ),
+    'uninstall' => array (
+    	'process_esearches' => 1,
+        'execute_sql' => 1,
+        'update_languages' => 1,
+        'update_relations' => 1,
+        'clear_db_cache' => 1,
+    ),
+    'enable' => array(
+        'execute_sql' => 1,
+        'update_relations' => 1,
+        'clear_db_cache' => 1,
+    ),
+    'enable_success' => array(
+        'process_menu_triggers' => 1,
+        'process_page_triggers' => 1,
+    	'process_esearches' => 1,
+        'register_transcoders' => 1,
+        'clear_db_cache' => 1,
+    ),
+    'disable' => array (
+        'execute_sql' => 1,
+        'update_relations' => 1,
+        'unregister_transcoders' => 1,
+        'clear_db_cache' => 1,
+    ),
+    'disable_failed' => array (
+        'register_transcoders' => 1,
+        'clear_db_cache' => 1,
+    ),
+
+    /**
+     * Dependencies Section
+     */
+    'dependencies' => array(),
+
+    /**
+     * Relations Section
+     */
+    'relations' => array(
+    	'bx_timeline',
+    	'bx_notifications'
+    ),
+
+);
+
+/** @} */

+ 367 - 0
modules/boonex/posts/updates/15.0.2_15.0.3/source/install/langs/en.xml

@@ -0,0 +1,367 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources name="en" flag="gb" title="English">
+
+    <string name="_bx_posts"><![CDATA[Posts]]></string>
+    <string name="_bx_posts_cmts"><![CDATA[Posts' Comments]]></string>
+    <string name="_bx_posts_reactions"><![CDATA[Posts' Reactions]]></string>
+
+    <string name="_bx_posts_option_enable_auto_approve"><![CDATA[Auto approve a post after creation]]></string>
+    <string name="_bx_posts_option_summary_chars"><![CDATA[Number of characters in auto-cropped post summary]]></string>
+    <string name="_bx_posts_option_plain_summary_chars"><![CDATA[Number of characters in plain post description when post hasn't thumb]]></string>
+    <string name="_bx_posts_option_per_page_browse"><![CDATA[Number of items per page]]></string>
+    <string name="_bx_posts_option_per_page_profile"><![CDATA[Number of items on profile/group page]]></string>
+    <string name="_bx_posts_option_rss_num"><![CDATA[Number of items in RSS feed]]></string>
+    <string name="_bx_posts_option_searchable_fields"><![CDATA[Searchable fields for keyword search]]></string>
+    <string name="_bx_posts_option_auto_activation_for_categories"><![CDATA[Auto-Activation For Categories]]></string>
+    <string name="_bx_posts_option_per_page_for_favorites_lists"><![CDATA[Number of favorite lists per page]]></string>
+
+    <string name="_bx_posts_form_entry"><![CDATA[Posts]]></string>
+    <string name="_bx_posts_form_entry_display_add"><![CDATA[Add Post]]></string>
+    <string name="_bx_posts_form_entry_display_edit"><![CDATA[Edit Post]]></string>
+    <string name="_bx_posts_form_entry_display_delete"><![CDATA[Delete Post]]></string>
+    <string name="_bx_posts_form_entry_display_view"><![CDATA[View Post]]></string>
+    <string name="_bx_posts_form_entry_input_author"><![CDATA[Author]]></string>
+    <string name="_bx_posts_form_entry_input_sys_do_submit"><![CDATA[Submit]]></string>
+    <string name="_bx_posts_form_entry_input_do_submit"><![CDATA[Submit]]></string>
+    <string name="_bx_posts_form_entry_input_sys_do_publish"><![CDATA[Publish]]></string>
+    <string name="_bx_posts_form_entry_input_do_publish"><![CDATA[Publish]]></string>
+    <string name="_bx_posts_form_entry_input_sys_title"><![CDATA[Title]]></string>
+    <string name="_bx_posts_form_entry_input_title"><![CDATA[Title]]></string>
+    <string name="_bx_posts_form_entry_input_title_err"><![CDATA[Title is essential min 3 max 160.]]></string>
+    <string name="_bx_posts_form_entry_input_sys_cat"><![CDATA[Category]]></string>
+    <string name="_bx_posts_form_entry_input_cat"><![CDATA[Category]]></string>
+    <string name="_bx_posts_form_entry_input_cat_err"><![CDATA[Please select category]]></string>
+    <string name="_bx_posts_form_entry_input_sys_multicat"><![CDATA[Categories]]></string>
+    <string name="_bx_posts_form_entry_input_multicat"><![CDATA[Categories]]></string>
+    <string name="_bx_posts_form_entry_input_multicat_err"><![CDATA[Please select category]]></string>
+    <string name="_bx_posts_form_entry_input_sys_abstract"><![CDATA[Summary]]></string>
+    <string name="_bx_posts_form_entry_input_abstract"><![CDATA[Summary]]></string>
+    <string name="_bx_posts_form_entry_input_sys_text"><![CDATA[Text]]></string>
+    <string name="_bx_posts_form_entry_input_text"><![CDATA[Text]]></string>
+    <string name="_bx_posts_form_entry_input_text_err"><![CDATA[Text field can't be empty]]></string>
+    <string name="_bx_posts_form_entry_input_sys_delete_confirm"><![CDATA[Delete confirmation]]></string>
+    <string name="_bx_posts_form_entry_input_delete_confirm"><![CDATA[I am sure I want to delete this post]]></string>
+    <string name="_bx_posts_form_entry_input_delete_confirm_info"><![CDATA[This action can not be undone]]></string>
+    <string name="_bx_posts_form_entry_input_delete_confirm_error"><![CDATA[Please check this checkbox if you really want to delete the post]]></string>
+    <string name="_bx_posts_form_entry_input_sys_covers"><![CDATA[Header Image]]></string>
+    <string name="_bx_posts_form_entry_input_covers"><![CDATA[Header Image]]></string>
+    <string name="_bx_posts_form_entry_input_covers_uploader_simple_title"><![CDATA[Upload]]></string>
+    <string name="_bx_posts_form_entry_input_covers_uploader_html5_title"><![CDATA[Upload]]></string>
+    <string name="_bx_posts_form_entry_input_sys_pictures"><![CDATA[Images]]></string>
+    <string name="_bx_posts_form_entry_input_pictures"><![CDATA[]]></string>
+    <string name="_bx_posts_form_entry_input_sys_videos"><![CDATA[Videos]]></string>
+    <string name="_bx_posts_form_entry_input_videos"><![CDATA[]]></string>
+    <string name="_bx_posts_form_entry_input_sys_sounds"><![CDATA[Sounds]]></string>
+    <string name="_bx_posts_form_entry_input_sounds"><![CDATA[]]></string>
+    <string name="_bx_posts_form_entry_input_sys_files"><![CDATA[Files]]></string>
+    <string name="_bx_posts_form_entry_input_files"><![CDATA[]]></string>
+    <string name="_bx_posts_form_entry_input_sys_polls"><![CDATA[Polls]]></string>
+    <string name="_bx_posts_form_entry_input_sys_allow_view_to"><![CDATA[Visibility]]></string>
+    <string name="_bx_posts_form_entry_input_allow_view_to"><![CDATA[Visibility]]></string>
+    <string name="_bx_posts_form_entry_input_allow_view_favorite_list"><![CDATA[Visibility]]></string>
+    <string name="_bx_posts_form_entry_input_sys_date_added"><![CDATA[Created]]></string>
+    <string name="_bx_posts_form_entry_input_date_added"><![CDATA[Created]]></string>
+    <string name="_bx_posts_form_entry_input_sys_date_changed"><![CDATA[Updated]]></string>
+    <string name="_bx_posts_form_entry_input_date_changed"><![CDATA[Updated]]></string>
+    <string name="_bx_posts_form_entry_input_sys_date_published"><![CDATA[Publishing time]]></string>
+    <string name="_bx_posts_form_entry_input_date_published"><![CDATA[Publishing time]]></string>
+    <string name="_bx_posts_form_entry_input_date_published_info"><![CDATA[Leave empty to publish immediately.]]></string>
+    <string name="_bx_posts_form_entry_input_sys_attachments"><![CDATA[Attachments]]></string>
+    <string name="_bx_posts_form_entry_input_sys_allow_comments"><![CDATA[Allow comments]]></string>
+    <string name="_bx_posts_form_entry_input_allow_comments"><![CDATA[Allow comments]]></string>
+
+    <string name="_bx_posts_form_poll"><![CDATA[Polls]]></string>
+    <string name="_bx_posts_form_poll_display_add"><![CDATA[Add Poll]]></string>
+    <string name="_bx_posts_form_poll_input_sys_text"><![CDATA[Question]]></string>
+    <string name="_bx_posts_form_poll_input_text"><![CDATA[Question]]></string>
+    <string name="_bx_posts_form_poll_input_text_err"><![CDATA[Question is essential. Please, fill in this field]]></string>
+    <string name="_bx_posts_form_poll_input_sys_answers"><![CDATA[Answers]]></string>
+    <string name="_bx_posts_form_poll_input_answers"><![CDATA[Answers]]></string>
+    <string name="_bx_posts_form_poll_input_answers_err"><![CDATA[Poll should have at least 2 non-empty answers.]]></string>
+    <string name="_bx_posts_form_poll_input_answers_add"><![CDATA[Add More]]></string>
+    <string name="_bx_posts_form_poll_input_sys_do_submit"><![CDATA[Add]]></string>
+    <string name="_bx_posts_form_poll_input_do_submit"><![CDATA[Add]]></string>
+    <string name="_bx_posts_form_poll_input_do_cancel"><![CDATA[Close]]></string>
+
+    <string name="_bx_posts_category_form_entry"><![CDATA[Categories Form]]></string>
+    <string name="_bx_posts_category_display_add"><![CDATA[Add category]]></string>
+    <string name="_bx_posts_category_display_edit"><![CDATA[Edit category]]></string>
+    <string name="_bx_posts_category_form_entry_input_sys_value"><![CDATA[Value]]></string>
+    <string name="_bx_posts_category_form_entry_input_value"><![CDATA[Value]]></string>>
+    <string name="_bx_posts_category_form_entry_input_value_err"><![CDATA[Value is essential. Please, fill in this field]]></string>
+    <string name="_bx_posts_lmi_cpt_categories"><![CDATA[Categories]]></string>
+
+    <string name="_bx_posts_acl_action_create_entry"><![CDATA[Create Post]]></string>
+    <string name="_bx_posts_acl_action_delete_entry"><![CDATA[Delete Post]]></string>
+    <string name="_bx_posts_acl_action_view_entry"><![CDATA[View Post]]></string>
+    <string name="_bx_posts_acl_action_set_thumb"><![CDATA[Set Post Header Image]]></string>
+    <string name="_bx_posts_acl_action_edit_any_entry"><![CDATA[Edit Any Post]]></string>
+    <string name="_bx_posts_acl_action_delete_any_entry"><![CDATA[Delete Any Post]]></string>
+
+    <string name="_bx_posts_page_title_sys_create_entry"><![CDATA[New Post]]></string>
+    <string name="_bx_posts_page_title_create_entry"><![CDATA[New Post]]></string>
+    <string name="_bx_posts_page_block_title_create_entry"><![CDATA[New Post]]></string>
+    <string name="_bx_posts_page_title_sys_edit_entry"><![CDATA[Edit]]></string>
+    <string name="_bx_posts_page_title_edit_entry"><![CDATA[Edit]]></string>
+    <string name="_bx_posts_page_block_title_edit_entry"><![CDATA[Edit]]></string>
+    <string name="_bx_posts_page_title_sys_delete_entry"><![CDATA[Delete]]></string>
+    <string name="_bx_posts_page_title_delete_entry"><![CDATA[Delete]]></string>
+    <string name="_bx_posts_page_block_title_delete_entry"><![CDATA[Delete]]></string>
+    <string name="_bx_posts_page_title_sys_view_entry"><![CDATA[View Post]]></string>
+    <string name="_bx_posts_page_title_view_entry"><![CDATA[{title}]]></string>
+    <string name="_bx_posts_page_block_title_entry_text"><![CDATA[Post Text]]></string>
+    <string name="_bx_posts_page_title_browse"><![CDATA[Posts]]></string>
+    <string name="_bx_posts_page_title_search_results"><![CDATA[Posts matching "{0}"]]></string>
+    <string name="_bx_posts_page_title_browse_by_author"><![CDATA[Posts of {display_name}]]></string>
+    <string name="_bx_posts_page_title_browse_by_context"><![CDATA[Posts in {display_name}]]></string>
+    <string name="_bx_posts_page_title_browse_featured"><![CDATA[Featured Posts]]></string>
+    <string name="_bx_posts_page_title_browse_recent"><![CDATA[Latest Posts]]></string>
+    <string name="_bx_posts_page_title_browse_popular"><![CDATA[Popular Posts]]></string>
+    <string name="_bx_posts_page_title_browse_top"><![CDATA[Top Posts]]></string>
+    <string name="_bx_posts_page_title_browse_updated"><![CDATA[Updated Posts]]></string>
+    <string name="_bx_posts_page_title_sys_home"><![CDATA[Posts Home]]></string>
+    <string name="_bx_posts_page_title_home"><![CDATA[Posts]]></string>
+    <string name="_bx_posts_page_block_title_featured_entries_view_extended"><![CDATA[Featured Posts]]></string>
+    <string name="_bx_posts_page_block_title_recent_entries"><![CDATA[Latest Posts (Gallery View)]]></string>
+    <string name="_bx_posts_page_block_title_recent_entries_view_extended"><![CDATA[Latest Posts]]></string>
+    <string name="_bx_posts_page_block_title_recent_entries_view_full"><![CDATA[Latest Posts (Full View)]]></string>
+    <string name="_bx_posts_page_block_title_entry_social_sharing"><![CDATA[Share]]></string>
+    <string name="_bx_posts_page_block_title_entry_author"><![CDATA[Author]]></string>
+    <string name="_bx_posts_page_block_title_entry_breadcrumb"><![CDATA[Breadcrumb]]></string>
+    <string name="_bx_posts_page_block_title_entry_actions"><![CDATA[Actions]]></string>
+    <string name="_bx_posts_page_block_title_entry_comments"><![CDATA[Comments]]></string>
+    <string name="_bx_posts_page_block_title_entry_reports"><![CDATA[Reports]]></string>
+    <string name="_bx_posts_page_block_title_entry_comments_link"><![CDATA[Comments to <a href="{entry_link}">{title}</a>]]></string>
+    <string name="_bx_posts_page_block_title_entry_location"><![CDATA[Location]]></string>
+    <string name="_bx_posts_page_block_title_entry_attachments"><![CDATA[Attachments]]></string>
+    <string name="_bx_posts_page_block_title_entry_polls"><![CDATA[Polls]]></string>
+    <string name="_bx_posts_page_block_title_entry_all_actions"><![CDATA[All Actions]]></string>
+    <string name="_bx_posts_page_title_sys_entries_popular"><![CDATA[Popular Posts]]></string>
+    <string name="_bx_posts_page_title_entries_popular"><![CDATA[Popular Posts]]></string>
+    <string name="_bx_posts_page_title_sys_entries_top"><![CDATA[Top Posts]]></string>
+    <string name="_bx_posts_page_title_entries_top"><![CDATA[Top Posts]]></string>
+    <string name="_bx_posts_page_title_sys_entries_updated"><![CDATA[Updated Posts]]></string>
+    <string name="_bx_posts_page_title_entries_updated"><![CDATA[Updated Posts]]></string>
+    <string name="_bx_posts_page_title_sys_entries_search"><![CDATA[Search]]></string>
+    <string name="_bx_posts_page_title_sys_entries_favorites"><![CDATA[Favorites Posts]]></string>
+    <string name="_bx_posts_page_title_entries_favorites"><![CDATA[Favorites Posts]]></string>
+    <string name="_bx_posts_page_title_entries_search"><![CDATA[Search]]></string>
+    <string name="_bx_posts_page_block_title_search_form"><![CDATA[Search Form]]></string>
+    <string name="_bx_posts_page_block_title_search_results"><![CDATA[Search Results]]></string>
+    <string name="_bx_posts_page_block_title_search_form_cmts"><![CDATA[Comments Search Form]]></string>
+    <string name="_bx_posts_page_block_title_search_results_cmts"><![CDATA[Comments Search Results]]></string>
+    <string name="_bx_posts_page_block_title_popular_entries"><![CDATA[Popular Posts]]></string>
+    <string name="_bx_posts_page_block_title_popular_entries_view_extended"><![CDATA[Popular Posts (Extended View)]]></string>
+    <string name="_bx_posts_page_block_title_popular_entries_view_full"><![CDATA[Popular Posts (Full View)]]></string>
+    <string name="_bx_posts_page_block_title_top_entries"><![CDATA[Top Posts]]></string>
+    <string name="_bx_posts_page_block_title_updated_entries"><![CDATA[Updated Posts]]></string>
+    <string name="_bx_posts_page_block_title_sys_favorites_entries"><![CDATA[Favorite List]]></string>
+    <string name="_bx_posts_page_block_title_favorites_entries"><![CDATA["{title}" List]]></string>
+    <string name="_bx_posts_page_block_title_favorites_entries_info"><![CDATA[Info]]></string>
+    <string name="_bx_posts_page_block_title_favorites_entries_actions"><![CDATA[Favorites List Actions]]></string>
+    <string name="_bx_posts_page_title_sys_view_entry_comments"><![CDATA[Post Comments]]></string>
+    <string name="_bx_posts_page_title_view_entry_comments"><![CDATA[Comments to {title}]]></string>
+    <string name="_bx_posts_page_title_sys_entries_of_author"><![CDATA[Posts of author]]></string>
+    <string name="_bx_posts_page_title_entries_of_author"><![CDATA[Posts by {display_name}]]></string>
+    <string name="_bx_posts_page_title_sys_entries_in_context"><![CDATA[Posts in context]]></string>
+    <string name="_bx_posts_page_title_entries_in_context"><![CDATA[Posts in {display_name}]]></string>
+    <string name="_bx_posts_page_block_title_favorites_of_author"><![CDATA[Favorites by <a href="{profile_link}">{display_name}</a>]]></string>
+    <string name="_bx_posts_page_block_title_sys_favorites_of_author"><![CDATA[Favorites of author]]></string>
+    <string name="_bx_posts_page_block_title_entries_of_author"><![CDATA[Posts by <a href="{profile_link}">{display_name}</a>]]></string>
+    <string name="_bx_posts_page_block_title_sys_entries_of_author"><![CDATA[Posts of author]]></string>
+    <string name="_bx_posts_page_block_title_entries_in_context"><![CDATA[Posts in <a href="{profile_link}">{display_name}</a>]]></string>
+    <string name="_bx_posts_page_block_title_sys_entries_in_context"><![CDATA[Posts in context]]></string>
+    <string name="_bx_posts_page_block_title_sys_multi_categories_in_context"><![CDATA[Multi categories in context]]></string>
+    <string name="_bx_posts_page_block_title_multi_categories_in_context"><![CDATA[Categories in <a href="{profile_link}">{display_name}</a>]]></string>
+    <string name="_bx_posts_page_block_title_entries_actions"><![CDATA[Posts actions]]></string>
+    <string name="_bx_posts_page_block_title_browse_cmts"><![CDATA[Posts' Comments]]></string>
+    <string name="_bx_posts_page_title_sys_manage"><![CDATA[Manage Own]]></string>
+    <string name="_bx_posts_page_title_sys_manage_administration"><![CDATA[Manage All]]></string>
+    <string name="_bx_posts_page_title_manage"><![CDATA[Manage]]></string>
+    <string name="_bx_posts_page_block_title_system_manage"><![CDATA[Manage Own]]></string>
+    <string name="_bx_posts_page_block_title_system_manage_administration"><![CDATA[Manage All]]></string>
+    <string name="_bx_posts_page_block_title_manage"><![CDATA[Manage]]></string>    
+    <string name="_bx_posts_page_block_title_popular_keywords"><![CDATA[Popular Hashtags]]></string>
+    <string name="_bx_posts_page_block_title_cats"><![CDATA[Posts Categories]]></string>
+    <string name="_bx_posts_page_block_title_sys_multicats"><![CDATA[Posts Categories(Multi)]]></string>
+    <string name="_bx_posts_page_block_title_multicats"><![CDATA[Posts Categories]]></string>
+    <string name="_bx_posts_page_block_title_entry_info"><![CDATA[Info]]></string>
+    <string name="_bx_posts_page_block_title_sys_my_entries"><![CDATA[User Posts]]></string>
+    <string name="_bx_posts_page_block_title_my_entries"><![CDATA[{display_name} Posts]]></string>
+    <string name="_bx_posts_page_block_title_sys_recent_entries_view_showcase"><![CDATA[Latest Posts (Showcase View)]]></string>
+    <string name="_bx_posts_page_block_title_recent_entries_view_showcase"><![CDATA[Latest Posts]]></string>
+    <string name="_bx_posts_page_block_title_sys_popular_entries_view_showcase"><![CDATA[Popular Posts (Showcase View)]]></string>
+    <string name="_bx_posts_page_block_title_popular_entries_view_showcase"><![CDATA[Popular Posts]]></string>
+    <string name="_bx_posts_page_block_title_sys_featured_entries_view_showcase"><![CDATA[Featured Posts (Showcase View)]]></string>
+    <string name="_bx_posts_page_block_title_featured_entries_view_showcase"><![CDATA[Featured Posts]]></string>
+    <string name="_bx_posts_page_block_title_sys_entry_context"><![CDATA[Posted in]]></string>
+    <string name="_bx_posts_page_block_title_entry_context"><![CDATA[Posted in]]></string>
+
+    <string name="_bx_posts_menu_title_entry_attachments"><![CDATA[Form Attachments]]></string>
+    <string name="_bx_posts_menu_set_title_entry_attachments"><![CDATA[Form Attachments]]></string>
+    <string name="_bx_posts_menu_item_title_system_cpa_photo_simple"><![CDATA[Add Photo (simple)]]></string>
+    <string name="_bx_posts_menu_item_title_cpa_photo_simple"><![CDATA[Add Photo]]></string>
+    <string name="_bx_posts_menu_item_title_system_cpa_photo_html5"><![CDATA[Add Photo (html5)]]></string>
+    <string name="_bx_posts_menu_item_title_cpa_photo_html5"><![CDATA[Add Photos]]></string>
+    <string name="_bx_posts_menu_item_title_system_cpa_video_simple"><![CDATA[Add Video (simple)]]></string>
+    <string name="_bx_posts_menu_item_title_cpa_video_simple"><![CDATA[Add Video]]></string>
+    <string name="_bx_posts_menu_item_title_system_cpa_video_record_video"><![CDATA[Record Video]]></string>
+    <string name="_bx_posts_menu_item_title_cpa_video_record_video"><![CDATA[Record Video]]></string>
+    <string name="_bx_posts_menu_item_title_system_cpa_video_html5"><![CDATA[Add Video (html5)]]></string>
+    <string name="_bx_posts_menu_item_title_cpa_video_html5"><![CDATA[Add Videos]]></string>
+    <string name="_bx_posts_menu_item_title_system_cpa_file_simple"><![CDATA[Add File (simple)]]></string>
+
+    <string name="_bx_posts_menu_item_title_system_cpa_sound_simple"><![CDATA[Add Sound (simple)]]></string>
+    <string name="_bx_posts_menu_item_title_cpa_sound_simple"><![CDATA[Add Sound]]></string>
+    <string name="_bx_posts_menu_item_title_system_cpa_sound_html5"><![CDATA[Add Sound (html5)]]></string>
+    <string name="_bx_posts_menu_item_title_cpa_sound_html5"><![CDATA[Add Sound]]></string>
+  
+    <string name="_bx_posts_menu_item_title_cpa_file_simple"><![CDATA[Add File]]></string>
+    <string name="_bx_posts_menu_item_title_system_cpa_file_html5"><![CDATA[Add File (html5)]]></string>
+    <string name="_bx_posts_menu_item_title_cpa_file_html5"><![CDATA[Add Files]]></string>
+    <string name="_bx_posts_menu_item_title_system_cpa_poll"><![CDATA[Add Poll]]></string>
+    <string name="_bx_posts_menu_item_title_cpa_poll"><![CDATA[Add Poll]]></string>
+    
+    <string name="_bx_posts_menu_item_title_system_add_link"><![CDATA[Add Link]]></string>
+    <string name="_bx_posts_menu_item_title_add_link"><![CDATA[Add Link]]></string>
+    <string name="_bx_posts_form_post_input_link_err_delete"><![CDATA[Cannot remove the link. Please report.]]></string>
+    <string name="_bx_posts_form_post_input_sys_link"><![CDATA[Link]]></string>
+    <string name="_bx_posts_form_post_input_link_alt"><![CDATA[Add Link]]></string>
+    <string name="_bx_posts_form_attach_link"><![CDATA[Attach Link]]></string>
+    <string name="_bx_posts_form_attach_link_display_add"><![CDATA[Attach Link]]></string>
+    <string name="_bx_posts_form_attach_link_input_sys_content_id"><![CDATA[Content Id]]></string>
+    <string name="_bx_posts_form_attach_link_input_sys_url"><![CDATA[Add Link]]></string>
+    <string name="_bx_posts_form_attach_link_input_url_err"><![CDATA[Correct Link is essential. Please, fill in this field.]]></string>
+    <string name="_bx_posts_form_attach_link_input_url"><![CDATA[Add Link]]></string>
+    <string name="_bx_posts_form_attach_link_input_do_submit"><![CDATA[Add]]></string>
+    <string name="_bx_posts_form_attach_link_input_sys_do_submit"><![CDATA[Add]]></string>
+    <string name="_bx_posts_form_attach_link_input_do_cancel"><![CDATA[Close]]></string>
+
+    <string name="_bx_posts_menu_set_title_view_entry"><![CDATA[Post Actions]]></string>
+    <string name="_bx_posts_menu_title_view_entry"><![CDATA[Post Actions]]></string>
+    <string name="_bx_posts_menu_title_submenu"><![CDATA[Posts Submenu]]></string>
+    <string name="_bx_posts_menu_title_public_submenu"><![CDATA[Posts]]></string>
+    <string name="_bx_posts_menu_set_title_submenu"><![CDATA[Posts Submenu]]></string>
+    <string name="_bx_posts_menu_item_title_system_create_entry"><![CDATA[Post]]></string>
+    <string name="_bx_posts_menu_item_title_create_entry"><![CDATA[Post]]></string>
+    <string name="_bx_posts_menu_item_title_system_edit_entry"><![CDATA[Edit]]></string>
+    <string name="_bx_posts_menu_item_title_edit_entry"><![CDATA[Edit]]></string>
+    <string name="_bx_posts_menu_item_title_system_delete_entry"><![CDATA[Delete]]></string>
+    <string name="_bx_posts_menu_item_title_delete_entry"><![CDATA[Delete]]></string>
+    <string name="_bx_posts_menu_item_title_system_view_entry"><![CDATA[View Post]]></string>
+    <string name="_bx_posts_menu_item_title_system_entries_home"><![CDATA[Posts]]></string>
+    <string name="_bx_posts_menu_item_title_entries_home"><![CDATA[Posts]]></string>
+    <string name="_bx_posts_menu_item_title_system_entries_public"><![CDATA[Latest]]></string>
+    <string name="_bx_posts_menu_item_title_entries_public"><![CDATA[Latest]]></string>
+    <string name="_bx_posts_menu_item_title_system_entries_manage"><![CDATA[Manage]]></string>
+    <string name="_bx_posts_menu_item_title_entries_manage"><![CDATA[Manage]]></string>
+    <string name="_bx_posts_menu_item_title_system_entries_popular"><![CDATA[Popular]]></string>
+    <string name="_bx_posts_menu_item_title_entries_popular"><![CDATA[Popular]]></string>
+    <string name="_bx_posts_menu_item_title_system_entries_top"><![CDATA[Top]]></string>
+    <string name="_bx_posts_menu_item_title_entries_top"><![CDATA[Top]]></string>
+    <string name="_bx_posts_menu_item_title_system_entries_search"><![CDATA[Search]]></string>
+    <string name="_bx_posts_menu_item_title_entries_search"><![CDATA[Search]]></string>
+    <string name="_bx_posts_menu_title_view_entry_submenu"><![CDATA[View Post Submenu]]></string>
+    <string name="_bx_posts_menu_set_title_view_entry_submenu"><![CDATA[View Post Submenu]]></string>
+    <string name="_bx_posts_menu_item_title_view_entry_submenu_entry"><![CDATA[Post]]></string>
+    <string name="_bx_posts_menu_item_title_view_entry_submenu_comments"><![CDATA[Comments]]></string>
+    <string name="_bx_posts_menu_item_title_system_view_entry_comments"><![CDATA[Post Comments]]></string>
+    <string name="_bx_posts_menu_item_title_system_view_entries_author"><![CDATA[Posts]]></string>
+    <string name="_bx_posts_menu_item_title_view_entries_author"><![CDATA[Posts]]></string>
+    <string name="_bx_posts_menu_item_title_system_view_entries_in_context"><![CDATA[Posts]]></string>
+    <string name="_bx_posts_menu_item_title_view_entries_in_context"><![CDATA[Posts]]></string>
+    <string name="_bx_posts_menu_title_entries_my"><![CDATA[My Posts Action Menu]]></string>
+    <string name="_bx_posts_menu_set_title_entries_my"><![CDATA[My Posts Menu]]></string>
+    <string name="_bx_posts_menu_item_title_system_manage_my_posts"><![CDATA[My posts]]></string>
+    <string name="_bx_posts_menu_item_title_manage_my_posts"><![CDATA[Posts]]></string>
+    <string name="_bx_posts_menu_set_title_manage_tools"><![CDATA[Manage Tools Submenu]]></string>
+    <string name="_bx_posts_menu_title_manage_tools"><![CDATA[Manage Tools Submenu]]></string>
+    <string name="_bx_posts_menu_item_title_system_manage_account"><![CDATA[Manage account]]></string>
+    <string name="_bx_posts_menu_item_title_manage_account"><![CDATA[Manage account]]></string>
+    <string name="_bx_posts_menu_item_title_system_admt_posts"><![CDATA[Posts]]></string>
+    <string name="_bx_posts_menu_item_title_admt_posts"><![CDATA[Posts]]></string>
+    <string name="_bx_posts_menu_item_title_manage_my"><![CDATA[My Posts]]></string>
+    <string name="_bx_posts_menu_item_title_manage_all"><![CDATA[All Posts]]></string>
+
+    <string name="_bx_posts_grid_filter_item_title_adm_select_one_filter1"><![CDATA[All Statuses]]></string>
+    <string name="_bx_posts_grid_filter_item_title_adm_select_one_filter2"><![CDATA[Any Audience]]></string>
+    <string name="_bx_posts_grid_filter_item_title_adm_active"><![CDATA[Active]]></string>
+    <string name="_bx_posts_grid_filter_item_title_adm_hidden"><![CDATA[Hidden]]></string>
+    <string name="_bx_posts_grid_filter_item_title_adm_pending"><![CDATA[Pending]]></string>
+    <string name="_bx_posts_grid_column_title_adm_active"><![CDATA[Active]]></string>
+    <string name="_bx_posts_grid_column_title_adm_title"><![CDATA[Title]]></string>
+    <string name="_bx_posts_grid_action_title_adm_audit_content"><![CDATA[Audit actions]]></string>
+    <string name="_bx_posts_grid_column_title_adm_added"><![CDATA[Added]]></string>
+    <string name="_bx_posts_grid_column_title_adm_author"><![CDATA[Author]]></string>>
+    <string name="_bx_posts_grid_action_title_adm_add"><![CDATA[Add]]></string>
+    <string name="_bx_posts_grid_action_title_adm_edit"><![CDATA[Edit]]></string>
+    <string name="_bx_posts_grid_action_title_adm_delete"><![CDATA[Delete]]></string>
+    <string name="_bx_posts_grid_action_title_adm_clear_reports"><![CDATA[Сlear reports]]></string>
+    <string name="_bx_posts_grid_action_title_adm_more_actions"><![CDATA[More Actions]]></string>
+    <string name="_bx_posts_grid_column_title_adm_status_admin"><![CDATA[Moderation]]></string>
+    <string name="_bx_posts_grid_action_err_delete"><![CDATA[Cannot delete the selected post(s).]]></string>
+    <string name="_bx_posts_grid_txt_account_manager"><![CDATA[Redirect to manage account.]]></string>
+
+    <string name="_bx_posts_chart_growth"><![CDATA[Posts: Growth]]></string>
+    <string name="_bx_posts_chart_growth_speed"><![CDATA[Posts: Growth Speed]]></string>
+
+    <string name="_bx_posts_search_extended"><![CDATA[Posts Search]]></string>
+    <string name="_bx_posts_search_extended_cmts"><![CDATA[Posts Comments Search]]></string>
+
+    <string name="_bx_posts_pre_lists_cats"><![CDATA[Post categories]]></string>
+    <string name="_bx_posts_cat_Animals_Pets"><![CDATA[Animals & Pets]]></string>
+    <string name="_bx_posts_cat_Architecture"><![CDATA[Architecture]]></string>
+    <string name="_bx_posts_cat_Art"><![CDATA[Art]]></string>
+    <string name="_bx_posts_cat_Cars_Motorcycles"><![CDATA[Cars & Motorcycles]]></string>
+    <string name="_bx_posts_cat_Celebrities"><![CDATA[Celebrities]]></string>
+    <string name="_bx_posts_cat_Design"><![CDATA[Design]]></string>
+    <string name="_bx_posts_cat_DIY_Crafts"><![CDATA[DIY & Crafts]]></string>
+    <string name="_bx_posts_cat_Education"><![CDATA[Education]]></string>
+    <string name="_bx_posts_cat_Film_Music_Books"><![CDATA[Film, Music & Books]]></string>
+    <string name="_bx_posts_cat_Food_Drink"><![CDATA[Food & Drink]]></string>
+    <string name="_bx_posts_cat_Gardening"><![CDATA[Gardening]]></string>
+    <string name="_bx_posts_cat_Geek"><![CDATA[Geek]]></string>
+    <string name="_bx_posts_cat_Hair_Beauty"><![CDATA[Hair & Beauty]]></string>
+    <string name="_bx_posts_cat_Health_Fitness"><![CDATA[Health & Fitness]]></string>
+    <string name="_bx_posts_cat_History"><![CDATA[History]]></string>
+    <string name="_bx_posts_cat_Holidays_Events"><![CDATA[Holidays & Events]]></string>
+    <string name="_bx_posts_cat_Home_Decor"><![CDATA[Home Decor]]></string>
+    <string name="_bx_posts_cat_Humor"><![CDATA[Humor]]></string>
+    <string name="_bx_posts_cat_Illustrations_Posters"><![CDATA[Illustrations & Posters]]></string>
+    <string name="_bx_posts_cat_Kids_Parenting"><![CDATA[Kids & Parenting]]></string>
+    <string name="_bx_posts_cat_Mens_Fashion"><![CDATA[Men's Fashion]]></string>
+    <string name="_bx_posts_cat_Outdoors"><![CDATA[Outdoors]]></string>
+    <string name="_bx_posts_cat_Photography"><![CDATA[Photography]]></string>
+    <string name="_bx_posts_cat_Products"><![CDATA[Products]]></string>
+    <string name="_bx_posts_cat_Quotes"><![CDATA[Quotes]]></string>
+    <string name="_bx_posts_cat_Science_Nature"><![CDATA[Science & Nature]]></string>
+    <string name="_bx_posts_cat_Sports"><![CDATA[Sports]]></string>
+    <string name="_bx_posts_cat_Tattoos"><![CDATA[Tattoos]]></string>
+    <string name="_bx_posts_cat_Technology"><![CDATA[Technology]]></string>
+    <string name="_bx_posts_cat_Travel"><![CDATA[Travel]]></string>
+    <string name="_bx_posts_cat_Weddings"><![CDATA[Weddings]]></string>
+    <string name="_bx_posts_cat_Womens_Fashion"><![CDATA[Women's Fashion]]></string>
+
+    <string name="_bx_posts_txt_all_entries_in"><![CDATA[<a href="{0}">All Posts in {1} ({2})</a>]]></string>
+    <string name="_bx_posts_txt_all_entries_by"><![CDATA[{0} posts]]></string>
+    <string name="_bx_posts_txt_sample_single"><![CDATA[post]]></string>
+    <string name="_bx_posts_txt_sample_single_with_article"><![CDATA[a post]]></string>
+    <string name="_bx_posts_txt_sample_comment_single"><![CDATA[comment to post]]></string>
+    <string name="_bx_posts_txt_sample_vote_single"><![CDATA[vote to post]]></string>
+    <string name="_bx_posts_txt_sample_reaction_single"><![CDATA['{0}' reaction to post]]></string>
+    <string name="_bx_posts_txt_sample_score_up_single"><![CDATA[score up vote to post]]></string>
+    <string name="_bx_posts_txt_sample_score_down_single"><![CDATA[score down vote to post]]></string>
+    <string name="_bx_posts_txt_processing_awaiting"><![CDATA[Scheduled for publishing as soon as video conversion is complete.]]></string>
+    <string name="_bx_posts_txt_processing_failed"><![CDATA[Post isn't published because video conversion failed, edit video to fix the issue.]]></string>
+    <string name="_bx_posts_txt_scheduled_awaiting"><![CDATA[Post publishing date is {date_publish_uf}]]></string>
+
+    <string name="_bx_posts_txt_msg_status_hidden"><![CDATA[This post was hidden.]]></string>
+    <string name="_bx_posts_txt_msg_status_pending"><![CDATA[This post is pending approval.]]></string>
+    <string name="_bx_posts_txt_err_cannot_perform_action"><![CDATA[Cannot perform action. Please report.]]></string>
+
+    <string name="_bx_posts_txt_poll_view_answers"><![CDATA[poll]]></string>
+    <string name="_bx_posts_txt_poll_view_results"><![CDATA[results]]></string>
+    <string name="_bx_posts_txt_poll_answer_vote_do_by"><![CDATA[Voted for]]></string>
+    <string name="_bx_posts_txt_poll_answer_vote_counter"><![CDATA[{0} votes]]></string>
+    <string name="_bx_posts_txt_poll_answer_vote_percent"><![CDATA[({0}%)]]></string>
+</resources>

+ 716 - 0
modules/boonex/posts/updates/15.0.2_15.0.3/source/install/sql/install.sql

@@ -0,0 +1,716 @@
+-- TABLE: entries
+CREATE TABLE IF NOT EXISTS `bx_posts_posts` (
+  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
+  `author` int(11) NOT NULL,
+  `added` int(11) NOT NULL,
+  `changed` int(11) NOT NULL,
+  `published` int(11) NOT NULL,
+  `thumb` int(11) NOT NULL,
+  `thumb_data` varchar(50) NOT NULL,
+  `title` varchar(255) NOT NULL,
+  `cat` int(11) NOT NULL,
+  `multicat` text NOT NULL,
+  `abstract` text NOT NULL,
+  `text` mediumtext NOT NULL,
+  `labels` text NOT NULL,
+  `location` text NOT NULL,
+  `views` int(11) NOT NULL default '0',
+  `rate` float NOT NULL default '0',
+  `votes` int(11) NOT NULL default '0',
+  `rrate` float NOT NULL default '0',
+  `rvotes` int(11) NOT NULL default '0',
+  `score` int(11) NOT NULL default '0',
+  `sc_up` int(11) NOT NULL default '0',
+  `sc_down` int(11) NOT NULL default '0',
+  `favorites` int(11) NOT NULL default '0',
+  `comments` int(11) NOT NULL default '0',
+  `reports` int(11) NOT NULL default '0',
+  `featured` int(11) NOT NULL default '0',
+  `cf` int(11) NOT NULL default '1',
+  `allow_view_to` varchar(16) NOT NULL DEFAULT '3',
+  `allow_comments` tinyint(4) NOT NULL DEFAULT '1',
+  `status` enum('active','awaiting','failed','hidden') NOT NULL DEFAULT 'active',
+  `status_admin` enum('active','hidden','pending') NOT NULL DEFAULT 'active',
+  PRIMARY KEY (`id`),
+  FULLTEXT KEY `title_text` (`title`,`text`)
+);
+
+-- TABLE: storages & transcoders
+CREATE TABLE IF NOT EXISTS `bx_posts_covers` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `profile_id` int(10) unsigned NOT NULL,
+  `remote_id` varchar(128) NOT NULL,
+  `path` varchar(255) NOT NULL,
+  `file_name` varchar(255) NOT NULL,
+  `mime_type` varchar(128) NOT NULL,
+  `ext` varchar(32) NOT NULL,
+  `size` bigint(20) NOT NULL,
+  `added` int(11) NOT NULL,
+  `modified` int(11) NOT NULL,
+  `private` int(11) NOT NULL,
+  `dimensions` varchar(12) NOT NULL,
+  PRIMARY KEY (`id`),
+  UNIQUE KEY `remote_id` (`remote_id`)
+);
+
+CREATE TABLE IF NOT EXISTS `bx_posts_files` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `profile_id` int(10) unsigned NOT NULL,
+  `remote_id` varchar(128) NOT NULL,
+  `path` varchar(255) NOT NULL,
+  `file_name` varchar(255) NOT NULL,
+  `mime_type` varchar(128) NOT NULL,
+  `ext` varchar(32) NOT NULL,
+  `size` bigint(20) NOT NULL,
+  `added` int(11) NOT NULL,
+  `modified` int(11) NOT NULL,
+  `private` int(11) NOT NULL,
+  PRIMARY KEY (`id`),
+  UNIQUE KEY `remote_id` (`remote_id`)
+);
+
+CREATE TABLE IF NOT EXISTS `bx_posts_photos` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `profile_id` int(10) unsigned NOT NULL,
+  `remote_id` varchar(128) NOT NULL,
+  `path` varchar(255) NOT NULL,
+  `file_name` varchar(255) NOT NULL,
+  `mime_type` varchar(128) NOT NULL,
+  `ext` varchar(32) NOT NULL,
+  `size` bigint(20) NOT NULL,
+  `added` int(11) NOT NULL,
+  `modified` int(11) NOT NULL,
+  `private` int(11) NOT NULL,
+  `dimensions` varchar(12) NOT NULL,
+  PRIMARY KEY (`id`),
+  UNIQUE KEY `remote_id` (`remote_id`)
+);
+
+-- TABLES: LINKS
+CREATE TABLE IF NOT EXISTS `bx_posts_links` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `profile_id` int(10) unsigned NOT NULL,
+  `media_id` int(11) NOT NULL DEFAULT '0',
+  `url` varchar(255) NOT NULL,
+  `title` varchar(255) NOT NULL,
+  `text` text NOT NULL,
+  `added` int(11) NOT NULL,
+  PRIMARY KEY (`id`),
+  KEY `profile_id` (`profile_id`)
+);
+
+CREATE TABLE IF NOT EXISTS `bx_posts_links2content` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `content_id` int(11) NOT NULL DEFAULT '0',
+  `link_id` int(11) NOT NULL DEFAULT '0',
+  PRIMARY KEY (`id`),
+  UNIQUE KEY `link` (`link_id`, `content_id`)
+);
+
+CREATE TABLE IF NOT EXISTS `bx_posts_photos_resized` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `profile_id` int(10) unsigned NOT NULL,
+  `remote_id` varchar(128) NOT NULL,
+  `path` varchar(255) NOT NULL,
+  `file_name` varchar(255) NOT NULL,
+  `mime_type` varchar(128) NOT NULL,
+  `ext` varchar(32) NOT NULL,
+  `size` bigint(20) NOT NULL,
+  `added` int(11) NOT NULL,
+  `modified` int(11) NOT NULL,
+  `private` int(11) NOT NULL,
+  PRIMARY KEY (`id`),
+  UNIQUE KEY `remote_id` (`remote_id`)
+);
+
+CREATE TABLE IF NOT EXISTS `bx_posts_videos` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `profile_id` int(10) unsigned NOT NULL,
+  `remote_id` varchar(128) NOT NULL,
+  `path` varchar(255) NOT NULL,
+  `file_name` varchar(255) NOT NULL,
+  `mime_type` varchar(128) NOT NULL,
+  `ext` varchar(32) NOT NULL,
+  `size` bigint(20) NOT NULL,
+  `dimensions` varchar(12) NOT NULL,
+  `added` int(11) NOT NULL,
+  `modified` int(11) NOT NULL,
+  `private` int(11) NOT NULL,
+  PRIMARY KEY (`id`),
+  UNIQUE KEY `remote_id` (`remote_id`)
+);
+
+CREATE TABLE IF NOT EXISTS `bx_posts_videos_resized` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `profile_id` int(10) unsigned NOT NULL,
+  `remote_id` varchar(128) NOT NULL,
+  `path` varchar(255) NOT NULL,
+  `file_name` varchar(255) NOT NULL,
+  `mime_type` varchar(128) NOT NULL,
+  `ext` varchar(32) NOT NULL,
+  `size` bigint(20) NOT NULL,
+  `added` int(11) NOT NULL,
+  `modified` int(11) NOT NULL,
+  `private` int(11) NOT NULL,
+  PRIMARY KEY (`id`),
+  UNIQUE KEY `remote_id` (`remote_id`)
+);
+
+CREATE TABLE IF NOT EXISTS `bx_posts_sounds` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `profile_id` int(10) unsigned NOT NULL,
+  `remote_id` varchar(128) NOT NULL,
+  `path` varchar(255) NOT NULL,
+  `file_name` varchar(255) NOT NULL,
+  `mime_type` varchar(128) NOT NULL,
+  `ext` varchar(32) NOT NULL,
+  `size` bigint(20) NOT NULL,
+  `added` int(11) NOT NULL,
+  `modified` int(11) NOT NULL,
+  `private` int(11) NOT NULL,
+  PRIMARY KEY (`id`),
+  UNIQUE KEY `remote_id` (`remote_id`)
+);
+
+CREATE TABLE IF NOT EXISTS `bx_posts_sounds_resized` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `profile_id` int(10) unsigned NOT NULL,
+  `remote_id` varchar(128) NOT NULL,
+  `path` varchar(255) NOT NULL,
+  `file_name` varchar(255) NOT NULL,
+  `mime_type` varchar(128) NOT NULL,
+  `ext` varchar(32) NOT NULL,
+  `size` bigint(20) NOT NULL,
+  `added` int(11) NOT NULL,
+  `modified` int(11) NOT NULL,
+  `private` int(11) NOT NULL,
+  PRIMARY KEY (`id`),
+  UNIQUE KEY `remote_id` (`remote_id`)
+);
+
+-- TABLE: comments
+CREATE TABLE IF NOT EXISTS `bx_posts_cmts` (
+  `cmt_id` int(11) NOT NULL AUTO_INCREMENT,
+  `cmt_parent_id` int(11) NOT NULL DEFAULT '0',
+  `cmt_vparent_id` int(11) NOT NULL DEFAULT '0',
+  `cmt_object_id` int(11) NOT NULL DEFAULT '0',
+  `cmt_author_id` int(11) NOT NULL DEFAULT '0',
+  `cmt_level` int(11) NOT NULL DEFAULT '0',
+  `cmt_text` text NOT NULL,
+  `cmt_mood` tinyint(4) NOT NULL DEFAULT '0',
+  `cmt_rate` int(11) NOT NULL DEFAULT '0',
+  `cmt_rate_count` int(11) NOT NULL DEFAULT '0',
+  `cmt_time` int(11) unsigned NOT NULL DEFAULT '0',
+  `cmt_replies` int(11) NOT NULL DEFAULT '0',
+  `cmt_pinned` int(11) NOT NULL default '0',
+  `cmt_cf` int(11) NOT NULL default '1',
+  PRIMARY KEY (`cmt_id`),
+  KEY `cmt_object_id` (`cmt_object_id`,`cmt_parent_id`),
+  FULLTEXT KEY `search_fields` (`cmt_text`)
+);
+
+CREATE TABLE IF NOT EXISTS `bx_posts_cmts_notes` (
+  `cmt_id` int(11) NOT NULL AUTO_INCREMENT,
+  `cmt_parent_id` int(11) NOT NULL DEFAULT '0',
+  `cmt_vparent_id` int(11) NOT NULL DEFAULT '0',
+  `cmt_object_id` int(11) NOT NULL DEFAULT '0',
+  `cmt_author_id` int(11) NOT NULL DEFAULT '0',
+  `cmt_level` int(11) NOT NULL DEFAULT '0',
+  `cmt_text` text NOT NULL,
+  `cmt_mood` tinyint(4) NOT NULL DEFAULT '0',
+  `cmt_rate` int(11) NOT NULL DEFAULT '0',
+  `cmt_rate_count` int(11) NOT NULL DEFAULT '0',
+  `cmt_time` int(11) unsigned NOT NULL DEFAULT '0',
+  `cmt_replies` int(11) NOT NULL DEFAULT '0',
+  `cmt_pinned` int(11) NOT NULL default '0',
+  PRIMARY KEY (`cmt_id`),
+  KEY `cmt_object_id` (`cmt_object_id`,`cmt_parent_id`),
+  FULLTEXT KEY `search_fields` (`cmt_text`)
+);
+
+-- TABLE: votes
+CREATE TABLE IF NOT EXISTS `bx_posts_votes` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `object_id` int(11) NOT NULL default '0',
+  `count` int(11) NOT NULL default '0',
+  `sum` int(11) NOT NULL default '0',
+  PRIMARY KEY (`id`),
+  UNIQUE KEY `object_id` (`object_id`)
+);
+
+CREATE TABLE IF NOT EXISTS `bx_posts_votes_track` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `object_id` int(11) NOT NULL default '0',
+  `author_id` int(11) NOT NULL default '0',
+  `author_nip` int(11) unsigned NOT NULL default '0',
+  `value` tinyint(4) NOT NULL default '0',
+  `date` int(11) NOT NULL default '0',
+  PRIMARY KEY (`id`),
+  KEY `vote` (`object_id`, `author_nip`)
+);
+
+CREATE TABLE IF NOT EXISTS `bx_posts_reactions` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `object_id` int(11) NOT NULL default '0',
+  `reaction` varchar(32) NOT NULL default '',
+  `count` int(11) NOT NULL default '0',
+  `sum` int(11) NOT NULL default '0',
+  PRIMARY KEY (`id`),
+  UNIQUE KEY `reaction` (`object_id`, `reaction`)
+);
+
+CREATE TABLE IF NOT EXISTS `bx_posts_reactions_track` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `object_id` int(11) NOT NULL default '0',
+  `author_id` int(11) NOT NULL default '0',
+  `author_nip` int(11) unsigned NOT NULL default '0',
+  `reaction` varchar(32) NOT NULL default '',
+  `value` tinyint(4) NOT NULL default '0',
+  `date` int(11) NOT NULL default '0',
+  PRIMARY KEY (`id`),
+  KEY `vote` (`object_id`, `author_nip`)
+);
+
+-- TABLE: views
+CREATE TABLE `bx_posts_views_track` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `object_id` int(11) NOT NULL default '0',
+  `viewer_id` int(11) NOT NULL default '0',
+  `viewer_nip` int(11) unsigned NOT NULL default '0',
+  `date` int(11) NOT NULL default '0',
+  PRIMARY KEY (`id`),
+  KEY `id` (`object_id`,`viewer_id`,`viewer_nip`)
+);
+
+-- TABLE: metas
+CREATE TABLE `bx_posts_meta_keywords` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `object_id` int(10) unsigned NOT NULL,
+  `keyword` varchar(255) NOT NULL,
+  PRIMARY KEY (`id`),
+  KEY `object_id` (`object_id`),
+  KEY `keyword` (`keyword`)
+);
+
+CREATE TABLE `bx_posts_meta_mentions` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `object_id` int(10) unsigned NOT NULL,
+  `profile_id` int(10) unsigned NOT NULL,
+  PRIMARY KEY (`id`),
+  KEY `object_id` (`object_id`),
+  KEY `profile_id` (`profile_id`)
+);
+
+CREATE TABLE `bx_posts_meta_locations` (
+  `object_id` int(10) unsigned NOT NULL,
+  `lat` double NOT NULL,
+  `lng` double NOT NULL,
+  `country` varchar(2) NOT NULL,
+  `state` varchar(255) NOT NULL,
+  `city` varchar(255) NOT NULL,
+  `zip` varchar(255) NOT NULL,
+  `street` varchar(255) NOT NULL,
+  `street_number` varchar(255) NOT NULL,
+  PRIMARY KEY (`object_id`),
+  KEY `country_state_city` (`country`,`state`(8),`city`(8))
+);
+
+-- TABLE: reports
+CREATE TABLE IF NOT EXISTS `bx_posts_reports` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `object_id` int(11) NOT NULL default '0',
+  `count` int(11) NOT NULL default '0',
+  PRIMARY KEY (`id`),
+  UNIQUE KEY `object_id` (`object_id`)
+);
+
+CREATE TABLE IF NOT EXISTS `bx_posts_reports_track` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `object_id` int(11) NOT NULL default '0',
+  `author_id` int(11) NOT NULL default '0',
+  `author_nip` int(11) unsigned NOT NULL default '0',
+  `type` varchar(32) NOT NULL default '',
+  `text` text NOT NULL default '',
+  `date` int(11) NOT NULL default '0',
+  `checked_by` int(11) NOT NULL default '0',
+  `status` tinyint(11) NOT NULL default '0',
+  PRIMARY KEY (`id`),
+  KEY `report` (`object_id`, `author_nip`)
+);
+
+-- TABLE: favorites
+CREATE TABLE `bx_posts_favorites_track` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `object_id` int(11) NOT NULL default '0',
+  `author_id` int(11) NOT NULL default '0',
+  `list_id` int(11) NOT NULL default '0',
+  `date` int(11) NOT NULL default '0',
+  PRIMARY KEY (`id`),
+  KEY `id` (`object_id`,`author_id`)
+);
+
+CREATE TABLE `bx_posts_favorites_lists` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `title` varchar(255) NOT NULL,
+  `author_id` int(11) NOT NULL default '0',
+  `date` int(11) NOT NULL default '0',
+  `allow_view_favorite_list_to` varchar(16) NOT NULL DEFAULT '3',
+   PRIMARY KEY (`id`)
+);
+
+-- TABLE: scores
+CREATE TABLE IF NOT EXISTS `bx_posts_scores` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `object_id` int(11) NOT NULL default '0',
+  `count_up` int(11) NOT NULL default '0',
+  `count_down` int(11) NOT NULL default '0',
+  PRIMARY KEY (`id`),
+  UNIQUE KEY `object_id` (`object_id`)
+);
+
+CREATE TABLE IF NOT EXISTS `bx_posts_scores_track` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `object_id` int(11) NOT NULL default '0',
+  `author_id` int(11) NOT NULL default '0',
+  `author_nip` int(11) unsigned NOT NULL default '0',
+  `type` varchar(8) NOT NULL default '',
+  `date` int(11) NOT NULL default '0',
+  PRIMARY KEY (`id`),
+  KEY `vote` (`object_id`, `author_nip`)
+);
+
+-- TABLE: polls
+CREATE TABLE IF NOT EXISTS `bx_posts_polls` (
+  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
+  `author_id` int(11) NOT NULL default '0',
+  `content_id` int(11) NOT NULL default '0',
+  `text` text NOT NULL,
+  PRIMARY KEY (`id`),
+  KEY `content_id` (`content_id`),
+  FULLTEXT KEY `search_fields` (`text`)
+);
+
+CREATE TABLE IF NOT EXISTS `bx_posts_polls_answers` (
+  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
+  `poll_id` int(11) unsigned NOT NULL default '0',
+  `title` varchar(255) NOT NULL,
+  `rate` float NOT NULL default '0',
+  `votes` int(11) NOT NULL default '0',
+  `order` int(11) NOT NULL default '0',
+  PRIMARY KEY (`id`),
+  KEY `poll_id` (`poll_id`),
+  FULLTEXT KEY `title` (`title`)
+);
+
+CREATE TABLE IF NOT EXISTS `bx_posts_polls_answers_votes` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `object_id` int(11) NOT NULL default '0',
+  `count` int(11) NOT NULL default '0',
+  `sum` int(11) NOT NULL default '0',
+  PRIMARY KEY (`id`),
+  UNIQUE KEY `object_id` (`object_id`)
+);
+
+CREATE TABLE IF NOT EXISTS `bx_posts_polls_answers_votes_track` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `object_id` int(11) NOT NULL default '0',
+  `author_id` int(11) NOT NULL default '0',
+  `author_nip` int(11) unsigned NOT NULL default '0',
+  `value` tinyint(4) NOT NULL default '0',
+  `date` int(11) NOT NULL default '0',
+  PRIMARY KEY (`id`),
+  KEY `vote` (`object_id`, `author_nip`)
+);
+
+-- STORAGES & TRANSCODERS
+SET @sStorageEngine = (SELECT `value` FROM `sys_options` WHERE `name` = 'sys_storage_default');
+
+INSERT INTO `sys_objects_storage` (`object`, `engine`, `params`, `token_life`, `cache_control`, `levels`, `table_files`, `ext_mode`, `ext_allow`, `ext_deny`, `quota_size`, `current_size`, `quota_number`, `current_number`, `max_file_size`, `ts`) VALUES
+('bx_posts_covers', @sStorageEngine, '', 360, 2592000, 3, 'bx_posts_covers', 'allow-deny', '{image}', '', 0, 0, 0, 0, 0, 0),
+
+('bx_posts_photos', @sStorageEngine, '', 360, 2592000, 3, 'bx_posts_photos', 'allow-deny', '{image}', '', 0, 0, 0, 0, 0, 0),
+('bx_posts_photos_resized', @sStorageEngine, '', 360, 2592000, 3, 'bx_posts_photos_resized', 'allow-deny', '{image}', '', 0, 0, 0, 0, 0, 0),
+
+('bx_posts_videos', @sStorageEngine, '', 360, 2592000, 3, 'bx_posts_videos', 'allow-deny', '{video}', '', 0, 0, 0, 0, 0, 0),
+('bx_posts_videos_resized', @sStorageEngine, '', 360, 2592000, 3, 'bx_posts_videos_resized', 'allow-deny', '{imagevideo}', '', 0, 0, 0, 0, 0, 0),
+
+('bx_posts_sounds', @sStorageEngine, '', 360, 2592000, 3, 'bx_posts_sounds', 'allow-deny', '{audio}', '', 0, 0, 0, 0, 0, 0),
+('bx_posts_sounds_resized', @sStorageEngine, '', 360, 2592000, 3, 'bx_posts_sounds_resized', 'allow-deny', '{audio}', '', 0, 0, 0, 0, 0, 0),
+
+('bx_posts_files', @sStorageEngine, '', 360, 2592000, 3, 'bx_posts_files', 'deny-allow', '', '{dangerous}', 0, 0, 0, 0, 0, 0);
+
+INSERT INTO `sys_objects_transcoder` (`object`, `storage_object`, `source_type`, `source_params`, `private`, `atime_tracking`, `atime_pruning`, `ts`, `override_class_name`, `override_class_file`) VALUES 
+('bx_posts_preview', 'bx_posts_photos_resized', 'Storage', 'a:1:{s:6:"object";s:15:"bx_posts_covers";}', 'no', '1', '2592000', '0', '', ''),
+('bx_posts_miniature', 'bx_posts_photos_resized', 'Storage', 'a:1:{s:6:"object";s:15:"bx_posts_covers";}', 'no', '1', '2592000', '0', '', ''),
+('bx_posts_gallery', 'bx_posts_photos_resized', 'Storage', 'a:1:{s:6:"object";s:15:"bx_posts_covers";}', 'no', '1', '2592000', '0', '', ''),
+('bx_posts_cover', 'bx_posts_photos_resized', 'Storage', 'a:1:{s:6:"object";s:15:"bx_posts_covers";}', 'no', '1', '2592000', '0', '', ''),
+
+('bx_posts_preview_photos', 'bx_posts_photos_resized', 'Storage', 'a:1:{s:6:"object";s:15:"bx_posts_photos";}', 'no', '1', '2592000', '0', '', ''),
+('bx_posts_miniature_photos', 'bx_posts_photos_resized', 'Storage', 'a:1:{s:6:"object";s:15:"bx_posts_photos";}', 'no', '1', '2592000', '0', '', ''),
+('bx_posts_gallery_photos', 'bx_posts_photos_resized', 'Storage', 'a:1:{s:6:"object";s:15:"bx_posts_photos";}', 'no', '1', '2592000', '0', '', ''),
+('bx_posts_view_photos', 'bx_posts_photos_resized', 'Storage', 'a:1:{s:6:"object";s:15:"bx_posts_photos";}', 'no', '1', '2592000', '0', '', ''),
+
+('bx_posts_videos_poster', 'bx_posts_videos_resized', 'Storage', 'a:1:{s:6:"object";s:15:"bx_posts_videos";}', 'no', '0', '0', '0', 'BxDolTranscoderVideo', ''),
+('bx_posts_videos_poster_preview', 'bx_posts_videos_resized', 'Storage', 'a:1:{s:6:"object";s:15:"bx_posts_videos";}', 'no', '0', '0', '0', 'BxDolTranscoderVideo', ''),
+('bx_posts_videos_mp4', 'bx_posts_videos_resized', 'Storage', 'a:1:{s:6:"object";s:15:"bx_posts_videos";}', 'no', '0', '0', '0', 'BxDolTranscoderVideo', ''),
+('bx_posts_videos_mp4_hd', 'bx_posts_videos_resized', 'Storage', 'a:1:{s:6:"object";s:15:"bx_posts_videos";}', 'no', '0', '0', '0', 'BxDolTranscoderVideo', ''),
+
+('bx_posts_sounds_mp3', 'bx_posts_sounds_resized', 'Storage', 'a:1:{s:6:"object";s:15:"bx_posts_sounds";}', 'no', '0', '0', '0', 'BxDolTranscoderAudio', ''),
+
+('bx_posts_preview_files', 'bx_posts_photos_resized', 'Storage', 'a:1:{s:6:"object";s:14:"bx_posts_files";}', 'no', '1', '2592000', '0', '', ''),
+('bx_posts_gallery_files', 'bx_posts_photos_resized', 'Storage', 'a:1:{s:6:"object";s:14:"bx_posts_files";}', 'no', '1', '2592000', '0', '', '');
+
+INSERT INTO `sys_transcoder_filters` (`transcoder_object`, `filter`, `filter_params`, `order`) VALUES 
+('bx_posts_preview', 'Resize', 'a:3:{s:1:"w";s:3:"300";s:1:"h";s:3:"200";s:11:"crop_resize";s:1:"1";}', '0'),
+('bx_posts_miniature', 'Resize', 'a:1:{s:1:"w";s:3:"300";}', '0'),
+('bx_posts_gallery', 'Resize', 'a:1:{s:1:"w";s:3:"500";}', '0'),
+('bx_posts_cover', 'Resize', 'a:1:{s:1:"w";s:4:"1200";}', '0'),
+
+('bx_posts_preview_photos', 'Resize', 'a:3:{s:1:"w";s:3:"300";s:1:"h";s:3:"200";s:11:"crop_resize";s:1:"1";}', '0'),
+('bx_posts_miniature_photos', 'Resize', 'a:4:{s:1:"w";s:3:"300";s:1:"h";s:3:"300";s:13:"square_resize";s:1:"1";s:10:"force_type";s:3:"jpg";}', '0'),
+('bx_posts_gallery_photos', 'Resize', 'a:4:{s:1:"w";s:3:"600";s:1:"h";s:3:"600";s:13:"square_resize";s:1:"1";s:10:"force_type";s:3:"jpg";}', '0'),
+('bx_posts_view_photos', 'Resize',  'a:2:{s:1:"w";s:4:"1200";s:1:"h";s:4:"1200";}', '0'),
+
+('bx_posts_videos_poster_preview', 'Resize', 'a:3:{s:1:"w";s:3:"300";s:1:"h";s:3:"200";s:13:"square_resize";s:1:"1";}', 10),
+('bx_posts_videos_poster_preview', 'Poster', 'a:2:{s:1:"h";s:3:"480";s:10:"force_type";s:3:"jpg";}', 0),
+('bx_posts_videos_poster', 'Poster', 'a:2:{s:1:"h";s:3:"318";s:10:"force_type";s:3:"jpg";}', 0),
+('bx_posts_videos_mp4', 'Mp4', 'a:2:{s:1:"h";s:3:"318";s:10:"force_type";s:3:"mp4";}', 0),
+('bx_posts_videos_mp4_hd', 'Mp4', 'a:3:{s:1:"h";s:3:"720";s:13:"video_bitrate";s:4:"1536";s:10:"force_type";s:3:"mp4";}', 0),
+
+('bx_posts_sounds_mp3', 'Mp3', 'a:0:{}', 0),
+
+('bx_posts_preview_files', 'Resize', 'a:3:{s:1:"w";s:3:"300";s:1:"h";s:3:"200";s:11:"crop_resize";s:1:"1";}', '0'),
+('bx_posts_gallery_files', 'Resize', 'a:4:{s:1:"w";s:3:"600";s:1:"h";s:3:"600";s:13:"square_resize";s:1:"1";s:10:"force_type";s:3:"jpg";}', '0');
+
+
+-- FORMS: entry (post)
+INSERT INTO `sys_objects_form`(`object`, `module`, `title`, `action`, `form_attrs`, `table`, `key`, `uri`, `uri_title`, `submit_name`, `params`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES 
+('bx_posts', 'bx_posts', '_bx_posts_form_entry', '', 'a:1:{s:7:"enctype";s:19:"multipart/form-data";}', 'bx_posts_posts', 'id', '', '', 'a:2:{i:0;s:9:"do_submit";i:1;s:10:"do_publish";}', '', 0, 1, 'BxPostsFormEntry', 'modules/boonex/posts/classes/BxPostsFormEntry.php');
+
+INSERT INTO `sys_form_displays`(`object`, `display_name`, `module`, `view_mode`, `title`) VALUES 
+('bx_posts', 'bx_posts_entry_add', 'bx_posts', 0, '_bx_posts_form_entry_display_add'),
+('bx_posts', 'bx_posts_entry_delete', 'bx_posts', 0, '_bx_posts_form_entry_display_delete'),
+('bx_posts', 'bx_posts_entry_edit', 'bx_posts', 0, '_bx_posts_form_entry_display_edit'),
+('bx_posts', 'bx_posts_entry_view', 'bx_posts', 1, '_bx_posts_form_entry_display_view');
+
+INSERT INTO `sys_form_inputs`(`object`, `module`, `name`, `value`, `values`, `checked`, `type`, `caption_system`, `caption`, `info`, `required`, `collapsed`, `html`, `attrs`, `attrs_tr`, `attrs_wrapper`, `checker_func`, `checker_params`, `checker_error`, `db_pass`, `db_params`, `editable`, `deletable`) VALUES 
+('bx_posts', 'bx_posts', 'cf', '1', '#!sys_content_filter', 0, 'select', '_sys_form_entry_input_sys_cf', '_sys_form_entry_input_cf', '', 0, 0, 0, '', '', '', '', '', '', 'Int', '', 1, 0),
+('bx_posts', 'bx_posts', 'allow_view_to', '', '', 0, 'custom', '_bx_posts_form_entry_input_sys_allow_view_to', '_bx_posts_form_entry_input_allow_view_to', '', 1, 0, 0, '', '', '', '', '', '', '', '', 1, 0),
+('bx_posts', 'bx_posts', 'delete_confirm', 1, '', 0, 'checkbox', '_bx_posts_form_entry_input_sys_delete_confirm', '_bx_posts_form_entry_input_delete_confirm', '_bx_posts_form_entry_input_delete_confirm_info', 1, 0, 0, '', '', '', 'Avail', '', '_bx_posts_form_entry_input_delete_confirm_error', '', '', 1, 0),
+('bx_posts', 'bx_posts', 'do_publish', '_bx_posts_form_entry_input_do_publish', '', 0, 'submit', '_bx_posts_form_entry_input_sys_do_publish', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0),
+('bx_posts', 'bx_posts', 'do_submit', '_bx_posts_form_entry_input_do_submit', '', 0, 'submit', '_bx_posts_form_entry_input_sys_do_submit', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0),
+('bx_posts', 'bx_posts', 'do_cancel', '_sys_form_input_cancel', '', 0, 'button', '_sys_form_input_sys_cancel', '', '', 0, 0, 0, 'a:2:{s:7:"onclick";s:41:"window.open(''{edit_cancel_url}'', ''_self'')";s:5:"class";s:22:"bx-def-margin-sec-left";}', '', '', '', '', '', '', '', 0, 0),
+('bx_posts', 'bx_posts', 'controls', '', 'do_submit,do_cancel', 0, 'input_set', '_sys_form_input_sys_controls', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 0, 0),
+('bx_posts', 'bx_posts', 'location', '', '', 0, 'location', '_sys_form_input_sys_location', '_sys_form_input_location', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0),
+('bx_posts', 'bx_posts', 'covers', 'a:1:{i:0;s:14:"bx_posts_html5";}', 'a:1:{s:14:"bx_posts_html5";s:25:"_sys_uploader_html5_title";}', 0, 'files', '_bx_posts_form_entry_input_sys_covers', '_bx_posts_form_entry_input_covers', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0),
+('bx_posts', 'bx_posts', 'pictures', 'a:1:{i:0;s:21:"bx_posts_photos_html5";}', 'a:1:{s:21:"bx_posts_photos_html5";s:25:"_sys_uploader_html5_title";}', 0, 'files', '_bx_posts_form_entry_input_sys_pictures', '_bx_posts_form_entry_input_pictures', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0),
+('bx_posts', 'bx_posts', 'videos', 'a:2:{i:0;s:21:"bx_posts_videos_html5";i:1;s:28:"bx_posts_videos_record_video";}', 'a:2:{s:21:"bx_posts_videos_html5";s:25:"_sys_uploader_html5_title";s:28:"bx_posts_videos_record_video";s:32:"_sys_uploader_record_video_title";}', 0, 'files', '_bx_posts_form_entry_input_sys_videos', '_bx_posts_form_entry_input_videos', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0),
+('bx_posts', 'bx_posts', 'link', '', '', 0, 'custom', '_bx_posts_form_post_input_sys_link', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0),
+('bx_posts', 'bx_posts', 'sounds', 'a:1:{i:0;s:21:"bx_posts_sounds_html5";}', 'a:1:{s:21:"bx_posts_sounds_html5";s:25:"_sys_uploader_html5_title";}', 0, 'files', '_bx_posts_form_entry_input_sys_sounds', '_bx_posts_form_entry_input_sounds', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0),
+('bx_posts', 'bx_posts', 'files', 'a:1:{i:0;s:20:"bx_posts_files_html5";}', 'a:1:{s:20:"bx_posts_files_html5";s:25:"_sys_uploader_html5_title";}', 0, 'files', '_bx_posts_form_entry_input_sys_files', '_bx_posts_form_entry_input_files', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0),
+('bx_posts', 'bx_posts', 'polls', '', '', 0, 'custom', '_bx_posts_form_entry_input_sys_polls', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0),
+('bx_posts', 'bx_posts', 'abstract', '', '', 0, 'textarea', '_bx_posts_form_entry_input_sys_abstract', '_bx_posts_form_entry_input_abstract', '', 0, 0, 0, '', '', '', '', '', '', 'Xss', '', 1, 0),
+('bx_posts', 'bx_posts', 'text', '', '', 0, 'textarea', '_bx_posts_form_entry_input_sys_text', '_bx_posts_form_entry_input_text', '', 1, 0, 2, '', '', '', 'Avail', '', '_bx_posts_form_entry_input_text_err', 'XssHtml', '', 1, 0),
+('bx_posts', 'bx_posts', 'title', '', '', 0, 'text', '_bx_posts_form_entry_input_sys_title', '_bx_posts_form_entry_input_title', '', 1, 0, 0, '', '', '', 'Length', 'a:2:{s:3:"min";i:3;s:3:"max";i:160;}', '_bx_posts_form_entry_input_title_err', 'Xss', '', 1, 0),
+('bx_posts', 'bx_posts', 'cat', '', '#!bx_posts_cats', 0, 'select', '_bx_posts_form_entry_input_sys_cat', '_bx_posts_form_entry_input_cat', '', 1, 0, 0, '', '', '', 'avail', '', '_bx_posts_form_entry_input_cat_err', 'Xss', '', 1, 0),
+('bx_posts', 'bx_posts', 'multicat', '', '', 0, 'custom', '_bx_posts_form_entry_input_sys_multicat', '_bx_posts_form_entry_input_multicat', '', 1, 0, 0, '', '', '', 'avail', '', '_bx_posts_form_entry_input_multicat_err', 'Xss', '', 1, 0),
+('bx_posts', 'bx_posts', 'added', '', '', 0, 'datetime', '_bx_posts_form_entry_input_sys_date_added', '_bx_posts_form_entry_input_date_added', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0),
+('bx_posts', 'bx_posts', 'changed', '', '', 0, 'datetime', '_bx_posts_form_entry_input_sys_date_changed', '_bx_posts_form_entry_input_date_changed', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0),
+('bx_posts', 'bx_posts', 'published', '', '', 0, 'datetime', '_bx_posts_form_entry_input_sys_date_published', '_bx_posts_form_entry_input_date_published', '_bx_posts_form_entry_input_date_published_info', 0, 0, 0, '', '', '', '', '', '', 'DateTimeTs', '', 1, 0),
+('bx_posts', 'bx_posts', 'attachments', '', '', 0, 'custom', '_bx_posts_form_entry_input_sys_attachments', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0),
+('bx_posts', 'bx_posts', 'labels', '', '', 0, 'custom', '_sys_form_input_sys_labels', '_sys_form_input_labels', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0),
+('bx_posts', 'bx_posts', 'anonymous', '', '', 0, 'switcher', '_sys_form_input_sys_anonymous', '_sys_form_input_anonymous', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0),
+('bx_posts', 'bx_posts', 'allow_comments', '1', '', 1, 'switcher', '_bx_posts_form_entry_input_sys_allow_comments', '_bx_posts_form_entry_input_allow_comments', '', 0, 0, 0, '', '', '', '', '', '', 'Int', '', 1, 0);
+
+
+
+INSERT INTO `sys_form_display_inputs`(`display_name`, `input_name`, `visible_for_levels`, `active`, `order`) VALUES 
+('bx_posts_entry_add', 'delete_confirm', 2147483647, 0, 1),
+('bx_posts_entry_add', 'title', 2147483647, 1, 2),
+('bx_posts_entry_add', 'cat', 2147483647, 1, 3),
+('bx_posts_entry_add', 'abstract', 2147483647, 1, 4),
+('bx_posts_entry_add', 'text', 2147483647, 1, 5),
+('bx_posts_entry_add', 'attachments', 2147483647, 1, 6),
+('bx_posts_entry_add', 'link', 2147483647, 1, 7),
+('bx_posts_entry_add', 'pictures', 2147483647, 1, 8),
+('bx_posts_entry_add', 'videos', 2147483647, 1, 9),
+('bx_posts_entry_add', 'sounds', 2147483647, 1, 10),
+('bx_posts_entry_add', 'files', 2147483647, 1, 11),
+('bx_posts_entry_add', 'polls', 2147483647, 1, 12),
+('bx_posts_entry_add', 'covers', 2147483647, 1, 13),
+('bx_posts_entry_add', 'allow_view_to', 2147483647, 1, 14),
+('bx_posts_entry_add', 'cf', 2147483647, 1, 15),
+('bx_posts_entry_add', 'location', 2147483647, 1, 16),
+('bx_posts_entry_add', 'published', 192, 0, 17),
+('bx_posts_entry_add', 'allow_comments', 192, 1, 18),
+('bx_posts_entry_add', 'do_publish', 2147483647, 1, 19),
+
+('bx_posts_entry_delete', 'delete_confirm', 2147483647, 1, 1),
+('bx_posts_entry_delete', 'do_submit', 2147483647, 1, 2),
+
+('bx_posts_entry_edit', 'do_publish', 2147483647, 0, 1),
+('bx_posts_entry_edit', 'delete_confirm', 2147483647, 0, 2),
+('bx_posts_entry_edit', 'title', 2147483647, 1, 3),
+('bx_posts_entry_edit', 'cat', 2147483647, 1, 4),
+('bx_posts_entry_edit', 'abstract', 2147483647, 1, 5),
+('bx_posts_entry_edit', 'text', 2147483647, 1, 6),
+('bx_posts_entry_edit', 'attachments', 2147483647, 1, 7),
+('bx_posts_entry_edit', 'link', 2147483647, 1, 8),
+('bx_posts_entry_edit', 'pictures', 2147483647, 1, 9),
+('bx_posts_entry_edit', 'videos', 2147483647, 1, 10),
+('bx_posts_entry_edit', 'sounds', 2147483647, 1, 11),
+('bx_posts_entry_edit', 'files', 2147483647, 1, 12),
+('bx_posts_entry_edit', 'polls', 2147483647, 1, 13),
+('bx_posts_entry_edit', 'covers', 2147483647, 1, 14),
+('bx_posts_entry_edit', 'allow_view_to', 2147483647, 1, 15),
+('bx_posts_entry_edit', 'cf', 2147483647, 1, 16),
+('bx_posts_entry_edit', 'location', 2147483647, 1, 17),
+('bx_posts_entry_edit', 'allow_comments', 192, 1, 18),
+('bx_posts_entry_edit', 'published', 192, 0, 19),
+('bx_posts_entry_edit', 'controls', 2147483647, 1, 20),
+('bx_posts_entry_edit', 'do_submit', 2147483647, 1, 21),
+('bx_posts_entry_edit', 'do_cancel', 2147483647, 1, 22),
+
+('bx_posts_entry_view', 'cat', 2147483647, 1, 1),
+('bx_posts_entry_view', 'added', 2147483647, 1, 2),
+('bx_posts_entry_view', 'changed', 2147483647, 1, 3),
+('bx_posts_entry_view', 'published', 192, 1, 4);
+
+-- FORMS: poll
+INSERT INTO `sys_objects_form` (`object`, `module`, `title`, `action`, `form_attrs`, `submit_name`, `table`, `key`, `uri`, `uri_title`, `params`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES
+('bx_posts_poll', 'bx_posts', '_bx_posts_form_poll', '', '', 'do_submit', 'bx_posts_polls', 'id', '', '', 'a:1:{s:14:"checker_helper";s:28:"BxPostsFormPollCheckerHelper";}', 0, 1, 'BxPostsFormPoll', 'modules/boonex/posts/classes/BxPostsFormPoll.php');
+
+INSERT INTO `sys_form_displays` (`display_name`, `module`, `object`, `title`, `view_mode`) VALUES
+('bx_posts_poll_add', 'bx_posts', 'bx_posts_poll', '_bx_posts_form_poll_display_add', 0);
+
+INSERT INTO `sys_form_inputs` (`object`, `module`, `name`, `value`, `values`, `checked`, `type`, `caption_system`, `caption`, `info`, `required`, `collapsed`, `html`, `attrs`, `attrs_tr`, `attrs_wrapper`, `checker_func`, `checker_params`, `checker_error`, `db_pass`, `db_params`, `editable`, `deletable`) VALUES
+('bx_posts_poll', 'bx_posts', 'text', '', '', 0, 'text', '_bx_posts_form_poll_input_sys_text', '_bx_posts_form_poll_input_text', '', 1, 0, 0, '', '', '', 'Avail', '', '_bx_posts_form_poll_input_text_err', 'Xss', '', 1, 0),
+('bx_posts_poll', 'bx_posts', 'answers', '', '', 0, 'custom', '_bx_posts_form_poll_input_sys_answers', '_bx_posts_form_poll_input_answers', '', 1, 0, 0, '', '', '', 'AvailAnswers', '', '_bx_posts_form_poll_input_answers_err', '', '', 1, 0),
+('bx_posts_poll', 'bx_posts', 'controls', '', 'do_submit,do_cancel', 0, 'input_set', '', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 0, 0),
+('bx_posts_poll', 'bx_posts', 'do_submit', '_bx_posts_form_poll_input_do_submit', '', 0, 'submit', '_bx_posts_form_poll_input_sys_do_submit', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 0, 0),
+('bx_posts_poll', 'bx_posts', 'do_cancel', '_bx_posts_form_poll_input_do_cancel', '', 0, 'button', '_bx_posts_form_poll_input_do_cancel', '', '', 0, 0, 0, 'a:2:{s:7:"onclick";s:45:"$(''.bx-popup-applied:visible'').dolPopupHide()";s:5:"class";s:22:"bx-def-margin-sec-left";}', '', '', '', '', '', '', '', 0, 0);
+
+INSERT INTO `sys_form_display_inputs` (`display_name`, `input_name`, `visible_for_levels`, `active`, `order`) VALUES
+('bx_posts_poll_add', 'text', 2147483647, 1, 1),
+('bx_posts_poll_add', 'answers', 2147483647, 1, 2),
+('bx_posts_poll_add', 'controls', 2147483647, 1, 3),
+('bx_posts_poll_add', 'do_submit', 2147483647, 1, 4),
+('bx_posts_poll_add', 'do_cancel', 2147483647, 1, 5);
+
+-- Forms -> Attach link
+INSERT INTO `sys_objects_form` (`object`, `module`, `title`, `action`, `form_attrs`, `submit_name`, `table`, `key`, `uri`, `uri_title`, `params`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES
+('bx_posts_attach_link', 'bx_posts', '_bx_posts_form_attach_link', '', '', 'do_submit', 'bx_posts_links', 'id', '', '', '', 0, 1, '', '');
+
+INSERT INTO `sys_form_displays` (`display_name`, `module`, `object`, `title`, `view_mode`) VALUES
+('bx_posts_attach_link_add', 'bx_posts', 'bx_posts_attach_link', '_bx_posts_form_attach_link_display_add', 0);
+
+INSERT INTO `sys_form_inputs` (`object`, `module`, `name`, `value`, `values`, `checked`, `type`, `caption_system`, `caption`, `info`, `required`, `collapsed`, `html`, `attrs`, `attrs_tr`, `attrs_wrapper`, `checker_func`, `checker_params`, `checker_error`, `db_pass`, `db_params`, `editable`, `deletable`) VALUES
+('bx_posts_attach_link', 'bx_posts', 'content_id', '0', '', 0, 'hidden', '_bx_posts_form_attach_link_input_sys_content_id', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 0, 0),
+('bx_posts_attach_link', 'bx_posts', 'url', '', '', 0, 'text', '_bx_posts_form_attach_link_input_sys_url', '_bx_posts_form_attach_link_input_url', '', 0, 0, 0, '', '', '', 'Preg', 'a:1:{s:4:"preg";s:0:"";}', '_bx_posts_form_attach_link_input_url_err', '', '', 0, 0),
+('bx_posts_attach_link', 'bx_posts', 'controls', '', 'do_submit,do_cancel', 0, 'input_set', '', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 0, 0),
+('bx_posts_attach_link', 'bx_posts', 'do_submit', '_bx_posts_form_attach_link_input_do_submit', '', 0, 'submit', '_bx_posts_form_attach_link_input_sys_do_submit', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 0, 0),
+('bx_posts_attach_link', 'bx_posts', 'do_cancel', '_bx_posts_form_attach_link_input_do_cancel', '', 0, 'button', '_bx_posts_form_attach_link_input_do_cancel', '', '', 0, 0, 0, 'a:2:{s:7:"onclick";s:45:"$(''.bx-popup-applied:visible'').dolPopupHide()";s:5:"class";s:22:"bx-def-margin-sec-left";}', '', '', '', '', '', '', '', 0, 0);
+
+INSERT INTO `sys_form_display_inputs` (`display_name`, `input_name`, `visible_for_levels`, `active`, `order`) VALUES
+('bx_posts_attach_link_add', 'content_id', 2147483647, 1, 1),
+('bx_posts_attach_link_add', 'url', 2147483647, 1, 2),
+('bx_posts_attach_link_add', 'controls', 2147483647, 1, 3),
+('bx_posts_attach_link_add', 'do_submit', 2147483647, 1, 4),
+('bx_posts_attach_link_add', 'do_cancel', 2147483647, 1, 5);
+
+-- PRE-VALUES
+INSERT INTO `sys_form_pre_lists`(`key`, `title`, `module`, `use_for_sets`) VALUES
+('bx_posts_cats', '_bx_posts_pre_lists_cats', 'bx_posts', '0');
+
+INSERT INTO `sys_form_pre_values`(`Key`, `Value`, `Order`, `LKey`, `LKey2`) VALUES
+('bx_posts_cats', '', 0, '_sys_please_select', ''),
+('bx_posts_cats', '1', 1, '_bx_posts_cat_Animals_Pets', ''),
+('bx_posts_cats', '2', 2, '_bx_posts_cat_Architecture', ''),
+('bx_posts_cats', '3', 3, '_bx_posts_cat_Art', ''),
+('bx_posts_cats', '4', 4, '_bx_posts_cat_Cars_Motorcycles', ''),
+('bx_posts_cats', '5', 5, '_bx_posts_cat_Celebrities', ''),
+('bx_posts_cats', '6', 6, '_bx_posts_cat_Design', ''),
+('bx_posts_cats', '7', 7, '_bx_posts_cat_DIY_Crafts', ''),
+('bx_posts_cats', '8', 8, '_bx_posts_cat_Education', ''),
+('bx_posts_cats', '9', 9, '_bx_posts_cat_Film_Music_Books', ''),
+('bx_posts_cats', '10', 10, '_bx_posts_cat_Food_Drink', ''),
+('bx_posts_cats', '11', 11, '_bx_posts_cat_Gardening', ''),
+('bx_posts_cats', '12', 12, '_bx_posts_cat_Geek', ''),
+('bx_posts_cats', '13', 13, '_bx_posts_cat_Hair_Beauty', ''),
+('bx_posts_cats', '14', 14, '_bx_posts_cat_Health_Fitness', ''),
+('bx_posts_cats', '15', 15, '_bx_posts_cat_History', ''),
+('bx_posts_cats', '16', 16, '_bx_posts_cat_Holidays_Events', ''),
+('bx_posts_cats', '17', 17, '_bx_posts_cat_Home_Decor', ''),
+('bx_posts_cats', '18', 18, '_bx_posts_cat_Humor', ''),
+('bx_posts_cats', '19', 19, '_bx_posts_cat_Illustrations_Posters', ''),
+('bx_posts_cats', '20', 20, '_bx_posts_cat_Kids_Parenting', ''),
+('bx_posts_cats', '21', 21, '_bx_posts_cat_Mens_Fashion', ''),
+('bx_posts_cats', '22', 22, '_bx_posts_cat_Outdoors', ''),
+('bx_posts_cats', '23', 23, '_bx_posts_cat_Photography', ''),
+('bx_posts_cats', '24', 24, '_bx_posts_cat_Products', ''),
+('bx_posts_cats', '25', 25, '_bx_posts_cat_Quotes', ''),
+('bx_posts_cats', '26', 26, '_bx_posts_cat_Science_Nature', ''),
+('bx_posts_cats', '27', 27, '_bx_posts_cat_Sports', ''),
+('bx_posts_cats', '28', 28, '_bx_posts_cat_Tattoos', ''),
+('bx_posts_cats', '29', 29, '_bx_posts_cat_Technology', ''),
+('bx_posts_cats', '30', 30, '_bx_posts_cat_Travel', ''),
+('bx_posts_cats', '31', 31, '_bx_posts_cat_Weddings', ''),
+('bx_posts_cats', '32', 32, '_bx_posts_cat_Womens_Fashion', '');
+
+-- COMMENTS
+INSERT INTO `sys_objects_cmts` (`Name`, `Module`, `Table`, `CharsPostMin`, `CharsPostMax`, `CharsDisplayMax`, `Html`, `PerView`, `PerViewReplies`, `BrowseType`, `IsBrowseSwitch`, `PostFormPosition`, `NumberOfLevels`, `IsDisplaySwitch`, `IsRatable`, `ViewingThreshold`, `IsOn`, `RootStylePrefix`, `BaseUrl`, `ObjectVote`, `TriggerTable`, `TriggerFieldId`, `TriggerFieldAuthor`, `TriggerFieldTitle`, `TriggerFieldComments`, `ClassName`, `ClassFile`) VALUES
+('bx_posts', 'bx_posts', 'bx_posts_cmts', 1, 5000, 1000, 3, 5, 3, 'tail', 1, 'bottom', 1, 1, 1, -3, 1, 'cmt', 'page.php?i=view-post&id={object_id}', '', 'bx_posts_posts', 'id', 'author', 'title', 'comments', '', ''),
+('bx_posts_notes', 'bx_posts', 'bx_posts_cmts_notes', 1, 5000, 1000, 0, 5, 3, 'tail', 1, 'bottom', 1, 1, 1, -3, 1, 'cmt', 'page.php?i=view-post&id={object_id}', '', 'bx_posts_posts', 'id', 'author', 'title', '', 'BxTemplCmtsNotes', '');
+
+-- VOTES
+INSERT INTO `sys_objects_vote` (`Name`, `Module`, `TableMain`, `TableTrack`, `PostTimeout`, `MinValue`, `MaxValue`, `IsUndo`, `IsOn`, `TriggerTable`, `TriggerFieldId`, `TriggerFieldAuthor`, `TriggerFieldRate`, `TriggerFieldRateCount`, `ClassName`, `ClassFile`) VALUES 
+('bx_posts', 'bx_posts', 'bx_posts_votes', 'bx_posts_votes_track', '604800', '1', '1', '0', '1', 'bx_posts_posts', 'id', 'author', 'rate', 'votes', '', ''),
+('bx_posts_reactions', 'bx_posts', 'bx_posts_reactions', 'bx_posts_reactions_track', '604800', '1', '1', '1', '1', 'bx_posts_posts', 'id', 'author', 'rrate', 'rvotes', 'BxTemplVoteReactions', ''),
+('bx_posts_poll_answers', 'bx_posts', 'bx_posts_polls_answers_votes', 'bx_posts_polls_answers_votes_track', '604800', '1', '1', '0', '1', 'bx_posts_polls_answers', 'id', '', 'rate', 'votes', 'BxPostsVotePollAnswers', 'modules/boonex/posts/classes/BxPostsVotePollAnswers.php');
+
+-- SCORES
+INSERT INTO `sys_objects_score` (`name`, `module`, `table_main`, `table_track`, `post_timeout`, `is_on`, `trigger_table`, `trigger_field_id`, `trigger_field_author`, `trigger_field_score`, `trigger_field_cup`, `trigger_field_cdown`, `class_name`, `class_file`) VALUES 
+('bx_posts', 'bx_posts', 'bx_posts_scores', 'bx_posts_scores_track', '604800', '0', 'bx_posts_posts', 'id', 'author', 'score', 'sc_up', 'sc_down', '', '');
+
+-- REPORTS
+INSERT INTO `sys_objects_report` (`name`, `module`, `table_main`, `table_track`, `is_on`, `base_url`, `object_comment`, `trigger_table`, `trigger_field_id`, `trigger_field_author`, `trigger_field_count`, `class_name`, `class_file`) VALUES 
+('bx_posts', 'bx_posts', 'bx_posts_reports', 'bx_posts_reports_track', '1', 'page.php?i=view-post&id={object_id}', 'bx_posts_notes', 'bx_posts_posts', 'id', 'author', 'reports', '', '');
+
+-- VIEWS
+INSERT INTO `sys_objects_view` (`name`, `module`, `table_track`, `period`, `is_on`, `trigger_table`, `trigger_field_id`, `trigger_field_author`, `trigger_field_count`, `class_name`, `class_file`) VALUES 
+('bx_posts', 'bx_posts', 'bx_posts_views_track', '86400', '1', 'bx_posts_posts', 'id', 'author', 'views', '', '');
+
+-- FAVORITES
+INSERT INTO `sys_objects_favorite` (`name`, `table_track`, `table_lists`, `is_on`, `is_undo`, `is_public`, `base_url`, `trigger_table`, `trigger_field_id`, `trigger_field_author`, `trigger_field_count`, `class_name`, `class_file`) VALUES 
+('bx_posts', 'bx_posts_favorites_track', 'bx_posts_favorites_lists', '1', '1', '1', 'page.php?i=view-post&id={object_id}', 'bx_posts_posts', 'id', 'author', 'favorites', '', '');
+
+-- FEATURED
+INSERT INTO `sys_objects_feature` (`name`, `module`, `is_on`, `is_undo`, `base_url`, `trigger_table`, `trigger_field_id`, `trigger_field_author`, `trigger_field_flag`, `class_name`, `class_file`) VALUES 
+('bx_posts', 'bx_posts', '1', '1', 'page.php?i=view-post&id={object_id}', 'bx_posts_posts', 'id', 'author', 'featured', '', '');
+
+-- CONTENT INFO
+INSERT INTO `sys_objects_content_info` (`name`, `title`, `alert_unit`, `alert_action_add`, `alert_action_update`, `alert_action_delete`, `class_name`, `class_file`) VALUES
+('bx_posts', '_bx_posts', 'bx_posts', 'added', 'edited', 'deleted', '', ''),
+('bx_posts_cmts', '_bx_posts_cmts', 'bx_posts', 'commentPost', 'commentUpdated', 'commentRemoved', 'BxDolContentInfoCmts', '');
+
+INSERT INTO `sys_content_info_grids` (`object`, `grid_object`, `grid_field_id`, `condition`, `selection`) VALUES
+('bx_posts', 'bx_posts_administration', 'id', '', ''),
+('bx_posts', 'bx_posts_common', 'id', '', '');
+
+-- SEARCH EXTENDED
+INSERT INTO `sys_objects_search_extended` (`object`, `object_content_info`, `module`, `title`, `active`, `class_name`, `class_file`) VALUES
+('bx_posts', 'bx_posts', 'bx_posts', '_bx_posts_search_extended', 1, '', ''),
+('bx_posts_cmts', 'bx_posts_cmts', 'bx_posts', '_bx_posts_search_extended_cmts', 1, 'BxTemplSearchExtendedCmts', '');
+
+-- STUDIO: page & widget
+INSERT INTO `sys_std_pages`(`index`, `name`, `header`, `caption`, `icon`) VALUES
+(3, 'bx_posts', '_bx_posts', '_bx_posts', 'bx_posts@modules/boonex/posts/|std-icon.svg');
+SET @iPageId = LAST_INSERT_ID();
+
+SET @iParentPageId = (SELECT `id` FROM `sys_std_pages` WHERE `name` = 'home');
+SET @iParentPageOrder = (SELECT MAX(`order`) FROM `sys_std_pages_widgets` WHERE `page_id` = @iParentPageId);
+INSERT INTO `sys_std_widgets` (`page_id`, `module`, `type`, `url`, `click`, `icon`, `caption`, `cnt_notices`, `cnt_actions`) VALUES
+(@iPageId, 'bx_posts', 'content', '{url_studio}module.php?name=bx_posts', '', 'bx_posts@modules/boonex/posts/|std-icon.svg', '_bx_posts', '', 'a:4:{s:6:"module";s:6:"system";s:6:"method";s:11:"get_actions";s:6:"params";a:0:{}s:5:"class";s:18:"TemplStudioModules";}');
+INSERT INTO `sys_std_pages_widgets` (`page_id`, `widget_id`, `order`) VALUES
+(@iParentPageId, LAST_INSERT_ID(), IF(ISNULL(@iParentPageOrder), 1, @iParentPageOrder + 1));
+

+ 51 - 0
modules/boonex/profiler/updates/15.0.1_15.0.2/install/config.php

@@ -0,0 +1,51 @@
+<?php
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ */
+
+$aConfig = array(
+    /**
+     * Main Section.
+     */
+    'title' => 'Profiler',
+    'version_from' => '15.0.1',
+    'version_to' => '15.0.2',
+    'vendor' => 'UNA INC',
+
+    'compatible_with' => array(
+        '15.0.0-B2'
+    ),
+
+    /**
+     * 'home_dir' and 'home_uri' - should be unique. Don't use spaces in 'home_uri' and the other special chars.
+     */
+    'home_dir' => 'boonex/profiler/updates/update_15.0.1_15.0.2/',
+    'home_uri' => 'profiler_update_1501_1502',
+
+    'module_dir' => 'boonex/profiler/',
+    'module_uri' => 'profiler',
+
+    'db_prefix' => 'bx_profiler_',
+    'class_prefix' => 'BxProfiler',
+
+    /**
+     * Installation/Uninstallation Section.
+     */
+    'install' => array(
+        'execute_sql' => 0,
+        'update_files' => 1,
+        'update_languages' => 0,
+        'clear_db_cache' => 0,
+    ),
+
+    /**
+     * Category for language keys.
+     */
+    'language_category' => 'Boonex Profiler',
+
+    /**
+     * Files Section
+     */
+    'delete_files' => array(),
+);

+ 13 - 0
modules/boonex/profiler/updates/15.0.1_15.0.2/install/installer.php

@@ -0,0 +1,13 @@
+<?php
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ */
+
+class BxProfilerUpdater extends BxDolStudioUpdater
+{
+    function __construct($aConfig)
+    {
+        parent::__construct($aConfig);
+    }
+}

+ 799 - 0
modules/boonex/profiler/updates/15.0.1_15.0.2/source/classes/BxProfiler.php

@@ -0,0 +1,799 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Profiler Profiler
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+define ('BX_PROFILER', true);
+define ('BX_PROFILER_DISPLAY', 1);
+
+require_once(BX_DIRECTORY_PATH_MODULES . 'boonex/profiler/install/config.php');
+$GLOBALS['bx_profiler_module'] = array (
+    'type' => BX_DOL_MODULE_TYPE_MODULE,
+    'name' => 'bx_profiler',
+    'title' => $aConfig['title'],
+    'vendor' => $aConfig['vendor'],
+    'path' => $aConfig['home_dir'],
+    'uri' => $aConfig['home_uri'],
+    'class_prefix' => $aConfig['class_prefix'],
+    'db_prefix' => $aConfig['db_prefix'],
+);
+
+bx_import('Template', $GLOBALS['bx_profiler_module']);
+bx_import('Config', $GLOBALS['bx_profiler_module']);
+
+class BxProfiler extends BxDol
+{
+    protected $oConfig, $oTemplate, $oTemplateAdmin;
+
+    protected $aConf = [];
+
+    protected $_iTimeStart = 0;
+
+    protected $_aQueries = [];
+    protected $_sQueryIndex = 0;
+
+    protected $_aModules = [];
+    protected $_aModulesNames = [];
+    protected $_aModulesLevel = 0;
+
+    protected $_aAlerts = [];
+    protected $_iAlertsLevel = 0;
+
+    protected $_aInjections = [];
+    protected $_sInjectionIndex = 0;
+
+    protected $_sLogDateFormat = "Y-m-d H:i:s";
+    protected $_sLogMaxArgLength = 64;
+    protected $_sLogFilename = 64;
+
+    protected $_aTemplates = [];
+    protected $_aTemplateIndexes = [];
+
+    protected $_aPages = [];
+    protected $_sPageIndex = '';
+    protected $_sPageBlockIndex = 0;
+    protected $_aPagesBlocks = [];
+    
+    protected $_aMenus = [];   
+
+    function __construct($iTimeStart)
+    {
+        parent::__construct();
+
+        $this->oConfig = new BxProfilerConfig ($GLOBALS['bx_profiler_module']);
+        $this->oTemplate = new BxProfilerTemplate ($this->oConfig);
+        $this->oTemplateAdmin = BxDolStudioTemplate::getInstance();
+
+        if (getParam ('bx_profiler_long_sql_queries_log'))
+            $this->aConf['long_query'] = getParam ('bx_profiler_long_sql_queries_time');
+        if (getParam ('bx_profiler_long_module_query_log'))
+            $this->aConf['long_module'] = getParam ('bx_profiler_long_module_query_time');
+        if (getParam ('bx_profiler_long_page_log'))
+            $this->aConf['long_page'] = getParam ('bx_profiler_long_page_time');
+
+        $this->_iTimeStart = $iTimeStart;
+    }
+
+    // output profiler debug panel
+    function output ()
+    {
+        $iPageTime = $this->_getCurrentDelay ();
+        if (isset($this->aConf['long_page']) && $iPageTime > $this->aConf['long_page'])
+            $this->logPageOpen ($iPageTime);
+
+        switch (getParam('bx_profiler_show_debug_panel')) {
+        case 'all':
+            break;
+        case 'admins':
+            if (!isset($GLOBALS['logged']) || !$GLOBALS['logged']['admin'])
+                return;
+            break;
+        case 'none':
+        default:
+            return;
+        }
+
+        $aCss = array (
+			'profiler.css',
+            BX_DIRECTORY_PATH_PLUGINS_PUBLIC . 'jush/|jush.css',
+        );
+        $aJs = array (
+            'jquery.tablesorter.min.js',
+            'profiler.js',
+            'jush/jush.js',
+        );
+
+        $sJsCss = '';
+        foreach ($aCss as $sCssPath)
+            $sJsCss .= $this->oTemplate->addCss($sCssPath, 1);
+        foreach ($aJs as $sJsPath)
+            $sJsCss .= $this->oTemplate->addJs($sJsPath, 1);
+
+        $sPlanks  = $this->_plankMain ();
+        $sPlanks .= $this->_plankMenus ();
+        $sPlanks .= $this->_plankTemplates ();
+        $sPlanks .= $this->_plankInjections ();
+        $sPlanks .= $this->_plankPagesBlocks ();
+        $sPlanks .= $this->_plankSql ();
+        $sPlanks .= $this->_plankModules ();
+        $sPlanks .= $this->_plankAlerts ();
+
+        echo ob_get_clean();
+
+        $sContentType = $this->oTemplate->getHeaderContentType();
+        if ('text/html' == $sContentType) {            
+            echo $sJsCss . $sPlanks;
+        } 
+        else if ('application/json' == $sContentType) {
+            echo $sPlanks;
+        }
+    }
+
+    function _logBegin ($s)
+    {
+        $sDate = date ($this->_sLogDateFormat);
+        return "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n" . $sDate . " " . $s . "\n" .
+        (getLoggedId() ? "User ID: " . getLoggedId()  . "\n" : '') .
+        "User role: " . ($GLOBALS['logged']['admin'] ? 'admin' : ($GLOBALS['logged']['member'] ? 'member' : 'guest')) . "\n";
+    }
+
+    function _logEnd ()
+    {
+        return "\n";
+    }
+
+    function _appendToLog ($s)
+    {
+		bx_log('bx_profiler', $s, BX_LOG_INFO);
+    }
+
+    function logSqlQuery ($iTime, $aSqlQuery, &$oStmt)
+    {
+        $s  = $this->_logBegin ('LONG SQL QUERY: ' . $aSqlQuery['time']);
+        $s .= "Rows: " . $aSqlQuery['rows'] . "\n";
+        $s .= "Affected: " . $aSqlQuery['affected'] . "\n";
+        $s .= "Query: " . $aSqlQuery['sql'] . "\n";
+        if (getParam('bx_profiler_long_sql_queries_debug'))
+            $s .= "Backtrace: \n" . $this->_debugBackTrace (3);
+        $s .= $this->_logEnd();
+        $this->_appendToLog ($s);
+    }
+
+    function logModuleQuery ($iTime, $aModuleQuery)
+    {
+        $s  = $this->_logBegin ('LONG MODULE QUERY: ' . $aModuleQuery['time']);
+        $s .= "Module name: " . $aModuleQuery['name'] . "\n";
+        $s .= "Query type: " . $aModuleQuery['type'] . "\n";
+        $s .= "Class/file: " . $aModuleQuery['class/file'] . "\n";
+        $s .= "Method: " . $aModuleQuery['method'] . "\n";
+        if (getParam('bx_profiler_long_module_query_debug'))
+            $s .= "Backtrace: \n" . $this->_debugBackTrace (3);
+        $s .= $this->_logEnd();
+        $this->_appendToLog ($s);
+    }
+
+    function logPageOpen ($iTime)
+    {
+        $s  = $this->_logBegin ('LONG PAGE OPEN: ' . $this->_formatTime($iTime));
+        $s .= "Request method: " . $_SERVER['REQUEST_METHOD'] . "\n";
+        $s .= "Query string: " . $_SERVER['QUERY_STRING'] . "\n";
+        $s .= "Request URI: " . $_SERVER['REQUEST_URI'] . "\n";
+        $s .= "Script name: " . $_SERVER['SCRIPT_NAME'] . "\n";
+        $s .= "PHP self: " . $_SERVER['PHP_SELF'] . "\n";
+        if (getParam('bx_profiler_long_page_debug'))
+            $s .= "All server vars: \n" . print_r ($_SERVER, true);
+        $s .= $this->_logEnd();
+        $this->_appendToLog ($s);
+    }
+
+    function beginModule($sType, $sHash, &$aModule, $sClassFile, $sMethod = '' )
+    {
+        ++$this->_aModulesLevel;
+        $this->_aModulesNames[$aModule['title']] = isset($this->_aModulesNames[$aModule['title']]) ? $this->_aModulesNames[$aModule['title']] + 1 : 1;
+        $this->_aModules[$sHash] = array (
+            'name' => str_repeat("--", $this->_aModulesLevel-1) . $aModule['title'],
+            'type' => $sType,
+            'class/file' => $sClassFile,
+            'method' => $sMethod,
+            'sql_counter' => BxDolDb::getInstance()->getQueriesCounter(),
+            'sql' => 0,
+            'kb_counter' => function_exists('memory_get_usage') ? memory_get_usage() : 0,
+            'kb' => 0,
+            'begin' => microtime (),
+            'time' => -1,
+        );
+    }
+
+    function endModule($sType, $sHash)
+    {
+        --$this->_aModulesLevel;
+
+        $iTime = $this->_calcTime ($this->_aModules[$sHash]['begin']);
+        unset ($this->_aModules[$sHash]['begin']);
+
+        $iSqlCounter = BxDolDb::getInstance()->getQueriesCounter() - $this->_aModules[$sHash]['sql_counter'];
+        unset ($this->_aModules[$sHash]['sql_counter']);
+
+        $iMemCounter = function_exists('memory_get_usage') ? memory_get_usage() - $this->_aModules[$sHash]['kb_counter']: 0;
+        unset ($this->_aModules[$sHash]['kb_counter']);
+
+        $this->_aModules[$sHash]['sql'] = $iSqlCounter;
+        $this->_aModules[$sHash]['kb'] = $this->_formatKb($iMemCounter);
+        $this->_aModules[$sHash]['time'] = $this->_formatTime($iTime);
+        $this->_aModules[$sHash]['raw_time'] = $iTime;
+        if (isset($this->aConf['long_module']) && $iTime > $this->aConf['long_module'])
+            $this->logModuleQuery ($iTime, $this->_aModules[$sHash]);
+    }
+
+    function beginAlert($sUnit, $sAction, $sHandler)
+    {
+        $sHash = md5($sUnit . $sAction . $sHandler . $this->_iAlertsLevel);
+        ++$this->_iAlertsLevel;
+        $this->_aAlerts[$sHash] = array (
+            'name' => str_repeat("--", $this->_iAlertsLevel-1) . $sHandler,
+            'unit' => $sUnit,
+            'action' => $sAction,
+            'handler' => $sHandler,
+            'sql_counter' => BxDolDb::getInstance()->getQueriesCounter(),
+            'sql' => 0,
+            'kb_counter' => function_exists('memory_get_usage') ? memory_get_usage() : 0,
+            'kb' => 0,
+            'begin' => microtime (),
+            'time' => -1,
+        );
+    }
+
+    function endAlert($sUnit, $sAction, $sHandler)
+    {
+        --$this->_iAlertsLevel;
+        $sHash = md5($sUnit . $sAction . $sHandler . $this->_iAlertsLevel);
+
+        $iTime = $this->_calcTime ($this->_aAlerts[$sHash]['begin']);
+        unset ($this->_aAlerts[$sHash]['begin']);
+
+        $iSqlCounter = BxDolDb::getInstance()->getQueriesCounter() - $this->_aAlerts[$sHash]['sql_counter'];
+        unset ($this->_aAlerts[$sHash]['sql_counter']);
+
+        $iMemCounter = function_exists('memory_get_usage') ? memory_get_usage() - $this->_aAlerts[$sHash]['kb_counter']: 0;
+        unset ($this->_aAlerts[$sHash]['kb_counter']);
+
+        $this->_aAlerts[$sHash]['sql'] = $iSqlCounter;
+        $this->_aAlerts[$sHash]['kb'] = $this->_formatKb($iMemCounter);
+        $this->_aAlerts[$sHash]['time'] = $this->_formatTime($iTime);
+        $this->_aAlerts[$sHash]['raw_time'] = $iTime;
+    }
+
+    function beginInjection ($sId)
+    {
+        $this->_sInjectionIndex = $sId;
+        $this->_aInjections[$sId] = [
+            'begin' => microtime (),
+            'sql_counter' => BxDolDb::getInstance()->getQueriesCounter(),
+            'kb_counter' => function_exists('memory_get_usage') ? memory_get_usage() : 0,
+        ];
+    }
+
+    function endInjection ($sId, $aInjection)
+    {
+        if (!isset($this->_aInjections[$sId]))
+            return;
+
+        $iTime = $this->_calcTime ($this->_aInjections[$sId]['begin']);
+        unset ($this->_aInjections[$sId]['begin']);
+
+        $iSqlCounter = BxDolDb::getInstance()->getQueriesCounter() - $this->_aInjections[$sId]['sql_counter'];
+        unset ($this->_aInjections[$sId]['sql_counter']);
+
+        $iMemCounter = function_exists('memory_get_usage') ? memory_get_usage() - $this->_aInjections[$sId]['kb_counter']: 0;
+        unset ($this->_aInjections[$sId]['kb_counter']);
+
+        $this->_aInjections[$sId]['name'] = isset($aInjection['name']) ? $aInjection['name'] : 'no-name';
+        $this->_aInjections[$sId]['key'] = $aInjection['key'];
+        $this->_aInjections[$sId]['replace'] = $aInjection['replace'] ? 'yes' : 'no';
+        $this->_aInjections[$sId]['sql'] = $iSqlCounter;
+        $this->_aInjections[$sId]['kb'] = $this->_formatKb($iMemCounter);
+        $this->_aInjections[$sId]['time'] = $this->_formatTime($iTime);
+        $this->_aInjections[$sId]['raw_time'] = $iTime;
+    }
+
+    function beginPageBlock ($sName, $iBlockId)
+    {
+        $this->_sPageBlockIndex = $iBlockId;
+        $this->_aPagesBlocks[$this->_sPageBlockIndex] = [
+            'name' => $sName,
+            'begin' => microtime (),
+            'sql_counter' => BxDolDb::getInstance()->getQueriesCounter(),
+            'kb_counter' => function_exists('memory_get_usage') ? memory_get_usage() : 0,
+        ];
+    }
+
+    function endPageBlock ($iBlockId, $isEmpty, $isCached)
+    {
+        if (!$this->_sPageBlockIndex)
+            return;
+
+        $iTime = $this->_calcTime ($this->_aPagesBlocks[$this->_sPageBlockIndex]['begin']);
+        unset ($this->_aPagesBlocks[$this->_sPageBlockIndex]['begin']);
+
+        $iSqlCounter = BxDolDb::getInstance()->getQueriesCounter() - $this->_aPagesBlocks[$this->_sPageBlockIndex]['sql_counter'];
+        unset ($this->_aPagesBlocks[$this->_sPageBlockIndex]['sql_counter']);
+
+        $iMemCounter = function_exists('memory_get_usage') ? memory_get_usage() - $this->_aPagesBlocks[$this->_sPageBlockIndex]['kb_counter']: 0;
+        unset ($this->_aPagesBlocks[$this->_sPageBlockIndex]['kb_counter']);
+
+        $this->_aPagesBlocks[$this->_sPageBlockIndex]['cached'] = $isCached ? 'yes' : 'no';
+        $this->_aPagesBlocks[$this->_sPageBlockIndex]['empty'] = $isEmpty ? 'yes' : 'no';
+        $this->_aPagesBlocks[$this->_sPageBlockIndex]['sql'] = $iSqlCounter;
+        $this->_aPagesBlocks[$this->_sPageBlockIndex]['kb'] = $this->_formatKb($iMemCounter);
+        $this->_aPagesBlocks[$this->_sPageBlockIndex]['time'] = $this->_formatTime($iTime);
+        $this->_aPagesBlocks[$this->_sPageBlockIndex]['raw_time'] = $iTime;
+    }
+
+    function beginPage ($sName)
+    {
+        $this->_sPageIndex = md5 ($sName.time().rand());
+        $this->_aPages[$this->_sPageIndex] = [
+            'name' => $sName,
+            'begin' => microtime (),
+            'sql_counter' => BxDolDb::getInstance()->getQueriesCounter(),
+            'kb_counter' => function_exists('memory_get_usage') ? memory_get_usage() : 0,
+        ];
+    }
+
+    function endPage (&$sContent)
+    {
+        if (!$this->_sPageIndex || !isset($this->_aPages[$this->_sPageIndex]['begin']))
+            return;
+
+        $iTime = $this->_calcTime ($this->_aPages[$this->_sPageIndex]['begin']);
+        unset ($this->_aPages[$this->_sPageIndex]['begin']);
+
+        $iSqlCounter = BxDolDb::getInstance()->getQueriesCounter() - $this->_aPages[$this->_sPageIndex]['sql_counter'];
+        unset ($this->_aPages[$this->_sPageIndex]['sql_counter']);
+
+        $iMemCounter = function_exists('memory_get_usage') ? memory_get_usage() - $this->_aPages[$this->_sPageIndex]['kb_counter']: 0;
+        unset ($this->_aPages[$this->_sPageIndex]['kb_counter']);
+
+        $this->_aPages[$this->_sPageIndex]['sql'] = $iSqlCounter;
+        $this->_aPages[$this->_sPageIndex]['kb'] = $this->_formatKb($iMemCounter);
+        $this->_aPages[$this->_sPageIndex]['time'] = $this->_formatTime($iTime);
+        $this->_aPages[$this->_sPageIndex]['raw_time'] = $iTime;
+    }
+
+    function beginTemplate ($sName, $sRand)
+    {
+        $this->_aTemplateIndexes[$sName.$sRand] = 1;
+        $this->_aTemplates[$sName.$sRand] = [
+            'name' => $sName,
+            'begin' => microtime (),
+            'sql_counter' => BxDolDb::getInstance()->getQueriesCounter(),
+            'kb_counter' => function_exists('memory_get_usage') ? memory_get_usage() : 0,
+        ];
+    }
+
+    function endTemplate ($sName, $sRand, &$sContent, $isCached)
+    {
+        if (!isset($this->_aTemplateIndexes[$sName.$sRand]))
+            return;
+
+        $iTime = $this->_calcTime ($this->_aTemplates[$sName.$sRand]['begin']);
+        unset ($this->_aTemplates[$sName.$sRand]['begin']);
+
+        $iSqlCounter = BxDolDb::getInstance()->getQueriesCounter() - $this->_aTemplates[$sName.$sRand]['sql_counter'];
+        unset ($this->_aTemplates[$sName.$sRand]['sql_counter']);
+
+        $iMemCounter = function_exists('memory_get_usage') ? memory_get_usage() - $this->_aTemplates[$sName.$sRand]['kb_counter']: 0;
+        unset ($this->_aTemplates[$sName.$sRand]['kb_counter']);
+
+        $this->_aTemplates[$sName.$sRand]['sql'] = $iSqlCounter;
+        $this->_aTemplates[$sName.$sRand]['kb'] = $this->_formatKb($iMemCounter);
+        $this->_aTemplates[$sName.$sRand]['cached'] = $isCached ? 'yes' : 'no';
+        $this->_aTemplates[$sName.$sRand]['time'] = $this->_formatTime($iTime);
+        $this->_aTemplates[$sName.$sRand]['raw_time'] = $iTime;
+    }
+
+    function beginQuery ($sSql)
+    {
+        $this->_sQueryIndex = md5 ($sSql.time().rand());
+        $this->_aQueries[$this->_sQueryIndex] = [
+            'sql' => $sSql,
+            'begin' => microtime (),
+            'kb_counter' => function_exists('memory_get_usage') ? memory_get_usage() : 0,
+        ];
+    }
+
+    function endQuery (&$oStmt)
+    {
+        if (!$this->_sQueryIndex)
+            return;
+
+        $iTime = $this->_calcTime ($this->_aQueries[$this->_sQueryIndex]['begin']);
+        unset ($this->_aQueries[$this->_sQueryIndex]['begin']);
+
+        $iMemCounter = function_exists('memory_get_usage') ? memory_get_usage() - $this->_aQueries[$this->_sQueryIndex]['kb_counter']: 0;
+        unset ($this->_aQueries[$this->_sQueryIndex]['kb_counter']);
+
+        $this->_aQueries[$this->_sQueryIndex]['time'] = $this->_formatTime($iTime);
+        $this->_aQueries[$this->_sQueryIndex]['raw_time'] = $iTime;
+        $this->_aQueries[$this->_sQueryIndex]['rows'] = $oStmt ? BxDolDb::getInstance()->getNumRows($oStmt) : '';
+        $this->_aQueries[$this->_sQueryIndex]['affected'] = $oStmt ? BxDolDb::getInstance()->getAffectedRows($oStmt) : '';
+        $this->_aQueries[$this->_sQueryIndex]['kb'] = $this->_formatKb($iMemCounter);
+        if (isset($this->aConf['long_query']) && $iTime > $this->aConf['long_query'])
+            $this->logSqlQuery ($iTime, $this->_aQueries[$this->_sQueryIndex], $oStmt);
+    }
+
+    function isMenu($sName)
+    {
+        return isset($this->_aMenus[$sName]);
+    }
+
+    function beginMenu ($sName)
+    {
+        $this->_aMenus[$sName] = [
+            'name' => $sName,
+            'begin' => microtime (),
+            'sql_counter' => BxDolDb::getInstance()->getQueriesCounter(),
+            'kb_counter' => function_exists('memory_get_usage') ? memory_get_usage() : 0,
+        ];
+    }
+
+    function endMenu ($sName, $sCacheType = '', $bCacheUsed = false)
+    {
+        if (!isset($this->_aMenus[$sName]))
+            return;
+
+        $iTime = $this->_calcTime ($this->_aMenus[$sName]['begin']);
+        unset ($this->_aMenus[$sName]['begin']);
+
+        $iSqlCounter = BxDolDb::getInstance()->getQueriesCounter() - $this->_aMenus[$sName]['sql_counter'];
+        unset ($this->_aMenus[$sName]['sql_counter']);
+
+        $iMemCounter = function_exists('memory_get_usage') ? memory_get_usage() - $this->_aMenus[$sName]['kb_counter']: 0;
+        unset ($this->_aMenus[$sName]['kb_counter']);
+
+        $this->_aMenus[$sName]['sql'] = $iSqlCounter;
+        $this->_aMenus[$sName]['kb'] = $this->_formatKb($iMemCounter);
+        $this->_aMenus[$sName]['time'] = $this->_formatTime($iTime);
+        $this->_aMenus[$sName]['raw_time'] = $iTime;        
+        $this->_aMenus[$sName]['cache type'] = $sCacheType;
+        $this->_aMenus[$sName]['cache used'] = $bCacheUsed ? 'yes' : 'no';
+    }
+
+    function _getCurrentDelay ()
+    {
+        $i1 = explode(' ', microtime ());
+        $i2 = explode(' ', $this->_iTimeStart);
+        return ($i1[0]+$i1[1]) - ($i2[0]+$i2[1]);
+    }
+
+    function _plankMain ()
+    {
+        $sTime = $this->_formatTime($this->_getCurrentDelay (), 3);
+        if (function_exists('memory_get_usage'))
+            $sMemory = $this->_formatBytes(memory_get_usage(true)) . ' of ' . ini_get('memory_limit') . ' allowed';
+        $aLoad = sys_getloadavg();
+        $sLoad = implode(',', array_map(function ($f) {
+            return round ($f, 2);
+        }, $aLoad));
+        return $this->oTemplate->plank(
+            $this->oTemplate->nameValue('Time:', $sTime) .
+            (function_exists('memory_get_usage') ? $this->oTemplate->nameValue('Memory:', $sMemory) : '') .
+            $this->oTemplate->nameValue('PHP:', phpversion()) .
+            $this->oTemplate->nameValue('SAPI:', php_sapi_name()) .
+            $this->oTemplate->nameValue('OS:', php_uname('s')) .
+            $this->oTemplate->nameValue('Avg load:', $sLoad)
+        );
+    }
+
+    function _plankTemplates ()
+    {
+        if (empty($GLOBALS['bx_profiler']->_aPages) && empty($GLOBALS['bx_profiler']->_aTemplates))
+            return;
+
+        $sPages = '';
+        if (!empty($GLOBALS['bx_profiler']->_aPages)) {
+            $iTimePages = 0;
+            foreach ($GLOBALS['bx_profiler']->_aPages as $k => $r) {
+                if (!isset($r['raw_time']))
+                    continue;
+                $iTimePages += $r['raw_time'];
+                unset ($GLOBALS['bx_profiler']->_aPages[$k]['raw_time']);
+            }
+            $sPages = count($GLOBALS['bx_profiler']->_aPages) . ' (' . $this->_formatTime($iTimePages, 3) . ')';
+        }
+
+        $sTemplatesCached = '';
+        $sTemplatesNotCached = '';
+        if ($GLOBALS['bx_profiler']->_aTemplates) {
+            $iTimeTemplatesCached = 0;
+            $iTimeTemplatesNotCached = 0;
+            $sTemplatesCached = 0;
+            $sTemplatesNotCached = 0;
+            foreach ($GLOBALS['bx_profiler']->_aTemplates as $k => $r) {
+                if (!isset($r['raw_time']))
+                    continue;
+                if ('yes' == $r['cached']) {
+                    $iTimeTemplatesCached += $r['raw_time'];
+                    ++$sTemplatesCached;
+                } else {
+                    $iTimeTemplatesNotCached += $r['raw_time'];
+                    ++$sTemplatesNotCached;
+                }
+                unset ($GLOBALS['bx_profiler']->_aTemplates[$k]['raw_time']);
+            }
+            if ($sTemplatesCached)
+                $sTemplatesCached .= ' (' . $this->_formatTime($iTimeTemplatesCached, 3) . ')';
+            if ($sTemplatesNotCached)
+                $sTemplatesNotCached .= ' (' . $this->_formatTime($iTimeTemplatesNotCached, 3) . ')';
+        }
+
+        return $this->oTemplate->plank(
+            ($sPages ? $this->oTemplate->nameValue('Pages:', $sPages) : '') .
+            ($sTemplatesCached ? $this->oTemplate->nameValue('Templates Cached:', $sTemplatesCached) : '') .
+            ($sTemplatesNotCached ? $this->oTemplate->nameValue('Templates Not Cached:', $sTemplatesNotCached) : ''),
+            $this->oTemplate->table($GLOBALS['bx_profiler']->_aTemplates)
+        );
+    }
+
+    function _plankInjections ()
+    {
+        if (!$GLOBALS['bx_profiler']->_aInjections)
+            return;
+
+        $iTimeInjections = 0;
+        foreach ($GLOBALS['bx_profiler']->_aInjections as $k => $r) {
+            if (!isset($r['raw_time']))
+                continue;
+            $iTimeInjections += $r['raw_time'];
+            unset ($GLOBALS['bx_profiler']->_aInjections[$k]['raw_time']);
+        }
+
+        $sInjections = count($GLOBALS['bx_profiler']->_aInjections) . ' injection (' . $this->_formatTime($iTimeInjections, 3) . ')';
+
+        return $this->oTemplate->plank(
+            $this->oTemplate->nameValue('Injections:', $sInjections),
+            $this->oTemplate->table($GLOBALS['bx_profiler']->_aInjections)
+        );
+    }
+
+    function _plankPagesBlocks ()
+    {
+        if (empty($GLOBALS['bx_profiler']->_aPagesBlocks))
+            return;
+
+        $iTimeBlocks = 0;
+        $iTimeBlocksCached = 0;
+        $iTimeBlocksNotCached = 0;
+        $iTimeBlocksEmpty = 0;
+        $iTimeBlocksNotEmpty = 0;
+
+        $iCountBlocksCached = 0;
+        $iCountBlocksNotCached = 0;
+        $iCountBlocksEmpty = 0;
+        $iCountBlocksNotEmpty = 0;
+
+        foreach ($GLOBALS['bx_profiler']->_aPagesBlocks as $k => $r) {
+            if (!isset($r['raw_time']))
+                continue;
+            $iTimeBlocks += $r['raw_time'];
+            if ($r['cached'] == 'yes') {
+                $iTimeBlocksCached += $r['raw_time'];
+                ++$iCountBlocksCached;
+            } else {
+                $iTimeBlocksNotCached += $r['raw_time'];
+                ++$iCountBlocksNotCached;
+            }
+            if ($r['empty'] == 'yes') {
+                $iTimeBlocksEmpty += $r['raw_time'];
+                ++$iCountBlocksEmpty;
+            } else {
+                $iTimeBlocksNotEmpty += $r['raw_time'];
+                ++$iCountBlocksNotEmpty;
+            }
+            unset ($GLOBALS['bx_profiler']->_aPagesBlocks[$k]['raw_time']);
+        }
+
+        $sBlocks = count($GLOBALS['bx_profiler']->_aPagesBlocks) . ' (' . $this->_formatTime($iTimeBlocks, 3) . ')';
+        if ($iCountBlocksCached)
+            $sBlocksCached = $iCountBlocksCached . ' (' . $this->_formatTime($iTimeBlocksCached, 3) . ')';
+        if ($iCountBlocksNotCached)
+            $sBlocksNotCached = $iCountBlocksNotCached . ' (' . $this->_formatTime($iTimeBlocksNotCached, 3) . ')';
+        if ($iCountBlocksEmpty)
+            $sBlocksEmpty = $iCountBlocksEmpty . ' (' . $this->_formatTime($iTimeBlocksEmpty, 3) . ')';
+        if ($iCountBlocksNotEmpty)
+            $sBlocksNotEmpty = $iCountBlocksNotEmpty . ' (' . $this->_formatTime($iTimeBlocksNotEmpty, 3) . ')';
+
+        return $this->oTemplate->plank(
+            $this->oTemplate->nameValue('Pages Blocks:', $sBlocks) .
+            ($iCountBlocksCached ? $this->oTemplate->nameValue('Cached:', $sBlocksCached) : '') .
+            ($iCountBlocksNotCached ? $this->oTemplate->nameValue('Not Cached:', $sBlocksNotCached) : '') .
+            ($iCountBlocksEmpty ? $this->oTemplate->nameValue('Empty:', $sBlocksEmpty) : '') .
+            ($iCountBlocksNotEmpty ? $this->oTemplate->nameValue('Not Empty:', $sBlocksNotEmpty) : ''),
+            $this->oTemplate->table($GLOBALS['bx_profiler']->_aPagesBlocks)
+        );
+    }
+
+    function _plankMenus ()
+    {
+        if (empty($GLOBALS['bx_profiler']->_aMenus))
+            return;
+
+        $iTimeMenus = 0;
+        foreach ($GLOBALS['bx_profiler']->_aMenus as $k => $r) {
+            if (!isset($r['raw_time']))
+                continue;
+            $iTimeMenus += $r['raw_time'];
+            unset ($GLOBALS['bx_profiler']->_aMenus[$k]['raw_time']);
+        }
+
+        $sMenus = count($GLOBALS['bx_profiler']->_aMenus) . ' menus (' . $this->_formatTime($iTimeMenus, 3) . ')';
+
+        return $this->oTemplate->plank(
+            $this->oTemplate->nameValue('Menus:', $sMenus),
+            $this->oTemplate->table($GLOBALS['bx_profiler']->_aMenus)
+        );
+    }
+
+    function _plankSql ()
+    {
+        if (empty($GLOBALS['bx_profiler']->_aQueries))
+            return;
+
+        $iTimeQueries = 0;
+        foreach ($GLOBALS['bx_profiler']->_aQueries as $k => $r) {
+            if (!isset($r['raw_time']))
+                continue;
+            $iTimeQueries += $r['raw_time'];
+            unset ($GLOBALS['bx_profiler']->_aQueries[$k]['raw_time']);
+        }
+
+        $sQueries = count($GLOBALS['bx_profiler']->_aQueries) . ' queries (' . $this->_formatTime($iTimeQueries, 3) . ')';
+
+        return $this->oTemplate->plank(
+            $this->oTemplate->nameValue('SQL:', $sQueries),
+            $this->oTemplate->table($GLOBALS['bx_profiler']->_aQueries, 'sql')
+        );
+    }
+
+    function _plankModules ()
+    {
+        if (empty($GLOBALS['bx_profiler']->_aModules))
+            return;
+
+        $iTimeModules = 0;
+        foreach ($GLOBALS['bx_profiler']->_aModules as $k => $r) {
+            if (!isset($r['raw_time']))
+                continue;
+            $iTimeModules += $r['raw_time'];
+            unset ($GLOBALS['bx_profiler']->_aModules[$k]['raw_time']);
+        }
+
+        $sModules = count($GLOBALS['bx_profiler']->_aModulesNames) . ' modules loaded';
+        $sModulesQueries = count($GLOBALS['bx_profiler']->_aModules) . ' modules queries (' . $this->_formatTime($iTimeModules, 3) . ')';
+
+        return $this->oTemplate->plank(
+            $this->oTemplate->nameValue('Modules:', $sModules) .
+            $this->oTemplate->nameValue('Modules Queries:', $sModulesQueries),
+            $this->oTemplate->table($GLOBALS['bx_profiler']->_aModules)
+        );
+    }
+
+    function _plankAlerts ()
+    {
+        if (empty($GLOBALS['bx_profiler']->_aAlerts))
+            return;
+
+        $iTimeAlerts = 0;
+        foreach ($GLOBALS['bx_profiler']->_aAlerts as $k => $r) {
+            if (!isset($r['raw_time']))
+                continue;
+            $iTimeAlerts += $r['raw_time'];
+            unset ($GLOBALS['bx_profiler']->_aAlerts[$k]['raw_time']);
+        }
+
+        $sAlerts = count($GLOBALS['bx_profiler']->_aAlerts) . ' alerts responses (' . $this->_formatTime($iTimeAlerts, 3) . ')';
+
+        return $this->oTemplate->plank(
+            $this->oTemplate->nameValue('Alerts:', $sAlerts),
+            $this->oTemplate->table($GLOBALS['bx_profiler']->_aAlerts)
+        );
+    }
+
+    function _formatTime ($i, $iPrecision = 4)
+    {
+        return round($i, $iPrecision) . ' sec';
+    }
+
+    function _formatBytes ($i)
+    {
+        return bx_format_bytes($i);
+    }
+
+    function _formatKb ($i)
+    {
+        $s = round($i / 1024, 0);
+        return $s == '-0' ? '0' : $s;
+    }
+
+    function _isProfilerDisabled()
+    {
+        if (isset($GLOBALS['bx_profiler_disable']) || isset($_GET['bx_profiler_disable']) || defined('BX_API'))
+            return true;
+
+        return false;
+    }
+
+    function _calcTime ($begin)
+    {
+        $i1 = explode(' ', microtime ());
+        $i2 = explode(' ', $begin);
+        return ($i1[0]+$i1[1]) - ($i2[0]+$i2[1]);
+    }
+
+    function _debugPrintArray ($mixed)
+    {
+        $sArgs .= 'Array(';
+        foreach ($mixed as $mixed2)
+            $sArgs .= (is_object($mixed2) ? $this->_debugPrintObject($mixed2) : $this->_debugPrintAny($mixed2)) . ',';
+        $sArgs = substr($sArgs, 0, -1);
+        $sArgs .= ')';
+        return $sArgs;
+    }
+
+    function _debugPrintObject ($mixed)
+    {
+        return get_class($mixed) . ' instance';
+    }
+
+    function _debugPrintAny ($mixed)
+    {
+        if (is_string($mixed))
+            return "'" . (strlen($mixed) > $this->_sLogMaxArgLength ? substr($mixed, 0, $this->_sLogMaxArgLength) . '...' : $mixed) . "'";
+        else
+            return $mixed;
+    }
+
+    function _debugBackTrace ($iShifts = 0)
+    {
+        $a = debug_backtrace();
+        while (--$iShifts > -1)
+            array_shift($a);
+
+        $s = '';
+        foreach ($a as $r) {
+
+            $sArgs = '';
+            foreach ($r['args'] as $mixed) {
+                switch (true) {
+                case is_array($mixed):
+                    $sArgs .= $this->_debugPrintArray($mixed);
+                    break;
+                case is_object($mixed):
+                    $sArgs .= $this->_debugPrintObject($mixed);
+                    break;
+                default:
+                    $sArgs .= $this->_debugPrintAny($mixed);
+                }
+                $sArgs .= ',';
+            }
+            $sArgs = substr($sArgs, 0, -1);
+
+            $s .= "--------------------------------------\n";
+            $s .= "{$r['line']} {$r['file']}\n";
+            $s .= "{$r['class']}{$r['type']}{$r['function']} ({$sArgs});\n";
+        }
+        return $s;
+    }
+}
+
+$GLOBALS['bx_profiler'] = new BxProfiler(BX_DOL_START);
+if (!$GLOBALS['bx_profiler']->_isProfilerDisabled())
+    register_shutdown_function (array ($GLOBALS['bx_profiler'], 'output'));
+
+/** @} */

+ 69 - 0
modules/boonex/profiler/updates/15.0.1_15.0.2/source/install/config.php

@@ -0,0 +1,69 @@
+<?php
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Profiler Profiler
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+$aConfig = array(
+
+    /**
+     * Main Section.
+     */
+    'type' => BX_DOL_MODULE_TYPE_MODULE,
+    'name' => 'bx_profiler',
+    'title' => 'Profiler',
+    'note' => 'Measure different site timings.',
+    'version' => '15.0.2',
+    'vendor' => 'UNA INC',
+    'help_url' => 'http://feed.una.io/?section={module_name}',
+
+    'compatible_with' => array(
+        '15.0.0-B2'
+    ),
+
+    /**
+     * 'home_dir' and 'home_uri' - should be unique. Don't use spaces in 'home_uri' and the other special chars.
+     */
+    'home_dir' => 'boonex/profiler/',
+    'home_uri' => 'profiler',
+
+    'db_prefix' => 'bx_profiler_',
+    'class_prefix' => 'BxProfiler',
+
+    /**
+     * Category for language keys.
+     */
+    'language_category' => 'Boonex Profiler',
+
+    /**
+     * Installation/Uninstallation Section.
+     */
+    'install' => array(
+        'execute_sql' => 1,
+        'update_languages' => 1,
+    ),
+    'uninstall' => array (
+        'execute_sql' => 1,
+        'update_languages' => 1,
+    ),
+    'enable' => array(
+        'execute_sql' => 1,
+        'clear_db_cache' => 1,
+    ),
+    'disable' => array(
+        'execute_sql' => 1,
+        'clear_db_cache' => 1,
+    ),
+
+    /**
+     * Dependencies Section
+     */
+    'dependencies' => array(),
+);
+
+/** @} */

+ 51 - 0
modules/boonex/protean/updates/15.0.2_15.0.3/install/config.php

@@ -0,0 +1,51 @@
+<?php
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ */
+
+$aConfig = array(
+    /**
+     * Main Section.
+     */
+    'title' => 'Protean',
+    'version_from' => '15.0.2',
+    'version_to' => '15.0.3',
+    'vendor' => 'UNA INC',
+
+    'compatible_with' => array(
+        '15.0.0-B2'
+    ),
+
+    /**
+     * 'home_dir' and 'home_uri' - should be unique. Don't use spaces in 'home_uri' and the other special chars.
+     */
+    'home_dir' => 'boonex/protean/updates/update_15.0.2_15.0.3/',
+    'home_uri' => 'protean_update_1502_1503',
+
+    'module_dir' => 'boonex/protean/',
+    'module_uri' => 'protean',
+
+    'db_prefix' => 'bx_protean_',
+    'class_prefix' => 'BxProtean',
+
+    /**
+     * Installation/Uninstallation Section.
+     */
+    'install' => array(
+        'execute_sql' => 0,
+        'update_files' => 1,
+        'update_languages' => 0,
+        'clear_db_cache' => 0,
+    ),
+
+    /**
+     * Category for language keys.
+     */
+    'language_category' => 'Boonex Protean Template',
+
+    /**
+     * Files Section
+     */
+    'delete_files' => array(),
+);

Некоторые файлы не были показаны из-за большого количества измененных файлов