Răsfoiți Sursa

Upgrade script from 15.0.0-B3 to 15.0.0-RC1

Aleksandr Trofimov 3 luni în urmă
părinte
comite
e3beaec60c
100 a modificat fișierele cu 45742 adăugiri și 0 ștergeri
  1. 702 0
      upgrade/files/15.0.0.B3-15.0.0.RC1/files/inc/classes/BxDolAI.php
  2. 1071 0
      upgrade/files/15.0.0.B3-15.0.0.RC1/files/inc/classes/BxDolAIQuery.php
  3. 46 0
      upgrade/files/15.0.0.B3-15.0.0.RC1/files/inc/classes/BxDolAIToolCmtsGetSingle.php
  4. 132 0
      upgrade/files/15.0.0.B3-15.0.0.RC1/files/inc/classes/BxDolAIVectorStoreFactory.php
  5. 1211 0
      upgrade/files/15.0.0.B3-15.0.0.RC1/files/inc/classes/BxDolAccount.php
  6. 2684 0
      upgrade/files/15.0.0.B3-15.0.0.RC1/files/inc/classes/BxDolCmts.php
  7. 950 0
      upgrade/files/15.0.0.B3-15.0.0.RC1/files/inc/classes/BxDolCmtsQuery.php
  8. 2096 0
      upgrade/files/15.0.0.B3-15.0.0.RC1/files/inc/classes/BxDolForm.php
  9. 1002 0
      upgrade/files/15.0.0.B3-15.0.0.RC1/files/inc/classes/BxDolPage.php
  10. 1008 0
      upgrade/files/15.0.0.B3-15.0.0.RC1/files/inc/classes/BxDolPrivacy.php
  11. 357 0
      upgrade/files/15.0.0.B3-15.0.0.RC1/files/inc/classes/BxDolReport.php
  12. 1511 0
      upgrade/files/15.0.0.B3-15.0.0.RC1/files/inc/classes/BxDolSearch.php
  13. 977 0
      upgrade/files/15.0.0.B3-15.0.0.RC1/files/inc/classes/BxDolWiki.php
  14. 998 0
      upgrade/files/15.0.0.B3-15.0.0.RC1/files/inc/js/classes/BxDolCmts.js
  15. 207 0
      upgrade/files/15.0.0.B3-15.0.0.RC1/files/inc/js/classes/BxDolForm.js
  16. 174 0
      upgrade/files/15.0.0.B3-15.0.0.RC1/files/inc/js/classes/BxDolReport.js
  17. 443 0
      upgrade/files/15.0.0.B3-15.0.0.RC1/files/inc/js/jquery.webForms.js
  18. 12 0
      upgrade/files/15.0.0.B3-15.0.0.RC1/files/inc/version.inc.php
  19. 4926 0
      upgrade/files/15.0.0.B3-15.0.0.RC1/files/modules/base/general/classes/BxBaseModGeneralModule.php
  20. 342 0
      upgrade/files/15.0.0.B3-15.0.0.RC1/files/modules/base/general/classes/BxBaseModGeneralSearchResult.php
  21. 2860 0
      upgrade/files/15.0.0.B3-15.0.0.RC1/files/modules/base/groups/classes/BxBaseModGroupsModule.php
  22. 306 0
      upgrade/files/15.0.0.B3-15.0.0.RC1/files/modules/base/profile/classes/BxBaseModProfileFormsEntryHelper.php
  23. 2749 0
      upgrade/files/15.0.0.B3-15.0.0.RC1/files/modules/base/profile/classes/BxBaseModProfileModule.php
  24. 509 0
      upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/akeeba/s3/src/Configuration.php
  25. 840 0
      upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/akeeba/s3/src/Request.php
  26. 216 0
      upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/akeeba/s3/src/Signature/V2.php
  27. 544 0
      upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/akeeba/s3/src/Signature/V4.php
  28. 22 0
      upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/autoload.php
  29. 73 0
      upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/composer.json
  30. 88 0
      upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/Acm/AcmClient.php
  31. 540 0
      upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/Api/Serializer/RestSerializer.php
  32. 121 0
      upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/AppConfig/AppConfigClient.php
  33. 69 0
      upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/ApplicationSignals/ApplicationSignalsClient.php
  34. 41 0
      upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/Artifact/ArtifactClient.php
  35. 225 0
      upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/Bedrock/BedrockClient.php
  36. 159 0
      upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/BedrockAgent/BedrockAgentClient.php
  37. 315 0
      upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/BedrockAgentCoreControl/BedrockAgentCoreControlClient.php
  38. 75 0
      upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/BedrockAgentRuntime/BedrockAgentRuntimeClient.php
  39. 29 0
      upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/BedrockRuntime/BedrockRuntimeClient.php
  40. 43 0
      upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/Billing/BillingClient.php
  41. 209 0
      upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/CleanRooms/CleanRoomsClient.php
  42. 441 0
      upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/CloudFront/CloudFrontClient.php
  43. 74 0
      upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/CloudFront/CookieSigner.php
  44. 267 0
      upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/CloudFront/Signer.php
  45. 128 0
      upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/CloudFront/UrlSigner.php
  46. 110 0
      upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/CloudWatch/CloudWatchClient.php
  47. 277 0
      upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/CloudWatchLogs/CloudWatchLogsClient.php
  48. 266 0
      upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/CognitoIdentityProvider/CognitoIdentityProviderClient.php
  49. 214 0
      upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/ConfigService/ConfigServiceClient.php
  50. 297 0
      upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/Configuration/ConfigurationResolver.php
  51. 767 0
      upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/Connect/ConnectClient.php
  52. 468 0
      upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/Credentials/InstanceProfileProvider.php
  53. 109 0
      upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/Crypto/AesGcmDecryptingStream.php
  54. 424 0
      upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/Crypto/DecryptionTraitV2.php
  55. 530 0
      upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/Crypto/DecryptionTraitV3.php
  56. 193 0
      upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/Crypto/EncryptionTrait.php
  57. 192 0
      upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/Crypto/EncryptionTraitV2.php
  58. 474 0
      upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/Crypto/EncryptionTraitV3.php
  59. 223 0
      upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/CustomerProfiles/CustomerProfilesClient.php
  60. 387 0
      upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/DataZone/DataZoneClient.php
  61. 261 0
      upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/Deadline/DeadlineClient.php
  62. 133 0
      upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/DevOpsAgent/DevOpsAgentClient.php
  63. 139 0
      upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/EKS/EKSClient.php
  64. 1602 0
      upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/Ec2/Ec2Client.php
  65. 140 0
      upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/Emr/EmrClient.php
  66. 59 0
      upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/GameLiftStreams/GameLiftStreamsClient.php
  67. 601 0
      upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/Glue/GlueClient.php
  68. 189 0
      upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/GuardDuty/GuardDutyClient.php
  69. 59 0
      upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/HealthLake/HealthLakeClient.php
  70. 91 0
      upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/IVS/IVSClient.php
  71. 171 0
      upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/Inspector2/Inspector2Client.php
  72. 32 0
      upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/IotDataPlane/IotDataPlaneClient.php
  73. 9 0
      upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/LambdaCore/Exception/LambdaCoreException.php
  74. 19 0
      upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/LambdaCore/LambdaCoreClient.php
  75. 9 0
      upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/LambdaMicrovms/Exception/LambdaMicrovmsException.php
  76. 57 0
      upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/LambdaMicrovms/LambdaMicrovmsClient.php
  77. 59 0
      upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/MQ/MQClient.php
  78. 473 0
      upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/Middleware.php
  79. 157 0
      upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/Multipart/AbstractUploader.php
  80. 237 0
      upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/Multipart/UploadState.php
  81. 177 0
      upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/NetworkFirewall/NetworkFirewallClient.php
  82. 141 0
      upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/Odb/OdbClient.php
  83. 201 0
      upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/OpenSearchService/OpenSearchServiceClient.php
  84. 95 0
      upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/Outposts/OutpostsClient.php
  85. 9 0
      upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/PartnerCentralRevenueMeasurement/Exception/PartnerCentralRevenueMeasurementException.php
  86. 45 0
      upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/PartnerCentralRevenueMeasurement/PartnerCentralRevenueMeasurementClient.php
  87. 99 0
      upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/PartnerCentralSelling/PartnerCentralSellingClient.php
  88. 227 0
      upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/PinpointSMSVoiceV2/PinpointSMSVoiceV2Client.php
  89. 547 0
      upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/QuickSight/QuickSightClient.php
  90. 9 0
      upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/Resiliencehubv2/Exception/Resiliencehubv2Exception.php
  91. 111 0
      upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/Resiliencehubv2/Resiliencehubv2Client.php
  92. 464 0
      upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/Retry/V3/RetryMiddleware.php
  93. 281 0
      upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/RetryMiddleware.php
  94. 389 0
      upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/RetryMiddlewareV2.php
  95. 105 0
      upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/Route53GlobalResolver/Route53GlobalResolverClient.php
  96. 153 0
      upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/Route53Resolver/Route53ResolverClient.php
  97. 359 0
      upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/S3/Crypto/S3EncryptionClient.php
  98. 475 0
      upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/S3/Crypto/S3EncryptionClientV2.php
  99. 588 0
      upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/S3/Crypto/S3EncryptionClientV3.php
  100. 47 0
      upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/S3/Exception/MultipartCopyAnnotationException.php

+ 702 - 0
upgrade/files/15.0.0.B3-15.0.0.RC1/files/inc/classes/BxDolAI.php

@@ -0,0 +1,702 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    UnaCore UNA Core
+ * @{
+ */
+
+define('BX_DOL_AI_ASSISTANT', 'assistant');
+define('BX_DOL_AI_AUTOMATOR_EVENT', 'event');
+define('BX_DOL_AI_AUTOMATOR_SCHEDULER', 'scheduler');
+define('BX_DOL_AI_AUTOMATOR_WEBHOOK', 'webhook');
+
+define('BX_DOL_AI_AUTOMATOR_STATUS_AUTO', 'auto');
+define('BX_DOL_AI_AUTOMATOR_STATUS_MANUAL', 'manual');
+define('BX_DOL_AI_AUTOMATOR_STATUS_READY', 'ready');
+
+class BxDolAI extends BxDolFactory implements iBxDolSingleton
+{
+    protected $_oDb;
+    protected $_iProfileId;
+    
+    protected $_aExcludeAlertUnits;
+
+    protected $_sCmtsAutomators;
+    protected $_sCmtsAssistantsChats;
+
+    protected $_bWriteLog;
+
+    protected function __construct()
+    {
+        if (isset($GLOBALS['bxDolClasses'][get_class($this)]))
+            trigger_error ('Multiple instances are not allowed for the class: ' . get_class($this), E_USER_ERROR);
+
+        parent::__construct();
+
+        $this->_oDb = new BxDolAIQuery();
+
+        $this->_iProfileId = (int)getParam('sys_profile_bot'); 
+
+        $this->_aExcludeAlertUnits = [
+            'system', 'module_template_method_call'
+        ];
+
+        $this->_sCmtsAutomators = 'sys_agents_automators';
+        $this->_sCmtsAssistantsChats = 'sys_agents_assistants_chats';
+
+        $this->_bWriteLog = true;
+    }
+
+    /**
+     * Prevent cloning the instance
+     */
+    public function __clone()
+    {
+        if (isset($GLOBALS['bxDolClasses'][get_class($this)]))
+            trigger_error('Clone is not allowed for the class: ' . get_class($this), E_USER_ERROR);
+    }
+
+    /**
+     * Get singleton instance of the class
+     */
+    public static function getInstance()
+    {
+        if (!isset($GLOBALS['bxDolClasses'][__CLASS__])) {
+            $GLOBALS['bxDolClasses'][__CLASS__] = BxDolDb::getInstance()->isTableExists('sys_agents_agents') ? new BxDolAI() : null;
+        }
+
+        return $GLOBALS['bxDolClasses'][__CLASS__];
+    }
+
+    public static function getAgentInstance(int $iId, array $aParams = []): NeuronAI\Agent\Agent
+    {
+        if (isset($GLOBALS['bxDolClasses'][__CLASS__ . '_Agent_' . $iId]))
+            return $GLOBALS['bxDolClasses'][__CLASS__ . '_Agent_' . $iId];
+
+        $a = BxDolAIQuery::getAgentObject($iId);
+        if (!$a) {
+            $s = "Agent with id {$iId} not found";
+            bx_log('sys_agents', $s, BX_LOG_ERR);
+            throw new Exception($s);
+        }
+        if (!$a['active']) {
+            $s = "Agent with id {$iId} isn't active";
+            bx_log('sys_agents', $s, BX_LOG_ERR);
+            throw new Exception($s);
+        }
+        if (!$a['prompt_system'] || !$a['model_id']) {
+            $s = "Agent with id {$iId} can't be used because it haven't prompt or AI model";
+            bx_log('sys_agents', $s, BX_LOG_ERR);
+            throw new Exception($s);
+        }
+
+        $o = BxDolAiAgent::make($a, $aParams);
+
+        if ((int)$a['tools_max_run'] > 0)
+            $o->toolMaxRuns($a['tools_max_run']);
+
+        if ($a['vector_store_id']) {
+            $aVectorStore = BxDolAIQuery::getVectorStoreObject($a['vector_store_id']);
+            if ($aVectorStore && $aVectorStore['embedding_provider_id']) {
+                $oEmbedder = self::getAiEmbeddingsProviderInstance($aVectorStore['embedding_provider_id']);
+                $o->setEmbeddingsProvider($oEmbedder);
+            }
+        }
+
+        $GLOBALS['bxDolClasses'][__CLASS__ . '_Agent_' . $iId] = $o;
+
+        return $o;
+    }
+
+    public static function getAiProviderInstance(int $iId):NeuronAI\Providers\AIProviderInterface
+    {
+        return BxDolAIModelFactory::getModelInstance($iId);
+    }   
+
+    public static function getAiEmbeddingsProviderInstance(int $iId):NeuronAI\RAG\Embeddings\EmbeddingsProviderInterface
+    {
+        return BxDolAIModelFactory::getModelInstance($iId);
+    }
+
+    public static function callHelper($mixedHelper, $sMessage)
+    {
+        $oAI = BxDolAI::getInstance();
+        if (is_numeric($mixedHelper))
+            $aHelper = $oAI->getHelperById($mixedHelper);
+        else
+             $aHelper = $oAI->getHelperByName($mixedHelper);
+        $oAIModel = $oAI->getModelObject($aHelper['model_id']);
+        return $oAIModel->getResponseText($aHelper['prompt'], $sMessage);
+    }
+
+    public static function pruning()
+    {
+        BxDolAIAssistant::pruning();
+    }
+
+    public static function getDefaultApiKey()
+    {
+        return getParam('sys_agents_api_key');
+    }
+
+    public static function getDefaultModel()
+    {
+        return (int)getParam('sys_agents_model');
+    }
+
+    public static function getAssistantForStudio()
+    {
+        return ($iId = (int)getParam('sys_agents_studio_assistant')) != 0 ? $iId : 0;
+    }
+
+    public static function getAssistantForLiveSearch()
+    {
+        return ($iId = (int)getParam('sys_agents_live_search_assistant')) != 0 ? $iId : 0;
+    }
+
+    public static function getAssistantForAskBlock()
+    {
+        return ($iId = (int)getParam('sys_agents_ask_block_assistant')) != 0 ? $iId : 0;
+    }
+
+    public function getProfileId()
+    {
+        return $this->_iProfileId;
+    }
+
+    public function getModels($aParams = [])
+    {
+        $aParamsDb = ['sample' => 'all_pairs'];
+        if(isset($aParams['active']))
+            $aParamsDb['active'] = $aParams['active'] === true ? 1 : 0;
+        if(isset($aParams['capabilities']))
+            $aParamsDb['capabilities'] = $aParams['capabilities'];
+
+        return $aModel = $this->_oDb->getModelsBy($aParamsDb);
+    }
+
+    public function getModel($iId)
+    {
+        $aModel = $this->_oDb->getModelsBy(['sample' => 'id', 'id' => $iId]);
+        if(!empty($aModel['params']))
+            $aModel['params'] = json_decode($aModel['params'], true);
+
+        return $aModel;
+    }
+
+    public function getModelObject($iId)
+    {
+        if(!$iId)
+            $iId = $this->getDefaultModel();
+        if(!$iId)
+            return false;
+
+        return BxDolAIModel::getObjectInstance($iId);
+    }
+    
+    public function getProviderObject($iId)
+    {
+        if(!$iId)
+            return false;
+
+        return BxDolAIProvider::getObjectInstance($iId);
+    }   
+
+    public function getAssistants($aParams = [])
+    {
+        $aParamsDb = ['sample' => 'all_pairs'];
+        if(isset($aParams['active']))
+            $aParamsDb['active'] = $aParams['active'] === true ? 1 : 0;
+        if(isset($aParams['hidden']))
+            $aParamsDb['hidden'] = $aParams['hidden'] === true ? 1 : 0;
+
+        return $aModel = $this->_oDb->getAssistantsBy($aParamsDb);
+    }
+
+    public function getAssistantById($iId)
+    {
+        return $this->_oDb->getAssistantsBy(['sample' => 'id', 'id' => $iId]);
+    }
+
+    public function getAssistantByName($sName)
+    {
+        return $this->_oDb->getAssistantsBy(['sample' => 'name', 'name' => $sName]);
+    }
+
+    public function getAssistantChatById($iId)
+    {
+        return $this->_oDb->getChatsBy(['sample' => 'id', 'id' => $iId]);
+    }
+
+    public function getAssistantChatsTransient($iLifetime = 0)
+    {
+        return $this->_oDb->getChatsBy(['sample' => 'type', 'type' => BX_DOL_AI_ASST_TYPE_TRANSIENT, 'lifetime' => $iLifetime]);
+    }
+
+    public function updateAssistantChatById($iId, $aSet)
+    {
+        return $this->_oDb->updateChats($aSet, ['id' => $iId]);
+    }
+
+    public function getAssistantChatCmts()
+    {
+        return $this->_sCmtsAssistantsChats;
+    }
+
+    public function getAssistantChatCmtsObject($iId, $oTemplate = false)
+    {
+        $oCmts = BxDolCmts::getObjectInstance($this->_sCmtsAssistantsChats, (int)$iId, true, $oTemplate);
+        if(!$oCmts || !$oCmts->isEnabled())
+            return false;
+
+        return $oCmts;
+    }
+
+    public function getHelperById($iId)
+    {
+        return $this->_oDb->getHelpersBy(['sample' => 'id', 'id' => $iId]);
+    }
+    
+    public function getHelperByName($sName)
+    {
+        return $this->_oDb->getHelpersBy(['sample' => 'name', 'name' => $sName]);
+    }
+
+    public function getAutomator($iId, $bFullInfo = false)
+    {
+        $aAutomator = $this->_oDb->getAutomatorsBy(['sample' => 'id' . ($bFullInfo ? '_full' : ''), 'id' => $iId]);
+        if(!empty($aAutomator['params']))
+            $aAutomator['params'] = json_decode($aAutomator['params'], true);
+        if($bFullInfo && !empty($aAutomator['model_params']))
+            $aAutomator['model_params'] = json_decode($aAutomator['model_params'], true);
+
+        return $aAutomator;
+    }
+
+    public function getAutomatorInstruction($sType, $mixedParams = false)
+    {
+        $mixedResult = '';
+
+        switch($sType) {
+            case 'profile':
+                $mixedResult = "\n ProfileId for system actions = " . $mixedParams;
+                break;
+
+            case 'providers':
+                $aProviders = $this->_oDb->getProvidersBy(['sample' => 'ids', 'ids' => $mixedParams]);
+                if(!empty($aProviders) && is_array($aProviders)) {
+                    $mixedResult = "\n Proividers list = [";
+                    foreach($aProviders as $aProvider)
+                        $mixedResult .= "\n {'ProviderName' => '" . $aProvider['name'] . "',  'ProviderType' => '" . $aProvider['type_name'] . "'}";
+                    $mixedResult .= "\n ]";
+                }
+                break;
+
+            case 'helpers':
+                $aHelpers = $this->_oDb->getHelpersBy(['sample' => 'ids', 'ids' => $mixedParams]);
+                if(!empty($aHelpers) && is_array($aHelpers)) {
+                    $mixedResult = "\n Helpers list = [";
+                    foreach($aHelpers as $aHelper)
+                        $mixedResult .= "\n {'" . $aHelper['name'] . "', 'HelperDescription' => '" . $aHelper['description'] . "'}";
+                    $mixedResult .= "\n ]";
+                }
+                break;
+
+            case 'assistants':
+                $aAssistants = $this->_oDb->getAssistantsBy(['sample' => 'ids', 'ids' => $mixedParams]);
+                if(!empty($aAssistants) && is_array($aAssistants)) {
+                    $mixedResult = "\n Assistants list = [";
+                    foreach($aAssistants as $aAssistant)
+                        $mixedResult .= "\n {'" . $aAssistant['name'] . "', 'AssistantDescription' => '" . $aAssistant['description'] . "'}";
+                    $mixedResult .= "\n ]";
+                }
+                break;
+        }
+
+        return $mixedResult;
+    }
+
+    public function getAutomatorCmts()
+    {
+        return $this->_sCmtsAutomators;
+    }
+
+    public function getAutomatorCmtsObject($iId, $oTemplate = false)
+    {
+        $oCmts = BxDolCmts::getObjectInstance($this->_sCmtsAutomators, (int)$iId, true, $oTemplate);
+        if(!$oCmts || !$oCmts->isEnabled())
+            return false;
+
+        return $oCmts;
+    }
+
+    public function hasAutomators($sType, $bActive = null)
+    {
+        $aParams = [
+            'sample' => 'type', 
+            'type' => $sType
+        ];
+        if($bActive !== null)
+            $aParams['active'] = $bActive;
+
+        return ($aAutomators = $this->_oDb->getAutomatorsBy($aParams)) && is_array($aAutomators);
+    }
+
+    public function getAutomatorsEvent($sUnit, $sAction)
+    {
+        if(in_array($sUnit, $this->_aExcludeAlertUnits))
+            return [];
+
+        return $this->_oDb->getAutomatorsBy([
+            'sample' => 'events', 
+            'alert_unit' => $sUnit,
+            'alert_action' => $sAction,
+            'active' => true
+        ]);
+    }
+
+    public function getAutomatorsScheduler()
+    {
+        $aAutomators = $this->_oDb->getAutomatorsBy(['sample' => 'schedulers', 'active' => true]);
+        foreach($aAutomators as &$aAutomator)
+            if(!empty($aAutomator['params']))
+                $aAutomator['params'] = json_decode($aAutomator['params'], true);
+
+        return $aAutomators;
+    }
+
+    public function getAutomatorsWebhook($iProviderId)
+    {
+        $aAutomators = $this->_oDb->getAutomatorsBy(['sample' => 'webhooks', 'provider_id' => $iProviderId, 'active' => true]);
+        foreach($aAutomators as &$aAutomator)
+            if(!empty($aAutomator['params']))
+                $aAutomator['params'] = json_decode($aAutomator['params'], true);
+
+        return $aAutomators;
+    }
+
+    public function callAgent($sType, $aAgent, $mixedParams = [])
+    {
+        if ($mixedParams)
+            $sParams = is_string($mixedParams) ? $mixedParams : json_encode($mixedParams);
+        else
+            $sParams = 'START';
+
+        // update sample data
+        $a = ['webhook' => 'webhook_sample'];
+        if (isset($a[$sType]) && empty($aAgent[$a[$sType]])) {
+            $this->_oDb->updateAgentField($aAgent['id'], $a[$sType], $sParams);
+        }
+
+        // set additional params
+        $aParams = [];
+        if ('message' == $sType || 'form-input' == $sType || 'alert' == $sType) {
+            $aParams = ['chat_history_subindex' => $mixedParams['sender_profile_id']];
+        }
+
+        // call agent
+        $mixed = '';
+        try {                        
+            $o = self::getAgentInstance($aAgent['id'], $aParams);
+            if (!$o)
+                return false;
+
+            $oMessage = $o->chat(new NeuronAI\Chat\Messages\UserMessage($sParams))->getMessage();
+
+            $mixed = $oMessage->getContent();
+
+        } catch (Exception $exception) {            
+            bx_log('sys_agents', "Exception in '{$aAgent['name']}' agent: " . $exception->getMessage() . " INPUT:" . $sParams, BX_LOG_ERR);
+            $mixed = _t('_sys_agents_exception');
+        }
+
+        return $mixed;
+    }
+
+    public function sendMessengerMessage ($iSender, $iRecipient, $sMsg) 
+    {        
+        $oMessengerModule = BxDolModule::getInstance('bx_messenger');
+
+        $aAutoReplyData = [
+            'message' => $sMsg,
+            'participants' => [$iSender, $iRecipient],
+        ];
+
+        $iSaveProfileId = $oMessengerModule->setProfileId($iSender);
+        $a = $oMessengerModule->sendMessage($aAutoReplyData, $iRecipient, $iSender);
+        $oMessengerModule->setProfileId($iSaveProfileId);
+
+        return $a;
+    }
+
+    public function getAgentsByAlertUnitAndAction($sUnit, $sAction)
+    {
+        $aAgents = [];
+        $a = $this->_oDb->getAgentsWithAlert();
+        foreach ($a as $r) {
+            $aAlert = explode(':', $r['alert']); // TODO: remake to concantenate $sUnit and $sAction and then compare
+            if (count($aAlert) == 2 && $aAlert[0] == $sUnit && $aAlert[1] == $sAction)
+                $aAgents[] = $r;
+        }
+
+        return $aAgents;
+    }
+
+    public function getAgentsBy($aParams)
+    {
+        return $this->_oDb->getAgentsBy($aParams);
+    }
+
+    public function getAgentsByProfileId($iProfileId)
+    {
+        return $this->_oDb->getAgentsByProfileId($iProfileId);
+    }
+    
+    public function getAgentsByFormObject($sFormObject)
+    {
+        return $this->_oDb->getAgentsByFormObject($sFormObject);
+    }
+
+    public function getAgentsByTriggerType($sTrigger)
+    {
+        return $this->_oDb->getAgentsByTriggerType($sTrigger);
+    }
+
+    public function getAgentById($iId)
+    {
+        return $this->_oDb->getAgentById($iId);
+    }
+
+    public function getAgentByTriggerWebhookKey($sKey)
+    {
+        return $this->_oDb->getAgentByTriggerWebhookKey($sKey);
+    }
+
+    public function callAutomator($sType, $aParams = [])
+    {
+        $sMethod = '_callAutomator' . bx_gen_method_name($sType);
+        if(!method_exists($this, $sMethod))
+            return false;
+
+        return $this->$sMethod($aParams);
+    }
+
+    protected function _callAutomatorEvent($aParams = [])
+    {
+        if(!isset($aParams['automator'], $aParams['alert']) || !is_a($aParams['alert'], 'BxDolAlerts'))
+            return false;
+        
+        $oAlert = &$aParams['alert'];
+
+        $this->evalCode($aParams['automator'], ['alert' => $oAlert]);
+    }
+
+    protected function _callAutomatorScheduler($aParams = [])
+    {
+        if(!isset($aParams['automator']))
+            return false;
+        
+        $this->evalCode($aParams['automator']);
+    }
+
+    protected function _callAutomatorWebhook($aParams = [])
+    {
+        if(!isset($aParams['automator']))
+            return false;
+
+        $this->evalCode($aParams['automator']);
+    }
+
+    public function evalCode($aAutomator, $aParams = [])
+    {
+        try {
+            $this->_evalCode($aAutomator, $aParams);
+        }
+        catch (Exception $oException) {
+            $this->log($oException->getFile() . ':' . $oException->getLine() . ' ' . $oException->getMessage());
+        }
+        catch (Error $oError) {
+            $this->log($oError->getFile() . ':' . $oError->getLine() . ' ' . $oError->getMessage());
+        }
+    }
+
+    public function emulCode($aAutomator, $aParams = [])
+    {
+        ob_start();
+
+        try {
+            $this->_evalCode($aAutomator, $aParams);
+        }
+        catch (Exception $oException) {
+            return $oException->getMessage();
+        }
+        catch (Error $oError) {
+            return $oError->getMessage();
+        }
+        finally {
+            $sOutput = ob_get_clean();
+
+            if(!empty($sOutput))
+                return $sOutput;
+        }
+    }
+
+    public function log($mixedContents, $sSection = '')
+    {
+        if(!$this->_bWriteLog)
+            return;
+
+        if(is_array($mixedContents))
+            $mixedContents = var_export($mixedContents, true);	
+        else if(is_object($mixedContents))
+            $mixedContents = json_encode($mixedContents);
+
+        if(empty($sSection))
+            $sSection = "Core";
+
+        bx_log('sys_agents', ":\n[" . $sSection . "] " . $mixedContents, BX_LOG_ERR);
+    }
+
+    protected function _evalCode($aAutomator, $aParams = [])
+    {
+        $sCode = '';
+        switch($aAutomator['type']) {
+            case BX_DOL_AI_AUTOMATOR_EVENT:
+                $sCode = $aAutomator['code']. '; onAlert($aParams["alert"]->iObject , $aParams["alert"]->iSender , $aParams["alert"]->aExtras);';
+                break;
+
+            case BX_DOL_AI_AUTOMATOR_SCHEDULER:
+                $sCode = $aAutomator['code'] . '; onCron();';
+                break;
+
+            case BX_DOL_AI_AUTOMATOR_WEBHOOK:
+                $sCode = $aAutomator['code'] . '; onHook();';
+                break;
+        }
+
+        eval($sCode);
+    }
+}
+
+class BxDolAIMessage
+{
+    /**
+     * @var string - message Type with following values: hb, ai 
+     */
+    protected $_sType;
+    
+    /**
+     * @var mixed - an array of message parts (text, image_url) or a string.
+     */
+    protected $_mixedContent;
+    
+    /**
+     * @var array - an array of of files attached to the message.
+     */
+    protected $_aAttachments;
+
+    public function __construct($sType)
+    {
+        $this->_sType = $sType;
+    }
+
+    public function isAi()
+    {
+        return $this->_sType == 'ai';
+    }
+
+    public function getContent()
+    {
+        return $this->_mixedContent;
+    }
+
+    public function getAttachments()
+    {
+        return $this->_aAttachments;
+    }
+}
+
+class BxDolAIMessageString extends BxDolAIMessage
+{
+    public function __construct($sType, $sContent)
+    {
+        parent::__construct($sType);
+
+        $this->_mixedContent = is_string($sContent) ? $sContent : '';
+    }
+}
+
+class BxDolAIMessageArray extends BxDolAIMessage
+{
+    public function __construct($sType, $aContent = '')
+    {
+        parent::__construct($sType);
+
+        $this->_mixedContent = is_array($aContent) ? $aContent : [];
+    }
+
+    public function addText($sText)
+    {
+        $this->_mixedContent[] = [
+            'type' => 'text',
+            'text' => $sText
+        ];
+    }
+
+    public function addImageUrl($sUrl, $sDetail = 'high')
+    {
+        $this->_mixedContent[] = [
+            'type' => 'image_url',
+            'image_url' => [
+                'url' => $sUrl,
+                'detail' => $sDetail
+            ]
+        ];
+    }
+
+    public function addAttachments($mixedAttachments, $mixedTools = false)
+    {
+        if(!is_array($mixedAttachments))
+            $mixedAttachments = [$mixedAttachments];
+
+        if(!$mixedTools)
+            $mixedTools = [['type' => 'file_search']];
+
+        foreach($mixedAttachments as $sAttachment)
+            $this->_aAttachments[] = [
+                'file_id' => $sAttachment,
+                'tools' => $mixedTools
+            ];
+    }
+}
+
+class BxDolAIMessages
+{
+    /**
+     * @var array - an array of items (messages)
+     */
+    protected $_aItems;
+
+    public function __construct($aItems = [])
+    {
+        $this->_aItems = !empty($aItems) && is_array($aItems) ? $aItems : [];
+    }
+
+    public function add($sType, $mixedMessage)
+    {
+        $sClass = 'BxDolAIMessage' . (is_string($mixedMessage) ? 'String' : 'Array');
+        $this->_aItems[] = new $sClass($sType, $mixedMessage);
+    }
+
+    public function getAll()
+    {
+        return $this->_aItems;
+    }
+
+    public function getLast()
+    {
+        return end($this->_aItems);
+    }
+}

+ 1071 - 0
upgrade/files/15.0.0.B3-15.0.0.RC1/files/inc/classes/BxDolAIQuery.php

@@ -0,0 +1,1071 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    UnaCore UNA Core
+ * @{
+ */
+
+class BxDolAIQuery extends BxDolDb
+{
+    public function __construct()
+    {
+        parent::__construct();
+    }
+
+    static protected function _getObject(int $iId, string $sTable): array|bool
+    {
+        $oDb = BxDolDb::getInstance();
+
+        $a = $oDb->getRow("SELECT * FROM `$sTable` WHERE `id` = :id", ['id' => $iId]);
+        if(!$a || !is_array($a))
+            return false;
+
+        return $a;
+    }
+
+    static public function getModelObject(int $iId): array|bool
+    {
+        return self::_getObject($iId, 'sys_agents_models');
+    }
+
+    static public function getVectorStoreObject(int $iId): array|bool
+    {
+        return self::_getObject($iId, 'sys_agents_vector_store');
+    }
+
+    static public function getAgentObject(int $iId): array|bool
+    {
+        return self::_getObject($iId, 'sys_agents_agents');
+    }
+
+    static public function getToolObject(int $iId): array|bool
+    {
+        return self::_getObject($iId, 'sys_agents_tools');
+    }
+
+    static public function getProviderObject(int $iId)
+    {
+        $oDb = BxDolDb::getInstance();
+
+        $aProvider = $oDb->getRow("SELECT * FROM `sys_agents_providers` WHERE `id` = :id", ['id' => $iId]);
+        if(!$aProvider || !is_array($aProvider))
+            return false;
+
+        // get type
+        $aProviderType = $oDb->getRow("SELECT * FROM `sys_agents_provider_types` WHERE `id` = :id", ['id' => $aProvider['type_id']]);
+        if(!$aProviderType || !is_array($aProviderType))
+            return false;
+
+        $aProvider['type'] = $aProviderType;
+
+        // get options
+        $sQuery = "SELECT
+               `tpo`.`name` AS `name`,
+               `tpv`.`value` AS `value`
+            FROM `sys_agents_provider_options` AS `tpo`
+            LEFT JOIN `sys_agents_providers_values` AS `tpv` ON `tpo`.`id` = `tpv`.`option_id` AND `tpv`.`provider_id` = :provider_id
+            WHERE 1 ORDER BY `tpo`.`order`";
+
+        $aProvider['options'] = $oDb->getAllWithKey($sQuery, 'name', [
+            'provider_id' => $iId
+        ]);
+
+        return $aProvider;
+    }
+
+    static public function getProviderIdByName($sName)
+    {
+        return (int)BxDolDb::getInstance()->getOne("SELECT `id` FROM `sys_agents_providers` WHERE `name`=:name LIMIT 1", [
+            'name' => $sName
+        ]);
+    }
+    
+    static public function getAssistantObject($iId)
+    {
+        $oDb = BxDolDb::getInstance();
+
+        $aAssistant = $oDb->getRow("SELECT * FROM `sys_agents_assistants` WHERE `id` = :id", ['id' => $iId]);
+        if(!$aAssistant || !is_array($aAssistant))
+            return false;
+
+        return $aAssistant;
+    }
+
+    public function insertModel($aModel)
+    {
+        if(empty($aModel))
+            return false;
+
+        return (int)$this->query("INSERT INTO `sys_agents_models` SET " . $this->arrayToSQL($aModel));
+    }
+
+    public function getModelsBy($aParams = [])
+    {
+        $aMethod = ['name' => 'getAll', 'params' => [0 => 'query']];
+    	$sWhereClause = "";
+
+        switch($aParams['sample']) {
+            case 'id':
+            	$aMethod['name'] = 'getRow';
+            	$aMethod['params'][1] = [
+                    'id' => $aParams['id']
+                ];
+
+                $sWhereClause .= " AND `id`=:id";
+                break;
+
+            case 'all_pairs':
+                $aMethod['name'] = 'getPairs';
+                $aMethod['params'][1] = 'id';
+                $aMethod['params'][2] = 'title';
+                $aMethod['params'][3] = [];
+
+                if(isset($aParams['active'])) {
+                    $aMethod['params'][3]['active'] = $aParams['active'];
+
+                    $sWhereClause .= " AND `active`=:active";
+                }
+
+                if(isset($aParams['capabilities'])) {
+                    if (is_array($aParams['capabilities']))
+                    {                        
+                        $sWhereClause .= " AND `capabilities` IN (" . $this->implode_escape($aParams['capabilities']) . ")"; 
+                    }
+                    else {
+                        $aMethod['params'][3]['capabilities'] = $aParams['capabilities'];
+                        $sWhereClause .= " AND `capabilities` = :capabilities";
+                    }
+                }
+                break;
+        }
+
+        $aMethod['params'][0] = "SELECT * 
+            FROM `sys_agents_models`
+            WHERE 1" . $sWhereClause;
+
+        return call_user_func_array([$this, $aMethod['name']], $aMethod['params']);
+    }
+
+    public function getAutomatorsBy($aParams = [], $bFromCache = true)
+    {
+        $aMethod = ['name' => 'getAll', 'params' => [0 => 'query']];
+        $sSelectClause = "`taa`.*";
+    	$sPostfix = $sJoinClause = $sWhereClause = "";
+
+        switch($aParams['sample']) {
+            case 'id':
+            	$aMethod['name'] = 'getRow';
+            	$aMethod['params'][1] = [
+                    'id' => $aParams['id']
+                ];
+
+                $sWhereClause .= " AND `taa`.`id`=:id";
+                break;
+
+            case 'id_full':
+            	$aMethod['name'] = 'getRow';
+            	$aMethod['params'][1] = [
+                    'id' => $aParams['id']
+                ];
+
+                $sSelectClause .= ", `tam`.`name` AS `model_name`, `tam`.`title` AS `model_title`, `tam`.`key` AS `model_key`, `tam`.`params` AS `model_params`";
+                $sJoinClause .= " LEFT JOIN `sys_agents_models` AS `tam` ON `taa`.`model_id`=`tam`.`id`";
+                $sWhereClause .= " AND `taa`.`id`=:id";
+                break;
+
+            case 'type':
+                $sPostfix .= '_' . $aParams['type'];
+
+                $aMethod['params'][1] = [
+                    'type' => $aParams['type']
+                ];
+
+                $sWhereClause .= " AND `taa`.`type`=:type";
+
+                if(isset($aParams['active'])) {
+                    $iActive = (int)$aParams['active'];
+                    $sPostfix .= '_' . (!$iActive ? 'in' : '') . 'active';
+
+                    $aMethod['params'][1]['active'] = $iActive;
+                    $sWhereClause .= " AND `taa`.`active`=:active";
+                }
+                break;
+
+            case 'events':
+                $aBindings = [
+                    'type' => BX_DOL_AI_AUTOMATOR_EVENT,
+                    'alert_unit' => $aParams['alert_unit'],
+                    'alert_action' => $aParams['alert_action']
+                ];
+                $sPostfix .= '_' . implode('_', $aBindings);
+
+                $aMethod['params'][1] = $aBindings;
+                $sWhereClause .= " AND `taa`.`type`=:type AND `taa`.`alert_unit`=:alert_unit AND `taa`.`alert_action`=:alert_action";
+
+                if(isset($aParams['active'])) {
+                    $iActive = (int)$aParams['active'];
+                    $sPostfix .= '_' . (!$iActive ? 'in' : '') . 'active';
+
+                    $aMethod['params'][1]['active'] = $iActive;
+                    $sWhereClause .= " AND `taa`.`active`=:active";
+                }
+                break;
+
+            case 'schedulers':
+                $aMethod['params'][1] = [
+                    'type' => BX_DOL_AI_AUTOMATOR_SCHEDULER,
+                ];
+
+                $sWhereClause .= " AND `taa`.`type`=:type";
+
+                if(isset($aParams['active'])) {
+                    $aMethod['params'][1]['active'] = (int)$aParams['active'];
+
+                    $sWhereClause .= " AND `taa`.`active`=:active";
+                }
+                break;
+
+            case 'webhooks':
+                $aMethod['params'][1] = [
+                    'type' => BX_DOL_AI_AUTOMATOR_WEBHOOK,
+                ];
+
+                $sWhereClause .= " AND `taa`.`type`=:type";
+
+                if(isset($aParams['provider_id'])) {
+                    $aMethod['params'][1]['provider_id'] = (int)$aParams['provider_id'];
+
+                    $sJoinClause = "INNER JOIN `sys_agents_automators_providers` AS `tap` ON `taa`.`id`=`tap`.`automator_id`";
+                    $sWhereClause .= " AND `tap`.`provider_id`=:provider_id";
+                }
+
+                if(isset($aParams['active'])) {
+                    $aMethod['params'][1]['active'] = (int)$aParams['active'];
+
+                    $sWhereClause .= " AND `taa`.`active`=:active";
+                }
+                break;
+
+            case 'providers_by_id_pairs':
+                $aMethod['name'] = 'getPairs';
+                $aMethod['params'][1] = 'id';
+                $aMethod['params'][2] = 'provider_id';
+                $aMethod['params'][3] = [
+                    'id' => $aParams['id']
+                ];
+
+                $sSelectClause = "`taap`.`id`, `taap`.`provider_id`";
+                $sJoinClause = "INNER JOIN `sys_agents_automators_providers` AS `taap` ON `taa`.`id`=`taap`.`automator_id`";
+                $sWhereClause = " AND `taa`.`id`=:id";
+                break;
+            
+            case 'helpers_by_id_pairs':
+                $aMethod['name'] = 'getPairs';
+                $aMethod['params'][1] = 'id';
+                $aMethod['params'][2] = 'helper_id';
+                $aMethod['params'][3] = [
+                    'id' => $aParams['id']
+                ];
+
+                $sSelectClause = "`taah`.`id`, `taah`.`helper_id`";
+                $sJoinClause = "INNER JOIN `sys_agents_automators_helpers` AS `taah` ON `taa`.`id`=`taah`.`automator_id`";
+                $sWhereClause = " AND `taa`.`id`=:id";
+                break;
+            
+            case 'assistants_by_id_pairs':
+                $aMethod['name'] = 'getPairs';
+                $aMethod['params'][1] = 'id';
+                $aMethod['params'][2] = 'assistant_id';
+                $aMethod['params'][3] = [
+                    'id' => $aParams['id']
+                ];
+
+                $sSelectClause = "`taaa`.`id`, `taaa`.`assistant_id`";
+                $sJoinClause = "INNER JOIN `sys_agents_automators_assistants` AS `taaa` ON `taa`.`id`=`taaa`.`automator_id`";
+                $sWhereClause = " AND `taa`.`id`=:id";
+                break;
+        }
+
+        $aMethod['params'][0] = "SELECT " . $sSelectClause . "
+            FROM `sys_agents_automators` AS `taa` " . $sJoinClause . "
+            WHERE 1" . $sWhereClause;
+
+        if(!$bFromCache || empty($sPostfix))
+            return call_user_func_array([$this, $aMethod['name']], $aMethod['params']);
+
+        return call_user_func_array([$this, 'fromMemory'], array_merge(['sys_automators' . $sPostfix, $aMethod['name']], $aMethod['params']));
+    }
+
+    public function updateAutomators($aSetClause, $aWhereClause)
+    {
+        if(empty($aSetClause) || empty($aWhereClause))
+            return false;
+
+        return (int)$this->query("UPDATE `sys_agents_automators` SET " . $this->arrayToSQL($aSetClause) . " WHERE " . $this->arrayToSQL($aWhereClause)) > 0;
+    }
+
+    public function insertAutomatorProvider($aParamsSet)
+    {
+        if(empty($aParamsSet))
+            return false;
+
+        return (int)$this->query("INSERT INTO `sys_agents_automators_providers` SET " . $this->arrayToSQL($aParamsSet)) > 0 ? (int)$this->lastId() : false;
+    }
+
+    public function updateAutomatorProvider($aParamsSet, $aParamsWhere)
+    {
+        if(empty($aParamsSet) || empty($aParamsWhere))
+            return false;
+
+        return $this->query("UPDATE `sys_agents_automators_providers` SET " . $this->arrayToSQL($aParamsSet) . " WHERE " . $this->arrayToSQL($aParamsWhere, " AND "));
+    }
+
+    public function deleteAutomatorProviders($aParamsWhere)
+    {
+        if(empty($aParamsWhere))
+            return false;
+
+        return (int)$this->query("DELETE FROM `sys_agents_automators_providers` WHERE " . $this->arrayToSQL($aParamsWhere)) > 0;
+    }
+    
+    public function deleteAutomatorProvidersById($mixedId)
+    {
+        if(!is_array($mixedId))
+            $mixedId = [$mixedId];
+
+        return (int)$this->query("DELETE FROM `sys_agents_automators_providers` WHERE `id` IN (" . $this->implode_escape($mixedId) . ")") > 0;
+    }
+
+    public function insertAutomatorHelper($aParamsSet)
+    {
+        if(empty($aParamsSet))
+            return false;
+
+        return (int)$this->query("INSERT INTO `sys_agents_automators_helpers` SET " . $this->arrayToSQL($aParamsSet)) > 0 ? (int)$this->lastId() : false;
+    }
+
+    public function updateAutomatorHelper($aParamsSet, $aParamsWhere)
+    {
+        if(empty($aParamsSet) || empty($aParamsWhere))
+            return false;
+
+        return $this->query("UPDATE `sys_agents_automators_helpers` SET " . $this->arrayToSQL($aParamsSet) . " WHERE " . $this->arrayToSQL($aParamsWhere, " AND "));
+    }
+
+    public function deleteAutomatorHelpers($aParamsWhere)
+    {
+        if(empty($aParamsWhere))
+            return false;
+
+        return (int)$this->query("DELETE FROM `sys_agents_automators_helpers` WHERE " . $this->arrayToSQL($aParamsWhere)) > 0;
+    }
+
+    public function deleteAutomatorHelpersById($mixedId)
+    {
+        if(!is_array($mixedId))
+            $mixedId = [$mixedId];
+
+        return (int)$this->query("DELETE FROM `sys_agents_automators_helpers` WHERE `id` IN (" . $this->implode_escape($mixedId) . ")") > 0;
+    }
+
+    public function insertAutomatorAssistant($aParamsSet)
+    {
+        if(empty($aParamsSet))
+            return false;
+
+        return (int)$this->query("INSERT INTO `sys_agents_automators_assistants` SET " . $this->arrayToSQL($aParamsSet)) > 0 ? (int)$this->lastId() : false;
+    }
+
+    public function updateAutomatorAssistant($aParamsSet, $aParamsWhere)
+    {
+        if(empty($aParamsSet) || empty($aParamsWhere))
+            return false;
+
+        return $this->query("UPDATE `sys_agents_automators_assistants` SET " . $this->arrayToSQL($aParamsSet) . " WHERE " . $this->arrayToSQL($aParamsWhere, " AND "));
+    }
+
+    public function deleteAutomatorAssistants($aParamsWhere)
+    {
+        if(empty($aParamsWhere))
+            return false;
+
+        return (int)$this->query("DELETE FROM `sys_agents_automators_assistants` WHERE " . $this->arrayToSQL($aParamsWhere)) > 0;
+    }
+    
+    public function deleteAutomatorAssistantsById($mixedId)
+    {
+        if(!is_array($mixedId))
+            $mixedId = [$mixedId];
+
+        return (int)$this->query("DELETE FROM `sys_agents_automators_assistants` WHERE `id` IN (" . $this->implode_escape($mixedId) . ")") > 0;
+    }
+
+    public function getProviderTypesBy($aParams = [])
+    {
+        $aMethod = ['name' => 'getAll', 'params' => [0 => 'query']];
+    	$sWhereClause = "";
+
+        switch($aParams['sample']) {
+            case 'id':
+            	$aMethod['name'] = 'getRow';
+            	$aMethod['params'][1] = [
+                    'id' => $aParams['id']
+                ];
+
+                $sWhereClause .= " AND `id`=:id";
+                break;
+
+            case 'name':
+            	$aMethod['name'] = 'getRow';
+            	$aMethod['params'][1] = [
+                    'name' => $aParams['name']
+                ];
+
+                $sWhereClause .= " AND `name`=:name";
+                break;
+
+            case 'all_pairs':
+                $aMethod['name'] = 'getPairs';
+                $aMethod['params'][1] = 'id';
+                $aMethod['params'][2] = 'title';
+
+                if(isset($aParams['active'])) {
+                    $aMethod['params'][3] = [
+                        'active' => $aParams['active']
+                    ];
+
+                    $sWhereClause = " AND `active`=:active";
+                }
+                break;
+        }
+
+        $aMethod['params'][0] = "SELECT * 
+            FROM `sys_agents_provider_types`
+            WHERE 1" . $sWhereClause;
+
+        return call_user_func_array([$this, $aMethod['name']], $aMethod['params']);
+    }
+
+    public function getProviderOptionsBy($aParams = [])
+    {
+        $aMethod = ['name' => 'getAll', 'params' => [0 => 'query']];
+    	$sWhereClause = "";
+
+        switch($aParams['sample']) {
+            case 'id':
+            	$aMethod['name'] = 'getRow';
+            	$aMethod['params'][1] = [
+                    'id' => $aParams['id']
+                ];
+
+                $sWhereClause .= " AND `id`=:id";
+                break;
+
+            case 'provider_type_id':
+            	$aMethod['params'][1] = [
+                    'provider_type_id' => $aParams['provider_type_id']
+                ];
+
+                $sWhereClause .= " AND `provider_type_id`=:provider_type_id";
+                break;
+        }
+
+        $aMethod['params'][0] = "SELECT * 
+            FROM `sys_agents_provider_options`
+            WHERE 1" . $sWhereClause;
+
+        return call_user_func_array([$this, $aMethod['name']], $aMethod['params']);
+    }
+
+    public function getProvidersBy($aParams = [])
+    {
+    	$aMethod = ['name' => 'getAll', 'params' => [0 => 'query']];
+
+    	$sSelectClause = "`tp`.*";
+    	$sJoinClause = $sWhereClause = $sGroupClause = $sOrderClause = $sLimitClause = "";
+        switch($aParams['sample']) {
+            case 'id':
+            	$aMethod['name'] = 'getRow';
+            	$aMethod['params'][1] = [
+                    'id' => $aParams['id']
+                ];
+
+                $sWhereClause = " AND `tp`.`id`=:id";
+                break;
+
+            case 'ids':
+                $sSelectClause .= ", `tpt`.`name` AS `type_name`";
+                $sJoinClause = "INNER JOIN `sys_agents_provider_types` AS `tpt` ON `tp`.`type_id`=`tpt`.`id`";
+                $sWhereClause = " AND `tp`.`id` IN (" . $this->implode_escape($aParams['ids']) . ")";
+                break;
+                 
+            case 'options_by_id':
+                $aMethod['params'][1] = [
+                    'id' => $aParams['id']
+                ];
+
+                $sSelectClause = "`tpo`.`id`, `tpo`.`name`, `tpo`.`type`, `tpo`.`title`, `tpo`.`description`, `tpv`.`value`";
+                $sJoinClause = "LEFT JOIN `sys_agents_provider_options` AS `tpo` ON `tp`.`type_id`=`tpo`.`provider_type_id` LEFT JOIN `sys_agents_providers_values` AS `tpv` ON `tp`.`id`=`tpv`.`provider_id` AND `tpo`.`id`=`tpv`.`option_id`";
+                $sWhereClause = " AND `tp`.`id`=:id";
+                break;
+            
+            case 'all_pairs':
+                $aMethod['name'] = 'getPairs';
+                $aMethod['params'][1] = 'id';
+                $aMethod['params'][2] = 'name';
+
+                if(isset($aParams['active'])) {
+                    $aMethod['params'][3] = [
+                        'active' => $aParams['active']
+                    ];
+
+                    $sWhereClause = " AND `tp`.`active`=:active";
+                }
+                break;
+        }
+
+        $sOrderClause = !empty($sOrderClause) ? "ORDER BY " . $sOrderClause : $sOrderClause;
+        $sLimitClause = !empty($sLimitClause) ? "LIMIT " . $sLimitClause : $sLimitClause;
+
+        $aMethod['params'][0] = "SELECT
+                " . $sSelectClause . "
+            FROM `sys_agents_providers` AS `tp` " . $sJoinClause . "
+            WHERE 1" . $sWhereClause . " " . $sGroupClause . " " . $sOrderClause . " " . $sLimitClause;
+
+        return call_user_func_array(array($this, $aMethod['name']), $aMethod['params']);
+    }
+
+    public function insertProviderValue($aParamsSet)
+    {
+        if(empty($aParamsSet) || !is_array($aParamsSet) || !isset($aParamsSet['value']))
+            return false;
+
+        return (int)$this->query("INSERT INTO `sys_agents_providers_values` SET " . $this->arrayToSQL($aParamsSet) . " ON DUPLICATE KEY UPDATE `value`=:value", [
+            'value' => $aParamsSet['value']
+        ]) > 0 ? (int)$this->lastId() : false;
+    }
+
+    public function updateProviderValue($aParamsSet, $aParamsWhere)
+    {
+        if(empty($aParamsSet))
+            return false;
+
+        $sWhereClause = "1";
+        if(!empty($aParamsWhere) && is_array($aParamsWhere))
+            $sWhereClause = $this->arrayToSQL($aParamsWhere, ' AND ');
+
+        return $this->query("UPDATE `sys_agents_providers_values` SET " . $this->arrayToSQL($aParamsSet) . " WHERE " . $sWhereClause) !== false;
+    }
+
+    public function deleteProviderValues($aParamsWhere)
+    {
+        if(empty($aParamsWhere))
+            return false;
+
+        return (int)$this->query("DELETE FROM `sys_agents_providers_values` WHERE " . $this->arrayToSQL($aParamsWhere, ' AND ')) > 0;
+    }
+    
+    public function getHelpersBy($aParams = [])
+    {
+        $aMethod = ['name' => 'getAll', 'params' => [0 => 'query']];
+        $sSelectClause = "`th`.*";
+    	$sJoinClause = $sWhereClause = "";
+
+        switch($aParams['sample']) {
+            case 'id':
+            	$aMethod['name'] = 'getRow';
+            	$aMethod['params'][1] = [
+                    'id' => $aParams['id']
+                ];
+
+                $sWhereClause .= " AND `th`.`id`=:id";
+                break;
+            case 'name':
+            	$aMethod['name'] = 'getRow';
+            	$aMethod['params'][1] = [
+                    'name' => $aParams['name']
+                ];
+
+                $sWhereClause .= " AND `th`.`name`=:name";
+                break;
+            case 'ids':
+                $sWhereClause = " AND `th`.`id` IN (" . $this->implode_escape($aParams['ids']) . ")";
+                break;
+
+            case 'all_pairs':
+                $aMethod['name'] = 'getPairs';
+                $aMethod['params'][1] = 'id';
+                $aMethod['params'][2] = 'name';
+
+                if(isset($aParams['active'])) {
+                    $aMethod['params'][3] = [
+                        'active' => $aParams['active']
+                    ];
+
+                    $sWhereClause = " AND `th`.`active`=:active";
+                }
+                break;
+        }
+
+        $aMethod['params'][0] = "SELECT " . $sSelectClause . "
+            FROM `sys_agents_helpers` AS `th` " . $sJoinClause . "
+            WHERE 1" . $sWhereClause;
+
+        return call_user_func_array([$this, $aMethod['name']], $aMethod['params']);
+    }
+
+    public function getAssistantsBy($aParams = [])
+    {
+        $aMethod = ['name' => 'getAll', 'params' => [0 => 'query']];
+        $sSelectClause = "`ta`.*";
+    	$sJoinClause = $sWhereClause = "";
+
+        switch($aParams['sample']) {
+            case 'id':
+            	$aMethod['name'] = 'getRow';
+            	$aMethod['params'][1] = [
+                    'id' => $aParams['id']
+                ];
+
+                $sWhereClause .= " AND `ta`.`id`=:id";
+                break;
+
+            case 'name':
+            	$aMethod['name'] = 'getRow';
+            	$aMethod['params'][1] = [
+                    'name' => $aParams['name']
+                ];
+
+                $sWhereClause .= " AND `ta`.`name`=:name";
+                break;
+
+            case 'ids':
+                $sWhereClause = " AND `ta`.`id` IN (" . $this->implode_escape($aParams['ids']) . ")";
+                break;
+
+            case 'all_pairs':
+                $aMethod['name'] = 'getPairs';
+                $aMethod['params'][1] = 'id';
+                $aMethod['params'][2] = 'name';
+                $aMethod['params'][3] = [];
+
+                if(isset($aParams['active'])) {
+                    $aMethod['params'][3]['active'] = $aParams['active'];
+
+                    $sWhereClause .= " AND `ta`.`active`=:active";
+                }
+
+                if(isset($aParams['hidden'])) {
+                    $aMethod['params'][3]['hidden'] = $aParams['hidden'];
+
+                    $sWhereClause .= " AND `ta`.`hidden`=:hidden";
+                }
+                break;
+        }
+
+        $aMethod['params'][0] = "SELECT " . $sSelectClause . "
+            FROM `sys_agents_assistants` AS `ta` " . $sJoinClause . "
+            WHERE 1" . $sWhereClause;
+
+        return call_user_func_array([$this, $aMethod['name']], $aMethod['params']);
+    }
+    
+    public function updateAssistants($aSetClause, $aWhereClause)
+    {
+        if(empty($aSetClause) || empty($aWhereClause))
+            return false;
+
+        return (int)$this->query("UPDATE `sys_agents_assistants` SET " . $this->arrayToSQL($aSetClause) . " WHERE " . $this->arrayToSQL($aWhereClause)) > 0;
+    }
+
+    public function getChatsBy($aParams = [])
+    {
+        $aMethod = ['name' => 'getAll', 'params' => [0 => 'query']];
+        $sSelectClause = "`tac`.*";
+    	$sJoinClause = $sWhereClause = "";
+
+        switch($aParams['sample']) {
+            case 'id':
+            	$aMethod['name'] = 'getRow';
+            	$aMethod['params'][1] = [
+                    'id' => $aParams['id']
+                ];
+
+                $sWhereClause .= " AND `tac`.`id`=:id";
+                break;
+
+            case 'name':
+            	$aMethod['name'] = 'getRow';
+            	$aMethod['params'][1] = [
+                    'name' => $aParams['name']
+                ];
+
+                $sWhereClause .= " AND `tac`.`name`=:name";
+                break;
+
+            case 'assistant_id':
+                $aMethod['params'][1] = [
+                    'assistant_id' => $aParams['assistant_id']
+                ];
+
+                $sWhereClause .= " AND `tac`.`assistant_id`=:assistant_id";
+                break;
+
+            case 'type':
+                $aMethod['params'][1] = [
+                    'type' => $aParams['type']
+                ];
+
+                $sWhereClause .= " AND `tac`.`type`=:type";
+                
+                if(isset($aParams['lifetime']) && (int)$aParams['lifetime'] > 0) {
+                    $aMethod['params'][1]['lifetime'] = (int)$aParams['lifetime'];
+
+                    $sWhereClause .= " AND (UNIX_TIMESTAMP() - `tac`.`added`) >= :lifetime";
+                }
+                break;
+        }
+
+        $aMethod['params'][0] = "SELECT " . $sSelectClause . "
+            FROM `sys_agents_assistants_chats` AS `tac` " . $sJoinClause . "
+            WHERE 1" . $sWhereClause;
+
+        return call_user_func_array([$this, $aMethod['name']], $aMethod['params']);
+    }
+    
+    public function insertChat($aParamsSet)
+    {
+        if(empty($aParamsSet) || !is_array($aParamsSet))
+            return false;
+
+        return (int)$this->query("INSERT INTO `sys_agents_assistants_chats` SET " . $this->arrayToSQL($aParamsSet)) > 0 ? (int)$this->lastId() : false;
+    }
+
+    public function updateChats($aSetClause, $aWhereClause)
+    {
+        if(empty($aSetClause) || empty($aWhereClause))
+            return false;
+
+        return (int)$this->query("UPDATE `sys_agents_assistants_chats` SET " . $this->arrayToSQL($aSetClause) . " WHERE " . $this->arrayToSQL($aWhereClause)) > 0;
+    }
+    
+    public function deleteChats($aParamsWhere)
+    {
+        if(empty($aParamsWhere))
+            return false;
+
+        return (int)$this->query("DELETE FROM `sys_agents_assistants_chats` WHERE " . $this->arrayToSQL($aParamsWhere, ' AND ')) > 0;
+    }
+    
+    public function getFilesBy($aParams = [])
+    {
+        $aMethod = ['name' => 'getAll', 'params' => [0 => 'query']];
+        $sSelectClause = "`taf`.*";
+    	$sJoinClause = $sWhereClause = "";
+
+        switch($aParams['sample']) {
+            case 'id':
+            	$aMethod['name'] = 'getRow';
+            	$aMethod['params'][1] = [
+                    'id' => $aParams['id']
+                ];
+
+                $sWhereClause .= " AND `taf`.`id`=:id";
+                break;
+
+            case 'assistant_id':
+                $aMethod['params'][1] = [
+                    'assistant_id' => $aParams['assistant_id']
+                ];
+
+                $sWhereClause .= " AND `taf`.`assistant_id`=:assistant_id";
+
+                if(!empty($aParams['name'])) {
+                    $aMethod['name'] = 'getRow';
+                    $aMethod['params'][1]['name'] = $aParams['name'];
+
+                    $sWhereClause .= " AND `taf`.`name`=:name";
+                }
+                break;                
+        }
+
+        $aMethod['params'][0] = "SELECT " . $sSelectClause . "
+            FROM `sys_agents_assistants_files` AS `taf` " . $sJoinClause . "
+            WHERE 1" . $sWhereClause;
+
+        return call_user_func_array([$this, $aMethod['name']], $aMethod['params']);
+    }
+
+    public function insertFile($aParamsSet)
+    {
+        if(empty($aParamsSet) || !is_array($aParamsSet))
+            return false;
+
+        return (int)$this->query("INSERT INTO `sys_agents_assistants_files` SET " . $this->arrayToSQL($aParamsSet)) > 0 ? (int)$this->lastId() : false;
+    }
+
+    public function updateFiles($aSetClause, $aWhereClause)
+    {
+        if(empty($aSetClause) || empty($aWhereClause))
+            return false;
+
+        return (int)$this->query("UPDATE `sys_agents_assistants_files` SET " . $this->arrayToSQL($aSetClause) . " WHERE " . $this->arrayToSQL($aWhereClause)) > 0;
+    }
+
+    public function deleteFiles($aParamsWhere)
+    {
+        if(empty($aParamsWhere))
+            return false;
+
+        return (int)$this->query("DELETE FROM `sys_agents_assistants_files` WHERE " . $this->arrayToSQL($aParamsWhere, ' AND ')) > 0;
+    }
+
+    public function getVectorStores (): mixed
+    {
+        $sQuery = "SELECT `id`, `title` FROM `sys_agents_vector_store` WHERE `active` = 1 ORDER BY `title` ASC";
+        return $this->getPairs($sQuery, 'id', 'title'); 
+    }
+
+    public function getVectorStoreById (int $iId): mixed
+    {
+        $sQuery = "SELECT * FROM `sys_agents_vector_store` WHERE `id` = :id";
+        return $this->getRow($sQuery, ['id' => $iId]); 
+    }
+
+    public function insertVectorStore($aVectorStore)
+    {
+        if(empty($aVectorStore) || !is_array($aVectorStore))
+            return false;
+
+        return (int)$this->query("INSERT INTO `sys_agents_vector_store` SET " . $this->arrayToSQL($aVectorStore));
+    }
+
+    public function getVectorStoreDataNum (int $iVectorStoreId): int
+    {
+        $sQuery = "SELECT COUNT(*) FROM `sys_agents_vector_store_data` WHERE `vector_store_id` = :vector_store_id";
+        return (int)$this->getOne($sQuery, ['vector_store_id' => $iVectorStoreId]);
+    }
+
+    public function addVectorStoreData (int $iVectorStoreId, string $sType, string $sName, int $iFileSize, string $sMetadata, string $sSettings, string $sContent): bool
+    {
+        $sQuery = "INSERT INTO `sys_agents_vector_store_data` SET  
+            `vector_store_id` = :vector_store_id,
+            `type` = :type, 
+            `name` = :name, 
+            `size` = :size,
+            `metadata` = :metadata, 
+            `settings` = :settings, 
+            `content` = :content,
+            `added` = :ts
+        ";
+        return $this->query($sQuery, [
+            'vector_store_id' => $iVectorStoreId,
+            'type' => $sType, 
+            'name' => $sName, 
+            'size' => $iFileSize,
+            'metadata' => $sMetadata, 
+            'settings' => $sSettings, 
+            'content' => $sContent,
+            'ts' => time()]) > 0;
+    }
+
+    public function getVectorStoreDataById (int $iId): mixed
+    {
+        $sQuery = "SELECT * FROM `sys_agents_vector_store_data` WHERE `id` = :id";
+        return $this->getRow($sQuery, ['id' => $iId]);
+    }
+
+    static public function getVectorStorePendingData (int $iLimit = 1): mixed
+    {
+        $oDb = BxDolDb::getInstance();
+        $sQuery = "SELECT * FROM `sys_agents_vector_store_data` WHERE `status` = 'pending' ORDER BY `added` ASC LIMIT :limit";
+        return $oDb->getAll($sQuery, ['limit' => $iLimit]);
+    }
+
+    static public function updateVectorStoreDataStatus (int $iId, string $sStatus): mixed
+    {
+        $oDb = BxDolDb::getInstance();
+        $sQuery = "UPDATE `sys_agents_vector_store_data` SET `status` = :status WHERE `id` = :id";
+        return $oDb->query($sQuery, ['status' => $sStatus, 'id' => $iId]);
+    }
+
+    public function getAgentsWithAlert($bActiveOnly = true)
+    {
+        return $this->fromCache('sys_agents_with_alert', 'getAll', "SELECT * FROM `sys_agents_agents` WHERE `trigger` = 'alert' AND `active` = :active", ['active' => $bActiveOnly ? 1 : 0]);
+    }
+
+    public function getAgentsByProfileId($iProfileId, $bActiveOnly = true)
+    {
+        return $this->getAll("SELECT * FROM `sys_agents_agents` WHERE `trigger` = 'message' AND `profile_id` = :profile AND `active` = :active", ['profile' => $iProfileId, 'active' => $bActiveOnly ? 1 : 0]);
+    }
+
+    public function getAgentsByFormObject($sFormObject, $bActiveOnly = true)
+    {
+        return $this->fromMemory('sys_agents_with_form_' . $sFormObject, 'getAll', "SELECT * FROM `sys_agents_agents` WHERE `trigger` = 'form-input' AND `form_object` = :form_object AND `active` = :active", ['form_object' => $sFormObject, 'active' => $bActiveOnly ? 1 : 0]);
+    }
+
+    public function getAgentsBy($aParams = [])
+    {
+        $aMethod = ['name' => 'getAll', 'params' => [0 => 'query']];
+    	$sWhereClause = "";
+
+        switch($aParams['sample']) {
+            case 'id':
+            	$aMethod['name'] = 'getRow';
+            	$aMethod['params'][1] = [
+                    'id' => $aParams['id']
+                ];
+
+                $sWhereClause .= " AND `id`=:id";
+                break;
+
+            case 'all':
+                if(isset($aParams['active'])) {
+                    $aMethod['params'][3]['active'] = $aParams['active'];
+
+                    $sWhereClause .= " AND `active`=:active";
+                }
+                break;
+        }
+
+        $aMethod['params'][0] = "SELECT * 
+            FROM `sys_agents_agents`
+            WHERE 1" . $sWhereClause;
+
+        return call_user_func_array([$this, $aMethod['name']], $aMethod['params']);
+    }
+
+    public function getAgentById(int $iId): mixed
+    {
+        return $this->getAgentsBy(['sample' => 'id', 'id' => $iId]);
+    }
+
+    public function getAgentByTriggerWebhookKey($sKey, $bActiveOnly = true)
+    {
+        return $this->getRow("SELECT * FROM `sys_agents_agents` WHERE `trigger` = 'scheduler' AND `webhook_key` = :key AND `active` = :active", ['key' => $sKey, 'active' => $bActiveOnly ? 1 : 0]);
+    }
+    
+    public function getAgentsByTriggerType($sTrigger, $bActiveOnly = true)
+    {
+        return $this->getAll("SELECT * FROM `sys_agents_agents` WHERE `trigger` = :trigger AND `active` = :active", ['trigger' => $sTrigger, 'active' => $bActiveOnly ? 1 : 0]);
+    }
+
+    public function updateAgentField($iId, $sField, $sValue)
+    {
+        return $this->query("UPDATE `sys_agents_agents` SET `$sField` = :value WHERE `id` = :id", ['value' => $sValue, 'id' => $iId]);
+    }
+
+    public function getToolById (int $iId): mixed
+    {
+        $sQuery = "SELECT * FROM `sys_agents_tools` WHERE `id` = :id";
+        return $this->getRow($sQuery, ['id' => $iId]); 
+    }
+
+    public function insertTool(array $aFields): int
+    {
+        if(empty($aFields) || !is_array($aFields))
+            return false;
+
+        return (int)$this->query("INSERT INTO `sys_agents_tools` SET " . $this->arrayToSQL($aFields));
+    }
+
+    public function getTools()
+    {
+        $sQuery = "SELECT `id`, `title` FROM `sys_agents_tools` WHERE `active` = 1 ORDER BY `title` ASC";
+        return $this->getPairs($sQuery, 'id', 'title'); 
+    }
+
+    public function wipeAgentChatHistory($aAgent) 
+    {
+        $sQuery = "DELETE FROM `sys_agents_chat_history` WHERE `thread_id` LIKE :val";
+        $iAffected = 0;
+        $iAffected += $this->query($sQuery, ['val' => $aAgent['trigger'] . ':' . $aAgent['id'] . ':%']);
+        $iAffected += $this->query($sQuery, ['val' => $aAgent['trigger'] . ':' . $aAgent['id']]);
+        return $iAffected;
+    }
+
+    static public function getAlert($s) {
+        if (!$s)
+            return false;        
+        $a = explode(':', $s);
+        $oDb = BxDolDb::getInstance();
+        return $oDb->getRow("SELECT * FROM `sys_alerts_log` WHERE `unit` = :unit AND `action` = :action", [
+            'unit' => $a[0] ?? '',
+            'action' => $a[1] ?? '',
+        ]);
+    }
+
+    public function getAlerts()
+    {
+        $aValues = [];
+        $aAlerts = $this->getAll("SELECT `unit`, `action`, `counter_24h`, `counter_per_request` FROM `sys_alerts_log` ORDER BY `unit`, `action`");
+        foreach ($aAlerts as $a) {
+            $sKey = $a['unit'] . ':' . $a['action'];
+            $aValues[$sKey] = [
+                'key' => $sKey,
+                'unit' => $a['unit'],
+                'action' => $a['action'],
+                'name' => $a['unit'] . ' - ' . $a['action'],
+                'desc' => $this->getAlertDesc($a['unit'] . ':' . $a['action']),
+                'counter_24h' => $a['counter_24h'],
+                'counter_per_request' => $a['counter_per_request'],
+            ];
+        }
+        return $aValues;
+    }
+
+    public function getFormDisplay($sObject)
+    {
+        $aDisplays = $this->getColumn("SELECT `display_name` FROM `sys_form_displays` WHERE `object` = :object", ['object' => $sObject]);
+        return $aDisplays ? current($aDisplays) : null;
+    }
+
+    public function getFormObjects()
+    {
+        $aValues = [];
+        $aForms = $this->getAll("SELECT `f`.`object`, `f`.`title`, `f`.`module`, `m`.`title` AS `module_title` FROM `sys_objects_form` AS f INNER JOIN `sys_modules` as `m` ON `m`.`name` = `f`.`module` ORDER BY `f`.`module`, `f`.`object` ASC");
+        foreach ($aForms as $r) {
+            if ('system' != $r['module']) {
+                $oModule = BxDolModule::getInstance($r['module']);
+                if (!$oModule || !$oModule->isEnabled())
+                    continue;
+            }
+            
+            $sDisplay = $this->getFormDisplay($r['object']);
+            if (!$sDisplay) 
+                continue;
+            $oForm = BxDolForm::getObjectInstance($r['object'], $sDisplay);
+            $sFormId = $oForm->getId();
+            $aValues[$r['object']] = [
+                'form_id' => $sFormId,
+                'form_object' => $r['object'],
+                'module' => $r['module'],
+                'module_title' => $r['module_title'],
+                'form_title' => _t($r['title']),
+            ];
+        }
+        return $aValues;
+    }
+
+    static public function getAlertDesc($sAlert) 
+    {
+        if (!$sAlert)
+            return '';
+        $oDb = BxDolDb::getInstance();
+        [$sUnit, $sAction] = explode(':', $sAlert);
+        $sDesc = $oDb->getOne("SELECT `description` FROM `sys_alerts_desc` WHERE `unit` = :unit AND `action` = :action LIMIT 1", [
+            'unit' => $sUnit,
+            'action' => $sAction,
+        ]);
+        if (!$sDesc) {
+            $oDb->getOne("SELECT `description` FROM `sys_alerts_desc` WHERE `unit` LIKE '{%}' AND `action` = :action LIMIT 1", [
+                'action' => $sAction,
+            ]);
+        }
+        return $sDesc;
+    }
+}
+
+/** @} */

+ 46 - 0
upgrade/files/15.0.0.B3-15.0.0.RC1/files/inc/classes/BxDolAIToolCmtsGetSingle.php

@@ -0,0 +1,46 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    UnaCore UNA Core
+ * @{
+ */
+
+use NeuronAI\Tools\PropertyType;
+use NeuronAI\Tools\ToolProperty;
+
+class BxDolAIToolCmtsGetSingle extends BxDolAITool
+{
+    public function __construct()
+    {
+        parent::__construct(
+            'comment_get',
+            'Get single comment info. Prepend base URL to links in comment info: ' . BX_DOL_URL_ROOT,
+        );
+    }
+    
+    protected function properties(): array
+    {
+        return [
+            new ToolProperty(
+                name: 'comment_id',
+                type: PropertyType::INTEGER,
+                description: 'ID of comment to get.',
+                required: true
+            ),
+        ];
+    }
+
+    public function __invoke(int $comment_id): array
+    {
+        $aCmt = BxDolCmtsQuery::getCommentExtendedByUniqId($comment_id);        
+        $oCmtsObject = $aCmt ? BxDolCmts::getObjectInstance($aCmt['system_name'], $aCmt['cmt_object_id']) : null;
+
+        if ($oCmtsObject) {
+            return $oCmtsObject->getDataAPI($aCmt);
+        }
+
+        return ['msg' => '_sys_txt_not_found', 'code' => 404];
+    }
+}

+ 132 - 0
upgrade/files/15.0.0.B3-15.0.0.RC1/files/inc/classes/BxDolAIVectorStoreFactory.php

@@ -0,0 +1,132 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    UnaCore UNA Core
+ * @{
+ */
+
+
+class BxDolAIVectorStoreFactory extends BxDolFactory 
+{
+    public static function getVectorStoreInstance(int $iId): NeuronAI\RAG\VectorStore\VectorStoreInterface 
+    {
+        if (isset($GLOBALS['bxDolClasses'][__CLASS__ . '_VectorStore_' . $iId]))
+            return $GLOBALS['bxDolClasses'][__CLASS__ . '_VectorStore_' . $iId];
+
+        $a = BxDolAIQuery::getVectorStoreObject($iId);
+        if (!$a) {
+            bx_log('sys_agents', "Vector store with id {$iId} not found", BX_LOG_ERR);
+            throw new Exception("Vector store with id {$iId} not found");
+        }
+
+        $aParametersSystem = !empty($a['params']) ? json_decode($a['params'], true) : [];
+        $aParametersUser = !empty($a['params_user']) ? json_decode($a['params_user'], true) : [];
+        $aParameters = array_merge($aParametersSystem, $aParametersUser);
+
+        // replace marker {topk} in $aParameters recoursively
+        $aParameters = bx_replace_markers($aParameters, [
+            'topk' => $a['topk'],
+        ]);
+        
+        switch($a['type']) {
+            case 'file':
+                $sDirectoryStores = BX_DIRECTORY_STORAGE . 'vector_stores/';
+                $sDirectory = $sDirectoryStores . $iId;
+                $sFile = '/data.store';
+                if (!file_exists($sDirectory . $sFile)) {
+                    @mkdir($sDirectoryStores, BX_DOL_DIR_RIGHTS);
+                    @chmod($sDirectoryStores, BX_DOL_DIR_RIGHTS);
+                    @mkdir($sDirectory, BX_DOL_DIR_RIGHTS);
+                    @chmod($sDirectory, BX_DOL_DIR_RIGHTS);
+                    @touch($sDirectory . $sFile);
+                    @chmod($sDirectory . $sFile, BX_DOL_FILE_RIGHTS);
+                }
+                $o = new NeuronAI\RAG\VectorStore\FileVectorStore(
+                    directory: $sDirectory,
+                    topK: $a['topk'] ?? 4,
+                    name: 'data',
+                    ext: '.store'
+                );
+                break;
+            case 'pinecon':
+                $o = new NeuronAI\RAG\VectorStore\PineconeVectorStore(
+                    key: $a['key'],
+                    indexUrl: $aParameters['indexUrl'],
+                    topK: $a['topk'] ?? 4,
+                    version: $aParameters['version'] ?? '2025-04',
+                    namespace: $aParameters['namespace'] ?? '__default__'
+                );
+                break;
+            case 'elasticsearch':
+                $oClient = Elastic\Elasticsearch\ClientBuilder::create()
+                    ->setHosts([$aParameters['client_params']['endpoint']])
+                    ->setApiKey($aParameters['client_params']['key'])
+                    ->build();
+                
+                $o = new NeuronAI\RAG\VectorStore\ElasticsearchVectorStore(
+                    client: $oClient,
+                    index: $aParameters['index'],
+                    topK: $a['topk'] ?? 4
+                );
+                break;
+            case 'opensearch':
+                $oClient = (new OpenSearch\GuzzleClientFactory())->create([
+                    'base_uri' => $aParameters['client_params']['endpoint'] ?? 'http://localhost:9200',
+                ]);
+        
+                $o = NeuronAI\RAG\VectorStore\OpenSearchVectorStore(
+                    client: $oClient,
+                    index: $aParameters['index'],
+                    topK: $a['topk'] ?? 4,
+                );
+                break;
+            case 'typesense':
+                $oClient = new \Typesense\Client($aParameters['client_params']);
+
+                $o = new NeuronAI\RAG\VectorStore\TypesenseVectorStore(
+                    client: $oClient,
+                    collection: $aParameters['collection'],
+                    vectorDimension: $aParameters['vectorDimension'] ?? 1024,
+                    topK: $a['topk'] ?? 4,
+                );
+                break;
+            case 'qdrant':
+                $o = new NeuronAI\RAG\VectorStore\QdrantVectorStore(
+                    collectionUrl: $aParameters['collectionUrl'],
+                    key: $a['key'],
+                    topK: $a['topk'] ?? 4,
+                    dimension: $aParameters['dimension'] ?? 1024
+                );
+                break;
+            case 'chromadb':
+                $o = new NeuronAI\RAG\VectorStore\ChromaVectorStore(
+                    collection: $aParameters['collection'],
+                    host: $aParameters['host'] ?? 'http://localhost:8000',
+                    tenant: $aParameters['tenant'] ?? 'default_tenant',
+                    database: $aParameters['database'] ?? 'default_database',
+                    key: $a['key'] ?? null,
+                    topK: $a['topk'] ?? 4
+                );
+                break;
+            case 'meilisearch':
+                $o = new NeuronAI\RAG\VectorStore\MeilisearchVectorStore(
+                    indexUid: $aParameters['indexUid'],
+                    host: $aParameters['host'] ?? 'http://localhost:8000',
+                    key: $a['key'] ?? null,
+                    embedder: $aParameters['embedder'] ?? 'default',
+                    topK: $a['topk'] ?? 4,
+                    dimension: $aParameters['dimension'] ?? 1024
+                );
+                break;
+            default:
+                bx_log('sys_agents', "Vector store type {$a['type']} is not supported", BX_LOG_ERR);
+                throw new Exception("Vector store type {$a['type']} is not supported");
+        }
+
+        $GLOBALS['bxDolClasses'][__CLASS__ . '_VectorStore_' . $iId] = $o;
+
+        return $o;
+    }
+}

+ 1211 - 0
upgrade/files/15.0.0.B3-15.0.0.RC1/files/inc/classes/BxDolAccount.php

@@ -0,0 +1,1211 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    UnaCore UNA Core
+ * @{
+ */
+
+bx_import('BxDolAcl');
+
+class BxDolAccount extends BxDolFactory implements iBxDolSingleton
+{
+    protected $_bIsApi;
+
+    protected $_iAccountID;
+    protected $_aInfo;
+    protected $_oQuery;
+
+    protected $_sImageField;
+    protected $_aImageTranscoders;
+
+    /**
+     * Constructor
+     */
+    protected function __construct ($iAccountId)
+    {
+        $iAccountId = (int)$iAccountId;
+        $sClass = get_class($this) . '_' . $iAccountId;
+        if (isset($GLOBALS['bxDolClasses'][$sClass]))
+            trigger_error ('Multiple instances are not allowed for the class: ' . get_class($this), E_USER_ERROR);
+
+        parent::__construct();
+
+        $this->_bIsApi = bx_is_api();
+
+        $this->_iAccountID = $iAccountId; // since constructor is protected $iAccountId is always valid
+        $this->_oQuery = BxDolAccountQuery::getInstance();
+
+        $this->_sImageField = 'picture';
+        $this->_aImageTranscoders = [
+            'icon' => 'sys_accounts_icon',
+            'thumb' => 'sys_accounts_thumb',
+            'ava' => 'sys_accounts_avatar',
+            'ava_big' => 'sys_accounts_avatar_big',
+            'picture' => 'sys_accounts_picture'
+        ];
+    }
+
+    /**
+     * Prevent cloning the instance
+     */
+    public function __clone()
+    {
+        $sClass = get_class($this) . '_' . $this->_iProfileID;
+        if (isset($GLOBALS['bxDolClasses'][$sClass]))
+            trigger_error('Clone is not allowed for the class: ' . get_class($this), E_USER_ERROR);
+    }
+
+    /**
+     * Get singleton instance of the class
+     */
+    public static function getInstance($mixedAccountId = false,  $bClearCache = false)
+    {
+        if (!$mixedAccountId)
+            $mixedAccountId = getLoggedId();
+
+        $iAccountId = self::getID($mixedAccountId);
+        if (!$iAccountId)
+            return false;
+
+        $sClass = __CLASS__ . '_' . $iAccountId;
+        
+        if ($bClearCache && isset($GLOBALS['bxDolClasses'][$sClass]))
+            unset($GLOBALS['bxDolClasses'][$sClass]);
+        
+        if(!isset($GLOBALS['bxDolClasses'][$sClass]))
+            $GLOBALS['bxDolClasses'][$sClass] = new BxDolAccount($iAccountId);
+
+        return $GLOBALS['bxDolClasses'][$sClass];
+    }
+
+    /**
+     * Get studio operator account singleton instance on the class
+     */
+    public static function getInstanceStudioOperator()
+    {
+        $oQuery = BxDolAccountQuery::getInstance();
+        if (!($iId = $oQuery->getStudioOperatorId()))
+            return false;
+
+        return self::getInstance($iId);
+    }
+
+    /**
+     * Get account id
+     */
+    public function id()
+    {
+        $a = $this->getInfo($this->_iAccountID);
+        return isset($a['id']) ? $a['id'] : false;
+    }
+
+    /**
+     * Check if account is confirmed, it is checked by email confirmation
+     */
+    public function isConfirmed($iAccountId = false)
+    {
+        $iId = (int)$iAccountId ? (int)$iAccountId : $this->_iAccountID;
+
+        $a = $this->getInfo($iId);
+
+        $bResult = false;
+        $sConfirmationType = getParam('sys_account_confirmation_type');
+        switch($sConfirmationType) {
+            case BX_ACCOUNT_CONFIRMATION_NONE:
+                $bResult = true;
+                break;
+
+            case BX_ACCOUNT_CONFIRMATION_EMAIL:
+                if($a['email_confirmed'])
+                    $bResult = true;
+                break;
+
+            case BX_ACCOUNT_CONFIRMATION_PHONE:
+                if($a['phone_confirmed'])
+                    $bResult = true;
+                break;
+
+            case BX_ACCOUNT_CONFIRMATION_EMAIL_PHONE:
+                if($a['email_confirmed'] && $a['phone_confirmed'])
+                    $bResult = true;
+                break;
+                
+            case BX_ACCOUNT_CONFIRMATION_EMAIL_OR_PHONE:
+                if($a['email_confirmed'] || $a['phone_confirmed'])
+                    $bResult = true;
+                break;  
+                
+        }
+
+        /**
+         * @hooks
+         * @hookdef hook-account-is_confirmed 'account', 'is_confirmed' - hook in  $oAccount->isConfirmed check
+         * - $unit_name - equals `account`
+         * - $action - equals `is_confirmed` 
+         * - $object_id - account id 
+         * - $sender_id - not used 
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `type` - [string] confirmation type can be none/phone/email/email_and_phone/email_or_phone
+         *      - `override_result` - [bool] by ref, if account confirmed = true, otherwise false, can be overridden in hook processing
+         * @hook @ref hook-account-is_confirmed
+         */
+        bx_alert('account', 'is_confirmed', $iId, false, array('type' => $sConfirmationType, 'override_result' => &$bResult));
+
+        return $bResult;
+    }
+    
+    public function getCurrentConfirmationStatusValue($iAccountId = false)
+    {
+        $a = $this->getInfo((int)$iAccountId);
+        $sTmp = $a['email_confirmed'] . $a['phone_confirmed'];
+        switch ($sTmp) {
+            case '01':
+                return BX_ACCOUNT_CONFIRMATION_PHONE;
+            case '10':
+                return BX_ACCOUNT_CONFIRMATION_EMAIL;
+            case '11':
+                return BX_ACCOUNT_CONFIRMATION_EMAIL_PHONE;
+        }
+        return BX_ACCOUNT_CONFIRMATION_NONE;
+    }
+
+    public function isConfirmedEmail($iAccountId = false)
+    {
+        $iId = (int)$iAccountId ? (int)$iAccountId : $this->_iAccountID;
+
+        $bResult = false;
+        if(self::isNeedConfirmEmail()) {
+            $a = $this->getInfo($iId);
+
+            $bResult = $a['email_confirmed'] ? true : false;
+        }
+        else 
+            $bResult = true;
+
+        /**
+         * @hooks
+         * @hookdef hook-account-is_confirmed 'account', 'is_confirmed_email' - hook in  $oAccount->isConfirmedEmail check
+         * - $unit_name - equals `account`
+         * - $action - equals `is_confirmed_email` 
+         * - $object_id - account id 
+         * - $sender_id - not used 
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `override_result` - [bool] by ref, if email confirmed = true, otherwise false, can be overridden in hook processing
+         * @hook @ref hook-account-is_confirmed_email
+         */
+        bx_alert('account', 'is_confirmed_email', $iId, false, array('override_result' => &$bResult));
+
+        return $bResult;
+    }
+
+    public function isConfirmedPhone($iAccountId = false)
+    {
+        $iId = (int)$iAccountId ? (int)$iAccountId : $this->_iAccountID;
+
+        $bResult = false;        
+        if(self::isNeedConfirmPhone()) {
+            $a = $this->getInfo((int)$iAccountId);
+
+            $bResult = $a['phone_confirmed'] ? true : false;
+        }
+        else
+            $bResult = true;
+
+        /**
+         * @hooks
+         * @hookdef hook-account-is_confirmed_phone 'account', 'is_confirmed_phone' - hook in  $oAccount->isConfirmedPhone check
+         * - $unit_name - equals `account`
+         * - $action - equals `is_confirmed_phone` 
+         * - $object_id - account id 
+         * - $sender_id - not used 
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `override_result` - [bool] by ref, if phone confirmed = true, otherwise false, can be overridden in hook processing
+         * @hook @ref hook-account-is_confirmed_phone
+         */
+        bx_alert('account', 'is_confirmed_phone', $iId, false, array('override_result' => &$bResult));
+
+        return $bResult;
+    }
+
+    static public function isNeedConfirmEmail()
+    {
+        if(in_array(getParam('sys_account_confirmation_type'), array(BX_ACCOUNT_CONFIRMATION_EMAIL, BX_ACCOUNT_CONFIRMATION_EMAIL_PHONE, BX_ACCOUNT_CONFIRMATION_EMAIL_OR_PHONE)))
+            return true;
+        return false;
+    }
+    
+    static public function isNeedConfirmPhone()
+    {
+        if(in_array(getParam('sys_account_confirmation_type'), array(BX_ACCOUNT_CONFIRMATION_PHONE, BX_ACCOUNT_CONFIRMATION_EMAIL_PHONE, BX_ACCOUNT_CONFIRMATION_EMAIL_OR_PHONE)))
+            return true;
+        return false;
+    }
+    
+    public function isLocked($iAccountId = false)
+    {
+        $a = $this->getInfo((int)$iAccountId);
+        return $a['locked'] ? true : false;
+    }
+    
+    //
+
+    /**
+     * Set account email to confirmed or unconfirmed
+     * @param  int  $isConfirmed - false: mark email as unconfirmed, true: as confirmed
+     * @param  int  $iAccountId  - optional account id
+     * @return true on success or false on error
+     */
+    public function updateEmailConfirmed($isConfirmed, $isAutoSendConfrmationEmail = true, $iAccountId = false)
+    {
+        $iId = (int)$iAccountId ? (int)$iAccountId : $this->_iAccountID;
+
+        if (!$isConfirmed && $isAutoSendConfrmationEmail && self::isNeedConfirmEmail()) // if email_confirmation procedure is enabled - send email confirmation letter
+            $this->sendConfirmationEmail($iId);
+
+        if ($this->_oQuery->updateEmailConfirmed($isConfirmed, $iId)) {
+            $this->_aInfo = false;
+            /**
+             * @hooks
+             * @hookdef hook-account-confirm 'account', 'confirm' - hook in email confirmation $oAccount->updateEmailConfirmed 
+             * - $unit_name - equals `account`
+             * - $action - can be confirm/unconfirm
+             * - $object_id - account id 
+             * - $sender_id - not used 
+             * - $extra_params - not used 
+             * @hook @ref hook-account-confirm
+             */
+            bx_alert('account', $this->isConfirmed() ? 'confirm' : 'unconfirm', $iId);
+            return true;
+        }
+        return false;
+    }
+    
+    /**
+     * Set account phone to confirmed or unconfirmed
+     * @param  int  $isConfirmed - false: mark phone as unconfirmed, true: as confirmed
+     * @param  int  $iAccountId  - optional account id
+     * @return true on success or false on error
+     */
+    public function updatePhoneConfirmed($isConfirmed, $iAccountId = false)
+    {
+        $iId = (int)$iAccountId ? (int)$iAccountId : $this->_iAccountID;
+        
+        if ($this->_oQuery->updatePhoneConfirmed($isConfirmed, $iId)) {
+            $this->_aInfo = false;
+            bx_alert('account', $this->isConfirmed() ? 'confirm' : 'unconfirm', $iId);
+            return true;
+        }
+        return false;
+    }
+    /**
+     * Change account password
+     * @param  string  $sPassword - new password
+     * @param  int  $iAccountId  - optional account id
+     * @return true on success or false on error
+     */
+    public function updatePassword($sPassword, $iAccountId = false)
+    {
+        $iId = (int)$iAccountId ? (int)$iAccountId : $this->_iAccountID;
+
+        $sSalt = genRndSalt();
+        $sPasswordHash = encryptUserPwd($sPassword, $sSalt);
+
+        $this->_oQuery->logPassword($iId);
+        
+        if((int)$this->_oQuery->updatePassword($sPasswordHash, $sSalt, $iId) > 0) {
+            /**
+             * @hooks
+             * @hookdef hook-account-edited 'account', 'edited' - hook on account edited $oAccount->updatePassword 
+             * - $unit_name - equals `account`
+             * - $action - equals edited
+             * - $object_id - account id 
+             * - $sender_id - account sender id 
+             * - $extra_params - array of additional params with the following array keys:
+             *      - `action` - [string] action's name, can be reset_password
+             * @hook @ref hook-account-edited
+             */
+            bx_alert('account', 'edited', $iId, ($iSenderId = getLoggedId()) != 0 ? $iSenderId : $iId, [
+                'action' => 'reset_password'
+            ]);
+
+            $this->doAudit($iId, '_sys_audit_action_account_reset_password');
+            return true;
+        }
+
+        return false;
+    }
+    /**
+     * Set account phone
+     * @param  string  $sPhone - phone number
+     * @param  int  $iAccountId  - optional account id
+     * @return true on success or false on error
+     */
+    public function updatePhone($sPhone, $iAccountId = false)
+    {
+        $iId = (int)$iAccountId ? (int)$iAccountId : $this->_iAccountID;
+        if ($this->_oQuery->updatePhone($sPhone, $iId)) {
+            /**
+             * @hooks
+             * @hookdef hook-account-set_phone 'account', 'set_phone' - hook after accout password changed
+             * - $unit_name - equals `account`
+             * - $action - equals `set_phone` 
+             * - $object_id - account id 
+             * - $sender_id - not used 
+             * - $extra_params - not used
+             * @hook @ref hook-account-set_phone
+             */
+            bx_alert('account', 'set_phone', $iId);
+            return true;
+        }
+        return false;
+    }
+    /**
+     * Switch context automatically to the first available profile
+     * @param $iProfileIdFilterOut profile ID to exclude from the list of possible profiles
+     * @param $iAccountId account ID to use istead of current account
+     * @return true on success or false on error
+     */ 
+    public function updateProfileContextAuto($iProfileIdFilterOut = false, $iAccountId = false)
+    {
+        $oAccount = (!$iAccountId || $iAccountId == $this->_iAccountID ? $this : BxDolAccount::getInstance ($iAccountId));
+        if (!$oAccount)
+            return false;
+        $aAccountInfo = $oAccount->getInfo();
+        $aProfiles = $oAccount->getProfiles();
+        $oProfileAccount = BxDolProfile::getInstanceAccountProfile($oAccount->id());
+
+        // unset deleted profile and account profile
+        if ($iProfileIdFilterOut)
+            unset($aProfiles[$iProfileIdFilterOut]);
+        unset($aProfiles[$oProfileAccount->id()]);
+
+        if ($aProfiles) {
+            // try to use another profile
+            reset($aProfiles);
+            $iProfileId = key($aProfiles);
+        } 
+        else {
+            // if no profiles exist, use account profile
+            $iProfileId = $oProfileAccount->id();
+        }
+
+        return $oAccount->updateProfileContext($iProfileId);
+    }
+    
+    public function updateProfileContext($iSwitchToProfileId, $iAccountId = false)
+    {
+        $iId = (int)$iAccountId ? (int)$iAccountId : $this->_iAccountID;
+        $aInfo = $this->getInfo((int)$iId);
+        if (!$aInfo)
+            return false;
+
+        $ret = null;
+        /**
+         * @hooks
+         * @hookdef hook-account-before_switch_context 'account', 'before_switch_context' - hook before switch profile_id from current logged user
+         * - $unit_name - equals `account`
+         * - $action - equals `before_switch_context` 
+         * - $object_id - account id 
+         * - $sender_id - profile_id to switch to
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `profile_id_current` - [int] current profile_id
+         *      - `override_result` - [int] by ref, profile_id to switch to, can be overridden in hook processing
+         * @hook @ref hook-account-before_switch_context
+         */
+        bx_alert('account', 'before_switch_context', $iId, $iSwitchToProfileId, array('profile_id_current' => $aInfo['profile_id'], 'override_result' => &$ret));
+        if ($ret !== null)
+            return $ret;
+
+        if (!$this->_oQuery->updateCurrentProfile($iId, $iSwitchToProfileId))
+            return false;
+
+        $this->_aInfo = false;
+        
+        /**
+         * @hooks
+         * @hookdef hook-account-switch_context 'account', 'switch_context' - hook before switch profile_id from current logged user
+         * - $unit_name - equals `account`
+         * - $action - equals `switch_context` 
+         * - $object_id - account id 
+         * - $sender_id - profile_id to switch to
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `profile_id_old` - [int] old profile_id
+         * @hook @ref hook-account-switch_context
+         */
+        bx_alert('account', 'switch_context', $iId, $iSwitchToProfileId, array('profile_id_old' => $aInfo['profile_id']));
+
+        return true;
+    }
+
+    /**
+     * Send "confirmation" email
+     */
+    public function sendConfirmationEmail($iAccountId = false)
+    {
+        $iAccountId = (int)$iAccountId;
+        if(!$iAccountId)
+            $iAccountId = $this->_iAccountID;
+
+        $aAccountInfo = $this->getInfo($iAccountId);
+        if(empty($aAccountInfo) || !is_array($aAccountInfo))
+            return false;
+
+        $oKey = BxDolKey::getInstance();
+        $sConfirmationCode = $oKey->getNewKeyNumeric(['account_id' => $iAccountId]);
+        $sConfirmationLink = bx_append_url_params(BX_DOL_URL_ROOT . BxDolPermalinks::getInstance()->permalink('page.php?i=confirm-email'), ['code' => $sConfirmationCode]);
+
+        $sEmailTemplate = 't_Confirmation';
+        $aEmailReplaceVars = [
+            'name' => $this->getDisplayName($iAccountId),
+            'email' => $aAccountInfo['email'],
+            'conf_code' => $sConfirmationCode,
+            'conf_link' => $sConfirmationLink,
+            'conf_form_link' => BX_DOL_URL_ROOT . BxDolPermalinks::getInstance()->permalink('page.php?i=confirm-email')
+        ];
+
+        $bResult = sendMailTemplate($sEmailTemplate, $iAccountId, (int)$aAccountInfo['profile_id'], $aEmailReplaceVars, BX_EMAIL_SYSTEM);
+        if($bResult)
+            $this->doAudit($iAccountId, '_sys_audit_action_account_resend_confirmation_email');
+
+        return $bResult;
+    }
+
+    /**
+     * Send "welcome" email
+     */
+    public function sendWelcomeEmail($iAccountId = false)
+    {
+        if(getParam('sys_account_welcome_letter') != 'on')
+            return false;
+
+        $iAccountId = (int)$iAccountId;
+        if(!$iAccountId)
+            $iAccountId = $this->_iAccountID;
+
+        $aAccountInfo = $this->getInfo($iAccountId);
+        if(empty($aAccountInfo) || !is_array($aAccountInfo))
+            return false;
+
+        if((int)$aAccountInfo['welcome_sent'] != 0)
+            return true;
+
+        $sEmailTemplate = 't_Welcome';
+        $aEmailReplaceVars = [
+            'name' => $this->getDisplayName($iAccountId),
+        ];
+
+        $bResult = sendMailTemplate($sEmailTemplate, $iAccountId, (int)$aAccountInfo['profile_id'], $aEmailReplaceVars, BX_EMAIL_SYSTEM);
+        if($bResult)
+            $this->_oQuery->updateWelcomeSent(1, $iAccountId);
+
+        return $bResult;
+    }
+
+    public function sendResetPasswordEmail($iAccountId = false)
+    {
+        $iAccountId = (int)$iAccountId;
+        if(!$iAccountId)
+            $iAccountId = $this->_iAccountID;
+
+        $aAccountInfo = $this->getInfo($iAccountId);
+        if(empty($aAccountInfo) || !is_array($aAccountInfo))
+            return false;
+
+        $sKey = bx_get_reset_password_key($aAccountInfo['email']);
+
+        $aReplaceVars = array(
+            'name' => $this->getDisplayName($iAccountId),
+            'email' => $aAccountInfo['email'],
+            'key' => $sKey,
+            'forgot_password_url' => bx_get_reset_password_link_by_key($sKey)
+        );
+
+        return sendMailTemplate('t_Forgot', $iAccountId, (int)$aAccountInfo['profile_id'], $aReplaceVars, BX_EMAIL_SYSTEM);
+    }
+
+    /**
+     * Get account info
+     */
+    public function getInfo($iAccountId = false)
+    {        
+        if ($iAccountId && $iAccountId != $this->_iAccountID)
+            return $this->_oQuery->getInfoById((int)$iAccountId ? (int)$iAccountId : $this->_iAccountID);
+
+        if ($this->_aInfo)
+            return $this->_aInfo;
+
+        $this->_aInfo = $this->_oQuery->getInfoById($this->_iAccountID);
+        return $this->_aInfo;
+    }
+
+    /**
+     * Get account display name
+     */
+    public function getDisplayName($iAccountId = false)
+    {
+        $aInfo = $this->getInfo($iAccountId);
+
+        $sDisplayName = !empty($aInfo['name']) ? $aInfo['name'] : _t('_sys_txt_user_n', $aInfo['id']);
+        
+        /**
+         * @hooks
+         * @hookdef hook-account-account_name 'account', 'account_name' - hook on get account display name
+         * - $unit_name - equals `account`
+         * - $action - equals `account_name` 
+         * - $object_id - account id 
+         * - $sender_id - not used 
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `info` - [array] contains account info from $oAccount->getInfo()
+         *      - `display_name` - [string] by ref, account display name,  can be overridden in hook processing
+         * @hook @ref hook-account-account_name
+         */
+        bx_alert('account', 'account_name', $iAccountId, 0, array('info' => $aInfo, 'display_name' => &$sDisplayName, 'display_name_ref' => &$sDisplayName));
+
+        return bx_process_output($sDisplayName);
+    }
+
+    /**
+     * Get account url
+     */
+    public function getUrl($iAccountId = false)
+    {
+        return 'javascript:void(0);';
+    }
+
+    /**
+     * Get account url
+     */
+    public function getUnit($iAccountId = false, $aParams = array())
+    {
+        $sTemplate = 'unit';
+        $sTemplateSize = false;
+        $aTemplateVars = array();
+        if(!empty($aParams['template'])) {
+            if(is_string($aParams['template']))
+                $sTemplate = $aParams['template'];
+            else if(is_array($aParams['template'])) {
+                if(!empty($aParams['template']['name']))
+                    $sTemplate = $aParams['template']['name'];
+
+                if(!empty($aParams['template']['size']))
+                    $sTemplateSize = $aParams['template']['size'];
+
+                if(!empty($aParams['template']['vars']))
+                    $aTemplateVars = $aParams['template']['vars'];
+            }
+        }
+
+        $sTemplate = 'account_' . $sTemplate . '.html';
+        if(empty($sTemplateSize))
+            $sTemplateSize = 'thumb';
+
+        $sTitle = $this->getDisplayName($iAccountId);
+        $aInfo = $this->getInfo($iAccountId);
+
+        $sImageUrl = $this->_getImageUrl($sTemplateSize, $aInfo);
+        $bImageUrl = !empty($sImageUrl);
+
+        $aTmplVars = [
+            'size' => $sTemplateSize,
+            'content_url' => $this->getUrl($iAccountId),
+            'title' => $sTitle,
+            'title_attr' => bx_html_attribute($sTitle),
+            'bx_if:show_thumb_image' => [
+                'condition' => $bImageUrl,
+                'content' => [
+                    'size' => $sTemplateSize,
+                    'url' => $sImageUrl
+                ]
+            ],
+            'bx_if:show_thumb_letter' => [
+                'condition' => !$bImageUrl,
+                'content' => [
+                    'size' => $sTemplateSize,
+                    'color' => implode(', ', BxDolTemplate::getColorCode(($iAccountId ? $iAccountId : $this->_iAccountID), 1.0)),
+                    'letter' => mb_strtoupper(mb_substr($sTitle, 0, 1)),
+                ]
+            ],
+            'bx_if:show_online' => [
+                'condition' => $this->isOnline($iAccountId),
+                'content' => []
+            ]
+        ];
+
+        if(!empty($aTemplateVars) && is_array($aTemplateVars))
+            $aTmplVars = array_merge ($aTmplVars, $aTemplateVars);
+
+        return BxDolTemplate::getInstance()->parseHtmlByName($sTemplate, $aTmplVars);
+    }
+    
+    public function getUnitApi($iAccountId = false, $aParams = array())
+    {
+        if(!$iAccountId)
+            $iAccountId = $this->_iAccountID;
+
+        $sModule = 'system';
+
+        $iAuthorId = 0;
+        $aAuthorData = [];
+        if(($oProfile = BxDolProfile::getInstanceByContentAndType($iAccountId, $sModule)) !== false) {
+            $iAuthorId = $oProfile->id();
+            $aAuthorData = BxDolProfile::getData($iAuthorId);
+        }
+
+        $aInfo = $this->getInfo($iAccountId);
+
+        return [
+            'id' => $aInfo['id'], 
+            'module' => $sModule,
+            'module_title' => $sModule,
+            'added' => $aInfo['added'],
+            'author' => $iAuthorId,
+            'author_data' => $aAuthorData,
+            'title' => $this->getDisplayName($iAccountId),
+        ];
+    }
+
+    /**
+     * Get picture url
+     */
+    public function getPicture($iAccountId = false)
+    {
+        if($this->_bIsApi)
+            return '';
+
+        $sImageUrl = $this->_getImageUrl('picture', $iAccountId);
+        if(!$sImageUrl)
+            $sImageUrl = BxDolTemplate::getInstance()->getImageUrl('account.svg');
+
+        return $sImageUrl;
+    }
+
+    /**
+     * Get big (2x) avatar url
+     */
+    public function getAvatarBig($iAccountId = false)
+    {
+        if($this->_bIsApi)
+            return '';
+
+        $sImageUrl = $this->_getImageUrl('ava_big', $iAccountId);
+        if(!$sImageUrl)
+            $sImageUrl = BxDolTemplate::getInstance()->getImageUrl('account.svg');
+
+        return $sImageUrl;
+    }
+
+    /**
+     * Get avatar url
+     */
+    public function getAvatar($iAccountId = false)
+    {
+        if($this->_bIsApi)
+            return '';
+
+        $sImageUrl = $this->_getImageUrl('ava', $iAccountId);
+        if(!$sImageUrl)
+            $sImageUrl = BxDolTemplate::getInstance()->getImageUrl('account.svg');
+
+        return $sImageUrl;
+    }
+
+    /**
+     * Get thumb picture url
+     */
+    public function getThumb($iAccountId = false)
+    {
+        if($this->_bIsApi)
+            return '';
+
+        $sImageUrl = $this->_getImageUrl('thumb', $iAccountId);
+        if(!$sImageUrl)
+            $sImageUrl = BxDolTemplate::getInstance()->getImageUrl('account.svg');
+
+        return $sImageUrl;
+    }
+
+    /**
+     * Get icon picture url
+     */
+    public function getIcon($iAccountId = false)
+    {
+        if($this->_bIsApi)
+            return '';
+
+        $sImageUrl = $this->_getImageUrl('icon', $iAccountId);
+        if(!$sImageUrl)
+            $sImageUrl = BxDolTemplate::getInstance()->getImageUrl('account.svg');
+
+        return $sImageUrl;
+    }
+
+    /**
+     * Get account email
+     */
+    public function getEmail($iAccountId = false)
+    {
+        $iAccountId = (int)$iAccountId ? (int)$iAccountId : $this->_iAccountID;
+        $aAccountInfo = $this->getInfo($iAccountId);
+        return $aAccountInfo['email'];
+    }
+
+    /**
+     * Get language ID
+     */
+    public function getLanguageId($iAccountId = false)
+    {
+        $iAccountId = (int)$iAccountId ? (int)$iAccountId : $this->_iAccountID;
+        $aAccountInfo = $this->getInfo($iAccountId);
+        return $aAccountInfo['lang_id'];
+    }
+
+    /**
+     * Is account online
+     */
+    public function isOnline($iAccountId = false)
+    {
+        $iAccountId = (int)$iAccountId ? (int)$iAccountId : $this->_iAccountID;
+        return $this->_oQuery->isOnline($iAccountId);
+    }
+
+    /**
+     * Validate account.
+     * @param $s - account identifier (id or email)
+     * @return account id or false if account was not found
+     */
+    static public function getID($s)
+    {
+        $oQuery = BxDolAccountQuery::getInstance();
+
+        bx_import('BxDolForm');
+        if (BxDolFormCheckerHelper::checkEmail($s)) {
+            $iId = (int)$oQuery->getIdByEmail($s);
+            return $iId ? $iId : false;
+        }
+        if (preg_match("/^\+[0-9\s]+$/", $s)) {
+            $iId = (int)$oQuery->getIdByPhone($s);
+            return $iId ? $iId : false;
+        }
+        
+        $iId = $oQuery->getIdById((int)$s);
+        return $iId ? $iId : false;
+    }
+
+    /**
+     * Check if profiles limit reached
+     */
+    public function isProfilesLimitReached ()
+    {
+        $iProfilesLimit = (int)getParam('sys_account_limit_profiles_number');
+        /**
+         * @hooks
+         * @hookdef hook-account-get_limit_profiles_number 'account', 'get_limit_profiles_number' - hook on get account limit on the number of profiles
+         * - $unit_name - equals `account`
+         * - $action - equals `get_limit_profiles_number` 
+         * - $object_id - not used 
+         * - $sender_id - not used 
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `account_id` - [int] account id 
+         *      - `number` - [int] by ref, account limit on the number of profiles,  can be overridden in hook processing
+         * @hook @ref hook-account-get_limit_profiles_number
+         */
+        bx_alert('account', 'get_limit_profiles_number', 0, 0, array('account_id' => $this->_iAccountID, 'number' => &$iProfilesLimit, 'number_ref' => &$iProfilesLimit));
+        if (!isAdmin() && $iProfilesLimit && ($iProfilesNum = $this->getProfilesNumber()) && $iProfilesNum >= $iProfilesLimit)
+            return true;
+
+        return false;
+    }
+
+    /**
+     * Get number of profiles associated with the account
+     */
+    public function getProfilesNumber ($isFilterNonSwitchableProfiles = true)
+    {
+        $a = $this->getProfilesIds($isFilterNonSwitchableProfiles);
+        return count($a);
+    }
+    
+    /**
+     * Get all profile ids associated with the account
+     */
+    public function getProfilesIds ($isFilterNonSwitchableProfiles = true, $isFilterSystemProfiles = true)
+    {
+        $a = $this->getProfiles ($isFilterNonSwitchableProfiles, $isFilterSystemProfiles);
+        return $a ? array_keys($a) : array();
+    }
+
+    /**
+     * Get all profiles associated with the account
+     */
+    public function getProfiles ($isFilterNonSwitchableProfiles = true, $isFilterSystemProfiles = true)
+    {
+        $oProfileQuery = BxDolProfileQuery::getInstance();
+        $aProfiles = $oProfileQuery->getProfilesByAccount($this->_iAccountID);
+
+        if ($isFilterNonSwitchableProfiles) {
+            foreach ($aProfiles as $iProfileId => $aProfile) {
+                if ('system' == $aProfile['type'])
+                    continue;
+                if (!BxDolService::call($aProfile['type'], 'act_as_profile'))
+                    unset($aProfiles[$iProfileId]);
+            }
+        }
+
+        if ($isFilterSystemProfiles) {
+            foreach ($aProfiles as $iProfileId => $aProfile) {
+                if ('system' == $aProfile['type'])
+                    unset($aProfiles[$iProfileId]);
+            }
+        }
+
+        return $aProfiles;
+    }
+
+    /**
+     * Delete profile.
+     * @param $bDeleteWithContent - delete associated profiles with all its contents
+     * @param $bScheduled - delete account using background jobs.
+     */
+    function delete($bDeleteWithContent = false, $bScheduled = false)
+    {
+        if ($bScheduled)
+            return BxDolBackgroundJobs::getInstance()->add('account_delete_' . $this->_iAccountID, ['system', 'account_delete', [$this->_iAccountID, $bDeleteWithContent], 'TemplServiceAccount']);
+
+        $aAccountInfo = $this->_oQuery->getInfoById($this->_iAccountID);
+        if (!$aAccountInfo)
+            return false;
+
+        // create system event before deletion
+        $isStopDeletion = false;
+        /**
+         * @hooks
+         * @hookdef hook-account-before_delete 'account', 'before_delete' - hook on before delete account, 
+         * - $unit_name - equals `account`
+         * - $action - equals `before_delete` 
+         * - $object_id - account id 
+         * - $sender_id - not used 
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `delete_with_content` - [bool] if account will delete with content = true, otherwise = false
+         *      - `stop_deletion` - [bool] by ref, if it set to true account deletion will stopped, can be overridden in hook processing
+         * @hook @ref hook-account-before_delete
+         */
+        bx_alert('account', 'before_delete', $this->_iAccountID, 0, array('delete_with_content' => $bDeleteWithContent, 'stop_deletion' => &$isStopDeletion, 'stop_deletion_ref' => &$isStopDeletion));
+        if ($isStopDeletion)
+            return false;
+
+        $oAccountQuery = BxDolAccountQuery::getInstance();
+
+        $oProfileQuery = BxDolProfileQuery::getInstance();
+        $aProfiles = $oProfileQuery->getProfilesByAccount($this->_iAccountID);
+        foreach ($aProfiles as $iProfileId => $aRow) {
+            $oProfile = BxDolProfile::getInstance($iProfileId);
+            if (!$oProfile)
+                continue;
+            $oProfile->delete(false, $bDeleteWithContent, true);
+        }
+
+        // delete profile
+        if (!$oAccountQuery->delete($this->_iAccountID))
+            return false;
+
+        // unset class instance to prevent creating the instance again
+        $sClass = __CLASS__ . '_' . $this->_iAccountID;
+        unset($GLOBALS['bxDolClasses'][$sClass]);
+
+       /**
+         * @hooks
+         * @hookdef hook-account-delete 'account', 'delete' - hook on after delete account 
+         * - $unit_name - equals `account`
+         * - $action - equals `delete` 
+         * - $object_id - account id 
+         * - $sender_id - not used 
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `delete_with_content` - [bool] if account will delete with content = true, otherwise = false
+         * @hook @ref hook-account-delete
+         */
+        bx_alert('account', 'delete', $this->_iAccountID, 0, array ('delete_with_content' => $bDeleteWithContent));
+        
+        $this->doAudit($this->_iAccountID, $bDeleteWithContent ? '_sys_audit_action_account_deleted_with_content' : '_sys_audit_action_account_deleted');
+        
+        return true;
+    }
+
+    /**
+     * Add permament messages.
+     */
+    public function addInformerPermanentMessages ($oInformer)
+    {
+        if (!$this->isConfirmed()) {
+            if (!$this->isConfirmedEmail()) {
+                $sUrl = BxDolPermalinks::getInstance()->permalink('page.php?i=confirm-email');
+                $aAccountInfo = $this->getInfo();
+                $oInformer->add('sys-account-unconfirmed-email', _t('_sys_txt_account_unconfirmed_email', $sUrl . '&resend=1', $aAccountInfo['email'], $sUrl), BX_INFORMER_ALERT);
+            }
+            if (!$this->isConfirmedPhone()) {
+                $sUrl = BxDolPermalinks::getInstance()->permalink('page.php?i=confirm-phone') . '';
+                $aAccountInfo = $this->getInfo();
+                $oInformer->add('sys-account-unconfirmed-phone', _t('_sys_txt_account_unconfirmed_phone', $sUrl), BX_INFORMER_ALERT);
+            }
+        }
+
+        $this->isNeedChangePassword(false, $oInformer);
+    }
+    
+    public function addInformerDeletionScheduled($oInformer)
+    {
+        if(BxDolBackgroundJobs::getInstance()->exists('account_delete_' . $this->_iAccountID))
+            $oInformer->add('sys-account-deletion-scheduled', _t('_sys_txt_account_deletion_scheduled'), BX_INFORMER_ALERT);
+    }
+
+    /**
+     * Get unsubscribe link for the specified mesage type
+     */
+    public function getUnsubscribeLink($iEmailType, $iAccountId = false)
+    {
+        $iAccountId = (int)$iAccountId ? (int)$iAccountId : $this->_iAccountID;
+        $sUrl = '';
+        switch ($iEmailType) {
+            case BX_EMAIL_NOTIFY:
+                $sUrl = 'page.php?i=unsubscribe-notifications';
+                break;
+            case BX_EMAIL_MASS:
+                $sUrl = 'page.php?i=unsubscribe-news';
+                break;
+            default:
+                return '';
+        }
+        return BxDolPermalinks::getInstance()->permalink($sUrl) . '&id=' . $iAccountId . '&code=' . $this->getEmailHash();
+    }
+
+    public function getEmailHash($iAccountId = false)
+    {
+        $iAccountId = (int)$iAccountId ? (int)$iAccountId : $this->_iAccountID;
+        $a = $this->getInfo();
+        return md5($a['email'] . $a['salt'] . BX_DOL_SECRET);
+    }
+    
+    public function getPasswordChangedDate($mixedAccount = false)
+    {
+        if(($bEmpty = empty($mixedAccount)) || !is_array($mixedAccount))
+            $mixedAccount = $this->_oQuery->getInfoById(!$bEmpty ? (int)$mixedAccount : $this->_iAccountID);
+
+        $iLastChanged = (int)$mixedAccount['password_changed'];
+        return $iLastChanged ? $iLastChanged : (int)$mixedAccount['added'];
+    }
+
+    public function getPasswordExpiredDate($iPasswordExpiredForMembership, $mixedAccount = false)
+    {
+        if($iPasswordExpiredForMembership == 0)
+            return 0;
+
+        return $iPasswordExpiredForMembership * 86400 + $this->getPasswordChangedDate($mixedAccount);
+    }
+
+    public function isNeedChangePassword($iAccountId = false, $oInformer = false)
+    {
+        $iAccountId = (int)$iAccountId ? (int)$iAccountId : $this->_iAccountID;
+
+        list($sPageLink, $aPageParams) = bx_get_base_url_inline();
+
+        $sChangePasswordUri = 'account-settings-password';
+        $bNeedRedirectToChangePassword = true;
+        if(isset($aPageParams['i']) && $aPageParams['i'] == $sChangePasswordUri)
+            $bNeedRedirectToChangePassword = false;
+
+        /**
+         * @hooks
+         * @hookdef hook-account-is_need_to_change_password 'account', 'is_need_to_change_password' - hook on after delete account 
+         * - $unit_name - equals `account`
+         * - $action - equals `is_need_to_change_password` 
+         * - $object_id - account id 
+         * - $sender_id - not used 
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `override_result` - [bool] by ref, if Need Redirect To Change Password = true, otherwise = false, can be overridden in hook processing
+         * @hook @ref hook-account-is_need_to_change_password
+         */
+        bx_alert('account', 'is_need_to_change_password',  $iAccountId, false, [
+            'override_result' => &$bNeedRedirectToChangePassword
+        ]);
+
+        if(!$bNeedRedirectToChangePassword)
+            return;
+
+        $aAccountInfo = $this->getInfo();
+        $aMembershipInfo = BxDolAcl::getInstance()->getMemberMembershipInfo($aAccountInfo['profile_id']);
+        $sChangePasswordUrl = BX_DOL_URL_ROOT . BxDolPermalinks::getInstance()->permalink('page.php?i=' . $sChangePasswordUri);
+
+        if(($iPasswordExpiredDate = $this->getPasswordExpiredDate($aMembershipInfo['password_expired'], $aAccountInfo)) && $iPasswordExpiredDate < time()) {
+            if(getParam('sys_account_accounts_force_password_change_after_expiration') == 'on') {
+                header('Location: ' . $sChangePasswordUrl);
+                exit;
+            }
+            else {
+                if(!$oInformer)
+                    $oInformer = BxDolInformer::getInstance();
+
+                $oInformer->add('sys-account-need-to-change-password', _t('_sys_txt_account_need_to_change_password', $sChangePasswordUrl), BX_INFORMER_ALERT);
+            }
+        }
+    }
+
+    public function doAudit($iAccountId, $sAction, $aData = [])
+    {
+        $iAccountId = (int)$iAccountId ? (int)$iAccountId : $this->_iAccountID;
+
+        bx_audit($iAccountId, 'bx_accounts', $sAction,  [
+            'content_title' => $this->getEmail(), 
+            'data' => $aData
+        ]);
+    }
+
+    /**
+     * @return CHECK_ACTION_RESULT_ALLOWED if access is granted or error message if access is forbidden.
+     */
+    static public function isAllowedCreate ($iProfileId, $isPerformAction = false)
+    {
+        $aCheck = checkActionModule($iProfileId, 'create account', 'system', $isPerformAction);
+        if ($aCheck[CHECK_ACTION_RESULT] !== CHECK_ACTION_RESULT_ALLOWED)
+            return MsgBox($aCheck[CHECK_ACTION_MESSAGE]);
+        return CHECK_ACTION_RESULT_ALLOWED;
+    }
+    
+    static public function isAllowedCreateMultiple ($iProfileId, $isPerformAction = false)
+    {
+        $iLimit = (int)getParam('sys_account_limit_profiles_number');
+
+        $bResult = false;
+        if(isAdmin() || $iLimit != 1)
+            $bResult = true;
+
+        $oProfile = BxDolProfile::getInstance($iProfileId);
+        if($iLimit == 1 && $oProfile->getModule() == 'system')
+            $bResult = true;
+
+        if($oProfile && $oProfile->getAccountId() != getLoggedId())
+            $bResult = false;
+
+        /**
+         * @hooks
+         * @hookdef hook-account-allow_create_another_profile 'profile', 'allow_create_another_profile' - hook on check allow create profile 
+         * - $unit_name - equals `profile`
+         * - $action - equals `allow_create_another_profile` 
+         * - $object_id - profile id 
+         * - $sender_id - not used 
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `override_result` - [bool] by ref, if allow create another profile = true, otherwise = false, can be overridden in hook processing
+         * @hook @ref hook-account-allow_create_another_profile
+         */
+        bx_alert('profile', 'allow_create_another_profile', $iProfileId, 0, [
+            'override_result' => &$bResult
+        ]);
+
+        return $bResult;
+    }
+
+    /**
+     * @return CHECK_ACTION_RESULT_ALLOWED if access is granted or error message if access is forbidden.
+     */
+    static public function isAllowedEdit ($iProfileId, $aContentInfo, $isPerformAction = false)
+    {
+        $oProfile = BxDolProfile::getInstance($iProfileId);
+        if (!$oProfile)
+            return _t('_sys_txt_access_denied');
+
+        $aProfileInfo = $oProfile->getInfo();
+        if (!$aProfileInfo || getLoggedId() != $aProfileInfo['account_id'])
+            return _t('_sys_txt_access_denied');
+
+        return CHECK_ACTION_RESULT_ALLOWED;
+    }
+
+    /**
+     * @return CHECK_ACTION_RESULT_ALLOWED if access is granted or error message if access is forbidden.
+     */
+    static public function isAllowedDelete ($iProfileId, $aContentInfo, $isPerformAction = false)
+    {
+        $iAccountId = (int)BxDolProfile::getInstance($iProfileId)->getAccountId();
+        if(isAdmin($iAccountId) && $iAccountId == (int)$aContentInfo['id'])
+            return _t('_sys_txt_account_cannot_delete');
+
+        $aCheck = checkActionModule($iProfileId, 'delete account', 'system', $isPerformAction);
+        if ($aCheck[CHECK_ACTION_RESULT] !== CHECK_ACTION_RESULT_ALLOWED)
+            return $aCheck[CHECK_ACTION_MESSAGE];
+
+        return CHECK_ACTION_RESULT_ALLOWED;
+    }
+    
+    static public function pruning ()
+    {
+        $iCount = 0;
+        $iTime = time() - getParam('sys_account_accounts_pruning_interval') * 86400;
+        $oAccountQuery = BxDolAccountQuery::getInstance();
+        $aAccounts = [];
+        $aAccountsSuspend = [];
+        $bSuspend = false;
+        $aPruning = explode(',', getParam('sys_account_accounts_pruning'));
+        foreach ($aPruning as $sPruning) {
+            switch($sPruning) {
+                 case 'no_login_suspend':
+                    $aAccountsSuspend = $oAccountQuery->getAccountsForPruning('no_login', $iTime);   
+                    break;  
+
+                case 'no_login_delete':
+                    $aAccounts = array_merge($aAccounts, $oAccountQuery->getAccountsForPruning('no_login', $iTime));   
+                    break;
+
+
+
+                case 'no_confirm_delete':
+                    $aAccounts1 = $oAccountQuery->getAccountsForPruning('no_confirm', $iTime);
+                    foreach ($aAccounts1 as $k => $aAccount) {
+                        $oAccount = BxDolAccount::getInstance($aAccount['id']);
+                        if($oAccount->isConfirmed()){
+                            unset($aAccounts1[$k]);
+                        }
+                    }
+                    $aAccounts = array_merge($aAccounts, $aAccounts1);   
+                    break;
+
+                case 'no_profile_delete':
+                    $aAccounts = array_merge($aAccounts, $aAccounts = $oAccountQuery->getAccountsForPruning('no_profile', $iTime));
+                    break;
+            }
+        }
+        
+        foreach ($aAccountsSuspend as $k => $aAccount) {
+            $oAccount = BxDolAccount::getInstance($aAccount['id']);
+            $oProfile = BxDolProfile::getInstanceAccountProfile($aAccount['id']);
+            $oProfile->suspend(BX_PROFILE_ACTION_AUTO, 0 ,false);
+            $aProfiles = $oAccount->getProfiles();
+            foreach($aProfiles as $aProfile){
+                BxDolProfile::getInstance($aProfile['id'])->suspend(BX_PROFILE_ACTION_AUTO, 0 ,false);
+            }
+            $iCount++;
+        }
+
+        
+        foreach ($aAccounts as $k => $aAccount) {
+            $oAccount = BxDolAccount::getInstance($aAccount['id']);
+            $oAccount->delete(false);
+            $iCount++;
+        }
+
+        return $iCount;
+    }
+
+    protected function _getImageUrl($sSize, $mixedData)
+    {
+        if(!is_array($mixedData))
+            $mixedData = $this->getInfo((int)$mixedData);
+
+        $sImageUrl = '';
+        if(!empty($mixedData[$this->_sImageField]) && !empty($this->_aImageTranscoders[$sSize]) && ($oImagesTranscoder = BxDolTranscoderImage::getObjectInstance($this->_aImageTranscoders[$sSize])) !== false)
+            $sImageUrl = $oImagesTranscoder->getFileUrl($mixedData[$this->_sImageField]);
+
+        return $sImageUrl;
+    }
+}
+
+/** @} */

+ 2684 - 0
upgrade/files/15.0.0.B3-15.0.0.RC1/files/inc/classes/BxDolCmts.php

@@ -0,0 +1,2684 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    UnaCore UNA Core
+ * @{
+ */
+
+bx_import('BxDolAcl');
+bx_import('BxDolPrivacy');
+
+define('BX_DOL_CMT_TYPE_COMMENTS', 'comments');
+define('BX_DOL_CMT_TYPE_REVIEWS', 'reviews');
+
+define('BX_CMT_OLD_VOTES', 365*86400); ///< comment votes older than this number of seconds will be deleted automatically
+
+define('BX_CMT_ACTION_POST', 'post');
+define('BX_CMT_ACTION_EDIT', 'edit');
+
+define('BX_CMT_DISPLAY_FLAT', 'flat');
+define('BX_CMT_DISPLAY_THREADED', 'threaded');
+
+define('BX_CMT_BROWSE_HEAD', 'head');
+define('BX_CMT_BROWSE_TAIL', 'tail');
+define('BX_CMT_BROWSE_POPULAR', 'popular');
+define('BX_CMT_BROWSE_CONNECTION', 'connection');
+
+define('BX_CMT_ORDER_BY_DATE', 'date');
+define('BX_CMT_ORDER_BY_POPULAR', 'popular');
+
+define('BX_CMT_FILTER_ALL', 'all');
+define('BX_CMT_FILTER_OTHERS', 'others');
+define('BX_CMT_FILTER_FRIENDS', 'friends');
+define('BX_CMT_FILTER_SUBSCRIPTIONS', 'subscriptions');
+define('BX_CMT_FILTER_PINNED', 'pinned');
+
+define('BX_CMT_ORDER_WAY_ASC', 'asc');
+define('BX_CMT_ORDER_WAY_DESC', 'desc');
+
+define('BX_CMT_PFP_TOP', 'top');
+define('BX_CMT_PFP_BOTTOM', 'bottom');
+
+define('BX_CMT_RATE_VALUE_PLUS', 1);
+define('BX_CMT_RATE_VALUE_MINUS', -1);
+
+define('BX_CMT_USAGE_BLOCK', 'block');
+define('BX_CMT_USAGE_INLINE', 'inline');
+define('BX_CMT_USAGE_DEFAULT', BX_CMT_USAGE_BLOCK);
+
+define('BX_CMT_STATUS_ACTIVE', 'active');
+define('BX_CMT_STATUS_HIDDEN', 'hidden');
+define('BX_CMT_STATUS_PENDING', 'pending');
+
+
+/**
+ * Comments for any content
+ *
+ * Related classes:
+ * - BxDolCmtsQuery - comments database queries
+ * - BxBaseCmts - comments base representation
+ * - BxTemplCmts - custom template representation
+ *
+ * AJAX comments for any content.
+ * Self moderated - users rate all comments, and if comment is
+ * below viewing treshold it is hidden by default.
+ *
+ * To add comments section to your module you need to add a record to 'sys_objects_cmts' table:
+ *
+ * - ID - autoincremented id for internal usage
+ * - ObjectName - your unique module name, with vendor prefix, lowercase and spaces are underscored
+ * - TableCmts - table name where comments are stored
+ * - Html - 0 - convert new lines to <br /> on saving, 1 - standard(default) visual editor, 2 - full visual editor, 3 - mini visual editor.
+ * - PerView - number of comments on a page
+ * - IsRatable - 0 or 1 allow to rate comments or not
+ * - ViewingThreshold - comment viewing treshost, if comment is below this number it is hidden by default
+ * - IsOn - is this comment object enabled
+ * - RootStylePrefix - toot comments style prefix, if you need root comments look different\
+ * - ObjectVote - Vote object name to process comments' votes. May be empty if Comment Vote is not needed.
+ * - TriggerTable - table to be updated upon each comment
+ * - TriggerFieldId - TriggerTable table field with unique record id of
+ * - TriggerFieldComments - TriggerTable table field with comments count, it will be updated automatically upon eaech comment
+ * - ClassName - your custom class name if you need to override default class, this class must have the same constructor arguments
+ * - ClassFile - file where your ClassName is stored.
+ *
+ * You can refer to BoonEx modules for sample record in this table.
+ *
+ *
+ *
+ * @section example Example of usage:
+ * After filling in the table you can show comments section in any place, using the following code:
+ *
+ * @code
+ * $o = new BxTemplCmts('value of ObjectName field', $iYourEntryId);
+ * if ($o->isEnabled())
+ *     echo $o->getCommentsBlock ();
+ * @endcode
+ *
+ * Please note that you never need to use BxDolCmts class directly, use BxTemplCmts instead.
+ * Also if you override comments class with your own then make it child of BxTemplCmts class.
+ *
+ *
+ *
+ * @section acl Memberships/ACL:
+ * - comments post
+ * - comments edit own
+ * - comments remove own
+ * - comments edit all
+ *
+ *
+ *
+ * @section alerts Alerts:
+ * Alerts type/unit - every module has own type/unit, it equals to ObjectName.
+ *
+ * The following alerts are rised
+ *
+ * - commentPost - comment was posted
+ *      - $iObjectId - entry id
+ *      - $iSenderId - author of comment
+ *      - $aExtra['comment_id'] - just added comment id
+ *
+ * - commentRemoved - comments was removed
+ *      - $iObjectId - entry id
+ *      - $iSenderId - comment deleter id
+ *      - $aExtra['comment_id'] - removed comment id
+ *
+ * - commentUpdated - comments was updated
+ *      - $iObjectId - entry id
+ *      - $iSenderId - comment deleter id
+ *      - $aExtra['comment_id'] - updated comment id
+ *
+ * - commentRated - comments was rated
+ *      - $iObjectId - entry id
+ *      - $iSenderId - comment rater id
+ *      - $aExtra['comment_id'] - rated comment id
+ *      - $aExtra['rate'] - comment rate 1 or -1
+ *
+ */
+class BxDolCmts extends BxDolFactory implements iBxDolReplaceable, iBxDolContentInfoService
+{
+    /**
+     * System tables which are UNITED for all 
+     * comment systems and cannot be overwritten.
+     */
+    public static $sTableSystems = 'sys_objects_cmts';
+    public static $sTableIds = 'sys_cmts_ids';
+
+    /**
+     * System tables which are used by default and
+     * can be overwritten in comment systems.
+     * @see BxDolCmts::getTableNameImages and BxDolCmts::getTableNameImages2Entries
+     */
+    protected $_sTableImages = 'sys_cmts_images';
+    protected $_sTableImages2Entries = 'sys_cmts_images2entries';
+
+    protected $_aElementDefaults;
+    protected $_aElementDefaultsApi;
+    protected $_aElementParamsApi; //--- Params from DefaultsApi array to be passed to Api
+
+    protected $_bIsApi;
+
+    protected $_sType;
+    protected $_oQuery = null;
+    protected $_oTemplate = null;
+
+    protected $_bPostQuote;
+    protected $_bMinPostForm;
+    protected $_sFormObject;
+    protected $_sFormDisplayPost;
+    protected $_sFormDisplayEdit;
+
+    protected $_sConnObjFriends;
+    protected $_sConnObjSubscriptions;
+
+    protected $_sMenuObjManage;
+    protected $_sMenuObjActions;
+    protected $_sMenuObjCounters;
+    protected $_sMenuObjMeta;
+
+    protected $_sMetatagsObj;
+
+    protected $_sViewUrl = '';
+    protected $_sBaseUrl = '';
+    protected $_sListAnchor = '';
+    protected $_sItemAnchor = '';
+    protected $_sItemAnchorApi = '';
+
+    protected $_aSystems = [];
+
+    protected $_sSystem = 'profile'; ///< current comment system name
+    protected $_aSystem = []; ///< current comments system array
+    protected $_iId = 0; ///< obect id to be commented
+    protected $_iAuthorId = 0; ///< currently logged in user who browse, post, etc.
+
+    protected $_aParams = [];
+    protected $_aT = []; ///< an array of lang keys
+    protected $_aMarkers = [];
+
+    protected $_sDisplayType = '';
+    protected $_sDpSessionKey = '';
+    protected $_iDpMaxLevel = 0;
+
+    protected $_sBrowseType = '';
+    protected $_bBrowseFilter = false;
+    protected $_sBrowseFilter = '';
+    protected $_sBpSessionKeyType = '';
+    protected $_sBpSessionKeyFilter = '';
+    protected $_aOrder = array();
+
+    protected $_sSnippetLenthLiveSearch = 50;
+
+    protected $_iRememberTime = 2592000;
+
+    protected $_bLiveUpdates = true;
+
+    /**
+     * Constructor
+     * $sSystem - comments system name
+     * $iId - obect id to be commented
+     */
+    protected function __construct($sSystem, $iId, $iInit = true, $oTemplate = false)
+    {
+        parent::__construct();
+
+        $this->_bIsApi = bx_is_api();
+
+        $this->_sType = BX_DOL_CMT_TYPE_COMMENTS;
+
+        $this->_aSystems = $this->getSystems();
+        if(!isset($this->_aSystems[$sSystem]))
+            return;
+
+        $this->_sSystem = $sSystem;
+        $this->_aSystem = $this->_aSystems[$sSystem];
+        $this->_aSystem['is_browse_filter'] = (int)$this->_bBrowseFilter;
+
+        $this->_iAuthorId = $this->_getAuthorId();
+
+        $this->_iDpMaxLevel = (int)$this->_aSystem['number_of_levels'];
+        $this->_sDisplayType = $this->_iDpMaxLevel == 0 ? BX_CMT_DISPLAY_FLAT : BX_CMT_DISPLAY_THREADED;
+        $this->_sDpSessionKey = 'bx_' . $this->_sSystem . '_dp_';
+
+        $this->_sBrowseType = $this->_aSystem['browse_type'];
+        $this->_sBrowseFilter = BX_CMT_FILTER_ALL;
+        $this->_sBpSessionKeyType = 'bx_' . $this->_sSystem . '_bpt_';
+        $this->_sBpSessionKeyFilter = 'bx_' . $this->_sSystem . '_bpf_';
+        $this->_aOrder = array(
+            'by' => BX_CMT_ORDER_BY_DATE,
+            'way' => BX_CMT_ORDER_WAY_ASC
+        );
+
+        list($mixedUserDp, $mixedUserBpType, $mixedUserBpFilter) = $this->_getUserChoice();
+        if(!empty($mixedUserDp))
+            $this->_sDisplayType = $mixedUserDp;
+        if(!empty($mixedUserBpType))
+            $this->_sBrowseType = $mixedUserBpType;
+        if(!empty($mixedUserBpFilter))
+            $this->_sBrowseFilter = $mixedUserBpFilter;
+
+        $this->_sViewUrl = 'page.php?i=cmts-view';
+        $this->_sBaseUrl = $this->_aSystem['base_url'];
+
+        $this->_sListAnchor = "cmts-anchor-%s-%d";
+        $this->_sItemAnchor = "cmt-anchor-%s-%d-%d";
+        $this->_sItemAnchorApi = "cid=%d";
+
+        $this->_oQuery = new BxDolCmtsQuery($this);
+
+        $this->_bPostQuote = false;
+        $this->_bMinPostForm = true;
+        $this->_sFormObject = 'sys_comment';
+        $this->_sFormDisplayPost = 'sys_comment_post';
+        $this->_sFormDisplayEdit = 'sys_comment_edit';
+
+        $this->_sConnObjFriends = 'sys_profiles_friends';
+        $this->_sConnObjSubscriptions = 'sys_profiles_subscriptions';
+
+        $this->_sMenuObjManage = 'sys_cmts_item_manage';
+        $this->_sMenuObjActions = 'sys_cmts_item_actions';
+        $this->_sMenuObjCounters = 'sys_cmts_item_counters';
+        $this->_sMenuObjMeta = 'sys_cmts_item_meta';
+
+        $this->_sMetatagsObj = 'sys_cmts';
+
+        if(($aParams = bx_get('params')) !== false) {
+            if(is_string($aParams))
+                $aParams = json_decode($aParams, true);
+            if(!empty($aParams) && is_array($aParams))
+                $this->_aParams = array_merge($this->_aParams, $aParams);
+        }
+
+        $this->_aT = [
+            'block_comments_title' => '_cmt_block_comments_title',
+            'txt_sample_single' => '_cmt_txt_sample_comment_single',
+            'txt_sample_vote_single' => '_cmt_txt_sample_vote_single',
+            'txt_sample_reaction_single' => '_cmt_txt_sample_reaction_single',
+            'txt_sample_score_up_single' => '_cmt_txt_sample_score_up_single',
+            'txt_sample_score_down_single' => '_cmt_txt_sample_score_down_single',
+            'txt_min_form_placeholder' => '_cmt_txt_min_form_placeholder'
+        ];
+
+        if ($iInit)
+            $this->init($iId);
+
+        if ($oTemplate)
+            $this->_oTemplate = $oTemplate;
+        else
+            $this->_oTemplate = BxDolTemplate::getInstance();
+    }
+
+    /**
+     * get comments object instanse
+     * @param $sSys comments object name
+     * @param $iId associated content id, where comments are postred in
+     * @param $iInit perform initialization
+     * @return null on error, or ready to use class instance
+     */
+    public static function getObjectInstance($sSys, $iId, $iInit = true, $oTemplate = false)
+    {
+        if(isset($GLOBALS['bxDolClasses']['BxDolCmts!' . $sSys . $iId]))
+            return $GLOBALS['bxDolClasses']['BxDolCmts!' . $sSys . $iId];
+
+        $aSystems = self::getSystems();
+        if (!isset($aSystems[$sSys]))
+            return null;
+
+        $sClassName = 'BxTemplCmts';
+        if(!empty($aSystems[$sSys]['class_name'])) {
+            $sClassName = $aSystems[$sSys]['class_name'];
+            if(!empty($aSystems[$sSys]['class_file']))
+                require_once(BX_DIRECTORY_PATH_ROOT . $aSystems[$sSys]['class_file']);
+        }
+
+        $o = new $sClassName($sSys, $iId, $iInit, $oTemplate);
+        return ($GLOBALS['bxDolClasses']['BxDolCmts!' . $sSys . $iId] = $o);
+    }
+    
+    /**
+     * get comments object instanse
+     * @param $iUniqId unique comment id
+     * @return null on error, or ready to use class instance
+     */
+    public static function getObjectInstanceByUniqId($iUniqId, $iInit = true, $oTemplate = false)
+    {
+        $aData = BxDolCmtsQuery::getInfoByUniqId($iUniqId);
+        if(empty($aData) || !is_array($aData))
+            return null;
+
+        return self::getObjectInstance($aData['system_name'], $aData['cmt_object_id']);
+    }
+
+    public static function &getSystems ()
+    {
+        $sKey = 'bx_dol_cache_memory_cmts_systems';
+
+        if (!isset($GLOBALS[$sKey])) {
+            $GLOBALS[$sKey] = BxDolDb::getInstance()->fromCache('sys_objects_cmts', 'getAllWithKey', '
+                SELECT
+                    `ID` as `system_id`,
+                    `Name` AS `name`,
+                    `Module` AS `module`,
+                    `Table` AS `table`,
+                    `CharsPostMin` AS `chars_post_min`,
+                    `CharsPostMax` AS `chars_post_max`,
+                    `CharsDisplayMax` AS `chars_display_max`,
+                    `Html` AS `html`,
+                    `PerView` AS `per_view`,
+                    `PerViewReplies` AS `per_view_replies`,
+                    `BrowseType` AS `browse_type`,
+                    `IsBrowseSwitch` AS `is_browse_switch`,
+                    `PostFormPosition` AS `post_form_position`,
+                    `NumberOfLevels` AS `number_of_levels`,
+                    `IsDisplaySwitch` AS `is_display_switch`,
+                    `IsRatable` AS `is_ratable`,
+                    `ViewingThreshold` AS `viewing_threshold`,
+                    `IsOn` AS `is_on`,
+                    `RootStylePrefix` AS `root_style_prefix`,
+                    `BaseUrl` AS `base_url`,
+                    `ObjectVote` AS `object_vote`,
+                    `ObjectReaction` AS `object_reaction`,
+                    `ObjectScore` AS `object_score`,
+                    `ObjectReport` AS `object_report`,
+                    `TriggerTable` AS `trigger_table`,
+                    `TriggerFieldId` AS `trigger_field_id`,
+                    `TriggerFieldAuthor` AS `trigger_field_author`,
+                    `TriggerFieldTitle` AS `trigger_field_title`,
+                    `TriggerFieldComments` AS `trigger_field_comments`,
+                    `ClassName` AS `class_name`,
+                    `ClassFile` AS `class_file`
+                FROM `' . self::$sTableSystems . '`', 'name');
+        }
+        return $GLOBALS[$sKey];
+    }
+
+    public static function getGlobalInfo ($iUniqueId)
+    {
+        return BxDolDb::getInstance()->getRow("SELECT `ti`.*, `ts`.`Name` AS `system_name` FROM `" . self::$sTableIds . "` AS `ti` LEFT JOIN `" . self::$sTableSystems . "` AS `ts` ON `ti`.`system_id`=`ts`.`ID` WHERE `ti`.`id`=:id LIMIT 1", array(
+            'id' => (int)$iUniqueId
+        ));
+    }
+
+    public static function getGlobalNumByParams($aParams = [])
+    {
+        $sQuery = "SELECT COUNT(*) FROM `" . self::$sTableIds . "` WHERE 1";
+        foreach($aParams as $aValue)
+            $sQuery .= " AND `" . $aValue['key'] ."` " . $aValue['operator'] . " '" . $aValue['value'] . "'";
+
+        return BxDolDb::getInstance()->getOne($sQuery);
+    }
+
+    public function init ($iId)
+    {
+        if (empty($this->iId) && $iId)
+            $this->setId($iId);
+
+        $this->addMarkers(array(
+            'object_id' => $this->getId(),
+            'user_id' => $this->_getAuthorId()
+        ));
+    }
+
+    public function setParam($sName, $sValue)
+    {
+        $this->_aParams[$sName] = $sValue;
+    }
+
+    public function isParam($sName)
+    {
+        return isset($this->_aParams[$sName]);
+    }
+
+    public function getParam($sName)
+    {
+        return $this->_aParams[$sName];
+    }
+
+    public function getId ()
+    {
+        return $this->_iId;
+    }
+
+    public function isEnabled ()
+    {
+        return isset($this->_aSystem['is_on']) && $this->_aSystem['is_on'];
+    }
+
+    public function getSystemId()
+    {
+        return $this->_aSystem['system_id'];
+    }
+
+    public function getSystemName()
+    {
+        return $this->_sSystem;
+    }
+
+    public function getSystemInfo()
+    {
+        return $this->_aSystem;
+    }
+
+    public function getModule()
+    {
+        return $this->_aSystem['module'];
+    }
+
+    public function getStorageObjectName()
+    {
+    	return $this->_getFormObject()->getStorageObjectName();
+    }
+
+    public function getTranscoderPreviewName()
+    {
+    	return $this->_getFormObject()->getTranscoderPreviewName();
+    }
+    
+    public function getFormObject()
+    {
+    	return $this->_getFormObject();
+    }
+
+    public function getTableNameImages()
+    {
+        return $this->_sTableImages;
+    }
+
+    public function getTableNameImages2Entries()
+    {
+        return $this->_sTableImages2Entries;
+    }
+
+    public function getLanguageKey($sIndex)
+    {
+        return isset($this->_aT[$sIndex]) ? $this->_aT[$sIndex] : '';
+    }
+
+    public function getMaxLevel()
+    {
+        return $this->_iDpMaxLevel;
+    }
+
+    public function getOrder ()
+    {
+        return $this->_sOrder;
+    }
+
+    public function getPerView ($iCmtParentId = 0)
+    {
+        return $iCmtParentId == 0 ? $this->_aSystem['per_view'] : $this->_aSystem['per_view_replies'];
+    }
+
+    public function getStatusAdmin()
+    {
+        return $this->isEditAllowedAll() || $this->isRemoveAllowedAll() || $this->isAutoApprove() ? BX_CMT_STATUS_ACTIVE : BX_CMT_STATUS_PENDING;
+    }
+
+    public function getViewUrl($iCmtId, $bAbsolute = true)
+    {
+    	if(empty($this->_aSystem['trigger_field_title']))
+            return '';
+
+        $s = BxDolPermalinks::getInstance()->permalink($this->_sViewUrl, [
+            'sys' => $this->_sSystem,
+            'id' => $this->_iId,
+            'cmt_id' => $iCmtId
+        ]);
+
+    	return $bAbsolute ? bx_absolute_url($s) : $s;
+    }
+
+    public function getViewText($mixedItem)
+    {
+        if(!is_array($mixedItem))
+            $mixedItem = $this->getCommentSimple((int)$mixedItem);
+
+        if(empty($mixedItem) || !is_array($mixedItem))
+            return '';
+
+        return $this->_prepareTextForOutput($mixedItem['cmt_text'], (int)$mixedItem['cmt_id']);
+    }
+
+    public function getViewSnippet($mixedItem, $sMaxLength = 20)
+    {
+        if(!is_array($mixedItem))
+            $mixedItem = $this->getCommentSimple((int)$mixedItem);
+
+        if(empty($mixedItem) || !is_array($mixedItem))
+            return '';
+
+        $sResult = bx_process_output(strip_tags($mixedItem['cmt_text']), BX_DATA_TEXT);
+        if(mb_strlen($sResult) > $sMaxLength)
+            $sResult = strmaxtextlen($sResult, $sMaxLength, '...');
+
+        return $sResult;
+    }
+
+    public function getBaseUrl($sPrefix = BX_DOL_URL_ROOT)
+    {
+        $sUrl = $this->_replaceMarkers($this->_sBaseUrl);
+        $sUrl = BxDolPermalinks::getInstance()->permalink($sUrl);
+        return bx_absolute_url($sUrl, $sPrefix);
+    }
+
+    public function getListUrl($sPrefix = BX_DOL_URL_ROOT)
+    {
+        $sBaseUrl = $this->getBaseUrl($sPrefix);
+        if(empty($sBaseUrl))
+            return '';
+
+        return $sBaseUrl . $this->getListAnchor(true);
+    }
+
+    /**
+     * Get URL for view commented content page with anchor to the coment. 
+     * @param integer $iItemId - comment ID.
+     * @param string $sPrefix - URL prefix.
+     * @return string with URL.
+     */
+    public function getItemUrl($iItemId, $sPrefix = BX_DOL_URL_ROOT)
+    {
+        $sBaseUrl = $this->getBaseUrl($sPrefix);
+        if(empty($sBaseUrl))
+            return '';
+
+        return $sBaseUrl . $this->getItemAnchor($iItemId, true);
+    }
+
+    public function getItemUrlApi($iItemId, $sPrefix = BX_DOL_URL_ROOT)
+    {
+        $sBaseUrl = $this->getBaseUrl($sPrefix);
+        if(empty($sBaseUrl))
+            return '';
+
+        return $sBaseUrl . $this->getItemAnchorApi($iItemId, true);
+    }
+
+    public function getListAnchor($bWithHash = false)
+    {
+        return ($bWithHash ? '#' : '') . sprintf($this->_sListAnchor, str_replace('_', '-', $this->getSystemName()), $this->getId());
+    }
+
+    public function getItemAnchor($iItemId, $bWithHash = false)
+    {
+        return ($bWithHash ? '#' : '') . sprintf($this->_sItemAnchor, str_replace('_', '-', $this->getSystemName()), $this->getId(), $iItemId);
+    }
+
+    public function getItemAnchorApi($iItemId, $bWithHash = false)
+    {
+        return ($bWithHash ? '#' : '') . sprintf($this->_sItemAnchorApi, $iItemId);
+    }
+
+    public function geModalViewApi()
+    {
+        return 'default';
+    }
+
+    public function getAttachments($iCmtId)
+    {
+        $aResult = array();
+
+        if(!$this->isAttachImageEnabled())
+            return $aResult; 
+
+        $aFiles = $this->_oQuery->getFiles($this->_aSystem['system_id'], $iCmtId);
+        if(empty($aFiles) || !is_array($aFiles)) 
+            return $aResult;
+
+        $oStorage = BxDolStorage::getObjectInstance($this->getStorageObjectName());
+        $oTranscoder = BxDolTranscoderImage::getObjectInstance($this->getTranscoderPreviewName());
+
+        foreach($aFiles as $aFile) {
+            $bImage = $oTranscoder && $oTranscoder->isMimeTypeSupported($aFile['mime_type']);
+
+            $sPreview = '';
+            if($bImage)
+                $sPreview = $oTranscoder->getFileUrl($aFile['image_id']);
+
+            if(!$sPreview)
+                $sPreview = $this->_oTemplate->getIconUrl($oStorage->getIconNameByFileName($aFile['file_name']));
+
+            $sUrl = $oStorage->getFileUrlById($aFile['image_id']);
+
+            $aResult[] = array(
+                'id' => $aFile['image_id'],
+                'src' => $sPreview,
+                'src_orig' => $bImage ? $sUrl : '',
+                'url' => !$bImage ? $sUrl : ''
+            );
+        }
+
+        return $aResult;
+    }
+
+    public function getConnectionObject($sType)
+    {
+        $sResult = '';
+
+        switch($sType) {
+            case BX_CMT_FILTER_FRIENDS:
+                $sResult = $this->_sConnObjFriends;
+                break;
+            case BX_CMT_FILTER_SUBSCRIPTIONS:
+                $sResult = $this->_sConnObjSubscriptions;
+                break;
+        }
+
+        return $sResult;
+    }
+
+    public function getVoteObject($iEniqId)
+    {
+        if(empty($this->_aSystem['object_vote']))
+            $this->_aSystem['object_vote'] = 'sys_cmts';
+
+        $oVote = BxDolVote::getObjectInstance($this->_aSystem['object_vote'], $iEniqId, true, $this->_oTemplate);
+        if(!$oVote || !$oVote->isEnabled())
+            return false;
+
+        return $oVote;
+    }
+
+    public function getReactionObject($iEniqId)
+    {
+        if(empty($this->_aSystem['object_reaction']))
+            $this->_aSystem['object_reaction'] = 'sys_cmts_reactions';
+
+        $oReaction = BxDolVote::getObjectInstance($this->_aSystem['object_reaction'], $iEniqId, true, $this->_oTemplate);
+        if(!$oReaction || !$oReaction->isEnabled())
+            return false;
+
+        return $oReaction;
+    }
+
+    public function getScoreObject($iEniqId)
+    {
+        if(empty($this->_aSystem['object_score']))
+            $this->_aSystem['object_score'] = 'sys_cmts';
+
+        $oScore = BxDolScore::getObjectInstance($this->_aSystem['object_score'], $iEniqId, true, $this->_oTemplate);
+        if(!$oScore || !$oScore->isEnabled())
+            return false;
+
+        return $oScore;
+    }
+
+    public function getReportObject($iEniqId)
+    {
+        if(empty($this->_aSystem['object_report']))
+            $this->_aSystem['object_report'] = 'sys_cmts';
+
+        $oReport = BxDolReport::getObjectInstance($this->_aSystem['object_report'], $iEniqId, true, $this->_oTemplate);
+        if(!$oReport || !$oReport->isEnabled())
+            return false;
+
+        return $oReport;
+    }
+
+    /**
+     * Is used as: 
+     * 1. Live Update's session key.
+     * 2. HTML ID for Live Update's 'New Content' button.
+     * @return string with ID.
+     */
+    public function getNotificationId()
+    {
+        return 'cmts-notification-' . $this->_sSystem . '-' . $this->_iId;
+    }
+
+    public function getSocketName()
+    {
+        return 'cmts_' . $this->_sSystem;
+    }
+
+    /**
+     * @deprecated since version 10.0.0-B3 and can be removed in later versions.
+     */
+    public function setTableNameFiles($sTable)
+    {
+        $this->_sTableImages = $sTable;
+    	$this->_oQuery->setTableNameFiles($sTable);
+    }
+
+    /**
+     * @deprecated since version 10.0.0-B3 and can be removed in later versions.
+     */
+    public function setTableNameFiles2Entries($sTable)
+    {
+    	$this->_sTableImages2Entries = $sTable;
+    	$this->_oQuery->setTableNameFiles2Entries($sTable);
+    }
+
+    public function isHtml ()
+    {
+        return $this->_aSystem['html'] > 0;
+    }
+
+    public function isRatable ()
+    {
+        return $this->_aSystem['is_ratable'];
+    }
+
+    public function isAttachImageEnabled()
+    {
+        return true;
+    }
+
+    public function isAutoApprove()
+    {
+        return getParam('sys_cmts_enable_auto_approve') == 'on';
+    }
+
+    /**
+     * set id to operate with votes
+     */
+    public function setId ($iId)
+    {
+        if ($iId == $this->getId()) return;
+        $this->_iId = $iId;
+    }
+
+    /**
+     * Add replace markers.
+     * @param $a array of markers as key => value
+     * @return true on success or false on error
+     */
+    public function addMarkers ($a)
+    {
+        if (empty($a) || !is_array($a))
+            return false;
+        $this->_aMarkers = array_merge ($this->_aMarkers, $a);
+        return true;
+    }
+
+    /**
+     * Database functions
+     */
+    public function getQueryObject ()
+    {
+        return $this->_oQuery;
+    }
+
+    public function getCommentsTableName ()
+    {
+        return $this->_oQuery->getTableName ();
+    }
+
+    public function getObjectAuthorId ($iObjectId = 0)
+    {
+    	if(empty($this->_aSystem['trigger_field_author']))
+    		return 0;
+
+        return $this->_oQuery->getObjectAuthorId ($iObjectId ? $iObjectId : $this->getId());
+    }
+
+    public function getObjectTitle ($iObjectId = 0)
+    {
+        if(empty($this->_aSystem['trigger_field_title']))
+            return '';
+
+        $sTitle = $this->_oQuery->getObjectTitle ($iObjectId ? $iObjectId : $this->getId());
+        if(get_mb_substr($sTitle, 0, 1) == '_')
+            $sTitle = _t($sTitle);
+
+        return $sTitle;
+    }
+    
+    public function getObjectPrivacyView ($iObjectId = 0)
+    {
+        if(empty($iObjectId))
+            $iObjectId = $this->getId();
+
+        $sFieldPrivacyView = '';
+        if(!empty($this->_aSystem['trigger_field_privacy_view']))
+            $sFieldPrivacyView = $this->_aSystem['trigger_field_privacy_view'];
+
+        if(($iPrivacyView = $this->_oQuery->getObjectPrivacyView($iObjectId, $sFieldPrivacyView)) !== false)
+            return $iPrivacyView;
+
+        return BX_DOL_PG_ALL;
+    }
+
+    /*
+     * Gets Content Filter object.
+     */
+    public function getObjectContentFilter ()
+    {
+        $oCf = BxDolContentFilter::getInstance();
+        if(!$oCf->isEnabledForComments())
+            return false;
+
+        return $oCf;
+    }
+
+    public function getCommentsCountAll ($iObjectId = 0, $bForceCalculate = false)
+    {
+        return $this->_oQuery->getCommentsCountAll ($iObjectId ? $iObjectId : $this->getId(), $this->_getAuthorId(), $bForceCalculate);
+    }
+
+    public function getCommentsCount ($iObjectId = 0, $iCmtVParentId = -1, $sFilter = '')
+    {
+        return $this->_oQuery->getCommentsCount ($iObjectId ? $iObjectId : $this->getId(), $iCmtVParentId, $this->_getAuthorId(), $sFilter);
+    }
+
+    public function getCommentsArray ($iVParentId, $sFilter, $aOrder, $iStart = 0, $iCount = -1)
+    {
+        return $this->_oQuery->getComments ($this->getId(), $iVParentId, $this->_getAuthorId(), $sFilter, $aOrder, $iStart, $iCount);
+    }
+
+    public function getCommentsBy ($aParams = [])
+    {
+        return $this->_oQuery->getCommentsBy($aParams); 
+    }
+
+    /**
+     * Get comment's unique id.
+     */
+    public function getCommentUniqId($iCmtId, $iAuthorId = 0)
+    {
+        return $this->_oQuery->getUniqId($this->getSystemId(), $iCmtId, ['author_id' => $iAuthorId]);
+    }
+
+    /**
+     * Get comment's short info.
+     */
+    public function getCommentSimple ($iCmtId)
+    {
+        return $this->_oQuery->getCommentSimple ($this->getId(), $iCmtId);
+    }
+
+    /**
+     * Get comment's full info.
+     */
+    public function getCommentRow ($iCmtId)
+    {
+        return $this->_oQuery->getComment ($this->getId(), $iCmtId);
+    }
+
+    public function getCommentParents ($mixedCmt, $iDepthMax = 0)
+    {
+        if(!is_array($mixedCmt))
+            $mixedCmt = $this->_oQuery->getCommentsBy(['type' => 'id', 'id' => (int)$mixedCmt]);
+
+        $iDepth = 0;
+        $aParents = [];
+        $this->_getParents($mixedCmt, $iDepthMax, $iDepth, $aParents);
+
+        return $aParents;
+    }
+
+    public function onObjectDelete ($iObjectId = 0)
+    {
+        // delete comments
+        $aFiles = $aCmtIds = [];
+        $this->_oQuery->deleteObjectComments ($iObjectId ? $iObjectId : $this->getId(), $aFiles, $aCmtIds);
+
+        // delete votes
+        $this->deleteVotes($aCmtIds);
+
+        // delete reactions
+        $this->deleteReactions($aCmtIds);
+
+        // delete scores
+        $this->deleteScores($aCmtIds);
+
+        // delete reports
+        $this->deleteReports($aCmtIds);
+
+        // delete meta info
+        $this->deleteMetaInfo($aCmtIds);
+
+        // delete files
+        if ($aFiles) {
+            $oStorage = BxDolStorage::getObjectInstance($this->getStorageObjectName());
+            if ($oStorage)
+                $oStorage->queueFilesForDeletion($aFiles);
+        }
+
+        // delete unique IDs
+        $this->deleteUniqueIds($aCmtIds);
+    }
+
+    public static function onAuthorDelete ($iAuthorId)
+    {
+        $aSystems = self::getSystems();
+        foreach($aSystems as $sSystem => $aSystem) {
+            $o = self::getObjectInstance($sSystem, 0);
+            $oQuery = $o->getQueryObject();
+
+            // delete comments
+            $aFiles = $aCmtIds = array ();
+            $oQuery->deleteAuthorComments($iAuthorId, $aFiles, $aCmtIds);
+
+            // delete votes
+            $o->deleteVotes($aCmtIds);
+
+            // delete reactions
+            $o->deleteReactions($aCmtIds);
+
+            // delete scores
+            $o->deleteScores($aCmtIds);
+
+            // delete reports
+            $o->deleteReports($aCmtIds);
+
+            // delete meta info
+            $o->deleteMetaInfo($aCmtIds);
+    
+            // delete files
+            $oStorage = BxDolStorage::getObjectInstance($o->getStorageObjectName());
+            if ($oStorage)
+                $oStorage->queueFilesForDeletion($aFiles);
+            
+            // delete unique IDs
+            $o->deleteUniqueIds($aCmtIds);
+        }
+        return true;
+    }
+
+    public static function onModuleEnable ($sModuleName)
+    {
+        $aSystems = self::getSystems();
+        foreach($aSystems as $sSystem => $aSystem) {
+            if ($sModuleName !== $aSystem['module'])
+                continue;
+
+            $o = self::getObjectInstance($sSystem, 0);
+            $o->registerTranscoders();
+        }
+
+        return true;
+    }
+
+    public static function onModuleDisable ($sModuleName)
+    {
+        $aSystems = self::getSystems();
+        foreach($aSystems as $sSystem => $aSystem) {
+            if ($sModuleName !== $aSystem['module'])
+                continue;
+
+            $o = self::getObjectInstance($sSystem, 0);
+            $o->unregisterTranscoders();
+        }
+
+        return true;
+    }
+
+    public static function onModuleUninstall ($sModuleName, &$iFiles = null)
+    {
+        $aSystems = self::getSystems();
+        foreach($aSystems as $sSystem => $aSystem) {
+            if ($sModuleName !== $aSystem['module'])
+                continue;
+
+            $o = self::getObjectInstance($sSystem, 0);
+            $oQuery = $o->getQueryObject();
+
+            // delete comments
+            $aFiles = $aCmtIds = array ();
+            $oQuery->deleteAll($aSystem['system_id'], $aFiles, $aCmtIds);
+
+            // delete votes
+            $o->deleteVotes($aCmtIds);
+
+            // delete reactions
+            $o->deleteReactions($aCmtIds);
+
+            // delete scores
+            $o->deleteScores($aCmtIds);
+
+            // delete reports
+            $o->deleteReports($aCmtIds);
+
+            // delete meta info
+            $o->deleteMetaInfo($aCmtIds);
+
+            // delete files
+            $oStorage = BxDolStorage::getObjectInstance($o->getStorageObjectName());
+            if ($oStorage && $aFiles)
+                $oStorage->queueFilesForDeletion($aFiles);
+
+            if (null !== $iFiles)
+                $iFiles += count($aFiles);
+
+            // delete unique IDs
+            $o->deleteUniqueIds($aCmtIds);
+        }
+
+        return true;
+    }
+
+    public function deleteVotes ($mixedCmtId)
+    {
+        if(!is_array($mixedCmtId))
+            $mixedCmtId = [$mixedCmtId];
+
+        foreach($mixedCmtId as $iCmtId)
+            if(($oReport = $this->getVoteObject($this->getCommentUniqId($iCmtId))) !== false)
+                $oReport->onObjectDelete();
+    }
+
+    public function deleteReactions ($mixedCmtId)
+    {
+        if(!is_array($mixedCmtId))
+            $mixedCmtId = [$mixedCmtId];
+
+        foreach($mixedCmtId as $iCmtId)
+            if(($oReport = $this->getReactionObject($this->getCommentUniqId($iCmtId))) !== false)
+                $oReport->onObjectDelete();
+    }
+
+    public function deleteScores ($mixedCmtId)
+    {
+        if(!is_array($mixedCmtId))
+            $mixedCmtId = [$mixedCmtId];
+
+        foreach($mixedCmtId as $iCmtId)
+            if(($oReport = $this->getScoreObject($this->getCommentUniqId($iCmtId))) !== false)
+                $oReport->onObjectDelete();
+    }
+
+    public function deleteReports ($mixedCmtId)
+    {
+        if(!is_array($mixedCmtId))
+            $mixedCmtId = [$mixedCmtId];
+
+        foreach($mixedCmtId as $iCmtId)
+            if(($oReport = $this->getReportObject($this->getCommentUniqId($iCmtId))) !== false)
+                $oReport->onObjectDelete();
+    }
+
+    public function deleteMetaInfo ($mixedCmtId)
+    {
+        if(!is_array($mixedCmtId))
+            $mixedCmtId = array($mixedCmtId);
+
+        $oMetatags = false;
+        if(!empty($this->_sMetatagsObj))
+            $oMetatags = BxDolMetatags::getObjectInstance($this->_sMetatagsObj);
+
+        if($oMetatags)
+            foreach($mixedCmtId as $iCmtId)
+                $oMetatags->onDeleteContent($this->getCommentUniqId($iCmtId));
+    }
+
+    public function deleteUniqueIds ($mixedCmtId)
+    {
+        if(!is_array($mixedCmtId))
+            $mixedCmtId = array($mixedCmtId);
+
+        foreach($mixedCmtId as $iCmtId)
+            $this->_oQuery->deleteCmtIds($this->_aSystem['system_id'], $iCmtId);
+    }
+
+    /**
+     * Permissions functions
+     */
+    public function isAdmin($iCmtAuthorId)
+    {
+        return BxDolAcl::getInstance()->isMemberLevelInSet(array(MEMBERSHIP_ID_MODERATOR, MEMBERSHIP_ID_ADMINISTRATOR), $iCmtAuthorId);
+    }
+
+    public function checkAction ($sAction, $isPerformAction = false)
+    {
+        $iId = $this->_getAuthorId();
+        $a = checkActionModule($iId, $sAction, 'system', $isPerformAction);
+        return $a[CHECK_ACTION_RESULT] === CHECK_ACTION_RESULT_ALLOWED;
+    }
+
+    public function checkActionErrorMsg ($sAction)
+    {
+        $iId = $this->_getAuthorId();
+        $a = checkActionModule($iId, $sAction, 'system');
+        return $a[CHECK_ACTION_RESULT] !== CHECK_ACTION_RESULT_ALLOWED ? $a[CHECK_ACTION_MESSAGE] : '';
+    }
+
+    public function isViewAllowed ($isPerformAction = false)
+    {
+        if (BxDolRequest::serviceExists($this->_aSystem['module'], 'check_allowed_comments_view')) {
+            $mixedResult = BxDolService::call($this->_aSystem['module'], 'check_allowed_comments_view', array($this->getId(), $this->getSystemName()));
+            if($mixedResult !== CHECK_ACTION_RESULT_ALLOWED)
+                return $mixedResult;
+        }
+
+        return CHECK_ACTION_RESULT_ALLOWED;
+    }
+
+    public function isVoteAllowed ($aCmt, $isPerformAction = false)
+    {
+        if(!$this->isRatable())
+            return false;
+
+        $oVote = $this->getVoteObject($this->getCommentUniqId($aCmt['cmt_id']));
+        if($oVote === false)
+            return false;
+
+        $iUserId = (int)$this->_getAuthorId();
+        if($iUserId == 0)
+            return false;
+
+        if(isAdmin())
+            return true;
+
+        return $oVote->isAllowedVote($isPerformAction);
+    }
+
+    public function isScoreAllowed ($aCmt, $isPerformAction = false)
+    {
+        if(!$this->isRatable())
+            return false;
+
+        $oScore = $this->getScoreObject($this->getCommentUniqId($aCmt['cmt_id']));
+        if($oScore === false)
+            return false;
+
+        $iUserId = (int)$this->_getAuthorId();
+        if($iUserId == 0)
+            return false;
+
+        if(isAdmin())
+            return true;
+
+        return $oScore->isAllowedVote($isPerformAction);
+    }
+
+    public function isReportAllowed ($aCmt, $isPerformAction = false)
+    {
+        $oReport = $this->getReportObject($aCmt['cmt_id']);
+        if($oReport === false)
+            return false;
+
+        $iUserId = (int)$this->_getAuthorId();
+        if($iUserId == 0)
+            return false;
+
+        if(isAdmin())
+            return true;
+
+        return $oReport->isAllowedReport($isPerformAction);
+    }
+
+    public function isPostAllowed ($isPerformAction = false)
+    {
+        if (BxDolRequest::serviceExists($this->_aSystem['module'], 'check_allowed_comments_post')) {
+            $mixedResult = BxDolService::call($this->_aSystem['module'], 'check_allowed_comments_post', array($this->getId(), $this->getSystemName()));
+            if($mixedResult !== CHECK_ACTION_RESULT_ALLOWED)
+                return false;
+        }
+
+        return $this->checkAction ('comments post', $isPerformAction);
+    }
+
+    public function msgErrPostAllowed ()
+    {
+        return $this->checkActionErrorMsg('comments post');
+    }
+
+    /**
+     * Determines whether a 'reply' action allowed or not.
+     * @param integer or array $mixedCmt - ID or an array which describes the comment to be replied
+     * @param boolean $isPerformAction
+     * @return boolean
+     */
+    public function isReplyAllowed ($mixedCmt, $isPerformAction = false)
+    {
+        return $this->isPostAllowed($isPerformAction);
+    }
+
+    public function msgErrReplyAllowed ()
+    {
+        return $this->msgErrPostAllowed ();
+    }
+
+    public function isQuoteAllowed ($mixedCmt, $isPerformAction = false)
+    {
+        return $this->_bPostQuote && $this->isReplyAllowed ($mixedCmt, $isPerformAction);
+    }
+
+    public function msgErrQuoteAllowed ()
+    {
+        return $this->msgErrReplyAllowed ();
+    }
+
+    public function isPinAllowed ($aCmt, $isPerformAction = false)
+    {
+        if((int)$aCmt['cmt_parent_id'] != 0 || (int)$aCmt['cmt_pinned'] != 0)
+            return false;
+
+        if(isAdmin())
+            return true;
+        
+        return $this->checkAction ('comments pin', $isPerformAction);
+    }
+
+    public function msgErrPinAllowed ()
+    {
+        return $this->checkActionErrorMsg('comments pin');
+    }
+
+    public function isUnpinAllowed ($aCmt, $isPerformAction = false)
+    {
+        if((int)$aCmt['cmt_pinned'] == 0)
+            return false;
+
+        if(isAdmin())
+            return true;
+        
+        return $this->checkAction ('comments pin', $isPerformAction);
+    }
+
+    public function msgErrUnpinAllowed ()
+    {
+        return $this->checkActionErrorMsg('comments pin');
+    }
+
+    public function isEditAllowed ($aCmt, $isPerformAction = false)
+    {
+        if(isAdmin())
+            return true;
+
+        if($this->isEditAllowedAll($isPerformAction))
+            return true;
+
+        $mixedResult = BxDolService::call($this->_aSystem['module'], 'check_allowed_comments_post', array($this->getId(), $this->getSystemName()));
+        if($mixedResult !== CHECK_ACTION_RESULT_ALLOWED)
+            return false;
+
+        return abs($aCmt['cmt_author_id']) == $this->_getAuthorId() && $this->checkAction ('comments edit own', $isPerformAction);
+    }
+
+    public function msgErrEditAllowed ()
+    {
+        return $this->checkActionErrorMsg ('comments edit own');
+    }
+
+    public function isEditAllowedAll ($isPerformAction = false)
+    {
+        return $this->checkAction('comments edit all', $isPerformAction);
+    }
+
+    public function isRemoveAllowed ($aCmt, $isPerformAction = false)
+    {
+        if(isAdmin())
+            return true;
+
+        if($this->isRemoveAllowedAll($isPerformAction))
+            return true;
+
+        if(abs($aCmt['cmt_author_id']) == $this->_getAuthorId() && $this->checkAction ('comments remove own', $isPerformAction))
+            return true;
+        
+        $aContentInfo = BxDolRequest::serviceExists($this->_aSystem['module'], 'get_all') ? BxDolService::call($this->_aSystem['module'], 'get_all', array(array('type' => 'id', 'id' => $this->getId()))) : array();
+        $oModule = BxDolModule::getInstance($this->_aSystem['module']);
+        $CNF = $oModule->_oConfig->CNF;
+        
+        if (isset($CNF['FIELD_AUTHOR']) && $aContentInfo[$CNF['FIELD_AUTHOR']] == $this->_getAuthorId() && $this->checkAction('comments remove in own content', $isPerformAction)){
+            return true;
+        }
+        
+        if (isset($CNF['FIELD_ALLOW_VIEW_TO']) &&  $aContentInfo[$CNF['FIELD_ALLOW_VIEW_TO']] < 0){
+            $iGroupProfileId = -(int)$aContentInfo[$CNF['FIELD_ALLOW_VIEW_TO']];
+            $oProfileContext = BxDolProfile::getInstance($iGroupProfileId);
+            $oModule = BxDolModule::getInstance($oProfileContext->getModule()); 
+            if ($oModule->_oConfig->isRoles() && $oModule->getRole($iGroupProfileId, $this->_getAuthorId()) === BX_BASE_MOD_GROUPS_ROLE_ADMINISTRATOR && $this->checkAction('comments remove in group context', $isPerformAction)){
+                return true;
+            }
+        }
+        
+        return false;
+    }
+
+    public function isRemoveAllowedAll ($isPerformAction = false)
+    {
+        return $this->checkAction ('comments remove all', $isPerformAction);
+    }
+
+    public function msgErrRemoveAllowed ()
+    {
+        return $this->checkActionErrorMsg('comments remove own');
+    }
+
+    public function isMoreAllowed ($aCmt, $isPerformAction = false)
+    {
+        $oMenuManage = BxDolMenu::getObjectInstance($this->_sMenuObjManage);
+        $oMenuManage->setCmtsData($this, $aCmt['cmt_id']);
+    	return $oMenuManage->isVisible();
+    }
+
+    public function isModerator($isPerformAction = false)
+    {
+        return $this->isEditAllowedAll($isPerformAction) || $this->isRemoveAllowedAll($isPerformAction);
+    }
+
+    /**
+     * Actions functions
+     */
+    public function actionPin ()
+    {
+        if (!$this->isEnabled())
+            return echoJson(array());
+
+        $iCmtId = 0;
+        if(bx_get('Cmt') !== false)
+            $iCmtId = bx_process_input(bx_get('Cmt'), BX_DATA_INT);
+
+        $aCmt = $this->getCommentRow($iCmtId);
+        if(empty($aCmt) || !is_array($aCmt))
+            return echoJson(array());
+
+        $iWay = 0;
+        if(bx_get('way') !== false)
+            $iWay = bx_process_input(bx_get('way'), BX_DATA_INT);
+
+        if(!$this->_oQuery->updateComments(array('cmt_pinned' => $iWay ? time() : 0), array('cmt_id' => $iCmtId)))
+            return echoJson(array());
+
+        $aBp = $aDp = array();
+        $this->_getParams($aBp, $aDp);
+        $this->_prepareParams($aBp, $aDp);
+
+        echoJson(array(
+            'parent_id' => $aCmt['cmt_parent_id'],
+            'per_view' => $aBp['per_view']
+        ));
+    }
+    
+    public function actionGetFormPost ()
+    {
+        if (!$this->isEnabled())
+            return '';
+
+        $iCmtParentId = bx_get('CmtParent');
+        $iCmtParentId = $iCmtParentId !== false ? bx_process_input($iCmtParentId, BX_DATA_INT) : 0;
+        
+        $sCmtBrowse = bx_get('CmtBrowse');
+        $sCmtBrowse = $sCmtBrowse !== false ? bx_process_input($sCmtBrowse, BX_DATA_TEXT) : '';
+
+        $sCmtDisplay = bx_get('CmtDisplay');
+        $sCmtDisplay = $sCmtDisplay !== false ? bx_process_input($sCmtDisplay, BX_DATA_TEXT) : '';
+
+        $bQuote = bx_get('CmtQuote');
+        $bQuote = $bQuote !== false ? bx_process_input($bQuote, BX_DATA_INT) == 1 : false;
+
+        $bMinPostForm = bx_get('CmtMinPostForm');
+        $bMinPostForm = $bMinPostForm !== false ? bx_process_input($bMinPostForm, BX_DATA_INT) == 1 : $this->_bMinPostForm;
+
+        return $this->getFormBoxPost(array('parent_id' => $iCmtParentId, 'type' => $sCmtBrowse), array('type' => $sCmtDisplay, 'dynamic_mode' => true, 'quote' => $bQuote, 'min_post_form' => $bMinPostForm));
+    }
+
+    public function actionGetFormEdit ()
+    {
+        if (!$this->isEnabled())
+            return echoJson(array());
+
+        $iCmtId = bx_process_input(bx_get('Cmt'), BX_DATA_INT);
+        echoJson($this->getFormEdit($iCmtId, array('dynamic_mode' => true)));
+    }
+
+    public function actionGetCmt ()
+    {
+        if(!$this->isEnabled())
+            return '';
+
+        if($this->isViewAllowed() !== CHECK_ACTION_RESULT_ALLOWED)
+            return '';
+
+        $iCmtId = bx_process_input($_REQUEST['Cmt'], BX_DATA_INT);
+        $sCmtBrowse = isset($_REQUEST['CmtBrowse']) ? bx_process_input($_REQUEST['CmtBrowse'], BX_DATA_TEXT) : '';
+        $sCmtDisplay = isset($_REQUEST['CmtDisplay']) ? bx_process_input($_REQUEST['CmtDisplay'], BX_DATA_TEXT) : '';
+
+        $aCmt = $this->getCommentRow($iCmtId);
+        echoJson([
+            'parent_id' => $aCmt['cmt_parent_id'],
+            'vparent_id' => $aCmt['cmt_parent_id'],
+            'content' => $this->getComment($aCmt, ['type' => $sCmtBrowse], ['type' => $sCmtDisplay, 'dynamic_mode' => true])
+        ]);
+    }
+
+    public function actionGetCmts ()
+    {
+        if (!$this->isEnabled())
+            return '';
+
+        if($this->isViewAllowed() !== CHECK_ACTION_RESULT_ALLOWED)
+            return '';
+
+        $aBp = $aDp = array();
+        $this->_getParams($aBp, $aDp);
+
+        $aDp['dynamic_mode'] = true;
+
+        //--- Beg: Using pregenerated structure
+        if(isset($aDp['structure']) && $aDp['structure'] === true) {
+            $iCmtId = isset($aBp['parent_id']) ? (int)$aBp['parent_id'] : 0;
+
+            $mixedStructure = $this->getCommentStructure($iCmtId, $aBp, $aDp);
+            if($mixedStructure === false || empty($mixedStructure[$iCmtId]['items'])) 
+                return '';
+
+            $aDp['structure'] = $mixedStructure[$iCmtId]['items'];
+            return $this->getCommentsByStructure($aBp, $aDp);
+        }
+        //--- End: Using pregenerated structure
+        else
+            return $this->{'getComments' . ($aBp['pinned'] ? 'Pinned' : '')}($aBp, $aDp);
+    }
+
+    public function actionSubmitPostForm()
+    {
+        if(!$this->isEnabled())
+            return echoJson(array());
+
+        $iCmtParentId = 0;
+        if(bx_get('cmt_parent_id') !== false)
+            $iCmtParentId = bx_process_input(bx_get('cmt_parent_id'), BX_DATA_INT);
+
+        echoJson($this->getFormPost($iCmtParentId, array('dynamic_mode' => true)));
+    }
+
+    public function actionSubmitEditForm()
+    {
+        if (!$this->isEnabled()) {
+            echoJson(array());
+            return;
+        };
+
+        $iCmtId = 0;
+        if(bx_get('cmt_id') !== false)
+            $iCmtId = bx_process_input(bx_get('cmt_id'), BX_DATA_INT);
+
+        echoJson($this->getFormEdit($iCmtId, array('dynamic_mode' => true)));
+    }
+
+    public function actionRemove()
+    {
+        if (!$this->isEnabled())
+            return echoJson([]);
+
+        $iCmtId = 0;
+        if(bx_get('Cmt') !== false)
+            $iCmtId = bx_process_input(bx_get('Cmt'), BX_DATA_INT);
+
+        echoJson($this->remove($iCmtId));
+    }
+    
+    public function remove($iCmtId)
+    {
+        $aCmt = $this->_oQuery->getCommentsBy(array('type' => 'id', 'id' => $iCmtId));
+        if(!$aCmt)
+            return array('msg' => _t('_No such comment'));
+        
+        $iObjId = $this->getId();
+        if(!$iObjId){
+            $this->setId($aCmt['cmt_object_id']);
+            $iObjId = $aCmt['cmt_object_id'];
+        }
+        $iObjAthrId = $this->getObjectAuthorId($iObjId);
+        $iObjAthrPrivacyView = $this->getObjectPrivacyView($iObjId);
+
+        if($aCmt['cmt_replies'] > 0) {
+            if(!$this->isModerator())
+                return array('msg' => _t('_Can not delete comments with replies'));
+
+            $aReplies = $this->_oQuery->getCommentsBy(array('type' => 'parent_id', 'parent_id' => $iCmtId));
+            foreach($aReplies as $aReply)
+                $this->remove($aReply['cmt_id']);
+        }
+
+        $iPerformerId = $this->_getAuthorId();
+        if(!$this->isRemoveAllowed($aCmt))
+            return array('msg' => $aCmt['cmt_author_id'] == $iPerformerId ? strip_tags($this->msgErrRemoveAllowed()) : _t('_Access denied'));
+
+        $iCmtPrntId = (int)$aCmt['cmt_parent_id'];
+        if(!$this->_oQuery->removeComment($iObjId, $iCmtId, $iCmtPrntId)) 
+            return array('msg' => _t('_cmt_err_cannot_perform_action'));
+
+        $this->_triggerComment();
+
+        $oStorage = BxDolStorage::getObjectInstance($this->getStorageObjectName());
+
+        $aImages = $this->_oQuery->getFiles($this->_aSystem['system_id'], $iCmtId);
+        foreach($aImages as $aImage)
+            $oStorage->deleteFile($aImage['image_id']);
+
+        $this->_oQuery->deleteImages($this->_aSystem['system_id'], $iCmtId);
+
+        $this->isRemoveAllowed($aCmt, true);
+
+        $this->deleteVotes($iCmtId);
+
+        $this->deleteReactions($iCmtId);
+
+        $this->deleteScores($iCmtId);
+
+        $this->deleteReports($iCmtId);
+
+        $this->deleteMetaInfo($iCmtId);
+
+        $aAuditParams = $this->_prepareAuditParams($iCmtId, array('comment_author_id' => $aCmt['cmt_author_id'], 'comment_text' => $aCmt['cmt_text']));
+        bx_audit($iObjId, $this->_aSystem['module'], '_sys_audit_action_delete_comment', $aAuditParams);
+
+        $aAlertParams = $this->_prepareAlertParams($aCmt);
+
+        /**
+         * @hooks
+         * @hookdef hook-bx_dol_comment-commentRemoved '{object_name}', 'commentRemoved' - hook after a comment was removed
+         * - $unit_name - comment object name
+         * - $action - equals `commentRemoved`
+         * - $object_id - commented object id
+         * - $sender_id - profile id who performed the action
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `source` - [string] unique comment source string
+         *      - `object_system` - [string] comment object name
+         *      - `object_id` - [int] commented object id
+         *      - `object_author_id` - [int] commented object author profile id
+         *      - `comment_id` - [int] comment id unique in the comment object scope
+         *      - `comment_uniq_id` - [int] system wide unique comment id
+         *      - `comment_author_id` - [int] comment author profile id
+         *      - `comment_text` - [string] comment text
+         *      - `privacy_view` - [int] or [string] privacy for view comment action, @see BxDolPrivacy
+         *      - `cf` - [int] comment's audience filter value
+         * @hook @ref hook-bx_dol_comment-commentRemoved
+         */
+        bx_alert($this->_sSystem, 'commentRemoved', $iObjId, $iPerformerId, $aAlertParams);
+        
+        /**
+         * @hooks
+         * @hookdef hook-comment-deleted 'comment', 'deleted' - hook after a comment was removed
+         * It's equivalent to @ref hook-bx_dol_comment-commentRemoved
+         * except 'comment id' is provided in $object_id
+         * @hook @ref hook-comment-deleted
+         */
+        bx_alert('comment', 'deleted', $iCmtId, $iPerformerId, $aAlertParams);
+
+        if(!empty($iCmtPrntId)) {
+            $aCmtPrnt = $this->_oQuery->getCommentSimple($iObjId, $iCmtPrntId);
+            if(!empty($aCmtPrnt) && is_array($aCmtPrnt)) {
+                $aAlertParamsReply = $this->_prepareAlertParamsReply($aCmt, $aCmtPrnt);
+
+                /**
+                 * @hooks
+                 * @hookdef hook-bx_dol_comment-replyRemoved '{object_name}', 'replyRemoved' - hook after a reply was removed
+                 * - $unit_name - comment object name
+                 * - $action - equals `replyRemoved`
+                 * - $object_id - commented object id
+                 * - $sender_id - profile id who performed the action
+                 * - $extra_params - array of additional params with the following array keys:
+                 *      - `source` - [string] unique comment source string
+                 *      - `object_system` - [string] comment object name
+                 *      - `object_id` - [int] commented object id
+                 *      - `object_author_id` - [int] commented object author profile id
+                 *      - `object_author_id` - [int] commented object author profile id
+                 *      - `parent_id` - [int] parent comment id unique in the comment object scope
+                 *      - `parent_uniq_id` - [int] system wide unique parent comment id
+                 *      - `parent_author_id` - [int] parent comment author profile id
+                 *      - `comment_id` - [int] comment id unique in the comment object scope
+                 *      - `comment_uniq_id` - [int] system wide unique comment id
+                 *      - `comment_author_id` - [int] comment author profile id
+                 *      - `comment_text` - [string] comment text
+                 *      - `privacy_view` - [int] or [string] privacy for view comment action, @see BxDolPrivacy
+                 * @hook @ref hook-bx_dol_comment-replyRemoved
+                 */
+                bx_alert($this->_sSystem, 'replyRemoved', $iCmtPrntId, $iPerformerId, $aAlertParamsReply);
+                
+                /**
+                 * @hooks
+                 * @hookdef hook-reply-deleted 'reply', 'deleted' - hook after a reply was removed
+                 * It's equivalent to @ref hook-bx_dol_comment-replyRemoved
+                 * except 'comment id' is provided in $object_id
+                 * @hook @ref hook-reply-deleted
+                 */
+                bx_alert('reply', 'deleted', $iCmtId, $iPerformerId, $aAlertParamsReply);
+            }
+        }
+
+        $this->deleteUniqueIds($iCmtId);
+
+        $iCount = (int)$this->getCommentsCountAll(0, true);
+        $aResult = [
+            'id' => $iCmtId,
+            'count' => $iCount,
+            'countf' => $iCount > 0 ? $this->getCounter() : ''
+        ];
+
+        if(($oSockets = BxDolSockets::getInstance()) && $oSockets->isEnabled()) {
+            $oSockets->sendEvent($this->getSocketName(), $iObjId, 'comment_deleted', json_encode(array_merge($aResult, [
+                'author_id' => $iPerformerId
+            ])));
+
+            /**
+             * Send 'content edited' event.
+             * Note. 0 is used as $iContentId to allow to subscribe on all events at once.
+             */
+            $oSockets->sendEvent($this->_aSystem['module'], 0, 'edited', json_encode([
+                'id' => $iObjId,
+                'author_id' => $this->getObjectAuthorId(),
+                'cmt_author_id' => $aCmt['cmt_author_id'],
+                'peformer_id' => $iPerformerId
+            ]));
+        }
+
+        return $aResult;
+    }
+
+    public function add($aValues)
+    {
+        return $this->_getFormDirectAdd($aValues);
+    }
+
+    public function edit($aValues, $iCmtId)
+    {
+        return $this->_getFormDirectEdit($aValues, $iCmtId);
+    }
+
+    public function actionResumeLiveUpdate()
+    {
+    	$sKey = $this->getNotificationId();
+
+    	bx_import('BxDolSession');
+    	BxDolSession::getInstance()->unsetValue($sKey);
+    }
+
+    public function actionPauseLiveUpdate()
+    {
+    	$sKey = $this->getNotificationId();
+
+    	bx_import('BxDolSession');
+    	BxDolSession::getInstance()->setValue($sKey, 1);
+    }
+
+    public function actionGetSiblingFiles()
+    {
+        $iFileId = 0;
+        if(bx_get('file_id') !== false)
+            $iFileId = bx_process_input(bx_get('file_id'), BX_DATA_INT);
+
+        if(!($aFileInfo = $this->_oQuery->getFileInfoById((int)$iFileId))) 
+            return echoJson(['error' => _t('_sys_txt_error_occured')]);
+
+        $aSiblings = [];
+        $aFiles = $this->_oQuery->getFiles($aFileInfo['system_id'], $aFileInfo['cmt_id']);
+        foreach($aFiles as $iIndex => $aFile) {
+            if($aFile['id'] != $iFileId)
+                continue;
+
+            $aSiblings['prev'] = isset($aFiles[$iIndex - 1]) ? $aFiles[$iIndex - 1] : false;
+            $aSiblings['next'] = isset($aFiles[$iIndex + 1]) ? $aFiles[$iIndex + 1] : false;
+        }
+
+        $oStorage = BxDolStorage::getObjectInstance($this->getStorageObjectName());
+        $oTranscoder = BxDolTranscoderImage::getObjectInstance($this->getTranscoderPreviewName());
+
+        foreach($aSiblings as $sSibling => $aSibling) {
+            if(!$aSibling)
+                continue;
+
+            $sFile = '';
+            if($oTranscoder && $oTranscoder->isMimeTypeSupported($aSibling['mime_type']))
+                $sFile = $oStorage->getFileUrlById($aSibling['image_id']);
+            else
+                $sFile = $this->_oTemplate->getIconUrl($oStorage->getIconNameByFileName($aFile['file_name']));
+
+            $aImageInfo = BxDolImageResize::getInstance()->getImageSize($sFile);
+
+            $iWidth = $iHeight = 0;
+            if(isset($aImageInfo['w']))
+                $iWidth = (int)$aImageInfo['w'];
+            if(isset($aImageInfo['h']))
+                $iHeight = (int)$aImageInfo['h'];
+
+            $aSiblings[$sSibling] = array_merge($aSibling, [
+                'file' => $sFile,
+                'file_id' => $aSibling['id'],
+                'w' => $iWidth, 
+                'h' => $iHeight
+            ]);
+        }
+
+        return echoJson($aSiblings);
+    }
+
+    public function onPostAfter($iCmtId, $aDp = [])
+    {
+        $iObjId = (int)$this->getId();
+
+        $aCmt = $this->_oQuery->getCommentSimple($iObjId, $iCmtId);
+        if(empty($aCmt) || !is_array($aCmt))
+            return false;
+
+        $iCmtPrntId = (int)$aCmt['cmt_parent_id'];
+        $iPerformerId = (int)$aCmt['cmt_author_id'];
+
+        $aAlertParams = $this->_prepareAlertParams($aCmt);
+        
+        /**
+         * @hooks
+         * @hookdef hook-bx_dol_comment-commentPost '{object_name}', 'commentPost' - hook after a comment was added
+         * - $unit_name - comment object name
+         * - $action - equals `commentPost`
+         * - $object_id - commented object id
+         * - $sender_id - profile id who performed the action
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `source` - [string] unique comment source string
+         *      - `object_system` - [string] comment object name
+         *      - `object_id` - [int] commented object id
+         *      - `object_author_id` - [int] commented object author profile id
+         *      - `comment_id` - [int] comment id unique in the comment object scope
+         *      - `comment_uniq_id` - [int] system wide unique comment id
+         *      - `comment_author_id` - [int] comment author profile id
+         *      - `comment_text` - [string] comment text
+         *      - `privacy_view` - [int] or [string] privacy for view comment action, @see BxDolPrivacy
+         *      - `cf` - [int] comment's audience filter value
+         * @hook @ref hook-bx_dol_comment-commentPost
+         */
+        bx_alert($this->_sSystem, 'commentPost', $iObjId, $iPerformerId, $aAlertParams);
+        
+        /**
+         * @hooks
+         * @hookdef hook-comment-added 'comment', 'added' - hook after a comment was added
+         * It's equivalent to @hook @ref hook-bx_dol_comment-commentPost
+         * except 'comment id' is provided in $object_id
+         * @hook @ref hook-comment-added
+         */
+        bx_alert('comment', 'added', $iCmtId, $iPerformerId, $aAlertParams);
+
+        $aAuditParams = $this->_prepareAuditParams($iCmtId, array('comment_author_id' => $aCmt['cmt_author_id'], 'comment_text' => $aCmt['cmt_text']));
+        bx_audit($iObjId, $this->_aSystem['module'], '_sys_audit_action_add_comment', $aAuditParams);
+
+        if(!empty($iCmtPrntId)) {
+            $aCmtPrnt = $this->_oQuery->getCommentSimple($iObjId, $iCmtPrntId);
+            if(!empty($aCmtPrnt) && is_array($aCmtPrnt)) {
+                $aAlertParamsReply = $this->_prepareAlertParamsReply($aCmt, $aCmtPrnt);
+                
+                /**
+                 * @hooks
+                 * @hookdef hook-bx_dol_comment-replyPost '{object_name}', 'replyPost' - hook after a reply was added
+                 * - $unit_name - comment object name
+                 * - $action - equals `replyPost`
+                 * - $object_id - parent comment id
+                 * - $sender_id - profile id who performed the action
+                 * - $extra_params - array of additional params with the following array keys:
+                 *      - `source` - [string] unique comment source string
+                 *      - `object_system` - [string] comment object name
+                 *      - `object_id` - [int] commented object id
+                 *      - `object_author_id` - [int] commented object author profile id
+                 *      - `object_author_id` - [int] commented object author profile id
+                 *      - `parent_id` - [int] parent comment id unique in the comment object scope
+                 *      - `parent_uniq_id` - [int] system wide unique parent comment id
+                 *      - `parent_author_id` - [int] parent comment author profile id
+                 *      - `comment_id` - [int] comment id unique in the comment object scope
+                 *      - `comment_uniq_id` - [int] system wide unique comment id
+                 *      - `comment_author_id` - [int] comment author profile id
+                 *      - `comment_text` - [string] comment text
+                 *      - `privacy_view` - [int] or [string] privacy for view comment action, @see BxDolPrivacy
+                 * @hook @ref hook-bx_dol_comment-replyPost
+                 */
+                bx_alert($this->_sSystem, 'replyPost', $iCmtPrntId, $iPerformerId, $aAlertParamsReply);
+                
+                /**
+                 * @hooks
+                 * @hookdef hook-comment-replied 'comment', 'replied' - hook after a reply was added
+                 * It's equivalent to @ref hook-bx_dol_comment-replyPost
+                 * except 'comment id' is provided in $object_id
+                 * @hook @ref hook-comment-replied
+                 */
+                bx_alert('comment', 'replied', $iCmtId, $iPerformerId, $aAlertParamsReply);
+            }
+        }
+
+        $iCount = (int)$this->getCommentsCountAll(0, true);
+        $aResult = [
+            'id' => $iCmtId, 
+            'parent_id' => $iCmtPrntId,
+            'count' => $iCount,
+            'countf' => $iCount > 0 ? $this->getCounter(['show_script' => false]) : ''
+        ];
+
+        if(($oSockets = BxDolSockets::getInstance()) && $oSockets->isEnabled()) {
+            $oSockets->sendEvent($this->getSocketName(), $iObjId, 'comment_added', json_encode(array_merge($aResult, [
+                'author_id' => $iPerformerId, 
+                'anchor' => $this->getItemAnchor($iCmtId)
+            ])));
+
+            /**
+             * Send 'content edited' event.
+             * Note. 0 is used as $iContentId to allow to subscribe on all events at once.
+             */
+            $oSockets->sendEvent($this->_aSystem['module'], 0, 'edited', json_encode([
+                'id' => $iObjId,
+            ]));
+        }
+
+        return $aResult;
+    }
+
+    public function onEditAfter($iCmtId, $aDp = [])
+    {
+    	$aCmt = $this->getCommentRow($iCmtId);
+        if(empty($aCmt) || !is_array($aCmt))
+            return false;
+
+        $aBp = [];
+        $this->_getParams($aBp, $aDp);
+
+        $iObjId = (int)$this->getId();
+        $iPerformerId = $this->_getAuthorId();
+
+        $aAlertParams = $this->_prepareAlertParams($aCmt);
+        /**
+         * @hooks
+         * @hookdef hook-bx_dol_comment-commentUpdated '{object_name}', 'commentUpdated' - hook after a comment was updated (edited)
+         * - $unit_name - comment object name
+         * - $action - equals `commentUpdated`
+         * - $object_id - commented object id
+         * - $sender_id - profile id who performed the action
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `source` - [string] unique comment source string
+         *      - `object_system` - [string] comment object name
+         *      - `object_id` - [int] commented object id
+         *      - `object_author_id` - [int] commented object author profile id
+         *      - `comment_id` - [int] comment id unique in the comment object scope
+         *      - `comment_uniq_id` - [int] system wide unique comment id
+         *      - `comment_author_id` - [int] comment author profile id
+         *      - `comment_text` - [string] comment text
+         *      - `privacy_view` - [int] or [string] privacy for view comment action, @see BxDolPrivacy
+         *      - `cf` - [int] comment's audience filter value
+         * @hook @ref hook-bx_dol_comment-commentUpdated
+         */
+        bx_alert($this->_sSystem, 'commentUpdated', $iObjId, $iPerformerId, $aAlertParams);
+        
+        /**
+         * @hooks
+         * @hookdef hook-comment-edited 'comment', 'edited' - hook after a comment was updated (edited)
+         * It's equivalent to @ref hook-bx_dol_comment-commentUpdated
+         * except 'comment id' is provided in $object_id
+         * @hook @ref hook-comment-edited
+         */
+        bx_alert('comment', 'edited', $iCmtId, $iPerformerId, $aAlertParams);
+
+        $aAuditParams = $this->_prepareAuditParams($iCmtId, ['comment_author_id' => $aCmt['cmt_author_id'], 'comment_text' => $aCmt['cmt_text']]);
+        bx_audit($iObjId, $this->_aSystem['module'], '_sys_audit_action_edit_comment', $aAuditParams);
+
+        $aResult = [
+            'id' => $iCmtId, 
+            'content' => $this->_getContent($aCmt, $aBp, $aDp)
+        ];
+
+        if(($oSockets = BxDolSockets::getInstance()) && $oSockets->isEnabled()) {
+            $oSockets->sendEvent($this->getSocketName(), $iObjId, 'comment_edited', json_encode(array_merge($aResult, [
+                'author_id' => $iPerformerId, 
+                'anchor' => $this->getItemAnchor($iCmtId)
+            ])));
+
+            /**
+             * Send 'content edited' event.
+             * Note. 0 is used as $iContentId to allow to subscribe on all events at once.
+             */
+            $oSockets->sendEvent($this->_aSystem['module'], 0, 'edited', json_encode([
+                'id' => $iObjId,
+            ]));
+        }
+
+        return $aResult;
+    }
+
+    public function serviceGetAuthor ($iContentId)
+    {
+        $aComment = $this->_oQuery->getCommentsBy(array('type' => 'id', 'id' => $iContentId));
+        $this->init($aComment['cmt_object_id']);
+
+        return $aComment['cmt_author_id'];
+    }
+
+    public function serviceGetDateAdded ($iContentId)
+    {
+        $aComment = $this->_oQuery->getCommentsBy(array('type' => 'id', 'id' => $iContentId));
+        $this->init($aComment['cmt_object_id']);
+
+        return $aComment['cmt_time'];
+    }
+
+    public function serviceGetDateChanged ($iContentId)
+    {
+        return 0;
+    }
+    public function serviceGetLink ($iContentId)
+    {
+        $aComment = $this->_oQuery->getCommentsBy(array('type' => 'id', 'id' => $iContentId));
+        $this->init($aComment['cmt_object_id']);
+
+        return $this->getViewUrl($iContentId);
+    }
+
+    public function serviceGetTitle ($iContentId)
+    {
+        return '';
+    }
+
+    public function serviceGetText ($iContentId)
+    {
+        $aComment = $this->_oQuery->getCommentsBy(array('type' => 'id', 'id' => $iContentId));
+        $this->init($aComment['cmt_object_id']);
+
+        return $aComment['cmt_text'];
+    }
+
+    public function serviceGetThumb ($iContentId)
+    {
+        return '';
+    }
+
+    public function serviceGetInfo ($iContentId, $bSearchableFieldsOnly = true)
+    {
+        $aComment = $this->_oQuery->getCommentsBy(array('type' => 'id', 'id' => $iContentId));
+        $this->init($aComment['cmt_object_id']);
+
+        return BxDolContentInfo::formatFields($aComment);
+    }
+
+    public function serviceGetInfoApi ($iContentId, $bExtendedUnits = false)
+    {
+        $aData = $this->serviceGetInfo($iContentId, false);
+        if($aData)
+            $aData = $this->getDataAPI($aData, ['extended' => $bExtendedUnits]);
+
+        return $aData;
+    }
+
+    public function serviceGetSearchResultUnit ($iContentId, $sUnitTemplate = '')
+    {
+        $aComment = $this->_oQuery->getCommentsBy(array('type' => 'id', 'id' => $iContentId));
+        if(empty($aComment) || !is_array($aComment))
+            return '';
+
+        $this->init($aComment['cmt_object_id']);
+
+        return $this->getComment($aComment, array(), array('type' => BX_CMT_DISPLAY_FLAT, 'view_only' => true));
+    }
+
+    public function serviceGetAll ($aParams = array())
+    {
+        if(empty($aParams) || !is_array($aParams))
+            $aParams = array('type' => 'all');
+
+        return $this->_oQuery->getCommentsBy($aParams);
+    }
+
+    public function serviceGetSearchableFieldsExtended($aInputsAdd = array())
+    {
+        $oForm = BxDolForm::getObjectInstance('sys_comment', 'sys_comment_post', $this->_oTemplate);
+        if(!$oForm)
+            return array();
+
+        $aSrchNamesExcept = array();
+        $aSrchCaptionsSystem = array(
+            'cmt_author_id' => '_sys_form_comment_input_caption_system_cmt_author_id',
+            'cmt_text' => '_sys_form_comment_input_caption_system_cmt_text'
+        );
+        $aSrchCaptions = array(
+            'cmt_author_id' => '_sys_form_comment_input_caption_cmt_author_id',
+            'cmt_text' => '_sys_form_comment_input_caption_cmt_text'
+        );
+
+        $aResult = array(
+            'cmt_author_id' => array(
+                'type' => 'text_auto', 
+                'caption_system' => $aSrchCaptionsSystem['cmt_author_id'],
+                'caption' => $aSrchCaptions['cmt_author_id'],
+                'info' => '',
+                'value' => '',
+                'values' => '',
+                'pass' => ''
+            )
+        );
+
+        $aInputs = $oForm->aInputs;
+        if(!empty($aInputsAdd) && is_array($aInputsAdd))
+            $aInputs = array_merge($aInputs, $aInputsAdd);
+
+        foreach($aInputs as $aInput)
+            if(in_array($aInput['type'], BxDolSearchExtended::$SEARCHABLE_TYPES) && !in_array($aInput['name'], $aSrchNamesExcept))
+                $aResult[$aInput['name']] = array(
+                    'type' => $aInput['type'], 
+                    'caption_system' => !empty($aInput['caption_system_src']) ? $aInput['caption_system_src'] : '',
+                    'caption' => !empty($aInput['caption_src']) ? $aInput['caption_src'] : (!empty($aSrchCaptions[$aInput['name']]) ? $aSrchCaptions[$aInput['name']] : ''),
+                    'info' => !empty($aInput['info_src']) ? $aInput['info_src'] : '',
+                    'value' => !empty($aInput['value']) ? $aInput['value'] : '',
+                    'values' => !empty($aInput['values_src']) ? $aInput['values_src'] : '',
+                    'pass' => !empty($aInput['db']['pass']) ? $aInput['db']['pass'] : ''
+                );
+
+        return $aResult;
+    }
+
+    /**
+     * Overwrite this method and register transcoder(s) if comments object uses custom transcoder(s), 
+     * which differs from default one 'sys_cmts_images_preview'
+     */
+    public function registerTranscoders()
+    {}
+
+	/**
+     * Overwrite this method and unregister transcoder(s) if comments object uses custom transcoder(s), 
+     * which differs from default one 'sys_cmts_images_preview'
+     */
+    public function unregisterTranscoders()
+    {}
+
+    public function serviceGetSearchResultExtended($aParams, $iStart = 0, $iPerPage = 0, $bFilterMode = false)
+    {
+        if((empty($aParams) || !is_array($aParams)) && !$bFilterMode)
+            return array();
+
+        return $this->_oQuery->getCommentsBy(array('type' => 'search_ids', 'search_params' => $aParams, 'start' => $iStart, 'per_page' => $iPerPage));
+    }
+
+    public function getAuthorInfo($iAuthorId = 0)
+    {
+        return $this->_getAuthorInfo($iAuthorId);
+    }
+    
+    public function getParams(&$aBp, &$aDp)
+    {
+        return $this->_getParams($aBp, $aDp);
+    }
+    
+    public function prepareParams(&$aBp, &$aDp)
+    {
+         return $this->_prepareParams($aBp, $aDp);
+    }
+
+    /**
+     * Internal functions
+     */
+    protected function _getAuthorId ()
+    {
+        return isMember() ? bx_get_logged_profile_id() : 0;
+    }
+
+    protected function _getAuthorPassword ()
+    {
+        return getLoggedPassword();
+    }
+
+    protected function _getAuthorIp ()
+    {
+        return getVisitorIP();
+    }
+
+    protected function _getAuthorInfo($iAuthorId = 0)
+    {
+        $iUserId = $this->_getAuthorId();
+        $iAuthorId = (int)$iAuthorId;
+        $oProfile = $this->_getAuthorObject($iAuthorId);
+        if (!$oProfile->isActive() && !isAdmin() && !BxDolAcl::getInstance()->isMemberLevelInSet(array(MEMBERSHIP_ID_MODERATOR, MEMBERSHIP_ID_ADMINISTRATOR)))
+            $oProfile = BxDolProfileUndefined::getInstance();
+
+        return array(
+            $oProfile->getDisplayName(),
+            $oProfile->getUrl(),
+            $oProfile->getThumb(),
+            $oProfile->getUnit(0, array('template' => 'unit_wo_info')),
+            $oProfile->getBadges()
+        );
+    }
+
+    protected function _getAuthorObject($iAuthorId = 0)
+    {
+        return BxDolProfile::getInstanceMagic((int)$iAuthorId);
+    }
+
+    protected function _getFormObject($sAction = BX_CMT_ACTION_POST)
+    {
+        $sDisplayName = '_sFormDisplay' . ucfirst($sAction);
+
+        return BxDolForm::getObjectInstance($this->_sFormObject, $this->$sDisplayName, $this->_oTemplate, $this->_sSystem);
+    }
+    
+    protected function _unsetFormObject($sAction = BX_CMT_ACTION_POST)
+    {
+        $sDisplayName = '_sFormDisplay' . ucfirst($sAction);
+
+        return BxDolForm::unsetObjectInstance($this->_sFormObject, $this->$sDisplayName, $this->_oTemplate, $this->_sSystem);
+    }
+
+    protected function _getParams(&$aBp, &$aDp)
+    {
+        //--- Process 'Browse' params. 
+        $aBp['parent_id'] = isset($aBp['parent_id']) ? (int)$aBp['parent_id'] : 0;
+
+        $aBp['vparent_id'] = isset($aBp['vparent_id']) ? (int)$aBp['vparent_id'] : 0;
+        if(bx_get('CmtParent') !== false)
+            $aBp['vparent_id'] = bx_process_input(bx_get('CmtParent'), BX_DATA_INT);
+
+    	$aBp['type'] = isset($aBp['type']) ? $aBp['type'] : '';
+    	if(bx_get('CmtBrowse') !== false) 
+        	$aBp['type'] = bx_process_input(bx_get('CmtBrowse'), BX_DATA_TEXT);
+
+    	$aBp['filter'] = isset($aBp['filter']) ? $aBp['filter'] : '';
+    	if(bx_get('CmtFilter') !== false) 
+    	    $aBp['filter'] = bx_process_input(bx_get('CmtFilter'), BX_DATA_TEXT);
+
+        $aBp['start'] = isset($aBp['start']) ? (int)$aBp['start'] : -1;
+        if(bx_get('CmtStart') !== false) 
+            $aBp['start'] = bx_process_input($_REQUEST['CmtStart'], BX_DATA_INT);
+
+        $aBp['per_view'] = isset($aBp['per_view']) ? (int)$aBp['per_view'] : -1;
+        if(bx_get('CmtPerView') !== false) 
+            $aBp['per_view'] = bx_process_input($_REQUEST['CmtPerView'], BX_DATA_INT);
+
+        $aBp['pinned'] = isset($aBp['pinned']) ? (int)$aBp['pinned'] : 0;
+        if(bx_get('CmtPinned') !== false) 
+            $aBp['pinned'] = bx_process_input(bx_get('CmtPinned'), BX_DATA_INT);
+
+        //--- Process 'Display' params.
+        $aDp['type'] = isset($aDp['type']) ? $aDp['type'] : '';
+        if(bx_get('CmtDisplay') !== false) 
+            $aDp['type'] = bx_process_input($_REQUEST['CmtDisplay'], BX_DATA_TEXT);
+
+        if(bx_get('CmtDisplayStructure') !== false) {
+            $aDp['structure'] = bx_process_input($_REQUEST['CmtDisplayStructure'], BX_DATA_INT) == 1;
+
+            if($aDp['structure'] && bx_get('CmtParent') !== false)
+                $aBp['parent_id'] = bx_process_input(bx_get('CmtParent'), BX_DATA_INT);
+        }
+
+        $aDp['blink'] = isset($aDp['blink']) ? $aDp['blink'] : '';
+        if(bx_get('CmtBlink') !== false) 
+            $aDp['blink'] = bx_process_input($_REQUEST['CmtBlink'], BX_DATA_TEXT);
+
+        $aDp['quote'] = isset($aDp['quote']) ? (int)$aDp['quote'] : 0;
+        if(bx_get('CmtQuote') !== false) 
+            $aDp['quote'] = bx_process_input($_REQUEST['CmtQuote'], BX_DATA_INT);
+
+        $aDp['min_post_form'] = isset($aDp['min_post_form']) ? (bool)$aDp['min_post_form'] : $this->_bMinPostForm;
+        if(bx_get('CmtMinPostForm') !== false)
+            $aDp['min_post_form'] = bx_process_input(bx_get('CmtMinPostForm'), BX_DATA_INT) == 1;
+
+        $aDp['in_designbox'] = isset($aDp['in_designbox']) ? (bool)$aDp['in_designbox'] : true;
+        $aDp['dynamic_mode'] = isset($aDp['dynamic_mode']) ? (bool)$aDp['dynamic_mode'] : false;
+        $aDp['show_empty'] = isset($aDp['show_empty']) ? (bool)$aDp['show_empty'] : false;
+    }
+
+    protected function _prepareAlertParams($aCmt)
+    {
+        $iObjId = (int)$this->getId();
+        $iObjAthrId = $this->getObjectAuthorId($iObjId);
+        $iObjAthrPrivacyView = $this->getObjectPrivacyView($iObjId);
+
+        $iCmtId = (int)$aCmt['cmt_id'];
+        $iCmtUniqId = $this->getCommentUniqId($iCmtId);
+        $iCmtCf = isset($aCmt['cmt_cf']) ? (int)$aCmt['cmt_cf'] : BxDolContentFilter::getInstance()->getDefaultValue();
+
+        return array(
+            'source' => 'sys_cmts_' . $iCmtUniqId,
+
+            'object_system' => $this->_sSystem, 
+            'object_id' => $iObjId, 
+            'object_author_id' => $iObjAthrId,
+
+            'comment_id' => $iCmtId, 
+            'comment_uniq_id' => $iCmtUniqId,
+            'comment_author_id' => $aCmt['cmt_author_id'], 
+            'comment_parent_id' => $aCmt['cmt_parent_id'], 
+            'comment_text' => $aCmt['cmt_text'],
+
+            'privacy_view' => $iObjAthrPrivacyView,
+            'cf' => $iCmtCf
+        );
+    }
+
+    protected function _prepareAlertParamsReply($aCmt, $aCmtPrnt)
+    {
+        $iObjId = (int)$this->getId();
+        $iObjAthrId = $this->getObjectAuthorId($iObjId);
+        $iObjAthrPrivacyView = $this->getObjectPrivacyView($iObjId);
+
+        $iCmtPrntId = (int)$aCmt['cmt_parent_id'];
+        $iCmtPrntUniqId = $this->getCommentUniqId($iCmtPrntId);
+
+        $iCmtId = (int)$aCmt['cmt_id'];
+        $iCmtUniqId = $this->getCommentUniqId($iCmtId);
+
+        return array(
+            'source' => 'sys_cmts_' . $iCmtUniqId,
+
+            'object_system' => $this->_sSystem, 
+            'object_id' => $iObjId, 
+            'object_author_id' => $iObjAthrId,
+
+            'parent_id' => $iCmtPrntId,
+            'parent_uniq_id' => $iCmtPrntUniqId,
+            'parent_author_id' => $aCmtPrnt['cmt_author_id'],
+
+            'comment_id' => $iCmtId,
+            'comment_uniq_id' => $iCmtUniqId,
+            'comment_author_id' => $aCmt['cmt_author_id'],  
+            'comment_text' => $aCmt['cmt_text'],
+
+            'privacy_view' => $iObjAthrPrivacyView,
+        );
+    }
+
+    protected function _prepareAuditParams($iId, $aData)
+    {
+        $sModule = $this->_aSystem['module'];
+        $oModule = BxDolModule::getInstance($sModule);
+        $CNF = isset($oModule->_oConfig->CNF) ? $oModule->_oConfig->CNF : array();
+
+        $aContentInfo = BxDolRequest::serviceExists($sModule, 'get_all') ? BxDolService::call($sModule, 'get_all', array(array('type' => 'id', 'id' => $this->getId()))) : array();
+        $iContextId = 0;
+        if (!empty($aContentInfo)){
+            $iContextId = isset($CNF['FIELD_ALLOW_VIEW_TO']) && (!empty($aContentInfo[$CNF['FIELD_ALLOW_VIEW_TO']]) && (int)$aContentInfo[$CNF['FIELD_ALLOW_VIEW_TO']] < 0) ? - $aContentInfo[$CNF['FIELD_ALLOW_VIEW_TO']] : 0; 
+        }
+        
+        $AuditParams = array(
+            'content_title' => $this->getObjectTitle() ,
+            'context_profile_id' => $iContextId,
+            'content_info_object' =>  isset($CNF['OBJECT_CMTS_CONTENT_INFO']) ? $CNF['OBJECT_CMTS_CONTENT_INFO'] : '',
+            'data' => array_merge(array('comment_id' => $iId), $aData)
+        );
+        if ($iContextId > 0)
+            $AuditParams['context_profile_title'] = BxDolProfile::getInstance($iContextId)->getDisplayName();
+        
+        return $AuditParams;
+    }
+
+    protected function _prepareTextForOutput ($s, $iCmtId = 0)
+    {
+    	$iDataAction = !$this->isHtml() ? BX_DATA_TEXT_MULTILINE : BX_DATA_HTML;
+    	$s = bx_process_output($s, $iDataAction);
+    	$s = bx_linkify_html($s, 'class="' . BX_DOL_LINK_CLASS . '"');
+
+        if($iCmtId && $this->_sMetatagsObj && ($oMetatags = BxDolMetatags::getObjectInstance($this->_sMetatagsObj)) !== false)
+            $s = $oMetatags->metaParse($this->_oQuery->getUniqId($this->_aSystem['system_id'], $iCmtId), $s);
+
+        return $s;
+    }
+
+    protected function _prepareStructureBp($sDType, &$aBp)
+    {
+        $aBp['type'] = !empty($aBp['type']) ? $aBp['type'] : $this->_sBrowseType;
+        $aBp['filter'] = !empty($aBp['filter']) ? $aBp['filter'] : $this->_sBrowseFilter;
+        $aBp['parent_id'] = isset($aBp['parent_id']) ? $aBp['parent_id'] : 0;
+        $aBp['start'] = isset($aBp['start']) ? $aBp['start'] : -1;
+        $aBp['init_view'] = isset($aBp['init_view']) ? $aBp['init_view'] : -1;
+        $aBp['per_view'] = isset($aBp['per_view']) ? $aBp['per_view'] : -1;
+        $aBp['order']['by'] = isset($aBp['order_by']) ? $aBp['order_by'] : $this->_aOrder['by'];
+        $aBp['order']['way'] = isset($aBp['order_way']) ? $aBp['order_way'] : $this->_aOrder['way'];
+
+        if($aBp['per_view'] == -1)
+            switch($sDType) {
+                case BX_CMT_DISPLAY_FLAT:
+                    $aBp['per_view'] = $this->getPerView(0);
+                    break;
+
+                case BX_CMT_DISPLAY_THREADED:
+                    $aBp['per_view'] = $this->getPerView($aBp['parent_id']);
+                    break;
+            }
+    }
+
+    protected function _prepareParams(&$aBp, &$aDp)
+    {
+        $aBp['type'] = !empty($aBp['type']) ? $aBp['type'] : $this->_sBrowseType;
+        $aBp['filter'] = !empty($aBp['filter']) ? $aBp['filter'] : $this->_sBrowseFilter;
+        $aBp['parent_id'] = isset($aBp['parent_id']) ? $aBp['parent_id'] : 0;
+        $aBp['start'] = isset($aBp['start']) ? $aBp['start'] : -1;
+        $aBp['init_view'] = isset($aBp['init_view']) ? $aBp['init_view'] : -1;
+        $aBp['per_view'] = isset($aBp['per_view']) ? $aBp['per_view'] : -1;
+        $aBp['pinned'] = isset($aBp['pinned']) ? (int)$aBp['pinned'] : 0;
+        $aBp['order']['by'] = isset($aBp['order_by']) ? $aBp['order_by'] : $this->_aOrder['by'];
+        $aBp['order']['way'] = isset($aBp['order_way']) ? $aBp['order_way'] : $this->_aOrder['way'];
+
+        $aDp['type'] = !empty($aDp['type']) ? $aDp['type'] : $this->_sDisplayType;
+        $aDp['blink'] = !empty($aDp['blink']) ? $aDp['blink'] : array();
+        if(!is_array($aDp['blink']))
+            $aDp['blink'] = explode(',', $aDp['blink']);
+        $aDp['quote'] = !empty($aDp['quote']) ? (int)$aDp['quote'] : 0;
+        if(!isset($aDp['min_post_form']))
+            $aDp['min_post_form'] = $this->_bMinPostForm;
+
+        switch($aDp['type']) {
+            case BX_CMT_DISPLAY_FLAT:
+                $aBp['vparent_id'] = -1;
+                $aBp['per_view'] = $aBp['per_view'] != -1 ? $aBp['per_view'] : $this->getPerView(0);
+                break;
+
+            case BX_CMT_DISPLAY_THREADED:
+                $iParent = 0;
+                if(isset($aBp['vparent_id']))
+                    $iParent = $aBp['vparent_id'];
+                else if(isset($aBp['parent_id']))
+                    $iParent = $aBp['parent_id'];
+
+                $aBp['per_view'] = $aBp['per_view'] != -1 ? $aBp['per_view'] : $this->getPerView($iParent);
+                break;
+        }
+
+        switch ($aBp['type']) {
+            case BX_CMT_BROWSE_POPULAR:
+                $aBp['order'] = array(
+                    'by' => BX_CMT_ORDER_BY_POPULAR,
+                    'way' => BX_CMT_ORDER_WAY_DESC
+                );
+                break;
+        }
+
+        if(!isset($aBp['count']))
+            $aBp['count'] = $this->getCommentsCount($this->_iId, $aBp['vparent_id'], $aBp['filter']);
+
+        if($aBp['start'] != -1)
+            return;
+
+        $aBp['start'] = 0;
+        if($aBp['type'] == BX_CMT_BROWSE_TAIL) {
+            $sPerView = ($aBp['init_view'] != -1 ? 'init' : 'per') . '_view';
+
+            $aBp['start'] = $aBp['count'] - $aBp[$sPerView];
+            if($aBp['start'] < 0) {
+                $aBp[$sPerView] += $aBp['start'];
+                $aBp['start'] = 0;
+            }
+        }
+
+        $this->_setUserChoice($aDp['type'], $aBp['type'], $aBp['filter']);
+    }
+
+    protected function _triggerComment()
+    {
+        if(!$this->_aSystem['trigger_table'] || !$this->_aSystem['trigger_field_id'] || !$this->_aSystem['trigger_field_comments'])
+            return false;
+
+        $iId = $this->getId();
+        if(!$iId)
+            return false;
+
+        $iCount = $this->getCommentsCount($iId);
+        return $this->_oQuery->updateTriggerTable($iId, $iCount);
+    }
+
+    /**
+     * Replace provided markers in a string
+     * @param $mixed string or array to replace markers in
+     * @return string where all occured markers are replaced
+     */
+    protected function _replaceMarkers ($mixed)
+    {
+        return bx_replace_markers($mixed, $this->_aMarkers);
+    }
+
+    protected function _getUserChoice()
+    {
+        $mixedDp = $mixedBpType = $mixedBpFilter = false;
+        if(!isLogged())
+            return array($mixedDp, $mixedBpType, $mixedBpFilter);
+
+        $iUserId = $this->_getAuthorId();
+
+        $oSession = BxDolSession::getInstance();
+
+        $mixedDp = $oSession->getValue($this->_sDpSessionKey . $iUserId);
+        $mixedBpType = $oSession->getValue($this->_sBpSessionKeyType . $iUserId);
+        $mixedBpFilter = $oSession->getValue($this->_sBpSessionKeyFilter . $iUserId);
+
+        return array($mixedDp, $mixedBpType, $mixedBpFilter);
+    }
+
+    protected function _setUserChoice($sDp, $sBpType, $sBpFilter)
+    {
+        if(!isLogged())
+            return;
+
+        $iUserId = $this->_getAuthorId();
+
+        $oSession = BxDolSession::getInstance();
+
+        if(!empty($sDp))
+            $oSession->setValue($this->_sDpSessionKey . $iUserId, $sDp);
+
+        if(!empty($sBpType))
+            $oSession->setValue($this->_sBpSessionKeyType . $iUserId, $sBpType);
+
+        if(!empty($sBpFilter))
+            $oSession->setValue($this->_sBpSessionKeyFilter . $iUserId, $sBpFilter);
+    }
+
+    protected function _sendNotificationEmail($iCmtId, $iCmtParentId)
+    {
+        $aCmt = $this->getCommentRow($iCmtId);
+        $aCmtParent = $this->getCommentRow($iCmtParentId);
+        if(empty($aCmt) || !is_array($aCmt) || empty($aCmtParent) || !is_array($aCmtParent) || (int)$aCmt['cmt_author_id'] == (int)$aCmtParent['cmt_author_id'])
+            return;
+
+        $oProfile = $this->_getAuthorObject($aCmtParent['cmt_author_id']);
+
+        if($oProfile instanceof BxDolProfileUndefined)
+        	return;
+
+        $iAccount = $oProfile->getAccountId();
+        $aAccount = BxDolAccount::getInstance($iAccount)->getInfo();
+
+        $aPlus = array();
+        $aPlus['sender_display_name'] = $oProfile->getDisplayName();
+        $aPlus['reply_text'] = $this->_prepareTextForOutput($aCmt['cmt_text'], $iCmtId);
+
+        $sPageUrl = $this->getBaseUrl();
+        if(empty($sPageUrl))
+            $sPageUrl = $this->getViewUrl($iCmtParentId);
+        else 
+            $sPageUrl .= $this->getItemAnchor($iCmtParentId, true);
+        $aPlus['page_url'] = $sPageUrl;
+
+        $sPageTitle = $this->getObjectTitle();
+        if(empty($sPageTitle))
+            $sPageTitle = _t('_Content');
+        $aPlus['page_title'] = $sPageTitle;
+
+        $aTemplate = BxDolEmailTemplates::getInstance()->parseTemplate('t_CommentReplied', $aPlus);
+        return $aTemplate && sendMail($aAccount['email'], $aTemplate['Subject'], $aTemplate['Body']);
+    }
+
+    protected function _isShowDoComment($aParams, $isAllowedComment, $bCount)
+    {
+        $bShowDoComment = !isset($aParams['show_do_comment']) || $aParams['show_do_comment'] == true;
+
+        return $bShowDoComment && ($isAllowedComment || $bCount);
+    }
+
+    protected function _isShowCounter($aParams, $isAllowedComment, $bCount)
+    {
+        $bShowCounter = isset($aParams['show_counter']) && $aParams['show_counter'] === true;
+
+        return $bShowCounter && ($isAllowedComment || $bCount);
+    }
+
+    /**
+     * Note. By default image based controls aren't used.
+     * Therefore it can be overwritten in custom template.
+     */
+    protected function _getImageDo()
+    {
+    	return '';
+    }
+
+    protected function _getIconDo()
+    {
+    	return 'far comment';
+    }
+
+    protected function _getTitleDo()
+    {
+    	return '_cmt_txt_do';
+    }
+
+    protected function _getParents($aCmt, $iDepthMax, &$iDepth, &$aParents)
+    {
+        $iParentId = (int)$aCmt['cmt_parent_id'];
+        if($iParentId == 0)
+            return;
+
+        $aParents[] = $iParentId;
+        $iDepth++;
+
+        if($iDepthMax != 0 && $iDepth == $iDepthMax)
+            return;
+
+        $aCmt = $this->_oQuery->getCommentsBy(['type' => 'id', 'id' => $iParentId]);
+        $this->_getParents($aCmt, $iDepthMax, $iDepth, $aParents);
+    }
+
+    public function _getStructure($mixedItem, $aBp, &$iLevel, &$aStructure)
+    {
+        $bItem = !empty($mixedItem) && is_array($mixedItem);
+
+        $iCmtId = $bItem ? (int)$mixedItem['cmt_id'] : 0;
+        $iCmtIndex = $iCmtId;
+
+        if($bItem)
+            $aStructure[$iCmtIndex] = [
+                'id' => $mixedItem['cmt_id'], 
+                'order' => isset($mixedItem['cmt_order']) ? $mixedItem['cmt_order'] : 0, 
+                'items' => [],
+            ];
+
+        if(!$bItem || (int)$mixedItem['cmt_replies'] > 0) {
+            $aItems = $this->_oQuery->getStructure($this->_iId, $this->_iAuthorId, $iCmtId, $aBp['filter'], $aBp['order']);
+            if(!empty($aItems)) {
+                if($bItem && $iLevel < (int)$this->_aSystem['number_of_levels']) {
+                    $iPassLevel = $iLevel + 1;
+                    $aPassStructure = &$aStructure[$iCmtIndex]['items'];
+                }
+                else {
+                    $iPassLevel = $iLevel;
+                    $aPassStructure = &$aStructure; //--- Is NEEDED here to correctly check sublevels.
+                }
+
+                foreach($aItems as $aItem)
+                    $this->_getStructure($aItem, $aBp, $iPassLevel, $aPassStructure);
+
+                //--- Sort subitems
+                $iWay = isset($aBp['order']['way']) && $aBp['order']['way'] == 'desc' ? -1 : 1;
+                uasort($aPassStructure, function($aItem1, $aItem2) use ($iWay) {
+                    if($aItem1['order'] == $aItem2['order'])
+                        return 0;
+
+                    return $iWay * ($aItem1['order'] < $aItem2['order'] ? -1 : 1);
+                });
+            }
+        }
+    }
+
+    public function _getStructureAPI($mixedItem, $aBp, &$iLevel, &$aStructure)
+    {
+        $bItem = !empty($mixedItem) && is_array($mixedItem);
+
+        $iCmtId = $bItem ? (int)$mixedItem['cmt_id'] : 0;
+        $sCmtIndex = 'i' . $iCmtId;
+
+        if($bItem) {
+            $aMenuActions = [];
+            if(($oMenuActions = BxDolMenu::getObjectInstance($this->_sMenuObjActions)) !== false) {
+                $oMenuActions->setCmtsData($this, $iCmtId, $aBp);
+                $aMenuActions = $oMenuActions->getCodeAPI();
+            }
+
+            $aMenuManage = [];
+            if(($oMenuManage = BxDolMenu::getObjectInstance($this->_sMenuObjManage)) !== false) {
+                $oMenuManage->setCmtsData($this, $iCmtId, $aBp);
+                if($oMenuManage->isVisible())
+                    $aMenuManage = $oMenuManage->getShortCodeAPI();
+            }
+
+            bx_import('BxDolEmbed');
+            $aData = $this->getDataAPI(array_merge($this->getCommentSimple($iCmtId), [
+                'embed' => bx_linkify_embeded($aData['cmt_text']),
+                'menu_actions' => $aMenuActions,
+                'menu_manage' => $aMenuManage,
+            ]));
+
+            $aStructure[$sCmtIndex] = [
+                'id' => $iCmtId, 
+                'order' => isset($mixedItem['cmt_order']) ? $mixedItem['cmt_order'] : 0, 
+                'data' => $aData,
+                'files' => $this->_getAttachments($mixedItem),
+                'items' => [],
+            ];
+        }
+
+        if(!$bItem || (int)$mixedItem['cmt_replies'] > 0) {
+            $aItems = $this->_oQuery->getStructure($this->_iId, $this->_iAuthorId, $iCmtId, $aBp['filter'], $aBp['order']);
+            if(!empty($aItems)) {
+                if($bItem && $iLevel < (int)$this->_aSystem['number_of_levels']) {
+                    $iPassLevel = $iLevel + 1;
+                    $aPassStructure = &$aStructure[$sCmtIndex]['items'];
+                }
+                else {
+                    $iPassLevel = $iLevel;
+                    $aPassStructure = [];
+                }
+                
+                foreach($aItems as $aItem)
+                    $this->_getStructureAPI($aItem, $aBp, $iPassLevel, $aPassStructure);
+                
+                //--- Sort subitems
+                $iWay = isset($aBp['order']['way']) && $aBp['order']['way'] == 'desc' ? -1 : 1;
+
+                uasort($aPassStructure, function($aItem1, $aItem2) use ($iWay) {
+                    if($aItem1['order'] == $aItem2['order'])
+                        return 0;
+
+                    return $iWay * ($aItem1['order'] < $aItem2['order'] ? -1 : 1);
+                });
+
+                $aStructure[$sCmtIndex]['items'] = $aPassStructure;
+            }
+        }
+    }
+
+    public function getDataAPI($aData, $aParams = [])
+    {
+        $aDataApi = array_merge($aData, [
+            'cmt_url' => bx_api_get_relative_url($this->getItemUrlApi($aData['cmt_id'])),
+            'author_data' => BxDolProfile::getData($aData['cmt_author_id']),
+            'author_badges' => BxDolProfile::getInstance($aData['cmt_author_id'])->getBadges()
+        ]);
+
+        $sModule = $this->_aSystem['module'];
+        $aExtras = [
+            'module' => $sModule,
+            'data' => $aData,
+            'params' => $aParams,
+            'data_api' => &$aDataApi,
+            'data_api_ref' => &$aDataApi,
+        ];
+
+        /**
+         * @hooks
+         * @hookdef hook-system-decode_comment_data_api 'system', 'decode_comment_data_api' - hook to override comment data prepared for sending in API response
+         * - $unit_name - equals `system`
+         * - $action - equals `decode_comment_data_api`
+         * - $object_id - not used
+         * - $sender_id - not used
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `module` - [string] module name
+         *      - `data` - [array] comment info array as key&value pairs
+         *      - `params` - [array] params array as key&value pairs
+         *      - `data_api` - [array] by ref, comment data prepared for sending in API response, can be overridden in hook processing
+         * @hook @ref hook-system-decode_comment_data_api
+         */
+        bx_alert('system', 'decode_comment_data_api', 0, 0, $aExtras);
+        
+        /**
+         * @hooks
+         * @hookdef hook-bx_dol_comment-decode_comment_data_api '{object_name}', 'decode_comment_data_api' - hook to override comment data prepared for sending in API response
+         * It's equivalent to @ref hook-system-decode_comment_data_api
+         * @hook @ref hook-bx_dol_comment-decode_comment_data_api
+         */
+        bx_alert($sModule, 'decode_comment_data_api', 0, 0, $aExtras);
+
+        return $aDataApi;
+    }
+}
+
+/** @} */

+ 950 - 0
upgrade/files/15.0.0.B3-15.0.0.RC1/files/inc/classes/BxDolCmtsQuery.php

@@ -0,0 +1,950 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    UnaCore UNA Core
+ * @{
+ */
+
+/**
+ * @see BxDolCmts
+ */
+class BxDolCmtsQuery extends BxDolDb
+{
+    protected $_oMain;
+
+    protected $_sTable;
+    protected $_sTriggerTable;
+    protected $_sTriggerFieldId;
+    protected $_sTriggerFieldAuthor;
+    protected $_sTriggerFieldTitle;
+    protected $_sTriggerFieldComments;
+
+    protected $_sTableFiles;
+    protected $_sTableFiles2Entries;
+
+    protected $_sTableSystems;
+    protected $_sTableIds;
+
+    public function __construct(&$oMain)
+    {
+        $this->_sTableSystems = BxDolCmts::$sTableSystems;
+        $this->_sTableIds = BxDolCmts::$sTableIds;
+
+        $this->_oMain = $oMain;
+
+        $this->_sTableFiles = $this->_oMain->getTableNameImages();
+        $this->_sTableFiles2Entries = $this->_oMain->getTableNameImages2Entries();
+
+        $aSystem = $this->_oMain->getSystemInfo();
+        $this->_sTable = $aSystem['table'];
+        $this->_sTriggerTable = $aSystem['trigger_table'];
+        $this->_sTriggerFieldId = $aSystem['trigger_field_id'];
+        $this->_sTriggerFieldAuthor = $aSystem['trigger_field_author'];
+        $this->_sTriggerFieldTitle = $aSystem['trigger_field_title'];
+        $this->_sTriggerFieldComments = $aSystem['trigger_field_comments'];
+
+        parent::__construct();
+    }
+
+    public static function getSystemBy($aParams)
+    {
+        $oDb = BxDolDb::getInstance();
+
+        $aMethod = ['name' => 'getAll', 'params' => [0 => 'query', 1 => []]];
+        $sSelectClause = $sJoinClause = $sWhereClause = $sOrderClause = $sLimitClause = "";
+
+        $sSelectClause = "`ts`.*";
+
+        switch($aParams['type']) {
+            case 'name':
+                $aMethod['name'] = 'getRow';
+                $aMethod['params'][1]['name'] = $aParams['name'];
+
+                $sWhereClause .= " AND `ts`.`Name` = :name";
+                break;
+
+            case 'all':
+                break;
+        }
+
+        if(!empty($sOrderClause))
+            $sOrderClause = 'ORDER BY ' . $sOrderClause;
+
+        if(!empty($sLimitClause))
+            $sLimitClause = 'LIMIT ' . $sLimitClause;
+
+        $aMethod['params'][0] = "SELECT " . $sSelectClause . " FROM `" . BxDolCmts::$sTableSystems . "` AS `ts` " . $sJoinClause . " WHERE 1 " . $sWhereClause . " " . $sOrderClause . " " . $sLimitClause;
+        return call_user_func_array(array($oDb, $aMethod['name']), $aMethod['params']);
+    }
+
+    public static function getInfoBy($aParams)
+    {
+        $oDb = BxDolDb::getInstance();
+
+        $aMethod = array('name' => 'getAll', 'params' => array(0 => 'query', 1 => array()));
+        $sSelectClause = $sJoinClause = $sWhereClause = $sOrderClause = $sLimitClause = "";
+        
+        $sSelectClause = "`ti`.*";
+
+        switch($aParams['type']) {
+            case 'uniq_id':
+                $aMethod['name'] = 'getRow';
+                $aMethod['params'][1]['uniq_id'] = (int)$aParams['uniq_id'];
+
+                $sWhereClause .= " AND `ti`.`id` = :uniq_id";
+                break;
+
+            case 'all':
+                if(isset($aParams['count']) && $aParams['count'] === true) {
+                    $aMethod['name'] = 'getOne';
+                    $sSelectClause = "COUNT(`ti`.`id`)";
+                }
+                break;
+        }
+
+        if(!empty($sOrderClause))
+            $sOrderClause = 'ORDER BY ' . $sOrderClause;
+
+        if(!empty($sLimitClause))
+            $sLimitClause = 'LIMIT ' . $sLimitClause;
+
+        $aMethod['params'][0] = "SELECT " . $sSelectClause . " FROM `" . BxDolCmts::$sTableIds . "` AS `ti` " . $sJoinClause . " WHERE 1 " . $sWhereClause . " " . $sOrderClause . " " . $sLimitClause;
+        return call_user_func_array(array($oDb, $aMethod['name']), $aMethod['params']);
+    }
+
+    public static function getInfoByUniqId($iUniqId)
+    {
+        $oDb = BxDolDb::getInstance();
+
+        $sQuery = "SELECT 
+                `ti`.`cmt_id` AS `cmt_id`, 
+                `to`.`Name` AS `system_name`, 
+                `to`.`Table` AS `table_name` 
+            FROM `" . BxDolCmts::$sTableIds . "` AS `ti` 
+            INNER JOIN  `" . BxDolCmts::$sTableSystems . "` AS `to` ON  `ti`.`system_id` = `to`.`ID`
+            WHERE `ti`.`id` = :uniq_ig 
+            LIMIT 1";
+
+        $aRow = $oDb->getRow($sQuery, array('uniq_ig' => $iUniqId));
+        if(empty($aRow) || !is_array($aRow))
+            return $aRow;
+
+        $aRow['cmt_object_id'] = $oDb->getOne("SELECT `cmt_object_id` FROM `" . $aRow['table_name'] . "` WHERE `cmt_id` = :cmt_id LIMIT 1", array(
+            'cmt_id' => $aRow['cmt_id']
+        ));
+
+        return $aRow;
+    }
+
+    /**
+     * @deprecated since version 12.0.1
+     */
+    public static function getCommentByUniq ($iUnicId)
+    {
+        return self::getInfoByUniqId($iUnicId);
+    }
+
+    public static function getCommentSimpleByUniqId($iUniqId)
+    {
+        $oDb = BxDolDb::getInstance();
+
+        $sQuery = "SELECT 
+                `ti`.`cmt_id` AS `cmt_id`, 
+                `to`.`Table` AS `cmt_table` 
+            FROM `" . BxDolCmts::$sTableIds . "` as `ti` 
+            INNER JOIN  `" . BxDolCmts::$sTableSystems . "` as `to` ON  `ti`.`system_id` = `to`.`ID`
+            WHERE `ti`.`id` = :uniq_ig 
+            LIMIT 1";
+
+        $aData = $oDb->getRow($sQuery, array('uniq_ig' => $iUniqId));
+        if(empty($aData) || !is_array($aData))
+            return array();
+
+        return $oDb->getRow("SELECT * FROM `" . $aData['cmt_table'] . "` WHERE `cmt_id` = :cmt_id LIMIT 1", array(
+            'cmt_id' => $aData['cmt_id']
+        ));
+    }
+
+    public static function getCommentExtendedByUniqId($iUniqId)
+    {
+        $oDb = BxDolDb::getInstance();
+
+        $sQuery = "SELECT 
+                `ti`.`cmt_id` AS `cmt_id`, 
+                `ti`.`system_id` AS `cmt_system_id`, 
+                `to`.`Name` AS `system_name`,
+                `to`.`Table` AS `cmt_table` 
+            FROM `" . BxDolCmts::$sTableIds . "` AS `ti` 
+            INNER JOIN  `" . BxDolCmts::$sTableSystems . "` AS `to` ON  `ti`.`system_id` = `to`.`ID`
+            WHERE `ti`.`id` = :uniq_ig 
+            LIMIT 1";
+
+        $aData = $oDb->getRow($sQuery, array('uniq_ig' => $iUniqId));
+        if(empty($aData) || !is_array($aData))
+            return array();
+
+        $sQuery = "SELECT 
+                `tc`.*,
+                `ti`.`rate`, `ti`.`votes`,
+                `ti`.`rrate`, `ti`.`rvotes`,
+                `ti`.`score`, `ti`.`sc_up`, `ti`.`sc_down`,
+                `ti`.`reports`,
+                :system_name AS `system_name`
+            FROM `" . $aData['cmt_table'] . "` AS `tc`
+            LEFT JOIN `" . BxDolCmts::$sTableIds . "` AS `ti` ON `ti`.`system_id` = :cmt_system_id AND `tc`.`cmt_id` = `ti`.`cmt_id` 
+            WHERE `tc`.`cmt_id` = :cmt_id 
+            LIMIT 1";       
+
+        return $oDb->getRow($sQuery, array(
+            'cmt_id' => $aData['cmt_id'],
+            'cmt_system_id' => $aData['cmt_system_id'],
+            'system_name' => $aData['system_name']
+        ));
+    }
+
+    function getTableName ()
+    {
+        return $this->_sTable;
+    }
+
+    /**
+     * @deprecated since version 10.0.0-B3 and can be removed in later versions.
+     */
+    function setTableNameFiles($sTable)
+    {
+    	$this->_sTableFiles = $sTable;
+    }
+
+    /**
+     * @deprecated since version 10.0.0-B3 and can be removed in later versions.
+     */
+    function setTableNameFiles2Entries($sTable)
+    {
+    	$this->_sTableFiles2Entries = $sTable;
+    }
+
+    function getCommentsCountAll ($iId, $iAuthorId = 0, $bForceCalculate = false)
+    {
+        $iCount = false;
+        /**
+         * @hooks
+         * @hookdef hook-comment-get_comments_count 'comment', 'get_comments_count' - hook to override number of comments for commented object
+         * - $unit_name - equals `comment`
+         * - $action - equals `get_comments_count`
+         * - $object_id - not used
+         * - $sender_id - profile id
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `system` - [string] comment object name
+         *      - `object_id` - [int] commented object id
+         *      - `result` - [int] by ref, number of comments, can be overridden in hook processing
+         * @hook @ref hook-comment-get_comments_count
+         */
+        bx_alert('comment', 'get_comments_count', 0, $iAuthorId, [
+            'system' => $this->_oMain->getSystemInfo(), 
+            'object_id' => $iId, 
+            'result' => &$iCount
+        ]);
+        if ($iCount !== false)
+            return $iCount;
+
+        if ($this->_sTriggerFieldComments && !$bForceCalculate)
+            return (int)$this->getOne("SELECT `{$this->_sTriggerFieldComments}` FROM `{$this->_sTriggerTable}` WHERE `{$this->_sTriggerFieldId}` = :id", [
+                'id' => $iId
+            ]);
+        else
+            return $this->getCommentsCount($iId, -1, $iAuthorId);
+    }
+
+    function getCommentsCount ($iId, $iCmtVParentId = -1, $iAuthorId = 0, $sFilter = '')
+    {
+    	$aBindings = array(
+            'cmt_object_id' => $iId,
+            'system_id' => $this->_oMain->getSystemId()
+    	);
+
+        $sWhereClause = $this->getCommentsCheckStatus($iAuthorId);
+
+        if((int)$iCmtVParentId >= 0) {
+            $aBindings['cmt_vparent_id'] = $iCmtVParentId;
+
+            $sWhereClause .= " AND `{$this->_sTable}`.`cmt_vparent_id` = :cmt_vparent_id";
+        }
+
+        $sJoinClause = '';
+        switch($sFilter) {
+            case BX_CMT_FILTER_FRIENDS:
+            case BX_CMT_FILTER_SUBSCRIPTIONS:
+                $oConnection = BxDolConnection::getObjectInstance($this->_oMain->getConnectionObject($sFilter));
+
+                $aQueryParts = $oConnection->getConnectedContentAsSQLParts($this->_sTable, 'cmt_author_id', $iAuthorId);
+                $sJoinClause .= ' ' . $aQueryParts['join'];
+                break;
+
+            case BX_CMT_FILTER_OTHERS:
+                $aBindings['cmt_author_id'] = $iAuthorId;
+
+                $sWhereClause .= " AND `{$this->_sTable}`.`cmt_author_id` <> :cmt_author_id";
+                break;
+        }
+
+        if(($oCf = $this->_oMain->getObjectContentFilter()) !== false)
+            $sWhereClause .= $oCf->getSQLParts($this->_sTable, 'cmt_cf');
+
+        /**
+         * @hooks
+         * @hookdef hook-comment-get_comments 'comment', 'get_comments' - hook to override comments list. Is used during comments count retrieving.
+         * - $unit_name - equals `comment`
+         * - $action - equals `get_comments`
+         * - $object_id - not used
+         * - $sender_id - currently logged in profile id
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `system` - [string] comment object 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
+         *      - `params` - [array] by ref, SQL query bindings array as key&value pairs, can be overridden in hook processing
+         * @hook @ref hook-comment-get_comments
+         */
+        bx_alert('comment', 'get_comments', 0, bx_get_logged_profile_id(), [
+            'system' => $this->_oMain->getSystemInfo(), 
+            'join_clause' => &$sJoinClause, 
+            'where_clause' => &$sWhereClause, 
+            'params' => &$aBindings,
+            'join_clause_ref' => &$sJoinClause, 
+            'where_clause_ref' => &$sWhereClause, 
+            'params_ref' => &$aBindings
+        ]);
+        
+        $sQuery = "SELECT
+                COUNT(*) 
+            FROM `{$this->_sTable}` 
+            LEFT JOIN `{$this->_sTableIds}` ON (`{$this->_sTable}`.`cmt_id` = `{$this->_sTableIds}`.`cmt_id` AND `{$this->_sTableIds}`.`system_id` = :system_id) $sJoinClause 
+            WHERE `{$this->_sTable}`.`cmt_object_id` = :cmt_object_id" . $sWhereClause;
+        return (int)$this->getOne($sQuery, $aBindings);
+    }
+
+    function getStructure($iObjectId, $iAuthorId = 0, $iParentId = 0, $sFilter = '', $aOrder = array())
+    {
+        $sSelectClause = $sJoinClause = $sWhereClause = "";
+
+    	$aBindings = array(
+            'cmt_object_id' => $iObjectId,
+            'system_id' => $this->_oMain->getSystemId()
+    	);
+
+        if((int)$iParentId >= 0) {
+            $aBindings['cmt_parent_id'] = $iParentId;
+
+            $sWhereClause .= " AND `tc`.`cmt_parent_id` = :cmt_parent_id";
+        }
+
+        if(in_array($sFilter, array(BX_CMT_FILTER_FRIENDS, BX_CMT_FILTER_SUBSCRIPTIONS))) {
+            $sConnection = $this->_oMain->getConnectionObject($sFilter);
+            $aQueryParts = BxDolConnection::getObjectInstance($sConnection)->getConnectedContentAsSQLParts($this->_sTable, 'cmt_author_id', $iAuthorId);
+            $sJoinClause .= ' ' . $aQueryParts['join'];
+        }
+
+        if(isset($aOrder['by']) && isset($aOrder['way']))
+            switch($aOrder['by']) {
+                case BX_CMT_ORDER_BY_DATE:
+                    $sSelectClause .= ", `tc`.`cmt_time` AS `cmt_order`";
+                    break;
+
+                case BX_CMT_ORDER_BY_POPULAR:
+                    $aOrderFields = array();
+                    if($this->_oMain->getVoteObject(0) !== false)
+                        $aOrderFields[] = "`ti`.`votes`";
+                    if($this->_oMain->getScoreObject(0) !== false)
+                        $aOrderFields[] = "`ti`.`score`";
+                    
+                    if(!empty($aOrderFields))
+                        $sSelectClause .= ", (" . implode(' + ', $aOrderFields) . ") AS `cmt_order`";
+                    else
+                        $sSelectClause .= ", `tc`.`id` AS `cmt_order`";
+                    break;
+            }
+
+        bx_alert('comment', 'get_comments', 0, $iAuthorId, [
+            'data_type' => 'structure',
+            'system' => $this->_oMain->getSystemInfo(), 
+            'select_clause' => &$sSelectClause, 
+            'join_clause' => &$sJoinClause, 
+            'where_clause' => &$sWhereClause,  
+            'params' => &$aBindings,
+            'select_clause_ref' => &$sSelectClause, 
+            'join_clause_ref' => &$sJoinClause, 
+            'where_clause_ref' => &$sWhereClause,  
+            'params_ref' => &$aBindings
+        ]);
+        
+        $sQuery = "SELECT
+                `tc`.`cmt_id`, 
+                `tc`.`cmt_replies`, 
+                `tc`.`cmt_time` $sSelectClause
+            FROM `{$this->_sTable}` AS `tc`
+            LEFT JOIN `{$this->_sTableIds}` AS `ti` ON `tc`.`cmt_id` = `ti`.`cmt_id` AND `ti`.`system_id` = :system_id $sJoinClause
+            WHERE `tc`.`cmt_object_id` = :cmt_object_id" . $sWhereClause;
+        
+       
+        
+        return $this->getAll($sQuery, $aBindings);
+    }
+
+    function getComments ($iId, $iCmtVParentId = 0, $iAuthorId = 0, $sFilter = '', $aOrder = array(), $iStart = 0, $iCount = -1)
+    {
+    	$aBindings = array(
+            'cmt_object_id' => $iId,
+            'system_id' => $this->_oMain->getSystemId()
+    	);
+        $sFields = $sJoin = "";
+
+        $sWhereStatus = $this->getCommentsCheckStatus($iAuthorId);
+
+        $sWhereParent = '';
+        if((int)$iCmtVParentId >= 0) {
+            $aBindings['cmt_vparent_id'] = $iCmtVParentId;
+
+            $sWhereParent = " AND `{$this->_sTable}`.`cmt_vparent_id` = :cmt_vparent_id";
+        }
+
+        $sWhereFilter = '';
+        switch($sFilter) {
+            case BX_CMT_FILTER_PINNED:
+                $sWhereFilter .= " AND `{$this->_sTable}`.`cmt_pinned` <> 0";
+                break;
+
+            case BX_CMT_FILTER_FRIENDS:
+            case BX_CMT_FILTER_SUBSCRIPTIONS:
+                $oConnection = BxDolConnection::getObjectInstance($this->_oMain->getConnectionObject($sFilter));
+
+                $aQueryParts = $oConnection->getConnectedContentAsSQLParts($this->_sTable, 'cmt_author_id', $iAuthorId);
+                $sJoin .= ' ' . $aQueryParts['join'];
+                break;
+        }
+
+        $sWhereCf = '';
+        if(($oCf = $this->_oMain->getObjectContentFilter()) !== false)
+            $sWhereCf = $oCf->getSQLParts($this->_sTable, 'cmt_cf');
+
+        $sOrder = " ORDER BY `{$this->_sTable}`.`cmt_pinned` DESC, `{$this->_sTable}`.`cmt_time` ASC";
+        if(isset($aOrder['by']) && isset($aOrder['way'])) {
+            $aOrder['way'] = strtoupper(in_array($aOrder['way'], array(BX_CMT_ORDER_WAY_ASC, BX_CMT_ORDER_WAY_DESC)) ? $aOrder['way'] : BX_CMT_ORDER_WAY_ASC);
+
+            switch($aOrder['by']) {
+                case BX_CMT_ORDER_BY_DATE:
+                    $sOrder = " ORDER BY `{$this->_sTable}`.`cmt_time` " . $aOrder['way'];
+                    break;
+
+                case BX_CMT_ORDER_BY_POPULAR:
+                    $aSortFields = array();
+                    if($this->_oMain->getVoteObject(0) !== false)
+                        array_push($aSortFields, '`' . $this->_sTableIds . '`.`votes`');
+                    if($this->_oMain->getReactionObject(0) !== false)
+                        array_push($aSortFields, '`' . $this->_sTableIds . '`.`rvotes`');
+                    if($this->_oMain->getScoreObject(0) !== false)
+                        array_push($aSortFields, '`' . $this->_sTableIds . '`.`score`');
+                    if(count($aSortFields) == 0)
+                        array_push($aSortFields, '`' . $this->_sTable . '`.`id`');
+
+                    $sOrder = " ORDER BY " . implode($aOrder['way'] . ', ', $aSortFields) . " " . $aOrder['way'];
+                    break;
+            }
+        }
+
+       	$sLimit = $iCount != -1 ? $this->prepareAsString(" LIMIT ?, ?", (int)$iStart, (int)$iCount) : '';
+
+        $sWhereClause = $sWhereStatus . $sWhereParent . $sWhereFilter . $sWhereCf;
+
+        $sQuery = "SELECT
+                `{$this->_sTable}`.*,
+                `{$this->_sTableIds}`.`id` AS `cmt_unique_id`,
+                `{$this->_sTableIds}`.`status_admin` AS `cmt_status_admin`
+                $sFields
+            FROM `{$this->_sTable}`
+            LEFT JOIN `{$this->_sTableIds}` ON (`{$this->_sTable}`.`cmt_id` = `{$this->_sTableIds}`.`cmt_id` AND `{$this->_sTableIds}`.`system_id` = :system_id) 
+            LEFT JOIN `sys_profiles` AS `p` ON `p`.`id` = `{$this->_sTable}`.`cmt_author_id`";
+
+        /**
+         * @hooks
+         * @hookdef hook-comment-get_comments 'comment', 'get_comments' - hook to override comments list.
+         * - $unit_name - equals `comment`
+         * - $action - equals `get_comments`
+         * - $object_id - not used
+         * - $sender_id - profile id
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `system` - [string] comment object name
+         *      - `select_clause` - [string] by ref, 'select' part of SQL query, can be overridden in hook processing
+         *      - `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
+         *      - `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
+         *      - `params` - [array] by ref, SQL query bindings array as key&value pairs, can be overridden in hook processing
+         * @hook @ref hook-comment-get_comments
+         */
+        bx_alert('comment', 'get_comments', 0, $iAuthorId, [
+            'system' => $this->_oMain->getSystemInfo(), 
+            'select_clause' => &$sQuery, 
+            'join_clause' => &$sJoin, 
+            'where_clause' => &$sWhereClause, 
+            'order_clause' => &$sOrder, 
+            'limit_clause' => &$sLimit, 
+            'params' => &$aBindings,
+            'select_clause_ref' => &$sQuery, 
+            'join_clause_ref' => &$sJoin, 
+            'where_clause_ref' => &$sWhereClause, 
+            'order_clause_ref' => &$sOrder, 
+            'limit_clause_ref' => &$sLimit, 
+            'params_ref' => &$aBindings
+        ]);
+
+        $sQuery = $sQuery . $sJoin . " WHERE `{$this->_sTable}`.`cmt_object_id`=:cmt_object_id AND (ISNULL(`p`.`status`) OR `p`.`status`='active' OR `{$this->_sTable}`.`cmt_replies`!=0)" . $sWhereClause . $sOrder . $sLimit;
+
+        return $this->getAll($sQuery, $aBindings);
+    }
+
+    protected function getCommentsCheckStatus($iAuthorId, $sStatus = BX_CMT_STATUS_ACTIVE)
+    {
+        if($this->_oMain->isModerator()) 
+            return '';
+
+        //--- Check viewer as comment author.
+        $sWhereClause = $this->prepareAsString("`{$this->_sTable}`.`cmt_author_id`=?", $iAuthorId);
+
+        //--- Check viewer as an administrator/moderator of comment author.
+        $aGroups = [];
+        $aModules = bx_srv('system', 'get_modules_by_type', ['profile']);
+        foreach($aModules as $aModule) {
+            $oModule = BxDolModule::getInstance($aModule['name']);
+            if(!$oModule || !($oModule instanceof BxBaseModGroupsModule))
+                continue;
+
+            $aGroups = array_merge($aGroups, $oModule->getGroupsByFan($iAuthorId, [
+                BX_BASE_MOD_GROUPS_ROLE_ADMINISTRATOR,
+                BX_BASE_MOD_GROUPS_ROLE_MODERATOR
+            ]));
+        }
+
+        if(!empty($aGroups))
+            $sWhereClause .= " OR `{$this->_sTable}`.`cmt_author_id` IN (" . $this->implode_escape($aGroups) . ")";
+
+        return $this->prepareAsString(" AND IF(" . $sWhereClause . ", 1, `{$this->_sTableIds}`.`status_admin`=?) ", $sStatus);
+    }
+
+    function getCommentsBy($aParams = array())
+    {
+    	$aMethod = array('name' => 'getAll', 'params' => array(0 => 'query', 1 => array()));
+        $sSelectClause = $sJoinClause = $sWhereClause = $sOrderClause = $sLimitClause = "";
+
+        $sSelectClause = "`{$this->_sTable}`.*";
+
+        if(isset($aParams['object_id'])) {
+            $aMethod['params'][1]['cmt_object_id'] = (int)$aParams['object_id'];
+
+            $sWhereClause .= " AND `{$this->_sTable}`.`cmt_object_id` = :cmt_object_id";
+        }
+
+        switch($aParams['type']) {
+            case 'id':
+                $aMethod['name'] = 'getRow';
+                $aMethod['params'][1]['id'] = (int)$aParams['id'];
+
+                $sWhereClause .= " AND `{$this->_sTable}`.`cmt_id` = :id";
+                break;
+
+            case 'uniq_id':
+                $aMethod['name'] = 'getRow';
+                $aMethod['params'][1]['system_id'] = $this->_oMain->getSystemId();
+                $aMethod['params'][1]['uniq_id'] = (int)$aParams['uniq_id'];
+
+                $sJoinClause = "LEFT JOIN `{$this->_sTableIds}` ON `{$this->_sTable}`.`cmt_id` = `{$this->_sTableIds}`.`cmt_id` AND `{$this->_sTableIds}`.`system_id` = :system_id";
+                $sWhereClause .= " AND `{$this->_sTableIds}`.`id` = :uniq_id";
+                break;
+
+            case 'latest':
+                if(!empty($aParams['object_id'])) {
+                    $aMethod['params'][1]['cmt_object_id'] = (int)$aParams['object_id'];
+
+                    $sWhereClause .= " AND `{$this->_sTable}`.`cmt_object_id` = :cmt_object_id";
+                }
+
+            	if(!empty($aParams['author'])) {
+                    $aMethod['params'][1]['cmt_author_id'] = (int)$aParams['author'];
+
+                    $sWhereClause .= " AND `{$this->_sTable}`.`cmt_author_id` " . (isset($aParams['others']) && (int)$aParams['others'] == 1 ? "<>" : "=") . " :cmt_author_id";
+            	}
+
+                $sOrderClause = "`{$this->_sTable}`.`cmt_time` DESC";
+                $sLimitClause = "";
+                if(isset($aParams['per_page']))
+                    $sLimitClause = $this->prepareAsString("?, ?", $aParams['start'], $aParams['per_page']);
+
+                break;
+
+            case 'parent_id':
+                $aMethod['params'][1]['cmt_parent_id'] = (int)$aParams['parent_id'];
+
+                $sWhereClause .= " AND `{$this->_sTable}`.`cmt_parent_id` = :cmt_parent_id";
+
+                $sOrderClause = "`{$this->_sTable}`.`cmt_time` ASC";
+                $sLimitClause = "";
+                if(isset($aParams['per_page']))
+                    $sLimitClause = $this->prepareAsString("?, ?", $aParams['start'], $aParams['per_page']);
+
+                break;
+
+            case 'object_id':
+                $aMethod['params'][1]['cmt_object_id'] = (int)$aParams['object_id'];
+
+                $sWhereClause .= " AND `{$this->_sTable}`.`cmt_object_id` = :cmt_object_id";
+
+                $sOrderClause = "`{$this->_sTable}`.`cmt_time` " . (!empty($aParams['order_way']) ? strtoupper($aParams['order_way']) : "ASC");
+                $sLimitClause = "";
+                if(isset($aParams['per_page']))
+                    $sLimitClause = $this->prepareAsString("?, ?", $aParams['start'], $aParams['per_page']);
+
+                break;
+
+            case 'author_id':
+                $aMethod['params'][1]['cmt_author_id'] = (int)$aParams['author_id'];
+
+                $sWhereClause .= " AND `{$this->_sTable}`.`cmt_author_id` = :cmt_author_id";
+
+                $sOrderClause = "`{$this->_sTable}`.`cmt_time` ASC";
+                $sLimitClause = "";
+                if(isset($aParams['per_page']))
+                    $sLimitClause = $this->prepareAsString("?, ?", $aParams['start'], $aParams['per_page']);
+
+                break;
+
+            case 'search_ids':
+                $aMethod['name'] = 'getColumn';
+
+                $sSelectClause = "`{$this->_sTable}`.`cmt_id`";
+
+                if (!empty($aParams['start']) && !empty($aParams['per_page']))
+                    $sLimitClause = $this->prepareAsString("?, ?", $aParams['start'], $aParams['per_page']);
+                elseif (!empty($aParams['per_page']))
+                    $sLimitClause = $this->prepareAsString("?", $aParams['per_page']);
+
+                BxDolSearchExtended::processParams($aParams['search_params'], [
+                    'table' => $this->_sTable,
+                    'bindings' => &$aMethod['params'][1],
+                    'where_clause' => &$sWhereClause,
+                    'bindings_ref' => &$aMethod['params'][1],
+                    'where_clause_ref' => &$sWhereClause
+                ]);
+
+                if(($oCf = $this->_oMain->getObjectContentFilter()) !== false)
+                    $sWhereClause .= $oCf->getSQLParts($this->_sTable, 'cmt_cf');
+
+                $sOrderClause .=  "`{$this->_sTable}`.`cmt_time` ASC";
+                break;
+
+            case 'all_ids':
+                $aMethod['name'] = 'getColumn';
+
+                $sSelectClause = "`{$this->_sTable}`.`cmt_id`";
+                $sOrderClause =  "`{$this->_sTable}`.`cmt_time` ASC";
+                break;
+        }
+
+        if(!empty($sOrderClause))
+            $sOrderClause = 'ORDER BY ' . $sOrderClause;
+
+        if(!empty($sLimitClause))
+            $sLimitClause = 'LIMIT ' . $sLimitClause;
+
+        $aMethod['params'][0] = "SELECT " . $sSelectClause . " FROM `{$this->_sTable}` " . $sJoinClause . " WHERE 1 " . $sWhereClause . " " . $sOrderClause . " " . $sLimitClause;
+        return call_user_func_array(array($this, $aMethod['name']), $aMethod['params']);
+    }
+
+    function getComment ($iId, $iCmtId)
+    {
+        $sFields = $sJoin = "";
+
+        $oVote = $this->_oMain->getVoteObject($iCmtId);
+        if($oVote !== false) {
+            $aSql = $oVote->getSqlParts($this->_sTableIds, 'id');
+
+            $sFields .= $aSql['fields'];
+            $sJoin .= $aSql['join'];
+        }
+
+        $sQuery = $this->prepare("SELECT
+                `{$this->_sTable}`.*,
+                `{$this->_sTableIds}`.`id` AS `cmt_unique_id`,
+                `{$this->_sTableIds}`.`status_admin` AS `cmt_status_admin`
+                $sFields
+            FROM `{$this->_sTable}`
+            LEFT JOIN `{$this->_sTableIds}` ON (`{$this->_sTable}`.`cmt_id` = `{$this->_sTableIds}`.`cmt_id` AND `{$this->_sTableIds}`.`system_id` = ?)
+            $sJoin
+            WHERE `{$this->_sTable}`.`cmt_object_id` = ? AND `{$this->_sTable}`.`cmt_id` = ?
+            LIMIT 1", $this->_oMain->getSystemId(), $iId, $iCmtId);
+        return $this->getRow($sQuery);
+    }
+
+    function getCommentSimple ($iId, $iCmtId)
+    {
+        $sQuery = $this->prepare("SELECT * FROM {$this->_sTable} AS `c` WHERE `cmt_object_id` = ? AND `cmt_id` = ? LIMIT 1", $iId, $iCmtId);
+        return $this->getRow($sQuery);
+    }
+
+    function removeComment ($iId, $iCmtId, $iCmtParentId)
+    {
+        $sQuery = $this->prepare("DELETE FROM {$this->_sTable} WHERE `cmt_object_id` = ? AND `cmt_id` = ? LIMIT 1", $iId, $iCmtId);
+        if (!$this->query($sQuery))
+            return false;
+
+        if($iCmtParentId)
+            $this->updateRepliesCount($iCmtParentId, -1);
+
+        return true;
+    }
+
+    function saveImages($iSystemId, $iCmtId, $iImageId)
+    {
+        $sQuery = $this->prepare("INSERT IGNORE INTO `{$this->_sTableFiles2Entries}` SET `system_id`=?, `cmt_id`=?, `image_id`=?", $iSystemId, $iCmtId, $iImageId);
+        return (int)$this->query($sQuery) > 0;
+    }
+
+    function getFiles($iSystemId, $iCmtId, $iId = false)
+    {
+    	$aBindings = array(
+    		'system_id' => $iSystemId
+    	);
+
+        $sJoin = "";
+        $sWhere = " AND `tf2e`.`system_id` = :system_id ";
+
+        if($iCmtId !== false) {
+        	$aBindings['cmt_id'] = $iCmtId;
+
+            $sWhere .= " AND `tf2e`.`cmt_id` = :cmt_id ";
+        }
+
+        if($iId !== false) {
+        	$aBindings['cmt_object_id'] = $iId;
+
+            $sWhere .= " AND `te`.`cmt_object_id` = :cmt_object_id";
+            $sJoin .= " INNER JOIN `{$this->_sTable}` AS `te` ON (`tf2e`.`cmt_id` = `te`.`cmt_id`) ";
+        }
+
+        $sQuery = "SELECT 
+        		`tf2e`.*,
+        		`tf`.`file_name` AS `file_name`,
+        		`tf`.`mime_type` AS `mime_type`,
+        		`tf`.`size` AS `size`,
+                        `tf`.`dimensions` AS `dimensions`
+        	FROM `{$this->_sTableFiles2Entries}` AS `tf2e` 
+        	LEFT JOIN `{$this->_sTableFiles}` AS `tf` ON (`tf2e`.`image_id` = `tf`.`id`) " . $sJoin . " 
+        	WHERE 1 " . $sWhere;
+
+        return $this->getAll($sQuery, $aBindings);
+    }
+
+    public function getFileInfoById($iFileId)
+    {
+        $sQuery = "SELECT 
+                `tf2e`.*,
+                `tf`.`file_name` AS `file_name`,
+                `tf`.`mime_type` AS `mime_type`,
+                `tf`.`size` AS `size` 
+            FROM `{$this->_sTableFiles2Entries}` AS `tf2e` 
+            LEFT JOIN `{$this->_sTableFiles}` AS `tf` ON (`tf2e`.`image_id` = `tf`.`id`) 
+            WHERE `tf2e`.`id`=:id ";
+
+        return $this->getRow($sQuery, array(
+            'id' => $iFileId
+    	));
+    }
+
+    function deleteImages($iSystemId, $iCmtId, $iImageId = false)
+    {
+        $sWhereAddon = "";
+        $aBindings = array();
+
+        if ($iSystemId !== false) {
+            $aBindings['system_id'] = $iSystemId;
+
+            $sWhereAddon .= " AND `system_id` = :system_id ";
+        }
+
+        if ($iCmtId !== false) {
+            $aBindings['cmt_id'] = $iCmtId;
+
+            $sWhereAddon .= " AND `cmt_id` = :cmt_id ";
+        }
+
+        if ($iImageId !== false) {
+            $aBindings['image_id'] = $iImageId;
+
+            $sWhereAddon .= " AND `image_id` = :image_id ";
+        }
+
+        return $this->query("DELETE FROM `{$this->_sTableFiles2Entries}` WHERE 1" . $sWhereAddon, $aBindings);
+    }
+
+    function updateComments($aSetClause, $aWhereClause)
+    {
+        if(empty($aSetClause) || empty($aWhereClause))
+            return;
+
+        return (int)$this->query("UPDATE `{$this->_sTable}` SET " . $this->arrayToSQL($aSetClause) . " WHERE " . $this->arrayToSQL($aWhereClause)) > 0;
+    }
+
+    function updateRepliesCount($iCmtId, $iCount)
+    {
+        $sQuery = $this->prepare("UPDATE `{$this->_sTable}` SET `cmt_replies`=`cmt_replies`+? WHERE `cmt_id`=? LIMIT 1", $iCount, $iCmtId);
+        return $this->query($sQuery);
+    }
+
+    function deleteAuthorComments ($iAuthorId, &$aFiles = null, &$aCmtIds = null)
+    {
+        $aSystem = $this->_oMain->getSystemInfo();
+
+        $isDelOccured = 0;
+        $sQuery = $this->prepare("SELECT `cmt_id`, `cmt_parent_id` FROM {$this->_sTable} WHERE `cmt_author_id` = ? AND `cmt_replies` = 0", $iAuthorId);
+        $a = $this->getAll ($sQuery);
+		foreach ($a as $r) {
+            $sQuery = $this->prepare("DELETE FROM {$this->_sTable} WHERE `cmt_id` = ?", $r['cmt_id']);
+            $this->query ($sQuery);
+
+            $sQuery = $this->prepare("UPDATE {$this->_sTable} SET `cmt_replies` = `cmt_replies` - 1 WHERE `cmt_id` = ?", $r['cmt_parent_id']);
+            $this->query ($sQuery);
+
+            $aFilesMore = $this->convertImagesArray($this->getFiles($aSystem['system_id'], $r['cmt_id']));
+            $this->deleteImages($aSystem['system_id'], $r['cmt_id']);
+            if ($aFilesMore && null !== $aFiles)
+                $aFiles = array_merge($aFiles, $aFilesMore);
+
+            if (null !== $aCmtIds)
+                $aCmtIds[] = $r['cmt_id'];
+
+            $isDelOccured = 1;
+        }
+        $sQuery = $this->prepare("UPDATE {$this->_sTable} SET `cmt_author_id` = 0 WHERE `cmt_author_id` = ? AND `cmt_replies` != 0", $iAuthorId);
+        $this->query ($sQuery);
+        if ($isDelOccured)
+            $this->query ("OPTIMIZE TABLE {$this->_sTable}");
+    }
+
+    function deleteObjectComments ($iObjectId, &$aFilesReturn = null, &$aCmtIds = null)
+    {
+        $aSystem = $this->_oMain->getSystemInfo();
+        $aFiles = $this->convertImagesArray($this->getFiles($aSystem['system_id'], false, $iObjectId));
+
+        if ($aFiles) {
+            $sQuery = $this->prepare("DELETE FROM {$this->_sTableFiles2Entries} WHERE `system_id` = ? AND `image_id` IN(" . $this->implode_escape($aFiles) . ")", $aSystem['system_id']);
+            $this->query($sQuery);
+        }
+
+        if (null !== $aCmtIds) {
+            $sQuery = $this->prepare("SELECT `cmt_id` FROM {$this->_sTable} WHERE `cmt_object_id` = ?", $iObjectId);
+            $aCmtIds = $this->getColumn ($sQuery);
+        }
+
+        $sQuery = $this->prepare("DELETE FROM {$this->_sTable} WHERE `cmt_object_id` = ?", $iObjectId);
+        $this->query ($sQuery);
+        $this->query ("OPTIMIZE TABLE {$this->_sTable}");
+
+        if (null !== $aFilesReturn)
+            $aFilesReturn = $aFiles;
+    }
+
+    function deleteAll ($iSystemId, &$aFiles = null, &$aCmtIds = null)
+    {
+        // get files
+        if (null !== $aFiles)
+            $aFiles = $this->convertImagesArray($this->getFiles($iSystemId, false));
+
+        // delete files
+        $this->deleteImages($iSystemId, false);
+
+        if (null !== $aCmtIds)
+            $aCmtIds = $this->getColumn ("SELECT `cmt_id` FROM {$this->_sTable}");
+
+        // delete comments
+        $sQuery = $this->prepare("TRUNCATE TABLE {$this->_sTable}");
+        $this->query ($sQuery);
+    }
+
+    function deleteCmtIds ($iSystemId, $iCmtId)
+    {
+        $sQuery = $this->prepare("DELETE FROM {$this->_sTableIds} WHERE `system_id` = ? AND `cmt_id` = ?", $iSystemId, $iCmtId);
+        return $this->query ($sQuery);
+    }
+
+    function getObjectAuthorId($iId)
+    {
+        $sQuery = $this->prepare("SELECT `{$this->_sTriggerFieldAuthor}` FROM `{$this->_sTriggerTable}` WHERE `{$this->_sTriggerFieldId}` = ? LIMIT 1", $iId);
+        return $this->getOne($sQuery);
+    }
+
+    function getObjectTitle($iId)
+    {
+        $sQuery = $this->prepare("SELECT `{$this->_sTriggerFieldTitle}` FROM `{$this->_sTriggerTable}` WHERE `{$this->_sTriggerFieldId}` = ? LIMIT 1", $iId);
+        return $this->getOne($sQuery);
+    }
+
+    function getObjectPrivacyView($iId, $sField = '')
+    {
+        if(empty($sField)) {
+            $sField = 'allow_view_to';
+            if(!$this->isFieldExists($this->_sTriggerTable, $sField))
+                return false;
+        }
+
+        return $this->getOne("SELECT `{$sField}` FROM `{$this->_sTriggerTable}` WHERE `{$this->_sTriggerFieldId}` = :id LIMIT 1", array(
+            'id' => $iId
+        ));
+    }
+    
+
+    public function updateTriggerTable($iId, $iCount)
+    {
+        if (!$this->_sTriggerFieldComments)
+            return true;
+        $sQuery = $this->prepare("UPDATE `{$this->_sTriggerTable}` SET `{$this->_sTriggerFieldComments}` = ? WHERE `{$this->_sTriggerFieldId}` = ? LIMIT 1", $iCount, $iId);
+        return $this->query($sQuery);
+    }
+
+    public function getUniqId($iSystemId, $iCmtId, $aData = [])
+    {
+        $sQuery = $this->prepare("SELECT `id` FROM `{$this->_sTableIds}` WHERE `system_id` = ? AND `cmt_id` = ?", $iSystemId, $iCmtId);
+        if(($iUniqId = (int)$this->getOne($sQuery)) != 0)
+            return $iUniqId;
+
+        $aDataDefault = [
+            'system_id' => $iSystemId, 
+            'cmt_id' => $iCmtId,
+            'author_id' => bx_get_logged_profile_id()
+        ];
+
+        if(!$this->query("INSERT INTO `{$this->_sTableIds}` SET " . $this->arrayToSQL(array_merge($aDataDefault, $aData))))
+            return false;
+
+        return $this->lastId();
+    }
+
+    public function updateUniqId($aSetClause, $aWhereClause)
+    {
+        if(empty($aSetClause) || empty($aWhereClause))
+            return;
+
+        return (int)$this->query("UPDATE `{$this->_sTableIds}` SET " . $this->arrayToSQL($aSetClause) . " WHERE " . $this->arrayToSQL($aWhereClause)) > 0;
+    }
+
+    protected function convertImagesArray($a)
+    {
+        if (!$a || !is_array($a))
+            return array();
+
+        $aFiles = array ();
+        foreach ($a as $aFile)
+            $aFiles[] = $aFile['image_id'];
+        return $aFiles;
+    }
+}
+
+/** @} */

+ 2096 - 0
upgrade/files/15.0.0.B3-15.0.0.RC1/files/inc/classes/BxDolForm.php

@@ -0,0 +1,2096 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    UnaCore UNA Core
+ * @{
+ */
+
+define('BX_DOL_FORM_METHOD_GET', 'get');
+define('BX_DOL_FORM_METHOD_POST', 'post');
+define('BX_DOL_FORM_METHOD_SPECIFIC', 'specific');
+define('BX_DOL_FORM_METHOD_DEFAULT', BX_DOL_FORM_METHOD_POST);
+
+define('BX_DATA_LISTS_KEY_PREFIX', '#!');
+define('BX_DATA_VALUES_DEFAULT', 'LKey'); ///< Use default values for data items, @see BxDolForm::getDataItems
+define('BX_DATA_VALUES_ADDITIONAL', 'LKey2'); ///< Use additional values for data items, @see BxDolForm::getDataItems
+define('BX_DATA_VALUES_ALL', 'all'); ///< Return all available info for data items, @see BxDolForm::getDataItems
+
+bx_import('BxDolPrivacy');
+
+/**
+ * Forms allows to display forms from data stored in DB tables, before it was possible to display forms from PHP arrays only.
+ *
+ *
+ * The Form Objects have the following main advantages:
+ * - Minimal coding is needed to create different forms
+ * - Easy forms alterations
+ * - Multiple representations of the same form
+ * - Automated data inserting into database
+ * - Automated data updating
+ * - Automated data checking
+ * - Automatic security checking
+ * - Automatic spam filter
+ *
+ *
+ * Forms API uses several definitions:
+ * - Form or Form Object - record in sys_objects_form table, or instance of Form class.
+ * - Form Display - set of some form inputs in particular order, displayed for some purpose; one form can have several displays, for example add and edit displays.
+ * - Form Input or Form Field - form input field, like textarea, checkbox or set of radio buttons.
+ *
+ *
+ * @section form_creating_object Creating the Form Object
+ *
+ * 1. Create Form Object, add record to sys_objects_form table:
+ * - object - name of the Form Object, in the format: vendor prefix, underscore, module prefix, underscore, internal identifier or nothing; for example: bx_group - for group data processing, like group adding or editing.
+ * - title - Form Object title to display in studio forms builder.
+ * - action - url to submit form to, if url is not full and not empty, then site url is added automatically.
+ * - form_attrs - serialized array of additional form attributes.
+ * - submit_name - name of form field with submit button, it is used to determine if form is submitted.
+ * - table - DB table name (for automatic saving/updating).
+ * - key - DB table field with unique ID (for automatic updating).
+ * - uri - DB table field with URI (for automatic URI generation, aling with uri_title).
+ * - uri_title - DB table field with data title (for automatic URI generation, aling with uri).
+ * - params - serialized array of additional form parameters:
+ * - checker_helper - name of custom BxDolFormCheckerHelper class.
+ * - csrf - array of Cross-site request forgery attack prevention parameters, for now only one boolean parameter is supported - disabled, so it can be disabled for particular form.
+ * - active - 1 or 0, if form is inactive then it can not be used anywhere.
+ * - override_class_name - user defined class name which is derived from BxTemplFormView.
+ * - override_class_file - the location of the user defined class, leave it empty if class is located in system folders.
+ *
+ *
+ * 2. Create Form Displays, add records to sys_form_displays table:
+ * - display_name - name of the Form Display, in the format:
+ *                  form object name, underscore, internal identifier or nothing;
+ *                  for example: bx_group_add - for displaying group adding form, bx_group_edit - for displaying group editing form
+ * - module - module name this display belongs to, it must be associated with name field in sys_modules table.
+ * - object - form object name from sys_objects_form table this Form Display belongs to.
+ * - title - Form Display title to display in studio forms builder.
+ * - view_mode - display form as read-only.
+ *
+ *
+ * 3. Create Form Fields, add records to sys_form_inputs table:
+ * - object - form object name from sys_objects_form table this Form Field belongs to.
+ * - module - module name this field belongs to.
+ * - name - unique Form Field name in particular From Object.
+ * - value - default value, or empty if there is no default value.
+ * - values - possible values, for certain form field types.
+ * - checked - 0 or 1, it determines if form field is checked, for certain form field types.
+ * - type - form field type, for now the following types are supported:
+ *      - text - text input field.
+ *      - password - password input field.
+ *      - textarea - multiline input field.
+ *      - number - number input field.
+ *      - select - select one from all available values.
+ *      - select_multiple - select one, multiple or all items from all available values.
+ *      - switcher - on/off switcher.
+ *      - checkbox - one checkbox.
+ *      - checkbox_set - set of checkboxes.
+ *      - radio_set - set of radio buttons.
+ *      - slider - select some numeric value within the range using slider control.
+ *      - doublerange - select range values within the range using slider control.
+ *      - datepicker - date selection control.
+ *      - datetime - date/time selection control.
+ *      - dateselect - date selection control (alternative).
+ *      - captcha - image captcha.
+ *      - hidden - hidden input field.
+ *      - file - file upload input.
+ *      - button - button control.
+ *      - image - form image button.
+ *      - reset - form reset button.
+ *      - submit - form submit button.
+ *      - value - just displaying value without any crontol.
+ *      - block_header - start group of field.
+ *      - custom - custom control.
+ *      - input_set - set of other form controls.
+ *      detailed description of every type will be described below.
+ * - caption - input title.
+ * - info - some info to help user to input data into the field, it's better to specify format and limits here.
+ * - required - indicate that the input is required by displaying asterisk near the field,
+ *              please note that this field don't perform any checking automatically,
+ *              since you mark field as required you need to specify checked function which will check entered value.
+ * - collapsed - display section as collapsed by default, for block_header field type only.
+ * - html - display visual editor of certain type, for textarea field type only.
+ *      - 0 - no visual editor, leave textarea field as it is.
+ *      - 1 - standard(default) visual editor, @see BxDolEditor.
+ *      - 2 - full visual editor, @see BxDolEditor.
+ *      - 3 - mini visual editor, @see BxDolEditor.
+ * - attrs - serialized array of additional input attributes.
+ * - attrs_tr - serialized array of additional attributes for the whole input row.
+ * - attrs_wrapper - serialized array of additional attributes for input wrapper.
+ * - checker_func - checked function, if you marked field as required in textarea field you need to point one of the following checked functions:
+ *      - Length - check value length, additional params must contain min and/or max values for checking.
+ *      - Date - check if date is entered correctly.
+ *      - DateTime - check if datetime is entered correctly.
+ *      - Preg - check value with provided regular expression in checker_params field.
+ *      - Avail - just check if value isn't 0 or empty string, additional function parameters are not used.
+ *      - Email - check if value is written in valid email format.
+ *      - Captcha - check if captcha is entered correctly, for captcha field type only.
+ *      You can inherit BxDolFormCheckerHelper class and add own checker functions, you will need to point your custom class in Form Object params array.
+ * - checker_params - serialized array of checker_func parameters.
+ * - checker_error - error message to show in case of checking function returns false.
+ * - db_pass - function to pass value through before saving to database and after restoring from database (for example when date need to be converted from/to timestamp value),
+ *              available values are the following:
+ *      - Int - convert value to integer.
+ *      - Float - convert value to floating point number.
+ *      - Date,DateUtc - convert value to timestamp value before saving to database, and convert from timespamp value after restoring from database.
+ *      - DateTime,DateTimeUtc - convert value to timestamp value before saving to database, and convert from timespamp value after restoring from database.
+ *      - Xss - it warns you that this text can contain XSS vulnerabilities and you need to be extra careful with this, and always use Forms engine to output string to the browser or use bx_process_output if going to output text manually.
+ *      - XssHtml - this text cam have HTML tags, so perform XSS vulnerabilies cleaning before saving to database.
+ *      - All - do not perform any conversion and pass text as it is, be careful with this, use it only when no other function can be used, and make all necessary security checking by yourself.
+ *      - Preg - perform regular expression on the text before saving data to database, regular expression can be provided in db_params field.
+ *      - Boolean - this is used for checkboxes with 'on' value which need to be converted into boolean value.
+ *      - Set - convert set of values into bit integer before saving to database, and restore bit integer into array of values upon restoration from database, it can be used for select_multiple and checkbox_set field types.
+ *      Please note that values for this field must be 1,2,4,8,... (values of power of 2); the max number of values are 31 for 32bit hardware and 63 for 64bit hardware.
+ *      You can inherit BxDolFormCheckerHelper class and add own pass functions, you will need to point your custom class in Form Object params array.
+ * - db_params - serialized array of db_pass parameters.
+ * - editable - allow to edit this field from admin forms builder.
+ * - deletable - allow to delete this field from admin forms builder.
+ *
+ *
+ * 4. Add Form Fields and Form Displays associations, add records to sys_form_display_inputs table:
+ * - display_name - name of the Form Display from sys_form_displays table.
+ * - input_name - name of the Form Field from sys_form_inputs table.
+ * - visible_for_levels - bit field with set of member level ids. To use member level id in bit field the level id minus 1 is used as power of 2, for example:
+ *      - user level id = 1 -> 2^(1-1) = 1
+ *      - user level id = 2 -> 2^(2-1) = 2
+ *      - user level id = 3 -> 2^(3-1) = 4
+ *      - user level id = 4 -> 2^(4-1) = 8
+ * - active - 1 - form field displayed on form, or 0 - isn't displayed.
+ * - order - fields are displayed in this order.
+ *
+ *
+ * @section form_field_types Form Field Types
+ *
+ * Detailed description of Form Field Types.
+ *
+ * Almost all fields have the following common parameters:
+ * - object
+ * - name
+ * - type
+ * - caption
+ * - info
+ * - required
+ * - attrs
+ * - attrs_tr
+ * - attrs_wrapper
+ *
+ * We will not describe above list of parameters in every type, since they work the same way for all types.
+ *
+ * The list below are field types with their unique parameters, which are designed especially for this field, or some parameters which work differently for the specified field type.
+ *
+ * text - text input field. It is displayed as regular single line text input.
+ *      Parameters:
+ *      - value - default value, or empty if there is no default value.
+ *      - values - not applicable here.
+ *      - checked - not applicable here.
+ *      - collapsed - not applicable here.
+ *      - html - not applicable here.
+ *      - checker_func
+ *          Can be used here: Length, Preg, Avail, Email
+ *          Make no sense to use it here: Date, DateTime, Captcha
+ *      - db_pass
+ *          Can be used here: Int, Float, Xss, All, Preg
+ *          Make no sense to use it here: Date, DateTime, XssHtml, Boolean, Set
+ *
+ * password - password input field. It is displayed as HTML input element with invisible input.
+ *      Parameters:
+ *      - value - default value, or empty if there is no default value.
+ *      - values - not applicable here.
+ *      - checked - not applicable here.
+ *      - collapsed - not applicable here.
+ *      - html - not applicable here.
+ *      - checker_func
+ *          Can be used here: Length, Preg, Avail.
+ *          Make no sense to use it here: Date, DateTime, Captcha, Email.
+ *      - db_pass
+ *          Can be used here: Xss, All.
+ *          Make no sense to use it here: Int, Float, Date, DateTime, XssHtml, Boolean, Set, Preg.
+ *
+ * textarea - multiline input field. It can be displayed as regular textarea field or as visual HTML editor.
+ *      Parameters:
+ *      - value - default value, or empty if there is no default value.
+ *      - values - not applicable here.
+ *      - checked - not applicable here.
+ *      - collapsed - not applicable here.
+ *      - html - use visual editor or not.
+ *          - 0 - no visual editor, leave textarea field as it is.
+ *          - 1 - standard(default) visual editor, @see BxDolEditor.
+ *          - 2 - full visual editor, @see BxDolEditor.
+ *          - 3 - mini visual editor, @see BxDolEditor.
+ *      - checker_func
+ *          Can be used here: Length, Preg, Avail
+ *          Make no sense to use it here: Email, Date, DateTime, Captcha
+ *      - db_pass
+ *          Can be used here: Int, Float, Xss, XssHtml, All, Preg
+ *          Make no sense to use it here: Date, DateTime, Boolean, Set
+ *
+ * number - number input field. It is displayed as HTL text input, but with limited width. Also some browsers can add additional controls to this field.
+ *      Parameters:
+ *      - value - default value, or empty if there is no default value.
+ *      - values - not applicable here.
+ *      - checked - not applicable here.
+ *      - collapsed - not applicable here.
+ *      - html - not applicable here.
+ *      - checker_func
+ *          Can be used here: Length, Preg, Avail
+ *          Make no sense to use it here: Email, Date, DateTime, Captcha
+ *      - db_pass
+ *          Can be used here: Int, Float
+ *          Make no sense to use it here: Xss, XssHtml, All, Preg, Date, DateTime, Boolean, Set
+ *
+ * select - select one from all available values. It is displayed as HTML combo-box.
+ *      Parameters:
+ *      - value - default value (array index of selected item from values array), or empty - if there is no default value.
+ *      - values - serialized array of available values, or reference to predefined set of values.
+ *      - checked - not applicable here.
+ *      - collapsed - not applicable here.
+ *      - html - not applicable here.
+ *      - checker_func
+ *          Can be used here: Length, Preg, Avail
+ *          Make no sense to use it here: Email, Date, DateTime, Captcha
+ *      - db_pass
+ *          Can be used here: Int, Float, Xss, All, Preg
+ *          Make no sense to use it here: Date, DateTime, XssHtml, Boolean, Set
+ *
+ * select_multiple - select one, multiple or all items from all available values. It is displayed as HTML multiple selection input.
+ *      Parameters:
+ *      - value - default value (bit integer of array indexes of selected items from values array), or empty - if there is no default value.
+ *      - values - serialized array of available values, or reference to predefined set of values. Array index must be power of 2. Max number of values is 31 on 32bit hardware or 63 on 64bit hardware.
+ *      - checked - not applicable here.
+ *      - collapsed - not applicable here.
+ *      - html - not applicable here.
+ *      - checker_func
+ *          Can be used here: Length, Preg, Avail
+ *          Make no sense to use it here: Email, Date, DateTime, Captcha
+ *      - db_pass
+ *          Can be used here: Int
+ *          Make no sense to use it here: Float, Xss, All, Preg, Date, DateTime, XssHtml, Boolean, Set
+ *
+ * switcher - on/off switcher. It is displayed as custom HTML element with own styles, but on background it works as regular HTML checkbox element.
+ *      Parameters:
+ *      - value - the value which will be submitted if switcher is on, if switcher is off - nothing is submitted.
+ *      - values - not applicable here.
+ *      - checked - if set to 1 then switcher is on by default, 0 - it is off by default.
+ *      - collapsed - not applicable here.
+ *      - html - not applicable here.
+ *      - checker_func
+ *          Can be used here: Length, Preg, Avail
+ *          Make no sense to use it here: Email, Date, DateTime, Captcha
+ *      - db_pass
+ *          Can be used here: Int, Float, Xss, All, Preg, Boolean
+ *          Make no sense to use it here: Date, DateTime, XssHtml, Set
+ *
+ * checkbox - one checkbox. Displayed as HTML checkbox input element.
+ *      Parameters:
+ *      - value - the value which will be submitted if checkbox is checked, if checkbox isn't checked - nothing is submitted.
+ *      - values - not applicable here.
+ *      - checked - if set to 1 then checkbox is checked by default, 0 - it is unchecked by default.
+ *      - collapsed - not applicable here.
+ *      - html - not applicable here.
+ *      - checker_func
+ *          Can be used here: Length, Preg, Avail
+ *          Make no sense to use it here: Email, Date, DateTime, Captcha
+ *      - db_pass
+ *          Can be used here: Int, Float, Xss, All, Preg, Boolean
+ *          Make no sense to use it here: Date, DateTime, XssHtml, Set
+ *
+ * checkbox_set - set of checkboxes. It is displayed as set of checkboxes. It is displayed in one row if number of items is equal or less than 3 or every item is displayed on new line if there is more than 3 items in the set.
+ *      Parameters:
+ *      - value - default value (bit integer of array indexes of selected items from values array), or empty - if there is no default value.
+ *      - values - serialized array of available values, or reference to predefined set of values. Array index must be power of 2. Max number of values is 31 on 32bit hardware or 63 on 64bit hardware.
+ *      - checked - not applicable here.
+ *      - collapsed - not applicable here.
+ *      - html - not applicable here.
+ *      - checker_func
+ *          Can be used here: Length, Preg, Avail
+ *          Make no sense to use it here: Email, Date, DateTime, Captcha
+ *      - db_pass
+ *          Can be used here: Int
+ *          Make no sense to use it here: Float, Xss, All, Preg, Date, DateTime, XssHtml, Boolean, Set
+ *
+ * radio_set - set of radio buttons. It is displayed as set of radio buttons. It is displayed in one row if number of items is equal or less than 3 or every item is displayed on new line if there is more than 3 items in the set.
+ *      Parameters:
+ *      - value - default value (array index of selected radio button from values array), or empty - if there is no default value.
+ *      - values - serialized array of available values, or reference to predefined set of values.
+ *      - checked - not applicable here.
+ *      - collapsed - not applicable here.
+ *      - html - not applicable here.
+ *      - checker_func
+ *          Can be used here: Length, Preg, Avail
+ *          Make no sense to use it here: Email, Date, DateTime, Captcha
+ *      - db_pass
+ *          Can be used here: Int, Float, Xss, All, Preg
+ *          Make no sense to use it here: Date, DateTime, XssHtml, Boolean, Set
+ *
+ * slider - select some numeric value within the range using slider control. It is displayed as jQuery UI HTML control, but on background it works as regular HTML text input element.
+ *      Parameters:
+ *      - value - default value in the format, or empty if there is no default value.
+ *      - values - not applicable here.
+ *      - checked - not applicable here.
+ *      - collapsed - not applicable here.
+ *      - html - not applicable here.
+ *      - attrs - the following additional attributes can be used here:
+ *      - min - minimal value, default is 0.
+ *      - max - maximal value, default is 100.
+ *      - step - value can be changed by this step only, default is 1.
+ *      - checker_func
+ *          Can be used here: Length, Avail
+ *          Make no sense to use it here: Preg, Email, Date, DateTime, Captcha
+ *      - db_pass
+ *          Can be used here: Int, Float
+ *          Make no sense to use it here: Xss, XssHtml, All, Preg, Date, DateTime, Boolean, Set
+ *
+ * doublerange - select range values within the range using slider control.
+ *      Parameters:
+ *      - value - default value in the format [min value]-[max value], for example 16-99, or empty if there is no default value.
+ *      - values - not applicable here.
+ *      - checked - not applicable here.
+ *      - collapsed - not applicable here.
+ *      - html - not applicable here.
+ *      - attrs - the following additional attributes can be used here:
+ *          - min - minimal value, default is 0.
+ *          - max - maximal value, default is 100.
+ *          - step - value can be changed by this step only, default is 1.
+ *      - checker_func
+ *          Can be used here: Length, Avail
+ *          Make no sense to use it here: Preg, Email, Date, DateTime, Captcha
+ *      - db_pass
+ *          Can be used here: Xss, All, Preg
+ *          Make no sense to use it here: Int, Float, XssHtml, Date, DateTime, Boolean, Set
+ *
+ * datepicker - date selection control. It is displayed as HTML text input control, when clicking on this input then popup with date selector control is appeared.
+ *      Parameters:
+ *      - value - default value, in the format YYYY-MMM-DD, or empty if there is no default value.
+ *      - values - not applicable here.
+ *      - checked - not applicable here.
+ *      - collapsed - not applicable here.
+ *      - html - not applicable here.
+ *      - checker_func
+ *          Can be used here: Date
+ *          Make no sense to use it here: Length, Preg, Avail, Email, DateTime, Captcha
+ *      - db_pass
+ *          Can be used here: Date, DateUtc
+ *          Make no sense to use it here: Int, Float, Xss, All, Preg, DateTime, XssHtml, Boolean, Set
+ *
+ * datetime - date/time selection control.
+ *      Parameters:
+ *      - value - default value, in the format YYYY-MMM-DD HH:MM:SS, or empty if there is no default value.
+ *      - values - not applicable here.
+ *      - checked - not applicable here.
+ *      - collapsed - not applicable here.
+ *      - html - not applicable here.
+ *      - checker_func
+ *          Can be used here: DateTime
+ *          Make no sense to use it here: Length, Preg, Avail, Email, Date, Captcha
+ *      - db_pass
+ *          Can be used here: DateTime, DateTimeUtc
+ *          Make no sense to use it here: Int, Float, Xss, All, Preg, Date, XssHtml, Boolean, Set
+ *
+ * captcha - image captcha. Displayed as image with some text along with HTML text input for entering displayed on the image text.
+ *      Parameters:
+ *      - value - not applicable here.
+ *      - values - not applicable here.
+ *      - checked - not applicable here.
+ *      - collapsed - not applicable here.
+ *      - html - not applicable here.
+ *      - checker_func
+ *          Can be used here: Captcha
+ *          Make no sense to use it here: Length, Preg, Avail, Email, Date, DateTime
+ *      - db_pass
+ *          Can be used here: Xss, All, Preg
+ *          Make no sense to use it here: Int, Float, Date, DateTime, XssHtml, Boolean, Set
+ *
+ * hidden - hidden input field. Displayed as hidden HTML input.
+ *      Parameters:
+ *      - value - hidden input value.
+ *      - values - not applicable here.
+ *      - checked - not applicable here.
+ *      - collapsed - not applicable here.
+ *      - html - not applicable here.
+ *      - checker_func
+ *          Can be used here: Length, Preg, Avail, Email, Date, DateTime
+ *          Make no sense to use it here: Captcha
+ *      - db_pass
+ *          Can be used here: Int, Float, Xss, All, Preg, Date, DateUtc, DateTime, DateTimeUtc, XssHtml, Boolean
+ *          Make no sense to use it here: Set
+ *
+ * file - file upload input. Displayed as file upload HTML input.
+ *      Parameters:
+ *      - value - not applicable here.
+ *      - values - not applicable here.
+ *      - checked - not applicable here.
+ *      - collapsed - not applicable here.
+ *      - html - not applicable here.
+ *      - checker_func
+ *          File name is passed for checking.
+ *          Can be used here: Avail, Length, Preg
+ *          Make no sense to use it here: Email, Date, DateTime, Captcha
+ *      - db_pass
+ *          File can't be stored in the database, so this field isn't applicable here.
+ *
+ * files - files upload input. Displayed as complex uploading HTML control.
+ *          This control is too complex to describe it using default set of database fields, you need to use custom class to display this control.
+ *
+ * button - button control. Displayes as HTML button element.
+ *      Parameters:
+ *      - value - translatable button caption.
+ *      - values - not applicable here.
+ *      - checked - not applicable here.
+ *      - collapsed - not applicable here.
+ *      - html - not applicable here.
+ *      - checker_func - not applicable here.
+ *      - db_pass - not applicable here.
+ *
+ * image - form image button. It is displayed as HTML form image input element.
+ *      Parameters:
+ *      - value - not applicable here.
+ *      - values - not applicable here.
+ *      - checked - not applicable here.
+ *      - collapsed - not applicable here.
+ *      - html - not applicable here.
+ *      - attrs - the following mandatory attribute must be specified here:
+ *          - src - image URL.
+ *      - checker_func - not applicable here.
+ *      - db_pass - not applicable here.
+ *
+ * reset - form reset button. Displayed as HTML form reset input button. By clicking on this button the form is reset to its default state.
+ *      Parameters:
+ *      - value - translatable button caption.
+ *      - values - not applicable here.
+ *      - checked - not applicable here.
+ *      - collapsed - not applicable here.
+ *      - html - not applicable here.
+ *      - checker_func - not applicable here.
+ *      - db_pass - not applicable here.
+ *
+ * submit - form submit button. Displayed as HTML form submit input button. This button have the primary button style to distinguish it from other buttons. By clicking on this button the form is submitted.
+ *      Parameters:
+ *      - value - translatable button caption.
+ *      - values - not applicable here.
+ *      - checked - not applicable here.
+ *      - collapsed - not applicable here.
+ *      - html - not applicable here.
+ *      - checker_func - not applicable here.
+ *      - db_pass - not applicable here.
+ *
+ * value - just displaying value without any control.
+ *      Parameters:
+ *      - value - the value to display.
+ *      - values - not applicable here.
+ *      - checked - not applicable here.
+ *      - collapsed - not applicable here.
+ *      - html - not applicable here.
+ *      - checker_func - not applicable here.
+ *      - db_pass - not applicable here.
+ *
+ * block_header - start group of fields. Displayed as form fields divider with caption - then it can be collapsible or without caption - then it is just divider without any functionality.
+ *      Parameters:
+ *      - value - not applicable here.
+ *      - values - not applicable here.
+ *      - checked - not applicable here.
+ *      - collapsed - display group of field collapsed by default, 1 - the group is collapsed, 0 - expanded (default value).
+ *      - html - not applicable here.
+ *      - checker_func - not applicable here.
+ *      - db_pass - not applicable here.
+ *
+ * custom - custom control. You need custom class to display this control, so the exact used values are determined by particular realisation.
+ *
+ * input_set - set of other form controls.
+ *      Parameters:
+ *      - value - not applicable here.
+ *      - values - comma separated list of field names (by name field) of fields to display here.
+ *      - checked - not applicable here.
+ *      - collapsed - not applicable here.
+ *      - html - not applicable here.
+ *      - checker_func - not applicable here.
+ *      - db_pass - not applicable here.
+ *
+ *
+ * @section form_using_own_class Using own class for custom behavior
+ *
+ * It is possible to provide own class for displaying and processing the form.
+ * To do this you need to point it in override_class_name and override_class_file fields in sys_objects_form table.
+ * Your custom class must be inherited from BxTemplFormView class or its descendants.
+ *
+ *
+ * @section form_display_custom_control Displaying custom field control
+ *
+ * It is possible to leave form field with default caption and override only the form field control.
+ * To override some field you need to define the following function:
+ * @code
+ *      protected function genCustomInput[field name] ($aInput).
+ * @endcode
+ * Where [field name] is form field name.
+ * For example:
+ *
+ * @code
+ *     protected function genCustomInputCustom ($aInput) {
+ *         return
+ *         'r: <input type="text" size="2" value="'.(isset($aInput['value'][0]) ? $aInput['value'][0] : '').'" name="'.$aInput['name'].'[]" />' .
+ *         'g: <input type="text" size="2" value="'.(isset($aInput['value'][1]) ? $aInput['value'][1] : '').'" name="'.$aInput['name'].'[]" />' .
+ *         'b: <input type="text" size="2" value="'.(isset($aInput['value'][2]) ? $aInput['value'][2] : '').'" name="'.$aInput['name'].'[]" />';
+ *     }
+ * @endcode
+ *
+ *
+ * @section form_display_custom_row Displaying custom field row
+ *
+ * Form row consists of caption and control, by default it is displayed with default design and functionality.
+ * If you need to display some field with custom header and control you need to declare the following function:
+ * @code
+ *      protected function genCustomRow[field name] ($aInput).
+ * @endcode
+ * Where [field name] is form field name.
+ *
+ *
+ * @section example Example of usage
+ *
+ * Printing the form for adding new record to the database:
+ *
+ * @code
+ *      $oForm = BxDolForm::getObjectInstance('sample_form_objects', 'sample_form_objects_add'); // get form instance for specified form object and display
+ *      if (!$oForm)
+ *          die('"sample_form_objects_add" form object or "sample_form_objects_add" display is not defined');
+ *      $oForm->initChecker(); // init form checker witout any data - adding new record
+ *      if ($oForm->isSubmittedAndValid())
+ *          echo 'inserted id: ' . $oForm->insert (); // add new record to the database
+ *      echo $oForm->getCode(); // display form
+ * @endcode
+ *
+ * Printing the form for editing existing record in the database:
+ *
+ * @code
+ *      // $iEditId - ID of edited row, for example from _GET parameter
+ *      $oDb = BxDolDb::getInstance();
+ *      $sQuery = $oDb->prepare("SELECT * FROM `sample_input_types` WHERE id = ?", $iEditId);
+ *      $aRecord = $oDb->getRow();
+ *      if (!$aRecord)
+ *          die("$iEditId record wasn't found.");
+ *
+ *      $oForm = BxDolForm::getObjectInstance('sample_form_objects', 'sample_form_objects_edit'); // get form instance for specified form object and display
+ *      if (!$oForm)
+ *          die('"sample_form_objects_edit" form object or "sample_form_objects_edit" display is not defined');
+ *      $oForm->initChecker($aRecord); // init form checker with edited data
+ *      if ($oForm->isSubmittedAndValid())
+ *          echo 'updated: ' . $oForm->update ($iEditId); // update database
+ *      echo $oForm->getCode(); // display form
+ * @endcode
+ *
+ * Example of custom form class and custom checking helper class:
+ *
+ * @code
+ *      class BxSampleForm extends BxTemplFormView {
+ *
+ *          public function __construct ($aInfo, $oTemplate = false) {
+ *              parent::__construct ($aInfo, $oTemplate);
+ *          }
+ *
+ *
+ *          // display input with 'custom' name
+ *          protected function genCustomInputCustom ($aInput) {
+ *              return
+ *              'r: <input type="text" size="2" value="'.(isset($aInput['value'][0]) ? $aInput['value'][0] : '').'" name="'.$aInput['name'].'[]" />' .
+ *              'g: <input type="text" size="2" value="'.(isset($aInput['value'][1]) ? $aInput['value'][1] : '').'" name="'.$aInput['name'].'[]" />' .
+ *              'b: <input type="text" size="2" value="'.(isset($aInput['value'][2]) ? $aInput['value'][2] : '').'" name="'.$aInput['name'].'[]" />';
+ *          }
+ *
+ *      }
+ *
+ *      class BxSampleFormCheckerHelper extends BxDolFormCheckerHelper {
+ *
+ *          protected $_sDiv = ',';
+ *
+ *          // prepare RBG values to save to the DB
+ *          function passRgb ($s) {
+ *              if (!is_array($s))
+ *                  return false;
+ *
+ *              $sRet = '';
+ *              foreach ($s as $k => $v)
+ *                  $sRet .= (int)trim($v) . $this->_sDiv;
+ *
+ *              return trim($sRet, $this->_sDiv);
+ *          }
+ *
+ *          // prepare RGB values to output to the screen
+ *          function displayRgb ($s) {
+ *              return explode($this->_sDiv, $s);
+ *          }
+ *      }
+ * @endcode
+ *
+ * The recommended way is to define forms in database, if it is impossible for some reasons you can init form object from array, there is an example:
+ *
+ * @code
+ *      $aForm = array(
+ *            'form_attrs' => array(
+ *                'name'     => 'form_my',
+ *                'method'   => 'post',
+ *            ),
+ *
+ *            'params' => array (
+ *                'db' => array(
+ *                    'table' => 'table_name', // table name
+ *                    'key' => 'ID', // key field name
+ *                    'uri' => 'EntryUri', // uri field name
+ *                    'uri_title' => 'Title', // title field to generate uri from
+ *                    'submit_name' => 'submit_form', // some filed name with non empty value to determine if the for was submitted,
+ *                                                       in most cases it is submit button name
+ *                ),
+ *                'csrf' => array(
+ *                      'disable' => true, //if it wasn't set or has some other value then CSRF checking is enabled for current form, take a look at sys_security_form_token_enable to disable CSRF checking completely.
+ *                )
+ *              ),
+ *
+ *            'inputs' => array(
+ *
+ *                'Title' => array(
+ *                    'type' => 'text',
+ *                    'name' => 'Title', // the same as key and database field name
+ *                    'caption' => 'Some caption',
+ *                    'required' => true,
+ *
+ *                    // checker params
+ *                    'checker' => array (
+ *                        'func' => 'length', // see BxDolFormCheckerHelper class for all check* functions
+ *                        'params' => array(3,100),
+ *                        'error' => 'length must be from 3 to 100 characters',
+ *                    ),
+ *                    // database params
+ *                    'db' => array (
+ *                        'pass' => 'Xss',  // do XSS clear before getting this value, see BxDolFormCheckerHelper class for all pass* functions
+ *                    ),
+ *                ),
+ *
+ *                'Description' => array(
+ *                    'type' => 'textarea',
+ *                    'name' => 'Description', // the same as key and database field name
+ *                    'caption' => 'Some caption',
+ *                    'required' => true,
+ *
+ *                    // checker params
+ *                    'checker' => array (
+ *                        'func' => 'length',
+ *                        'error' => 'enter at least 3 characters',
+ *                        'params' => array(3,64000),
+ *                    ),
+ *                    'db' => array (
+ *                        'pass' => 'XssHtml',  // do XSS clear, but keep HTML before getting this value
+ *                    ),
+ *                ),
+ *            );
+ * @endcode
+ *
+ * Using of above array:
+ *
+ * @code
+ *        $oForm = new BxTemplFormView ($aForm);
+ *        $oForm->initChecker();
+ *
+ *        if ($oForm->isSubmittedAndValid ()) {
+ *
+ *            // add additional vars to database, in this case creation date field is added
+ *            $aValsAdd = array (
+ *                'Date' => time(),
+ *            );
+ *
+ *            echo 'insert last id: ' . $oForm->insert ($aValsAdd); // insert validated data to database
+ *
+ *        } else {
+ *
+ *            echo $oForm->getCode (); // show form
+ *
+ *        }
+ *
+ * @endcode
+ *
+ */
+class BxDolForm extends BxDol implements iBxDolReplaceable
+{
+    static $TYPES_SKIP = array('files' => 1, 'location' => 1, 'nested_form' => 1);
+    static $TYPES_CHECKBOX = array('checkbox' => 1, 'switcher' => 1);
+    static $TYPES_TEXT = array('text' => 1, 'textarea' => 1);
+    static $TYPES_FILE = array('file' => 1);
+
+    static $FUNC_SKIP_DOMAIN_CHECK = array('email' => 1, 'emails' => 1, 'emailexist' => 1, 'emailuniq' => 1, 'emailexistorempty' => 1, 'hostdomain' => 1, 'hostdomainchat' => 1, 'emailorempty' => 1);
+    static $FUNC_SKIP_MACROS_CHECK = array();
+
+    static $LOCATION_INDEXES = array ('lat', 'lng', 'country', 'state', 'city', 'zip', 'street', 'street_number');
+    static $LOCATION_INDEXES_MANDATORY = array ('lat', 'lng');
+
+    protected $_bIsApi;
+
+    protected $_aMarkers = array ();
+
+    protected $oTemplate;
+
+    protected $_isValid = true;
+    protected $_bForceSetToPending = false;
+    protected $_sChecker;
+    protected $_sCheckerHelper;
+    protected $_aSpecificValues;
+
+    public $aFormAttrs; ///< form html element attributes
+    public $aInputs; ///< form inputs
+    public $aParams; ///< additional form parameters
+    public $id; ///< Form element id
+
+    protected $_aFieldsCheckForSpam = array(); ///< additional fields names to check for spam(profanity filter), now only fields with 'textarea' and 'text' are checked for spam, 'textarea' fields are checked for spam and filter for profanity, while 'text' fields are filtetered for profanity only
+    protected $_aFieldsExcludeFromCheckForSpam = array(); ///<  fields names('textarea' and 'text') to exclude from  check for spam(profanity filter)
+
+    
+    protected $_iAuthorId;
+    protected $_sAuthorKey; ///< array key to get author ID from Values array provided in BxDolForm::initChecker.
+    protected $_sPrivacyObjectView;
+    protected $_sPrivacyGroupDefault;
+
+    public function __construct ($aInfo, $oTemplate)
+    {
+        parent::__construct();
+
+        $this->_bIsApi = bx_is_api();
+
+        if ($oTemplate)
+            $this->oTemplate = $oTemplate;
+        else
+            $this->oTemplate = BxDolTemplate::getInstance();
+
+        $this->aFormAttrs    = isset($aInfo['form_attrs'])   ? $aInfo['form_attrs']  : array();
+        $this->aInputs       = isset($aInfo['inputs'])       ? $aInfo['inputs']      : array();
+        $this->aParams       = isset($aInfo['params'])       ? $aInfo['params']      : array();
+
+        // get form element id
+        $this->id = $this->aFormAttrs['id'] = (!empty($this->aFormAttrs['id']) ? $this->aFormAttrs['id'] : (!empty($this->aFormAttrs['name']) ? $this->aFormAttrs['name'] : 'form_advanced'));
+
+        // set default method
+        if (!isset($this->aFormAttrs['method']))
+            $this->aFormAttrs['method'] = BX_DOL_FORM_METHOD_DEFAULT;
+
+        // set default action
+        if (!isset($this->aFormAttrs['action']))
+            $this->aFormAttrs['action'] = '';
+
+        $this->_sChecker = isset($this->aParams['checker']) ? $this->aParams['checker'] : 'BxDolFormChecker';
+        $this->_sCheckerHelper = isset($this->aParams['checker_helper']) ? $this->aParams['checker_helper'] : '';
+
+        $this->_sAuthorKey = 'author';
+        $this->_sPrivacyObjectView = 'sys_form_inputs_allow_view_to';
+        $this->_sPrivacyGroupDefault = BX_DOL_PG_ALL;
+    }
+
+    /**
+     * Get form object instance by object name
+     * @param $sObject object name
+     * @return object instance or false on error
+     */
+    static public function getObjectInstance($sObject, $sDisplayName, $oTemplate = false, $sParam = '')
+    {
+        $sKey = 'BxDolForm!'.$sObject.'!'.$sDisplayName.'!'.$sParam;
+
+        if (isset($GLOBALS['bxDolClasses'][$sKey]))
+            return $GLOBALS['bxDolClasses'][$sKey];
+
+        $aObject = BxDolFormQuery::getFormArray($sObject, $sDisplayName);
+        if (!$aObject || !is_array($aObject))
+            return false;
+
+        $sClass = 'BxTemplFormView';
+        if (!empty($aObject['override_class_name'])) {
+            $sClass = $aObject['override_class_name'];
+            if (!empty($aObject['override_class_file']))
+                require_once(BX_DIRECTORY_PATH_ROOT . $aObject['override_class_file']);
+        }
+
+        $o = new $sClass($aObject, $oTemplate);
+
+        return ($GLOBALS['bxDolClasses'][$sKey] = $o);
+    }
+    
+     static public function unSetObjectInstance($sObject, $sDisplayName, $oTemplate = false, $sParam = '')
+     {
+        $sKey = 'BxDolForm!'.$sObject.'!'.$sDisplayName.'!'.$sParam;
+         unset($GLOBALS['bxDolClasses'][$sKey]);
+     }
+
+    /**
+     * Get data items array
+     * @param $sKey data items identifier
+     * @param $isUseForSet convert data items keys to use in set fields, make it power of 2 (1,2,4,8,16,etc).
+     * @param $sUseValues use default(BX_DATA_VALUES_DEFAULT) or additional(BX_DATA_VALUES_ADDITIONAL) value titles, if additinal value title is missing default title is used
+     * @return data items array
+     */
+    public static function getDataItems($sKey, $isUseForSet = false, $sUseValues = BX_DATA_VALUES_DEFAULT)
+    {
+        return BxDolFormQuery::getDataItems($sKey, $isUseForSet, $sUseValues);
+    }
+
+    function initChecker ($aValues = array (), $aSpecificValues = array())
+    {
+        $this->_aSpecificValues = $aSpecificValues;
+
+        $oChecker = new $this->_sChecker($this->_sCheckerHelper);
+        $oChecker->setFormMethod($this->aFormAttrs['method'], $aSpecificValues);
+        $oChecker->setFormParams($this->aParams);
+        $oChecker->setFieldsCheckForSpam($this->_aFieldsCheckForSpam, $this->_aFieldsExcludeFromCheckForSpam);
+
+        // init form with default values
+
+        $aValuesDef = array ();
+        foreach ($this->aInputs as $k => $a) {
+            if (!isset($a['value']) || !isset($a['db']['pass']) || isset(self::$TYPES_CHECKBOX[$a['type']]) || isset(self::$TYPES_SKIP[$a['type']]))
+                continue;
+            $aValuesDef[$k] = $a['value'];
+        }
+
+        $oChecker->fillWithValues($this->aInputs, $aValuesDef);
+
+        // init form with provided values
+
+        if ($aValues)
+            $oChecker->fillWithValues($this->aInputs, $aValues);
+
+        // init author from provided values if it's available
+
+        if (isset($aValues[$this->_sAuthorKey]))
+            $this->_iAuthorId = (int)$aValues[$this->_sAuthorKey];
+
+
+        if ($this->isSubmitted ()) {
+
+            // init form with submitted data, overwrite prevously declared values
+
+            $bViewMode = isset($this->aParams['view_mode']) && (int)$this->aParams['view_mode'] == 1;
+            $bCsrfDisabled = isset($this->aParams['csrf']['disable']) && $this->aParams['csrf']['disable'] === true;
+            $oChecker->enableFormCsrfChecking(!$bViewMode && !$bCsrfDisabled);
+
+            $this->_isValid = $oChecker->check($this->aInputs, $aValues);
+
+            if (!$this->_initCheckerNestedForms ())
+                $this->_isValid = false;
+
+        }
+
+        /**
+         * @hooks
+         * @hookdef hook-system-form_check 'system', 'form_check' - hook to override form object after data checking was performed
+         * - $unit_name - equals `system`
+         * - $action - equals `form_check`
+         * - $object_id - not used
+         * - $sender_id - not used
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `object` - [object] by ref, an instance of form, @see BxDolForm, can be overridden in hook processing
+         * @hook @ref hook-system-form_check
+         */
+        bx_alert('system', 'form_check', 0, 0, [
+            'object' => &$this,
+            'inputs_ref' => &$this->aInputs,
+        ]);
+    }
+
+    function getKeyValuesPair ()
+    {
+        $aRet = array ();
+        foreach ($this->aInputs as $k => $a) {
+            if (!isset($a['value']) || isset(self::$TYPES_CHECKBOX[$a['type']]) || isset(self::$TYPES_SKIP[$a['type']]))
+                continue;
+            $aRet[$k] = $a['value'];
+        }
+        return $aRet;
+    }
+
+    function insert ($aValsToAdd = array(), $isIgnore = false)
+    {
+        $this->autoSetToPending($aValsToAdd);
+
+        $oChecker = new $this->_sChecker($this->_sCheckerHelper);
+        $oChecker->setFormMethod($this->aFormAttrs['method'], $this->_aSpecificValues);
+        $sSql = $oChecker->dbInsert($this->aParams['db'], $this->aInputs, $aValsToAdd, $isIgnore);
+        if (!$sSql)
+            return false;
+        $oDb = BxDolDb::getInstance();
+        if ($oDb->query($sSql)) {
+            $iRes = $oDb->lastId();
+
+            /**
+             * @hooks
+             * @hookdef hook-system-form_submitted 'system', 'form_submitted' - hook to override form object after data was submitted and saved in database
+             * - $unit_name - equals `system`
+             * - $action - equals `form_submitted`
+             * - $object_id - newly created database record id
+             * - $sender_id - currently logged in profile id
+             * - $extra_params - array of additional params with the following array keys:
+             *      - `action` - [string] action equals to 'insert'
+             *      - `module` - [string] module name if it's available
+             *      - `entry_id` - [int] newly created database record id
+             *      - `form_object` - [object] by ref, an instance of form, @see BxDolForm, can be overridden in hook processing
+             * @hook @ref hook-system-form_submitted
+             */
+            bx_alert('system', 'form_submitted', $iRes, bx_get_logged_profile_id(), [
+                'action' => 'insert',
+                'module' => isset($this->aParams['module']) ? $this->aParams['module'] : '',
+                'entry_id' => $iRes,
+                'form_object' => &$this,
+                'inputs_ref' => &$this->aInputs,
+            ]);
+
+            return $iRes;
+        }
+        return false;
+    }
+
+    function update ($val, $aValsToAdd = array(), &$aTrackTextFieldsChanges = null)
+    {
+        $this->autoSetToPending($aValsToAdd);
+
+        $oChecker = new $this->_sChecker($this->_sCheckerHelper);
+        $oChecker->setFormMethod($this->aFormAttrs['method'], $this->_aSpecificValues);
+        $sSql = $oChecker->dbUpdate($val, $this->aParams['db'], $this->aInputs, $aValsToAdd, $aTrackTextFieldsChanges);
+        if (!$sSql)
+            return false;
+        $bRes = BxDolDb::getInstance()->query($sSql);
+
+        /**
+         * @hooks
+         * @hookdef hook-system-form_submitted 'system', 'form_submitted' - hook to override form object after data was submitted and saved in database
+         * - $unit_name - equals `system`
+         * - $action - equals `form_submitted`
+         * - $object_id - updated database record id
+         * - $sender_id - currently logged in profile id
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `action` - [string] action equals to 'update'
+         *      - `module` - [string] module name if it's available
+         *      - `entry_id` - [int] updated database record id
+         *      - `form_object` - [object] by ref, an instance of form, @see BxDolForm, can be overridden in hook processing
+         * @hook @ref hook-system-form_submitted
+         */
+        bx_alert('system', 'form_submitted', $val, bx_get_logged_profile_id(), [
+            'action' => 'update',
+            'module' => isset($this->aParams['module']) ? $this->aParams['module'] : '',
+            'entry_id' => $val,
+            'form_object' => &$this,
+            'inputs_ref' => &$this->aInputs,
+        ]);
+
+        return $bRes;
+    }
+
+    function isStatusFieldSupported() {
+        // check whether we have a status field available for this type of content
+        if (isset($this->aParams['module']) && $this->aParams['module'] && $oModule = BxDolModule::getInstance($this->aParams['module'])) {
+            if (isset($oModule->_oConfig->CNF)) {
+                $CNF = &$oModule->_oConfig->CNF;
+                if (isset($CNF['FIELD_STATUS_ADMIN']) &&
+                    isset($this->aParams['db']['table']) && isset($CNF['TABLE_ENTRIES']) && $this->aParams['db']['table'] == $CNF['TABLE_ENTRIES']) {
+                    return true;
+                }
+            }
+        }
+
+        //if this is a comments form then we support it since V13.A3 as a special case
+        if (isset($this->aParams['module']) && $this->aParams['module'] == 'system' && isset($this->aParams['object']) && $this->aParams['object'] == 'sys_comment')
+            return true;
+
+        return false;
+    }
+
+    function autoSetToPending(&$aValsToAdd) {
+        if ($this->isStatusFieldSupported() && $this->_bForceSetToPending) {
+            $oModule = BxDolModule::getInstance($this->aParams['module']);
+            $CNF = &$oModule->_oConfig->CNF;
+
+            if (isset($oModule->_oConfig->CNF) && isset($CNF['FIELD_STATUS_ADMIN'])) $aValsToAdd[$CNF['FIELD_STATUS_ADMIN']] = 'pending';
+        }
+    }
+
+    function delete ($val)
+    {
+        $oChecker = new $this->_sChecker($this->_sCheckerHelper);
+        $oChecker->setFormMethod($this->aFormAttrs['method'], $this->_aSpecificValues);
+        $sSql = $oChecker->dbDelete($val, $this->aParams['db'], $this->aInputs);
+        if (!$sSql)
+            return false;
+        return BxDolDb::getInstance()->query($sSql);
+    }
+
+    function generateUri ()
+    {
+        $f = &$this->aParams['db'];
+        $sUri = $this->getCleanValue ($f['uri_title']);
+        return uriGenerate($sUri, $f['table'], $f['uri']);
+    }
+
+    function getCleanValue ($sName)
+    {
+        $oChecker = new $this->_sChecker($this->_sCheckerHelper);
+        $oChecker->setFormMethod($this->aFormAttrs['method'], $this->_aSpecificValues);
+        $a = isset($this->aInputs[$sName]) ? $this->aInputs[$sName] : false;
+        $oRv = null;
+
+        if ($a && isset($a['db']['pass']))
+            $oRv = $oChecker->get ($sName, $a['db']['pass'], isset($a['db']['params']) && $a['db']['params'] ? $a['db']['params'] : array());
+        else
+            $oRv =  $oChecker->get ($sName);
+
+        // process comma separated string for api values
+        if ($this->_bIsApi && isset($this->aInputs[$sName]['type']) && !empty($oRv) && is_string($oRv) && (in_array($this->aInputs[$sName]['type'], ['checkbox_set', 'files', 'select_multiple']) || in_array($sName, ['labels'])))
+            $oRv = explode(',', $oRv);
+
+        return $oRv;
+    }
+
+    function isSubmitted ()
+    {
+        $aSubmitName = $this->aParams['db']['submit_name'];
+        if(!is_array($aSubmitName))
+            $aSubmitName = array($aSubmitName);
+
+        foreach($aSubmitName as $sSubmitName)
+            if(BxDolForm::getSubmittedValue($sSubmitName, $this->aFormAttrs['method'], $this->_aSpecificValues))
+                return true;
+        
+        return false;
+    }
+
+    function getTemplate ()
+    {
+        return $this->oTemplate;
+    }
+
+    function getId ()
+    {
+        return $this->id;
+    }
+
+    function getName ()
+    {
+        return isset($this->aFormAttrs['name']) ? $this->aFormAttrs['name'] : '';
+    }
+
+    function setId ($sId)
+    {
+        $this->id = $sId;
+        $this->aFormAttrs['id'] = $sId;
+    }
+
+    function setName($sName)
+    {
+        $this->aFormAttrs['name'] = $sName;
+    }
+
+    function setAction($sAction)
+    {
+        $this->aFormAttrs['action'] = $sAction;
+    }
+
+    function setForceSetToPending ($isValid)
+    {
+        $this->_bForceSetToPending = $isValid;
+    }
+
+    function setValid ($isValid)
+    {
+        $this->_isValid = $isValid;
+    }
+
+    function isValid ()
+    {
+        return $this->_isValid;
+    }
+
+    function isSubmittedAndValid ()
+    {
+        return ($this->isSubmitted() && $this->isValid());
+    }
+
+    function getSpecificValues()
+    {
+        return $this->_aSpecificValues;
+    }
+
+    function setSpecificValue($sName, $sVal)
+    {
+        $this->_aSpecificValues[$sName] = $sVal;
+    }
+
+    function getAuthorId()
+    {
+        return $this->_iAuthorId;
+    }
+
+    function setAuthorId($iAuthorId)
+    {
+        $this->_iAuthorId = (int)$iAuthorId;
+        $this->aParams['params']['author_id'] = $this->_iAuthorId;
+    }
+
+    public static function getSubmittedValue($sKey, $sMethod, &$aSpecificValues = false)
+    {
+        $aData = array();
+        if($sMethod == BX_DOL_FORM_METHOD_GET) {
+            $aData = &$_GET;
+        } else if($sMethod == BX_DOL_FORM_METHOD_POST) {
+            $aData = &$_POST;
+        } else if($sMethod == BX_DOL_FORM_METHOD_SPECIFIC) {
+            $aData = &$aSpecificValues;
+        }
+
+        return isset($aData[$sKey]) ? $aData[$sKey] : false;
+    }
+
+    public static function setSubmittedValue($sKey, $mixedValue, $sMethod, &$aSpecificValues = false)
+    {
+        $aData = array();
+        if($sMethod == BX_DOL_FORM_METHOD_GET) {
+            $aData = &$_GET;
+        } else if($sMethod == BX_DOL_FORM_METHOD_POST) {
+            $aData = &$_POST;
+        } else if($sMethod == BX_DOL_FORM_METHOD_SPECIFIC) {
+            $aData = &$aSpecificValues;
+        }
+
+        return $aData[$sKey] = $mixedValue;
+    }
+
+    /**
+     * Check if field exists
+     * @param $sName field name 
+     * @param $bCheckAllFields true - check all fields; false - all fields except: password, captcha, hidden, file, button, image, reset, submit, block_header, input_set
+     * @return true if field exists or false otherwise
+     */
+    public function isFieldExist($sName, $bCheckAllFields = false)
+    {
+        if (!isset($this->aInputs[$sName]))
+            return false;
+        return $bCheckAllFields ? true : !in_array($this->aInputs[$sName]['type'], array('password', 'captcha', 'hidden', 'button', 'reset', 'submit', 'block_header', 'input_set', 'location'));
+    }
+
+
+    // Static Methods related to CSRF Tocken
+    public static function genCsrfToken($bReturn = false)
+    {
+        // TODO: remove
+    }
+    
+    public static function getCsrfToken()
+    {
+        if (getParam('sys_security_form_token_enable') != 'on')
+            return false;
+
+        if (!($oKeys = BxDolKey::getInstance()))
+            return false;
+
+        return $oKeys->getNewKey (false, (int)getParam('sys_security_form_token_lifetime'), BxDolSession::getInstance()->getId());
+    }
+    
+    public static function isCsrfTokenValid($s, $bDeleteToken = true)
+    {
+        if (getParam('sys_security_form_token_enable') != 'on')
+            return true;
+
+        if (!($oKeys = BxDolKey::getInstance()))
+            return true;
+
+        if ($oKeys->isKeyExists($s)) {
+            $bRet = $oKeys->isKeyExists($s, BxDolSession::getInstance()->getId());
+            if ($bDeleteToken)
+                $oKeys->removeKey($s);
+            return $bRet;
+        }
+        return false;
+    }
+
+    public static function onModuleUninstall ($sModuleName)
+    {
+        BxDolFormQuery::removeFormFields($sModuleName);
+    }
+    
+    function _initCheckerNestedForms ()
+    {
+        $isValid = true;
+
+        // process nested forms
+        foreach ($this->aInputs as $sKey => $aInput) {
+
+            if (!isset($aInput['ghost_template']))
+                continue;
+
+            if (!(is_array($aInput['ghost_template']) && isset($aInput['ghost_template']['inputs'])) && !(is_object($aInput['ghost_template']) && $aInput['ghost_template'] instanceof BxDolFormNestedGhost))
+                continue;
+
+            $sName = $aInput['name'];
+            $aIds = $this->getSubmittedValue($sName, $this->aFormAttrs['method']);
+            if (!$aIds)
+                continue;
+
+            $aNestedForms = array ();
+            foreach ($aIds as $i => $iFileId) {
+
+                // create separate form instance for each file
+                $oFormNested = false;
+                if (is_object($aInput['ghost_template'])) {
+                    $oFormNested = clone($aInput['ghost_template']);
+                } else {
+                    $oFormNested = new BxDolFormNestedGhost($aInput['name'], $aInput['ghost_template'], $this->aParams['db']['submit_name'], $this->oTemplate);
+                }
+                if ($iFileId && 0 != $iFileId)
+                    $aNestedForms[$iFileId] = $oFormNested;
+                else
+                    $aNestedForms[] = $oFormNested;
+
+                // collect nested form values
+                $aSpecificValues = array ();
+                if (isset($this->aParams['db']['submit_name'])) {
+                    $sSubmitName = $this->aParams['db']['submit_name'];
+                    if(is_array($sSubmitName))
+                        $sSubmitName = reset($sSubmitName);
+        
+                    $aSpecificValues = array ($sSubmitName => 1);
+                }
+
+                foreach ($oFormNested->aInputs as $r) {
+                    $sName = str_replace('[]', '', $r['name']);
+                    $aValue = $this->getSubmittedValue($sName, $this->aFormAttrs['method']);
+                    $aSpecificValues[$sName] = isset($aValue[$i]) ? $aValue[$i] : '';
+                }
+                $oFormNested->initChecker(array(), $aSpecificValues);
+
+                // if nested form in invalid - then the whole worm is failed
+                if (!$oFormNested->isValid ())
+                    $isValid = false;
+            }
+
+            if ($aNestedForms)
+                $this->aInputs[$sKey]['ghost_template'] = $aNestedForms;
+
+        }
+
+        return $isValid;
+    }
+
+    /**
+     * Check if form field is visible.
+     * @param $aInput form field array
+     * @return boolean
+     */
+    static public function isVisible ($aInput)
+    {
+        return isset($aInput['visible_for_levels']) ? BxDolAcl::getInstance()->isMemberLevelInSet($aInput['visible_for_levels']) : true;
+    }
+
+    protected function _genMethodName ($s)
+    {
+        return bx_gen_method_name($s);
+    }
+
+    /**
+     * Add replace markers. Curently markers are replaced in action, form_attrs fields.
+     * @param $a array of markers as key => value
+     * @return true on success or false on error
+     */
+    public function addMarkers ($a)
+    {
+        if (empty($a) || !is_array($a))
+            return false;
+        $this->_aMarkers = array_merge ($this->_aMarkers, $a);
+        return true;
+    }
+
+    /**
+     * Replace provided markers in form array
+     * @param $a form description array
+     * @return array where markes are replaced with real values
+     */
+    protected function _replaceMarkers ($a)
+    {
+        return bx_replace_markers($a, $this->_aMarkers);
+    }
+
+    public function getFormErrors ()
+    {
+        $s = '';
+        foreach ($this->aInputs as $k => $a) {
+            if (isset($this->aInputs[$k]['error']) && $this->aInputs[$k]['error'])
+                $s .= $k . ': ' . $this->aInputs[$k]['error'] . " \n";
+        }
+        return $s;
+    }
+
+    protected function _getPrivacyIcon($mixedPrivacy)
+    {
+        switch($mixedPrivacy) {
+            case BX_DOL_PG_MEONLY:
+                $sResult = 'lock';
+                break;
+
+            case BX_DOL_PG_ALL:
+                $sResult = 'globe';
+                break;
+
+            default:
+                $sResult = 'user';
+                break;
+        }
+
+        return $sResult;
+    }
+    
+    protected function _getPrivacyGroup($sPrivacyObject, $iInputId, $iAuthorId = false)
+    {
+        if(!$iAuthorId)
+            $iAuthorId = bx_get_logged_profile_id();
+
+        $mixedPrivacyGroup = BxDolFormQuery::getInputPrivacy($iInputId, $iAuthorId, BxDolPrivacy::getFieldName($sPrivacyObject));
+        if(empty($mixedPrivacyGroup))
+            $mixedPrivacyGroup = $this->_sPrivacyGroupDefault;
+
+        return $mixedPrivacyGroup;
+    }
+}
+
+class BxDolFormChecker
+{
+    protected $_oChecker;
+    protected $_sFormMethod;
+    protected $_aFormParams;
+    protected $_bFormCsrfChecking;
+    protected $_aSpecificValues;
+    protected $_aFieldsCheckForSpam;
+    protected $_aFieldsExcludeFromCheckForSpam;
+
+    function __construct ($sHelper = '')
+    {
+        $this->_sFormMethod = BX_DOL_FORM_METHOD_GET;
+        $this->_bFormCsrfChecking = true;
+
+        $sCheckerName = !empty($sHelper) ? $sHelper : 'BxDolFormCheckerHelper';
+        $this->_oChecker = new $sCheckerName();
+    }
+
+    function setFormMethod($sMethod, $aSpecificValues = array())
+    {
+        $this->_sFormMethod = $sMethod;
+        $this->_aSpecificValues = $aSpecificValues;
+    }
+
+    function setFormParams($aParams)
+    {
+        $this->_aFormParams = $aParams;
+    }
+
+    function setFieldsCheckForSpam($aFieldsCheckForSpam, $aFieldsExcludeFromCheckForSpam)
+    {
+        $this->_aFieldsCheckForSpam = $aFieldsCheckForSpam;
+        $this->_aFieldsExcludeFromCheckForSpam = $aFieldsExcludeFromCheckForSpam;
+    }
+    
+    function enableFormCsrfChecking($bFormCsrfChecking)
+    {
+        $this->_bFormCsrfChecking = $bFormCsrfChecking;
+    }
+
+    // check function
+    function check (&$aInputs, $aValues = array())
+    {
+        $oChecker = $this->_oChecker;
+        $iErrors = 0;
+
+        $sSubmitName = false;
+
+        foreach ($aInputs as $k => $a) {
+            if (isset($a['visible_for_levels']) && !BxDolForm::isVisible($a))
+                continue;
+
+            if (empty($a['name']) || 'submit' == $a['type'] || 'reset' == $a['type'] || 'button' == $a['type'] || 'value' == $a['type']) {
+                if (isset($a['type']) && 'submit' == $a['type'])
+                    $sSubmitName = $k;
+                continue;
+            }
+
+            if ('input_set' == $a['type'])
+                foreach ($a as $r)
+                    if (isset($r['type']) && 'submit' == $r['type'])
+                        $sSubmitName = $k;
+
+            $a['name'] = str_replace('[]', '', $a['name']);
+
+            $sMethodGetSubmittedValue = 'getSubmittedValue' . bx_gen_method_name($a['name']);
+            if(method_exists($this, $sMethodGetSubmittedValue))
+                $val = $this->$sMethodGetSubmittedValue($a['name'], $this->_sFormMethod, $this->_aSpecificValues);
+            else
+                $val = BxDolForm::getSubmittedValue($a['name'], $this->_sFormMethod, $this->_aSpecificValues);
+
+            if (isset(BxDolForm::$TYPES_FILE[$a['type']]))
+                $val = isset($_FILES[$a['name']]['name']) ? $_FILES[$a['name']]['name'] : '';
+
+            // check for unique
+            if(isset($aInputs[$k]['unique']) && $aInputs[$k]['unique'] && !empty($this->_aFormParams['db']['key']) && !empty($this->_aFormParams['db']['table'])) {
+                $sKey = $this->_aFormParams['db']['key'];
+                $sTable = $this->_aFormParams['db']['table'];
+                $sError = _t('_sys_form_err_not_unique_value');
+
+                if(!empty($aValues[$sKey])) {
+                    $sValDb = BxDolFormQuery::fieldGetValue($sTable, $aInputs[$k]['name'], $sKey, $aValues[$sKey]);
+                    if($val != $sValDb && !BxDolFormQuery::fieldCheckUnique($sTable, $aInputs[$k]['name'], $val)) {
+                        ++$iErrors;
+                        $aInputs[$k]['error'] = $sError;
+                    }
+                }
+                else if(!BxDolFormQuery::fieldCheckUnique($sTable, $aInputs[$k]['name'], $val)) {
+                    ++$iErrors;
+                    $aInputs[$k]['error'] = $sError;
+                }
+            }
+
+            // check for links in text fields
+            $sCheckerFunc = isset($a['checker']['func']) ? strtolower($a['checker']['func']) : '';
+            if (
+                !isset(BxDolForm::$FUNC_SKIP_DOMAIN_CHECK[$sCheckerFunc]) && 
+                (!isset($a['skip_domain_check']) || false == $a['skip_domain_check']) && 
+                isset(BxDolForm::$TYPES_TEXT[$a['type']]) && 
+                bx_is_url_in_content($val, true) && 
+                !isAdmin())
+            {
+                $aCheck = checkActionModule(bx_get_logged_profile_id(), 'post links', 'system');
+                if ($aCheck[CHECK_ACTION_RESULT] !== CHECK_ACTION_RESULT_ALLOWED) {
+                    ++$iErrors;
+                    $aInputs[$k]['error'] = $aCheck[CHECK_ACTION_MESSAGE];
+                }
+                else {
+                    checkActionModule(bx_get_logged_profile_id(), 'post links', 'system', true);
+                }
+            }
+
+            // check for macros in text fields
+            $sCheckerFunc = isset($a['checker']['func']) ? strtolower($a['checker']['func']) : '';
+            if (
+                !isset(BxDolForm::$FUNC_SKIP_MACROS_CHECK[$sCheckerFunc]) && 
+                (!isset($a['skip_macros_check']) || false == $a['skip_macros_check']) && 
+                isset(BxDolForm::$TYPES_TEXT[$a['type']]) && 
+                bx_is_macros_in_content($val) && 
+                !isAdmin())
+            {
+                $aCheck = checkActionModule(bx_get_logged_profile_id(), 'use macros', 'system');
+                if ($aCheck[CHECK_ACTION_RESULT] !== CHECK_ACTION_RESULT_ALLOWED) {
+                    ++$iErrors;
+                    $aInputs[$k]['error'] = $aCheck[CHECK_ACTION_MESSAGE];
+                }
+                else {
+                    checkActionModule(bx_get_logged_profile_id(), 'use macros', 'system', true);
+                }
+            }
+
+            if (!isset ($a['checker']))  {
+                if (isset(BxDolForm::$TYPES_CHECKBOX[$a['type']]))
+                    $aInputs[$k]['checked'] = (isset($aInputs[$k]['value']) && $aInputs[$k]['value'] == $val);
+                elseif (!isset(BxDolForm::$TYPES_FILE[$a['type']]) && !isset(BxDolForm::$TYPES_SKIP[$a['type']]))
+                    $aInputs[$k]['value'] = bx_process_input($val);
+                continue;
+            }
+
+            $sCheckFunction = array($oChecker, 'check' . bx_gen_method_name($a['checker']['func']));
+
+            if (is_callable($sCheckFunction))
+                $bool = call_user_func_array ($sCheckFunction, !empty($a['checker']['params']) ? array_merge(array($val), array_values($a['checker']['params'])) : array ($val));
+            else
+                $bool = true;
+
+            if (is_string($bool)) {
+                ++$iErrors;
+                $aInputs[$k]['error'] = $bool;
+            } elseif (!$bool) {
+                ++$iErrors;
+				if (isset($a['checker']['error']))
+                	$aInputs[$k]['error'] = $a['checker']['error'];
+            }
+
+            if (isset(BxDolForm::$TYPES_CHECKBOX[$a['type']]))
+                $aInputs[$k]['checked'] = ($aInputs[$k]['value'] == $val);
+            elseif (!isset(BxDolForm::$TYPES_FILE[$a['type']]) && !isset(BxDolForm::$TYPES_SKIP[$a['type']]))
+                $aInputs[$k]['value'] = bx_process_input($val);
+        }
+
+        // check CSRF token if it's needed.
+        if (getParam('sys_security_form_token_enable') == 'on' && $this->_bFormCsrfChecking === true && !bx_is_api()) {
+            $mixedCsrfTokenUsr = BxDolForm::getSubmittedValue('csrf_token', $this->_sFormMethod, $this->_aSpecificValues);
+            unset($aInputs['csrf_token']);
+
+            if ($mixedCsrfTokenUsr === false || !BxDolForm::isCsrfTokenValid($mixedCsrfTokenUsr)) {
+                $aInputs[$sSubmitName]['error'] = _t('_sys_txt_form_submission_error_csrf_expired');
+                return false;
+            }
+        }
+
+        // check for spam
+        if (!$iErrors) {
+
+            foreach ($aInputs as $k => $a) {
+
+                if (!isset($a['name']))
+                    continue;
+
+                $a['name'] = str_replace('[]', '', $a['name']);
+
+                if ($a['type'] != 'textarea' && $a['type'] != 'text' && !in_array($a['name'], $this->_aFieldsCheckForSpam) || in_array($a['name'], $this->_aFieldsExcludeFromCheckForSpam))
+                    continue;
+                
+                $val = BxDolForm::getSubmittedValue($a['name'], $this->_sFormMethod, $this->_aSpecificValues);
+                if (!$val)
+                    continue;
+
+                if (!$oChecker->checkIsSpam($val, $a['type'])){
+					BxDolForm::setSubmittedValue($a['name'], $val, $this->_sFormMethod, $this->_aSpecificValues);
+                    continue;
+				}
+                
+                ++$iErrors;
+
+                $sErr = _t('_sys_spam_detected');
+                if (BxDolRequest::serviceExists('bx_contact', 'get_contact_page_url') && ($sUrl = BxDolService::call('bx_contact', 'get_contact_page_url')))
+                    $sErr = _t('_sys_spam_detected_contact', $sUrl);
+                $aInputs[$k]['error'] = $sErr;
+            }
+        }
+
+        // add error message near submit button
+        if ($iErrors && $sSubmitName && !($this->_aFormParams['checker_errors']['summary']['disabled'] ?? false))
+            $aInputs[$sSubmitName]['error'] = _t($this->_aFormParams['checker_errors']['summary']['text'] ?? '_sys_txt_form_submission_error');
+    
+        return $iErrors ? false : true;
+    }
+
+    // get clean value from GET/POST
+    function get ($sName, $sPass = 'Xss', $aParams = array())
+    {
+        if (!$sPass)
+            $sPass = 'Xss';
+        $this->_oChecker;
+        $val = BxDolForm::getSubmittedValue($sName, $this->_sFormMethod, $this->_aSpecificValues);
+        return call_user_func_array (array($this->_oChecker, 'pass'.ucfirst($sPass)), $aParams ? array_merge(array($val), $aParams) : array ($val));
+    }
+
+    // db functions
+    function serializeDbValues (&$aInputs, &$aValsToAdd, &$aTrackTextFieldsChanges = null, $aUnset = null)
+    {
+        $aValsToUpdate = array();
+
+        if (null !== $aTrackTextFieldsChanges && isset($aTrackTextFieldsChanges['data']))
+            $aTrackTextFieldsChanges['changed_fields'] = array();
+
+        // get values from form description array
+        foreach ($aInputs as $k => $a) {
+            if (!isset ($a['db']) || !BxDolForm::isVisible($a)) continue;
+            $sKey = str_replace('[]', '', $a['name']);
+            $valClean = $this->get ($sKey, $a['db']['pass'], !empty($a['db']['params']) ? $a['db']['params'] : array());
+            $aValsToUpdate[$sKey] = $valClean;
+            $aInputs[$k]['db']['value'] = $valClean;
+
+            if (null !== $aTrackTextFieldsChanges && $this->isTrackableField($a) && isset($aTrackTextFieldsChanges['data'][$a['name']]) && $aTrackTextFieldsChanges['data'][$a['name']] != $valClean)
+                $aTrackTextFieldsChanges['changed_fields'][] = $a['name'];
+        }
+
+        // get values which are provided manually
+        foreach ($aValsToAdd as $k => $val) {
+            $aValsToUpdate[$k] = $val;
+        }
+
+        // don't update id field for update statement
+        if ($aUnset) {
+            foreach ($aUnset as $sKey) {
+                if (isset($aValsToUpdate[$sKey]))
+                    unset($aValsToUpdate[$sKey]);
+            }
+        }
+
+        // build SQL query part
+        return BxDolDb::getInstance()->arrayToSQL($aValsToUpdate);
+    }
+
+    function dbInsert (&$aDb, &$aInputs, $aValsToAdd = array(), $isIgnore = false)
+    {
+        if (!$aDb['table'])
+            return '';
+
+        $sFields = $this->serializeDbValues ($aInputs, $aValsToAdd);
+        if (!$sFields)
+            return '';
+
+        return "INSERT " . ($isIgnore ? 'IGNORE' : '') . " INTO `{$aDb['table']}` SET $sFields";
+    }
+
+    function dbUpdate ($val, &$aDb, &$aInputs, $aValsToAdd = array(), &$aTrackTextFieldsChanges = null)
+    {
+        if (!$aDb['table'] || !$aDb['key'])
+            return '';
+
+        $oDb = BxDolDb::getInstance();
+
+        if (null !== $aTrackTextFieldsChanges && !isset($aTrackTextFieldsChanges['data'])) {
+            // get row values to compare old and new values
+            $sQuery = $oDb->prepare("SELECT * FROM `{$aDb['table']}` WHERE `{$aDb['key']}` = ?", $val);
+            $aTrackTextFieldsChanges['data'] = $oDb->getRow($sQuery);
+        }
+
+        $sFields = $this->serializeDbValues ($aInputs, $aValsToAdd, $aTrackTextFieldsChanges, array($aDb['key']));
+        if (!$sFields)
+            return '';
+
+        return $oDb->prepare("UPDATE `{$aDb['table']}` SET $sFields WHERE `{$aDb['key']}` = ?", $val);
+    }
+
+    function dbDelete ($val, &$aDb, &$aInputs)
+    {
+        if (!$aDb['table'] || !$aDb['key'])
+            return '';
+
+        $oDb = BxDolDb::getInstance();
+
+        return $oDb->prepare("DELETE FROM `{$aDb['table']}` WHERE `{$aDb['key']}` = ?", $val);
+    }
+
+    function fillWithValues (&$aInputs, &$aValues)
+    {
+        foreach ($aInputs as $k => $a) {
+            if (!isset($aValues[$k]) || isset(BxDolForm::$TYPES_SKIP[$aInputs[$k]['type']])) 
+                continue;
+
+            if (isset(BxDolForm::$TYPES_CHECKBOX[$aInputs[$k]['type']])) {
+                $aInputs[$k]['checked'] = isset($aInputs[$k]['value']) ? ($aInputs[$k]['value'] == $aValues[$k]) : false;
+            } else {
+                $sMethod = 'display' . (isset($a['db']['pass']) ? ucfirst($a['db']['pass']) : 'Undefined');
+                if (method_exists($this->_oChecker, $sMethod))
+                    $aInputs[$k]['value'] = call_user_func_array (array($this->_oChecker, $sMethod), !empty($a['db']['params']) ? array_merge(array($aValues[$k]), $a['db']['params']) : array ($aValues[$k]));
+                else
+                    $aInputs[$k]['value'] = $aValues[$k];
+            }
+        }
+    }
+
+    function isTrackableField($aInput)
+    {
+        return isset(BxDolForm::$TYPES_TEXT[$aInput['type']]);
+    }
+}
+
+class BxDolFormCheckerHelper
+{
+    // check functions - check values for limits or patterns
+
+    static public function checkLength ($s, $iLenMin, $iLenMax)
+    {
+        if (is_array($s)) {
+            foreach ($s as $k => $v) {
+                $iLen = get_mb_len ($v);
+                if ($iLen < $iLenMin || $iLen > $iLenMax)
+                    return false;
+            }
+            return true;
+        }
+        $iLen = get_mb_len ($s);
+        return $iLen >= $iLenMin && $iLen <= $iLenMax ? true : false;
+    }
+    static public function checkDate ($s)
+    {
+        return self::checkPreg ($s, '#^\d+\-\d+\-\d+$#');
+    }
+    static public function checkDateRange ($s, $iMin, $iMax, $bRequired = false)
+    {
+        if (!$bRequired && (empty($s) || '0000-00-00' == $s || '0000-00-00Z' == $s))
+            return true;   
+        if (self::checkPreg ($s, '#^\d+\-\d+\-\d+$#')){
+            $dDate = new DateTime($s);
+            $dDateMax = new DateTime("-" . $iMin . " years");
+            $dDateMin = new DateTime("-" . $iMax . " years");
+            if ($dDate > $dDateMin && $dDate < $dDateMax){
+                return true;
+            }
+        }
+        return false;
+    }
+    static public function checkDateTime ($s)
+    {
+        
+        if (!bx_is_api()){
+            // remove unnecessary opera's input value;
+            $s = str_replace('T', ' ', $s);
+            $s = str_replace('Z', ':00', $s);
+        }
+        else{
+            // remove unnecessary opera's input value;
+            $s = str_replace('Z', '+00:00', $s);
+        }
+
+        return self::checkPreg ($s, '#^\d+\-\d+\-\d+[\sT]{1}\d+:\d+(:\d+)?(\+\d+:\d+)?$#');
+    }
+    static public function checkPreg ($s, $r)
+    {
+        if (is_array($s)) {
+            foreach ($s as $k => $v)
+                if (!preg_match($r, $v))
+                    return false;
+            return true;
+        }
+        return preg_match($r, $s) ? true : false;
+    }
+    static public function checkAvail ($s)
+    {
+        if (is_array($s)) {
+            return !self::_isEmptyArray($s);
+        }
+        return $s ? true : false;
+    }
+    static public function checkJson ($mixed, $bAllowEmpty = false )
+    {
+        if (is_array($mixed)) {            
+            foreach ($mixed as $v)
+                if (!self::_isJsonValid($v, $bAllowEmpty))
+                    return false;
+        }
+        return self::_isJsonValid($mixed, $bAllowEmpty);
+    }
+    static public function checkProfileName($s)
+    {
+        if (!self::checkAvail($s))
+            return false;
+        
+        if (self::checkPreg ($s, '#^@.+$#')){
+            return false;
+        }
+        return true;
+    }
+
+    static public function checkLocation($s, $sName, $sMethod = BX_DOL_FORM_METHOD_DEFAULT, $bAll = false)
+    {
+        $aIndexes = BxDolForm::$LOCATION_INDEXES;
+        foreach($aIndexes as $sIndex) {
+            $sValue = BxDolForm::getSubmittedValue($sName . '_' . $sIndex, $sMethod);
+            $bValue = self::checkAvail($sValue);
+
+            if(in_array($sIndex, BxDolForm::$LOCATION_INDEXES_MANDATORY) && !$bValue)
+                return false;
+            if($bAll && !$bValue)
+                return false;
+            if(!$bAll && $bValue)
+                return true;
+        }
+
+        return $bAll ? true : false;
+    }
+
+    static public function checkEmailOrEmpty($s)
+    {
+        if (empty($s))
+            return true;
+        return self::checkEmail($s);
+    }
+    static public function checkEmail($s)
+    {
+        if (false === strpos($s, '@') || strpos($s, '@') != strrpos($s, '@')) // simple check
+            return false;
+
+        if (!preg_match("/^[\pL\pNd]/u", $s)) // must start with letter or number
+            return false;
+
+        if (!preg_match("/@[\pL\pNd\.\-]+$/u", $s)) // validate domain
+            return false;
+
+        if (!getParam('sys_account_allow_plus_in_email') && false !== strpos($s, '+'))
+            return false;
+
+        $s = str_replace(array('@', '.', '-', '+', '_'), '', $s); // allowed symbols
+        if (preg_match("/[^\pL^\pNd]/u", $s)) // check for undesirable chars
+            return false;
+
+        return true;
+        // return self::checkPreg ($s, "/(([A-Za-z]{3,9}:(?:\/\/)?)(?:[\-;:&=\+\$,\w]+@)?[A-Za-z0-9\.\-]+|(?:www\.|[\-;:&=\+\$,\w]+@)[A-Za-z0-9\.\-]+)((?:\/[\+~%\/\.\w\-_]*)?\??(?:[\-\+=&;%@\.\w_]*)#?(?:[\.\!\/\\\w]*))?/");
+    }
+    static public function checkCaptcha($s)
+    {
+        return !bx_is_api() && ($oCaptcha = BxDolCaptcha::getObjectInstance()) !== false ? $oCaptcha->check() : true;
+    }
+    static public function checkIsSpam(&$val, $sType = 'textarea')
+    {
+        $bSpam = false;
+        /**
+         * @hooks
+         * @hookdef hook-system-check_spam 'system', 'check_spam' - hook to override (perform) spam checking 
+         * - $unit_name - equals `system`
+         * - $action - equals `check_spam`
+         * - $object_id - not used
+         * - $sender_id - currently logged in account id
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `is_spam` - [boolean] by ref, if checked conetent is spam or not, can be overridden in hook processing
+         *      - `content` - [string] by ref, content to check, can be overridden in hook processing
+         *      - `where` - [string] where the content was received from, equals to 'form'
+         *      - `type` - [string] subsection where the content was received from
+         * @hook @ref hook-system-check_spam
+         */
+        bx_alert('system', 'check_spam', 0, getLoggedId(), [
+            'is_spam' => &$bSpam, 
+            'content' => &$val, 
+
+            'is_spam_ref' => &$bSpam, 
+            'content_ref' => &$val,
+
+            'where' => 'form', 
+            'type' => $sType
+        ]);
+        return $bSpam;
+    }
+
+    // pass functions, prepare values to insert to database
+    static public function passInt ($s)
+    {
+        if (is_array($s)) {
+            $a = array ();
+            foreach ($s as $k => $v) {
+                $a[$k] = (int)trim($v);
+            }
+            return $a;
+        }
+        return (int)$s;
+    }
+    static public function passFloat ($s)
+    {
+        if (is_array($s)) {
+            $a = array ();
+            foreach ($s as $k => $v) {
+                $a[$k] = (float)$v;
+            }
+            return $a;
+        }
+        return (float)$s;
+    }
+    static public function passDate ($s)
+    {
+        if (is_array($s)) {
+            $a = array ();
+            foreach ($s as $k => $v) {
+                $a[$k] = self::_passDate ($v, BX_DATA_DATE);
+            }
+            return $a;
+        }
+        return self::_passDate ($s, BX_DATA_DATE);
+    }
+    static public function passDateTs ($s)
+    {
+        if (is_array($s)) {
+            $a = array ();
+            foreach ($s as $k => $v) {
+                $a[$k] = self::_passDate ($v, BX_DATA_DATE_TS);
+            }
+            return $a;
+        }
+        return self::_passDate ($s, BX_DATA_DATE_TS);
+    }
+    static public function passDateUtc ($s)
+    {
+        if (is_array($s)) {
+            $a = array ();
+            foreach ($s as $k => $v) {
+                $a[$k] = self::_passDate ($v, BX_DATA_DATE_TS_UTC);
+            }
+            return $a;
+        }
+        return self::_passDate ($s, BX_DATA_DATE_TS_UTC);
+    }
+    static public function passDateTime ($s)
+    {
+        if (is_array($s)) {
+            $a = array ();
+            foreach ($s as $k => $v) {
+                $a[$k] = self::_passDate ($v, BX_DATA_DATETIME);
+            }
+            return $a;
+        }
+        return self::_passDate ($s, BX_DATA_DATETIME);
+    }
+    static public function passDateTimeTs ($s)
+    {
+        if (is_array($s)) {
+            $a = array ();
+            foreach ($s as $k => $v) {
+                $a[$k] = self::_passDate ($v, BX_DATA_DATETIME_TS);
+            }
+            return $a;
+        }
+        return self::_passDate ($s, BX_DATA_DATETIME_TS);
+    }
+    static public function passDateTimeUtc ($s)
+    {
+        if (is_array($s)) {
+            $a = array ();
+            foreach ($s as $k => $v) {
+                $a[$k] = self::_passDate ($v, BX_DATA_DATETIME_TS_UTC);
+            }
+            return $a;
+        }
+        return self::_passDate ($s, BX_DATA_DATETIME_TS_UTC);
+    }
+    static public function _passDate ($s, $iFormat)
+    {
+        $iRet = bx_process_input ($s, $iFormat);
+        if (false === $iRet)
+            return 0;
+        return $iRet;
+    }    
+    static public function passXss ($s)
+    {
+        if (is_array($s)) {
+            $a = array ();
+            foreach ($s as $k => $v) {
+                $a[$k] = bx_process_input ($v, BX_DATA_TEXT); // "strip tags" option was here in 7.0
+            }
+            return $a;
+        }
+        return bx_process_input ($s, BX_DATA_TEXT); // "strip tags" option was here in 7.0
+    }
+
+	static public function passXssMultiline ($s)
+    {
+        if (is_array($s)) {
+            $a = array ();
+            foreach ($s as $k => $v) {
+                $a[$k] = bx_process_input ($v, BX_DATA_TEXT_MULTILINE);
+            }
+            return $a;
+        }
+        return bx_process_input ($s, BX_DATA_TEXT_MULTILINE);
+    }
+
+    static public function passXssHtml ($s)
+    {
+        if (is_array($s)) {
+            $a = array ();
+            foreach ($s as $k => $v) {
+                $a[$k] = bx_process_input ($v, BX_DATA_HTML);
+            }
+            return $a;
+        }
+        return bx_process_input ($s, BX_DATA_HTML);
+    }
+
+    static public function passAll ($s)
+    {
+        if (is_array($s)) {
+            $a = array ();
+            foreach ($s as $k => $v) {
+                $a[$k] = bx_process_input ($v);
+            }
+            return $a;
+        }
+        return bx_process_input ($s);
+    }
+
+    static public function passPreg ($s, $r)
+    {
+        if (is_array($s)) {
+            $a = array ();
+            foreach ($s as $k => $v) {
+                $a[$k] = self::_passPreg ($v, $r);
+            }
+            return $a;
+        }
+        return self::_passPreg($s, $r);
+    }
+    static public function _passPreg ($s, $r)
+    {
+        if (preg_match ($r, $s, $m)) {
+            return $m[1];
+        }
+        return '';
+    }
+    static public function passBoolean ($s)
+    {
+        if (is_array($s)) {
+            $a = array ();
+            foreach ($s as $k => $v) {
+                $a[$k] = $v == 'on' ? true : false;
+            }
+            return $a;
+        }
+        return $s == 'on' ? true : false;
+    }
+
+    static public function passSet ($s)
+    {
+        if (is_array($s)) {
+            $i = 0;
+            foreach ($s as $v)
+                $i |= pow (2, $v - 1);
+            return $i;
+        }
+        return (int)$s;
+    }
+
+    // display functions, prepare values to output to the screen
+
+    static public function displayRaw ($s)
+    {
+        return $s;
+    }
+
+    static public function displayDate ($i)
+    {
+        return bx_process_output ($i, BX_DATA_DATE_UTC);
+    }
+    static public function displayDateTs ($i)
+    {
+        return bx_process_output ($i, BX_DATA_DATETIME_TS_UTC);
+    }
+    static public function displayDateUtc ($i)
+    {
+        return bx_process_output ($i, BX_DATA_DATETIME_TS_UTC);
+    }    
+    static public function displayDateTime ($i)
+    {
+        return bx_process_output ($i, BX_DATA_DATETIME_UTC);
+    }
+    static public function displayDateTimeTs ($i)
+    {
+        return bx_process_output ($i, BX_DATA_DATETIME_TS_UTC);
+    }
+    static public function displayDateTimeUtc ($i)
+    {
+        return bx_process_output ($i, BX_DATA_DATETIME_TS_UTC);
+    }    
+    static public function displaySet ($i)
+    {
+        $i = (int)$i;
+
+        $bit = 1;
+        $bitpos = 1;
+        $a = array();
+        while ($bit < BX_DOL_INT_MAX && $bit > 0) {
+            if ($bit & $i)
+                $a[] = $bitpos;
+            $bit <<= 1;
+            $bitpos++;
+        }
+        return $a;
+    }
+
+    // for internal usage only
+
+    static public function _isEmptyArray ($a)
+    {
+        return bx_is_empty_array($a);
+    }
+
+    static public function _isFullArray ($a)
+    {
+        return bx_is_full_array($a);
+    }
+
+    static public function _isJsonValid($s, $bAllowEmpty = false)
+    {
+        if ($bAllowEmpty && empty($s))
+            return true;
+
+        json_decode($s);
+        return (json_last_error() == JSON_ERROR_NONE);
+    }
+}
+
+/** @} */

+ 1002 - 0
upgrade/files/15.0.0.B3-15.0.0.RC1/files/inc/classes/BxDolPage.php

@@ -0,0 +1,1002 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    UnaCore UNA Core
+ * @{
+ */
+
+/**
+ * Pages.
+ *
+ * It allows to display pages which are built from studio.
+ *
+ * The new system has the following page features:
+ * - Layouts: page can have any structure, not just columns.
+ * - SEO: page can have own SEO options, like meta tags and meta keywords, as well as instructions for search bots.
+ * - Cache: page can be cached on the server.
+ * - Access control: page access can be controlled using member levels.
+ *
+ *
+ *
+ * @section page_create Creating the Page object:
+ *
+ * 1. add record to 'sys_objects_page' table:
+ *
+ * - object: name of the page object, in the format: vendor prefix, underscore, module prefix, underscore, internal identifier or nothing; for example: bx_profiles_view - profile view page.
+ * - title: name to display as page title.
+ * - module: the module this page belongs to.
+ * - layout_id: page layout to use, this is id of the record from 'sys_pages_layouts' table.
+ * - visible_for_levels: bit field with set of member level ids. To use member level id in bit field - the level id minus 1 as power of 2 is used, for example:
+ *      - user level id = 1 -> 2^(1-1) = 1
+ *      - user level id = 2 -> 2^(2-1) = 2
+ *      - user level id = 3 -> 2^(3-1) = 4
+ *      - user level id = 4 -> 2^(4-1) = 8
+ * - visible_for_levels_editable: it determines if 'visible_for_levels' field is editable from page builder, visibility options can be overriden by custom class and shouldn't be editable in this case.
+ * - url: the page url, if it is static page.
+ * - content_info: content info object name related to the content on the page,
+ *                 if different from module name
+ * - meta_description: meta description of the page.
+ * - meta_keywords: meta keywords of the page.
+ * - meta_robots: instructions for search bots.
+ * - cache_lifetime: number of seconds to store cache for.
+ * - cache_editable: it determines if cache can be edited from page builder.
+ * - deletable: it determines if page can be deleted from page builder.
+ * - override_class_name: user defined class name which is derived from BxTemplPage.
+ * - override_class_file: the location of the user defined class, leave it empty if class is located in system folders.
+ *
+ * Page can select appropriate menu automatically if 'module' and 'object' fields in 'sys_objects_page' table are matched with 'module' and 'name' fields in 'sys_menu_items' table.
+ *
+ *
+ * Page layout are stored in 'sys_pages_layouts' table:
+ * - name: inner unique layout name.
+ * - icon: layout icon to display in page builder, it should represent basic view of the layout to help studio operator determine the layout structure.
+ * - title: layout name to display in page builder.
+ * - template: template name to use to display page with certain layout.
+ * - cells_number: number of areas in the layout, page blocks can be places into this areas(cells).
+ * To define areas in the layout they should be named as '__cell_N__', where N is cell number, starting from 1.
+ *
+ *
+ * 2. Add page blocks to 'sys_pages_blocks' table:
+ * - object: page object name this block belongs to.
+ * - cell_id: cell number in page layout to place block to.
+ * - module: module name this block belongs to.
+ * - title: block title.
+ * - designbox_id: design box to use to diplay page block, it is id of the record from 'sys_pages_design_boxes' table.
+ * - visible_for_levels: bit field with set of member level ids. To use member level id in bit field - the level id minus 1 as power of 2 is used, for example:
+ *      - user level id = 1 -> 2^(1-1) = 1
+ *      - user level id = 2 -> 2^(2-1) = 2
+ *      - user level id = 3 -> 2^(3-1) = 4
+ *      - user level id = 4 -> 2^(4-1) = 8
+ * - type: block type
+ *      - raw: HTML block, displayed in page builder as HTML textarea.
+ *      - html: HTML block, displayed in page builder as visual editor, like TinyMCE.
+ *      - lang: translatable language string, displayed in page builder as editable language key.
+ *      - image: just an image, displayed in page builder as HTML upload form.
+ *      - rss: RSS block, displayed in page builder as editable URL to RSS resource, along with number of displayed items.
+ *      - menu: menu block, displayed as menu selector.
+ *      - service: to display block content, the provided service method is used.
+ * - content: depending on 'type' field:
+ *      - raw: HTML string.
+ *      - html: HTML string.
+ *      - lang: language key.
+ *      - image: image id in the storage and alignment (left, center, right) for example: 36\#center
+ *      - rss: URL to RSS with number of displayed items, for example: http://www.example.com/rss#4
+ *      - menu: menu object name.
+ *      - service: serialized array of service call parameters: module - module name, method - service method name, params - array of parameters.
+ * - deletable: is block deletable from page builder
+ * - copyable: is block can be copied to any other page from page builder.
+ * - order: block order in particular cell.
+ *
+ * Block design boxes are stored in 'sys_pages_design_boxes' table:
+ * - id: consistent id, there are the following defines can be used in the code for each system block style:
+ *      - 0 - BX_DB_CONTENT_ONLY: design box with content only - no borders, no background, no caption.
+ *      - 1 - BX_DB_DEF: default design box with content, borders and caption.
+ *      - 2 - BX_DB_EMPTY: just empty design box, without anything.
+ *      - 3 - BX_DB_NO_CAPTION: design box with content, like BX_DB_DEF but without caption.
+ *      - 10 - BX_DB_PADDING_CONTENT_ONLY: design box with content only wrapped with default padding - no borders, no background, no caption; it can be used to just wrap content with default padding.
+ *      - 11 - BX_DB_PADDING_DEF: default design box with content wrapped with default padding, borders and caption.
+ *      - 13 - BX_DB_PADDING_NO_CAPTION: design box with content wrapped with default padding, like BX_DB_DEF but without caption.
+ * - title: block name which is displayed in studio, describes block styles.
+ * - template: template name to use to display page block.
+ *
+ *
+ * 3. Display Page.
+ * Use the following sample code to display page:
+ * @code
+ *     $oPage = BxDolPage::getObjectInstance('sample'); // 'sample' is 'object' field from 'sys_objects_page' table, it automatically creates instance of default or custom class by object name
+ *     if ($oPage)
+ *         echo $oPage->getCode(); // print page
+ * @endcode
+ *
+ */
+class BxDolPage extends BxDolFactory implements iBxDolFactoryObject, iBxDolReplaceable
+{
+    protected static $_aBlockProcessing = [];
+
+    protected $_sObject;
+    protected $_aObject;
+    protected $_oQuery;
+    protected $_aMarkers = [];
+
+    protected $_sForceRedirect = false;
+
+    /**
+     * Constructor
+     * @param $aObject array of page options
+     */
+    protected function __construct($aObject)
+    {
+        parent::__construct();
+
+        $this->_sObject = $aObject['object'];
+        $this->_aObject = $aObject;
+        $this->_oQuery = new BxDolPageQuery($this->_aObject);
+    }
+
+    /**
+     * Get page object instance by Module name and page URI
+     * @param $sModule module name
+     * @param $sURI unique page URI
+     * @return object instance or false on error
+     */
+    static public function getObjectInstanceByModuleAndURI($sModule, $sURI = '', $oTemplate = false)
+    {
+    	if(empty($sURI) && bx_get('i') !== false)
+    		$sURI = bx_process_input(bx_get('i'));
+
+    	if(empty($sURI))
+			return false;
+
+        $sObject = BxDolPageQuery::getPageObjectNameByURI($sURI, $sModule);
+        return $sObject ? self::getObjectInstance($sObject, $oTemplate) : false;
+    }
+
+    /**
+     * Get page object instance by page URI
+     * @param $sURI unique page URI
+     * @return object instance or false on error
+     */
+    static public function getObjectInstanceByURI($sURI = '', $oTemplate = false, $bRedirectCheck = false)
+    {
+        if(empty($sURI) && bx_get('i') !== false)
+            $sURI = bx_process_input(bx_get('i'));
+
+        if(empty($sURI))
+            return false;
+
+        $sObject = BxDolPageQuery::getPageObjectNameByURI($sURI);
+        if($bRedirectCheck && !$sObject && '/' == substr($sURI, -1)) {
+            unset($_GET['i']);
+
+            header("HTTP/1.1 301 Moved Permanently");
+            header('Location:' . bx_append_url_params(bx_absolute_url(BxDolPermalinks::getInstance()->permalink('page.php?i=' . trim($sURI, '/'))), $_GET));
+            exit;
+        }
+
+        if(!$sObject)
+            return false;
+
+        $oObject = self::getObjectInstance($sObject, $oTemplate);
+        if(($sRedirectUrl = $oObject->getForceRedirect()) !== false) {
+            if(!bx_is_api()) {
+                header("Location: " . $sRedirectUrl);
+                exit;
+            }
+            else 
+                $oObject = bx_api_get_relative_url($sRedirectUrl);
+        }
+
+        return $oObject;
+    }
+
+    /**
+     * Get page object instance by object name
+     * @param $sObject object name
+     * @return object instance or false on error
+     */
+    static public function getObjectInstance($sObject, $oTemplate = false)
+    {
+        if (isset($GLOBALS['bxDolClasses']['BxDolPage!'.$sObject]))
+            return $GLOBALS['bxDolClasses']['BxDolPage!'.$sObject];
+
+        $aObject = BxDolPageQuery::getPageObject($sObject);
+        if (!$aObject || !is_array($aObject))
+            return false;
+
+        $sClass = 'BxTemplPage';
+        if (!empty($aObject['override_class_name'])) {
+            $sClass = $aObject['override_class_name'];
+            if (!empty($aObject['override_class_file']))
+                require_once(BX_DIRECTORY_PATH_ROOT . $aObject['override_class_file']);
+        }
+
+        $o = new $sClass($aObject, $oTemplate);
+
+        return ($GLOBALS['bxDolClasses']['BxDolPage!'.$sObject] = $o);
+    }
+
+	/**
+     * Process page triggers.
+     * Page triggers allow to automatically add page blocks to modules with no different if dependant module was install before or after the module page block belongs to.
+     * For example module "Notes" adds page blocks to all profiles modules (Persons, Organizations, etc)
+     * with no difference if persons module was installed before or after "Notes" module was installed.
+     * @param $sPageTriggerName trigger name to process, usually specified in module installer class - @see BxBaseModGeneralInstaller
+     * @return always true, always success
+     */
+    static public function processPageTrigger ($sPageTriggerName)
+    {
+        // get list of active modules
+        $aModules = BxDolModuleQuery::getInstance()->getModulesBy(array(
+            'type' => 'modules',
+            'active' => 1,
+        ));
+
+        // get list of page block triggers
+        $aPageBlocks = BxDolPageQuery::getPageTriggers($sPageTriggerName);
+
+        // check each page block trigger for all modules
+        foreach ($aPageBlocks as $aPageBlock) {
+            foreach ($aModules as $aModule) {
+                if (!BxDolRequest::serviceExists($aModule['name'], 'get_page_object_for_page_trigger'))
+                    continue;
+
+				$mixedPageObject = BxDolService::call($aModule['name'], 'get_page_object_for_page_trigger', array($sPageTriggerName));
+                if (!$mixedPageObject)
+                    continue;
+
+                $aPageBlockRow = $aPageBlock;
+
+                if (is_array($mixedPageObject))
+                    $aPageBlockRow = array_merge($aPageBlockRow, $mixedPageObject);
+                else
+                    $aPageBlockRow['object'] = $mixedPageObject;
+                
+                BxDolPageQuery::addPageBlockToPage($aPageBlockRow);
+            }
+        }
+
+        return true;
+    }
+
+    static public function multisiteLinkCheck ($sLink, $sPageUri = '', $sPageModule = '', $aQueryParams = [])
+    {
+        $sMultisiteDomain = self::getMultisite($sLink, $sPageUri, $sPageModule, $aQueryParams);
+        if ($sMultisiteDomain) {
+            if (parse_url($sMultisiteDomain, PHP_URL_HOST) !== $_SERVER['HTTP_HOST'])
+                return $sMultisiteDomain . $sLink;
+        }
+
+        if (!$sMultisiteDomain && parse_url(BX_MULTISITE_URL_MAIN, PHP_URL_HOST) !== $_SERVER['HTTP_HOST']) {
+            return BX_MULTISITE_URL_MAIN . $sLink;
+        }
+
+        return false;
+
+    }
+
+	/**
+     * Get multisite link
+     * @param $sLink link to check
+     * @return return multisite link if provided link is multisite, or false is other case
+     */
+    static public function getMultisite ($sLink, $sPageUri = '', $sPageModule = '', $aQueryParams = [])
+    {
+        $sMultisiteDomain = '';
+        if (!$sPageModule || !$aQueryParams) {
+
+            $sQuery = parse_url($sLink, PHP_URL_QUERY);
+            if ($sQuery) {
+
+                $aQueryParams = bx_parse_str($sQuery);
+                $sPageUri = !empty($aQueryParams['i']) ? $aQueryParams['i'] : false;
+                if ($sPageUri) {
+                    $sPageName = BxDolPageQuery::getPageObjectNameByURI($sPageUri);
+                    $aPage = $sPageName ? BxDolPageQuery::getPageObject($sPageName) : false;
+                    $sPageModule = $aPage ? $aPage['module'] : '';
+                }
+            }
+        }
+
+        $sMultisiteDomain = '';
+        if (!empty($aQueryParams['profile_id'])) {
+            $oProfile = BxDolProfile::getInstance($aQueryParams['profile_id']);
+            if (BX_MULTISITE_MODULE == $oProfile->getModule())
+                $sMultisiteDomain = $oProfile->getDisplayName();
+        }
+        elseif (!empty($aQueryParams['id']) && $sPageModule) {
+            $sContentInfo = !empty($aPage['content_info']) ? $aPage['content_info'] : $sPageModule;
+            $oContentInfo = BxDolContentInfo::getObjectInstance($sContentInfo);
+            if ($oContentInfo && BX_MULTISITE_MODULE == $sPageModule) {
+                $sMultisiteDomain = $oContentInfo->getContentTitle($aQueryParams['id']);
+            }
+            elseif ($oContentInfo && BX_MULTISITE_MODULE != $sPageModule) {
+                $iPrivacy = $oContentInfo->getContentPrivacy($aQueryParams['id']);
+                if (0 > $iPrivacy) {
+                    $oProfile = BxDolProfile::getInstance(abs($iPrivacy));
+                    if ($oProfile && BX_MULTISITE_MODULE == $oProfile->getModule())
+                        $sMultisiteDomain = $oProfile->getDisplayName();
+                }
+            }
+        }
+
+        if ($sMultisiteDomain)
+            return str_replace('{domain}', mb_strtolower($sMultisiteDomain), BX_MULTISITE_URL_PATTERN);
+
+        return false;
+    }
+
+	/**
+     * Delete SEO link
+     * @param $sModule module name
+     * @param $sContentInfoObject content info object
+     * @param $sId content id
+     * @return number of affected rows
+     */
+    static public function deleteSeoLink ($sModule, $sContentInfoObject, $sId)
+    {
+        return BxDolPageQuery::deleteSeoLink($sModule, $sContentInfoObject, $sId);
+    }
+
+	/**
+     * Delete SEO links by param
+     * @param $sParamName GET param name
+     * @param $sId content id
+     * @return number of affected rows
+     */
+    static public function deleteSeoLinkByParam ($sParamName, $sId)
+    {
+        return BxDolPageQuery::deleteSeoLinkByParam($sParamName, $sId);
+    }
+
+	/**
+     * Delete SEO links by module
+     * @param $sModule module name
+     * @return number of affected rows
+     */
+    static public function deleteSeoLinkByModule ($sModule)
+    {
+        return BxDolPageQuery::deleteSeoLinkByModule($sModule);
+    }
+
+	/**
+     * Get page object by SEO link. It takes request part from SEO link and returns page object
+     * @param $sRequest request URI with SEO link
+     * @return false - if page wasn't found,  
+     *         page object - on success,  
+     *         string URL - if permanent redirect is needed
+     */
+    static public function getPageBySeoLink ($sRequest)
+    {
+        if (!$sRequest || '/' === $sRequest || !getParam('permalinks_seo_links'))
+            return false;
+
+        // redirect to the correct URL
+        if ('/' === $sRequest[-1] || $sRequest != mb_strtolower($sRequest)) {
+            unset($_GET['_q']);
+            $sUrl = BX_DOL_URL_ROOT . bx_append_url_params(mb_strtolower(trim($sRequest, '/')), $_GET);
+            return $sUrl;    
+        }
+
+        // parse URL
+        $a = explode('/', $sRequest);
+        if (!$a || empty($a[0]))
+            return false;
+
+        // check page URI rewrite redirect
+        $aSeoUriRewrites = BxDolPageQuery::getSeoUriRewrites();
+        if (isset($aSeoUriRewrites[$a[0]])) {
+            unset($_GET['_q']);
+            $a[0] = $aSeoUriRewrites[$a[0]];
+            $sUrl = BX_DOL_URL_ROOT . bx_append_url_params(mb_strtolower(implode('/', $a)), $_GET);
+            return $sUrl;
+        }
+
+        // check page URI rewrite
+        $aSeoUriRewritesInv = array_flip($aSeoUriRewrites);
+        if (isset($aSeoUriRewritesInv[$a[0]]))
+            $a[0] = $aSeoUriRewritesInv[$a[0]];
+
+        // get page
+        $sPageName = BxDolPageQuery::getPageObjectNameByURI($a[0]);
+        $aPage = $sPageName ? BxDolPageQuery::getPageObject($sPageName) : false;
+        if (!$aPage)
+            return false;
+
+        // page with params
+        if (!empty($a[1])) { 
+            $r = BxDolPageQuery::getSeoLink($aPage['module'], $a[0], ['uri' => $a[1]]);
+            if ($r)
+                $_GET[$r['param_name']] = $_REQUEST[$r['param_name']] = $r['param_value'];
+        }
+
+        // multisite redirect
+        if (defined('BX_MULTISITE_MODULE')) {
+            list($sPageLink, $aPageParams) = bx_get_base_url_inline();
+            unset($aPageParams['_q']);
+            $sLink = bx_append_url_params($sPageLink, $aPageParams);
+            if (0 === strpos($sLink, BX_DOL_URL_ROOT))
+                $sLink = substr($sLink, strlen(BX_DOL_URL_ROOT));
+
+            $s = BxDolPage::multisiteLinkCheck ('', $a[0], $aPage['module'], $_GET);
+            if (false !== $s)
+                return $s . $sLink;
+        }
+
+        // display page
+        $_REQUEST['i'] = $_GET['i'] = $a[0];
+        $oPage = BxDolPage::getObjectInstanceByURI($a[0], false, true);
+        return $oPage;
+    }
+    
+	/**
+     * Process SEO links. It takes request part from SEO link and process it 
+     * to make it work as regular page link
+     * @param $sRequest request URI with SEO link
+     * @return true - if page was found and processed correctly, false - if page wasn't found
+     */
+    static public function processSeoLink ($sRequest)
+    {
+        $mixed = self::getPageBySeoLink($sRequest);
+        if (($sUrl = $mixed) && is_string($sUrl)) {
+            header('Location:' . $sUrl, true, 301);
+            exit;
+        }
+        elseif (($oPage = $mixed) && is_object($oPage)) {
+            $oPage->displayPage();
+            return true;
+        }
+        else {
+            return false;
+        }
+    }
+
+	/**
+     * Transform regular link to SEO link. It takes regular list as param and return SEO link.
+     * @param $sLink regular link
+     * @param $sPrefix prefix to add to the final URL, usually BX_DOL_URL_ROOT
+     * @param $aParams additional GET params
+     * @return SEO link string on success, false if transform failed or not necessary
+     */
+    static public function transformSeoLink ($sLink, $sPrefix, $aParams = array())
+    {
+        static $aMemoryUrls = [];
+        if (isset($aMemoryUrls[$sLink]))
+            return $aMemoryUrls[$sLink];
+
+        if (!getParam('permalinks_seo_links'))
+            return false;
+
+        if (0 !== strncmp('page.php', $sLink, 8)) // only page.php links are supported
+            return false;
+
+        $sQuery = parse_url($sLink, PHP_URL_QUERY);
+        if (false === $sQuery)
+            return false;
+
+        if (function_exists('bx_parse_str'))
+            $aQueryParams = bx_parse_str($sQuery);
+        else
+            parse_str($sQuery, $aQueryParams);
+
+        $sPageUri = !empty($aQueryParams['i']) ? $aQueryParams['i'] : false;
+        unset($aQueryParams['i']);
+
+        if (!$sPageUri) // page URI wasn't found
+            return false;
+
+        $sPageModule = '';
+
+        $aSeoParams = array('id', 'profile_id'); // supported SEO params which are transformed to SEO strings
+        $sSeoParamName = '';
+        $sSeoParamValue = '';
+        if ('cmts-view' != $sPageUri) {
+            foreach ($aSeoParams as $k) {
+                if (empty($aQueryParams[$k]) && empty($aParams[$k]))
+                    continue;
+                $sSeoParamName = $k;
+                $sSeoParamValue = !empty($aParams[$k]) ? $aParams[$k] : $aQueryParams[$k];
+                unset($aQueryParams[$k]);
+                unset($aParams[$k]);
+                break; // only 1 SEO param will be transformed
+            }
+        }
+        if (!empty($sSeoParamValue) && 0 === strpos($sSeoParamValue, '{'))
+            return false;
+        
+        $aSeoUriRewrites = BxDolPageQuery::getSeoUriRewrites();
+        if (isset($aSeoUriRewrites[$sPageUri])) {
+            $sSeoPageUri = $aSeoUriRewrites[$sPageUri];
+        } else {
+            $sSeoPageUri = $sPageUri;
+        }
+
+        if ($sSeoParamName && $sSeoParamValue) { // process page with SEO param
+            $sPageName = BxDolPageQuery::getPageObjectNameByURI($sPageUri);
+            $aPage = $sPageName ? BxDolPageQuery::getPageObject($sPageName) : false;
+            if ($aPage) {
+                $sPageModule = $aPage['module'];
+                $sContentInfo = !empty($aPage['content_info']) ? $aPage['content_info'] : $aPage['module'];
+                $bSeoUrlFound = true;
+
+                if ('id' == $sSeoParamName) {
+                    $oContentInfo = BxDolContentInfo::getObjectInstance($sContentInfo);
+                    if (!$oContentInfo) {
+                        $bSeoUrlFound = false;
+                    } else {
+                        $sSeoTitle = $oContentInfo->getContentTitle($sSeoParamValue);
+                    }
+                    if (!$sSeoTitle)
+                        $sSeoTitle = base_convert((string)sprintf('%u', crc32($sSeoParamValue . BX_DOL_SECRET)), 10, 36);
+                }
+                elseif ('profile_id' == $sSeoParamName) {
+                    $oProfile = BxDolProfile::getInstance($sSeoParamValue);
+                    if (!$oProfile) {
+                        $bSeoUrlFound = false;
+                    } else {
+                        $sSeoTitle = $oProfile->getDisplayName();
+                    }
+                }
+                
+                $r = false;
+                if (!$bSeoUrlFound) {
+                    $sSeoPageUri = false;
+                } else {
+                    $r = BxDolPageQuery::getSeoLink($sPageModule, $sPageUri, ['param_value' => $sSeoParamValue]);
+                }
+                if ($bSeoUrlFound && !$r) {
+                    $sSeoTitleLimited = BxTemplFunctions::getInstance()->getStringWithLimitedLength($sSeoTitle, 45);
+                    $sUri = uriGenerate ($sSeoTitleLimited, 'sys_seo_links', 'uri', ['cond' => ['module' => $sPageModule, 'page_uri' => $sPageUri]]);
+
+                    /**
+                     * @hooks
+                     * @hookdef hook-system-uri_generate 'system', 'uri_generate' - hook to override SEO URI generated for a page
+                     * - $unit_name - equals `system`
+                     * - $action - equals `uri_generate`
+                     * - $object_id - not used
+                     * - $sender_id - not used
+                     * - $extra_params - array of additional params with the following array keys:
+                     *      - `module` - [string] module name
+                     *      - `page_uri` - [string] page default URI
+                     *      - `param_name` - [string] param name
+                     *      - `param_value` - [string] param value
+                     *      - `title` - [string] SEO page title
+                     *      - `uri` - [string] by ref, generated SEO URI, can be overridden in hook processing
+                     * @hook @ref hook-system-uri_generate
+                     */
+                    bx_alert('system', 'uri_generate', 0, false, [
+                        'module' => $sPageModule,
+                        'page_uri' =>$sPageUri,
+                        'param_name' => $sSeoParamName,
+                        'param_value' => $sSeoParamValue,
+                        'title' => $sSeoTitle,
+                        'uri' => &$sUri,
+                        'uri_ref' => &$sUri,
+                    ]);
+
+                    BxDolPageQuery::insertSeoLink($sPageModule, $sPageUri, $sSeoParamName, $sSeoParamValue, $sUri);
+                }
+                elseif ($r && $r['param_name'] == $sSeoParamName) {
+                    $sUri = $r['uri'];
+                } 
+                else {
+                    $sUri = false;
+                }
+
+                if ($sUri)
+                    $sSeoPageUri .= '/' . $sUri;
+                else
+                    $sSeoPageUri = false;
+            }
+        }
+
+        $sRet = false;        
+        if ($sSeoPageUri) {
+            $sLinkTransformed = $sPrefix . bx_append_url_params($sSeoPageUri, array_merge($aQueryParams, $aParams), false);
+            if (defined('BX_MULTISITE_MODULE')) {
+                $s = BxDolPage::multisiteLinkCheck ($sLinkTransformed, $sPageUri, $sPageModule, [$sSeoParamName => $sSeoParamValue]);
+                if (false !== $s) 
+                    $sRet = $s;
+            }
+            else {
+                $sRet = $sLinkTransformed;
+            }
+        }
+        
+        $aMemoryUrls[$sLink] = $sRet;
+
+        return $sRet;
+    }
+
+	/**
+     * Transform SEO regular link into regular link with permalinks off.
+     * @param $sSeoLink SEO link
+     * @param $sPrefix prefix to add to the final URL, usually BX_DOL_URL_ROOT
+     * @return unSEO link string on success, false if no transform is needed
+     */
+    static public function untransformSeoLink ($sSeoLink, $sPrefix)
+    {
+        // check for standard links first
+        if (preg_match('/^(page\/|s\/|m\/|modules\/|page\.php|storage\.php)/', $sSeoLink))
+            return false;
+
+        // parse link
+        $aParts = parse_url($sSeoLink);
+        if (!$aParts || empty($aParts['path']))
+            return false;
+
+        $aUris = explode('/', trim($aParts['path'], '/'));
+
+        // check if link starts with page URI and page with this URI exists 
+        if (!$aUris || empty($aUris[0]) || !($sPageName = BxDolPageQuery::getPageObjectNameByURI($aUris[0], false, true)))
+            return false;
+
+        $aPage = BxDolPageQuery::getPageObject ($sPageName);
+
+        // make final URL
+        $s = 'page.php?i=' . $aPage['uri'];
+
+        // add params
+        if (!empty($aUris[1])) {
+            if ($aPage) {
+                $r = BxDolPageQuery::getSeoLink($aPage['module'], $aPage['uri'], ['uri' => urldecode($aUris[1])]);     
+                if (!$r)
+                    return false;
+                $s .= '&' . $r['param_name'] . '=' .  $r['param_value'];
+            }
+        }
+
+        return $s . (!empty($aParts['query']) ? '&' . $aParts['query'] : '');
+    }
+
+	/**
+     * Perform SEO redorect from regular pages if needed
+     * @param $sSeoLink SEO link
+     * @param $sPrefix prefix to add to the final URL, usually BX_DOL_URL_ROOT
+     * @return unSEO link string on success, false if no transform is needed
+     */
+    static public function seoRedirect ()
+    {
+        if (!getParam('permalinks_seo_links'))
+            return;
+
+        list($sPageLink, $aPageParams) = bx_get_base_url_inline();
+        $sLink = bx_append_url_params($sPageLink, $aPageParams);
+        if (0 === strpos($sLink, BX_DOL_URL_ROOT))
+            $sLink = substr($sLink, strlen(BX_DOL_URL_ROOT));
+
+        if (defined('BX_MULTISITE_MODULE')) {
+            $s = BxDolPage::multisiteLinkCheck ($sLink);
+            if (false !== $s) {
+                header('Location:' . $s, true, 301);
+                exit;
+            }
+        }
+
+        if ($sSeoLink = self::transformSeoLink ($sLink, BX_DOL_URL_ROOT)) {
+            header("Location:{$sSeoLink}", true, 301);
+            exit;
+        }
+    }
+
+    static public function getSeoHash($s)
+    {
+        return base_convert(substr(md5($s), -8), 16, 36);
+    }
+
+    /**
+     * Static method to Get embed code
+     * @return string.
+     */
+    static public function getEmbedData ($sUrl)
+    {
+        $sUrl = urldecode($sUrl);
+        $aParams = [];
+        
+        $aUrl = bx_get_base_url($sUrl);
+        if (!isset($aUrl[1]['i'])){
+            return [];
+        }
+            
+        $sUri = $aUrl[1]['i'];
+        unset($aUrl[1]['i']);
+        $aParams = $aUrl[1];
+
+        $sTitle = $sAuthorName = $sAuthorUrl = $sThumb = $sHtml = '';
+        if (isset($aParams['id'])) {
+            $sContentInfo = BxDolPageQuery::getContentInfoObjectNameByURI($sUri);
+            if(($oContentInfo = BxDolContentInfo::getObjectInstance($sContentInfo))) {
+                $sTitle = $oContentInfo->getContentTitle($aParams['id']);
+                $iAuthor = $oContentInfo->getContentAuthor($aParams['id']);
+                if(($oAuthor = BxDolProfile::getInstance($iAuthor)) !== false) {
+                    $sAuthorName = $oAuthor->getDisplayName();
+                    $sAuthorUrl = $oAuthor->getUrl();
+                }
+                $sThumb = $oContentInfo->getContentThumb($aParams['id']);
+                $sHtml = $oContentInfo->getContentEmbed($aParams['id']);
+            }
+        }
+        else {
+            $oPage = BxDolPage::getObjectInstanceByURI($sUri, false, true);
+            $aPage = $oPage->getObject();
+            $sTitle = $oPage->_getPageTitle();
+            $sHtml = BxDolTemplate::getInstance()->parseHtmlByName('embed.html', [
+                'title' => $sTitle,
+                'url' => BX_DOL_URL_ROOT . 'page.php?a=embed&o=' . $oPage->getName()
+            ]);
+        }
+        return ['url' => $sUrl, 'title' => $sTitle, 'author_name' => $sAuthorName, 'author_url' => $sAuthorUrl, 'thumbnail_url' => $sThumb, 'html' => $sHtml];
+    }
+
+    static public function getPageBlockData($iBlockId, $iContentId = 0, $sContentModule = '')
+    {
+        $oDb = new BxDolPageQuery([]);
+
+        $sData = $oDb->getPageBlockData($iBlockId, $iContentId, $sContentModule);
+        $aData = !empty($sData) ? json_decode($sData, true) : [];
+
+        foreach($aData as &$j) {
+            foreach($j as &$k) {
+                switch($k['type']) {
+                    case 'image':
+                        $aImage = bx_api_get_image(['sys_images_editor', 'sys_images_editor'], (int)$k['content']);
+                        if($aImage && is_array($aImage))
+                            $k['content'] = $aImage;
+                        break;
+
+                    case 'link':
+                        if(($oEmbed = BxDolEmbed::getObjectInstance('sys_system')) !== false)
+                            $k['content_data'] = $oEmbed->getData($k['content'], '');
+                        break;
+                }
+            }
+        }
+
+        return $aData;
+    }
+
+    static public function setPageBlockData($iBlockId, $iContentId = 0, $sContentModule = '', $mixedData = '')
+    {
+        $oDb = new BxDolPageQuery([]);
+
+        $sData = is_array($mixedData) ? json_encode($mixedData) : $mixedData;
+
+        return $oDb->setPageBlockData($iBlockId, $iContentId, $sContentModule, $sData);
+    }
+    
+    static public function getBlockProcessing()
+    {
+        return self::$_aBlockProcessing;
+    }
+
+    static public function setBlockProcessing($aBlock)
+    {
+        self::$_aBlockProcessing = $aBlock && is_array($aBlock) ? $aBlock : [];
+    }
+
+    static public function unsetBlockProcessing()
+    {
+        self::$_aBlockProcessing = [];
+    }
+
+    /**
+     * Display complete page
+     */
+    public function displayPage ($oTemplate = null)
+    {
+        $sSessionKey = 'sys_entrance_url';
+        $oSession = BxDolSession::getInstance();
+        if(!$oSession->getValue($sSessionKey)) {
+            list($sPageLink, $aPageParams) = bx_get_base_url_inline();
+
+            $oSession->setValue($sSessionKey, bx_append_url_params($sPageLink, array_intersect_key($aPageParams, array_flip(['i', 'id', 'profile_id']))));
+        }
+
+        if(isLogged())
+            BxDolAccount::getInstance()->isNeedChangePassword();
+
+        if ($this->isLockedFromUnauthenticated ($this->_aObject['uri'])) {
+            $this->redirectToLoginForm();
+            exit;
+        }
+
+        if(!$oTemplate)
+            $oTemplate = BxDolTemplate::getInstance();
+
+        $oTemplate->setPageNameIndex(BX_PAGE_DEFAULT);
+        if(($sHxTarget = bx_get_htmx_target()) !== false) 
+            $oTemplate->setPageNameIndexByTarget($sHxTarget);
+
+        $oTemplate->setPageUrl($this->_aObject['url']);
+        $oTemplate->setPageType($this->getType());
+        $oTemplate->setPageInjections($this->getInjections());
+        if($oTemplate->getPageNameIndex() == BX_PAGE_CONTENT_PRELOAD)
+            $oTemplate->setPageContent('page_main_code', $this->getIncludes());
+        else
+            $oTemplate->setPageContent('page_main_code', $this->getCode());
+        $oTemplate->getPageCode();
+    }
+
+    public function getId ()
+    {
+    	return (int)$this->_aObject['id'];
+    }
+
+    public function getType ()
+    {
+        if (defined('BX_MULTISITE_FORCE_PAGETYPE') && defined('BX_MULTISITE_MODULE')) {
+
+            list($sPageLink, $aPageParams) = bx_get_base_url_inline();
+            $sLink = bx_append_url_params($sPageLink, $aPageParams);
+            if (0 === strpos($sLink, BX_DOL_URL_ROOT))
+                $sLink = substr($sLink, strlen(BX_DOL_URL_ROOT));
+
+            if (BxDolPage::getMultisite ($sLink))
+                return BX_MULTISITE_FORCE_PAGETYPE;
+        }
+
+        return (int)$this->_aObject['type_id'];
+    }
+
+    public function getModule ()
+    {
+    	return $this->_aObject['module'];
+    }
+    
+    public function getSubMenu ()
+    {
+        return $this->_aObject['submenu'];
+    }
+
+    public function getMetaDescription ()
+    {
+        return $this->_aObject['meta_description'];
+    }
+
+    public function getName ()
+    {
+    	return $this->_sObject;
+    }
+    
+    public function getObject ()
+    {
+    	return $this->_aObject;
+    }
+    
+    public function getInjections ()
+    {
+        $aResult = array();
+
+        foreach($this->_aObject as $sKey => $sValue)
+            if(strpos($sKey, 'inj_') === 0)
+                $aResult[substr($sKey, 4)] = $sValue;
+
+        return $aResult;
+    }
+
+    public function getForceRedirect ()
+    {
+        return $this->_sForceRedirect ?: false;
+    }
+
+    public function setForceRedirect ($sUrl)
+    {
+        $this->_sForceRedirect = $sUrl;
+    }
+
+    public function setTitle ($sTitle)
+    {
+        return $this->_aObject['title'] = $sTitle;
+    }
+
+    /**
+     * Add replace markers. Markers are replaced in raw, html, lang blocks and page title, description, keywords and block titles.
+     * @param $a array of markers as key => value
+     * @return true on success or false on error
+     */
+    public function addMarkers ($a)
+    {
+        if (empty($a) || !is_array($a))
+            return false;
+        $this->_aMarkers = array_merge ($this->_aMarkers, $a);
+        return true;
+    }
+
+    public function isAvailablePage ()
+    {
+        return $this->_isAvailablePage($this->_aObject);
+    }
+
+    public function isVisiblePage ()
+    {
+        return $this->_isVisiblePage($this->_aObject);
+    }
+
+    /**
+     * Check if page can be seen by viewer.
+     * @param array $a - page object.
+     * @return type boolean (true or false).
+     */
+    public function isPage()
+    {
+        return $this->_isAvailablePage($this->_aObject) === true && $this->_isVisiblePage($this->_aObject) === true;
+    }
+
+    public function isVisiblePageSubmenu ()
+    {
+        return $this->_aObject['submenu'] != 'disabled';
+    }
+
+    public function isEditAllowed ()
+    {
+        return false;
+    }
+
+    public function isDeleteAllowed ()
+    {
+        return false;
+    }
+
+    /**
+     * Replace provided markers in a string
+     * @param $mixed string or array to replace markers in
+     * @return string where all occured markers are replaced
+     */
+    protected function _replaceMarkers ($mixed, $aAdditionalMarkers = array())
+    {
+        return bx_replace_markers($mixed, array_merge($this->_aMarkers, $aAdditionalMarkers));
+    }
+
+    /**
+     * Check if page block is visible.
+     */
+    protected function _isVisibleBlock ($a)
+    {
+        return BxDolAcl::getInstance()->isMemberLevelInSet($a['visible_for_levels']);
+    }
+
+    /**
+     * Check if page is available.
+     * @param type $a - page object.
+     * @return boolean true if available, false or a string with error message otherwise.
+     */
+    protected function _isAvailablePage ($a)
+    {
+        return true;
+    }
+
+    /**
+     * Check if page is visible.
+     * @param array $a - page object.
+     * @return boolean true if visible, false or a string with error message otherwise.
+     */
+    protected function _isVisiblePage ($a)
+    {
+        return isAdmin() || BxDolAcl::getInstance()->isMemberLevelInSet($a['visible_for_levels']);
+    }
+
+    public static function isLockedFromUnauthenticated ($sUri)
+    {
+        if (!isLogged() && getParam('sys_lock_from_unauthenticated') && !defined('BX_DOL_CRON_EXECUTE')) {
+            $aURIs = explode(',', getParam('sys_lock_from_unauthenticated_exceptions'));
+            array_walk($aURIs, function (&$sVal) {
+                $sVal = trim($sVal);
+            });
+            $aI = array_combine($aURIs, array_fill(0, count($aURIs), 1));
+            if (!preg_match('/\/oauth2\//', $_SERVER['REQUEST_URI']) /*&& !preg_match('/searchKeyword.php$/', $_SERVER['PHP_SELF'])*/ && !preg_match('/member.php$/', $_SERVER['PHP_SELF']) && !isset($aI[$sUri])) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    public static function redirectToLoginForm ()
+    {
+        header("Location: " . bx_append_url_params(bx_absolute_url(BxDolPermalinks::getInstance()->permalink('page.php?i=login')), ['relocate' => bx_get_self_url()]));
+        exit;
+    }
+}
+
+/** @} */

+ 1008 - 0
upgrade/files/15.0.0.B3-15.0.0.RC1/files/inc/classes/BxDolPrivacy.php

@@ -0,0 +1,1008 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    UnaCore UNA Core
+ * @{
+ */
+
+define('BX_DOL_PG_HIDDEN', '1');
+define('BX_DOL_PG_MEONLY', '2');
+define('BX_DOL_PG_ALL', '3');
+define('BX_DOL_PG_MEMBERS', '4');
+define('BX_DOL_PG_FRIENDS', '5');
+define('BX_DOL_PG_FRIENDS_SELECTED', '6');
+define('BX_DOL_PG_RELATIONS', '7');
+define('BX_DOL_PG_RELATIONS_SELECTED', '8');
+define('BX_DOL_PG_MEMBERSHIPS_SELECTED', '9');
+define('BX_DOL_PG_CUSTOM', '99');
+
+define('BX_DOL_PG_DEFAULT', BX_DOL_PG_ALL);
+
+/**
+ * Privacy settings for any content.
+ *
+ * Integration of the content with privacy engine allows site member
+ * to organize the access to his content.
+ *
+ * In addition to regular privacy groups (Public, Friends), spaces are supported. 
+ * When some space (usually some another profile) is specified as privacy, 
+ * then another profile visibility is used to check the privacy.
+ *
+ * Related classes:
+ *  BxDolPrivacyQuery - database queries.
+ *
+ * Example of usage:
+ * 1. Register your privacy actions in `sys_privacy_actions` database table.
+ * 2. Add one privacy field(with INT type) in the table with your items for each action.
+ *    For example, for action 'comment', the field name should be 'allow_comment_to'.
+ * 3. Add group choosers for necessary actions in the form, which is used to add new items.
+ * @code
+ *    $oPrivacy = new BxDolPrivacy();
+ *    $oPrivacy->getGroupChooser($iItemOwnerId, $sModuleUri, $sModuleAction);
+ * @endcode
+ *
+ * 4. Check privacy when any user tries to view an item.
+ * @code
+ *    $oPrivacy = new BxDolPrivacy($sTable, $sFieldId, $sFieldOwnerId);
+ *    if($oPrivacy->check($sAction, $iObjectId, $iViewerId)) {
+ *     //show necessary content
+ *    }
+ * @endcode
+ *
+ *    @see an example of integration in BoonEx modules, for example: Posts
+ *
+ *
+ * Memberships/ACL:
+ * Doesn't depend on user's membership.
+ *
+ *
+ * Alerts:
+ * no alerts available
+ *
+ */
+class BxDolPrivacy extends BxDolFactory implements iBxDolFactoryObject
+{
+    protected $_oDb;
+    protected $_sObject;
+    protected $_aObject;
+
+    protected $_aGroupsSettings;
+    protected $_aGroupsExclude;
+    
+    protected $_sFormGroupCustom;
+    protected $_sFormDisplayGcMembers;
+    protected $_sFormDisplayGcMemberships;
+
+    /**
+     * Constructor
+     * @param $aObject array of grid options
+     */
+    protected function __construct($aObject)
+    {
+        parent::__construct();
+
+        $this->_aObject = $aObject;
+        $this->_sObject = $aObject['object'];
+
+        $this->_oDb = new BxDolPrivacyQuery();
+        $this->_oDb->init($this->_aObject);
+
+        $this->_aGroupsSettings = [
+            BX_DOL_PG_FRIENDS_SELECTED => [
+                'name' => 'friends_selected',
+                'is_allowed' => '',
+                'connection' => 'sys_profiles_friends', 
+                'js_method_create_group' => 'selectMembers',
+                'db_table_items' => 'sys_privacy_groups_custom_members',
+                'db_field_item' => 'member_id',
+                'uri_get_items' => 'users_list',
+            ],
+            BX_DOL_PG_RELATIONS => [
+                'name' => 'relations',
+                'is_allowed' => 'isAllowedRelations',
+                'connection' => 'sys_profiles_relations',
+            ],
+            BX_DOL_PG_RELATIONS_SELECTED => [
+                'name' => 'relations_selected',
+                'is_allowed' => 'isAllowedRelations',
+                'connection' => 'sys_profiles_relations', 
+                'js_method_create_group' => 'selectMembers',
+                'db_table_items' => 'sys_privacy_groups_custom_members',
+                'db_field_item' => 'member_id',
+                'uri_get_items' => 'users_list',
+            ],
+            BX_DOL_PG_MEMBERSHIPS_SELECTED => [
+                'name' => 'memberships_selected',
+                'is_allowed' => 'isAllowedMemberships',
+                'connection' => '',
+                'js_method_create_group' => 'selectMemberships',
+                'db_table_items' => 'sys_privacy_groups_custom_memberships',
+                'db_field_item' => 'membership_id',
+                'uri_get_items' => 'memberships_list',
+            ]
+        ];
+
+        $this->_aGroupsExclude = array();
+
+        $this->_sFormGroupCustom = 'sys_privacy_group_custom';
+        $this->_sFormDisplayGcMembers = 'sys_privacy_group_custom_members';
+        $this->_sFormDisplayGcMemberships = 'sys_privacy_group_custom_memberships';
+    }
+
+    /**
+     * Get privacy object instance by object name
+     * @param $sObject object name
+     * @return object instance or false on error
+     */
+    public static function getObjectInstance($sObject)
+    {
+        if(isset($GLOBALS['bxDolClasses']['BxDolPrivacy!' . $sObject]))
+            return $GLOBALS['bxDolClasses']['BxDolPrivacy!' . $sObject];
+
+        $aObject = BxDolPrivacyQuery::getPrivacyObject($sObject);
+        if(!$aObject || !is_array($aObject))
+            return false;
+
+        $sClass = 'BxTemplPrivacy';
+        if(!empty($aObject['override_class_name'])) {
+            $sClass = $aObject['override_class_name'];
+            if(!empty($aObject['override_class_file']))
+                require_once(BX_DIRECTORY_PATH_ROOT . $aObject['override_class_file']);
+        }
+
+        $o = new $sClass($aObject);
+        return ($GLOBALS['bxDolClasses']['BxDolPrivacy!' . $sObject] = $o);
+    }
+
+    /**
+     * Get Select element with available groups.
+     *
+     * @param  string  $sObject  privacy object name.
+     * @param  integer $iOwnerId object's owner ID.
+     * @param  array   $aParams  an array of custom selector's params (dynamic_groups - an array of arrays('key' => group_id, 'value' => group_title), title - the title to be used for generated field).
+     * @return an      array with Select element description.
+     */
+    public static function getGroupChooser($sObject, $iOwnerId = 0, $aParams = array())
+    {
+        $oPrivacy = BxDolPrivacy::getObjectInstance($sObject);
+        if(empty($oPrivacy))
+            return array();
+
+        $sModule = $oPrivacy->_aObject['module'];
+        $sAction = $oPrivacy->_aObject['action'];
+
+        if($iOwnerId == 0)
+            $iOwnerId = bx_get_logged_profile_id();
+
+        $sValue = $oPrivacy->_oDb->getDefaultGroupByUser($sModule, $sAction, $iOwnerId);
+        if(empty($sValue))
+            $sValue = $oPrivacy->_oDb->getDefaultGroup($sModule, $sAction);
+
+        $aValues = $oPrivacy->getGroups($iOwnerId, $aParams);
+
+        $aValues = $oPrivacy->addDynamicGroups($aValues, $iOwnerId, $aParams);
+
+        if(getParam('sys_enable_post_to_context_for_privacy') == 'on')
+            $aValues = $oPrivacy->addSpaces($aValues, $iOwnerId, $aParams);
+
+        $sName = $oPrivacy->convertActionToField($sAction);
+
+        $sTitle = isset($aParams['title']) && !empty($aParams['title']) ? $aParams['title'] : '';
+        if(empty($sTitle)) {
+            $sTitle = $oPrivacy->_oDb->getTitle($sModule, $sAction);
+            $sTitle = _t(!empty($sTitle) ? $sTitle : '_' . $sName);
+        }
+
+        $bDynamicMode = (isset($aParams['dynamic_mode']) && (bool)$aParams['dynamic_mode'] === true) || bx_is_dynamic_request();
+        return array(
+            'type' => 'select',
+            'name' => $sName,
+            'caption' => $sTitle,
+            'value' => $sValue,
+            'values' => $aValues,
+            'attrs' => array(
+                'class' => 'sys-privacy-group',
+                'onchange' => 'javascript: ' . $oPrivacy->getJsObjectName() . '.selectGroup(this);'
+            ),
+            'checker' => array(
+                'func' => 'avail',
+                'error' => _t('_sys_ps_ferr_incorrect_select')
+            ),
+            'db' => array(
+                'pass' => 'Int'
+            ),
+            'content' => $oPrivacy->addCssJs($bDynamicMode)
+        );
+    }
+
+    public static function initGroupChooser($sObject, $iOwnerId = 0, $aParams = array())
+    {
+        $sResult = '';
+
+        $oPrivacy = BxDolPrivacy::getObjectInstance($sObject);
+        if(empty($oPrivacy))
+            return $sResult;
+
+        $iOwnerId = !empty($iOwnerId) ? (int)$iOwnerId : bx_get_logged_profile_id();
+        $iContentId = !empty($aParams['content_id']) ? (int)$aParams['content_id'] : 0;
+        $iGroupId = !empty($aParams['group_id']) ? (int)$aParams['group_id'] : 0;
+        $bDynamicMode = (isset($aParams['dynamic_mode']) && (bool)$aParams['dynamic_mode'] === true) || bx_is_dynamic_request();
+
+        $sJsCodeAdd = '';
+        if($oPrivacy->isGroupsCustom())
+            $sJsCodeAdd = $oPrivacy->getLoadGroupCustom($iOwnerId, $iContentId, $iGroupId, isset($aParams['html_ids']) ? $aParams['html_ids'] : array());
+
+        return $oPrivacy->getJsScript($sJsCodeAdd, $bDynamicMode);
+    }
+    
+    public static function initGroupChooserAPI($sObject, $iOwnerId = 0, $aParams = [])
+    {
+        $sResult = '';
+
+        $oPrivacy = BxDolPrivacy::getObjectInstance($sObject);
+        if(empty($oPrivacy))
+            return $sResult;
+
+        $iOwnerId = !empty($iOwnerId) ? (int)$iOwnerId : bx_get_logged_profile_id();
+        $iContentId = !empty($aParams['content_id']) ? (int)$aParams['content_id'] : 0;
+        $iGroupId = !empty($aParams['group_id']) ? (int)$aParams['group_id'] : 0;
+
+        if($oPrivacy->isGroupsCustom() && ($aGroupsSettings = $oPrivacy->getGroupSettings($iGroupId)) !== false) {
+            $aGroupCustom = $oPrivacy->getGroupCustom([
+                'type' => 'pcog_ext', 
+                'profile_id' => $iOwnerId, 
+                'content_id' => $iContentId, 
+                'object' => $sObject, 
+                'group_id' => $iGroupId,
+                'group_items_table' => $aGroupsSettings['db_table_items'],
+                'group_items_field' => $aGroupsSettings['db_field_item']
+            ]);
+
+            if(is_array($aGroupCustom) && !empty($aGroupCustom['items']) && is_array($aGroupCustom['items']))
+                $sResult = implode(',', $aGroupCustom['items']);
+        }
+
+        return $sResult;
+    }
+    
+    public static function getIcon($iVisibility)
+    {
+        $aIcons =array(
+           BX_DOL_PG_MEONLY => 'lock',
+           BX_DOL_PG_ALL => 'globe',
+           BX_DOL_PG_FRIENDS => 'user-friends',
+           BX_DOL_PG_FRIENDS => 'user-friends'
+       );
+       return isset($aIcons[$iVisibility]) ? $aIcons[$iVisibility] : 'eye';
+    }
+    
+            
+    public function actionLoadGroupCustom()
+    {
+        $iProfileId = (int)bx_get('profile_id');
+        $iContentId = (int)bx_get('content_id');
+        $iGroupId = (int)bx_get('group_id');
+
+        $oForm = BxDolForm::getObjectInstance($this->_sFormGroupCustom, $this->_sFormDisplayGcMembers);
+        return echoJson(array('eval' => $this->getJsObjectName() . '.onSelectGroup(oData);', 'content' => $oForm->getElementGroupCustom(array(
+            'profile_id' => $iProfileId, 
+            'content_id' => $iContentId, 
+            'object' => $this->_sObject, 
+            'group_id' => $iGroupId
+        ))));
+    }
+
+    public function actionSelectMembers()
+    {
+        $aValues = array(
+            'profile_id' => (int)bx_get('profile_id'),
+            'content_id' => (int)bx_get('content_id'),
+            'object' => $this->_sObject,
+            'group_id' => (int)bx_get('group_id')
+        );
+
+        $aParams = array(
+            'popup_only' => (bool)bx_get('popup_only')
+        );
+
+        if(!isset($this->_aGroupsSettings[$aValues['group_id']]))
+            return echoJson(array());
+
+        if($aValues['profile_id'] != bx_get_logged_profile_id())
+            return echoJson(array('msg' => _t('_sys_ps_ferr_incorrect_gc_owner')));
+
+        if(($mixedResult = $this->isSelectGroupCustomUsers($aValues)) !== true)
+            return echoJson(array('msg' => $mixedResult));
+
+        return echoJson($this->getSelectGroup($aValues, $aParams));
+    }
+
+    public function actionSelectMemberships()
+    {
+        $aValues = array(
+            'profile_id' => (int)bx_get('profile_id'),
+            'content_id' => (int)bx_get('content_id'),
+            'object' => $this->_sObject,
+            'group_id' => (int)bx_get('group_id')
+        );
+
+        $aParams = array(
+            'popup_only' => (bool)bx_get('popup_only')
+        );
+
+        if(!isset($this->_aGroupsSettings[$aValues['group_id']]))
+            return echoJson(array());
+
+        if($aValues['profile_id'] != bx_get_logged_profile_id())
+            return echoJson(array('msg' => _t('_sys_ps_ferr_incorrect_gc_owner')));
+
+        if(($mixedResult = $this->isSelectGroupCustomMemberships($aValues)) !== true)
+            return echoJson(array('msg' => $mixedResult));
+
+        return echoJson($this->getSelectMemberships($aValues, $aParams));
+    }
+
+    public function actionUsersList()
+    {
+        $iGroup = (int)bx_get('group');
+        if(!isset($this->_aGroupsSettings[$iGroup]))
+            return echoJson(array());
+
+        $oConnection = BxDolConnection::getObjectInstance($this->_aGroupsSettings[$iGroup]['connection']);
+        if(!$oConnection)
+            return echoJson(array());
+
+        $iProfileId = bx_get_logged_profile_id();
+        $aConnectedIds = $oConnection->getConnectedContent($iProfileId, true);
+        if(empty($aConnectedIds) || !is_array($aConnectedIds))
+            return echoJson(array());
+
+        $sTerm = bx_get('term');
+        $aProfiles = BxDolService::call('system', 'profiles_search', array($sTerm), 'TemplServiceProfiles');
+        if(empty($aProfiles))
+            return echoJson(array());
+        
+        $aResult = array();
+        foreach($aProfiles as $aProfile)
+            if(in_array($aProfile['value'], $aConnectedIds))
+                $aResult[] = $aProfile;
+
+        echoJson($aResult);
+    }
+
+    public function getGroupSettings($iGroup)
+    {
+        if(empty($this->_aGroupsSettings[$iGroup]) || !is_array($this->_aGroupsSettings[$iGroup]))
+            return false;
+
+        return $this->_aGroupsSettings[$iGroup];
+    }
+
+    public function isGroupsCustom()
+    {
+        $aGroups = $this->_oDb->getGroupsBy(array('type' => 'active_list'));
+
+        return in_array(BX_DOL_PG_FRIENDS_SELECTED, $aGroups) || in_array(BX_DOL_PG_RELATIONS_SELECTED, $aGroups) || in_array(BX_DOL_PG_MEMBERSHIPS_SELECTED, $aGroups);
+    }
+        
+    public function getGroupsBy($aParams)
+    {
+        return $this->_oDb->getGroupsBy($aParams);          
+    }
+
+    public function getGroupCustom($aParams)
+    {
+        return $this->_oDb->getGroupCustom($aParams);
+    }
+
+    /**
+     * Checks if this privacy object allows to add content in specified context.
+     * 
+     * @param type $sContext - context module name
+     * @return boolean
+     */
+    public function isAllowedAddInContext($sContext)
+    {
+        $bSpaces = !empty($this->_aObject['spaces']);
+
+        if($bSpaces && $this->_aObject['spaces'] == 'all') 
+            return true;
+
+        if($bSpaces && in_array($sContext, explode(',', $this->_aObject['spaces'])))
+            return true;
+
+        return false;
+    }
+
+    /**
+     * Note. Is used when privacy group is processing after the main form submit.
+     */
+    public function addGroupCustom($aGroup, $aItems = [])
+    {
+        $this->deleteGroupCustom([
+            'profile_id' => $aGroup['profile_id'],
+            'content_id' => $aGroup['content_id'],
+            'object' => $aGroup['object']
+        ]);
+
+        if(empty($aItems) || !is_array($aItems))
+            return 0;
+
+        $iGroupId = (int)$aGroup['group_id'];
+        $iGroupCustomId = $this->_oDb->insertGroupCustom($aGroup);
+        if($iGroupCustomId !== false && !empty($aItems) && is_array($aItems)) {
+            $bMembers = $iGroupId == BX_DOL_PG_FRIENDS_SELECTED || $iGroupId == BX_DOL_PG_RELATIONS_SELECTED;
+            $bMemberships = $iGroupId == BX_DOL_PG_MEMBERSHIPS_SELECTED;
+            if(($bMembers || $bMemberships) && ($sType = $bMembers ? 'member' : ($bMemberships ? 'membership' : '')) !== '')
+                foreach($aItems as $iItem)
+                    $this->_oDb->{'insertGroupCustom' . ucfirst($sType)}(['group_id' => $iGroupCustomId, $sType . '_id' => $iItem]);
+        }
+
+        return $iGroupCustomId;
+    }
+
+    /**
+     * Note. Is used when privacy group is processing after the main form submit.
+     */
+    public function editGroupCustom($aGroup, $aItems = [])
+    {
+        $aGroupCustom = $this->getGroupCustom([
+            'type' => 'pco',
+            'profile_id' => $aGroup['profile_id'],
+            'content_id' => $aGroup['content_id'],
+            'object' => $this->_sObject
+        ]);
+        if(empty($aGroupCustom) || !is_array($aGroupCustom))
+            return $this->addGroupCustom($aGroup, $aItems);
+
+        $iGroupId = (int)$aGroupCustom['group_id'];
+        $iGroupCustomId = (int)$aGroupCustom['id'];
+
+        if($iGroupId != (int)$aGroup['group_id'])
+            return $this->addGroupCustom($aGroup, $aItems);
+
+        $bMembers = $iGroupId == BX_DOL_PG_FRIENDS_SELECTED || $iGroupId == BX_DOL_PG_RELATIONS_SELECTED;
+        $bMemberships = $iGroupId == BX_DOL_PG_MEMBERSHIPS_SELECTED;
+        if(($bMembers || $bMemberships) && ($sType = $bMembers ? 'member' : ($bMemberships ? 'membership' : '')) !== '') {
+            $sTypeUc = ucfirst($sType);
+
+            $this->_oDb->{'deleteGroupCustom' . $sTypeUc}(['group_id' => $iGroupCustomId]);
+
+            if(!empty($aItems) && is_array($aItems))
+                foreach($aItems as $iItemId)
+                    $this->_oDb->{'insertGroupCustom' . $sTypeUc}(['group_id' => $iGroupCustomId, $sType . '_id' => $iItemId]);
+        }
+
+        return $iGroupCustomId;
+    }
+
+    public function updateGroupCustom($aParamsSet, $aParamsWhere)
+    {
+        return $this->_oDb->updateGroupCustom($aParamsSet, $aParamsWhere);
+    }
+
+    public function deleteGroupCustom($aParamsWhere)
+    {
+        return $this->_oDb->deleteGroupCustom($aParamsWhere);
+    }
+
+    public function associateGroupCustomWithContent($iProfileId, $iContentId, $iGroupId)
+    {
+        return $this->updateGroupCustom(array('content_id' => $iContentId), array(
+            'profile_id' => $iProfileId,
+            'content_id' => 0,
+            'object' => $this->_sObject,
+            'group_id' => $iGroupId
+        ));
+    }
+
+    public function reassociateGroupCustomWithContent($iProfileId, $iContentId, $iGroupId)
+    {
+        $aGroupCustom = $this->getGroupCustom(array(
+            'type' => 'pco', 
+            'profile_id' => $iProfileId,
+            'content_id' => $iContentId,
+            'object' => $this->_sObject
+        ));
+
+        if(!empty($aGroupCustom) && is_array($aGroupCustom) && $aGroupCustom['group_id'] != $iGroupId) {
+            $this->deleteGroupCustom(array('id' => $aGroupCustom['id']));
+
+            $this->associateGroupCustomWithContent($iProfileId, $iContentId, $iGroupId);
+        }
+    }
+
+    public function deleteGroupCustomByContentId($iContentId)
+    {
+        return $this->_oDb->deleteGroupCustom(array('content_id' => $iContentId, 'object' => $this->_sObject));
+    }
+
+    public function deleteGroupCustomByProfileId($iProfileId, $mixedContentId = false)
+    {
+        $aParams = ['type' => 'profile_id', 'profile_id' => $iProfileId];
+        if($mixedContentId !== false)
+            $aParams['content_id'] = (int)$mixedContentId;
+
+        $aGroups = $this->_oDb->getGroupCustom($aParams);
+        if(empty($aGroups) || !is_array($aGroups))
+            return true;
+
+        foreach($aGroups as $aGroup)
+            $this->_oDb->deleteGroupCustom(array('id' => $aGroup['id']));
+
+        return true;
+    }
+
+    public function deleteGroupCustomByProfileIdUnused($iProfileId)
+    {
+        return $this->deleteGroupCustomByProfileId($iProfileId, 0);
+    }
+
+    public function addDynamicGroups($aValues, $iOwnerId, $aParams)
+    {
+        if (isset($aParams['dynamic_groups']) && is_array($aParams['dynamic_groups']))
+            $aValues = array_merge($aValues, $aParams['dynamic_groups']);
+
+        return $aValues;
+    }
+
+    public function addSpaces($aValues, $iOwnerId, $aParams)
+    {
+        if (!$this->_aObject['spaces'])
+            return $aValues;
+
+        if (!($oProfile = BxDolProfile::getInstance($iOwnerId)))
+            return $aValues;
+
+        if (!($aModules = BxDolModuleQuery::getInstance()->getModules()))
+            return $aValues;
+        
+        $aExcludeModules = explode(',', getParam('sys_hide_post_to_context_for_privacy'));
+        
+        foreach ($aModules as $aModule) {
+            if (!$aModule['enabled'])
+                continue;
+
+            if ('all' != $this->_aObject['spaces'] && false === stripos($this->_aObject['spaces'], $aModule['name']))
+                continue;
+
+            if (!BxDolRequest::serviceExists($aModule['name'], 'act_as_profile'))
+                continue;
+            
+            if (in_array($aModule['name'], $aExcludeModules))
+                continue;
+
+            $oModule = BxDolModule::getInstance($aModule['name']);
+            if (bx_srv($aModule['name'], 'act_as_profile') && (!isset($oModule->_oConfig->CNF['ALLOW_AS_CONTEXT']) || $oModule->_oConfig->CNF['ALLOW_AS_CONTEXT'] == false))
+                continue;
+
+            $a = BxDolService::call($aModule['name'], 'get_participating_profiles', array($oProfile->id()));
+
+            // for an organization we should treat the organization profile itself as a participant of itself
+            // to be able to post into an organization's context while being logged as that organization
+            if ($aModule['name'] == 'bx_organizations' && $oProfile->getModule() == 'bx_organizations') $a = array_merge($a, [$oProfile->id()]);
+
+            $aSpaces = array();       
+            foreach ($a as $iProfileId) {
+                if (!($o = BxDolProfile::getInstance($iProfileId)))
+                    continue;
+
+                // check whether a profile is allowed to post this type of content to a context
+                $oConnectedProfile = BxDolProfile::getInstance($iProfileId);
+                if (bx_srv($aModule['name'], 'check_allowed_post_in_profile', array($oConnectedProfile->getContentId(), $this->_aObject['module'])) !== CHECK_ACTION_RESULT_ALLOWED)
+                    continue;
+
+                $aSpaces[-$iProfileId] = array('key' => -$iProfileId, 'value' => $o->getDisplayName());
+            }
+
+            if ($aSpaces) {
+                $aItemStart = array(array('type' => 'group_header', 'value' => mb_strtoupper(BxDolService::call($aModule['name'], 'get_space_title'))));
+                $aItemEnd = array(array('type' => 'group_end'));
+                $aValues = array_merge($aValues, $aItemStart, array_values($aSpaces), $aItemEnd);
+            }
+        }
+        
+        return $aValues;
+    }
+
+    /**
+     * Get database field name for action.
+     *
+     * @param  string $sObject privacy object name.
+     * @param  string $sAction action name.
+     * @return string with field name.
+     */
+    public static function getFieldName($sObject, $sAction = '')
+    {
+        $oPrivacy = BxDolPrivacy::getObjectInstance($sObject);
+        if(empty($oPrivacy))
+            return '';
+
+        if(empty($sAction))
+            $sAction = $oPrivacy->_aObject['action'];
+
+        return $oPrivacy->convertActionToField($sAction);
+    }
+
+    /**
+     * Get necessary condition array to use privacy in search classes
+     * @param $mixedGroupId group ID or array of group IDs
+     * @return array of conditions, for now with 'restriction' part only is returned
+     */
+    public function getContentByGroupAsCondition($mixedGroupId)
+    {
+        $aResult = array(
+            'restriction' => array (
+                'privacy_' . $this->_sObject => array(
+                    'value' => $mixedGroupId,
+                    'field' => $this->convertActionToField($this->_aObject['action']),
+                    'operator' => is_array($mixedGroupId) ? 'in' : '=',
+                    'table' => $this->_aObject['table'],
+                ),
+            ),
+        );   
+         /**
+         * @hooks
+         * @hookdef hook-system-privacy_condition 'system', 'privacy_condition' - hook on get necessary condition array to use privacy in search classes
+         * - $unit_name - equals `profile`
+         * - $action - equals `privacy_condition` 
+         * - $object_id - not used
+         * - $sender_id - not used 
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `group_id` - [int] group ID or array of group IDs
+         *      - `field` - [string] field name
+         *      - `object` - [array] array with object privacy 
+         *      - `privacy_object` - [array] object privacy 
+         *      - `result` - [bool] by ref, on success return true otherwise false, can be overridden in hook processing
+         * @hook @ref hook-system-privacy_condition
+         */
+        bx_alert('system', 'privacy_condition', 0, false, array(
+            'group_id' => $mixedGroupId,
+            'field' => $this->convertActionToField($this->_aObject['action']),
+            'object' => $this->_aObject,
+            'privacy_object' => $this,
+            'result' => &$aResult
+            )
+        );
+        return $aResult;
+    }
+
+    /**
+     * Get necessary condition array to use privacy in search classes
+     * @param $iProfileIdOwner owner profile ID
+     * @return array of conditions, for now with 'restriction' part only is returned
+     */
+    public function getContentPublicAsCondition($iProfileIdOwner = 0, $aCustomGroups = array())
+    {
+        $mixedPrivacyGroups = $this->getPrivacyGroupsForContentPublic($iProfileIdOwner, $aCustomGroups);
+        if($mixedPrivacyGroups === true)
+        	return array();
+
+        return $this->getContentByGroupAsCondition($mixedPrivacyGroups);
+    }
+
+    /**
+     * Get necessary parts of SQL query to use privacy in other queries
+     * @param $mixedGroupId group ID or array of group IDs
+     * @return array of SQL string parts, for now 'where' part only is returned
+     */
+    public function getContentByGroupAsSQLPart($mixedGroupId)
+    {
+        $sField = $this->convertActionToField($this->_aObject['action']);
+        return $this->_oDb->getContentByGroupAsSQLPart($sField, $mixedGroupId);
+    }
+
+    /**
+     * Get necessary parts of SQL query to use privacy in other queries
+     * @param $iProfileIdOwner owner profile ID
+     * @return array of SQL string parts, for now 'where' part only is returned
+     */
+    public function getContentPublicAsSQLPart($iProfileIdOwner = 0, $aCustomGroups = array())
+    {
+        $mixedPrivacyGroups = $this->getPrivacyGroupsForContentPublic($iProfileIdOwner, $aCustomGroups);
+        if($mixedPrivacyGroups === true)
+            return array();
+
+        return $this->getContentByGroupAsSQLPart($mixedPrivacyGroups);
+    }
+    
+    /**
+     * Get necessary parts of SQL query to use privacy in other queries
+     * @param $iProfileIdOwner owner profile ID
+     * @return array of SQL string parts, for now 'where' part only is returned
+     */
+    public function getContentPublicAndInContextAsSQLPart($iProfileIdOwner = 0, $aCustomGroups = [], $aCustomContexts = [])
+    {
+        $mixedPrivacyGroups = $this->getPrivacyGroupsForContentPublic($iProfileIdOwner, $aCustomGroups);
+        if($mixedPrivacyGroups === true)
+            return [];
+
+        $sField = $this->convertActionToField($this->_aObject['action']);
+        return $this->_oDb->getContentByGroupAndContextAsSQLPart($sField, $mixedPrivacyGroups, $aCustomContexts);
+    }
+
+    /**
+     * Check whether the viewer can make requested action.
+     *
+     * @param  integer $iObjectId object ID the action to be performed with.
+     * @param  integer $iViewerId viewer ID.
+     * @return boolean result of operation.
+     */
+    public function check($iObjectId, $iViewerId = 0)
+    {
+        $aObject = $this->getObjectInfo($this->convertActionToField($this->_aObject['action']), $iObjectId);
+        $bRv = $this->_check($iObjectId, $iViewerId, $aObject);
+        /**
+         * @hooks
+         * @hookdef hook-system-check_privacy 'system', 'check_privacy' - check privacy for object
+         * - $unit_name - equals `profile`
+         * - $action - equals `check_privacy` 
+         * - $object_id - not used
+         * - $sender_id - not used 
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `object_id` - [int] object id
+         *      - `viewer_id` - [int] profile_id for viewer
+         *      - `object` - [array] object privacy 
+         *      - `object_privacy` - [array] arry with object privacy 
+         *      - `result` - [bool] by ref, on success return true otherwise false, can be overridden in hook processing
+         * @hook @ref hook-system-check_privacy
+         */
+        bx_alert('system', 'check_privacy', 0, 0, array(
+           'object_id' => $iObjectId,
+           'viewer_id' => $iViewerId,
+           'object' => $aObject,
+           'object_privacy' => $this->_aObject,
+           'result' => &$bRv
+        ));
+        return $bRv;
+    }
+
+    public function checkSpace($aObject, $iViewerId)
+    {
+        $oProfile = BxDolProfile::getInstance(-$aObject['group_id']);
+        if (!$oProfile)
+            return false;
+
+        return CHECK_ACTION_RESULT_ALLOWED === bx_srv($oProfile->getModule(), 'check_space_privacy_for_profile', [$oProfile->getContentId(), $iViewerId]);
+    }
+
+    public function checkMeOnly($iOwnerId, $iViewerId)
+    {
+        return false;
+    }
+
+    public function checkPublic($iOwnerId, $iViewerId)
+    {
+        return true;
+    }
+
+    public function checkMembers($iOwnerId, $iViewerId)
+    {
+        return isMember();
+    }
+
+    public function checkFriends($iOwnerId, $iViewerId)
+    {
+        return BxDolConnection::getObjectInstance('sys_profiles_friends')->isConnected($iOwnerId, $iViewerId, true);
+    }
+
+    public function checkFriendsSelectedByObject($aObject, $iViewerId)
+    {
+        if(!$this->checkFriends($aObject['owner_id'], $iViewerId))
+            return false;
+
+        $aGroupCustom = $this->getGroupCustom(array(
+            'type' => 'pcog_ext', 
+            'profile_id' => $aObject['owner_id'], 
+            'content_id' => $aObject['id'], 
+            'object' => $this->_sObject, 
+            'group_id' => $aObject['group_id'],
+            'group_items_table' => $this->_aGroupsSettings[$aObject['group_id']]['db_table_items'],
+            'group_items_field' => $this->_aGroupsSettings[$aObject['group_id']]['db_field_item']
+        ));
+
+        return !empty($aGroupCustom['items']) && is_array($aGroupCustom['items']) && in_array($iViewerId, $aGroupCustom['items']);
+    }
+
+    public function checkRelations($iOwnerId, $iViewerId)
+    {
+        return BxDolConnection::getObjectInstance('sys_profiles_relations')->isConnected($iOwnerId, $iViewerId, true);
+    }
+
+    public function checkRelationsSelectedByObject($aObject, $iViewerId)
+    {
+        if(!$this->checkRelations($aObject['owner_id'], $iViewerId))
+            return false;
+
+        $aGroupCustom = $this->getGroupCustom(array(
+            'type' => 'pcog_ext', 
+            'profile_id' => $aObject['owner_id'], 
+            'content_id' => $aObject['id'], 
+            'object' => $this->_sObject, 
+            'group_id' => $aObject['group_id'],
+            'group_items_table' => $this->_aGroupsSettings[$aObject['group_id']]['db_table_items'],
+            'group_items_field' => $this->_aGroupsSettings[$aObject['group_id']]['db_field_item']
+        ));
+
+        return !empty($aGroupCustom['items']) && is_array($aGroupCustom['items']) && in_array($iViewerId, $aGroupCustom['items']);
+    }
+
+    public function checkMembershipsSelectedByObject($aObject, $iViewerId)
+    {
+        $aGroupCustom = $this->getGroupCustom(array(
+            'type' => 'pcog_ext', 
+            'profile_id' => $aObject['owner_id'], 
+            'content_id' => $aObject['id'], 
+            'object' => $this->_sObject, 
+            'group_id' => $aObject['group_id'],
+            'group_items_table' => $this->_aGroupsSettings[$aObject['group_id']]['db_table_items'],
+            'group_items_field' => $this->_aGroupsSettings[$aObject['group_id']]['db_field_item']
+        ));
+
+        return !empty($aGroupCustom['items']) && is_array($aGroupCustom['items']) && BxDolAcl::getInstance()->isMemberLevelInSet($aGroupCustom['items'], $iViewerId);
+    }
+
+    public function checkCustomByObject($aObject, $iViewerId)
+    {
+        return '';
+    }
+
+    public function setTableFieldAuthor($sValue)
+    {
+        $this->_aObject['table_field_author'] = $sValue;
+
+        $this->_oDb->init($this->_aObject);
+    }
+
+    protected function getObjectInfo($sAction, $iObjectId)
+    {
+        return $this->_oDb->getObjectInfo($sAction, $iObjectId);
+    }
+
+    protected function getPrivacyGroupsForContentPublic($iProfileIdOwner = 0, $aCustomGroups = array())
+    {
+        $aGroups = array(BX_DOL_PG_ALL);
+        if(isLogged()) {
+            $iProfileIdLogged = bx_get_logged_profile_id();
+            if($iProfileIdLogged == $iProfileIdOwner)
+                return true;
+
+            $aGroups[] = BX_DOL_PG_MEMBERS;
+            if($iProfileIdOwner && $this->checkFriends($iProfileIdOwner, $iProfileIdLogged))
+                $aGroups[] = BX_DOL_PG_FRIENDS;
+        }
+
+        return array_merge($aGroups, $aCustomGroups);
+    }
+
+    protected function getCheckMethod($s)
+    {
+        if(substr($s, 0, 1) != '@')
+            return false;
+
+        return bx_gen_method_name(str_replace('@', 'check_', $s));
+    }
+
+    protected function convertActionToField($sAction)
+    {
+    	return 'allow_' . strtolower(str_replace(' ', '-', $sAction)) . '_to';
+    }
+
+    /**
+     * Check whethere viewer is a member of dynamic group.
+     *
+     * @param  mixed   $mixedGroupId   dynamic group ID.
+     * @param  integer $iObjectOwnerId object owner ID.
+     * @param  integer $iViewerId      viewer ID.
+     * @return boolean result of operation.
+     */
+    protected function isDynamicGroupMember($mixedGroupId, $iObjectOwnerId, $iViewerId, $iObjectId)
+    {
+        return false;
+    }
+
+    /**
+     * get privacy groups for getGroupChooser
+     */ 
+    protected function getGroups($iOwnerId = 0, $aParams = []) 
+    {
+        $aValues = array();
+
+        $aGroups = $this->_oDb->getGroupsBy(array('type' => 'active'));
+        foreach($aGroups as $aGroup) {
+            $iGroupId = (int)$aGroup['id'];
+
+            if((int)$aGroup['active'] == 0 || in_array($iGroupId, $this->_aGroupsExclude))
+               continue;
+
+            if(isset($this->_aGroupsSettings[$iGroupId]) && !empty($this->_aGroupsSettings[$iGroupId]['is_allowed'])) {
+                $sMethodIsAllowed = $this->_aGroupsSettings[$iGroupId]['is_allowed'];
+                if(method_exists($this, $sMethodIsAllowed) && $this->$sMethodIsAllowed($iOwnerId) !== true)
+                    continue;
+            }
+
+            $aValues[] = array('key' => $aGroup['id'], 'value' => _t($aGroup['title']));
+        }
+
+        return $aValues;
+    }
+
+    /**
+     * Check whethere a custom group (based on users list) is allowed in current circumstances.
+     * NOTE. Can be overwritten if it's needed.
+     * 
+     * @param type $aParams an array of parameters.
+     * @return boolean result of operation.
+     */
+    protected function isSelectGroupCustomUsers($aParams)
+    {
+        return true;
+    }
+
+    /**
+     * Check whethere a custom group (based on memberships list) is allowed in current circumstances.
+     * NOTE. Can be overwritten if it's needed.
+     * 
+     * @param type $aParams an array of parameters.
+     * @return boolean result of operation.
+     */
+    protected function isSelectGroupCustomMemberships($aParams)
+    {
+        return true;
+    }
+
+    public function isAllowedRelations($iUserId)
+    {
+        return BxDolConnectionRelation::isEnabled();
+    }
+
+    public function isAllowedMemberships($iUserId)
+    {
+        $aCheck = checkActionModule($iUserId, 'show membership levels in privacy groups', 'system', false);
+        return $aCheck[CHECK_ACTION_RESULT] === CHECK_ACTION_RESULT_ALLOWED;
+    }
+
+    /**
+     * Check whether the viewer can make requested action.
+     *
+     * @param  integer $iObjectId object ID the action to be performed with.
+     * @param  integer $iViewerId viewer ID.
+     * @return boolean result of operation.
+     */
+    protected function _check($iObjectId, $iViewerId, $aObject)
+    {
+        if(empty($iViewerId))
+            $iViewerId = (int)bx_get_logged_profile_id();
+
+        if(empty($aObject) || !is_array($aObject))
+            return false;
+
+        if($aObject['group_id'] == BX_DOL_PG_HIDDEN)
+            return false;
+
+        $aViewer = BxDolProfileQuery::getInstance()->getInfoById($iViewerId);
+        if(($aViewer && isAdmin($aViewer['account_id'])) || $iViewerId == $aObject['owner_id'])
+            return true;
+
+        if(strncmp($aObject['group_id'], 'ml', 2) === 0) {
+            $iLevel = (int)substr($aObject['group_id'], 2);
+            return (bool)BxDolAcl::getInstance()->isMemberLevelInSet(array($iLevel), $iViewerId);
+        }
+
+        if($aObject['group_id'] < 0)
+            return $this->checkSpace($aObject, $iViewerId);
+
+        $aGroup = $this->_oDb->getGroupsBy(array('type' => 'id', 'id' => $aObject['group_id']));
+        if(!empty($aGroup) && is_array($aGroup) && (int)$aGroup['active'] == 1 && !empty($aGroup['check'])) {
+            $sCheckMethod = $this->getCheckMethod($aGroup['check']);
+            if(method_exists($this, $sCheckMethod) && $this->$sCheckMethod((substr($sCheckMethod, -8) == 'ByObject' ? $aObject : $aObject['owner_id']), $iViewerId))
+                return true;
+        }
+
+        return $this->isDynamicGroupMember($aObject['group_id'], $aObject['owner_id'], $iViewerId, $iObjectId);
+    }
+}
+
+/** @} */

+ 357 - 0
upgrade/files/15.0.0.B3-15.0.0.RC1/files/inc/classes/BxDolReport.php

@@ -0,0 +1,357 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    UnaCore UNA Core
+ * @{
+ */
+
+bx_import('BxDolAcl');
+
+define('BX_DOL_REPORT_USAGE_BLOCK', 'block');
+define('BX_DOL_REPORT_USAGE_INLINE', 'inline');
+define('BX_DOL_REPORT_USAGE_DEFAULT', BX_DOL_REPORT_USAGE_BLOCK);
+
+define('BX_DOL_REPORT_STASUS_NEW', 0);
+define('BX_DOL_REPORT_STASUS_IN_PROCESS', 1);
+define('BX_DOL_REPORT_STASUS_PROCESSED', 2);
+/**
+ * Report any content
+ *
+ * Related classes:
+ * - BxDolReportQuery - report database queries
+ * - BxBaseReport - report base representation
+ * - BxTemplReport - custom template representation
+ *
+ * AJAX report for any content.
+ *
+ * To add report section to your feature you need to add a record to 'sys_objects_report' table:
+ *
+ * - id - autoincremented id for internal usage
+ * - name - your unique module name, with vendor prefix, lowercase and spaces are underscored
+ * - table_main - table name where summary reports are stored
+ * - table_track - table name where each report is stored
+ * - is_on - is this report object enabled
+ * - base_url - base URL for reported object
+ * - trigger_table - table to be updated upon each report
+ * - trigger_field_id - trigger_table table field with unique record id, primary key
+ * - trigger_field_author - trigger_table table field with author
+ * - trigger_field_count - trigger_table table field with reports count
+ * - class_name - your custom class name, if you overrride default class
+ * - class_file - your custom class path
+ *
+ * You can refer to BoonEx modules for sample record in this table.
+ *
+ *
+ *
+ * @section example Example of usage:
+ * You can show report in any place, using the following code:
+ * @code
+ * $o = BxDolReport::getObjectInstance('system object name', $iYourEntryId);
+ * if (!$o->isEnabled()) 
+ *     return '';
+ * echo $o->getElementBlock();
+ * @endcode
+ *
+ *
+ * @section acl Memberships/ACL:
+ * - report
+ * - report view
+ *
+ *
+ * @section alerts Alerts:
+ * Alerts type/unit - every module has own type/unit, it equals to ObjectName.
+ * The following alerts are rised:
+ *
+ * - type: 'object name', action: doReport
+ * - type: report, action: do
+ *
+ */
+
+class BxDolReport extends BxDolObject
+{
+    protected $_oTemplate;
+
+    protected $_bUndo;
+    protected $_bProcessible;   ///< Determines whether the report should be processed by admins/moderators or not.
+    protected $_sBaseUrl;
+
+    protected $_sObjectCmts;
+
+    protected $_sFormObject;
+    protected $_sFormDisplayPost;
+
+    protected $_sTypesPreList;
+    protected $_aTypes;
+
+    protected $_aReport;
+
+    protected function __construct($sSystem, $iId, $iInit = true, $oTemplate = false)
+    {
+        parent::__construct($sSystem, $iId, $iInit);
+        if(empty($this->_sSystem))
+            return;
+
+        $this->_oQuery = new BxDolReportQuery($this);
+
+        if ($oTemplate)
+            $this->_oTemplate = $oTemplate;
+        else
+            $this->_oTemplate = BxDolTemplate::getInstance();
+
+        $this->_bUndo = true;
+        $this->_bProcessible = true;
+
+        $this->_sBaseUrl = BxDolPermalinks::getInstance()->permalink($this->_aSystem['base_url']);
+        if(get_mb_substr($this->_sBaseUrl, 0, 4) != 'http')
+            $this->_sBaseUrl = BX_DOL_URL_ROOT . $this->_sBaseUrl;
+
+        $this->_sObjectCmts = $this->_aSystem['object_comment'];
+
+        $this->_sFormObject = 'sys_report';
+        $this->_sFormDisplayPost = 'sys_report_post';
+
+        $this->_sTypesPreList = 'sys_report_types';
+
+        $aTypes = BxDolFormQuery::getDataItems($this->_sTypesPreList);
+        if(!empty($aTypes) && is_array($aTypes))
+            $this->_aTypes = array_keys($aTypes);
+        else
+            $this->_aTypes = array('spam', 'scam', 'fraud', 'nude', 'other');
+
+        $this->_aReport = [];
+    }
+
+    /**
+     * get reports object instanse
+     * @param $sSys report object name
+     * @param $iId associated content id, where report is available
+     * @param $iInit perform initialization
+     * @return null on error, or ready to use class instance
+     */
+    public static function getObjectInstance($sSys, $iId, $iInit = true, $oTemplate = false)
+    {
+        $sKey = 'BxDolReport!' . $sSys . $iId . ($oTemplate ? $oTemplate->getClassName() : '');
+        if(isset($GLOBALS['bxDolClasses'][$sKey]))
+            return $GLOBALS['bxDolClasses'][$sKey];
+
+        $aSystems = self::getSystems();
+        if(!isset($aSystems[$sSys]))
+            return null;
+
+        $sClassName = 'BxTemplReport';
+        if(!empty($aSystems[$sSys]['class_name'])) {
+            $sClassName = $aSystems[$sSys]['class_name'];
+            if(!empty($aSystems[$sSys]['class_file']))
+                require_once(BX_DIRECTORY_PATH_ROOT . $aSystems[$sSys]['class_file']);
+        }
+
+        $o = new $sClassName($sSys, $iId, $iInit, $oTemplate);
+        return ($GLOBALS['bxDolClasses'][$sKey] = $o);
+    }
+
+    public static function &getSystems()
+    {
+        $sKey = 'bx_dol_cache_memory_report_systems';
+
+        if(!isset($GLOBALS[$sKey]))
+            $GLOBALS[$sKey] = BxDolDb::getInstance()->fromCache('sys_objects_report', 'getAllWithKey', '
+                SELECT
+                    `id` as `id`,
+                    `name` AS `name`,
+                    `module` AS `module_name`,
+                    `table_main` AS `table_main`,
+                    `table_track` AS `table_track`,
+                    `pruning` AS `pruning`,
+                    `is_on` AS `is_on`,
+                    `base_url` AS `base_url`,
+                    `object_comment` AS `object_comment`,
+                    `trigger_table` AS `trigger_table`,
+                    `trigger_field_id` AS `trigger_field_id`,
+                    `trigger_field_author` AS `trigger_field_author`,
+                    `trigger_field_count` AS `trigger_field_count`,
+                    `class_name` AS `class_name`,
+                    `class_file` AS `class_file`
+                FROM `sys_objects_report`', 'name');
+
+        return $GLOBALS[$sKey];
+    }
+
+    public static function onAuthorDelete ($iAuthorId)
+    {
+        $aSystems = self::getSystems();
+        foreach($aSystems as $sSystem => $aSystem)
+            self::getObjectInstance($sSystem, 0)->getQueryObject()->deleteAuthorEntries($iAuthorId);
+
+        return true;
+    }
+
+    /**
+     * Interface functions for outer usage
+     */
+    public function isUndo()
+    {
+        return (int)$this->_bUndo == 1;
+    }
+
+    public function isProcessible()
+    {
+        return $this->_bProcessible;
+    }
+
+    public function getBaseUrl()
+    {
+        return $this->_replaceMarkers($this->_sBaseUrl);
+    }
+
+    public function getStatCounter()
+    {
+        $aReport = $this->_oQuery->getReport($this->getId());
+        return $aReport['count'];
+    }
+    
+    public function getCountByStatus($iStatus)
+    {
+        return $this->_oQuery->getReportsCountByStatus($iStatus);
+    }
+
+    public function getSocketName()
+    {
+        return $this->_sSystem . '_reports';
+    }
+
+    /**
+     * Actions functions
+     */
+    public function actionReport()
+    {
+        return echoJson($this->report());
+    }
+
+    public function actionClearReport()
+    {
+       $this->_oQuery->clearReports($this->getId());
+    }
+
+    public function actionGetReportedBy()
+    {
+        if (!$this->isEnabled())
+           return '';
+
+	    if(!$this->isAllowedReportView(true))
+            return $this->msgErrAllowedReportView();
+
+        return $this->_getReportedBy();
+    }
+
+    /**
+     * Permissions functions
+     */
+    public function isAllowedReport($isPerformAction = false)
+    {
+        if(isAdmin())
+            return true;
+
+        return $this->checkAction('report', $isPerformAction);
+    }
+
+    public function msgErrAllowedReport()
+    {
+        return $this->checkActionErrorMsg('report');
+    }
+
+    public function isAllowedReportView($isPerformAction = false)
+    {
+        if(isAdmin())
+            return true;
+
+        return $this->checkAction('report_view', $isPerformAction);
+    }
+    
+    public function changeStatusReport($iStatus, $iAuthorId, $sCmtText)
+    {
+        $iId = $this->getId();
+        $aReport = $this->_oQuery->getDataById($iId);
+        if(!empty($this->_sObjectCmts) && ($oCmts = BxDolCmts::getObjectInstance($this->_sObjectCmts, $aReport['object_id']))) {
+            $oCmts->add(array(
+                'cmt_author_id' => $iAuthorId,
+                'cmt_parent_id' => 0,
+                'cmt_text' => $sCmtText
+            ));
+        }
+        $this->_oQuery->changeStatusReport($iId, $iStatus, $iAuthorId);
+    }
+
+    public function msgErrAllowedReportView()
+    {
+        return $this->checkActionErrorMsg('report_view');
+    }
+
+    /**
+     * Internal functions
+     */
+    protected function _isCount($aVote = array())
+    {
+        if(empty($aReport))
+            $aReport = $this->_getReport();
+
+        return isset($aReport['count']) && (int)$aReport['count'] != 0;
+    }
+
+    protected function _getReport($iObjectId = 0, $bForceGet = false)
+    {
+        if(!empty($this->_aReport) && !$bForceGet)
+            return $this->_aReport;
+
+        if(empty($iObjectId))
+            $iObjectId = $this->getId();
+
+        $this->_aReport = $this->_oQuery->getReport($iObjectId);
+        return $this->_aReport;
+    }
+
+    protected function _isReport($iObjectId = 0, $bForceGet = false)
+    {
+        $aReport = $this->_getReport($iObjectId, $bForceGet);
+
+        return (int)$aReport['count'] > 0;
+    }
+
+    protected function _getTrack($iObjectId, $iAuthorId)
+    {
+        return $this->_oQuery->getTrack($iObjectId, $iAuthorId);
+    }
+
+    protected function _getIconDoReport($bPerformed)
+    {
+    	return $bPerformed && $this->isUndo() ? 'exclamation-circle' : 'exclamation-circle';
+    }
+
+    protected function _getTitleDoReport($bPerformed, $aParams = [])
+    {
+        if($bPerformed && $this->isUndo())
+            return ['_report_do_unreport'];
+
+        $sSample = '_' . $this->_sSystem . '_txt_sample_single';
+        if(($$sSample = _t($sSample)) && strcmp($sSample, $$sSample) != 0)
+            return ['_report_do_report_with_sample', $$sSample];
+
+    	return ['_report_do_report'];
+    }
+
+    protected function _getFormObject()
+    {
+        $oForm = BxDolForm::getObjectInstance($this->_sFormObject, $this->_sFormDisplayPost);
+        $oForm->setId($this->_aHtmlIds['do_form']);
+        $oForm->setName($this->_aHtmlIds['do_form']);
+        $oForm->aParams['db']['table'] = $this->_aSystem['table_track'];
+        $oForm->aInputs['sys']['value'] = $this->_sSystem;
+        $oForm->aInputs['object_id']['value'] = $this->_iId;
+        $oForm->aInputs['action']['value'] = 'Report';
+
+        return $oForm;
+    }
+}
+
+/** @} */

+ 1511 - 0
upgrade/files/15.0.0.B3-15.0.0.RC1/files/inc/classes/BxDolSearch.php

@@ -0,0 +1,1511 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    UnaCore UNA Core
+ * @{
+ */
+
+define('BX_DOL_SEARCH_RESULTS_PER_PAGE_DEFAULT', 10);
+define('BX_DOL_SEARCH_KEYWORD_PAGE', 'site-search-page');
+
+/**
+ * Search class for different content.
+ *
+ * Allows present content in main search area for all modules.
+ *
+ * To add taking part content from your module to search area you need add a record to `sys_objects_search` table:
+ * @code
+ *   ID - autoincremented id for internal usage
+ *   ObjectName - your unique module name, with vendor prefix, lowercase and spaces are underscored
+ *   Title - language key for module's choicer in global search form
+ *   ClassName - class name which is responsible for search process ad showing result for found results
+ *   ClassPath - file where your ClassName is stored (if class is stored in template folder then you can use key {tmpl})
+ * @endcode
+ *
+ * For using this class you should have unit of BxDolSearchResult class (see description below) with method processing which is responsible for processing of search request.
+ *
+ * Example of usage can be seen in the BoonEx modules, for example: Posts
+ *
+ * Memberships/ACL:
+ * Doesn't depend on user's membership.
+ *
+ * Alerts:
+ * no alerts available
+ *
+ */
+class BxDolSearch extends BxDol
+{
+    protected $_bIsApi;
+    protected $_bAssitantForLiveSearch = true;
+        
+    protected $aClasses = array(); ///< array of all search classes
+    protected $aChoice  = array(); ///< array of current search classes which were choosen in search area
+    protected $_bRawProcessing = false; ///< display search results without design box and paginate
+    protected $_bDataProcessing = false; ///< return result as array of data
+
+    protected $_bLiveSearch = false;
+    protected $_sMetaType = '';
+    protected $_sCategoryObject = ''; ///< by default = object from sys_objects_category table, for multicategories set to 'multi' string 
+    protected $_aCustomSearchCondition = array();
+    protected $_aCustomCurrentCondition = array();
+    protected $_sUnitTemplate = '';
+
+    /**
+     * Constructor
+     * @param array $aChoice - array of choosen classes (will take a part only existing in `sys_objects_search` table)
+     */
+    public function __construct ($aChoice = '')
+    {
+        parent::__construct();
+
+        $this->_bIsApi = bx_is_api();
+
+        $this->aClasses = self::getSections();
+
+        if (is_array($aChoice) && !empty($aChoice)) {
+            foreach ($aChoice as $sValue) {
+                if (isset($this->aClasses[$sValue]))
+                    $this->aChoice[$sValue] = $this->aClasses[$sValue];
+            }
+        } else {
+            $this->aChoice = $this->aClasses;
+        }
+    }
+
+    public static function getSections($bGlobal = null) 
+    {
+        $sWhere = '';
+        if ($bGlobal != null)
+            $sWhere = ' AND `GlobalSearch` = ' . ($bGlobal ? '1' : '0');
+
+        return BxDolDb::getInstance()->fromCache('sys_objects_search', 'getAllWithKey',
+           'SELECT `ID` as `id`,
+                   `Title` as `title`,
+                   `ClassName` as `class`,
+                   `ClassPath` as `file`,
+                   `ObjectName`,
+                   `GlobalSearch`
+            FROM `sys_objects_search`
+            WHERE 1 ' . $sWhere . '
+            ORDER BY `Order` ASC', 'ObjectName'
+        );
+    }
+
+    public function setApiOutput($bIsApi)
+    {
+        $this->_bIsApi = $bIsApi;
+    }   
+
+    public function setAssistantForLiveSearch($bAssistantForLiveSearch)
+    {
+        $this->_bAssitantForLiveSearch = $bAssistantForLiveSearch;
+    }  
+
+    /**
+     * create units for all classes and calling their processing methods
+     */
+    public function response ()
+    {
+        $sCode = $this->_bDataProcessing ? [] : '';
+
+        if($this->_bAssitantForLiveSearch && $this->_bLiveSearch && ($iAssistant = BxDolAI::getAssistantForLiveSearch()) != 0) {
+            $sKeyword = '';
+            if(($sKeyword = bx_get('keyword')) !== false)
+                $sKeyword = bx_process_input($sKeyword);
+
+            if($this->_bIsApi)
+                $sCode .= BxDolAIAssistant::getObjectInstance($iAssistant)->getAskButton($sKeyword);
+        }
+
+        $bSingle = count($this->aChoice) == 1;
+        foreach($this->aChoice as $sKey => $aValue) {
+            if(!$this->_sMetaType && !$aValue['GlobalSearch'])
+                continue;
+
+            $sClassName = 'BxTemplSearchResult';
+            if(!empty($aValue['class'])) {
+                $sClassName = $aValue['class'];
+                if(!empty($aValue['file']))
+                    require_once(BX_DIRECTORY_PATH_ROOT . $aValue['file']);
+            }
+
+            $oEx = new $sClassName();            
+            if($this->_sMetaType && !$oEx->isMetaEnabled($this->_sMetaType))
+                continue;
+
+            $oEx->setId($aValue['id']);
+            $oEx->setLiveSearch($this->_bLiveSearch);
+            $oEx->setMetaType($this->_sMetaType);
+            $oEx->setCategoryObject($this->_sCategoryObject);
+            $oEx->setCenterContentUnitSelector(false);
+            $oEx->setSingleSearch($bSingle);
+            $oEx->setCustomSearchCondition($this->_aCustomSearchCondition);
+            
+            $oEx->aCurrent = array_merge_recursive($oEx->aCurrent, $this->_aCustomCurrentCondition);
+            if($this->_sUnitTemplate)
+                $oEx->setUnitTemplate($this->_sUnitTemplate);
+
+            if($this->_bDataProcessing) {
+                if($this->_bIsApi) {
+                    if($bSingle) {
+                        $sMethod = 'decodeDataAPI';
+                        if($this->_bLiveSearch && ($sMethodLs = 'decodeLsDataAPI') && method_exists($oEx, $sMethodLs))
+                            $sMethod = $sMethodLs;
+
+                        $sCode = $oEx->$sMethod($oEx->getSearchData());
+                    }
+                    else
+                        $sCode[$sKey] = $oEx->getSearchQuery($sKey);
+                }
+                else
+                    $sCode[$sKey] = $oEx->getSearchData();
+            }
+            else
+                $sCode .= $this->_bRawProcessing ? $oEx->processingRaw() : $oEx->processing();
+        }
+
+        if($this->_bIsApi && !$bSingle && is_array($sCode)) {
+            $bExtendedUnits = getParam('sys_api_extended_units') == 'on';
+
+            $aQueries = [];
+            foreach($sCode as $aQuery)
+                if(!empty($aQuery['query']))
+                    $aQueries[] = $aQuery['query'];
+
+            $aItems = BxDolDb::getInstance()->getAll('(' . implode(') UNION (', $aQueries) . ') ORDER BY `added` DESC ' . current($sCode)['limit']);
+
+            $sCode = [];
+            foreach($aItems as $aItem)
+                if(($oContentInfo = BxDolContentInfo::getObjectInstance($aItem['content_info'])) !== false)
+                    $sCode[] = $oContentInfo->getContentInfoAPI($aItem['id'], $bExtendedUnits);
+        }
+
+        return $sCode;
+    }
+
+    public function getEmptyResult ()
+    {
+        $sKey = _t('_Empty');
+        return DesignBoxContent($sKey, MsgBox($sKey), BX_DB_PADDING_DEF);
+    }
+
+    public function getSearchResultObject($sChoice = '')
+    {
+        $aSearchResult = [];
+
+        if($sChoice) {
+            if(empty($this->aChoice[$sChoice]) || !is_array($this->aChoice[$sChoice]))
+                return false;
+
+            $aSearchResult = $this->aChoice[$sChoice];
+        }
+        else
+            $aSearchResult = reset($this->aChoice);
+
+        $sClassName = 'BxTemplSearchResult';
+        if(!empty($aSearchResult['class'])) {
+            $sClassName = $aSearchResult['class'];
+            if(!empty($aSearchResult['file']))
+                require_once(BX_DIRECTORY_PATH_ROOT . $aSearchResult['file']);
+        }
+
+        return new $sClassName();
+    }
+
+    protected function getKeyTitlesPairs ()
+    {
+        $a = array();
+        foreach ($this->aChoice as $sKey => $r)
+            if ($this->_sMetaType || $r['GlobalSearch'])
+                $a[$sKey] = _t($r['title']);
+        return $a;
+    }
+
+    public function setLiveSearch($bLiveSearch)
+    {
+        $this->_bLiveSearch = $bLiveSearch;
+    }
+
+    public function setMetaType($s)
+    {
+        $aMetaTypes = array('location_country', 'location_country_city', 'location_country_state', 'mention', 'keyword');
+        if (in_array($s, $aMetaTypes))
+            $this->_sMetaType = $s;
+    }
+    
+    public function setCategoryObject($s)
+    {
+        $this->_sCategoryObject = $s;
+    }
+
+    /**
+     * Set custom search condition to use istead of GET/POST variables
+     * @param $a array of params, such as 'keyword', 'state', 'city'
+     * @return nothing
+     */
+    public function setCustomSearchCondition($a)
+    {
+        $this->_aCustomSearchCondition = $a;
+    }
+
+    /**
+     * Set custom data for aCurrent array
+     * @param $a array of params
+     * @return nothing
+     */
+    public function setCustomCurrentCondition($a)
+    {
+        $this->_aCustomCurrentCondition = $a;
+    }
+
+    /**
+     * Set custom unit template
+     * @param $s template name
+     * @return nothing
+     */
+    public function setUnitTemplate($s)
+    {
+        $this->_sUnitTemplate = $s;
+    }
+    
+    /**
+     * Display search results without design box and paginate
+     */ 
+    public function setRawProcessing($b)
+    {
+        $this->_bRawProcessing = $b;
+    }
+
+    /**
+     * Return search result as array of data
+     */ 
+    public function setDataProcessing($b)
+    {
+        $this->_bDataProcessing = $b;
+    }
+}
+
+/*
+ * Search class for processing search requests and displaying search results.
+ *
+ * Allows present content from modules on search params or internal (via fields of class) conditions.
+ *
+ * Example of usage (you can see example in any of default Dolhpin's modules):
+ *
+ * 1. Extends your own search class from this one (or from BxBaseSearchResult or BxBaseSearchResultSharedMedia classes)
+ * 2. Set necessary fields of class (using as example BxFilesSearch):
+ *
+ * @code
+ *
+ *  // main field of search class
+ *  $this->aCurrent = array(
+ *
+ *      // name of module
+ *      'name' => 'bx_files',
+ *
+ *      // language key with name of module
+ *      'title' => '_bx_files',
+ *
+ *      // main content table
+ *      'table' => 'bx_files_main',
+ *
+ *      // array of all fields which can be choosen for select in result query
+ *      'ownFields' => array('ID', 'Title', 'Uri', 'Desc', 'Date', 'Size', 'Ext', 'Views', 'Rate', 'RateCount', 'Type'),
+ *
+ *      // array of fields which take a part in search by keyword (global search and related words only - in other cases leave it blank)
+ *      'searchFields' => array('Title', 'Tags', 'Desc', 'Categories'),
+ *
+ *      // array of join tables
+ *      //   'type' - type of join
+ *      //   'table' - join table
+ *      //   'mainField' - field from main table for 'on' condition
+ *      //   'onField' - field from joining table for 'on' condition
+ *      //   'joinFields' - array of fields from joining table
+ *
+ *      'join' => array(
+ *          'profile' => array(
+ *              'type' => 'left',
+ *              'table' => 'Profiles',
+ *              'mainField' => 'Owner',
+ *              'onField' => 'ID',
+ *              'joinFields' => array('NickName'),
+ *          ),
+ *          // ...
+ *      ),
+ *
+ *      // array of search parameters
+ *      //   'value' - value of search parameter (can be number, string or array)
+ *      //   'field' - field which will take value of search, may be lefy as blank then in search query will be pasted to WHERE conditon via operator AGAINST
+ *      //   'operator' - operator between field and value (can be 'in', 'not in', '>', '<', 'against', 'like' and '=' by default),
+ *      //   'paramName' - GET param which will keep 'value' for pagianation
+ *
+ *      'restriction' => array(
+ *          'activeStatus' => array('value'=>'approved', 'field'=>'Status', 'operator'=>'=', 'paramName' => 'status'),
+ *          'albumType' => array('value'=>'', 'field'=>'Type', 'operator'=>'=', 'paramName'=>'albumType', 'table'=>'sys_albums'),
+ *      ),
+ *
+ *      // array of pagination
+ *      //   'perPage' - units per page
+ *      //   'start' - show search results starting from this number
+ *      //   'num' - number of element to show on current page + 1
+ *
+ *      'paginate' => array('perPage' => 10, 'start' => 0, 'num' => 11),
+ *
+ *      // sort mode - by default it was last (DESC by date)
+ *      'sorting' => 'last',
+ *
+ *      // mode of units presentation in search result, can be 'short' or 'full' view
+ *      'view' => 'full',
+ *
+ *      // field of id
+ *      'ident' => 'ID',
+ *
+ *      // rss feed array
+ *      'rss' => array(
+ *          'title' => '',
+ *          'link' => '',
+ *          'image' => '',
+ *          'profile' => 0,
+ *          'fields' => array (
+ *              'Link' => '',
+ *              'Title' => 'Title',
+ *              'DateTimeUTS' => 'Date',
+ *              'Desc' => 'Desc',
+ *              'Photo' => '',
+ *          ),
+ *      ),
+ *  );
+ *
+ *  // array of fields renamings
+ *  $aPseud - filling in costructor by function _getPseud
+ *
+ *  // unique identificator from `sys_objects_search` table
+ *  $id;
+ *
+ * @endcode
+ *
+ * Memberships/ACL:
+ * Doesn't depend on user's membership.
+ *
+ * Alerts:
+ * no alerts available
+ *
+ */
+
+class BxDolSearchResult implements iBxDolReplaceable
+{
+    public $aCurrent; ///< search results configuration
+
+    protected $aPseud; ///< array of fields renamings
+    protected $id; ///< unique identificator of block on mixed search results page
+    protected $bDisplayEmptyMsg = false; ///< display empty message instead of nothing, when no results
+    protected $sDisplayEmptyMsgKey = ''; ///< custom empty message language key, instead of default "empty" message
+    protected $bProcessPrivateContent = true; ///< check each item for privacy, if view isn't allowed then display private view instead
+    protected $aPrivateConditionsIndexes = array('restriction' => array(), 'join' => array()); ///< conditions indexes for bProcessPrivateContent
+    protected $bForceAjaxPaginate = false; ///< force ajax paginate
+    protected $iPaginatePerPage = BX_DOL_SEARCH_RESULTS_PER_PAGE_DEFAULT; ///< default 'per page' value for paginate.
+
+    protected $_bIsApi;
+    protected $_bSingleSearch = true;
+    protected $_bLiveSearch = false;
+    protected $_sMetaType = '';
+    protected $_sMode = '';
+    protected $_aParams = [];
+    protected $_sCategoryObject = '';
+    protected $_aCustomSearchCondition = array();
+
+    protected $_aMarkers = array (); ///< markers to replace somewhere, usually title and browse url (defined in custom class)
+    
+    /**
+     * constructor
+     * filling identificator field
+     */
+    function __construct ()
+    {
+        $this->_bIsApi = bx_is_api();
+
+        if (isset($this->aPseud['id']))
+            $this->aCurrent['ident'] = $this->aPseud['id'];
+    }
+
+    public function getId()
+    {
+        return $this->id;
+    }
+
+    public function setId($sId)
+    {
+        $this->id = $sId;
+    }
+
+    public function getModuleName()
+    {
+        return isset($this->aCurrent['module_name']) ? $this->aCurrent['module_name'] : '';
+    }
+
+    public function getContentInfoName()
+    {
+        return isset($this->aCurrent['name']) ? $this->aCurrent['name'] : '';
+    }
+
+    public function setAjaxPaginate($b = true)
+    {
+        $this->bForceAjaxPaginate = $b;
+    }
+
+    public function setPaginatePerPage($iPerPage)
+    {
+        $this->iPaginatePerPage = $iPerPage;
+    }
+
+    public function setSingleSearch($bSingleSearch)
+    {
+        $this->_bSingleSearch = $bSingleSearch;
+    }
+
+    public function setLiveSearch($bLiveSearch)
+    {
+        $this->_bLiveSearch = $bLiveSearch;
+    }
+
+    public function setMetaType($s)
+    {
+        $this->_sMetaType = $s;
+    }
+
+    public function isMetaEnabled($s)
+    {
+        if (empty($this->aCurrent['object_metatags']))
+            return false;
+            
+        if (!($o = BxDolMetatags::getObjectInstance($this->aCurrent['object_metatags'])))
+            return false;
+
+        switch ($s) {
+            case 'location_country_city':
+            case 'location_country_state':            
+            case 'location_country':
+                return $o->locationsIsEnabled();
+            case 'mention':
+                return $o->mentionsIsEnabled();
+            case 'keyword':
+                return $o->keywordsIsEnabled();
+        }
+
+        return false;
+    }
+    
+    public function setCategoryObject($s)
+    {
+        $this->_sCategoryObject = $s;
+    }
+
+    public function setCustomSearchCondition($a)
+    {
+        $this->_aCustomSearchCondition = $a;
+    }
+    
+    public function setCustomCurrentCondition($a)
+    {
+        $this->aCurrent = array_merge_recursive($this->aCurrent, $a);
+    }
+
+    public function setCategoriesCondition($sKeyword)
+    {
+		$this->aCurrent['join']['multicat'] = array(
+            'type' => 'INNER',
+            'table' => 'sys_categories2objects',
+            'mainField' => 'id',
+            'onField' => 'object_id',
+            'joinFields' => array(),
+        );
+		
+		if (isset($this->aCurrent['tableSearch'])){
+			$this->aCurrent['join']['multicat']['mainTable'] = $this->aCurrent['tableSearch'];
+		}
+		
+        $this->aCurrent['join']['multicat2'] = array(
+           'type' => 'INNER',
+           'table' => 'sys_categories',
+           'mainField' => 'category_id',
+           'mainTable' => 'sys_categories2objects',
+           'onField' => 'id',
+           'joinFields' => array(),
+       );
+       $this->aCurrent['restriction']['multicat'] = array('value' => $sKeyword, 'field' => 'value', 'operator' => '=', 'table' => 'sys_categories');
+    }
+    
+    /**
+     * Display empty message if there is no content, custom empty message can be used.
+     * @param $b - boolan value to enable or disable 'empty' message
+     * @param $sLangKey [optional] - custom 'empty' message
+     */
+    public function setDisplayEmptyMsg($b, $sLangKey = '')
+    {
+        $this->bDisplayEmptyMsg = $b;
+        if ($sLangKey)
+           $this->sDisplayEmptyMsgKey = $sLangKey;
+    }
+
+    /**
+     * Perform privacy checking for every unit
+     * @param $b - boolan value to enable or disable privacy checking
+     */
+    public function setProcessPrivateContent ($b)
+    {
+        $this->bProcessPrivateContent = $b;
+        if ($b) {
+            // unset condition which was set when 'bProcessPrivateContent' was set to 'false'
+            foreach ($this->aPrivateConditionsIndexes['restriction'] as $sKey) 
+                unset($this->aCurrent['restriction'][$sKey]);
+            foreach ($this->aPrivateConditionsIndexes['join'] as $sKey)
+                unset($this->aCurrent['join'][$sKey]);
+        }
+    }
+
+    /**
+     * Get search results without design box and paginate
+     * @return html code
+     */
+    function processingRaw ()
+    {
+        $sCode = $this->displayResultBlock();
+        return $this->aCurrent['paginate']['num'] > 0 ? $sCode : '';
+    }
+    
+    /**
+     * Get html box of search results (usually used in grlobal search)
+     * @return html code
+     */
+    function processing ()
+    {
+        if($this->_bIsApi)
+            return $this->processingAPI();
+
+        $sCode = $this->displayResultBlock();
+        if ($this->aCurrent['paginate']['num'] > 0) {
+            $sPaginate = $this->showPagination();
+            $sCode = $this->displaySearchBox($sCode, $sPaginate);
+        }
+        else {
+            $sCode = $this->bDisplayEmptyMsg ? $this->displaySearchBox($this->displayResultBlockEmpty()) : '';
+        }
+
+        return $sCode;
+    }
+
+    function processingAPI ($bForceGetData = false)
+    {
+        $sModule = 'system';
+        $sUnitType = 'content';
+        $sHomeUrl = '';
+        
+        if(!empty($this->oModule)) {
+            $sModule = $this->oModule->getName();
+
+            if(method_exists($this->oModule, 'serviceActAsProfile') && $this->oModule->serviceActAsProfile())
+                 $sUnitType = 'profile';
+            if(method_exists($this->oModule, 'serviceIsGroupProfile') && $this->oModule->serviceIsGroupProfile())
+                 $sUnitType = 'context';
+            
+            $sHomeUrl = bx_api_get_relative_url(BxDolPermalinks::getInstance()->permalink($this->oModule->_oConfig->CNF['URL_HOME']));
+        }
+
+        $sUnit =  'list';
+        if(in_array($this->sUnitViewDefault, ['showcase', 'gallery']))
+            $sUnit = 'card';
+        
+        $aData = defined('BX_API_PAGE') && !$bForceGetData ? [] : $this->decodeDataAPI($this->getSearchData());
+
+        $aParams =  [
+            'type' => $this->_sMode,
+            'start' => $this->aCurrent['paginate']['start'],
+            'per_page' => $this->aCurrent['paginate']['perPage'],
+            'view' => $this->_aParams['unit_view'] ?? '',
+        ];
+
+        if($sHomeUrl)
+            $aParams['home_url'] = $sHomeUrl;
+
+        if(($sK = 'class_search_result') && isset($this->_aParams[$sK]))
+            $aParams[$sK] = $this->_aParams[$sK];
+
+        $aParamsAdd = [];
+        if(($sMethod = 'addProcessingParamsAPI') && method_exists($this, $sMethod))
+            $aParamsAdd = $this->$sMethod();
+
+        foreach($aParamsAdd as $sParamAdd)
+            if(isset($this->_aParams[$sParamAdd]))
+                $aParams[$sParamAdd] = $this->_aParams[$sParamAdd];
+
+        return [
+            'module' => $sModule,
+            'unit' => 'general-' . $sUnitType . '-' . $sUnit,
+            'request_url' => !empty($this->aCurrent['api_request_url']) ? $this->aCurrent['api_request_url'] : '/api.php?r=' . $sModule . '/browse/&params[]=',
+            'data' =>  $aData,
+            'params' => $aParams
+        ];
+    }
+
+    function addProcessingParamsAPI()
+    {
+        return ['author', 'category', 'context', 'joined_profile', 'followed_contexts', 'level'];
+    }
+
+    function decodeDataAPI ($a)
+    {
+        return $a;
+    }
+
+    /**
+     * Get html output of search result
+     * @return html code
+     */
+    function displayResultBlock ()
+    {
+        $aData = $this->getSearchData();
+
+        $sCode = '';
+        if (count($aData) > 0) {
+            $sCode = $this->addCustomParts();
+            foreach ($aData as $iKey => $aValue) {
+                $sCode .= $this->displaySearchUnit($aValue);
+            }
+        }
+        return $sCode;
+    }
+
+    /**
+     * Get html output of empty search result
+     * @return html code
+     */
+    function displayResultBlockEmpty ()
+    {
+        return MsgBox(_t($this->sDisplayEmptyMsgKey ? $this->sDisplayEmptyMsgKey : '_Empty'));
+    }
+            
+    /**
+     * Add different code before html output (usually redeclared)
+     * no return result
+     */
+    function addCustomParts ()
+    {
+
+    }
+
+    /**
+     * Get XML string for rss output
+     */
+    function rss ()
+    {
+        if (!isset($this->aCurrent['rss']['fields']) || !isset($this->aCurrent['rss']['link']))
+            return '';
+
+        $aData = $this->getSearchData();
+        $f = &$this->aCurrent['rss']['fields'];
+        if ($aData) {
+            foreach ($aData as $k => $a) {
+                $aData[$k][$f['Link']] = $this->getRssUnitLink ($a);
+
+                if(isset($f['Image']))
+                    $aData[$k][$f['Image']] = $this->getRssUnitImage ($a, $f['Image']);
+            }
+        }
+
+        $oRss = new BxDolRssFactory ();
+
+        return $oRss->GenRssByCustomData(
+            $aData,
+            isset($this->aCurrent['rss']['title']) && $this->aCurrent['rss']['title'] ? $this->aCurrent['rss']['title'] : $this->aCurrent['title'],
+            $this->aCurrent['rss']['link'],
+            $this->aCurrent['rss']['fields'],
+            isset($this->aCurrent['rss']['image']) ? $this->aCurrent['rss']['image'] : '',
+            isset($this->aCurrent['rss']['profile']) ? $this->aCurrent['rss']['profile'] : 0
+        );
+    }
+
+    /**
+     * Output RSS XML with XML header
+     */
+    function outputRSS ()
+    {
+        header('Content-Type: text/xml; charset=UTF-8');
+        echo $this->rss();
+    }
+
+    /**
+     * Return rss unit link (redeclared)
+     */
+    function getRssUnitLink (&$a)
+    {
+        // override this functions to return permalink to rss unit
+    }
+
+	/**
+     * Return rss unit image (redeclared)
+     */
+    function getRssUnitImage (&$a, $sField)
+    {
+        // override this functions to return image for rss unit
+    }
+
+    /**
+     * Naming fields in query's body
+     * @param string  $sFieldName  name of field
+     * @param string  $sTableName  name of field's table
+     *                             $param string $sOperator of field's calculation (like MAX)
+     * @param boolean $bRenameMode indicator for renaming and unsetting fields from field of class $this->aPseud
+     *                             return $sqlUnit sql code and unsetting elements from aPseud field
+     */
+    function setFieldUnit ($sFieldName, $sTableName, $sOperator = '', $bRenameMode = true)
+    {
+        $bOperator = !empty($sOperator);
+
+        $sqlUnit  = "`$sTableName`.`$sFieldName`";
+        if($bOperator)
+            $sqlUnit = $sOperator . '(' . $sqlUnit . ')';
+
+        if(!empty($this->aPseud) && $bRenameMode !== false && ($sKey = array_search($sFieldName . ($bOperator ? '_' . strtolower($sOperator) : ''), $this->aPseud)) !== false) {
+            $sqlUnit .= " as `$sKey`";
+            unset($this->aPseud[$sKey]);
+        }
+
+        return $sqlUnit . ', ';
+    }
+
+    /**
+     * Get html code of of every search unit
+     * @param array $aData array of every search unit
+     *                     return html code
+     */
+    function displaySearchUnit ($aData)
+    {
+
+    }
+
+    /**
+     * Get html code of search box with search results
+     * @param string $sCode html code of search results
+     *                      $param $sPaginate html code of paginate
+     *                      return html code
+     */
+    function displaySearchBox ($sCode, $sPaginate = '')
+    {
+
+    }
+
+    /**
+     * Get html code of pagination
+     */
+    function showPagination ($bAdmin = false, $bChangePage = true, $bPageReload = true)
+    {
+
+    }
+
+    /**
+     * Get array of data with search results
+     * return array with data
+     */
+    function getSearchData ()
+    {
+        /**
+         * @hooks
+         * @hookdef hook-simple_search-before_get_data 'simple_search', 'before_get_data' - hook on before after get data 
+         * - $unit_name - equals `simple_search`
+         * - $action - equals `before_get_data` 
+         * - $object_id - not used 
+         * - $sender_id - not used 
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `object` - [array] by ref, array of parameters, can be overridden in hook processing
+         *      - `mode` - [string] search mode
+         * @hook @ref hook-simple_search-before_get_data
+         */
+        bx_alert('simple_search', 'before_get_data', 0, false, [
+            'object' => &$this->aCurrent, 
+            'object_ref' => &$this->aCurrent, 
+            'mode' => $this->_sMode
+        ]);
+
+        if(($this->aPseud = $this->_getPseudFromParam()) === false)
+            $this->aPseud = $this->_getPseud();
+
+        $this->setConditionParams();
+        $aData = $this->aCurrent['paginate']['num'] > 0 ? $this->getSearchDataByParams() : [];
+
+        /**
+         * @hooks
+         * @hookdef hook-simple_search-get_data 'simple_search', 'get_data' - hook on after get data 
+         * - $unit_name - equals `simple_search`
+         * - $action - equals `get_data` 
+         * - $object_id - not used 
+         * - $sender_id - not used 
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `object` - [array] by ref, array of parameters, can be overridden in hook processing
+         *      - `mode` - [string] search mode
+         *      - `search_object` - [string] search object name
+         * @hook @ref hook-simple_search-get_data
+         */
+        bx_alert('simple_search', 'get_data', 0, false, [
+            'object' => &$this->aCurrent, 
+            'object_ref' => &$this->aCurrent, 
+            'mode' => $this->_sMode, 
+            'search_results' => &$aData,
+            'search_results_ref' => &$aData
+        ]);
+
+        return $aData;
+    }
+
+    /**
+     * Get query [query, limit] for search results. Is used for combined search from different sections.
+     * @param type $aParams array with params
+     * @return type array with query and limit
+     */
+    function getSearchQuery($sObject, $aParams = [])
+    {
+        if(!is_array($aParams))
+            $aParams = [];
+        $aParams = array_merge($aParams, ['for_union' => true]);
+
+        $this->aPseud = [
+            'id' => !empty($this->aCurrent['ident']) ? $this->aCurrent['ident'] : 'id', 
+            'added' => !empty($this->aCurrent['added']) ? $this->aCurrent['added'] : 'added'
+        ];
+
+        $this->setConditionParams();
+        $aQuery = $this->getSearchDataByParams($aParams);
+
+        /**
+         * @hooks
+         * @hookdef hook-simple_search-get_query 'simple_search', 'get_query' - hook on get sql queries
+         * - $unit_name - equals `simple_search`
+         * - $action - equals `get_query` 
+         * - $object_id - not used 
+         * - $sender_id - not used 
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `object` - [array] by ref, array of parameters, can be overridden in hook processing
+         *      - `mode` - [string] search mode
+         *      - `search_object` - [string] search object name
+         *      - `search_query` - [array] by ref, array of sql, can be overridden in hook processing
+         * @hook @ref hook-simple_search-get_query
+         */
+        bx_alert('simple_search', 'get_query', 0, false, [
+            'object' => &$this->aCurrent, 
+            'object_ref' => &$this->aCurrent, 
+            'mode' => $this->_sMode, 
+            'search_object' => $sObject,
+            'search_query' => &$aQuery,
+            'search_query_ref' => &$aQuery
+        ]);
+
+        return $aQuery;
+    }
+
+    function getFieldsOwn()
+    {
+        return false;
+    }
+
+    function getFieldsJoin($sJoin)
+    {
+        return false;
+    }
+
+    /**
+     * Get array with code for sql elements
+     * @param $bRenameMode indicator of renmaing fields
+     * return array with joinFields, ownFields, groupBy and join elements
+     */
+    function getJoins ($bRenameMode = true)
+    {
+        if(!isset($this->aCurrent['join']) || !is_array($this->aCurrent['join']))
+            return false;
+
+        $aSql = [
+            'join' => '', 
+            'ownFields' => '', 
+            'joinFields' => '', 
+            'groupBy' => '', 
+            'groupHaving' => ''
+        ];
+
+        foreach($this->aCurrent['join'] as $sKey => $aValue) {
+            $sAlias = isset($aValue['table_alias']) ? $aValue['table_alias'] : $aValue['table'];
+            $sTableAlias = isset($aValue['table_alias']) ? " AS {$aValue['table_alias']} " : '';
+            $sOperator = isset($aValue['operator']) ? $aValue['operator'] : null;
+
+            // joinFields
+            $aJoinFields = $this->getFieldsJoin($sKey);
+            if($aJoinFields === false && !empty($aValue['joinFields']) && is_array($aValue['joinFields']))
+                $aJoinFields = $aValue['joinFields'];
+
+            if($aJoinFields)
+                foreach($aJoinFields as $mixedField) {
+                    list($sFldName, $sFldOperator) = is_array($mixedField) ? $mixedField : [$mixedField, $sOperator];
+
+                    $aSql['joinFields'] .= $this->setFieldUnit($sFldName, $sAlias, $sFldOperator, $bRenameMode);
+                }
+
+            // group by
+            if(isset($aValue['groupTable']))
+                $aSql['groupBy'] .= "`{$aValue['groupTable']}`.`{$aValue['groupField']}`, ";
+
+            // having
+            if(isset($aValue['groupHaving']))
+                $aSql['groupHaving'] .= $aValue['groupHaving'];
+
+            $sOn = isset($aValue['mainTable']) ? $aValue['mainTable'] : $this->aCurrent['table'];
+            $aSql['join'] .= " {$aValue['type']} JOIN `{$aValue['table']}` $sTableAlias ON " . (!empty($aValue['on_sql']) ? $aValue['on_sql'] : "`{$sAlias}`.`{$aValue['onField']}`=" . trim($this->setFieldUnit($aValue['mainField'], $sOn, isset($aValue['mainFieldFunc']) ? $aValue['mainFieldFunc'] : '', false), ", "));
+            $aSql['ownFields'] .= $this->setFieldUnit($aValue['mainField'], $sOn, '', $bRenameMode);
+        }
+
+        $aSql['joinFields'] = trim($aSql['joinFields'], ', ');
+
+        if(!empty($aSql['groupBy']))
+            $aSql['groupBy'] = trim('GROUP BY ' . $aSql['groupBy'], ', ');
+
+        if(!empty($aSql['groupHaving']))
+            $aSql['groupHaving'] = 'HAVING ' . $aSql['groupHaving'];
+
+        return $aSql;
+    }
+
+    /**
+     * Concat sql parts of query, run it and return result array
+     * @param $aParams addon param
+     * return $aData multivariate array
+     */
+    function getSearchDataByParams ($aParams = '')
+    {
+        $bForUnion = isset($aParams['for_union']) && $aParams['for_union'] === true;
+
+        $aSql = [
+            'ownFields' => '', 
+            'order' => ''
+        ];
+
+        // searchFields
+        if($bForUnion) {
+            $sTable = isset($this->aCurrent['tableSearch']) ? $this->aCurrent['tableSearch'] : $this->aCurrent['table'];
+
+            $aSql['ownFields'] .= $this->setFieldUnit(!empty($this->aCurrent['ident']) ? $this->aCurrent['ident'] : 'id', $sTable);
+            $aSql['ownFields'] .= $this->setFieldUnit(!empty($this->aCurrent['added']) ? $this->aCurrent['added'] : 'added', $sTable);
+            $aSql['ownFields'] .= "'" . $this->getContentInfoName()  . "' AS `content_info`";
+        }
+        else {
+            $aOwnFields = $this->getFieldsOwn();
+            if($aOwnFields === false)
+                $aOwnFields = $this->aCurrent['ownFields'];
+
+            foreach($aOwnFields as $mixedField) {
+                list($sFldName, $sFldOperator) = is_array($mixedField) ? $mixedField : [$mixedField, ''];
+
+                $aSql['ownFields'] .= $this->setFieldUnit($sFldName, $this->aCurrent['table'], $sFldOperator);
+            }
+        }
+
+        // joinFields & join
+        if(($aJoins = $this->getJoins()) !== false) {
+            if(!$bForUnion) {
+                $aSql['ownFields'] .= $aJoins['ownFields'];
+                $aSql['ownFields'] .= $aJoins['joinFields'];
+            }
+
+            $aSql['join'] = $aJoins['join'];
+            $aSql['groupBy'] = $aJoins['groupBy'];
+            $aSql['groupHaving'] = $aJoins['groupHaving'];
+        }
+
+        $aSql['ownFields'] = trim($aSql['ownFields'], ', ');
+
+        // from
+        $aSql['from'] = " FROM `{$this->aCurrent['table']}`";
+
+        // where
+        $aSql['where'] = $this->getRestriction();
+
+        // limit
+        $aSql['limit'] = $this->getLimit();
+
+        // sorting
+        $this->setSorting();
+
+        $aSort = $this->getSorting($this->aCurrent['sorting']);
+        foreach ($aSort as $sKey => $sValue)
+            $aSql[$sKey] .= $sValue;
+
+        // execution
+        $sqlQuery = 'SELECT';
+
+        if(isset($this->aCurrent['distinct']) && $this->aCurrent['distinct'] === true)
+            $sqlQuery .= ' DISTINCT';
+
+        $sqlQuery .= ' ' . $aSql['ownFields'];
+
+        $sqlQuery .= ' ' . $aSql['from'];
+
+        if (isset($aSql['join']))
+            $sqlQuery .= ' ' . $aSql['join'];
+
+        if (isset($aSql['where']))
+            $sqlQuery .= ' ' . $aSql['where'];
+
+        if (isset($aSql['groupBy']))
+            $sqlQuery .= ' ' . $aSql['groupBy'];
+
+        if (isset($aSql['groupHaving']))
+            $sqlQuery .= ' ' . $aSql['groupHaving'];
+
+        if($bForUnion)
+            return [
+                'query' => $sqlQuery, 
+                'limit' => $aSql['limit']
+            ];
+
+        if (isset($aSql['order']))
+            $sqlQuery .= ' ' . $aSql['order'];
+
+        if (isset($aSql['limit']))
+            $sqlQuery .= ' ' . $aSql['limit'];
+
+        //echoDbg($sqlQuery);
+        $aRes = BxDolDb::getInstance()->getAll($sqlQuery);
+        return $aRes;
+    }
+
+    /**
+     * Set class fields condition params and paginate array
+     */
+    function setConditionParams()
+    {
+        $this->aCurrent['paginate']['num'] = 0;
+
+        // keyword
+        $sKeyword = bx_process_input(isset($this->_aCustomSearchCondition['keyword']) ? $this->_aCustomSearchCondition['keyword'] : bx_get('keyword'));
+        $bKeyword = !empty($sKeyword);
+
+        if ($this->_bLiveSearch && !$bKeyword)
+            return;
+
+        if ($bKeyword) {
+            if (substr($sKeyword, 0, 1) == '@') {
+                $sModule = $this->aCurrent['module_name'];
+                $sMethod = 'act_as_profile';
+                if(!bx_is_srv($sModule, $sMethod) || !bx_srv($sModule, $sMethod))
+                    return;
+
+                $sKeyword = substr($sKeyword, 1);
+            }
+
+            $this->aCurrent['restriction']['keyword'] = array(
+                'value' => $sKeyword,
+                'field' => '',
+                'operator' => 'against'
+            );
+
+            // for search results we need to show all items, not only public content
+            $this->setProcessPrivateContent(true);
+        }
+
+        // owner
+        if (isset($_GET['ownerName'])) {
+            $sName = bx_process_input($_GET['ownerName']);
+            $iUser = (int)BxDolProfileQuery::getInstance()->getIdByNickname($sName);
+            BxDolMenu::getInstance()->setCurrentProfileID($iUser);
+        } elseif (isset($_GET['userID']))
+            $iUser = bx_process_input($_GET['userID'], BX_DATA_INT);
+
+        if (!empty($iUser))
+            $this->aCurrent['restriction']['owner']['value'] = $iUser;
+        
+        // meta info
+        if ($this->_sMetaType && !empty($this->aCurrent['object_metatags'])) {
+            $o = BxDolMetatags::getObjectInstance($this->aCurrent['object_metatags']);
+            if ($o) {
+                unset($this->aCurrent['restriction']['keyword']);
+
+                $aLocationString = [];
+                switch ($this->_sMetaType) {
+                    case 'location_country':
+                        $aLocationString['country'] = $sKeyword;
+                        $o->locationsSetSearchCondition($this, $sKeyword);
+                        break;
+                    case 'location_country_state':
+                        $aLocationString['country'] = $sKeyword;
+                        $aLocationString['state'] = bx_process_input(isset($this->_aCustomSearchCondition['state']) ? $this->_aCustomSearchCondition['state'] : bx_get('state'));
+                        $o->locationsSetSearchCondition($this, $sKeyword, $aLocationString['state']);
+                        break;
+                    case 'location_country_city':
+                        $aLocationString['country'] = $sKeyword;
+                        $aLocationString['state'] = bx_process_input(isset($this->_aCustomSearchCondition['state']) ? $this->_aCustomSearchCondition['state'] : bx_get('state'));
+                        $aLocationString['city'] = bx_process_input(isset($this->_aCustomSearchCondition['city']) ? $this->_aCustomSearchCondition['city'] : bx_get('city'));
+                        $o->locationsSetSearchCondition($this, $sKeyword, $aLocationString['state'], $aLocationString['city']);
+                        break;
+                    case 'location_state':
+                        $aLocationString['state'] = $sKeyword;
+                        $o->locationsSetSearchCondition($this, false, $sKeyword);
+                        break;
+                    case 'location_city':
+                        $aLocationString['city'] = $sKeyword;
+                        $o->locationsSetSearchCondition($this, false, false, $sKeyword);
+                        break;
+                    case 'mention':
+                        $oCmts = !empty($this->sModuleObjectComments) ? BxDolCmts::getObjectInstance($this->sModuleObjectComments, 0, false) : false;
+                        $o->mentionsSetSearchCondition($this, $sKeyword, $oCmts ? $oCmts->getSystemId() : 0);
+
+                        if(($oProfile = BxDolProfile::getInstance((int)$sKeyword)) !== false)
+                            $this->_setPageDescription('_sys_page_description_mention', $oProfile->getDisplayName(), $this->aCurrent['title']);
+                        break;
+                    case 'keyword':
+                        $oCmts = !empty($this->sModuleObjectComments) ? BxDolCmts::getObjectInstance($this->sModuleObjectComments, 0, false) : false;
+                        $o->keywordsSetSearchCondition($this, $sKeyword, $oCmts ? $oCmts->getSystemId() : 0);
+
+                        $this->_setPageDescription('_sys_page_description_hashtag', $sKeyword, $this->aCurrent['title']);
+                        break;
+                }
+
+                if(in_array($this->_sMetaType, ['location_country', 'location_country_state', 'location_country_city', 'location_state', 'location_city']))
+                    $this->_setPageDescription('_sys_page_description_location', $o->locationsStringFromArray($aLocationString, false), $this->aCurrent['title']);
+            }
+        }
+
+        // category
+        if ($this->_sCategoryObject) {
+            if(($o = BxDolCategory::getObjectInstance($this->_sCategoryObject)) && $this->_bSingleSearch) {
+                if ($this->aCurrent['name'] == $o->getSearchObject()) {
+                    unset($this->aCurrent['restriction']['keyword']);
+                    $o->setSearchCondition($this, $sKeyword);
+                }
+
+                $this->_setPageDescription('_sys_page_description_category', $o->getCategoryTitle($sKeyword), $this->aCurrent['title']);
+            }
+
+            if ($this->_sCategoryObject == 'multi'){
+                unset($this->aCurrent['restriction']['keyword']);
+                $this->setCategoriesCondition($sKeyword);
+            }
+        }
+
+        if($bKeyword && !$this->_sMetaType && !$this->_sCategoryObject)
+            $this->_setPageDescription('_sys_page_description_keyword', $sKeyword, $this->aCurrent['title']);
+
+        $this->setPaginate();
+        $iNum = $this->getNum();
+        if ($iNum > 0)
+            $this->aCurrent['paginate']['num'] = $iNum;
+    }
+
+    /**
+     * Check number of records on current page
+     * return number of records on current page + 1
+     */
+    function getNum ()
+    {
+        $aJoins = $this->getJoins(false);
+        $sqlQuery =  "SELECT * FROM `{$this->aCurrent['table']}` " . (isset($aJoins['join']) ? ' ' . $aJoins['join'] : '' ) . $this->getRestriction() . (isset($aJoins['groupBy']) ? ' ' . $aJoins['groupBy'] : '') . ' ' . $this->getLimit(true);
+        return count(BxDolDb::getInstance()->getAll($sqlQuery));
+    }
+
+    /**
+     * Get total number of records
+     * return total number of records
+     */
+    function getTotal ()
+    {
+        $aJoins = $this->getJoins(false);
+        $sqlQuery =  "SELECT COUNT(*) FROM `{$this->aCurrent['table']}` " . (isset($aJoins['join']) ? ' ' . $aJoins['join'] : '' ) . $this->getRestriction() . (isset($aJoins['groupBy']) ? ' ' . $aJoins['groupBy'] : '');
+        return BxDolDb::getInstance()->getOne($sqlQuery);
+    }
+
+    /**
+     * Check restriction params and make condition part of query
+     * return $sqlWhere sql code of query for WHERE part
+     */
+    function getRestriction ()
+    {
+        $oDb = BxDolDb::getInstance();
+        $sqlWhere = '';
+        if (isset($this->aCurrent['restriction'])) {
+            $aWhere[] = '1';
+            foreach ($this->aCurrent['restriction'] as $sKey => $aValue) {
+                $sqlCondition = '';
+                if (isset($aValue['operator']) && isset($aValue['value']) && $aValue['value'] !== '' && $aValue['value'] !== false && $aValue['value'] !== null) {
+                   $sFieldTable = isset($aValue['table']) ? $aValue['table'] : $this->aCurrent['table'];
+                   $sqlCondition = "`{$sFieldTable}`.`{$aValue['field']}` ";
+                   switch ($aValue['operator']) {
+                       case 'empty value':
+                            $sqlCondition .= " = '' ";
+                            break;
+                       case 'not empty value':
+                            $sqlCondition .= " != '' ";
+                            break;
+                       case 'nothing':
+                            $sqlCondition = " 0 ";
+                            break;
+                       case 'against':
+                            $aCond = isset($aValue['field']) && strlen($aValue['field']) > 0 ? $aValue['field'] : $this->aCurrent['searchFields'];
+                            $sqlCondition = !empty($aCond) ? $this->getSearchFieldsCond($aCond, $aValue['value']) : "";
+                            break;
+                       case 'like':
+                            $sqlCondition .= "LIKE " . $oDb->escape('%' . $aValue['value'] . '%');
+                            break;
+                       case 'in':
+                       case 'not in':
+                            $sValuesString = $this->getMultiValues($aValue['value']);
+                            $sqlCondition .= strtoupper($aValue['operator']) . '(' . $sValuesString . ')';
+                            break;
+                       case 'in_set':
+                           $sqlCondition = "1 << (" . $sqlCondition . " - 1) & " . (int)$aValue['value'];
+                           break;
+                       default:
+                               $sqlCondition .= $aValue['operator'] . (isset($aValue['no_quote_value']) && $aValue['no_quote_value'] ?  $aValue['value'] : $oDb->escape($aValue['value']));
+                       break;
+                    }
+                }
+                if (strlen($sqlCondition) > 0)
+                    $aWhere[] = $sqlCondition;
+            }
+            $sqlWhere .= "WHERE ". implode(' AND ', $aWhere) . (isset($this->aCurrent['restriction_sql']) ? $this->aCurrent['restriction_sql'] : '');
+        }
+
+        return $sqlWhere;
+    }
+
+    /**
+     * Get limit part of query
+     * return $sqlFrom code for limit part pf query
+     */
+    function getLimit ($isAddPlusOne = false)
+    {
+        if (!isset($this->aCurrent['paginate']))
+            return;
+
+        $sqlFrom = (int)$this->aCurrent['paginate']['start'] > 0 ? (int)$this->aCurrent['paginate']['start'] : 0;
+        $sqlTo = $this->aCurrent['paginate']['perPage'] + ($isAddPlusOne ? 1 : 0);
+        if ($sqlTo > 0)
+            return 'LIMIT ' . $sqlFrom . ', ' . $sqlTo;
+    }
+
+    /**
+     * Set sorting field of class
+     */
+    function setSorting ()
+    {
+        $this->aCurrent['sorting'] = isset($_GET[$this->aCurrent['name'] . '_mode']) ? $_GET[$this->aCurrent['name'] . '_mode'] : $this->aCurrent['sorting'];
+    }
+
+    /**
+     * Get sorting part of query according current sorting mode
+     * @param string $sSortType sorting type
+     *                          return array with sql elements order and ownFields
+     */
+    function getSorting ($sSortType = 'last')
+    {
+        if (isset($this->aCurrent['sorting_sql']))
+            return array('order' => $this->aCurrent['sorting_sql']);
+        
+        $aOverride = $this->getAlterOrder();
+        if (is_array($aOverride) && !empty($aOverride))
+            return $aOverride;
+
+       $aSql = array();
+       switch ($sSortType) {
+           case 'rand':
+                $aSql['order'] = "ORDER BY RAND()";
+                break;
+           case 'score':
+                if (is_array($this->aCurrent['restriction']['keyword'])) {
+                    $sPseud = '';
+                    if ('on' == getParam('useLikeOperator')) {
+                        $aSql['order'] = "ORDER BY `score` DESC";
+                        $sPseud = 'score';
+                    }
+                    $aSql['ownFields'] .= $this->getSearchFieldsCond($this->aCurrent['searchFields'], $this->aCurrent['restriction']['keyword']['value'], $sPseud) . ',';
+                }
+                break;
+           case 'none':
+                $aSql['order'] = "";
+                break;
+           default:
+                $aSql['order'] = "ORDER BY `date` DESC";
+        }
+        return $aSql;
+    }
+
+    /**
+     * Return own varaint for sorting (redeclare if necessary)
+     * return array of sql elements
+     */
+    function getAlterOrder ()
+    {
+        return array();
+    }
+
+    /**
+     * Set paginate fields of class according GET params 'start' and 'per_page'
+     * forcePage is need for setting most important number of current page
+     */
+    function setPaginate ()
+    {
+        $iStart = 0;
+        $iPerPage = 0;
+
+        //--- Check in aCurrent (low priority).
+        if(isset($this->aCurrent['paginate']['perPage']) && (int)$this->aCurrent['paginate']['perPage'] != 0)
+            $iPerPage = (int)$this->aCurrent['paginate']['perPage'];
+        
+        //--- Check in aParams (middle priority).
+        if(isset($this->_aParams['per_page']) && (int)$this->_aParams['per_page'] != 0)
+            $iPerPage = (int)$this->_aParams['per_page'];
+
+        //--- Check in GET params (high priority).
+        if(isset($_GET['per_page']) && (int)$_GET['per_page'] != 0)
+            $iPerPage = (int)$_GET['per_page'];
+
+        //--- Trying to get from System settings.
+        if (empty($iPerPage))
+            $iPerPage = (int)getParam('sys_per_page_search_keyword_' . ($this->_bSingleSearch ? 'single' : 'plural'));
+
+        //--- Use default value in case of emergency.
+        if (empty($iPerPage))
+            $iPerPage = BX_DOL_SEARCH_RESULTS_PER_PAGE_DEFAULT;
+        
+        if ($this->iPaginatePerPage != BX_DOL_SEARCH_RESULTS_PER_PAGE_DEFAULT)
+            $iPerPage = $this->iPaginatePerPage;
+
+        $this->aCurrent['paginate']['perPage'] = $iPerPage;
+
+        if(!isset($this->aCurrent['paginate']['forceStart'])) {
+            if(isset($this->_aParams['start']))
+                $iStart = (int)$this->_aParams['start'];
+
+            if(($iStartGet = bx_get('start')) !== false)
+                $iStart = (int)$iStartGet;
+        }
+        else
+            $iStart = (int)$this->aCurrent['paginate']['forceStart'];
+
+        if($iStart < 0)
+            $iStart = 0;
+
+        $this->aCurrent['paginate']['start'] = $iStart;
+    }
+
+    function unsetPaginate()
+    {
+    	unset($this->aCurrent['paginate']);
+    }
+
+    /**
+     * Get sql where condition for search fields
+     * @param array of search fields
+     * @param string $sKeyword keyword value for search
+     * @param string sPseud for setting new name for generated set of fields in query
+     *                         return sql code of WHERE part in query
+     */
+    function getSearchFieldsCond ($aFields, $sKeyword, $sPseud = '')
+    {
+        if (!$sKeyword)
+            return '';
+
+        $sTable = empty($this->aCurrent['tableSearch']) ? $this->aCurrent['table'] : $this->aCurrent['tableSearch'];
+
+        $oDb = BxDolDb::getInstance();
+
+        $bLike = getParam('useLikeOperator');
+
+        if (!is_array($aFields))
+            $aFields = array($aFields);
+
+        if ($bLike == 'on') {
+            $sKeyword = $oDb->escape('%' . preg_replace('/\s+/', '%', $sKeyword) . '%');
+
+            $sSqlWhere = '';
+            foreach ($aFields as $sValue)
+                $sSqlWhere .= "`{$sTable}`.`$sValue` LIKE  " . $sKeyword . " OR ";
+
+            $sSqlWhere = '(' . trim($sSqlWhere, 'OR ') . ')';
+
+        } else {
+        	$sKeyword = $oDb->escape($sKeyword);
+
+            $sSqlWhere = '';
+            foreach ($aFields as $sValue)
+                $sSqlWhere .= "`{$sTable}`.`$sValue`, ";
+
+            $sSqlWhere = trim($sSqlWhere, ', ');
+            $sSqlWhere = " MATCH({$sSqlWhere}) AGAINST (" . $sKeyword . ") ";
+
+            if (!empty($sPseud))
+                $sSqlWhere .= " AS `$sPseud` ";
+        }
+
+        return $sSqlWhere;
+    }
+
+    /**
+     * Get set from several values for 'in' and 'not in' operators
+     * @param $aValues array of values
+     * return sql code for field with operator IN (NOT IN)
+     */
+    function getMultiValues ($aValues)
+    {
+        $oDb = BxDolDb::getInstance();
+        return $oDb->implode_escape($aValues);
+    }
+
+    /**
+     * System method for filling aPseud array. Fill field aPseud for current class from system option.
+     * It may be useful when Fields are taken from system option too.
+     */
+    function _getPseudFromParam ()
+    {
+        return false;
+    }
+
+    /**
+     * System method for filling aPseud array.
+     * Fill field aPseud for current class (if you will use own getSearchUnit methods then not necessary to redeclare).
+     */
+    function _getPseud ()
+    {
+
+    }
+
+    /**
+     * Add replace markers. Markers are replaced in titles and browse urls
+     * @param $a array of markers as key => value
+     * @return true on success or false on error
+     */
+    public function addMarkers ($a)
+    {
+        if (empty($a) || !is_array($a))
+            return false;
+        $this->_aMarkers = array_merge ($this->_aMarkers, $a);
+        return true;
+    }
+
+    /**
+     * Replace provided markers in a string
+     * @param $mixed string or array to replace markers in
+     * @return string where all occured markers are replaced
+     */
+    protected function _replaceMarkers ($mixed)
+    {
+        return bx_replace_markers($mixed, $this->_aMarkers);
+    }
+
+    protected function _setPageDescription()
+    {
+        $aArgs = func_get_args();
+
+        if($this->_bSingleSearch)
+            $aArgs[0] .= '_in_section';
+
+        BxDolTemplate::getInstance()->setPageDescription(call_user_func_array('_t', $aArgs));
+    }
+}
+
+/** @} */

+ 977 - 0
upgrade/files/15.0.0.B3-15.0.0.RC1/files/inc/classes/BxDolWiki.php

@@ -0,0 +1,977 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    UnaCore UNA Core
+ * @{
+ */
+
+/**
+ * WIKI object.
+ *
+ * It's possble to create different WIKI object which will different URLs, Menus and permissions.
+ * For example it's possible to create 
+ * http://example.com/wiki/somepageshere and http://example.com/docs/anotherpageshere
+ *
+ * @section wiki_create Creating the WIKI object:
+ *
+ *
+ * Add record to 'sys_objects_wiki' table:
+ *
+ * - object: name of the WIKI object, this name will be user in URL as well, 
+ *          for example, 'wiki' will have URLs like this: http://example.com/wiki/somepageshere
+ * - uri: wiki module URI
+ * - title: title of the WIKI, for example, documentation, help, tutorial
+ * - module: module name WIKI object belongs to
+ * - override_class_name: user defined class name 
+ * - override_class_file: the location of the user defined class, leave it empty if class is located in system folders.
+ *
+ * Add record to 'sys_rewrite_rules' table:
+ * - preg - regular expression which matches some URL
+ * - service - service method to call if abbe regular expression matches
+ * - active - active flag
+ *
+ * Add record to 'sys_permalinks' table:
+ * - standard - how link should look like when permalinks are off
+ * - permalink - how link should look like when permalinks are on, 
+ *      some special server configuration may be required to make permalink to work, 
+ *      such as 'mod_rewrite' and .htaccess file for Apache
+ * - check - option name which enables/disables permalinks
+ * - compare_by_prefix - compare by prefix
+ */
+class BxDolWiki extends BxDolFactory implements iBxDolFactoryObject
+{
+    protected $_bIsApi;
+
+    protected $_sObject;
+    protected $_aObject;
+    protected $_oQuery;
+    protected $_sLangCateg = 'Wiki';
+    protected $_sACLprefix = 'wiki ';
+    protected $_bProcessMarkdown = true;
+
+    /**
+     * Constructor
+     * @param $aObject array of WIKI options
+     */
+    protected function __construct($aObject)
+    {
+        parent::__construct();
+
+        $this->_bIsApi = bx_is_api();
+
+        $this->_sObject = $aObject['object'];
+        $this->_aObject = $aObject;
+        $this->_oQuery = new BxDolWikiQuery($aObject);
+    }
+
+    /**
+     * Get WIKI object instance by object URI
+     * @param $sObject object name
+     * @return object instance or false on error
+     */
+    static public function getObjectInstanceByUri($sUri, $oTemplate = false)
+    {
+        $aObject = BxDolWikiQuery::getWikiObjectByUri($sUri);
+        if (!$aObject || !is_array($aObject))
+            return false;
+
+        return self::getObjectInstance($aObject['object'], $oTemplate);
+    }
+
+    /**
+     * Get WIKI object instance by object name
+     * @param $sObject object name
+     * @return object instance or false on error
+     */
+    static public function getObjectInstance($sObject, $oTemplate = false)
+    {
+        if (isset($GLOBALS['bxDolClasses']['BxDolWiki!'.$sObject]))
+            return $GLOBALS['bxDolClasses']['BxDolWiki!'.$sObject];
+
+        $aObject = BxDolWikiQuery::getWikiObject($sObject);
+        if (!$aObject || !is_array($aObject))
+            $aObject = BxDolWikiQuery::getWikiObject('system');
+
+        $sClass = empty($aObject['override_class_name']) ? 'BxDolWiki' : $aObject['override_class_name'];
+        if (!empty($aObject['override_class_file']))
+            require_once(BX_DIRECTORY_PATH_ROOT . $aObject['override_class_file']);
+
+        $o = new $sClass($aObject, $oTemplate);
+
+        return ($GLOBALS['bxDolClasses']['BxDolWiki!'.$sObject] = $o);
+    }
+
+    static public function onModuleUninstall($sModule)
+    {
+        $aBlockIds = BxDolWikiQuery::getBlocks ($sModule);
+        if ($aBlockIds && is_array($aBlockIds))
+            self::onBlockDelete($aBlockIds);
+    }
+
+    static public function onBlockDelete($mixedBlockIds)
+    {
+        BxDolWikiQuery::deleteAllRevisions($mixedBlockIds);
+
+        $aBlockIds = is_array($mixedBlockIds) ? $mixedBlockIds : [$mixedBlockIds];
+        $oStorage = BxDolStorage::getObjectInstance('sys_wiki_files');
+        if ($oStorage) {
+            foreach ($aBlockIds as $iBlockId) {
+                $aFiles = $oStorage->getGhosts(0, $iBlockId, false, true);
+                $oStorage->queueFiles($aFiles);
+            }
+        }
+    }
+
+    /**
+     * Get object name
+     */
+    public function getObjectName ()
+    {
+        return $this->_sObject;
+    }
+
+    /**
+     * Get URI
+     */
+    public function getUri ()
+    {
+        return $this->_aObject['uri'];
+    }
+
+    /**
+     * Get WIKI block content
+     * @param $iBlockId block ID
+     * @param $sLang optional language name
+     * @return block content
+     */
+    public function getBlockContent ($iBlockId, $sLang = false, $iRevision = false)
+    {
+        if (!$sLang)
+            $sLang = bx_lang_name();
+
+        $s = '';
+        $sControls = '';
+        $aWikiVer = $this->_oQuery->getBlockContent ($iBlockId, $sLang, $iRevision);
+        $aWikiLatest = $this->_oQuery->getBlockContent ($iBlockId, $sLang);
+        if ($aWikiVer) {
+            if ($this->_bProcessMarkdown && !$this->_bIsApi) {
+                $oParsedown = new BxDolParsedown();
+                $oParsedown->setSafeMode($aWikiVer['unsafe'] ? false : true);
+                $s = $oParsedown->text($aWikiVer['content']);
+            }
+            else {
+                $s = $aWikiVer['content'];
+            }
+        }
+
+        if (!$aWikiVer && $aWikiLatest) {
+            return _t('_sys_wiki_error_no_rev', $iRevision ? $iRevision : 0, $sLang);
+        }
+
+        if (!$aWikiVer && !$aWikiLatest && $this->isAllowed('edit')) {
+            $s = _t('_sys_wiki_error_no_revs');
+        }
+
+        $sControls = '';
+        if (!$this->_bIsApi && ($aWikiVer || $this->isAllowed('edit'))) {
+            $sControls = BxDolService::call('system', 'wiki_controls', array($this, $aWikiVer, $aWikiLatest, $iBlockId), 'TemplServiceWiki');
+        }
+
+        return $s . $sControls;
+    }
+
+    /**
+     * Generate wiki contents - list of all wiki pages
+     */
+    public function getContents ($sAllExceptSpecified = '', $sOnlySpecified = '')
+    {
+        $aAllExceptSpecified = $sAllExceptSpecified ? explode(',', $sAllExceptSpecified) : array();
+        $aAllExceptSpecified = array_merge($aAllExceptSpecified, ['wiki-pages-list', 'wiki-page-contents']);
+        $aOnlySpecified = $sOnlySpecified ? explode(',', $sOnlySpecified) : array();
+        if (!($a = $this->_oQuery->getPages($aAllExceptSpecified, $aOnlySpecified)))
+            return '';
+
+        $aVars = array('bx_repeat:pages' => array());
+        foreach ($a as $r) {
+            $oPage = BxDolPage::getObjectInstance($r['object']);
+            if (!$oPage->isVisiblePage())
+                continue;
+            $sUrl = $this->getPageUrl($r['uri']);
+            $sTitle = _t($r['title']);
+            $aVars['bx_repeat:pages'][] = array(
+                'url' => $sUrl,
+                'title' => $sTitle ? $sTitle : _t('_Empty'),
+            );
+        }
+        usort($aVars['bx_repeat:pages'], function ($r1, $r2) {
+            return strcmp($r1['title'], $r2['title']);
+        });
+        return BxDolTemplate::getInstance()->parseHtmlByName('wiki_contents.html', $aVars);
+    }
+
+    /**
+     * Generate list of wiki blocks with missing translations for the given language
+     */
+    public function getMissingTranslations ($sLang = false)
+    {
+        if (!$sLang)
+            $sLang = bx_lang_name();
+
+        if (!$this->isAllowed('edit') && !$this->isAllowed('translate') || !preg_match("/^[a-z]+$/", $sLang))
+            return _t('_sys_txt_access_denied');
+
+        if (!BxDolLanguages::getInstance()->getLangId($sLang))
+            return _t('_sys_wiki_error_no_such_lang');
+
+        $a = $this->_oQuery->getBlocksWithMissingTranslations($sLang);
+        if (!$a)
+            return _t('_sys_wiki_no_missing_translations', $sLang);
+
+        $aVars = array(
+            'title_title' => _t('_sys_wiki_title_title'),
+            'title_lang' => _t('_sys_wiki_title_lang_missing'),
+            'title_author' => _t('_sys_wiki_title_author', _t('_sys_wiki_orig')),
+            'title_content' => _t('_sys_wiki_title_content', _t('_sys_wiki_orig')),
+            'title_time' => _t('_sys_wiki_title_time', _t('_sys_wiki_orig')),
+            'bx_repeat:blocks' => array()
+        );
+        foreach ($a as $iBlockId) {
+            $aWikiVerMain = $this->_oQuery->getBlockContent ($iBlockId, false);
+            $aPage = $this->_oQuery->getPageByBlockId($iBlockId);
+            $sUrl = $this->getPageUrl($aPage['uri']) . '#bx-page-wiki-container-' . $iBlockId;
+            $oProfile = BxDolProfile::getInstanceMagic($aWikiVerMain['profile_id']);
+
+            $aVars['bx_repeat:blocks'][] = array(
+                'author_url' => $oProfile->getUrl(),
+                'author_name' => $oProfile->getDisplayName(),
+                'url' => $sUrl,
+                'lang' => $sLang,
+                'title' => _t($aPage['title']),
+                'content' => strmaxtextlen($aWikiVerMain['content']),
+                'timejs' => bx_time_js($aWikiVerMain['added']),
+            );
+        }
+        return BxDolTemplate::getInstance()->parseHtmlByName('wiki_translations_missing.html', $aVars);
+    }
+
+    /**
+     * Generate list of wiki blocks with outdated translations for the given language
+     */
+    public function getOutdatedTranslations ($sLang = false)
+    {
+        if (!$sLang)
+            $sLang = bx_lang_name();
+
+        if (!$this->isAllowed('edit') && !$this->isAllowed('translate') || !preg_match("/^[a-z]+$/", $sLang))
+            return _t('_sys_txt_access_denied');
+
+        if (!BxDolLanguages::getInstance()->getLangId($sLang))
+            return _t('_sys_wiki_error_no_such_lang');
+
+        $aVars = array(
+            'title_title' => _t('_sys_wiki_title_title'),
+            'title_lang' => _t('_sys_wiki_title_lang_outated'),
+            'title_author' => _t('_sys_wiki_title_author', _t('_sys_wiki_orig')),
+            'title_content' => _t('_sys_wiki_title_content', _t('_sys_wiki_orig')),
+            'title_time_main' => _t('_sys_wiki_title_time', _t('_sys_wiki_orig')),
+            'title_time' => _t('_sys_wiki_title_time', '"'.$sLang.'"'),
+            'bx_repeat:blocks' => array()
+        );
+        $a = $this->_oQuery->getBlocksWithOutdatedTranslations($sLang);
+        if (!$a)
+            return _t('_sys_wiki_all_translations_up_to_date', $sLang);
+
+        foreach ($a as $iBlockId) {
+            $aWikiVer = $this->_oQuery->getBlockContent ($iBlockId, $sLang, false, false);
+            $aWikiVerMain = $this->_oQuery->getBlockContent ($iBlockId, false);
+            $aPage = $this->_oQuery->getPageByBlockId($iBlockId);
+            $sUrl = $this->getPageUrl($aPage['uri']) . '#bx-page-wiki-container-' . $iBlockId;
+            $oProfile = BxDolProfile::getInstanceMagic($aWikiVerMain['profile_id']);
+
+            $aVars['bx_repeat:blocks'][] = array(
+                'author_url' => $oProfile->getUrl(),
+                'author_name' => $oProfile->getDisplayName(),
+                'url' => $sUrl,
+                'lang' => $sLang,
+                'title' => _t($aPage['title']),
+                'content' => strmaxtextlen($aWikiVerMain['content']),                
+                'timejs_main' => bx_time_js($aWikiVerMain['added']),
+                'timejs' => bx_time_js($aWikiVer['added']),
+            );
+        }
+        return BxDolTemplate::getInstance()->parseHtmlByName('wiki_translations_outdated.html', $aVars);
+    }
+
+    /**
+     * Check if partucular action is allowed
+     * @param $sType action type: add, edit, delete, translate
+     * @param $sProfileId profile to check, if not provided then current profile is used
+     * @return true if action is allowed, false otherwise
+     */
+    public function isAllowed ($sType, $iProfileId = false)
+    {
+        if ('convert-links' == $sType) {
+            return isLogged();
+        }
+
+        // translate isn't allowed when only one language on the site
+        if ('translate' == $sType) {
+            $aLangs = BxDolLanguages::getInstance()->getLanguages(false, true);
+            if (count($aLangs) < 2)
+                return false;
+        }
+
+        // add page isn't implemented for the system
+        if ('add-page' == $sType && 'system' == $this->_aObject['module'])
+            return false;
+
+        // any action is allowed for admin(operator)
+        if (isAdmin())
+            return true;
+
+        // map 'action' to 'acl action'
+        $aTypes = array(
+            'add-page' => 'add page',
+            'add' => 'add block',
+            'edit' => 'edit block',
+            'translate' => 'translate block',
+            'delete-version' => 'delete version',
+            'delete-block' => 'delete block',
+            'get-traaslation' => 'translate block',
+            'history' => 'history',
+            'unsafe' => 'unsafe',
+        );
+
+        // not listed actions aren't allowed
+        if (!isset($aTypes[$sType]))
+            return false;
+
+        // hardcoded actions (not implemented for now)
+        if (true === $aTypes[$sType] || false === $aTypes[$sType])
+            return $aTypes[$sType];
+
+        // all system actions starts with special prefix
+        $sAction = ('system' == $this->_aObject['module'] ? $this->_sACLprefix : '') . $aTypes[$sType];
+        if (!$iProfileId)
+            $iProfileId = bx_get_logged_profile_id();
+        $aCheck = checkActionModule($iProfileId, $sAction, $this->_aObject['module']);
+        return $aCheck[CHECK_ACTION_RESULT] === CHECK_ACTION_RESULT_ALLOWED;
+    }
+
+    public function addPage ($sPageUri, $sTitleLangKey)
+    {
+        $sUrl = $this->getPageUrl($sPageUri, false, false);
+        return $this->_oQuery->insertPage ($sPageUri, $sUrl, $sTitleLangKey);
+    }
+
+    public function actionGetTranslation ()
+    {
+        $aWikiVer = $this->_oQuery->getBlockContent ((int)bx_get('block_id'), bx_get('language'), false, false);
+        if (!$aWikiVer)
+            return array('code' => 1, 'actions' => 'ShowMsg', 'msg' => 'no translation was found');
+        else
+            return array('code' => 0, 'language' => $aWikiVer['language'], 'content' => $aWikiVer['content'], 'block_id' => $aWikiVer['block_id']);
+    }
+
+    public function actionDeleteVersion ()
+    {
+        $iBlockId = (int)bx_get('block_id');
+        $sLang = bx_lang_name();
+        $oLang = BxDolLanguages::getInstance();
+
+        $aVars = $this->getVarsForHistory($iBlockId, $sLang);
+        $aVars['select_all'] = _t('_Select_all');
+
+        if (!$aVars['bx_repeat:revisions'])
+            return BxDolTemplate::getInstance()->parseHtmlByName('wiki_msg.html', array(
+                'close' => _t('_sys_close'),
+                'msg' => _t('_sys_wiki_error_no_revs'),
+            ));
+
+        $aForm = array(
+            'form_attrs' => array(
+                'name' => 'bx-wiki-del-rev',
+                'method' => 'post',
+            ),
+            'params' => array (
+                'db' => array(
+                    'submit_name' => 'do_submit',
+                ),
+            ),
+            'inputs' => array(
+                'block_id' => array(
+                    'type' => 'hidden',
+                    'name' => 'block_id',
+                    'value' => $iBlockId,
+                ),
+                'language' => array(
+                    'type' => 'hidden',
+                    'name' => 'language',
+                    'value' => $sLang,
+                ),
+                'revision' => array(
+                    'type' => 'custom',
+                    'name' => 'revision',
+                    'caption' => '',
+                    'content' => BxDolTemplate::getInstance()->parseHtmlByName('wiki_delete_version.html', $aVars),
+                ),
+                'buttons' => array(
+                    'type' => 'input_set',
+                    array(
+                        'type' => 'submit',
+                        'name' => 'do_submit',
+                        'value' => _t('_Submit'),
+                    ),
+                    array(
+                        'type' => 'reset',
+                        'name' => 'close',
+                        'value' => _t('_sys_close'),
+                        'attrs' => array(
+                            'onclick' => "$('.bx-popup-applied:visible').dolPopupHide();",
+                            'class' => "bx-def-margin-sec-left",
+                        ),
+                    ),
+                ),
+            ),
+        );
+
+        $oForm = new BxTemplFormView ($aForm);
+        $oForm->initChecker();
+
+        if ($oForm->isSubmittedAndValid ()) {
+            $i = $this->_oQuery->deleteRevisions ($iBlockId, $sLang, bx_get('revision'));
+            return array('code' => 0, 'actions' => array('Reload', 'ClosePopup', 'ShowMsg'), 'block_id' => $iBlockId, 'msg' => _t('_sys_wiki_revisions_deleted', $i));
+        }
+        else {
+            return BxDolTemplate::getInstance()->parseHtmlByName('wiki_form.html', array(
+                'form' => $oForm->getCode(),
+                'block_id' => $iBlockId,
+                'wiki_action_uri' => $this->getUri(),
+                'action' => 'delete-version',
+                'txt_open_editor' => bx_js_string(_t('_sys_wiki_open_in_editor')),
+            ));
+        }
+    }
+
+    public function actionAddPage ()
+    {
+        // validate page URI
+        $sPageUri = strtolower(bx_get('page'));
+        if (!preg_match("/^[a-z0-9_-]+$/", $sPageUri))
+            return _t('_sys_wiki_error_incorrect_page_uri', bx_process_output($sPageUri));
+
+        // check if such page exist
+        $oPage1 = BxDolPage::getObjectInstanceByUri($sPageUri);
+        $oPage2 = BxDolPage::getObjectInstance($this->_aObject['module'] . '_' . str_replace('-', '_', $sPageUri));
+        if ($oPage1 || $oPage2)
+            return _t('_sys_wiki_error_page_exists', bx_process_output($sPageUri));
+
+        // get lang category where translations will be added
+        $oLang = BxDolStudioLanguagesUtils::getInstance();
+        $iLangCat = $oLang->getLanguageCategory($this->_sLangCateg);
+        if (!$iLangCat)
+            return _t('_sys_wiki_error_occured', 9);
+
+        // set default values for the form
+        $aValues = array();
+        $aLangs = $oLang->getLanguages(false, true);
+        foreach ($aLangs as $sKey => $sLang)
+            $aValues[$sKey] = ucfirst($sPageUri);
+
+        // init form
+        $aForm = array(
+            'form_attrs' => array(
+                'name' => 'bx-wiki-create-page',
+                'method' => 'post',
+            ),
+            'params' => array (
+                'db' => array(
+                    'submit_name' => 'do_submit',
+                ),
+            ),
+            'inputs' => array(
+                'page' => array(
+                    'type' => 'hidden',
+                    'name' => 'page',
+                    'value' => $sPageUri,
+                ),
+                'title' => array(
+                    'type' => 'text_translatable',
+                    'name' => 'title',
+                    'caption' => _t('_adm_bp_txt_page_title'),
+                    'info' => _t('_adm_bp_dsc_page_title'),
+                    'value' => '',
+                    'values' => $aValues,
+                    'required' => '1',
+                    'db' => array (
+                        'pass' => 'Xss',
+                    ),
+                    'checker' => array (
+                        'func' => 'LengthTranslatable',
+                        'params' => array(3,100, 'title'),
+                        'error' => _t('_adm_bp_err_page_title'),
+                    ),
+                ),
+                'buttons' => array(
+                    'type' => 'input_set',
+                    array(
+                        'type' => 'submit',
+                        'name' => 'do_submit',
+                        'value' => _t('_Submit'),
+                    ),
+                    array(
+                        'type' => 'reset',
+                        'name' => 'close',
+                        'value' => _t('_sys_close'),
+                        'attrs' => array(
+                            'onclick' => "$('.bx-popup-applied:visible').dolPopupHide();",
+                            'class' => "bx-def-margin-sec-left",
+                        ),
+                    ),
+                ),
+            ),
+        );
+
+        $oForm = new BxTemplStudioFormView ($aForm);
+        $oForm->initChecker();
+
+        if ($oForm->isSubmittedAndValid ()) {
+
+            // insert page
+            $sLangKey = '_' . $this->_aObject['module'] . '_' . str_replace('-', '_', $sPageUri) . '_' . time();
+            $iPageId = $this->addPage ($sPageUri, $sLangKey);
+            if (!$iPageId)
+                return array('code' => 10, 'actions' => array('ShowMsg'), 'msg' => _t('_sys_wiki_error_occured', 10));
+
+            // insert translations
+            $aLangs = $oLang->getLanguages(true, true);
+            foreach ($aLangs as $iLangId => $sLangTitle) {
+                $sLang = $oLang->getLangName($iLangId);
+                if (!($sVal = $oForm->getCleanValue('title-' . $sLang)))
+                    continue;
+                $oLang->addLanguageString($sLangKey, $sVal, $iLangId, $iLangCat);
+            }
+
+            $sUrl = $this->getPageUrl($sPageUri, false, false);
+            return array('code' => 0, 'url' => BxDolPermalinks::getInstance()->permalink($sUrl));
+        }
+        else {
+            // display form
+            return BxDolTemplate::getInstance()->parseHtmlByName('wiki_create_page_form.html', array(
+                'form' => $oForm->getCode(),
+                'wiki_action_uri' => $this->getUri(),
+                'action' => 'add-page',
+            ));
+        }
+    }
+
+    public function actionAdd ()
+    {
+        $iCellId = (int)bx_get('cell_id');
+        $sPage = bx_get('page');
+        $oPage = BxDolPage::getObjectInstance($sPage);
+        if (!$oPage)
+            return array('code' => 4, 'actions' => array('ShowMsg'), 'msg' => _t('_sys_wiki_error_occured', 4));
+
+        if ($this->_aObject['module'] != $oPage->getModule())
+            return array('code' => 5, 'actions' => array('ShowMsg'), 'msg' => _t('_sys_txt_access_denied'));
+
+        $iDesignBox = getParam($this->_aObject['module'] . '_design_box');
+        $aBlock = array(
+            'object' => $sPage,
+            'cell_id' => $iCellId,
+            'module' => $this->_aObject['module'],
+            'title_system' => '',
+            'title' => '',
+            'designbox_id' => false === $iDesignBox ? 0 : $iDesignBox,
+            'visible_for_levels' => 2147483647, 
+            'type' => 'wiki',
+            'deletable' => 1,
+            'copyable' => 0,
+            'active' => 1,
+        );
+        $oQueryPageBuilder = new BxDolStudioBuilderPageQuery();
+        if (!($iBlockId = $oQueryPageBuilder->insertBlock($aBlock)))
+            return array('code' => 6, 'actions' => array('ShowMsg'), 'msg' => _t('_sys_wiki_error_occured', 6));
+
+        return array('code' => 0, 'block_id' => $iBlockId, 'cell_id' => $iCellId);
+    }
+
+    public function actionDeleteBlock ()
+    {
+        $iBlockId = (int)bx_get('block_id');
+
+        $oQueryPageBuilder = new BxDolStudioBuilderPageQuery();
+        if (!$oQueryPageBuilder->deleteBlocks(array('type' => 'by_id', 'value' => $iBlockId)))
+            return array('code' => 3, 'actions' => array('ShowMsg'), 'block_id' => $iBlockId, 'msg' => _t('_sys_wiki_error_occured', 3));
+
+        self::onBlockDelete($iBlockId);
+
+        return array('code' => 0, 'actions' => array('DeleteBlock', 'ShowMsg'), 'block_id' => $iBlockId, 'msg' => _t('_sys_wiki_block_deleted'));
+    }
+    public function actionHistory ()
+    {
+        $iBlockId = (int)bx_get('block_id');
+        $sLang = bx_lang_name();
+        $oLang = BxDolLanguages::getInstance();
+
+        $aVars = $this->getVarsForHistory($iBlockId, $sLang);
+        $aVars['language'] = $oLang->getLangTitle($oLang->getLangId($sLang));
+        $aVars['close'] = _t('_sys_close');
+        $aVars['msg'] = $aVars['bx_repeat:revisions'] ? '' : _t('_sys_wiki_error_no_revs');
+        return BxDolTemplate::getInstance()->parseHtmlByName('wiki_history.html', $aVars);
+    }
+
+    public function actionTranslate ()
+    {
+        return $this->actionEdit (true);
+    }
+
+    public function actionEdit ($bTranslate = false)
+    {
+        $iBlockId = (int)bx_get('block_id');
+        $sMainLangLabel = '';
+        $aWikiVerMain = array();
+        $sLangForTranslate = '';
+        $aLangsForInput = $this->getLangsForInput ($iBlockId, $bTranslate, $sMainLangLabel, $aWikiVerMain, $sLangForTranslate);
+
+        // don't allow to translate empty blocks
+        if (!$aWikiVerMain && $bTranslate)
+            return BxDolTemplate::getInstance()->parseHtmlByName('wiki_msg.html', array(
+                'close' => _t('_sys_close'),
+                'msg' => _t('_sys_wiki_error_no_revs'),
+            ));
+
+        // get latest revision for block with current lang
+        if ($bTranslate) {
+            $aWikiVer = $this->_oQuery->getBlockContent ($iBlockId, $sLangForTranslate, false, false);
+        }
+        else {
+            $aWikiVer = $this->_oQuery->getBlockContent ($iBlockId, bx_lang_name());
+        }
+
+        if ($aWikiVer) // unset notes since we need this field empty in the form
+            unset($aWikiVer['notes']);
+
+        if (!$aWikiVer) { // check for new block, so initialize with default values
+            $aWikiVer = array('block_id' => $iBlockId);
+            if ($bTranslate)
+                $aWikiVer['language'] = $sLangForTranslate;
+            else
+                $aWikiVer['language'] = bx_lang_name();
+        }
+
+        // init form object
+        $oForm = BxDolForm::getObjectInstance('sys_wiki', $bTranslate ? 'sys_wiki_translate' : 'sys_wiki_edit');
+        if (!$oForm)
+            return _t('_sys_wiki_error_occured', 12);
+
+        if (isset($oForm->aInputs['language']))
+            $oForm->aInputs['language']['values'] = $aLangsForInput;
+        if (isset($oForm->aInputs['content_main']) && $sMainLangLabel) {
+            $oForm->aInputs['content_main']['caption'] = $sMainLangLabel;
+            $oForm->aInputs['content_main']['content'] = $aWikiVerMain ? BxDolTemplate::getInstance()->parseHtmlByName('wiki_content.html', array('content' => $aWikiVerMain['content'])) : '';
+        }
+
+        $oForm->initChecker($aWikiVer);
+        if (!$oForm->isSubmittedAndValid()) {
+            // display form
+            return BxDolTemplate::getInstance()->parseHtmlByName('wiki_form.html', array(
+                'form' => $oForm->getCode(),
+                'block_id' => $iBlockId,
+                'wiki_action_uri' => $this->getUri(),
+                'action' => $bTranslate ? 'translate' : 'edit',
+                'txt_open_editor' => bx_js_string(_t('_sys_wiki_open_in_editor')),
+            ));
+        } 
+        else {
+            $sLang = $oForm->getCleanValue('language');
+
+            // get previous revision with priority for current language
+            $aWikiVer = $this->_oQuery->getBlockContent ($iBlockId, $sLang);
+
+            $bMainLang = $this->getFieldMainLangFlag ($oForm, $sLang, $aWikiVer);
+            $sRev = $this->getFieldRev ($oForm, $sLang, $aWikiVer);
+            $bUnsafe = $this->getFieldUnsafeFlag ($oForm, $sLang, $aWikiVer);
+
+            // insert new revision (main lang is NOT allowed for translations)
+            $iTime = time();
+            if ((!$bMainLang || ($bMainLang && $this->isAllowed('edit'))) && $this->isContentChanged($iBlockId, $sLang, $oForm->getCleanValue('content'))) {
+                $sId = $oForm->insert(array(
+                    'added' => $iTime, 
+                    'revision' => $sRev,
+                    'main_lang' => $bMainLang, 
+                    'profile_id' => bx_get_logged_profile_id(),
+                    'unsafe' => $bUnsafe,
+                ));
+            }
+
+            // process translations if available
+            if (($sTranslations = bx_get('translations')) && ($aTranslations = json_decode($sTranslations, true))) {
+                foreach ($aTranslations as $sLang => $sContent) {
+                    if ($sLang == $oForm->getCleanValue('language'))
+                        continue;
+
+                    // get previous revision with priority for current language
+                    $aWikiVer = $this->_oQuery->getBlockContent ($iBlockId, $sLang);
+
+                    $bMainLang = $this->getFieldMainLangFlag ($oForm, $sLang, $aWikiVer);
+                    $sRev = $this->getFieldRev ($oForm, $sLang, $aWikiVer);
+                    $bUnsafe = $this->getFieldUnsafeFlag ($oForm, $sLang, $aWikiVer);
+
+                    // insert new revision (main lang is NOT allowed for translations)
+                    if ((!$bMainLang || ($bMainLang && $this->isAllowed('edit'))) && $this->isContentChanged($iBlockId, $sLang, $sContent)) {
+                        $sId =  $oForm->insert(array(
+                            'added' => $iTime, 
+                            'revision' => $sRev,
+                            'main_lang' => $bMainLang, 
+                            'profile_id' => bx_get_logged_profile_id(),
+                            'unsafe' => $bUnsafe,
+                            'language' => $sLang,
+                            'content' => $sContent,
+                        ));
+                    }
+                }
+            }
+
+            // update indexing data
+            $this->updateBlockIndexingData($iBlockId);
+
+            return array('code' => 0, 'actions' => array('Reload', 'ClosePopup'), 'block_id' => $iBlockId);
+        }
+    }
+
+    public function actionConvertLinks ()
+    {
+        $s = bx_get('s');
+        if (!$s)
+            return ['s' => ''];
+
+        // convert links to be viewable in external editor
+        $s = preg_replace_callback('#\((([a-zA-Z0-9_]+)/([a-zA-Z0-9]+))\)#', function ($aMatches) {
+            $oStorage = BxDolStorage::getObjectInstance($aMatches[2]);
+            if ($oStorage) {
+                $sUrl = $oStorage->getFileUrlByRemoteId($aMatches[3]);
+                if ($sUrl)
+                    return '(' . $sUrl . ')';
+            }
+
+            return '(' . $aMatches[0] . ')';
+        }, $s);
+
+        // add references to existing pages, so short references will work in external editor
+        $s .= "\n<!-- " . _t("_sys_wiki_external_editor_references_comment") . " -->\n";
+
+        $this->_aPages = $this->_oQuery->getAllPages ();
+        if ($this->_aPages) {
+            foreach ($this->_aPages as $sUri => $r)
+                $s .= "[{$sUri}]: " . BX_DOL_URL_ROOT . BxDolPermalinks::getInstance()->permalink($r['url']) . "\n";
+        }        
+
+        return ['s' => $s];
+    }
+
+    public function updateBlockIndexingData($iBlockId)
+    {
+        if (!($aLangs = $this->_oQuery->getBlockLangs ($iBlockId)))
+            return false;
+        $sText = '';
+        foreach ($aLangs as $sLang) {
+            $aWikiVer = $this->_oQuery->getBlockContent ($iBlockId, $sLang, false, false);
+            $sText .= trim(strip_tags($aWikiVer['content'])) . ' ';
+        }
+        return $this->_oQuery->updateBlockIndexingData ($iBlockId, $sText);
+    }
+
+    protected function getPageUrl ($sPageUri, $bPermalink = true, $bAddRootUrl = true)
+    {
+        $sUrl = ($bAddRootUrl ? BX_DOL_URL_ROOT : '') . 'r.php?_q=' . $this->_aObject['uri'] . '/' . $sPageUri;
+        return $bPermalink ? BxDolPermalinks::getInstance()->permalink($sUrl) : $sUrl;
+    }
+
+    protected function isContentChanged ($iBlockId, $sLang, $sContent)
+    {
+        if (!$sContent) // don't allow revisions with empty content
+            return false;
+
+        $aWikiVer = $this->_oQuery->getBlockContent ($iBlockId, $sLang, false, false);
+        if (!$aWikiVer) // when no previous revision available
+            return true;
+
+        return $sContent != $aWikiVer['content'];
+    }
+
+    protected function getFieldRev ($oForm, $sLang, $aWikiVer) {
+        // increase revision for particular language or start with first revision
+        return $aWikiVer && $sLang == $aWikiVer['language'] ? $aWikiVer['revision'] + 1 : 1;
+    }
+
+    protected function getFieldMainLangFlag ($oForm, $sLang, $aWikiVer) {
+        // detect main language flag
+        if ($aWikiVer && $sLang == $aWikiVer['language']) 
+            return $aWikiVer['main_lang']; // when revision is increased (language matches) - copy this flag from previous revision
+        elseif (!$aWikiVer) 
+            return 1; // when it's first revision and no translations - start as main language
+        else
+            return 0;
+    }
+
+    protected function getFieldUnsafeFlag ($oForm, $sLang, $aWikiVer) {
+
+        if ($aWikiVer && $sLang == $aWikiVer['language'] && !$aWikiVer['unsafe'])
+            return 0; // copy 'unsafe' from previous revision only when unsafe = 0
+        else
+            return $this->isAllowed('unsafe') ? 1 : 0; // in other cases - check permissions
+    }
+
+    protected function getLangsForInput ($iBlockId, $bTranslateForm, &$sMainLangLabel, &$aWikiVerMain, &$sLangForTranslate)
+    {
+        // get main lang update time
+        $aWikiVerMain = $this->_oQuery->getBlockContent ($iBlockId, 'neverhood');
+        $iUpdatedMainLang = $aWikiVerMain ? $aWikiVerMain['added'] : 0;
+
+        // generate values for radio set
+        $aLangs = BxDolLanguages::getInstance()->getLanguages(false, true);
+        foreach ($aLangs as $sKey => $sLang) {
+            $aWikiVer = $this->_oQuery->getBlockContent ($iBlockId, $sKey, false, false);
+
+            $bMainLang = $aWikiVer && $aWikiVer['main_lang'];
+            $sMainLang = $bMainLang ? '★' : '';
+
+            $sComment = !$aWikiVer ? _t('_sys_wiki_lang_missing') : bx_time_js($aWikiVer['added']);
+            if(!$aWikiVer || $iUpdatedMainLang > $aWikiVer['added'])
+                $aLangs[$sKey] = _t('_sys_wiki_lang_mask_warn', $sLang, $sMainLang, $sComment);
+            else
+                $aLangs[$sKey] = _t('_sys_wiki_lang_mask', $sLang, $sMainLang, $sComment);
+
+            if($bTranslateForm) {
+                if(!$bMainLang && !$sLangForTranslate)
+                    $sLangForTranslate = $sKey;
+
+                if($bMainLang) {
+                    $sMainLangLabel = $aLangs[$sKey];
+                    unset($aLangs[$sKey]);
+                    continue;
+                }
+            }
+        }
+
+        return $aLangs;
+    }    
+
+    public function getVarsForHistory ($iBlockId, $sLang)
+    {
+        $a = $this->_oQuery->getBlockHistory($iBlockId, $sLang);
+
+        $aVars = array(
+            'bx_repeat:revisions' => array()
+        );
+        foreach ($a as $r) {
+            $oProfile = BxDolProfile::getInstanceMagic($r['profile_id']);
+            list($sPageLink, $aPageParams) = bx_get_base_url_popup(array($r['block_id'].'rev' => $r['revision']));
+            $r['author_url'] = $oProfile->getUrl();
+            $r['author_name'] = $oProfile->getDisplayName();
+            $r['timejs'] = bx_time_js($r['added']);
+            $r['rev_url'] = BxDolPermalinks::getInstance()->permalink(bx_append_url_params($sPageLink, $aPageParams));
+            $aVars['bx_repeat:revisions'][] = $r;
+        }
+        return $aVars;
+    }
+}
+
+class BxDolParsedown extends Parsedown
+{
+    protected $_aPages;
+
+    protected function textElements($text)
+    {
+        $res = parent::textElements($text);
+
+        // add all available pages as references
+        $this->_aPages = BxDolWikiQuery::getAllPages ();
+        if ($this->_aPages) {
+            foreach ($this->_aPages as $sUri => $r) {
+                $aData = array(
+                    // real link URL is set later when link is referenced
+                    'url' => 'bx-internal-page://' . $sUri, 
+                    'title' => !empty($r['title']) ? _t($r['title']) : null,
+                );
+                $this->DefinitionData['Reference'][$sUri] = $aData;
+            }
+        }
+
+        return $res;
+    }
+
+    protected function inlineLink($Excerpt)
+    {
+        $a = parent::inlineLink($Excerpt);
+
+        if ($a && @isset($a['element']['attributes']['href']) && 0 === strncmp($a['element']['attributes']['href'], 'bx-internal-page://', 19)) {
+            $sUri = strtolower(substr($a['element']['attributes']['href'], 19));
+            if (isset($this->_aPages[$sUri])) {
+                $sHref = BX_DOL_URL_ROOT . BxDolPermalinks::getInstance()->permalink($this->_aPages[$sUri]['url']);
+                $a['element']['attributes']['href'] = $sHref;
+            }
+            else {
+                $a['element']['attributes']['href'] = $sUri;
+            }
+        }
+
+        if ($a && @isset($a['element']['attributes']['title']) && '#' === $a['element']['attributes']['title']) {
+            $a['element']['attributes']['class'] = 'bx-def-font-grayed';
+        }
+
+        return $a;
+    }
+
+    protected function inlineImage($Excerpt)
+    {
+        $a = parent::inlineImage($Excerpt);
+
+        if (@isset($a['element']['attributes']['src']) && preg_match('#^([a-zA-Z0-9_]+)/([a-zA-Z0-9]+)$#', $a['element']['attributes']['src'], $aMatches) && is_array($aMatches) && 3 == count($aMatches)) {
+
+            $oStorage = BxDolStorage::getObjectInstance($aMatches[1]);
+            if ($oStorage) {
+                $sUrl = $oStorage->getFileUrlByRemoteId($aMatches[2]);
+                if ($sUrl)
+                    $a['element']['attributes']['src'] = $sUrl;
+            }
+        }
+        return $a;
+    }
+
+	protected function blockHeader($Excerpt) {
+		$a = parent::blockHeader($Excerpt);
+
+		if (isset($a)) {
+			$sText = trim($a['element']['handler']['argument'], '#');
+			$sText = trim($sText, ' ');
+			$sLink = preg_replace('/[^\p{L}\p{N}\p{M}-]+/u', '', mb_strtolower(mb_ereg_replace(' ','-', $sText)));
+			$aAttr = array();
+
+			if (!empty($sLink)) {
+				$aAttr = isset($a['element']['attributes']) ? $a['element']['attributes'] : [];
+				$aAttr['id'] = $sLink;
+
+				$aHandler = array(
+					'function' => 'lineElements',
+					'argument' => $sText . (isset($_SERVER['REQUEST_URI']) ? ' [](' . bx_get_self_url() . '#' . $sLink . ' "#")' : ''),
+					'destination' => 'elements',
+				);
+
+				$a['element']['attributes'] = $aAttr;
+				$a['element']['handler'] = $aHandler;
+			}
+		} 
+        else {
+			$a = null;
+		}
+
+        return $a;
+	}
+}
+
+/** @} */

+ 998 - 0
upgrade/files/15.0.0.B3-15.0.0.RC1/files/inc/js/classes/BxDolCmts.js

@@ -0,0 +1,998 @@
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    UnaCore UNA Core
+ * @{
+ */
+
+function BxDolCmts (options) {
+    this._sObjName = undefined == options.sObjName ? 'oCmts' : options.sObjName;    // javascript object name, to run current object instance from onTimer
+    this._sActionsUrl = options.sRootUrl + 'cmts.php'; // actions url address
+
+    this._sSystem = options.sSystem; // current comment system
+    this._iAuthorId = options.iAuthorId; // this comment's author ID.
+    this._iObjId = options.iObjId; // this object id comments
+    this._sBaseUrl = options.sBaseUrl; // base url to view comment's listing.
+    this._sSocket = options.sSocket === undefined ? this._sSystem : options.sSocket;
+
+    this._iMinPostForm = undefined == options.iMinPostForm ? 0 : options.iMinPostForm;
+    this._sPostFormPosition = undefined == options.sPostFormPosition ? 'top' : options.sPostFormPosition;
+    this._sDisplayType = undefined == options.sDisplayType ? 'threaded' : options.sDisplayType;
+    this._iDisplayStructure = undefined == options.iDisplayStructure ? 0 : options.iDisplayStructure;
+
+    this._sBrowseType = undefined == options.sBrowseType ? 'tail' : options.sBrowseType;
+    this._sBrowseFilter = undefined == options.sBrowseFilter ? 'all' : options.sBrowseFilter;
+
+    this._sSP = options.sStylePrefix === undefined ? 'cmt' : options.sStylePrefix;
+    this._aParams = options.aParams === undefined ? false : options.aParams;
+    this._aHtmlIds = options.aHtmlIds;
+    this._sAnimationEffect = 'fade';
+    this._iAnimationSpeed = 'slow';
+
+    this._oSavedTexts = {};
+    this._sRootId = '#cmts-box-' + this._sSystem + '-' + this._iObjId;
+
+    this._bLiveUpdatePaused = false;
+}
+
+/*--- Main layout functionality ---*/
+BxDolCmts.prototype.cmtInit = function()
+{
+    var $this = this;
+
+    $(document).ready(function() {
+        // init socket
+        if(window.oBxDolSockets !== undefined && $this._sSocket)
+            oBxDolSockets.subscribe($this._sSocket, $this._iObjId, 'comment_added', function(oData) {
+                $this.cmtUpdateCounterAs(oData);
+                $this.showLiveUpdateForSocket(oData);
+            });
+
+        // init post comment form    
+        var sFormId = $this._sRootId + ' .cmt-post-reply form';
+        if ($(sFormId).length) {
+            $(sFormId).each(function() {
+                $this.cmtInitFormPost($(this));
+            });
+        }
+
+        // blink (highlight) necessary comments
+        $this._cmtsBlink($($this._sRootId));
+
+        // check content to show 'See More'
+        $this._cmtsInitSeeMore($($this._sRootId));
+
+        // init gallery
+        $this._cmtsInitGallery($($this._sRootId));
+    });
+};
+
+BxDolCmts.prototype.cmtInitFormPost = function(oCmtForm)
+{
+    var $this = this;
+
+    oCmtForm.ajaxForm({
+        dataType: "json",
+        beforeSubmit: function (formData, jqForm, options) {
+            window[$this._sObjName].cmtBeforePostSubmit(oCmtForm);
+        },
+        success: function (oData) {
+            window[$this._sObjName].cmtAfterPostSubmit(oCmtForm, oData);
+        }
+    });
+};
+
+BxDolCmts.prototype.cmtShowForm = function(oElement)
+{
+    var oForm = $(oElement).parents('.cmt-reply.cmt-reply-min:first');
+    oForm.find('.cmt-body-min').bx_anim('hide', this._sAnimationEffect, this._iAnimationSpeed, function() {
+        oForm.find('.cmt-body').show(function() {
+            var oTextarea = oForm.find("[name='cmt_text']");
+            if(oTextarea && oTextarea.hasClass('bx-form-input-html') && typeof bx_editor_get_htmleditable === 'function')
+                oTextarea = bx_editor_get_htmleditable(oTextarea);
+
+            if(!oTextarea || oTextarea.length == 0)
+                return;
+            
+            if (oTextarea.attr('object_editor'))
+                eval('bx_editor_activate(' + oTextarea.attr('object_editor') + ')');
+            else
+                oTextarea.focus();
+        });
+    });
+};
+
+BxDolCmts.prototype.cmtBeforePostSubmit = function(oCmtForm)
+{
+    this._loadingInButton($(oCmtForm).children().find(':submit'), true);
+};
+
+BxDolCmts.prototype.cmtAfterPostSubmit = function (oCmtForm, oData)
+{
+    var $this = this;
+    var fContinue = function() {
+        var oParent = oCmtForm.parents('.cmt-reply:first');
+
+        if(oData && oData.id != undefined) {
+            $this._getCmt(oCmtForm, oData.id);
+
+            //--- Update form
+            var iCmtParentId = parseInt(oData.parent_id);
+            if(iCmtParentId == 0)
+                $this._getForm(undefined, {CmtParent: iCmtParentId}, function(sFormWrp) {
+                    if(sFormWrp && sFormWrp.length > 0)
+                        sFormWrp = $(sFormWrp).html();
+
+                    oParent.hide().html(sFormWrp).bxProcessHtml().show();
+
+                    $this.cmtInitFormPost(oParent.find('form'));
+                });
+            else
+                oParent.remove();
+
+            //--- Update counter
+            $this.cmtUpdateCounter(oCmtForm, oData);
+
+            return;
+        }
+
+        if(oData && oData.form != undefined && oData.form_id != undefined) {
+            oParent.find('form').replaceWith(oData.form);
+
+            $this.cmtInitFormPost(oParent.find('form'));
+
+            return;
+        }
+    };
+
+    this._loadingInButton($(oCmtForm).children().find(':submit'), false);
+
+    if(oData && oData.msg != undefined)
+        bx_alert(oData.msg, fContinue);
+    else 
+        fContinue();
+};
+
+BxDolCmts.prototype.cmtInitFormEdit = function(sCmtFormId)
+{
+	var $this = this;
+	var oCmtForm = $('#' + sCmtFormId);
+
+	oCmtForm.ajaxForm({
+        dataType: "json",
+        beforeSubmit: function (formData, jqForm, options) {
+            window[$this._sObjName].cmtBeforeEditSubmit(oCmtForm);
+        },
+        success: function (oData) {
+            window[$this._sObjName].cmtAfterEditSubmit(oCmtForm, oData);
+        }
+    });
+};
+
+BxDolCmts.prototype.cmtBeforeEditSubmit = function(oCmtForm)
+{
+    this._loadingInButton($(oCmtForm).children().find(':submit'), true);
+};
+
+BxDolCmts.prototype.cmtAfterEditSubmit = function (oCmtForm, oData, onComplete)
+{
+    var $this = this;
+    var fContinue = function() {
+        if(oData && oData.id != undefined && oData.content != undefined) {
+            var iCmtId = parseInt(oData.id);
+            if(iCmtId > 0) {
+                $('#cmt' + iCmtId + ' .cmt-cont-cnt:first').bx_anim('hide', $this._sAnimationEffect, $this._iAnimationSpeed, function() {
+                    $(this).html(oData.content).bxProcessHtml().bx_anim('show', $this._sAnimationEffect, $this._iAnimationSpeed);
+                });
+            }
+        }
+
+        if(oData && oData.form != undefined && oData.form_id != undefined) {
+            $('#' + oData.form_id).replaceWith(oData.form);
+            $this.cmtInitFormEdit(oData.form_id);
+        }
+
+        if(typeof onComplete == 'function')
+            onComplete(oCmtForm, oData);
+    };
+
+    this._loadingInButton($(oCmtForm).children().find(':submit'), false);
+
+    if(oData && oData.msg != undefined)
+        bx_alert(oData.msg, fContinue);
+    else 
+        fContinue();
+};
+
+BxDolCmts.prototype.cmtUpdateCounter = function (oElement, oData)
+{
+    if(oData && (oData.count == undefined || parseInt(oData.count) == 0))
+        return;
+
+    if(oData.countf != undefined && oData.countf.length != 0) {
+        var oCounter = this._getCounter(oElement);
+        if(oCounter && oCounter.length > 0)
+            oCounter.replaceWith(oData.countf);
+    }
+
+    var oCounter = this._getCounter(oElement, true);
+    if(oCounter && oCounter.length > 0)
+        oCounter.html(oData.count);
+
+    var sClassHidden = 'sys-ac-hidden';
+    if(!oCounter.is('.' + sClassHidden))
+        oCounter = oCounter.parents('.' + sClassHidden + ':first');
+
+    oCounter.toggleClass(sClassHidden);
+};
+
+BxDolCmts.prototype.cmtUpdateCounterAs = function (oData)
+{
+    this.cmtUpdateCounter(null, JSON.parse(oData));
+};
+
+BxDolCmts.prototype.cmtPin = function(oLink, iCmtId, iWay, bHideMenu) {
+    var $this = this;
+
+    if(bHideMenu == undefined || bHideMenu)
+        $(oLink).parents('.bx-popup-applied:first:visible').dolPopupHide();
+
+    var oParams = this._getDefaultActions();
+    oParams['action'] = 'Pin';
+    oParams['Cmt'] = iCmtId;
+    oParams['way'] = iWay;
+
+    var oCmt = $(this._sRootId + ' #cmt' + iCmtId);
+    this._loadingInBlock(oCmt, true);
+
+    jQuery.post (
+        this._sActionsUrl,
+        oParams,
+        function (oData) {
+            var fContinue = function() {
+                if(oData && oData.parent_id != undefined) {
+                    $this._getCmts(oLink, {
+                        CmtParent: oData.parent_id,
+                        CmtBrowse: $this._sBrowseType,
+                        CmtFilter: $this._sBrowseFilter,
+                        CmtDisplay: $this._sDisplayType,
+                        CmtPinned: 1
+                    }, function(sListId, sContent) {
+                        $this._loadingInBlock(oCmt, false);
+
+                        $this._sDisplayType = $this._sDisplayType;
+                        $this._cmtsReplaceContent($(sListId), sContent);
+
+                        var oDivider = $(sListId).siblings('.cmts-divider');
+                        if(oDivider.length > 0) {
+                            if(oDivider.is(':hidden') && sContent.length != 0)
+                                oDivider.show();
+                            else if(!oDivider.is(':hidden') && sContent.length == 0)
+                                oDivider.hide();
+                        }
+                    });
+            	}
+            };
+
+            if(oData && oData.msg != undefined)
+                bx_alert(oData.msg, fContinue);
+            else
+                fContinue();
+        },
+        'json'
+    );
+};
+
+BxDolCmts.prototype.cmtEdit = function(oLink, iCmtId, bHideMenu) {
+    var $this = this;
+
+    if(bHideMenu == undefined || bHideMenu)
+        $(oLink).parents('.bx-popup-applied:first:visible').dolPopupHide();
+
+    var sContentId = this._sRootId + ' #cmt' + iCmtId + ' .cmt-cont-cnt:first';
+    if ($(sContentId + ' > form').length) {
+        $(sContentId).bx_anim('hide', $this._sAnimationEffect, $this._iAnimationSpeed, function() {
+            $(this).html($this._oSavedTexts[iCmtId]).bxProcessHtml().bx_anim('show', $this._sAnimationEffect, $this._iAnimationSpeed);
+        });
+
+        return;
+    }
+
+    var oParams = this._getDefaultActions();
+    oParams['action'] = 'GetFormEdit';
+    oParams['Cmt'] = iCmtId;
+
+    this._oSavedTexts[iCmtId] = $(sContentId).html();
+
+    this._loadingInContent(oLink, true);
+
+    jQuery.post (
+        this._sActionsUrl,
+        oParams,
+        function (oData) {
+            var fContinue = function() {
+                if(oData && oData.form != undefined && oData.form_id != undefined) {
+                    $(sContentId).bx_anim('hide', $this._sAnimationEffect, $this._iAnimationSpeed, function() {
+                        $(this).html(oData.form).bxProcessHtml().bx_anim('show', $this._sAnimationEffect, $this._iAnimationSpeed, function() {
+                            $this.cmtInitFormEdit(oData.form_id);
+                        });
+                    });
+            	}
+            };
+
+            $this._loadingInContent(oLink, false);
+
+            if(oData && oData.msg != undefined)
+                bx_alert(oData.msg, fContinue);
+            else
+                fContinue();
+        },
+        'json'
+    );
+};
+
+BxDolCmts.prototype.cmtRemove = function(e, iCmtId) {
+	var $this = this;
+
+	$(e).parents('.bx-popup-active:first').dolPopupHide();
+
+	bx_confirm('', function() {
+	    var oParams = $this._getDefaultActions();
+	    oParams['action'] = 'Remove';
+	    oParams['Cmt'] = iCmtId;
+
+	    $this._loadingInContent(e, true);
+
+	    jQuery.post (
+	        $this._sActionsUrl,
+	        oParams,
+	        function(oData) {
+	            var fContinue = function() {
+	            	if(oData && oData.id != undefined) {
+                            $(e).parents('.bx-popup-applied:first:visible').dolPopupHide();
+
+                            var fDelete = function() {
+                                var sCmtSel = '#cmt' + oData.id;
+
+                                $(sCmtSel).bx_anim('hide', $this._sAnimationEffect, $this._iAnimationSpeed, function() {
+                                    //--- Update counter
+                                    if(oData && oData.count != undefined && parseInt(oData.count) >= 0) {
+                                        var oSource = $(this);
+
+                                        var oCounter = $this._getCounter(oSource);
+                                        if(oCounter && oCounter.length > 0) {
+                                            if(oData.countf != undefined && oData.countf.length != 0)
+                                                oCounter.html(oData.countf);
+
+                                            if(parseInt(oData.count) == 0)
+                                                oCounter.toggleClass('sys-ac-hidden');
+                                        }
+
+                                        var oCounter = $this._getCounter(oSource, true);
+                                        if(oCounter && oCounter.length > 0)
+                                            oCounter.html(oData.count);
+                                    }
+
+                                    $(this).remove();
+
+                                    var oCmt = $(sCmtSel);
+                                    if(oCmt && oCmt.length > 0)
+                                        fDelete();
+                                });
+                            };
+
+                            fDelete();
+                        }
+	            };
+
+	            $this._loadingInContent(e, false);
+
+	            if(oData && oData.msg != undefined)
+	                bx_alert(oData.msg, fContinue);	            
+	            else
+	            	fContinue();
+	        },
+	        'json'
+	    );
+	});
+};
+
+BxDolCmts.prototype.cmtLoad = function(oLink, iCmtParentId, iStart, iPerView)
+{
+	var $this = this;
+	var bButton = $(oLink).hasClass('bx-btn');
+
+	if(bButton)
+		this._loadingInButton(oLink, true);
+	else 
+		this._loading($(oLink).parents('ul.cmts:first'), true);
+
+	this._getCmts(oLink, {
+		CmtParent: iCmtParentId,
+		CmtStart: iStart,
+		CmtPerView: iPerView,
+		CmtBrowse: this._sBrowseType,
+		CmtFilter: this._sBrowseFilter,
+		CmtDisplay: this._sDisplayType,
+                CmtDisplayStructure: this._iDisplayStructure
+	}, function(sListId, sContent) {
+		if(bButton)
+			$this._loadingInButton(oLink, false);
+		else 
+			$this._loading($(oLink).parents('ul.cmts:first'), false);
+
+		$this._cmtsReplace($(oLink).parents('li:first'), sContent);
+	});
+};
+
+BxDolCmts.prototype.cmtChangeDisplay = function(oLink, sType)
+{
+	var $this = this;
+	this._getCmts(oLink, {
+		CmtParent: 0,
+		CmtBrowse: this._sBrowseType,
+		CmtFilter: this._sBrowseFilter,
+		CmtDisplay: sType
+	}, function(sListId, sContent) {
+		$this._sDisplayType = sType;
+		$this._cmtsReplaceContent($(sListId), sContent);
+	});
+};
+
+BxDolCmts.prototype.cmtChangeBrowse = function(oLink, sType)
+{
+	var $this = this;
+	this._getCmts(oLink, {
+		CmtParent: 0,
+		CmtBrowse: sType,
+		CmtFilter: this._sBrowseFilter,
+		CmtDisplay: this._sDisplayType
+	}, function(sListId, sContent) {
+		$this._sBrowseType = sType;
+		$this._cmtsReplaceContent($(sListId), sContent);
+	});
+};
+
+BxDolCmts.prototype.cmtChangeFilter = function(oLink, sType)
+{
+	var $this = this;
+	this._getCmts(oLink, {
+		CmtParent: 0,
+		CmtBrowse: this._sBrowseType,
+		CmtFilter: sType,
+		CmtDisplay: this._sDisplayType
+	}, function(sListId, sContent) {
+		$this._sBrowseFilter = sType;
+		$this._cmtsReplaceContent($(sListId), sContent);
+	});
+};
+
+BxDolCmts.prototype.showReplacement = function(iCmtId)
+{
+    $('#cmt' + iCmtId + '-hidden').bx_anim('hide', this._sAnimationEffect, this._iAnimationSpeed, function(){
+        $(this).next('#cmt' + iCmtId).bx_anim('show', this._sAnimationEffect, this._iAnimationSpeed);
+    });
+};
+
+BxDolCmts.prototype.toggleReply = function(oElement, iCmtParentId, iQuote)
+{
+    var $this = this;
+    var aParams = {
+        CmtParent: iCmtParentId,
+        CmtQuote: iQuote != undefined ? parseInt(iQuote) : 0
+    };
+    var fOnShow = function() {
+        $(this).find('textarea:first').focus();
+    };
+
+    var oParentId = null;
+    if(oElement)
+        oParentId = $(oElement).parents('#cmt' + iCmtParentId);
+    else
+        oParentId = $(this._sRootId + ' #cmt' + iCmtParentId);
+
+    var sReplyQuoteId = '.cmt-reply-quote';
+    var sReplyQuoteIdOpst = ':not(' + sReplyQuoteId + ')';
+
+    var sReplyId = '';
+    var sReplyIdOpst = '';
+    if(aParams['CmtQuote']) {
+        sReplyId = '.cmt-reply' + sReplyQuoteId;
+        sReplyIdOpst = '.cmt-reply' + sReplyQuoteIdOpst;
+    }
+    else {
+        sReplyId = '.cmt-reply' + sReplyQuoteIdOpst;
+        sReplyIdOpst = '.cmt-reply' + sReplyQuoteId;
+    }
+
+    //--- Hide opposite form.
+    if (oParentId.find('> ' + sReplyIdOpst + ':visible').length)
+        oParentId.find('> ' + sReplyIdOpst).hide();
+
+    if (oParentId.find('> ' + sReplyId).length) {
+        oParentId.find('> ' + sReplyId).bx_anim('toggle', this._sAnimationEffect, this._iAnimationSpeed, fOnShow);
+        return;
+    }
+
+    this._getForm(oElement, aParams, function(sForm) {
+        var oForm = $(sForm).hide().addClass('cmt-reply-' + $this._sPostFormPosition).addClass('cmt-reply-margin');
+        var oFormSibling = oParentId.find('> ul.cmts:first');
+        switch($this._sPostFormPosition) {
+            case 'top':
+                oFormSibling.before(oForm);
+                break;
+
+            case 'bottom':
+                oFormSibling.after(oForm);
+                break;
+        }
+
+        $this.cmtInitFormPost(oForm.find('form'));
+
+        oParentId.children(sReplyId).bx_anim('toggle', $this._sAnimationEffect, $this._iAnimationSpeed, fOnShow);
+    });
+};
+
+BxDolCmts.prototype.toggleQuote = function(e, iCmtParentId)
+{
+    this.toggleReply(e, iCmtParentId, 1);
+};
+
+BxDolCmts.prototype.goTo = function(oLink, sGoToId, sBlinkIds, onLoad)
+{
+    $(oLink).parents('.bx-popup-applied:first:visible').dolPopupHide();
+
+    var $this = this;
+    this._getCmts(null, {
+        CmtParent: 0,
+        CmtBrowse: this._sBrowseType,
+        CmtFilter: this._sBrowseFilter,
+        CmtDisplay: this._sDisplayType,
+        CmtBlink: sBlinkIds
+    }, function(sListId, sContent) {
+        $this._cmtsReplaceContent($(sListId), sContent, function() {
+            location.hash = sGoToId;
+
+            if(typeof onLoad == 'function')
+                onLoad();
+        });
+    });
+};
+
+BxDolCmts.prototype.goToBtn = function(oLink, sGoToId, sBlinkIds, onLoad)
+{
+    var $this = this;
+
+    this._loadingInButton(oLink, true);
+
+    this._getCmts(null, {
+        CmtParent: 0,
+        CmtBrowse: this._sBrowseType,
+        CmtFilter: this._sBrowseFilter,
+        CmtDisplay: this._sDisplayType,
+        CmtBlink: sBlinkIds
+    }, function(sListId, sContent) {
+        $this._cmtsReplaceContent($(sListId), sContent, function() {
+            location.hash = sGoToId;
+
+            if(typeof onLoad == 'function')
+                onLoad();
+
+            $(oLink).parents('.cmt-lu-button:first').remove();
+
+            $this.resumeLiveUpdates();
+        });
+    });
+};
+
+BxDolCmts.prototype.goToAndReply = function(oLink, sGoToId, sBlinkIds)
+{
+    var $this = this;
+    this.goTo(oLink, sGoToId, sBlinkIds, function() {
+        var aBlinkIds = sBlinkIds.split(",");
+        $.each(aBlinkIds, function(iIndex, iValue) {
+            $this.toggleReply(null, iValue);
+        });
+    });
+};
+
+/*----------------------------*/
+/*--- Live Updates methods ---*/
+/*----------------------------*/
+BxDolCmts.prototype.showLiveUpdate = function(oData)
+{
+    if(!oData.code)
+        return;
+
+    var oButton = $(oData.code);
+    var sId = oButton.attr('id');
+    $('#' + sId).remove();
+
+    oButton.prependTo(this._sRootId).bxProcessHtml();
+};
+
+BxDolCmts.prototype.showLiveUpdateForSocket = function(sData)
+{
+    var oData = JSON.parse(sData);
+    if(this._iAuthorId == oData.author_id)
+        return;
+
+    var sSelector = this._sRootId + ' .' + this._sSP + '-lu-button';
+    if($(sSelector + ':visible').length != 0)
+        return;
+
+    var oElement = $(sSelector + ':hidden').clone();
+    if(!oElement || oElement.length == 0)
+        return;
+
+    var sOnClick = oElement.find('.bx-btn').attr('onclick');
+    oElement.find('.bx-btn').attr('onclick', sOnClick.replace('{cmt_id}', oData.id).replace('{cmt_anchor}', oData.anchor));
+    oElement.prependTo(this._sRootId).show();
+};
+
+BxDolCmts.prototype.showLiveUpdates = function(oData)
+{
+	/*
+	 * Note. oData.count_old and oData.count_new are also available and can be checked or used in notification popup.  
+	 */
+	if(!oData.code)
+            return;
+
+	var $this = this;
+
+	var oNotifs = $(oData.code);
+	var sId = oNotifs.attr('id');
+	$('#' + sId).remove();
+
+	oNotifs.prependTo('body').dolPopup({
+    	position: 'fixed',
+    	left: '1rem',
+    	top: 'auto',
+    	bottom: '1rem',
+    	fog: false,
+    	onBeforeShow: function() {
+    	},
+    	onBeforeHide: function() {
+    	},
+        onShow: function() {
+            setTimeout(function() {
+                $('.bx-popup-chain.bx-popup-applied:visible:first').dolPopupHide();
+            }, 5000);
+        },
+    	onHide: function() {
+            $this.resumeLiveUpdates();
+    	}
+    });
+};
+
+BxDolCmts.prototype.previousLiveUpdate = function(oLink)
+{
+	var fPrevious = function() {
+		var sClass = 'bx-popup-chain-item';
+		$(oLink).parents('.' + sClass + ':first').hide().prev('.' + sClass).show();
+	};
+
+	if(!this.pauseLiveUpdates(fPrevious));
+		fPrevious();
+};
+
+BxDolCmts.prototype.hideLiveUpdate = function(oLink)
+{
+	$(oLink).parents('.bx-popup-applied:visible:first').dolPopupHide();
+};
+
+BxDolCmts.prototype.resumeLiveUpdates = function(onLoad)
+{
+	if(!this._bLiveUpdatePaused)
+		return false;
+
+	var $this = this;
+	this.changeLiveUpdates('ResumeLiveUpdate', function() {
+		$this._bLiveUpdatePaused = false;
+
+		if(typeof onLoad == 'function')
+			onLoad();
+	});
+
+	return true;
+};
+
+BxDolCmts.prototype.pauseLiveUpdates = function(onLoad)
+{
+	if(this._bLiveUpdatePaused)
+		return false;
+
+	var $this = this;
+	this.changeLiveUpdates('PauseLiveUpdate', function() {
+		$this._bLiveUpdatePaused = true;
+
+		if(typeof onLoad == 'function')
+			onLoad();
+	});
+
+	return true;
+};
+
+BxDolCmts.prototype.changeLiveUpdates = function(sAction, onLoad)
+{
+	var $this = this;
+    var oParams = this._getDefaultActions();
+    oParams['action'] = sAction;
+
+	jQuery.get(
+	    this._sActionsUrl,
+	    oParams,
+	    function() {
+	    	if(typeof onLoad == 'function')
+				onLoad();
+	    }
+	);
+};
+
+BxDolCmts.prototype.cmtShowMore = function(oLink)
+{
+    var oShowMore = $(oLink).parents('.' + this._sSP + '-body-show-more:first');
+    if(!oShowMore.length)
+        return;
+
+    var sClassOverflow = 'bx-overflow';
+
+    oShowMore.siblings('.' + sClassOverflow).css('max-height', 'none').removeClass(sClassOverflow);
+    oShowMore.remove();
+};
+
+BxDolCmts.prototype.cmtOnFindOverflow = function(oElement) {
+    $(oElement).after($(oElement).parents(this._sRootId + ':first').find('.' + this._sSP + '-body-show-more:hidden:first').clone().show());
+};
+
+/*----------------------------------*/
+/*--- Methods for internal usage ---*/
+/*----------------------------------*/
+BxDolCmts.prototype._getCmt = function (e, iCmtId)
+{
+    var $this = this;
+    var oData = this._getDefaultActions();
+    oData['action'] = 'GetCmt';
+    oData['Cmt'] = iCmtId;
+    oData['CmtBrowse'] = this._sBrowseType;
+    oData['CmtDisplay'] = this._sDisplayType;
+
+    this._loadingInBlock (e);
+
+    jQuery.post (
+        this._sActionsUrl,
+        oData,
+        function (oData) {
+            $this._loadingInBlock (e, false);
+
+            var sListId = $this._sRootId + ' #cmt' + oData.vparent_id + ' > ul.cmts-all';
+            var sReplyFormId = $this._sRootId + ' #cmt' + oData.parent_id + ' > .cmt-reply';
+
+            //--- Hide reply form ---//
+            if($(sReplyFormId).length)
+            	$(sReplyFormId).bx_anim('hide', $this._sAnimationEffect, $this._iAnimationSpeed);
+
+            $(sListId).each(function() {
+                //--- Some number of comments already loaded ---//
+                if($(this).children('li.cmt').length) {
+                    var oAdded = null;
+                    if($('#cmt' + iCmtId).length) {
+                        $('#cmt' + iCmtId).replaceWith($(oData.content).hide());
+
+                        oAdded = $('#cmt' + iCmtId);
+                    }
+                    else {
+                        switch($this._sPostFormPosition) {
+                            case 'top':
+                                oAdded = $(this).children('li.cmt:first').before($(oData.content).hide()).prevAll('li.cmt:hidden');
+                                break;
+
+                            case 'bottom':
+                                oAdded = $(this).children('li.cmt:last').after($(oData.content).hide()).nextAll('li.cmt:hidden');
+                                break;
+                        }
+                    }
+
+                    oAdded.each(function() {
+                        $(this).bxProcessHtml().bx_anim('toggle', $this._sAnimationEffect, $this._iAnimationSpeed);
+                    });
+                }
+                //-- There is no comments at all ---//
+                else
+                    $(this).hide().html(oData.content).bxProcessHtml().bx_anim('show', $this._sAnimationEffect, $this._iAnimationSpeed);
+
+                $this._cmtsInitSeeMore($(this));
+                $this._cmtsInitGallery($(this));
+            });
+        },
+        'json'
+    );
+};
+
+BxDolCmts.prototype._getCmts = function (oElement, oRequestParams, onLoad)
+{
+    var $this = this;
+    var oData = this._getDefaultActions();    
+    oData['action'] = 'GetCmts';
+    oData = $.extend({}, oData, oRequestParams);
+
+    var sListId =  this._sRootId + ' #cmt' + oData['CmtParent'] + ' > ul.cmts-' + (oRequestParams.CmtPinned ? 'pinned' : 'all') + ':first';
+
+    if(oElement)
+        this._loadingInBlock(oElement, true);
+
+    jQuery.post (
+        this._sActionsUrl,
+        oData,
+        function(s) {
+            if(oElement)
+                $this._loadingInBlock(oElement, false);
+
+            if(typeof onLoad == 'function')
+                onLoad(sListId, s);
+            else
+                $this._cmtsAppend(sListId, s);
+        }
+    );
+};
+
+BxDolCmts.prototype._getForm = function (e, oParams, onLoad)
+{
+    var $this = this;
+    var oData = $.extend({}, this._getDefaultActions(), {
+        action: 'GetFormPost',
+        CmtType: 'reply',
+        CmtBrowse: this._sBrowseType, 
+        CmtDisplay: this._sDisplayType, 
+        CmtMinPostForm: this._iMinPostForm
+    }, oParams);
+
+    if(e)
+    	this._loadingInContent(e, true);
+
+    jQuery.post (
+        this._sActionsUrl,
+        oData,
+        function (s) {
+            if(e)
+                $this._loadingInContent(e, false);
+
+            if(typeof onLoad == 'function')
+                onLoad(s);
+        }
+    );
+};
+
+BxDolCmts.prototype._cmtsAppend = function(sIdTo, sContent)
+{
+	$(sIdTo).append($(sContent).hide()).children(':hidden').bxProcessHtml().bx_anim('show', this._sAnimationEffect, this._iAnimationSpeed);
+};
+
+BxDolCmts.prototype._cmtsPrepend = function(sIdTo, sContent)
+{
+	$(sIdTo).prepend($(sContent).hide()).children(':hidden').bxProcessHtml().bx_anim('show', this._sAnimationEffect, this._iAnimationSpeed);
+};
+
+BxDolCmts.prototype._cmtsReplace = function(oReplace, sContent, onLoad)
+{
+    var $this = this;
+    $(oReplace).bx_anim('hide', this._sAnimationEffect, this._iAnimationSpeed, function() {
+        $(this).after($(sContent).hide()).nextAll(':hidden').bxProcessHtml().bx_anim('show', $this._sAnimationEffect, $this._iAnimationSpeed, function() {
+            $this._cmtsBlink($(this));
+
+            $this._cmtsInitSeeMore($(this));
+            $this._cmtsInitGallery($(this));
+
+            if(typeof onLoad == 'function')
+                onLoad();
+        });
+        $(this).remove();
+    });
+};
+BxDolCmts.prototype._cmtsReplaceContent = function(oParent, sContent, onLoad)
+{
+    var $this = this;
+    $(oParent).bx_anim('hide', this._sAnimationEffect, this._iAnimationSpeed, function() {
+        $(this).html(sContent).bxProcessHtml().bx_anim('show', $this._sAnimationEffect, $this._iAnimationSpeed, function() {
+            $this._cmtsBlink($(this));
+
+            $this._cmtsInitSeeMore($(this));
+            $this._cmtsInitGallery($(this));
+
+            if(typeof onLoad == 'function')
+            onLoad();
+        });
+    });
+};
+
+BxDolCmts.prototype._cmtsBlink = function(oParent)
+{
+    var sBlinkClass = 'cmt-blink';
+
+    oParent.find('.' + sBlinkClass + '-plate:visible').animate({
+        opacity: 0
+    }, 5000, function() {
+        oParent.find('.' + sBlinkClass).removeClass(sBlinkClass);
+    });
+};
+
+BxDolCmts.prototype._cmtsInitGallery = function(oParent) 
+{
+    // init gallery
+    const lightbox = new PhotoSwipeLightbox({
+        gallery: '.pswp-gallery',
+        children: 'a',
+        pswpModule: PhotoSwipe,
+    });
+    lightbox.init();
+}
+
+BxDolCmts.prototype._cmtsInitSeeMore = function(oParent)
+{
+    var $this = this;
+
+    oParent.find('.cmt-body.bx-overflow-ready').bxCheckOverflowHeight('', function(oElement) {
+        $this.cmtOnFindOverflow(oElement);
+    });
+};
+        
+        
+        
+BxDolCmts.prototype._getCounter = function(oElement, bText)
+{
+    var oCounter = null;
+    var sSelector = '.' + this._sSP + '-counter' + (bText ? '-text' : '');
+
+    if(oElement) {
+        if($(oElement).hasClass(this._sSP))
+            oCounter = $(oElement).find(sSelector);
+        else 
+            oCounter = $(oElement).parents('.' + this._sSP + ':first').find(sSelector);
+    }
+
+    if((!oCounter || !oCounter.length) && this._aHtmlIds['counter'] != undefined) {
+        oCounter = $('#' + this._aHtmlIds['counter']);
+        if(!oCounter.is(sSelector))
+            oCounter = oCounter.find(sSelector);
+    }
+
+    return oCounter;
+};
+
+BxDolCmts.prototype._getDefaultActions = function() {
+    var oDate = new Date();
+    var oResult = {
+        sys: this._sSystem,
+        id: this._iObjId,
+        _t: oDate.getTime()
+    };
+    if(this._aParams)
+        oResult['params'] = this._aParams;
+
+    return oResult;
+};
+
+BxDolCmts.prototype._loading = function(e, bShow) {
+    var oParent = $(e).length ? $(e) : $('body'); 
+    bx_loading(oParent, bShow);
+};
+
+BxDolCmts.prototype._loadingInBlock = function(e, bShow) {
+    var oParent = $(e).length ? $(e).parents('.bx-db-content:first') : $('body'); 
+    bx_loading(oParent, bShow);
+};
+
+BxDolCmts.prototype._loadingInContent = function(e, bShow) {
+    var oParent = $(e).length ? $(e).parents('li.cmt:first,.cmt-reply:first') : $('body'); 
+    bx_loading(oParent, bShow);
+};
+
+BxDolCmts.prototype._loadingInButton = function(e, bShow) {
+    if($(e).length)
+        bx_loading_btn($(e), bShow);
+    else
+        bx_loading($('body'), bShow);
+};
+
+/** @} */

+ 207 - 0
upgrade/files/15.0.0.B3-15.0.0.RC1/files/inc/js/classes/BxDolForm.js

@@ -0,0 +1,207 @@
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    UnaCore UNA Core
+ * @{
+ */
+
+function BxDolForm(oOptions)
+{
+    if(typeof oOptions === 'undefined')
+        return;
+
+    this._sObjName = oOptions.sObjName === undefined ? 'oForm' : oOptions.sObjName; // javascript object name, to run current object instance from onTimer
+    this._sId = oOptions.sId; // form HTML ID
+    this._sName = oOptions.sName; // form name
+    this._sObject = oOptions.sObject; // form object
+    this._sDisplay = oOptions.sDisplay; // form display
+
+    this._sActionsUri = 'form.php';
+    this._sActionsUrl = oOptions.sRootUrl + this._sActionsUri; // actions url address
+    this._bInitCodeMirror = oOptions.bInitCodeMirror == undefined ? false : oOptions.bInitCodeMirror;
+    this._bLeavePageConfirmation = oOptions.bLeavePageConfirmation == undefined ? false : oOptions.bLeavePageConfirmation;
+    this._sTxtLeavePageConfirmation = oOptions.sTxtLeavePageConfirmation === undefined ? _t('_sys_leave_page_confirmation') : oOptions.sTxtLeavePageConfirmation;
+
+    this._bChanged = false;
+
+    this._sAnimationEffect = 'fade';
+    this._iAnimationSpeed = 'slow';
+    this._aHtmlIds = oOptions.aHtmlIds;
+
+    if(this._bLeavePageConfirmation)
+        this.initLeavePageConfirmation();
+}
+
+/**
+ * Note. Is called anytime a form was loaded, even if previously created object of the form is used.
+ */
+BxDolForm.prototype.init = function()
+{
+    if(this._bInitCodeMirror) {
+        setTimeout(() => {
+            this.initCodeMirror();
+        }, 500);
+    }
+};
+
+BxDolForm.prototype.initCodeMirror = function()
+{
+    var oSelector = $('#' + this._sId + ' .bx-form-input-code');
+
+    for(var i = 0; i < oSelector.length; i++) {
+        CodeMirror.fromTextArea(oSelector.get(i), {
+            lineNumbers: true,
+            mode: "htmlmixed",
+            htmlMode: true,
+            matchBrackets: true
+        }).on('blur', function(oEditor) {
+            oEditor.save();
+        });
+    }
+};
+
+BxDolForm.prototype.initLeavePageConfirmation = function()
+{
+    var $this = this;
+
+    var bName = this._sName != undefined && this._sName.length > 0;
+    var bObject = this._sObject != undefined && this._sObject.length > 0;
+    if(!bName && !bObject)
+        return;
+
+    var sForm = '';
+    var oForm = null;
+    if(bName) {
+        sForm = this._sName;
+        oForm = $('#' + sForm);
+    }
+    if(!oForm.length && bObject) {
+        sForm = this._sObject;
+        oForm = $('#' + sForm);
+    }
+    if(!oForm.length)
+        return;
+
+    if(oForm.find('.bx-form-warn:visible').length > 0) {
+        oForm.find(':text').each(function() {
+            if($(this).val() > 0)
+                $this.setChanged();
+        });
+    }
+
+    document.getElementById(sForm).addEventListener('input', (event) => {
+        if(!event?.inputType || !event.inputType.length)
+            return;
+
+        $this.setChanged();
+    });
+
+    document.getElementById(sForm).addEventListener('submit', (event) => {
+        $this.resetChanged();
+    });
+
+    window.addEventListener('beforeunload', (event) => {
+        if(!$this._bChanged) 
+            return;
+
+        event.preventDefault();
+        event.returnValue = '';
+    });
+    
+    $('a').bind('click', function() {
+        if(!$this._bChanged)
+            return;
+
+        var oLink = $(this);
+        var sHref = oLink.attr('href');
+        var sOnclick = oLink.attr('onclick');
+        if(!sHref || (sOnclick != undefined && sOnclick.trim().length > 0))
+            return;
+
+        if(sHref.indexOf(sUrlRoot) == -1)
+            sHref = sUrlRoot + sHref;
+ 
+        var oRegExp = new RegExp('^' + bx_get_regexp('url') + '$', 'i');
+        if(!sHref.trim().match(oRegExp))
+            return;
+
+        event.preventDefault();
+
+        bx_confirm($this._sTxtLeavePageConfirmation, function() {
+            $this.resetChanged();
+
+            oLink.get(0).click();
+        });
+    });
+};
+
+BxDolForm.prototype.setChanged = function() {
+    this._bChanged = true;
+};
+
+BxDolForm.prototype.resetChanged = function() {
+    this._bChanged = false;
+};
+
+BxDolForm.prototype.showHelp = function(oLink, sInputName)
+{
+    var oData = this._getDefaultParams();
+    oData['a'] = 'get_help';
+    oData['input'] = sInputName;
+
+    $(oLink).dolPopupAjax({
+        id: {value:this._aHtmlIds['help_popup'] + sInputName, force:1}, 
+        url: bx_append_url_params(this._sActionsUri, oData),
+        closeOnOuterClick: true,
+        removeOnClose: true,
+        onBeforeShow: function(oPopup) {
+            oPopup.addClass('bx-popup-help');
+        }
+    });
+};
+
+BxDolForm.prototype.pgcTogglePopup = function(oLink, iInputId, sPrivacyObject)
+{
+    var oData = this._getDefaultParams();
+    oData['a'] = 'get_privacy_group_chooser';
+    oData['input_id'] = iInputId;
+    oData['privacy_object'] = sPrivacyObject;
+
+    $(oLink).dolPopupAjax({
+        id: {value:this._aHtmlIds['pgc_popup'] + iInputId, force:1},
+        url: bx_append_url_params(this._sActionsUri, oData),
+        closeOnOuterClick: false,
+        removeOnClose: true,
+    });
+};
+
+BxDolForm.prototype.pgcOnSelectGroup = function(oData)
+{
+    if(oData && parseInt(oData.code) != 0)
+        return;
+
+    if(oData.form_id && oData.chooser_id && oData.icon)
+        $('#' + oData.form_id + ' #' + oData.chooser_id + ' .bx-form-input-pgc-current .sys-icon').removeClass().addClass('sys-icon ' + oData.icon);
+};
+
+BxDolForm.prototype._getDefaultParams = function() 
+{
+    var oDate = new Date();
+    return {
+        o: this._sObject,
+        d: this._sDisplay,
+        _t: oDate.getTime()
+    };
+};
+
+BxDolForm.setCheckBoxValue = function (obj) {
+    var oHidden = $(obj).parent('div').find('INPUT[type=hidden]')
+    var val = 0;
+    if ($(obj).attr("checked") == 'checked') {
+        val = 1;
+    }
+    oHidden.val(val);
+}
+
+/** @} */

+ 174 - 0
upgrade/files/15.0.0.B3-15.0.0.RC1/files/inc/js/classes/BxDolReport.js

@@ -0,0 +1,174 @@
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    UnaCore UNA Core
+ * @{
+ */
+
+function BxDolReport(options)
+{
+    this._sObjName = undefined == options.sObjName ? 'oReport' : options.sObjName; // javascript object name, to run current object instance from onTimer
+    this._sSystem = options.sSystem; // current comment system
+    this._iAuthorId = options.iAuthorId; // this comment's author ID.
+    this._iObjId = options.iObjId; // this object id comments
+
+    this._sActionsUri = 'report.php';
+    this._sActionsUrl = options.sRootUrl + this._sActionsUri; // actions url address
+
+    this._sAnimationEffect = 'fade';
+    this._iAnimationSpeed = 'slow';
+    this._sSP = options.sStylePrefix == undefined ? 'bx-report' : options.sStylePrefix;
+    this._aHtmlIds = options.aHtmlIds;
+    this._oRequestParams = options.oRequestParams == undefined ? {} : options.oRequestParams;
+    this._sUnreportConfirm = options.sUnreportConfirm == undefined ? _t('_Are_you_sure') : options.sUnreportConfirm;
+
+    this._oParent = null;
+}
+
+BxDolReport.prototype.toggleByPopup = function(oLink) {
+    var $this = this;
+    var oData = this._getDefaultParams();
+    oData['action'] = 'GetReportedBy';
+
+    $(oLink).dolPopupAjax({
+        id: this._aHtmlIds['by_popup'], 
+        url: bx_append_url_params(this._sActionsUri, oData)
+    });
+};
+
+BxDolReport.prototype.report = function(oLink) {
+    var $this = this;
+
+    this._oParent = $(oLink);
+
+    var fPerform = function() {
+        var oData = $this._getDefaultParams();
+        oData['action'] = 'Report';
+
+        $.get(
+            $this._sActionsUrl,
+            oData,
+            function(oData) {
+                    $this.processJson(oData, $this._oParent);
+            },
+            'json'
+        );
+    };
+
+    if(this._oParent.hasClass('bx-report-reported'))
+        bx_confirm(this._sUnreportConfirm, fPerform);
+    else 
+    	fPerform();
+};
+
+BxDolReport.prototype.onReport = function(oData, oElement)
+{
+    var $this = this;
+    var fPerform = function() {
+        if(oData && oData.code != 0)
+            return;
+
+        if(oData && oData.reported != undefined)
+            $(oElement).toggleClass('bx-report-reported', oData.reported);
+
+        if(oData && oData.disabled)
+            $(oElement).removeAttr('onclick').addClass($(oElement).hasClass('bx-btn') ? 'bx-btn-disabled' : 'bx-report-disabled');
+
+        if(oData && oData.label_icon)
+            $(oElement).find('.sys-action-do-icon .sys-icon').attr('class', 'sys-icon ' + oData.label_icon);
+
+        if(oData && oData.label_title) {
+            $(oElement).attr('title', oData.label_title);
+            $(oElement).find('.sys-action-do-text').html(oData.label_title);
+        }
+
+        var oCounter = $this._getCounter(oElement);
+        if(oCounter && oCounter.length > 0) {
+            oCounter.html(oData.countf);
+
+            oCounter.parents('.' + $this._sSP + '-counter-holder:first').bx_anim(oData.count > 0 ? 'show' : 'hide');
+        }
+    };
+
+    if(oData && oData.msg != undefined)
+        bx_alert(oData.msg, fPerform);
+    else
+        fPerform();
+};
+
+BxDolReport.prototype.processJson = function(oData, oElement) {
+    oElement = oElement != undefined ? oElement : this._oParent;
+
+    var fContinue = function() {
+        //--- Show Popup
+        if(oData && oData.popup != undefined) {
+            $('#' + oData.popup_id).remove();
+
+            var oPopup = null;
+            var oOptions = {
+                pointer: {
+                    el: oElement
+                },
+                fog: {
+                    color: '#fff',
+                    opacity: .7
+                },
+                closeOnOuterClick: false
+            };
+
+            if(typeof(oData.popup) == 'object') {
+                oOptions = $.extend({}, oOptions, oData.popup.options);
+                oPopup = $(oData.popup.html);
+            }
+            else 
+                oPopup = $(oData.popup);
+
+            oPopup.hide().prependTo('body').dolPopup(oOptions);
+        }
+
+        //--- Evaluate JS code
+        if (oData && oData.eval != undefined)
+            eval(oData.eval);
+    };
+
+    //--- Show Message
+    if(oData && oData.message != undefined)
+        bx_alert(oData.message, fContinue);
+    else
+    	fContinue();
+};
+
+BxDolReport.prototype._getButtons = function(oElement) {
+    if($(oElement).hasClass(this._sSP))
+        return $(oElement).find('.' + this._sSP + '-button');
+    else
+        return $(oElement).parents('.' + this._sSP + ':first').find('.' + this._sSP + '-button');
+};
+
+BxDolReport.prototype._getCounter = function(oElement) {
+    if($(oElement).hasClass(this._sSP))
+        return $(oElement).find('.' + this._sSP + '-counter');
+    else 
+        return $(oElement).parents('.' + this._sSP + ':first').find('.' + this._sSP + '-counter');
+};
+
+BxDolReport.prototype._loadingInButton = function(e, bShow) {
+    if($(e).length)
+        bx_loading_btn($(e), bShow);
+    else
+        bx_loading($('body'), bShow);	
+};
+
+BxDolReport.prototype._getDefaultParams = function() {
+    var oDate = new Date();
+
+    return jQuery.extend({
+        sys: this._sSystem,
+        object_id: this._iObjId
+    }, this._oRequestParams, {
+        _t: oDate.getTime()
+    });
+};
+
+/** @} */

+ 443 - 0
upgrade/files/15.0.0.B3-15.0.0.RC1/files/inc/js/jquery.webForms.js

@@ -0,0 +1,443 @@
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    UnaCore UNA Core
+ * @{
+ */
+
+(function($) {
+
+    $.fn.addWebForms = function(onLoad) {
+        if ('undefined' === typeof(glJsLoadOnaddWebForms) || !glJsLoadOnaddWebForms.length) {
+            $.fn.processWebForms.apply(this);
+
+            if(typeof onLoad == 'function')
+                onLoad();
+        }
+        else {
+            var $this = this;
+            bx_get_scripts(glJsLoadOnaddWebForms, function () {
+                $.fn.processWebForms.apply($this);
+
+                if(typeof onLoad == 'function')
+                    onLoad();
+            });
+        }
+
+        return this;
+    }
+    
+    $.fn.processWebForms = function() {
+        // move to the first error
+        var aErrors = $('.bx-form-warn:visible', this);
+        if(aErrors.length > 0)
+            $([document.documentElement, document.body]).animate({
+                scrollTop: aErrors.first().closest('.bx-form-element-wrapper').offset().top - 50
+            }, 200);
+
+        // switchers
+        $('.bx-switcher-cont', this).each(function() {
+            var eSwitcher = $(this);
+            var eInput = $(this).find('input');
+
+            if (eSwitcher.hasClass('bx-form-switcher-processed'))
+                return;
+            eSwitcher.addClass('bx-form-switcher-processed');
+
+            eSwitcher.on('click', function() {
+                var $this = $(this);
+                if ($this.hasClass('on')) {
+                    $this.find('input').prop('checked', false).trigger('change');
+                    $this.removeClass('on').addClass('off');
+                } else {
+                    $this.removeClass('off').addClass('on');
+                    $this.find('input').prop('checked', true).trigger('change');
+                }
+                return false;
+            });
+
+            eInput.on('enable', function () {
+                if (!$(this).prop('checked'))
+                    $(this).prop('checked', true).trigger('change');
+                if (!eSwitcher.hasClass('on'))
+                    eSwitcher.removeClass('off').addClass('on');
+            });
+
+            eInput.on('disable', function () {
+                if ($(this).prop('checked'))
+                    $(this).prop('checked', false).trigger('change');
+                if (!eSwitcher.hasClass('off'))
+                    eSwitcher.removeClass('on').addClass('off');
+            });
+        });
+
+        // collapsable headers 
+        $('.bx-form-collapsable', this).each(function() {
+
+            var eFormSection = $(this);
+
+            if (eFormSection.hasClass('bx-form-js-processed'))
+                return;
+
+            eFormSection.addClass('bx-form-js-processed');
+
+            var fCallback = function() {
+
+                if (eFormSection.hasClass('bx-form-collapsed')) {
+                    // show
+                    eFormSection.removeClass('bx-form-collapsed');
+
+                    if (eFormSection.hasClass('bx-form-section-hidden')) {
+                        $('.bx-form-section-content:first', eFormSection).hide();
+                        eFormSection.removeClass('bx-form-section-hidden');
+                    }
+
+                    $('.bx-form-section-content:first', eFormSection).slideDown(function () {
+                        eFormSection.removeClass('bx-form-section-hidden');
+
+                        $(this).addWebForms();
+                        $(this).find('.CodeMirror').each(function() {
+                            this.CodeMirror.refresh();
+                        });
+
+                        //--- fire custom event 'bx_show'
+                        eFormSection.trigger('bx_show');
+                    }); 
+
+                } else {
+                    // hide
+                    eFormSection.addClass('bx-form-collapsed');
+
+                    $('.bx-form-section-content:first', eFormSection).slideUp(function () {                    
+                        eFormSection.addClass('bx-form-collapsed bx-form-section-hidden');
+
+                        //--- fire custom event 'bx_hide'
+                        eFormSection.trigger('bx_hide');
+                    }); 
+                }
+
+            };
+
+            $('.bx-form-section-title:first', eFormSection).click(fCallback);
+        });
+
+        $("select", this).each(function () {
+            // Labels selector
+            var oInput = $(this);
+            if (oInput.hasClass('bx-form-select-labels')) {
+                $(".bx-form-select-labels").select2ToTree();
+            }
+             
+            if(oInput.hasClass('bx-form-input-rgb-list')) {
+				oInput.bind('change', function() {
+                    oInput.removeClassWild('bg-*').addClass('bg-' + $(this).val());
+                });
+                oInput.removeClassWild('bg-*').addClass('bg-' + $(this).val());
+			}
+        });
+
+        $(".bx-form-input-wrapper-password", this).each(function() {
+            var sClassInited = "bx-inited";
+            if($(this).hasClass(sClassInited))
+                return;
+
+            var sClassFocus = "bx-form-input-focus";
+            $(this).find("input").bind("focus", function() {
+                $(this).parents(".bx-form-input-wrapper-password:first").addClass(sClassFocus);
+            }).bind("blur", function() {
+                $(this).parents(".bx-form-input-wrapper-password:first").removeClass(sClassFocus);
+            });
+
+            $(this).find("a").on("click", function () {
+                var oLink = $(this);
+                var oFld = oLink.parents(".bx-form-input-wrapper-password:first").find("input");
+                if (oLink.hasClass('password-show')) {
+                    oLink.attr('title', _t('_sys_form_input_password_hide'));
+                    oFld.attr("type", "text");
+                }
+                else {
+                    oLink.attr('title', _t('_sys_form_input_password_show'));
+                    oFld.attr("type", "password");
+                }
+                oLink.toggleClass('password-show password-hide');
+                oLink.find('i').toggleClass('eye eye-slash');
+            });
+
+            $(this).addClass(sClassInited);
+        });
+
+        $("input", this).each(function() {
+            var oInput = $(this);
+
+            var onCreateRange = function (event, ui) {
+                var eInput = $(this).parent().find('input');
+                var iSliderWidth = eInput.innerWidth() - 160;
+                $(this).css('width',  iSliderWidth + 'px').css('top', (eInput.innerHeight() - $(this).outerHeight())/2 + 1 + 'px');
+                eInput.css('padding-right', (iSliderWidth + parseFloat($(this).css('margin-right')) + 10) + 'px');                        
+            };
+
+            // DoubleRange
+            if (this.getAttribute("type") == 'doublerange') {
+
+                var cur = $(this);
+                if(!cur.is(':visible') || cur.hasClass('bx-form-doublerange-processed'))
+                    return;
+
+                cur.addClass('bx-form-doublerange-processed');
+
+                var $slider = $('<div class="bx-def-margin-right"></div>').insertAfter(cur);
+
+                var iMin = cur.attr("min") ? parseFloat(cur.attr("min"), 10) : 0;
+                var iMax = cur.attr("max") ? parseFloat(cur.attr("max"), 10) : 100;
+                var sRangeDv = cur.attr("range-divider") ? cur.attr("range-divider") : '-';
+
+                var funcGetValues = function (e) {
+
+                    var values = e.val().split(sRangeDv, 2); // get values
+
+                    if (typeof(values[0]) != 'undefined' && values[0].length)
+                        values[0] = parseFloat(values[0]);
+                    else
+                        values[0] = iMin;
+
+                    if (typeof(values[1]) != 'undefined' && values[1].length)
+                        values[1] = parseFloat(values[1]);
+                    else
+                        values[1] = iMax;
+
+                    return values;
+                };
+
+                var onChange = function(e, ui) {
+                    values = ui.values;
+                    cur.val( values[0] + sRangeDv + values[1] );
+                };
+
+                $slider.slider({
+                    range: true,
+                    min: iMin,
+                    max: iMax,
+                    step: parseFloat(cur.attr("step")) ? parseFloat(cur.attr("step")) : 1,
+                    values: funcGetValues(cur),
+                    change: onChange,
+                    slide: onChange,
+                    create: onCreateRange
+                });
+
+                cur.bind('change', function () {
+                    var values = funcGetValues($(this));
+                    $slider.slider("option", "values", values);
+                });
+
+            }
+
+            // Single range or slider
+            else if (this.getAttribute("type") == 'slider') {
+
+                var cur = $(this);
+                if(!cur.is(':visible') || cur.hasClass('bx-form-range-processed'))
+                    return;
+
+                cur.addClass('bx-form-range-processed');
+
+                var $slider = $('<div class="bx-def-margin-right"></div>').insertAfter(cur)
+
+                $slider.css('width', ($slider.parent().innerWidth() - cur.outerWidth() - 50) + 'px');
+
+                var iMin = cur.attr("min") ? parseFloat(cur.attr("min"), 10) : 0;
+                var iMax = cur.attr("max") ? parseFloat(cur.attr("max"), 10) : 100;
+
+                var onChange = function(e, ui) {
+                    cur.val( ui.value );
+                };
+
+                $slider.slider({
+                    min: iMin,
+                    max: iMax,
+                    step: parseFloat(cur.attr("step")) ? parseFloat(cur.attr("step")) : 1,
+                    value: cur.val(),
+                    change: onChange,
+                    slide: onChange,
+                    create: onCreateRange
+                });
+
+                cur.bind('change', function () {
+                    $slider.slider("option", "value", $(this).val());
+                });
+
+            }
+
+			// Date/Time pickers
+			if (this.getAttribute("type") == "date" || this.getAttribute("type") == "date_calendar" || this.getAttribute("type") == "datetime" || this.getAttribute("type") == "date_time" || this.getAttribute("type") == "datepicker" || this.getAttribute("type") == "dateselect") {
+                if ($(this).hasClass('bx-form-datepicker-processed'))
+                    return;
+                $(this).addClass('bx-form-datepicker-processed');
+
+                var sYearMin = '1900';
+                var sYearMax = '2100';
+                var m;
+
+                if ($(this).attr('min') && (m = $(this).attr('min').match(/^(\d{4})/)))
+                    sYearMin = m[1];
+                if ($(this).attr('max') && (m = $(this).attr('max').match(/^(\d{4})/)))
+                    sYearMax = m[1];
+
+                var onBeforeShow = function(oInput, oInstance) {
+                	$(oInstance.dpDiv).addClass('bx-form-datepicker-modal');
+                };
+
+                var parseDateUtc = function (sDate, sFormat) {
+                    let oDate = moment.utc(sDate);
+                    return new Date(
+                        oDate.year(),
+                        oDate.month(),
+                        oDate.date(),
+                        oDate.hour(),
+                        oDate.minute(),
+                        oDate.second()
+                    );
+                }
+                var formatDateUtc = function (oDate, sFormat) {
+                    return moment.utc([
+                        oDate.getFullYear(),
+                        oDate.getMonth(),
+                        oDate.getDate(),
+                        oDate.getHours(),
+                        oDate.getMinutes(),
+                        oDate.getSeconds()
+                    ]).format(sFormat);
+                }
+
+                var bDatePicker = false;
+                if (this.getAttribute("type") == "date" || this.getAttribute("type") == "date_calendar" || this.getAttribute("type") == "datepicker") { // Date picker
+
+                    flatpickr(this, {
+                        locale: sLang,
+                        disableMobile: true,
+                        altInput: true,
+                        altFormat: this.getAttribute("data-frmt-date") ? this.getAttribute("data-frmt-date") : "F j, Y",
+                        dateFormat: "YYYY-MM-DD",
+                        minDate: sYearMin,
+                        maxDate: sYearMax,
+                        onOpen: onBeforeShow,
+                        parseDate: parseDateUtc,
+                        formatDate: formatDateUtc,
+                    });
+
+                    bDatePicker = true;
+
+                } else if(this.getAttribute("type") == "datetime" || this.getAttribute("type") == "date_time") { // DateTime picker
+
+                    var oPickerOptions = {
+                        locale: sLang,
+                        disableMobile: true,
+                        enableTime: true,
+                        altInput: true,
+                        altFormat: this.getAttribute("data-frmt-date") ? this.getAttribute("data-frmt-datetime") : "D MMM YYYY h:mma",
+                        dateFormat: "YYYY-MM-DD\\THH:mm:ssZ",
+                        time_24hr: null === this.getAttribute("data-frmt-24h") || 'on' == this.getAttribute("data-frmt-24h") ? true : false,
+                        minDate: sYearMin,
+                        maxDate: sYearMax,
+                        onOpen: onBeforeShow,
+                        parseDate: function (sDate, sFormat) {
+                            let oDate = moment.utc(sDate);
+                            return oDate.toDate();
+                        },
+                        formatDate: function (oDate, sFormat, locale) {
+                            let o;
+                            if (sFormat.endsWith('Z'))
+                                o = moment.utc(oDate);
+                            else
+                                o = moment(oDate);
+                            return o.format(sFormat);
+                        }
+                    };
+
+                    if (1 == $(this).attr('data-utc')) {
+                        oPickerOptions.parseDate = parseDateUtc;
+                        oPickerOptions.formatDate = formatDateUtc;
+                    }
+                    flatpickr(this, oPickerOptions);
+
+                    bDatePicker = true;
+
+                } else if(this.getAttribute("type") == "dateselect") { // DateTime selector
+                    moment.locale(sLang);
+                    $(this).combodate({
+                        minYear: sYearMin,
+                        maxYear: sYearMax,
+                        format: 'YYYY-MM-DD',
+                        template: 'DD MMMM YYYY',
+                        firstItem: 'none',
+                        'smartDays': true,
+                        customClass: 'bx-def-font-inputs bx-form-input-select block w-full py-2 px-3 border border-gray-300 dark:border-gray-700 rounded-md shadow-sm bg-white dark:bg-gray-900 placeholder-gray-500 focus:outline-none focus:placeholder-gray-400 focus:ring-2 focus:text-gray-900 dark:focus:text-gray-100 focus:ring-blue-500 focus:border-opacity-70 focus:ring-opacity-20 focus:border-blue-500 text-sm text-gray-700 dark:text-gray-300 appearance-none',
+                    });
+                }
+                
+                if(bDatePicker) {
+                    if (typeof window.glOnColorSchemeChange === 'undefined')
+                        window.glOnColorSchemeChange = [];    
+
+                    window.glOnColorSchemeChange.push(function(iCode) {
+                        var sNameL = 'flatpickr.min.css';
+                        var sNameD = 'themes/dark.css';
+                        var oStylesheet = null;
+                        switch(iCode) {
+                            case 1: //--- light
+                                oStylesheet = document.head.querySelector("link[href*='" + sNameD + "']");
+                                if(oStylesheet)
+                                    oStylesheet.href = oStylesheet.href.replace(sNameD, sNameL);
+                                else
+                                    bx_get_style(sUrlRoot + 'plugins_public/flatpickr/dist/' + sNameL);
+                                break;
+
+                            case 2: //--- dark
+                                oStylesheet = document.head.querySelector("link[href*='" + sNameL + "']");
+                                if(oStylesheet)
+                                    oStylesheet.href = oStylesheet.href.replace(sNameL, sNameD);
+                                else
+                                    bx_get_style(sUrlRoot + 'plugins_public/flatpickr/dist/' + sNameD);
+                                break;
+                        }
+                    });
+                }
+
+                if (window.navigator.appVersion.search(/Chrome\/(.*?) /) == -1 || parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10) < 24)
+                    if( this.getAttribute("allow_input") == null)
+                        $(this).attr('readonly', 'readonly');
+			}
+
+			// RGB/RGBA pickers
+			if(this.getAttribute('type') == 'text' && (oInput.hasClass('bx-form-input-rgb') || oInput.hasClass('bx-form-input-rgba')) && !oInput.hasClass('minicolors-input')) {
+				oInput.attr('autocomplete', 'off');
+				oInput.minicolors({
+                    control: oInput.attr('data-control') || 'hue',
+                    format: oInput.attr('data-format') || 'rgb',
+                    letterCase: oInput.attr('data-letterCase') || 'lowercase',
+                    opacity: oInput.hasClass('bx-form-input-rgba'),
+                    position: oInput.attr('data-position') || 'bottom left',
+                    theme: 'bootstrap'
+                });
+				
+			}
+        });
+        $('form', this).addClass('bx-form-processed');
+        return this;
+    };
+
+})(jQuery);
+
+$(document).ready(function() {
+    $(this).addWebForms();
+});
+
+(function($) {
+    $.fn.removeClassWild = function(mask) {
+        return this.removeClass(function(index, cls) {
+            var re = mask.replace(/\*/g, '\\S+');
+            return (cls.match(new RegExp('\\b' + re + '', 'g')) || []).join(' ');
+        });
+    };
+})(jQuery);
+/** @} */

+ 12 - 0
upgrade/files/15.0.0.B3-15.0.0.RC1/files/inc/version.inc.php

@@ -0,0 +1,12 @@
+<?php defined('BX_DOL') or defined('BX_DOL_INSTALL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    UnaCore UNA Core
+ * @{
+ */
+
+define('BX_DOL_VERSION', '15.0.0-RC1'); ///< system files version, for DB version @see bx_get_ver, DB and files version must match to
+
+/** @} */

+ 4926 - 0
upgrade/files/15.0.0.B3-15.0.0.RC1/files/modules/base/general/classes/BxBaseModGeneralModule.php

@@ -0,0 +1,4926 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    BaseGeneral Base classes for modules
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+define('BX_BASE_MOD_GENERAL_STATUS_ACTIVE', 'active');
+define('BX_BASE_MOD_GENERAL_STATUS_HIDDEN', 'hidden');
+define('BX_BASE_MOD_GENERAL_STATUS_PENDING', 'pending');
+
+bx_import('BxDolAcl');
+
+/**
+ * Base module class.
+ */
+class BxBaseModGeneralModule extends BxDolModule
+{
+    protected $_bIsApi;
+    protected $_iProfileId;
+    protected $_aSearchableNamesExcept;
+    protected $_aFormParams;
+
+    protected $_aBrowsingFiltersKeys;
+
+    function __construct(&$aModule)
+    {
+        parent::__construct($aModule);
+
+        $this->_bIsApi = bx_is_api();
+        $this->_iProfileId = bx_get_logged_profile_id();
+        $this->_aSearchableNamesExcept = [];
+
+        $this->_aFormParams = array(
+            'display' => false, 
+            'dynamic_mode' => false, 
+            'ajax_mode' => false, 
+            'absolute_action_url' => false,
+            'visibility_autoselect' => false,
+            'context_id' => 0,
+            'custom' => array()
+        );
+
+        $this->_aBrowsingFiltersKeys = ['mode'];
+    }
+
+    // ====== ACTIONS METHODS
+
+    public function isEntryActive($aContentInfo)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $iProfileId = bx_get_logged_profile_id();
+        $bModerator = $this->_isModerator();
+
+        $mixedResult = null;
+        /**
+         * @hooks
+         * @hookdef hook-bx_base_general-is_entry_active '{module_name}', 'is_entry_active' - hook to override whether an entry (content) active or not
+         * - $unit_name - module name
+         * - $action - equals `is_entry_active`
+         * - $object_id - not used
+         * - $sender_id - not used
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `viewer_id` - [int] viewer profile id
+         *      - `is_moderator` - [boolean] is viewer has moderator status or not
+         *      - `content_info` - [array] content info array as key&value pairs
+         *      - `override_result` - [boolean] by ref, boolean value which determines whether entry (content) active or not, can be overridden in hook processing
+         * @hook @ref hook-bx_base_general-is_entry_active
+         */
+        bx_alert($this->getName(), 'is_entry_active', 0, 0, [
+            'viewer_id' => $iProfileId, 
+            'is_moderator' => $bModerator, 
+            'content_info' => $aContentInfo, 
+            'override_result' => &$mixedResult
+        ]);
+        if($mixedResult !== null)
+            return $mixedResult;
+
+        if($this->isEntryAuthor($aContentInfo, $iProfileId) || $bModerator)
+            return true;
+
+        if(!empty($CNF['FIELD_ALLOW_VIEW_TO']) && (int)$aContentInfo[$CNF['FIELD_ALLOW_VIEW_TO']] < 0) {
+            $iContextProfileId = abs((int)$aContentInfo[$CNF['FIELD_ALLOW_VIEW_TO']]);
+            $oContextProfile = BxDolProfile::getInstance($iContextProfileId);
+
+            $aAdmins = bx_srv($oContextProfile->getModule(), 'get_admins_to_manage_content', [$iContextProfileId]);
+            if(!empty($aAdmins) && in_array($iProfileId, $aAdmins))
+                return true;
+        }
+
+        if(isset($CNF['FIELD_STATUS']) && $aContentInfo[$CNF['FIELD_STATUS']] != 'active')
+            return false;
+
+        if(isset($CNF['FIELD_STATUS_ADMIN']) && isset($aContentInfo[$CNF['FIELD_STATUS_ADMIN']]) && $aContentInfo[$CNF['FIELD_STATUS_ADMIN']] != 'active')
+            return false;
+
+        return true;        
+    }
+
+    public function isEntryAuthor($aContentInfo, $iProfileId = 0)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        if(!$iProfileId)
+            $iProfileId = bx_get_logged_profile_id();
+
+        $mixedResult = null;
+        /**
+         * @hooks
+         * @hookdef hook-bx_base_general-is_entry_author '{module_name}', 'is_entry_author' - hook to check if a viewer is an author of viewed entry (content) or not
+         * - $unit_name - module name
+         * - $action - equals `is_entry_author`
+         * - $object_id - not used
+         * - $sender_id - not used
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `viewer_id` - [int] viewer profile id
+         *      - `content_info` - [array] content info array as key&value pairs
+         *      - `override_result` - [boolean] by ref, boolean value which determines whether the viewer is an author of viewed entry (content) or not, can be overridden in hook processing
+         * @hook @ref hook-bx_base_general-is_entry_author
+         */
+        bx_alert($this->getName(), 'is_entry_author', 0, 0, [
+            'viewer_id' => $iProfileId, 
+            'content_info' => $aContentInfo, 
+            'override_result' => &$mixedResult
+        ]);
+        if($mixedResult !== null)
+            return $mixedResult;
+
+        return abs($aContentInfo[$CNF['FIELD_AUTHOR']]) == $iProfileId;
+    }
+
+    public function actionUpdateImage($sFiledName, $iContentId, $sValue)
+    {
+        $mixedResult = $this->serviceUpdateImage($sFiledName, $iContentId, $sValue);
+        if($mixedResult !== false)
+            echo $mixedResult;
+    }
+
+    public function actionUpdateImagePosition($iContentId, $sFiledName, $sH, $sV)
+    {
+        // TODO: check permissions
+        $this->serviceUpdateImagePosition($iContentId, $sFiledName, $sH, $sV);
+    }
+
+    public function actionApprove()
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        if(!isset($CNF['FIELD_STATUS_ADMIN']))
+            return echoJson([]);
+
+        $iContentId = (int)bx_get('content_id');
+        $aContentInfo = $this->_oDb->getContentInfoById($iContentId);
+        if(empty($aContentInfo) || !is_array($aContentInfo) || $aContentInfo[$CNF['FIELD_STATUS_ADMIN']] != BX_BASE_MOD_GENERAL_STATUS_PENDING)
+            return echoJson([]);
+
+        if(($mixedCheckResult = $this->checkAllowedApprove($aContentInfo)) !== CHECK_ACTION_RESULT_ALLOWED)
+            return echoJson(['msg' => $mixedCheckResult]);
+
+        $oForm = $this->_getApproveForm($iContentId, $aContentInfo);
+        $oForm->initChecker();
+
+        if(!$oForm->isSubmitted() || !$oForm->isValid()) {
+            $sPopupId = $this->getName() . '_approve_' . $iContentId;
+            $sPopupTitle = '_sys_manage_popup_approve_title';
+            if(!empty($CNF['T']['txt_approve_popup_title'])) 
+                $sPopupTitle = $CNF['T']['txt_approve_popup_title'];
+
+            return echoJson(['popup' => BxTemplFunctions::getInstance()->popupBox($sPopupId, _t($sPopupTitle), $oForm->getCode(true))]);
+        }
+
+        if($oForm->getCleanValue('do_send')) {
+            $aResult = [];
+            if($this->_sendApproveMessage($iContentId, $aContentInfo, $oForm))
+                $aResult = ['msg' => _t('_sys_manage_txt_sent')];
+            else
+                $aResult = ['msg' => _t('_sys_manage_err_cannot_perform_action')];
+
+            return echoJson($aResult);
+        }
+
+        if($oForm->getCleanValue('do_submit')) {
+            $aResult = [];
+            if($this->_oDb->updateEntriesBy([$CNF['FIELD_STATUS_ADMIN'] => BX_BASE_MOD_GENERAL_STATUS_ACTIVE], [$CNF['FIELD_ID'] => $iContentId])) {
+                $this->checkAllowedApprove($aContentInfo, true);
+
+                $this->onApprove($aContentInfo);
+
+                /*
+                 * Process metas.
+                 * Note. It's essential to process metas a the very end, 
+                 * because all data related to an entry should be already
+                 * processed and are ready to be passed to alert. 
+                 */
+                $this->processMetasAdd($iContentId);
+
+                $aResult = ['msg' => _t('_sys_manage_txt_approved'), 'reload' => 1];
+            }
+            else
+                $aResult = ['msg' => _t('_sys_manage_err_cannot_perform_action')];
+
+            return echoJson($aResult);
+        }
+    }
+
+    public function serviceSetStatus($iId, $sValue, $sStatus = '')
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        if(!$sStatus && !empty($CNF['FIELD_STATUS_ADMIN']))
+            $sStatus = $CNF['FIELD_STATUS_ADMIN'];
+
+        $aStatuses = [];
+        if(!empty($CNF['FIELD_STATUS_ADMIN']))
+            $aStatuses[] = $CNF['FIELD_STATUS_ADMIN'];
+        if(!empty($CNF['FIELD_STATUS']))
+            $aStatuses[] = $CNF['FIELD_STATUS'];
+
+        if(!in_array($sStatus, $aStatuses))
+            return false;
+
+        if((int)$this->_oDb->updateEntriesBy([$sStatus => $sValue], [$CNF['FIELD_ID'] => $iId]) == 0)
+            return false;
+
+        if($sValue == BX_BASE_MOD_GENERAL_STATUS_ACTIVE)
+            $this->onPublished($iId);
+    }
+
+    public function actionRss ()
+    {
+        $aArgs = func_get_args();
+        $this->_rss($aArgs);
+    }
+
+    /**
+     * Attach link
+     */
+    public function actionGetAttachLinkForm()
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $iContentId = ($iContentId = bx_get($CNF['FIELD_ATTACH_LINK_CONTENT_ID'])) !== false ? (int)$iContentId : 0;
+
+        echo $this->_oTemplate->getAttachLinkForm($iContentId);
+    }
+    
+    public function actionSubmitAttachLinkForm()
+    {
+        echoJson($this->getFormAttachLink());
+    }
+
+    public function actionAddAttachLink()
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $sUrl = bx_process_input(bx_get($CNF['FIELD_ATTACH_LINK_URL']));
+        if(empty($sUrl))
+            return echoJson([]);
+        
+        $sUrl = htmlspecialchars_decode($sUrl);
+        $oStreamContext = stream_context_create([
+            'http' => [
+                'timeout' => getParam('sys_default_socket_timeout'), 
+            ]
+        ]);
+
+        $sHeader = 'Content-Type';
+        $aHeaders = @get_headers($sUrl, 1, $oStreamContext);
+        if(!empty($aHeaders) && is_array($aHeaders) && !empty($aHeaders[$sHeader])) {
+            $mixedContentType = $aHeaders[$sHeader];
+            if(!is_array($mixedContentType))
+                $mixedContentType = [$mixedContentType];
+
+            foreach($mixedContentType as $sContentType)
+                if(strpos($sContentType, 'image') !== false) 
+                    return echoJson([]);
+        }
+
+        echoJson($this->addAttachLink([
+            $CNF['FIELD_ATTACH_LINK_CONTENT_ID'] => ($iContentId = bx_get($CNF['FIELD_ATTACH_LINK_CONTENT_ID'])) !== false ? (int)$iContentId : 0,
+            $CNF['FIELD_ATTACH_LINK_URL'] => $sUrl
+        ]));
+    }
+
+    public function actionDeleteAttachLink()
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+    	$iUserId = $this->getUserId();
+        $iLinkId = bx_process_input(bx_get('id'), BX_DATA_INT);
+        if(empty($iLinkId))
+            return echoJson([]);
+
+        $aLink = $this->_oDb->getLinksBy(['type' => 'id', 'id' => $iLinkId, 'profile_id' => $iUserId]);
+    	if(empty($aLink) || !is_array($aLink))
+            return echoJson([]);
+
+        if(!empty($aLink['media_id']))
+            BxDolStorage::getObjectInstance($CNF['OBJECT_STORAGE_PHOTOS'])->deleteFile($aLink['media_id']);
+
+        $aResult = [];
+        if($this->_oDb->deleteLink($iLinkId))
+            $aResult = ['code' => 0, 'url' => $aLink['url']];
+        else
+            $aResult = ['code' => 1, 'message' => _t(!empty($CNF['txt_link_form_err_delete']) ? $CNF['txt_link_form_err_delete'] : $this->getName() . '_form_post_input_link_err_delete')];
+
+        echoJson($aResult);
+    }
+
+    /**
+     * Attach poll
+     */
+    public function actionEmbedPoll($iPollId = 0)
+    {
+        if(empty($iPollId) && bx_get('poll_id') !== false)
+            $iPollId = (int)bx_get('poll_id');
+
+        $aParams = bx_get_with_prefix('param');
+        array_walk($aParams, function(&$sValue) {
+            $sValue = bx_process_input($sValue);
+        });
+
+        $this->_oTemplate->embedPollItem($iPollId, $aParams);
+    }
+
+    public function actionEmbedPolls($iId = 0)
+    {
+        list($iContentId, $aContentInfo) = $this->_getContent($iId);
+        if($iContentId === false)
+            return;
+
+        $aParams = bx_get_with_prefix('param');
+        array_walk($aParams, function(&$sValue) {
+            $sValue = bx_process_input($sValue);
+        });
+
+        $this->_oTemplate->embedPollItems($aContentInfo, $aParams);
+    }
+
+    public function actionGetPoll()
+    {
+        $iPollId = (int)bx_get('poll_id');
+        $sView = bx_process_input(bx_get('view'));
+
+        $sMethod = 'serviceGetBlockPoll' . bx_gen_method_name($sView);
+        if(!method_exists($this, $sMethod))
+            return echoJson(array());
+
+        $aBlock = $this->$sMethod($iPollId, true);
+        if(empty($aBlock) || !is_array($aBlock))
+            return echoJson(array());
+
+        return echoJson(array(
+            'content' => $aBlock['content']
+        ));
+    }
+    public function actionDeletePoll()
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $iId = bx_process_input(bx_get('id'), BX_DATA_INT);
+        if(empty($iId))
+            return echoJson([]);
+
+        $aResult = [];
+        if($this->serviceDeletePoll($iId))
+            $aResult = ['code' => 0];
+        else
+            $aResult = ['code' => 1, 'message' => _t($CNF['txt_err_cannot_perform_action'])];
+
+        echoJson($aResult);
+    }
+
+    public function actionGetPollForm()
+    {
+        echo $this->_oTemplate->getPollForm((int)bx_get('parent_cid'));
+    }
+
+    public function actionSubmitPollForm()
+    {
+        echoJson($this->getPollForm((int)bx_get('parent_cid')));
+    }
+
+    public function serviceGetPollForm()
+    {
+        if(!$this->_bIsApi)
+            return false;
+
+        $aResult = $this->getPollForm();
+
+        if(isset($aResult['code'])) {
+            if((int)$aResult['code'] == 0) {
+                return [
+                    'id' => $aResult['id'],
+                    'item' => $aResult['item']
+                ];
+            }
+            else
+                return isset($aResult['message']) ? [bx_api_get_msg($aResult['message'])] : [];
+        }
+        else if(isset($aResult['form'])) {
+            $sModule = $this->getName();
+
+            return [bx_api_get_block('form', $aResult['form'], [
+                'ext' => [
+                    'name' => $sModule, 
+                    'request' => ['url' => '/api.php?r=' . $sModule . '/submit_poll_form', 'immutable' => true]
+                ]
+            ])];
+        }
+    }
+
+    public function serviceSubmitPollForm()
+    {
+        if(!$this->_bIsApi)
+            return false;
+
+        return $this->serviceGetPollForm();
+    }
+
+    public function serviceDeletePoll($iId)
+    {
+        return $this->_oDb->deletePolls([$this->_oConfig->CNF['FIELD_POLL_ID'] => $iId]);
+    }
+
+    public function getPollForm($iParentCid = 0)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        if(empty($CNF['OBJECT_FORM_POLL']))
+            return ['code' => 1, 'message' => '_sys_txt_error_occured'];
+
+        $iProfileId = bx_get_logged_profile_id();
+
+        $oForm = BxDolForm::getObjectInstance($CNF['OBJECT_FORM_POLL'], $CNF['OBJECT_FORM_POLL_DISPLAY_ADD'], $this->_oTemplate);
+        $oForm->setParentContentId($iParentCid);
+
+        $oForm->initChecker();
+        if($oForm->isSubmittedAndValid()) {
+            $iId = $oForm->insert();
+            if($iId)
+                return ['code' => 0, 'id' => $iId, 'item' => $this->_oTemplate->getPollItem($iId, $iProfileId, [
+                    'parent_cid' => $iParentCid,
+                    'manage' => true
+                ])];
+            else
+                return ['code' => 2, 'message' => '_sys_txt_error_entry_creation'];
+        }
+
+        return [
+            'form' => $oForm->{'getCode' . ($this->_bIsApi ? 'API' : '')}(), 
+            'form_id' => $oForm->id
+        ];
+    }
+
+    public function actionGetCreatePostForm()
+    {
+        $sName = $this->_oConfig->getName();
+
+    	$aParams = bx_process_input(array_intersect_key($_GET, $this->_aFormParams));
+    	$aParams = array_merge($this->_aFormParams, $aParams);
+        $aParams['context_id'] = (bool)$aParams['context_id'] ? (int)$aParams['context_id'] : false;
+
+    	$mixedResponse = $this->serviceGetCreatePostForm($aParams);
+    	if(empty($mixedResponse))
+            return echoJson(array());
+        else if(is_array($mixedResponse)) {
+            $mixedResponse['module'] = $sName;
+            return echoJson($mixedResponse);
+        }
+
+        return echoJson(array(
+            'module' => $sName,
+            'content' => $mixedResponse
+    	));
+    }
+
+    public function actionGetNotes()
+    {
+        $CNF = &$this->_oConfig->CNF;
+        if(empty($CNF['OBJECT_NOTES']))
+            return echoJson([]);
+
+        $iContentId = (int)bx_get('content_id');
+
+        $oCmtsNotes = BxDolCmts::getObjectInstance($CNF['OBJECT_NOTES'], $iContentId, true, $this->_oTemplate);
+        $aCmtsNotes = $oCmtsNotes->getCommentsBlock([], ['in_designbox' => false]);
+        if(empty($aCmtsNotes) || !is_array($aCmtsNotes))
+            return echoJson([]);
+
+        $sPostfix = $iContentId < 0 ? '_rc' : '';
+
+        $sPopupId = $this->getName() . '_notes_' . $iContentId;
+        $sPopupTitle = !empty($CNF['T']['txt_cmts_notes_popup_view_title' . $sPostfix]) ? $CNF['T']['txt_cmts_notes_popup_view_title' . $sPostfix] : '_cmt_nts_popup_view_title' . $sPostfix;
+        echoJson(['popup' => BxTemplFunctions::getInstance()->popupBox($sPopupId, _t($sPopupTitle), $aCmtsNotes['content'])]);
+    }
+    
+    public function actionNested()
+    {
+        $sAction = bx_get('a');
+        $sMethodName = 'subaction' . ucfirst($sAction);
+        if (!method_exists($this, $sMethodName)) {
+            return;
+        }
+        $this->$sMethodName();
+    }
+    
+    public function actionEmbed($iContentId, $sUnitTemplate = '', $sAddCode = '')
+    {
+        $oTemplate = BxDolTemplate::getInstance();
+        
+        $aContentInfo = $this->_oDb->getContentInfoById($iContentId);
+        if(empty($aContentInfo))
+            $oTemplate->getEmbed(false);
+
+        if(empty($sUnitTemplate))
+            $sUnitTemplate = 'unit_gallery.html';
+
+        $CNF = &$this->_oConfig->CNF;
+        
+        if(!empty($CNF['OBJECT_VIEWS'])) {
+            $oView = BxDolView::getObjectInstance($CNF['OBJECT_VIEWS'], $iContentId);
+            if($oView && $oView->isEnabled())
+                $oView->doView();
+        }
+
+        $oTemplate->getEmbed($this->_oTemplate->unit($aContentInfo, true, $sUnitTemplate, ['embed' => true]) . $sAddCode);
+    }
+   
+    public function subactionDelete()
+    {
+        header('Content-type: text/html; charset=utf-8');
+
+        $iNestedId = (int)bx_get('id');
+		$sNestedForm = bx_get('s');
+        
+        $oForm = BxDolForm::getObjectInstance($sNestedForm, $sNestedForm);
+        if (!$oForm){
+            echo _t('_sys_request_page_not_found_cpt');
+            return;
+        }
+
+        $aNested = $this->_oDb->getNestedBy(array('type' => 'id', 'id' => $iNestedId, 'key_name' => $oForm->aParams['db']['key']), $oForm->aParams['db']['table']);
+        if (empty($aNested)){
+            echo _t('_sys_request_page_not_found_cpt');
+            return;
+        }
+        
+        $aContentInfo = $this->_oDb->getContentInfoById ($aNested['content_id']); 
+        if (!$aContentInfo){
+            echo _t('_sys_request_page_not_found_cpt');
+            return;
+        }
+
+        elseif (CHECK_ACTION_RESULT_ALLOWED !== ($sMsg = $this->checkAllowedEdit ($aContentInfo))) {
+            echo $sMsg;
+        } 
+        elseif (!$this->_oDb->deleteNestedById($iNestedId, $oForm->aParams['db']['key'], $oForm->aParams['db']['table'])) {
+            echo _t('_sys_txt_error_occured');
+        } 
+        else {
+            echo 'ok';
+        }
+    }
+    
+    /**
+     * Get possible recipients for start conversation form
+     */
+    public function actionAjaxGetProfiles ()
+    {
+        $sTerm = bx_get('term');
+
+        $a = BxDolService::call('system', 'profiles_search', array($sTerm), 'TemplServiceProfiles');
+
+        header('Content-Type:text/javascript; charset=utf-8');
+        echo(json_encode($a));
+    }
+    
+    public function serviceGetProfiles ($sParams)
+    {
+        $aOptions = json_decode($sParams, true);
+        if (!$sParams || !isset($aOptions['term']))
+            return [];
+
+        return BxDolService::call('system', 'profiles_search', array($aOptions['term']), 'TemplServiceProfiles');
+    }
+
+    public function actionGetBrowsingFilters()
+    {
+        $aParams = $this->_prepareBrowsingFiltersParamsGet();
+
+        $sContent = $this->_oTemplate->getBrowsingFilters($aParams);
+        if(empty($sContent))
+            return echoJson([]);
+
+        echoJson([
+            'code' => 0,
+            'popup' => [
+                'html' => $sContent,
+                'options' => [
+                    'closeOnOuterClick' => false,
+                    'removeOnClose' => false,
+                ]
+            ],
+        ]);
+    }
+
+    public function actionApplyBrowsingFilters()
+    {
+        $aParams = $this->_prepareBrowsingFiltersParamsGet();
+
+        $aBrowseParams = ['mode' => $aParams['mode'], 'empty_message' => true];
+        unset($aParams['mode']);
+        $aBrowseParams['params'] = $aParams;
+
+        $mixedResult = $this->serviceBrowse($aBrowseParams);
+        if(empty($mixedResult))
+            return echoJson([]);
+
+        if(is_array($mixedResult) && isset($mixedResult['content']))
+            $mixedResult = $mixedResult['content'];
+
+        return echoJson([
+            'code' => 0, 
+            'content' => $mixedResult, 
+            'eval' => $this->_oConfig->getJsObject('main') . '.onApplyBrowsingFilter(oData)'
+        ]);
+    }
+
+    protected function _prepareBrowsingFiltersParamsGet($mParams = false)
+    {
+        $aParams = [];
+        $bParams = !empty($mParams) && is_array($mParams);
+
+        foreach($this->_aBrowsingFiltersKeys as $sKey)
+            if($bParams) {
+                if(isset($mParams[$sKey]))
+                    $aParams[$sKey] = $mParams[$sKey];
+            }
+            else {
+                if(($sValue = bx_get($sKey)) !== false)
+                    $aParams[$sKey] = $sValue;
+            }
+
+        return $aParams;
+    }
+
+    // ====== SERVICE METHODS
+
+    /**
+     * Checkes whether a content is active by status (status_admin).
+     * 
+     * @param type $iContentId
+     * @return boolean
+     */
+    public function serviceIsActive($iContentId)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $aContentInfo = $this->_oDb->getContentInfoById($iContentId);
+        if(empty($aContentInfo))
+            return false;
+
+        if(($sKey = 'FIELD_STATUS') && isset($CNF[$sKey]) && $aContentInfo[$CNF[$sKey]] != 'active')
+            return false;
+
+        if(($sKey = 'FIELD_STATUS_ADMIN') && isset($CNF[$sKey]) && isset($aContentInfo[$CNF[$sKey]]) && $aContentInfo[$CNF[$sKey]] != 'active')
+            return false;
+
+        return true;
+    }
+
+    public function serviceIsAllowedAddContentToContext($iContextPid)
+    {
+        $oContext = false;
+        if(!$iContextPid || !($oContext = BxDolProfile::getInstance((int)$iContextPid)))
+            return false;
+
+        if($iContextPid == bx_get_logged_profile_id())
+            return true;
+
+        return bx_srv($oContext->getModule(), 'check_allowed_post_in_profile', [$oContext->getContentId(), $this->getName()]) === CHECK_ACTION_RESULT_ALLOWED;
+    }
+
+    public function serviceIsBadgesAvaliable()
+    {
+        if(!isAdmin() && !$this->_isAdministrator())
+            return false;
+
+        $aBadges = BxDolBadges::getInstance()->getData([
+            'type' => 'by_module&object', 
+            'object_id' => 0, 
+            'module' => $this->getName()
+        ]);
+
+        return count($aBadges) > 0 ? true : false;
+    }
+
+    public function serviceGetSafeServices()
+    {
+        return array(
+            // other
+            'ModuleIcon' => '',
+            'GetLink' => '',
+            // browse
+            'GetSearchResultUnit' => '',
+            'Browse' => '',
+            'BrowseFeatured' => '',
+            'BrowseFavorite' => '',
+            // forms
+            'GetCreatePostForm' => '',
+            'EntityCreate' => '',
+            'EntityEdit' => '',
+            'EntityDelete' => '',
+            'UpdateImage' => '',
+            // polls
+            'GetPollForm' => '',
+            'SubmitPollForm' => '',
+            'DeletePoll' => '',
+            'GetBlockPollAnswers' => '',
+            'GetBlockPollResults' => '',
+            // page blocks
+            'EntityTextBlock' => '',
+            'EntityInfo' => '',
+            'EntityInfoFull' => '',
+            'EntityInfoExtended' => '',
+            'EntityLocation' => '',
+            'EntityComments' => '',
+            'EntityAttachments' => '',
+            'CategoriesMultiList' => '',
+            // menu
+            'EntityAllActions' => '',
+            'EntityActions' => '',
+            'EntitySocialSharing' => '',
+            'MyEntriesActions' => '',
+            
+            'GetProfiles' => '',
+        );
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_base_general Base General
+     * @subsection bx_base_general-other Other
+     * @subsubsection bx_base_general-module_icon module_icon
+     * 
+     * @code bx_srv('bx_posts', 'module_icon', [...]); @endcode
+     * 
+     * Get module icon as CSS class name with FontAwesome icon name class and color class
+     * 
+     * @see BxBaseModGeneralModule::serviceModuleIcon
+     */
+    /** 
+     * @ref bx_base_general-module_icon "module_icon"
+     */
+    public function serviceModuleIcon ()
+    {
+        return isset($this->_oConfig->CNF['ICON']) ? $this->_oConfig->CNF['ICON'] : '';
+    }
+
+    public function serviceGetModerators($iContentId)
+    {
+        return $this->getModerators($iContentId);
+    }
+
+    public function serviceGetAuthor ($iContentId)
+    {
+        $mixedResult = $this->_getFieldValue('FIELD_AUTHOR', $iContentId);
+        return $mixedResult !== false ? (int)$mixedResult : 0; 
+    }
+
+    public function serviceGetPrivacyView ($iContentId)
+    {
+        return $this->_getFieldValue('FIELD_ALLOW_VIEW_TO', $iContentId);
+    }
+
+    public function serviceGetDateAdded ($iContentId)
+    {
+        $mixedResult = $this->_getFieldValue('FIELD_ADDED', $iContentId);
+        return $mixedResult !== false ? (int)$mixedResult : 0; 
+    }
+
+    public function serviceGetDateChanged ($iContentId)
+    {
+        $mixedResult = $this->_getFieldValue('FIELD_CHANGED', $iContentId);
+        return $mixedResult !== false ? (int)$mixedResult : 0;
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_base_general Base General
+     * @subsection bx_base_general-other Other
+     * @subsubsection bx_base_general-get_link_add get_link_add
+     * 
+     * @code bx_srv('bx_posts', 'get_link_add', [...]); @endcode
+     * 
+     * Get add entry URL.
+     * 
+     * @see BxBaseModGeneralModule::serviceGetLinkAdd
+     */
+    /** 
+     * @ref bx_base_general-get_link_add "get_link_add"
+     */
+    public function serviceGetLinkAdd ()
+    {
+        $sUri = $this->_oConfig->getEntryUri('add');
+        if(!$sUri)
+            return '';         
+
+        return bx_absolute_url(BxDolPermalinks::getInstance()->permalink('page.php?i=' . $sUri));
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_base_general Base General
+     * @subsection bx_base_general-other Other
+     * @subsubsection bx_base_general-get_link_edit get_link_edit
+     * 
+     * @code bx_srv('bx_posts', 'get_link_edit', [...]); @endcode
+     * 
+     * Get edit entry URL for the specified content.
+     * @param $iContentId content id
+     * 
+     * @see BxBaseModGeneralModule::serviceGetLinkEdit
+     */
+    /** 
+     * @ref bx_base_general-get_link_edit "get_link_edit"
+     */
+    public function serviceGetLinkEdit ($iContentId)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $sUri = $this->_oConfig->getEntryUri('edit');        
+        if(!$sUri)
+            return '';
+
+        $aContentInfo = $this->_oDb->getContentInfoById($iContentId);
+        if(empty($aContentInfo))
+            return '';
+
+        return bx_absolute_url(BxDolPermalinks::getInstance()->permalink('page.php?i=' . $sUri . '&id=' . $aContentInfo[$CNF['FIELD_ID']]));
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_base_general Base General
+     * @subsection bx_base_general-other Other
+     * @subsubsection bx_base_general-get_link get_link
+     * 
+     * @code bx_srv('bx_posts', 'get_link', [...]); @endcode
+     * 
+     * Get URL for the specified content.
+     * @param $iContentId content id
+     * 
+     * @see BxBaseModGeneralModule::serviceGetLink
+     */
+    /** 
+     * @ref bx_base_general-get_link "get_link"
+     */
+    public function serviceGetLink ($iContentId)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $sUri = $this->_oConfig->getEntryUri('view');        
+        if(!$sUri)
+            return '';
+
+        $aContentInfo = $this->_oDb->getContentInfoById($iContentId);
+        if(empty($aContentInfo))
+            return '';
+
+        return bx_absolute_url(BxDolPermalinks::getInstance()->permalink('page.php?i=' . $sUri . '&id=' . $aContentInfo[$CNF['FIELD_ID']]));
+    }
+
+    public function serviceGetTitle ($iContentId)
+    {
+        $mixedResult = $this->_getFieldValue('FIELD_TITLE', $iContentId);
+        return $mixedResult !== false ? $mixedResult : '';
+    }
+
+    public function serviceGetText ($iContentId)
+    {
+        $mixedResult = $this->_getFieldValue('FIELD_TEXT', $iContentId);
+        if (false === $mixedResult)
+            return '';
+
+        $CNF = &$this->_oConfig->CNF;
+        if (!empty($CNF['OBJECT_METATAGS']) && is_string($mixedResult)) {
+            $oMetatags = BxDolMetatags::getObjectInstance($CNF['OBJECT_METATAGS']);
+            $mixedResult = $oMetatags->metaParse($iContentId, $mixedResult);
+        }
+
+        return $mixedResult;
+    }
+    
+    public function serviceGetLocation ($iContentId)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        if(empty($CNF['OBJECT_METATAGS']))
+            return [];
+
+        $mixedResult = $this->_getFieldValue('FIELD_LOCATION', $iContentId);
+        if(false === $mixedResult)
+            return [];
+
+        $oMeta = false;
+        if(!($oMeta = BxDolMetatags::getObjectInstance($CNF['OBJECT_METATAGS'])) || !$oMeta->locationsIsEnabled())
+            return false;
+
+        $aLocation = $oMeta->locationGet($iContentId);
+        if(empty($aLocation) || !is_array($aLocation))
+            return false;
+
+        return array_values(array_slice($aLocation, 1));
+    }
+
+    public function serviceGetEmbed ($iContentId)
+    {
+        $sTitle = $this->_getFieldValue('FIELD_TITLE', $iContentId);
+        return $this->_oTemplate->parseHtmlByName('embed.html', [
+            'title' => $sTitle,
+            'url' => BX_DOL_URL_ROOT . $this->_oConfig->getBaseUri() . 'embed/' . $iContentId . '/'
+        ]);
+    }
+
+    public function serviceGetInfo ($iContentId, $bSearchableFieldsOnly = true)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $aContentInfo = $this->_getFields($iContentId);
+        if(empty($aContentInfo))
+            return array();
+
+        if(!$bSearchableFieldsOnly)
+            return $aContentInfo;
+
+        if(empty($CNF['PARAM_SEARCHABLE_FIELDS']))
+            return array();
+
+        $aFields = explode(',', getParam($CNF['PARAM_SEARCHABLE_FIELDS']));
+        if(empty($aFields))
+            return array();
+
+        $aResult = array();
+        foreach($aFields as $sField)
+            if(isset($aContentInfo[$sField]))
+                $aResult[$sField] = $aContentInfo[$sField];
+
+        return $aResult;
+    }
+
+    public function serviceGetInfoApi ($iContentId, $bExtendedUnits = false)
+    {
+        $aData = $this->serviceGetInfo($iContentId, false);
+        if($aData)
+            $aData = $this->getDataAPI($aData, ['extended' => $bExtendedUnits]);
+
+        return $aData;
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_base_general Base General
+     * @subsection bx_base_general-browsing Browsing
+     * @subsubsection bx_base_general-get_search_result_unit get_search_result_unit
+     * 
+     * @code bx_srv('bx_posts', 'get_search_result_unit', [3,"unit_gallery.html"]); @endcode
+     * 
+     * Get browsing unit for the specified content
+     * @param $iContentId content id
+     * @param $sUnitTemplate unit template, such as: unit_full.html, unit_gallery.html, unit_live_search.html
+     * 
+     * @see BxBaseModGeneralModule::serviceGetSearchResultUnit
+     */
+    /** 
+     * @ref bx_base_general-get_search_result_unit "get_search_result_unit"
+     */
+    public function serviceGetSearchResultUnit ($iContentId, $sUnitTemplate = '')
+    {
+        $aContentInfo = $this->_oDb->getContentInfoById($iContentId);
+        if($this->_bIsApi)
+            return $this->getDataAPI($aContentInfo);
+
+        if(empty($aContentInfo))
+            return '';
+
+        if(empty($sUnitTemplate))
+            $sUnitTemplate = 'unit.html';
+
+        return $this->_oTemplate->unit($aContentInfo, true, $sUnitTemplate);
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_base_general Base General
+     * @subsection bx_base_general-browsing Browsing
+     * @subsubsection bx_base_general-get_view get_view
+     * 
+     * @code bx_srv('bx_posts', 'get_view', [3]); @endcode
+     * 
+     * Get view for the specified content
+     * @param $iContentId content id
+     * 
+     * @see BxBaseModGeneralModule::serviceGetView
+     */
+    /** 
+     * @ref bx_base_general-get_view "get_view"
+     */
+    public function serviceGetView ($iContentId)
+    {
+        return $this->serviceEntityTextBlock($iContentId);
+    }
+
+    public function serviceGetAll ($aParams = array())
+    {
+        if(empty($aParams) || !is_array($aParams))
+            $aParams = array('type' => 'all');
+
+        return $this->_oDb->getEntriesBy($aParams);
+    }
+
+    public function serviceGetAllByAuthor ($iProfileId)
+    {
+        return $this->_oDb->getEntriesByAuthor((int)$iProfileId);
+    }
+
+    public function serviceGetSortableFieldsExtended($aInputsAdd = array())
+    {
+        $CNF = &$this->_oConfig->CNF;
+        if(empty($CNF['OBJECT_FORM_ENTRY']))
+            return array();
+        
+        $aResult = array();
+        
+        $aSortableFields = [];
+        
+        $aDisplays = [];
+        if(!empty($CNF['OBJECT_FORM_ENTRY_DISPLAY_ADD'])) {
+            $aDisplays[] = $CNF['OBJECT_FORM_ENTRY_DISPLAY_ADD'];
+        }
+        if(!empty($CNF['OBJECT_FORM_ENTRY_DISPLAY_EDIT'])) {
+            $aDisplays[] = $CNF['OBJECT_FORM_ENTRY_DISPLAY_EDIT'];
+        }
+        
+        $aInputsAll = BxDolFormQuery::getFormInputs($CNF['OBJECT_FORM_ENTRY']);    
+        foreach($aInputsAll as $aInput){
+            $aInputsAll[$aInput['name']] = $aInput;
+        }
+        
+        $aInputs = BxDolFormQuery::getFormInputs($CNF['OBJECT_FORM_ENTRY'],  $aDisplays);
+        foreach($aInputs as $aInput){
+            $aInputs[$aInput['name']] = $aInput;
+            if ($aInput['type'] == 'text'){
+                $aSortableFields[] = $aInput['name'];
+            }
+        }
+        
+        if(!empty($CNF['FIELD_ADDED']) && isset($aInputsAll[$CNF['FIELD_ADDED']])){
+           $aSortableFields[] = $CNF['FIELD_ADDED'];
+        }
+        
+        if(!empty($CNF['FIELD_CHANGED']) && isset($aInputsAll[$CNF['FIELD_CHANGED']])){
+           $aSortableFields[] = $CNF['FIELD_CHANGED'];
+        }     
+        
+        foreach($aSortableFields as $sSortableField){
+             $aResult[$sSortableField . '_asc'] = [
+                'name' => $sSortableField,
+                'caption' => $aInputsAll[$sSortableField]['caption'],
+                'direction' => 'asc'
+            ];
+            
+            $aResult[$sSortableField . '_desc']  = [
+                'name' => $sSortableField,
+                'caption' => $aInputsAll[$sSortableField]['caption'],
+                'direction' => 'desc'
+            ];
+        }
+
+        /**
+         * @hooks
+         * @hookdef hook-bx_base_general-get_sortable_fields '{module_name}', 'get_sortable_fields' - hook to override a list of sortable fields
+         * - $unit_name - module name
+         * - $action - equals `get_sortable_fields`
+         * - $object_id - not used
+         * - $sender_id - not used
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `override_result` - [array] a list of searchable fields, can be overridden in hook processing
+         * @hook @ref hook-bx_base_general-get_sortable_fields
+         */
+        bx_alert($this->getName(), 'get_sortable_fields', 0, 0, [
+            'extended' => true, 
+            'override_result' => &$aResult
+        ]);
+
+        return $aResult;
+    }
+    
+    public function serviceGetSearchableFieldsExtended($aInputsAdd = array())
+    {
+        $CNF = &$this->_oConfig->CNF;
+        if(empty($CNF['OBJECT_FORM_ENTRY']))
+            return array();
+
+        $aResult = array();
+        if(!empty($CNF['FIELD_AUTHOR']) && !in_array($CNF['FIELD_AUTHOR'], $this->_aSearchableNamesExcept))
+            $aResult[$CNF['FIELD_AUTHOR']] = array(
+                'type' => 'text_auto', 
+                'caption' => $CNF['T']['form_field_author'],
+                'info' => '',
+            	'value' => '',
+                'values' => '',
+                'pass' => ''
+            );
+
+        $aInputs = array();
+        if(!empty($CNF['OBJECT_FORM_ENTRY_DISPLAY_ADD'])) {
+            $oForm = BxDolForm::getObjectInstance($CNF['OBJECT_FORM_ENTRY'], $CNF['OBJECT_FORM_ENTRY_DISPLAY_ADD'], $this->_oTemplate);
+
+            $aInputs = array_merge($aInputs, $oForm->aInputs);
+        }
+        if(!empty($CNF['OBJECT_FORM_ENTRY_DISPLAY_EDIT'])) {
+            $oForm = BxDolForm::getObjectInstance($CNF['OBJECT_FORM_ENTRY'], $CNF['OBJECT_FORM_ENTRY_DISPLAY_EDIT'], $this->_oTemplate);
+
+            $aInputs = array_merge($aInputs, $oForm->aInputs);
+        }
+
+        if(!empty($aInputsAdd) && is_array($aInputsAdd))
+            $aInputs = array_merge($aInputs, $aInputsAdd);
+
+        if(!empty($CNF['FIELD_LABELS']) && array_key_exists($CNF['FIELD_LABELS'], $aInputs) && !in_array($CNF['FIELD_LABELS'], $this->_aSearchableNamesExcept))
+            $aResult[$CNF['FIELD_LABELS']] = [
+                'type' => 'checkbox_set', 
+                'caption' => $CNF['T']['form_field_labels'] ?? '_sys_form_input_labels',
+                'info' => '',
+            	'value' => '',
+                'values' => '',
+                'pass' => '',
+                'search_operator' => 'like'
+            ];
+
+        if(($sField = $CNF['FIELD_ALLOW_VIEW_TO'] ?? '') != '' && array_key_exists($sField, $aInputs) && !in_array($sField, $this->_aSearchableNamesExcept)) 
+            $aInputs[$sField] = array_merge($aInputs[$sField], [
+                'search_type' => 'select',
+                'search_operator' => '='
+            ]);
+
+        foreach($aInputs as $aInput){
+            if(in_array($aInput['type'], BxDolSearchExtended::$SEARCHABLE_TYPES) && !in_array($aInput['name'], $this->_aSearchableNamesExcept)) {
+                $aField = array(
+                    'type' => $aInput['type'], 
+                    'caption_system' => $aInput['caption_system_src'],
+                    'caption' => $aInput['caption_src'],
+                    'info' => $aInput['info_src'],
+                    'value' => !empty($aInput['value']) ? $aInput['value'] : '',
+                    'values' => !empty($aInput['values_src']) ? $aInput['values_src'] : '',
+                    'pass' => !empty($aInput['db']['pass']) ? $aInput['db']['pass'] : '',
+                );
+
+                if(isset($aInput['search_type']))
+                    $aField['search_type'] = $aInput['search_type'];
+
+                if(isset($aInput['search_operator']))
+                    $aField['search_operator'] = $aInput['search_operator'];
+
+                $aResult[$aInput['name']] = $aField;
+            }
+        }
+
+        /**
+         * @hooks
+         * @hookdef hook-bx_base_general-get_searchable_fields '{module_name}', 'get_searchable_fields' - hook to override a list of searchable fields
+         * - $unit_name - module name
+         * - $action - equals `get_searchable_fields`
+         * - $object_id - not used
+         * - $sender_id - not used
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `override_result` - [array] a list of searchable fields, can be overridden in hook processing
+         * @hook @ref hook-bx_base_general-get_searchable_fields
+         */
+        bx_alert($this->getName(), 'get_searchable_fields', 0, 0, [
+            'extended' => true, 
+            'override_result' => &$aResult
+        ]);
+
+        return $aResult;
+    }
+
+    public function serviceGetSearchResultExtended($aParams, $iStart = 0, $iPerPage = 0, $bFilterMode = false)
+    {
+        if((empty($aParams) || !is_array($aParams)) && !$bFilterMode)
+            return array();
+
+        return $this->_oDb->getEntriesBy(array('type' => 'search_ids', 'search_params' => $aParams, 'start' => $iStart, 'per_page' => $iPerPage));
+    }
+
+    public function serviceGetSearchableFields ($aInputsAdd = array())
+    {
+        $CNF = $this->_oConfig->CNF;
+
+        if(!isset($CNF['PARAM_SEARCHABLE_FIELDS']) || !isset($CNF['OBJECT_FORM_ENTRY']) || !isset($CNF['OBJECT_FORM_ENTRY_DISPLAY_ADD']))
+            return array();
+
+        $oForm = BxDolForm::getObjectInstance($CNF['OBJECT_FORM_ENTRY'], $CNF['OBJECT_FORM_ENTRY_DISPLAY_ADD'], $this->_oTemplate);
+        if(!$oForm)
+            return array();
+
+        $aInputs = $oForm->aInputs;
+        if(!empty($aInputsAdd) && is_array($aInputsAdd))
+            $aInputs = array_merge($aInputs, $aInputsAdd);
+
+        $aTextTypes = array('text', 'textarea');
+        $aTextFields = array();
+        foreach($aInputs as $r)
+            if(in_array($r['type'], $aTextTypes))
+                $aTextFields[$r['name']] = $r['caption'];
+
+        return $aTextFields;
+    }
+
+    public function serviceUpdateImage($sFiledName, $iContentId, $sValue)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $aData = $this->_oDb->getContentInfoById($iContentId);
+        if(empty($aData) || !is_array($aData))
+            return false;
+
+        if($this->checkAllowedEdit($aData) !== CHECK_ACTION_RESULT_ALLOWED)
+            return false;
+
+        //TODO add transcoder settings
+        $oImgStorage = BxDolStorage::getObjectInstance($CNF['OBJECT_STORAGE']);
+        if(!$oImgStorage)
+            return false;
+
+        $this->_oDb->updateEntriesBy([$sFiledName => $sValue], [$CNF['FIELD_ID'] => $iContentId]);
+
+        $this->serviceUpdateImagePosition($iContentId, $sFiledName, '', '');
+
+        $this->onUpdateImage($iContentId, $sFiledName, $sValue);
+
+        return $oImgStorage->getFileUrlById($sValue);
+    }
+
+    public function serviceUpdateImagePosition($iContentId, $sFiledName, $sH, $sV)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $sFieldNamePos = 'FIELD_' . strtoupper($sFiledName) . '_POSITION';
+        if(!isset($CNF[$sFieldNamePos]))
+            return false;
+
+        $sValue = '';
+        if($sH != '' || $sV != '')
+            $sValue = json_encode(['x' => $sH, 'y' => $sV]);
+
+        $this->_oDb->updateEntriesBy([$CNF[$sFieldNamePos] => $sValue], [$CNF['FIELD_ID'] => $iContentId]);
+
+        if($this instanceof BxBaseModProfileModule) {
+            $aContentInfo = $this->_oDb->getContentInfoById($iContentId);
+            bx_content_cache_del_by_prefix('sprofile_unit_vars:' . $aContentInfo['profile_id'] . ':');
+        }
+
+        return true;
+    }
+
+    public function serviceManageTools($sType = 'common')
+    {
+        if(!isLogged())
+            return '';
+
+        $oGrid = BxDolGrid::getObjectInstance($this->_oConfig->getGridObject($sType));
+        if(!$oGrid)
+            return '';
+
+        if($this->_bIsApi)
+            return [
+                bx_api_get_block('grid', $oGrid->getCodeAPI())
+            ];
+
+        $CNF = &$this->_oConfig->CNF;
+
+        $mixedMenu = '';
+        if(BxDolAcl::getInstance()->isMemberLevelInSet(192)) {
+            $oPermalink = BxDolPermalinks::getInstance();
+
+            $aMenuItems = array();
+            if(!empty($CNF['OBJECT_GRID_COMMON']) && !empty($CNF['T']['menu_item_manage_my']))
+                $aMenuItems[] = array('id' => 'manage-common', 'name' => 'manage-common', 'class' => '', 'link' => $oPermalink->permalink($CNF['URL_MANAGE_COMMON']), 'target' => '_self', 'title' => _t($CNF['T']['menu_item_manage_my']), 'active' => 1);
+            if(!empty($CNF['OBJECT_GRID_ADMINISTRATION']) && !empty($CNF['T']['menu_item_manage_all']))
+                $aMenuItems[] = array('id' => 'manage-administration', 'name' => 'manage-administration', 'class' => '', 'link' => $oPermalink->permalink($CNF['URL_MANAGE_ADMINISTRATION']), 'target' => '_self', 'title' => _t($CNF['T']['menu_item_manage_all']), 'active' => 1);
+
+            if(count($aMenuItems) > 1) {
+                $mixedMenu = new BxTemplMenu(array(
+                    'template' => 'menu_block_submenu_ver.html', 
+                    'menu_items' => $aMenuItems
+                ), $this->_oTemplate);
+                $mixedMenu->setSelected($this->_aModule['name'], 'manage-' . $sType);
+            }
+        }
+
+        if(!empty($CNF['OBJECT_MENU_SUBMENU']) && isset($CNF['URI_MANAGE_COMMON']) && ($oSubmenu = BxDolMenu::getObjectInstance($CNF['OBJECT_MENU_SUBMENU'])) !== false)
+            $oSubmenu->setSelected($this->_aModule['name'], $CNF['URI_MANAGE_COMMON']);
+
+        $this->_oTemplate->addCss(array('manage_tools.css'));
+        $this->_oTemplate->addJs(array('manage_tools.js'));
+        $this->_oTemplate->addJsTranslation(array('_sys_grid_search'));
+        return array(
+            'content' => $this->_oTemplate->getJsCode('manage_tools', array('sObjNameGrid' => $this->_oConfig->getGridObject($sType))) . $oGrid->getCode(),
+            'menu' => $mixedMenu
+        );
+    }
+
+    public function serviceGetMenuAddonManageTools()
+    {
+        return 0;
+    }
+
+    public function serviceGetMenuAddonManageToolsProfileStats($iProfileId = 0)
+    {
+        return 0;
+    }
+
+    public function serviceGetObjectBrowse($sMode, $aParams = false, $sClassSearchResult = 'SearchResult')
+    {
+        if(empty($aParams) || !is_array($aParams))
+            $aParams = [];
+
+        return $this->getObjectBrowse($sMode, array_merge(['mode' => $sMode], $aParams), $sClassSearchResult);
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_base_general Base General
+     * @subsection bx_base_general-browsing Browsing
+     * @subsubsection bx_base_general-browse browse
+     * 
+     * @code bx_srv('bx_posts', 'browse', [...]); @endcode
+     * @code {{~bx_posts:browse[{"mode":"author", "params":{"author":"10"}}]~}} @endcode
+     * 
+     * Universal browse method.
+     * @param $aParams custom browse params, possible params are the following:
+     *  - mode - browse mode, such as 'recent', 'featured', etc
+     *  - params - custom params to browse method, for example 'unit_view' can be passed here
+     *  - design_box - design box style, @see BxBaseFunctions::DesignBoxContent 
+     *  - empty_message - display or not "empty" message when there is no content
+     *  - ajax_paginate - use AJAX paginate or not
+     * 
+     * @see BxBaseModGeneralModule::serviceBrowse
+     */
+    /** 
+     * @ref bx_base_general-browse "browse"
+     */
+    public function serviceBrowse ($aParams = array())
+    {
+        if($this->_bIsApi && is_string($aParams)){
+            $aParams = json_decode($aParams, true);
+            if (isset($aParams['params'])) {
+                if(($sK = 'type') && isset($aParams['params'][$sK]))
+                    $aParams['mode'] = $aParams['params'][$sK];
+
+                if(($sK = 'class_search_result') && isset($aParams['params'][$sK]))
+                    $aParams[$sK] = $aParams['params'][$sK];
+
+                if(isset($aParams['params']['filters'])) {
+                    foreach($aParams['params']['filters'] as $sKey => $sValue)
+                        $aParams['params'][$sKey] = $sValue;
+
+                    $aParams['params']['filters'] = [
+                        'values' => $aParams['params']['filters']
+                    ];
+                }
+            }
+        }
+
+        if (isset($aParams['params']['condition']))
+            unset($aParams['params']['condition']);
+
+        return $this->serviceBrowseWithCondition ($aParams);
+    }
+
+    public function serviceBrowseWithCondition ($aParams = array())
+    {
+        $aDefaults = array (
+            'mode' => 'recent',
+            'params' => false,
+            'design_box' => BX_DB_PADDING_DEF,
+            'empty_message' => false,
+            'ajax_paginate' => true,
+            'class_search_result' => 'SearchResult'
+        );
+
+        $aParams = array_merge($aDefaults, $aParams);
+        
+        return $this->_serviceBrowse ($aParams['mode'], $aParams['params'], $aParams['design_box'], $aParams['empty_message'], $aParams['ajax_paginate'], $aParams['class_search_result']);
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_base_general Base General
+     * @subsection bx_base_general-browsing Browsing
+     * @subsubsection bx_base_general-browse_featured browse_featured
+     * 
+     * @code bx_srv('bx_posts', 'browse_featured', [...]); @endcode
+     * 
+     * Display featured entries
+     * @param $sUnitView browsing unity view, 
+     *                   such as: full, extended, gallery, showcase
+     * @param $bEmptyMessage display or not "empty" message when there is no content
+     * @param $bAjaxPaginate use AJAX paginate or not
+     * 
+     * @see BxBaseModGeneralModule::serviceBrowseFeatured
+     */
+    /** 
+     * @ref bx_base_general-browse_featured "browse_featured"
+     */
+    public function serviceBrowseFeatured ($sUnitView = false, $bEmptyMessage = false, $bAjaxPaginate = true)
+    {
+        return $this->_serviceBrowse ('featured', $sUnitView ? array('unit_view' => $sUnitView) : false, BX_DB_PADDING_DEF, $bEmptyMessage, $bAjaxPaginate);
+    }
+	
+    /**
+     * @page service Service Calls
+     * @section bx_base_general Base General
+     * @subsection bx_base_general-browsing Browsing
+     * @subsubsection bx_base_general-browse_favorite browse_favorite
+     * 
+     * @code bx_srv('bx_posts', 'browse_favorite', [...]); @endcode
+     * 
+     * Display entries which were added to favorite list by some member
+     * @param $iProfileId profile ID
+     * @param $aParams additional browse params, see BxBaseModGeneralModule::serviceBrowse
+     * 
+     * @see BxBaseModGeneralModule::serviceBrowseFavorite BxBaseModGeneralModule::serviceBrowse
+     */
+    /** 
+     * @ref bx_base_general-browse_favorite "browse_favorite"
+     */
+    public function serviceBrowseFavorite ($iProfileId = 0, $aParams = array())
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $oProfile = null;
+        if((int)$iProfileId)
+            $oProfile = BxDolProfile::getInstance($iProfileId);
+        if(!$oProfile && bx_get('profile_id') !== false)
+            $oProfile = BxDolProfile:: getInstance(bx_process_input(bx_get('profile_id'), BX_DATA_INT));
+        if(!$oProfile)
+            $oProfile = BxDolProfile::getInstance();
+        if(!$oProfile)
+            return '';
+
+        $bEmptyMessage = true;
+        if(isset($aParams['empty_message'])) {
+            $bEmptyMessage = (bool)$aParams['empty_message'];
+            unset($aParams['empty_message']);
+        }
+        
+        if(bx_get('list_id') !== false && !isset($aParams['list_id']))
+            $aParams['list_id'] = (int) bx_get('list_id');        
+
+        $aBlock = $this->_serviceBrowse ('favorite', array_merge(array('user' => $oProfile->id()), $aParams), BX_DB_PADDING_DEF, $bEmptyMessage);
+        if(!$aBlock)
+            return $aBlock;
+
+        $sTitle = _t('_sys_txt_default_favorite_list');
+        if(!empty($aParams['list_id']) && ($oFavorite = BxDolFavorite::getObjectInstance($CNF['OBJECT_FAVORITES'], 0, true))) {
+            $aList = $oFavorite->getQueryObject()->getList(['type' => 'id', 'list_id' => $aParams['list_id']]);
+            if(!empty($aList) && is_array($aList))
+                $sTitle = $aList['title'];
+        }
+
+        return array_merge($aBlock, ['markers' => [
+            'title' => $sTitle
+        ]]);
+    }
+    
+    /**
+     * @page service Service Calls
+     * @section bx_base_general Base General
+     * @subsection bx_base_general-browsing Browsing
+     * @subsubsection bx_base_general-browse_favorite_lists browse_favorite_lists
+     * 
+     * @code bx_srv('bx_posts', 'browse_favorite_lists', [...]); @endcode
+     * 
+     * Display entries which were added to favorite lists grouped by lists by some member
+     * @param $iProfileId profile ID
+     * @param $aParams additional browse params, see BxBaseModGeneralModule::serviceBrowse
+     * 
+     * @see BxBaseModGeneralModule::serviceBrowseFavoriteLists BxBaseModGeneralModule::serviceBrowse
+     */
+    /** 
+     * @ref bx_base_general-browse_favorite_lists "browse_favorite_lists"
+     */
+    public function serviceBrowseFavoriteLists ($iProfileId = 0, $aParams = array())
+    {
+        $CNF = &$this->_oConfig->CNF;
+        
+        $oProfile = null;
+        if((int)$iProfileId)
+            $oProfile = BxDolProfile::getInstance($iProfileId);
+        if(!$oProfile && bx_get('profile_id') !== false)
+            $oProfile = BxDolProfile:: getInstance(bx_process_input(bx_get('profile_id'), BX_DATA_INT));
+        if(!$oProfile)
+            $oProfile = BxDolProfile::getInstance();
+        if(!$oProfile)
+            return '';
+        
+        $iStart = (bx_get('list_start') !== false ? (int)bx_get('list_start') : 0);
+        $iPerPage = (int)getParam($CNF['PARAM_PER_PAGE_FOR_FAVORITES_LISTS']);
+        
+        return $this->_oTemplate->getFavoriteList($oProfile, $iStart, $iPerPage, $aParams);
+    }
+    
+    /**
+     * @page service Service Calls
+     * @section bx_base_general Base General
+     * @subsection bx_base_general-browsing Browsing
+     * @subsubsection bx_base_general-browse_by_category category
+     * 
+     * @code bx_srv('bx_posts', 'browse_by_category', [...]); @endcode
+     * 
+     * Display entries in category
+     * @param $sUnitView browsing unity view, 
+     *                   such as: full, extended, gallery, showcase
+     * @param $bEmptyMessage display or not "empty" message when there is no content
+     * @param $bAjaxPaginate use AJAX paginate or not
+     * 
+     * @see BxBaseModGeneralModule::serviceBrowseByCategory BxBaseModGeneralModule::serviceBrowse
+     */
+    /** 
+     * @ref bx_base_general-browse_by_category "browse_by_category"
+     */
+    public function serviceBrowseCategory($sUnitView = false, $bEmptyMessage = true, $bAjaxPaginate = true, $aParams = [])
+    {
+        $sType = 'category';
+
+        $aParams = array_merge(['category' => bx_process_input(bx_get('category'), BX_DATA_INT)], $aParams);
+        if($sUnitView)
+            $aParams['unit_view'] = $sUnitView;
+
+        return $this->_serviceBrowse($sType, $aParams, BX_DB_PADDING_DEF, $bEmptyMessage, $bAjaxPaginate);
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_base_general Base General
+     * @subsection bx_base_general-browsing Browsing
+     * @subsubsection bx_base_general-browse_multi_category category
+     * 
+     * @code bx_srv('bx_posts', 'browse_multi_category', [...]); @endcode
+     * 
+     * Display entries in multi category
+     * @param $sUnitView browsing unity view, 
+     *                   such as: full, extended, gallery, showcase
+     * @param $bEmptyMessage display or not "empty" message when there is no content
+     * @param $bAjaxPaginate use AJAX paginate or not
+     * 
+     * @see BxBaseModGeneralModule::serviceBrowseMultiCategory BxBaseModGeneralModule::serviceBrowse
+     */
+    /** 
+     * @ref bx_base_general-browse_multi_category "browse_multi_category"
+     */
+    public function serviceBrowseMultiCategory($sUnitView = false, $bEmptyMessage = true, $bAjaxPaginate = true, $aParams = [])
+    {
+        $sType = 'multi_category';
+
+        $aParams = array_merge(['category' => bx_process_input(bx_get('category'))], $aParams);
+        if($sUnitView)
+            $aParams['unit_view'] = $sUnitView;
+
+        return $this->_serviceBrowse($sType, $aParams, BX_DB_PADDING_DEF, $bEmptyMessage, $bAjaxPaginate);
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_base_general Base General
+     * @subsection bx_base_general-browsing Browsing
+     * @subsubsection bx_base_general-browse_favorite_list_actions browse_favorite_list_actions
+     * 
+     * @code bx_srv('bx_posts', 'browse_favorite_list_actions', [...]); @endcode
+     * 
+     * Display menu actions for favorite lists
+     * 
+     * @see BxBaseModGeneralModule::serviceFavoritesListActions
+     */
+    /** 
+     * @ref bx_base_general-browse_favorite_list_actions "browse_favorite_list_actions"
+     */
+    public function serviceFavoritesListActions()
+    {
+        $iListId = 0;
+        if(bx_get('list_id') !== false)
+            $iListId = (int) bx_get('list_id');        
+
+        $oProfile = null;
+        if(bx_get('profile_id') !== false)
+            $oProfile = BxDolProfile:: getInstance(bx_process_input(bx_get('profile_id'), BX_DATA_INT));
+        if(!$oProfile)
+            return false;
+
+        $CNF = &$this->_oConfig->CNF;
+        $oFavorite = BxDolFavorite::getObjectInstance($CNF['OBJECT_FAVORITES'], 0, true);
+
+        $aList = $oFavorite->getQueryObject()->getList(array('type' => 'id', 'list_id' => $iListId));
+        if($iListId != 0 && (empty($aList) || !is_array($aList)))
+            return false;
+
+        $sRv = '';
+        if (!empty($aList) && $oFavorite->isAllowedEditList($aList['author_id'])){  
+            $aMarkers = array(
+                'js_object' => $oFavorite->getJsObjectName(),
+                'list_id' => $iListId,
+            );
+
+            $oMenu = BxDolMenu::getObjectInstance('sys_favorite_list');
+
+            $oMenu->addMarkers($aMarkers);
+            $sMenu = $oMenu->getCode();
+
+            $sRv .= $sMenu . $oFavorite->getJsScript();
+        }
+
+        $aMarkers = array(
+            'id' => $iListId,
+            'module' => $this->_aModule['name'],
+            'url' => $this->_getFavoriteListUrl($iListId, $oProfile->id()),
+            'title' => $iListId > 0 ? $aList['title'] : _t('_sys_txt_default_favorite_list')
+        );
+
+        $oMenu = BxDolMenu::getObjectInstance('sys_social_sharing');
+        $oMenu->addMarkers($aMarkers);
+        $sRv .= $sMenu = $oMenu->getCode();
+        return $sRv;
+    }
+     
+     /**
+    * @page service Service Calls
+    * @section bx_base_general Base General
+    * @subsection bx_base_general-menu Menu
+    * @subsubsection bx_base_general-favorites_list_info favorites_list_info
+    * 
+    * @code bx_srv('bx_posts', 'favorites_list_info', [...]); @endcode
+    * 
+    * Favorites list info
+    * @param $aParams array with additional custom params 
+    *                 which may overwrite some default values
+    * 
+    * @see BxBaseModGeneralModule::serviceFavoritesListInfo
+    */
+    /** 
+    * @ref bx_base_general-favorites_list_info "favorites_list_info"
+    */
+    public function serviceFavoritesListInfo($aParams = array())
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $iListId = 0;
+        if(bx_get('list_id') !== false)
+            $iListId = (int) bx_get('list_id');       
+
+        $oFavorite = BxDolFavorite::getObjectInstance($CNF['OBJECT_FAVORITES'], 0, true);
+        $aList = $oFavorite->getQueryObject()->getList(array('type' => 'id', 'list_id' => $iListId));
+        if($iListId != 0 && (empty($aList) || !is_array($aList)))
+            return false;
+
+        $oProfile = null;
+        if(bx_get('profile_id') !== false)
+            $oProfile = BxDolProfile:: getInstance(bx_process_input(bx_get('profile_id'), BX_DATA_INT));
+
+        if(!$oProfile)
+            return false;
+
+        return $this->_oTemplate->getFavoritesListInfo($aList, $oProfile);
+    }
+    
+    /**
+     * Display entries posted into particular context
+     * @return HTML string
+     */
+    public function serviceBrowseContext ($iProfileId = 0, $aParams = array())
+    {
+        return $this->_serviceBrowseWithParam ('context', 'profile_id', $iProfileId, $aParams);
+    }
+
+    public function serviceBrowseFollowedContexts ($iProfileId = 0, $aParams = [])
+    {
+        return $this->_serviceBrowseWithParam ('followed_contexts', 'profile_id', $iProfileId, $aParams);
+    }
+
+    public function _serviceBrowseWithParam ($sParamName, $sParamGet, $sParamVal, $aParams = array())
+    {
+        if(!$sParamVal)
+            $sParamVal = bx_process_input(bx_get($sParamGet), BX_DATA_INT);
+        if(!$sParamVal)
+            return '';
+
+        $bEmptyMessage = true;
+        if(isset($aParams['empty_message'])) {
+            $bEmptyMessage = (bool)$aParams['empty_message'];
+            unset($aParams['empty_message']);
+        }
+
+        $bAjaxPaginate = true;
+        if(isset($aParams['ajax_paginate'])) {
+            $bAjaxPaginate = (bool)$aParams['ajax_paginate'];
+            unset($aParams['ajax_paginate']);
+        }
+
+        return $this->_serviceBrowse ($sParamName, array_merge(array($sParamName => $sParamVal), $aParams), BX_DB_PADDING_DEF, $bEmptyMessage, $bAjaxPaginate);
+    }
+
+    public function getFormsHelper ()
+    {
+        $sClass = 'FormsEntryHelper';
+        $oObject = null;
+
+        bx_alert('system', 'get_forms_helper', 0, 0, [
+            'module' => $this->getName(),
+            'class' => &$sClass,
+            'class_ref' => &$sClass,
+            'object' => &$oObject
+        ]);
+
+        if($oObject !== null) 
+            return $oObject;
+
+        bx_import($sClass, $this->_aModule);
+        $sClass = $this->_aModule['class_prefix'] . $sClass;
+        return new $sClass($this);
+    }
+
+    public function serviceFormsHelper()
+    {
+        return $this->getFormsHelper();
+    }
+
+    /**
+     * Add entry using provided fields' values.
+     * @return array with result: 
+     * 'code' is 0 on success or non-zero on error, 
+     * 'message' is error message in case of error, 
+     * 'content' is content info array in case of success
+     */
+    public function serviceEntityAdd($iProfile, $aValues, $sDisplay = false)
+    {
+        $oFormsHelper = $this->getFormsHelper();
+        return $oFormsHelper->addData($iProfile, $aValues, $sDisplay);
+    }
+
+    public function serviceEntityAddForcedly($iProfile, $aValues, $sDisplay = false)
+    {
+        $oFormsHelper = $this->getFormsHelper();
+        $oFormsHelper->setValidMode(true);
+        return $oFormsHelper->addData($iProfile, $aValues, $sDisplay);
+    }
+
+    /**
+     * Perform redirect after content creation
+     * @return nothing, rediret header is sent
+     */    
+    public function serviceRedirectAfterAdd($aContentInfo)
+    {
+        $oFormsHelper = $this->getFormsHelper();
+        $oFormsHelper->redirectAfterAdd($aContentInfo);
+    }
+
+    /**
+     * Get form object for add, edit, view or delete the content 
+     * @param $sType 'add', 'edit', 'view' or 'delete'
+     * @param $aParams optional array with parameters(display name, etc)
+     * @return form object or false on error
+     */
+    public function serviceGetObjectForm ($sType, $aParams = array())
+    {
+        if(!in_array($sType, array('add', 'edit', 'view', 'delete')))
+            return false;
+
+        $iLoggedId = (int)bx_get_logged_profile_id();
+        $mixedContextId = isset($aParams['context_id']) ? $aParams['context_id'] : false;
+
+        $oContextProfile = false;
+        $bContext = $mixedContextId !== false;
+        if($bContext) {
+            $oContextProfile = BxDolProfile::getInstance(abs($mixedContextId));
+            $bContext = $oContextProfile !== false;
+
+            if($bContext && $oContextProfile->checkAllowedPostInProfile() !== CHECK_ACTION_RESULT_ALLOWED)
+                return false;
+        }
+
+        $CNF = &$this->_oConfig->CNF;
+        $oFormsHelper = $this->getFormsHelper();
+
+        $sParamsKey = 'ajax_mode';
+        if(isset($aParams[$sParamsKey]) && (bool)$aParams[$sParamsKey] === true)
+            $oFormsHelper->setAjaxMode((bool)$aParams[$sParamsKey]);
+
+        $sParamsKey = 'absolute_action_url';
+        if(isset($aParams[$sParamsKey]) && (bool)$aParams[$sParamsKey] === true)
+            $oFormsHelper->setAbsoluteActionUrl((bool)$aParams[$sParamsKey]);
+
+        if($bContext)
+            $oFormsHelper->setContextId($mixedContextId);
+
+        $sDisplay = !empty($aParams['display']) ? $aParams['display'] : false;
+
+        $sFunc = 'getObjectForm' . ucfirst($sType);
+        $oForm = $oFormsHelper->$sFunc($sDisplay);
+
+        $sKey = 'FIELD_ALLOW_VIEW_TO';
+        if(!empty($CNF[$sKey]) && !empty($oForm->aInputs[$CNF[$sKey]]) && (!$bContext || $mixedContextId < 0)) {
+            $bContextOwner = $bContext && abs($mixedContextId) == $iLoggedId;
+
+            if(!$bContext || $bContextOwner) {
+                $iGc = 0;
+                $iKeyGh = false;
+                foreach($oForm->aInputs[$CNF[$sKey]]['values'] as $iKey => $aValue) {
+                    if(isset($aValue['type']) && in_array($aValue['type'], array('group_header', 'group_end'))) {
+                        if($iKeyGh !== false && $iGc == 0) {
+                            unset($oForm->aInputs[$CNF[$sKey]]['values'][$iKeyGh]);
+                            $iKeyGh = false;
+
+                            if($aValue['type'] == 'group_end')
+                                unset($oForm->aInputs[$CNF[$sKey]]['values'][$iKey]);
+                        }
+
+                        if($aValue['type'] == 'group_header') {
+                            $iGc = 0;
+                            $iKeyGh = $iKey;
+                        }
+
+                        continue;
+                    }
+
+                    //--- Show 'Public' privacy group only in Public post form. 
+                    if(!$bContext && $aValue['key'] == BX_DOL_PG_ALL) {
+                        $iGc += 1;
+                        continue;
+                    }
+
+                    //--- Show a default privacy groups in Profile (for Owner) post form.
+                    if($bContextOwner && ((int)$aValue['key'] >= 0 || $mixedContextId == $aValue['key'])) {
+                        $iGc += 1;
+                        continue;
+                    }
+
+                    unset($oForm->aInputs[$CNF[$sKey]]['values'][$iKey]);
+                }
+            }
+            else {
+                $oForm->aInputs[$CNF[$sKey]]['value'] = $mixedContextId;
+                $oForm->aInputs[$CNF[$sKey]]['type'] = 'hidden';
+            }
+        }
+
+        $sKey = 'FIELD_LABELS';
+        if(!empty($CNF[$sKey]) && !empty($oForm->aInputs[$CNF[$sKey]]) && empty($oForm->aInputs[$CNF[$sKey]]['value']) && $bContext) {
+            $iContextProfileId = $oContextProfile->id();
+            $sContextModule = $oContextProfile->getModule();
+            
+            if(bx_srv($sContextModule, 'is_fan', [$iContextProfileId, $iLoggedId])) {
+                $aContextInfo = bx_srv($sContextModule, 'get_content_info_by_profile_id', [$iContextProfileId]);
+                if(!empty($aContextInfo['hashtag']))
+                    $oForm->aInputs[$CNF[$sKey]]['value'] = [$aContextInfo['hashtag']];
+            }
+        }
+
+        /**
+         * @hooks
+         * @hookdef hook-system-get_object_form 'system', 'get_object_form' - hook to override an object of create content form, @see BxDolForm
+         * - $unit_name - equals `system`
+         * - $action - equals `get_object_form`
+         * - $object_id - not used
+         * - $sender_id - not used
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `module` - [string] module name
+         *      - `type` - [string] 'add', 'edit', 'view' or 'delete' form display type
+         *      - `params` - [array] form params array as key&value pairs
+         *      - `form` - [object] by ref, an object of create content form, @see BxDolForm, can be overridden in hook processing
+         * @hook @ref hook-system-get_object_form
+         */
+        bx_alert('system', 'get_object_form', 0, 0, [
+            'module' => $this->_oConfig->getName(),
+            'type' => $sType,
+            'params' => $aParams,
+            'form' => &$oForm
+        ]);
+
+        return $oForm;
+    }
+
+    /**
+     *
+     *
+     * Create entry form
+     * @return HTML string
+     */
+    public function serviceEntityCreate ($sParams = false)
+    {
+        if($this->_bIsApi && ($aParams = bx_api_get_browse_params($sParams))) {
+            if(($aKeys = ['context_pid', 'context_nid', 'context_usage']) && ($aParamsContext = array_intersect_key($aParams, array_flip($aKeys)))) {
+                $_GET = array_merge($_GET, $aParamsContext);
+                $sParams = array_diff_key($aParams, array_flip($aKeys));
+            }
+        }
+
+        $bParamsArray = is_array($sParams);
+
+        $sDisplay = is_string($sParams) ? $sParams : false;
+        if($bParamsArray && !empty($sParams['display']))
+            $sDisplay = $sParams['display'];
+
+        $oFormsHelper = $this->getFormsHelper();
+        if($bParamsArray && isset($sParams['dynamic_mode']))
+            $oFormsHelper->setDynamicMode($sParams['dynamic_mode']);
+
+        $mixedResult = $oFormsHelper->addDataForm($sDisplay);
+        if($this->_bIsApi)
+            return $mixedResult;
+        
+        if(isset($mixedResult['_dt']) && $mixedResult['_dt'] == 'json') {
+            echoJson($mixedResult);
+            exit;
+        }
+
+        return $mixedResult;
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_base_general Base General
+     * @subsection bx_base_general-forms Forms
+     * @subsubsection bx_base_general-get_create_post_form get_create_post_form
+     * 
+     * @code bx_srv('bx_posts', 'get_create_post_form'); @endcode
+     * 
+     * Get content creation form
+     * @param $aParams additional parameters array: 
+     *                 context_id, ajax_mode, absolute_action_url, displays
+     * 
+     * @see BxBaseModGeneralModule::serviceGetCreatePostForm
+     */
+    /** 
+     * @ref bx_base_general-get_create_post_form "get_create_post_form"
+     */
+    public function serviceGetCreatePostForm($aParams = [])
+    {
+    	$aParams = array_merge($this->_aFormParams, $aParams);
+
+        if($aParams['context_id'] !== false && ($aContextInfo = BxDolProfileQuery::getInstance()->getInfoById(abs($aParams['context_id']))))
+            if(bx_srv($aContextInfo['type'], 'check_allowed_post_in_profile', [$aContextInfo['content_id'], $this->getName()]) !== CHECK_ACTION_RESULT_ALLOWED)
+                return '';
+
+    	$oForm = $this->serviceGetObjectForm('add', $aParams);
+    	if(!$oForm)
+            return '';
+
+    	return $this->serviceEntityCreate($aParams);
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_base_general Base General
+     * @subsection bx_base_general-forms Forms
+     * @subsubsection bx_base_general-entity_edit entity_edit
+     * 
+     * @code bx_srv('bx_posts', 'entity_edit', [...]); @endcode
+     * 
+     * Get content edit form
+     * @param $iContentId content ID
+     * @param $sDisplay optional form display name
+     * 
+     * @see BxBaseModGeneralModule::serviceEntityEdit
+     */
+    /** 
+     * @ref bx_base_general-entity_edit "entity_edit"
+     */
+    public function serviceEntityEdit ($iContentId = 0, $sDisplay = false)
+    {
+        return $this->_serviceEntityForm ('editDataForm', $iContentId, $sDisplay);
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_base_general Base General
+     * @subsection bx_base_general-forms Forms
+     * @subsubsection bx_base_general-entity_delete entity_delete
+     * 
+     * @code bx_srv('bx_posts', 'entity_delete', [...]); @endcode
+     * 
+     * Get content delete form
+     * @param $iContentId content ID
+     * 
+     * @see BxBaseModGeneralModule::serviceEntityDelete
+     */
+    /** 
+     * @ref bx_base_general-entity_delete "entity_delete"
+     */
+    public function serviceEntityDelete ($iContentId = 0)
+    {
+        $mixedResult = $this->_serviceEntityForm ('deleteDataForm', $iContentId);
+        if(!bx_is_api()) 
+            return $mixedResult;
+
+        $aResult = [];
+        if(is_a($mixedResult, 'BxTemplFormView')){
+            $iContentId = $this->_getContent($iContentId, false);
+            $aResult = bx_api_get_block('form', $mixedResult->getCodeAPI(), ['ext' => ['name' => $this->getName(), 'request' => ['url' => '/api.php?r=' . $this->_aModule['name'] . '/entity_delete&params[]=' . $iContentId . '&params[]=' . $mixedResult->aParams['display'], 'immutable' => true]]]);
+        }
+        else
+            $aResult = $mixedResult;
+
+        return [
+            $aResult
+        ];
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_base_general Base General
+     * @subsection bx_base_general-page_blocks Page Blocks
+     * @subsubsection bx_base_general-entity_text_block entity_text_block
+     * 
+     * @code bx_srv('bx_posts', 'entity_text_block', [...]); @endcode
+     * 
+     * Get content text/description
+     * @param $iContentId content ID
+     * 
+     * @see BxBaseModGeneralModule::serviceEntityTextBlock
+     */
+    /** 
+     * @ref bx_base_general-entity_text_block "entity_text_block"
+     */
+    public function serviceEntityTextBlock ($iContentId = 0)
+    {
+        return $this->_serviceEntityForm ('viewDataEntry', $iContentId);
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_base_general Base General
+     * @subsection bx_base_general-page_blocks Page Blocks
+     * @subsubsection bx_base_general-entity_info entity_info
+     * 
+     * @code bx_srv('bx_posts', 'entity_info', [...]); @endcode
+     * 
+     * Get content info
+     * @param $iContentId content ID
+     * 
+     * @see BxBaseModGeneralModule::serviceEntityInfo
+     */
+    /** 
+     * @ref bx_base_general-entity_info "entity_info"
+     */
+    public function serviceEntityInfo ($iContentId = 0, $sDisplay = false)
+    {
+        return $this->_serviceEntityForm ('viewDataForm', $iContentId, $sDisplay);
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_base_general Base General
+     * @subsection bx_base_general-page_blocks Page Blocks
+     * @subsubsection bx_base_general-entity_info_full entity_info_full
+     * 
+     * @code bx_srv('bx_posts', 'entity_info_full', [...]); @endcode
+     * 
+     * Get full content info
+     * @param $iContentId content ID
+     * 
+     * @see BxBaseModGeneralModule::serviceEntityInfoFull
+     */
+    /** 
+     * @ref bx_base_general-entity_info_full "entity_info_full"
+     */
+	public function serviceEntityInfoFull ($iContentId = 0)
+    {
+    	$CNF = &$this->_oConfig->CNF;
+
+    	$sDisplayName = 'OBJECT_FORM_ENTRY_DISPLAY_VIEW_FULL';
+        return $this->_serviceEntityForm ('viewDataForm', $iContentId, !empty($CNF[$sDisplayName]) ? $CNF[$sDisplayName] : false);
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_base_general Base General
+     * @subsection bx_base_general-page_blocks Page Blocks
+     * @subsubsection bx_base_general-entity_info_extended entity_info_extended
+     * 
+     * @code bx_srv('bx_posts', 'entity_info_extended', [...]); @endcode
+     * 
+     * Get extended content info
+     * @param $iContentId content ID
+     * 
+     * @see BxBaseModGeneralModule::serviceEntityInfoExtended
+     */
+    /** 
+     * @ref bx_base_general-entity_info_extended "entity_info_extended"
+     */
+	public function serviceEntityInfoExtended ($iContentId = 0)
+    {
+        return $this->_serviceTemplateFunc ('entryInfo', $iContentId);
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_base_general Base General
+     * @subsection bx_base_general-page_blocks Page Blocks
+     * @subsubsection bx_base_general-entity_location entity_location
+     * 
+     * @code bx_srv('bx_posts', 'entity_location', [...]); @endcode
+     * 
+     * Get content location
+     * @param $iContentId content ID
+     * 
+     * @see BxBaseModGeneralModule::serviceEntityLocation
+     */
+    /** 
+     * @ref bx_base_general-entity_location "entity_location"
+     */
+    public function serviceEntityLocation ($iContentId = 0)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $mixedContent = $this->_getContent($iContentId);
+        if($mixedContent === false)
+            return false;
+
+        list($iContentId, $aContentInfo) = $mixedContent;
+
+        $oFormsHelper = $this->getFormsHelper();
+        $oFormView = $oFormsHelper->getObjectFormView();
+        if(!$oFormView)
+            return false;
+        
+        $oFormView->initChecker($aContentInfo);
+        if(empty($CNF['FIELD_LOCATION']) || !$oFormView->isInputVisible($CNF['FIELD_LOCATION']))
+            return false;
+
+        return $this->_oTemplate->entryLocation ($iContentId);
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_base_general Base General
+     * @subsection bx_base_general-page_blocks Page Blocks
+     * @subsubsection bx_base_general-entity_comments entity_comments
+     * 
+     * @code bx_srv('bx_posts', 'entity_comments', [...]); @endcode
+     * 
+     * Get content comments
+     * @param $iContentId content ID
+     * 
+     * @see BxBaseModGeneralModule::serviceEntityComments
+     */
+    /** 
+     * @ref bx_base_general-entity_comments "entity_comments"
+     */
+    public function serviceEntityComments ($iContentId = 0)
+    {
+        $CNF = &$this->_oConfig->CNF;
+        if(empty($CNF['OBJECT_COMMENTS']))
+            return '';
+
+        return $this->_entityComments($CNF['OBJECT_COMMENTS'], $iContentId);
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_base_general Base General
+     * @subsection bx_base_general-page_blocks Page Blocks
+     * @subsubsection bx_base_general-entity_attachments entity_attachments
+     * 
+     * @code bx_srv('bx_posts', 'entity_attachments', [...]); @endcode
+     * 
+     * Get content attachments
+     * @param $iContentId content ID
+     * 
+     * @see BxBaseModGeneralModule::serviceEntityAttachments
+     */
+    /** 
+     * @ref bx_base_general-entity_attachments "entity_attachments"
+     */
+    public function serviceEntityAttachments ($iContentId = 0)
+    {
+        return $this->_serviceTemplateFunc ('entryAttachments', $iContentId);
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_base_general Base General
+     * @subsection bx_base_general-page_blocks Page Blocks
+     * @subsubsection bx_base_general-entity_polls entity_polls
+     * 
+     * @code bx_srv('bx_posts', 'entity_polls', [...]); @endcode
+     * 
+     * Display polls for the specified post
+     * @param $iContentId content ID
+     * 
+     * @see BxBaseModGeneralModule::serviceEntityPolls
+     */
+    /** 
+     * @ref bx_base_general-entity_polls "entity_polls"
+     */
+    public function serviceEntityPolls ($iContentId = 0)
+    {
+        return $this->_serviceTemplateFunc ('entryPolls', $iContentId);
+    }
+
+    /**
+     * Delete content entry
+     * @param $iContentId content id 
+     * @return error message or empty string on success
+     */
+    public function serviceDeleteEntity ($iContentId, $sFuncDelete = 'deleteData')
+    {
+        $oFormsHelper = $this->getFormsHelper();
+        return $oFormsHelper->$sFuncDelete($iContentId);
+    }
+
+    /**
+     * Edit content entry
+     * @param $iContentId content id 
+     * @param $aValues key value pairs to update
+     * @return error message or empty string on success
+     */
+    public function serviceEditEntity ($iContentId, $aValues, $sDisplay = false)
+    {
+        $oFormsHelper = $this->getFormsHelper();
+        return $oFormsHelper->editData($iContentId, $aValues, $sDisplay);
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_base_general Base General
+     * @subsection bx_base_general-menu Menu
+     * @subsubsection bx_base_general-my_entries_actions my_entries_actions
+     * 
+     * @code bx_srv('bx_posts', 'my_entries_actions', [...]); @endcode
+     * 
+     * My entries actions menu
+     * @param $iProfileId profiles ID, 
+     *        if omitted it try to get it from 'profile_id' GET param
+     * 
+     * @see BxBaseModGeneralModule::serviceMyEntriesActions
+     */
+    /** 
+     * @ref bx_base_general-my_entries_actions "my_entries_actions"
+     */
+    public function serviceMyEntriesActions ($iProfileId = 0)
+    {
+        $CNF = &$this->_oConfig->CNF;
+        if(empty($CNF['OBJECT_MENU_ACTIONS_MY_ENTRIES']))
+            return false;
+
+        if (!$iProfileId)
+            $iProfileId = bx_process_input(bx_get('profile_id'), BX_DATA_INT);
+        if (!$iProfileId || !($oProfile = BxDolProfile::getInstance($iProfileId)))
+            return false;
+
+        if ($iProfileId != $this->_iProfileId)
+            return false;
+
+        $oMenu = BxTemplMenu::getObjectInstance($CNF['OBJECT_MENU_ACTIONS_MY_ENTRIES']);
+        return $oMenu ? $oMenu->getCode() : false;
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_base_general Base General
+     * @subsection bx_base_general-menu Menu
+     * @subsubsection bx_base_general-entity_all_actions entity_all_actions
+     * 
+     * @code bx_srv('bx_posts', 'entity_all_actions', [...]); @endcode
+     * 
+     * Entry actions and social sharing actions
+     * @param $mixedContent content ID
+     * @param $aParams additional params
+     * 
+     * @see BxBaseModGeneralModule::serviceEntityAllActions
+     */
+    /** 
+     * @ref bx_base_general-entity_all_actions "entity_all_actions"
+     */
+    public function serviceEntityAllActions ($mixedContent = false, $aParams = array())
+    {
+        $mixedResult = $this->getEntryAllActions($mixedContent, $aParams);
+
+        if(bx_is_api())
+            return [bx_api_get_block('entity_actions', $mixedResult)];
+        else
+            return $this->_oTemplate->entryAllActions($mixedResult);
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_base_general Base General
+     * @subsection bx_base_general-menu Menu
+     * @subsubsection bx_base_general-entity_actions entity_actions
+     * 
+     * @code bx_srv('bx_posts', 'entity_actions', [...]); @endcode
+     * 
+     * Entry actions, without social sharing actions
+     * @param $iContentId content ID
+     * 
+     * @see BxBaseModGeneralModule::serviceEntityActions
+     */
+    /** 
+     * @ref bx_base_general-entity_actions "entity_actions"
+     */
+    public function serviceEntityActions ($iContentId = 0)
+    {
+        $iContentId = $this->_getContent($iContentId, false);
+        if($iContentId === false)
+            return false;
+
+        $oMenu = BxTemplMenu::getObjectInstance($this->_oConfig->CNF['OBJECT_MENU_ACTIONS_VIEW_ENTRY']);
+        return $oMenu ? $oMenu->getCode() : false;
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_base_general Base General
+     * @subsection bx_base_general-page_blocks Page Blocks
+     * @subsubsection bx_base_general-entity_reports entity_reports
+     * 
+     * @code bx_srv('bx_posts', 'entity_reports', [...]); @endcode
+     * 
+     * Get content reports
+     * @param $iContentId content ID
+     * 
+     * @see BxBaseModGeneralModule::serviceEntityReports
+     */
+    /** 
+     * @ref bx_base_general-entity_reports "entity_reports"
+     */
+    public function serviceEntityReports ($iContentId = 0)
+    {
+        $mixedContent = $this->_getContent($iContentId);
+        list($iContentId, $aContentInfo) = $mixedContent;
+        
+        if($iContentId === false)
+            return false;
+        
+        $CNF = &$this->_oConfig->CNF;
+        
+        if (!isset($CNF['OBJECT_REPORTS']) || !isset($CNF['OBJECT_NOTES']))
+            return false;
+
+        if(!$aContentInfo || !(BxDolAcl::getInstance()->isMemberLevelInSet(192) || (isset($CNF['FIELD_AUTHOR']) && bx_get_logged_profile_id() == $aContentInfo[$CNF['FIELD_AUTHOR']])))
+            return false;
+
+        $oReport = BxDolReport::getObjectInstance($CNF['OBJECT_REPORTS'], $iContentId, true);
+        if(!$oReport)
+            return false;
+
+        return $oReport->getReportedByWithComments($CNF['OBJECT_NOTES']);
+    }
+    
+     /**
+     * @page service Service Calls
+     * @section bx_base_general Base General
+     * @subsection bx_base_general-page_blocks Page Blocks
+     * @subsubsection bx_base_general-reports_count_by_status reports_count_by_status
+     * 
+     * @code bx_srv('bx_posts', 'reports_count_by_status', [...]); @endcode
+     * 
+     * Get number of reports with specified status
+     * @param $iStatus status ID
+     * 
+     * @see BxBaseModGeneralModule::serviceReportsCountByStatus
+     */
+    /** 
+     * @ref bx_base_general-entity_reports "entity_reports"
+     */
+    public function serviceReportsCountByStatus ($iStatus)
+    {
+        $CNF = &$this->_oConfig->CNF;
+        
+        if (!isset($CNF['OBJECT_REPORTS']) || !isset($CNF['OBJECT_NOTES']))
+            return false;
+        
+        $oReport = BxDolReport::getObjectInstance($CNF['OBJECT_REPORTS'], 0, false);
+        return $oReport->getCountByStatus($iStatus);
+    }
+    
+    /**
+     * @page service Service Calls
+     * @section bx_base_general Base General
+     * @subsection bx_base_general-menu Menu
+     * @subsubsection bx_base_general-entity_social_sharing entity_social_sharing
+     * 
+     * @code bx_srv('bx_posts', 'entity_social_sharing', [...]); @endcode
+     * 
+     * Entry social sharing actions
+     * @param $mixedContent content ID or array with integer content ID and 
+     *                      array with content info, or false
+     * @param $aParams array with additional custom params 
+     *                 which may overwrite some default values
+     * 
+     * @see BxBaseModGeneralModule::serviceEntitySocialSharing
+     */
+    /** 
+     * @ref bx_base_general-entity_social_sharing "entity_social_sharing"
+     */
+    public function serviceEntitySocialSharing($mixedContent = false, $aParams = array())
+    {
+        if(!empty($mixedContent)) {
+            if(!is_array($mixedContent))
+               $mixedContent = array((int)$mixedContent, array());
+        }
+        else {
+            $mixedContent = $this->_getContent();
+            if($mixedContent === false)
+                return false;
+        }
+
+        list($iContentId, $aContentInfo) = $mixedContent;
+
+        $CNF = &$this->_oConfig->CNF;
+
+        $sUri = !empty($aParams['uri']) ? $aParams['uri'] : '';
+        if(empty($sUri) && !empty($CNF['URI_VIEW_ENTRY']))
+            $sUri = $CNF['URI_VIEW_ENTRY'];
+
+        $sUrl = !empty($sUri) ? BxDolPermalinks::getInstance()->permalink('page.php?i=' . $sUri . '&id=' . $iContentId) : '';
+
+        $sTitle = !empty($aParams['title']) ? $aParams['title'] : '';
+        if(empty($sTitle) && !empty($aContentInfo[$CNF['FIELD_TITLE']]))
+            $sTitle = $aContentInfo[$CNF['FIELD_TITLE']];
+
+        $aMarkers = array(
+            'id' => $iContentId,
+            'module' => $this->_aModule['name'],
+            'url' => bx_absolute_url($sUrl),
+            'title' => $sTitle,
+        );
+
+        $iIdThumb = !empty($aParams['id_thumb']) ? (int)$aParams['id_thumb'] : 0;
+        if(empty($iIdThumb) && !empty($CNF['FIELD_THUMB']) && !empty($aContentInfo[$CNF['FIELD_THUMB']]))
+            $iIdThumb = (int)$aContentInfo[$CNF['FIELD_THUMB']];
+
+        if ($iIdThumb) {
+            $sTranscoder = !empty($aParams['object_transcoder']) ? $aParams['object_transcoder'] : '';
+            $sStorage = !empty($aParams['object_storage']) ? $aParams['object_storage'] : '';
+            if(empty($sStorage) && !empty($CNF['OBJECT_STORAGE']))
+                $sStorage = $CNF['OBJECT_STORAGE'];
+
+            if(!empty($sTranscoder))
+                $o = BxDolTranscoder::getObjectInstance($sTranscoder);
+            else if(!empty($sStorage))
+                $o = BxDolStorage::getObjectInstance($sStorage);
+
+            $sImgUrl = $o ? $o->getFileUrlById($iIdThumb) : '';
+            if($sImgUrl)
+                $aMarkers['img_url'] = $sImgUrl;
+        }
+
+        $oMenu = BxDolMenu::getObjectInstance('sys_social_sharing');
+        $oMenu->addMarkers($aMarkers);
+        $sMenu = $oMenu->getCode();
+
+        if(empty($sMenu))
+            return '';
+
+        return $this->_oTemplate->parseHtmlByName('entry-share.html', array(
+            'menu' => $sMenu
+        ));
+    }
+    
+    /**
+     * Entry context block
+     */
+    public function serviceEntityContext ($iContentId = 0)
+    {
+        return $this->_serviceTemplateFunc ('entryContext', $iContentId);
+    }
+
+    /**
+     * Blocks for lables tree browsing
+     */
+    public function serviceGetLablesTree()
+    {
+		$aBreadcrumbs = array();
+		$this->_getLablesBreadcrumbsArray(bx_get('label'), $aBreadcrumbs);
+		return $this->_getLablesTreeLevel($aBreadcrumbs);
+	}	
+    
+    public function serviceGetLablesBreadcrumbs()
+    {
+		if (bx_get('label')){
+            $aBreadcrumbs = array();
+            $this->_getLablesBreadcrumbsArray(bx_process_input(bx_get('label'), BX_DATA_INT), $aBreadcrumbs);
+            $aLabels = array();
+            foreach (array_reverse($aBreadcrumbs) as $aLabel){
+                $aLabels[] = array(
+                   'value' => $aLabel['value'], 
+                   'url' => $this->_getLablesBrowseUrl($aLabel['id'])
+               );
+            }
+            
+            return $this->_oTemplate->parseHtmlByName('labels_breadcrumbs.html', array('bx_repeat:items' => $aLabels));
+		}
+        return '';
+	}
+    
+    public function serviceBrowseByLabel()
+    {   
+        $CNF = &$this->_oConfig->CNF;
+        if(empty($CNF['OBJECT_METATAGS']))
+            return '';
+
+        $sMode = 'recent';
+        if(bx_srv('system', 'is_module_content', [$this->_aModule['name']]))
+           $sMode = 'public';
+
+        $o = $this->getObjectBrowse($sMode);
+        $o->setDesignBoxTemplateId(BX_DB_PADDING_DEF);
+        $o->setDisplayEmptyMsg(true);
+        $o->setAjaxPaginate(false);
+        $o->setUnitParams(['context' => $sMode]);
+
+        if(($mixedLabel = bx_get('label')) !== false) {
+            $sLabel = '';
+            if(is_numeric($mixedLabel) && ($aLabel = BxDolLabel::getInstance()->getLabels(['type' => 'id', 'id' => (int)$mixedLabel])) && is_array($aLabel))
+                $sLabel = $aLabel['value'];
+            else
+                $sLabel = bx_process_url_param($mixedLabel, "/^[\d\w\s_-]+$/");
+
+            if($sLabel)
+                BxDolMetatags::getObjectInstance($CNF['OBJECT_METATAGS'])->keywordsSetSearchCondition($o, $sLabel);
+        }
+
+        if($o->isError)
+            return '';
+
+        if($s = $o->processing())
+            return $s;
+        else
+            return '';
+    }
+    
+    public function serviceBrowseByCategories($sUnitView, $bEmptyMessage, $bAjaxPaginate, $sMode, $iPerPage)
+    {   
+        $o = $this->getObjectBrowse($sMode, ['unit_view' => $sUnitView]);
+        $o->setDesignBoxTemplateId(BX_DB_PADDING_DEF);
+        $o->setDisplayEmptyMsg($bEmptyMessage);
+        $o->setAjaxPaginate($bAjaxPaginate);
+        $o->setCategoryObject('multi');
+
+        $aCategories = BxDolCategories::getInstance()->getData([
+            'type' => 'by_module_with_num', 
+            'module' => $this->_aModule['name']
+        ]);
+
+        $aCategoriesOutput = [];
+        foreach($aCategories as $aCategory) {
+            if($aCategory['num'] > 0) {
+                $o->setCustomSearchCondition(['keyword' => $aCategory['value']]);
+                $o->setPaginatePerPage($iPerPage);
+                if(!$o->isError){
+                    $aResult = $o->processing();
+                    if($aResult && $aResult['content'] != '')
+                        $aCategoriesOutput[] = [
+                            'name' => _t($aCategory['value']), 
+                            'url' => '', 
+                            'content' => $aResult['content']
+                        ];
+                }
+            }
+        }
+
+        return $this->_oTemplate->parseHtmlByName('browse_by_categories.html', [
+            'bx_repeat:categories' => $aCategoriesOutput,
+        ]);
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_base_general Base General
+     * @subsection bx_base_general-polls Polls Blocks
+     * @subsubsection bx_base_general-get_block_poll_answers get_block_poll_answers
+     * 
+     * @code bx_srv('bx_posts', 'get_block_poll_answers', [...]); @endcode
+     * 
+     * Get block with poll answers
+     * @param $iPollId poll ID
+     * 
+     * @see BxBaseModGeneralModule::serviceGetBlockPollAnswers
+     */
+    /** 
+     * @ref bx_base_general-get_block_poll_answers "get_block_poll_answers"
+     */
+    public function serviceGetBlockPollAnswers($iPollId, $bForceDisplay = false)
+    {
+        if(!$iPollId)
+            return false;
+
+        if(!$bForceDisplay && $this->isPollPerformed($iPollId))
+            return $this->serviceGetBlockPollResults($iPollId);
+
+        return $this->_serviceTemplateFunc('entryPollAnswers', $iPollId, 'getPollInfoById');
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_base_general Base General
+     * @subsection bx_base_general-polls Polls Blocks
+     * @subsubsection bx_base_general-get_block_poll_results get_block_poll_results
+     * 
+     * @code bx_srv('bx_posts', 'get_block_poll_results', [...]); @endcode
+     * 
+     * Get block with poll results
+     * @param $iPollId poll ID
+     * 
+     * @see BxBaseModGeneralModule::serviceGetBlockPollResults
+     */
+    /** 
+     * @ref bx_base_general-get_block_poll_results "get_block_poll_results"
+     */
+    public function serviceGetBlockPollResults($iPollId)
+    {
+        return $this->_serviceTemplateFunc('entryPollResults', $iPollId, 'getPollInfoById');
+    }
+
+    /**
+     * Data for Notifications module
+     */
+    public function serviceGetNotificationsData()
+    {
+    	$sModule = $this->_aModule['name'];
+
+    	$sEventPrivacy = $sModule . '_allow_view_event_to';
+        if(BxDolPrivacy::getObjectInstance($sEventPrivacy) === false)
+            $sEventPrivacy = '';
+
+        $aResult = [
+            'handlers' => [
+                ['group' => $sModule . '_object', 'type' => 'insert', 'alert_unit' => $sModule, 'alert_action' => 'added', 'module_name' => $sModule, 'module_method' => 'get_notifications_post', 'module_class' => 'Module', 'module_event_privacy' => $sEventPrivacy],
+                ['group' => $sModule . '_object', 'type' => 'update', 'alert_unit' => $sModule, 'alert_action' => 'edited'],
+                ['group' => $sModule . '_object', 'type' => 'delete', 'alert_unit' => $sModule, 'alert_action' => 'deleted'],
+
+                ['group' => $sModule . '_object_approved', 'type' => 'insert', 'alert_unit' => $sModule, 'alert_action' => 'approved', 'module_name' => $sModule, 'module_method' => 'get_notifications_post_approved', 'module_class' => 'Module', 'module_event_privacy' => $sEventPrivacy],
+
+                ['group' => $sModule . '_comment', 'type' => 'insert', 'alert_unit' => $sModule, 'alert_action' => 'commentPost', 'module_name' => $sModule, 'module_method' => 'get_notifications_comment', 'module_class' => 'Module', 'module_event_privacy' => $sEventPrivacy],
+                ['group' => $sModule . '_comment', 'type' => 'delete', 'alert_unit' => $sModule, 'alert_action' => 'commentRemoved'],
+
+                ['group' => $sModule . '_reply', 'type' => 'insert', 'alert_unit' => $sModule, 'alert_action' => 'replyPost', 'module_name' => $sModule, 'module_method' => 'get_notifications_reply', 'module_class' => 'Module', 'module_event_privacy' => $sEventPrivacy],
+                ['group' => $sModule . '_reply', 'type' => 'delete', 'alert_unit' => $sModule, 'alert_action' => 'replyRemoved'],
+
+                ['group' => $sModule . '_vote', 'type' => 'insert', 'alert_unit' => $sModule, 'alert_action' => 'doVote', 'module_name' => $sModule, 'module_method' => 'get_notifications_vote', 'module_class' => 'Module', 'module_event_privacy' => $sEventPrivacy],
+                ['group' => $sModule . '_vote', 'type' => 'delete', 'alert_unit' => $sModule, 'alert_action' => 'undoVote'],
+
+                ['group' => $sModule . '_reaction', 'type' => 'insert', 'alert_unit' => $sModule . '_reactions', 'alert_action' => 'doVote', 'module_name' => $sModule, 'module_method' => 'get_notifications_reaction', 'module_class' => 'Module', 'module_event_privacy' => $sEventPrivacy],
+                ['group' => $sModule . '_reaction', 'type' => 'delete', 'alert_unit' => $sModule . '_reactions', 'alert_action' => 'undoVote'],
+
+                ['group' => $sModule . '_score_up', 'type' => 'insert', 'alert_unit' => $sModule, 'alert_action' => 'doVoteUp', 'module_name' => $sModule, 'module_method' => 'get_notifications_score_up', 'module_class' => 'Module', 'module_event_privacy' => $sEventPrivacy],
+
+                ['group' => $sModule . '_score_down', 'type' => 'insert', 'alert_unit' => $sModule, 'alert_action' => 'doVoteDown', 'module_name' => $sModule, 'module_method' => 'get_notifications_score_down', 'module_class' => 'Module', 'module_event_privacy' => $sEventPrivacy],
+
+                //--- Moderation related: For 'admins'.
+                ['group' => $sModule . '_object_pending_approval', 'type' => 'insert', 'alert_unit' => $sModule, 'alert_action' => 'pending_approval', 'module_name' => $sModule, 'module_method' => 'get_notifications_post_pending_approval', 'module_class' => 'Module', 'module_event_privacy' => $sEventPrivacy],
+                ['group' => $sModule . '_object_reported', 'type' => 'insert', 'alert_unit' => $sModule, 'alert_action' => 'reported_content', 'module_name' => $sModule, 'module_method' => 'get_notifications_post_reported', 'module_class' => 'Module', 'module_event_privacy' => $sEventPrivacy],
+            ],
+            'settings' => [
+                ['group' => 'content', 'unit' => $sModule, 'action' => 'added', 'types' => ['follow_member', 'follow_context']],
+                ['group' => 'content_updated', 'unit' => $sModule, 'action' => 'approved', 'types' => ['personal']],
+                ['group' => 'comment', 'unit' => $sModule, 'action' => 'commentPost', 'types' => ['personal', 'follow_member', 'follow_context']],
+                ['group' => 'reply', 'unit' => $sModule, 'action' => 'replyPost', 'types' => ['personal']],
+                ['group' => 'vote', 'unit' => $sModule, 'action' => 'doVote', 'types' => ['personal', 'follow_member', 'follow_context']],
+                ['group' => 'vote', 'unit' => $sModule . '_reactions', 'action' => 'doVote', 'types' => ['personal', 'follow_member', 'follow_context']],
+                ['group' => 'score_up', 'unit' => $sModule, 'action' => 'doVoteUp', 'types' => ['personal', 'follow_member', 'follow_context']],
+                ['group' => 'score_down', 'unit' => $sModule, 'action' => 'doVoteDown', 'types' => ['personal', 'follow_member', 'follow_context']],
+
+                //--- Moderation related: For 'admins'.
+                ['group' => 'action_required', 'unit' => $sModule, 'action' => 'pending_approval', 'types' => ['personal']],
+                ['group' => 'action_required', 'unit' => $sModule, 'action' => 'reported_content', 'types' => ['personal']],
+            ],
+            'alerts' => [
+                ['unit' => $sModule, 'action' => 'added'],
+                ['unit' => $sModule, 'action' => 'edited'],
+                ['unit' => $sModule, 'action' => 'deleted'],
+
+                ['unit' => $sModule, 'action' => 'approved'],
+
+                ['unit' => $sModule, 'action' => 'commentPost'],
+                ['unit' => $sModule, 'action' => 'commentRemoved'],
+
+                ['unit' => $sModule, 'action' => 'replyPost'],
+                ['unit' => $sModule, 'action' => 'replyRemoved'],
+
+                ['unit' => $sModule, 'action' => 'doVote'],
+                ['unit' => $sModule, 'action' => 'undoVote'],
+
+                ['unit' => $sModule . '_reactions', 'action' => 'doVote'],
+                ['unit' => $sModule . '_reactions', 'action' => 'undoVote'],
+
+                ['unit' => $sModule, 'action' => 'doVoteUp'],
+                ['unit' => $sModule, 'action' => 'doVoteDown'],
+
+                //--- Moderation related: For 'admins'.
+                ['unit' => $sModule, 'action' => 'pending_approval'],
+                ['unit' => $sModule, 'action' => 'reported_content'],
+            ]
+        ];
+
+        if(!empty($this->_oConfig->CNF['FIELDS_DELAYED_PROCESSING'])) {
+            $aResult['handlers'] = array_merge($aResult['handlers'], [
+                ['group' => $sModule . '_object_publish_failed', 'type' => 'insert', 'alert_unit' => $sModule, 'alert_action' => 'publish_failed', 'module_name' => $sModule, 'module_method' => 'get_notifications_post_publish_failed', 'module_class' => 'Module', 'module_event_privacy' => ''],
+                ['group' => $sModule . '_object_publish_succeeded', 'type' => 'insert', 'alert_unit' => $sModule, 'alert_action' => 'publish_succeeded', 'module_name' => $sModule, 'module_method' => 'get_notifications_post_publish_succeeded', 'module_class' => 'Module', 'module_event_privacy' => ''],
+            ]);
+
+            $aResult['settings'] = array_merge($aResult['settings'], [
+                ['group' => 'content_updated', 'unit' => $sModule, 'action' => 'publish_failed', 'types' => ['personal']],
+                ['group' => 'content_updated', 'unit' => $sModule, 'action' => 'publish_succeeded', 'types' => ['personal']],
+            ]);
+
+            $aResult['alerts'] = array_merge($aResult['alerts'], [
+                ['unit' => $sModule, 'action' => 'publish_failed'],
+                ['unit' => $sModule, 'action' => 'publish_succeeded'],
+            ]);
+        }
+
+        return $aResult;
+    }
+
+    /**
+     * Entry post for Notifications module
+     */
+    public function serviceGetNotificationsPost($aEvent)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $aContentInfo = $this->_oDb->getContentInfoById($aEvent['object_id']);
+        if(empty($aContentInfo) || !is_array($aContentInfo))
+            return [];
+
+        $sEntryUrl = bx_absolute_url(BxDolPermalinks::getInstance()->permalink('page.php?i=' . $CNF['URI_VIEW_ENTRY'] . '&id=' . $aContentInfo[$CNF['FIELD_ID']]), '{bx_url_root}');
+        $sEntryCaption = isset($aContentInfo[$CNF['FIELD_TITLE']]) ? $aContentInfo[$CNF['FIELD_TITLE']] : strmaxtextlen($aContentInfo[$CNF['FIELD_TEXT']], 20, '...');
+        $sEntrySummary = isset($aContentInfo[$CNF['FIELD_TEXT']]) ? $aContentInfo[$CNF['FIELD_TEXT']] : '';
+
+        return [
+            'entry_sample' => $CNF['T']['txt_sample_single'],
+            'entry_url' => $sEntryUrl,
+            'entry_caption' => $sEntryCaption,
+            'entry_summary' => $sEntrySummary,
+            'entry_author' => $aContentInfo[$CNF['FIELD_AUTHOR']],
+            'entry_privacy' => '', //may be empty or not specified. In this case Public privacy will be used.
+            'lang_key' => '', //may be empty or not specified, or a string, or an array('site' => '...', 'email' => '...', 'push' => '...'). In this case of empty/not specified the default one from Notification module will be used.
+            /*
+             * Custom settings for email and/or push notifications can be provided here. 
+             * Only necessary parts of 'settings' array can be used.
+             * 
+            'settings' => array(
+                'email' => array(
+                    'template' => '',   //--- custom email template
+                    'markers' => '',    //--- markers to parse email parts (subject, body) with
+                    'subject' => ''     //--- custom email subject
+                ),
+                'push' => array(
+                    'subject' => ''     //--- custom push notification subject
+                )
+            )
+             */
+        ];
+    }
+
+    public function serviceGetNotificationsPostPendingApproval($aEvent)
+    {
+        return $this->serviceGetNotificationsPostForModeration($aEvent);
+    }
+
+    public function serviceGetNotificationsPostReported($aEvent)
+    {
+        return $this->serviceGetNotificationsPostForModeration($aEvent);
+    }
+
+    public function serviceGetNotificationsPostForModeration($aEvent)
+    {
+        $aResult = $this->serviceGetNotificationsPost($aEvent);
+
+        /**
+         * Unset Entry Author because the notification is addressed to 'admins'.
+         */
+        if(isset($aResult['entry_author']))
+            unset($aResult['entry_author']);
+
+        return $aResult;
+    }
+
+    public function serviceGetNotificationsPostApproved($aEvent)
+    {
+        return $this->serviceGetNotificationsPost($aEvent);
+    }
+
+    public function serviceGetNotificationsPostPublishFailed($aEvent)
+    {
+        return $this->serviceGetNotificationsPost($aEvent);
+    }
+
+    public function serviceGetNotificationsPostPublishSucceeded($aEvent)
+    {
+        return $this->serviceGetNotificationsPost($aEvent);
+    }
+
+
+    /**
+     * Entry post comment for Notifications module
+     */
+    public function serviceGetNotificationsComment($aEvent)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $iContentId = (int)$aEvent['object_id'];
+        $aContentInfo = $this->_oDb->getContentInfoById($iContentId);
+        if(empty($aContentInfo) || !is_array($aContentInfo))
+            return [];
+
+        $oComment = BxDolCmts::getObjectInstance($CNF['OBJECT_COMMENTS'], $iContentId);
+        if(!$oComment || !$oComment->isEnabled())
+            return [];
+
+        $sEntryUrl = bx_absolute_url(BxDolPermalinks::getInstance()->permalink('page.php?i=' . $CNF['URI_VIEW_ENTRY'] . '&id=' . $aContentInfo[$CNF['FIELD_ID']]), '{bx_url_root}');
+        $sEntryCaption = isset($aContentInfo[$CNF['FIELD_TITLE']]) ? $aContentInfo[$CNF['FIELD_TITLE']] : strmaxtextlen($aContentInfo[$CNF['FIELD_TEXT']], 20, '...');
+        $sEntrySummary = isset($aContentInfo[$CNF['FIELD_TEXT']]) ? $aContentInfo[$CNF['FIELD_TEXT']] : '';
+
+        $iCommentId = (int)$aEvent['subobject_id'];
+
+        return [
+            'entry_sample' => $CNF['T']['txt_sample_single'],
+            'entry_url' => $sEntryUrl,
+            'entry_caption' => $sEntryCaption,
+            'entry_summary' => $sEntrySummary,
+            'entry_author' => $aContentInfo[$CNF['FIELD_AUTHOR']],
+            'subentry_sample' => $CNF['T']['txt_sample_comment_single'],
+            'subentry_url' => $oComment->getItemUrl($iCommentId, '{bx_url_root}'),
+            'subentry_url_api' => $oComment->getItemUrlApi($iCommentId, '{bx_url_root}'),
+            'subentry_summary' => $oComment->getViewText($iCommentId),
+            'lang_key' => '', //may be empty or not specified. In this case the default one from Notification module will be used.
+        ];
+    }
+
+	/**
+     * Entry post reply for Notifications module
+     */
+    public function serviceGetNotificationsReply($aEvent)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $oComment = BxDolCmts::getObjectInstance($CNF['OBJECT_COMMENTS'], 0, false);
+        if(!$oComment || !$oComment->isEnabled())
+            return [];
+
+        $iParentId = (int)$aEvent['object_id'];
+        $aParentInfo = $oComment->getQueryObject()->getCommentsBy(['type' => 'id', 'id' => $iParentId]);
+        if(empty($aParentInfo) || !is_array($aParentInfo))
+            return [];
+
+        $iObjectId = (int)$aParentInfo['cmt_object_id'];
+        $oComment->init($iObjectId);
+        $iCommentId = (int)$aEvent['subobject_id'];
+
+        return [
+            'object_id' => $iObjectId,
+            'entry_sample' => '_cmt_txt_sample_comment_single',
+            'entry_url' => $oComment->getItemUrl($iParentId, '{bx_url_root}'),
+            'entry_url_api' => $oComment->getItemUrlApi($iParentId, '{bx_url_root}'),
+            'entry_caption' => strmaxtextlen($aParentInfo['cmt_text'], 20, '...'),
+            'entry_summary' => $oComment->getViewText($iParentId),
+            'entry_author' => (int)$aParentInfo['cmt_author_id'],
+            'subentry_sample' => '_cmt_txt_sample_reply_to',
+            'subentry_url' => $oComment->getItemUrl($iCommentId, '{bx_url_root}'),
+            'subentry_url_api' => $oComment->getItemUrlApi($iCommentId, '{bx_url_root}'),
+            'subentry_summary' => $oComment->getViewText($iCommentId),
+            'lang_key' => '', //may be empty or not specified. In this case the default one from Notification module will be used.
+        ];
+    }
+
+	/**
+     * Entry post vote for Notifications module
+     */
+    public function serviceGetNotificationsVote($aEvent)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $iContentId = (int)$aEvent['object_id'];
+        $aContentInfo = $this->_oDb->getContentInfoById($iContentId);
+        if(empty($aContentInfo) || !is_array($aContentInfo))
+            return [];
+
+        $oVote = BxDolVote::getObjectInstance($CNF['OBJECT_VOTES'], $iContentId);
+        if(!$oVote || !$oVote->isEnabled())
+            return [];
+
+        $sEntryUrl = bx_absolute_url(BxDolPermalinks::getInstance()->permalink('page.php?i=' . $CNF['URI_VIEW_ENTRY'] . '&id=' . $aContentInfo[$CNF['FIELD_ID']]), '{bx_url_root}');
+        $sEntryCaption = isset($aContentInfo[$CNF['FIELD_TITLE']]) ? $aContentInfo[$CNF['FIELD_TITLE']] : strmaxtextlen($aContentInfo[$CNF['FIELD_TEXT']], 20, '...');
+        $sEntrySummary = isset($aContentInfo[$CNF['FIELD_TEXT']]) ? $aContentInfo[$CNF['FIELD_TEXT']] : '';
+
+        return [
+            'entry_sample' => $CNF['T']['txt_sample_single'],
+            'entry_url' => $sEntryUrl,
+            'entry_caption' => $sEntryCaption,
+            'entry_summary' => $sEntrySummary,
+            'entry_author' => $aContentInfo[$CNF['FIELD_AUTHOR']],
+            'subentry_sample' => $CNF['T']['txt_sample_vote_single'],
+            'lang_key' => '', //may be empty or not specified. In this case the default one from Notification module will be used.
+        ];
+    }
+
+    /**
+     * Entry post vote for Notifications module
+     */
+    public function serviceGetNotificationsReaction($aEvent)
+    {
+    	$CNF = &$this->_oConfig->CNF;
+
+    	$iContentId = (int)$aEvent['object_id'];
+        $aContentInfo = $this->_oDb->getContentInfoById($iContentId);
+        if(empty($aContentInfo) || !is_array($aContentInfo))
+            return [];
+
+        $oReaction = BxDolVote::getObjectInstance($CNF['OBJECT_REACTIONS'], $iContentId);
+        if(!$oReaction || !$oReaction->isEnabled())
+            return [];
+
+        $aSubentry = $oReaction->getTrackBy(array('type' => 'id', 'id' => (int)$aEvent['subobject_id']));
+        if(empty($aSubentry) || !is_array($aSubentry))
+            return [];
+
+        $aSubentrySampleParams = array();
+        $aReaction = $oReaction->getReaction($aSubentry['reaction']);
+        if(!empty($aReaction['title']))
+            $aSubentrySampleParams[] = $aReaction['title'];
+        else
+            $aSubentrySampleParams[] = '_undefined';
+
+        $sEntryUrl = bx_absolute_url(BxDolPermalinks::getInstance()->permalink('page.php?i=' . $CNF['URI_VIEW_ENTRY'] . '&id=' . $aContentInfo[$CNF['FIELD_ID']]), '{bx_url_root}');
+        $sEntryCaption = isset($aContentInfo[$CNF['FIELD_TITLE']]) ? $aContentInfo[$CNF['FIELD_TITLE']] : strmaxtextlen($aContentInfo[$CNF['FIELD_TEXT']], 20, '...');
+        $sEntrySummary = isset($aContentInfo[$CNF['FIELD_TEXT']]) ? $aContentInfo[$CNF['FIELD_TEXT']] : '';
+
+        return [
+            'entry_sample' => $CNF['T']['txt_sample_single'],
+            'entry_url' => $sEntryUrl,
+            'entry_caption' => $sEntryCaption,
+            'entry_summary' => $sEntrySummary,
+            'entry_author' => $aContentInfo[$CNF['FIELD_AUTHOR']],
+            'subentry_sample' => $CNF['T']['txt_sample_reaction_single'],
+            'subentry_sample_params' => $aSubentrySampleParams,
+            'lang_key' => '', //may be empty or not specified. In this case the default one from Notification module will be used.
+        ];
+    }
+
+    /**
+     * Entry post score -> vote up for Notifications module
+     */
+    public function serviceGetNotificationsScoreUp($aEvent)
+    {
+    	return $this->_serviceGetNotificationsScore('up', $aEvent);
+    }
+
+    /**
+     * Entry post score -> vote up for Notifications module
+     */
+    public function serviceGetNotificationsScoreDown($aEvent)
+    {
+    	return $this->_serviceGetNotificationsScore('down', $aEvent);
+    }
+
+    protected function _serviceGetNotificationsScore($sType, $aEvent)
+    {
+    	$CNF = &$this->_oConfig->CNF;
+
+    	$iContentId = (int)$aEvent['object_id'];
+        $aContentInfo = $this->_oDb->getContentInfoById($iContentId);
+        if(empty($aContentInfo) || !is_array($aContentInfo))
+            return array();
+
+        $oScore = BxDolScore::getObjectInstance($CNF['OBJECT_SCORES'], $iContentId);
+        if(!$oScore || !$oScore->isEnabled())
+            return array();
+
+        $sEntryUrl = bx_absolute_url(BxDolPermalinks::getInstance()->permalink('page.php?i=' . $CNF['URI_VIEW_ENTRY'] . '&id=' . $aContentInfo[$CNF['FIELD_ID']]), '{bx_url_root}');
+        $sEntryCaption = isset($aContentInfo[$CNF['FIELD_TITLE']]) ? $aContentInfo[$CNF['FIELD_TITLE']] : strmaxtextlen($aContentInfo[$CNF['FIELD_TEXT']], 20, '...');
+        $sEntrySummary = isset($aContentInfo[$CNF['FIELD_TEXT']]) ? $aContentInfo[$CNF['FIELD_TEXT']] : '';
+
+        return [
+            'entry_sample' => $CNF['T']['txt_sample_single'],
+            'entry_url' => $sEntryUrl,
+            'entry_caption' => $sEntryCaption,
+            'entry_summary' => $sEntrySummary,
+            'entry_author' => $aContentInfo[$CNF['FIELD_AUTHOR']],
+            'subentry_sample' => $CNF['T']['txt_sample_score_' . $sType . '_single'],
+            'lang_key' => '', //may be empty or not specified. In this case the default one from Notification module will be used.
+        ];
+    }
+
+    /**
+     * Data for Reputation module
+     */
+    public function serviceGetReputationData()
+    {
+    	$sModule = $this->_aModule['name'];
+
+        $aResult = [
+            'handlers' => [
+                ['group' => $sModule . '_object', 'type' => 'insert', 'alert_unit' => $sModule, 'alert_action' => 'added', 'points_active' => 3, 'points_passive' => 0],
+                ['group' => $sModule . '_object', 'type' => 'delete', 'alert_unit' => $sModule, 'alert_action' => 'deleted', 'points_active' => -3, 'points_passive' => 0],
+
+                ['group' => $sModule . '_comment', 'type' => 'insert', 'alert_unit' => $sModule, 'alert_action' => 'commentPost', 'points_active' => 2, 'points_passive' => 1],
+                ['group' => $sModule . '_comment', 'type' => 'delete', 'alert_unit' => $sModule, 'alert_action' => 'commentRemoved', 'points_active' => -2, 'points_passive' => -1],
+
+                ['group' => $sModule . '_vote', 'type' => 'insert', 'alert_unit' => $sModule, 'alert_action' => 'doVote', 'points_active' => 1, 'points_passive' => 1],
+                ['group' => $sModule . '_vote', 'type' => 'delete', 'alert_unit' => $sModule, 'alert_action' => 'undoVote', 'points_active' => -1, 'points_passive' => -1],
+
+                ['group' => $sModule . '_reaction', 'type' => 'insert', 'alert_unit' => $sModule . '_reactions', 'alert_action' => 'doVote', 'points_active' => 1, 'points_passive' => 1],
+                ['group' => $sModule . '_reaction', 'type' => 'delete', 'alert_unit' => $sModule . '_reactions', 'alert_action' => 'undoVote', 'points_active' => -1, 'points_passive' => -1],
+
+                ['group' => $sModule . '_score_up', 'type' => 'insert', 'alert_unit' => $sModule, 'alert_action' => 'doVoteUp', 'points_active' => 1, 'points_passive' => 1],
+                ['group' => $sModule . '_score_up', 'type' => 'delete', 'alert_unit' => $sModule, 'alert_action' => 'undoVoteUp', 'points_active' => -1, 'points_passive' => -1],
+
+                ['group' => $sModule . '_score_down', 'type' => 'insert', 'alert_unit' => $sModule, 'alert_action' => 'doVoteDown', 'points_active' => 1, 'points_passive' => -1],
+                ['group' => $sModule . '_score_down', 'type' => 'delete', 'alert_unit' => $sModule, 'alert_action' => 'undoVoteDown', 'points_active' => -1, 'points_passive' => 1],
+            ],
+            'alerts' => [
+                ['unit' => $sModule, 'action' => 'added'],
+                ['unit' => $sModule, 'action' => 'deleted'],
+
+                ['unit' => $sModule, 'action' => 'commentPost'],
+                ['unit' => $sModule, 'action' => 'commentRemoved'],
+
+                ['unit' => $sModule, 'action' => 'doVote'],
+                ['unit' => $sModule, 'action' => 'undoVote'],
+
+                ['unit' => $sModule . '_reactions', 'action' => 'doVote'],
+                ['unit' => $sModule . '_reactions', 'action' => 'undoVote'],
+
+                ['unit' => $sModule, 'action' => 'doVoteUp'],
+                ['unit' => $sModule, 'action' => 'undoVoteUp'],
+                ['unit' => $sModule, 'action' => 'doVoteDown'],
+                ['unit' => $sModule, 'action' => 'undoVoteDown'],
+            ]
+        ];
+
+        return $aResult;
+    }
+
+    /**
+     * Data for Timeline module
+     */
+    public function serviceGetTimelineData()
+    {
+    	$sModule = $this->_aModule['name'];
+
+        return array(
+            'handlers' => array(
+                array('group' => $sModule . '_object', 'type' => 'insert', 'alert_unit' => $sModule, 'alert_action' => 'added', 'module_name' => $sModule, 'module_method' => 'get_timeline_post', 'module_class' => 'Module',  'groupable' => 0, 'group_by' => ''),
+                array('group' => $sModule . '_object', 'type' => 'update', 'alert_unit' => $sModule, 'alert_action' => 'edited'),
+                array('group' => $sModule . '_object', 'type' => 'delete', 'alert_unit' => $sModule, 'alert_action' => 'deleted')
+            ),
+            'alerts' => array(
+                array('unit' => $sModule, 'action' => 'added'),
+                array('unit' => $sModule, 'action' => 'edited'),
+                array('unit' => $sModule, 'action' => 'deleted'),
+            )
+        );
+    }
+
+    /**
+     * Entry post for Timeline module
+     */
+    public function serviceGetTimelinePost($aEvent, $aBrowseParams = array())
+    {
+        $aContentInfo = $this->_oDb->getContentInfoById($aEvent['object_id']);
+        if(empty($aContentInfo) || !is_array($aContentInfo))
+            return false;
+
+        $CNF = &$this->_oConfig->CNF;
+
+        if((!empty($CNF['FIELD_STATUS']) && $aContentInfo[$CNF['FIELD_STATUS']] != 'active') || (!empty($CNF['FIELD_STATUS_ADMIN']) && $aContentInfo[$CNF['FIELD_STATUS_ADMIN']] != 'active'))
+            return false;
+
+        $bCache = true;
+        $iUserId = $this->getUserId();
+        $iAuthorId = (int)$aContentInfo[$CNF['FIELD_AUTHOR']];
+        $iAuthorIdAbs = abs($iAuthorId);
+
+        /**
+         * Don't show anonymous posts on the post's owner timeline
+         * and don't cache them when they're viewed by their authors. 
+         */
+        if($iAuthorId < 0 && ((is_numeric($aEvent['owner_id']) && $iAuthorIdAbs == (int)$aEvent['owner_id']) || (is_array($aEvent['owner_id']) && in_array($iAuthorIdAbs, $aEvent['owner_id'])))) {
+            if($iAuthorIdAbs != $iUserId)
+                return false;
+
+            $bCache = false;
+        }
+
+        //--- Views
+        $oViews = isset($CNF['OBJECT_VIEWS']) ? BxDolView::getObjectInstance($CNF['OBJECT_VIEWS'], $aContentInfo[$CNF['FIELD_ID']]) : null;
+
+        $aViews = array();
+        if ($oViews && $oViews->isEnabled())
+            $aViews = array(
+                'system' => $CNF['OBJECT_VIEWS'],
+                'object_id' => $aContentInfo[$CNF['FIELD_ID']],
+                'count' => $aContentInfo['views']
+            );
+
+        //--- Votes
+        $oVotes = isset($CNF['OBJECT_VOTES']) ? BxDolVote::getObjectInstance($CNF['OBJECT_VOTES'], $aContentInfo[$CNF['FIELD_ID']]) : null;
+
+        $aVotes = array();
+        if ($oVotes && $oVotes->isEnabled())
+            $aVotes = array(
+                'system' => $CNF['OBJECT_VOTES'],
+                'object_id' => $aContentInfo[$CNF['FIELD_ID']],
+                'count' => $aContentInfo['votes']
+            );
+        
+        //--- Reactions
+        $oReactions = isset($CNF['OBJECT_REACTIONS']) ? BxDolVote::getObjectInstance($CNF['OBJECT_REACTIONS'], $aContentInfo[$CNF['FIELD_ID']]) : null;
+
+        $aReactions = array();
+        if ($oReactions && $oReactions->isEnabled())
+            $aReactions = array(
+                'system' => $CNF['OBJECT_REACTIONS'],
+                'object_id' => $aContentInfo[$CNF['FIELD_ID']],
+                'count' => $aContentInfo['rvotes']
+            );
+
+        //--- Scores
+        $oScores = isset($CNF['OBJECT_SCORES']) ? BxDolScore::getObjectInstance($CNF['OBJECT_SCORES'], $aContentInfo[$CNF['FIELD_ID']]) : null;
+
+        $aScores = array();
+        if ($oScores && $oScores->isEnabled())
+            $aScores = array(
+                'system' => $CNF['OBJECT_SCORES'],
+                'object_id' => $aContentInfo[$CNF['FIELD_ID']],
+                'score' => $aContentInfo['score']
+            );
+
+        //--- Reports
+        $oReports = isset($CNF['OBJECT_REPORTS']) ? BxDolReport::getObjectInstance($CNF['OBJECT_REPORTS'], $aContentInfo[$CNF['FIELD_ID']]) : null;
+
+        $aReports = array();
+        if ($oReports && $oReports->isEnabled())
+            $aReports = array(
+                'system' => $CNF['OBJECT_REPORTS'],
+                'object_id' => $aContentInfo[$CNF['FIELD_ID']],
+                'count' => $aContentInfo['reports']
+            );
+
+        //--- Comments
+        $oCmts = isset($CNF['OBJECT_COMMENTS']) ? BxDolCmts::getObjectInstance($CNF['OBJECT_COMMENTS'], $aContentInfo[$CNF['FIELD_ID']]) : null;
+
+        $aComments = array();
+        if($oCmts && $oCmts->isEnabled())
+            $aComments = array(
+                'system' => $CNF['OBJECT_COMMENTS'],
+                'object_id' => $aContentInfo[$CNF['FIELD_ID']],
+                'count' => $aContentInfo['comments']
+            );
+
+        //--- Title & Description
+        $sTitle = !empty($aContentInfo[$CNF['FIELD_TITLE']]) ? $aContentInfo[$CNF['FIELD_TITLE']] : '';
+        if(empty($sTitle) && !empty($aContentInfo[$CNF['FIELD_TEXT']]))
+            $sTitle = $aContentInfo[$CNF['FIELD_TEXT']];
+
+        $iOwnerId = $iAuthorIdAbs;
+        if(isset($aEvent['object_privacy_view']) && (int)$aEvent['object_privacy_view'] < 0)
+            $iOwnerId = abs($aEvent['object_privacy_view']);
+
+        $aContent = $this->_getContentForTimelinePost($aEvent, $aContentInfo, $aBrowseParams);
+        if(isset($aContent['_cache'])) {
+            if($bCache)
+                $bCache = (bool)$aContent['_cache'];
+
+            unset($aContent['_cache']);
+        }
+
+        return [
+            '_cache' => $bCache,
+            'owner_id' => $iOwnerId,
+            'object_owner_id' => $iAuthorId,
+            'icon' => !empty($CNF['ICON']) ? $CNF['ICON'] : '',
+            'sample' => isset($CNF['T']['txt_sample_single_with_article']) ? $CNF['T']['txt_sample_single_with_article'] : $CNF['T']['txt_sample_single'],
+            'sample_wo_article' => $CNF['T']['txt_sample_single'],
+            'sample_action' => isset($CNF['T']['txt_sample_action']) ? $CNF['T']['txt_sample_action'] : '',
+            'url' => bx_absolute_url(BxDolPermalinks::getInstance()->permalink('page.php?i=' . $CNF['URI_VIEW_ENTRY'] . '&id=' . $aContentInfo[$CNF['FIELD_ID']])),
+            'content' => $aContent, //a string to display or array to parse default template before displaying.
+            'date' => $aContentInfo[$CNF['FIELD_ADDED']],
+            'views' => $aViews,
+            'votes' => $aVotes,
+            'reactions' => $aReactions,
+            'scores' => $aScores,
+            'reports' => $aReports,
+            'comments' => $aComments,
+            'title' => $sTitle, //may be empty.
+            'description' => '' //may be empty.
+        ];
+    }
+
+    public function serviceGetTimelinePostAllowedView($aEvent)
+    {
+        $iContentId = (int)$aEvent['object_id'];
+        $aContentInfo = $this->_oDb->getContentInfoById($iContentId);
+        if(empty($aContentInfo) || !is_array($aContentInfo))
+            return _t('_sys_txt_access_denied');
+
+        return $this->serviceCheckAllowedViewForProfile($aContentInfo);
+    }
+
+    /**
+     * Check particular action permission without content
+     * @param $sAction action to check, for example: Browse, Add
+     * @param $iContentId content ID
+     * @return message on error, or CHECK_ACTION_RESULT_ALLOWED when allowed
+     */ 
+    public function serviceCheckAllowed($sAction, $isPerformAction = false)
+    {
+        $sMethod = 'checkAllowed' . bx_gen_method_name($sAction);
+        if (!method_exists($this, $sMethod))
+            return _t('_sys_request_method_not_found_cpt');
+
+        return $this->$sMethod($isPerformAction);
+    }
+    
+    /**
+     * Check particular action permission with content
+     * @param $sAction action to check, for example: View, Edit
+     * @param $iContentId content ID
+     * @return message on error, or CHECK_ACTION_RESULT_ALLOWED when allowed
+     */ 
+    public function serviceCheckAllowedWithContent($sAction, $iContentId, $isPerformAction = false)
+    {
+        if (!$iContentId || !($aContentInfo = $this->_oDb->getContentInfoById($iContentId)))
+            return _t('_sys_request_page_not_found_cpt');
+
+        $sMethod = 'checkAllowed' . bx_gen_method_name($sAction);
+        if (!method_exists($this, $sMethod))
+            return _t('_sys_request_method_not_found_cpt');
+
+        return $this->$sMethod($aContentInfo, $isPerformAction);
+    }
+
+    /**
+     * Check particular action permission with content for specified profile
+     * @param $sAction action to check, for example: View, Edit
+     * @param $iContentId content ID
+     * @param $iProfileId profile ID which the permissions to be cheked for
+     * @return message on error, or CHECK_ACTION_RESULT_ALLOWED when allowed
+     */ 
+    public function serviceCheckAllowedWithContentForProfile($sAction, $iContentId, $iProfileId, $isPerformAction = false)
+    {
+        if (!$iContentId || !($aContentInfo = $this->_oDb->getContentInfoById($iContentId)))
+            return _t('_sys_request_page_not_found_cpt');
+
+        $sMethod = 'checkAllowed' . bx_gen_method_name($sAction) . 'ForProfile';
+        if (!method_exists($this, $sMethod))
+            return _t('_sys_request_method_not_found_cpt');
+
+        return $this->$sMethod($aContentInfo, $iProfileId, $isPerformAction);
+    }
+    
+    public function serviceCheckAllowedCommentsView($iContentId, $sObjectComments) 
+    {
+        //negative id used in comments for reports
+        if ($iContentId < 0)
+            return CHECK_ACTION_RESULT_ALLOWED;
+        
+        return $this->serviceCheckAllowedWithContent('comments_view', $iContentId);
+    }
+    
+    public function serviceCheckAllowedCommentsPost($iContentId, $sObjectComments) 
+    {
+        //negative id used in comments for reports
+        if ($iContentId < 0)
+            return CHECK_ACTION_RESULT_ALLOWED;
+        
+        return $this->serviceCheckAllowedWithContent('comments_post', $iContentId);
+    }
+
+    public function serviceGetContentOwnerProfileId ($iContentId)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        // file owner must be author of the content or profile itself in case of profile based module
+        if ($iContentId) {
+            $sModule = $this->getName();
+            if ($this instanceof iBxDolProfileService && BxDolService::call($sModule, 'act_as_profile')) {
+                $oProfile = BxDolProfile::getInstanceByContentAndType($iContentId, $sModule);
+            }
+            else {
+                $aContentInfo = $this->_oDb->getContentInfoById($iContentId);
+                $iContentAuthor = (int)$aContentInfo[$CNF['FIELD_AUTHOR']];
+                if($iContentAuthor < 0)
+                    $iContentAuthor = abs($iContentAuthor);
+
+                $oProfile = $aContentInfo ? BxDolProfile::getInstance($iContentAuthor) : null;
+            }
+
+            $iProfileId = $oProfile ? $oProfile->id() : bx_get_logged_profile_id();
+        }
+        else
+            $iProfileId = bx_get_logged_profile_id();
+
+        return $iProfileId;
+    }
+	
+    public function serviceGetBadges($iContentId,  $bIsSingle = false, $bIsCompact  = false)
+    {
+        $sModule = $this->getName();
+
+        $oBadges = BxDolBadges::getInstance();
+        $aBadges = $oBadges->getData(array(
+            'type' => ($bIsSingle ? 'by_module&object2_single' : 'by_module&object2'),
+            'module' => $sModule,
+            'object_id' => $iContentId
+        ));
+
+        $sResult = false;
+        /**
+         * @hooks
+         * @hookdef hook-system-get_badges 'system', 'get_badges' - hook to override bages assigned to an entry (content)
+         * - $unit_name - equals `system`
+         * - $action - equals `get_badges`
+         * - $object_id - not used
+         * - $sender_id - not used
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `module` - [string] module name
+         *      - `content_id` - [int] content id
+         *      - `is_single` - [boolean] only one badge can be used or not
+         *      - `is_compact` - [boolean] badge in compact mode or not
+         *      - `badges` - [array] a list of all badges assigned to the content
+         *      - `override_result` - [string] or [boolean] by ref, if string is returned then it will be used as resulting badges code, can be overridden in hook processing
+         * @hook @ref hook-system-get_badges
+         */
+        bx_alert('system', 'get_badges', 0, 0, [
+            'module' => $sModule, 
+            'content_id' => $iContentId,
+            'is_single' => $bIsSingle,
+            'is_compact' => $bIsCompact,
+            'badges' => $aBadges, 
+            'override_result' => &$sResult
+        ]);
+        if($sResult !== false)
+            return $sResult;
+
+        if(empty($aBadges) || !is_array($aBadges))
+            return $this->_bIsApi ? [] : '';
+
+        if($this->_bIsApi) {
+            foreach($aBadges as &$aBadge)
+                if(($mixedIcon = $aBadge['icon']) && is_numeric($mixedIcon) && (int)$mixedIcon > 0)
+                    $aBadge['icon_url'] = $this->_oTemplate->getIcon($aBadge['icon'], ['wrap_in_tag' => false]);
+                else
+                    $aBadge['icon'] = $mixedIcon;
+
+            return $aBadges;
+        }
+
+        if($bIsSingle)
+            return BxDolService::call('system', 'get_badge', array($aBadges[0], $bIsCompact), 'TemplServices');
+
+        $aBadgesOutput = array();
+        foreach($aBadges as $aBadge)
+            $aBadgesOutput[] =  array('badge' => BxDolService::call('system', 'get_badge', array($aBadge, $bIsCompact), 'TemplServices'));
+
+        return $this->_oTemplate->parseHtmlByName('badges.html', array(
+            'bx_repeat:items' => $aBadgesOutput,
+        ));
+    }
+    
+    /**
+     * @page service Service Calls
+     * @section bx_base_general Base General
+     * @subsection bx_base_general-page_blocks Page Blocks
+     * @subsubsection bx_base_general-categories_multi_list categories_multi_list
+     * 
+     * @code bx_srv('bx_posts', 'categories_multi_list', [...]); @endcode
+     * 
+     * Display multi-categorories block with number of posts in each category
+     * @param $bAsArray boolean reature as array or not.
+     * 
+     * @see BxBaseModGeneralModule::serviceCategoriesMultiList
+     */
+    /** 
+     * @ref bx_base_general-categories_multi_list "categories_multi_list"
+     */
+    public function serviceCategoriesMultiList($bAsArray = false)
+    {
+        $oCategories = BxDolCategories::getInstance();
+        $oCategories->setModule($this->getName());
+        $mixedResult = $oCategories->getCategoriesList($bAsArray || $this->_bIsApi);
+
+        return !$this->_bIsApi ? $mixedResult : [bx_api_get_block('categories_list',  $mixedResult)];
+    }
+
+    /**
+     * ======
+     * PERMISSION METHODS
+     * ======
+     */
+    public function serviceCheckAllowedViewForProfile ($aDataEntry, $isPerformAction = false, $iProfileId = false)
+    {
+        $mixedResult = $this->_serviceCheckAllowedViewForProfile ($aDataEntry, $isPerformAction, $iProfileId);
+
+        /**
+         * @hooks
+         * @hookdef hook-system-check_allowed_view 'system', 'check_allowed_view' - hook to override the result of checking whether 'view' action is allowed or not to specified profile
+         * - $unit_name - equals `system`
+         * - $action - equals `check_allowed_view`
+         * - $object_id - not used
+         * - $sender_id - not used
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `module` - [string] module name
+         *      - `content_info` - [array] content info array as key&value pairs
+         *      - `profile_id` - [boolean] or [int] profile id to be checked the availability of the action to
+         *      - `override_result` - [string] or [int] by ref, check action result, can be overridden in hook processing. Return string with an error if action isn't allowed or CHECK_ACTION_RESULT_ALLOWED, @see BxDolAcl
+         * @hook @ref hook-system-check_allowed_view
+         */
+        bx_alert('system', 'check_allowed_view', 0, 0, [
+            'module' => $this->getName(), 
+            'content_info' => $aDataEntry, 
+            'profile_id' => $iProfileId, 
+            'override_result' => &$mixedResult
+        ]);
+
+        return $mixedResult;
+    }
+
+    public function checkAllowedSetThumb ($iContentId = 0)
+    {
+        return CHECK_ACTION_RESULT_ALLOWED;
+    }
+    
+    /**
+     * @return CHECK_ACTION_RESULT_ALLOWED if access is granted or error message if access is forbidden. So make sure to make "true === " checking.
+     */
+    public function checkAllowedBrowse ()
+    {
+        $mixedResult = null;
+        /**
+         * @hooks
+         * @hookdef hook-system-check_allowed_browse 'system', 'check_allowed_browse' - hook to override the result of checking whether 'browse' action is allowed or not to currently logged in profile
+         * It's equivalent to @ref hook-system-check_allowed_view 
+         * except `content_info` parameter in $extra_params is missing
+         * @hook @ref hook-system-check_allowed_browse
+         */
+        bx_alert('system', 'check_allowed_browse', 0, 0, [
+            'module' => $this->getName(), 
+            'profile_id' => $this->_iProfileId, 
+            'override_result' => &$mixedResult
+        ]);
+        if($mixedResult !== null)
+            return $mixedResult;
+
+        return CHECK_ACTION_RESULT_ALLOWED;
+    }
+
+    /**
+     * @return CHECK_ACTION_RESULT_ALLOWED if access is granted or error message if access is forbidden. So make sure to make strict(===) checking.
+     */
+    public function checkAllowedView ($aDataEntry, $isPerformAction = false)
+    {
+        return $this->serviceCheckAllowedViewForProfile ($aDataEntry, $isPerformAction);
+    }
+
+    /**
+     * @return CHECK_ACTION_RESULT_ALLOWED if access is granted or error message if access is forbidden. So make sure to make strict(===) checking.
+     */
+    public function checkAllowedViewForProfile ($aDataEntry, $iProfileId, $isPerformAction = false)
+    {
+        return $this->serviceCheckAllowedViewForProfile ($aDataEntry, $isPerformAction, $iProfileId);
+    }
+
+    /**
+     * @return CHECK_ACTION_RESULT_ALLOWED if access is granted or error message if access is forbidden. So make sure to make strict(===) checking.
+     */
+    public function checkAllowedAdd ($isPerformAction = false)
+    {
+        // check ACL
+        $aCheck = checkActionModule($this->_iProfileId, 'create entry', $this->getName(), $isPerformAction);
+        if ($aCheck[CHECK_ACTION_RESULT] !== CHECK_ACTION_RESULT_ALLOWED)
+            return $aCheck[CHECK_ACTION_MESSAGE];
+        return CHECK_ACTION_RESULT_ALLOWED;
+    }
+
+    public function serviceCheckAllowedAddInContext($sContextModule)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        if(($sKey = 'OBJECT_PRIVACY_VIEW') && !empty($CNF[$sKey]) && ($oPrivacy = BxDolPrivacy::getObjectInstance($CNF[$sKey])) !== false && !$oPrivacy->isAllowedAddInContext($sContextModule))
+            return _t('_sys_txt_access_denied');
+
+        return CHECK_ACTION_RESULT_ALLOWED;   
+    }
+
+    /**
+     * @return CHECK_ACTION_RESULT_ALLOWED if access is granted or error message if access is forbidden. So make sure to make strict(===) checking.
+     */
+    public function checkAllowedApprove ($aDataEntry, $isPerformAction = false)
+    {
+        $CNF = &$this->_oConfig->CNF;
+        $sError = '_sys_txt_access_denied';
+
+        if($this->_oConfig->isAutoApproveEnabled())
+            return _t($sError);
+
+        if($aDataEntry[$CNF['FIELD_STATUS_ADMIN']] != BX_BASE_MOD_GENERAL_STATUS_PENDING)
+            return _t($sError);
+
+        // moderator always have access
+        if ($this->_isModerator($isPerformAction))
+            return CHECK_ACTION_RESULT_ALLOWED;
+
+        // check for context's admins 
+        if (!empty($CNF['FIELD_ALLOW_VIEW_TO']) && (int)$aDataEntry[$CNF['FIELD_ALLOW_VIEW_TO']] < 0) {
+            $oProfile = BxDolProfile::getInstance(-(int)$aDataEntry[$CNF['FIELD_ALLOW_VIEW_TO']]);
+            if ($oProfile){
+                $sModule = $oProfile->getModule();
+                $aEntity = BxDolRequest::serviceExists($sModule, 'get_all') ? BxDolService::call($sModule, 'get_all', array(array('type' => 'id', 'id' => $oProfile->getContentId()))) : array();
+
+                $oModule = BxDolModule::getInstance($sModule);
+
+                // check for context's extra roles with rights
+                if (method_exists($oModule, 'isAllowedModuleActionByProfile')) {
+                    $bResult = $oModule->isAllowedModuleActionByProfile($oProfile->getContentId(), $this->getName(), 'edit_any');
+                    if ($bResult !== NULL) return $bResult;
+                }
+
+                // if allowed edit a group then allowed to edit anything inside its context
+                if(isset($aEntity) && $oModule->checkAllowedEdit($aEntity) === CHECK_ACTION_RESULT_ALLOWED){
+                    return CHECK_ACTION_RESULT_ALLOWED;
+                }
+            }
+        }
+
+        return _t($sError);
+    }
+
+    /**
+     * @return CHECK_ACTION_RESULT_ALLOWED if access is granted or error message if access is forbidden. So make sure to make strict(===) checking.
+     */
+    public function checkAllowedEdit ($aDataEntry, $isPerformAction = false)
+    {
+        // moderator and owner always have access
+        if ($this->isEntryAuthor($aDataEntry, $this->_iProfileId) || $this->_isModerator($isPerformAction))
+            return CHECK_ACTION_RESULT_ALLOWED;
+
+        // check for context's admins 
+        if (!empty($this->_oConfig->CNF['FIELD_ALLOW_VIEW_TO']) && (int)$aDataEntry[$this->_oConfig->CNF['FIELD_ALLOW_VIEW_TO']] < 0) {
+            $oProfile = BxDolProfile::getInstance(-(int)$aDataEntry[$this->_oConfig->CNF['FIELD_ALLOW_VIEW_TO']]);
+            if ($oProfile){
+                $sModule = $oProfile->getModule();
+                $aEntity = BxDolRequest::serviceExists($sModule, 'get_all') ? BxDolService::call($sModule, 'get_all', array(array('type' => 'id', 'id' => $oProfile->getContentId()))) : array();
+
+                $oModule = BxDolModule::getInstance($sModule);
+
+                // check for context's extra roles with rights
+                if (method_exists($oModule, 'isAllowedModuleActionByProfile')) {
+                    $bResult = $oModule->isAllowedModuleActionByProfile($oProfile->getContentId(), $this->getName(), 'edit_any');
+                    if ($bResult !== NULL) return $bResult;
+                }
+
+                // if allowed edit a group then allowed to edit anything inside its context
+                if(isset($aEntity) && $oModule->checkAllowedEdit($aEntity) === CHECK_ACTION_RESULT_ALLOWED){
+                    return CHECK_ACTION_RESULT_ALLOWED;
+                }
+            }
+        }
+
+        return _t('_sys_txt_access_denied');
+    }
+
+    /**
+     * @return CHECK_ACTION_RESULT_ALLOWED if access is granted or error message if access is forbidden. So make sure to make strict(===) checking.
+     */
+    public function checkAllowedDelete (&$aDataEntry, $isPerformAction = false)
+    {
+        // moderator always has access
+        if ($this->_isAdministrator($isPerformAction))
+            return CHECK_ACTION_RESULT_ALLOWED;
+
+        // check ACL
+        $aCheck = checkActionModule($this->_iProfileId, 'delete entry', $this->getName(), $isPerformAction);
+        if ($this->isEntryAuthor($aDataEntry, $this->_iProfileId) && $aCheck[CHECK_ACTION_RESULT] === CHECK_ACTION_RESULT_ALLOWED)
+            return CHECK_ACTION_RESULT_ALLOWED;
+
+        // check for context's admins 
+        if (isset($this->_oConfig->CNF['FIELD_ALLOW_VIEW_TO']) && (int)$aDataEntry[$this->_oConfig->CNF['FIELD_ALLOW_VIEW_TO']] < 0){
+            $oProfile = BxDolProfile::getInstance(-(int)$aDataEntry[$this->_oConfig->CNF['FIELD_ALLOW_VIEW_TO']]);
+            if ($oProfile){
+                $sModule = $oProfile->getModule();
+                $aEntity = BxDolRequest::serviceExists($sModule, 'get_all') ? BxDolService::call($sModule, 'get_all', array(array('type' => 'id', 'id' => $oProfile->getContentId()))) : array();
+
+                $oModule = BxDolModule::getInstance($sModule);
+
+                // check for context's extra roles with rights
+                if (method_exists($oModule, 'isAllowedModuleActionByProfile')) {
+                    $bResult = $oModule->isAllowedModuleActionByProfile($oProfile->getContentId(), $this->getName(), 'delete_any');
+                    if ($bResult !== NULL) return $bResult;
+                }
+
+                // if allowed delete a group then allowed to delete anything inside its context
+                if(isset($aEntity) && $oModule->checkAllowedDelete($aEntity) === CHECK_ACTION_RESULT_ALLOWED){
+                    return CHECK_ACTION_RESULT_ALLOWED;
+                }
+            }
+        }
+
+        return _t('_sys_txt_access_denied');
+    }
+
+    /**
+     * @return CHECK_ACTION_RESULT_ALLOWED if access is granted or error message if access is forbidden. So make sure to make strict(===) checking.
+     */
+    public function checkAllowedSetMembership (&$aDataEntry, $isPerformAction = false)
+    {
+        // admin always has access
+        if (isAdmin())
+            return CHECK_ACTION_RESULT_ALLOWED;
+
+        // check ACL
+        $aCheck = checkActionModule($this->_iProfileId, 'set acl level', 'system', $isPerformAction);
+        if ($aCheck[CHECK_ACTION_RESULT] !== CHECK_ACTION_RESULT_ALLOWED)
+            return $aCheck[CHECK_ACTION_MESSAGE];
+
+        return CHECK_ACTION_RESULT_ALLOWED;
+    }
+
+    /**
+     * @return CHECK_ACTION_RESULT_ALLOWED if access is granted or error message if access is forbidden. So make sure to make strict(===) checking.
+     */
+    public function checkAllowedEditAnyEntry ($isPerformAction = false)
+    {
+    	return $this->checkAllowedEditAnyEntryForProfile($isPerformAction, $this->_iProfileId);
+    }
+    
+    /**
+     * @return CHECK_ACTION_RESULT_ALLOWED if access is granted or error message if access is forbidden. So make sure to make strict(===) checking.
+     */
+    public function checkAllowedDeleteAnyEntry ($isPerformAction = false)
+    {
+    	return $this->checkAllowedDeleteAnyEntryForProfile($isPerformAction, $this->_iProfileId);
+    }
+    
+    /**
+     * @return CHECK_ACTION_RESULT_ALLOWED if access is granted or error message if access is forbidden. So make sure to make strict(===) checking.
+     */
+    public function checkAllowedEditAnyEntryForProfile ($isPerformAction = false, $iProfileId = false)
+    {
+        if(!$iProfileId)
+            $iProfileId = $this->_iProfileId;
+
+    	$aCheck = checkActionModule($iProfileId, MEMBERSHIP_ACTION_EDIT_ANY_ENTRY, $this->getName(), $isPerformAction);
+    	if($aCheck[CHECK_ACTION_RESULT] === CHECK_ACTION_RESULT_ALLOWED)
+    		return CHECK_ACTION_RESULT_ALLOWED;
+
+    	return _t('_sys_txt_access_denied');
+    }
+
+    /**
+     * @return CHECK_ACTION_RESULT_ALLOWED if access is granted or error message if access is forbidden. So make sure to make strict(===) checking.
+     */
+    public function checkAllowedDeleteAnyEntryForProfile ($isPerformAction = false, $iProfileId = false)
+    {
+        if(!$iProfileId)
+            $iProfileId = $this->_iProfileId;
+
+    	$aCheck = checkActionModule($iProfileId, MEMBERSHIP_ACTION_DELETE_ANY_ENTRY, $this->getName(), $isPerformAction);
+    	if($aCheck[CHECK_ACTION_RESULT] === CHECK_ACTION_RESULT_ALLOWED)
+    		return CHECK_ACTION_RESULT_ALLOWED;
+
+    	return _t('_sys_txt_access_denied');
+    }
+
+    /**
+     * @return CHECK_ACTION_RESULT_ALLOWED if access is granted or error message if access is forbidden. So make sure to make "true === " checking.
+     */
+    public function checkAllowedCommentsView ($aContentInfo, $isPerformAction = false)
+    {
+        return $this->checkAllowedView ($aContentInfo, $isPerformAction);
+    }
+
+    /**
+     * @return CHECK_ACTION_RESULT_ALLOWED if access is granted or error message if access is forbidden. So make sure to make "true === " checking.
+     */
+    public function checkAllowedCommentsPost ($aContentInfo, $isPerformAction = false)
+    {
+        return $this->checkAllowedView ($aContentInfo, $isPerformAction);
+    }
+
+    protected function _serviceCheckAllowedViewForProfile ($aDataEntry, $isPerformAction, $iProfileId)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        if(!$iProfileId)
+            $iProfileId = $this->_iProfileId;
+
+        if(empty($aDataEntry) || !is_array($aDataEntry))
+            return _t('_sys_txt_not_found');
+
+        if(!empty($iProfileId) && abs($aDataEntry[$CNF['FIELD_AUTHOR']]) == (int)$iProfileId)
+            return CHECK_ACTION_RESULT_ALLOWED;
+
+        // below goes mem cached response for current page load
+
+        $sCacheKey = $this->getName() . ':' . __CLASS__ . ':_checkAllowedViewForProfile:' . $aDataEntry[$CNF['FIELD_ID']] . ':' . $iProfileId;        
+        $mixedRet = bx_mem_cache_get($sCacheKey);
+        if (null !== $mixedRet)
+            return $mixedRet;
+
+        $mixedRet = CHECK_ACTION_RESULT_ALLOWED;
+
+        if (empty($iProfileId) || !$this->_isModeratorForProfile($isPerformAction, $iProfileId)) { // skip checking if moderator
+            $aCheck = checkActionModule($iProfileId, 'view entry', $this->getName(), $isPerformAction); 
+            if ($aCheck[CHECK_ACTION_RESULT] !== CHECK_ACTION_RESULT_ALLOWED) { // check ACL
+                $mixedRet = $aCheck[CHECK_ACTION_MESSAGE];
+            } elseif(!empty($CNF['OBJECT_PRIVACY_VIEW'])) { // check privacy
+                $oPrivacy = BxDolPrivacy::getObjectInstance($CNF['OBJECT_PRIVACY_VIEW']);
+                if ($oPrivacy && !$oPrivacy->check($aDataEntry[$CNF['FIELD_ID']], $iProfileId))
+                    $mixedRet = _t('_sys_access_denied_to_private_content');
+            }
+        }
+
+        bx_mem_cache_set($sCacheKey, $mixedRet);
+
+        return $mixedRet;
+    }
+    
+    public function getObjectBrowse ($sMode, $aParams = false, $sClass = 'SearchResult')
+    {
+        $oObject = null;
+
+        bx_alert('system', 'get_object_browse', 0, 0, [
+            'module' => $this->getName(),
+            'mode' => &$sMode,
+            'params' => &$aParams,
+            'class' => &$sClass,
+            'object' => &$oObject,
+
+            'mode_ref' => &$sMode,
+            'params_ref' => &$aParams,
+            'class_ref' => &$sClass,
+            'object_ref' => &$oObject
+        ]);
+
+        if($oObject !== null) 
+            return $oObject;
+
+        if($aParams === false || !is_array($aParams))
+            $aParams = [];
+        $aParams['class_search_result'] ??= $sClass;
+
+        bx_import($sClass, $this->_aModule);
+        $sClass = $this->_aModule['class_prefix'] . $sClass;
+        return new $sClass($sMode, $aParams);
+    }
+
+    public function _serviceBrowse ($sMode, $aParams = false, $iDesignBox = BX_DB_PADDING_DEF, $bDisplayEmptyMsg = false, $bAjaxPaginate = true, $sClassSearchResult = 'SearchResult')
+    {
+        if(CHECK_ACTION_RESULT_ALLOWED !== ($sMsg = $this->checkAllowedBrowse()))
+            return $this->_bIsApi ? [bx_api_get_msg($sMsg)] : MsgBox($sMsg);
+
+        $o = $this->getObjectBrowse($sMode, $aParams, $sClassSearchResult);
+        $o->setDesignBoxTemplateId($iDesignBox);
+        $o->setDisplayEmptyMsg($bDisplayEmptyMsg);
+        $o->setAjaxPaginate($bAjaxPaginate);
+        $o->setUnitParams(array('context' => $sMode));
+        if(isset($aParams['condition']) && is_array($aParams['condition']))
+            $o->setCustomCurrentCondition($aParams['condition']);
+
+        if($o->isError)
+            return '';
+
+        if($this->_bIsApi) {
+            $aBlock = BxDolPage::getBlockProcessing();
+
+            $sContentType = 'browse';
+            if(($aConfigApi = $aBlock['config_api'] ?? false) && is_array($aConfigApi))
+                $sContentType = $aConfigApi['content_type'] ?? $sContentType;
+
+            $bBrowseSimple = $sContentType == 'browse_simple';
+
+            $a = $o->processingAPI($bBrowseSimple);
+            if($a && is_array($a))
+                $a['hide_empty_msg'] = !(bool)$bDisplayEmptyMsg;
+
+            return !$bBrowseSimple || $a['data'] ? [bx_api_get_block($sContentType, $a)] : [];
+        }
+        else
+            return ($s = $o->processing()) ? $s : '';
+    }
+
+    /**
+     * Shows a list of profiles.
+     */
+    protected function _serviceBrowseQuick($aProfiles, $iStart = 0, $iLimit = 4, $aAdditionalParams = [])
+    {
+        return bx_srv('system', 'browse_quick', [$aProfiles, $iStart, $iLimit, ['additional_params' => $aAdditionalParams]], 'TemplServiceProfiles');
+    }
+
+    // ====== COMMON METHODS
+    public function isPollPerformed($iObjectId, $iAuthorId = 0, $iAuthorIp = 0)
+    {
+        if(empty($iAuthorId)) {
+            $iAuthorId = bx_get_logged_profile_id();
+            $iAuthorIp = bx_get_ip_hash(getVisitorIP());
+        }
+
+        return $this->_oDb->isPollPerformed($iObjectId, $iAuthorId, $iAuthorIp);
+    }
+
+    public function getPollPerformedValue($iObjectId, $iAuthorId = 0)
+    {
+        if(empty($iAuthorId))
+            $iAuthorId = bx_get_logged_profile_id();
+
+        return $this->_oDb->getPollPerformedValue($iObjectId, $iAuthorId);
+    }
+
+    public function onPublished($iContentId)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $aContentInfo = $this->_oDb->getContentInfoById($iContentId);
+        if(!$aContentInfo)
+            return;
+
+        /*
+         * Process metas.
+         * Note. It's essential to process metas a the very end, 
+         * because all data related to an entry should be already
+         * processed and are ready to be passed to alert. 
+         */
+        $this->processMetasAdd($iContentId);
+
+        $this->alertAfterAdd($aContentInfo);
+    }
+
+    public function onFailed($iContentId)
+    {
+        $CNF = &$this->_oConfig->CNF;
+        
+        $aContentInfo = $this->_oDb->getContentInfoById($iContentId);
+        if(!$aContentInfo)
+            return;
+
+        /**
+         * @hooks
+         * @hookdef hook-bx_base_general-failed '{module_name}', 'failed' - hook after content creation when publishing was failed
+         * - $unit_name - module name
+         * - $action - equals `failed`
+         * - $object_id - content id
+         * - $sender_id - content author profile id
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `object_author_id` - [int] content author profile id
+         * @hook @ref hook-bx_base_general-failed
+         */
+        bx_alert($this->getName(), 'failed', $iContentId, $aContentInfo[$CNF['FIELD_AUTHOR']], [
+            'object_author_id' => $aContentInfo[$CNF['FIELD_AUTHOR']]
+        ]);
+    }
+
+    public function onApprove($mixedContent)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        if(!is_array($mixedContent))
+            $mixedContent = $this->_oDb->getContentInfoById((int)$mixedContent);
+
+        $this->alertAfterApprove($mixedContent);
+
+        $this->onPublished($mixedContent[$CNF['FIELD_ID']]);
+    }
+
+    public function onUpdateImage($iContentId, $sFiledName, $sFiledValue, $iProfileId = 0) {}
+
+    public function alertAfterAdd($aContentInfo) {}
+    
+    public function alertAfterEdit($aContentInfo) {}
+
+    public function alertAfterApprove($aContentInfo)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $iId = (int)$aContentInfo[$CNF['FIELD_ID']];
+
+        $sModule = $this->getName();
+        $aParams = $this->_alertParams($aContentInfo);
+
+        /**
+         * @hooks
+         * @hookdef hook-bx_base_general-approved '{module_name}', 'approved' - hook when module content has been approved
+         * - $unit_name - module name
+         * - $action - equals `approved` 
+         * - $object_id - content id 
+         * - $sender_id - not used, always `false`
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `source` - [string] uniq string for particular content in the following format `{module}_{content}`
+         *      - `object_author_id` - [int] content author profile id
+         * @hook @ref hook-bx_base_general-approved
+         */
+        bx_alert($sModule, 'approved', $iId, false, $aParams);
+    }
+
+    /**
+     * Get array of params to be passed in Add/Edit Alert.
+     */
+    protected function _alertParams($aContentInfo)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        return [
+            'source' => $this->_oConfig->getName() . '_' . (int)$aContentInfo[$CNF['FIELD_ID']],
+
+            'object_author_id' => (int)$aContentInfo[$CNF['FIELD_AUTHOR']]
+        ];
+    }
+
+    public function processMetasAdd($iContentId)
+    {        
+        return $this->processMetas('add', $iContentId);
+    }
+
+    public function processMetasEdit($iContentId, $oForm)
+    {
+        return $this->processMetas('edit', $iContentId, $oForm);
+    }
+
+    public function processMetas($aAction, $iContentId, $oForm = false)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        if(empty($CNF['OBJECT_METATAGS']))
+            return false;
+
+        $aContentInfo = $this->_oDb->getContentInfoById($iContentId, true);
+
+        $bFldStatus = !empty($CNF['FIELD_STATUS']);
+        $bFldStatusAdmin = !empty($CNF['FIELD_STATUS_ADMIN']);
+        $bContentInfo = $aContentInfo && (!$bFldStatus || ($bFldStatus && $aContentInfo[$CNF['FIELD_STATUS']] == 'active')) && (!$bFldStatusAdmin || ($bFldStatusAdmin && $aContentInfo[$CNF['FIELD_STATUS_ADMIN']] == 'active'));
+        if(!$bContentInfo)
+            return false;
+
+        $oMetatags = BxDolMetatags::getObjectInstance($CNF['OBJECT_METATAGS']);
+        $oMetatags->metaAddAuto($iContentId, $aContentInfo, $CNF, $CNF['OBJECT_FORM_ENTRY_DISPLAY_' . strtoupper($aAction)]);
+
+        if($oMetatags->locationsIsEnabled() && ($sKey = 'FIELD_LOCATION') && !empty($CNF[$sKey]) && !empty($aContentInfo[$CNF[$sKey]])) {
+            $aLocation = unserialize($aContentInfo[$CNF[$sKey]]);
+            if(!empty($aLocation) && is_array($aLocation))
+                call_user_func_array(array($oMetatags, 'locationsAdd'), array_merge(array($iContentId), array_values($aLocation)));
+        }
+
+        if($oMetatags->keywordsIsEnabled() && ($sKey = 'FIELD_LABELS') && !empty($CNF[$sKey]) && !empty($aContentInfo[$CNF[$sKey]])) {
+            $aLabels = unserialize($aContentInfo[$CNF[$sKey]]);
+            if(!empty($aLabels) && is_array($aLabels))
+                foreach ($aLabels as $sLabel) {
+                    if(!preg_match("/(\pL[\pL\pN_]+)/u", $sLabel))
+                        continue;
+
+                    $oMetatags->keywordsAddOne($iContentId, $sLabel, false);
+                }
+        }
+
+        return true;
+    }
+
+    public function addAttachLink($aValues, $sDisplay = false)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        if(!$sDisplay)
+            $sDisplay = $CNF['OBJECT_FORM_ATTACH_LINK_DISPLAY_ADD'];
+
+        $oForm = BxDolForm::getObjectInstance($CNF['OBJECT_FORM_ATTACH_LINK'], $sDisplay, $this->_oTemplate);
+        if(!$oForm)
+            return array('message' => '_sys_txt_error_occured');
+
+        $oForm->aFormAttrs['method'] = BX_DOL_FORM_METHOD_SPECIFIC;
+        $oForm->aParams['csrf']['disable'] = true;
+        if(!empty($oForm->aParams['db']['submit_name'])) {
+            $sSubmitName = $oForm->aParams['db']['submit_name'];
+            if(!isset($oForm->aInputs[$sSubmitName])) {
+                if(isset($oForm->aInputs[$CNF['FIELD_ATTACH_LINK_CONTROLS']]))
+                    foreach($oForm->aInputs[$CNF['FIELD_ATTACH_LINK_CONTROLS']] as $mixedIndex => $aInput) {
+                        if(!is_numeric($mixedIndex) || empty($aInput['name']) || $aInput['name'] != $sSubmitName)
+                            continue;
+    
+                        $aValues[$sSubmitName] = $aInput['value'];
+                    }
+            }
+            else            
+                $aValues[$sSubmitName] = $oForm->aInputs[$sSubmitName]['value'];
+        }
+
+        $oForm->aInputs['url']['checker']['params']['preg'] = $this->_oConfig->getPregPattern('url');
+
+        $oForm->initChecker(array(), $aValues);
+        if(!$oForm->isSubmittedAndValid())
+            return array('message' => '_sys_txt_error_occured');
+
+        return $this->_addLink($oForm);
+    }
+
+    public function getFormAttachLink($iContentId = 0)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $oForm = BxDolForm::getObjectInstance($CNF['OBJECT_FORM_ATTACH_LINK'], $CNF['OBJECT_FORM_ATTACH_LINK_DISPLAY_ADD'], $this->_oTemplate);
+        $oForm->aFormAttrs['action'] = BX_DOL_URL_ROOT . $this->_oConfig->getBaseUri() . 'submit_attach_link_form/';
+        $oForm->aInputs[$CNF['FIELD_ATTACH_LINK_CONTENT_ID']]['value'] = $iContentId;
+        $oForm->aInputs[$CNF['FIELD_ATTACH_LINK_URL']]['checker']['params']['preg'] = $this->_oConfig->getPregPattern('url');
+
+        $oForm->initChecker();
+        if($oForm->isSubmittedAndValid())
+            return $this->_addLink($oForm);
+
+        return ['form' => $oForm->getCode(), 'form_id' => $oForm->id];
+    }
+
+    protected function _addLink(&$oForm)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $iUserId = $this->getUserId();
+
+        $iContentId = (int)$oForm->getCleanValue($CNF['FIELD_ATTACH_LINK_CONTENT_ID']);
+        $sLink = rtrim($oForm->getCleanValue('url'), '/');
+        $sHost = parse_url($sLink, PHP_URL_HOST);
+        if($sHost && is_private_ip(gethostbyname($sHost)))
+            return ['message' => _t('_sys_txt_error_occured')];
+
+        $aMatches = [];
+        preg_match($this->_oConfig->getPregPattern('url'), $sLink, $aMatches);
+        $sLink = (empty($aMatches[2]) ? 'http://' : '') . $aMatches[0];
+
+        $aSiteInfo = bx_get_site_info($sLink, [
+            'thumbnailUrl' => ['tag' => 'link', 'content_attr' => 'href'],
+            'OGImage' => ['name_attr' => 'property', 'name' => 'og:image'],
+        ]);
+
+        $sTitle = !empty($aSiteInfo['title']) ? $aSiteInfo['title'] : $sHost;
+        $sDescription = !empty($aSiteInfo['description']) ? $aSiteInfo['description'] : '';
+
+        $sMediaUrl = '';
+        if(!empty($aSiteInfo['thumbnailUrl']))
+            $sMediaUrl = $aSiteInfo['thumbnailUrl'];
+        else if(!empty($aSiteInfo['OGImage']))
+            $sMediaUrl = $aSiteInfo['OGImage'];
+
+        $iMediaId = 0;
+        $oStorage = null;
+        if(!empty($sMediaUrl)) {
+            $oStorage = BxDolStorage::getObjectInstance($CNF['OBJECT_STORAGE_PHOTOS']);
+
+            $iMediaId = $oStorage->storeFileFromUrl($sMediaUrl, true, $iUserId);
+        }
+
+        $iId = (int)$oForm->insert(['profile_id' => $iUserId, 'media_id' => $iMediaId, 'url' => $sLink, 'title' => $sTitle, 'text' => $sDescription, 'added' => time()]);
+        if(!empty($iId)) {
+            if(!empty($oStorage) && !empty($iMediaId))
+                $oStorage->afterUploadCleanup($iMediaId, $iUserId);
+
+            return [
+                'id' => $iId, 
+                $CNF['FIELD_ATTACH_LINK_CONTENT_ID'] => $iContentId, 
+                'url' => $sLink,
+                'item' => $this->_oTemplate->getAttachLinkItem($iUserId, $iId)
+            ];
+        }
+
+        return ['message' => _t('_bx_timeline_txt_err_cannot_perform_action')];
+    }
+
+    public function getEntryImageData($aContentInfo, $sField = 'FIELD_THUMB', $aTranscoders = array())
+    {
+        if(empty($aTranscoders))
+            $aTranscoders = array('OBJECT_TRANSCODER_COVER', 'OBJECT_IMAGES_TRANSCODER_COVER', 'OBJECT_IMAGES_TRANSCODER_GALLERY');
+
+        $CNF = &$this->_oConfig->CNF;
+        if(empty($CNF[$sField]) || empty($aContentInfo[$CNF[$sField]]) || empty($CNF['OBJECT_STORAGE']))
+            return false;
+
+        $iId = (int)$aContentInfo[$CNF[$sField]];
+        $aFile = BxDolStorage::getObjectInstance($CNF['OBJECT_STORAGE'])->getFile($iId);
+        if(!empty($aFile) && is_array($aFile) && strpos($aFile['mime_type'], 'svg') !== false)
+            return array('id' => $iId, 'object' => $CNF['OBJECT_STORAGE']);
+
+        foreach($aTranscoders as $sTranscoder)
+            if(!empty($CNF[$sTranscoder]))
+                return array('id' => $iId, 'transcoder' => $CNF[$sTranscoder]);
+
+        return array('id' => $iId, 'object' => $CNF['OBJECT_STORAGE']);
+    }
+
+    public function getEntryAllActions ($mixedContent = false, $aParams = [])
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        if(!empty($mixedContent)) {
+            if(!is_array($mixedContent))
+                $mixedContent = array((int)$mixedContent, (method_exists($this->_oDb, 'getContentInfoById')) ? $this->_oDb->getContentInfoById((int)$mixedContent) : array());
+        }
+        else {
+            $mixedContent = $this->_getContent();
+            if($mixedContent === false)
+                return false;
+        }
+
+        list($iContentId, $aContentInfo) = $mixedContent;
+
+        $sObjectMenu = !empty($aParams['object_menu']) ? $aParams['object_menu'] : '';
+        if(empty($sObjectMenu) && !empty($CNF['OBJECT_MENU_ACTIONS_VIEW_ENTRY_ALL']))
+            $sObjectMenu = $CNF['OBJECT_MENU_ACTIONS_VIEW_ENTRY_ALL'];
+
+        if(empty($sObjectMenu))
+            return false;
+
+        $sEntryTitle = !empty($aParams['entry_title']) ? $aParams['entry_title'] : '';
+        if(empty($sEntryTitle) && !empty($CNF['FIELD_TITLE']) && !empty($aContentInfo[$CNF['FIELD_TITLE']]))
+            $sEntryTitle = $aContentInfo[$CNF['FIELD_TITLE']];
+
+        $sEntryUrl = !empty($aParams['entry_url']) ? $aParams['entry_url'] : '';
+        if(empty($sEntryUrl) && !empty($CNF['URI_VIEW_ENTRY']))
+            $sEntryUrl = bx_absolute_url(BxDolPermalinks::getInstance()->permalink('page.php?i=' . $CNF['URI_VIEW_ENTRY'] . '&id=' . $iContentId));
+
+        $iEntryThumb = !empty($aParams['entry_thumb']) ? (int)$aParams['entry_thumb'] : 0;
+        if(empty($iEntryThumb) && !empty($CNF['FIELD_THUMB']) && !empty($aContentInfo[$CNF['FIELD_THUMB']]))
+            $iEntryThumb = (int)$aContentInfo[$CNF['FIELD_THUMB']];
+
+        $sObjectStorage = !empty($aParams['object_storage']) ? $aParams['object_storage'] : false;
+        if(empty($sObjectStorage) && !empty($CNF['OBJECT_STORAGE']))
+            $sObjectStorage = $CNF['OBJECT_STORAGE'];
+
+        $sObjectTranscoder = !empty($aParams['object_transcoder']) ? $aParams['object_transcoder'] : false;
+
+        $aMarkers = [
+            'id' => $iContentId,
+            'module' => $this->_oConfig->getName(),
+            'title' => !empty($sEntryTitle) ? $sEntryTitle : '',
+            'url' => !empty($sEntryUrl) ? $sEntryUrl : '',
+            'img_url' => ''
+        ];
+
+        if(!empty($iEntryThumb)) {
+            if(!empty($sObjectTranscoder))
+                $o = BxDolTranscoder::getObjectInstance($sObjectTranscoder);
+            else if(!empty($sObjectStorage))
+                $o = BxDolStorage::getObjectInstance($sObjectStorage);
+
+            $sImageUrl = $o ? $o->getFileUrlById($iEntryThumb) : '';
+            if(!empty($sImageUrl))
+                $aMarkers['img_url'] = $sImageUrl;
+        }
+
+        $oActions = BxDolMenu::getObjectInstance($sObjectMenu, $this->_oTemplate);
+        if(!$oActions)
+            return false;
+
+        $oActions->setContentId($iContentId);
+        $oActions->addMarkers($aMarkers);
+
+        return $oActions->{bx_is_api() ? 'getCodeAPI' : 'getCode'}();
+    }
+
+    public function setProfileId($i)
+    {
+        $iOldProfileId = $this->_iProfileId;
+        $this->_iProfileId = $i;
+        return $iOldProfileId;
+    }
+    
+    public function getProfileId()
+    {
+        return $this->_iProfileId;
+    }
+
+    public function getProfileInfo($iUserId = false)
+    {
+        $oProfile = $this->getObjectUser($iUserId);
+
+        $oAccount = null;
+        if($oProfile && !($oProfile instanceof BxDolProfileUndefined) && !($oProfile instanceof BxDolProfileAnonymous))
+            $oAccount = $oProfile->getAccountObject();
+        $bAccount = !empty($oAccount);
+
+        if(!$bAccount)
+            $oProfile = BxDolProfileUndefined::getInstance();
+
+        return array(
+            'id' => $oProfile->id(),
+            'name' => $oProfile->getDisplayName(),
+            'email' => $bAccount ? $oAccount->getEmail() : '',
+            'link' => $oProfile->getUrl(),
+            'icon' => $oProfile->getIcon(),
+            'thumb' => $oProfile->getThumb(),
+            'avatar' => $oProfile->getAvatar(),
+            'active' => $oProfile->isActive(),
+        );
+    }
+
+    public function getObjectUser($iUserId = false)
+    {
+    	bx_import('BxDolProfile');
+        return BxDolProfile::getInstanceMagic($iUserId);
+    }
+
+    public function getObjectFavorite($sSystem = '', $iId = 0)
+    {
+        $CNF = &$this->_oConfig->CNF;
+        if(empty($sSystem) && !empty($CNF['OBJECT_FAVORITES']))
+            $sSystem = $CNF['OBJECT_FAVORITES'];
+
+        if(empty($sSystem))
+            return false;
+
+        $oFavorite = BxDolFavorite::getObjectInstance($sSystem, $iId, true, $this->_oTemplate);
+        if(!$oFavorite || !$oFavorite->isEnabled())
+            return false;
+
+        return $oFavorite;
+    }
+
+	public function getUserId()
+    {
+        return isLogged() ? bx_get_logged_profile_id() : 0;
+    }
+
+    public function getUserIp()
+    {
+        return getVisitorIP();
+    }
+    
+    public function getUserInfo($iUserId = 0)
+    {
+        $oProfile = BxDolProfile::getInstanceMagic($iUserId);
+
+        return array(
+            $oProfile->getDisplayName(),
+            $oProfile->getUrl(),
+            $oProfile->getThumb(),
+            $oProfile->getUnit(),
+            $oProfile->getUnit(0, array('template' => 'unit_wo_info'))
+        );
+    }
+    
+    public function getUserInfoWithBadges($iUserId = 0)
+    {
+        $oProfile = BxDolProfile::getInstanceMagic($iUserId);
+
+        return array(
+            $oProfile->getDisplayName(),
+            $oProfile->getUrl(),
+            $oProfile->getThumb(),
+            $oProfile->getUnit(),
+            $oProfile->getUnit(0, array('template' => 'unit_wo_info')),
+            $oProfile->getBadges()
+        );
+    }
+
+    public function isMenuItemVisible($sObject, &$aItem, &$aContentInfo)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        // default visible settings
+        if(!BxDolAcl::getInstance()->isMemberLevelInSet($aItem['visible_for_levels']))
+            return false;
+
+        if (!empty($aItem['visibility_custom'])) {
+            $oMenu = BxDolMenu::getObjectInstance($sObject);
+            if ($oMenu && !BxDolService::callSerialized($aItem['visibility_custom'], $oMenu->getMarkers()))
+                return false;
+        }
+        
+        // get custom function name to check menu item visibility
+        $sFuncCheckAccess = false;
+        if(isset($CNF['MENU_ITEM_TO_METHOD'][$sObject][$aItem['name']]))
+            $sFuncCheckAccess = $CNF['MENU_ITEM_TO_METHOD'][$sObject][$aItem['name']];
+
+        // check custom visibility settings defined in module config class
+        if(!isset($aContentInfo))
+            $aContentInfo = array();
+
+        if($sFuncCheckAccess && CHECK_ACTION_RESULT_ALLOWED !== call_user_func_array(array($this, $sFuncCheckAccess), array(&$aContentInfo)))
+            return false;
+
+        return true;
+    }
+
+    public function getModerators($mixedContentInfo)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $sModule = $this->_oConfig->getName();
+
+        if(!is_array($mixedContentInfo))
+            $mixedContentInfo = $this->_oDb->getContentInfoById((int)$mixedContentInfo);
+
+        $aModerators = [];
+        if(getParam('sys_notify_to_approve_by_role') == 'on' && bx_srv('system', 'is_module_content', [$sModule]) && ($sField = 'FIELD_ALLOW_VIEW_TO') && !empty($CNF[$sField]) && (int)$mixedContentInfo[$CNF[$sField]] < 0) {
+            $iContextProfileId = abs((int)$mixedContentInfo[$CNF['FIELD_ALLOW_VIEW_TO']]);
+            $oContextProfile = BxDolProfile::getInstance($iContextProfileId);
+
+            $aModerators = bx_srv($oContextProfile->getModule(), 'get_admins_to_manage_content', [$iContextProfileId]);
+        }
+
+        if(empty($aModerators))
+            $aModerators = BxDolAclQuery::getInstance()->getProfilesByAction([
+                MEMBERSHIP_ACTION_EDIT_ANY_ENTRY, 
+                MEMBERSHIP_ACTION_DELETE_ANY_ENTRY
+            ], [
+                'module' => $sModule, 
+                'ids_only' => true
+            ]);
+
+        return $aModerators;
+    }
+
+    public function _isModerator ($isPerformAction = false)
+    {
+        return $this->_isModeratorForProfile($isPerformAction, $this->_iProfileId);
+    }
+
+    public function _isModeratorForProfile($isPerformAction = false, $iProfileId = false)
+    {
+        return CHECK_ACTION_RESULT_ALLOWED === $this->checkAllowedEditAnyEntryForProfile ($isPerformAction, $iProfileId);
+    }
+
+    public function _isAdministrator ($isPerformAction = false)
+    {
+        return $this->_isAdministratorForProfile($isPerformAction, $this->_iProfileId);
+    }
+
+    public function _isAdministratorForProfile($isPerformAction = false, $iProfileId = false)
+    {
+        return CHECK_ACTION_RESULT_ALLOWED === $this->checkAllowedDeleteAnyEntryForProfile ($isPerformAction, $iProfileId);
+    }
+
+    public function _prepareAuditParams($aContentInfo, $bIsSaveData = true, $aOverrideAuditParams  = array())
+    {
+        $CNF = &$this->_oConfig->CNF;
+        
+        $iContextId = isset($CNF['FIELD_ALLOW_VIEW_TO']) && (!empty($aContentInfo[$CNF['FIELD_ALLOW_VIEW_TO']]) && (int)$aContentInfo[$CNF['FIELD_ALLOW_VIEW_TO']] < 0) ? - $aContentInfo[$CNF['FIELD_ALLOW_VIEW_TO']] : 0;
+        
+        $AuditParams = array(
+            'content_title' => (isset($CNF['FIELD_TITLE']) && isset($aContentInfo[$CNF['FIELD_TITLE']])) ? $aContentInfo[$CNF['FIELD_TITLE']] : '',
+            'context_profile_id' => $iContextId,
+            'content_info_object' =>  isset($CNF['OBJECT_CONTENT_INFO']) ? $CNF['OBJECT_CONTENT_INFO'] : '',
+            'data' => ($bIsSaveData ? $aContentInfo : array())
+        );
+        if ($iContextId > 0)
+            $AuditParams['context_profile_title'] = BxDolProfile::getInstance($iContextId)->getDisplayName();
+        
+        $AuditParams = array_merge($AuditParams, $aOverrideAuditParams);
+        
+        return $AuditParams;
+    }
+    
+    public function _getFavoriteListUrl ($iListId, $iProfileId)
+    {
+        $CNF = &$this->_oConfig->CNF;
+        return bx_absolute_url(BxDolPermalinks::getInstance()->permalink('page.php?i=' . $CNF['URI_FAVORITES_LIST'] . '&profile_id=' . $iProfileId . '&list_id=' . $iListId));
+    }
+
+    public function getDataAPI($aData, $aParams = [])
+    {
+        $aDataApi = $this->decodeDataAPI($aData, $aParams);
+
+        $sModule = $this->getName();
+        $aExtras = [
+            'module' => $sModule,
+            'data' => $aData,
+            'params' => $aParams,
+            'data_api' => &$aDataApi,
+            'data_api_ref' => &$aDataApi,
+        ];
+
+        /**
+         * @hooks
+         * @hookdef hook-system-decode_data_api 'system', 'decode_data_api' - hook to override content data prepared for sending in API response
+         * - $unit_name - equals `system`
+         * - $action - equals `decode_data_api`
+         * - $object_id - not used
+         * - $sender_id - not used
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `module` - [string] module name
+         *      - `data` - [array] content info array as key&value pairs
+         *      - `params` - [array] params array as key&value pairs
+         *      - `data_api` - [array] by ref, content data prepared for sending in API response, can be overridden in hook processing
+         * @hook @ref hook-system-decode_data_api
+         */
+        bx_alert('system', 'decode_data_api', 0, 0, $aExtras);
+
+        /**
+         * @hooks
+         * @hookdef hook-bx_base_general-decode_data_api '{module_name}', 'decode_data_api' - hook to override content data prepared for sending in API response
+         * It's equivalent to @ref hook-system-decode_data_api
+         * @hook @ref hook-bx_base_general-decode_data_api
+         */
+        bx_alert($sModule, 'decode_data_api', 0, 0, $aExtras);
+
+        return $aDataApi;
+    }
+
+    public function decodeDataAPI($aData, $aParams = [])
+    {
+        return $aData;
+    }
+
+    protected function decodeDataAPICommonFields(&$aResult, $aData, $aParams) 
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        if (!empty($CNF['FIELD_LABELS'])) {
+            $aResult[$CNF['FIELD_LABELS']] = empty($aData[$CNF['FIELD_LABELS']]) ? [] : unserialize($aData[$CNF['FIELD_LABELS']]);
+        }
+
+        if (!empty($CNF['FIELD_LOCATION'])) {
+            $aResult[$CNF['FIELD_LOCATION']] = empty($aData[$CNF['FIELD_LOCATION']]) ? [] : unserialize($aData[$CNF['FIELD_LOCATION']]);
+        }
+    }
+
+    // ====== PROTECTED METHODS
+
+    protected function _serviceEntityForm ($sFormMethod, $iContentId = 0, $sDisplay = false, $sCheckFunction = false, $bErrorMsg = true)
+    {
+        $iContentId = $this->_getContent($iContentId, false);
+        if($iContentId === false)
+            return false;
+
+        $oFormsHelper = $this->getFormsHelper();
+        return $oFormsHelper->$sFormMethod((int)$iContentId, $sDisplay, $sCheckFunction, $bErrorMsg);
+    }
+
+    protected function _serviceTemplateFunc ($sFunc, $iContentId, $sFuncGetContent = 'getContentInfoById')
+    {
+        return $this->_serviceTemplateFuncEx($sFunc, $iContentId, array('function_get_content' => $sFuncGetContent));
+    }
+    
+    protected function _serviceTemplateFuncEx ($sFunc, $iContentId, $aParams = array())
+    {
+        if (!isset($aParams['function_get_content']))
+            $aParams['function_get_content'] = 'getContentInfoById';
+        
+        $mixedContent = $this->_getContent($iContentId, $aParams['function_get_content']);
+        if($mixedContent === false)
+            return false;
+
+        list($iContentId, $aContentInfo) = $mixedContent;
+
+        unset($aParams['function_get_content']);
+        
+        if (!empty($aParams))
+            return $this->_oTemplate->$sFunc($aContentInfo, $aParams);
+        else
+            return $this->_oTemplate->$sFunc($aContentInfo);
+    }
+
+    protected function _getApproveForm($iContentId, $aContentInfo)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $sForm = 'sys_manage';
+        if(!empty($CNF['OBJECT_FORM_MANAGE']))
+            $sForm = $CNF['OBJECT_FORM_MANAGE'];
+
+        $sFormDisplay = 'sys_manage_approve';
+        if(!empty($CNF['OBJECT_FORM_MANAGE_APPROVE']))
+            $sFormDisplay = $CNF['OBJECT_FORM_MANAGE_APPROVE'];
+
+        $oForm = BxTemplFormView::getObjectInstance($sForm, $sFormDisplay);
+        $oForm->aFormAttrs['action'] = BX_DOL_URL_ROOT . $this->_oConfig->getBaseUri() . 'approve';
+        $oForm->aInputs['content_id']['value'] = $iContentId;
+        foreach($oForm->aInputs['controls'] as $iKey => $mixedValue)
+            if(is_numeric($iKey) && isset($mixedValue['name']) && $mixedValue['name'] == 'do_submit')
+                $oForm->aInputs['controls'][$iKey]['value'] = _t('_sys_form_manage_input_do_submit_approve');
+
+        /**
+         * @hooks
+         * @hookdef hook-bx_base_general-get_approve_form '{module_name}', 'get_approve_form' - hook to override approve content form
+         * - $unit_name - module name
+         * - $action - equals `get_approve_form`
+         * - $object_id - not used
+         * - $sender_id - not used
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `content_id` - [int] content id
+         *      - `content_info` - [array] content info array as key&value pairs
+         *      - `override_result` - [object] by ref, an instance of approve content form, @see BxDolForm, can be overridden in hook processing
+         * @hook @ref hook-bx_base_general-get_approve_form
+         */
+        bx_alert($this->_oConfig->getName(), 'get_approve_form', 0, 0, [
+            'content_id' => $iContentId,
+            'content_info' => $aContentInfo,
+            'override_result' => &$oForm
+        ]);
+
+        return $oForm;
+    }
+
+    protected function _sendApproveMessage($iContentId, $aContentInfo, &$oForm)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $sETemplate = 't_ManageApprove';
+        if(!empty($CNF['ETEMPLATE_MANAGE_APPROVE']))
+            $sETemplate = $CNF['ETEMPLATE_MANAGE_APPROVE'];
+
+        $aEParams = array(
+            'content_title' => !empty($CNF['FIELD_TITLE']) && !empty($aContentInfo[$CNF['FIELD_TITLE']]) ? $aContentInfo[$CNF['FIELD_TITLE']] : '',
+            'notes' => $oForm->getCleanValue('notes'),
+        );
+
+        /**
+         * @hooks
+         * @hookdef hook-bx_base_general-get_approve_message '{module_name}', 'get_approve_form' - hook to override approve content message
+         * - $unit_name - module name
+         * - $action - equals `get_approve_message`
+         * - $object_id - not used
+         * - $sender_id - not used
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `content_id` - [int] content id
+         *      - `content_info` - [array] content info array as key&value pairs
+         *      - `form` - [object] an instance of approve content form
+         *      - `email_template` - [string] by ref, email template name, @see BxDolEmailTemplates, can be overridden in hook processing
+         *      - `email_params` - [array] by ref, email template params, can be overridden in hook processing
+         * @hook @ref hook-bx_base_general-get_approve_message
+         */
+        bx_alert($this->_oConfig->getName(), 'get_approve_message', 0, 0, [
+            'content_id' => $iContentId,
+            'content_info' => $aContentInfo,
+            'form' => $oForm,
+
+            'email_template' => &$sETemplate,
+            'email_params' => &$aEParams,
+
+            'email_template_ref' => &$sETemplate,
+            'email_params_ref' => &$aEParams
+        ]);
+
+        return sendMailTemplate($sETemplate, 0, $aContentInfo[$CNF['FIELD_AUTHOR']], $aEParams);
+    }
+
+    protected function _processModerationNotifications($aContentInfo)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        if(empty($CNF['PARAM_AUTO_APPROVE']) || getParam($CNF['PARAM_AUTO_APPROVE']) == 'on')
+            return;
+
+        $aRecipients = $this->getModerators($aContentInfo);
+        if(empty($aRecipients))
+            return;
+
+        $sModule = $this->_oConfig->getName();
+        foreach($aRecipients as $iRecipientId)
+            /**
+             * @hooks
+             * @hookdef hook-bx_base_general-pending_approval '{module_name}', 'pending_approval' - hook to notify admins/moderators about new pending approval content
+             * - $unit_name - module name
+             * - $action - equals `pending_approval`
+             * - $object_id - content id
+             * - $sender_id - content author profile id
+             * - $extra_params - array of additional params with the following array keys:
+             *      - `object_author_id` - [int] admin/moderator profile id
+             * @hook @ref hook-bx_base_general-pending_approval
+             */
+            bx_alert($sModule, 'pending_approval', $aContentInfo[$CNF['FIELD_ID']], $aContentInfo[$CNF['FIELD_AUTHOR']], [
+                'object_author_id' => (int)$iRecipientId
+            ]);
+    }
+
+    protected function _rss ($aArgs, $sClass = 'SearchResult')
+    {
+        if (CHECK_ACTION_RESULT_ALLOWED !== ($sMsg = $this->checkAllowedBrowse())) {
+            $this->_oTemplate->displayAccessDenied ($sMsg);
+            exit;
+        }
+
+        $sMode = array_shift($aArgs);
+        $aParams = $this->_buildRssParams($sMode, $aArgs);
+
+        $o = $this->getObjectBrowse($sMode, $aParams, $sClass);
+        if ($o->isError)
+            $this->_oTemplate->displayPageNotFound ();
+        else
+            $o->outputRSS();
+
+        exit;
+    }
+
+    protected function _getContent($iContentId = 0, $sFuncGetContent = true)
+    {
+        if(!$iContentId)
+            $iContentId = bx_process_input(bx_get('id'), BX_DATA_INT);
+
+        if(!$iContentId)
+            return false;
+
+        if($sFuncGetContent === true)
+            $sFuncGetContent = 'getContentInfoById';
+
+        if(empty($sFuncGetContent) || !method_exists($this->_oDb, $sFuncGetContent))
+            return $iContentId;
+
+        $aContentInfo = $this->_oDb->$sFuncGetContent($iContentId);
+        if(!$aContentInfo)
+            return false;
+
+        return array($iContentId, $aContentInfo);
+    }
+
+    protected function _getContentForTimelinePost($aEvent, $aContentInfo, $aBrowseParams = array())
+    {
+    	$CNF = &$this->_oConfig->CNF;
+
+    	$sUrl = bx_absolute_url(BxDolPermalinks::getInstance()->permalink('page.php?i=' . $CNF['URI_VIEW_ENTRY'] . '&id=' . $aContentInfo[$CNF['FIELD_ID']]));
+
+    	//--- Image(s)
+        $aImages = $this->_getImagesForTimelinePost($aEvent, $aContentInfo, $sUrl, $aBrowseParams);
+        $aImagesAttach = $this->_getImagesForTimelinePostAttach($aEvent, $aContentInfo, $sUrl, $aBrowseParams);
+
+        //--- Video(s)
+        $aVideos = $this->_getVideosForTimelinePost($aEvent, $aContentInfo, $sUrl, $aBrowseParams);
+        $aVideosAttach = $this->_getVideosForTimelinePostAttach($aEvent, $aContentInfo, $sUrl, $aBrowseParams);
+
+        //--- Files(s)
+        $aFiles = $this->_getFilesForTimelinePost($aEvent, $aContentInfo, $sUrl, $aBrowseParams);
+        $aFilesAttach = $this->_getFilesForTimelinePostAttach($aEvent, $aContentInfo, $sUrl, $aBrowseParams);
+
+        if($this->_bIsApi && getParam('sys_api_extended_units') != 'on') {
+            $sTitle = '';
+            if(isset($CNF['FIELD_TITLE']) && isset($aContentInfo[$CNF['FIELD_TITLE']]))
+                $sTitle = $aContentInfo[$CNF['FIELD_TITLE']];
+            else if(isset($CNF['FIELD_TEXT']) && isset($aContentInfo[$CNF['FIELD_TEXT']]))
+                $sTitle = strmaxtextlen($aContentInfo[$CNF['FIELD_TEXT']], 20, '...');
+
+            $sAbstract = isset($CNF['FIELD_ABSTRACT']) && isset($aContentInfo[$CNF['FIELD_ABSTRACT']]) ? $aContentInfo[$CNF['FIELD_ABSTRACT']] : '';
+
+            $sText = isset($CNF['FIELD_TEXT']) && isset($aContentInfo[$CNF['FIELD_TEXT']]) ? $aContentInfo[$CNF['FIELD_TEXT']] : '';
+            $sText = BxTemplFunctions::getInstance()->getStringWithLimitedLength(strip_tags($sText), 240);
+
+            $aResults = [
+                'url' => $sUrl,
+                'title' => $sTitle,
+                'abstract' => $sAbstract,
+                'text' => $sText
+            ];
+
+            if(!empty($aImages) && is_array($aImages))
+                $aResults['images'] = $aImages;
+            if(!empty($aVideos) && is_array($aVideos))
+                $aResults['videos'] = $aVideos;
+            if(!empty($aFiles) && is_array($aFiles))
+                $aResults['files'] = $aFiles;
+
+            return $aResults;
+        }
+
+        //--- Title
+        $sTitle = '';
+        if(isset($CNF['FIELD_TITLE']) && isset($aContentInfo[$CNF['FIELD_TITLE']]))
+            $sTitle = $aContentInfo[$CNF['FIELD_TITLE']];
+        else if(isset($CNF['FIELD_TEXT']) && isset($aContentInfo[$CNF['FIELD_TEXT']]))
+            $sTitle = strmaxtextlen($aContentInfo[$CNF['FIELD_TEXT']], 20, '...');
+
+        //--- Text
+        $sText = '';
+        if(isset($CNF['FIELD_ABSTRACT']) && isset($aContentInfo[$CNF['FIELD_ABSTRACT']]))
+            $sText = $aContentInfo[$CNF['FIELD_ABSTRACT']];
+        if(empty($sText) && isset($CNF['FIELD_TEXT']) && isset($aContentInfo[$CNF['FIELD_TEXT']]))
+            $sText = $aContentInfo[$CNF['FIELD_TEXT']];
+
+        if(!empty($CNF['OBJECT_METATAGS']) && is_string($sText)) {
+            $oMetatags = BxDolMetatags::getObjectInstance($CNF['OBJECT_METATAGS']);
+            $sText = $oMetatags->metaParse($aContentInfo[$CNF['FIELD_ID']], $sText);
+        }
+
+        $sCategory = '';
+        if (isset($CNF['OBJECT_CATEGORY']) && isset($CNF['OBJECT_CATEGORY']) && isset($aContentInfo[$CNF['FIELD_CATEGORY']])){
+            $oCategory = BxDolCategory::getObjectInstance($CNF['OBJECT_CATEGORY']);
+            if ($oCategory)
+                $sCategory = $oCategory->getCategoryTitle($aContentInfo[$CNF['FIELD_CATEGORY']]);
+        } 
+
+        $aResult = [
+            'title' => $sTitle,
+            'text' => $sText,
+            'images' => $aImages,
+            'images_attach' => $aImagesAttach,
+            'videos' => $aVideos,
+            'videos_attach' => $aVideosAttach,
+            'files' => $aFiles,
+            'files_attach' => $aFilesAttach
+        ];
+
+        return $this->_bIsApi ? $aResult : array_merge($aResult, [
+            'sample' => isset($CNF['T']['txt_sample_single_with_article']) ? $CNF['T']['txt_sample_single_with_article'] : $CNF['T']['txt_sample_single'],
+            'sample_wo_article' => $CNF['T']['txt_sample_single'],
+            'sample_action' => isset($CNF['T']['txt_sample_action']) ? $CNF['T']['txt_sample_action'] : '',
+            'url' => $sUrl,
+            'category' => $sCategory,
+        ]);
+    }
+
+    protected function _getImagesForTimelinePost($aEvent, $aContentInfo, $sUrl, $aBrowseParams = array())
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        if($this->_bIsApi) {
+            $aResult = [];
+
+            if(isset($CNF['FIELD_COVER']) && !empty($aContentInfo[$CNF['FIELD_COVER']])) {
+                $aResult[] = bx_api_get_image($CNF['OBJECT_STORAGE'], (int)$aContentInfo[$CNF['FIELD_COVER']]);
+            }
+
+            if((($sK = $CNF['FIELD_THUMB'] ?? false) && !empty($aContentInfo[$sK])) || (($sK = $CNF['FIELD_PICTURE'] ?? false) && !empty($aContentInfo[$sK]))) {
+                $aResult[] = bx_api_get_image($CNF['OBJECT_STORAGE'], (int)$aContentInfo[$sK]);
+            }
+
+            return $aResult;
+        }
+
+        $iImageId = 0;
+        $sImageSm = $sImageMd = $sImageXl = '';
+        if(isset($CNF['FIELD_COVER']) && !empty($aContentInfo[$CNF['FIELD_COVER']])) {
+            $iImageId = (int)$aContentInfo[$CNF['FIELD_COVER']];
+            $sImageSm = $this->_oConfig->getImageUrl($iImageId, ['OBJECT_IMAGES_TRANSCODER_MINIATURE', 'OBJECT_IMAGES_TRANSCODER_THUMB']);
+            $sImageMd = $this->_oConfig->getImageUrl($iImageId, ['OBJECT_IMAGES_TRANSCODER_GALLERY', 'OBJECT_IMAGES_TRANSCODER_THUMB']);
+            $sImageXl = $this->_oConfig->getImageUrl($iImageId, ['OBJECT_IMAGES_TRANSCODER_COVER']);
+        }
+
+        if($sImageMd == '' && (($sK = $CNF['FIELD_THUMB'] ?? false) && !empty($aContentInfo[$sK])) || (($sK = $CNF['FIELD_PICTURE'] ?? false) && !empty($aContentInfo[$sK]))) {
+            $iImageId = (int)$aContentInfo[$sK];
+            $sImageSm = $this->_oConfig->getImageUrl($iImageId, ['OBJECT_IMAGES_TRANSCODER_MINIATURE', 'OBJECT_IMAGES_TRANSCODER_THUMB']);
+            $sImageMd = $this->_oConfig->getImageUrl($iImageId, ['OBJECT_IMAGES_TRANSCODER_GALLERY', 'OBJECT_IMAGES_TRANSCODER_THUMB']);
+            $sImageXl = $this->_oConfig->getImageUrl($iImageId, ['OBJECT_IMAGES_TRANSCODER_COVER']);
+        }
+
+        if(empty($sImageMd))
+            return [];
+
+        if($sImageSm == '')
+            $sImageSm = $sImageMd;
+
+        if($sImageXl == '')
+            $sImageXl = $sImageMd;
+
+        return [[
+            'id' => $iImageId, 
+            'url' => $sUrl, 
+            'src' => $sImageMd, 
+            'src_small' => $sImageSm, 
+            'src_medium' => $sImageMd, 
+            'src_orig' => $sImageXl
+        ]];
+    }
+
+    protected function _getImagesForTimelinePostAttach($aEvent, $aContentInfo, $sUrl, $aBrowseParams = array())
+    {
+        return array();
+    }
+
+    protected function _getVideosForTimelinePost($aEvent, $aContentInfo, $sUrl, $aBrowseParams = array())
+    {
+        return array();
+    }
+
+    protected function _getVideosForTimelinePostAttach($aEvent, $aContentInfo, $sUrl, $aBrowseParams = array())
+    {
+        return array();
+    }
+
+    protected function _getFilesForTimelinePost($aEvent, $aContentInfo, $sUrl, $aBrowseParams = array())
+    {
+        return array();
+    }
+
+    protected function _getFilesForTimelinePostAttach($aEvent, $aContentInfo, $sUrl, $aBrowseParams = array())
+    {
+        return array();
+    }
+
+    protected function _entityComments ($sObject, $iId = 0)
+    {
+        if (!$iId)
+            $iId = bx_process_input(bx_get('id'), BX_DATA_INT);
+
+        if (!$iId)
+            return false;
+
+        $oCmts = BxDolCmts::getObjectInstance($sObject, $iId);
+        if (!$oCmts || !$oCmts->isEnabled())
+            return false;
+        
+        if($this->_bIsApi)
+            return [
+                'title' => $oCmts->getCommentsBlockTitle(),
+                'content' => [bx_srv('system', 'get_data_api', [['module' => $sObject, 'object_id' => $iId]], 'TemplCmtsServices')]
+            ];
+
+        return $oCmts->getCommentsBlock([], ['in_designbox' => false, 'show_empty' => false]);
+    }
+
+    protected function _getFields($iContentId)
+    {
+        $aContentInfo = $this->_oDb->getContentInfoById($iContentId);
+        if(empty($aContentInfo))
+            return array();
+
+        return BxDolContentInfo::formatFields($aContentInfo);
+    }
+
+    protected function _getFieldValue($sField, $iContentId)
+    {
+        $CNF = &$this->_oConfig->CNF;
+        if(empty($CNF[$sField]))
+            return false;
+
+        $aContentInfo = $this->_oDb->getContentInfoById($iContentId);
+        if(empty($aContentInfo) || empty($aContentInfo[$CNF[$sField]]))
+            return false;
+
+        return $aContentInfo[$CNF[$sField]];
+    }
+
+    protected function _getFieldValueThumb($sField, $iContentId, $sTranscoder = '') 
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        if(empty($sTranscoder) || empty($CNF[$sField]))
+            return false;
+
+        $aContentInfo = $this->_oDb->getContentInfoById($iContentId);
+        if(empty($aContentInfo) || empty($aContentInfo[$CNF[$sField]]))
+            return false;
+
+        $oImagesTranscoder = BxDolTranscoderImage::getObjectInstance($sTranscoder);
+        if(!$oImagesTranscoder)
+            return false;
+
+        return $oImagesTranscoder->getFileUrl($aContentInfo[$CNF[$sField]]);
+    }
+
+	protected function _prepareResponse($aResponse, $bAsJson = false, $aAdditional = array())
+    {
+    	if(!$bAsJson)
+    		return $aResponse;
+
+		if(!empty($aAdditional) && is_array($aAdditional))
+			$aResponse = array_merge($aResponse, $aAdditional);
+
+		echoJson($aResponse);
+		exit;
+    }  
+    
+    /**
+     * Blocks for lables tree browsing private functions
+     */
+    
+    private function _getLablesBreadcrumbsArray($iLabelId, &$aBreadcrumbs)
+	{
+		$oLabel = BxDolLabel::getInstance();
+		$aLabel = $oLabel->getLabels(array('type' => 'id', 'id' => $iLabelId));
+		if ($aLabel){
+            $aBreadcrumbs[$aLabel['id']] = array('id' => $aLabel['id'], 'value' => $aLabel['value']);
+			$this->_getLablesBreadcrumbsArray($aLabel['parent'], $aBreadcrumbs);
+		}
+	}
+    
+    private function _getLablesBrowseUrl($iLabelId)
+	{
+        list($sPageLink, $aPageParams) = bx_get_base_url_inline();
+		return BxDolPermalinks::getInstance()->permalink(bx_append_url_params($sPageLink, array_merge($aPageParams, array('label' => $iLabelId))));
+	}
+    
+    private function _getLablesTreeLevel($aBreadcrumbs, $iParent = 0)
+	{
+		$oLabel = BxDolLabel::getInstance();
+		$aLabelsOutput = array();
+        $aLabels = $oLabel->getLabels(array('type' => 'parent', 'parent' => $iParent));
+        if (count($aLabels) > 0){
+			foreach($aLabels as $aLabel) {
+				$sChild = $this->_getLablesTreeLevel($aBreadcrumbs, $aLabel['id']);
+				$bChildPresent = $sChild != '' ? true : false;
+				$bIsOpen = array_key_exists($aLabel['id'], $aBreadcrumbs) ? true : false;
+				if (!$bIsOpen){
+					$sChild = '';
+				}
+				$aLabelsOutput[] = array(
+					'value' => $aLabel['value'], 
+					'url' => $this->_getLablesBrowseUrl($aLabel['id']),
+					'child' => $sChild,
+					
+					'selected' => bx_process_input(bx_get('label'), BX_DATA_INT) == $aLabel['id'] ? 'selected' : ''.$aLabel['id'], 
+					'bx_if:open' => array(
+						'condition' => $bChildPresent && $bIsOpen,
+						'content' => array()
+					),
+					'bx_if:can_open' => array(
+						'condition' => $bChildPresent && !$bIsOpen,
+						'content' => array()
+					)
+				);
+			}
+			return $this->_oTemplate->parseHtmlByName('labels_tree.html', 
+				array(
+					'bx_repeat:items' => $aLabelsOutput,
+					'parent' => $iParent,
+				)
+			);
+		}
+		return '';
+	}
+}
+
+/** @} */

+ 342 - 0
upgrade/files/15.0.0.B3-15.0.0.RC1/files/modules/base/general/classes/BxBaseModGeneralSearchResult.php

@@ -0,0 +1,342 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    BaseGeneral Base classes for modules
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+define('BX_SYS_PER_PAGE_BROWSE_SHOWCASE', 32);
+
+class BxBaseModGeneralSearchResult extends BxTemplSearchResult
+{
+    protected $oModule;
+    protected $sFilterName;
+    protected $bShowcaseView = false;
+    protected $aUnitViews = array();
+    protected $sUnitViewDefault = 'gallery';
+
+    function __construct($sMode = '', $aParams = array())
+    {
+        $this->_sMode = $sMode;
+        $this->_aParams = $aParams;
+
+        parent::__construct();
+    }
+
+    function getMain()
+    {
+        if(!$this->oModule)
+            $this->oModule = BxDolModule::getInstance($this->getModuleName());
+
+        return $this->oModule;
+    }
+
+    function getContentInfoObject()
+    {
+        return BxDolContentInfo::getObjectInstance($this->getContentInfoName());
+    }
+    
+    function getFieldsOwn()
+    {
+        $mixedFields = getParam($this->getModuleName() . '_browse_fields_own');
+        if(empty($mixedFields))
+            return false;
+
+        if(($aFields = json_decode($mixedFields, true)) !== null)
+            return $aFields;
+
+        $sDelimiter = ',';
+        if(strpos($mixedFields, $sDelimiter) !== false)
+            return explode($sDelimiter, $mixedFields);
+
+        return false;
+    }
+
+    function getFieldsJoin($sJoin)
+    {
+        $mixedFields = getParam($this->getModuleName() . '_browse_fields_join');
+        if(empty($mixedFields))
+            return false;
+
+        return ($aJoins = json_decode($mixedFields, true)) !== null && !empty($aJoins[$sJoin]) ? $aJoins[$sJoin] : false;
+    }
+
+    function getRssUnitLink (&$a)
+    {
+        $CNF = &$this->oModule->_oConfig->CNF;
+
+        return bx_absolute_url(BxDolPermalinks::getInstance()->permalink('page.php?i=' . $CNF['URI_VIEW_ENTRY'] . '&id=' . $a[$CNF['FIELD_ID']]));
+    }
+
+    function getRssPageUrl ()
+    {
+        if (false === parent::getRssPageUrl())
+            return false;
+
+        $oPermalinks = BxDolPermalinks::getInstance();
+        return bx_absolute_url($oPermalinks->permalink($this->aCurrent['rss']['link']));
+    }
+
+    function rss ()
+    {
+        if (!isset($this->aCurrent['rss']))
+            return '';
+
+        $this->aCurrent['paginate']['perPage'] = empty($this->oModule->_oConfig->CNF['PARAM_NUM_RSS']) ? 10 : getParam($this->oModule->_oConfig->CNF['PARAM_NUM_RSS']);
+
+        return parent::rss();
+    }
+
+    function processingAPI ($bForceGetData = false) 
+    {
+        $aResult = parent::processingAPI($bForceGetData);
+
+        if(isset($this->_aParams['filters']) && is_array($this->_aParams['filters'])) {
+            $oModule = $this->getMain();
+
+            if(!empty($this->_aParams['filters']['values']) && is_array($this->_aParams['filters']['values']))
+                $aResult['params']['filters'] = $this->_aParams['filters']['values'];
+
+            $aResult['filters'] = $oModule->_oTemplate->getBrowsingFilters(array_merge(['mode' => $this->_sMode], $this->_aParams));
+        }
+
+        return $aResult;
+    }
+
+    protected function addCustomConditions($CNF, $oProfile, $sMode, $aParams)
+    {
+        $this->addConditionsForAuthorStatus($CNF);
+
+        $this->addConditionsForCf($CNF);
+
+        if(!empty($aParams['filter']) && is_array($aParams['filter']))
+            $this->addConditionsForFilter($CNF, $sMode, $aParams);
+    }
+
+    protected function addConditionsForAuthorStatus($CNF)
+    {
+        if (empty($CNF['FIELD_AUTHOR']))
+            return;
+
+        $this->aCurrent['restriction']['statusAuthor'] = [
+            'value' => 'active',
+            'field' => 'status',
+            'operator' => '=',
+            'table' => 'sys_profiles',
+        ];
+
+        $this->aCurrent['join']['statusAuthor'] = [
+            'type' => 'INNER',
+            'table' => 'sys_profiles',
+            'mainField' => $CNF['FIELD_AUTHOR'],
+            'mainFieldFunc' => 'ABS',
+            'onField' => 'id',
+            'joinFields' => array(),
+        ];
+    }
+
+    protected function addConditionsForCf($CNF)
+    {
+        if(empty($CNF['FIELD_CF']))
+            return;
+
+        $oCf = BxDolContentFilter::getInstance();
+        if(!$oCf->isEnabled()) 
+            return;
+
+        $aConditions = $oCf->getConditions($this->aCurrent['table'], $CNF['FIELD_CF']);
+        if(!empty($aConditions) && is_array($aConditions))
+            $this->aCurrent['restriction'] = array_merge($this->aCurrent['restriction'], $aConditions);
+    }
+    
+    protected function addConditionsForFilter($CNF, $sMode, $aParams)
+    {
+        $aFilter = $aParams['filter'];
+        
+        if(empty($aFilter['field']) || empty($aFilter['value']))
+            return;
+        
+        $aRestriction = [
+            'value' => $aFilter['value'],
+            'field' => $aFilter['field'],
+            'operator' => '=',
+        ];
+
+        if(isset($aFilter['operator']))
+            $aRestriction['operator'] = $aFilter['operator'];
+
+        if(isset($aFilter['table']))
+            switch($aFilter['table']) {
+                case 'table':
+                    $aRestriction['table'] = $this->aCurrent['table'];
+                    break;
+
+                case 'tableSearch':
+                    $aRestriction['table'] = $this->aCurrent['tableSearch'];
+                    break;
+
+                default: 
+                    $aRestriction['table'] = $aFilter['table'];
+            }
+
+        $this->aCurrent['restriction']['filter'] = $aRestriction;
+    }
+
+    /**
+     * Add conditions for private content
+     */
+    protected function addConditionsForPrivateContent($CNF, $oProfile, $aCustomGroup = array()) 
+    {
+        // default is bProcessPrivateContent = 1, 
+        // so private items are shown as empty boxes with "Private" title
+
+        // we can show public content when privacy object is available
+        
+        if(empty($CNF['OBJECT_PRIVACY_VIEW']))
+            return;
+
+        $oPrivacy = BxDolPrivacy::getObjectInstance($CNF['OBJECT_PRIVACY_VIEW']);
+        if(!$oPrivacy)
+            return;
+
+        // for posts in some context we need to show all items, not only public content
+        if (!empty($this->aCurrent['restriction']['context']['value']) || !empty($this->aCurrent['restriction']['author']['value'])) {
+            $this->setProcessPrivateContent(true);
+            return;
+        }
+
+        // build condition to show only public content
+        $aCondition = $oPrivacy->getContentPublicAsCondition($oProfile ? $oProfile->id() : 0, $aCustomGroup);
+        if(empty($aCondition) || !is_array($aCondition))
+            return;
+
+        if(isset($aCondition['restriction'])) {
+            $this->aCurrent['restriction'] = array_merge($this->aCurrent['restriction'], $aCondition['restriction']);
+            $this->aPrivateConditionsIndexes['restriction'] = array_keys($aCondition['restriction']);
+        }
+        if(isset($aCondition['join'])) {
+            $this->aCurrent['join'] = array_merge($this->aCurrent['join'], $aCondition['join']);
+            $this->aPrivateConditionsIndexes['join'] = array_keys($aCondition['join']);
+        }
+
+        $this->setProcessPrivateContent(false);
+    }
+
+    function showPagination($bAdmin = false, $bChangePage = true, $bPageReload = true)
+    {
+        if($this->bShowcaseView)
+            return '';
+
+        $sPagination = parent::showPagination ($bAdmin, $bChangePage, $bPageReload);
+        if(empty($sPagination))
+            return '';
+
+        return $sPagination;
+    }
+
+    protected function getItemPerPageInShowCase ()
+    {
+        $iPerPageInShowCase = (int)getParam('sys_per_page_browse_showcase');
+
+        $CNF = &$this->oModule->_oConfig->CNF;
+        if(isset($CNF['PARAM_PER_PAGE_BROWSE_SHOWCASE']))
+            $iPerPageInShowCase = (int)getParam($CNF['PARAM_PER_PAGE_BROWSE_SHOWCASE']);
+
+        if(!$iPerPageInShowCase)
+            $iPerPageInShowCase = BX_SYS_PER_PAGE_BROWSE_SHOWCASE;
+
+        return $iPerPageInShowCase;
+    }
+
+    function displayResultBlock()
+    {
+        if ($this->bShowcaseView) {
+            $this->addContainerClass(array('bx-base-unit-showcase-wrapper'));
+            $this->aCurrent['paginate']['perPage'] = $this->getItemPerPageInShowCase();
+            $this->oModule->_oTemplate->addCss(array(BX_DIRECTORY_PATH_PLUGINS_PUBLIC . 'flickity/|flickity.css'));
+            $this->oModule->_oTemplate->addJs(array('flickity/flickity.pkgd.min.js','modules/base/general/js/|showcase.js'));
+        }
+
+        return parent::displayResultBlock();
+    }
+
+    function displaySearchBox ($sContent, $sPaginate = '')
+    {
+        $aResult = parent::displaySearchBox($sContent, $sPaginate);
+
+        if(isset($this->_aParams['filters']) && is_array($this->_aParams['filters']))
+            $aResult['buttons'] = [
+                ['title' => _t('_Filters'), 'href' => 'javascript:void(0)', 'onclick' => 'javascript:' . $this->_aParams['filters']['onclick']]
+            ];
+
+        return $aResult;
+    }
+
+    function applyContainerId()
+    {
+        if(empty($this->aCurrent['name']) || empty($this->_sMode))
+            return parent::applyContainerId();
+
+        return str_replace('_', '-', $this->aCurrent['name'] . '-search-result-block-' . $this->_sMode);
+    }
+
+    function decodeDataAPI($a, $sMethod = 'getDataAPI')
+    {
+        if(!is_array($a))
+            return $a;
+
+        $bExtendedUnits = getParam('sys_api_extended_units') == 'on';
+
+        foreach($a as $i => $r)
+            $a[$i] = $this->oModule->$sMethod($r, ['extended' => $bExtendedUnits]);
+
+        return $a;
+    }
+
+    protected function _updateCurrentForFollowedContexts($sMode, $aParams, &$oProfileContext)
+    {
+        $CNF = &$this->oModule->_oConfig->CNF;
+
+        if(empty($aParams['followed_contexts']))
+            return false;
+
+        $iProfileId = (int)$aParams['followed_contexts'];
+        $aContextTypes = array_keys(bx_srv('system', 'get_modules_by_type', ['context', ['name_as_key' => true]]));
+        $aContextIds = BxDolConnection::getObjectInstance('sys_profiles_subscriptions')->getConnectedContentByType($iProfileId, $aContextTypes);
+
+        $this->aCurrent['restriction']['context'] = [
+            'value' => array_map(function($iValue) {
+                return -$iValue;
+            }, $aContextIds),
+            'field' => $CNF['FIELD_ALLOW_VIEW_TO'],
+            'operator' => 'in',
+        ];
+
+        if(!empty($aParams['per_page']))
+            $this->aCurrent['paginate']['perPage'] = is_numeric($aParams['per_page']) ? (int)$aParams['per_page'] : (int)getParam($aParams['per_page']);
+
+        $this->sBrowseUrl = '';
+        $this->aCurrent['title'] = '';
+        unset($this->aCurrent['rss']);
+
+        return true;
+    }
+
+    function _getPseudFromParam ()
+    {
+        $mixedPseud = getParam($this->getModuleName() . '_browse_pseud');
+        if(empty($mixedPseud))
+            return false;
+
+        if(($aPseud = json_decode($mixedPseud, true)) !== null)
+            return $aPseud;
+
+        return false;
+    }
+}
+
+/** @} */

+ 2860 - 0
upgrade/files/15.0.0.B3-15.0.0.RC1/files/modules/base/groups/classes/BxBaseModGroupsModule.php

@@ -0,0 +1,2860 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    BaseGroups Base classes for groups modules
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+define('BX_BASE_MOD_GROUPS_MMODE_MULTI_ROLES', 'multi_roles');
+
+define('BX_BASE_MOD_GROUPS_ROLE_COMMON', 0);
+define('BX_BASE_MOD_GROUPS_ROLE_ADMINISTRATOR', 1);
+define('BX_BASE_MOD_GROUPS_ROLE_MODERATOR', 2);
+
+define('BX_BASE_MOD_GROUPS_ACTION_EDIT', 'edit');
+define('BX_BASE_MOD_GROUPS_ACTION_CHANGE_SETTINGS', 'change_settings');
+define('BX_BASE_MOD_GROUPS_ACTION_CHANGE_COVER', 'change_cover');
+define('BX_BASE_MOD_GROUPS_ACTION_INVITE', 'invite');
+define('BX_BASE_MOD_GROUPS_ACTION_MANAGE_FANS', 'manage_fans');
+define('BX_BASE_MOD_GROUPS_ACTION_MANAGE_ROLES', 'manage_roles');
+define('BX_BASE_MOD_GROUPS_ACTION_DELETE', 'delete');
+define('BX_BASE_MOD_GROUPS_ACTION_EDIT_CONTENT', 'edit_any');
+define('BX_BASE_MOD_GROUPS_ACTION_DELETE_CONTENT', 'delete_any');
+define('BX_BASE_MOD_GROUPS_ACTION_TIMELINE_POST_PIN', 'pin'); //for timeline posts only
+
+define('BX_BASE_MOD_GROUPS_PERIOD_UNIT_DAY', 'day');
+define('BX_BASE_MOD_GROUPS_PERIOD_UNIT_WEEK', 'week');
+define('BX_BASE_MOD_GROUPS_PERIOD_UNIT_MONTH', 'month');
+define('BX_BASE_MOD_GROUPS_PERIOD_UNIT_YEAR', 'year');
+
+/**
+ * Groups profiles module.
+ */
+class BxBaseModGroupsModule extends BxBaseModProfileModule
+{
+    function __construct(&$aModule)
+    {
+        parent::__construct($aModule);
+
+        $CNF = &$this->_oConfig->CNF;
+
+        if(isset($CNF['FIELD_PUBLISHED']))
+            $this->_aSearchableNamesExcept = array_merge($this->_aSearchableNamesExcept, array(
+                $CNF['FIELD_PUBLISHED'],
+            ));
+    }
+
+    /**
+     * Get possible recipients for start conversation form
+     */
+    public function actionAjaxGetInitialMembers ()
+    {
+        $sTerm = bx_get('term');
+
+        $a = BxDolService::call('system', 'profiles_search', [$sTerm, ['module' => $this->_oConfig->getName()]], 'TemplServiceProfiles');
+
+        header('Content-Type:text/javascript; charset=utf-8');
+        echo(json_encode($a));
+    }
+    
+    public function serviceGetInitialMembers ($sParams)
+    {
+        $aOptions = json_decode($sParams, true);
+        if (!$sParams || !isset($aOptions['term']))
+            return [];
+        
+        $a = BxDolService::call('system', 'profiles_search', [$aOptions['term'], ['module' => $this->_oConfig->getName()]], 'TemplServiceProfiles');
+
+        return $a;
+    }
+    
+    /**
+     * Process Process Invitation
+     */
+    public function actionProcessInvite ($sKey, $iGroupProfileId, $bAccept)
+    {
+        return $this->serviceProcessInvite($sKey, $iGroupProfileId, $bAccept);
+    }
+
+    public function serviceProcessInvite ($sKey, $iGroupProfileId, $bAccept)
+    {
+        $aData = $this->_oDb->getInviteByKey($sKey, $iGroupProfileId);
+        if (isset($aData['invited_profile_id'])){
+            $CNF = &$this->_oConfig->CNF;
+            if (!isset($CNF['OBJECT_CONNECTIONS']) || !($oConnection = BxDolConnection::getObjectInstance($CNF['OBJECT_CONNECTIONS'])))
+                return '';
+            $iInvitedProfileId = $aData['invited_profile_id'];
+            if ($iInvitedProfileId != bx_get_logged_profile_id())
+                return '';
+            if ($bAccept){
+                if($oConnection && !$oConnection->isConnected($iInvitedProfileId, $iGroupProfileId)){
+                    $oConnection->addConnection($iInvitedProfileId, $iGroupProfileId);
+                    $oConnection->addConnection($iGroupProfileId, $iInvitedProfileId);
+                }
+            }
+            $this->_oDb->deleteInviteByKey($sKey, $iGroupProfileId);
+        }   
+    }
+
+    public function actionCheckName()
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+    	$sName = bx_process_input(bx_get('name'));
+    	if(empty($sName))
+            return echoJson(array());
+
+        $sResult = '';
+
+        $iId = (int)bx_get('id');
+        if(!empty($iId)) {
+            $aPrice = $this->_oDb->getPrices(array('type' => 'by_id', 'value' => $iId)); 
+            if(strcmp($sName, $aPrice[$CNF['FIELD_PRICE_NAME']]) == 0) 
+                $sResult = $sName;
+        }
+
+    	echoJson(array(
+            'name' => !empty($sResult) ? $sResult : $this->_oConfig->getPriceName($sName)
+    	));
+    }
+
+    public function actionGetQuestionnaire()
+    {
+        $sSource = '';
+        if(($sSource = bx_get('s')) !== false)
+            $sSource = bx_process_url_param($sSource);
+
+        $sObject = '';
+        if(($sObject = bx_get('o')) !== false)
+            $sObject = bx_process_url_param($sObject);
+        
+        $sAction = '';
+        if(($sAction = bx_get('a')) !== false)
+            $sAction = bx_process_url_param($sAction);
+
+        $iContentProfileId = 0;
+        if(($iContentProfileId = bx_get('cpi')) !== false)
+            $iContentProfileId = (int)$iContentProfileId;
+
+        echoJson($this->serviceGetQuestionnaire($sSource, $sObject, $sAction, $iContentProfileId));
+    }
+
+    public function serviceManageTools($sType = 'common')
+    {
+        $this->_oTemplate->addJs(['modules/base/groups/js/|manage_tools.js']);
+
+        return parent::serviceManageTools($sType);
+    }
+    
+    public function decodeDataAPI($aData, $aParams = [])
+    {
+        $CNF = $this->_oConfig->CNF;
+        
+        $aResult = parent::decodeDataAPI($aData, $aParams);
+
+        if(isset($aParams['template']) && $aParams['template'] == 'unit_wo_info')
+            return $aResult;
+
+        if(getParam('sys_api_conn_in_prof_units') == 'on' && ($oConnection = BxDolConnection::getObjectInstance($CNF['OBJECT_CONNECTIONS'])) !== false) {
+            $oProfile = BxDolProfile::getInstanceByContentAndType($aData[$CNF['FIELD_ID']], $this->_aModule['name']);
+
+            $aResult['members_count'] = $oConnection->getConnectedInitiatorsCount($oProfile->id(), false);
+            $aResult['members_list'] = $oConnection->getConnectedListAPI($oProfile->id(), false, BX_CONNECTIONS_CONTENT_TYPE_INITIATORS);
+        }
+
+        return array_merge($aResult, [
+            'author_data' => BxDolProfile::getData($aData[$CNF['FIELD_AUTHOR']]),
+            'visibility' => $aData[$CNF['FIELD_ALLOW_VIEW_TO']]
+        ]);
+    }
+
+    public function serviceGetMenuAddonManageTools()
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $aResult = parent::serviceGetMenuAddonManageTools();
+
+        if(!empty($CNF['FIELD_STATUS_ADMIN']))
+            $aResult['counter1_value'] = $this->_oDb->getEntriesNumByParams([[
+                'key' => $CNF['FIELD_STATUS_ADMIN'],
+                'value' => BX_BASE_MOD_GENERAL_STATUS_PENDING, 
+                'operator' => '='
+            ]]);
+
+        return $aResult;
+    }
+
+    public function serviceGetOptionsMembersMode()
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        return array(
+            array('key' => '', 'value' => _t('_None')),
+            array('key' => BX_BASE_MOD_GROUPS_MMODE_MULTI_ROLES, 'value' => _t($CNF['T']['option_members_mode_' . BX_BASE_MOD_GROUPS_MMODE_MULTI_ROLES])),
+        );
+    }
+
+    public function serviceGetSearchResultUnit ($iContentId, $sUnitTemplate = '')
+    {
+        if(empty($sUnitTemplate))
+            $sUnitTemplate = 'unit.html';
+
+        return parent::serviceGetSearchResultUnit($iContentId, $sUnitTemplate);
+    }
+
+    /**
+     * @see BxBaseModProfileModule::serviceGetSpaceTitle
+     */ 
+    public function serviceGetSpaceTitle()
+    {
+        return _t($this->_oConfig->CNF['T']['txt_sample_single']);
+    }
+
+    public function serviceGetFansConnectionObject()
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        return ($sKey = 'OBJECT_CONNECTIONS') && !empty($CNF[$sKey]) && ($oConnection = BxDolConnection::getObjectInstance($CNF[$sKey])) !== false ? $oConnection : false;
+    }
+
+    /**
+     * @see iBxDolProfileService::serviceGetParticipatingProfiles
+     */ 
+    public function serviceGetParticipatingProfiles($iProfileId, $aConnectionObjects = false)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $mixedCo = $aConnectionObjects;
+        $bCoEmpty = $mixedCo === false;
+        $bCoString = !$bCoEmpty && is_string($mixedCo);
+
+        $aConnectionObjects = [];
+        if($bCoEmpty || ($bCoString && $mixedCo == 'subscriptions'))
+            $aConnectionObjects[] = 'sys_profiles_subscriptions';
+        
+        if(($bCoEmpty || ($bCoString && $mixedCo == 'fans')) && !empty($CNF['OBJECT_CONNECTIONS']))
+            $aConnectionObjects[] = $CNF['OBJECT_CONNECTIONS'];
+
+        return parent::serviceGetParticipatingProfiles($iProfileId, $aConnectionObjects);
+    }
+
+    public function serviceGetSafeServices()
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $a = [
+            'ProcessInvite' => '',
+            'GetQuestionnaire' => '',
+            'GetInitialMembers' => '',
+            'EntityInvite' => '',
+            'Invitations' => '',
+            'FansWithoutAdmins' => '',
+        ];
+
+        if(!empty($CNF['OBJECT_RECOMMENDATIONS_FANS']))
+            $a['BrowseRecommendationsFans'] = '';
+
+        return array_merge(parent::serviceGetSafeServices(), $a);
+    }
+
+    /**
+     * Check if this module entry can be used as profile
+     */
+    public function serviceActAsProfile ()
+    {
+        return false;
+    }
+
+    /**
+     * Check if this module is group profile
+     */
+    public function serviceIsGroupProfile ()
+    {
+        return true;
+    }
+
+    public function serviceIsEnableForContext($iProfileId = 0)
+    {
+        $CNF = &$this->_oConfig->CNF;
+        $bRet = true;
+
+        $sCnfKey = 'ENABLE_FOR_CONTEXT_IN_MODULES';
+        if(empty($iProfileId) || empty($CNF[$sCnfKey]) || !is_array($CNF[$sCnfKey]))
+            $bRet = false;
+
+        $oProfile = null;
+        if($bRet && !($oProfile = BxDolProfile::getInstance($iProfileId)))
+            $bRet = false;
+
+        if($bRet && !in_array($oProfile->getModule(), $CNF[$sCnfKey]))
+            $bRet = false;
+
+        bx_alert($this->getName(), 'is_enabled_for_context', $iProfileId, false, [
+            'cnf' => $CNF,
+            'module' => $this,
+            'context_profile' => $oProfile,
+            'result' => &$bRet
+        ]);
+
+        return $bRet;
+    }
+
+    /**
+     * check if provided profile is member of the group 
+     */ 
+    public function serviceIsFan ($iGroupProfileId, $iProfileId = false) 
+    {
+        $oGroupProfile = BxDolProfile::getInstance($iGroupProfileId);
+        return $oGroupProfile !== false && $this->isFan($oGroupProfile->getContentId(), $iProfileId);
+    }
+
+    /**
+     * check if provided profile is admin of the group 
+     */ 
+    public function serviceIsAdmin ($iGroupProfileId, $iProfileId = false) 
+    {
+        if(!$iProfileId)
+            $iProfileId = bx_get_logged_profile_id();
+
+        $oGroupProfile = BxDolProfile::getInstance($iGroupProfileId);
+        if(!$oGroupProfile)
+            return false;
+
+        $iGroupContentId = $oGroupProfile->getContentId();
+        if(!$this->isFan($iGroupContentId, $iProfileId))
+            return false;
+
+        $aGroupContentInfo = $this->_oDb->getContentInfoById($iGroupContentId);
+        return $this->_oDb->isAdmin($iGroupProfileId, $iProfileId, $aGroupContentInfo);
+    }
+
+    public function serviceGetAdminRole($iGroupProfileId, $iProfileId = false)
+    {
+        if(!$iProfileId)
+            $iProfileId = bx_get_logged_profile_id();
+
+        if(!$this->serviceIsAdmin($iGroupProfileId, $iProfileId))
+            return 0;
+
+        return $this->_oDb->getRole($iGroupProfileId, $iProfileId);
+    }
+
+    /*
+     * Get context (group) advanced members who can perform the specified action.
+     * If 'Roles' are disabled for the context then all context admins are returned.
+     */
+    public function serviceGetAdminsByAction($iGroupProfileId, $mixedAction)
+    {
+        if(!$this->_oConfig->isAdmins())
+            return [];
+
+        $aGroupContentInfo = $this->_oDb->getContentInfoByProfileId($iGroupProfileId);
+        if(empty($aGroupContentInfo) || !is_array($aGroupContentInfo))
+            return [];
+
+        $aAdmins = $this->_oDb->getAdmins($iGroupProfileId);
+        if(!$this->_oConfig->isRoles())
+            return $aAdmins;
+
+        if(!is_array($mixedAction))
+            $mixedAction = [$mixedAction];
+
+        $aResult = [];
+        foreach($mixedAction as $sAction)
+            foreach($aAdmins as $iAdminProfileId)
+                if(!in_array($iAdminProfileId, $aResult) && $this->isAllowedActionByRole($sAction, $aGroupContentInfo, $iGroupProfileId, $iAdminProfileId))
+                    $aResult[] = $iAdminProfileId;
+
+        return $aResult;
+    }
+
+    public function serviceGetAdminsToManageContent($iGroupProfileId)
+    {
+        return $this->serviceGetAdminsByAction($iGroupProfileId, [
+            BX_BASE_MOD_GROUPS_ACTION_EDIT_CONTENT, 
+            BX_BASE_MOD_GROUPS_ACTION_DELETE_CONTENT
+        ]);
+    }
+
+    /**
+     * Delete profile from fans and admins tables
+     * @param $iProfileId profile id 
+     */
+    public function serviceDeleteProfileFromFansAndAdmins ($iProfileId)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $this->_oDb->deleteAdminsByProfileId($iProfileId);
+
+        if (isset($CNF['OBJECT_CONNECTIONS']) && ($oConnection = BxDolConnection::getObjectInstance($CNF['OBJECT_CONNECTIONS'])))
+            $oConnection->onDeleteInitiatorAndContent($iProfileId);
+    }
+
+    /**
+     * Reset group's author for particular group
+     * @param $iContentId group id 
+     * @parem $iAuthorId new author profile ID
+     * @return false of error, or number of updated records on success
+     */
+    public function serviceReassignEntityAuthor ($iContentId, $iAuthorId = 0)
+    {
+        $aContentInfo = $this->_oDb->getContentInfoById((int)$iContentId);
+        if (!$aContentInfo)
+            return false;
+
+        if (empty($iAuthorId)) {
+            $oGroupProfile = BxDolProfile::getInstanceByContentAndType($iContentId, $this->getName());
+            if (!$oGroupProfile)
+                return false;
+
+            $aAdmins = $this->_oDb->getAdmins($oGroupProfile->id());
+            if($aAdmins)
+                $iAuthorId = array_pop($aAdmins);
+        }
+
+        return $this->_oDb->updateAuthorById($iContentId, $iAuthorId);
+    }
+
+    /**
+     * Entry actions and social sharing block
+     */
+    public function serviceEntityAllActions ($mixedContent = false, $aParams = array())
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        if(!empty($mixedContent)) {
+            if(!is_array($mixedContent))
+                $mixedContent = array((int)$mixedContent, (method_exists($this->_oDb, 'getContentInfoById')) ? $this->_oDb->getContentInfoById((int)$mixedContent) : array());
+        }
+        else {
+            $mixedContent = $this->_getContent();
+            if($mixedContent === false)
+                return false;
+        }
+
+        list($iContentId, $aContentInfo) = $mixedContent;
+
+        if(!empty($CNF['FIELD_PICTURE']) && !empty($aContentInfo[$CNF['FIELD_PICTURE']]))
+            $aParams = array_merge(array(
+                'entry_thumb' => (int)$aContentInfo[$CNF['FIELD_PICTURE']]
+            ), $aParams); 
+
+        return parent::serviceEntityAllActions ($mixedContent, $aParams);
+    }
+    
+    /**
+     * Reset group's author when author profile is deleted
+     * @param $iProfileId author profile id 
+     * @param $iAuthorId new author profile id 
+     * @return number of changed items
+     */
+    public function serviceReassignEntitiesByAuthor ($iProfileId, $iAuthorId = 0)
+    {
+        $a = $this->_oDb->getEntriesByAuthor((int)$iProfileId);
+        if (!$a)
+            return 0;
+
+        $iCount = 0;
+        foreach ($a as $aContentInfo)
+            $iCount += ('' == $this->serviceReassignEntityAuthor($aContentInfo[$this->_oConfig->CNF['FIELD_ID']], $iAuthorId) ? 1 : 0);
+
+        return $iCount;
+    }
+
+    public function servicePrepareFields ($aFieldsProfile)
+    {
+        $CNF = &$this->_oConfig->CNF;
+        
+        $aFieldsProfile[$CNF['FIELD_NAME']] = $aFieldsProfile['name'];
+        $aFieldsProfile[$CNF['FIELD_TEXT']] = isset($aFieldsProfile['description']) ? $aFieldsProfile['description'] : '';
+        unset($aFieldsProfile['name']);
+        unset($aFieldsProfile['description']);
+        return $aFieldsProfile;
+    }
+
+    public function serviceOnRemoveConnection ($iGroupProfileId, $iInitiatorId)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        list ($iProfileId, $iGroupProfileId, $oGroupProfile) = $this->_prepareProfileAndGroupProfile($iGroupProfileId, $iInitiatorId);
+        if (!$oGroupProfile)
+            return false;
+
+        $this->_oDb->fromAdmins($iGroupProfileId, $iProfileId);
+
+        if ($oConn = BxDolConnection::getObjectInstance('sys_profiles_subscriptions'))
+            return $oConn->removeConnection($iProfileId, $iGroupProfileId);
+
+        return false;
+    }
+
+    public function serviceAddInvitation ($iContextPid, $iPid, $iPerformerPid = 0)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $oGroupProfile = false;
+        if(!($oGroupProfile = BxDolProfile::getInstance($iContextPid)))
+            return false;
+
+        if(!($aContentInfo = $this->_oDb->getContentInfoById((int)$oGroupProfile->getContentId())))
+            return false;
+
+        $oConnection = false;
+        if(!isset($CNF['OBJECT_CONNECTIONS']) || !($oConnection = BxDolConnection::getObjectInstance($CNF['OBJECT_CONNECTIONS'])))
+            return false;
+
+        if($oConnection->isConnected((int)$iPid, $iContextPid) || $oConnection->isConnected($iContextPid, (int)$iPid))
+            return false;
+
+        if(!$iPerformerPid)
+            $iPerformerPid = bx_get_logged_profile_id();
+
+        $sEntryUrl = BxDolPermalinks::getInstance()->permalink('page.php?i=' . $CNF['URI_VIEW_ENTRY'] . '&id=' . $aContentInfo[$CNF['FIELD_ID']]);
+        if(!empty($CNF['TABLE_INVITES']) && !$this->_oDb->isInviteByInvited($iPid, $iContextPid)) {
+            $sKey = BxDolKey::getInstance()->getNewKey(false, $CNF['INVITES_KEYS_LIFETIME']);
+
+            $this->_oDb->insertInvite($sKey, $iContextPid, $iPerformerPid, $iPid);
+
+            $sEntryUrl = bx_append_url_params($sEntryUrl, [
+                'key' => $sKey
+            ]);
+        }
+
+        $sModule = $this->getName();
+
+        /**
+         * @hooks
+         * @hookdef hook-bx_base_groups-join_invitation '{module_name}', 'join_invitation' - hook before adding (sending) new join to context invitation
+         * - $unit_name - module name
+         * - $action - equals `join_invitation`
+         * - $object_id - context id
+         * - $sender_id - context profile id
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `content` - [array] context info array as key&value pairs
+         *      - `entry_title` - [string] context title
+         *      - `entry_url` - [string] context URL
+         *      - `group_profile` - [int] context profile id
+         *      - `profile` - [int] profile id who was invited
+         *      - `notification_subobject_id` - [int] profile id who was invited
+         *      - `object_author_id` - [int] context profile id
+         * @hook @ref hook-bx_base_groups-join_invitation
+         */
+        bx_alert($sModule, 'join_invitation', $aContentInfo[$CNF['FIELD_ID']], $iContextPid, [
+            'content' => $aContentInfo, 
+            'entry_title' => $aContentInfo[$CNF['FIELD_NAME']], 
+            'entry_url' => bx_absolute_url($sEntryUrl), 
+            'group_profile' => $iContextPid, 
+            'profile' => $iPid, 
+            'notification_subobject_id' => $iPid, 
+            'object_author_id' => $iContextPid
+        ]);
+
+        /**
+         * 'Invitation Received' alert for Notifications module.
+         * Note. It's essential to use Recipient ($iPid) in 'object_author_id' parameter. 
+         * In this case notification will be received by Recipient profile.
+         */
+        /**
+         * @hooks
+         * @hookdef hook-bx_base_groups-join_invitation_notif '{module_name}', 'join_invitation_notif' - hook before adding new join to context invitation. Is needed for Notifications module.
+         * - $unit_name - module name
+         * - $action - equals `join_invitation_notif`
+         * - $object_id - context id
+         * - $sender_id - context profile id
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `object_author_id` - [int] profile id who was invited
+         *      - `privacy_view` - [int] or [string] privacy for view context action, @see BxDolPrivacy
+         * @hook @ref hook-bx_base_groups-join_invitation_notif
+         */
+        bx_alert($sModule, 'join_invitation_notif', $aContentInfo[$CNF['FIELD_ID']], $iContextPid, [
+            'object_author_id' => $iPid, 
+            'privacy_view' => isset($aContentInfo[$CNF['FIELD_ALLOW_VIEW_TO']]) ? $aContentInfo[$CNF['FIELD_ALLOW_VIEW_TO']] : 3, 
+        ]);
+
+        return true;
+    }
+
+    public function serviceAddMutualConnection ($iGroupProfileId, $iInitiatorId, $bSendInviteOnly = false)
+    {        
+        $CNF = &$this->_oConfig->CNF;
+
+        list($iProfileId, $iGroupProfileId, $oGroupProfile) = $this->_prepareProfileAndGroupProfile($iGroupProfileId, $iInitiatorId);
+        if(!$oGroupProfile)
+            return false;
+
+        if(!($aContentInfo = $this->_oDb->getContentInfoById((int)BxDolProfile::getInstance($iGroupProfileId)->getContentId())))
+            return false;
+
+        $oConnection = false;
+        if(!isset($CNF['OBJECT_CONNECTIONS']) || !($oConnection = BxDolConnection::getObjectInstance($CNF['OBJECT_CONNECTIONS'])))
+            return false;
+
+        $sEntryTitle = $aContentInfo[$CNF['FIELD_NAME']];
+        $sEntryUrl = bx_absolute_url(BxDolPermalinks::getInstance()->permalink('page.php?i=' . $CNF['URI_VIEW_ENTRY'] . '&id=' . $aContentInfo[$CNF['FIELD_ID']]));
+
+        // send invitation to the group 
+        $iPerformerId = bx_get_logged_profile_id();
+        if($bSendInviteOnly)
+            return $iProfileId != $iPerformerId ? $this->serviceAddInvitation($oGroupProfile->id(), $iInitiatorId, $iPerformerId) : false;
+
+        $sModule = $this->getName();
+        $sModuleGroup = $oGroupProfile->getModule();
+
+        // send notification to group's admins that new connection is pending confirmation 
+        if($oConnection->isConnected((int)$iInitiatorId, $oGroupProfile->id()) && !$oConnection->isConnected($oGroupProfile->id(), (int)$iInitiatorId) && $aContentInfo['join_confirmation'] && $aContentInfo[$CNF['FIELD_AUTHOR']] != $iProfileId) {
+            /**
+             * @hooks
+             * @hookdef hook-bx_base_groups-join_request '{module_name}', 'join_request' - hook before adding new join to context request
+             * - $unit_name - module name
+             * - $action - equals `join_request`
+             * - $object_id - context id
+             * - $sender_id - context profile id
+             * - $extra_params - array of additional params with the following array keys:
+             *      - `object_author_id` - [int] context profile id
+             *      - `performer_id` - [int] profile id who wants to join
+             *      - `content` - [array] context info array as key&value pairs
+             *      - `entry_title` - [string] context title
+             *      - `entry_url` - [string] context URL
+             *      - `group_profile` - [int] context profile id
+             *      - `profile` - [int] profile id who wants to join
+             * @hook @ref hook-bx_base_groups-join_request
+             */
+            bx_alert($this->getName(), 'join_request', $aContentInfo[$CNF['FIELD_ID']], $iGroupProfileId, [
+            	'object_author_id' => $iGroupProfileId,
+            	'performer_id' => $iProfileId, 
+
+            	'content' => $aContentInfo, 
+            	'entry_title' => $sEntryTitle, 
+            	'entry_url' => $sEntryUrl, 
+
+            	'group_profile' => $iGroupProfileId, 
+            	'profile' => $iProfileId
+            ]);
+        }
+        // send notification that join request was accepted 
+        else if($oConnection->isConnected((int)$iInitiatorId, $oGroupProfile->id(), true) && $sModuleGroup != $sModule && $iProfileId != $iPerformerId) {
+            /**
+             * @hooks
+             * @hookdef hook-bx_base_groups-join_request_accepted '{module_name}', 'join_request_accepted' - hook before accepting join to context request
+             * It's equivalent to @ref hook-bx_base_groups-join_request
+             * @hook @ref hook-bx_base_groups-join_request_accepted
+             */
+            bx_alert($this->getName(), 'join_request_accepted', $aContentInfo[$CNF['FIELD_ID']], $iGroupProfileId, [
+            	'object_author_id' => $iGroupProfileId,
+            	'performer_id' => $iProfileId,
+
+            	'content' => $aContentInfo, 
+            	'entry_title' => $sEntryTitle, 
+            	'entry_url' => $sEntryUrl, 
+
+            	'group_profile' => $iGroupProfileId, 
+            	'profile' => $iProfileId
+            ]);
+        }
+
+        // new fan was added
+        if($oConnection->isConnected($oGroupProfile->id(), (int)$iInitiatorId, true)) {
+            // follow group on join
+            if(bx_srv($sModuleGroup, 'act_as_profile'))
+                 $this->addFollower($oGroupProfile->id(), (int)$iInitiatorId);
+            else
+                 $this->addFollower((int)$iInitiatorId, $oGroupProfile->id()); 
+
+            if($aContentInfo[$CNF['FIELD_AUTHOR']] != $iProfileId) {
+                /**
+                 * @hooks
+                 * @hookdef hook-bx_base_groups-fan_added '{module_name}', 'fan_added' - hook before adding (registering) new context member
+                 * It's equivalent to @ref hook-bx_base_groups-join_request
+                 * @hook @ref hook-bx_base_groups-fan_added
+                 */
+                bx_alert($this->getName(), 'fan_added', $aContentInfo[$CNF['FIELD_ID']], $iGroupProfileId, [
+                    'object_author_id' => $iGroupProfileId,
+                    'performer_id' => $iProfileId,
+
+                    'content' => $aContentInfo,
+                    'entry_title' => $sEntryTitle, 
+                    'entry_url' => $sEntryUrl,
+
+                    'group_profile' => $iGroupProfileId, 
+                    'profile' => $iProfileId,
+                ]);
+            }
+
+            $this->doAudit($iGroupProfileId, $iInitiatorId, '_sys_audit_action_group_join_request_accepted');
+            
+            return false;
+        }
+
+        // don't automatically add connection (mutual) if group requires manual join confirmation
+        if($aContentInfo['join_confirmation'])
+            return false;
+
+        // check if connection already exists
+        if($oConnection->isConnected($oGroupProfile->id(), (int)$iInitiatorId, true) || $oConnection->isConnected($oGroupProfile->id(), (int)$iInitiatorId))
+            return false;
+
+        if(!$oConnection->addConnection($oGroupProfile->id(), (int)$iInitiatorId))
+            return false;
+
+        return true;
+    }
+
+    public function serviceFansTable ()
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $oGrid = BxDolGrid::getObjectInstance($CNF['OBJECT_GRID_CONNECTIONS']);
+        if(!$oGrid)
+            return false;
+
+        if($this->_bIsApi){
+            return [
+                bx_api_get_block('grid', $oGrid->getCodeAPI())
+            ];
+        }
+
+        return $oGrid->getCode();
+    }
+    
+    public function serviceInvitesTable ()
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        if(!isset($CNF['OBJECT_GRID_INVITES']))
+            return false;
+
+        $oGrid = BxDolGrid::getObjectInstance($CNF['OBJECT_GRID_INVITES']);
+        if(!$oGrid)
+            return false;
+
+        if($this->_bIsApi)
+            return [
+                bx_api_get_block('grid', $oGrid->getCodeAPI())
+            ];
+
+        return $oGrid->getCode();
+    }
+
+    public function serviceBansTable ()
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        if(!isset($CNF['OBJECT_GRID_BANS']))
+            return false;
+
+        $oGrid = BxDolGrid::getObjectInstance($CNF['OBJECT_GRID_BANS']);
+        if(!$oGrid)
+            return false;
+
+        if($this->_bIsApi)
+            return [
+                bx_api_get_block('grid', $oGrid->getCodeAPI())
+            ];
+
+        return $oGrid->getCode();
+    }
+
+    public function serviceInvitations ($iInvitedPid = 0, $bAsArray = false)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        if(!$iInvitedPid)
+            $iInvitedPid = bx_process_input(bx_get('profile_id'), BX_DATA_INT);
+        if(!$iInvitedPid)
+            return false;
+
+        $aInvites = $this->_oDb->getInvites(['sample' => 'invited_pid', 'invited_pid' => $iInvitedPid]);
+        if(empty($aInvites) || !is_array($aInvites))
+            return false;
+
+        if($bAsArray)
+            return $aInvites;
+
+        $iStart = $iLimit = 0;
+        if($this->_bIsApi) {
+            $aParams = bx_api_get_browse_params($bAsArray);
+
+            $iStart = isset($aParams['start']) ? (int)$aParams['start'] : 0;
+            $iLimit = isset($aParams['per_page']) ? (int)$aParams['per_page'] : 0;
+        }
+        else {
+            $iStart = (int)bx_get('start');
+            $iLimit = (int)bx_get('per_page');
+        }
+
+        $iLimit = !$iLimit && ($sKey = 'PARAM_NUM_CONNECTIONS_QUICK') && !empty($CNF[$sKey]) && ($iValue = (int)getParam($CNF[$sKey])) ? $iValue : 4;
+
+        if($this->_bIsApi) {
+            $aData = [
+                'data' => [],
+                'request_url' => '/api.php?r=' . $this->_oConfig->getName() . '/invites/&params[]=' . $iInvitedPid . '&params[]=',
+                'params' => [
+                    'start' => $iStart,
+                    'per_page' => $iLimit
+                ]
+            ];
+
+            foreach($aInvites as $aInvite)
+                $aData['data'][] = BxDolProfile::getData($aInvite['group_profile_id']);
+
+            return [bx_api_get_block('profiles_list', $aData)];
+        }
+        else
+            return $this->_serviceBrowseQuick(array_keys($aInvites), $iStart, $iLimit);
+    }
+
+    public function serviceFans ($iContentId = 0, $bAsArray = false)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        if(!$iContentId)
+            $iContentId = bx_process_input(bx_get('id'), BX_DATA_INT);
+        if(!$iContentId)
+            return false;
+
+        $aContentInfo = $this->_oDb->getContentInfoById($iContentId);
+        if(!$aContentInfo)
+            return false;
+
+        if(!($oGroupProfile = BxDolProfile::getInstanceByContentAndType($iContentId, $this->getName())))
+            return false;
+
+        if(is_bool($bAsArray) && $bAsArray === true)
+            return BxDolConnection::getObjectInstance($CNF['OBJECT_CONNECTIONS'])->getConnectedContent($oGroupProfile->id(), true);
+
+        if($this->_bIsApi) {
+            $aParams = bx_api_get_browse_params($bAsArray);
+
+            $iStart = isset($aParams['start']) ? (int)$aParams['start'] : 0;
+            $iLimit = isset($aParams['per_page']) ? (int)$aParams['per_page'] : 0;
+            $iLimit = !$iLimit && ($sKey = 'PARAM_NUM_CONNECTIONS_QUICK') && !empty($CNF[$sKey]) && ($iValue = (int)getParam($CNF[$sKey])) ? $iValue : 4;
+
+            $aProfiles = BxDolConnection::getObjectInstance($CNF['OBJECT_CONNECTIONS'])->getConnectedContent($oGroupProfile->id(), true, $iStart, $iLimit);
+            if(empty($aProfiles) || !is_array($aProfiles))
+                return false;
+
+            $aData = [
+                'data' => [],
+                'request_url' => '/api.php?r=' . $this->_oConfig->getName() . '/fans/&params[]=' . $iContentId . '&params[]=',
+                'params' => [
+                    'start' => $iStart,
+                    'per_page' => $iLimit
+                ]
+            ];
+
+            foreach($aProfiles as $iProfileId)
+                $aData['data'][] = BxDolProfile::getData($iProfileId);
+
+            return [bx_api_get_block('profiles_list', $aData)];
+        }
+
+        bx_import('BxDolConnection');
+        $mixedResult = $this->serviceBrowseConnectionsQuick ($oGroupProfile->id(), $CNF['OBJECT_CONNECTIONS'], BX_CONNECTIONS_CONTENT_TYPE_CONTENT, true);
+        if(!$mixedResult)
+            return MsgBox(_t('_sys_txt_empty'));
+
+        return $mixedResult;
+    }
+    
+    public function serviceFansWithoutAdmins ($iContentId = 0, $bAsArray = false)
+    {
+        if (!$iContentId)
+            $iContentId = bx_process_input(bx_get('id'), BX_DATA_INT);
+        if (!$iContentId)
+            return false;
+
+        $aContentInfo = $this->_oDb->getContentInfoById($iContentId);
+        if (!$aContentInfo)
+            return false;
+
+        if (!($oGroupProfile = BxDolProfile::getInstanceByContentAndType($iContentId, $this->getName())))
+            return false;
+        
+        $CNF = &$this->_oConfig->CNF;
+
+        $aFans = BxDolConnection::getObjectInstance($CNF['OBJECT_CONNECTIONS'])->getConnectedContent($oGroupProfile->id(), true);
+        if(empty($aFans) || !is_array($aFans))
+            return false;
+
+        $aAdmins = $this->_oDb->getAdmins($oGroupProfile->id());
+        if(!empty($aAdmins) && is_array($aAdmins) && !($aFans = array_diff($aFans, $aAdmins)))
+            return false;
+
+        if(is_bool($bAsArray) && $bAsArray === true)
+            return $aFans;
+
+        $iStart = $iLimit = 0;
+        if($this->_bIsApi) {
+            $aParams = bx_api_get_browse_params($bAsArray);
+
+            $iStart = isset($aParams['start']) ? (int)$aParams['start'] : 0;
+            $iLimit = isset($aParams['per_page']) ? (int)$aParams['per_page'] : 0;
+        }
+        else {
+            $iStart = (int)bx_get('start');
+            $iLimit = (int)bx_get('per_page');
+        }
+
+        $iLimit = !$iLimit && ($sKey = 'PARAM_NUM_CONNECTIONS_QUICK') && !empty($CNF[$sKey]) && ($iValue = (int)getParam($CNF[$sKey])) ? $iValue : 4;
+
+        if($this->_bIsApi) {
+            $aData = [
+                'data' => [],
+                'request_url' => '/api.php?r=' . $this->_oConfig->getName() . '/fans_without_admins/&params[]=' . $iContentId . '&params[]=',
+                'params' => [
+                    'start' => $iStart,
+                    'per_page' => $iLimit
+                ]
+            ];
+
+            foreach($aProfiles as $iProfileId)
+                $aData['data'][] = BxDolProfile::getData($iProfileId);
+
+            return [bx_api_get_block('profiles_list', $aData)];
+        }
+        else
+            return $this->_serviceBrowseQuick($aFans, $iStart, $iLimit);
+    }
+
+    public function serviceAdmins ($iContentId = 0, $sParams = '')
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        if(!$iContentId)
+            $iContentId = bx_process_input(bx_get('id'), BX_DATA_INT);
+        if(!$iContentId)
+            return false;
+
+        $oGroupProfile = BxDolProfile::getInstanceByContentAndType($iContentId, $this->getName());
+        if(!$oGroupProfile)
+            return false;
+
+        $iStart = (int)bx_get('start');
+        $iLimit = !empty($CNF['PARAM_NUM_CONNECTIONS_QUICK']) ? (int)getParam($CNF['PARAM_NUM_CONNECTIONS_QUICK']) : 4;
+        if(!$iLimit)
+            $iLimit = 4;
+
+        if($this->_bIsApi && ($aParams = bx_api_get_browse_params($sParams))) {
+            if(isset($aParams['start']))
+                $iStart = (int)$aParams['start'];
+            if(isset($aParams['per_page']))
+                $iLimit = (int)$aParams['per_page'];
+        }
+
+        $aProfiles = $this->_oDb->getAdmins($oGroupProfile->id(), $iStart,  $iLimit+1);
+        if(empty($aProfiles) || !is_array($aProfiles))
+            return false;
+
+        if($this->_bIsApi) {
+            $aData = [
+                'data' => [],
+                'request_url' => '/api.php?r=' . $this->_oConfig->getName() . '/admins/&params[]=' . $iContentId . '&params[]=',
+                'params' => [
+                    'start' => $iStart,
+                    'per_page' => $iLimit
+                ]
+            ];
+            foreach($aProfiles as $iProfileId)
+                $aData['data'][] = BxDolProfile::getData($iProfileId);
+
+            return [bx_api_get_block('profiles_list', $aData)];
+        }
+
+        return $this->_serviceBrowseQuick($aProfiles, $iStart, $iLimit);
+    }
+
+    public function serviceMembersByRole ($iContentId = 0, $iRole = BX_BASE_MOD_GROUPS_ROLE_COMMON)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        if(!$iContentId)
+            $iContentId = bx_process_input(bx_get('id'), BX_DATA_INT);
+        if(!$iContentId)
+            return false;
+
+        $oGroupProfile = BxDolProfile::getInstanceByContentAndType($iContentId, $this->getName());
+        if(!$oGroupProfile)
+            return false;
+
+        $iStart = (int)bx_get('start');
+        $iLimit = !empty($CNF['PARAM_NUM_CONNECTIONS_QUICK']) ? getParam($CNF['PARAM_NUM_CONNECTIONS_QUICK']) : 4;
+        if(!$iLimit)
+            $iLimit = 4;
+
+        $aProfiles = $this->_oDb->getRoles([
+            'type' => 'fan_pids_by_group_pid', 
+            'group_profile_id' => $oGroupProfile->id(), 
+            'role' => $iRole,
+            'start' => $iStart,  
+            'limit' => $iLimit + 1
+        ]);
+
+        if(empty($aProfiles) || !is_array($aProfiles))
+            return false;
+
+        return $this->_serviceBrowseQuick($aProfiles, $iStart, $iLimit);
+    }
+
+    public function serviceBrowseJoinedEntries ($iProfileId = 0, $bDisplayEmptyMsg = false)
+    {
+        if (!$iProfileId)
+            $iProfileId = bx_process_input(bx_get('profile_id'), BX_DATA_INT);
+        if (!$iProfileId)
+            return '';
+
+        return $this->_serviceBrowse ('joined_entries', array('joined_profile' => $iProfileId), BX_DB_PADDING_DEF, $bDisplayEmptyMsg);
+    }
+
+    /**
+     * Display entries posted into particular context and joined by profile
+     */
+    public function serviceBrowseContextJoinedEntries ($iContextPid = 0, $iProfileId = 0, $aParams = [])
+    {
+        if(!$iContextPid)
+            $iContextPid = bx_process_input(bx_get('profile_id'), BX_DATA_INT);
+        if(!$iContextPid)
+            return $this->_bIsApi ? [] : '';
+
+        if(!$iProfileId)
+            $iProfileId = bx_get_logged_profile_id();
+        if(!$iProfileId)
+            return $this->_bIsApi ? [] : '';
+
+        $bEmptyMessage = true;
+        if(isset($aParams['empty_message'])) {
+            $bEmptyMessage = (bool)$aParams['empty_message'];
+            unset($aParams['empty_message']);
+        }
+
+        $bAjaxPaginate = true;
+        if(isset($aParams['ajax_paginate'])) {
+            $bAjaxPaginate = (bool)$aParams['ajax_paginate'];
+            unset($aParams['ajax_paginate']);
+        }
+
+        return $this->_serviceBrowse ('context_joined_entries', ['context' => $iContextPid, 'joined_profile' => $iProfileId], BX_DB_PADDING_DEF, $bEmptyMessage, $bAjaxPaginate);
+    }
+
+    public function serviceBrowseFollowedEntries ($iProfileId = 0, $bDisplayEmptyMsg = false)
+    {
+        if (!$iProfileId)
+            $iProfileId = bx_process_input(bx_get('profile_id'), BX_DATA_INT);
+        if (!$iProfileId)
+            return '';
+
+        return $this->_serviceBrowse ('followed_entries', array('followed_profile' => $iProfileId), BX_DB_PADDING_DEF, $bDisplayEmptyMsg);
+    }
+
+    public function serviceBrowseCreatedEntries ($iProfileId = 0, $bDisplayEmptyMsg = false)
+    {
+        if (!$iProfileId)
+            $iProfileId = bx_process_input(bx_get('profile_id'), BX_DATA_INT);
+        if (!$iProfileId)
+            return '';
+
+        return $this->_serviceBrowse ('created_entries', array('author' => $iProfileId), BX_DB_PADDING_DEF, $bDisplayEmptyMsg);
+    }
+
+    public function serviceBrowseRecommendationsFans ($iProfileId = 0, $aParams = [])
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        if($this->_bIsApi)
+            $aParams = bx_api_get_browse_params($aParams, true);
+
+        if(!$iProfileId)
+            $iProfileId = bx_get_logged_profile_id();
+        if(!$iProfileId)
+            return '';
+
+        $aParams = array_merge([
+            'empty_message' => false,
+            'start' => 0,
+            'per_page' => 0
+        ], $aParams);
+
+        if(($iStartGet = bx_get('start')) !== false)
+            $aParams['start'] = (int)$iStartGet;
+
+        if(($iPerPageGet = bx_get('per_page')) !== false)
+            $aParams['per_page'] = (int)$iPerPageGet;
+
+        $oRecommendation = BxDolRecommendation::getObjectInstance($CNF['OBJECT_RECOMMENDATIONS_FANS']);
+        if(!$oRecommendation)
+            return false;
+
+        if($this->_bIsApi) {
+            $aData = $oRecommendation->getCodeAPI($iProfileId, $aParams);
+            $aData = array_merge($aData, [
+                'module' => 'system',
+                'unit' => 'mixed', 
+                'request_url' => '/api.php?r=' . $this->getName() .'/browse_recommendations_fans&params[]=' . $iProfileId . '&params[]='
+            ]);
+
+            return [bx_api_get_block('browse', $aData)];
+        }
+
+        $sCode = $oRecommendation->getCode($iProfileId, $aParams);
+        if(!$sCode && $aParams['empty_message'])
+            $sCode = MsgBox(_t(!empty($aParams['empty_message_text']) ? $aParams['empty_message_text'] : '_Empty'));
+
+        return $sCode;
+    }
+
+    public function serviceBrowseMembers ($iProfileId = 0, $aParams = [])
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        if(!$iProfileId)
+            $iProfileId = bx_process_input(bx_get('profile_id'), BX_DATA_INT);
+        if(!$iProfileId)
+            return '';
+
+        $oGroupProfile = BxDolProfile::getInstance($iProfileId);
+        if(!($oGroupProfile))
+            return '';
+
+        return bx_srv('system', 'browse_members', [$oGroupProfile->id(), $CNF['OBJECT_CONNECTIONS'], $aParams], 'TemplServiceProfiles');
+    }
+
+    public function serviceEntityEditQuestionnaire($iProfileId = 0)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        if(!$iProfileId)
+            $iProfileId = bx_process_input(bx_get('profile_id'), BX_DATA_INT);
+        if(!$iProfileId)
+            return '';
+
+        $aProfileInfo = BxDolProfileQuery::getInstance()->getInfoById($iProfileId);
+        if(empty($aProfileInfo) || !is_array($aProfileInfo))
+            return '';
+        
+        $aContentInfo = $this->_oDb->getContentInfoById($aProfileInfo['content_id']);
+        if(empty($aContentInfo) || !is_array($aContentInfo))
+            return '';
+
+        if($this->checkAllowedEdit($aContentInfo) !== CHECK_ACTION_RESULT_ALLOWED)
+            return MsgBox(_t('_Access denied'));
+
+        $oGrid = BxDolGrid::getObjectInstance($CNF['OBJECT_GRID_QUESTIONS_MANAGE']);
+        if(!$oGrid)
+            return '';
+        
+        if($this->_bIsApi){
+            return [
+                bx_api_get_block('grid', $oGrid->getCodeAPI())
+            ];
+        }
+
+        return $oGrid->getCode();
+    }
+
+    public function serviceEntityPricing($iProfileId = 0)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        if(!$iProfileId)
+            $iProfileId = bx_process_input(bx_get('profile_id'), BX_DATA_INT);
+        if(!$iProfileId)
+            return $this->_bIsApi ? [] : '';
+
+        if(!$this->_oConfig->isPaidJoin())
+            return $this->_bIsApi ? [] : '';
+
+        $oPayments = BxDolPayments::getInstance();
+        if(!$oPayments->isActive())
+            return ($sMsg = _t('_sys_payments_err_no_payments')) && $this->_bIsApi ? [bx_api_get_msg($sMsg)] : MsgBox($sMsg);
+
+        if($this->checkAllowedUsePaidJoin() !== CHECK_ACTION_RESULT_ALLOWED)
+            return ($sMsg = _t('_Access denied')) && $this->_bIsApi ? [bx_api_get_msg($sMsg)] : MsgBox($sMsg);
+
+        if($this->checkAllowedManageAdmins($iProfileId) !== CHECK_ACTION_RESULT_ALLOWED)
+            return ($sMsg = _t('_Access denied')) && $this->_bIsApi ? [bx_api_get_msg($sMsg)] : MsgBox($sMsg);
+
+        $oGrid = BxDolGrid::getObjectInstance($CNF['OBJECT_GRID_PRICES_MANAGE']);
+        if(!$oGrid)
+            return '';
+
+        $sNote = '';
+        if(!$oPayments->isAcceptingPayments($this->_iProfileId))
+            $sNote = MsgBox(_t('_sys_payments_err_not_accept_payments', $oPayments->getDetailsUrl()));
+
+        if($this->_bIsApi) {
+            $aBlocks = [];
+            if(!empty($sNote))
+                $aBlocks[] = bx_api_get_msg($sNote);
+            $aBlocks[] = bx_api_get_block('grid', $oGrid->getCodeAPI(true));
+
+            return $aBlocks;
+        }
+
+        return $sNote . $oGrid->getCode();
+    }
+
+    public function serviceEntityJoin($iProfileId = 0)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        if(!$iProfileId)
+            $iProfileId = bx_process_input(bx_get('profile_id'), BX_DATA_INT);
+        if(!$iProfileId)
+            return $this->_bIsApi ? [] : '';
+
+        if(!$this->_oConfig->isPaidJoin())
+            return $this->_bIsApi ? [] : '';
+
+        if($this->_bIsApi && !$this->isPaidJoinByProfile($iProfileId))
+            return [];
+
+        $oGrid = BxDolGrid::getObjectInstance($CNF['OBJECT_GRID_PRICES_VIEW']);
+        if(!$oGrid)
+            return $this->_bIsApi ? [] : '';
+
+        $oGrid->setProfileId($iProfileId);
+
+        if($this->_bIsApi) {
+            $aContentInfo = $this->_oDb->getContentInfoByProfileId($iProfileId);
+
+            return [
+                bx_api_get_block('pricing', array_merge_recursive($oGrid->getCodeAPI(true), ['settings' => [
+                    'context_name' => $aContentInfo[$CNF['FIELD_TITLE']],
+                    'unit' => 'productlist'
+                ]]))
+            ];
+        }
+
+        return $oGrid->getCode();
+    }
+
+    public function serviceEntityInvite ($iContentId = 0, $bErrorMsg = true)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        if(!isset($CNF['OBJECT_FORM_ENTRY_DISPLAY_INVITE']))
+            return false;
+
+        return $this->_serviceEntityForm ('inviteForm', $iContentId, false, false, $bErrorMsg);
+    }
+    
+    /**
+     * Entry social sharing block
+     */
+    public function serviceEntitySocialSharing ($mixedContent = false, $aParams = array())
+    {
+        if(!empty($mixedContent)) {
+            if(!is_array($mixedContent))
+               $mixedContent = array((int)$mixedContent, array());
+        }
+        else {
+            $mixedContent = $this->_getContent();
+            if($mixedContent === false)
+                return false;
+        }
+
+        list($iContentId, $aContentInfo) = $mixedContent;
+
+        $oGroupProfile = BxDolProfile::getInstanceByContentAndType((int)$iContentId, $this->getName());
+        if(!$oGroupProfile)
+            return false;
+
+        return parent::serviceEntitySocialSharing(array($iContentId, $aContentInfo), array(
+            'title' => $oGroupProfile->getDisplayName()
+        ));
+    }
+
+    public function serviceIsPricingAvaliable($iProfileId)
+    {
+        if(!$this->_oConfig->isPaidJoin())
+            return false;
+
+        if($this->checkAllowedUsePaidJoin() !== CHECK_ACTION_RESULT_ALLOWED)
+            return false;        
+
+        if($this->checkAllowedManageAdmins($iProfileId) !== CHECK_ACTION_RESULT_ALLOWED)
+            return false;
+
+        return true;
+    }
+
+    public function serviceIsPaidJoinAvaliable($iGroupProfileId, $iProfileId = 0)
+    {
+        return $this->isPaidJoinByProfileForProfile($iGroupProfileId, $iProfileId);
+    }
+
+    public function serviceIsPaidJoinAvaliableByContent($iGroupContentId, $iProfileId = 0)
+    {
+        $oGroupProfile = BxDolProfile::getInstanceByContentAndType($iGroupContentId, $this->getName());
+        if(!$oGroupProfile)
+            return false;
+
+        return $this->isPaidJoinByProfileForProfile($oGroupProfile->id(), $iProfileId);
+    }
+
+    public function serviceIsFreeJoinAvaliable($iGroupProfileId, $iProfileId = 0)
+    {
+        return !$this->isPaidJoinByProfileForProfile($iGroupProfileId, $iProfileId);
+    }
+
+    public function serviceIsFreeJoinAvaliableByContent($iGroupContentId, $iProfileId = 0)
+    {
+        $oGroupProfile = BxDolProfile::getInstanceByContentAndType($iGroupContentId, $this->getName());
+        if(!$oGroupProfile)
+            return false;
+
+        return !$this->isPaidJoinByProfileForProfile($oGroupProfile->id(), $iProfileId);
+    }
+
+    /**
+     * Is Paid Join enabled in the group and whether a profile can use it.
+     * 
+     * @param type $iGroupProfileId - Group profile ID.
+     * @param type $iProfileId - Profile ID of the user who wants to join.
+     * @return boolean
+     */
+    public function isPaidJoinByProfileForProfile($iGroupProfileId, $iProfileId = 0)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        if(empty($iProfileId))
+            $iProfileId = $this->_iProfileId;
+
+        if(BxDolConnection::getObjectInstance($CNF['OBJECT_CONNECTIONS'])->isConnected($iProfileId, $iGroupProfileId))
+            return false;
+
+        return $this->isPaidJoinByProfile($iGroupProfileId);
+    }
+
+    /**
+     * Is Paid Join enabled as is and whether a group has pricing plans added.
+     * 
+     * @param type $iGroupProfileId - Group profile ID.
+     * @return boolean
+     */
+    public function isPaidJoinByProfile($iGroupProfileId)
+    {
+        if(!$this->_oConfig->isPaidJoin())
+            return false;
+
+        $aPrices = $this->_oDb->getPrices(['type' => 'by_profile_id', 'profile_id' => $iGroupProfileId, 'active' => 1]);
+        if(empty($aPrices) || !is_array($aPrices))
+            return false;
+
+        return true;
+    }
+
+    /**
+     * Integration with Payments.
+     */
+    public function serviceGetPaymentData()
+    {
+        return $this->_aModule;
+    }
+
+    public function serviceGetCartItem($mixedItemId)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        if(!$mixedItemId)
+            return [];
+
+        if(is_numeric($mixedItemId))
+            $aItem = $this->_oDb->getPrices(['type' => 'by_id', 'value' => (int)$mixedItemId]);
+        else 
+            $aItem = $this->_oDb->getPrices(['type' => 'by_name', 'value' => $mixedItemId]);
+
+        if(empty($aItem) || !is_array($aItem))
+            return [];
+
+        if(!$this->isPaidJoinByProfile($aItem['profile_id']))
+            return [];
+
+        $oGroupProfile = BxDolProfile::getInstance($aItem['profile_id']);
+        if(!$oGroupProfile)
+            return [];
+
+        $aGroupProfile = $this->_oDb->getContentInfoById($oGroupProfile->getContentId());
+        
+        $aRoles = BxDolFormQuery::getDataItems($CNF['OBJECT_PRE_LIST_ROLES']);
+
+        $sTitle = '';
+        if(!empty($aItem['period']) && !empty($aItem['period_unit']))
+            $sTitle = _t($CNF['T']['txt_cart_item_title'], $oGroupProfile->getDisplayName(), $aRoles[$aItem['role_id']], $aItem['period'], $aItem['period_unit']);
+        else
+            $sTitle = _t($CNF['T']['txt_cart_item_title_lifetime'], $oGroupProfile->getDisplayName(), $aRoles[$aItem['role_id']]);
+
+        return [
+            'id' => $aItem['id'],
+            'author_id' => $aGroupProfile[$CNF['FIELD_AUTHOR']],
+            'name' => $aItem['name'],
+            'title' => $sTitle,
+            'description' => '',
+            'url' => $oGroupProfile->getUrl(),
+            'price_single' => $aItem['price'],
+            'price_recurring' => $aItem['price'],
+            'period_recurring' => $aItem['period'],
+            'period_unit_recurring' => $aItem['period_unit'],
+            'trial_recurring' => 0,
+            'added' => $aItem['added']
+        ];
+    }
+
+    public function serviceGetCartItems($iSellerId)
+    {
+    	$CNF = &$this->_oConfig->CNF;
+
+    	if(empty($iSellerId))
+    	    return array();
+
+        $sModule = $this->getName();
+        $aRoles = BxDolFormQuery::getDataItems($CNF['OBJECT_PRE_LIST_ROLES']);
+
+        $aGroups = $this->_oDb->getEntriesBy(array('type' => 'author', 'author' => $iSellerId));
+
+        $aResult = array();
+        foreach($aGroups as $aGroup) {
+            $oGroupProfile = BxDolProfile::getInstanceByContentAndType($aGroup[$CNF['FIELD_ID']], $sModule);
+            if(!$oGroupProfile)
+                continue;
+
+            $aPrices = $this->_oDb->getPrices(array('type' => 'by_profile_id', 'profile_id' => $oGroupProfile->id()));
+            if(empty($aPrices) || !is_array($aPrices))
+                continue;
+
+            $sTitle = $oGroupProfile->getDisplayName();
+            $sUrl = $oGroupProfile->getUrl();
+
+            foreach($aPrices as $aPrice)
+                $aResult[] = array(
+                    'id' => $aPrice['id'],
+                    'author_id' => $iSellerId,
+                    'name' => $aPrice['name'],
+                    'title' => _t($CNF['T']['txt_cart_item_title'], $sTitle, $aRoles[$aPrice['role_id']], $aPrice['period'], $aPrice['period_unit']),
+                    'description' => '',
+                    'url' => $sUrl,
+                    'price_single' => $aPrice['price'],
+                    'price_recurring' => $aPrice['price'],
+                    'period_recurring' => $aPrice['period'],
+                    'period_unit_recurring' => $aPrice['period_unit']
+               );
+        }
+
+        return $aResult;
+    }
+
+    public function serviceRegisterCartItem($iClientId, $iSellerId, $iItemId, $iItemCount, $sOrder, $sLicense)
+    {
+        return $this->_serviceRegisterItem($iClientId, $iSellerId, $iItemId, $iItemCount, $sOrder);
+    }
+
+    public function serviceRegisterSubscriptionItem($iClientId, $iSellerId, $iItemId, $iItemCount, $sOrder, $sLicense)
+    {
+        return $this->_serviceRegisterItem($iClientId, $iSellerId, $iItemId, $iItemCount, $sOrder);
+    }
+
+    public function serviceReregisterCartItem($iClientId, $iSellerId, $iItemIdOld, $iItemIdNew, $sOrder)
+    {
+        return $this->_serviceReregisterItem($iClientId, $iSellerId, $iItemIdOld, $iItemIdNew, $sOrder);
+    }
+
+    public function serviceReregisterSubscriptionItem($iClientId, $iSellerId, $iItemIdOld, $iItemIdNew, $sOrder)
+    {
+        return $this->_serviceReregisterItem($iClientId, $iSellerId, $iItemIdOld, $iItemIdNew, $sOrder);
+    }
+
+    public function serviceUnregisterCartItem($iClientId, $iSellerId, $iItemId, $iItemCount, $sOrder, $sLicense)
+    {
+        return $this->_serviceUnregisterItem($iClientId, $iSellerId, $iItemId, $iItemCount, $sOrder);
+    }
+
+    public function serviceUnregisterSubscriptionItem($iClientId, $iSellerId, $iItemId, $iItemCount, $sOrder, $sLicense)
+    {
+    	return $this->_serviceUnregisterItem($iClientId, $iSellerId, $iItemId, $iItemCount, $sOrder); 
+    }
+
+    public function serviceCancelSubscriptionItem($iClientId, $iSellerId, $iItemId, $iItemCount, $sOrder)
+    {
+    	return true;
+    }
+
+    protected function _serviceRegisterItem($iClientId, $iSellerId, $iItemId, $iItemCount, $sOrder)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+    	$aItem = $this->serviceGetCartItem($iItemId);
+        if(empty($aItem) || !is_array($aItem))
+            return array();
+
+        $aItemInfo = $this->_oDb->getPrices(array('type' => 'by_id', 'value' => $iItemId));
+
+        $mixedPeriod = false;
+        if((int)$aItemInfo['period'] != 0)
+            $mixedPeriod = array(
+                'period' => (int)$aItemInfo['period'], 
+                'period_unit' => $aItemInfo['period_unit'], 
+                'period_reserve' => $CNF['PARAM_RECURRING_RESERVE']
+            );
+
+        if(!$this->setRole($aItemInfo['profile_id'], $iClientId, $aItemInfo['role_id'], $mixedPeriod, $sOrder))
+            return array();
+
+        return $aItem;
+    }
+
+    protected function _serviceReregisterItem($iClientId, $iSellerId, $iItemIdOld, $iItemIdNew, $sOrder)
+    {
+        $aItem = $this->serviceGetCartItem($iItemIdNew);
+        if(empty($aItem) || !is_array($aItem))
+            return array();
+
+        $aItemInfoOld = $this->_oDb->getPrices(array('type' => 'by_id', 'value' => $iItemIdOld));
+        if(empty($aItemInfoOld) || !is_array($aItemInfoOld))
+            return array();
+
+        $aItemInfoNew = $this->_oDb->getPrices(array('type' => 'by_id', 'value' => $iItemIdNew));
+        if(empty($aItemInfoNew) || !is_array($aItemInfoNew))
+            return array();
+
+        if(!$this->unsetRole($aItemInfoOld['profile_id'], $iClientId))
+            return array();
+        
+        $aResult = $this->_serviceRegisterItem($iClientId, $iSellerId, $iItemIdNew, 1, $sOrder);
+        if(empty($aResult) || !is_array($aResult))
+            return array();
+
+    	return $aItem;
+    }
+
+    protected function _serviceUnregisterItem($iClientId, $iSellerId, $iItemId, $iItemCount, $sOrder)
+    {
+        $aItemInfo = $this->_oDb->getPrices(array('type' => 'by_id', 'value' => $iItemId));
+        if(empty($aItemInfo) || !is_array($aItemInfo))
+            return false;
+
+        return $this->unsetRole($aItemInfo['profile_id'], $iClientId);
+    }
+
+    public function serviceGetQuestionnaire($sSource, $sObject, $sAction, $iContentProfileId)
+    {
+        $CNF = &$this->_oConfig->CNF;
+        $sMsg = _t('_sys_txt_not_found');
+
+        $aContentInfo = $this->_oDb->getContentInfoByProfileId($iContentProfileId);
+        if(empty($aContentInfo) || !is_array($aContentInfo))
+            return $this->_bIsApi ? [bx_api_get_msg($sMsg)] : ['code' => 1, 'msg' => $sMsg];
+        
+        $oForm = null;
+        if(($oConnection = BxDolConnection::getObjectInstance($sObject)) !== false) {
+            $oForm = $oConnection->getQuestionnaireForm($sAction, $iContentProfileId, ['request' => [
+                's' => $sSource,
+            ]]);
+
+            if($oForm === false)
+                return $this->_bIsApi ? [bx_api_get_msg($sMsg)] : ['code' => 3, 'msg' => $sMsg];
+        }
+        else
+            return $this->_bIsApi ? [bx_api_get_msg($sMsg)] : ['code' => 2, 'msg' => $sMsg];
+
+        $oForm->initChecker();
+        if($oForm->isSubmittedAndValid()) {
+            $iProfileId = bx_get_logged_profile_id();
+
+            $aQuestions = $this->_oDb->getQuestions(['sample' => 'content_pid', 'content_pid' => $iContentProfileId]);
+            foreach($aQuestions as $aQuestion)
+                $this->_oDb->insertAnswer((int)$aQuestion['id'], $iProfileId, $oForm->getCleanValue('question_' . $aQuestion['id']));
+
+            return $this->_bIsApi ? [] : ['code' => 0, 'o' => $sObject, 'a' => $sAction, 'cpi' => $iContentProfileId, 'ci' => $aContentInfo[$CNF['FIELD_ID']], 'eval' => $this->_oConfig->getJsObject($sSource) . '.connActionPerformed(oData)'];
+        }
+
+        if($this->_bIsApi)
+            return [bx_api_get_block('form', $oForm->getCodeAPI(), ['ext' => [
+                'name' => $this->_oModule->getName(), 
+                'request' => ['url' => $oForm->aFormAttrs['action'], 'immutable' => true]]
+            ])];
+
+        bx_import('BxTemplFunctions');
+        $sContent = BxTemplFunctions::getInstance()->popupBox($this->_oConfig->getHtmlIds('popup_questionnaire'), _t($CNF['T']['popup_title_questionnaire']), $this->_oTemplate->parseHtmlByName('popup_qnr_questionnaire.html', [
+            'form_id' => $oForm->getId(),
+            'form' => $oForm->getCode(true),
+        ]));
+
+        return ['popup' => ['html' => $sContent, 'options' => ['closeOnOuterClick' => false]]];
+    }
+
+    /**
+     * Data for Notifications module
+     */
+    public function serviceGetNotificationsData()
+    {
+    	$sModule = $this->_aModule['name'];
+
+        $aSettingsTypes = ['follow_member', 'follow_context'];
+        if($this->serviceActAsProfile())
+            $aSettingsTypes = ['personal', 'follow_member'];
+
+        return [
+            'handlers' => [
+                ['group' => $sModule . '_vote', 'type' => 'insert', 'alert_unit' => $sModule, 'alert_action' => 'doVote', 'module_name' => $sModule, 'module_method' => 'get_notifications_vote', 'module_class' => 'Module'],
+                ['group' => $sModule . '_vote', 'type' => 'delete', 'alert_unit' => $sModule, 'alert_action' => 'undoVote'],
+                
+                ['group' => $sModule . '_score_up', 'type' => 'insert', 'alert_unit' => $sModule, 'alert_action' => 'doVoteUp', 'module_name' => $sModule, 'module_method' => 'get_notifications_score_up', 'module_class' => 'Module'],
+
+                ['group' => $sModule . '_score_down', 'type' => 'insert', 'alert_unit' => $sModule, 'alert_action' => 'doVoteDown', 'module_name' => $sModule, 'module_method' => 'get_notifications_score_down', 'module_class' => 'Module'],
+
+                ['group' => $sModule . '_fan_added', 'type' => 'insert', 'alert_unit' => $sModule, 'alert_action' => 'fan_added', 'module_name' => $sModule, 'module_method' => 'get_notifications_fan_added', 'module_class' => 'Module'],
+
+                ['group' => $sModule . '_join_invitation', 'type' => 'insert', 'alert_unit' => $sModule, 'alert_action' => 'join_invitation_notif', 'module_name' => $sModule, 'module_method' => 'get_notifications_join_invitation', 'module_class' => 'Module'],
+                
+                ['group' => $sModule . '_join_request', 'type' => 'insert', 'alert_unit' => $sModule, 'alert_action' => 'join_request', 'module_name' => $sModule, 'module_method' => 'get_notifications_join_request', 'module_class' => 'Module', 'module_event_privacy' => $this->_oConfig->CNF['OBJECT_PRIVACY_VIEW_NOTIFICATION_EVENT']],
+                
+                ['group' => $sModule . '_timeline_post_common', 'type' => 'insert', 'alert_unit' => $sModule, 'alert_action' => 'timeline_post_common', 'module_name' => $sModule, 'module_method' => 'get_notifications_timeline_post_common', 'module_class' => 'Module'],
+                
+                //--- Moderation related: For 'admins'.
+                ['group' => $sModule . '_object_pending_approval', 'type' => 'insert', 'alert_unit' => $sModule, 'alert_action' => 'pending_approval', 'module_name' => $sModule, 'module_method' => 'get_notifications_post_pending_approval', 'module_class' => 'Module'],
+                ['group' => $sModule . '_object_reported', 'type' => 'insert', 'alert_unit' => $sModule, 'alert_action' => 'reported_content', 'module_name' => $sModule, 'module_method' => 'get_notifications_post_reported', 'module_class' => 'Module'],
+            ],
+            'settings' => [
+                ['group' => 'vote', 'unit' => $sModule, 'action' => 'doVote', 'types' => $aSettingsTypes],
+
+                ['group' => 'score_up', 'unit' => $sModule, 'action' => 'doVoteUp', 'types' => $aSettingsTypes],
+
+                ['group' => 'score_down', 'unit' => $sModule, 'action' => 'doVoteDown', 'types' => $aSettingsTypes],
+                
+                ['group' => 'fan', 'unit' => $sModule, 'action' => 'fan_added', 'types' => $aSettingsTypes],
+
+                ['group' => 'invite', 'unit' => $sModule, 'action' => 'join_invitation_notif', 'types' => ['personal']],
+
+                ['group' => 'join', 'unit' => $sModule, 'action' => 'join_request', 'types' => $aSettingsTypes],
+
+                ['group' => 'timeline_post', 'unit' => $sModule, 'action' => 'timeline_post_common', 'types' => $aSettingsTypes],
+
+                //--- Moderation related: For 'admins'.
+                ['group' => 'action_required', 'unit' => $sModule, 'action' => 'pending_approval', 'types' => ['personal']],
+                ['group' => 'action_required', 'unit' => $sModule, 'action' => 'reported_content', 'types' => ['personal']],
+            ],
+            'alerts' => [
+                ['unit' => $sModule, 'action' => 'doVote'],
+                ['unit' => $sModule, 'action' => 'undoVote'],
+
+                ['unit' => $sModule, 'action' => 'doVoteUp'],
+                ['unit' => $sModule, 'action' => 'doVoteDown'],
+
+                ['unit' => $sModule, 'action' => 'fan_added'],
+
+                ['unit' => $sModule, 'action' => 'join_invitation_notif'],
+
+                ['unit' => $sModule, 'action' => 'join_request'],
+
+                ['unit' => $sModule, 'action' => 'timeline_post_common'],
+
+                //--- Moderation related: For 'admins'.
+                ['unit' => $sModule, 'action' => 'pending_approval'],
+                ['unit' => $sModule, 'action' => 'reported_content'],
+            ]
+        ];
+    }
+
+    public function serviceGetNotificationsInsertData($oAlert, $aHandler, $aDataItems)
+    {
+        if($oAlert->sAction != 'join_invitation_notif' || empty($aDataItems) || !is_array($aDataItems))
+            return $aDataItems;
+
+        foreach($aDataItems as $iIndex => $aDataItem)
+            $aDataItems[$iIndex]['object_privacy_view'] = BX_DOL_PG_ALL;
+
+        return $aDataItems;
+    }
+
+    /**
+     * Notification about new invitation to join the group
+     */
+    public function serviceGetNotificationsJoinInvitation($aEvent)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $iContentId = (int)$aEvent['object_id'];
+        $oGroupProfile = BxDolProfile::getInstanceByContentAndType((int)$iContentId, $this->getName());
+        if(!$oGroupProfile)
+            return array();
+
+        $aContentInfo = $this->_oDb->getContentInfoById($iContentId);
+        if(empty($aContentInfo) || !is_array($aContentInfo))
+            return array();
+
+        /*
+         * It's essential that 'object_owner_id' contains invited member profile id.
+         */
+        $oProfile = BxDolProfile::getInstance((int)$aEvent['object_owner_id']);
+        if(!$oProfile)
+            return array();
+
+        /*
+         * Note. Group Profile URL is used for both Entry and Subentry URLs, 
+         * because Subentry URL has higher display priority and notification
+         * should be linked to Group Profile (Group Profile -> Members tab) 
+         * instead of Personal Profile of invited member.
+         */
+        $sEntryUrl = bx_absolute_url(str_replace(BX_DOL_URL_ROOT, '', $oGroupProfile->getUrl()), '{bx_url_root}');
+
+        return array(
+            'entry_sample' => $CNF['T']['txt_sample_single'],
+            'entry_url' => $sEntryUrl,
+            'entry_caption' => $oGroupProfile->getDisplayName(),
+            'subentry_sample' => $oProfile->getDisplayName(),
+            'subentry_url' => $sEntryUrl,
+            'lang_key' => $this->_oConfig->CNF['T']['txt_ntfs_join_invitation']
+        );
+    }
+
+    /**
+     * Notification about new member requst in the group
+     */
+    public function serviceGetNotificationsJoinRequest($aEvent)
+    {
+        return $this->_serviceGetNotification($aEvent, 'join_request', $this->_oConfig->CNF['T']['txt_ntfs_join_request']);
+    }
+
+	/**
+     * Notification about new member in the group
+     */
+    public function serviceGetNotificationsFanAdded($aEvent)
+    {
+        return $this->_serviceGetNotification($aEvent, 'fan_added', $this->_oConfig->CNF['T']['txt_ntfs_fan_added']);
+    }
+
+    protected function _serviceGetNotification($aEvent, $sType, $sLangKey)
+    {
+    	$CNF = &$this->_oConfig->CNF;
+
+        $iContentId = (int)$aEvent['object_id'];
+        $oGroupProfile = BxDolProfile::getInstanceByContentAndType((int)$iContentId, $this->getName());
+        if(!$oGroupProfile)
+            return array();
+
+        $aContentInfo = $this->_oDb->getContentInfoById($iContentId);
+        if(empty($aContentInfo) || !is_array($aContentInfo))
+            return array();
+
+        $oProfile = BxDolProfile::getInstance((int)$aEvent['subobject_id']);
+        if(!$oProfile)
+            return array();
+
+        $iGroupProfileId = $oGroupProfile->id();
+
+        /*
+         * Note. Group Profile URL is used for both Entry and Subentry URLs, 
+         * because Subentry URL has higher display priority and notification
+         * should be linked to Group Profile (Group Profile -> Members tab or Manage page) 
+         * instead of Personal Profile of a member, who performed an action.
+         */
+        if($sType == 'join_request' && !empty($CNF['URL_ENTRY_MANAGE']))
+            $sEntryUrl = bx_absolute_url(BxDolPermalinks::getInstance()->permalink($CNF['URL_ENTRY_MANAGE'], [
+                'profile_id' => $iGroupProfileId
+            ]), '{bx_url_root}');
+        else if(!empty($CNF['URL_ENTRY_FANS']))
+            $sEntryUrl = bx_absolute_url(BxDolPermalinks::getInstance()->permalink($CNF['URL_ENTRY_FANS'], [
+                'profile_id' => $iGroupProfileId
+            ]), '{bx_url_root}');
+        else
+            $sEntryUrl = bx_absolute_url(str_replace(BX_DOL_URL_ROOT, '', $oGroupProfile->getUrl()), '{bx_url_root}');
+
+        return [
+            'entry_sample' => $CNF['T']['txt_sample_single'],
+            'entry_url' => $sEntryUrl,
+            'entry_caption' => $oGroupProfile->getDisplayName(),
+            'entry_author' => $iGroupProfileId,
+            'subentry_sample' => $oProfile->getDisplayName(),
+            'subentry_url' => $sEntryUrl,
+            'lang_key' => $sLangKey
+        ];
+    }
+
+    /**
+     * Data for Reputation module
+     */
+    public function serviceGetReputationData()
+    {
+        $sModule = $this->_aModule['name'];
+
+        $aResult = parent::serviceGetReputationData();
+
+        $bHandlers = !empty($aResult['handlers']) && is_array($aResult['handlers']);
+        $bAlerts = !empty($aResult['alerts']) && is_array($aResult['alerts']);
+
+        /**
+         * Add Connections related handlers/alerts.
+         */
+        if($bHandlers)
+            $aResult['handlers'] = array_merge($aResult['handlers'], [
+                ['group' => $sModule . '_fan', 'type' => 'insert', 'alert_unit' => $sModule . '_fans', 'alert_action' => 'connection_added', 'points_active' => 1, 'points_passive' => 0],
+                ['group' => $sModule . '_fan', 'type' => 'delete', 'alert_unit' => $sModule . '_fans', 'alert_action' => 'connection_removed', 'points_active' => -1, 'points_passive' => 0]
+            ]);
+
+        if($bAlerts)
+            $aResult['alerts'] = array_merge($aResult['alerts'], [
+                ['unit' => $sModule . '_fans', 'action' => 'connection_added'],
+                ['unit' => $sModule . '_fans', 'action' => 'connection_removed']
+            ]);
+
+        /**
+         * Remove Comments and Reactions related handlers/alerts because these actions aren't available in Contexts for now.
+         */
+        if($bHandlers)
+            foreach($aResult['handlers'] as $iKey => $aHandler)
+                if(in_array($aHandler['group'], [$sModule . '_comment', $sModule . '_reaction']))
+                    unset($aResult['handlers'][$iKey]);
+
+        if($bAlerts)
+            foreach($aResult['alerts'] as $iKey => $aAlert)
+                if($aAlert['unit'] == $sModule . '_reactions' || in_array($aAlert['action'], ['commentPost', 'commentRemoved']))
+                    unset($aResult['alerts'][$iKey]);
+
+        return $aResult;
+    }
+
+    /**
+     * Data for Timeline module
+     */
+    public function serviceGetTimelineData()
+    {
+        $aResult = BxBaseModGeneralModule::serviceGetTimelineData();
+
+        $sModule = $this->_aModule['name'];
+        $aResult['handlers'] = array_merge($aResult['handlers'], [
+            ['group' => $sModule . '_object', 'type' => 'update', 'alert_unit' => $sModule, 'alert_action' => 'context_cover_changed'],
+            ['group' => $sModule . '_object', 'type' => 'update', 'alert_unit' => $sModule, 'alert_action' => 'context_cover_deleted']
+        ]);
+        $aResult['alerts'] = array_merge($aResult['alerts'], [
+            ['unit' => $sModule, 'action' => 'context_cover_changed'],
+            ['unit' => $sModule, 'action' => 'context_cover_deleted']
+        ]);
+
+        return $aResult;
+    }
+
+    /**
+     * Entry post for Timeline module
+     */
+    public function serviceGetTimelinePost($aEvent, $aBrowseParams = array())
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $a = parent::serviceGetTimelinePost($aEvent, $aBrowseParams);
+        if($a === false)
+            return false;
+
+        $oGroupProfile = BxDolProfile::getInstanceByContentAndType($aEvent['object_id'], $this->getName());
+        $a['content']['url'] = $oGroupProfile->getUrl();
+        $a['content']['title'] = $oGroupProfile->getDisplayName();
+        
+        $oConnection = BxDolConnection::getObjectInstance($CNF['OBJECT_CONNECTIONS']);
+        if($oConnection)
+            $a['content']['members'] = $oConnection->getConnectedInitiatorsCount($oGroupProfile->id(), true);
+
+        if(isset($aEvent['object_privacy_view']))
+            $a['content']['visibility'] = $aEvent['object_privacy_view'];
+
+        if(isset($CNF['FIELD_PUBLISHED'])) {
+            $aContentInfo = $this->_oDb->getContentInfoById($aEvent['object_id']);
+            if($aContentInfo[$CNF['FIELD_PUBLISHED']] > $a['date'])
+                $a['date'] = $aContentInfo[$CNF['FIELD_PUBLISHED']];
+        }
+
+        return $a;
+    }
+
+
+    // ====== PERMISSION METHODS
+    /**
+     * @return CHECK_ACTION_RESULT_ALLOWED if access is granted or error message if access is forbidden.
+     */
+    public function checkAllowedUsePaidJoin($isPerformAction = false)
+    {
+        // check ACL
+        $aCheck = checkActionModule($this->_iProfileId, 'use paid join', $this->getName(), $isPerformAction);
+        if($aCheck[CHECK_ACTION_RESULT] !== CHECK_ACTION_RESULT_ALLOWED)
+            return $aCheck[CHECK_ACTION_MESSAGE];
+
+        return CHECK_ACTION_RESULT_ALLOWED;
+    }
+
+    /**
+     * @return CHECK_ACTION_RESULT_ALLOWED if access is granted or error message if access is forbidden.
+     */
+    public function checkAllowedView ($aDataEntry, $isPerformAction = false)
+    {
+        return $this->serviceCheckAllowedViewForProfile ($aDataEntry, $isPerformAction);
+    }
+
+    public function serviceCheckAllowedViewForProfile ($aDataEntry, $isPerformAction = false, $iProfileId = false)
+    {
+        $CNF = &$this->_oConfig->CNF;
+        
+        $iGroupContentId = (int)$aDataEntry[$CNF['FIELD_ID']];
+
+        $bInvited = false;
+        if(!empty($CNF['TABLE_INVITES'])) {
+            $iGroupProfileId = BxDolProfile::getInstanceByContentAndType($iGroupContentId, $this->getName())->id();
+
+            if(($sKey = bx_get('key')) !== false) {
+                $mixedInvited = $this->isInvited($sKey, $iGroupProfileId);
+                if($mixedInvited === true)
+                    $bInvited = true;
+            }
+            else {
+                $mixedInvited = $this->isInvitedByProfileId($iProfileId ? $iProfileId : bx_get_logged_profile_id(), $iGroupProfileId);
+                if($mixedInvited === true)
+                    $bInvited = true;
+            }
+        }
+
+        if ($this->isFan($iGroupContentId, $iProfileId) || $bInvited)
+            return CHECK_ACTION_RESULT_ALLOWED;
+
+        return parent::serviceCheckAllowedViewForProfile ($aDataEntry, $isPerformAction, $iProfileId);
+    }
+
+    /**
+     * @return CHECK_ACTION_RESULT_ALLOWED if access is granted or error message if access is forbidden.
+     */
+    public function checkAllowedCompose(&$aDataEntry, $isPerformAction = false)
+    {
+        if(!$this->isFan($aDataEntry[$this->_oConfig->CNF['FIELD_ID']]))
+            return _t('_sys_txt_access_denied');
+
+        return parent::checkAllowedCompose ($aDataEntry, $isPerformAction);
+    }
+
+    public function checkAllowedFans(&$aDataEntry, $isPerformAction = false)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        if(($sMsg = $this->checkAllowedView($aDataEntry)) !== CHECK_ACTION_RESULT_ALLOWED)
+            return $sMsg;
+
+        return $this->_checkAllowedConnect($aDataEntry, $isPerformAction, [$CNF['OBJECT_GRID_CONNECTIONS'], 'checkAllowedConnectByAcl'], false, false);
+    }
+
+    /**
+     * @return CHECK_ACTION_RESULT_ALLOWED if access is granted or error message if access is forbidden.
+     */
+    public function checkAllowedFanAdd(&$aDataEntry, $isPerformAction = false)
+    {
+        $mixedResult = $this->_modGroupsCheckAllowedFanAdd($aDataEntry, $isPerformAction);
+
+        /**
+         * @hooks
+         * @hookdef hook-system-check_allowed_fan_add 'system', 'check_allowed_fan_add' - hook to override the result of checking whether 'fan add' to context action is allowed or not to currently logged in user
+         * - $unit_name - equals `system`
+         * - $action - equals `check_allowed_fan_add`
+         * - $object_id - not used
+         * - $sender_id - not used
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `module` - [string] module name
+         *      - `content_info` - [array] context info array as key&value pairs
+         *      - `profile_id` - [int] currently logged in profile id to be checked the availability of the action to
+         *      - `override_result` - [string] or [int] by ref, check action result, can be overridden in hook processing. Return string with an error if action isn't allowed or CHECK_ACTION_RESULT_ALLOWED, @see BxDolAcl
+         * @hook @ref hook-system-check_allowed_fan_add
+         */
+        bx_alert('system', 'check_allowed_fan_add', 0, 0, [
+            'module' => $this->getName(), 
+            'content_info' => $aDataEntry, 
+            'profile_id' => bx_get_logged_profile_id(), 
+            'override_result' => &$mixedResult
+        ]);
+
+        return $mixedResult;
+    }
+
+    public function _modGroupsCheckAllowedFanAdd (&$aDataEntry, $isPerformAction = false)
+    {
+        if ($this->isFan($aDataEntry[$this->_oConfig->CNF['FIELD_ID']]) || !isLogged())
+            return _t('_sys_txt_access_denied');
+
+        return $this->_checkAllowedConnect ($aDataEntry, $isPerformAction, $this->_oConfig->CNF['OBJECT_CONNECTIONS'], false, false);
+    }
+
+    /**
+     * @return CHECK_ACTION_RESULT_ALLOWED if access is granted or error message if access is forbidden.
+     */
+    public function checkAllowedFanRemove (&$aDataEntry, $isPerformAction = false)
+    {
+        if (CHECK_ACTION_RESULT_ALLOWED === $this->_checkAllowedConnect ($aDataEntry, $isPerformAction, $this->_oConfig->CNF['OBJECT_CONNECTIONS'], false, true, true))
+            return CHECK_ACTION_RESULT_ALLOWED;
+        return $this->_checkAllowedConnect ($aDataEntry, $isPerformAction, $this->_oConfig->CNF['OBJECT_CONNECTIONS'], false, true, false);
+    }
+
+    protected function _checkAllowedActionByFan($sAction, $aDataEntry, $iProfileId = 0)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $bRoles = $this->_oConfig->isRoles();
+        if(empty($iProfileId))
+            $iProfileId = bx_get_logged_profile_id();
+
+        $oGroupProfile = BxDolProfile::getInstanceByContentAndType($aDataEntry[$CNF['FIELD_ID']], $this->getName());
+        if(!$oGroupProfile)
+            return $sAction == BX_BASE_MOD_GROUPS_ACTION_DELETE ? CHECK_ACTION_RESULT_ALLOWED : _t('_sys_txt_not_found');
+
+        $iGroupProfileId = $oGroupProfile->id();
+
+        if(!$bRoles && $this->_oDb->isAdmin($iGroupProfileId, $iProfileId, $aDataEntry))
+            return CHECK_ACTION_RESULT_ALLOWED;
+
+        if($bRoles && $this->isAllowedActionByRole($sAction, $aDataEntry, $iGroupProfileId, $iProfileId))
+            return CHECK_ACTION_RESULT_ALLOWED;
+
+        return _t('_sys_txt_access_denied');
+    }
+
+    public function isAllowedActionByRole($mAction, $aDataEntry, $iGroupProfileId, $iProfileId)
+    {
+        $iProfileRole = $this->_oDb->getRole($iGroupProfileId, $iProfileId);
+
+        if (is_array($mAction)) {
+            $sAction = $mAction['action'];
+            $sActionModule = $mAction['module'];
+        } else {
+            $sAction = $mAction;
+            $sActionModule = $this->getName();
+        }
+
+        $bResult = false;
+        if($iProfileId)
+            $bResult = $this->isAllowedModuleActionByRole($sActionModule, $sAction, $iProfileRole);
+
+        // in case neither of the profile's roles are having permissions set explicitly then fallback to an old way
+        if ($bResult === NULL) {
+            $bResult = false;
+            if($this->isFanByGroupProfileId($iGroupProfileId)) {
+                switch ($sAction) {
+                    case BX_BASE_MOD_GROUPS_ACTION_DELETE:
+                    case BX_BASE_MOD_GROUPS_ACTION_EDIT:
+                    case BX_BASE_MOD_GROUPS_ACTION_CHANGE_SETTINGS:
+                    case BX_BASE_MOD_GROUPS_ACTION_CHANGE_COVER:
+                    case BX_BASE_MOD_GROUPS_ACTION_MANAGE_ROLES:
+                        if($this->isRole($iProfileRole, BX_BASE_MOD_GROUPS_ROLE_ADMINISTRATOR)) 
+                            $bResult = true;
+                        break;
+
+                    case BX_BASE_MOD_GROUPS_ACTION_MANAGE_FANS:
+                    case BX_BASE_MOD_GROUPS_ACTION_INVITE:
+                    case BX_BASE_MOD_GROUPS_ACTION_EDIT_CONTENT:
+                    case BX_BASE_MOD_GROUPS_ACTION_DELETE_CONTENT:
+                    case BX_BASE_MOD_GROUPS_ACTION_TIMELINE_POST_PIN:
+                        if($this->isRole($iProfileRole, BX_BASE_MOD_GROUPS_ROLE_ADMINISTRATOR) || $this->isRole($iProfileRole, BX_BASE_MOD_GROUPS_ROLE_MODERATOR)) 
+                            $bResult = true;
+                        break;
+
+                    default:
+                        $bResult = true;
+                }
+            }
+        }
+
+        // in case current user is not allowed to edit/delete this group then
+        // if it is a subgroup inside a context then give to the admin roles of a parent context the ability to edit/delete that subgroup.
+        if (
+            !$bResult &&
+            ($sAction == BX_BASE_MOD_GROUPS_ACTION_EDIT || $sAction == BX_BASE_MOD_GROUPS_ACTION_DELETE) &&
+            isset($this->_oConfig->CNF['FIELD_ALLOW_VIEW_TO']) &&
+            $this->_oConfig->CNF['FIELD_ALLOW_VIEW_TO'] &&
+            isset($aDataEntry[$this->_oConfig->CNF['FIELD_ALLOW_VIEW_TO']]) &&
+            $aDataEntry[$this->_oConfig->CNF['FIELD_ALLOW_VIEW_TO']] < 0)
+        {
+            $iParentContextProfileId = -$aDataEntry[$this->_oConfig->CNF['FIELD_ALLOW_VIEW_TO']];
+            $oParentContext = BxDolProfile::getInstance($iParentContextProfileId);
+            if ($oParentContext) {
+                $sCheckAction = $sAction == BX_BASE_MOD_GROUPS_ACTION_EDIT ? BX_BASE_MOD_GROUPS_ACTION_EDIT_CONTENT : BX_BASE_MOD_GROUPS_ACTION_DELETE_CONTENT;
+                $aParentDataEntry = bx_srv($oParentContext->getModule(), 'get_info', [$oParentContext->getContentId(), false]);
+                return $this->isAllowedActionByRole(['action' => $sCheckAction, 'module' => $oParentContext->getModule()], $aParentDataEntry, $iParentContextProfileId, $iProfileId);
+            }
+        }
+
+        /**
+         * @hooks
+         * @hookdef hook-system-check_allowed_action_by_role 'system', 'check_allowed_action_by_role' - hook to override the result of checking whether an action is allowed or not to context member by his role in the context
+         * - $unit_name - equals `system`
+         * - $action - equals `check_allowed_action_by_role`
+         * - $object_id - not used
+         * - $sender_id - not used
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `module` - [string] module name
+         *      - `multi_roles` - [boolean] whether multi roles are enabled in context or not
+         *      - `action` - [string] action to be checked
+         *      - `action_module` - [string] module name which the action belongs to
+         *      - `content_profile_id` - [int] context profile id
+         *      - `content_info` - [array] context info array as key&value pairs
+         *      - `profile_id` - [int] profile id to be checked the availability of the action to
+         *      - `profile_role` - [int] profile role in the context
+         *      - `override_result` - [boolean] by ref, check action result, can be overridden in hook processing.
+         * @hook @ref hook-system-check_allowed_action_by_role
+         */
+        bx_alert('system', 'check_allowed_action_by_role', 0, 0, [
+            'module' => $this->getName(), 
+            'multi_roles' => $this->_oConfig->isMultiRoles(),
+            'action' => $sAction,
+            'action_module' => $sActionModule,
+            'content_profile_id' => $iGroupProfileId, 
+            'content_info' => $aDataEntry, 
+            'profile_id' => $iProfileId, 
+            'profile_role' => $iProfileRole,
+            'override_result' => &$bResult
+        ]);
+
+        return $bResult;
+    }
+
+    public function isAllowedModuleActionByRole($sModule, $sAction, $iProfileRole)
+    {
+        if(($aRoles = $this->_oConfig->getRolesData()) && is_array($aRoles))
+            foreach ($aRoles as $iRole => $aRoleData) {
+                if(($iRole == 0 && $iProfileRole == 0) || ($iRole > 0 && $this->isRole($iProfileRole, $iRole))) {
+                    $mPermissions = !empty($aRoleData['Data']) ? unserialize($aRoleData['Data']) : false;
+                    if($mPermissions && isset($mPermissions[$sModule]))
+                        return isset($mPermissions[$sModule][$sAction]) && $mPermissions[$sModule][$sAction];
+                }
+            }
+
+        return NULL;
+    }
+
+    public function isAllowedModuleActionByProfile($iContentId, $sPostModule, $sAction, $iProfileId = 0) {
+        if (!$iProfileId) $iProfileId = bx_get_logged_profile_id();
+
+        if ($iProfileId && $this->isFan($iContentId, $iProfileId)) {
+            $sModuleName = $this->getName();
+            $oGroupProfile = BxDolProfile::getInstanceByContentAndType($iContentId, $sModuleName);
+            $aDataEntry = $this->_oDb->getContentInfoById($iContentId);
+            $bResult = $this->isAllowedActionByRole(['action' => $sAction, 'module' => $sPostModule], $aDataEntry, $oGroupProfile->id(), $iProfileId);
+
+            if ($bResult === true) return CHECK_ACTION_RESULT_ALLOWED;
+            if ($bResult === false) return _t('_sys_txt_access_denied');
+        }
+
+        return NULL; //undefined, because the profile is either not a fan or his role is not having permissions defined. So process the default way then.
+    }
+
+    public function isRole($iProfileRole, $iRole)
+    {
+        if(!$this->_oConfig->isMultiRoles())
+            return $iProfileRole == $iRole;
+        else 
+            return $iProfileRole & (1 << ($iRole - 1));
+    }
+
+    public function serviceIsRole($iProfileRole, $iRole)
+    {
+        return $this->isRole($iProfileRole, $iRole);
+    }
+
+    public function checkAllowedManageFans($mixedDataEntry, $isPerformAction = false)
+    {
+        $aDataEntry = array();
+        if(!is_array($mixedDataEntry)) {
+            $oGroupProfile = BxDolProfile::getInstance((int)$mixedDataEntry);
+            if($oGroupProfile && $this->getName() == $oGroupProfile->getModule())
+                $aDataEntry = $this->_oDb->getContentInfoById($oGroupProfile->getContentId());
+        }
+        else
+            $aDataEntry = $mixedDataEntry;
+
+        if($this->_checkAllowedActionByFan(BX_BASE_MOD_GROUPS_ACTION_MANAGE_FANS, $aDataEntry) === CHECK_ACTION_RESULT_ALLOWED)
+            return CHECK_ACTION_RESULT_ALLOWED;
+
+        return parent::checkAllowedEdit($aDataEntry, $isPerformAction);
+    }
+
+    public function checkAllowedManageAdmins($mixedDataEntry, $isPerformAction = false)
+    {
+        $aDataEntry = array();
+        if(!is_array($mixedDataEntry)) {
+            $oGroupProfile = BxDolProfile::getInstance((int)$mixedDataEntry);
+            if($oGroupProfile && $this->getName() == $oGroupProfile->getModule())
+                $aDataEntry = $this->_oDb->getContentInfoById($oGroupProfile->getContentId());
+        }
+        else
+            $aDataEntry = $mixedDataEntry;
+
+        if($this->_checkAllowedActionByFan(BX_BASE_MOD_GROUPS_ACTION_MANAGE_ROLES, $aDataEntry) === CHECK_ACTION_RESULT_ALLOWED)
+            return CHECK_ACTION_RESULT_ALLOWED;
+
+        return parent::checkAllowedEdit($aDataEntry, $isPerformAction);
+    }
+
+    public function checkAllowedEdit($aDataEntry, $isPerformAction = false)
+    {
+        if($this->_checkAllowedActionByFan(BX_BASE_MOD_GROUPS_ACTION_EDIT, $aDataEntry) === CHECK_ACTION_RESULT_ALLOWED)
+            return CHECK_ACTION_RESULT_ALLOWED;
+
+        return parent::checkAllowedEdit($aDataEntry, $isPerformAction);
+    }
+
+    public function checkAllowedInvite($aDataEntry, $isPerformAction = false)
+    {
+        if($this->_checkAllowedActionByFan(BX_BASE_MOD_GROUPS_ACTION_INVITE, $aDataEntry) === CHECK_ACTION_RESULT_ALLOWED)
+            return CHECK_ACTION_RESULT_ALLOWED;
+
+        return parent::checkAllowedEdit($aDataEntry, $isPerformAction);
+    }
+
+    public function checkAllowedChangeCover($aDataEntry, $isPerformAction = false)
+    {
+        if($this->_checkAllowedActionByFan(BX_BASE_MOD_GROUPS_ACTION_CHANGE_COVER, $aDataEntry) === CHECK_ACTION_RESULT_ALLOWED)
+            return CHECK_ACTION_RESULT_ALLOWED;
+
+        return parent::checkAllowedChangeCover($aDataEntry, $isPerformAction);
+    }
+
+    public function checkAllowedChangeSettings($aDataEntry, $isPerformAction = false)
+    {
+        if($this->_checkAllowedActionByFan(BX_BASE_MOD_GROUPS_ACTION_CHANGE_SETTINGS, $aDataEntry) === CHECK_ACTION_RESULT_ALLOWED)
+            return CHECK_ACTION_RESULT_ALLOWED;
+
+        return parent::checkAllowedChangeSettings($aDataEntry, $isPerformAction);
+    }
+
+    public function checkAllowedDelete(&$aDataEntry, $isPerformAction = false)
+    {
+        if($this->_checkAllowedActionByFan(BX_BASE_MOD_GROUPS_ACTION_DELETE, $aDataEntry) === CHECK_ACTION_RESULT_ALLOWED)
+            return CHECK_ACTION_RESULT_ALLOWED;
+
+        return parent::checkAllowedDelete($aDataEntry, $isPerformAction);
+    }
+
+    public function checkAllowedJoin(&$aDataEntry, $isPerformAction = false)
+    {
+        if (bx_get('key')){
+            $sKey = bx_get('key');
+            $oGroupProfile = BxDolProfile::getInstanceByContentAndType($aDataEntry[$this->_oConfig->CNF['FIELD_ID']], $this->getName());
+            $aData = $this->_oDb->getInviteByKey($sKey, $oGroupProfile->id());
+            if (isset($aData['invited_profile_id']) && $aData['invited_profile_id'] == bx_get_logged_profile_id()){
+                return CHECK_ACTION_RESULT_ALLOWED;
+            }
+        }   
+        return _t('_sys_txt_access_denied');
+    }   
+
+    public function checkAllowedSubscribeAdd(&$aDataEntry, $isPerformAction = false)
+    {
+        $mixedResult = $this->_modGroupsCheckAllowedSubscribeAdd($aDataEntry, $isPerformAction);
+
+        /**
+         * @hooks
+         * @hookdef hook-system-check_allowed_subscribe_add 'system', 'check_allowed_subscribe_add' - hook to override the result of checking whether currently logged in user can subscribe (follow) the context or not
+         * - $unit_name - equals `system`
+         * - $action - equals `check_allowed_subscribe_add`
+         * - $object_id - not used
+         * - $sender_id - not used
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `module` - [string] module name
+         *      - `content_info` - [array] context info array as key&value pairs
+         *      - `profile_id` - [int] currently logged in profile id to be checked the availability of the action to
+         *      - `override_result` - [string] or [int] by ref, check action result, can be overridden in hook processing. Return string with an error if action isn't allowed or CHECK_ACTION_RESULT_ALLOWED, @see BxDolAcl
+         * @hook @ref hook-system-check_allowed_subscribe_add
+         */
+        bx_alert('system', 'check_allowed_subscribe_add', 0, 0, [
+            'module' => $this->getName(), 
+            'content_info' => $aDataEntry, 
+            'profile_id' => bx_get_logged_profile_id(), 
+            'override_result' => &$mixedResult
+        ]);
+
+        return $mixedResult;
+    }
+    
+    public function checkAllowedAddContent(&$aDataEntry, $isPerformAction = false)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $sErrAccessDenied = _t('_sys_txt_access_denied');
+
+        $sModule = $this->getName();
+        $iProfileId = bx_get_logged_profile_id();
+
+        $aContexts = BxDolService::call($sModule, 'get_participating_profiles', [$iProfileId]);
+        if(!in_array($aDataEntry['profile_id'], $aContexts))
+            return $sErrAccessDenied;
+
+        if(bx_srv($sModule, 'check_allowed_post_in_profile', [$aDataEntry[$CNF['FIELD_ID']]]) !== CHECK_ACTION_RESULT_ALLOWED)
+            return $sErrAccessDenied;
+
+        return CHECK_ACTION_RESULT_ALLOWED;
+    }
+
+    /**
+     * Note. Is mainly needed for internal usage. Access level is 'public' to allow outer calls from alerts.
+     */
+    public function _modGroupsCheckAllowedSubscribeAdd(&$aDataEntry, $isPerformAction = false)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        if(!$this->isFan($aDataEntry[$CNF['FIELD_ID']]) && (!isset($CNF['PARAM_SBS_WO_JOIN']) || getParam($CNF['PARAM_SBS_WO_JOIN']) != 'on'))
+            return _t('_sys_txt_access_denied');
+
+        return parent::_modProfileCheckAllowedSubscribeAdd($aDataEntry, $isPerformAction);
+    }
+
+    /**
+     * @deprecated since version 11.0.3 and can be removed in the next version.
+     */
+    public function _checkAllowedSubscribeAdd (&$aDataEntry, $isPerformAction = false)
+    {
+        return parent::checkAllowedSubscribeAdd ($aDataEntry, $isPerformAction);
+    }
+    
+    public function doAudit($iGroupProfileId, $iFanId, $sAction)
+    {
+        $oProfile = BxDolProfile::getInstance($iFanId);
+        
+        $iContentId = $oProfile->getContentId();
+        $sModule = $oProfile->getModule();
+        $oModule = BxDolModule::getInstance($sModule);
+        if (BxDolRequest::serviceExists($sModule, 'act_as_profile') && BxDolService::call($sModule, 'act_as_profile') && $oModule->_oConfig){
+            $CNF = $oModule->_oConfig->CNF;
+
+            $aContentInfo = BxDolRequest::serviceExists($sModule, 'get_all') ? BxDolService::call($sModule, 'get_all', array(array('type' => 'id', 'id' => $iContentId))) : array();
+        
+            $AuditParams = array(
+                'content_title' => (isset($CNF['FIELD_TITLE']) && isset($aContentInfo[$CNF['FIELD_TITLE']])) ? $aContentInfo[$CNF['FIELD_TITLE']] : '',
+                'context_profile_id' => $iGroupProfileId,
+                'context_profile_title' => BxDolProfile::getInstance($iGroupProfileId)->getDisplayName()
+            );
+        
+            bx_audit(
+                $iContentId, 
+                $sModule, 
+                $sAction,  
+                $AuditParams
+            );
+        }
+    }
+    
+    protected function _checkAllowedConnect (&$aDataEntry, $isPerformAction, $sObjConnection, $isMutual, $isInvertResult, $isSwap = false)
+    {
+        $sResult = $this->checkAllowedView($aDataEntry);
+
+        $oPrivacy = BxDolPrivacy::getObjectInstance($this->_oConfig->CNF['OBJECT_PRIVACY_VIEW']);
+
+        // when context is in another context
+        if ($aDataEntry[$this->_oConfig->CNF['FIELD_ALLOW_VIEW_TO']] < 0 && getParam('sys_check_fan_in_parent_context')) {
+            $oParent = BxDolProfile::getInstance(abs($aDataEntry[$this->_oConfig->CNF['FIELD_ALLOW_VIEW_TO']]));
+            $oModule = $oParent ? BxDolModule::getInstance($oParent->getModule()) : null;
+            if ($oModule && method_exists($oModule, 'isFan') && !$oModule->isFan($oParent->getContentId()))
+                return _t('_sys_txt_access_denied');
+        }
+
+        // if profile view isn't allowed but visibility is in partially visible groups 
+        // then display buttons to connect (befriend, join) to profile, 
+        // if other conditions (in parent::_checkAllowedConnect) are met as well
+        if (CHECK_ACTION_RESULT_ALLOWED !== $sResult && !in_array($aDataEntry[$this->_oConfig->CNF['FIELD_ALLOW_VIEW_TO']], array_merge($oPrivacy->getPartiallyVisiblePrivacyGroups(), array('s'))))
+            return $sResult;
+
+        return parent::_checkAllowedConnect ($aDataEntry, $isPerformAction, $sObjConnection, $isMutual, $isInvertResult, $isSwap);
+    }
+
+
+    // ====== COMMON METHODS
+    public function onUpdateImage($iContentId, $sFiledName, $sFiledValue, $iProfileId = 0)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $aContentInfo = $this->_oDb->getContentInfoById($iContentId);
+
+        $aField2Method = [
+            $CNF['FIELD_PICTURE'] => 'picture',
+            $CNF['FIELD_COVER'] => 'cover',
+        ];
+
+        bx_content_cache_del_by_prefix('sprofile_unit_vars:' . $aContentInfo['profile_id'] . ':');
+        bx_content_cache_del_by_prefix('menu_sys_toolbar_member_p' . $aContentInfo['profile_id']);
+
+        if(!empty($aField2Method[$sFiledName]))
+            /**
+             * @hooks
+             * @hookdef hook-bx_base_groups-context_picture_changed '{module_name}', 'context_picture_changed' - hook after context picture was changed
+             * - $unit_name - module name
+             * - $action - equals `context_picture_changed`
+             * - $object_id - context id
+             * - $sender_id - profile id who performed the action
+             * - $extra_params - array of additional params with the following array keys:
+             *      - `status` - [string] context status
+             *      - `status_admin` - [string] context admin status
+             *      - `privacy_view` - [int] or [string] privacy for view context action, @see BxDolPrivacy
+             *      - `cf` - [int] context's audience filter value
+             * @hook @ref hook-bx_base_groups-context_picture_changed
+             */
+            /**
+             * @hooks
+             * @hookdef hook-bx_base_groups-context_cover_changed '{module_name}', 'context_cover_changed' - hook after context cover was changed
+             * It's equivalent to @ref hook-bx_base_groups-context_picture_changed 
+             * @hook @ref hook-bx_base_groups-context_cover_changed
+             */
+            bx_alert($this->getName(), 'context_' . $aField2Method[$sFiledName] . '_changed', $iContentId, $iProfileId, $this->_alertParams($aContentInfo));
+    }
+
+    protected function _alertParams($aContentInfo)
+    {
+        $aParams = parent::_alertParams($aContentInfo);
+
+        $CNF = &$this->_oConfig->CNF;
+
+        if(!empty($CNF['FIELD_CF']) && isset($aContentInfo[$CNF['FIELD_CF']]))
+            $aParams['cf'] = $aContentInfo[$CNF['FIELD_CF']];
+
+        return $aParams;
+    }
+
+    public function alertAfterAdd($aContentInfo)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $iId = (int)$aContentInfo[$CNF['FIELD_ID']];
+        $iAuthorId = (int)$aContentInfo[$CNF['FIELD_AUTHOR']];
+
+        $sAction = 'added';
+        if(isset($CNF['FIELD_STATUS_ADMIN']) && isset($aContentInfo[$CNF['FIELD_STATUS_ADMIN']]) && $aContentInfo[$CNF['FIELD_STATUS_ADMIN']] == BX_BASE_MOD_GENERAL_STATUS_PENDING)
+            $sAction = 'deferred';        
+
+        $sModule = $this->getName();
+        $aParams = $this->_alertParams($aContentInfo);
+        /**
+         * @hooks
+         * @hookdef hook-system-prepare_alert_params 'system', 'prepare_alert_params' - hook to override alert (hook) params
+         * - $unit_name - equals `system`
+         * - $action - equals `prepare_alert_params`
+         * - $object_id - not used
+         * - $sender_id - not used
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `unit` - [string] unit name
+         *      - `action` - [string] by ref, action, can be overridden in hook processing
+         *      - `object_id` - [int] by ref, object id, can be overridden in hook processing
+         *      - `sender_id` - [int] by ref, action performer profile id, can be overridden in hook processing
+         *      - `extras` - [array] by ref, extra params array as key&value pairs, can be overridden in hook processing
+         * @hook @ref hook-system-prepare_alert_params
+         */
+        bx_alert('system', 'prepare_alert_params', 0, 0, [
+            'unit'=> $sModule, 
+
+            'action' => &$sAction, 
+            'object_id' => &$iId, 
+            'sender_id' => &$iAuthorId, 
+            'extras' => &$aParams,
+
+            'action_ref' => &$sAction, 
+            'object_id_ref' => &$iId, 
+            'sender_id_ref' => &$iAuthorId, 
+            'extras_ref' => &$aParams
+        ]);
+        /**
+         * @hooks
+         * @hookdef hook-bx_base_groups-added '{module_name}', 'added' - hook after context was added (published)
+         * - $unit_name - module name
+         * - $action - equals `added`
+         * - $object_id - context id
+         * - $sender_id - not used
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `status` - [string] context status
+         *      - `status_admin` - [string] context admin status
+         *      - `privacy_view` - [int] or [string] privacy for view context action, @see BxDolPrivacy
+         *      - `cf` - [int] context's audience filter value
+         * @hook @ref hook-bx_base_groups-added
+         */
+        /**
+         * @hooks
+         * @hookdef hook-bx_base_groups-deferred '{module_name}', 'deferred' - hook after context was added with pending approval status
+         * It's equivalent to @ref hook-bx_base_groups-added
+         * @hook @ref hook-bx_base_groups-deferred
+         */
+        bx_alert($sModule, $sAction, $iId, false, $aParams);
+
+        $this->_processModerationNotifications($aContentInfo);
+    }
+
+    public function addFollower ($iProfileId1, $iProfileId2)
+    {
+        $oConnectionFollow = BxDolConnection::getObjectInstance('sys_profiles_subscriptions');
+        if($oConnectionFollow && !$oConnectionFollow->isConnected($iProfileId1, $iProfileId2)){
+            $oConnectionFollow->addConnection($iProfileId1, $iProfileId2);
+            return true;
+        }
+        return false;
+    }
+    
+    public function isFan ($iContentId, $iProfileId = false) 
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $oGroupProfile = BxDolProfile::getInstanceByContentAndType($iContentId, $this->getName());
+        if($oGroupProfile && isset($CNF['OBJECT_CONNECTIONS']))
+            return ($oConnection = BxDolConnection::getObjectInstance($CNF['OBJECT_CONNECTIONS'])) && $oConnection->isConnected($iProfileId ? $iProfileId : bx_get_logged_profile_id(), $oGroupProfile->id(), true);
+
+        return false;
+    }
+
+    public function isFanByGroupProfileId ($iGroupProfileId, $iProfileId = false) 
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $oGroupProfile = BxDolProfile::getInstance($iGroupProfileId);
+        if($oGroupProfile && isset($CNF['OBJECT_CONNECTIONS']))
+            return ($oConnection = BxDolConnection::getObjectInstance($CNF['OBJECT_CONNECTIONS'])) && $oConnection->isConnected($iProfileId ? $iProfileId : bx_get_logged_profile_id(), $oGroupProfile->id(), true);
+
+        return false;
+    }
+
+    public function isInvited ($sKey, $iGroupProfileId) 
+    {
+        $CNF = &$this->_oConfig->CNF;
+        $aData = $this->_oDb->getInviteByKey($sKey,  $iGroupProfileId);
+        if (!isset($aData['invited_profile_id']))
+            return _t($CNF['T']['txt_invitation_popup_error_invitation_absent']);
+        
+        if ($aData['invited_profile_id'] != bx_get_logged_profile_id())
+            return _t($CNF['T']['txt_invitation_popup_error_wrong_user']);
+        
+        return true;
+    }
+
+    public function isInvitedByProfileId ($iProfileId, $iGroupProfileId) 
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $aData = $this->_oDb->getInviteByInvited($iProfileId,  $iGroupProfileId);
+        if (!isset($aData['invited_profile_id']))
+            return _t($CNF['T']['txt_invitation_popup_error_invitation_absent']);
+
+        if ($aData['invited_profile_id'] != bx_get_logged_profile_id())
+            return _t($CNF['T']['txt_invitation_popup_error_wrong_user']);
+
+        return true;
+    }
+
+    public function serviceIsInvited($iGroupProfileId, $iProfileId = false, $sKey = '')
+    {
+        if(!$iProfileId)
+            $iProfileId = bx_get_logged_profile_id();
+
+        if(empty($sKey) && ($sKey = bx_get('key')) !== false)
+            $sKey = bx_process_input($sKey);
+
+        $mixedInvited = false;
+        if(!empty($sKey))
+            $mixedInvited = $this->isInvited($sKey, $iGroupProfileId);
+        else if($iProfileId !== false)
+            $mixedInvited = $this->isInvitedByProfileId($iProfileId, $iGroupProfileId);
+
+        return $mixedInvited === true;
+    }
+
+    public function serviceIsNotInvited($iGroupProfileId, $iProfileId = false, $sKey = '')
+    {
+        return !$this->serviceIsInvited($iGroupProfileId, $iProfileId, $sKey);
+    }
+
+    public function serviceGetInvitedKey($iGroupProfileId, $iProfileId = false)
+    {
+        $sKey = '';
+        if(($sKey = bx_get('key')) !== false)
+            $sKey = bx_process_input($sKey);
+
+        if(!$sKey) {
+            if(!$iProfileId)
+                $iProfileId = bx_get_logged_profile_id();
+
+            if($iProfileId !== false) {
+                $aInvite = $this->_oDb->getInviteByInvited($iProfileId, $iGroupProfileId);
+                if(!empty($aInvite) && is_array($aInvite))
+                    $sKey = $aInvite['key'];
+            }
+        }
+
+        return $sKey;
+    }
+
+    public function getRole($iGroupProfileId, $iFanProfileId)
+    {
+        if(!$this->isFanByGroupProfileId($iGroupProfileId, $iFanProfileId))
+            return false;
+
+        return $this->_oDb->getRole($iGroupProfileId, $iFanProfileId);
+    }
+
+    public function setRole($iGroupProfileId, $iFanProfileId, $mixedRole, $mixedPeriod = false, $sOrder = '')
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        if(!$this->_oConfig->isMultiRoles() && is_array($mixedRole))
+            $mixedRole = reset($mixedRole);
+
+        if(!isset($CNF['OBJECT_CONNECTIONS']))
+            return false;
+
+        $oConnection = BxDolConnection::getObjectInstance($CNF['OBJECT_CONNECTIONS']);
+        $oGroupProfile = BxDolProfile::getInstance($iGroupProfileId);
+        if(!$oConnection || !$oGroupProfile)
+            return false;
+
+        if(!$oConnection->isConnected($iFanProfileId, $iGroupProfileId, true) && !$oConnection->addConnection($iFanProfileId, $iGroupProfileId))
+            return false;
+
+        if(!$this->_oDb->setRole($iGroupProfileId, $iFanProfileId, $mixedRole, $mixedPeriod, $sOrder))
+            return false;
+
+        $this->onSetRole($iGroupProfileId, $iFanProfileId, $mixedRole);
+
+        return true;
+    }
+
+    public function onSetRole($iGroupProfileId, $iFanProfileId, $mixedRole)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $iProfileId = bx_get_logged_profile_id();
+        $oGroupProfile = BxDolProfile::getInstance($iGroupProfileId);
+        $aGroupProfileInfo = $this->_oDb->getContentInfoById((int)$oGroupProfile->getContentId());
+        $aRoles = BxDolFormQuery::getDataItems($CNF['OBJECT_PRE_LIST_ROLES']);
+
+        // notify about admin status
+        if(!empty($CNF['EMAIL_FAN_SET_ROLE']) && $iFanProfileId != $iProfileId) {
+            $aSetRoles = is_array($mixedRole) ? $mixedRole : [$mixedRole];
+            $aRolesNames = [];
+            foreach ($aSetRoles as $iRole)
+                $aRolesNames[] = $aRoles[(int)$iRole];
+
+            sendMailTemplate($CNF['EMAIL_FAN_SET_ROLE'], 0, $iFanProfileId, array(
+                'EntryUrl' => $oGroupProfile->getUrl(),
+                'EntryTitle' => $oGroupProfile->getDisplayName(),
+                'Role' => implode(', ', $aRolesNames),
+            ), BX_EMAIL_NOTIFY);
+        }
+
+        /**
+         * @hooks
+         * @hookdef hook-bx_base_groups-set_role '{module_name}', 'set_role' - hook after 'set role' action was applied to context member
+         * - $unit_name - module name
+         * - $action - equals `set_role`
+         * - $object_id - context id
+         * - $sender_id - context profile id
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `object_author_id` - [int] context profile id
+         *      - `performer_id` - [int] performer profile id
+         *      - `fan_id` - [int] context member profile id
+         *      - `content` - [array] context info array as key&value pairs
+         *      - `role` - [int] or [array] role or an array of roles to be set
+         *      - `group_profile` - [int] context profile id
+         *      - `profile` - [int] performer profile id
+         * @hook @ref hook-bx_base_groups-set_role
+         */
+        bx_alert($this->getName(), 'set_role', $aGroupProfileInfo[$CNF['FIELD_ID']], $iGroupProfileId, array(
+            'object_author_id' => $iGroupProfileId,
+            'performer_id' => $iProfileId, 
+            'fan_id' => $iFanProfileId,
+
+            'content' => $aGroupProfileInfo, 
+            'role' => $mixedRole,
+
+            'group_profile' => $iGroupProfileId, 
+            'profile' => $iProfileId
+        ));
+
+        $this->doAudit($iGroupProfileId, $iFanProfileId, '_sys_audit_action_group_role_changed');
+    }
+
+    public function unsetRole($iGroupProfileId, $iFanProfileId)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        if(!isset($CNF['OBJECT_CONNECTIONS']))
+            return false;
+
+        $oConnection = BxDolConnection::getObjectInstance($CNF['OBJECT_CONNECTIONS']);
+        $oGroupProfile = BxDolProfile::getInstance($iGroupProfileId);
+        if(!$oConnection || !$oGroupProfile)
+            return false;
+
+        if($oConnection->isConnected($iFanProfileId, $iGroupProfileId, true) && !$oConnection->removeConnection($iFanProfileId, $iGroupProfileId))
+            return false;
+
+        $iRole = $this->_oDb->getRole($iGroupProfileId, $iFanProfileId);
+
+        if(!$this->_oDb->unsetRole($iGroupProfileId, $iFanProfileId))
+            return false;
+
+        $this->onUnsetRole($iGroupProfileId, $iFanProfileId, $iRole);
+
+        return true;
+    }
+
+    public function onUnsetRole($iGroupProfileId, $iFanProfileId, $iRole)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $iProfileId = bx_get_logged_profile_id();
+        $oGroupProfile = BxDolProfile::getInstance($iGroupProfileId);
+        $aGroupProfileInfo = $this->_oDb->getContentInfoById((int)$oGroupProfile->getContentId());
+
+        /**
+         * @hooks
+         * @hookdef hook-bx_base_groups-set_role '{module_name}', 'set_role' - hook after 'set role' action was applied to context member
+         * - $unit_name - module name
+         * - $action - equals `set_role`
+         * - $object_id - context id
+         * - $sender_id - context profile id
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `object_author_id` - [int] context profile id
+         *      - `performer_id` - [int] performer profile id
+         *      - `fan_id` - [int] context member profile id
+         *      - `content` - [array] context info array as key&value pairs
+         *      - `role` - [int] or [array] role or an array of roles to be set
+         *      - `group_profile` - [int] context profile id
+         *      - `profile` - [int] performer profile id
+         * @hook @ref hook-bx_base_groups-set_role
+         */
+        bx_alert($this->getName(), 'set_role', $aGroupProfileInfo[$CNF['FIELD_ID']], $iGroupProfileId, array(
+            'object_author_id' => $iGroupProfileId,
+            'performer_id' => $iProfileId, 
+            'fan_id' => $iFanProfileId,
+
+            'content' => $aGroupProfileInfo,
+            'role' => $iRole,
+
+            'group_profile' => $iGroupProfileId, 
+            'profile' => $iProfileId
+        ));
+
+        $this->doAudit($iGroupProfileId, $iFanProfileId, '_sys_audit_action_group_role_changed');
+    }
+
+    public function getGroupsByFan($iProfileId, $mixedRole = false)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        if(!isset($CNF['OBJECT_CONNECTIONS']))
+            return false;
+
+        if($mixedRole === false)
+            $mixedRole = BX_BASE_MOD_GROUPS_ROLE_COMMON;
+
+        if(!is_array($mixedRole))
+            $mixedRole = [$mixedRole];
+
+        $aResult = [];
+        foreach($mixedRole as $iRole) {
+            switch($iRole) {
+                case BX_BASE_MOD_GROUPS_ROLE_COMMON:
+                    $aIds = BxDolConnection::getObjectInstance($CNF['OBJECT_CONNECTIONS'])->getConnectedContent($iProfileId);
+                    break;
+
+                default:
+                    $aIds = $this->_oDb->getRoles([
+                        'type' => 'group_pids_by_fan_id', 
+                        'fan_id' => $iProfileId,
+                        'role' => $iRole
+                    ]);
+            }
+
+            $aResult = array_merge($aResult, $aIds);
+        }
+
+        return $aResult;
+    }
+
+    public function getMenuItemTitleByConnection($sConnection, $sAction, $iContentProfileId, $iInitiatorProfileId = 0)
+    {
+        $CNF = $this->_oConfig->getCNF();
+
+        $aResult = parent::getMenuItemTitleByConnection($sConnection, $sAction, $iContentProfileId, $iInitiatorProfileId);
+        if(!empty($aResult))
+            return $aResult;
+
+        $oConnection = BxDolConnection::getObjectInstance($sConnection);
+        if(!$oConnection)
+            return false;
+
+        if(!$iInitiatorProfileId)
+            $iInitiatorProfileId = bx_get_logged_profile_id();
+
+        $aResult = [];
+        if($oConnection->isConnectedNotMutual($iInitiatorProfileId, $iContentProfileId))
+            $aResult = [
+                'add' => _t(!empty($CNF['T']['menu_item_title_sm_join_requested']) ? $CNF['T']['menu_item_title_sm_join_requested'] : '_sys_menu_item_title_sm_join_requested'),
+                'remove' => _t(!empty($CNF['T']['menu_item_title_sm_leave_cancel']) ? $CNF['T']['menu_item_title_sm_leave_cancel'] : '_sys_menu_item_title_sm_leave_cancel'),
+            ];
+        else if($oConnection->isConnectedNotMutual($iContentProfileId, $iInitiatorProfileId))
+            $aResult = [
+                'add' => _t(!empty($CNF['T']['menu_item_title_sm_join_confirm']) ? $CNF['T']['menu_item_title_sm_join_confirm'] : '_sys_menu_item_title_sm_join_confirm'),
+                'remove' => _t(!empty($CNF['T']['menu_item_title_sm_leave_reject']) ? $CNF['T']['menu_item_title_sm_leave_reject'] : '_sys_menu_item_title_sm_leave_reject'),
+            ];
+        else if($oConnection->isConnected($iInitiatorProfileId, $iContentProfileId, true))
+            $aResult = [
+                'add' => '',
+                'remove' => _t(!empty($CNF['T']['menu_item_title_sm_leave']) ? $CNF['T']['menu_item_title_sm_leave'] : '_sys_menu_item_title_sm_leave'),
+            ];
+        else
+            $aResult = [
+                'add' => _t(!empty($CNF['T']['menu_item_title_sm_join']) ? $CNF['T']['menu_item_title_sm_join'] : '_sys_menu_item_title_sm_join'),
+                'remove' => '',
+            ];
+
+        return !empty($sAction) && isset($aResult[$sAction]) ? $aResult[$sAction] : $aResult;
+    }
+
+    protected function _getImagesForTimelinePost($aEvent, $aContentInfo, $sUrl, $aBrowseParams = array())
+    {
+        $CNF = &$this->_oConfig->CNF;
+        
+        $iImageId = 0;
+        $sImageMd = $sImageXl = '';
+        if(isset($CNF['FIELD_COVER']) && !empty($aContentInfo[$CNF['FIELD_COVER']])) {
+            $iImageId = (int)$aContentInfo[$CNF['FIELD_COVER']];
+            $sImageMd = $this->_oConfig->getImageUrl($iImageId, ['OBJECT_IMAGES_TRANSCODER_GALLERY']);
+            $sImageXl = $this->_oConfig->getImageUrl($iImageId, ['OBJECT_IMAGES_TRANSCODER_COVER']);
+        }
+
+        if($sImageXl == '' && isset($CNF['FIELD_PICTURE']) && !empty($aContentInfo[$CNF['FIELD_PICTURE']])) {
+            $iImageId = (int)$aContentInfo[$CNF['FIELD_PICTURE']];
+            $sImageMd = $this->_oConfig->getImageUrl($iImageId, ['OBJECT_IMAGES_TRANSCODER_GALLERY']);
+            $sImageXl = $this->_oConfig->getImageUrl($iImageId, ['OBJECT_IMAGES_TRANSCODER_COVER']);
+        }
+
+        if(empty($sImageXl))
+            return [];
+
+        $aImage = [
+            'id' => $iImageId, 
+            'url' => $sUrl, 
+            'src' => $sImageXl, 
+            'src_orig' => $sImageXl
+        ];
+
+        if(!empty($sImageMd))
+            $aImage['src_medium'] = $sImageMd;
+
+        return [
+            $aImage
+        ];
+    }
+
+    protected function _prepareProfileAndGroupProfile($iGroupProfileId, $iInitiatorId)
+    {
+        if (!($oGroupProfile = BxDolProfile::getInstance($iGroupProfileId)))
+            return array(0, 0, null);
+
+        if ($oGroupProfile->getModule() == $this->getName()) {
+            $iProfileId = $iInitiatorId;
+            $iGroupProfileId = $oGroupProfile->id();
+        } else {
+            $iProfileId = $oGroupProfile->id();
+            $iGroupProfileId = $iInitiatorId;
+        }
+
+        return array($iProfileId, $iGroupProfileId, $oGroupProfile);
+    }
+}
+
+/** @} */

+ 306 - 0
upgrade/files/15.0.0.B3-15.0.0.RC1/files/modules/base/profile/classes/BxBaseModProfileFormsEntryHelper.php

@@ -0,0 +1,306 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    BaseProfile Base classes for profile modules
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+/**
+ * Profile forms helper functions
+ */
+class BxBaseModProfileFormsEntryHelper extends BxBaseModGeneralFormsEntryHelper
+{
+    protected $_sAutoApproval = false;
+
+    public function __construct($oModule)
+    {
+        parent::__construct($oModule);
+
+        $CNF = &$this->_oModule->_oConfig->CNF;
+
+        $sAutoApproval = isset($CNF['PARAM_AUTOAPPROVAL']) ? getParam($CNF['PARAM_AUTOAPPROVAL']) : BX_DOL_PROFILE_ACTIVATE_ALWAYS;
+        $bAdministrator = BxDolAcl::getInstance()->isMemberLevelInSet(array(MEMBERSHIP_ID_ADMINISTRATOR));
+        if (isAdmin() || $bAdministrator)
+            $sAutoApproval = BX_DOL_PROFILE_ACTIVATE_ALWAYS;
+        $this->setAutoApproval($sAutoApproval);
+    }
+
+    public function isAutoApproval($sAction = BX_DOL_PROFILE_ACTIVATE_ALWAYS)
+    {
+        if ($this->_sAutoApproval == BX_DOL_PROFILE_ACTIVATE_ALWAYS || $this->_sAutoApproval == $sAction)
+            return true;
+        
+        return false;
+    }
+    
+    public function setAutoApproval($mValue)
+    {
+        if ($mValue === true)
+            $mValue = BX_DOL_PROFILE_ACTIVATE_ALWAYS;
+        
+        return ($this->_sAutoApproval = $mValue);
+    }
+
+    public function getObjectFormEdit ($sDisplay = false)
+    {
+        $CNF = &$this->_oModule->_oConfig->CNF;
+
+        $oForm = parent::getObjectFormEdit ($sDisplay);
+        if(!$oForm)
+            return $oForm;
+
+        //--- Edit Settings: Fill in tabs list
+        if(($sKey = 'OBJECT_FORM_ENTRY_DISPLAY_EDIT_SETTINGS') && isset($CNF[$sKey]) && $CNF[$sKey] == $sDisplay)
+            if(($sField = 'FIELD_STG_TABS') && !empty($CNF[$sField]) && !empty($oForm->aInputs[$CNF[$sField]]) && is_array($oForm->aInputs[$CNF[$sField]])) 
+                if(($sMenu = 'OBJECT_MENU_SUBMENU_VIEW_ENTRY') && !empty($CNF[$sMenu]) && ($oMenu = BxDolMenu::getObjectInstance($CNF[$sMenu])) !== false && ($aMenuItems = $oMenu->getQueryObject()->getMenuItems()))
+                    foreach($aMenuItems as $aMenuItem) {
+                        if($aMenuItem['name'] == 'more-auto' || (int)$aMenuItem['active'] == 0)
+                            continue;
+
+                        $oForm->aInputs[$CNF[$sField]]['values'][] = [
+                            'key' => $aMenuItem['name'],
+                            'value' => _t($aMenuItem['title'])
+                        ];
+                    }
+
+        return $oForm;
+    }
+
+    protected function _getProfileAndContentData ($iContentId)
+    {
+        $aContentInfo = $this->_oModule->_oDb->getContentInfoById($iContentId);
+        if(!$aContentInfo)
+            return array (false, false);
+
+        $oProfile = BxDolProfile::getInstanceMagic($aContentInfo['profile_id']);
+        return array($oProfile, $aContentInfo);
+    }
+
+    public function deleteData ($iContentId, $aContentInfo = false, $oProfile = null, $oForm = null)
+    {
+        if (!$aContentInfo)
+            list ($oProfile, $aContentInfo) = $this->_getProfileAndContentData($iContentId);
+
+        // delete profile with content
+        $oProfile = BxDolProfile::getInstance($aContentInfo['profile_id']);
+        if (!$oProfile->delete(false, true))
+            return _t('_sys_txt_error_entry_delete');
+
+        return '';
+    }
+
+    public function deleteDataService ($iContentId, $aContentInfo = false, $oProfile = null, $oForm = null)
+    {
+        return parent::deleteData ($iContentId, $aContentInfo, $oProfile, $oForm);
+    }
+
+    public function onDataDeleteAfter ($iContentId, $aContentInfo, $oProfile)
+    {
+        if($s = parent::onDataDeleteAfter($iContentId, $aContentInfo, $oProfile))
+            return $s;
+
+        $CNF = &$this->_oModule->_oConfig->CNF;
+
+        $bActAsProfile = BxDolService::call($oProfile->getModule(), 'act_as_profile');
+        if(($oPrivacyView = BxDolPrivacy::getObjectInstance($CNF['OBJECT_PRIVACY_VIEW'])) !== false && $bActAsProfile)
+            $oPrivacyView->deleteGroupCustomByProfileId($oProfile->id());
+
+        if(($oPrivacyPost = BxDolPrivacy::getObjectInstance($CNF['OBJECT_PRIVACY_POST'])) !== false) {
+            $oPrivacyPost->deleteGroupCustomByContentId($iContentId);
+
+            if($bActAsProfile)
+                $oPrivacyPost->deleteGroupCustomByProfileId($oProfile->id());
+        }
+
+        return '';
+    }
+
+    public function onDataEditBefore ($iContentId, $aContentInfo, &$aTrackTextFieldsChanges, &$oProfile, &$oForm)
+    {
+        $CNF = &$this->_oModule->_oConfig->CNF;
+
+        list ($oProfile, $aContentInfo) = $this->_getProfileAndContentData($iContentId);
+
+        $oEditedProfile = BxDolProfile::getInstanceMagic($aContentInfo['profile_id']);
+        
+        $sStatus = $oEditedProfile->getStatus();
+        if (!$this->isAutoApproval(BX_DOL_PROFILE_ACTIVATE_EDIT) && BX_PROFILE_STATUS_ACTIVE == $sStatus){
+            $aTrackTextFieldsChanges = array ();
+        }
+
+        foreach(['TITLE', 'BIRTHDAY', 'PICTURE', 'COVER', 'BADGE'] as $sIt)
+            if(($sField = 'FIELD_' . $sIt) && isset($CNF[$sField], $aContentInfo[$CNF[$sField]]))
+                $oForm->addTrackFields($CNF[$sField], $aContentInfo);
+    }
+
+    public function onDataEditAfter ($iContentId, $aContentInfo, $aTrackTextFieldsChanges, $oProfile, $oForm)
+    {
+        if($s = parent::onDataEditAfter($iContentId, $aContentInfo, $aTrackTextFieldsChanges, $oProfile, $oForm))
+            return $s;
+
+        $CNF = &$this->_oModule->_oConfig->CNF;
+
+        /*
+         * Load updated data.
+         */
+        $aContentInfo = $this->_oModule->_oDb->getContentInfoById($iContentId);
+       
+        // change profile to 'pending' only if profile is 'active' 
+        $oEditedProfile = BxDolProfile::getInstanceMagic($aContentInfo['profile_id']);
+        $sStatus = $oEditedProfile->getStatus();
+
+        if(!$this->isAutoApproval(BX_DOL_PROFILE_ACTIVATE_EDIT) && BX_PROFILE_STATUS_ACTIVE == $sStatus && !empty($aTrackTextFieldsChanges['changed_fields']))
+            $oEditedProfile->disapprove(BX_PROFILE_ACTION_AUTO, 0, $this->_oModule->serviceActAsProfile());
+
+        // process uploaded files
+        foreach(['PICTURE', 'COVER', 'BADGE'] as $sIt) {
+            $sField = 'FIELD_' . $sIt;
+            if(!isset($CNF[$sField]))
+                continue;
+
+            $oForm->processFiles($CNF[$sField], $iContentId, false);
+
+            if($this->_bIsApi)
+                $oForm->processFilesFlagsApi($CNF[$sField], $iContentId);
+
+            if(($aChanged = $oForm->isTrackFieldChanged($CNF[$sField], true)) !== false)
+                $oForm->processFileDeletion($CNF[$sField], $aChanged['old']);
+        }
+
+        if(isset($CNF['FIELD_ALLOW_POST_TO']) && !empty($aContentInfo[$CNF['FIELD_ALLOW_POST_TO']]) && ($oPrivacy = BxDolPrivacy::getObjectInstance($CNF['OBJECT_PRIVACY_POST'])) !== false)
+            $oPrivacy->reassociateGroupCustomWithContent($oProfile->id(), $iContentId, (int)$aContentInfo[$CNF['FIELD_ALLOW_POST_TO']]);
+
+        // update content filters
+        if(isset($CNF['FIELD_BIRTHDAY']) && $oForm->isTrackFieldChanged($CNF['FIELD_BIRTHDAY']))
+            BxDolContentFilter::getInstance()->updateValuesByProfile($oProfile->getInfo());
+
+        // reset profile switcher cache
+        if ($oEditedProfile->id() !== bx_get_logged_profile_id() && $oForm->isTrackFieldChanged($CNF['FIELD_TITLE']) || $oForm->isTrackFieldChanged($CNF['FIELD_PICTURE'])) {
+            bx_content_cache_del("profile_switcher_" . $oEditedProfile->getAccountId() . "_0");
+            bx_content_cache_del("profile_switcher_" . $oEditedProfile->getAccountId() . "_1");
+        }
+
+        bx_content_cache_del_by_prefix('sprofile_unit_vars:' . $oEditedProfile->id() . ':');
+
+        if(($oSockets = BxDolSockets::getInstance()) && $oSockets->isEnabled()) {
+            $aProfileData = BxDolProfile::getDataForPage($oEditedProfile);
+            $oSockets->sendEvent('profile', $aContentInfo['profile_id'], 'changed', json_encode($aProfileData));
+        }
+
+        return '';
+    }
+
+    public function onDataAddAfter ($iAccountId, $iContentId)
+    {
+        /*
+         * Add account and content association.
+         * Note. It should be done first to correctly get and use author's profile later.
+         */
+        $iProfileId = BxDolProfile::add(BX_PROFILE_ACTION_MANUAL, $iAccountId, $iContentId, BX_PROFILE_STATUS_PENDING, $this->_oModule->getName());
+        $oProfile = BxDolProfile::getInstance($iProfileId);
+
+        if($s = parent::onDataAddAfter($iAccountId, $iContentId))
+            return $s;
+
+        $CNF = &$this->_oModule->_oConfig->CNF;
+
+        /*
+         * Load updated data.
+         */
+        $aContentInfo = $this->_oModule->_oDb->getContentInfoById($iContentId);
+
+        /* 
+         * approve profile if auto-approval is enabled and profile status is 'pending'
+         * don't send Activation letter when 'Auto Approval' mode is enabled.
+         */
+        $sStatus = $oProfile->getStatus();
+        if ($sStatus == BX_PROFILE_STATUS_PENDING && $this->isAutoApproval(BX_DOL_PROFILE_ACTIVATE_ADD))
+            $oProfile->approve(BX_PROFILE_ACTION_AUTO, 0, false);
+
+        // set created profile some default membership
+        if ((int)bx_get('level_id') && bx_srv('bx_acl', 'get_prices', [(int)bx_get('level_id'), true]))
+            $iAclLevel = (int)bx_get('level_id');
+        else if(isset($CNF['PARAM_DEFAULT_ACL_LEVEL']))
+            $iAclLevel = isAdmin() && getLoggedId() == $iAccountId ? MEMBERSHIP_ID_ADMINISTRATOR : getParam($CNF['PARAM_DEFAULT_ACL_LEVEL']);
+        else
+            $iAclLevel = MEMBERSHIP_ID_STANDARD;
+
+        BxDolAcl::getInstance()->setMembership($iProfileId, $iAclLevel, 0, true);
+        
+        // process uploaded files
+        $oForm = $this->getObjectFormAdd();
+        if (isset($CNF['FIELD_PICTURE']))
+            $oForm->processFiles($CNF['FIELD_PICTURE'], $iContentId, true);
+        if (isset($CNF['FIELD_COVER']))
+            $oForm->processFiles($CNF['FIELD_COVER'], $iContentId, true);
+        if (isset($CNF['FIELD_BADGE']))
+            $oForm->processFiles($CNF['FIELD_BADGE'], $iContentId, true);
+
+        if(isset($CNF['FIELD_ALLOW_POST_TO']) && !empty($aContentInfo[$CNF['FIELD_ALLOW_POST_TO']]) && ($oPrivacy = BxDolPrivacy::getObjectInstance($CNF['OBJECT_PRIVACY_POST'])) !== false)
+            $oPrivacy->associateGroupCustomWithContent($oProfile->id(), $iContentId, (int)$aContentInfo[$CNF['FIELD_ALLOW_POST_TO']]);
+
+        // switch context to the created profile
+        if ($this->_oModule->serviceActAsProfile()) {
+            $oAccount = BxDolAccount::getInstance($iAccountId);
+            $oAccount->updateProfileContext($iProfileId);
+
+            //update recomedations
+            BxDolRecommendation::updateData($iProfileId, true);
+
+            // update content filters
+            BxDolContentFilter::getInstance()->updateValuesByProfile($oProfile->getInfo());
+        }
+
+        return '';
+    }
+
+    public function redirectAfterAdd($aContentInfo, $sUrl = '')
+    {
+        $CNF = &$this->_oModule->_oConfig->CNF;
+
+        $oSession = BxDolSession::getInstance();
+
+        $sRedirectType = empty($CNF['PARAM_REDIRECT_AADD']) ? BX_DOL_PROFILE_REDIRECT_PROFILE : getParam($CNF['PARAM_REDIRECT_AADD']);
+        $sRedirectDefault = 'page.php?i=' . $CNF['URI_VIEW_ENTRY'] . '&id=' . $aContentInfo[$CNF['FIELD_ID']];
+
+        $sRedirectUrl = $sRedirectDefault;
+        switch ($sRedirectType) {
+            case BX_DOL_PROFILE_REDIRECT_PROFILE:
+                break;
+
+            // if user just joined the redirect to the page where user comes from. 
+            case BX_DOL_PROFILE_REDIRECT_LAST:
+                $sJoinReferrer = $oSession->getValue('join-referrer');
+                if($sJoinReferrer) {
+                    $sRedirectUrl = $sJoinReferrer;
+                    $oSession->unsetValue('join-referrer');
+                }
+                break;
+
+            case BX_DOL_PROFILE_REDIRECT_CUSTOM:
+                $sRedirectCustom = getParam($CNF['PARAM_REDIRECT_AADD_CUSTOM_URL']);
+                if($sRedirectCustom) {
+                    $sRedirectUrl = $this->prepareCustomRedirectUrl($sRedirectCustom, $aContentInfo);
+                }
+                break;
+                
+            case BX_DOL_PROFILE_REDIRECT_HOMEPAGE:
+                $sRedirectUrl =  BX_DOL_URL_ROOT;  
+                break;
+        }
+
+        $sCustomReferrer = $oSession->getValue('custom-referrer');
+        if($sCustomReferrer) {
+            $sRedirectUrl = $sCustomReferrer;
+            $oSession->unsetValue('custom-referrer');
+        }
+
+        return parent::redirectAfterAdd($aContentInfo, $sRedirectUrl);
+    }
+}
+
+/** @} */

+ 2749 - 0
upgrade/files/15.0.0.B3-15.0.0.RC1/files/modules/base/profile/classes/BxBaseModProfileModule.php

@@ -0,0 +1,2749 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    BaseProfile Base classes for profile modules
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+define('BX_DOL_PROFILE_REDIRECT_PROFILE', 'profile');
+define('BX_DOL_PROFILE_REDIRECT_LAST', 'last');
+define('BX_DOL_PROFILE_REDIRECT_CUSTOM', 'custom');
+define('BX_DOL_PROFILE_REDIRECT_HOMEPAGE', 'homepage');
+
+define('BX_DOL_PROFILE_ACTIVATE_ALWAYS', 'on');
+define('BX_DOL_PROFILE_ACTIVATE_NEVER', 'off');
+define('BX_DOL_PROFILE_ACTIVATE_ADD', 'add');
+define('BX_DOL_PROFILE_ACTIVATE_EDIT', 'edit');
+
+/**
+ * Base class for profile modules.
+ */
+class BxBaseModProfileModule extends BxBaseModGeneralModule implements iBxDolContentInfoService, iBxDolProfileService
+{
+    protected $_iAccountId;
+
+    function __construct(&$aModule)
+    {
+        parent::__construct($aModule);
+
+        $CNF = &$this->_oConfig->CNF;
+
+        if(!empty($CNF['FIELD_ALLOW_POST_TO']))
+            $this->_aSearchableNamesExcept[] = $CNF['FIELD_ALLOW_POST_TO'];
+
+        if(!empty($CNF['FIELD_ALLOW_CONTACT_TO']))
+            $this->_aSearchableNamesExcept[] = $CNF['FIELD_ALLOW_CONTACT_TO'];
+
+        $this->_iAccountId = getLoggedId();
+    }
+
+    public function actionDeleteProfileImg($iFileId, $iContentId, $sFieldPicture) 
+    {
+        $aResult = array();
+        $CNF = &$this->_oConfig->CNF;
+
+        $oSrorage = BxDolStorage::getObjectInstance($CNF['OBJECT_STORAGE']);
+        if (!($aFile = $oSrorage->getFile((int)$iFileId)) || !($aContentInfo = $this->_oDb->getContentInfoById($iContentId)) || $aContentInfo[$sFieldPicture] != (int)$iFileId)
+            $aResult = array('error' => 1, 'msg' => _t('_sys_storage_err_file_not_found'));
+
+        $oAccountProfile = BxDolProfile::getInstanceAccountProfile();
+        if ($oAccountProfile)
+            $iAccountProfileId = $oAccountProfile->id();
+
+        if ((!$aResult && !isLogged()) || (!$aResult && $aFile['profile_id'] != $iAccountProfileId && !$this->_isModerator()))           
+            $aResult = array('error' => 2, 'msg' => _t('_Access denied'));
+
+        $oForm = BxDolForm::getObjectInstance($CNF['OBJECT_FORM_ENTRY'], $CNF['OBJECT_FORM_ENTRY_DISPLAY_ADD'], $this->_oTemplate);
+
+        if (!$aResult && !$oForm->_deleteFile($iContentId, $sFieldPicture, (int)$iFileId, true))
+            $aResult = array('error' => 3, 'msg' => _t('_Failed'));
+        elseif (!$aResult)            
+            $aResult = array('error' => 0, 'msg' => '');
+
+        header('Content-Type: application/json; charset=utf-8');
+        echo json_encode($aResult);
+    }
+	
+	public function actionProfileCalendarData()
+    {
+		$iProfileId = (int)bx_get('profile_id');
+        $aEntries = array();
+		$BxDolModuleQuery = BxDolModuleQuery::getInstance();
+        $aModules = $BxDolModuleQuery->getModulesBy(array('type' => 'modules', 'active' => 1));
+        foreach($aModules as $aModule){
+			$sModuleName = $aModule['name'];
+            $oModule = BxDolModule::getInstance($sModuleName);
+            if($oModule instanceof iBxDolCalendarService){
+				if(BxDolRequest::serviceExists($sModuleName, 'get_calendar_entries')){
+					$aEntries2 = BxDolService::call($sModuleName, 'get_calendar_entries', array($iProfileId));
+					$aEntries = array_merge($aEntries, $aEntries2);
+				}
+            }
+        }
+		
+        header('Content-Type: application/json; charset=utf-8');
+        echo json_encode($aEntries);
+    }
+    
+    public function actionEmbed($iContentId, $sUnitTemplate = '', $sAddCode = '')
+    {
+        return parent::actionEmbed($iContentId, 'unit_with_cover.html');
+    }
+
+    // ====== SERVICE METHODS
+
+    public function serviceGetSafeServices()
+    {
+        $a = parent::serviceGetSafeServices();
+        return array_merge($a, array (
+            'ProfileUnitSafe' => '',
+            'ProfileUrl' => '',
+            'EntityCreate' => '',
+            'BrowseRecommended' => '',
+            'BrowseRecentProfiles' => '',
+            'BrowseActiveProfiles' => '',
+            'BrowseTopProfiles' => '',
+            'BrowseOnlineProfiles' => '',
+            'BrowseConnections' => '',
+            'BrowseConnectionsEverywhere' => '',
+            'BrowseByAcl' => '',
+        ));
+    }
+
+    public function serviceGetOptionsRedirectAfterAdd()
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $aResult = array();
+        $aChoices = array(BX_DOL_PROFILE_REDIRECT_PROFILE, BX_DOL_PROFILE_REDIRECT_LAST, BX_DOL_PROFILE_REDIRECT_CUSTOM, BX_DOL_PROFILE_REDIRECT_HOMEPAGE);
+        foreach($aChoices as $sChoice) 
+            $aResult[] = array('key' => $sChoice, 'value' => _t($CNF['T']['option_redirect_aadd_' . $sChoice]));
+
+        return $aResult;
+    }
+    
+    public function serviceGetOptionsActivation()
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $aResult = array();
+        $aChoices = array(BX_DOL_PROFILE_ACTIVATE_ALWAYS, BX_DOL_PROFILE_ACTIVATE_NEVER, BX_DOL_PROFILE_ACTIVATE_ADD, BX_DOL_PROFILE_ACTIVATE_EDIT);
+        foreach($aChoices as $sChoice) 
+            $aResult[] = array('key' => $sChoice, 'value' => _t($CNF['T']['option_activation_' . $sChoice]));
+
+        return $aResult;
+    }
+
+    public function serviceGetThumb ($iContentId, $sTranscoder = '') 
+    {
+        $CNF = &$this->_oConfig->CNF;
+        
+        if(bx_is_api()){
+            $aContentInfo = $this->_oDb->getContentInfoById($iContentId);
+            return bx_api_get_image($CNF['OBJECT_STORAGE'], $aContentInfo[$CNF['FIELD_PICTURE']]);
+        }
+
+        if(empty($sTranscoder) && !empty($CNF['OBJECT_IMAGES_TRANSCODER_THUMB']))
+            $sTranscoder = $CNF['OBJECT_IMAGES_TRANSCODER_THUMB'];
+
+        $mixedResult = $this->_getFieldValueThumb('FIELD_PICTURE', $iContentId, $sTranscoder);
+        return $mixedResult !== false ? $mixedResult : '';
+    }
+    
+    public function serviceGetCover ($iContentId, $sTranscoder = '') 
+    {
+        $CNF = &$this->_oConfig->CNF;
+        
+        if(bx_is_api()){
+            $aContentInfo = $this->_oDb->getContentInfoById($iContentId);
+            $aTmp = bx_api_get_image($CNF['OBJECT_STORAGE'], $aContentInfo[$CNF['FIELD_COVER']]);
+            if (!$aTmp){
+                return ['storage' => $CNF['OBJECT_STORAGE']];
+            }
+            return $aTmp;
+        }
+
+        if(empty($sTranscoder) && !empty($CNF['OBJECT_IMAGES_TRANSCODER_COVER']))
+            $sTranscoder = $CNF['OBJECT_IMAGES_TRANSCODER_COVER'];
+
+        $mixedResult = $this->_getFieldValueThumb('FIELD_COVER', $iContentId, $sTranscoder);
+        return $mixedResult !== false ? $mixedResult : '';
+    }
+
+    public function serviceGetBadges($iContentId, $bIsSingle = false, $bIsCompact = false)
+    {
+        $mixedBadges = parent::serviceGetBadges($iContentId, $bIsSingle, $bIsCompact);
+
+        if(($mixedBadge = $this->_oTemplate->getBadge($iContentId))) {
+            if($this->_bIsApi)
+                $mixedBadges[] = $mixedBadge;
+            else
+                $mixedBadges = $mixedBadge . $mixedBadges;
+        }
+
+        return $mixedBadges;
+    }
+
+    public function serviceGetSearchResultUnit ($iContentId, $sUnitTemplate = '')
+    {
+        if(empty($sUnitTemplate))
+            $sUnitTemplate = 'unit_with_cover.html';
+
+        return parent::serviceGetSearchResultUnit($iContentId, $sUnitTemplate);
+    }
+
+    public function serviceGetSearchableFieldsExtended($aInputsAdd = array())
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $aResult = parent::serviceGetSearchableFieldsExtended($aInputsAdd);
+        if(!$this->serviceActAsProfile())
+            return $aResult;
+
+        if(!in_array('online', $this->_aSearchableNamesExcept))
+            $aResult['online'] = array(
+                'type' => 'checkbox', 
+                'caption' => $CNF['T']['form_field_online'],
+                'info' => '',
+            	'value' => '1',
+                'values' => '',
+                'pass' => ''
+            );
+
+        if(!empty($CNF['FIELD_PICTURE']) && !in_array($CNF['FIELD_PICTURE'], $this->_aSearchableNamesExcept))
+            $aResult[$CNF['FIELD_PICTURE']] = array(
+                'type' => 'checkbox', 
+                'caption' => $CNF['T']['form_field_picture'],
+                'info' => '',
+            	'value' => '1',
+                'values' => '',
+                'pass' => '',
+                'search_operator' => '>=' 
+            );
+
+        return $aResult;
+    }
+
+	
+	/**
+     * @page service Service Calls
+     * @section bx_base_profile Base Profile
+     * @subsection bx_base_profile-general General
+     * @subsubsection bx_base_profile-entity_calendar entity_calendar
+     * 
+     * @code bx_srv('bx_persons', 'entity_calendar', [...]); @endcode
+     * 
+     * Get calendar block
+     * @param $iContentId content ID
+     * 
+     * @see BxBaseModProfileModule::serviceEntityCalendar
+     */
+    /** 
+     * @ref bx_base_profile-entity_calendar "entity_calendar"
+     */
+	public function serviceEntityCalendar($iContentId = 0, $sTemplate = 'calendar.html')
+    {
+		$iContentId = $this->_getContent($iContentId, false);
+        $oProfile = BxDolProfile::getInstanceByContentAndType($iContentId, $this->_oConfig->getName());
+        if($oProfile){
+			$o = new BxTemplCalendar(array(
+				'eventSources' => array (
+					bx_append_url_params(BX_DOL_URL_ROOT . $this->_oConfig->getBaseUri() . 'profile_calendar_data', array('profile_id' => $oProfile->id())),
+				),
+        	), $this->_oTemplate);
+        	return $o->display($sTemplate);			     
+		}
+		return '';	
+    }
+	
+    public function servicePrivateProfileMsg()
+    {
+        $sMessage = '';
+
+        $mixedContent = $this->_getContent();
+        if($mixedContent) {
+            list($iContentId, $aContentInfo) = $mixedContent;
+            $sMessage = $this->checkAllowedView($aContentInfo);
+        }
+        else
+            $sMessage = MsgBox(_t('_sys_access_denied_to_private_content'));
+
+        return !$this->_bIsApi ? $sMessage : [bx_api_get_msg($sMessage, ['ext' => ['msg_type' => 'result']])];
+    }
+    
+    public function serviceGetContentInfoById($iContentId)
+    {
+        return $this->_oDb->getContentInfoById((int)$iContentId);
+    }
+    
+    public function serviceGetContentInfoByProfileId($iProfileId)
+    {
+        return $this->_oDb->getContentInfoByProfileId((int)$iProfileId);
+    }
+
+    public function serviceGetMenuAddonManageTools()
+    {
+        $CNF = &$this->_oConfig->CNF;
+        
+		$iNumTotal = $this->_oDb->getEntriesNumByParams();
+
+        $iNum1 = $this->_oDb->getEntriesNumByParams([
+            [
+                'key' => 'status', 
+                'table' => 'sys_profiles',
+                'value' => BX_PROFILE_STATUS_PENDING, 
+                'operator' => '='
+            ]
+        ]);
+        
+        $iNum2 = 0;
+        if (isset($CNF['OBJECT_REPORTS'])){
+            $iNum2 = $this->_oDb->getEntriesNumByParams([
+                [
+                    'key' => 'reports',
+                    'value' => '0', 
+                    'operator' => '>'
+                ]
+            ]);
+        }
+        
+        return array('counter1_value' => $iNum1, 'counter2_value' => $iNum2, 'counter3_value' => $iNumTotal, 'counter1_caption' => _t('_sys_menu_dashboard_manage_tools_addon_counter1_caption_profile_default'));
+    }
+
+    public function serviceGetMenuAddonManageToolsProfileStats($iProfileId = 0)
+    {
+        if(!$iProfileId)
+            $iProfileId = bx_get_logged_profile_id();
+
+        $aAccountInfo = BxDolProfileQuery::getInstance()->getAccountInfoByProfileId($iProfileId);
+        if(empty($aAccountInfo) || !is_array($aAccountInfo))
+            return 0;
+
+        bx_import('SearchResult', $this->_aModule);
+        $sClass = $this->_aModule['class_prefix'] . 'SearchResult';
+        $o = new $sClass();
+        $o->fillFilters([
+            'account_id' => $aAccountInfo['id'],
+            'perofileStatus' => ''
+        ]);
+        $o->unsetPaginate();
+
+        return $o->getNum();
+    }
+
+    public function serviceGetMenuAddonFavoritesProfileStats()
+    {
+    	bx_import('SearchResult', $this->_aModule);
+        $sClass = $this->_aModule['class_prefix'] . 'SearchResult';
+        $o = new $sClass('favorite', array('user' => bx_get_logged_profile_id()));
+        $o->unsetPaginate();
+
+        return $o->getNum();
+    }
+
+    public function serviceGetSubmenuObject ()
+    {
+        return $this->_oConfig->CNF['OBJECT_MENU_SUBMENU_VIEW_ENTRY'];
+    }
+
+    public function serviceGetMenuSetNameForMenuTrigger ($sMenuTriggerName)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        if (isset($CNF['TRIGGER_MENU_PROFILE_VIEW_SUBMENU']) && $CNF['TRIGGER_MENU_PROFILE_VIEW_SUBMENU'] == $sMenuTriggerName)
+            return $CNF['OBJECT_MENU_SUBMENU_VIEW_ENTRY'];
+        elseif (isset($CNF['TRIGGER_MENU_PROFILE_SNIPPET_META']) && $CNF['TRIGGER_MENU_PROFILE_SNIPPET_META'] == $sMenuTriggerName)
+            return $CNF['OBJECT_MENU_SNIPPET_META'];
+        else if (isset($CNF['TRIGGER_MENU_PROFILE_VIEW_ACTIONS']) && $CNF['TRIGGER_MENU_PROFILE_VIEW_ACTIONS'] == $sMenuTriggerName) {
+            if(empty($CNF['OBJECT_MENU_ACTIONS_VIEW_ENTRY_ALL']))
+                return $CNF['OBJECT_MENU_ACTIONS_VIEW_ENTRY'];
+            else
+                return array($CNF['OBJECT_MENU_ACTIONS_VIEW_ENTRY'], $CNF['OBJECT_MENU_ACTIONS_VIEW_ENTRY_ALL']);
+        }
+
+        return '';
+    }
+
+    public function serviceGetSnippetMenuVars($iProfileId, $bPublic = null, $aParams = [])
+    {
+        return $this->_oTemplate->getSnippetMenuVars($iProfileId, $bPublic, $aParams);
+    }
+
+    public function serviceGetPageObjectForPageTrigger ($sPageTriggerName)
+    {
+        if (isset($this->_oConfig->CNF['TRIGGER_PAGE_VIEW_ENTRY']) && $this->_oConfig->CNF['TRIGGER_PAGE_VIEW_ENTRY'] == $sPageTriggerName)
+        	return $this->_oConfig->CNF['OBJECT_PAGE_VIEW_ENTRY'];
+
+        return '';
+    }
+
+    public function serviceProfilesSearch ($sTerm, $mixedParams)
+    {
+        $aRet = [];
+
+        $a = $this->_oDb->searchByTerm($sTerm, $mixedParams);
+        foreach ($a as $r) {
+            $oProfile = BxDolProfile::getInstance($r['profile_id']);
+
+            if ($this->_bIsApi) {
+                $aData = $oProfile->getUnitAPI(0, ['template' => 'unit_wo_info']);
+                $aData['author_data']['label'] = $this->serviceProfileName($r['content_id']);
+
+                $aRet[] = $aData['author_data'];
+            }
+            else{
+                $aRet[] = [
+                    'label' => $this->serviceProfileName($r['content_id']), 
+                    'value' => $r['profile_id'], 
+                    'url' => $oProfile->getUrl(),
+                    'thumb' => $oProfile->getThumb(),
+                    'unit' => $oProfile->getUnit(0, ['template' => ['name' => 'unit_wo_info', 'size' => 'icon']])
+                ];
+            }
+        }
+
+        return $aRet;
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_base_profile Base Profile
+     * @subsection bx_base_profile-general General
+     * @subsubsection bx_base_profile-profile_unit_safe profile_unit_safe
+     * 
+     * @code bx_srv('bx_persons', 'profile_unit_safe', [...]); @endcode
+     * 
+     * Get profile unit
+     * @param $iContentId content ID
+     * 
+     * @see BxBaseModProfileModule::serviceProfileUnitSafe
+     */
+    /** 
+     * @ref bx_base_profile-profile_unit_safe "profile_unit_safe"
+     */
+    public function serviceProfileUnitSafe ($iContentId, $aParams = array())
+    {
+        unset($aParams['check_private_content']);
+        return $this->serviceProfileUnit ($iContentId, $aParams);
+    }
+
+    public function serviceProfileUnit ($iContentId, $aParams = [])
+    {
+        $mixedContent = $this->_getContent($iContentId);
+        if($mixedContent === false)
+            return false;
+
+        list($iContentId, $aContentInfo) = $mixedContent;
+
+        $bCheckPrivateContent = isset($aParams['check_private_content']) ? (bool)$aParams['check_private_content'] : true;
+
+        $aUnitTemplate = ['name' => 'unit.html', 'size' => false, 'vars' => []];
+        if(!empty($aParams['template'])) {
+            $mixedTemplate = $aParams['template'];
+            unset($aParams['template']);
+
+            if(is_string($mixedTemplate))
+                $aUnitTemplate['name'] = $mixedTemplate . '.html';
+            else if(is_array($mixedTemplate)) {
+                if(!empty($mixedTemplate['name']))
+                    $aUnitTemplate['name'] = $mixedTemplate['name'] . '.html';
+
+                if(!empty($mixedTemplate['size']))
+                    $aUnitTemplate['size'] = $mixedTemplate['size'];
+
+                if(!empty($mixedTemplate['vars']))
+                    $aUnitTemplate['vars'] = $mixedTemplate['vars'];
+            }
+        }
+
+        $aUnitParams = [];
+        if(!empty($aParams))
+            $aUnitParams = $aParams;
+
+        return $this->_oTemplate->unit($aContentInfo, $bCheckPrivateContent, array_values($aUnitTemplate), $aUnitParams);
+    }
+
+    public function serviceProfileUnitApi ($iContentId, $aParams = [])
+    {
+        $mixedContent = $this->_getContent($iContentId);
+        if($mixedContent === false)
+            return false;
+
+        list($iContentId, $aContentInfo) = $mixedContent;
+
+        return $this->_oTemplate->unitAPI($aContentInfo, $aParams);
+    }
+
+    public function serviceHasImage ($iContentId)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $mixedContent = $this->_getContent($iContentId, 'getContentInfoById');
+        if($mixedContent === false)
+            return false;
+
+        list($iContentId, $aContentInfo) = $mixedContent;
+
+        return !empty($aContentInfo[$CNF['FIELD_PICTURE']]);
+    }
+
+    public function serviceProfilePicture ($iContentId)
+    {
+        return $this->_serviceTemplateFunc('urlPicture', $iContentId);
+    }
+
+    public function serviceProfileAvatar ($iContentId)
+    {
+        return $this->_serviceTemplateFunc('urlAvatar', $iContentId);
+    }
+
+    public function serviceProfileAvatarBig ($iContentId)
+    {
+        return $this->_serviceTemplateFunc('urlAvatarBig', $iContentId);
+    }
+
+    public function serviceProfileCover ($iContentId)
+    {
+        return $this->_serviceTemplateFunc('urlCover', $iContentId);
+    }
+
+    public function serviceProfileUnitCover ($iContentId)
+    {
+        return $this->_serviceTemplateFunc('urlCoverUnit', $iContentId);
+    }
+
+    public function serviceProfileEditUrl ($iContentId)
+    {
+        return bx_absolute_url(BxDolPermalinks::getInstance()->permalink('page.php?i=' . $this->_oConfig->CNF['URI_EDIT_ENTRY'] . '&id=' . $iContentId));
+    }
+
+    public function serviceProfileThumb ($iContentId)
+    {
+        return $this->_serviceTemplateFunc('urlThumb', $iContentId);
+    }
+
+    public function serviceProfileIcon ($iContentId)
+    {
+        return $this->_serviceTemplateFunc('urlIcon', $iContentId);
+    }
+
+    public function serviceProfileName ($iContentId)
+    {
+        if (!$iContentId)
+            return false;
+        $aContentInfo = $this->_oDb->getContentInfoById($iContentId);
+        if (!$aContentInfo)
+            return false;
+        
+        $sDisplayName = $this->getProfileName($aContentInfo);
+
+        /**
+         * @hooks
+         * @hookdef hook-bx_base_profile-profile_name '{module_name}', 'profile_name' - hook to override profile display name
+         * - $unit_name - module name
+         * - $action - equals `profile_name`
+         * - $object_id - profile id
+         * - $sender_id - not used
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `info` - [array] profile info array as key&value pairs
+         *      - `display_name` - [string] by ref, profile display name, can be overridden in hook processing
+         * @hook @ref hook-bx_base_profile-profile_name
+         */
+        bx_alert($this->getName(), 'profile_name', $aContentInfo['profile_id'], 0, [
+            'info' => $aContentInfo, 
+            'display_name' => &$sDisplayName,
+            'display_name_ref' => &$sDisplayName
+        ]);
+        
+        return $sDisplayName;
+    }
+    
+    public function serviceProfileSettings ($iContentId)
+    {
+        if (!$iContentId)
+            return false;
+        $aContentInfo = $this->_oDb->getContentInfoById($iContentId);
+        if (!$aContentInfo)
+            return false;
+        
+       if (isset($aContentInfo['settings']))
+           return json_decode($aContentInfo['settings']);
+    }
+    
+    public function serviceProfileSettingsSet ($iContentId, $oValue)
+    {
+        $CNF = $this->_oConfig->CNF;
+        $this->_oDb->updateEntriesBy(['settings' => json_encode($oValue)], [$CNF['FIELD_ID'] => $iContentId]);
+    }
+  
+    public function serviceProfileCreateUrl ($bAbsolute = true)
+    {
+    	$CNF = $this->_oConfig->CNF;
+    	if(empty($CNF['URL_CREATE']))
+    		return false;
+
+    	return $bAbsolute ? bx_absolute_url(BxDolPermalinks::getInstance()->permalink($CNF['URL_CREATE'])) : $CNF['URL_CREATE'];
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_base_profile Base Profile
+     * @subsection bx_base_profile-general General
+     * @subsubsection bx_base_profile-profile_url profile_url
+     * 
+     * @code bx_srv('bx_persons', 'profile_url', [...]); @endcode
+     * 
+     * Get profile URL
+     * @param $iContentId content ID
+     * 
+     * @see BxBaseModProfileModule::serviceProfileUrl
+     */
+    /** 
+     * @ref bx_base_profile-profile_url "profile_url"
+     */
+    public function serviceProfileUrl ($iContentId)
+    {
+        if (!$iContentId)
+            return false;
+        $aContentInfo = $this->_oDb->getContentInfoById($iContentId);
+        if (!$aContentInfo)
+            return false;
+        $CNF = $this->_oConfig->CNF;
+        return bx_absolute_url(BxDolPermalinks::getInstance()->permalink('page.php?i=' . $CNF['URI_VIEW_ENTRY'] . '&id=' . $aContentInfo[$CNF['FIELD_ID']]));
+    }
+
+    /**
+     * @see iBxDolProfileService::serviceGetSpaceTitle
+     */ 
+    public function serviceGetSpaceTitle()
+    {
+        return _t('_sys_ps_space_title_friend');
+    }
+
+    /**
+     * @see iBxDolProfileService::serviceGetParticipatingProfiles
+     */ 
+    public function serviceGetParticipatingProfiles($iProfileId, $aConnectionObjects = false)
+    {
+        if (false === $aConnectionObjects)
+            $aConnectionObjects = array('sys_profiles_friends');
+
+        $a = array();
+        foreach ($aConnectionObjects as $sConnectionObject) {
+            if (!($o = BxDolConnection::getObjectInstance($sConnectionObject)))
+                continue;
+
+            if (BX_CONNECTIONS_TYPE_MUTUAL == $o->getType())
+                $a = array_merge($a, $o->getConnectedContentByType($iProfileId, $this->getName(), true));
+            else
+                $a = array_merge($a, $o->getConnectedContentByType($iProfileId, $this->getName()));
+        }
+        $aRet = array_unique($a);
+
+        // the check for an ability to post in profile has been moved to BxDolPrivacy because we need to have an extended check
+        // with an ability to check for extended roles taking into account the type of content which is going be posted/edited
+        // so now this service returns just a fans, not filtered by an ability to post into an entry's context
+        /*foreach ($a as $iConnectedProfileId) {
+            if (!($oConnectedProfile = BxDolProfile::getInstance($iConnectedProfileId)))
+                continue;
+
+             if (CHECK_ACTION_RESULT_ALLOWED === bx_srv($oConnectedProfile->getModule(), 'check_allowed_post_in_profile', array($oConnectedProfile->getContentId(), $iProfileId)))
+                $aRet[] = $iConnectedProfileId;
+        }*/
+
+        /**
+         * @hooks
+         * @hookdef hook-system-get_participating_profiles 'system', 'get_participating_profiles' - hook to override context participants list
+         * - $unit_name - equals `system`
+         * - $action - equals `get_participating_profiles`
+         * - $object_id - context profile id
+         * - $sender_id - not used
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `module` - [string] module name
+         *      - `profiles` - [array] by ref, a list of participating profiles ids, can be overridden in hook processing
+         * @hook @ref hook-system-get_participating_profiles
+         */
+        bx_alert('system', 'get_participating_profiles', $iProfileId, false, [
+            'module' => $this->_oConfig->getName(),
+            'profiles' => &$aRet,
+            'profiles_ref' => &$aRet
+        ]);
+
+        return $aRet;
+    }
+
+    /**
+     * Prepare fields from some universal set of fields to fields in particular profile module. 
+     * By default only 'name' and 'description' fields are supported.
+     * After fields convertion it can be used in @see BxBaseModGeneralModule::serviceEntityAdd
+     * @param $aFieldsProfile fields in soem universal format.
+     * @return array which is ready to use for particular module
+     */ 
+    public function servicePrepareFields ($aFieldsProfile)
+    {
+        /**
+         * @hooks
+         * @hookdef hook-bx_base_profile-prepare_fields '{module_name}', 'prepare_fields' - hook to override prepared profile fields
+         * - $unit_name - module name
+         * - $action - equals `prepare_fields`
+         * - $object_id - not used
+         * - $sender_id - not used
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `fields_orig` - [array] original fields array as key&value pairs
+         *      - `fields_result` - [array] by ref, resulting fields array as key&value pairs, can be overridden in hook processing
+         * @hook @ref hook-bx_base_profile-prepare_fields
+         */
+        bx_alert($this->getName(), 'prepare_fields', 0, 0, [
+            'fields_orig' => $aFieldsProfile, 
+            'fields_result' => &$aFieldsProfile
+        ]);
+
+        return $aFieldsProfile;
+    }
+
+    protected function _servicePrepareFields ($aFieldsProfile, $aFieldsDefault, $aMap)
+    {
+        $aFieldsOrig = $aFieldsProfile;
+
+        bx_import('BxDolPrivacy');
+        $aFieldsDefault2 = array(
+            'allow_view_to' => BX_DOL_PG_ALL,
+            'allow_contact_to' => BX_DOL_PG_ALL, 
+            'allow_post_to' => BX_DOL_PG_FRIENDS,
+        );
+        $aFieldsProfile = array_merge($aFieldsDefault2, $aFieldsDefault, $aFieldsProfile);
+
+        foreach ($aMap as $k => $v) {
+            if (isset($aFieldsProfile[$v]))
+                $aFieldsProfile[$k] = $aFieldsProfile[$v];
+            if ($k != $v && !isset($aMap[$v]))
+                unset($aFieldsProfile[$v]);
+        }
+
+        /**
+         * @hooks
+         * @hookdef hook-bx_base_profile-prepare_fields '{module_name}', 'prepare_fields' - hook to override prepared profile fields
+         * - $unit_name - module name
+         * - $action - equals `prepare_fields`
+         * - $object_id - not used
+         * - $sender_id - not used
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `fields_orig` - [array] original fields array as key&value pairs
+         *      - `fields_result` - [array] by ref, resulting fields array as key&value pairs, can be overridden in hook processing
+         * @hook @ref hook-bx_base_profile-prepare_fields
+         */
+        bx_alert($this->getName(), 'prepare_fields', 0, 0, [
+            'fields_orig' => $aFieldsOrig, 
+            'fields_result' => &$aFieldsProfile
+        ]);
+
+        return $aFieldsProfile;
+    }
+
+    public function serviceFormsHelper ()
+    {
+        return parent::serviceFormsHelper ();
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_base_profile Base Profile
+     * @subsection bx_base_profile-forms Forms
+     * @subsubsection bx_base_profile-entity_create entity_create
+     * 
+     * @code bx_srv('bx_persons', 'entity_create', [...]); @endcode
+     * 
+     * Get profile creation form
+     * @param $sDisplay optional form display name
+     * 
+     * @see BxBaseModProfileModule::serviceEntityCreate
+     */
+    /** 
+     * @ref bx_base_profile-entity_create "entity_create"
+     */
+    public function serviceEntityCreate ($sDisplay = false)
+    {
+	    BxDolInformer::getInstance($this->_oTemplate)->setEnabled(false);
+
+	    return parent::serviceEntityCreate ($sDisplay);
+    }
+
+    public function serviceActAsProfile ()
+    {
+        return true;
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_base_profile Base Profile
+     * @subsection bx_base_profile-browse Browse
+     * @subsubsection bx_base_profile-browse_recommended browse_recommended
+     * 
+     * @code bx_srv('bx_persons', 'browse_recommended', [...]); @endcode
+     * 
+     * Browse recommended profiles
+     * @param $sUnitView optional, unit view, for example - showcase
+     * @param $bEmptyMessage optional, display or not "empty" message when there is no content
+     * @param $bAjaxPaginate optional, use AJAX paginate or not
+     * 
+     * @see BxBaseModProfileModule::serviceBrowseRecommended
+     */
+    /** 
+     * @ref bx_base_profile-browse_recommended "browse_recommended"
+     */
+    public function serviceBrowseRecommended ($sUnitView = false, $bEmptyMessage = false, $bAjaxPaginate = true)
+    {
+        if (!isLogged())
+            return '';
+        return $this->_serviceBrowse ('recommended', $sUnitView ? array('unit_view' => $sUnitView) : false, BX_DB_PADDING_DEF, $bEmptyMessage, $bAjaxPaginate);
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_base_profile Base Profile
+     * @subsection bx_base_profile-browse Browse
+     * @subsubsection bx_base_profile-browse_recent_profiles browse_recent_profiles
+     * 
+     * @code bx_srv('bx_persons', 'browse_recent_profiles', [...]); @endcode
+     * 
+     * Browse recently joined profiles
+     * @param $bEmptyMessage optional, display or not "empty" message when there is no content
+     * @param $bAjaxPaginate optional, use AJAX paginate or not
+     * 
+     * @see BxBaseModProfileModule::serviceBrowseRecentProfiles
+     */
+    /** 
+     * @ref bx_base_profile-browse_recent_profiles "browse_recent_profiles"
+     */
+    public function serviceBrowseRecentProfiles ($bDisplayEmptyMsg = false, $bAjaxPaginate = true, $sUnitView = false)
+    {
+        return $this->_serviceBrowse ('recent', $sUnitView ? array('unit_view' => $sUnitView) : false, BX_DB_PADDING_DEF, $bDisplayEmptyMsg, $bAjaxPaginate);
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_base_profile Base Profile
+     * @subsection bx_base_profile-browse Browse
+     * @subsubsection bx_base_profile-browse_active_profiles browse_active_profiles
+     * 
+     * @code bx_srv('bx_persons', 'browse_active_profiles', [...]); @endcode
+     * 
+     * Browse recently active profiles
+     * @param $bEmptyMessage optional, display or not "empty" message when there is no content
+     * @param $bAjaxPaginate optional, use AJAX paginate or not
+     * 
+     * @see BxBaseModProfileModule::serviceBrowseActiveProfiles
+     */
+    /** 
+     * @ref bx_base_profile-browse_active_profiles "browse_active_profiles"
+     */
+    public function serviceBrowseActiveProfiles ($sUnitView = false, $bEmptyMessage = false, $bAjaxPaginate = false)
+    {
+        return $this->_serviceBrowse ('active', $sUnitView ? array('unit_view' => $sUnitView) : false, BX_DB_PADDING_DEF, $bEmptyMessage, $bAjaxPaginate);
+    }
+    
+    /**
+     * @page service Service Calls
+     * @section bx_base_profile Base Profile
+     * @subsection bx_base_profile-browse Browse
+     * @subsubsection bx_base_profile-browse_familiar_profiles browse_familiar_profiles
+     * 
+     * @code bx_srv('bx_persons', 'browse_familiar_profiles', [...]); @endcode
+     * 
+     * Browse profiles you might be familiar with. By default using 'Profile Friends' connection.
+     * @param $bEmptyMessage optional, display or not "empty" message when there is no content
+     * @param $bAjaxPaginate optional, use AJAX paginate or not
+     * 
+     * @see BxBaseModProfileModule::serviceBrowseFamiliarProfiles
+     */
+    /** 
+     * @ref bx_base_profile-browse_familiar_profiles "browse_familiar_profiles"
+     */
+    public function serviceBrowseFamiliarProfiles ($sConnection = '', $sUnitView = false, $bEmptyMessage = false, $bAjaxPaginate = false)
+    {
+        $aParams = [
+            'object' => 'sys_profiles_friends',
+            'profile' => bx_get_logged_profile_id(),
+        ];
+
+        if(!empty($sConnection)) {
+            if(is_string($sConnection))
+                $aParams['object'] = $sConnection;
+            else if(is_array($sConnection))
+                $aParams = array_merge($aParams, $sConnection);
+        }
+
+        if($sUnitView)
+            $aParams['unit_view'] = $sUnitView;
+
+        return $this->_serviceBrowse ('familiar', $aParams, BX_DB_PADDING_DEF, $bEmptyMessage, $bAjaxPaginate);
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_base_profile Base Profile
+     * @subsection bx_base_profile-browse Browse
+     * @subsubsection bx_base_profile-browse_top_profiles browse_top_profiles
+     * 
+     * @code bx_srv('bx_persons', 'browse_top_profiles', [...]); @endcode
+     * 
+     * Browse top profiles
+     * @param $bEmptyMessage optional, display or not "empty" message when there is no content
+     * @param $bAjaxPaginate optional, use AJAX paginate or not
+     * 
+     * @see BxBaseModProfileModule::serviceBrowseTopProfiles
+     */
+    /** 
+     * @ref bx_base_profile-browse_top_profiles "browse_top_profiles"
+     */
+    public function serviceBrowseTopProfiles ($bDisplayEmptyMsg = false, $bAjaxPaginate = false)
+    {
+        return $this->_serviceBrowse ('top', false, BX_DB_PADDING_DEF, $bDisplayEmptyMsg, $bAjaxPaginate);
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_base_profile Base Profile
+     * @subsection bx_base_profile-browse Browse
+     * @subsubsection bx_base_profile-browse_online_profiles browse_online_profiles
+     * 
+     * @code bx_srv('bx_persons', 'browse_online_profiles', [...]); @endcode
+     * 
+     * Browse online profiles
+     * @param $bEmptyMessage optional, display or not "empty" message when there is no content
+     * @param $bAjaxPaginate optional, use AJAX paginate or not
+     * 
+     * @see BxBaseModProfileModule::serviceBrowseOnlineProfiles
+     */
+    /** 
+     * @ref bx_base_profile-browse_online_profiles "browse_online_profiles"
+     */
+    public function serviceBrowseOnlineProfiles ($bDisplayEmptyMsg = false, $bAjaxPaginate = false)
+    {
+        return $this->_serviceBrowse ('online', false, BX_DB_PADDING_DEF, $bDisplayEmptyMsg, $bAjaxPaginate);
+    }
+
+    public function serviceBrowseConnections ($iProfileId, $sObjectConnections = 'sys_profiles_friends', $sConnectionsType = 'content', $iMutual = false, $iDesignBox = BX_DB_PADDING_DEF, $iProfileId2 = 0)
+    {
+        return $this->_serviceBrowse (
+            'connections', [
+                'object' => $sObjectConnections,
+                'type' => $sConnectionsType,
+                'mutual' => $iMutual,
+                'profile' => (int)$iProfileId,
+                'profile2' => (int)$iProfileId2
+            ], $iDesignBox
+        );
+    }
+
+    public function serviceBrowseRelationsQuick ($iProfileId, $sObjectConnections = 'sys_profiles_friends', $sConnectionsType = 'content', $iMutual = false, $iProfileId2 = 0)
+    {
+        // get connections object
+        $oConnection = BxDolConnection::getObjectInstance($sObjectConnections);
+        if (!$oConnection)
+            return '';       
+
+        // set some vars
+        $iStart = (int)bx_get('start');
+        $iLimit = empty($this->_oConfig->CNF['PARAM_NUM_CONNECTIONS_QUICK']) ? 4 : getParam($this->_oConfig->CNF['PARAM_NUM_CONNECTIONS_QUICK']);
+        if (!$iLimit)
+            $iLimit = 4;
+
+        // get connections array
+        bx_import('BxDolConnection');
+        $aConnections = $oConnection->getConnectionsAsArrayExt($sConnectionsType, $iProfileId, $iProfileId2, $iMutual, $iStart, $iLimit + 1, BX_CONNECTIONS_ORDER_ADDED_DESC);
+        if(empty($aConnections) || !is_array($aConnections))
+            return '';
+
+        $aResult = array();
+        foreach($aConnections as $iProfile => $aConnection)
+            $aResult[] = array(
+                'id' => $iProfile,
+                'info' => array(
+                    'addon' => $oConnection->getRelationTranslation($aConnection['relation'])
+                )
+            );
+
+        return $this->_serviceBrowseQuick($aResult, $iStart, $iLimit);
+    }
+
+    public function serviceBrowseConnectionsQuick ($iProfileId, $sObjectConnections = 'sys_profiles_friends', $sConnectionsType = 'content', $iMutual = false, $iProfileId2 = 0)
+    {
+        // get connections object
+        $oConnection = BxDolConnection::getObjectInstance($sObjectConnections);
+        if (!$oConnection)
+            return '';
+
+        // set some vars
+        $iLimit = empty($this->_oConfig->CNF['PARAM_NUM_CONNECTIONS_QUICK']) ? 4 : getParam($this->_oConfig->CNF['PARAM_NUM_CONNECTIONS_QUICK']);
+        if (!$iLimit)
+            $iLimit = 4;
+        $iStart = (int)bx_get('start');
+
+        // get connections array
+        bx_import('BxDolConnection');
+        $a = $oConnection->getConnectionsAsArray ($sConnectionsType, $iProfileId, $iProfileId2, $iMutual, (int)bx_get('start'), $iLimit + 1, BX_CONNECTIONS_ORDER_ADDED_DESC);
+        if (!$a)
+            return '';
+
+        return $this->_serviceBrowseQuick($a, $iStart, $iLimit);
+    }
+
+    public function serviceBrowseConnectionsByType ($aParamsCnn, $aParamsBrs = array())
+    {
+        $sAll = 'all';
+
+        $aParamsCnn['object'] = !empty($aParamsCnn['object']) ? $aParamsCnn['object'] : 'sys_profiles_friends';
+        $aParamsCnn['type'] = !empty($aParamsCnn['type']) ? $aParamsCnn['type'] : 'content';
+        $aParamsCnn['profile_id2'] = !empty($aParamsCnn['profile_id2']) ? (int)$aParamsCnn['profile_id2'] : 0;
+        $aParamsCnn['mutual'] = isset($aParamsCnn['mutual']) ? $aParamsCnn['mutual'] : false;
+
+        $oConnection = BxDolConnection::getObjectInstance($aParamsCnn['object']);
+        if(!$oConnection)
+            return '';
+
+        $aSQLParts = $oConnection->getConnectionsAsSQLParts ($aParamsCnn['type'], 'sys_profiles', 'id', $aParamsCnn['profile_id'], $aParamsCnn['profile_id2'], $aParamsCnn['mutual']);
+
+        $sType = !empty($aParamsBrs['type']) ? $aParamsBrs['type'] : $sAll;
+        if(bx_get('type') !== false)
+            $sType = bx_process_input(bx_get('type'));
+
+        $iStart = (int)bx_get('start');
+
+        $iLimitDefault = 4;
+        $iLimit = !empty($this->_oConfig->CNF['PARAM_NUM_CONNECTIONS_QUICK']) ? getParam($this->_oConfig->CNF['PARAM_NUM_CONNECTIONS_QUICK']) : $iLimitDefault;
+        if(!empty($aParamsBrs['per_page']))
+            $iLimit = (int)$aParamsBrs['per_page'];
+        if(!$iLimit)
+            $iLimit = $iLimitDefault;
+
+        $aProfiles = BxDolProfileQuery::getInstance()->getConnectedProfilesByType($aSQLParts, ($sType != $sAll ? $sType : ''), $iStart, $iLimit + 1);
+
+        $mixedMenu = '';
+        if(!isset($aParamsBrs['filter_menu']) || $aParamsBrs['filter_menu'] === true) {
+            $aModules = array(
+                array('name' => $sAll)
+            );
+            $aModules = array_merge($aModules, BxDolModuleQuery::getInstance()->getModulesBy(array('type' => 'modules', 'active' => 1)));
+
+            $aMenuItems = array();
+            foreach($aModules as $aModule)
+                if($aModule['name'] == $sAll || BxDolRequest::serviceExists($aModule['name'], 'act_as_profile'))
+                    $aMenuItems[] = array(
+                    	'id' => $aModule['name'], 
+                    	'name' => $aModule['name'], 
+                    	'class' => '', 
+                    	'link' => 'javascript:void(0)', 
+                    	'onclick' => "return !loadDynamicBlockAutoPaginate(this, " . $iStart . ", " . $iLimit . ", " . bx_js_string(json_encode(array('type' => $aModule['name']))) . ");", 
+                    	'target' => '_self', 
+                    	'title' => _t('_' . $aModule['name']), 
+                    	'active' => 1
+                    );
+    
+            if(!empty($aMenuItems)) {
+                $mixedMenu = new BxTemplMenu(array('template' => 'menu_vertical.html', 'menu_id'=> $this->_oConfig->getName() . '-connections-by-type', 'menu_items' => $aMenuItems));
+                $mixedMenu->setSelected('', $sType);
+            }
+        }
+
+        return array(
+            'menu' => $mixedMenu,
+            'content' => $this->_serviceBrowseQuick(array_keys($aProfiles), $iStart, $iLimit, array('type' => $sType))
+        );
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_base_profile Base Profile
+     * @subsection bx_base_profile-browse Browse
+     * @subsubsection bx_base_profile-browse_by_acl browse_by_acl
+     * 
+     * @code bx_srv('bx_persons', 'browse_by_acl', [...]); @endcode
+     * 
+     * Browse profiles by membership(ACL) level
+     * @param $mixedLevelId membership level, or array of membership levels
+     * @param $iDesignBox optional, design box identifier
+     * 
+     * @see BxBaseModProfileModule::serviceBrowseByAcl
+     */
+    /** 
+     * @ref bx_base_profile-browse_by_acl "browse_by_acl"
+     */
+	public function serviceBrowseByAcl ($mixedLevelId, $iDesignBox = BX_DB_PADDING_DEF)
+    {
+        return $this->_serviceBrowse (
+            'acl',
+            array(
+                'level' => $mixedLevelId,
+			),
+            $iDesignBox,
+            true
+        );
+    }
+
+    public function serviceEntityEditCover($iContentId = 0)
+    {
+        return $this->_serviceEntityForm('editDataForm', $iContentId, $this->_oConfig->CNF['OBJECT_FORM_ENTRY_DISPLAY_EDIT_COVER']);
+    }
+
+    public function serviceEntityEditBadge($iContentId = 0)
+    {
+        return $this->_serviceEntityForm('editDataForm', $iContentId, $this->_oConfig->CNF['OBJECT_FORM_ENTRY_DISPLAY_EDIT_BADGE'], 'checkAllowedChangeBadge');
+    }
+
+    public function serviceEntityEditSettings($iContentId = 0)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        if(empty($CNF['OBJECT_FORM_ENTRY_DISPLAY_EDIT_SETTINGS']))
+            return false;
+
+        return $this->_serviceEntityForm('editDataForm', $iContentId, $CNF['OBJECT_FORM_ENTRY_DISPLAY_EDIT_SETTINGS']);
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_base_profile Base Profile
+     * @subsection bx_base_profile-page_blocks Page Blocks
+     * @subsubsection bx_base_profile-entity_cover entity_cover
+     * 
+     * @code bx_srv('bx_persons', 'entity_cover', [...]); @endcode
+     * 
+     * Get cover
+     * @param $iContentId content ID
+     * 
+     * @see BxBaseModProfileModule::serviceEntityCover
+     */
+    /** 
+     * @ref bx_base_general-entity_cover "entity_cover"
+     */
+    public function serviceEntityCover ($iContentId = 0, $aParams = [])
+    {
+        $mixedContent = $this->_getContent($iContentId);
+        if($mixedContent === false)
+            return false;
+
+        list($iContentId, $aContentInfo) = $mixedContent;
+
+        if($this->_bIsApi) {
+            $CNF = &$this->_oConfig->CNF;
+
+            $aContentInfo['cover'] = $this->serviceGetCover($iContentId);
+            $aContentInfo['image'] = $this->serviceGetThumb($iContentId);            
+
+            $sKey = 'OBJECT_MENU_VIEW_ENTRY_META';
+            if(!empty($CNF[$sKey]) && ($oMetaMenu = BxTemplMenu::getObjectInstance($CNF[$sKey])) !== false)
+                $aContentInfo['meta_menu'] = $oMetaMenu->getCodeAPI();
+
+            $sKey = 'OBJECT_MENU_ACTIONS_VIEW_ENTRY_ALL';
+            if(!empty($CNF[$sKey]) && ($oActionMenu = BxTemplMenu::getObjectInstance($CNF[$sKey])) !== false)
+                $aContentInfo['actions_menu'] = $oActionMenu->getCodeAPI();
+
+            if(($oMenuManage = BxDolMenu::getObjectInstance('sys_site_manage')) !== false) {
+                if(!empty($CNF['FIELD_ID']))
+                    $oMenuManage->setContentId($aContentInfo[$CNF['FIELD_ID']]);
+
+                $aObjectManage = [];
+                if(!empty($CNF['OBJECT_MENU_MANAGE_VIEW_ENTRY']))
+                    $aObjectManage = [$CNF['OBJECT_MENU_MANAGE_VIEW_ENTRY']];
+                else if(!empty($CNF['OBJECT_MENU_ACTIONS_VIEW_ENTRY_MORE']))
+                    $aObjectManage = [$CNF['OBJECT_MENU_ACTIONS_VIEW_ENTRY_MORE'], true];
+
+                call_user_func_array([$oMenuManage, 'setObjectManage'], $aObjectManage);
+
+                $aMenuManage = $oMenuManage->getCodeAPI();
+                if(!empty($aMenuManage) && is_array($aMenuManage)) {
+                    if(isset($aContentInfo['actions_menu']) && is_array($aContentInfo['actions_menu']))
+                        $aContentInfo['actions_menu']['items'] = array_merge($aContentInfo['actions_menu']['items'], $aMenuManage['items']);
+                    else
+                       $aContentInfo['actions_menu'] = $aMenuManage;
+                }   
+            }
+
+            if(($oProfile = BxDolProfile::getInstanceByContentAndType($iContentId, $this->getName())) !== false);
+                $aContentInfo['profile'] = BxDolProfile::getData($oProfile, [
+                    'get_avatar' => 'getAvatarBig',
+                    'with_info' => false
+                ]);
+
+            return [bx_api_get_block('entity_cover', $aContentInfo)];
+        }
+        
+        return $this->_oTemplate->getBlockCover($aContentInfo, $aParams);
+    }
+    
+	/**
+     * Entry comments
+     */
+    public function serviceEntityCommentsByProfile ($iProfileId)
+    {
+        $CNF = &$this->_oConfig->CNF;
+        if(empty($CNF['OBJECT_COMMENTS']))
+            return '';
+
+        $oProfile = BxDolProfile::getInstance($iProfileId);
+        if(!$oProfile)
+            return '';
+
+        return $this->_entityComments($CNF['OBJECT_COMMENTS'], $oProfile->getContentId());
+    }
+
+    /**
+     * Entry social sharing block
+     */
+    public function serviceEntitySocialSharing ($mixedContent = false, $aParams = array())
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        if(!empty($mixedContent)) {
+            if(!is_array($mixedContent))
+               $mixedContent = array((int)$mixedContent, array());
+        }
+        else {
+            $mixedContent = $this->_getContent();
+            if($mixedContent === false)
+                return false;
+        }
+
+        list($iContentId, $aContentInfo) = $mixedContent;    
+
+        return parent::serviceEntitySocialSharing(array($iContentId, $aContentInfo), array(
+            'id_thumb' => !empty($CNF['FIELD_PICTURE']) && !empty($aContentInfo[$CNF['FIELD_PICTURE']]) ? $aContentInfo[$CNF['FIELD_PICTURE']] : 0, 
+        ));
+    }
+
+    public function serviceProfileMembership ($iContentId = 0)
+    {
+    	$mixedContent = $this->_getContent($iContentId);
+        if($mixedContent === false)
+            return false;
+
+        list($iContentId, $aContentInfo) = $mixedContent;
+
+        $mixedResult = BxDolAcl::getInstance()->getProfileMembership($aContentInfo['profile_id']);
+
+        return $this->_bIsApi ? [bx_api_get_block('entity_membership', $mixedResult)] : $mixedResult;
+    }
+
+    public function serviceProfileFriends ($iContentId = 0)
+    {
+        if(!$this->_oConfig->isFriends())
+            return false;
+
+        $mixedContent = $this->_getContent($iContentId);
+        if($mixedContent === false)
+            return false;
+
+        list($iContentId, $aContentInfo) = $mixedContent;
+
+        bx_import('BxDolConnection');
+        $s = $this->serviceBrowseConnectionsQuick ($aContentInfo['profile_id'], 'sys_profiles_friends', BX_CONNECTIONS_CONTENT_TYPE_CONTENT, true);
+        if (!$s)
+            return MsgBox(_t('_sys_txt_empty'));
+
+        return $s;
+    }
+
+    public function serviceProfileFriendsMutual ($iContentId = 0)
+    {
+        if(!$this->_oConfig->isFriends())
+            return false;
+
+        $mixedContent = $this->_getContent($iContentId);
+        if($mixedContent === false)
+            return false;
+
+        list($iContentId, $aContentInfo) = $mixedContent;
+
+        $iViewer = bx_get_logged_profile_id();
+        $iOwner = (int)$aContentInfo['profile_id'];
+        if($iViewer == $iOwner)
+            return false;
+
+        bx_import('BxDolConnection');
+        $s = $this->serviceBrowseConnectionsQuick ($iOwner, 'sys_profiles_friends', BX_CONNECTIONS_CONTENT_TYPE_COMMON, true, $iViewer);
+        if(!$s)
+            return MsgBox(_t('_sys_txt_empty'));
+
+        return $s;
+    }
+
+    public function serviceProfileSubscriptions ($iContentId = 0, $aParams = array())
+    {
+        $mixedContent = $this->_getContent($iContentId);
+        if($mixedContent === false)
+            return false;
+
+        list($iContentId, $aContentInfo) = $mixedContent;
+
+        bx_import('BxDolConnection');
+        $aResult = $this->serviceBrowseConnectionsByType(array(
+        	'profile_id' => $aContentInfo['profile_id'],  
+        	'object' => 'sys_profiles_subscriptions', 
+            'type' => BX_CONNECTIONS_CONTENT_TYPE_CONTENT
+        ), array(
+            'type' => isset($aParams['type']) ? $aParams['type'] : '',
+            'filter_menu' => isset($aParams['filter_menu']) ? $aParams['filter_menu'] : true,
+        ));
+        if(empty($aResult['content']))
+            $aResult['content'] = MsgBox(_t('_sys_txt_empty'));
+
+        return $aResult;
+    }
+
+    public function serviceProfileSubscribedMe ($iContentId = 0)
+    {
+        $mixedContent = $this->_getContent($iContentId);
+        if($mixedContent === false)
+            return false;
+
+        list($iContentId, $aContentInfo) = $mixedContent;
+
+        bx_import('BxDolConnection');
+        $s = $this->serviceBrowseConnectionsQuick ($aContentInfo['profile_id'], 'sys_profiles_subscriptions', BX_CONNECTIONS_CONTENT_TYPE_INITIATORS);
+        if (!$s)
+            return MsgBox(_t('_sys_txt_empty'));
+
+        return $s;
+    }
+
+    public function serviceProfileRelations ($iContentId = 0, $aParams = array())
+    {
+        if(!BxDolConnectionRelation::isEnabled())
+            return false;
+
+        $mixedContent = $this->_getContent($iContentId);
+        if($mixedContent === false)
+            return false;
+
+        list($iContentId, $aContentInfo) = $mixedContent;
+
+        bx_import('BxDolConnection');
+        $s = $this->serviceBrowseRelationsQuick ($aContentInfo['profile_id'], 'sys_profiles_relations', BX_CONNECTIONS_CONTENT_TYPE_CONTENT, 1);
+        if (!$s)
+            return MsgBox(_t('_sys_txt_empty'));
+
+        return $s;
+    }
+
+    public function serviceProfileRelatedMe ($iContentId = 0)
+    {
+        if(!BxDolConnectionRelation::isEnabled())
+            return false;
+
+        $mixedContent = $this->_getContent($iContentId);
+        if($mixedContent === false)
+            return false;
+
+        list($iContentId, $aContentInfo) = $mixedContent;
+
+        bx_import('BxDolConnection');
+        $s = $this->serviceBrowseRelationsQuick ($aContentInfo['profile_id'], 'sys_profiles_relations', BX_CONNECTIONS_CONTENT_TYPE_INITIATORS, 1);
+        if (!$s)
+            return MsgBox(_t('_sys_txt_empty'));
+
+        return $s;
+    }
+
+    /**
+     * check enabled profile activation letter
+     */
+    public function  serviceIsEnableProfileActivationLetter()
+    {
+        $CNF = &$this->_oConfig->CNF;
+        return isset($CNF['PARAM_ENABLE_ACTIVATION_LETTER']) ? (bool)getParam($CNF['PARAM_ENABLE_ACTIVATION_LETTER']) : true;
+    }
+
+    public function serviceIsEnableFriends()
+    {
+        return $this->_oConfig->isFriends();
+    }
+
+    public function serviceIsEnableRelations()
+    {
+        if(!BxDolConnectionRelation::isEnabled())
+            return false;
+
+        $sModule = $this->_oConfig->getName();
+        $oRelations = BxDolConnection::getObjectInstance('sys_profiles_relations');
+        return $oRelations->isRelationAvailableWithProfile($sModule) || $oRelations->isRelationAvailableFromProfile($sModule);
+    }
+
+    /**
+     * For internal usage only.
+     */
+    public function serviceDeleteEntityService ($iContentId, $bDeleteWithContent = false)
+    {
+        return parent::serviceDeleteEntity ($iContentId, 'deleteDataService');
+    }
+
+	/**
+     * Data for Notifications module
+     */
+    public function serviceGetNotificationsData()
+    {
+        $a = parent::serviceGetNotificationsData();
+
+        $sModule = $this->_aModule['name'];
+        
+        $a['handlers'][] = array('group' => $sModule . '_timeline_post_common', 'type' => 'insert', 'alert_unit' => $sModule, 'alert_action' => 'timeline_post_common', 'module_name' => $sModule, 'module_method' => 'get_notifications_timeline_post_common', 'module_class' => 'Module');
+
+        $a['settings'][] = array('group' => 'timeline_post', 'unit' => $sModule, 'action' => 'timeline_post_common', 'types' => array('follow_member'));
+
+        $a['alerts'][] = array('unit' => $sModule, 'action' => 'timeline_post_common');
+
+        return $a;
+    }
+
+    public function serviceGetNotificationsPost($aEvent)
+    {
+        $aResult = parent::serviceGetNotificationsVote($aEvent);
+        if(empty($aResult) || !is_array($aResult) || !$this->serviceActAsProfile())
+            return $aResult;
+
+        $oProfile = BxDolProfile::getInstanceByContentAndType((int)$aEvent['object_id'], $this->_oConfig->getName());
+        if($oProfile !== false)
+            $aResult['entry_author'] = $oProfile->id();
+
+        return $aResult;
+    }
+
+    public function serviceGetNotificationsVote($aEvent)
+    {
+        $aResult = parent::serviceGetNotificationsVote($aEvent);
+        if(empty($aResult) || !is_array($aResult) || !$this->serviceActAsProfile())
+            return $aResult;
+
+        $oProfile = BxDolProfile::getInstanceByContentAndType((int)$aEvent['object_id'], $this->_oConfig->getName());
+        if($oProfile !== false)
+            $aResult['entry_author'] = $oProfile->id();
+
+        return $aResult;
+    }
+
+    /**
+     * Notification about new member requst in the group
+     */
+    public function serviceGetNotificationsTimelinePostCommon($aEvent)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $iContentId = (int)$aEvent['object_id'];
+        $oGroupProfile = BxDolProfile::getInstanceByContentAndType((int)$iContentId, $this->getName());
+        if(!$oGroupProfile)
+            return [];
+
+        $aContentInfo = $this->_oDb->getContentInfoById($iContentId);
+        if(empty($aContentInfo) || !is_array($aContentInfo))
+            return [];
+            
+        $aSubcontentInfo = BxDolService::call('bx_timeline', 'get_info', array((int)$aEvent['subobject_id'], false));
+        if(empty($aSubcontentInfo) || !is_array($aSubcontentInfo))
+            return [];
+
+        $sEntrySummary = isset($aContentInfo[$CNF['FIELD_TEXT']]) ? $aContentInfo[$CNF['FIELD_TEXT']] : '';
+
+        $sSubentryUrl = bx_absolute_url(str_replace(BX_DOL_URL_ROOT, '', BxDolService::call('bx_timeline', 'get_link', array((int)$aEvent['subobject_id']))), '{bx_url_root}');
+        $sSubentrySample = $aSubcontentInfo['title'];
+        if(empty($sSubentrySample))
+            $sSubentrySample = strmaxtextlen($aSubcontentInfo['description'], 20, '...');
+        $sSubentrySummary = $aSubcontentInfo['description'];
+
+        return [
+            'entry_sample' => $CNF['T']['txt_sample_single'],
+            'entry_url' => bx_absolute_url(str_replace(BX_DOL_URL_ROOT, '', $oGroupProfile->getUrl()), '{bx_url_root}'),
+            'entry_caption' => $oGroupProfile->getDisplayName(),
+            'entry_summary' => $sEntrySummary,
+            'entry_author' => $oGroupProfile->id(),
+            'subentry_sample' => $sSubentrySample,
+            'subentry_url' => $sSubentryUrl,
+            'subentry_summary' => $sSubentrySummary,
+            'lang_key' => $CNF['T']['txt_ntfs_timeline_post_common'],
+        ];
+    }
+
+    /**
+     * Data for Timeline module
+     */
+    public function serviceGetTimelineData()
+    {
+        $CNF = &$this->_oConfig->CNF;
+        $sModule = $this->_aModule['name'];
+
+        $aResult = parent::serviceGetTimelineData();
+
+        if(!empty($CNF['FIELD_PICTURE'])) {
+            $aResult['handlers'] = array_merge($aResult['handlers'], [
+                ['group' => $sModule . '_profile_picture', 'type' => 'insert', 'alert_unit' => $sModule, 'alert_action' => 'profile_picture_changed', 'module_name' => $sModule, 'module_method' => 'get_timeline_profile_picture', 'module_class' => 'Module',  'groupable' => 0, 'group_by' => ''],
+                ['group' => $sModule . '_profile_picture', 'type' => 'delete', 'alert_unit' => $sModule, 'alert_action' => 'profile_picture_deleted']
+            ]);
+
+            $aResult['alerts'] = array_merge($aResult['alerts'], [
+                ['unit' => $sModule, 'action' => 'profile_picture_changed'],
+                ['unit' => $sModule, 'action' => 'profile_picture_deleted']
+            ]);
+        }
+
+        if(!empty($CNF['FIELD_COVER'])) {
+            $aResult['handlers'] = array_merge($aResult['handlers'], [
+                ['group' => $sModule . '_profile_cover', 'type' => 'insert', 'alert_unit' => $sModule, 'alert_action' => 'profile_cover_changed', 'module_name' => $sModule, 'module_method' => 'get_timeline_profile_cover', 'module_class' => 'Module',  'groupable' => 0, 'group_by' => ''],
+                ['group' => $sModule . '_profile_cover', 'type' => 'delete', 'alert_unit' => $sModule, 'alert_action' => 'profile_cover_deleted']
+            ]);
+
+            $aResult['alerts'] = array_merge($aResult['alerts'], [
+                ['unit' => $sModule, 'action' => 'profile_cover_changed'],
+                ['unit' => $sModule, 'action' => 'profile_cover_deleted']
+            ]);
+        }
+
+        return $aResult;
+    }
+
+    /**
+     * Entry post for Timeline module
+     */
+    public function serviceGetTimelinePost($aEvent, $aBrowseParams = [])
+    {
+        $mixedResult = parent::serviceGetTimelinePost($aEvent, $aBrowseParams);
+
+        if($mixedResult !== false && ($oAuthor = BxDolProfile::getInstanceByContentAndType($aEvent['object_id'], $this->_aModule['name'])) !== false)
+            $mixedResult['object_owner_id'] = $oAuthor->id();
+
+        /*
+         * Item should be shown to the author only as a 'welcome' item just after join.
+         */
+        $mixedResult['object_privacy_view'] = 2;
+
+        return $mixedResult;
+    }
+
+    /**
+     * Entry post for Timeline module
+     */
+    public function serviceGetTimelineProfilePicture($aEvent, $aBrowseParams = [])
+    {
+        $aResult = $this->_serviceGetTimelineProfileImage($aEvent, $aBrowseParams, [
+            'stg' => 'OBJECT_STORAGE',
+            'trans' => ['OBJECT_IMAGES_TRANSCODER_GALLERY', 'OBJECT_IMAGES_TRANSCODER_AVATAR'],
+            'trans_orig' => ['OBJECT_IMAGES_TRANSCODER_PICTURE', 'OBJECT_IMAGES_TRANSCODER_GALLERY'],
+            'txt_ss' => 'txt_sample_pp_single',
+            'txt_sswa' => 'txt_sample_pp_single_with_article',
+            'txt_sa' => 'txt_sample_pi_action',
+            'txt_sau' => 'txt_sample_pi_action_user'
+        ]);
+
+        if($aResult !== false)
+            $aResult['allowed_view'] = ['module' => $this->_oConfig->getName(), 'method' => 'get_timeline_profile_picture_allowed_view'];
+
+        return $aResult;
+    }
+
+    public function serviceGetTimelineProfilePictureAllowedView($aEvent)
+    {
+        return $this->_serviceGetTimelineProfileImageAllowedView($aEvent);
+    }
+
+    public function serviceGetTimelineProfileCover($aEvent, $aBrowseParams = [])
+    {
+        $aResult = $this->_serviceGetTimelineProfileImage($aEvent, $aBrowseParams, [
+            'stg' => 'OBJECT_STORAGE_COVER',
+            'trans' => ['OBJECT_IMAGES_TRANSCODER_GALLERY', 'OBJECT_IMAGES_TRANSCODER_COVER_THUMB'],
+            'trans_orig' => ['OBJECT_IMAGES_TRANSCODER_COVER', 'OBJECT_IMAGES_TRANSCODER_GALLERY'],
+            'txt_ss' => 'txt_sample_pc_single',
+            'txt_sswa' => 'txt_sample_pc_single_with_article',
+            'txt_sa' => 'txt_sample_pi_action',
+            'txt_sau' => 'txt_sample_pi_action_user'
+        ]);
+
+        if($aResult !== false)
+            $aResult['allowed_view'] = ['module' => $this->_oConfig->getName(), 'method' => 'get_timeline_profile_cover_allowed_view'];
+
+        return $aResult;
+    }
+    
+    public function serviceGetTimelineProfileCoverAllowedView($aEvent)
+    {
+        return $this->_serviceGetTimelineProfileImageAllowedView($aEvent);
+    }
+
+    public function serviceGetMenuItemTitleByConnection($sConnection, $sAction, $iContentProfileId, $iInitiatorProfileId = 0)
+    {
+        return $this->getMenuItemTitleByConnection($sConnection, $sAction, $iContentProfileId, $iInitiatorProfileId);
+    }
+
+
+    // ====== PERMISSION METHODS
+    /**
+     * @see iBxDolProfileService::serviceCheckAllowedProfileView
+     */ 
+    public function serviceCheckAllowedProfileView($iContentId)
+    {        
+        return $this->serviceCheckAllowedWithContent('View', $iContentId);
+    }
+
+    /**
+     * @see iBxDolProfileService::serviceCheckAllowedProfileContact
+     */ 
+    public function serviceCheckAllowedProfileContact($iContentId)
+    {        
+        return $this->serviceCheckAllowedWithContent('Contact', $iContentId);
+    }
+
+    /**
+     * @see iBxDolProfileService::serviceCheckAllowedPostInProfile
+     */
+    public function serviceCheckAllowedPostInProfile($iContentId, $sPostModule = '')
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        if(!empty($CNF['FIELD_ALLOW_VIEW_TO']) && getParam('sys_treat_cxt_in_cxt_as_cnt') == 'on') {
+            $aContentInfo = $this->_oDb->getContentInfoById($iContentId);
+            if($aContentInfo && isset($aContentInfo[$CNF['FIELD_ALLOW_VIEW_TO']]) && (int)$aContentInfo[$CNF['FIELD_ALLOW_VIEW_TO']] < 0)
+                return _t('_sys_txt_access_denied');
+        }
+
+        // for groups based profiles we do have a Role permissions which have a higher priority than the site-wide permissions.
+        if (method_exists($this, 'isAllowedModuleActionByProfile')) {
+            $iProfileId = $this->_iProfileId;
+
+            if(($sPrivacy = $CNF['OBJECT_PRIVACY_POST'] ?? false)) {
+                $oPrivacy = BxDolPrivacy::getObjectInstance($sPrivacy);
+                if($oPrivacy && !$oPrivacy->check($iContentId, $iProfileId))
+                    return _t('_sys_access_denied_to_private_content');
+            }
+
+            // if a profile is having a role and a role is having permissions set then it overrides the site-wide setting.
+            if (($bResult = $this->isAllowedModuleActionByProfile($iContentId, $sPostModule, 'post', $iProfileId)) !== NULL) 
+                return $bResult;
+        }
+
+        return $this->serviceCheckAllowedWithContent('Post', $iContentId);
+    }
+
+    /**
+     * @see iBxDolProfileService::serviceCheckAllowedModuleActionInProfile
+     */
+    public function serviceCheckAllowedModuleActionInProfile($iContentId, $sPostModule, $sActionName)
+    {
+        if (method_exists($this, 'isAllowedModuleActionByProfile')) {
+            $bResult = $this->isAllowedModuleActionByProfile($iContentId, $sPostModule, $sActionName);
+            if ($bResult !== NULL) return $bResult;
+        }
+
+        return _t('_Access denied');
+    }
+
+    /**
+     * @see iBxDolProfileService::serviceCheckSpacePrivacy
+     */ 
+    public function serviceCheckSpacePrivacy($iContentId)
+    {
+        return $this->serviceCheckAllowedProfileView($iContentId);
+    }
+
+    public function serviceCheckSpacePrivacyForProfile($iContentId, $iProfileId = false)
+    {
+        return $this->serviceCheckAllowedWithContentForProfile('View', $iContentId, $iProfileId);
+    }
+
+    /**
+     * Check if the profile can be viewed.
+     * 
+     * NOTE. This service should be used if it's needed to pass some specific values in 
+     * $isPerformAction and $iProfileId parameters, otherwise it's recommended to use 
+     * BxBaseModProfileModule::serviceCheckAllowedProfileView service method or 
+     * BxDolProfile::checkAllowedProfileView method.
+     * 
+     * @param type $aDataEntry - entry which the action will be performed for
+     * @param type $isPerformAction - perform or just check the action
+     * @param type $iProfileId - performer's profile ID
+     * @return integer - one of CHECK_ACTION_RESULT_XXX constants.
+     */
+    public function serviceCheckAllowedViewForProfile ($aDataEntry, $isPerformAction = false, $iProfileId = false)
+    {
+        if (!$iProfileId)
+            $iProfileId = $this->_iProfileId;
+
+        if(empty($aDataEntry) || !is_array($aDataEntry))
+            return _t('_sys_txt_not_found');
+
+        $sCacheKey = $this->getName() . ':' . __CLASS__ . ':serviceCheckAllowedViewForProfile:' . $aDataEntry['id'] . ':' . $iProfileId;
+        $mixedRet = bx_mem_cache_get($sCacheKey);
+        if (null !== $mixedRet)
+            return $mixedRet;
+        
+        $oProfile = BxDolProfile::getInstanceByContentAndType($aDataEntry[$this->_oConfig->CNF['FIELD_ID']], $this->getName());
+        if ($oProfile && $oProfile->id() == $iProfileId)
+            $mixedRet = CHECK_ACTION_RESULT_ALLOWED;
+        else
+            $mixedRet = parent::serviceCheckAllowedViewForProfile ($aDataEntry, $isPerformAction, $iProfileId);
+
+        bx_mem_cache_set($sCacheKey, $mixedRet);
+
+        return $mixedRet;
+    }
+
+    /**
+     * Check if posting (comment, post in Timeline) is available.
+     * 
+     * NOTE. This service should be used if it's needed to pass some specific values in 
+     * $isPerformAction and $iProfileId parameters, otherwise it's recommended to use 
+     * BxBaseModProfileModule::serviceCheckAllowedPostInProfile service method or 
+     * BxDolProfile::checkAllowedPostInProfile method.
+     * 
+     * @param type $aDataEntry - entry which the action will be performed for
+     * @param type $isPerformAction - perform or just check the action
+     * @param type $iProfileId - performer's profile ID
+     * @return integer - one of CHECK_ACTION_RESULT_XXX constants.
+     */
+    public function serviceCheckAllowedPostForProfile ($aDataEntry, $isPerformAction = false, $iProfileId = false)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        if(!$iProfileId)
+            $iProfileId = $this->_iProfileId;
+
+        // check is view allowed
+        if(($mixedResult = $this->serviceCheckAllowedViewForProfile($aDataEntry, $isPerformAction, $iProfileId)) !== CHECK_ACTION_RESULT_ALLOWED)
+            return $mixedResult;
+
+        // moderator and owner always have access
+        $oProfile = BxDolProfile::getInstanceByContentAndType($aDataEntry[$CNF['FIELD_ID']], $this->getName());
+        if(($oProfile && $oProfile->id() == $iProfileId) || $this->_isModerator($isPerformAction))
+            return CHECK_ACTION_RESULT_ALLOWED;
+
+        // check privacy
+        if(!empty($CNF['OBJECT_PRIVACY_POST'])) {
+            $oPrivacy = BxDolPrivacy::getObjectInstance($CNF['OBJECT_PRIVACY_POST']);
+            if($oPrivacy && !$oPrivacy->check($aDataEntry[$CNF['FIELD_ID']], $iProfileId))
+                return _t('_sys_access_denied_to_private_content');
+        }
+
+        // check alert to allow custom checks
+        $mixedResult = null;
+
+        /**
+         * @hooks
+         * @hookdef hook-system-check_allowed_post 'system', 'check_allowed_post' - hook to override the result of checking whether 'post' action is allowed or not to specified profile
+         * It's equivalent to @ref hook-system-check_allowed_view
+         * @hook @ref hook-system-check_allowed_post
+         */
+        bx_alert('system', 'check_allowed_post', 0, 0, [
+            'module' => $this->getName(), 
+            'content_info' => $aDataEntry, 
+            'profile_id' => $iProfileId, 
+            'override_result' => &$mixedResult
+        ]);
+        if($mixedResult !== null)
+            return $mixedResult;
+
+        return CHECK_ACTION_RESULT_ALLOWED;
+    }
+
+    /**
+     * Check if profile can be contacted.
+     * 
+     * NOTE. This service should be used if it's needed to pass some specific values in 
+     * $isPerformAction and $iProfileId parameters, otherwise it's recommended to use 
+     * BxBaseModProfileModule::serviceCheckAllowedProfileContact service method or 
+     * BxDolProfile::checkAllowedProfileContact method.
+     * 
+     * @param type $aDataEntry - entry which the action will be performed for
+     * @param type $isPerformAction - perform or just check the action
+     * @param type $iProfileId - performer's profile ID
+     * @return integer - one of CHECK_ACTION_RESULT_XXX constants.
+     */
+    public function serviceCheckAllowedContactForProfile ($aDataEntry, $isPerformAction = false, $iProfileId = false)
+    {
+        $mixedResult = $this->_serviceCheckAllowedContactForProfile($aDataEntry, $isPerformAction, $iProfileId);
+
+        /**
+         * @hooks
+         * @hookdef hook-system-check_allowed_contact 'system', 'check_allowed_contact' - hook to override the result of checking whether 'contact' action is allowed or not to specified profile
+         * It's equivalent to @ref hook-system-check_allowed_view
+         * @hook @ref hook-system-check_allowed_contact
+         */
+        bx_alert('system', 'check_allowed_contact', 0, 0, [
+            'module' => $this->getName(), 
+            'content_info' => $aDataEntry, 
+            'profile_id' => $iProfileId, 
+            'override_result' => &$mixedResult
+        ]);
+
+        return $mixedResult;
+    }
+
+    public function serviceSetViewProfileCover($oPage, $aProfileInfo)
+    {
+        $this->_oTemplate->setCover($oPage,$aProfileInfo);
+    }
+    
+    /** 
+     * Returns list of members by mode with limited number of records for React Jot
+     * @param string $sMode
+     * @param int $iStart
+     * @param int $iPerPage
+     * @return mixed
+     */
+    public function serviceGetMembers($sMode = 'active', $iStart = 0, $iPerPage = 10){
+        bx_import('SearchResult', $this->_aModule);
+        $sClass = $this->_aModule['class_prefix'] . 'SearchResult';
+        $o = new $sClass($sMode);
+
+        $o -> aCurrent['paginate'] = array('perPage' => $iPerPage, 'forceStart' => $iStart);
+        return $o -> getSearchData();
+    }
+
+    /**
+     * @return CHECK_ACTION_RESULT_ALLOWED if access is granted or error message if access is forbidden. So make sure to make strict(===) checking.
+     */
+    public function checkAllowedAdd ($isPerformAction = false)
+    {
+        if($this->serviceActAsProfile() && ($oAccount = BxDolAccount::getInstance()) !== false && $oAccount->isProfilesLimitReached())
+            return _t('_sys_txt_access_denied');
+
+        return parent::checkAllowedAdd ($isPerformAction);
+    }
+
+    /**
+     * @return CHECK_ACTION_RESULT_ALLOWED if access is granted or error message if access is forbidden. So make sure to make strict(===) checking.
+     */
+    public function checkAllowedView ($aDataEntry, $isPerformAction = false)
+    {
+        return $this->serviceCheckAllowedViewForProfile ($aDataEntry, $isPerformAction);
+    }
+    
+    /**
+     * @return CHECK_ACTION_RESULT_ALLOWED if access is granted or error message if access is forbidden.
+     */
+    public function checkAllowedViewProfileImage ($aDataEntry, $isPerformAction = false)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $sCacheKey = $this->getName() . ':' . __CLASS__ . ':checkAllowedViewProfileImage:' . $aDataEntry[$CNF['FIELD_ID']];
+        $mixedRet = bx_mem_cache_get($sCacheKey);
+        if (null !== $mixedRet)
+            return $mixedRet;
+
+        // check privacy
+
+        if (empty($CNF['OBJECT_PRIVACY_VIEW']) || isAdmin() || CHECK_ACTION_RESULT_ALLOWED === $this->checkAllowedEditAnyEntry()) {
+            $mixedRet = CHECK_ACTION_RESULT_ALLOWED;
+        } 
+        elseif (($oPrivacy = BxDolPrivacy::getObjectInstance($CNF['OBJECT_PRIVACY_VIEW'])) && !$oPrivacy->check($aDataEntry[$CNF['FIELD_ID']]) && !$oPrivacy->isPartiallyVisible($aDataEntry[$CNF['FIELD_ALLOW_VIEW_TO']])) {
+            $mixedRet = _t('_sys_access_denied_to_private_content');
+        }
+        else {
+            $mixedRet = CHECK_ACTION_RESULT_ALLOWED;
+        }
+
+        bx_mem_cache_set($sCacheKey, $mixedRet);
+
+        return $mixedRet;
+    }
+
+    /**
+     * @return CHECK_ACTION_RESULT_ALLOWED if access is granted or error message if access is forbidden.
+     */
+    public function checkAllowedViewCoverImage ($aDataEntry, $isPerformAction = false)
+    {
+        return $this->checkAllowedViewProfileImage($aDataEntry);
+    }
+    
+    /**
+     * @return CHECK_ACTION_RESULT_ALLOWED if access is granted or error message if access is forbidden.
+     */
+    public function checkAllowedViewBadgeImage ($aDataEntry, $isPerformAction = false)
+    {
+        $oProfile = BxDolProfile::getInstanceByContentAndType($aDataEntry[$this->_oConfig->CNF['FIELD_ID']], $this->_aModule['name']);
+        if(!$oProfile)
+            return _t('_sys_txt_error_occured');
+
+        $aCheck = checkActionModule($oProfile->id(), 'change badge', $this->_aModule['name'], false);
+        if($aCheck[CHECK_ACTION_RESULT] !== CHECK_ACTION_RESULT_ALLOWED)
+            return $aCheck[CHECK_ACTION_MESSAGE];       
+
+        return $this->checkAllowedViewProfileImage($aDataEntry, $isPerformAction);
+    }
+
+    /**
+     * @return CHECK_ACTION_RESULT_ALLOWED if access is granted or error message if access is forbidden.
+     */
+    public function checkAllowedPost ($aDataEntry, $isPerformAction = false)
+    {
+        return $this->serviceCheckAllowedPostForProfile ($aDataEntry, $isPerformAction);
+    }
+
+    /**
+     * @return CHECK_ACTION_RESULT_ALLOWED if access is granted or error message if access is forbidden.
+     */
+    public function checkAllowedContact ($aDataEntry, $isPerformAction = false)
+    {
+        return $this->serviceCheckAllowedContactForProfile ($aDataEntry, $isPerformAction);
+    }
+
+    /**
+     * @return CHECK_ACTION_RESULT_ALLOWED if access is granted or error message if access is forbidden.
+     */
+    public function checkAllowedEdit ($aDataEntry, $isPerformAction = false)
+    {
+        if(empty($aDataEntry) || !is_array($aDataEntry))
+            return _t('_sys_txt_not_found');
+
+        // moderator always has access
+        if ($this->_isModerator($isPerformAction))
+            return CHECK_ACTION_RESULT_ALLOWED;
+
+        // owner (checked by account instead of author!) always have access
+        $oProfile = BxDolProfile::getInstanceByContentAndType($aDataEntry[$this->_oConfig->CNF['FIELD_ID']], $this->_aModule['name']);
+        if (!$oProfile)
+            return _t('_sys_txt_error_occured');
+
+        if ($oProfile->id() == $this->_iProfileId || $oProfile->getAccountId() == $this->_iAccountId)
+            return CHECK_ACTION_RESULT_ALLOWED;
+
+        return _t('_sys_txt_access_denied');
+    }
+
+    public function checkAllowedChangeBadge ($aDataEntry, $isPerformAction = false)
+    {
+        if(empty($aDataEntry) || !is_array($aDataEntry))
+            return _t('_sys_txt_not_found');
+
+        // moderator always has access
+        if($this->_isModerator($isPerformAction))
+            return CHECK_ACTION_RESULT_ALLOWED;
+
+        // owner (checked by account instead of author!) always have access
+        $oProfile = BxDolProfile::getInstanceByContentAndType($aDataEntry[$this->_oConfig->CNF['FIELD_ID']], $this->_aModule['name']);
+        if(!$oProfile)
+            return _t('_sys_txt_error_occured');
+
+        if($oProfile->getAccountId() != $this->_iAccountId)
+            return _t('_sys_txt_access_denied');
+
+        $aCheck = checkActionModule($this->_iProfileId, 'change badge', $this->getName(), false);
+        if($aCheck[CHECK_ACTION_RESULT] !== CHECK_ACTION_RESULT_ALLOWED)
+            return $aCheck[CHECK_ACTION_MESSAGE];
+
+        return CHECK_ACTION_RESULT_ALLOWED;
+    }
+
+    /**
+     * Check if user can change cover image
+     */
+    public function checkAllowedChangeCover ($aDataEntry, $isPerformAction = false)
+    {
+        // moderator always has access
+        if ($this->_isModerator($isPerformAction))
+            return CHECK_ACTION_RESULT_ALLOWED;
+
+        // owner (checked by account instead of author!) always have access
+        $oProfile = BxDolProfile::getInstanceByContentAndType($aDataEntry[$this->_oConfig->CNF['FIELD_ID']], $this->_aModule['name']);
+        if (!$oProfile)
+            return _t('_sys_txt_error_occured');
+
+        if ($oProfile->id() == $this->_iProfileId || $oProfile->getAccountId() == $this->_iAccountId)
+            return CHECK_ACTION_RESULT_ALLOWED;
+
+        return _t('_sys_txt_access_denied');
+    }
+
+    /**
+     * Check if user can change settings
+     */
+    public function checkAllowedChangeSettings ($aDataEntry, $isPerformAction = false)
+    {
+        // moderator always has access
+        if ($this->_isModerator($isPerformAction))
+            return CHECK_ACTION_RESULT_ALLOWED;
+
+        // owner (checked by account instead of author!) always have access
+        $oProfile = BxDolProfile::getInstanceByContentAndType($aDataEntry[$this->_oConfig->CNF['FIELD_ID']], $this->_aModule['name']);
+        if (!$oProfile)
+            return _t('_sys_txt_error_occured');
+
+        if ($oProfile->id() == $this->_iProfileId || $oProfile->getAccountId() == $this->_iAccountId)
+            return CHECK_ACTION_RESULT_ALLOWED;
+
+        return _t('_sys_txt_access_denied');
+    }
+
+    /**
+     * @return CHECK_ACTION_RESULT_ALLOWED if access is granted or error message if access is forbidden.
+     */
+    public function checkAllowedDelete (&$aDataEntry, $isPerformAction = false)
+    {
+        // moderator always has access
+        if ($this->_isModerator($isPerformAction))
+            return CHECK_ACTION_RESULT_ALLOWED;
+
+        // owner (checked by account instead of author!) always have access
+        $aCheck = checkActionModule($this->_iProfileId, 'delete entry', $this->getName(), $isPerformAction);
+
+        $oProfile = BxDolProfile::getInstanceByContentAndType($aDataEntry[$this->_oConfig->CNF['FIELD_ID']], $this->_aModule['name'], $isPerformAction);
+        if (!$oProfile)
+            return _t('_sys_txt_error_occured');
+
+        if (($oProfile->id() == $this->_iProfileId || $oProfile->getAccountId() == $this->_iAccountId) && $aCheck[CHECK_ACTION_RESULT] === CHECK_ACTION_RESULT_ALLOWED)
+            return CHECK_ACTION_RESULT_ALLOWED;
+
+        return _t('_sys_txt_access_denied');
+    }
+
+    /**
+     * @return CHECK_ACTION_RESULT_ALLOWED if access is granted or error message if access is forbidden.
+     */
+    public function checkAllowedViewMoreMenu (&$aDataEntry, $isPerformAction = false)
+    {
+        $oMenu = BxTemplMenu::getObjectInstance($this->_oConfig->CNF['OBJECT_MENU_ACTIONS_VIEW_ENTRY_MORE']);
+        if (!$oMenu || !$oMenu->getCode())
+            return _t('_sys_txt_access_denied');
+        return CHECK_ACTION_RESULT_ALLOWED;
+    }
+
+    /**
+     * Compose differs from Contact. For example, a user should NOT be able to start conversation (compose) 
+     * with himself but he should be able to view conversation page where he is one of the participants.
+     * 
+     * @return CHECK_ACTION_RESULT_ALLOWED if access is granted or error message if access is forbidden.
+     */
+    public function checkAllowedCompose(&$aDataEntry, $isPerformAction = false)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $oProfile = BxDolProfile::getInstanceByContentAndType($aDataEntry[$CNF['FIELD_ID']], $this->getName());
+        if($oProfile && $oProfile->id() == $this->_iProfileId)
+            return _t('_sys_txt_access_denied');
+
+        return $this->checkAllowedContact($aDataEntry, $isPerformAction);
+    }
+
+    public function checkAllowedFriendsView (&$aDataEntry, $isPerformAction = false)
+    {
+        $sResult = _t('_sys_txt_access_denied');
+        if(!$this->_oConfig->isFriends())
+            return $sResult;
+
+        if(empty($aDataEntry) || !is_array($aDataEntry))
+            return $sResult;
+
+        return CHECK_ACTION_RESULT_ALLOWED;
+    }
+
+    public function checkAllowedFriends (&$aDataEntry, $isPerformAction = false)
+    {
+        if(!$this->_oConfig->isFriends() || ($oProfile = BxDolProfile::getInstance($this->_iProfileId)) === false || !bx_srv($oProfile->getModule(), 'is_enable_friends'))
+            return _t('_sys_txt_access_denied');
+
+        return CHECK_ACTION_RESULT_ALLOWED;
+    }
+
+    /**
+     * @return CHECK_ACTION_RESULT_ALLOWED if access is granted or error message if access is forbidden.
+     */
+    public function checkAllowedFriendAdd (&$aDataEntry, $isPerformAction = false)
+    {
+        if(!$this->_oConfig->isFriends() || ($oProfile = BxDolProfile::getInstance($this->_iProfileId)) === false || !bx_srv($oProfile->getModule(), 'is_enable_friends'))
+            return _t('_sys_txt_access_denied');
+
+        return $this->_checkAllowedConnect ($aDataEntry, $isPerformAction, ['sys_profiles_friends', 'checkAllowedAddConnection'], false, false);
+    }
+
+    /**
+     * @return CHECK_ACTION_RESULT_ALLOWED if access is granted or error message if access is forbidden.
+     */
+    public function checkAllowedFriendRemove (&$aDataEntry, $isPerformAction = false)
+    {
+        if(!$this->_oConfig->isFriends() || ($oProfile = BxDolProfile::getInstance($this->_iProfileId)) === false || !bx_srv($oProfile->getModule(), 'is_enable_friends'))
+            return _t('_sys_txt_access_denied');
+
+        if (CHECK_ACTION_RESULT_ALLOWED === $this->_checkAllowedConnect ($aDataEntry, $isPerformAction, ['sys_profiles_friends', 'checkAllowedRemoveConnection'], false, true, true))
+            return CHECK_ACTION_RESULT_ALLOWED;
+
+        return $this->_checkAllowedConnect ($aDataEntry, $isPerformAction, ['sys_profiles_friends', 'checkAllowedRemoveConnection'], false, true, false);
+    }
+
+    public function checkAllowedRelations (&$aDataEntry, $isPerformAction = false)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $sResult = _t('_sys_txt_access_denied');
+        if(!BxDolConnectionRelation::isEnabled())
+            return $sResult;
+
+        if(($sMsg = $this->checkAllowedView($aDataEntry)) !== CHECK_ACTION_RESULT_ALLOWED)
+            return $sMsg;
+
+        $oProfile = BxDolProfile::getInstanceByContentAndType($aDataEntry[$CNF['FIELD_ID']], $this->_aModule['name']);
+        if(!$oProfile || $oProfile->id() == $this->_iProfileId)
+            return $sResult;
+
+        if(!BxDolConnection::getObjectInstance('sys_profiles_relations')->isRelationAvailable($this->_iProfileId, $oProfile->id()))
+            return $sResult;
+
+        return CHECK_ACTION_RESULT_ALLOWED;
+    }
+
+    /**
+     * @return CHECK_ACTION_RESULT_ALLOWED if access is granted or error message if access is forbidden.
+     */
+    public function checkAllowedRelationAdd (&$aDataEntry, $isPerformAction = false)
+    {
+        $sResult = _t('_sys_txt_access_denied');
+        if(!BxDolConnectionRelation::isEnabled())
+            return $sResult;
+
+        if(($sMsg = $this->checkAllowedView($aDataEntry)) !== CHECK_ACTION_RESULT_ALLOWED)
+            return $sMsg;
+
+        return $this->_checkAllowedConnect ($aDataEntry, $isPerformAction, 'sys_profiles_relations', false, false);
+    }
+
+    /**
+     * @return CHECK_ACTION_RESULT_ALLOWED if access is granted or error message if access is forbidden.
+     */
+    public function checkAllowedRelationRemove (&$aDataEntry, $isPerformAction = false)
+    {
+        $sResult = _t('_sys_txt_access_denied');
+        if(!BxDolConnectionRelation::isEnabled())
+            return $sResult;
+
+        return $this->_checkAllowedConnect ($aDataEntry, $isPerformAction, 'sys_profiles_relations', false, true);
+    }
+
+    public function checkAllowedRelationsView (&$aDataEntry, $isPerformAction = false)
+    {
+        $sResult = _t('_sys_txt_access_denied');
+        if(!BxDolConnectionRelation::isEnabled())
+            return $sResult;
+
+        $sModule = $this->_oConfig->getName();
+        $oRelations = BxDolConnection::getObjectInstance('sys_profiles_relations');
+        if(!$oRelations->isRelationAvailableWithProfile($sModule) && !$oRelations->isRelationAvailableFromProfile($sModule))
+            return $sResult;
+
+        if(empty($aDataEntry) || !is_array($aDataEntry))
+            return $sResult;
+
+        return CHECK_ACTION_RESULT_ALLOWED;
+    }
+
+    public function checkAllowedSubscriptions(&$aDataEntry, $isPerformAction = false)
+    {
+        if(($sMsg = $this->checkAllowedView($aDataEntry)) !== CHECK_ACTION_RESULT_ALLOWED)
+            return $sMsg;
+
+        return $this->_checkAllowedConnect ($aDataEntry, $isPerformAction, ['sys_profiles_subscriptions', 'checkAllowedConnectByAcl'], false, false);
+    }
+
+    /**
+     * @return CHECK_ACTION_RESULT_ALLOWED if access is granted or error message if access is forbidden.
+     */
+    public function checkAllowedSubscribeAdd(&$aDataEntry, $isPerformAction = false)
+    {
+        $mixedResult = $this->_modProfileCheckAllowedSubscribeAdd($aDataEntry, $isPerformAction);
+
+        /**
+         * @hooks
+         * @hookdef hook-system-check_allowed_subscribe_add 'system', 'check_allowed_subscribe_add' - hook to override the result of checking whether 'subscribe' action is allowed or not to currently logged in user
+         * It's equivalent to @ref hook-system-check_allowed_view
+         * @hook @ref hook-system-check_allowed_subscribe_add
+         */
+        bx_alert('system', 'check_allowed_subscribe_add', 0, 0, [
+            'module' => $this->getName(), 
+            'content_info' => $aDataEntry, 
+            'profile_id' => bx_get_logged_profile_id(), 
+            'override_result' => &$mixedResult
+        ]);
+
+        return $mixedResult;
+    }
+
+    /**
+     * Note. Is mainly needed for internal usage. Access level is 'public' to allow outer calls from alerts.
+     */
+    public function _modProfileCheckAllowedSubscribeAdd(&$aDataEntry, $isPerformAction = false)
+    {
+        if(($sMsg = $this->checkAllowedView($aDataEntry)) !== CHECK_ACTION_RESULT_ALLOWED)
+            return $sMsg;
+
+        return $this->_checkAllowedConnect($aDataEntry, $isPerformAction, 'sys_profiles_subscriptions', false, false);
+    }
+
+    /**
+     * @return CHECK_ACTION_RESULT_ALLOWED if access is granted or error message if access is forbidden.
+     */
+    public function checkAllowedSubscribeRemove (&$aDataEntry, $isPerformAction = false)
+    {
+        return $this->_checkAllowedConnect ($aDataEntry, $isPerformAction, 'sys_profiles_subscriptions', false, true);
+    }
+
+    public function checkAllowedSubscriptionsView (&$aDataEntry, $isPerformAction = false)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $sResult = _t('_sys_txt_access_denied');
+        if(empty($aDataEntry) || !is_array($aDataEntry))
+            return $sResult;
+
+        $oProfile = BxDolProfile::getInstanceByContentAndType($aDataEntry[$CNF['FIELD_ID']], $this->_aModule['name']);
+        if(!$oProfile || ($oProfile->id() != $this->_iProfileId && $this->_oDb->getParam($CNF['PARAM_PUBLIC_SBSN']) != 'on' && $this->_oDb->getParam($CNF['PARAM_PUBLIC_SBSD']) != 'on'))
+            return $sResult;
+
+        return CHECK_ACTION_RESULT_ALLOWED;
+    }
+
+    public function checkMyself($iContentId)
+    {
+		$iLogged = (int)bx_get_logged_profile_id();
+    	if(empty($iLogged))
+    		return false;
+
+    	$oProfile = BxDolProfile::getInstanceByContentAndType((int)$iContentId, $this->_oConfig->getName());
+    	if(!$oProfile)
+    		return false;
+
+		return $oProfile->id() == $iLogged;
+    }
+    
+    public function isAllowDeleteOrDisable($iActorProfileId, $iTargetProfileId)
+    {
+        if (BxDolAcl::getInstance()->isMemberLevelInSet(array(MEMBERSHIP_ID_MODERATOR), $iActorProfileId) && BxDolAcl::getInstance()->isMemberLevelInSet(array(MEMBERSHIP_ID_MODERATOR, MEMBERSHIP_ID_ADMINISTRATOR), $iTargetProfileId))
+            return false;
+        
+        return true;    
+    }
+    
+    public function getProfileObject($iContentId)
+    {
+    	$oProfile = BxDolProfile::getInstanceByContentAndType((int)$iContentId, $this->_oConfig->getName());
+        if (!$oProfile) 
+            $oProfile = BxDolProfileUndefined::getInstance();
+
+        return $oProfile;
+    }
+
+    protected function _serviceCheckAllowedContactForProfile($aDataEntry, $isPerformAction = false, $iProfileId = false)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        if(!$iProfileId)
+            $iProfileId = $this->_iProfileId;
+
+        /*
+         * allow to 'contact myself'. It's needed to allow a user to view conversation page 
+         * where he is one of the participants.
+         */
+        $oProfile = BxDolProfile::getInstanceByContentAndType($aDataEntry[$CNF['FIELD_ID']], $this->getName());
+        if($oProfile && $oProfile->id() == $iProfileId)
+            return CHECK_ACTION_RESULT_ALLOWED;
+
+        // moderator always has access
+        if($this->_isModeratorForProfile($isPerformAction, $iProfileId))
+            return CHECK_ACTION_RESULT_ALLOWED;
+
+        // check privacy
+        if(!empty($CNF['OBJECT_PRIVACY_CONTACT'])) {
+            $oPrivacy = BxDolPrivacy::getObjectInstance($CNF['OBJECT_PRIVACY_CONTACT']);
+            if($oPrivacy && !$oPrivacy->check($aDataEntry[$CNF['FIELD_ID']], $iProfileId))
+                return _t('_sys_access_denied_to_private_content');
+        }
+
+        return CHECK_ACTION_RESULT_ALLOWED;
+    }
+
+    // ====== COMMON METHODS
+    public function isBadge($aData)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        return !empty($CNF['FIELD_BADGE']) && $this->checkAllowedViewBadgeImage($aData) === CHECK_ACTION_RESULT_ALLOWED;
+    }
+
+    public function isMenuItemVisible($sObject, &$aItem, &$aContentInfo)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $bResult = parent::isMenuItemVisible($sObject, $aItem, $aContentInfo);
+        if(!$bResult)
+            return $bResult;
+
+        if(($sField = 'FIELD_STG_TABS') && !empty($CNF[$sField]) && isset($aContentInfo[$CNF[$sField]]) && ($sTabs = $aContentInfo[$CNF[$sField]])) {
+            $aTabs = explode(',', $sTabs);
+            if(in_array($aItem['name'], $aTabs))
+                return false;
+        }
+
+        return $bResult;
+    }
+
+    public function onUpdateImage($iContentId, $sFiledName, $sFiledValue, $iProfileId = 0)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $sModule = $this->getName();
+
+        if(!$iProfileId && ($oProfile = BxDolProfile::getInstanceByContentAndType($iContentId, $sModule)) !== false)
+            $iProfileId = $oProfile->id();
+
+        bx_content_cache_del_by_prefix('sprofile_unit_vars:' . $iProfileId . ':');
+        bx_content_cache_del_by_prefix('menu_sys_toolbar_member_p' . $iProfileId);
+
+        $aField2Method = [
+            $CNF['FIELD_PICTURE'] => 'picture',
+            $CNF['FIELD_COVER'] => 'cover',
+        ];
+
+        if(!empty($aField2Method[$sFiledName]))
+            /**
+             * @hooks
+             * @hookdef hook-bx_base_profile-profile_picture_changed '{module_name}', 'profile_picture_changed' - hook after profile picture was changed
+             * - $unit_name - module name
+             * - $action - equals `profile_picture_changed`
+             * - $object_id - image id
+             * - $sender_id - profile id who performed the action
+             * - $extra_params - array of additional params with the following array keys:
+             *      - `object_author_id` - [int] profile id
+             *      - `content` - [int] profile content id
+             *      - `field` - [string] field name
+             * @hook @ref hook-bx_base_profile-profile_picture_changed
+             */
+            /**
+             * @hooks
+             * @hookdef hook-bx_base_profile-profile_cover_changed '{module_name}', 'profile_cover_changed' - hook after profile cover was changed
+             * It's equivalent to @ref hook-bx_base_profile-profile_picture_changed
+             * @hook @ref hook-bx_base_profile-profile_cover_changed
+             */
+            bx_alert($sModule, 'profile_' . $aField2Method[$sFiledName] . '_changed', $sFiledValue, $iProfileId, [
+                'object_author_id' => $iProfileId, 
+                'content' => $iContentId, 
+                'field' => $sFiledName
+            ]);
+    }
+
+    protected function _alertParams($aContentInfo)
+    {
+        $aParams = parent::_alertParams($aContentInfo);
+
+        $CNF = &$this->_oConfig->CNF;
+
+        if(!empty($CNF['FIELD_STATUS']) && isset($aContentInfo[$CNF['FIELD_STATUS']]))
+            $aParams['status'] = $aContentInfo[$CNF['FIELD_STATUS']];
+
+        if(!empty($CNF['FIELD_STATUS_ADMIN']) && isset($aContentInfo[$CNF['FIELD_STATUS_ADMIN']]))
+            $aParams['status_admin'] = $aContentInfo[$CNF['FIELD_STATUS_ADMIN']];
+
+        if(!empty($CNF['FIELD_ALLOW_VIEW_TO']) && isset($aContentInfo[$CNF['FIELD_ALLOW_VIEW_TO']]))
+            $aParams['privacy_view'] = $aContentInfo[$CNF['FIELD_ALLOW_VIEW_TO']];
+
+        return $aParams;
+    }
+
+    public function alertAfterAdd($aContentInfo)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $sModule = $this->getName();
+        $iContentId = (int)$aContentInfo[$CNF['FIELD_ID']];
+        $iAuthorId = false;
+        if(($oProfile = BxDolProfile::getInstanceByContentAndType($iContentId, $sModule)) !== false)
+            $iAuthorId = $oProfile->id();
+
+        $aParams = $this->_alertParams($aContentInfo);
+
+        /**
+         * @hooks
+         * @hookdef hook-bx_base_profile-added '{module_name}', 'added' - hook after profile was added
+         * - $unit_name - module name
+         * - $action - equals `added`
+         * - $object_id - profile content id
+         * - $sender_id - not used
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `status` - [string] context status
+         *      - `status_admin` - [string] context admin status
+         *      - `privacy_view` - [int] or [string] privacy for view context action, @see BxDolPrivacy
+         * @hook @ref hook-bx_base_profile-added
+         */
+        bx_alert($this->getName(), 'added', $iContentId, $iAuthorId, $aParams);
+    }
+
+    public function alertAfterEdit($aContentInfo)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $sModule = $this->getName();
+        $iContentId = (int)$aContentInfo[$CNF['FIELD_ID']];
+
+        $aParams = $this->_alertParams($aContentInfo);
+        /**
+         * @hooks
+         * @hookdef hook-bx_base_profile-edited '{module_name}', 'edited' - hook after profile was changed
+         * It's equivalent to @ref hook-bx_base_profile-added
+         * @hook @ref hook-bx_base_profile-edited
+         */
+        bx_alert($sModule, 'edited', $iContentId, false, $aParams);
+
+        $oProfile = BxDolProfile::getInstanceByContentAndType($iContentId, $sModule);
+        
+        /**
+         * @hooks
+         * @hookdef hook-profile-edit 'profile', 'edit' - hook after profile was changed
+         * - $unit_name - equals `profile`
+         * - $action - equals `edit`
+         * - $object_id - profile id
+         * - $sender_id - not used
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `content` - [int] profile content id
+         *      - `module` - [string] module name
+         * @hook @ref hook-profile-added
+         */
+        bx_alert('profile', 'edit', $oProfile->id(), 0, [
+            'content' => $iContentId, 
+            'module' => $sModule
+        ]);
+    }
+
+    public function getProfileByCurrentUrl ()
+    {
+        $iProfileId = bx_process_input(bx_get('profile_id'), BX_DATA_INT);
+        
+        if ($iProfileId)
+            return  BxDolProfile::getInstance($iProfileId);
+
+        $iContentId = bx_process_input(bx_get('id'), BX_DATA_INT);
+        if ($iContentId)
+            return BxDolProfile::getInstanceByContentAndType($iContentId, $this->getName());
+        
+        return false;
+    }
+    
+    public function getEntryImageData($aContentInfo, $sField = 'FIELD_PICTURE', $aTranscoders = array())
+    {
+        return parent::getEntryImageData($aContentInfo, $sField, $aTranscoders);
+    }
+    
+    public function getProfileName ($aContentInfo)
+    {
+        return bx_process_output($aContentInfo[$this->_oConfig->CNF['FIELD_NAME']]);
+    }
+    
+    public function getMenuItemTitleByConnection($sConnection, $sAction, $iContentProfileId, $iInitiatorProfileId = 0)
+    {
+        $oConnection = BxDolConnection::getObjectInstance($sConnection);
+        if(!$oConnection)
+            return false;
+        
+        if(!$iInitiatorProfileId)
+            $iInitiatorProfileId = bx_get_logged_profile_id();
+
+        $aResult = [];
+        switch($sConnection) {
+            case 'sys_profiles_friends':
+                $aResult = $this->_getMenuItemTitleProfilesFriends($sAction, $iContentProfileId, $iInitiatorProfileId, $oConnection);
+                break;
+
+            case 'sys_profiles_subscriptions':
+                $aResult = $this->_getMenuItemTitleProfilesSubscriptions($sAction, $iContentProfileId, $iInitiatorProfileId, $oConnection);
+                break;
+        }
+
+        return $aResult;
+    }
+
+    protected function _getMenuItemTitleProfilesFriends($sAction, $iContentProfileId, $iInitiatorProfileId, &$oConnection)
+    {
+        $CNF = $this->_oConfig->getCNF();
+
+        $aResult = [];
+        if($oConnection->isConnectedNotMutual($iInitiatorProfileId, $iContentProfileId))
+            $aResult = [
+                'add' => _t(!empty($CNF['T']['menu_item_title_befriend_sent']) ? $CNF['T']['menu_item_title_befriend_sent'] : '_sys_menu_item_title_sm_befriend_sent'),
+                'remove' => _t(!empty($CNF['T']['menu_item_title_unfriend_cancel']) ? $CNF['T']['menu_item_title_unfriend_cancel'] : '_sys_menu_item_title_sm_unfriend_cancel'),
+            ];
+        else if($oConnection->isConnectedNotMutual($iContentProfileId, $iInitiatorProfileId))
+            $aResult = [
+                'add' => _t(!empty($CNF['T']['menu_item_title_befriend_confirm']) ? $CNF['T']['menu_item_title_befriend_confirm'] : '_sys_menu_item_title_sm_befriend_confirm'),
+                'remove' => _t(!empty($CNF['T']['menu_item_title_unfriend_reject']) ? $CNF['T']['menu_item_title_unfriend_reject'] : '_sys_menu_item_title_sm_unfriend_reject'),
+            ];
+        else if($oConnection->isConnected($iInitiatorProfileId, $iContentProfileId, true))
+            $aResult = [
+                'add' => '',
+                'remove' => _t(!empty($CNF['T']['menu_item_title_unfriend']) ? $CNF['T']['menu_item_title_unfriend'] : '_sys_menu_item_title_sm_unfriend'),
+            ];
+        else
+            $aResult = [
+                'add' => _t(!empty($CNF['T']['menu_item_title_befriend']) ? $CNF['T']['menu_item_title_befriend'] : '_sys_menu_item_title_sm_befriend'),
+                'remove' => '',
+            ];
+
+        return !empty($sAction) && isset($aResult[$sAction]) ? $aResult[$sAction] : $aResult;
+    }
+
+    protected function _getMenuItemTitleProfilesSubscriptions($sAction, $iContentProfileId, $iInitiatorProfileId, &$oConnection)
+    {
+        $CNF = $this->_oConfig->getCNF();
+
+        $aResult = [];
+        if($oConnection->isConnected($iInitiatorProfileId, $iContentProfileId))
+            $aResult = [
+                'add' => '',
+                'remove' => _t(!empty($CNF['T']['menu_item_title_unsubscribe']) ? $CNF['T']['menu_item_title_unsubscribe'] : '_sys_menu_item_title_sm_unsubscribe'),
+            ];
+        else
+            $aResult = [
+                'add' => _t(!empty($CNF['T']['menu_item_title_subscribe']) ? $CNF['T']['menu_item_title_subscribe'] : '_sys_menu_item_title_sm_subscribe'),
+                'remove' => '',
+            ];
+
+        return !empty($sAction) && !empty($aResult[$sAction]) ? $aResult[$sAction] : $aResult;
+    }
+    
+    public function decodeDataAPI($aData, $aParams = [])
+    {
+        $CNF = $this->_oConfig->CNF;
+
+        $sModule = $this->getName();
+        $iId = (int)$aData[$CNF['FIELD_ID']];
+        $oProfile = BxDolProfile::getInstanceByContentAndType($iId, $sModule);
+
+        $aResult = [
+            'id' => $iId, 
+            'module' => $sModule,
+            'module_title' => _t($CNF['T']['txt_sample_single']),
+            'added' => $aData[$CNF['FIELD_ADDED']],
+            'author' => $aData[$CNF['FIELD_AUTHOR']],
+            'author_data' => $oProfile !== false ? BxDolProfile::getData($oProfile->id()) : '',
+            'title' => $aData[$CNF['FIELD_TITLE']],
+            $CNF['FIELD_TITLE'] => $aData[$CNF['FIELD_TITLE']],
+            'url' => bx_api_get_relative_url($this->serviceGetLink($iId)),
+            'image' => $this->serviceGetThumb($iId),
+            'cover' => $this->serviceGetCover($iId),
+        ];
+
+        if(isset($aParams['template']) && $aParams['template'] == 'unit_wo_info')
+            return $aResult;
+
+        if(isset($aParams['extended']) && $aParams['extended'] === true)
+            $aResult['text'] = $aData[$CNF['FIELD_TEXT']];
+
+        if(getParam('sys_api_conn_in_prof_units') == 'on' && $oProfile !== false) {
+            $iProfileId = $oProfile->id();
+            $aResult['title'] = $oProfile->getDisplayName();
+            $aResult['online'] = $oProfile->isOnline();
+            if(($oConnection = BxDolConnection::getObjectInstance('sys_profiles_friends')) !== false && isset($CNF['URI_VIEW_FRIENDS'])) {
+                $aResult['friends_count'] = $oConnection->getConnectedContentCount($iProfileId, true);
+                $aResult['friends_list'] = $oConnection->getConnectedListAPI($iProfileId, true, BX_CONNECTIONS_CONTENT_TYPE_CONTENT);
+                if(isLogged()) {
+                    $iLoggedId = bx_get_logged_profile_id();
+                    $aResult['mutual_friends_count'] = $oConnection->getCommonContentCount($iProfileId, $iLoggedId, true);
+                    $aResult['mutual_friends_list'] = $oConnection->getCommonListAPI($iProfileId, $iLoggedId, true);
+                }
+            }
+
+            if(($oConnection = BxDolConnection::getObjectInstance('sys_profiles_subscriptions')) !== false){
+                $aResult['followers_count'] = $oConnection->getConnectedInitiatorsCount($iProfileId);
+                $aResult['followers_list'] = $oConnection->getConnectedListAPI($iProfileId, false, BX_CONNECTIONS_CONTENT_TYPE_INITIATORS);
+            }
+        }
+
+        $sKey = 'OBJECT_MENU_SNIPPET_META';
+        if(!empty($CNF[$sKey]) && ($oMetaMenu = BxDolMenu::getObjectInstance($CNF[$sKey], $this->_oTemplate)) !== false) {
+            $oPrivacy = BxDolPrivacy::getObjectInstance($CNF['OBJECT_PRIVACY_VIEW']);
+            $bPublic = !$oPrivacy || $oPrivacy->check($iId) || $oPrivacy->isPartiallyVisible($aData[$CNF['FIELD_ALLOW_VIEW_TO']]);
+
+            $oMetaMenu->setContentId($iId);
+            $oMetaMenu->setContentPublic($bPublic);
+            if(isset($aParams['context']))
+                $oMetaMenu->setContext($aParams['context']);
+
+            $aResult['meta'] = $oMetaMenu->getCodeAPI();
+        }
+
+        $this->decodeDataAPICommonFields($aResult, $aData, $aParams);
+
+        return $aResult;
+    }
+
+
+    // ====== PROTECTED METHODS
+    protected function _checkAllowedConnect (&$aDataEntry, $isPerformAction, $mixedConnection, $isMutual, $isInvertResult, $isSwap = false)
+    {
+        if (!$this->_iProfileId)
+            return _t('_sys_txt_access_denied');
+
+        $CNF = &$this->_oConfig->CNF;
+
+        $oProfile = BxDolProfile::getInstanceByContentAndType($aDataEntry[$CNF['FIELD_ID']], $this->_aModule['name']);
+        if (!$oProfile || $oProfile->id() == $this->_iProfileId)
+            return _t('_sys_txt_access_denied');
+
+        $sConnObject = '';
+        $sConnMethod = 'checkAllowedConnect';
+        if(is_array($mixedConnection))
+            list($sConnObject, $sConnMethod) = $mixedConnection;
+        else
+            $sConnObject = $mixedConnection;
+
+        return BxDolConnection::getObjectInstance($sConnObject)->$sConnMethod($this->_iProfileId, $oProfile->id(), $isPerformAction, $isMutual, $isInvertResult, $isSwap);
+    }
+
+    protected function _buildRssParams($sMode, $aArgs)
+    {
+        $aParams = array ();
+        $sMode = bx_process_input($sMode);
+        switch ($sMode) {
+            case 'connections':
+                $aParams = array(
+                    'object' => isset($aArgs[0]) ? $aArgs[0] : '',
+                    'type' => isset($aArgs[1]) ? $aArgs[1] : '',
+                    'profile' => isset($aArgs[2]) ? (int)$aArgs[2] : 0,
+                    'mutual' => isset($aArgs[3]) ? (int)$aArgs[3] : 0,
+                    'profile2' => isset($aArgs[4]) ? (int)$aArgs[4] : 0,
+                );
+                break;
+        }
+
+        return $aParams;
+    }
+
+    protected function _serviceGetTimelineProfileImage($aEvent, $aBrowseParams, $aBuildParams)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $aFileInfo = BxDolStorage::getObjectInstance($CNF[$aBuildParams['stg']])->getFile((int)$aEvent['object_id']);
+        if(empty($aFileInfo) || !is_array($aFileInfo))
+            return false;
+            
+        $aEventContent = unserialize($aEvent['content']);
+        if(!is_array($aEventContent) || empty($aEventContent['content']))
+            return false;
+
+        $aContentInfo = $this->_oDb->getContentInfoById($aEventContent['content']);
+        if(empty($aContentInfo) || !is_array($aContentInfo))
+            return false;
+
+        $oProfile = BxDolProfile::getInstanceMagic($aContentInfo['profile_id']);
+        if (!$oProfile->isActive())
+            return false;
+            
+        $sUserName = $oProfile->getDisplayName();
+
+        $sSample = isset($CNF['T'][$aBuildParams['txt_sswa']]) ? $CNF['T'][$aBuildParams['txt_sswa']] : $CNF['T'][$aBuildParams['txt_ss']];
+
+        //--- Title & Description
+        $sTitle = !empty($aContentInfo[$CNF['FIELD_TITLE']]) ? $aContentInfo[$CNF['FIELD_TITLE']] : '';
+        if(empty($sTitle) && !empty($aContentInfo[$CNF['FIELD_TEXT']]))
+            $sTitle = $aContentInfo[$CNF['FIELD_TEXT']];
+
+        $sDescription = _t($CNF['T'][$aBuildParams['txt_sau']], $sUserName, _t($sSample));
+
+        return array(
+            'owner_id' => $aEvent['owner_id'],
+            'object_owner_id' => $aContentInfo['profile_id'],
+            'icon' => !empty($CNF['ICON']) ? $CNF['ICON'] : '',
+            'sample' => $sSample,
+            'sample_wo_article' => $CNF['T'][$aBuildParams['txt_ss']],
+            'sample_action' => isset($CNF['T'][$aBuildParams['txt_sa']]) ? $CNF['T'][$aBuildParams['txt_sa']] : '',
+            'url' => bx_absolute_url(BxDolPermalinks::getInstance()->permalink('page.php?i=' . $CNF['URI_VIEW_ENTRY'] . '&id=' . $aContentInfo[$CNF['FIELD_ID']])),
+            'content' => $this->_getContentForTimelineProfileImage($aEvent, $aBrowseParams, $aBuildParams, $aContentInfo, $aFileInfo), //a string to display or array to parse default template before displaying.
+            'date' => $aContentInfo[$CNF['FIELD_ADDED']],
+            'views' => '',
+            'votes' => '',
+            'scores' => '',
+            'reports' => '',
+            'comments' => '',
+            'title' => $sTitle, //may be empty.
+            'description' => $sDescription //may be empty.
+        );
+    }
+
+    protected function _serviceGetTimelineProfileImageAllowedView($aEvent)
+    {
+        $sError = _t('_sys_access_denied_to_private_content');
+
+        if(empty($aEvent['content']) || !is_array($aEvent['content']) || empty($aEvent['content']['id']))
+            return $sError;
+
+        $aContentInfo = $this->_oDb->getContentInfoById($aEvent['content']['id']);
+        if(empty($aContentInfo) || !is_array($aContentInfo))
+            return $sError;
+
+        return $this->serviceCheckAllowedViewForProfile($aContentInfo);
+    }
+
+    protected function _getContentForTimelineProfileImage($aEvent, $aBrowseParams, $aBuildParams, $aContentInfo, $aFileInfo)
+    {
+    	$CNF = &$this->_oConfig->CNF;
+
+    	$sUrl = bx_absolute_url(BxDolPermalinks::getInstance()->permalink('page.php?i=' . $CNF['URI_VIEW_ENTRY'] . '&id=' . $aContentInfo[$CNF['FIELD_ID']]));
+
+    	//--- Image(s)
+        $sImage = $this->_oConfig->getImageUrl($aFileInfo['id'], $aBuildParams['trans']);
+        $sImageOrig = $this->_oConfig->getImageUrl($aFileInfo['id'], $aBuildParams['trans_orig']);
+        if(!empty($sImage)) {
+            if(empty($sImageOrig))
+                $sImageOrig = $sImage;
+
+            $a = ['id' => $aFileInfo['id'], 'url' => $sUrl, 'src' => $sImage];
+            if(CHECK_ACTION_RESULT_ALLOWED === $this->checkAllowedView($aContentInfo)) {
+                $a['src_orig'] = $sImageOrig;
+
+                $sCnfKey = 'OBJECT_IMAGES_TRANSCODER_GALLERY';
+                if(!empty($CNF[$sCnfKey]) && ($sSrcMedium = $this->_oConfig->getImageUrl($aFileInfo['id'], [$sCnfKey])) != '')
+                    $a['src_medium'] = $sSrcMedium;
+            }
+            $aImages = [$a];
+        }
+
+    	return array(
+            'sample' => isset($CNF['T'][$aBuildParams['txt_sswa']]) ? $CNF['T'][$aBuildParams['txt_sswa']] : $CNF['T'][$aBuildParams['txt_ss']],
+            'sample_wo_article' => $CNF['T'][$aBuildParams['txt_ss']],
+            'sample_action' => isset($CNF['T'][$aBuildParams['txt_sa']]) ? $CNF['T'][$aBuildParams['txt_sa']] : '',
+            'id' => $aContentInfo[$CNF['FIELD_ID']],
+            'url' => $sUrl,
+            'title' =>  '',
+            'text' => '',
+            'images' => $aImages,
+            'videos' => array()
+        );
+    }
+
+    protected function _entityComments($sObject, $iId = 0)
+    {
+        if(!$iId)
+            $iId = bx_process_input(bx_get('id'), BX_DATA_INT);
+
+        if(!$iId)
+            $iId = bx_process_input(bx_get('profile_id'), BX_DATA_INT);
+
+        if(!$iId)
+            return false;
+
+        $oCmts = BxDolCmts::getObjectInstance($sObject, $iId);
+        if(!$oCmts || !$oCmts->isEnabled())
+            return false;
+
+        if (bx_is_api())
+            return [bx_srv('system', 'get_data_api', [['module' => $sObject, 'object_id' => $iId]], 'TemplCmtsServices')];
+
+        return $oCmts->getCommentsBlock(array(), array('in_designbox' => false));
+    }
+
+    protected function _getContent($iContentId = 0, $sFuncGetContent = 'getContentInfoById')
+    {
+        if(!$iContentId && bx_get('id') === false && bx_get('profile_id') !== false) {
+            $oProfile = BxDolProfile::getInstance((int)bx_get('profile_id'));
+            if($oProfile)
+                $iContentId = $oProfile->getContentId();
+        }
+
+        return parent::_getContent($iContentId, $sFuncGetContent);
+    }
+}
+
+/** @} */

+ 509 - 0
upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/akeeba/s3/src/Configuration.php

@@ -0,0 +1,509 @@
+<?php
+/**
+ * Akeeba Engine
+ *
+ * @package   akeebaengine
+ * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
+ * @license   GNU General Public License version 3, or later
+ */
+
+namespace Akeeba\S3;
+
+// Protection against direct access
+defined('AKEEBAENGINE') || die();
+
+/**
+ * Holds the Amazon S3 confiugration credentials
+ */
+class Configuration
+{
+	/**
+	 * Access Key
+	 *
+	 * @var  string
+	 */
+	protected $access = '';
+
+	/**
+	 * Secret Key
+	 *
+	 * @var  string
+	 */
+	protected $secret = '';
+
+	/**
+	 * Security token. This is only required with temporary credentials provisioned by an EC2 instance.
+	 *
+	 * @var  string
+	 */
+	protected $token = '';
+
+	/**
+	 * Signature calculation method ('v2' or 'v4')
+	 *
+	 * @var  string
+	 */
+	protected $signatureMethod = 'v2';
+
+	/**
+	 * AWS region, used for v4 signatures
+	 *
+	 * @var  string
+	 */
+	protected $region = 'us-east-1';
+
+	/**
+	 * Should I use SSL (HTTPS) to communicate to Amazon S3?
+	 *
+	 * @var  bool
+	 */
+	protected $useSSL = true;
+
+	/**
+	 * Should I use SSL (HTTPS) to communicate to Amazon S3?
+	 *
+	 * @var  bool
+	 */
+	protected $useDualstackUrl = false;
+
+	/**
+	 * Should I use legacy, path-style access to the bucket? When it's turned off (default) we use virtual hosting style
+	 * paths which are RECOMMENDED BY AMAZON per http://docs.aws.amazon.com/AmazonS3/latest/API/APIRest.html
+	 *
+	 * @var  bool
+	 */
+	protected $useLegacyPathStyle = false;
+
+	/**
+	 * Amazon S3 endpoint. You can use a custom endpoint with v2 signatures to access third party services which offer
+	 * S3 compatibility, e.g. OwnCloud, Google Storage etc.
+	 *
+	 * @var  string
+	 */
+	protected $endpoint = 's3.amazonaws.com';
+
+	/**
+	 * Should I use an alternative date header format (D, d M Y H:i:s T instead of D, d M Y H:i:s O) for non-Amazon,
+	 * S3-compatible services?
+	 *
+	 * This is enabled by default.
+	 *
+	 * @var  bool
+	 */
+	protected $alternateDateHeaderFormat = true;
+
+	/**
+	 * Should I use the standard HTTP Date header instead of the X-Amz-Date header?
+	 *
+	 * @var  bool
+	 */
+	protected $useHTTPDateHeader = false;
+
+	/**
+	 * Should pre-signed URLs include the bucket name in the URL? Only applies to v4 signatures.
+	 *
+	 * Amazon S3 and most implementations need this turned off (default). LocalStack seems to not work properly with the
+	 * bucket name as a subdomain, hence the need for this flag.
+	 *
+	 * @var  bool
+	 */
+	protected $preSignedBucketInURL = false;
+
+	/**
+	 * Maximum time, in seconds, to wait while trying to establish the connection to the S3 endpoint. A value of 0
+	 * (default) means no explicit limit, i.e. cURL's own default is used.
+	 *
+	 * @var  int
+	 */
+	protected $connectTimeout = 0;
+
+	/**
+	 * Maximum time, in seconds, allowed for the entire request to complete. A value of 0 (default) means no explicit
+	 * limit, i.e. the request is allowed to run for as long as it takes.
+	 *
+	 * @var  int
+	 */
+	protected $requestTimeout = 0;
+
+	/**
+	 * Public constructor
+	 *
+	 * @param   string  $access           Amazon S3 Access Key
+	 * @param   string  $secret           Amazon S3 Secret Key
+	 * @param   string  $signatureMethod  Signature method (v2 or v4)
+	 * @param   string  $region           Region, only required for v4 signatures
+	 */
+	function __construct(string $access, string $secret, string $signatureMethod = 'v2', string $region = '')
+	{
+		$this->setAccess($access);
+		$this->setSecret($secret);
+		$this->setSignatureMethod($signatureMethod);
+		$this->setRegion($region);
+	}
+
+	/**
+	 * Get the Amazon access key
+	 *
+	 * @return  string
+	 */
+	public function getAccess(): string
+	{
+		return $this->access;
+	}
+
+	/**
+	 * Set the Amazon access key
+	 *
+	 * @param   string  $access  The access key to set
+	 *
+	 * @throws  Exception\InvalidAccessKey
+	 */
+	public function setAccess(string $access): void
+	{
+		if (empty($access))
+		{
+			throw new Exception\InvalidAccessKey;
+		}
+
+		$this->access = $access;
+	}
+
+	/**
+	 * Get the Amazon secret key
+	 *
+	 * @return string
+	 */
+	public function getSecret(): string
+	{
+		return $this->secret;
+	}
+
+	/**
+	 * Set the Amazon secret key
+	 *
+	 * @param   string  $secret  The secret key to set
+	 *
+	 * @throws  Exception\InvalidSecretKey
+	 */
+	public function setSecret(string $secret): void
+	{
+		if (empty($secret))
+		{
+			throw new Exception\InvalidSecretKey;
+		}
+
+		$this->secret = $secret;
+	}
+
+	/**
+	 * Return the security token. Only for temporary credentials provisioned through an EC2 instance.
+	 *
+	 * @return  string
+	 */
+	public function getToken(): string
+	{
+		return $this->token;
+	}
+
+	/**
+	 * Set the security token. Only for temporary credentials provisioned through an EC2 instance.
+	 *
+	 * @param   string  $token
+	 */
+	public function setToken(string $token): void
+	{
+		$this->token = $token;
+	}
+
+	/**
+	 * Get the signature method to use
+	 *
+	 * @return  string
+	 */
+	public function getSignatureMethod(): string
+	{
+		return $this->signatureMethod;
+	}
+
+	/**
+	 * Set the signature method to use
+	 *
+	 * @param   string  $signatureMethod  One of v2 or v4
+	 *
+	 * @throws  Exception\InvalidSignatureMethod
+	 */
+	public function setSignatureMethod(string $signatureMethod): void
+	{
+		$signatureMethod = strtolower($signatureMethod);
+		$signatureMethod = trim($signatureMethod);
+
+		if (!in_array($signatureMethod, ['v2', 'v4']))
+		{
+			throw new Exception\InvalidSignatureMethod;
+		}
+
+		$this->signatureMethod = $signatureMethod;
+
+		// If you switch to v2 signatures we unset the region.
+		if ($signatureMethod == 'v2')
+		{
+			$this->setRegion('');
+
+			/**
+			 * If we are using Amazon S3 proper (not a custom endpoint) we have to set path style access to false.
+			 * Amazon S3 does not support v2 signatures with path style access at all (it returns an error telling
+			 * us to use the virtual hosting endpoint BUCKETNAME.s3.amazonaws.com).
+			 */
+			if (strpos($this->endpoint, 'amazonaws.com') !== false)
+			{
+				$this->setUseLegacyPathStyle(false);
+			}
+
+		}
+	}
+
+	/**
+	 * Get the Amazon S3 region
+	 *
+	 * @return  string
+	 */
+	public function getRegion(): string
+	{
+		return $this->region;
+	}
+
+	/**
+	 * Set the Amazon S3 region
+	 *
+	 * @param   string  $region
+	 */
+	public function setRegion(string $region): void
+	{
+		/**
+		 * You can only leave the region empty if you're using v2 signatures. Anything else gets you an exception.
+		 */
+		if (empty($region) && ($this->signatureMethod == 'v4'))
+		{
+			throw new Exception\InvalidRegion;
+		}
+
+		/**
+		 * Setting a Chinese-looking region force-changes the endpoint but ONLY if you were using the original Amazon S3
+		 * endpoint. If you're using a custom endpoint and provide a region with 'cn-' in its name we don't override
+		 * your custom endpoint.
+		 */
+		if (($this->endpoint == 's3.amazonaws.com') && (substr($region, 0, 3) == 'cn-'))
+		{
+			$this->setEndpoint('amazonaws.com.cn');
+		}
+
+		$this->region = $region;
+	}
+
+	/**
+	 * Is the connection to be made over HTTPS?
+	 *
+	 * @return  bool
+	 */
+	public function isSSL(): bool
+	{
+		return $this->useSSL;
+	}
+
+	/**
+	 * Set the connection SSL preference
+	 *
+	 * @param   bool  $useSSL  True to use HTTPS
+	 */
+	public function setSSL(bool $useSSL): void
+	{
+		$this->useSSL = $useSSL ? true : false;
+	}
+
+	/**
+	 * Get the Amazon S3 endpoint
+	 *
+	 * @return  string
+	 */
+	public function getEndpoint(): string
+	{
+		return $this->endpoint;
+	}
+
+	/**
+	 * Set the Amazon S3 endpoint. Do NOT use a protocol
+	 *
+	 * @param   string  $endpoint  Custom endpoint, e.g. 's3.example.com' or 'www.example.com/s3api'
+	 */
+	public function setEndpoint(string $endpoint): void
+	{
+		if (stristr($endpoint, '://'))
+		{
+			throw new Exception\InvalidEndpoint;
+		}
+
+		/**
+		 * If you set a custom endpoint we have to switch to v2 signatures since our v4 implementation only supports
+		 * Amazon endpoints.
+		 */
+		if ((strpos($endpoint, 'amazonaws.com') === false))
+		{
+			$this->setSignatureMethod('v2');
+		}
+
+		$this->endpoint = $endpoint;
+	}
+
+	/**
+	 * Should I use legacy, path-style access to the bucket? You should only use it with custom endpoints. Amazon itself
+	 * is currently deprecating support for path-style access but has extended the migration date to an unknown
+	 * time https://aws.amazon.com/blogs/aws/amazon-s3-path-deprecation-plan-the-rest-of-the-story/
+	 *
+	 * @return  bool
+	 */
+	public function getUseLegacyPathStyle(): bool
+	{
+		return $this->useLegacyPathStyle;
+	}
+
+	/**
+	 * Set the flag for using legacy, path-style access to the bucket
+	 *
+	 * @param   bool  $useLegacyPathStyle
+	 */
+	public function setUseLegacyPathStyle(bool $useLegacyPathStyle): void
+	{
+		$this->useLegacyPathStyle = $useLegacyPathStyle;
+
+		/**
+		 * If we are using Amazon S3 proper (not a custom endpoint) we have to set path style access to false.
+		 * Amazon S3 does not support v2 signatures with path style access at all (it returns an error telling
+		 * us to use the virtual hosting endpoint BUCKETNAME.s3.amazonaws.com).
+		 */
+		if ((strpos($this->endpoint, 'amazonaws.com') !== false) && ($this->signatureMethod == 'v2'))
+		{
+			$this->useLegacyPathStyle = false;
+		}
+	}
+
+	/**
+	 * Should we use the dualstack URL (which will ship traffic over ipv6 in most cases). For more information on these
+	 * endpoints please read https://docs.aws.amazon.com/AmazonS3/latest/dev/dual-stack-endpoints.html
+	 *
+	 * @return  bool
+	 */
+	public function getDualstackUrl(): bool
+	{
+		return $this->useDualstackUrl;
+	}
+
+	/**
+	 * Set the flag for using legacy, path-style access to the bucket
+	 *
+	 * @param   bool  $useDualstackUrl
+	 */
+	public function setUseDualstackUrl(bool $useDualstackUrl): void
+	{
+		$this->useDualstackUrl = $useDualstackUrl;
+	}
+
+	/**
+	 * Get the flag for using an alternate date format for non-Amazon, S3-compatible services.
+	 *
+	 * @return bool
+	 */
+	public function getAlternateDateHeaderFormat(): bool
+	{
+		return $this->alternateDateHeaderFormat;
+	}
+
+	/**
+	 * Set the flag for using an alternate date format for non-Amazon, S3-compatible services.
+	 *
+	 * @param   bool  $alternateDateHeaderFormat
+	 *
+	 * @return  void
+	 */
+	public function setAlternateDateHeaderFormat(bool $alternateDateHeaderFormat): void
+	{
+		$this->alternateDateHeaderFormat = $alternateDateHeaderFormat;
+	}
+
+	/**
+	 * Get the flag indicating whether to use the HTTP Date header
+	 *
+	 * @return  bool  Flag indicating whether to use the HTTP Date header
+	 */
+	public function getUseHTTPDateHeader(): bool
+	{
+		return $this->useHTTPDateHeader;
+	}
+
+	/**
+	 * Set the flag indicating whether to use the HTTP Date header.
+	 *
+	 * @param   bool  $useHTTPDateHeader  Whether to use the HTTP Date header
+	 *
+	 * @return  void
+	 */
+	public function setUseHTTPDateHeader(bool $useHTTPDateHeader): void
+	{
+		$this->useHTTPDateHeader = $useHTTPDateHeader;
+	}
+
+	public function getPreSignedBucketInURL(): bool
+	{
+		return $this->preSignedBucketInURL;
+	}
+
+	public function setPreSignedBucketInURL(bool $preSignedBucketInURL): void
+	{
+		$this->preSignedBucketInURL = $preSignedBucketInURL;
+	}
+
+	/**
+	 * Get the maximum time, in seconds, to wait while establishing the connection to the S3 endpoint.
+	 *
+	 * @return  int  Timeout in seconds; 0 means no explicit limit.
+	 */
+	public function getConnectTimeout(): int
+	{
+		return $this->connectTimeout;
+	}
+
+	/**
+	 * Set the maximum time, in seconds, to wait while establishing the connection to the S3 endpoint.
+	 *
+	 * @param   int  $connectTimeout  Timeout in seconds; 0 (or any negative value, which is clamped to 0) means no
+	 *                                explicit limit.
+	 *
+	 * @return  void
+	 */
+	public function setConnectTimeout(int $connectTimeout): void
+	{
+		$this->connectTimeout = max(0, $connectTimeout);
+	}
+
+	/**
+	 * Get the maximum time, in seconds, allowed for the entire request to complete.
+	 *
+	 * @return  int  Timeout in seconds; 0 means no explicit limit.
+	 */
+	public function getRequestTimeout(): int
+	{
+		return $this->requestTimeout;
+	}
+
+	/**
+	 * Set the maximum time, in seconds, allowed for the entire request to complete.
+	 *
+	 * @param   int  $requestTimeout  Timeout in seconds; 0 (or any negative value, which is clamped to 0) means no
+	 *                                explicit limit.
+	 *
+	 * @return  void
+	 */
+	public function setRequestTimeout(int $requestTimeout): void
+	{
+		$this->requestTimeout = max(0, $requestTimeout);
+	}
+}

+ 840 - 0
upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/akeeba/s3/src/Request.php

@@ -0,0 +1,840 @@
+<?php
+/**
+ * Akeeba Engine
+ *
+ * @package   akeebaengine
+ * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
+ * @license   GNU General Public License version 3, or later
+ */
+
+namespace Akeeba\S3;
+
+use Akeeba\S3\Response\Error;
+
+// Protection against direct access
+defined('AKEEBAENGINE') || die();
+
+
+class Request
+{
+	/**
+	 * The HTTP verb to use
+	 *
+	 * @var  string
+	 */
+	private $verb = 'GET';
+
+	/**
+	 * The bucket we are using
+	 *
+	 * @var  string
+	 */
+	private $bucket = '';
+
+	/**
+	 * The object URI, relative to the bucket's root
+	 *
+	 * @var  string
+	 */
+	private $uri = '';
+
+	/**
+	 * The remote resource we are querying
+	 *
+	 * @var  string
+	 */
+	private $resource = '';
+
+	/**
+	 * Query string parameters
+	 *
+	 * @var  array
+	 */
+	private $parameters = [];
+
+	/**
+	 * Amazon-specific headers to pass to the request
+	 *
+	 * @var  array
+	 */
+	private $amzHeaders = [];
+
+	/**
+	 * Regular HTTP headers to send in the request
+	 *
+	 * @var  array
+	 */
+	private $headers = [
+		'Host'         => '',
+		'Date'         => '',
+		'Content-MD5'  => '',
+		'Content-Type' => '',
+	];
+
+	/**
+	 * Input data for the request
+	 *
+	 * @var  Input
+	 */
+	private $input = null;
+
+	/**
+	 * The file resource we are writing data to
+	 *
+	 * @var  resource|null
+	 */
+	private $fp = null;
+
+	/**
+	 * The Amazon S3 configuration object
+	 *
+	 * @var Configuration
+	 */
+	private $configuration = null;
+
+	/**
+	 * The response object
+	 *
+	 * @var  Response
+	 */
+	private $response = null;
+
+	/**
+	 * The location of the CA certificate cache. It can be a file or a directory. If it's not specified, the location
+	 * set in AKEEBA_CACERT_PEM will be used
+	 *
+	 * @var  string|null
+	 */
+	private $caCertLocation = null;
+
+	/**
+	 * Constructor
+	 *
+	 * @param   string         $verb           HTTP verb, e.g. 'POST'
+	 * @param   string         $bucket         Bucket name, e.g. 'example-bucket'
+	 * @param   string         $uri            Object URI
+	 * @param   Configuration  $configuration  The Amazon S3 configuration object to use
+	 *
+	 * @return  void
+	 */
+	function __construct(string $verb, string $bucket, string $uri, Configuration $configuration)
+	{
+		$this->verb          = $verb;
+		$this->bucket        = $bucket;
+		$this->uri           = '/';
+		$this->configuration = $configuration;
+
+		if (!empty($uri))
+		{
+			$this->uri = '/' . str_replace('%2F', '/', rawurlencode($uri));
+		}
+
+		$this->headers['Host'] = $this->getHostName($configuration, $this->bucket);
+		$this->resource        = $this->uri;
+
+		if (($this->bucket !== '') && $configuration->getUseLegacyPathStyle())
+		{
+			$this->resource = '/' . $this->bucket . $this->uri;
+
+			$this->uri = $this->resource;
+		}
+
+		// The date must always be added as a header
+		$this->headers['Date'] = gmdate('D, d M Y H:i:s O');
+
+		// S3-"compatible" services use a different date format. Because why not?
+		if ($this->configuration->getAlternateDateHeaderFormat() && strpos($this->headers['Host'], '.amazonaws.com') === false)
+		{
+			$this->headers['Date'] = gmdate('D, d M Y H:i:s T');
+		}
+
+		// If there is a security token we need to set up the X-Amz-Security-Token header
+		$token = $this->configuration->getToken();
+
+		if (!empty($token))
+		{
+			$this->setAmzHeader('x-amz-security-token', $token);
+		}
+
+		// Initialize the response object
+		$this->response = new Response();
+	}
+
+	/**
+	 * Get the input object
+	 *
+	 * @return  Input|null
+	 */
+	public function getInput(): ?Input
+	{
+		return $this->input;
+	}
+
+	/**
+	 * Set the input object
+	 *
+	 * @param   Input  $input
+	 *
+	 * @return  void
+	 */
+	public function setInput(Input $input): void
+	{
+		$this->input = $input;
+	}
+
+	/**
+	 * Set a request parameter
+	 *
+	 * @param   string       $key    The parameter name
+	 * @param   string|null  $value  The parameter value
+	 *
+	 * @return  void
+	 */
+	public function setParameter(string $key, ?string $value): void
+	{
+		$this->parameters[$key] = $value;
+	}
+
+	/**
+	 * Set a request header
+	 *
+	 * @param   string  $key    The header name
+	 * @param   string  $value  The header value
+	 *
+	 * @return  void
+	 */
+	public function setHeader(string $key, string $value): void
+	{
+		$this->headers[$key] = $value;
+	}
+
+	/**
+	 * Set an x-amz-meta-* header
+	 *
+	 * @param   string  $key    The header name
+	 * @param   string  $value  The header value
+	 *
+	 * @return  void
+	 */
+	public function setAmzHeader(string $key, string $value): void
+	{
+		$this->amzHeaders[$key] = $value;
+	}
+
+	/**
+	 * Get the HTTP verb of this request
+	 *
+	 * @return  string
+	 */
+	public function getVerb(): string
+	{
+		return $this->verb;
+	}
+
+	/**
+	 * Get the S3 bucket's name
+	 *
+	 * @return  string
+	 */
+	public function getBucket(): string
+	{
+		return $this->bucket;
+	}
+
+	/**
+	 * Get the absolute URI of the resource we're accessing
+	 *
+	 * @return  string
+	 */
+	public function getResource(): string
+	{
+		return $this->resource;
+	}
+
+	/**
+	 * Get the parameters array
+	 *
+	 * @return  array
+	 */
+	public function getParameters(): array
+	{
+		return $this->parameters;
+	}
+
+	/**
+	 * Get the Amazon headers array
+	 *
+	 * @return  array
+	 */
+	public function getAmzHeaders(): array
+	{
+		return $this->amzHeaders;
+	}
+
+	/**
+	 * Get the other headers array
+	 *
+	 * @return  array
+	 */
+	public function getHeaders(): array
+	{
+		return $this->headers;
+	}
+
+	/**
+	 * Get a reference to the Amazon configuration object
+	 *
+	 * @return  Configuration
+	 */
+	public function getConfiguration(): Configuration
+	{
+		return $this->configuration;
+	}
+
+	/**
+	 * Get the file pointer resource (for PUT and POST requests)
+	 *
+	 * @return  resource|null
+	 */
+	public function &getFp()
+	{
+		return $this->fp;
+	}
+
+	/**
+	 * Set the data resource as a file pointer
+	 *
+	 * @param   resource  $fp
+	 */
+	public function setFp($fp): void
+	{
+		$this->fp = $fp;
+	}
+
+	/**
+	 * Get the certificate authority location
+	 *
+	 * @return  string|null
+	 */
+	public function getCaCertLocation(): ?string
+	{
+		if (!empty($this->caCertLocation))
+		{
+			return $this->caCertLocation;
+		}
+
+		if (defined('AKEEBA_CACERT_PEM'))
+		{
+			return AKEEBA_CACERT_PEM;
+		}
+
+		return null;
+	}
+
+	/**
+	 * @param   null|string  $caCertLocation
+	 */
+	public function setCaCertLocation(?string $caCertLocation): void
+	{
+		if (empty($caCertLocation))
+		{
+			$caCertLocation = null;
+		}
+
+		if (!is_null($caCertLocation) && !is_file($caCertLocation) && !is_dir($caCertLocation))
+		{
+			$caCertLocation = null;
+		}
+
+		$this->caCertLocation = $caCertLocation;
+	}
+
+	/**
+	 * Get a pre-signed URL for the request.
+	 *
+	 * Typically used to pre-sign GET requests to objects, i.e. give shareable pre-authorized URLs for downloading
+	 * private or otherwise inaccessible files from S3.
+	 *
+	 * @param   int|null  $lifetime  Lifetime in seconds
+	 * @param   bool      $https     Use HTTPS ($hostBucket should be false for SSL verification)?
+	 *
+	 * @return  string  The authenticated URL, complete with signature
+	 */
+	public function getAuthenticatedURL(?int $lifetime = null, bool $https = false): string
+	{
+		$this->processParametersIntoResource();
+		$signer = Signature::getSignatureObject($this, $this->configuration->getSignatureMethod());
+
+		return $signer->getAuthenticatedURL($lifetime, $https);
+	}
+
+	/**
+	 * Get the S3 response
+	 *
+	 * @return  Response
+	 */
+	public function getResponse(bool $rawResponse = false): Response
+	{
+		$this->processParametersIntoResource();
+
+		$schema = 'http://';
+
+		if ($this->configuration->isSSL())
+		{
+			$schema = 'https://';
+		}
+
+		// Very special case. IF the URI ends in /?location AND the region is us-east-1 (Host is
+		// s3-external-1.amazonaws.com) THEN the host MUST become s3.amazonaws.com for the request to work. This is case
+		// of us not knowing the region of the bucket, therefore having to use a special endpoint which lets us query
+		// the region of the bucket without knowing its region. See
+		// http://stackoverflow.com/questions/27091816/retrieve-buckets-objects-without-knowing-buckets-region-with-aws-s3-rest-api
+		if ((substr($this->uri, -10) == '/?location') && ($this->headers['Host'] == 's3-external-1.amazonaws.com'))
+		{
+			$this->headers['Host'] = 's3.amazonaws.com';
+		}
+
+		$url = $schema . $this->headers['Host'] . $this->uri;
+
+		// Basic setup
+		$curl = curl_init();
+		curl_setopt($curl, CURLOPT_USERAGENT, 'AkeebaBackupProfessional/S3PostProcessor');
+
+		// Apply the optional connection and request timeouts. A value of 0 means "no explicit limit".
+		$connectTimeout = $this->configuration->getConnectTimeout();
+		$requestTimeout = $this->configuration->getRequestTimeout();
+
+		if ($connectTimeout > 0)
+		{
+			curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, $connectTimeout);
+		}
+
+		if ($requestTimeout > 0)
+		{
+			curl_setopt($curl, CURLOPT_TIMEOUT, $requestTimeout);
+		}
+
+		if ($this->configuration->isSSL())
+		{
+			// Set the CA certificate cache location
+			$caCert = $this->getCaCertLocation();
+
+			if (!empty($caCert))
+			{
+				if (is_dir($caCert))
+				{
+					@curl_setopt($curl, CURLOPT_CAPATH, $caCert);
+				}
+				else
+				{
+					@curl_setopt($curl, CURLOPT_CAINFO, $caCert);
+				}
+			}
+
+			/**
+			 * Verify the host name in the certificate and the certificate itself.
+			 *
+			 * Caveat: if your bucket contains dots in the name we have to turn off host verification due to the way the
+			 * S3 SSL certificates are set up.
+			 */
+			$isAmazonS3  = (substr($this->headers['Host'], -14) == '.amazonaws.com')
+			               || substr(
+				                  $this->headers['Host'], -16
+			                  ) == 'amazonaws.com.cn';
+			$tooManyDots = substr_count($this->headers['Host'], '.') > 4;
+
+			$verifyHost = ($isAmazonS3 && $tooManyDots) ? 0 : 2;
+
+			curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, $verifyHost);
+			curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, true);
+		}
+
+		curl_setopt($curl, CURLOPT_URL, $url);
+
+		/**
+		 * Set the optional x-amz-date header instead of the standard HTTP Date header.
+		 *
+		 * Amazon S3 proper expects to get the date from the Date header. It also allows you to instead use the optional
+		 * X-Amz-Date header as a means to resolve situations where your HTTP library does not let you control the
+		 * standard Date header. In other words, it accepts both, it encourages the standard Date header, but it will
+		 * give priority to the X-Amz-Date header to help you get out of a sticky situation.
+		 *
+		 * Unfortunately, third party services which claim to be "S3-compatible" are written by people with poor reading
+		 * skills or, more likely, under unrealistic time constraints to deliver working code. They are implementing the
+		 * date handling behaviout wrong. Instead of using the Date header unless the X-Amz-Date header is set, they
+		 * **expect** to only ever see the X-Amz-Date header. If it's missing, they do not fall back to the standard
+		 * Date header; they just spit out a message about the signature being wrong. Wasabi and ExoScale are two prime
+		 * examples of that, and only when using v2 signatures.
+		 *
+		 * To avoid this problem, we are now defaulting to always using the X-Amz-Date header everywhere. If you want to
+		 * revert to using the Date header with S3 proper please use setUseHTTPDateHeader(true) to your configuration
+		 * object. In this case DO NOT set the X-Amz-Date header yourself, or you're going to have a *really* bad time.
+		 */
+		if (!$this->configuration->getUseHTTPDateHeader())
+		{
+			$this->amzHeaders['x-amz-date'] = (new \DateTime($this->headers['Date']))->format('Ymd\THis\Z');
+
+			unset ($this->headers['Date']);
+		}
+
+		/**
+		 * Remove empty headers.
+		 *
+		 * While Amazon S3 proper and most third party implementations have no problem with that, there a few of them
+		 * (such as Synology C2) which choke on empty headers.
+		 */
+		$this->headers = array_filter($this->headers);
+
+		// Get the request signature
+		$signer = Signature::getSignatureObject($this, $this->configuration->getSignatureMethod());
+		$signer->preProcessHeaders($this->headers, $this->amzHeaders);
+
+		// Headers
+		$headers = [];
+
+		foreach ($this->amzHeaders as $header => $value)
+		{
+			if (strlen($value) > 0)
+			{
+				$headers[] = $header . ': ' . $value;
+			}
+		}
+
+		foreach ($this->headers as $header => $value)
+		{
+			if (strlen($value) > 0)
+			{
+				$headers[] = $header . ': ' . $value;
+			}
+		}
+
+		$headers[] = 'Authorization: ' . $signer->getAuthorizationHeader();
+
+		curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
+		curl_setopt($curl, CURLOPT_HEADER, false);
+		curl_setopt($curl, CURLOPT_RETURNTRANSFER, false);
+		curl_setopt($curl, CURLOPT_WRITEFUNCTION, [$this, '__responseWriteCallback']);
+		curl_setopt($curl, CURLOPT_HEADERFUNCTION, [$this, '__responseHeaderCallback']);
+		curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true);
+
+		// Request types
+		switch ($this->verb)
+		{
+			case 'GET':
+				break;
+
+			case 'PUT':
+			case 'POST':
+				if (!is_object($this->input) || !($this->input instanceof Input))
+				{
+					$this->input = new Input();
+				}
+
+				$size = $this->input->getSize();
+				$type = $this->input->getInputType();
+
+				if ($type == Input::INPUT_DATA)
+				{
+					curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $this->verb);
+
+					$data = $this->input->getDataReference();
+
+					if (strlen($data ?? ''))
+					{
+						curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
+					}
+
+					if ($size > 0)
+					{
+						curl_setopt($curl, CURLOPT_BUFFERSIZE, $size);
+					}
+				}
+				else
+				{
+					curl_setopt($curl, CURLOPT_PUT, true);
+					curl_setopt($curl, CURLOPT_INFILE, $this->input->getFp());
+
+					if ($size > 0)
+					{
+						curl_setopt($curl, CURLOPT_INFILESIZE, $size);
+					}
+				}
+
+
+				break;
+
+			case 'HEAD':
+				curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'HEAD');
+				curl_setopt($curl, CURLOPT_NOBODY, true);
+				break;
+
+			case 'DELETE':
+				curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'DELETE');
+				break;
+
+			default:
+				break;
+		}
+
+		// Execute, grab errors
+		$this->response->resetBody();
+
+		if (curl_exec($curl))
+		{
+			$this->response->code = curl_getinfo($curl, CURLINFO_HTTP_CODE);
+		}
+		else
+		{
+			$this->response->error = new Error(
+				curl_errno($curl),
+				curl_error($curl),
+				$this->resource
+			);
+		}
+
+		if (version_compare(PHP_VERSION, '8.5.0', 'lt'))
+		{
+			@curl_close($curl);
+		}
+
+		// Set the body data
+		$this->response->finaliseBody($rawResponse);
+
+		// Clean up file resources
+		if (!is_null($this->fp) && is_resource($this->fp))
+		{
+			try
+			{
+				@fclose($this->fp);
+			}
+			catch (\Throwable $e)
+			{
+			}
+		}
+
+		return $this->response;
+	}
+
+
+	/**
+	 * cURL write callback
+	 *
+	 * @param   resource   &$curl  cURL resource
+	 * @param   string     &$data  Data
+	 *
+	 * @return  int  Length in bytes
+	 */
+	protected function __responseWriteCallback($curl, string $data): int
+	{
+		if (in_array($this->response->code, [0, 200, 206]) && !is_null($this->fp) && is_resource($this->fp))
+		{
+			return fwrite($this->fp, $data);
+		}
+
+		$this->response->addToBody($data);
+
+		return strlen($data);
+	}
+
+	/**
+	 * cURL header callback
+	 *
+	 * @param   resource   $curl  cURL resource
+	 * @param   string    &$data  Data
+	 *
+	 * @return  int  Length in bytes
+	 */
+	protected function __responseHeaderCallback($curl, string $data): int
+	{
+		if (($strlen = strlen($data)) <= 2)
+		{
+			return $strlen;
+		}
+
+		if (substr($data, 0, 4) == 'HTTP')
+		{
+			$this->response->code = (int) substr($data, 9, 3);
+
+			return $strlen;
+		}
+
+		// Ignore malformed headers without a value.
+		if (strpos($data, ':') === false)
+		{
+			return $strlen;
+		}
+
+		[$header, $value] = explode(':', trim($data), 2);
+		$header = trim($header ?? '');
+		$value  = trim($value ?? '');
+
+		switch (strtolower($header))
+		{
+			case 'last-modified':
+				$this->response->setHeader('time', strtotime($value));
+				break;
+
+			case 'content-length':
+				$this->response->setHeader('size', (int) $value);
+				break;
+
+			case 'content-type':
+				$this->response->setHeader('type', $value);
+				break;
+
+			case 'etag':
+				$this->response->setHeader('hash', trim($value, '"'));
+				break;
+
+			default:
+				$this->response->setHeader(strtolower($header), is_numeric($value) ? (int) $value : $value);
+
+				if (preg_match('/^x-amz-meta-.*$/', $header))
+				{
+					$this->setHeader($header, is_numeric($value) ? (int) $value : $value);
+				}
+				break;
+		}
+
+		return $strlen;
+	}
+
+	/**
+	 * Processes $this->parameters as a query string into $this->resource
+	 *
+	 * @return  void
+	 */
+	private function processParametersIntoResource(): void
+	{
+		if (count($this->parameters))
+		{
+			$query = substr($this->uri, -1) !== '?' ? '?' : '&';
+
+			ksort($this->parameters);
+
+			foreach ($this->parameters as $var => $value)
+			{
+				if ($value == null || $value == '')
+				{
+					$query .= $var . '&';
+				}
+				else
+				{
+					// Parameters must be URL-encoded
+					$query .= $var . '=' . rawurlencode($value) . '&';
+				}
+			}
+
+			$query     = substr($query, 0, -1);
+			$this->uri .= $query;
+
+			if (array_key_exists('acl', $this->parameters) || array_key_exists('location', $this->parameters)
+			    || array_key_exists('torrent', $this->parameters)
+			    || array_key_exists('logging', $this->parameters)
+			    || array_key_exists('uploads', $this->parameters)
+			    || array_key_exists('uploadId', $this->parameters)
+			    || array_key_exists('partNumber', $this->parameters)
+			)
+			{
+				$this->resource .= $query;
+			}
+		}
+	}
+
+	/**
+	 * Get the region-specific hostname for an operation given a configuration and a bucket name. This ensures we can
+	 * always use an HTTPS connection, even with buckets containing dots in their names, without SSL certificate host
+	 * name validation issues.
+	 *
+	 * Please note that this requires the pathStyle flag to be set in Configuration because Amazon RECOMMENDS using the
+	 * virtual-hosted style request where applicable. See http://docs.aws.amazon.com/AmazonS3/latest/API/APIRest.html
+	 * Quoting this documentation:
+	 * "Although the path-style is still supported for legacy applications, we recommend using the virtual-hosted style
+	 * where applicable."
+	 *
+	 * @param   Configuration  $configuration
+	 * @param   string         $bucket
+	 *
+	 * @return  string
+	 */
+	private function getHostName(Configuration $configuration, string $bucket): string
+	{
+		// http://docs.aws.amazon.com/general/latest/gr/rande.html#s3_region
+		$endpoint = $configuration->getEndpoint();
+		$region   = $configuration->getRegion();
+
+		// If it's a bucket in China we need to use a different endpoint
+		if (($endpoint == 's3.amazonaws.com') && (substr($region, 0, 3) == 'cn-'))
+		{
+			$endpoint = 'amazonaws.com.cn';
+		}
+
+		/**
+		 * If there is no bucket we use the default endpoint, whatever it is. For Amazon S3 this format is only used
+		 * when we are making account-level, cross-region requests, e.g. list all buckets. For S3-compatible APIs it
+		 * depends on the API, but generally it's just for listing available buckets.
+		 */
+		if (empty($bucket))
+		{
+			return $endpoint;
+		}
+
+		/**
+		 * Are we using v2 signatures? In this case we use the endpoint defined by the user without translating it.
+		 */
+		if ($configuration->getSignatureMethod() != 'v4')
+		{
+			// Legacy path style: the hostname is the endpoint
+			if ($configuration->getUseLegacyPathStyle())
+			{
+				return $endpoint;
+			}
+
+			// Virtual hosting style: the hostname is the bucket, dot and endpoint.
+			return $bucket . '.' . $endpoint;
+		}
+
+		/**
+		 * Only applies to Amazon S3 proper.
+		 *
+		 * When using the Amazon S3 with the v4 signature API we have to use a different hostname per region. The
+		 * mapping can be found in https://docs.aws.amazon.com/general/latest/gr/s3.html#s3_region
+		 *
+		 * This means changing the endpoint to s3.REGION.amazonaws.com with the following exceptions:
+		 * For China: s3.REGION.amazonaws.com.cn
+		 *
+		 * v4 signing does NOT support non-Amazon endpoints.
+		 */
+		if (in_array($endpoint, ['s3.amazonaws.com', 'amazonaws.com.cn']))
+		{
+			// Most endpoints: s3-REGION.amazonaws.com
+			$regionalEndpoint = $region . '.amazonaws.com';
+
+			// Exception: China
+			if (substr($region, 0, 3) == 'cn-')
+			{
+				// Chinese endpoint, e.g.: s3.cn-north-1.amazonaws.com.cn
+				$regionalEndpoint = $regionalEndpoint . '.cn';
+			}
+
+			// If dual-stack URLs are enabled then prepend the endpoint
+			if ($configuration->getDualstackUrl())
+			{
+				$endpoint = 's3.dualstack.' . $regionalEndpoint;
+			}
+			else
+			{
+				$endpoint = 's3.' . $regionalEndpoint;
+			}
+		}
+
+		// Legacy path style access: return just the endpoint
+		if ($configuration->getUseLegacyPathStyle())
+		{
+			return $endpoint;
+		}
+
+		// Recommended virtual hosting access: bucket, dot, endpoint.
+		return $bucket . '.' . $endpoint;
+	}
+}

+ 216 - 0
upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/akeeba/s3/src/Signature/V2.php

@@ -0,0 +1,216 @@
+<?php
+/**
+ * Akeeba Engine
+ *
+ * @package   akeebaengine
+ * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
+ * @license   GNU General Public License version 3, or later
+ */
+
+namespace Akeeba\S3\Signature;
+
+// Protection against direct access
+defined('AKEEBAENGINE') || die();
+
+use Akeeba\S3\Signature;
+
+/**
+ * Implements the Amazon AWS v2 signatures
+ *
+ * @see http://docs.aws.amazon.com/AmazonS3/latest/dev/RESTAuthentication.html
+ */
+class V2 extends Signature
+{
+	/**
+	 * Pre-process the request headers before we convert them to cURL-compatible format. Used by signature engines to
+	 * add custom headers, e.g. x-amz-content-sha256
+	 *
+	 * @param   array  $headers     The associative array of headers to process
+	 * @param   array  $amzHeaders  The associative array of amz-* headers to process
+	 *
+	 * @return  void
+	 */
+	public function preProcessHeaders(array &$headers, array &$amzHeaders): void
+	{
+		// No pre-processing required for V2 signatures
+	}
+
+	/**
+	 * Get a pre-signed URL for the request. Typically used to pre-sign GET requests to objects, i.e. give shareable
+	 * pre-authorized URLs for downloading files from S3.
+	 *
+	 * @param   integer|null  $lifetime  Lifetime in seconds. NULL for default lifetime.
+	 * @param   bool          $https     Use HTTPS ($hostBucket should be false for SSL verification)?
+	 *
+	 * @return  string  The presigned URL
+	 */
+	public function getAuthenticatedURL(?int $lifetime = null, bool $https = false): string
+	{
+		// Set the Expires header
+		if (is_null($lifetime))
+		{
+			$lifetime = 10;
+		}
+
+		$expires = time() + $lifetime;
+		$this->request->setHeader('Expires', $expires);
+
+		$bucket    = $this->request->getBucket();
+		$uri       = $this->request->getResource();
+		$headers   = $this->request->getHeaders();
+		$accessKey = $this->request->getConfiguration()->getAccess();
+		$protocol  = $https ? 'https' : 'http';
+		$signature = $this->getAuthorizationHeader();
+
+		// NOTE: Pre-signed URLs are always generated through Connector::getAuthenticatedURL(), which forces path-style
+		// access. Therefore $uri (the request resource) already starts with "/{bucket}" and matches the resource that
+		// getAuthorizationHeader() signed. We must NOT add the bucket to the path again, or the URL path will not match
+		// the signature and the request will be rejected with a 403 SignatureDoesNotMatch.
+
+		$queryParameters = array_merge($this->request->getParameters(), [
+			'AWSAccessKeyId' => $accessKey,
+			'Expires'        => sprintf('%u', $expires),
+			'Signature'      => $signature,
+		]);
+
+		$query = http_build_query($queryParameters);
+
+		// fix authenticated url for Google Cloud Storage - https://cloud.google.com/storage/docs/access-control/create-signed-urls-program
+		if ($this->request->getConfiguration()->getEndpoint() === "storage.googleapis.com")
+		{
+			// replace host with endpoint
+			$headers['Host'] = 'storage.googleapis.com';
+			// replace "AWSAccessKeyId" with "GoogleAccessId"
+			$query = str_replace('AWSAccessKeyId', 'GoogleAccessId', $query);
+			// NOTE: the bucket is NOT added to the path here. $uri already begins with "/{bucket}" (see the note above),
+			// so prepending it again would produce "/{bucket}/{bucket}/..." which no longer matches the signed resource
+			// and Google Cloud Storage rejects it with 403 SignatureDoesNotMatch.
+		}
+
+		$url = $protocol . '://' . $headers['Host'] . $uri;
+		$url .= (strpos($uri, '?') !== false) ? '&' : '?';
+		$url .= $query;
+
+		return $url;
+	}
+
+	/**
+	 * Returns the authorization header for the request
+	 *
+	 * @return  string
+	 */
+	public function getAuthorizationHeader(): string
+	{
+		$verb           = strtoupper($this->request->getVerb());
+		$resourcePath   = $this->request->getResource();
+		$headers        = $this->request->getHeaders();
+		$amzHeaders     = $this->request->getAmzHeaders();
+		$parameters     = $this->request->getParameters();
+		$bucket         = $this->request->getBucket();
+		$isPresignedURL = false;
+
+		$amz       = [];
+		$amzString = '';
+
+		// Collect AMZ headers for signature
+		foreach ($amzHeaders as $header => $value)
+		{
+			if (strlen($value) > 0)
+			{
+				$amz[] = strtolower($header) . ':' . $value;
+			}
+		}
+
+		// AMZ headers must be sorted and sent as separate lines
+		if (count($amz) > 0)
+		{
+			sort($amz);
+			$amzString = "\n" . implode("\n", $amz);
+		}
+
+		// If the Expires query string parameter is set up we're pre-signing a download URL. The string to sign is a bit
+		// different in this case; it does not include the Date, it includes the Expires.
+		// See http://docs.aws.amazon.com/AmazonS3/latest/dev/RESTAuthentication.html#RESTAuthenticationQueryStringAuth
+		if (isset($headers['Expires']))
+		{
+			if (isset($headers['Date']))
+			{
+				$headers['Date'] = $headers['Expires'];
+			}
+			else
+			{
+				$amzHeaders['x-amz-date'] = $headers['Expires'];
+			}
+
+			unset ($headers['Expires']);
+
+			$isPresignedURL = true;
+		}
+
+		/**
+		 * The resource path in S3 V2 signatures must ALWAYS contain the bucket name if a bucket is defined, even if we
+		 * are not using path-style access to the resource
+		 */
+		if (!empty($bucket) && !$this->request->getConfiguration()->getUseLegacyPathStyle())
+		{
+			$resourcePath = '/' . $bucket . $resourcePath;
+		}
+
+		$stringToSign = $verb . "\n" .
+			($headers['Content-MD5'] ?? '') . "\n" .
+			($headers['Content-Type'] ?? '') . "\n" .
+			($headers['Date'] ?? '') .
+			$amzString . "\n" .
+			$resourcePath;
+
+		// CloudFront only requires a date to be signed
+		if ($headers['Host'] == 'cloudfront.amazonaws.com')
+		{
+			$stringToSign = $headers['Date'] ?? $amzHeaders['x-amz-date'] ?? '';
+		}
+
+		$amazonV2Hash = $this->amazonV2Hash($stringToSign);
+
+		// For presigned URLs we only return the Base64-encoded signature without the AWS format specifier and the
+		// public access key.
+		if ($isPresignedURL)
+		{
+			return $amazonV2Hash;
+		}
+
+		return 'AWS ' .
+			$this->request->getConfiguration()->getAccess() . ':' .
+			$amazonV2Hash;
+	}
+
+	/**
+	 * Creates a HMAC-SHA1 hash. Uses the hash extension if present, otherwise falls back to slower, manual calculation.
+	 *
+	 * @param   string  $stringToSign  String to sign
+	 *
+	 * @return  string
+	 */
+	private function amazonV2Hash(string $stringToSign): string
+	{
+		$secret = $this->request->getConfiguration()->getSecret();
+
+		if (extension_loaded('hash'))
+		{
+			$raw = hash_hmac('sha1', $stringToSign, $secret, true);
+
+			return base64_encode($raw);
+		}
+
+		$raw = pack('H*', sha1(
+				(str_pad($secret, 64, chr(0x00)) ^ (str_repeat(chr(0x5c), 64))) .
+				pack('H*', sha1(
+						(str_pad($secret, 64, chr(0x00)) ^ (str_repeat(chr(0x36), 64))) . $stringToSign
+					)
+				)
+			)
+		);
+
+		return base64_encode($raw);
+	}
+
+}

+ 544 - 0
upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/akeeba/s3/src/Signature/V4.php

@@ -0,0 +1,544 @@
+<?php
+/**
+ * Akeeba Engine
+ *
+ * @package   akeebaengine
+ * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
+ * @license   GNU General Public License version 3, or later
+ */
+
+namespace Akeeba\S3\Signature;
+
+// Protection against direct access
+defined('AKEEBAENGINE') || die();
+
+use Akeeba\S3\Signature;
+use DateTime;
+
+/**
+ * Implements the Amazon AWS v4 signatures
+ *
+ * @see http://docs.aws.amazon.com/general/latest/gr/signature-version-4.html
+ */
+class V4 extends Signature
+{
+	/**
+	 * Pre-process the request headers before we convert them to cURL-compatible format. Used by signature engines to
+	 * add custom headers, e.g. x-amz-content-sha256
+	 *
+	 * @param   array  $headers     The associative array of headers to process
+	 * @param   array  $amzHeaders  The associative array of amz-* headers to process
+	 *
+	 * @return  void
+	 */
+	public function preProcessHeaders(array &$headers, array &$amzHeaders): void
+	{
+		// Do we already have an SHA-256 payload hash?
+		if (isset($amzHeaders['x-amz-content-sha256']))
+		{
+			return;
+		}
+
+		// Set the payload hash header
+		$input = $this->request->getInput();
+
+		if (is_object($input))
+		{
+			$requestPayloadHash = $input->getSha256();
+		}
+		else
+		{
+			$requestPayloadHash = hash('sha256', '', false);
+		}
+
+		$amzHeaders['x-amz-content-sha256'] = $requestPayloadHash;
+	}
+
+	/**
+	 * Get a pre-signed URL for the request. Typically used to pre-sign GET requests to objects, i.e. give shareable
+	 * pre-authorized URLs for downloading files from S3.
+	 *
+	 * @param   integer|null  $lifetime  Lifetime in seconds. NULL for default lifetime.
+	 * @param   bool          $https     Use HTTPS ($hostBucket should be false for SSL verification)?
+	 *
+	 * @return  string  The presigned URL
+	 */
+	public function getAuthenticatedURL(?int $lifetime = null, bool $https = false): string
+	{
+		// Set the Expires header
+		if (is_null($lifetime))
+		{
+			$lifetime = 10;
+		}
+
+		/**
+		 * Authenticated URLs must always go through the generic regional endpoint, not the virtual hosting-style domain
+		 * name. This means that if you have a bucket "example" in the EU West 1 (Ireland) region we have to go through
+		 * http://s3-eu-west-1.amazonaws.com/example instead of http://example.amazonaws.com/ for all authenticated URLs
+		 */
+		$region   = $this->request->getConfiguration()->getRegion();
+		$bucket   = $this->request->getBucket();
+		$hostname = $this->getPresignedHostnameForRegion($region);
+
+		if (!$this->request->getConfiguration()->getPreSignedBucketInURL() && $this->isValidBucketName($bucket))
+		{
+			$hostname = $bucket . '.' . $hostname;
+		}
+
+		$this->request->setHeader('Host', $hostname);
+
+		// Set the expiration time in seconds
+		$this->request->setHeader('Expires', (int) $lifetime);
+
+		// Get the query parameters, including the calculated signature
+		$uri              = $this->request->getResource();
+		$headers          = $this->request->getHeaders();
+		$protocol         = $https ? 'https' : 'http';
+		$serialisedParams = $this->getAuthorizationHeader();
+
+		// The query parameters are returned serialized; unserialize them, then build and return the URL.
+		$queryParameters = unserialize($serialisedParams);
+
+		// This should be toggleable
+		if (
+			!$this->request->getConfiguration()->getPreSignedBucketInURL()
+			&& $this->isValidBucketName($bucket)
+			&& strpos($uri, '/' . $bucket) === 0)
+		{
+			$uri = substr($uri, strlen($bucket) + 1);
+		}
+
+		$query = http_build_query($queryParameters);
+
+		$url = $protocol . '://' . $headers['Host'] . $uri;
+		$url .= (strpos($uri, '?') !== false) ? '&' : '?';
+		$url .= $query;
+
+		return $url;
+	}
+
+	/**
+	 * Returns the authorization header for the request
+	 *
+	 * @return  string
+	 */
+	public function getAuthorizationHeader(): string
+	{
+		$verb           = strtoupper($this->request->getVerb());
+		$resourcePath   = $this->request->getResource();
+		$headers        = $this->request->getHeaders();
+		$amzHeaders     = $this->request->getAmzHeaders();
+		$parameters     = $this->request->getParameters();
+		$bucket         = $this->request->getBucket();
+		$isPresignedURL = false;
+
+		// See the Connector class for the explanation behind this ugly workaround
+		$amazonIsBraindead = isset($headers['workaround-braindead-error-from-amazon']);
+
+		if ($amazonIsBraindead)
+		{
+			unset ($headers['workaround-braindead-error-from-amazon']);
+		}
+
+		// Get the credentials scope
+		$signatureDate = new DateTime($headers['Date'] ?? $amzHeaders['x-amz-date']);
+
+		$credentialScope = $signatureDate->format('Ymd') . '/' .
+		                   $this->request->getConfiguration()->getRegion() . '/' .
+		                   's3/aws4_request';
+
+		/**
+		 * If the Expires header is set up we're pre-signing a download URL. The string to sign is a bit
+		 * different in this case and we have to pass certain headers as query string parameters.
+		 *
+		 * @see http://docs.aws.amazon.com/general/latest/gr/sigv4-create-string-to-sign.html
+		 */
+		if (isset($headers['Expires']))
+		{
+			$gmtDate = clone $signatureDate;
+			$gmtDate->setTimezone(new \DateTimeZone('GMT'));
+
+			$parameters['X-Amz-Algorithm']  = "AWS4-HMAC-SHA256";
+			$parameters['X-Amz-Credential'] = $this->request->getConfiguration()->getAccess() . '/' . $credentialScope;
+			$parameters['X-Amz-Date']       = $gmtDate->format('Ymd\THis\Z');
+			$parameters['X-Amz-Expires']    = sprintf('%u', $headers['Expires']);
+			$token                          = $this->request->getConfiguration()->getToken();
+
+			if (!empty($token))
+			{
+				$parameters['x-amz-security-token'] = $token;
+			}
+
+			unset($headers['Expires']);
+			unset($headers['Date']);
+			unset($headers['Content-MD5']);
+			unset($headers['Content-Type']);
+
+			$isPresignedURL = true;
+		}
+
+		// ========== Step 1: Create a canonical request ==========
+		// See http://docs.aws.amazon.com/general/latest/gr/sigv4-create-canonical-request.html
+
+		$canonicalHeaders   = "";
+		$signedHeadersArray = [];
+
+		// Calculate the canonical headers and the signed headers
+		if ($isPresignedURL)
+		{
+			// Presigned URLs use UNSIGNED-PAYLOAD instead
+			unset($amzHeaders['x-amz-content-sha256']);
+		}
+
+		$allHeaders = array_merge($headers, $amzHeaders);
+		ksort($allHeaders);
+
+		foreach ($allHeaders as $k => $v)
+		{
+			$lowercaseHeaderName = strtolower($k);
+
+			if ($amazonIsBraindead && ($lowercaseHeaderName == 'content-length'))
+			{
+				/**
+				 * I know it looks crazy. It is. Somehow Amazon requires me to do this and only on _some_ servers, mind
+				 * you. This is something undocumented and which is not covered by their official SDK. I had to write
+				 * my own library because of that and the official SDK's inability to upload large files without using
+				 * at least as much memory as the file itself (which doesn't fly well for files around 2Gb, let me tell
+				 * you that!).
+				 */
+				$v = "$v,$v";
+			}
+
+			$canonicalHeaders     .= $lowercaseHeaderName . ':' . trim($v) . "\n";
+			$signedHeadersArray[] = $lowercaseHeaderName;
+		}
+
+		$signedHeaders = implode(';', $signedHeadersArray);
+
+		if ($isPresignedURL)
+		{
+			$parameters['X-Amz-SignedHeaders'] = $signedHeaders;
+		}
+
+		// The canonical URI is the resource path
+		$canonicalURI     = $resourcePath;
+		$bucketResource   = '/' . $bucket . '/';
+		$regionalHostname = ($headers['Host'] != 's3.amazonaws.com')
+		                    && ($headers['Host'] != $bucket . '.s3.amazonaws.com');
+
+		/**
+		 * Yet another special case for third party, S3-compatible services, when using pre-signed URLs.
+		 *
+		 * Given a bucket `example` and filepath `foo/bar.txt` the canonical URI to sign is supposed to be
+		 * /example/foo/bar.txt regardless of whether we are using path style or subdomain hosting style access to the
+		 * bucket.
+		 *
+		 * When calculating a pre-signed URL, the URL we will be accessing will be something to the tune of
+		 * example.endpoint.com/foo/bar.txt. Amazon S3 proper allows us to use EITHER the nominal canonical URI
+		 * /foo/bar.txt OR the /example/foo/bar.txt canonical URI for consistency. Some third party providers, like
+		 * Wasabi, will choke on the former and complain about the signature being invalid.
+		 *
+		 * To address this issue we check if all the following conditions are met:
+		 * - We are calculating a signature for a pre-signed URL.
+		 * - The service is NOT Amazon S3 proper.
+		 * - The domain name starts with the bucket name.
+		 * In this case, and this case only, we set $regionalHostname to false. This triggers an if-block further down
+		 * which strips the `/bucketName/` prefix from the canonical URI, converting it to `/`. Therefore, the canonical
+		 * URI in the signature becomes the nominal URI we will be accessing in the bucket, solving the problem with
+		 * those third party services.
+		 *
+		 * IMPORTANT: this stripping is only correct when the bucket is NOT part of the URL path we will actually request,
+		 * i.e. when the bucket lives in the hostname (virtual-hosting style). When getPreSignedBucketInURL() is true we
+		 * deliberately keep the bucket as the first path component of the pre-signed URL (path-style access — required by
+		 * S3-compatible services reached through a host:port endpoint with no per-bucket DNS, such as a local MinIO). In
+		 * that case the bucket IS in the requested path, so the canonical URI must keep it too; stripping it here would
+		 * sign `/object` while requesting `/bucket/object`, which strict services reject with SignatureDoesNotMatch.
+		 */
+		// Figuring out whether it's a regional hostname DOES NOT work above if it's not AWS S3 proper. Let's fix that.
+		if ($isPresignedURL
+		    && !$this->request->getConfiguration()->getPreSignedBucketInURL()
+		    && strpos($headers['Host'], 'amazonaws.com') === false
+		    && !strpos($headers['Host'], $bucket . '.'))
+		{
+			$regionalHostname = false;
+		}
+
+		// Special case: if the canonical URI ends in /?location the bucket name DOES count as part of the canonical URL
+		// even though the Host is s3.amazonaws.com (in which case it normally shouldn't count). Yeah, I know, it makes
+		// no sense!!!
+		if (!$regionalHostname && ($headers['Host'] == 's3.amazonaws.com')
+		    && (substr($canonicalURI, -10) == '/?location'))
+		{
+			$regionalHostname = true;
+		}
+
+		if (!$regionalHostname && (strpos($canonicalURI, $bucketResource) === 0 || strpos($canonicalURI, substr($bucketResource, 0, -1)) === 0))
+		{
+			if ($canonicalURI === substr($bucketResource, 0, -1))
+			{
+				$canonicalURI = '/';
+			}
+			else
+			{
+				$canonicalURI = substr($canonicalURI, strlen($bucketResource) - 1);
+			}
+		}
+
+		// If the resource path has a query yank it and parse it into the parameters array
+		$questionMarkPos = strpos($canonicalURI, '?');
+
+		if ($questionMarkPos !== false)
+		{
+			$canonicalURI = substr($canonicalURI, 0, $questionMarkPos);
+			$queryString  = @substr($canonicalURI, $questionMarkPos + 1);
+			@parse_str($queryString, $extraQuery);
+
+			if (count($extraQuery))
+			{
+				$parameters = array_merge($parameters, $extraQuery);
+			}
+		}
+
+		// The canonical query string is the string representation of $parameters, alpha sorted by key
+		ksort($parameters);
+
+		// We build the query the hard way because http_build_query in PHP 5.3 does NOT have the fourth parameter
+		// (encoding type), defaulting to RFC 1738 encoding whereas S3 expects RFC 3986 encoding
+		$canonicalQueryString = '';
+
+		if (!empty($parameters))
+		{
+			$temp = [];
+
+			foreach ($parameters as $k => $v)
+			{
+				$temp[] = $this->urlencode($k) . '=' . $this->urlencode($v);
+			}
+
+			$canonicalQueryString = implode('&', $temp);
+		}
+
+		// Get the payload hash
+		$requestPayloadHash = 'UNSIGNED-PAYLOAD';
+
+		if (isset($amzHeaders['x-amz-content-sha256']))
+		{
+			$requestPayloadHash = $amzHeaders['x-amz-content-sha256'];
+		}
+
+		// Calculate the canonical request
+		$canonicalRequest = $verb . "\n" .
+		                    $canonicalURI . "\n" .
+		                    $canonicalQueryString . "\n" .
+		                    $canonicalHeaders . "\n" .
+		                    $signedHeaders . "\n" .
+		                    $requestPayloadHash;
+
+		$hashedCanonicalRequest = hash('sha256', $canonicalRequest);
+
+		// ========== Step 2: Create a string to sign ==========
+		// See http://docs.aws.amazon.com/general/latest/gr/sigv4-create-string-to-sign.html
+
+		if (!isset($headers['Date']))
+		{
+			$headers['Date'] = '';
+		}
+
+		/**
+		 * The Date in the String-to-Sign is a messy situation.
+		 *
+		 * Amazon's documentation says it must be in ISO 8601 format: `Ymd\THis\Z`. Unfortunately, Amazon's
+		 * documentation is actually wrong :troll_face: The actual Amazon S3 service expects the date to be formatted as
+		 * per RFC1123.
+		 *
+		 * Most third party implementations have caught up to the fact that Amazon has documented the v4 signatures
+		 * wrongly (naughty AWS!) and accept either format.
+		 *
+		 * Some other third party implementations, which never bothered to validate their implementations against Amazon
+		 * S3 proper, only expect what Amazon has documented as "ISO 8601". Therefore, we detect third party services
+		 * and switch to the as-documented date format.
+		 *
+		 * Some other third party services, like Wasabi, are broken in yet a different way. They will only use the date
+		 * from the x-amz-date header, WITHOUT falling back to the Date header if the former is not present. This is
+		 * the opposite of Amazon S3 proper which does expect the Date header. That's why the Request class sets both
+		 * headers if the request is made to a service _other_ than Amazon S3 proper.
+		 */
+		$dateToSignFor = strpos($headers['Host'], '.amazonaws.com') !== false
+			? (($headers['Date'] ?? null) ?: ($amzHeaders['x-amz-date'] ?? null) ?: $signatureDate->format('Ymd\THis\Z'))
+			: $signatureDate->format('Ymd\THis\Z');
+
+		$stringToSign = "AWS4-HMAC-SHA256\n" .
+		                $dateToSignFor . "\n" .
+		                $credentialScope . "\n" .
+		                $hashedCanonicalRequest;
+
+		if ($isPresignedURL)
+		{
+			$stringToSign = "AWS4-HMAC-SHA256\n" .
+			                $parameters['X-Amz-Date'] . "\n" .
+			                $credentialScope . "\n" .
+			                $hashedCanonicalRequest;
+		}
+
+		// ========== Step 3: Calculate the signature ==========
+		// See http://docs.aws.amazon.com/general/latest/gr/sigv4-calculate-signature.html
+		$kSigning = $this->getSigningKey($signatureDate);
+
+		$signature = hash_hmac('sha256', $stringToSign, $kSigning, false);
+
+		// ========== Step 4: Add the signing information to the Request ==========
+		// See http://docs.aws.amazon.com/general/latest/gr/sigv4-add-signature-to-request.html
+
+		$authorization = 'AWS4-HMAC-SHA256 Credential=' .
+		                 $this->request->getConfiguration()->getAccess() . '/' . $credentialScope . ', ' .
+		                 'SignedHeaders=' . $signedHeaders . ', ' .
+		                 'Signature=' . $signature;
+
+		// For presigned URLs we only return the Base64-encoded signature without the AWS format specifier and the
+		// public access key.
+		if ($isPresignedURL)
+		{
+			$parameters['X-Amz-Signature'] = $signature;
+
+			return serialize($parameters);
+		}
+
+		return $authorization;
+	}
+
+	/**
+	 * Calculate the AWS4 signing key
+	 *
+	 * @param   DateTime  $signatureDate  The date the signing key is good for
+	 *
+	 * @return  string
+	 */
+	private function getSigningKey(DateTime $signatureDate): string
+	{
+		$kSecret  = $this->request->getConfiguration()->getSecret();
+		$kDate    = hash_hmac('sha256', $signatureDate->format('Ymd'), 'AWS4' . $kSecret, true);
+		$kRegion  = hash_hmac('sha256', $this->request->getConfiguration()->getRegion(), $kDate, true);
+		$kService = hash_hmac('sha256', 's3', $kRegion, true);
+		$kSigning = hash_hmac('sha256', 'aws4_request', $kService, true);
+
+		return $kSigning;
+	}
+
+	private function urlencode(?string $toEncode): string
+	{
+		return empty($toEncode) ? '' : rawurlencode($toEncode);
+	}
+
+	/**
+	 * Get the correct hostname for the given AWS region
+	 *
+	 * @param   string  $region
+	 *
+	 * @return  string
+	 */
+	private function getPresignedHostnameForRegion(string $region): string
+	{
+		$config   = $this->request->getConfiguration();
+		$endpoint = $config->getEndpoint();
+
+		if (empty($endpoint))
+		{
+			$endpoint = 's3.' . $region . '.amazonaws.com';
+		}
+
+		// As of October 2023, AWS does not consider DualStack signed URLs as valid. Whatever.
+		$dualstackEnabled = false && $this->request->getConfiguration()->getDualstackUrl();
+
+		// If dual-stack URLs are enabled then prepend the endpoint
+		if ($dualstackEnabled)
+		{
+			$endpoint = 's3.dualstack.' . $region . '.amazonaws.com';
+		}
+
+		if ($region == 'cn-north-1')
+		{
+			return $endpoint . '.cn';
+		}
+
+		return $endpoint;
+	}
+
+	/**
+	 * Is this a valid bucket name?
+	 *
+	 * @param   string  $bucketName   The bucket name to check
+	 * @param   bool    $asSubdomain  Should I put additional restrictions for use as a subdomain?
+	 *
+	 * @return  bool
+	 * @since   2.3.1
+	 *
+	 * @see     https://docs.aws.amazon.com/AmazonS3/latest/userguide/bucketnamingrules.html
+	 */
+	private function isValidBucketName(string $bucketName, bool $asSubdomain = true): bool
+	{
+		/**
+		 * If there are dots in the bucket name I can't use it as a subdomain.
+		 *
+		 * "If you include dots in a bucket's name, you can't use virtual-host-style addressing over HTTPS, unless you
+		 * perform your own certificate validation. This is because the security certificates used for virtual hosting
+		 * of buckets don't work for buckets with dots in their names."
+		 */
+		if ($asSubdomain && strpos($bucketName, '.') !== false)
+		{
+			return false;
+		}
+
+		/**
+		 * - Bucket names must be between 3 (min) and 63 (max) characters long.
+		 * - Bucket names can consist only of lowercase letters, numbers, dots (.), and hyphens (-).
+		 */
+		if (!preg_match('/^[a-z0-9\-.]{3,63}$/', $bucketName))
+		{
+			return false;
+		}
+
+		// Bucket names must begin and end with a letter or number.
+		if (!preg_match('/^[a-z0-9].*[a-z0-9]$/', $bucketName))
+		{
+			return false;
+		}
+
+		// Bucket names must not contain two adjacent periods.
+		if (preg_match('/\.\./', $bucketName))
+		{
+			return false;
+		}
+
+		// Bucket names must not be formatted as an IP address (for example, 192.168.5.4).
+		if (preg_match('/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/', $bucketName))
+		{
+			return false;
+		}
+
+		// Bucket names must not start with the prefix xn--.
+		if (strpos($bucketName, 'xn--') === 0)
+		{
+			return false;
+		}
+
+		// Bucket names must not start with the prefix sthree- and the prefix sthree-configurator.
+		if (strpos($bucketName, 'sthree-') === 0)
+		{
+			return false;
+		}
+
+		// Bucket names must not end with the suffix -s3alias.
+		if (substr($bucketName, -8) === '-s3alias')
+		{
+			return false;
+		}
+
+		// Bucket names must not end with the suffix --ol-s3.
+		if (substr($bucketName, -7) === '--ol-s3')
+		{
+			return false;
+		}
+
+		return true;
+	}
+}

+ 22 - 0
upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/autoload.php

@@ -0,0 +1,22 @@
+<?php
+
+// autoload.php @generated by Composer
+
+if (PHP_VERSION_ID < 50600) {
+    if (!headers_sent()) {
+        header('HTTP/1.1 500 Internal Server Error');
+    }
+    $err = 'Composer 2.3.0 dropped support for autoloading on PHP <5.6 and you are running '.PHP_VERSION.', please upgrade PHP or use Composer 2.2 LTS via "composer self-update --2.2". Aborting.'.PHP_EOL;
+    if (!ini_get('display_errors')) {
+        if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') {
+            fwrite(STDERR, $err);
+        } elseif (!headers_sent()) {
+            echo $err;
+        }
+    }
+    throw new RuntimeException($err);
+}
+
+require_once __DIR__ . '/composer/autoload_real.php';
+
+return ComposerAutoloaderInitd17564377c879180b700e94c9bf41bd3::getLoader();

+ 73 - 0
upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/composer.json

@@ -0,0 +1,73 @@
+{
+    "name": "aws/aws-sdk-php",
+    "homepage": "https://aws.amazon.com/sdk-for-php",
+    "description": "AWS SDK for PHP - Use Amazon Web Services in your PHP project",
+    "keywords": ["aws","amazon","sdk","s3","ec2","dynamodb","cloud","glacier"],
+    "type": "library",
+    "license": "Apache-2.0",
+    "authors": [
+        {
+            "name": "Amazon Web Services",
+            "homepage": "https://aws.amazon.com"
+        }
+    ],
+    "support": {
+        "forum": "https://github.com/aws/aws-sdk-php/discussions",
+        "issues": "https://github.com/aws/aws-sdk-php/issues"
+    },
+    "require": {
+        "php": ">=8.1",
+        "guzzlehttp/guzzle": "^7.4.5",
+        "guzzlehttp/psr7": "^2.4.5",
+        "guzzlehttp/promises": "^2.0",
+        "mtdowling/jmespath.php": "^2.9.1",
+        "ext-pcre": "*",
+        "ext-json": "*",
+        "ext-simplexml": "*",
+        "aws/aws-crt-php": "^1.2.3",
+        "psr/http-message": "^1.0 || ^2.0",
+        "symfony/filesystem": "^v5.4.45 || ^v6.4.3 || ^v7.1.0 || ^v8.0.0"
+    },
+    "require-dev": {
+        "composer/composer" : "^2.7.8",
+        "ext-openssl": "*",
+        "ext-dom": "*",
+        "ext-sockets": "*",
+        "phpunit/phpunit": "^10.0",
+        "behat/behat": "~3.0",
+        "doctrine/cache": "~1.4",
+        "aws/aws-php-sns-message-validator": "~1.0",
+        "andrewsville/php-token-reflection": "^1.4",
+        "psr/cache": "^2.0 || ^3.0",
+        "psr/simple-cache": "^2.0 || ^3.0",
+        "sebastian/comparator": "^1.2.3 || ^4.0 || ^5.0",
+        "yoast/phpunit-polyfills": "^2.0",
+        "dms/phpunit-arraysubset-asserts": "^v0.5.0"
+    },
+    "suggest": {
+        "ext-openssl": "Allows working with CloudFront private distributions and verifying received SNS messages",
+        "ext-curl": "To send requests using cURL",
+        "ext-sockets": "To use client-side monitoring",
+        "ext-pcntl": "To use client-side monitoring",
+        "doctrine/cache": "To use the DoctrineCacheAdapter",
+        "aws/aws-php-sns-message-validator": "To validate incoming SNS notifications"
+    },
+    "autoload": {
+        "psr-4": {
+            "Aws\\": "src/"
+        },
+        "files": ["src/functions.php"],
+        "exclude-from-classmap": ["src/data/"]
+    },
+    "autoload-dev": {
+        "psr-4": {
+            "Aws\\Test\\": "tests/"
+        },
+        "classmap": ["build/"]
+    },
+    "extra": {
+        "branch-alias": {
+            "dev-master": "3.0-dev"
+        }
+    }
+}

+ 88 - 0
upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/Acm/AcmClient.php

@@ -0,0 +1,88 @@
+<?php
+namespace Aws\Acm;
+
+use Aws\AwsClient;
+
+/**
+ * This client is used to interact with the **AWS Certificate Manager** service.
+ *
+ * @method \Aws\Result addTagsToCertificate(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise addTagsToCertificateAsync(array $args = [])
+ * @method \Aws\Result createAcmeDomainValidation(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createAcmeDomainValidationAsync(array $args = [])
+ * @method \Aws\Result createAcmeEndpoint(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createAcmeEndpointAsync(array $args = [])
+ * @method \Aws\Result createAcmeExternalAccountBinding(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createAcmeExternalAccountBindingAsync(array $args = [])
+ * @method \Aws\Result deleteAcmeDomainValidation(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteAcmeDomainValidationAsync(array $args = [])
+ * @method \Aws\Result deleteAcmeEndpoint(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteAcmeEndpointAsync(array $args = [])
+ * @method \Aws\Result deleteAcmeExternalAccountBinding(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteAcmeExternalAccountBindingAsync(array $args = [])
+ * @method \Aws\Result deleteCertificate(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteCertificateAsync(array $args = [])
+ * @method \Aws\Result describeAcmeAccount(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeAcmeAccountAsync(array $args = [])
+ * @method \Aws\Result describeAcmeDomainValidation(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeAcmeDomainValidationAsync(array $args = [])
+ * @method \Aws\Result describeAcmeEndpoint(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeAcmeEndpointAsync(array $args = [])
+ * @method \Aws\Result describeAcmeExternalAccountBinding(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeAcmeExternalAccountBindingAsync(array $args = [])
+ * @method \Aws\Result describeCertificate(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeCertificateAsync(array $args = [])
+ * @method \Aws\Result exportCertificate(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise exportCertificateAsync(array $args = [])
+ * @method \Aws\Result getAccountConfiguration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getAccountConfigurationAsync(array $args = [])
+ * @method \Aws\Result getAcmeExternalAccountBindingCredentials(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getAcmeExternalAccountBindingCredentialsAsync(array $args = [])
+ * @method \Aws\Result getCertificate(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getCertificateAsync(array $args = [])
+ * @method \Aws\Result importCertificate(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise importCertificateAsync(array $args = [])
+ * @method \Aws\Result listAcmeAccounts(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listAcmeAccountsAsync(array $args = [])
+ * @method \Aws\Result listAcmeDomainValidations(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listAcmeDomainValidationsAsync(array $args = [])
+ * @method \Aws\Result listAcmeEndpoints(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listAcmeEndpointsAsync(array $args = [])
+ * @method \Aws\Result listAcmeExternalAccountBindings(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listAcmeExternalAccountBindingsAsync(array $args = [])
+ * @method \Aws\Result listCertificates(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listCertificatesAsync(array $args = [])
+ * @method \Aws\Result listTagsForCertificate(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listTagsForCertificateAsync(array $args = [])
+ * @method \Aws\Result listTagsForResource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listTagsForResourceAsync(array $args = [])
+ * @method \Aws\Result putAccountConfiguration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise putAccountConfigurationAsync(array $args = [])
+ * @method \Aws\Result removeTagsFromCertificate(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise removeTagsFromCertificateAsync(array $args = [])
+ * @method \Aws\Result renewCertificate(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise renewCertificateAsync(array $args = [])
+ * @method \Aws\Result requestCertificate(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise requestCertificateAsync(array $args = [])
+ * @method \Aws\Result resendValidationEmail(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise resendValidationEmailAsync(array $args = [])
+ * @method \Aws\Result revokeAcmeAccount(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise revokeAcmeAccountAsync(array $args = [])
+ * @method \Aws\Result revokeAcmeExternalAccountBinding(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise revokeAcmeExternalAccountBindingAsync(array $args = [])
+ * @method \Aws\Result revokeCertificate(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise revokeCertificateAsync(array $args = [])
+ * @method \Aws\Result searchCertificates(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise searchCertificatesAsync(array $args = [])
+ * @method \Aws\Result tagResource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise tagResourceAsync(array $args = [])
+ * @method \Aws\Result untagResource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise untagResourceAsync(array $args = [])
+ * @method \Aws\Result updateAcmeDomainValidation(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateAcmeDomainValidationAsync(array $args = [])
+ * @method \Aws\Result updateAcmeEndpoint(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateAcmeEndpointAsync(array $args = [])
+ * @method \Aws\Result updateCertificateOptions(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateCertificateOptionsAsync(array $args = [])
+ */
+class AcmClient extends AwsClient {}

+ 540 - 0
upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/Api/Serializer/RestSerializer.php

@@ -0,0 +1,540 @@
+<?php
+namespace Aws\Api\Serializer;
+
+use Aws\Api\ListShape;
+use Aws\Api\MapShape;
+use Aws\Api\Service;
+use Aws\Api\Operation;
+use Aws\Api\Shape;
+use Aws\Api\StructureShape;
+use Aws\Api\TimestampShape;
+use Aws\CommandInterface;
+use Aws\EndpointV2\EndpointV2SerializerTrait;
+use Aws\EndpointV2\Ruleset\RulesetEndpoint;
+use DateTimeInterface;
+use GuzzleHttp\Psr7;
+use GuzzleHttp\Psr7\Request;
+use GuzzleHttp\Psr7\Uri;
+use GuzzleHttp\Psr7\UriResolver;
+use Psr\Http\Message\RequestInterface;
+use Psr\Http\Message\UriInterface;
+
+/**
+ * Serializes HTTP locations like header, uri, payload, etc...
+ * @internal
+ */
+abstract class RestSerializer
+{
+    private const TEMPLATE_STRING_REGEX = '/\{([^\}]+)\}/';
+
+    private static array $excludeContentType = [
+        's3' => true,
+        'glacier' => true
+    ];
+
+    /** @var Service */
+    private Service $api;
+
+    /** @var Uri */
+    private $endpoint;
+
+    /** @var bool */
+    private $isUseEndpointV2;
+
+    use EndpointV2SerializerTrait;
+
+    /**
+     * @param Service $api Service API description
+     * @param string $endpoint Endpoint to connect to
+     */
+    public function __construct(Service $api, $endpoint)
+    {
+        $this->api = $api;
+        $this->endpoint = Psr7\Utils::uriFor($endpoint);
+    }
+
+    /**
+     * @param CommandInterface $command Command to serialize into a request.
+     * @param mixed|null $endpoint
+     * @return RequestInterface
+     */
+    public function __invoke(
+        CommandInterface $command,
+        mixed $endpoint = null
+    )
+    {
+        $operation = $this->api->getOperation($command->getName());
+        $commandArgs = $command->toArray();
+        $opts = $this->serialize($operation, $commandArgs);
+        $headers = $opts['headers'] ?? [];
+
+        if ($endpoint instanceof RulesetEndpoint) {
+            $this->isUseEndpointV2 = true;
+            $this->setEndpointV2RequestOptions($endpoint, $headers);
+        }
+
+        $uri = $this->buildEndpoint($operation, $commandArgs, $opts);
+
+        return new Request(
+            $operation['http']['method'],
+            $uri,
+            $headers,
+            $opts['body'] ?? null
+        );
+    }
+
+    /**
+     * Modifies a hash of request options for a payload body.
+     *
+     * @param StructureShape $member Member to serialize
+     * @param array $value Value to serialize
+     * @param array $opts Request options to modify.
+     */
+    abstract protected function payload(
+        StructureShape $member,
+        array $value,
+        array &$opts
+    );
+
+    private function serialize(Operation $operation, array $args)
+    {
+        $opts = [];
+        $input = $operation->getInput();
+
+        // Apply the payload trait if present
+        if ($payload = $input['payload']) {
+            $this->applyPayload($input, $payload, $args, $opts);
+        }
+
+        foreach ($args as $name => $value) {
+            if ($input->hasMember($name)) {
+                $member = $input->getMember($name);
+                $location = $member['location'];
+                if (!$payload && !$location) {
+                    $bodyMembers[$name] = $value;
+                } elseif ($location === 'header') {
+                    $this->applyHeader($name, $member, $value, $opts);
+                } elseif ($location === 'querystring') {
+                    $this->applyQuery($name, $member, $value, $opts);
+                } elseif ($location === 'headers') {
+                    $this->applyHeaderMap($name, $member, $value, $opts);
+                }
+            }
+        }
+
+        if (isset($bodyMembers)) {
+            $this->payload($input, $bodyMembers, $opts);
+        } else if (!isset($opts['body']) && $this->hasPayloadParam($input, $payload)) {
+            $this->payload($input, [], $opts);
+        }
+
+        return $opts;
+    }
+
+    private function applyPayload(StructureShape $input, $name, array $args, array &$opts)
+    {
+        if (!isset($args[$name])) {
+            return;
+        }
+
+        $m = $input->getMember($name);
+
+        $type = $m->getType();
+        if ($m['streaming'] ||
+           ($type === 'string' || $type === 'blob')
+        ) {
+            // This path skips setting the content-type header usually done in
+            // RestJsonSerializer and RestXmlSerializer.certain S3 and glacier
+            // operations determine content type in Middleware::ContentType()
+            if (!isset(self::$excludeContentType[$this->api->getServiceName() ?? ''])) {
+                switch ($type) {
+                    case 'string':
+                        $opts['headers']['Content-Type'] = 'text/plain';
+                        break;
+                    case 'blob':
+                        $opts['headers']['Content-Type'] = 'application/octet-stream';
+                        break;
+                }
+            }
+
+            $body = $args[$name];
+            if (!$m['streaming'] && is_string($body)) {
+                $opts['headers']['Content-Length'] = (string) strlen($body);
+            }
+
+            // Streaming bodies or payloads that are strings are
+            // always just a stream of data.
+            $stream = Psr7\Utils::streamFor($body);
+            // User-owned resource which should be detached instead of closed
+            // during garbage-collection
+            if (is_resource($body)) {
+                $stream = \Aws\detach_on_close_stream($stream);
+            }
+            $opts['body'] = $stream;
+            return;
+        }
+
+        $this->payload($m, $args[$name], $opts);
+    }
+
+    private function applyHeader($name, Shape $member, $value, array &$opts)
+    {
+        if ($value === null) {
+            return;
+        }
+
+        // Handle lists by applying header logic to each element
+        if ($member instanceof ListShape) {
+            if (!is_array($value)) {
+                throw new \InvalidArgumentException('Header values must be scalar or an array of scalars.');
+            }
+
+            $listMember = $member->getMember();
+            $headerValues = [];
+
+            foreach ($value as $listValue) {
+                if ($listValue === null) {
+                    throw new \InvalidArgumentException('Header values must be scalar or an array of scalars.');
+                }
+
+                $tempOpts = ['headers' => []];
+                $this->applyHeader('temp', $listMember, $listValue, $tempOpts);
+                if (!array_key_exists('temp', $tempOpts['headers'])) {
+                    throw new \InvalidArgumentException('Header values must be scalar or an array of scalars.');
+                }
+
+                $convertedValue = $tempOpts['headers']['temp'];
+                $headerValues[] = $convertedValue;
+            }
+
+            $value = $headerValues;
+        } else {
+            switch ($member->getType()) {
+                case 'timestamp':
+                    $timestampFormat = $member['timestampFormat'] ?? 'rfc822';
+                    $value = $this->formatTimestamp($value, $timestampFormat);
+                    break;
+                case 'boolean':
+                    $value = $this->formatBoolean($value);
+                    break;
+            }
+        }
+
+        if ($member['jsonvalue']) {
+            $value = json_encode($value);
+            if (empty($value) && JSON_ERROR_NONE !== json_last_error()) {
+                throw new \InvalidArgumentException('Unable to encode the provided value'
+                    . ' with \'json_encode\'. ' . json_last_error_msg());
+            }
+
+            $value = base64_encode($value);
+        }
+
+        $opts['headers'][$member['locationName'] ?: $name] = self::prepareHeaderValue($value);
+    }
+
+    /**
+     * Note: This is currently only present in the Amazon S3 model.
+     */
+    private function applyHeaderMap($name, Shape $member, array $value, array &$opts)
+    {
+        $prefix = $member['locationName'];
+        foreach ($value as $k => $v) {
+            if ($v === null) {
+                continue;
+            }
+
+            $opts['headers'][$prefix . $k] = self::prepareHeaderValue($v);
+        }
+    }
+
+    /**
+     * @return string|string[]
+     */
+    private static function prepareHeaderValue($value)
+    {
+        if (is_scalar($value)) {
+            return (string) $value;
+        }
+
+        if (is_array($value)) {
+            if ($value === []) {
+                return '';
+            }
+
+            foreach ($value as $key => $item) {
+                if (!is_scalar($item)) {
+                    throw new \InvalidArgumentException('Header values must be scalar or an array of scalars.');
+                }
+
+                $value[$key] = (string) $item;
+            }
+
+            return $value;
+        }
+
+        throw new \InvalidArgumentException('Header values must be scalar or an array of scalars.');
+    }
+
+    private function applyQuery($name, Shape $member, $value, array &$opts)
+    {
+        if ($member instanceof MapShape) {
+            $opts['query'] = isset($opts['query']) && is_array($opts['query'])
+                ? $opts['query'] + $value
+                : $value;
+        } elseif ($member instanceof ListShape) {
+            $listMember = $member->getMember();
+            $paramName = $member['locationName'] ?: $name;
+
+            foreach ($value as $listValue) {
+                // Recursively call applyQuery for each list element
+                $tempOpts = ['query' => []];
+                $this->applyQuery('temp', $listMember, $listValue, $tempOpts);
+                $opts['query'][$paramName][] = $tempOpts['query']['temp'];
+            }
+        } elseif (!is_null($value)) {
+            switch ($member->getType()) {
+                case 'timestamp':
+                    $timestampFormat = $member['timestampFormat'] ?? 'iso8601';
+                    $value = $this->formatTimestamp($value, $timestampFormat);
+                    break;
+                case 'boolean':
+                    $value = $this->formatBoolean($value);
+                    break;
+            }
+
+            $opts['query'][$member['locationName'] ?: $name] = $value;
+        }
+    }
+
+    private function buildEndpoint(
+        Operation $operation,
+        array $args,
+        array $opts
+    ): UriInterface
+    {
+        // Expand `requestUri` field members
+        $relativeUri = $this->expandUriTemplate($operation, $args);
+
+        // Add query members to relativeUri
+        if (!empty($opts['query'])) {
+            $relativeUri = $this->appendQuery($opts['query'], $relativeUri);
+        }
+
+        // Special case - S3 keys that need path preservation
+        if ($this->api->getServiceName() === 's3'
+            && isset($args['Key'])
+            && $this->shouldPreservePath($args['Key'])
+        ) {
+            return new Uri($this->endpoint . $relativeUri);
+        }
+
+        return $this->resolveUri($relativeUri, $opts);
+    }
+
+    /**
+     * Expands `requestUri` members
+     *
+     * @param Operation $operation
+     * @param array $args
+     *
+     * @return string
+     */
+    private function expandUriTemplate(Operation $operation, array $args): string
+    {
+        $varDefinitions = $this->getVarDefinitions($operation, $args);
+
+        return preg_replace_callback(
+            self::TEMPLATE_STRING_REGEX,
+            static function (array $matches) use ($varDefinitions) {
+                $isGreedy = str_ends_with($matches[1], '+');
+                $varName = $isGreedy ? substr($matches[1], 0, -1) : $matches[1];
+
+                if (!isset($varDefinitions[$varName])) {
+                    return '';
+                }
+
+                $value = $varDefinitions[$varName];
+
+                if ($isGreedy) {
+                    return str_replace('%2F', '/', rawurlencode($value));
+                }
+
+                return rawurlencode($value);
+            },
+            $operation['http']['requestUri']
+        );
+    }
+
+    /**
+     * Checks for path-like key names. If detected, traditional
+     * URI resolution is bypassed.
+     *
+     * @param string $key
+     * @return bool
+     */
+    private function shouldPreservePath(string $key): bool
+    {
+        // Keys with dot segments
+        if (str_contains($key, '.')) {
+            $segments = explode('/', $key);
+            foreach ($segments as $segment) {
+                if ($segment === '.' || $segment === '..') {
+                    return true;
+                }
+            }
+        }
+
+        // Keys starting with slash
+        if (str_starts_with($key, '/')) {
+            return true;
+        }
+
+        return false;
+    }
+
+    /**
+     * @param string $relativeUri
+     * @param array $opts
+     *
+     * @return UriInterface
+     */
+    private function resolveUri(string $relativeUri, array $opts): UriInterface
+    {
+        $basePath = $this->endpoint->getPath();
+
+        // Only process if we have a non-empty base path
+        if (!empty($basePath) && $basePath !== '/') {
+            // if relative is just '/', we want just the base path without trailing slash
+            if ($relativeUri === '/' || empty($relativeUri)) {
+                // Remove trailing slash if present
+                return $this->endpoint->withPath(rtrim($basePath, '/'));
+            }
+
+            // if relative is '/?query', we want base path without trailing slash + query
+            // for now, this is only seen with S3 GetBucketLocation after processing the model
+            if (empty($opts['query'])
+                && str_starts_with($relativeUri, '/?')
+            ) {
+                $query = substr($relativeUri, 2); // Remove '/?'
+                return $this->endpoint->withQuery($query);
+            }
+
+            // Ensure base path has trailing slash
+            if (!str_ends_with($basePath, '/')) {
+                $this->endpoint = $this->endpoint->withPath($basePath . '/');
+            }
+
+            // Remove leading slash from relative path to make it relative
+            if (str_starts_with($relativeUri, '/')) {
+                $relativeUri = substr($relativeUri, 1);
+            }
+        }
+
+        return UriResolver::resolve($this->endpoint, new Uri($relativeUri));
+    }
+
+    /**
+     * @param StructureShape $input
+     * @param $payload
+     *
+     * @return bool
+     */
+    private function hasPayloadParam(StructureShape $input, $payload)
+    {
+        if ($payload) {
+            $potentiallyEmptyTypes = ['blob','string'];
+            if ($this->api->getProtocol() === 'rest-xml') {
+                $potentiallyEmptyTypes[] = 'structure';
+            }
+
+            $payloadMember = $input->getMember($payload);
+            //unions may also be empty/unset
+            if (!empty($payloadMember['union'])
+                || in_array($payloadMember['type'], $potentiallyEmptyTypes)
+            ) {
+                return false;
+            }
+        }
+
+        foreach ($input->getMembers() as $member) {
+            if (!isset($member['location'])) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    /**
+     * @param $query
+     * @param $relativeUri
+     *
+     * @return string
+     */
+    private function appendQuery($query, $relativeUri): string
+    {
+        $append = Psr7\Query::build($query);
+        return $relativeUri
+            . (str_contains($relativeUri, '?') ? "&{$append}" : "?{$append}");
+    }
+
+    /**
+     * @param CommandInterface $command
+     * @param array $args
+     *
+     * @return array
+     */
+    private function getVarDefinitions(
+        Operation $operation,
+        array $args
+    ): array
+    {
+        $varDefinitions = [];
+
+        foreach ($operation->getInput()->getMembers() as $name => $member) {
+            if ($member['location'] === 'uri') {
+                $value = $args[$name] ?? null;
+                if (!is_null($value)) {
+                    switch ($member->getType()) {
+                        case 'timestamp':
+                            $timestampFormat = $member['timestampFormat'] ?? 'iso8601';
+                            $value = $this->formatTimestamp($value, $timestampFormat);
+                            break;
+                        case 'boolean':
+                            $value = $this->formatBoolean($value);
+                            break;
+                    }
+                }
+
+                $varDefinitions[$member['locationName'] ?: $name] = $value;
+            }
+        }
+
+        return $varDefinitions;
+    }
+
+    /**
+     * @param DateTimeInterface|string|int $value
+     * @param string $timestampFormat
+     *
+     * @return string
+     */
+    private function formatTimestamp(
+        DateTimeInterface|string|int $value,
+        string $timestampFormat
+    ): string
+    {
+        return TimestampShape::format($value, $timestampFormat);
+    }
+
+    /**
+     * @param $value
+     *
+     * @return string
+     */
+    private function formatBoolean($value): string
+    {
+        return $value ? 'true' : 'false';
+    }
+}

+ 121 - 0
upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/AppConfig/AppConfigClient.php

@@ -0,0 +1,121 @@
+<?php
+namespace Aws\AppConfig;
+
+use Aws\AwsClient;
+
+/**
+ * This client is used to interact with the **Amazon AppConfig** service.
+ * @method \Aws\Result createApplication(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createApplicationAsync(array $args = [])
+ * @method \Aws\Result createConfigurationProfile(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createConfigurationProfileAsync(array $args = [])
+ * @method \Aws\Result createDeploymentStrategy(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createDeploymentStrategyAsync(array $args = [])
+ * @method \Aws\Result createEnvironment(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createEnvironmentAsync(array $args = [])
+ * @method \Aws\Result createExperimentDefinition(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createExperimentDefinitionAsync(array $args = [])
+ * @method \Aws\Result createExtension(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createExtensionAsync(array $args = [])
+ * @method \Aws\Result createExtensionAssociation(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createExtensionAssociationAsync(array $args = [])
+ * @method \Aws\Result createHostedConfigurationVersion(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createHostedConfigurationVersionAsync(array $args = [])
+ * @method \Aws\Result deleteApplication(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteApplicationAsync(array $args = [])
+ * @method \Aws\Result deleteConfigurationProfile(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteConfigurationProfileAsync(array $args = [])
+ * @method \Aws\Result deleteDeploymentStrategy(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteDeploymentStrategyAsync(array $args = [])
+ * @method \Aws\Result deleteEnvironment(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteEnvironmentAsync(array $args = [])
+ * @method \Aws\Result deleteExperimentDefinition(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteExperimentDefinitionAsync(array $args = [])
+ * @method \Aws\Result deleteExtension(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteExtensionAsync(array $args = [])
+ * @method \Aws\Result deleteExtensionAssociation(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteExtensionAssociationAsync(array $args = [])
+ * @method \Aws\Result deleteHostedConfigurationVersion(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteHostedConfigurationVersionAsync(array $args = [])
+ * @method \Aws\Result getAccountSettings(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getAccountSettingsAsync(array $args = [])
+ * @method \Aws\Result getApplication(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getApplicationAsync(array $args = [])
+ * @method \Aws\Result getConfiguration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getConfigurationAsync(array $args = [])
+ * @method \Aws\Result getConfigurationProfile(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getConfigurationProfileAsync(array $args = [])
+ * @method \Aws\Result getDeployment(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getDeploymentAsync(array $args = [])
+ * @method \Aws\Result getDeploymentStrategy(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getDeploymentStrategyAsync(array $args = [])
+ * @method \Aws\Result getEnvironment(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getEnvironmentAsync(array $args = [])
+ * @method \Aws\Result getExperimentDefinition(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getExperimentDefinitionAsync(array $args = [])
+ * @method \Aws\Result getExperimentRun(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getExperimentRunAsync(array $args = [])
+ * @method \Aws\Result getExtension(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getExtensionAsync(array $args = [])
+ * @method \Aws\Result getExtensionAssociation(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getExtensionAssociationAsync(array $args = [])
+ * @method \Aws\Result getHostedConfigurationVersion(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getHostedConfigurationVersionAsync(array $args = [])
+ * @method \Aws\Result listApplications(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listApplicationsAsync(array $args = [])
+ * @method \Aws\Result listConfigurationProfiles(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listConfigurationProfilesAsync(array $args = [])
+ * @method \Aws\Result listDeploymentStrategies(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listDeploymentStrategiesAsync(array $args = [])
+ * @method \Aws\Result listDeployments(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listDeploymentsAsync(array $args = [])
+ * @method \Aws\Result listEnvironments(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listEnvironmentsAsync(array $args = [])
+ * @method \Aws\Result listExperimentDefinitions(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listExperimentDefinitionsAsync(array $args = [])
+ * @method \Aws\Result listExperimentRunEvents(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listExperimentRunEventsAsync(array $args = [])
+ * @method \Aws\Result listExperimentRuns(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listExperimentRunsAsync(array $args = [])
+ * @method \Aws\Result listExtensionAssociations(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listExtensionAssociationsAsync(array $args = [])
+ * @method \Aws\Result listExtensions(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listExtensionsAsync(array $args = [])
+ * @method \Aws\Result listHostedConfigurationVersions(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listHostedConfigurationVersionsAsync(array $args = [])
+ * @method \Aws\Result listTagsForResource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listTagsForResourceAsync(array $args = [])
+ * @method \Aws\Result startDeployment(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise startDeploymentAsync(array $args = [])
+ * @method \Aws\Result startExperimentRun(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise startExperimentRunAsync(array $args = [])
+ * @method \Aws\Result stopDeployment(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise stopDeploymentAsync(array $args = [])
+ * @method \Aws\Result stopExperimentRun(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise stopExperimentRunAsync(array $args = [])
+ * @method \Aws\Result tagResource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise tagResourceAsync(array $args = [])
+ * @method \Aws\Result untagResource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise untagResourceAsync(array $args = [])
+ * @method \Aws\Result updateAccountSettings(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateAccountSettingsAsync(array $args = [])
+ * @method \Aws\Result updateApplication(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateApplicationAsync(array $args = [])
+ * @method \Aws\Result updateConfigurationProfile(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateConfigurationProfileAsync(array $args = [])
+ * @method \Aws\Result updateDeploymentStrategy(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateDeploymentStrategyAsync(array $args = [])
+ * @method \Aws\Result updateEnvironment(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateEnvironmentAsync(array $args = [])
+ * @method \Aws\Result updateExperimentDefinition(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateExperimentDefinitionAsync(array $args = [])
+ * @method \Aws\Result updateExperimentRun(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateExperimentRunAsync(array $args = [])
+ * @method \Aws\Result updateExtension(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateExtensionAsync(array $args = [])
+ * @method \Aws\Result updateExtensionAssociation(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateExtensionAssociationAsync(array $args = [])
+ * @method \Aws\Result validateConfiguration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise validateConfigurationAsync(array $args = [])
+ */
+class AppConfigClient extends AwsClient {}

+ 69 - 0
upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/ApplicationSignals/ApplicationSignalsClient.php

@@ -0,0 +1,69 @@
+<?php
+namespace Aws\ApplicationSignals;
+
+use Aws\AwsClient;
+
+/**
+ * This client is used to interact with the **Amazon CloudWatch Application Signals** service.
+ * @method \Aws\Result batchDeleteInstrumentationConfigurations(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise batchDeleteInstrumentationConfigurationsAsync(array $args = [])
+ * @method \Aws\Result batchGetServiceLevelObjectiveBudgetReport(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise batchGetServiceLevelObjectiveBudgetReportAsync(array $args = [])
+ * @method \Aws\Result batchUpdateExclusionWindows(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise batchUpdateExclusionWindowsAsync(array $args = [])
+ * @method \Aws\Result createInstrumentationConfiguration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createInstrumentationConfigurationAsync(array $args = [])
+ * @method \Aws\Result createServiceLevelObjective(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createServiceLevelObjectiveAsync(array $args = [])
+ * @method \Aws\Result deleteGroupingConfiguration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteGroupingConfigurationAsync(array $args = [])
+ * @method \Aws\Result deleteInstrumentationConfiguration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteInstrumentationConfigurationAsync(array $args = [])
+ * @method \Aws\Result deleteServiceLevelObjective(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteServiceLevelObjectiveAsync(array $args = [])
+ * @method \Aws\Result getInstrumentationConfiguration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getInstrumentationConfigurationAsync(array $args = [])
+ * @method \Aws\Result getInstrumentationConfigurationStatus(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getInstrumentationConfigurationStatusAsync(array $args = [])
+ * @method \Aws\Result getService(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getServiceAsync(array $args = [])
+ * @method \Aws\Result getServiceLevelObjective(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getServiceLevelObjectiveAsync(array $args = [])
+ * @method \Aws\Result listAuditFindings(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listAuditFindingsAsync(array $args = [])
+ * @method \Aws\Result listEntityEvents(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listEntityEventsAsync(array $args = [])
+ * @method \Aws\Result listGroupingAttributeDefinitions(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listGroupingAttributeDefinitionsAsync(array $args = [])
+ * @method \Aws\Result listInstrumentationConfigurations(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listInstrumentationConfigurationsAsync(array $args = [])
+ * @method \Aws\Result listServiceDependencies(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listServiceDependenciesAsync(array $args = [])
+ * @method \Aws\Result listServiceDependents(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listServiceDependentsAsync(array $args = [])
+ * @method \Aws\Result listServiceLevelObjectiveExclusionWindows(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listServiceLevelObjectiveExclusionWindowsAsync(array $args = [])
+ * @method \Aws\Result listServiceLevelObjectives(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listServiceLevelObjectivesAsync(array $args = [])
+ * @method \Aws\Result listServiceOperations(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listServiceOperationsAsync(array $args = [])
+ * @method \Aws\Result listServiceStates(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listServiceStatesAsync(array $args = [])
+ * @method \Aws\Result listServices(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listServicesAsync(array $args = [])
+ * @method \Aws\Result listTagsForResource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listTagsForResourceAsync(array $args = [])
+ * @method \Aws\Result putGroupingConfiguration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise putGroupingConfigurationAsync(array $args = [])
+ * @method \Aws\Result reportInstrumentationConfigurationStatus(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise reportInstrumentationConfigurationStatusAsync(array $args = [])
+ * @method \Aws\Result startDiscovery(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise startDiscoveryAsync(array $args = [])
+ * @method \Aws\Result tagResource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise tagResourceAsync(array $args = [])
+ * @method \Aws\Result untagResource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise untagResourceAsync(array $args = [])
+ * @method \Aws\Result updateServiceLevelObjective(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateServiceLevelObjectiveAsync(array $args = [])
+ */
+class ApplicationSignalsClient extends AwsClient {}

+ 41 - 0
upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/Artifact/ArtifactClient.php

@@ -0,0 +1,41 @@
+<?php
+namespace Aws\Artifact;
+
+use Aws\AwsClient;
+
+/**
+ * This client is used to interact with the **AWS Artifact** service.
+ * @method \Aws\Result createComplianceInquiry(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createComplianceInquiryAsync(array $args = [])
+ * @method \Aws\Result exportComplianceInquiry(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise exportComplianceInquiryAsync(array $args = [])
+ * @method \Aws\Result getAccountSettings(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getAccountSettingsAsync(array $args = [])
+ * @method \Aws\Result getComplianceInquiryMetadata(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getComplianceInquiryMetadataAsync(array $args = [])
+ * @method \Aws\Result getReport(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getReportAsync(array $args = [])
+ * @method \Aws\Result getReportMetadata(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getReportMetadataAsync(array $args = [])
+ * @method \Aws\Result getTermForReport(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getTermForReportAsync(array $args = [])
+ * @method \Aws\Result listComplianceInquiries(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listComplianceInquiriesAsync(array $args = [])
+ * @method \Aws\Result listComplianceInquiryQueries(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listComplianceInquiryQueriesAsync(array $args = [])
+ * @method \Aws\Result listCustomerAgreements(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listCustomerAgreementsAsync(array $args = [])
+ * @method \Aws\Result listReportVersions(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listReportVersionsAsync(array $args = [])
+ * @method \Aws\Result listReports(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listReportsAsync(array $args = [])
+ * @method \Aws\Result listTagsForResource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listTagsForResourceAsync(array $args = [])
+ * @method \Aws\Result putAccountSettings(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise putAccountSettingsAsync(array $args = [])
+ * @method \Aws\Result tagResource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise tagResourceAsync(array $args = [])
+ * @method \Aws\Result untagResource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise untagResourceAsync(array $args = [])
+ */
+class ArtifactClient extends AwsClient {}

+ 225 - 0
upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/Bedrock/BedrockClient.php

@@ -0,0 +1,225 @@
+<?php
+namespace Aws\Bedrock;
+
+use Aws\AwsClient;
+
+/**
+ * This client is used to interact with the **Amazon Bedrock** service.
+ * @method \Aws\Result batchDeleteAdvancedPromptOptimizationJob(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise batchDeleteAdvancedPromptOptimizationJobAsync(array $args = [])
+ * @method \Aws\Result batchDeleteEvaluationJob(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise batchDeleteEvaluationJobAsync(array $args = [])
+ * @method \Aws\Result cancelAutomatedReasoningPolicyBuildWorkflow(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise cancelAutomatedReasoningPolicyBuildWorkflowAsync(array $args = [])
+ * @method \Aws\Result createAdvancedPromptOptimizationJob(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createAdvancedPromptOptimizationJobAsync(array $args = [])
+ * @method \Aws\Result createAutomatedReasoningPolicy(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createAutomatedReasoningPolicyAsync(array $args = [])
+ * @method \Aws\Result createAutomatedReasoningPolicyTestCase(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createAutomatedReasoningPolicyTestCaseAsync(array $args = [])
+ * @method \Aws\Result createAutomatedReasoningPolicyVersion(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createAutomatedReasoningPolicyVersionAsync(array $args = [])
+ * @method \Aws\Result createCustomModel(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createCustomModelAsync(array $args = [])
+ * @method \Aws\Result createCustomModelDeployment(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createCustomModelDeploymentAsync(array $args = [])
+ * @method \Aws\Result createEvaluationJob(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createEvaluationJobAsync(array $args = [])
+ * @method \Aws\Result createFoundationModelAgreement(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createFoundationModelAgreementAsync(array $args = [])
+ * @method \Aws\Result createGuardrail(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createGuardrailAsync(array $args = [])
+ * @method \Aws\Result createGuardrailVersion(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createGuardrailVersionAsync(array $args = [])
+ * @method \Aws\Result createInferenceProfile(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createInferenceProfileAsync(array $args = [])
+ * @method \Aws\Result createMarketplaceModelEndpoint(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createMarketplaceModelEndpointAsync(array $args = [])
+ * @method \Aws\Result createModelCopyJob(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createModelCopyJobAsync(array $args = [])
+ * @method \Aws\Result createModelCustomizationJob(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createModelCustomizationJobAsync(array $args = [])
+ * @method \Aws\Result createModelImportJob(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createModelImportJobAsync(array $args = [])
+ * @method \Aws\Result createModelInvocationJob(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createModelInvocationJobAsync(array $args = [])
+ * @method \Aws\Result createPromptRouter(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createPromptRouterAsync(array $args = [])
+ * @method \Aws\Result createProvisionedModelThroughput(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createProvisionedModelThroughputAsync(array $args = [])
+ * @method \Aws\Result deleteAutomatedReasoningPolicy(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteAutomatedReasoningPolicyAsync(array $args = [])
+ * @method \Aws\Result deleteAutomatedReasoningPolicyBuildWorkflow(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteAutomatedReasoningPolicyBuildWorkflowAsync(array $args = [])
+ * @method \Aws\Result deleteAutomatedReasoningPolicyTestCase(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteAutomatedReasoningPolicyTestCaseAsync(array $args = [])
+ * @method \Aws\Result deleteCustomModel(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteCustomModelAsync(array $args = [])
+ * @method \Aws\Result deleteCustomModelDeployment(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteCustomModelDeploymentAsync(array $args = [])
+ * @method \Aws\Result deleteEnforcedGuardrailConfiguration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteEnforcedGuardrailConfigurationAsync(array $args = [])
+ * @method \Aws\Result deleteFoundationModelAgreement(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteFoundationModelAgreementAsync(array $args = [])
+ * @method \Aws\Result deleteGuardrail(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteGuardrailAsync(array $args = [])
+ * @method \Aws\Result deleteImportedModel(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteImportedModelAsync(array $args = [])
+ * @method \Aws\Result deleteInferenceProfile(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteInferenceProfileAsync(array $args = [])
+ * @method \Aws\Result deleteMarketplaceModelEndpoint(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteMarketplaceModelEndpointAsync(array $args = [])
+ * @method \Aws\Result deleteModelInvocationLoggingConfiguration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteModelInvocationLoggingConfigurationAsync(array $args = [])
+ * @method \Aws\Result deletePromptRouter(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deletePromptRouterAsync(array $args = [])
+ * @method \Aws\Result deleteProvisionedModelThroughput(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteProvisionedModelThroughputAsync(array $args = [])
+ * @method \Aws\Result deleteResourcePolicy(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteResourcePolicyAsync(array $args = [])
+ * @method \Aws\Result deregisterMarketplaceModelEndpoint(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deregisterMarketplaceModelEndpointAsync(array $args = [])
+ * @method \Aws\Result exportAutomatedReasoningPolicyVersion(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise exportAutomatedReasoningPolicyVersionAsync(array $args = [])
+ * @method \Aws\Result getAccountDataRetention(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getAccountDataRetentionAsync(array $args = [])
+ * @method \Aws\Result getAdvancedPromptOptimizationJob(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getAdvancedPromptOptimizationJobAsync(array $args = [])
+ * @method \Aws\Result getAutomatedReasoningPolicy(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getAutomatedReasoningPolicyAsync(array $args = [])
+ * @method \Aws\Result getAutomatedReasoningPolicyAnnotations(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getAutomatedReasoningPolicyAnnotationsAsync(array $args = [])
+ * @method \Aws\Result getAutomatedReasoningPolicyBuildWorkflow(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getAutomatedReasoningPolicyBuildWorkflowAsync(array $args = [])
+ * @method \Aws\Result getAutomatedReasoningPolicyBuildWorkflowResultAssets(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getAutomatedReasoningPolicyBuildWorkflowResultAssetsAsync(array $args = [])
+ * @method \Aws\Result getAutomatedReasoningPolicyNextScenario(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getAutomatedReasoningPolicyNextScenarioAsync(array $args = [])
+ * @method \Aws\Result getAutomatedReasoningPolicyTestCase(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getAutomatedReasoningPolicyTestCaseAsync(array $args = [])
+ * @method \Aws\Result getAutomatedReasoningPolicyTestResult(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getAutomatedReasoningPolicyTestResultAsync(array $args = [])
+ * @method \Aws\Result getCustomModel(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getCustomModelAsync(array $args = [])
+ * @method \Aws\Result getCustomModelDeployment(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getCustomModelDeploymentAsync(array $args = [])
+ * @method \Aws\Result getEvaluationJob(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getEvaluationJobAsync(array $args = [])
+ * @method \Aws\Result getFoundationModel(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getFoundationModelAsync(array $args = [])
+ * @method \Aws\Result getFoundationModelAvailability(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getFoundationModelAvailabilityAsync(array $args = [])
+ * @method \Aws\Result getGuardrail(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getGuardrailAsync(array $args = [])
+ * @method \Aws\Result getImportedModel(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getImportedModelAsync(array $args = [])
+ * @method \Aws\Result getInferenceProfile(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getInferenceProfileAsync(array $args = [])
+ * @method \Aws\Result getMarketplaceModelEndpoint(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getMarketplaceModelEndpointAsync(array $args = [])
+ * @method \Aws\Result getModelCopyJob(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getModelCopyJobAsync(array $args = [])
+ * @method \Aws\Result getModelCustomizationJob(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getModelCustomizationJobAsync(array $args = [])
+ * @method \Aws\Result getModelImportJob(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getModelImportJobAsync(array $args = [])
+ * @method \Aws\Result getModelInvocationJob(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getModelInvocationJobAsync(array $args = [])
+ * @method \Aws\Result getModelInvocationLoggingConfiguration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getModelInvocationLoggingConfigurationAsync(array $args = [])
+ * @method \Aws\Result getPromptRouter(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getPromptRouterAsync(array $args = [])
+ * @method \Aws\Result getProvisionedModelThroughput(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getProvisionedModelThroughputAsync(array $args = [])
+ * @method \Aws\Result getResourcePolicy(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getResourcePolicyAsync(array $args = [])
+ * @method \Aws\Result getUseCaseForModelAccess(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getUseCaseForModelAccessAsync(array $args = [])
+ * @method \Aws\Result listAdvancedPromptOptimizationJobs(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listAdvancedPromptOptimizationJobsAsync(array $args = [])
+ * @method \Aws\Result listAutomatedReasoningPolicies(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listAutomatedReasoningPoliciesAsync(array $args = [])
+ * @method \Aws\Result listAutomatedReasoningPolicyBuildWorkflows(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listAutomatedReasoningPolicyBuildWorkflowsAsync(array $args = [])
+ * @method \Aws\Result listAutomatedReasoningPolicyTestCases(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listAutomatedReasoningPolicyTestCasesAsync(array $args = [])
+ * @method \Aws\Result listAutomatedReasoningPolicyTestResults(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listAutomatedReasoningPolicyTestResultsAsync(array $args = [])
+ * @method \Aws\Result listCustomModelDeployments(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listCustomModelDeploymentsAsync(array $args = [])
+ * @method \Aws\Result listCustomModels(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listCustomModelsAsync(array $args = [])
+ * @method \Aws\Result listEnforcedGuardrailsConfiguration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listEnforcedGuardrailsConfigurationAsync(array $args = [])
+ * @method \Aws\Result listEvaluationJobs(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listEvaluationJobsAsync(array $args = [])
+ * @method \Aws\Result listFoundationModelAgreementOffers(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listFoundationModelAgreementOffersAsync(array $args = [])
+ * @method \Aws\Result listFoundationModels(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listFoundationModelsAsync(array $args = [])
+ * @method \Aws\Result listGuardrails(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listGuardrailsAsync(array $args = [])
+ * @method \Aws\Result listImportedModels(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listImportedModelsAsync(array $args = [])
+ * @method \Aws\Result listInferenceProfiles(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listInferenceProfilesAsync(array $args = [])
+ * @method \Aws\Result listMarketplaceModelEndpoints(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listMarketplaceModelEndpointsAsync(array $args = [])
+ * @method \Aws\Result listModelCopyJobs(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listModelCopyJobsAsync(array $args = [])
+ * @method \Aws\Result listModelCustomizationJobs(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listModelCustomizationJobsAsync(array $args = [])
+ * @method \Aws\Result listModelImportJobs(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listModelImportJobsAsync(array $args = [])
+ * @method \Aws\Result listModelInvocationJobs(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listModelInvocationJobsAsync(array $args = [])
+ * @method \Aws\Result listPromptRouters(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listPromptRoutersAsync(array $args = [])
+ * @method \Aws\Result listProvisionedModelThroughputs(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listProvisionedModelThroughputsAsync(array $args = [])
+ * @method \Aws\Result listTagsForResource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listTagsForResourceAsync(array $args = [])
+ * @method \Aws\Result putAccountDataRetention(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise putAccountDataRetentionAsync(array $args = [])
+ * @method \Aws\Result putEnforcedGuardrailConfiguration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise putEnforcedGuardrailConfigurationAsync(array $args = [])
+ * @method \Aws\Result putModelInvocationLoggingConfiguration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise putModelInvocationLoggingConfigurationAsync(array $args = [])
+ * @method \Aws\Result putResourcePolicy(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise putResourcePolicyAsync(array $args = [])
+ * @method \Aws\Result putUseCaseForModelAccess(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise putUseCaseForModelAccessAsync(array $args = [])
+ * @method \Aws\Result registerMarketplaceModelEndpoint(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise registerMarketplaceModelEndpointAsync(array $args = [])
+ * @method \Aws\Result startAutomatedReasoningPolicyBuildWorkflow(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise startAutomatedReasoningPolicyBuildWorkflowAsync(array $args = [])
+ * @method \Aws\Result startAutomatedReasoningPolicyTestWorkflow(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise startAutomatedReasoningPolicyTestWorkflowAsync(array $args = [])
+ * @method \Aws\Result stopAdvancedPromptOptimizationJob(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise stopAdvancedPromptOptimizationJobAsync(array $args = [])
+ * @method \Aws\Result stopEvaluationJob(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise stopEvaluationJobAsync(array $args = [])
+ * @method \Aws\Result stopModelCustomizationJob(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise stopModelCustomizationJobAsync(array $args = [])
+ * @method \Aws\Result stopModelInvocationJob(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise stopModelInvocationJobAsync(array $args = [])
+ * @method \Aws\Result tagResource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise tagResourceAsync(array $args = [])
+ * @method \Aws\Result untagResource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise untagResourceAsync(array $args = [])
+ * @method \Aws\Result updateAutomatedReasoningPolicy(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateAutomatedReasoningPolicyAsync(array $args = [])
+ * @method \Aws\Result updateAutomatedReasoningPolicyAnnotations(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateAutomatedReasoningPolicyAnnotationsAsync(array $args = [])
+ * @method \Aws\Result updateAutomatedReasoningPolicyTestCase(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateAutomatedReasoningPolicyTestCaseAsync(array $args = [])
+ * @method \Aws\Result updateCustomModelDeployment(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateCustomModelDeploymentAsync(array $args = [])
+ * @method \Aws\Result updateGuardrail(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateGuardrailAsync(array $args = [])
+ * @method \Aws\Result updateMarketplaceModelEndpoint(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateMarketplaceModelEndpointAsync(array $args = [])
+ * @method \Aws\Result updateProvisionedModelThroughput(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateProvisionedModelThroughputAsync(array $args = [])
+ */
+class BedrockClient extends AwsClient {}

+ 159 - 0
upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/BedrockAgent/BedrockAgentClient.php

@@ -0,0 +1,159 @@
+<?php
+namespace Aws\BedrockAgent;
+
+use Aws\AwsClient;
+
+/**
+ * This client is used to interact with the **Agents for Amazon Bedrock** service.
+ * @method \Aws\Result associateAgentCollaborator(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise associateAgentCollaboratorAsync(array $args = [])
+ * @method \Aws\Result associateAgentKnowledgeBase(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise associateAgentKnowledgeBaseAsync(array $args = [])
+ * @method \Aws\Result createAgent(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createAgentAsync(array $args = [])
+ * @method \Aws\Result createAgentActionGroup(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createAgentActionGroupAsync(array $args = [])
+ * @method \Aws\Result createAgentAlias(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createAgentAliasAsync(array $args = [])
+ * @method \Aws\Result createDataSource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createDataSourceAsync(array $args = [])
+ * @method \Aws\Result createFlow(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createFlowAsync(array $args = [])
+ * @method \Aws\Result createFlowAlias(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createFlowAliasAsync(array $args = [])
+ * @method \Aws\Result createFlowVersion(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createFlowVersionAsync(array $args = [])
+ * @method \Aws\Result createKnowledgeBase(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createKnowledgeBaseAsync(array $args = [])
+ * @method \Aws\Result createPrompt(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createPromptAsync(array $args = [])
+ * @method \Aws\Result createPromptVersion(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createPromptVersionAsync(array $args = [])
+ * @method \Aws\Result deleteAgent(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteAgentAsync(array $args = [])
+ * @method \Aws\Result deleteAgentActionGroup(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteAgentActionGroupAsync(array $args = [])
+ * @method \Aws\Result deleteAgentAlias(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteAgentAliasAsync(array $args = [])
+ * @method \Aws\Result deleteAgentVersion(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteAgentVersionAsync(array $args = [])
+ * @method \Aws\Result deleteDataSource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteDataSourceAsync(array $args = [])
+ * @method \Aws\Result deleteFlow(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteFlowAsync(array $args = [])
+ * @method \Aws\Result deleteFlowAlias(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteFlowAliasAsync(array $args = [])
+ * @method \Aws\Result deleteFlowVersion(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteFlowVersionAsync(array $args = [])
+ * @method \Aws\Result deleteKnowledgeBase(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteKnowledgeBaseAsync(array $args = [])
+ * @method \Aws\Result deleteKnowledgeBaseDocuments(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteKnowledgeBaseDocumentsAsync(array $args = [])
+ * @method \Aws\Result deletePrompt(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deletePromptAsync(array $args = [])
+ * @method \Aws\Result deleteResourcePolicy(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteResourcePolicyAsync(array $args = [])
+ * @method \Aws\Result disassociateAgentCollaborator(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise disassociateAgentCollaboratorAsync(array $args = [])
+ * @method \Aws\Result disassociateAgentKnowledgeBase(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise disassociateAgentKnowledgeBaseAsync(array $args = [])
+ * @method \Aws\Result getAgent(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getAgentAsync(array $args = [])
+ * @method \Aws\Result getAgentActionGroup(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getAgentActionGroupAsync(array $args = [])
+ * @method \Aws\Result getAgentAlias(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getAgentAliasAsync(array $args = [])
+ * @method \Aws\Result getAgentCollaborator(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getAgentCollaboratorAsync(array $args = [])
+ * @method \Aws\Result getAgentKnowledgeBase(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getAgentKnowledgeBaseAsync(array $args = [])
+ * @method \Aws\Result getAgentVersion(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getAgentVersionAsync(array $args = [])
+ * @method \Aws\Result getDataSource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getDataSourceAsync(array $args = [])
+ * @method \Aws\Result getFlow(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getFlowAsync(array $args = [])
+ * @method \Aws\Result getFlowAlias(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getFlowAliasAsync(array $args = [])
+ * @method \Aws\Result getFlowVersion(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getFlowVersionAsync(array $args = [])
+ * @method \Aws\Result getIngestionJob(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getIngestionJobAsync(array $args = [])
+ * @method \Aws\Result getKnowledgeBase(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getKnowledgeBaseAsync(array $args = [])
+ * @method \Aws\Result getKnowledgeBaseDocuments(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getKnowledgeBaseDocumentsAsync(array $args = [])
+ * @method \Aws\Result getPrompt(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getPromptAsync(array $args = [])
+ * @method \Aws\Result getResourcePolicy(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getResourcePolicyAsync(array $args = [])
+ * @method \Aws\Result ingestKnowledgeBaseDocuments(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise ingestKnowledgeBaseDocumentsAsync(array $args = [])
+ * @method \Aws\Result listAgentActionGroups(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listAgentActionGroupsAsync(array $args = [])
+ * @method \Aws\Result listAgentAliases(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listAgentAliasesAsync(array $args = [])
+ * @method \Aws\Result listAgentCollaborators(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listAgentCollaboratorsAsync(array $args = [])
+ * @method \Aws\Result listAgentKnowledgeBases(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listAgentKnowledgeBasesAsync(array $args = [])
+ * @method \Aws\Result listAgentVersions(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listAgentVersionsAsync(array $args = [])
+ * @method \Aws\Result listAgents(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listAgentsAsync(array $args = [])
+ * @method \Aws\Result listDataSources(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listDataSourcesAsync(array $args = [])
+ * @method \Aws\Result listFlowAliases(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listFlowAliasesAsync(array $args = [])
+ * @method \Aws\Result listFlowVersions(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listFlowVersionsAsync(array $args = [])
+ * @method \Aws\Result listFlows(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listFlowsAsync(array $args = [])
+ * @method \Aws\Result listIngestionJobs(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listIngestionJobsAsync(array $args = [])
+ * @method \Aws\Result listKnowledgeBaseDocuments(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listKnowledgeBaseDocumentsAsync(array $args = [])
+ * @method \Aws\Result listKnowledgeBases(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listKnowledgeBasesAsync(array $args = [])
+ * @method \Aws\Result listPrompts(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listPromptsAsync(array $args = [])
+ * @method \Aws\Result listTagsForResource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listTagsForResourceAsync(array $args = [])
+ * @method \Aws\Result prepareAgent(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise prepareAgentAsync(array $args = [])
+ * @method \Aws\Result prepareFlow(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise prepareFlowAsync(array $args = [])
+ * @method \Aws\Result putResourcePolicy(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise putResourcePolicyAsync(array $args = [])
+ * @method \Aws\Result startIngestionJob(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise startIngestionJobAsync(array $args = [])
+ * @method \Aws\Result stopIngestionJob(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise stopIngestionJobAsync(array $args = [])
+ * @method \Aws\Result tagResource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise tagResourceAsync(array $args = [])
+ * @method \Aws\Result untagResource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise untagResourceAsync(array $args = [])
+ * @method \Aws\Result updateAgent(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateAgentAsync(array $args = [])
+ * @method \Aws\Result updateAgentActionGroup(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateAgentActionGroupAsync(array $args = [])
+ * @method \Aws\Result updateAgentAlias(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateAgentAliasAsync(array $args = [])
+ * @method \Aws\Result updateAgentCollaborator(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateAgentCollaboratorAsync(array $args = [])
+ * @method \Aws\Result updateAgentKnowledgeBase(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateAgentKnowledgeBaseAsync(array $args = [])
+ * @method \Aws\Result updateDataSource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateDataSourceAsync(array $args = [])
+ * @method \Aws\Result updateFlow(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateFlowAsync(array $args = [])
+ * @method \Aws\Result updateFlowAlias(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateFlowAliasAsync(array $args = [])
+ * @method \Aws\Result updateKnowledgeBase(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateKnowledgeBaseAsync(array $args = [])
+ * @method \Aws\Result updatePrompt(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updatePromptAsync(array $args = [])
+ * @method \Aws\Result validateFlowDefinition(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise validateFlowDefinitionAsync(array $args = [])
+ */
+class BedrockAgentClient extends AwsClient {}

+ 315 - 0
upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/BedrockAgentCoreControl/BedrockAgentCoreControlClient.php

@@ -0,0 +1,315 @@
+<?php
+namespace Aws\BedrockAgentCoreControl;
+
+use Aws\AwsClient;
+
+/**
+ * This client is used to interact with the **Amazon Bedrock Agent Core Control Plane Fronting Layer** service.
+ * @method \Aws\Result addDatasetExamples(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise addDatasetExamplesAsync(array $args = [])
+ * @method \Aws\Result createAgentRuntime(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createAgentRuntimeAsync(array $args = [])
+ * @method \Aws\Result createAgentRuntimeEndpoint(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createAgentRuntimeEndpointAsync(array $args = [])
+ * @method \Aws\Result createApiKeyCredentialProvider(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createApiKeyCredentialProviderAsync(array $args = [])
+ * @method \Aws\Result createBrowser(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createBrowserAsync(array $args = [])
+ * @method \Aws\Result createBrowserProfile(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createBrowserProfileAsync(array $args = [])
+ * @method \Aws\Result createCodeInterpreter(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createCodeInterpreterAsync(array $args = [])
+ * @method \Aws\Result createConfigurationBundle(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createConfigurationBundleAsync(array $args = [])
+ * @method \Aws\Result createDataset(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createDatasetAsync(array $args = [])
+ * @method \Aws\Result createDatasetVersion(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createDatasetVersionAsync(array $args = [])
+ * @method \Aws\Result createEvaluator(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createEvaluatorAsync(array $args = [])
+ * @method \Aws\Result createGateway(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createGatewayAsync(array $args = [])
+ * @method \Aws\Result createGatewayRule(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createGatewayRuleAsync(array $args = [])
+ * @method \Aws\Result createGatewayTarget(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createGatewayTargetAsync(array $args = [])
+ * @method \Aws\Result createHarness(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createHarnessAsync(array $args = [])
+ * @method \Aws\Result createHarnessEndpoint(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createHarnessEndpointAsync(array $args = [])
+ * @method \Aws\Result createMemory(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createMemoryAsync(array $args = [])
+ * @method \Aws\Result createOauth2CredentialProvider(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createOauth2CredentialProviderAsync(array $args = [])
+ * @method \Aws\Result createOnlineEvaluationConfig(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createOnlineEvaluationConfigAsync(array $args = [])
+ * @method \Aws\Result createPaymentConnector(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createPaymentConnectorAsync(array $args = [])
+ * @method \Aws\Result createPaymentCredentialProvider(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createPaymentCredentialProviderAsync(array $args = [])
+ * @method \Aws\Result createPaymentManager(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createPaymentManagerAsync(array $args = [])
+ * @method \Aws\Result createPolicy(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createPolicyAsync(array $args = [])
+ * @method \Aws\Result createPolicyEngine(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createPolicyEngineAsync(array $args = [])
+ * @method \Aws\Result createRegistry(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createRegistryAsync(array $args = [])
+ * @method \Aws\Result createRegistryRecord(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createRegistryRecordAsync(array $args = [])
+ * @method \Aws\Result createWorkloadIdentity(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createWorkloadIdentityAsync(array $args = [])
+ * @method \Aws\Result deleteAgentRuntime(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteAgentRuntimeAsync(array $args = [])
+ * @method \Aws\Result deleteAgentRuntimeEndpoint(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteAgentRuntimeEndpointAsync(array $args = [])
+ * @method \Aws\Result deleteApiKeyCredentialProvider(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteApiKeyCredentialProviderAsync(array $args = [])
+ * @method \Aws\Result deleteBrowser(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteBrowserAsync(array $args = [])
+ * @method \Aws\Result deleteBrowserProfile(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteBrowserProfileAsync(array $args = [])
+ * @method \Aws\Result deleteCodeInterpreter(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteCodeInterpreterAsync(array $args = [])
+ * @method \Aws\Result deleteConfigurationBundle(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteConfigurationBundleAsync(array $args = [])
+ * @method \Aws\Result deleteDataset(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteDatasetAsync(array $args = [])
+ * @method \Aws\Result deleteDatasetExamples(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteDatasetExamplesAsync(array $args = [])
+ * @method \Aws\Result deleteEvaluator(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteEvaluatorAsync(array $args = [])
+ * @method \Aws\Result deleteGateway(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteGatewayAsync(array $args = [])
+ * @method \Aws\Result deleteGatewayRule(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteGatewayRuleAsync(array $args = [])
+ * @method \Aws\Result deleteGatewayTarget(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteGatewayTargetAsync(array $args = [])
+ * @method \Aws\Result deleteHarness(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteHarnessAsync(array $args = [])
+ * @method \Aws\Result deleteHarnessEndpoint(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteHarnessEndpointAsync(array $args = [])
+ * @method \Aws\Result deleteMemory(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteMemoryAsync(array $args = [])
+ * @method \Aws\Result deleteOauth2CredentialProvider(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteOauth2CredentialProviderAsync(array $args = [])
+ * @method \Aws\Result deleteOnlineEvaluationConfig(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteOnlineEvaluationConfigAsync(array $args = [])
+ * @method \Aws\Result deletePaymentConnector(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deletePaymentConnectorAsync(array $args = [])
+ * @method \Aws\Result deletePaymentCredentialProvider(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deletePaymentCredentialProviderAsync(array $args = [])
+ * @method \Aws\Result deletePaymentManager(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deletePaymentManagerAsync(array $args = [])
+ * @method \Aws\Result deletePolicy(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deletePolicyAsync(array $args = [])
+ * @method \Aws\Result deletePolicyEngine(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deletePolicyEngineAsync(array $args = [])
+ * @method \Aws\Result deleteRegistry(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteRegistryAsync(array $args = [])
+ * @method \Aws\Result deleteRegistryRecord(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteRegistryRecordAsync(array $args = [])
+ * @method \Aws\Result deleteResourcePolicy(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteResourcePolicyAsync(array $args = [])
+ * @method \Aws\Result deleteWorkloadIdentity(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteWorkloadIdentityAsync(array $args = [])
+ * @method \Aws\Result getAgentRuntime(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getAgentRuntimeAsync(array $args = [])
+ * @method \Aws\Result getAgentRuntimeEndpoint(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getAgentRuntimeEndpointAsync(array $args = [])
+ * @method \Aws\Result getApiKeyCredentialProvider(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getApiKeyCredentialProviderAsync(array $args = [])
+ * @method \Aws\Result getBrowser(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getBrowserAsync(array $args = [])
+ * @method \Aws\Result getBrowserProfile(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getBrowserProfileAsync(array $args = [])
+ * @method \Aws\Result getCodeInterpreter(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getCodeInterpreterAsync(array $args = [])
+ * @method \Aws\Result getConfigurationBundle(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getConfigurationBundleAsync(array $args = [])
+ * @method \Aws\Result getConfigurationBundleVersion(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getConfigurationBundleVersionAsync(array $args = [])
+ * @method \Aws\Result getDataset(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getDatasetAsync(array $args = [])
+ * @method \Aws\Result getEvaluator(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getEvaluatorAsync(array $args = [])
+ * @method \Aws\Result getGateway(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getGatewayAsync(array $args = [])
+ * @method \Aws\Result getGatewayRule(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getGatewayRuleAsync(array $args = [])
+ * @method \Aws\Result getGatewayTarget(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getGatewayTargetAsync(array $args = [])
+ * @method \Aws\Result getHarness(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getHarnessAsync(array $args = [])
+ * @method \Aws\Result getHarnessEndpoint(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getHarnessEndpointAsync(array $args = [])
+ * @method \Aws\Result getMemory(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getMemoryAsync(array $args = [])
+ * @method \Aws\Result getOauth2CredentialProvider(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getOauth2CredentialProviderAsync(array $args = [])
+ * @method \Aws\Result getOnlineEvaluationConfig(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getOnlineEvaluationConfigAsync(array $args = [])
+ * @method \Aws\Result getPaymentConnector(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getPaymentConnectorAsync(array $args = [])
+ * @method \Aws\Result getPaymentCredentialProvider(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getPaymentCredentialProviderAsync(array $args = [])
+ * @method \Aws\Result getPaymentManager(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getPaymentManagerAsync(array $args = [])
+ * @method \Aws\Result getPolicy(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getPolicyAsync(array $args = [])
+ * @method \Aws\Result getPolicyEngine(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getPolicyEngineAsync(array $args = [])
+ * @method \Aws\Result getPolicyEngineSummary(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getPolicyEngineSummaryAsync(array $args = [])
+ * @method \Aws\Result getPolicyGeneration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getPolicyGenerationAsync(array $args = [])
+ * @method \Aws\Result getPolicyGenerationSummary(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getPolicyGenerationSummaryAsync(array $args = [])
+ * @method \Aws\Result getPolicySummary(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getPolicySummaryAsync(array $args = [])
+ * @method \Aws\Result getRegistry(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getRegistryAsync(array $args = [])
+ * @method \Aws\Result getRegistryRecord(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getRegistryRecordAsync(array $args = [])
+ * @method \Aws\Result getResourcePolicy(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getResourcePolicyAsync(array $args = [])
+ * @method \Aws\Result getTokenVault(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getTokenVaultAsync(array $args = [])
+ * @method \Aws\Result getWorkloadIdentity(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getWorkloadIdentityAsync(array $args = [])
+ * @method \Aws\Result listAgentRuntimeEndpoints(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listAgentRuntimeEndpointsAsync(array $args = [])
+ * @method \Aws\Result listAgentRuntimeVersions(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listAgentRuntimeVersionsAsync(array $args = [])
+ * @method \Aws\Result listAgentRuntimes(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listAgentRuntimesAsync(array $args = [])
+ * @method \Aws\Result listApiKeyCredentialProviders(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listApiKeyCredentialProvidersAsync(array $args = [])
+ * @method \Aws\Result listBrowserProfiles(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listBrowserProfilesAsync(array $args = [])
+ * @method \Aws\Result listBrowsers(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listBrowsersAsync(array $args = [])
+ * @method \Aws\Result listCodeInterpreters(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listCodeInterpretersAsync(array $args = [])
+ * @method \Aws\Result listConfigurationBundleVersions(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listConfigurationBundleVersionsAsync(array $args = [])
+ * @method \Aws\Result listConfigurationBundles(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listConfigurationBundlesAsync(array $args = [])
+ * @method \Aws\Result listDatasetExamples(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listDatasetExamplesAsync(array $args = [])
+ * @method \Aws\Result listDatasetVersions(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listDatasetVersionsAsync(array $args = [])
+ * @method \Aws\Result listDatasets(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listDatasetsAsync(array $args = [])
+ * @method \Aws\Result listEvaluators(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listEvaluatorsAsync(array $args = [])
+ * @method \Aws\Result listGatewayRules(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listGatewayRulesAsync(array $args = [])
+ * @method \Aws\Result listGatewayTargets(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listGatewayTargetsAsync(array $args = [])
+ * @method \Aws\Result listGateways(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listGatewaysAsync(array $args = [])
+ * @method \Aws\Result listHarnessEndpoints(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listHarnessEndpointsAsync(array $args = [])
+ * @method \Aws\Result listHarnessVersions(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listHarnessVersionsAsync(array $args = [])
+ * @method \Aws\Result listHarnesses(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listHarnessesAsync(array $args = [])
+ * @method \Aws\Result listMemories(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listMemoriesAsync(array $args = [])
+ * @method \Aws\Result listOauth2CredentialProviders(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listOauth2CredentialProvidersAsync(array $args = [])
+ * @method \Aws\Result listOnlineEvaluationConfigs(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listOnlineEvaluationConfigsAsync(array $args = [])
+ * @method \Aws\Result listPaymentConnectors(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listPaymentConnectorsAsync(array $args = [])
+ * @method \Aws\Result listPaymentCredentialProviders(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listPaymentCredentialProvidersAsync(array $args = [])
+ * @method \Aws\Result listPaymentManagers(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listPaymentManagersAsync(array $args = [])
+ * @method \Aws\Result listPolicies(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listPoliciesAsync(array $args = [])
+ * @method \Aws\Result listPolicyEngineSummaries(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listPolicyEngineSummariesAsync(array $args = [])
+ * @method \Aws\Result listPolicyEngines(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listPolicyEnginesAsync(array $args = [])
+ * @method \Aws\Result listPolicyGenerationAssets(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listPolicyGenerationAssetsAsync(array $args = [])
+ * @method \Aws\Result listPolicyGenerationSummaries(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listPolicyGenerationSummariesAsync(array $args = [])
+ * @method \Aws\Result listPolicyGenerations(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listPolicyGenerationsAsync(array $args = [])
+ * @method \Aws\Result listPolicySummaries(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listPolicySummariesAsync(array $args = [])
+ * @method \Aws\Result listRegistries(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listRegistriesAsync(array $args = [])
+ * @method \Aws\Result listRegistryRecords(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listRegistryRecordsAsync(array $args = [])
+ * @method \Aws\Result listTagsForResource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listTagsForResourceAsync(array $args = [])
+ * @method \Aws\Result listWorkloadIdentities(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listWorkloadIdentitiesAsync(array $args = [])
+ * @method \Aws\Result putResourcePolicy(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise putResourcePolicyAsync(array $args = [])
+ * @method \Aws\Result setTokenVaultCMK(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise setTokenVaultCMKAsync(array $args = [])
+ * @method \Aws\Result startPolicyGeneration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise startPolicyGenerationAsync(array $args = [])
+ * @method \Aws\Result submitRegistryRecordForApproval(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise submitRegistryRecordForApprovalAsync(array $args = [])
+ * @method \Aws\Result synchronizeGatewayTargets(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise synchronizeGatewayTargetsAsync(array $args = [])
+ * @method \Aws\Result tagResource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise tagResourceAsync(array $args = [])
+ * @method \Aws\Result untagResource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise untagResourceAsync(array $args = [])
+ * @method \Aws\Result updateAgentRuntime(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateAgentRuntimeAsync(array $args = [])
+ * @method \Aws\Result updateAgentRuntimeEndpoint(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateAgentRuntimeEndpointAsync(array $args = [])
+ * @method \Aws\Result updateApiKeyCredentialProvider(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateApiKeyCredentialProviderAsync(array $args = [])
+ * @method \Aws\Result updateConfigurationBundle(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateConfigurationBundleAsync(array $args = [])
+ * @method \Aws\Result updateDataset(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateDatasetAsync(array $args = [])
+ * @method \Aws\Result updateDatasetExamples(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateDatasetExamplesAsync(array $args = [])
+ * @method \Aws\Result updateEvaluator(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateEvaluatorAsync(array $args = [])
+ * @method \Aws\Result updateGateway(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateGatewayAsync(array $args = [])
+ * @method \Aws\Result updateGatewayRule(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateGatewayRuleAsync(array $args = [])
+ * @method \Aws\Result updateGatewayTarget(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateGatewayTargetAsync(array $args = [])
+ * @method \Aws\Result updateHarness(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateHarnessAsync(array $args = [])
+ * @method \Aws\Result updateHarnessEndpoint(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateHarnessEndpointAsync(array $args = [])
+ * @method \Aws\Result updateMemory(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateMemoryAsync(array $args = [])
+ * @method \Aws\Result updateOauth2CredentialProvider(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateOauth2CredentialProviderAsync(array $args = [])
+ * @method \Aws\Result updateOnlineEvaluationConfig(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateOnlineEvaluationConfigAsync(array $args = [])
+ * @method \Aws\Result updatePaymentConnector(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updatePaymentConnectorAsync(array $args = [])
+ * @method \Aws\Result updatePaymentCredentialProvider(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updatePaymentCredentialProviderAsync(array $args = [])
+ * @method \Aws\Result updatePaymentManager(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updatePaymentManagerAsync(array $args = [])
+ * @method \Aws\Result updatePolicy(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updatePolicyAsync(array $args = [])
+ * @method \Aws\Result updatePolicyEngine(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updatePolicyEngineAsync(array $args = [])
+ * @method \Aws\Result updateRegistry(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateRegistryAsync(array $args = [])
+ * @method \Aws\Result updateRegistryRecord(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateRegistryRecordAsync(array $args = [])
+ * @method \Aws\Result updateRegistryRecordStatus(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateRegistryRecordStatusAsync(array $args = [])
+ * @method \Aws\Result updateWorkloadIdentity(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateWorkloadIdentityAsync(array $args = [])
+ */
+class BedrockAgentCoreControlClient extends AwsClient {}

+ 75 - 0
upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/BedrockAgentRuntime/BedrockAgentRuntimeClient.php

@@ -0,0 +1,75 @@
+<?php
+namespace Aws\BedrockAgentRuntime;
+
+use Aws\AwsClient;
+
+/**
+ * This client is used to interact with the **Agents for Amazon Bedrock Runtime** service.
+ * @method \Aws\Result agenticRetrieveStream(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise agenticRetrieveStreamAsync(array $args = [])
+ * @method \Aws\Result createInvocation(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createInvocationAsync(array $args = [])
+ * @method \Aws\Result createSession(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createSessionAsync(array $args = [])
+ * @method \Aws\Result deleteAgentMemory(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteAgentMemoryAsync(array $args = [])
+ * @method \Aws\Result deleteSession(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteSessionAsync(array $args = [])
+ * @method \Aws\Result endSession(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise endSessionAsync(array $args = [])
+ * @method \Aws\Result generateQuery(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise generateQueryAsync(array $args = [])
+ * @method \Aws\Result getAgentMemory(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getAgentMemoryAsync(array $args = [])
+ * @method \Aws\Result getDocumentContent(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getDocumentContentAsync(array $args = [])
+ * @method \Aws\Result getExecutionFlowSnapshot(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getExecutionFlowSnapshotAsync(array $args = [])
+ * @method \Aws\Result getFlowExecution(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getFlowExecutionAsync(array $args = [])
+ * @method \Aws\Result getInvocationStep(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getInvocationStepAsync(array $args = [])
+ * @method \Aws\Result getSession(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getSessionAsync(array $args = [])
+ * @method \Aws\Result invokeAgent(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise invokeAgentAsync(array $args = [])
+ * @method \Aws\Result invokeFlow(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise invokeFlowAsync(array $args = [])
+ * @method \Aws\Result invokeInlineAgent(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise invokeInlineAgentAsync(array $args = [])
+ * @method \Aws\Result listFlowExecutionEvents(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listFlowExecutionEventsAsync(array $args = [])
+ * @method \Aws\Result listFlowExecutions(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listFlowExecutionsAsync(array $args = [])
+ * @method \Aws\Result listInvocationSteps(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listInvocationStepsAsync(array $args = [])
+ * @method \Aws\Result listInvocations(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listInvocationsAsync(array $args = [])
+ * @method \Aws\Result listSessions(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listSessionsAsync(array $args = [])
+ * @method \Aws\Result listTagsForResource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listTagsForResourceAsync(array $args = [])
+ * @method \Aws\Result optimizePrompt(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise optimizePromptAsync(array $args = [])
+ * @method \Aws\Result putInvocationStep(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise putInvocationStepAsync(array $args = [])
+ * @method \Aws\Result rerank(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise rerankAsync(array $args = [])
+ * @method \Aws\Result retrieve(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise retrieveAsync(array $args = [])
+ * @method \Aws\Result retrieveAndGenerate(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise retrieveAndGenerateAsync(array $args = [])
+ * @method \Aws\Result retrieveAndGenerateStream(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise retrieveAndGenerateStreamAsync(array $args = [])
+ * @method \Aws\Result startFlowExecution(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise startFlowExecutionAsync(array $args = [])
+ * @method \Aws\Result stopFlowExecution(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise stopFlowExecutionAsync(array $args = [])
+ * @method \Aws\Result tagResource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise tagResourceAsync(array $args = [])
+ * @method \Aws\Result untagResource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise untagResourceAsync(array $args = [])
+ * @method \Aws\Result updateSession(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateSessionAsync(array $args = [])
+ */
+class BedrockAgentRuntimeClient extends AwsClient {}

+ 29 - 0
upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/BedrockRuntime/BedrockRuntimeClient.php

@@ -0,0 +1,29 @@
+<?php
+namespace Aws\BedrockRuntime;
+
+use Aws\AwsClient;
+
+/**
+ * This client is used to interact with the **Amazon Bedrock Runtime** service.
+ * @method \Aws\Result applyGuardrail(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise applyGuardrailAsync(array $args = [])
+ * @method \Aws\Result converse(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise converseAsync(array $args = [])
+ * @method \Aws\Result converseStream(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise converseStreamAsync(array $args = [])
+ * @method \Aws\Result countTokens(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise countTokensAsync(array $args = [])
+ * @method \Aws\Result getAsyncInvoke(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getAsyncInvokeAsync(array $args = [])
+ * @method \Aws\Result invokeGuardrailChecks(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise invokeGuardrailChecksAsync(array $args = [])
+ * @method \Aws\Result invokeModel(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise invokeModelAsync(array $args = [])
+ * @method \Aws\Result invokeModelWithResponseStream(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise invokeModelWithResponseStreamAsync(array $args = [])
+ * @method \Aws\Result listAsyncInvokes(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listAsyncInvokesAsync(array $args = [])
+ * @method \Aws\Result startAsyncInvoke(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise startAsyncInvokeAsync(array $args = [])
+ */
+class BedrockRuntimeClient extends AwsClient {}

+ 43 - 0
upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/Billing/BillingClient.php

@@ -0,0 +1,43 @@
+<?php
+namespace Aws\Billing;
+
+use Aws\AwsClient;
+
+/**
+ * This client is used to interact with the **AWS Billing** service.
+ * @method \Aws\Result associateSourceViews(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise associateSourceViewsAsync(array $args = [])
+ * @method \Aws\Result createBillingView(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createBillingViewAsync(array $args = [])
+ * @method \Aws\Result deleteBillingView(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteBillingViewAsync(array $args = [])
+ * @method \Aws\Result disassociateSourceViews(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise disassociateSourceViewsAsync(array $args = [])
+ * @method \Aws\Result getBillingPreferences(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getBillingPreferencesAsync(array $args = [])
+ * @method \Aws\Result getBillingView(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getBillingViewAsync(array $args = [])
+ * @method \Aws\Result getCreditAllocationHistory(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getCreditAllocationHistoryAsync(array $args = [])
+ * @method \Aws\Result getCredits(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getCreditsAsync(array $args = [])
+ * @method \Aws\Result getResourcePolicy(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getResourcePolicyAsync(array $args = [])
+ * @method \Aws\Result listBillingViews(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listBillingViewsAsync(array $args = [])
+ * @method \Aws\Result listSourceViewsForBillingView(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listSourceViewsForBillingViewAsync(array $args = [])
+ * @method \Aws\Result listTagsForResource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listTagsForResourceAsync(array $args = [])
+ * @method \Aws\Result redeemCredits(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise redeemCreditsAsync(array $args = [])
+ * @method \Aws\Result tagResource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise tagResourceAsync(array $args = [])
+ * @method \Aws\Result untagResource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise untagResourceAsync(array $args = [])
+ * @method \Aws\Result updateBillingPreferences(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateBillingPreferencesAsync(array $args = [])
+ * @method \Aws\Result updateBillingView(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateBillingViewAsync(array $args = [])
+ */
+class BillingClient extends AwsClient {}

+ 209 - 0
upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/CleanRooms/CleanRoomsClient.php

@@ -0,0 +1,209 @@
+<?php
+namespace Aws\CleanRooms;
+
+use Aws\AwsClient;
+
+/**
+ * This client is used to interact with the **AWS Clean Rooms Service** service.
+ * @method \Aws\Result batchGetCollaborationAnalysisTemplate(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise batchGetCollaborationAnalysisTemplateAsync(array $args = [])
+ * @method \Aws\Result batchGetSchema(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise batchGetSchemaAsync(array $args = [])
+ * @method \Aws\Result batchGetSchemaAnalysisRule(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise batchGetSchemaAnalysisRuleAsync(array $args = [])
+ * @method \Aws\Result createAnalysisTemplate(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createAnalysisTemplateAsync(array $args = [])
+ * @method \Aws\Result createCollaboration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createCollaborationAsync(array $args = [])
+ * @method \Aws\Result createCollaborationChangeRequest(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createCollaborationChangeRequestAsync(array $args = [])
+ * @method \Aws\Result createConfiguredAudienceModelAssociation(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createConfiguredAudienceModelAssociationAsync(array $args = [])
+ * @method \Aws\Result createConfiguredTable(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createConfiguredTableAsync(array $args = [])
+ * @method \Aws\Result createConfiguredTableAnalysisRule(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createConfiguredTableAnalysisRuleAsync(array $args = [])
+ * @method \Aws\Result createConfiguredTableAssociation(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createConfiguredTableAssociationAsync(array $args = [])
+ * @method \Aws\Result createConfiguredTableAssociationAnalysisRule(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createConfiguredTableAssociationAnalysisRuleAsync(array $args = [])
+ * @method \Aws\Result createIdMappingTable(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createIdMappingTableAsync(array $args = [])
+ * @method \Aws\Result createIdNamespaceAssociation(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createIdNamespaceAssociationAsync(array $args = [])
+ * @method \Aws\Result createIntermediateTable(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createIntermediateTableAsync(array $args = [])
+ * @method \Aws\Result createIntermediateTableAnalysisRule(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createIntermediateTableAnalysisRuleAsync(array $args = [])
+ * @method \Aws\Result createMembership(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createMembershipAsync(array $args = [])
+ * @method \Aws\Result createPrivacyBudgetTemplate(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createPrivacyBudgetTemplateAsync(array $args = [])
+ * @method \Aws\Result deleteAnalysisTemplate(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteAnalysisTemplateAsync(array $args = [])
+ * @method \Aws\Result deleteCollaboration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteCollaborationAsync(array $args = [])
+ * @method \Aws\Result deleteConfiguredAudienceModelAssociation(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteConfiguredAudienceModelAssociationAsync(array $args = [])
+ * @method \Aws\Result deleteConfiguredTable(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteConfiguredTableAsync(array $args = [])
+ * @method \Aws\Result deleteConfiguredTableAnalysisRule(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteConfiguredTableAnalysisRuleAsync(array $args = [])
+ * @method \Aws\Result deleteConfiguredTableAssociation(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteConfiguredTableAssociationAsync(array $args = [])
+ * @method \Aws\Result deleteConfiguredTableAssociationAnalysisRule(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteConfiguredTableAssociationAnalysisRuleAsync(array $args = [])
+ * @method \Aws\Result deleteIdMappingTable(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteIdMappingTableAsync(array $args = [])
+ * @method \Aws\Result deleteIdNamespaceAssociation(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteIdNamespaceAssociationAsync(array $args = [])
+ * @method \Aws\Result deleteIntermediateTable(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteIntermediateTableAsync(array $args = [])
+ * @method \Aws\Result deleteIntermediateTableAnalysisRule(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteIntermediateTableAnalysisRuleAsync(array $args = [])
+ * @method \Aws\Result deleteMember(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteMemberAsync(array $args = [])
+ * @method \Aws\Result deleteMembership(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteMembershipAsync(array $args = [])
+ * @method \Aws\Result deletePrivacyBudgetTemplate(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deletePrivacyBudgetTemplateAsync(array $args = [])
+ * @method \Aws\Result disallowIntermediateTable(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise disallowIntermediateTableAsync(array $args = [])
+ * @method \Aws\Result getAnalysisTemplate(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getAnalysisTemplateAsync(array $args = [])
+ * @method \Aws\Result getCollaboration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getCollaborationAsync(array $args = [])
+ * @method \Aws\Result getCollaborationAnalysisTemplate(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getCollaborationAnalysisTemplateAsync(array $args = [])
+ * @method \Aws\Result getCollaborationChangeRequest(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getCollaborationChangeRequestAsync(array $args = [])
+ * @method \Aws\Result getCollaborationConfiguredAudienceModelAssociation(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getCollaborationConfiguredAudienceModelAssociationAsync(array $args = [])
+ * @method \Aws\Result getCollaborationIdNamespaceAssociation(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getCollaborationIdNamespaceAssociationAsync(array $args = [])
+ * @method \Aws\Result getCollaborationPrivacyBudgetTemplate(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getCollaborationPrivacyBudgetTemplateAsync(array $args = [])
+ * @method \Aws\Result getConfiguredAudienceModelAssociation(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getConfiguredAudienceModelAssociationAsync(array $args = [])
+ * @method \Aws\Result getConfiguredTable(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getConfiguredTableAsync(array $args = [])
+ * @method \Aws\Result getConfiguredTableAnalysisRule(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getConfiguredTableAnalysisRuleAsync(array $args = [])
+ * @method \Aws\Result getConfiguredTableAssociation(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getConfiguredTableAssociationAsync(array $args = [])
+ * @method \Aws\Result getConfiguredTableAssociationAnalysisRule(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getConfiguredTableAssociationAnalysisRuleAsync(array $args = [])
+ * @method \Aws\Result getIdMappingTable(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getIdMappingTableAsync(array $args = [])
+ * @method \Aws\Result getIdNamespaceAssociation(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getIdNamespaceAssociationAsync(array $args = [])
+ * @method \Aws\Result getIntermediateTable(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getIntermediateTableAsync(array $args = [])
+ * @method \Aws\Result getIntermediateTableAnalysisRule(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getIntermediateTableAnalysisRuleAsync(array $args = [])
+ * @method \Aws\Result getMembership(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getMembershipAsync(array $args = [])
+ * @method \Aws\Result getPrivacyBudgetTemplate(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getPrivacyBudgetTemplateAsync(array $args = [])
+ * @method \Aws\Result getProtectedJob(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getProtectedJobAsync(array $args = [])
+ * @method \Aws\Result getProtectedQuery(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getProtectedQueryAsync(array $args = [])
+ * @method \Aws\Result getSchema(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getSchemaAsync(array $args = [])
+ * @method \Aws\Result getSchemaAnalysisRule(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getSchemaAnalysisRuleAsync(array $args = [])
+ * @method \Aws\Result listAnalysisTemplates(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listAnalysisTemplatesAsync(array $args = [])
+ * @method \Aws\Result listCollaborationAnalysisTemplates(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listCollaborationAnalysisTemplatesAsync(array $args = [])
+ * @method \Aws\Result listCollaborationChangeRequests(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listCollaborationChangeRequestsAsync(array $args = [])
+ * @method \Aws\Result listCollaborationConfiguredAudienceModelAssociations(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listCollaborationConfiguredAudienceModelAssociationsAsync(array $args = [])
+ * @method \Aws\Result listCollaborationIdNamespaceAssociations(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listCollaborationIdNamespaceAssociationsAsync(array $args = [])
+ * @method \Aws\Result listCollaborationPrivacyBudgetTemplates(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listCollaborationPrivacyBudgetTemplatesAsync(array $args = [])
+ * @method \Aws\Result listCollaborationPrivacyBudgets(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listCollaborationPrivacyBudgetsAsync(array $args = [])
+ * @method \Aws\Result listCollaborations(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listCollaborationsAsync(array $args = [])
+ * @method \Aws\Result listConfiguredAudienceModelAssociations(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listConfiguredAudienceModelAssociationsAsync(array $args = [])
+ * @method \Aws\Result listConfiguredTableAssociations(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listConfiguredTableAssociationsAsync(array $args = [])
+ * @method \Aws\Result listConfiguredTables(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listConfiguredTablesAsync(array $args = [])
+ * @method \Aws\Result listIdMappingTables(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listIdMappingTablesAsync(array $args = [])
+ * @method \Aws\Result listIdNamespaceAssociations(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listIdNamespaceAssociationsAsync(array $args = [])
+ * @method \Aws\Result listIntermediateTableVersions(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listIntermediateTableVersionsAsync(array $args = [])
+ * @method \Aws\Result listIntermediateTables(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listIntermediateTablesAsync(array $args = [])
+ * @method \Aws\Result listMembers(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listMembersAsync(array $args = [])
+ * @method \Aws\Result listMemberships(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listMembershipsAsync(array $args = [])
+ * @method \Aws\Result listPrivacyBudgetTemplates(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listPrivacyBudgetTemplatesAsync(array $args = [])
+ * @method \Aws\Result listPrivacyBudgets(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listPrivacyBudgetsAsync(array $args = [])
+ * @method \Aws\Result listProtectedJobs(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listProtectedJobsAsync(array $args = [])
+ * @method \Aws\Result listProtectedQueries(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listProtectedQueriesAsync(array $args = [])
+ * @method \Aws\Result listSchemas(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listSchemasAsync(array $args = [])
+ * @method \Aws\Result listTagsForResource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listTagsForResourceAsync(array $args = [])
+ * @method \Aws\Result populateIdMappingTable(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise populateIdMappingTableAsync(array $args = [])
+ * @method \Aws\Result populateIntermediateTable(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise populateIntermediateTableAsync(array $args = [])
+ * @method \Aws\Result previewPrivacyImpact(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise previewPrivacyImpactAsync(array $args = [])
+ * @method \Aws\Result startProtectedJob(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise startProtectedJobAsync(array $args = [])
+ * @method \Aws\Result startProtectedQuery(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise startProtectedQueryAsync(array $args = [])
+ * @method \Aws\Result tagResource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise tagResourceAsync(array $args = [])
+ * @method \Aws\Result untagResource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise untagResourceAsync(array $args = [])
+ * @method \Aws\Result updateAnalysisTemplate(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateAnalysisTemplateAsync(array $args = [])
+ * @method \Aws\Result updateCollaboration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateCollaborationAsync(array $args = [])
+ * @method \Aws\Result updateCollaborationChangeRequest(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateCollaborationChangeRequestAsync(array $args = [])
+ * @method \Aws\Result updateConfiguredAudienceModelAssociation(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateConfiguredAudienceModelAssociationAsync(array $args = [])
+ * @method \Aws\Result updateConfiguredTable(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateConfiguredTableAsync(array $args = [])
+ * @method \Aws\Result updateConfiguredTableAnalysisRule(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateConfiguredTableAnalysisRuleAsync(array $args = [])
+ * @method \Aws\Result updateConfiguredTableAssociation(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateConfiguredTableAssociationAsync(array $args = [])
+ * @method \Aws\Result updateConfiguredTableAssociationAnalysisRule(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateConfiguredTableAssociationAnalysisRuleAsync(array $args = [])
+ * @method \Aws\Result updateIdMappingTable(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateIdMappingTableAsync(array $args = [])
+ * @method \Aws\Result updateIdNamespaceAssociation(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateIdNamespaceAssociationAsync(array $args = [])
+ * @method \Aws\Result updateIntermediateTable(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateIntermediateTableAsync(array $args = [])
+ * @method \Aws\Result updateIntermediateTableAnalysisRule(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateIntermediateTableAnalysisRuleAsync(array $args = [])
+ * @method \Aws\Result updateMembership(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateMembershipAsync(array $args = [])
+ * @method \Aws\Result updatePrivacyBudgetTemplate(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updatePrivacyBudgetTemplateAsync(array $args = [])
+ * @method \Aws\Result updateProtectedJob(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateProtectedJobAsync(array $args = [])
+ * @method \Aws\Result updateProtectedQuery(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateProtectedQueryAsync(array $args = [])
+ */
+class CleanRoomsClient extends AwsClient {}

+ 441 - 0
upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/CloudFront/CloudFrontClient.php

@@ -0,0 +1,441 @@
+<?php
+namespace Aws\CloudFront;
+
+use Aws\AwsClient;
+
+/**
+ * This client is used to interact with the **Amazon CloudFront** service.
+ *
+ * @method \Aws\Result createCloudFrontOriginAccessIdentity(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createCloudFrontOriginAccessIdentityAsync(array $args = [])
+ * @method \Aws\Result createDistribution(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createDistributionAsync(array $args = [])
+ * @method \Aws\Result createInvalidation(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createInvalidationAsync(array $args = [])
+ * @method \Aws\Result createStreamingDistribution(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createStreamingDistributionAsync(array $args = [])
+ * @method \Aws\Result deleteCloudFrontOriginAccessIdentity(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteCloudFrontOriginAccessIdentityAsync(array $args = [])
+ * @method \Aws\Result deleteDistribution(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteDistributionAsync(array $args = [])
+ * @method \Aws\Result deleteStreamingDistribution(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteStreamingDistributionAsync(array $args = [])
+ * @method \Aws\Result getCloudFrontOriginAccessIdentity(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getCloudFrontOriginAccessIdentityAsync(array $args = [])
+ * @method \Aws\Result getCloudFrontOriginAccessIdentityConfig(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getCloudFrontOriginAccessIdentityConfigAsync(array $args = [])
+ * @method \Aws\Result getDistribution(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getDistributionAsync(array $args = [])
+ * @method \Aws\Result getDistributionConfig(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getDistributionConfigAsync(array $args = [])
+ * @method \Aws\Result getInvalidation(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getInvalidationAsync(array $args = [])
+ * @method \Aws\Result getStreamingDistribution(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getStreamingDistributionAsync(array $args = [])
+ * @method \Aws\Result getStreamingDistributionConfig(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getStreamingDistributionConfigAsync(array $args = [])
+ * @method \Aws\Result listCloudFrontOriginAccessIdentities(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listCloudFrontOriginAccessIdentitiesAsync(array $args = [])
+ * @method \Aws\Result listDistributions(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listDistributionsAsync(array $args = [])
+ * @method \Aws\Result listDistributionsByWebACLId(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listDistributionsByWebACLIdAsync(array $args = [])
+ * @method \Aws\Result listInvalidations(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listInvalidationsAsync(array $args = [])
+ * @method \Aws\Result listStreamingDistributions(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listStreamingDistributionsAsync(array $args = [])
+ * @method \Aws\Result updateCloudFrontOriginAccessIdentity(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateCloudFrontOriginAccessIdentityAsync(array $args = [])
+ * @method \Aws\Result updateDistribution(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateDistributionAsync(array $args = [])
+ * @method \Aws\Result updateStreamingDistribution(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateStreamingDistributionAsync(array $args = [])
+ * @method \Aws\Result createDistributionWithTags(array $args = []) (supported in versions 2016-08-01, 2016-08-20, 2016-09-07, 2016-09-29, 2016-11-25, 2017-03-25, 2017-10-30, 2018-06-18, 2018-11-05, 2019-03-26, 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise createDistributionWithTagsAsync(array $args = []) (supported in versions 2016-08-01, 2016-08-20, 2016-09-07, 2016-09-29, 2016-11-25, 2017-03-25, 2017-10-30, 2018-06-18, 2018-11-05, 2019-03-26, 2020-05-31)
+ * @method \Aws\Result createStreamingDistributionWithTags(array $args = []) (supported in versions 2016-08-01, 2016-08-20, 2016-09-07, 2016-09-29, 2016-11-25, 2017-03-25, 2017-10-30, 2018-06-18, 2018-11-05, 2019-03-26, 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise createStreamingDistributionWithTagsAsync(array $args = []) (supported in versions 2016-08-01, 2016-08-20, 2016-09-07, 2016-09-29, 2016-11-25, 2017-03-25, 2017-10-30, 2018-06-18, 2018-11-05, 2019-03-26, 2020-05-31)
+ * @method \Aws\Result listTagsForResource(array $args = []) (supported in versions 2016-08-01, 2016-08-20, 2016-09-07, 2016-09-29, 2016-11-25, 2017-03-25, 2017-10-30, 2018-06-18, 2018-11-05, 2019-03-26, 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise listTagsForResourceAsync(array $args = []) (supported in versions 2016-08-01, 2016-08-20, 2016-09-07, 2016-09-29, 2016-11-25, 2017-03-25, 2017-10-30, 2018-06-18, 2018-11-05, 2019-03-26, 2020-05-31)
+ * @method \Aws\Result tagResource(array $args = []) (supported in versions 2016-08-01, 2016-08-20, 2016-09-07, 2016-09-29, 2016-11-25, 2017-03-25, 2017-10-30, 2018-06-18, 2018-11-05, 2019-03-26, 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise tagResourceAsync(array $args = []) (supported in versions 2016-08-01, 2016-08-20, 2016-09-07, 2016-09-29, 2016-11-25, 2017-03-25, 2017-10-30, 2018-06-18, 2018-11-05, 2019-03-26, 2020-05-31)
+ * @method \Aws\Result untagResource(array $args = []) (supported in versions 2016-08-01, 2016-08-20, 2016-09-07, 2016-09-29, 2016-11-25, 2017-03-25, 2017-10-30, 2018-06-18, 2018-11-05, 2019-03-26, 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise untagResourceAsync(array $args = []) (supported in versions 2016-08-01, 2016-08-20, 2016-09-07, 2016-09-29, 2016-11-25, 2017-03-25, 2017-10-30, 2018-06-18, 2018-11-05, 2019-03-26, 2020-05-31)
+ * @method \Aws\Result deleteServiceLinkedRole(array $args = []) (supported in versions 2017-03-25)
+ * @method \GuzzleHttp\Promise\Promise deleteServiceLinkedRoleAsync(array $args = []) (supported in versions 2017-03-25)
+ * @method \Aws\Result createFieldLevelEncryptionConfig(array $args = []) (supported in versions 2017-10-30, 2018-06-18, 2018-11-05, 2019-03-26, 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise createFieldLevelEncryptionConfigAsync(array $args = []) (supported in versions 2017-10-30, 2018-06-18, 2018-11-05, 2019-03-26, 2020-05-31)
+ * @method \Aws\Result createFieldLevelEncryptionProfile(array $args = []) (supported in versions 2017-10-30, 2018-06-18, 2018-11-05, 2019-03-26, 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise createFieldLevelEncryptionProfileAsync(array $args = []) (supported in versions 2017-10-30, 2018-06-18, 2018-11-05, 2019-03-26, 2020-05-31)
+ * @method \Aws\Result createPublicKey(array $args = []) (supported in versions 2017-10-30, 2018-06-18, 2018-11-05, 2019-03-26, 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise createPublicKeyAsync(array $args = []) (supported in versions 2017-10-30, 2018-06-18, 2018-11-05, 2019-03-26, 2020-05-31)
+ * @method \Aws\Result deleteFieldLevelEncryptionConfig(array $args = []) (supported in versions 2017-10-30, 2018-06-18, 2018-11-05, 2019-03-26, 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise deleteFieldLevelEncryptionConfigAsync(array $args = []) (supported in versions 2017-10-30, 2018-06-18, 2018-11-05, 2019-03-26, 2020-05-31)
+ * @method \Aws\Result deleteFieldLevelEncryptionProfile(array $args = []) (supported in versions 2017-10-30, 2018-06-18, 2018-11-05, 2019-03-26, 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise deleteFieldLevelEncryptionProfileAsync(array $args = []) (supported in versions 2017-10-30, 2018-06-18, 2018-11-05, 2019-03-26, 2020-05-31)
+ * @method \Aws\Result deletePublicKey(array $args = []) (supported in versions 2017-10-30, 2018-06-18, 2018-11-05, 2019-03-26, 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise deletePublicKeyAsync(array $args = []) (supported in versions 2017-10-30, 2018-06-18, 2018-11-05, 2019-03-26, 2020-05-31)
+ * @method \Aws\Result getFieldLevelEncryption(array $args = []) (supported in versions 2017-10-30, 2018-06-18, 2018-11-05, 2019-03-26, 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise getFieldLevelEncryptionAsync(array $args = []) (supported in versions 2017-10-30, 2018-06-18, 2018-11-05, 2019-03-26, 2020-05-31)
+ * @method \Aws\Result getFieldLevelEncryptionConfig(array $args = []) (supported in versions 2017-10-30, 2018-06-18, 2018-11-05, 2019-03-26, 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise getFieldLevelEncryptionConfigAsync(array $args = []) (supported in versions 2017-10-30, 2018-06-18, 2018-11-05, 2019-03-26, 2020-05-31)
+ * @method \Aws\Result getFieldLevelEncryptionProfile(array $args = []) (supported in versions 2017-10-30, 2018-06-18, 2018-11-05, 2019-03-26, 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise getFieldLevelEncryptionProfileAsync(array $args = []) (supported in versions 2017-10-30, 2018-06-18, 2018-11-05, 2019-03-26, 2020-05-31)
+ * @method \Aws\Result getFieldLevelEncryptionProfileConfig(array $args = []) (supported in versions 2017-10-30, 2018-06-18, 2018-11-05, 2019-03-26, 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise getFieldLevelEncryptionProfileConfigAsync(array $args = []) (supported in versions 2017-10-30, 2018-06-18, 2018-11-05, 2019-03-26, 2020-05-31)
+ * @method \Aws\Result getPublicKey(array $args = []) (supported in versions 2017-10-30, 2018-06-18, 2018-11-05, 2019-03-26, 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise getPublicKeyAsync(array $args = []) (supported in versions 2017-10-30, 2018-06-18, 2018-11-05, 2019-03-26, 2020-05-31)
+ * @method \Aws\Result getPublicKeyConfig(array $args = []) (supported in versions 2017-10-30, 2018-06-18, 2018-11-05, 2019-03-26, 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise getPublicKeyConfigAsync(array $args = []) (supported in versions 2017-10-30, 2018-06-18, 2018-11-05, 2019-03-26, 2020-05-31)
+ * @method \Aws\Result listFieldLevelEncryptionConfigs(array $args = []) (supported in versions 2017-10-30, 2018-06-18, 2018-11-05, 2019-03-26, 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise listFieldLevelEncryptionConfigsAsync(array $args = []) (supported in versions 2017-10-30, 2018-06-18, 2018-11-05, 2019-03-26, 2020-05-31)
+ * @method \Aws\Result listFieldLevelEncryptionProfiles(array $args = []) (supported in versions 2017-10-30, 2018-06-18, 2018-11-05, 2019-03-26, 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise listFieldLevelEncryptionProfilesAsync(array $args = []) (supported in versions 2017-10-30, 2018-06-18, 2018-11-05, 2019-03-26, 2020-05-31)
+ * @method \Aws\Result listPublicKeys(array $args = []) (supported in versions 2017-10-30, 2018-06-18, 2018-11-05, 2019-03-26, 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise listPublicKeysAsync(array $args = []) (supported in versions 2017-10-30, 2018-06-18, 2018-11-05, 2019-03-26, 2020-05-31)
+ * @method \Aws\Result updateFieldLevelEncryptionConfig(array $args = []) (supported in versions 2017-10-30, 2018-06-18, 2018-11-05, 2019-03-26, 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise updateFieldLevelEncryptionConfigAsync(array $args = []) (supported in versions 2017-10-30, 2018-06-18, 2018-11-05, 2019-03-26, 2020-05-31)
+ * @method \Aws\Result updateFieldLevelEncryptionProfile(array $args = []) (supported in versions 2017-10-30, 2018-06-18, 2018-11-05, 2019-03-26, 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise updateFieldLevelEncryptionProfileAsync(array $args = []) (supported in versions 2017-10-30, 2018-06-18, 2018-11-05, 2019-03-26, 2020-05-31)
+ * @method \Aws\Result updatePublicKey(array $args = []) (supported in versions 2017-10-30, 2018-06-18, 2018-11-05, 2019-03-26, 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise updatePublicKeyAsync(array $args = []) (supported in versions 2017-10-30, 2018-06-18, 2018-11-05, 2019-03-26, 2020-05-31)
+ * @method \Aws\Result associateAlias(array $args = []) (supported in versions 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise associateAliasAsync(array $args = []) (supported in versions 2020-05-31)
+ * @method \Aws\Result associateDistributionTenantWebACL(array $args = []) (supported in versions 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise associateDistributionTenantWebACLAsync(array $args = []) (supported in versions 2020-05-31)
+ * @method \Aws\Result associateDistributionWebACL(array $args = []) (supported in versions 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise associateDistributionWebACLAsync(array $args = []) (supported in versions 2020-05-31)
+ * @method \Aws\Result copyDistribution(array $args = []) (supported in versions 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise copyDistributionAsync(array $args = []) (supported in versions 2020-05-31)
+ * @method \Aws\Result createAnycastIpList(array $args = []) (supported in versions 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise createAnycastIpListAsync(array $args = []) (supported in versions 2020-05-31)
+ * @method \Aws\Result createCachePolicy(array $args = []) (supported in versions 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise createCachePolicyAsync(array $args = []) (supported in versions 2020-05-31)
+ * @method \Aws\Result createConnectionFunction(array $args = []) (supported in versions 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise createConnectionFunctionAsync(array $args = []) (supported in versions 2020-05-31)
+ * @method \Aws\Result createConnectionGroup(array $args = []) (supported in versions 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise createConnectionGroupAsync(array $args = []) (supported in versions 2020-05-31)
+ * @method \Aws\Result createContinuousDeploymentPolicy(array $args = []) (supported in versions 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise createContinuousDeploymentPolicyAsync(array $args = []) (supported in versions 2020-05-31)
+ * @method \Aws\Result createDistributionTenant(array $args = []) (supported in versions 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise createDistributionTenantAsync(array $args = []) (supported in versions 2020-05-31)
+ * @method \Aws\Result createFunction(array $args = []) (supported in versions 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise createFunctionAsync(array $args = []) (supported in versions 2020-05-31)
+ * @method \Aws\Result createInvalidationForDistributionTenant(array $args = []) (supported in versions 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise createInvalidationForDistributionTenantAsync(array $args = []) (supported in versions 2020-05-31)
+ * @method \Aws\Result createKeyGroup(array $args = []) (supported in versions 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise createKeyGroupAsync(array $args = []) (supported in versions 2020-05-31)
+ * @method \Aws\Result createKeyValueStore(array $args = []) (supported in versions 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise createKeyValueStoreAsync(array $args = []) (supported in versions 2020-05-31)
+ * @method \Aws\Result createMonitoringSubscription(array $args = []) (supported in versions 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise createMonitoringSubscriptionAsync(array $args = []) (supported in versions 2020-05-31)
+ * @method \Aws\Result createOriginAccessControl(array $args = []) (supported in versions 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise createOriginAccessControlAsync(array $args = []) (supported in versions 2020-05-31)
+ * @method \Aws\Result createOriginRequestPolicy(array $args = []) (supported in versions 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise createOriginRequestPolicyAsync(array $args = []) (supported in versions 2020-05-31)
+ * @method \Aws\Result createRealtimeLogConfig(array $args = []) (supported in versions 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise createRealtimeLogConfigAsync(array $args = []) (supported in versions 2020-05-31)
+ * @method \Aws\Result createResponseHeadersPolicy(array $args = []) (supported in versions 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise createResponseHeadersPolicyAsync(array $args = []) (supported in versions 2020-05-31)
+ * @method \Aws\Result createTrustStore(array $args = []) (supported in versions 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise createTrustStoreAsync(array $args = []) (supported in versions 2020-05-31)
+ * @method \Aws\Result createVpcOrigin(array $args = []) (supported in versions 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise createVpcOriginAsync(array $args = []) (supported in versions 2020-05-31)
+ * @method \Aws\Result deleteAnycastIpList(array $args = []) (supported in versions 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise deleteAnycastIpListAsync(array $args = []) (supported in versions 2020-05-31)
+ * @method \Aws\Result deleteCachePolicy(array $args = []) (supported in versions 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise deleteCachePolicyAsync(array $args = []) (supported in versions 2020-05-31)
+ * @method \Aws\Result deleteConnectionFunction(array $args = []) (supported in versions 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise deleteConnectionFunctionAsync(array $args = []) (supported in versions 2020-05-31)
+ * @method \Aws\Result deleteConnectionGroup(array $args = []) (supported in versions 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise deleteConnectionGroupAsync(array $args = []) (supported in versions 2020-05-31)
+ * @method \Aws\Result deleteContinuousDeploymentPolicy(array $args = []) (supported in versions 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise deleteContinuousDeploymentPolicyAsync(array $args = []) (supported in versions 2020-05-31)
+ * @method \Aws\Result deleteDistributionTenant(array $args = []) (supported in versions 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise deleteDistributionTenantAsync(array $args = []) (supported in versions 2020-05-31)
+ * @method \Aws\Result deleteFunction(array $args = []) (supported in versions 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise deleteFunctionAsync(array $args = []) (supported in versions 2020-05-31)
+ * @method \Aws\Result deleteKeyGroup(array $args = []) (supported in versions 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise deleteKeyGroupAsync(array $args = []) (supported in versions 2020-05-31)
+ * @method \Aws\Result deleteKeyValueStore(array $args = []) (supported in versions 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise deleteKeyValueStoreAsync(array $args = []) (supported in versions 2020-05-31)
+ * @method \Aws\Result deleteMonitoringSubscription(array $args = []) (supported in versions 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise deleteMonitoringSubscriptionAsync(array $args = []) (supported in versions 2020-05-31)
+ * @method \Aws\Result deleteOriginAccessControl(array $args = []) (supported in versions 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise deleteOriginAccessControlAsync(array $args = []) (supported in versions 2020-05-31)
+ * @method \Aws\Result deleteOriginRequestPolicy(array $args = []) (supported in versions 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise deleteOriginRequestPolicyAsync(array $args = []) (supported in versions 2020-05-31)
+ * @method \Aws\Result deleteRealtimeLogConfig(array $args = []) (supported in versions 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise deleteRealtimeLogConfigAsync(array $args = []) (supported in versions 2020-05-31)
+ * @method \Aws\Result deleteResourcePolicy(array $args = []) (supported in versions 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise deleteResourcePolicyAsync(array $args = []) (supported in versions 2020-05-31)
+ * @method \Aws\Result deleteResponseHeadersPolicy(array $args = []) (supported in versions 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise deleteResponseHeadersPolicyAsync(array $args = []) (supported in versions 2020-05-31)
+ * @method \Aws\Result deleteTrustStore(array $args = []) (supported in versions 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise deleteTrustStoreAsync(array $args = []) (supported in versions 2020-05-31)
+ * @method \Aws\Result deleteVpcOrigin(array $args = []) (supported in versions 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise deleteVpcOriginAsync(array $args = []) (supported in versions 2020-05-31)
+ * @method \Aws\Result describeConnectionFunction(array $args = []) (supported in versions 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise describeConnectionFunctionAsync(array $args = []) (supported in versions 2020-05-31)
+ * @method \Aws\Result describeFunction(array $args = []) (supported in versions 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise describeFunctionAsync(array $args = []) (supported in versions 2020-05-31)
+ * @method \Aws\Result describeKeyValueStore(array $args = []) (supported in versions 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise describeKeyValueStoreAsync(array $args = []) (supported in versions 2020-05-31)
+ * @method \Aws\Result disassociateDistributionTenantWebACL(array $args = []) (supported in versions 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise disassociateDistributionTenantWebACLAsync(array $args = []) (supported in versions 2020-05-31)
+ * @method \Aws\Result disassociateDistributionWebACL(array $args = []) (supported in versions 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise disassociateDistributionWebACLAsync(array $args = []) (supported in versions 2020-05-31)
+ * @method \Aws\Result getAnycastIpList(array $args = []) (supported in versions 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise getAnycastIpListAsync(array $args = []) (supported in versions 2020-05-31)
+ * @method \Aws\Result getCachePolicy(array $args = []) (supported in versions 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise getCachePolicyAsync(array $args = []) (supported in versions 2020-05-31)
+ * @method \Aws\Result getCachePolicyConfig(array $args = []) (supported in versions 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise getCachePolicyConfigAsync(array $args = []) (supported in versions 2020-05-31)
+ * @method \Aws\Result getConnectionFunction(array $args = []) (supported in versions 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise getConnectionFunctionAsync(array $args = []) (supported in versions 2020-05-31)
+ * @method \Aws\Result getConnectionGroup(array $args = []) (supported in versions 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise getConnectionGroupAsync(array $args = []) (supported in versions 2020-05-31)
+ * @method \Aws\Result getConnectionGroupByRoutingEndpoint(array $args = []) (supported in versions 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise getConnectionGroupByRoutingEndpointAsync(array $args = []) (supported in versions 2020-05-31)
+ * @method \Aws\Result getContinuousDeploymentPolicy(array $args = []) (supported in versions 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise getContinuousDeploymentPolicyAsync(array $args = []) (supported in versions 2020-05-31)
+ * @method \Aws\Result getContinuousDeploymentPolicyConfig(array $args = []) (supported in versions 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise getContinuousDeploymentPolicyConfigAsync(array $args = []) (supported in versions 2020-05-31)
+ * @method \Aws\Result getDistributionTenant(array $args = []) (supported in versions 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise getDistributionTenantAsync(array $args = []) (supported in versions 2020-05-31)
+ * @method \Aws\Result getDistributionTenantByDomain(array $args = []) (supported in versions 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise getDistributionTenantByDomainAsync(array $args = []) (supported in versions 2020-05-31)
+ * @method \Aws\Result getFunction(array $args = []) (supported in versions 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise getFunctionAsync(array $args = []) (supported in versions 2020-05-31)
+ * @method \Aws\Result getInvalidationForDistributionTenant(array $args = []) (supported in versions 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise getInvalidationForDistributionTenantAsync(array $args = []) (supported in versions 2020-05-31)
+ * @method \Aws\Result getKeyGroup(array $args = []) (supported in versions 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise getKeyGroupAsync(array $args = []) (supported in versions 2020-05-31)
+ * @method \Aws\Result getKeyGroupConfig(array $args = []) (supported in versions 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise getKeyGroupConfigAsync(array $args = []) (supported in versions 2020-05-31)
+ * @method \Aws\Result getManagedCertificateDetails(array $args = []) (supported in versions 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise getManagedCertificateDetailsAsync(array $args = []) (supported in versions 2020-05-31)
+ * @method \Aws\Result getMonitoringSubscription(array $args = []) (supported in versions 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise getMonitoringSubscriptionAsync(array $args = []) (supported in versions 2020-05-31)
+ * @method \Aws\Result getOriginAccessControl(array $args = []) (supported in versions 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise getOriginAccessControlAsync(array $args = []) (supported in versions 2020-05-31)
+ * @method \Aws\Result getOriginAccessControlConfig(array $args = []) (supported in versions 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise getOriginAccessControlConfigAsync(array $args = []) (supported in versions 2020-05-31)
+ * @method \Aws\Result getOriginRequestPolicy(array $args = []) (supported in versions 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise getOriginRequestPolicyAsync(array $args = []) (supported in versions 2020-05-31)
+ * @method \Aws\Result getOriginRequestPolicyConfig(array $args = []) (supported in versions 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise getOriginRequestPolicyConfigAsync(array $args = []) (supported in versions 2020-05-31)
+ * @method \Aws\Result getRealtimeLogConfig(array $args = []) (supported in versions 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise getRealtimeLogConfigAsync(array $args = []) (supported in versions 2020-05-31)
+ * @method \Aws\Result getResourcePolicy(array $args = []) (supported in versions 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise getResourcePolicyAsync(array $args = []) (supported in versions 2020-05-31)
+ * @method \Aws\Result getResponseHeadersPolicy(array $args = []) (supported in versions 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise getResponseHeadersPolicyAsync(array $args = []) (supported in versions 2020-05-31)
+ * @method \Aws\Result getResponseHeadersPolicyConfig(array $args = []) (supported in versions 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise getResponseHeadersPolicyConfigAsync(array $args = []) (supported in versions 2020-05-31)
+ * @method \Aws\Result getTrustStore(array $args = []) (supported in versions 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise getTrustStoreAsync(array $args = []) (supported in versions 2020-05-31)
+ * @method \Aws\Result getVpcOrigin(array $args = []) (supported in versions 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise getVpcOriginAsync(array $args = []) (supported in versions 2020-05-31)
+ * @method \Aws\Result listAnycastIpLists(array $args = []) (supported in versions 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise listAnycastIpListsAsync(array $args = []) (supported in versions 2020-05-31)
+ * @method \Aws\Result listCachePolicies(array $args = []) (supported in versions 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise listCachePoliciesAsync(array $args = []) (supported in versions 2020-05-31)
+ * @method \Aws\Result listConflictingAliases(array $args = []) (supported in versions 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise listConflictingAliasesAsync(array $args = []) (supported in versions 2020-05-31)
+ * @method \Aws\Result listConnectionFunctions(array $args = []) (supported in versions 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise listConnectionFunctionsAsync(array $args = []) (supported in versions 2020-05-31)
+ * @method \Aws\Result listConnectionGroups(array $args = []) (supported in versions 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise listConnectionGroupsAsync(array $args = []) (supported in versions 2020-05-31)
+ * @method \Aws\Result listContinuousDeploymentPolicies(array $args = []) (supported in versions 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise listContinuousDeploymentPoliciesAsync(array $args = []) (supported in versions 2020-05-31)
+ * @method \Aws\Result listDistributionTenants(array $args = []) (supported in versions 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise listDistributionTenantsAsync(array $args = []) (supported in versions 2020-05-31)
+ * @method \Aws\Result listDistributionTenantsByCustomization(array $args = []) (supported in versions 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise listDistributionTenantsByCustomizationAsync(array $args = []) (supported in versions 2020-05-31)
+ * @method \Aws\Result listDistributionsByAnycastIpListId(array $args = []) (supported in versions 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise listDistributionsByAnycastIpListIdAsync(array $args = []) (supported in versions 2020-05-31)
+ * @method \Aws\Result listDistributionsByCachePolicyId(array $args = []) (supported in versions 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise listDistributionsByCachePolicyIdAsync(array $args = []) (supported in versions 2020-05-31)
+ * @method \Aws\Result listDistributionsByConnectionFunction(array $args = []) (supported in versions 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise listDistributionsByConnectionFunctionAsync(array $args = []) (supported in versions 2020-05-31)
+ * @method \Aws\Result listDistributionsByConnectionMode(array $args = []) (supported in versions 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise listDistributionsByConnectionModeAsync(array $args = []) (supported in versions 2020-05-31)
+ * @method \Aws\Result listDistributionsByKeyGroup(array $args = []) (supported in versions 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise listDistributionsByKeyGroupAsync(array $args = []) (supported in versions 2020-05-31)
+ * @method \Aws\Result listDistributionsByOriginRequestPolicyId(array $args = []) (supported in versions 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise listDistributionsByOriginRequestPolicyIdAsync(array $args = []) (supported in versions 2020-05-31)
+ * @method \Aws\Result listDistributionsByOwnedResource(array $args = []) (supported in versions 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise listDistributionsByOwnedResourceAsync(array $args = []) (supported in versions 2020-05-31)
+ * @method \Aws\Result listDistributionsByRealtimeLogConfig(array $args = []) (supported in versions 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise listDistributionsByRealtimeLogConfigAsync(array $args = []) (supported in versions 2020-05-31)
+ * @method \Aws\Result listDistributionsByResponseHeadersPolicyId(array $args = []) (supported in versions 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise listDistributionsByResponseHeadersPolicyIdAsync(array $args = []) (supported in versions 2020-05-31)
+ * @method \Aws\Result listDistributionsByTrustStore(array $args = []) (supported in versions 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise listDistributionsByTrustStoreAsync(array $args = []) (supported in versions 2020-05-31)
+ * @method \Aws\Result listDistributionsByVpcOriginId(array $args = []) (supported in versions 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise listDistributionsByVpcOriginIdAsync(array $args = []) (supported in versions 2020-05-31)
+ * @method \Aws\Result listDomainConflicts(array $args = []) (supported in versions 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise listDomainConflictsAsync(array $args = []) (supported in versions 2020-05-31)
+ * @method \Aws\Result listFunctions(array $args = []) (supported in versions 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise listFunctionsAsync(array $args = []) (supported in versions 2020-05-31)
+ * @method \Aws\Result listInvalidationsForDistributionTenant(array $args = []) (supported in versions 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise listInvalidationsForDistributionTenantAsync(array $args = []) (supported in versions 2020-05-31)
+ * @method \Aws\Result listKeyGroups(array $args = []) (supported in versions 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise listKeyGroupsAsync(array $args = []) (supported in versions 2020-05-31)
+ * @method \Aws\Result listKeyValueStores(array $args = []) (supported in versions 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise listKeyValueStoresAsync(array $args = []) (supported in versions 2020-05-31)
+ * @method \Aws\Result listOriginAccessControls(array $args = []) (supported in versions 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise listOriginAccessControlsAsync(array $args = []) (supported in versions 2020-05-31)
+ * @method \Aws\Result listOriginRequestPolicies(array $args = []) (supported in versions 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise listOriginRequestPoliciesAsync(array $args = []) (supported in versions 2020-05-31)
+ * @method \Aws\Result listRealtimeLogConfigs(array $args = []) (supported in versions 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise listRealtimeLogConfigsAsync(array $args = []) (supported in versions 2020-05-31)
+ * @method \Aws\Result listResponseHeadersPolicies(array $args = []) (supported in versions 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise listResponseHeadersPoliciesAsync(array $args = []) (supported in versions 2020-05-31)
+ * @method \Aws\Result listTrustStores(array $args = []) (supported in versions 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise listTrustStoresAsync(array $args = []) (supported in versions 2020-05-31)
+ * @method \Aws\Result listVpcOrigins(array $args = []) (supported in versions 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise listVpcOriginsAsync(array $args = []) (supported in versions 2020-05-31)
+ * @method \Aws\Result publishConnectionFunction(array $args = []) (supported in versions 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise publishConnectionFunctionAsync(array $args = []) (supported in versions 2020-05-31)
+ * @method \Aws\Result publishFunction(array $args = []) (supported in versions 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise publishFunctionAsync(array $args = []) (supported in versions 2020-05-31)
+ * @method \Aws\Result putResourcePolicy(array $args = []) (supported in versions 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise putResourcePolicyAsync(array $args = []) (supported in versions 2020-05-31)
+ * @method \Aws\Result testConnectionFunction(array $args = []) (supported in versions 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise testConnectionFunctionAsync(array $args = []) (supported in versions 2020-05-31)
+ * @method \Aws\Result testFunction(array $args = []) (supported in versions 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise testFunctionAsync(array $args = []) (supported in versions 2020-05-31)
+ * @method \Aws\Result updateAnycastIpList(array $args = []) (supported in versions 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise updateAnycastIpListAsync(array $args = []) (supported in versions 2020-05-31)
+ * @method \Aws\Result updateCachePolicy(array $args = []) (supported in versions 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise updateCachePolicyAsync(array $args = []) (supported in versions 2020-05-31)
+ * @method \Aws\Result updateConnectionFunction(array $args = []) (supported in versions 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise updateConnectionFunctionAsync(array $args = []) (supported in versions 2020-05-31)
+ * @method \Aws\Result updateConnectionGroup(array $args = []) (supported in versions 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise updateConnectionGroupAsync(array $args = []) (supported in versions 2020-05-31)
+ * @method \Aws\Result updateContinuousDeploymentPolicy(array $args = []) (supported in versions 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise updateContinuousDeploymentPolicyAsync(array $args = []) (supported in versions 2020-05-31)
+ * @method \Aws\Result updateDistributionTenant(array $args = []) (supported in versions 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise updateDistributionTenantAsync(array $args = []) (supported in versions 2020-05-31)
+ * @method \Aws\Result updateDistributionWithStagingConfig(array $args = []) (supported in versions 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise updateDistributionWithStagingConfigAsync(array $args = []) (supported in versions 2020-05-31)
+ * @method \Aws\Result updateDomainAssociation(array $args = []) (supported in versions 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise updateDomainAssociationAsync(array $args = []) (supported in versions 2020-05-31)
+ * @method \Aws\Result updateFunction(array $args = []) (supported in versions 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise updateFunctionAsync(array $args = []) (supported in versions 2020-05-31)
+ * @method \Aws\Result updateKeyGroup(array $args = []) (supported in versions 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise updateKeyGroupAsync(array $args = []) (supported in versions 2020-05-31)
+ * @method \Aws\Result updateKeyValueStore(array $args = []) (supported in versions 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise updateKeyValueStoreAsync(array $args = []) (supported in versions 2020-05-31)
+ * @method \Aws\Result updateOriginAccessControl(array $args = []) (supported in versions 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise updateOriginAccessControlAsync(array $args = []) (supported in versions 2020-05-31)
+ * @method \Aws\Result updateOriginRequestPolicy(array $args = []) (supported in versions 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise updateOriginRequestPolicyAsync(array $args = []) (supported in versions 2020-05-31)
+ * @method \Aws\Result updateRealtimeLogConfig(array $args = []) (supported in versions 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise updateRealtimeLogConfigAsync(array $args = []) (supported in versions 2020-05-31)
+ * @method \Aws\Result updateResponseHeadersPolicy(array $args = []) (supported in versions 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise updateResponseHeadersPolicyAsync(array $args = []) (supported in versions 2020-05-31)
+ * @method \Aws\Result updateTrustStore(array $args = []) (supported in versions 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise updateTrustStoreAsync(array $args = []) (supported in versions 2020-05-31)
+ * @method \Aws\Result updateVpcOrigin(array $args = []) (supported in versions 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise updateVpcOriginAsync(array $args = []) (supported in versions 2020-05-31)
+ * @method \Aws\Result verifyDnsConfiguration(array $args = []) (supported in versions 2020-05-31)
+ * @method \GuzzleHttp\Promise\Promise verifyDnsConfigurationAsync(array $args = []) (supported in versions 2020-05-31)
+ */
+class CloudFrontClient extends AwsClient
+{
+    /**
+     * Create a signed Amazon CloudFront URL.
+     *
+     * This method accepts an array of configuration options:
+     *
+     * - url: (string)  URL of the resource being signed (can include query
+     *   string and wildcards). For example: rtmp://s5c39gqb8ow64r.cloudfront.net/videos/mp3_name.mp3
+     *   http://d111111abcdef8.cloudfront.net/images/horizon.jpg?size=large&license=yes
+     * - policy: (string) JSON policy. Use this option when creating a signed
+     *   URL for a custom policy.
+     * - expires: (int) UTC Unix timestamp used when signing with a canned
+     *   policy. Not required when passing a custom 'policy' option.
+     * - key_pair_id: (string) The ID of the key pair used to sign CloudFront
+     *   URLs for private distributions.
+     * - private_key: (string) The filepath to the private key used to sign
+     *   CloudFront URLs for private distributions.
+     * - algorithm: (int|string) Algorithm (name or openssl constant) to be used.
+     *   Defaults to SHA1. Supported algorithms are SHA1 and SHA256.
+     *
+     * @param array $options Array of configuration options used when signing
+     *
+     * @return string Signed URL with authentication parameters
+     * @throws \InvalidArgumentException if url, key_pair_id, or private_key
+     *     were not specified.
+     * @link http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/WorkingWithStreamingDistributions.html
+     */
+    public function getSignedUrl(array $options)
+    {
+        foreach (['url', 'key_pair_id', 'private_key'] as $required) {
+            if (!isset($options[$required])) {
+                throw new \InvalidArgumentException("$required is required");
+            }
+        }
+
+        $urlSigner = new UrlSigner(
+            $options['key_pair_id'],
+            $options['private_key'],
+            $options['algorithm'] ?? Signer::DEFAULT_ALGORITHM,
+        );
+
+        return $urlSigner->getSignedUrl(
+            $options['url'],
+            isset($options['expires']) ? $options['expires'] : null,
+            isset($options['policy']) ? $options['policy'] : null
+        );
+    }
+
+    /**
+     * Create a signed Amazon CloudFront cookie.
+     *
+     * This method accepts an array of configuration options:
+     *
+     * - url: (string)  URL of the resource being signed (can include query
+     *   string and wildcards). For example: http://d111111abcdef8.cloudfront.net/images/horizon.jpg?size=large&license=yes
+     * - policy: (string) JSON policy. Use this option when creating a signed
+     *   URL for a custom policy.
+     * - expires: (int) UTC Unix timestamp used when signing with a canned
+     *   policy. Not required when passing a custom 'policy' option.
+     * - key_pair_id: (string) The ID of the key pair used to sign CloudFront
+     *   URLs for private distributions.
+     * - private_key: (string) The filepath ot the private key used to sign
+     *   CloudFront URLs for private distributions.
+     * - algorithm: (int|string) OpenSSL signature algorithm constant (e.g.
+     *   OPENSSL_ALGO_SHA1, OPENSSL_ALGO_SHA256) or algorithm name string
+     *   (e.g. "sha256"). Defaults to OPENSSL_ALGO_SHA1.
+     *
+     * @param array $options Array of configuration options used when signing
+     *
+     * @return array Key => value pairs of signed cookies to set
+     * @throws \InvalidArgumentException if url, key_pair_id, or private_key
+     *     were not specified.
+     * @link http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/WorkingWithStreamingDistributions.html
+     */
+    public function getSignedCookie(array $options)
+    {
+        foreach (['key_pair_id', 'private_key'] as $required) {
+            if (!isset($options[$required])) {
+                throw new \InvalidArgumentException("$required is required");
+            }
+        }
+
+        $cookieSigner = new CookieSigner(
+            $options['key_pair_id'],
+            $options['private_key'],
+            $options['algorithm'] ?? Signer::DEFAULT_ALGORITHM,
+        );
+
+        return $cookieSigner->getSignedCookie(
+            isset($options['url']) ? $options['url'] : null,
+            isset($options['expires']) ? $options['expires'] : null,
+            isset($options['policy']) ? $options['policy'] : null
+        );
+    }
+}

+ 74 - 0
upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/CloudFront/CookieSigner.php

@@ -0,0 +1,74 @@
+<?php
+namespace Aws\CloudFront;
+
+class CookieSigner
+{
+    /** @var Signer */
+    private $signer;
+
+    private static $schemes = [
+        'http' => true,
+        'https' => true,
+    ];
+
+    /**
+     * @param string     $keyPairId  ID of the key pair.
+     * @param string     $privateKey Path to the private key used for signing,
+     *                               or a PEM-encoded key string.
+     * @param int|string $algorithm  Signing hash algorithm. Accepts either an
+     *                               OpenSSL constant (OPENSSL_ALGO_SHA1,
+     *                               OPENSSL_ALGO_SHA256) or the canonical name
+     *                               string ("SHA1", "SHA256"). Defaults to SHA1.
+     *
+     * @throws \RuntimeException if the openssl extension is missing.
+     * @throws \InvalidArgumentException if the private key cannot be found,
+     *                                   the key type is not supported by
+     *                                   CloudFront (RSA or ECDSA P-256), or
+     *                                   the requested algorithm is not supported.
+     */
+    public function __construct($keyPairId, $privateKey, $algorithm = Signer::DEFAULT_ALGORITHM)
+    {
+        $this->signer = new Signer($keyPairId, $privateKey, '', $algorithm);
+    }
+
+
+    /**
+     * Create a signed Amazon CloudFront Cookie.
+     *
+     * @param string              $url     URL to sign (can include query string
+     *                                     and wildcards). Not required
+     *                                     when passing a custom $policy.
+     * @param string|integer|null $expires UTC Unix timestamp used when signing
+     *                                     with a canned policy. Not required
+     *                                     when passing a custom $policy.
+     * @param string              $policy  JSON policy. Use this option when
+     *                                     creating a signed cookie for a custom
+     *                                     policy.
+     *
+     * @return array The authenticated cookie parameters
+     * @throws \InvalidArgumentException if the URL provided is invalid
+     * @link http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/private-content-signed-cookies.html
+     */
+    public function getSignedCookie($url = null, $expires = null, $policy = null)
+    {
+        if ($url) {
+            $this->validateUrl($url);
+        }
+
+        $cookieParameters = [];
+        $signature = $this->signer->getSignature($url, $expires, $policy);
+        foreach ($signature as $key => $value) {
+            $cookieParameters["CloudFront-$key"] = $value;
+        }
+
+        return $cookieParameters;
+    }
+
+    private function validateUrl($url)
+    {
+        $scheme = str_replace('*', '', explode('://', $url)[0]);
+        if (empty(self::$schemes[strtolower($scheme)])) {
+            throw new \InvalidArgumentException('Invalid or missing URI scheme');
+        }
+    }
+}

+ 267 - 0
upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/CloudFront/Signer.php

@@ -0,0 +1,267 @@
+<?php
+namespace Aws\CloudFront;
+
+/**
+ * @internal
+ */
+class Signer
+{
+    private $keyPairId;
+    private $pkHandle;
+    private $algorithm;
+
+    public const DEFAULT_ALGORITHM = 'SHA1';
+
+    /**
+     * Supported signing algorithms, keyed by their canonical (normalized)
+     * name. Values are unused sentinels — presence via isset() is the check.
+     */
+    public const SUPPORTED_ALGORITHMS = [
+        'SHA1'   => true,
+        'SHA256' => true,
+    ];
+
+    /**
+     * Mapping of OpenSSL algorithm integer constants to their canonical
+     * string name. Used to normalize callers who pass e.g. OPENSSL_ALGO_SHA256
+     * into the string form stored in {@see self::$algorithm}.
+     */
+    private const OPENSSL_ALGORITHM_NAMES = [
+        OPENSSL_ALGO_SHA1   => 'SHA1',
+        OPENSSL_ALGO_SHA256 => 'SHA256',
+    ];
+
+    /**
+     * A signer for creating the signature values used in CloudFront signed URLs
+     * and signed cookies.
+     *
+     * @param string     $keyPairId  ID of the key pair.
+     * @param string     $privateKey Path to the private key used for signing,
+     *                               or a PEM-encoded key string.
+     * @param string     $passphrase Passphrase to private key file, if one exists.
+     * @param int|string $algorithm  Signing hash algorithm. Accepts either an
+     *                               OpenSSL constant (OPENSSL_ALGO_SHA1,
+     *                               OPENSSL_ALGO_SHA256) or the canonical name
+     *                               string ("SHA1", "SHA256"). Defaults to SHA1.
+     *
+     * @throws \RuntimeException if the openssl extension is missing.
+     * @throws \InvalidArgumentException if the private key cannot be found,
+     *                                   the key type is not supported by
+     *                                   CloudFront (RSA or ECDSA P-256), or
+     *                                   the requested algorithm is not supported.
+     */
+    public function __construct(
+        $keyPairId,
+        $privateKey,
+        $passphrase = "",
+        string|int $algorithm = self::DEFAULT_ALGORITHM
+    ) {
+        if (!extension_loaded('openssl')) {
+            //@codeCoverageIgnoreStart
+            throw new \RuntimeException('The openssl extension is required to '
+                . 'sign CloudFront urls.');
+            //@codeCoverageIgnoreEnd
+        }
+
+        $this->keyPairId = $keyPairId;
+
+        // Normalize an OpenSSL integer constant to its canonical string form,
+        // then uppercase for consistent comparison. After this, $algorithm is
+        // always the canonical string (matching DEFAULT_ALGORITHM's storage).
+        if (is_int($algorithm) && isset(self::OPENSSL_ALGORITHM_NAMES[$algorithm])) {
+            $algorithm = self::OPENSSL_ALGORITHM_NAMES[$algorithm];
+        }
+        $algorithm = strtoupper((string) $algorithm);
+        if (!isset(self::SUPPORTED_ALGORITHMS[$algorithm])) {
+            throw new \InvalidArgumentException(
+                "Unsupported signature algorithm: {$algorithm}. Supported algorithms are: "
+                . implode(', ', array_keys(self::SUPPORTED_ALGORITHMS)) . '.'
+            );
+        }
+
+        $this->algorithm = $algorithm;
+
+        if (!$this->pkHandle = openssl_pkey_get_private($privateKey, $passphrase)) {
+            if (!file_exists($privateKey)) {
+                throw new \InvalidArgumentException("PK file not found: $privateKey");
+            }
+
+            $this->pkHandle = openssl_pkey_get_private("file://$privateKey", $passphrase);
+            if (!$this->pkHandle) {
+                $errorMessages = [];
+                while(($newMessage = openssl_error_string()) !== false){
+                    $errorMessages[] = $newMessage;
+                }
+                throw new \InvalidArgumentException(implode("\n",$errorMessages));
+            }
+        }
+
+        $this->validateKeyType($this->pkHandle);
+    }
+
+    /**
+     * Ensures the loaded key is one CloudFront can verify: RSA of any modulus
+     * size, or ECDSA on the P-256 curve (prime256v1 / secp256r1). Anything
+     * else (DSA, EdDSA, EC on a non-P-256 curve, etc.) is rejected with an
+     * actionable error message rather than surfacing as an opaque openssl_sign
+     * failure at signing time.
+     *
+     * @param \OpenSSLAsymmetricKey|resource $pkHandle
+     *
+     * @throws \InvalidArgumentException on unsupported key material.
+     */
+    private function validateKeyType($pkHandle): void
+    {
+        $details = openssl_pkey_get_details($pkHandle);
+        if ($details === false) {
+            throw new \InvalidArgumentException(
+                'Unable to read the details of the provided private key.'
+            );
+        }
+
+        $type = $details['type'] ?? null;
+        if ($type === OPENSSL_KEYTYPE_RSA) {
+            return;
+        }
+
+        if (defined('OPENSSL_KEYTYPE_EC') && $type === OPENSSL_KEYTYPE_EC) {
+            $curve = $details['ec']['curve_name'] ?? 'unknown';
+            // OpenSSL reports the P-256 curve as either "prime256v1" (its
+            // canonical name) or "secp256r1" (SEC 2 alias); accept both.
+            if ($curve === 'prime256v1' || $curve === 'secp256r1') {
+                return;
+            }
+
+            throw new \InvalidArgumentException(
+                "Unsupported CloudFront key type: ECDSA on curve '{$curve}'. "
+                . 'CloudFront requires ECDSA keys to be on the P-256 curve '
+                . '(prime256v1 / secp256r1).'
+            );
+        }
+
+        throw new \InvalidArgumentException(
+            'Unsupported CloudFront key type. CloudFront requires an RSA or '
+            . 'ECDSA P-256 (prime256v1) private key.'
+        );
+    }
+
+    /**
+     * Create the values used to construct signed URLs and cookies.
+     *
+     * @param string              $resource     The CloudFront resource to which
+     *                                          this signature will grant access.
+     *                                          Not used when a custom policy is
+     *                                          provided.
+     * @param string|integer|null $expires      UTC Unix timestamp used when
+     *                                          signing with a canned policy.
+     *                                          Not required when passing a
+     *                                          custom $policy.
+     * @param string              $policy       JSON policy. Use this option when
+     *                                          creating a signature for a custom
+     *                                          policy.
+     *
+     * @return array The values needed to construct a signed URL or cookie
+     * @throws \InvalidArgumentException  when not provided either a policy or a
+     *                                    resource and a expires
+     * @throws \RuntimeException when generated signature is empty
+     *
+     * @link http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/private-content-signed-cookies.html
+     */
+    public function getSignature($resource = null, $expires = null, $policy = null)
+    {
+        $signatureHash = [];
+        if ($policy) {
+            $policy = preg_replace('/\s/s', '', $policy);
+            self::validatePolicy($policy);
+            $signatureHash['Policy'] = $this->encode($policy);
+        } elseif ($resource && $expires) {
+            self::validateResourceUrl($resource);
+            $expires = (int) $expires; // Handle epoch passed as string
+            $policy = $this->createCannedPolicy($resource, $expires);
+            $signatureHash['Expires'] = $expires;
+        } else {
+            throw new \InvalidArgumentException('Either a policy or a resource'
+                . ' and an expiration time must be provided.');
+        }
+
+        $signatureHash['Signature'] = $this->encode($this->sign($policy));
+        $signatureHash['Key-Pair-Id'] = $this->keyPairId;
+
+        if ($this->algorithm !== self::DEFAULT_ALGORITHM) {
+            $signatureHash['Hash-Algorithm'] = $this->algorithm;
+        }
+
+        return $signatureHash;
+    }
+
+    private function createCannedPolicy($resource, $expiration)
+    {
+        return json_encode([
+            'Statement' => [
+                [
+                    'Resource' => $resource,
+                    'Condition' => [
+                        'DateLessThan' => ['AWS:EpochTime' => $expiration],
+                    ],
+                ],
+            ],
+        ], JSON_UNESCAPED_SLASHES);
+    }
+
+    private function sign($policy)
+    {
+        $signature = '';
+        
+        if(!openssl_sign($policy, $signature, $this->pkHandle, $this->algorithm)) {
+            $errorMessages = [];
+            while(($newMessage = openssl_error_string()) !== false) {
+                $errorMessages[] = $newMessage;
+            }
+            
+            $exceptionMessage = "An error has occurred when signing the policy";
+            if (count($errorMessages) > 0) {
+                $exceptionMessage = implode("\n", $errorMessages);
+            }
+
+            throw new \RuntimeException($exceptionMessage);
+        }
+
+        return $signature;
+    }
+
+    private function encode($policy)
+    {
+        return strtr(base64_encode($policy), '+=/', '-_~');
+    }
+
+    /**
+     * Validates a customer provided json document.
+     *
+     * @param string $jsonPolicy
+     *
+     * @return void
+     */
+    private static function validatePolicy(string $jsonPolicy): void
+    {
+        $policy = json_decode($jsonPolicy, true);
+        foreach ($policy['Statement'] ?? [] as $statement) {
+            if (isset($statement['Resource'])) {
+                self::validateResourceUrl($statement['Resource']);
+            }
+        }
+    }
+
+    /**
+     * @param string $url
+     *
+     * @return void
+     */
+    private static function validateResourceUrl(string $url): void
+    {
+        if (preg_match('/["\\\\\x00-\x1F]/', $url)) {
+            throw new \InvalidArgumentException(
+                'URL contains invalid characters: ", \\, or control characters'
+            );
+        }
+    }
+}

+ 128 - 0
upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/CloudFront/UrlSigner.php

@@ -0,0 +1,128 @@
+<?php
+namespace Aws\CloudFront;
+
+use GuzzleHttp\Psr7;
+use GuzzleHttp\Psr7\Uri;
+use Psr\Http\Message\UriInterface;
+
+/**
+ * Creates signed URLs for Amazon CloudFront resources.
+ */
+class UrlSigner
+{
+    private $signer;
+
+    /**
+     * @param string     $keyPairId  ID of the key pair.
+     * @param string     $privateKey Path to the private key used for signing,
+     *                               or a PEM-encoded key string.
+     * @param int|string $algorithm  Signing hash algorithm. Accepts either an
+     *                               OpenSSL constant (OPENSSL_ALGO_SHA1,
+     *                               OPENSSL_ALGO_SHA256) or the canonical name
+     *                               string ("SHA1", "SHA256"). Defaults to SHA1.
+     *
+     * @throws \RuntimeException if the openssl extension is missing.
+     * @throws \InvalidArgumentException if the private key cannot be found,
+     *                                   the key type is not supported by
+     *                                   CloudFront (RSA or ECDSA P-256), or
+     *                                   the requested algorithm is not supported.
+     */
+    public function __construct($keyPairId, $privateKey, $algorithm = Signer::DEFAULT_ALGORITHM)
+    {
+        $this->signer = new Signer($keyPairId, $privateKey, '', $algorithm);
+    }
+
+
+    /**
+     * Create a signed Amazon CloudFront URL.
+     *
+     * Keep in mind that URLs meant for use in media/flash players may have
+     * different requirements for URL formats (e.g. some require that the
+     * extension be removed, some require the file name to be prefixed
+     * - mp4:<path>, some require you to add "/cfx/st" into your URL).
+     *
+     * @param string              $url     URL to sign (can include query
+     *                                     string string and wildcards)
+     * @param string|integer|null $expires UTC Unix timestamp used when signing
+     *                                     with a canned policy. Not required
+     *                                     when passing a custom $policy.
+     * @param string              $policy  JSON policy. Use this option when
+     *                                     creating a signed URL for a custom
+     *                                     policy.
+     *
+     * @return string The file URL with authentication parameters
+     * @throws \InvalidArgumentException if the URL provided is invalid
+     * @link http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/WorkingWithStreamingDistributions.html
+     */
+    public function getSignedUrl($url, $expires = null, $policy = null)
+    {
+        // Determine the scheme of the url
+        $urlSections = explode('://', $url);
+
+        if (count($urlSections) < 2) {
+            throw new \InvalidArgumentException("Invalid URL: {$url}");
+        }
+
+        // Get the real scheme by removing wildcards from the scheme
+        $scheme = str_replace('*', '', $urlSections[0]);
+        $uri = new Uri($scheme . '://' . $urlSections[1]);
+        $query = Psr7\Query::parse($uri->getQuery(), PHP_QUERY_RFC3986);
+        $signature = $this->signer->getSignature(
+            $this->createResource($scheme, (string) $uri),
+            $expires,
+            $policy
+        );
+        $uri = $uri->withQuery(
+            http_build_query($query + $signature, '', '&', PHP_QUERY_RFC3986)
+        );
+
+        return $scheme === 'rtmp'
+            ? $this->createRtmpUrl($uri)
+            : (string) $uri;
+    }
+
+    private function createRtmpUrl(UriInterface $uri)
+    {
+        // Use a relative URL when creating Flash player URLs
+        $result = ltrim($uri->getPath(), '/');
+
+        if ($query = $uri->getQuery()) {
+            $result .= '?' . $query;
+        }
+
+        return $result;
+    }
+
+    /**
+     * @param $scheme
+     * @param $url
+     *
+     * @return string
+     */
+    private function createResource($scheme, $url)
+    {
+        switch ($scheme) {
+            case 'http':
+            case 'http*':
+            case 'https':
+                return $url;
+            case 'rtmp':
+                $parts = parse_url($url);
+                $pathParts = pathinfo($parts['path']);
+                $resource = ltrim(
+                    str_replace('\\', '/', $pathParts['dirname']) . '/' . $pathParts['basename'],
+                    '/'
+                );
+
+                // Add a query string if present.
+                if (isset($parts['query'])) {
+                    $resource .= "?{$parts['query']}";
+                }
+
+                return $resource;
+        }
+
+        throw new \InvalidArgumentException("Invalid URI scheme: {$scheme}. "
+            . "Scheme must be one of: http, https, or rtmp");
+    }
+}

+ 110 - 0
upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/CloudWatch/CloudWatchClient.php

@@ -0,0 +1,110 @@
+<?php
+namespace Aws\CloudWatch;
+
+use Aws\AwsClient;
+
+/**
+ * This client is used to interact with the **Amazon CloudWatch** service.
+ *
+ * @method \Aws\Result associateDatasetKmsKey(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise associateDatasetKmsKeyAsync(array $args = [])
+ * @method \Aws\Result deleteAlarmMuteRule(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteAlarmMuteRuleAsync(array $args = [])
+ * @method \Aws\Result deleteAlarms(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteAlarmsAsync(array $args = [])
+ * @method \Aws\Result deleteAnomalyDetector(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteAnomalyDetectorAsync(array $args = [])
+ * @method \Aws\Result deleteDashboards(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteDashboardsAsync(array $args = [])
+ * @method \Aws\Result deleteInsightRules(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteInsightRulesAsync(array $args = [])
+ * @method \Aws\Result deleteMetricStream(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteMetricStreamAsync(array $args = [])
+ * @method \Aws\Result describeAlarmContributors(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeAlarmContributorsAsync(array $args = [])
+ * @method \Aws\Result describeAlarmHistory(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeAlarmHistoryAsync(array $args = [])
+ * @method \Aws\Result describeAlarms(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeAlarmsAsync(array $args = [])
+ * @method \Aws\Result describeAlarmsForMetric(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeAlarmsForMetricAsync(array $args = [])
+ * @method \Aws\Result describeAnomalyDetectors(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeAnomalyDetectorsAsync(array $args = [])
+ * @method \Aws\Result describeInsightRules(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeInsightRulesAsync(array $args = [])
+ * @method \Aws\Result disableAlarmActions(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise disableAlarmActionsAsync(array $args = [])
+ * @method \Aws\Result disableInsightRules(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise disableInsightRulesAsync(array $args = [])
+ * @method \Aws\Result disassociateDatasetKmsKey(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise disassociateDatasetKmsKeyAsync(array $args = [])
+ * @method \Aws\Result enableAlarmActions(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise enableAlarmActionsAsync(array $args = [])
+ * @method \Aws\Result enableInsightRules(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise enableInsightRulesAsync(array $args = [])
+ * @method \Aws\Result getAlarmMuteRule(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getAlarmMuteRuleAsync(array $args = [])
+ * @method \Aws\Result getDashboard(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getDashboardAsync(array $args = [])
+ * @method \Aws\Result getDataset(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getDatasetAsync(array $args = [])
+ * @method \Aws\Result getInsightRuleReport(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getInsightRuleReportAsync(array $args = [])
+ * @method \Aws\Result getMetricData(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getMetricDataAsync(array $args = [])
+ * @method \Aws\Result getMetricStatistics(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getMetricStatisticsAsync(array $args = [])
+ * @method \Aws\Result getMetricStream(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getMetricStreamAsync(array $args = [])
+ * @method \Aws\Result getMetricWidgetImage(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getMetricWidgetImageAsync(array $args = [])
+ * @method \Aws\Result getOTelEnrichment(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getOTelEnrichmentAsync(array $args = [])
+ * @method \Aws\Result listAlarmMuteRules(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listAlarmMuteRulesAsync(array $args = [])
+ * @method \Aws\Result listDashboards(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listDashboardsAsync(array $args = [])
+ * @method \Aws\Result listManagedInsightRules(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listManagedInsightRulesAsync(array $args = [])
+ * @method \Aws\Result listMetricStreams(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listMetricStreamsAsync(array $args = [])
+ * @method \Aws\Result listMetrics(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listMetricsAsync(array $args = [])
+ * @method \Aws\Result listTagsForResource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listTagsForResourceAsync(array $args = [])
+ * @method \Aws\Result putAlarmMuteRule(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise putAlarmMuteRuleAsync(array $args = [])
+ * @method \Aws\Result putAnomalyDetector(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise putAnomalyDetectorAsync(array $args = [])
+ * @method \Aws\Result putCompositeAlarm(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise putCompositeAlarmAsync(array $args = [])
+ * @method \Aws\Result putDashboard(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise putDashboardAsync(array $args = [])
+ * @method \Aws\Result putInsightRule(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise putInsightRuleAsync(array $args = [])
+ * @method \Aws\Result putLogAlarm(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise putLogAlarmAsync(array $args = [])
+ * @method \Aws\Result putManagedInsightRules(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise putManagedInsightRulesAsync(array $args = [])
+ * @method \Aws\Result putMetricAlarm(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise putMetricAlarmAsync(array $args = [])
+ * @method \Aws\Result putMetricData(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise putMetricDataAsync(array $args = [])
+ * @method \Aws\Result putMetricStream(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise putMetricStreamAsync(array $args = [])
+ * @method \Aws\Result setAlarmState(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise setAlarmStateAsync(array $args = [])
+ * @method \Aws\Result startMetricStreams(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise startMetricStreamsAsync(array $args = [])
+ * @method \Aws\Result startOTelEnrichment(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise startOTelEnrichmentAsync(array $args = [])
+ * @method \Aws\Result stopMetricStreams(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise stopMetricStreamsAsync(array $args = [])
+ * @method \Aws\Result stopOTelEnrichment(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise stopOTelEnrichmentAsync(array $args = [])
+ * @method \Aws\Result tagResource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise tagResourceAsync(array $args = [])
+ * @method \Aws\Result untagResource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise untagResourceAsync(array $args = [])
+ */
+class CloudWatchClient extends AwsClient {}

+ 277 - 0
upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/CloudWatchLogs/CloudWatchLogsClient.php

@@ -0,0 +1,277 @@
+<?php
+namespace Aws\CloudWatchLogs;
+
+use Aws\AwsClient;
+use Aws\CommandInterface;
+use Generator;
+
+/**
+ * This client is used to interact with the **Amazon CloudWatch Logs** service.
+ *
+ * @method \Aws\Result associateKmsKey(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise associateKmsKeyAsync(array $args = [])
+ * @method \Aws\Result associateSourceToS3TableIntegration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise associateSourceToS3TableIntegrationAsync(array $args = [])
+ * @method \Aws\Result cancelExportTask(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise cancelExportTaskAsync(array $args = [])
+ * @method \Aws\Result cancelImportTask(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise cancelImportTaskAsync(array $args = [])
+ * @method \Aws\Result createDelivery(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createDeliveryAsync(array $args = [])
+ * @method \Aws\Result createExportTask(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createExportTaskAsync(array $args = [])
+ * @method \Aws\Result createImportTask(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createImportTaskAsync(array $args = [])
+ * @method \Aws\Result createLogAnomalyDetector(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createLogAnomalyDetectorAsync(array $args = [])
+ * @method \Aws\Result createLogGroup(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createLogGroupAsync(array $args = [])
+ * @method \Aws\Result createLogStream(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createLogStreamAsync(array $args = [])
+ * @method \Aws\Result createLookupTable(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createLookupTableAsync(array $args = [])
+ * @method \Aws\Result createScheduledQuery(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createScheduledQueryAsync(array $args = [])
+ * @method \Aws\Result deleteAccountPolicy(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteAccountPolicyAsync(array $args = [])
+ * @method \Aws\Result deleteDataProtectionPolicy(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteDataProtectionPolicyAsync(array $args = [])
+ * @method \Aws\Result deleteDelivery(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteDeliveryAsync(array $args = [])
+ * @method \Aws\Result deleteDeliveryDestination(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteDeliveryDestinationAsync(array $args = [])
+ * @method \Aws\Result deleteDeliveryDestinationPolicy(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteDeliveryDestinationPolicyAsync(array $args = [])
+ * @method \Aws\Result deleteDeliverySource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteDeliverySourceAsync(array $args = [])
+ * @method \Aws\Result deleteDestination(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteDestinationAsync(array $args = [])
+ * @method \Aws\Result deleteIndexPolicy(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteIndexPolicyAsync(array $args = [])
+ * @method \Aws\Result deleteIntegration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteIntegrationAsync(array $args = [])
+ * @method \Aws\Result deleteLogAnomalyDetector(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteLogAnomalyDetectorAsync(array $args = [])
+ * @method \Aws\Result deleteLogGroup(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteLogGroupAsync(array $args = [])
+ * @method \Aws\Result deleteLogStream(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteLogStreamAsync(array $args = [])
+ * @method \Aws\Result deleteLookupTable(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteLookupTableAsync(array $args = [])
+ * @method \Aws\Result deleteMetricFilter(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteMetricFilterAsync(array $args = [])
+ * @method \Aws\Result deleteQueryDefinition(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteQueryDefinitionAsync(array $args = [])
+ * @method \Aws\Result deleteResourcePolicy(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteResourcePolicyAsync(array $args = [])
+ * @method \Aws\Result deleteRetentionPolicy(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteRetentionPolicyAsync(array $args = [])
+ * @method \Aws\Result deleteScheduledQuery(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteScheduledQueryAsync(array $args = [])
+ * @method \Aws\Result deleteSubscriptionFilter(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteSubscriptionFilterAsync(array $args = [])
+ * @method \Aws\Result deleteSyslogConfiguration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteSyslogConfigurationAsync(array $args = [])
+ * @method \Aws\Result deleteTransformer(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteTransformerAsync(array $args = [])
+ * @method \Aws\Result describeAccountPolicies(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeAccountPoliciesAsync(array $args = [])
+ * @method \Aws\Result describeConfigurationTemplates(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeConfigurationTemplatesAsync(array $args = [])
+ * @method \Aws\Result describeDeliveries(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeDeliveriesAsync(array $args = [])
+ * @method \Aws\Result describeDeliveryDestinations(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeDeliveryDestinationsAsync(array $args = [])
+ * @method \Aws\Result describeDeliverySources(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeDeliverySourcesAsync(array $args = [])
+ * @method \Aws\Result describeDestinations(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeDestinationsAsync(array $args = [])
+ * @method \Aws\Result describeExportTasks(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeExportTasksAsync(array $args = [])
+ * @method \Aws\Result describeFieldIndexes(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeFieldIndexesAsync(array $args = [])
+ * @method \Aws\Result describeImportTaskBatches(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeImportTaskBatchesAsync(array $args = [])
+ * @method \Aws\Result describeImportTasks(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeImportTasksAsync(array $args = [])
+ * @method \Aws\Result describeIndexPolicies(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeIndexPoliciesAsync(array $args = [])
+ * @method \Aws\Result describeLogGroups(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeLogGroupsAsync(array $args = [])
+ * @method \Aws\Result describeLogStreams(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeLogStreamsAsync(array $args = [])
+ * @method \Aws\Result describeLookupTables(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeLookupTablesAsync(array $args = [])
+ * @method \Aws\Result describeMetricFilters(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeMetricFiltersAsync(array $args = [])
+ * @method \Aws\Result describeQueries(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeQueriesAsync(array $args = [])
+ * @method \Aws\Result describeQueryDefinitions(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeQueryDefinitionsAsync(array $args = [])
+ * @method \Aws\Result describeResourcePolicies(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeResourcePoliciesAsync(array $args = [])
+ * @method \Aws\Result describeSubscriptionFilters(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeSubscriptionFiltersAsync(array $args = [])
+ * @method \Aws\Result disassociateKmsKey(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise disassociateKmsKeyAsync(array $args = [])
+ * @method \Aws\Result disassociateSourceFromS3TableIntegration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise disassociateSourceFromS3TableIntegrationAsync(array $args = [])
+ * @method \Aws\Result filterLogEvents(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise filterLogEventsAsync(array $args = [])
+ * @method \Aws\Result getDataProtectionPolicy(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getDataProtectionPolicyAsync(array $args = [])
+ * @method \Aws\Result getDelivery(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getDeliveryAsync(array $args = [])
+ * @method \Aws\Result getDeliveryDestination(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getDeliveryDestinationAsync(array $args = [])
+ * @method \Aws\Result getDeliveryDestinationPolicy(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getDeliveryDestinationPolicyAsync(array $args = [])
+ * @method \Aws\Result getDeliverySource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getDeliverySourceAsync(array $args = [])
+ * @method \Aws\Result getIntegration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getIntegrationAsync(array $args = [])
+ * @method \Aws\Result getLogAnomalyDetector(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getLogAnomalyDetectorAsync(array $args = [])
+ * @method \Aws\Result getLogEvents(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getLogEventsAsync(array $args = [])
+ * @method \Aws\Result getLogFields(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getLogFieldsAsync(array $args = [])
+ * @method \Aws\Result getLogGroupFields(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getLogGroupFieldsAsync(array $args = [])
+ * @method \Aws\Result getLogObject(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getLogObjectAsync(array $args = [])
+ * @method \Aws\Result getLogRecord(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getLogRecordAsync(array $args = [])
+ * @method \Aws\Result getLookupTable(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getLookupTableAsync(array $args = [])
+ * @method \Aws\Result getQueryResults(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getQueryResultsAsync(array $args = [])
+ * @method \Aws\Result getScheduledQuery(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getScheduledQueryAsync(array $args = [])
+ * @method \Aws\Result getScheduledQueryHistory(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getScheduledQueryHistoryAsync(array $args = [])
+ * @method \Aws\Result getStorageTierPolicy(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getStorageTierPolicyAsync(array $args = [])
+ * @method \Aws\Result getTransformer(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getTransformerAsync(array $args = [])
+ * @method \Aws\Result listAggregateLogGroupSummaries(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listAggregateLogGroupSummariesAsync(array $args = [])
+ * @method \Aws\Result listAnomalies(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listAnomaliesAsync(array $args = [])
+ * @method \Aws\Result listIntegrations(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listIntegrationsAsync(array $args = [])
+ * @method \Aws\Result listLogAnomalyDetectors(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listLogAnomalyDetectorsAsync(array $args = [])
+ * @method \Aws\Result listLogGroups(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listLogGroupsAsync(array $args = [])
+ * @method \Aws\Result listLogGroupsForQuery(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listLogGroupsForQueryAsync(array $args = [])
+ * @method \Aws\Result listScheduledQueries(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listScheduledQueriesAsync(array $args = [])
+ * @method \Aws\Result listSourcesForS3TableIntegration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listSourcesForS3TableIntegrationAsync(array $args = [])
+ * @method \Aws\Result listSyslogConfigurations(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listSyslogConfigurationsAsync(array $args = [])
+ * @method \Aws\Result listTagsForResource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listTagsForResourceAsync(array $args = [])
+ * @method \Aws\Result listTagsLogGroup(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listTagsLogGroupAsync(array $args = [])
+ * @method \Aws\Result putAccountPolicy(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise putAccountPolicyAsync(array $args = [])
+ * @method \Aws\Result putBearerTokenAuthentication(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise putBearerTokenAuthenticationAsync(array $args = [])
+ * @method \Aws\Result putDataProtectionPolicy(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise putDataProtectionPolicyAsync(array $args = [])
+ * @method \Aws\Result putDeliveryDestination(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise putDeliveryDestinationAsync(array $args = [])
+ * @method \Aws\Result putDeliveryDestinationPolicy(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise putDeliveryDestinationPolicyAsync(array $args = [])
+ * @method \Aws\Result putDeliverySource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise putDeliverySourceAsync(array $args = [])
+ * @method \Aws\Result putDestination(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise putDestinationAsync(array $args = [])
+ * @method \Aws\Result putDestinationPolicy(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise putDestinationPolicyAsync(array $args = [])
+ * @method \Aws\Result putIndexPolicy(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise putIndexPolicyAsync(array $args = [])
+ * @method \Aws\Result putIntegration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise putIntegrationAsync(array $args = [])
+ * @method \Aws\Result putLogEvents(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise putLogEventsAsync(array $args = [])
+ * @method \Aws\Result putLogGroupDeletionProtection(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise putLogGroupDeletionProtectionAsync(array $args = [])
+ * @method \Aws\Result putMetricFilter(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise putMetricFilterAsync(array $args = [])
+ * @method \Aws\Result putQueryDefinition(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise putQueryDefinitionAsync(array $args = [])
+ * @method \Aws\Result putResourcePolicy(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise putResourcePolicyAsync(array $args = [])
+ * @method \Aws\Result putRetentionPolicy(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise putRetentionPolicyAsync(array $args = [])
+ * @method \Aws\Result putStorageTierPolicy(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise putStorageTierPolicyAsync(array $args = [])
+ * @method \Aws\Result putSubscriptionFilter(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise putSubscriptionFilterAsync(array $args = [])
+ * @method \Aws\Result putSyslogConfiguration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise putSyslogConfigurationAsync(array $args = [])
+ * @method \Aws\Result putTransformer(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise putTransformerAsync(array $args = [])
+ * @method \Aws\Result startLiveTail(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise startLiveTailAsync(array $args = [])
+ * @method \Aws\Result startQuery(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise startQueryAsync(array $args = [])
+ * @method \Aws\Result stopQuery(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise stopQueryAsync(array $args = [])
+ * @method \Aws\Result tagLogGroup(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise tagLogGroupAsync(array $args = [])
+ * @method \Aws\Result tagResource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise tagResourceAsync(array $args = [])
+ * @method \Aws\Result testMetricFilter(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise testMetricFilterAsync(array $args = [])
+ * @method \Aws\Result testTransformer(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise testTransformerAsync(array $args = [])
+ * @method \Aws\Result untagLogGroup(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise untagLogGroupAsync(array $args = [])
+ * @method \Aws\Result untagResource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise untagResourceAsync(array $args = [])
+ * @method \Aws\Result updateAnomaly(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateAnomalyAsync(array $args = [])
+ * @method \Aws\Result updateDeliveryConfiguration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateDeliveryConfigurationAsync(array $args = [])
+ * @method \Aws\Result updateLogAnomalyDetector(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateLogAnomalyDetectorAsync(array $args = [])
+ * @method \Aws\Result updateLookupTable(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateLookupTableAsync(array $args = [])
+ * @method \Aws\Result updateScheduledQuery(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateScheduledQueryAsync(array $args = [])
+ */
+class CloudWatchLogsClient extends AwsClient {
+
+    /**
+     * Helper method for 'startLiveTail' operation that checks for results.
+     *
+     * Initiates 'startLiveTail' operation with given arguments, and continuously
+     * checks response stream for session updates or results, yielding each
+     * stream chunk when results are not empty. This method abstracts from users
+     * the need of checking if there are logs entry available to be watched, which means
+     * that users will always get a next item to be iterated when more log entries are
+     * available.
+     *
+     * @param array $args Command arguments.
+     *
+     * @return Generator Yields session update or result stream chunks.
+     */
+    public function startLiveTailCheckingForResults(array $args): Generator
+    {
+        $response = $this->startLiveTail($args);
+        foreach ($response['responseStream'] as $streamChunk) {
+            if (isset($streamChunk['sessionUpdate'])) {
+                if (!empty($streamChunk['sessionUpdate']['sessionResults'])) {
+                    yield $streamChunk;
+                }
+            } else {
+                yield $streamChunk;
+            }
+        }
+    }
+}

+ 266 - 0
upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/CognitoIdentityProvider/CognitoIdentityProviderClient.php

@@ -0,0 +1,266 @@
+<?php
+namespace Aws\CognitoIdentityProvider;
+
+use Aws\AwsClient;
+
+/**
+ * This client is used to interact with the **Amazon Cognito Identity Provider** service.
+ * 
+ * @method \Aws\Result addCustomAttributes(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise addCustomAttributesAsync(array $args = [])
+ * @method \Aws\Result addUserPoolClientSecret(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise addUserPoolClientSecretAsync(array $args = [])
+ * @method \Aws\Result adminAddUserToGroup(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise adminAddUserToGroupAsync(array $args = [])
+ * @method \Aws\Result adminConfirmSignUp(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise adminConfirmSignUpAsync(array $args = [])
+ * @method \Aws\Result adminCreateUser(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise adminCreateUserAsync(array $args = [])
+ * @method \Aws\Result adminDeleteUser(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise adminDeleteUserAsync(array $args = [])
+ * @method \Aws\Result adminDeleteUserAttributes(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise adminDeleteUserAttributesAsync(array $args = [])
+ * @method \Aws\Result adminDisableProviderForUser(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise adminDisableProviderForUserAsync(array $args = [])
+ * @method \Aws\Result adminDisableUser(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise adminDisableUserAsync(array $args = [])
+ * @method \Aws\Result adminEnableUser(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise adminEnableUserAsync(array $args = [])
+ * @method \Aws\Result adminForgetDevice(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise adminForgetDeviceAsync(array $args = [])
+ * @method \Aws\Result adminGetDevice(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise adminGetDeviceAsync(array $args = [])
+ * @method \Aws\Result adminGetUser(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise adminGetUserAsync(array $args = [])
+ * @method \Aws\Result adminInitiateAuth(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise adminInitiateAuthAsync(array $args = [])
+ * @method \Aws\Result adminLinkProviderForUser(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise adminLinkProviderForUserAsync(array $args = [])
+ * @method \Aws\Result adminListDevices(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise adminListDevicesAsync(array $args = [])
+ * @method \Aws\Result adminListGroupsForUser(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise adminListGroupsForUserAsync(array $args = [])
+ * @method \Aws\Result adminListUserAuthEvents(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise adminListUserAuthEventsAsync(array $args = [])
+ * @method \Aws\Result adminRemoveUserFromGroup(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise adminRemoveUserFromGroupAsync(array $args = [])
+ * @method \Aws\Result adminResetUserPassword(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise adminResetUserPasswordAsync(array $args = [])
+ * @method \Aws\Result adminRespondToAuthChallenge(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise adminRespondToAuthChallengeAsync(array $args = [])
+ * @method \Aws\Result adminSetUserMFAPreference(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise adminSetUserMFAPreferenceAsync(array $args = [])
+ * @method \Aws\Result adminSetUserPassword(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise adminSetUserPasswordAsync(array $args = [])
+ * @method \Aws\Result adminSetUserSettings(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise adminSetUserSettingsAsync(array $args = [])
+ * @method \Aws\Result adminUpdateAuthEventFeedback(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise adminUpdateAuthEventFeedbackAsync(array $args = [])
+ * @method \Aws\Result adminUpdateDeviceStatus(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise adminUpdateDeviceStatusAsync(array $args = [])
+ * @method \Aws\Result adminUpdateUserAttributes(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise adminUpdateUserAttributesAsync(array $args = [])
+ * @method \Aws\Result adminUserGlobalSignOut(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise adminUserGlobalSignOutAsync(array $args = [])
+ * @method \Aws\Result associateSoftwareToken(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise associateSoftwareTokenAsync(array $args = [])
+ * @method \Aws\Result changePassword(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise changePasswordAsync(array $args = [])
+ * @method \Aws\Result completeWebAuthnRegistration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise completeWebAuthnRegistrationAsync(array $args = [])
+ * @method \Aws\Result confirmDevice(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise confirmDeviceAsync(array $args = [])
+ * @method \Aws\Result confirmForgotPassword(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise confirmForgotPasswordAsync(array $args = [])
+ * @method \Aws\Result confirmSignUp(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise confirmSignUpAsync(array $args = [])
+ * @method \Aws\Result createGroup(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createGroupAsync(array $args = [])
+ * @method \Aws\Result createIdentityProvider(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createIdentityProviderAsync(array $args = [])
+ * @method \Aws\Result createManagedLoginBranding(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createManagedLoginBrandingAsync(array $args = [])
+ * @method \Aws\Result createResourceServer(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createResourceServerAsync(array $args = [])
+ * @method \Aws\Result createTerms(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createTermsAsync(array $args = [])
+ * @method \Aws\Result createUserImportJob(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createUserImportJobAsync(array $args = [])
+ * @method \Aws\Result createUserPool(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createUserPoolAsync(array $args = [])
+ * @method \Aws\Result createUserPoolClient(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createUserPoolClientAsync(array $args = [])
+ * @method \Aws\Result createUserPoolDomain(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createUserPoolDomainAsync(array $args = [])
+ * @method \Aws\Result createUserPoolReplica(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createUserPoolReplicaAsync(array $args = [])
+ * @method \Aws\Result deleteGroup(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteGroupAsync(array $args = [])
+ * @method \Aws\Result deleteIdentityProvider(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteIdentityProviderAsync(array $args = [])
+ * @method \Aws\Result deleteManagedLoginBranding(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteManagedLoginBrandingAsync(array $args = [])
+ * @method \Aws\Result deleteResourceServer(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteResourceServerAsync(array $args = [])
+ * @method \Aws\Result deleteTerms(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteTermsAsync(array $args = [])
+ * @method \Aws\Result deleteUser(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteUserAsync(array $args = [])
+ * @method \Aws\Result deleteUserAttributes(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteUserAttributesAsync(array $args = [])
+ * @method \Aws\Result deleteUserPool(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteUserPoolAsync(array $args = [])
+ * @method \Aws\Result deleteUserPoolClient(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteUserPoolClientAsync(array $args = [])
+ * @method \Aws\Result deleteUserPoolClientSecret(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteUserPoolClientSecretAsync(array $args = [])
+ * @method \Aws\Result deleteUserPoolDomain(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteUserPoolDomainAsync(array $args = [])
+ * @method \Aws\Result deleteUserPoolReplica(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteUserPoolReplicaAsync(array $args = [])
+ * @method \Aws\Result deleteWebAuthnCredential(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteWebAuthnCredentialAsync(array $args = [])
+ * @method \Aws\Result describeIdentityProvider(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeIdentityProviderAsync(array $args = [])
+ * @method \Aws\Result describeManagedLoginBranding(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeManagedLoginBrandingAsync(array $args = [])
+ * @method \Aws\Result describeManagedLoginBrandingByClient(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeManagedLoginBrandingByClientAsync(array $args = [])
+ * @method \Aws\Result describeResourceServer(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeResourceServerAsync(array $args = [])
+ * @method \Aws\Result describeRiskConfiguration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeRiskConfigurationAsync(array $args = [])
+ * @method \Aws\Result describeTerms(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeTermsAsync(array $args = [])
+ * @method \Aws\Result describeUserImportJob(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeUserImportJobAsync(array $args = [])
+ * @method \Aws\Result describeUserPool(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeUserPoolAsync(array $args = [])
+ * @method \Aws\Result describeUserPoolClient(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeUserPoolClientAsync(array $args = [])
+ * @method \Aws\Result describeUserPoolDomain(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeUserPoolDomainAsync(array $args = [])
+ * @method \Aws\Result forgetDevice(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise forgetDeviceAsync(array $args = [])
+ * @method \Aws\Result forgotPassword(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise forgotPasswordAsync(array $args = [])
+ * @method \Aws\Result getCSVHeader(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getCSVHeaderAsync(array $args = [])
+ * @method \Aws\Result getDevice(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getDeviceAsync(array $args = [])
+ * @method \Aws\Result getGroup(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getGroupAsync(array $args = [])
+ * @method \Aws\Result getIdentityProviderByIdentifier(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getIdentityProviderByIdentifierAsync(array $args = [])
+ * @method \Aws\Result getLogDeliveryConfiguration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getLogDeliveryConfigurationAsync(array $args = [])
+ * @method \Aws\Result getProvisionedLimit(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getProvisionedLimitAsync(array $args = [])
+ * @method \Aws\Result getSigningCertificate(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getSigningCertificateAsync(array $args = [])
+ * @method \Aws\Result getTokensFromRefreshToken(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getTokensFromRefreshTokenAsync(array $args = [])
+ * @method \Aws\Result getUICustomization(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getUICustomizationAsync(array $args = [])
+ * @method \Aws\Result getUser(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getUserAsync(array $args = [])
+ * @method \Aws\Result getUserAttributeVerificationCode(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getUserAttributeVerificationCodeAsync(array $args = [])
+ * @method \Aws\Result getUserAuthFactors(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getUserAuthFactorsAsync(array $args = [])
+ * @method \Aws\Result getUserPoolMfaConfig(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getUserPoolMfaConfigAsync(array $args = [])
+ * @method \Aws\Result globalSignOut(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise globalSignOutAsync(array $args = [])
+ * @method \Aws\Result initiateAuth(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise initiateAuthAsync(array $args = [])
+ * @method \Aws\Result listDevices(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listDevicesAsync(array $args = [])
+ * @method \Aws\Result listGroups(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listGroupsAsync(array $args = [])
+ * @method \Aws\Result listIdentityProviders(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listIdentityProvidersAsync(array $args = [])
+ * @method \Aws\Result listResourceServers(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listResourceServersAsync(array $args = [])
+ * @method \Aws\Result listTagsForResource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listTagsForResourceAsync(array $args = [])
+ * @method \Aws\Result listTerms(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listTermsAsync(array $args = [])
+ * @method \Aws\Result listUserImportJobs(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listUserImportJobsAsync(array $args = [])
+ * @method \Aws\Result listUserPoolClientSecrets(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listUserPoolClientSecretsAsync(array $args = [])
+ * @method \Aws\Result listUserPoolClients(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listUserPoolClientsAsync(array $args = [])
+ * @method \Aws\Result listUserPoolReplicas(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listUserPoolReplicasAsync(array $args = [])
+ * @method \Aws\Result listUserPools(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listUserPoolsAsync(array $args = [])
+ * @method \Aws\Result listUsers(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listUsersAsync(array $args = [])
+ * @method \Aws\Result listUsersInGroup(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listUsersInGroupAsync(array $args = [])
+ * @method \Aws\Result listWebAuthnCredentials(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listWebAuthnCredentialsAsync(array $args = [])
+ * @method \Aws\Result resendConfirmationCode(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise resendConfirmationCodeAsync(array $args = [])
+ * @method \Aws\Result respondToAuthChallenge(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise respondToAuthChallengeAsync(array $args = [])
+ * @method \Aws\Result revokeToken(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise revokeTokenAsync(array $args = [])
+ * @method \Aws\Result setLogDeliveryConfiguration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise setLogDeliveryConfigurationAsync(array $args = [])
+ * @method \Aws\Result setRiskConfiguration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise setRiskConfigurationAsync(array $args = [])
+ * @method \Aws\Result setUICustomization(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise setUICustomizationAsync(array $args = [])
+ * @method \Aws\Result setUserMFAPreference(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise setUserMFAPreferenceAsync(array $args = [])
+ * @method \Aws\Result setUserPoolMfaConfig(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise setUserPoolMfaConfigAsync(array $args = [])
+ * @method \Aws\Result setUserSettings(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise setUserSettingsAsync(array $args = [])
+ * @method \Aws\Result signUp(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise signUpAsync(array $args = [])
+ * @method \Aws\Result startUserImportJob(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise startUserImportJobAsync(array $args = [])
+ * @method \Aws\Result startWebAuthnRegistration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise startWebAuthnRegistrationAsync(array $args = [])
+ * @method \Aws\Result stopUserImportJob(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise stopUserImportJobAsync(array $args = [])
+ * @method \Aws\Result tagResource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise tagResourceAsync(array $args = [])
+ * @method \Aws\Result untagResource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise untagResourceAsync(array $args = [])
+ * @method \Aws\Result updateAuthEventFeedback(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateAuthEventFeedbackAsync(array $args = [])
+ * @method \Aws\Result updateDeviceStatus(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateDeviceStatusAsync(array $args = [])
+ * @method \Aws\Result updateGroup(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateGroupAsync(array $args = [])
+ * @method \Aws\Result updateIdentityProvider(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateIdentityProviderAsync(array $args = [])
+ * @method \Aws\Result updateManagedLoginBranding(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateManagedLoginBrandingAsync(array $args = [])
+ * @method \Aws\Result updateProvisionedLimit(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateProvisionedLimitAsync(array $args = [])
+ * @method \Aws\Result updateResourceServer(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateResourceServerAsync(array $args = [])
+ * @method \Aws\Result updateTerms(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateTermsAsync(array $args = [])
+ * @method \Aws\Result updateUserAttributes(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateUserAttributesAsync(array $args = [])
+ * @method \Aws\Result updateUserPool(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateUserPoolAsync(array $args = [])
+ * @method \Aws\Result updateUserPoolClient(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateUserPoolClientAsync(array $args = [])
+ * @method \Aws\Result updateUserPoolDomain(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateUserPoolDomainAsync(array $args = [])
+ * @method \Aws\Result updateUserPoolReplica(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateUserPoolReplicaAsync(array $args = [])
+ * @method \Aws\Result verifySoftwareToken(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise verifySoftwareTokenAsync(array $args = [])
+ * @method \Aws\Result verifyUserAttribute(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise verifyUserAttributeAsync(array $args = [])
+ */
+class CognitoIdentityProviderClient extends AwsClient {}

+ 214 - 0
upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/ConfigService/ConfigServiceClient.php

@@ -0,0 +1,214 @@
+<?php
+namespace Aws\ConfigService;
+
+use Aws\AwsClient;
+
+/**
+ * This client is used to interact with AWS Config.
+ *
+ * @method \Aws\Result associateResourceTypes(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise associateResourceTypesAsync(array $args = [])
+ * @method \Aws\Result batchGetAggregateResourceConfig(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise batchGetAggregateResourceConfigAsync(array $args = [])
+ * @method \Aws\Result batchGetResourceConfig(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise batchGetResourceConfigAsync(array $args = [])
+ * @method \Aws\Result deleteAggregationAuthorization(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteAggregationAuthorizationAsync(array $args = [])
+ * @method \Aws\Result deleteConfigRule(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteConfigRuleAsync(array $args = [])
+ * @method \Aws\Result deleteConfigurationAggregator(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteConfigurationAggregatorAsync(array $args = [])
+ * @method \Aws\Result deleteConfigurationRecorder(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteConfigurationRecorderAsync(array $args = [])
+ * @method \Aws\Result deleteConformancePack(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteConformancePackAsync(array $args = [])
+ * @method \Aws\Result deleteConnector(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteConnectorAsync(array $args = [])
+ * @method \Aws\Result deleteDeliveryChannel(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteDeliveryChannelAsync(array $args = [])
+ * @method \Aws\Result deleteEvaluationResults(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteEvaluationResultsAsync(array $args = [])
+ * @method \Aws\Result deleteOrganizationConfigRule(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteOrganizationConfigRuleAsync(array $args = [])
+ * @method \Aws\Result deleteOrganizationConformancePack(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteOrganizationConformancePackAsync(array $args = [])
+ * @method \Aws\Result deletePendingAggregationRequest(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deletePendingAggregationRequestAsync(array $args = [])
+ * @method \Aws\Result deleteRemediationConfiguration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteRemediationConfigurationAsync(array $args = [])
+ * @method \Aws\Result deleteRemediationExceptions(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteRemediationExceptionsAsync(array $args = [])
+ * @method \Aws\Result deleteResourceConfig(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteResourceConfigAsync(array $args = [])
+ * @method \Aws\Result deleteRetentionConfiguration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteRetentionConfigurationAsync(array $args = [])
+ * @method \Aws\Result deleteServiceLinkedConfigurationRecorder(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteServiceLinkedConfigurationRecorderAsync(array $args = [])
+ * @method \Aws\Result deleteStoredQuery(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteStoredQueryAsync(array $args = [])
+ * @method \Aws\Result deliverConfigSnapshot(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deliverConfigSnapshotAsync(array $args = [])
+ * @method \Aws\Result describeAggregateComplianceByConfigRules(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeAggregateComplianceByConfigRulesAsync(array $args = [])
+ * @method \Aws\Result describeAggregateComplianceByConformancePacks(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeAggregateComplianceByConformancePacksAsync(array $args = [])
+ * @method \Aws\Result describeAggregationAuthorizations(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeAggregationAuthorizationsAsync(array $args = [])
+ * @method \Aws\Result describeComplianceByConfigRule(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeComplianceByConfigRuleAsync(array $args = [])
+ * @method \Aws\Result describeComplianceByResource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeComplianceByResourceAsync(array $args = [])
+ * @method \Aws\Result describeConfigRuleEvaluationStatus(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeConfigRuleEvaluationStatusAsync(array $args = [])
+ * @method \Aws\Result describeConfigRules(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeConfigRulesAsync(array $args = [])
+ * @method \Aws\Result describeConfigurationAggregatorSourcesStatus(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeConfigurationAggregatorSourcesStatusAsync(array $args = [])
+ * @method \Aws\Result describeConfigurationAggregators(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeConfigurationAggregatorsAsync(array $args = [])
+ * @method \Aws\Result describeConfigurationRecorderStatus(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeConfigurationRecorderStatusAsync(array $args = [])
+ * @method \Aws\Result describeConfigurationRecorders(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeConfigurationRecordersAsync(array $args = [])
+ * @method \Aws\Result describeConformancePackCompliance(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeConformancePackComplianceAsync(array $args = [])
+ * @method \Aws\Result describeConformancePackStatus(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeConformancePackStatusAsync(array $args = [])
+ * @method \Aws\Result describeConformancePacks(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeConformancePacksAsync(array $args = [])
+ * @method \Aws\Result describeDeliveryChannelStatus(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeDeliveryChannelStatusAsync(array $args = [])
+ * @method \Aws\Result describeDeliveryChannels(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeDeliveryChannelsAsync(array $args = [])
+ * @method \Aws\Result describeOrganizationConfigRuleStatuses(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeOrganizationConfigRuleStatusesAsync(array $args = [])
+ * @method \Aws\Result describeOrganizationConfigRules(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeOrganizationConfigRulesAsync(array $args = [])
+ * @method \Aws\Result describeOrganizationConformancePackStatuses(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeOrganizationConformancePackStatusesAsync(array $args = [])
+ * @method \Aws\Result describeOrganizationConformancePacks(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeOrganizationConformancePacksAsync(array $args = [])
+ * @method \Aws\Result describePendingAggregationRequests(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describePendingAggregationRequestsAsync(array $args = [])
+ * @method \Aws\Result describeRemediationConfigurations(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeRemediationConfigurationsAsync(array $args = [])
+ * @method \Aws\Result describeRemediationExceptions(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeRemediationExceptionsAsync(array $args = [])
+ * @method \Aws\Result describeRemediationExecutionStatus(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeRemediationExecutionStatusAsync(array $args = [])
+ * @method \Aws\Result describeRetentionConfigurations(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeRetentionConfigurationsAsync(array $args = [])
+ * @method \Aws\Result disassociateResourceTypes(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise disassociateResourceTypesAsync(array $args = [])
+ * @method \Aws\Result getAggregateComplianceDetailsByConfigRule(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getAggregateComplianceDetailsByConfigRuleAsync(array $args = [])
+ * @method \Aws\Result getAggregateConfigRuleComplianceSummary(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getAggregateConfigRuleComplianceSummaryAsync(array $args = [])
+ * @method \Aws\Result getAggregateConformancePackComplianceSummary(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getAggregateConformancePackComplianceSummaryAsync(array $args = [])
+ * @method \Aws\Result getAggregateDiscoveredResourceCounts(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getAggregateDiscoveredResourceCountsAsync(array $args = [])
+ * @method \Aws\Result getAggregateResourceConfig(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getAggregateResourceConfigAsync(array $args = [])
+ * @method \Aws\Result getComplianceDetailsByConfigRule(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getComplianceDetailsByConfigRuleAsync(array $args = [])
+ * @method \Aws\Result getComplianceDetailsByResource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getComplianceDetailsByResourceAsync(array $args = [])
+ * @method \Aws\Result getComplianceSummaryByConfigRule(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getComplianceSummaryByConfigRuleAsync(array $args = [])
+ * @method \Aws\Result getComplianceSummaryByResourceType(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getComplianceSummaryByResourceTypeAsync(array $args = [])
+ * @method \Aws\Result getConformancePackComplianceDetails(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getConformancePackComplianceDetailsAsync(array $args = [])
+ * @method \Aws\Result getConformancePackComplianceSummary(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getConformancePackComplianceSummaryAsync(array $args = [])
+ * @method \Aws\Result getConnector(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getConnectorAsync(array $args = [])
+ * @method \Aws\Result getCustomRulePolicy(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getCustomRulePolicyAsync(array $args = [])
+ * @method \Aws\Result getDiscoveredResourceCounts(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getDiscoveredResourceCountsAsync(array $args = [])
+ * @method \Aws\Result getOrganizationConfigRuleDetailedStatus(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getOrganizationConfigRuleDetailedStatusAsync(array $args = [])
+ * @method \Aws\Result getOrganizationConformancePackDetailedStatus(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getOrganizationConformancePackDetailedStatusAsync(array $args = [])
+ * @method \Aws\Result getOrganizationCustomRulePolicy(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getOrganizationCustomRulePolicyAsync(array $args = [])
+ * @method \Aws\Result getResourceConfigHistory(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getResourceConfigHistoryAsync(array $args = [])
+ * @method \Aws\Result getResourceEvaluationSummary(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getResourceEvaluationSummaryAsync(array $args = [])
+ * @method \Aws\Result getStoredQuery(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getStoredQueryAsync(array $args = [])
+ * @method \Aws\Result listAggregateDiscoveredResources(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listAggregateDiscoveredResourcesAsync(array $args = [])
+ * @method \Aws\Result listConfigurationRecorders(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listConfigurationRecordersAsync(array $args = [])
+ * @method \Aws\Result listConformancePackComplianceScores(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listConformancePackComplianceScoresAsync(array $args = [])
+ * @method \Aws\Result listConnectors(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listConnectorsAsync(array $args = [])
+ * @method \Aws\Result listDiscoveredResources(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listDiscoveredResourcesAsync(array $args = [])
+ * @method \Aws\Result listResourceEvaluations(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listResourceEvaluationsAsync(array $args = [])
+ * @method \Aws\Result listStoredQueries(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listStoredQueriesAsync(array $args = [])
+ * @method \Aws\Result listTagsForResource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listTagsForResourceAsync(array $args = [])
+ * @method \Aws\Result putAggregationAuthorization(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise putAggregationAuthorizationAsync(array $args = [])
+ * @method \Aws\Result putConfigRule(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise putConfigRuleAsync(array $args = [])
+ * @method \Aws\Result putConfigurationAggregator(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise putConfigurationAggregatorAsync(array $args = [])
+ * @method \Aws\Result putConfigurationRecorder(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise putConfigurationRecorderAsync(array $args = [])
+ * @method \Aws\Result putConformancePack(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise putConformancePackAsync(array $args = [])
+ * @method \Aws\Result putConnector(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise putConnectorAsync(array $args = [])
+ * @method \Aws\Result putDeliveryChannel(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise putDeliveryChannelAsync(array $args = [])
+ * @method \Aws\Result putEvaluations(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise putEvaluationsAsync(array $args = [])
+ * @method \Aws\Result putExternalEvaluation(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise putExternalEvaluationAsync(array $args = [])
+ * @method \Aws\Result putOrganizationConfigRule(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise putOrganizationConfigRuleAsync(array $args = [])
+ * @method \Aws\Result putOrganizationConformancePack(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise putOrganizationConformancePackAsync(array $args = [])
+ * @method \Aws\Result putRemediationConfigurations(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise putRemediationConfigurationsAsync(array $args = [])
+ * @method \Aws\Result putRemediationExceptions(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise putRemediationExceptionsAsync(array $args = [])
+ * @method \Aws\Result putResourceConfig(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise putResourceConfigAsync(array $args = [])
+ * @method \Aws\Result putRetentionConfiguration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise putRetentionConfigurationAsync(array $args = [])
+ * @method \Aws\Result putServiceLinkedConfigurationRecorder(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise putServiceLinkedConfigurationRecorderAsync(array $args = [])
+ * @method \Aws\Result putStoredQuery(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise putStoredQueryAsync(array $args = [])
+ * @method \Aws\Result putThirdPartyServiceLinkedConfigurationRecorder(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise putThirdPartyServiceLinkedConfigurationRecorderAsync(array $args = [])
+ * @method \Aws\Result selectAggregateResourceConfig(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise selectAggregateResourceConfigAsync(array $args = [])
+ * @method \Aws\Result selectResourceConfig(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise selectResourceConfigAsync(array $args = [])
+ * @method \Aws\Result startConfigRulesEvaluation(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise startConfigRulesEvaluationAsync(array $args = [])
+ * @method \Aws\Result startConfigurationRecorder(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise startConfigurationRecorderAsync(array $args = [])
+ * @method \Aws\Result startRemediationExecution(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise startRemediationExecutionAsync(array $args = [])
+ * @method \Aws\Result startResourceEvaluation(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise startResourceEvaluationAsync(array $args = [])
+ * @method \Aws\Result stopConfigurationRecorder(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise stopConfigurationRecorderAsync(array $args = [])
+ * @method \Aws\Result tagResource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise tagResourceAsync(array $args = [])
+ * @method \Aws\Result untagResource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise untagResourceAsync(array $args = [])
+ */
+class ConfigServiceClient extends AwsClient {}

+ 297 - 0
upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/Configuration/ConfigurationResolver.php

@@ -0,0 +1,297 @@
+<?php
+
+namespace Aws\Configuration;
+
+/**
+ * Resolves configuration values from, in order of precedence:
+ *   1. An AWS_-prefixed environment variable.
+ *   2. The shared config file (AWS_CONFIG_FILE, defaulting to ~/.aws/config).
+ *   3. A caller-supplied default.
+ */
+class ConfigurationResolver
+{
+    const ENV_PROFILE = 'AWS_PROFILE';
+    const ENV_CONFIG_FILE = 'AWS_CONFIG_FILE';
+
+    const DEFAULT_PROFILE = 'default';
+
+    /** Prefix AWS applies to every non-default profile section in the config file. */
+    const PROFILE_PREFIX = 'profile ';
+
+    public static $envPrefix = 'AWS_';
+
+    /**
+     * @param string $key          Key to look up in the environment / config file.
+     * @param mixed  $defaultValue Returned when nothing else resolves.
+     * @param string $expectedType Type to coerce the resolved value to.
+     * @param array  $config       Options: 'ini_resolver_options',
+     *                             'use_aws_shared_config_files'.
+     *
+     * @return mixed
+     */
+    public static function resolve($key, $defaultValue, $expectedType, $config = [])
+    {
+        $envValue = self::env($key, $expectedType);
+        if ($envValue !== null) {
+            return $envValue;
+        }
+
+        $useSharedConfig = $config['use_aws_shared_config_files'] ?? true;
+        if ($useSharedConfig !== false) {
+            $iniValue = self::ini(
+                $key,
+                $expectedType,
+                null,
+                null,
+                $config['ini_resolver_options'] ?? []
+            );
+            if ($iniValue !== null) {
+                return $iniValue;
+            }
+        }
+
+        return $defaultValue;
+    }
+
+    /**
+     * Resolves a value from an AWS_-prefixed environment variable.
+     *
+     * @param string $key
+     * @param string $expectedType
+     *
+     * @return mixed|null
+     */
+    public static function env($key, $expectedType = 'string')
+    {
+        $envValue = getenv(self::$envPrefix . strtoupper($key));
+
+        // false => variable is unset; '' => set but empty. Both resolve to null.
+        // A literal "0" is a valid value and must NOT be treated as empty.
+        if ($envValue === false || $envValue === '') {
+            return null;
+        }
+
+        return $expectedType
+            ? self::convertType($envValue, $expectedType)
+            : $envValue;
+    }
+
+    /**
+     * Resolves a value from the shared config file.
+     *
+     * @param string      $key
+     * @param string      $expectedType
+     * @param string|null $profile  Profile to read. Defaults to AWS_PROFILE,
+     *                              then "default".
+     * @param string|null $filename Config file path. Defaults to AWS_CONFIG_FILE,
+     *                              then ~/.aws/config.
+     * @param array       $options  Subsection lookup options
+     *                             ('section', 'subsection', 'key').
+     *
+     * @return mixed|null
+     */
+    public static function ini(
+        $key,
+        $expectedType,
+        $profile = null,
+        $filename = null,
+        $options = []
+    ) {
+        $filename = $filename ?: self::getDefaultConfigFilename();
+        $profile = $profile ?: (getenv(self::ENV_PROFILE) ?: self::DEFAULT_PROFILE);
+
+        if (!@is_readable($filename)) {
+            return null;
+        }
+
+        // INI_SCANNER_TYPED coerces bool/int/float/null at parse time; a value
+        // left empty (key =) still comes back as an empty string. convertType()
+        // normalizes both these typed values and the raw strings from env().
+        $data = @\Aws\parse_ini_file($filename, true, INI_SCANNER_TYPED);
+        if ($data === false) {
+            return null;
+        }
+
+        if (isset($options['section'], $options['subsection'], $options['key'])) {
+            return self::retrieveValueFromIniSubsection(
+                $data,
+                $profile,
+                $filename,
+                $expectedType,
+                $options
+            );
+        }
+
+        $section = self::getProfileSection($data, $profile);
+        if ($section === null || !isset($section[$key])) {
+            return null;
+        }
+
+        return self::convertType($section[$key], $expectedType);
+    }
+
+    /**
+     * Returns the config-file section for a profile, accounting for the
+     * "profile " prefix AWS applies to every non-default profile.
+     *
+     * For a non-default profile "foo" the lookup order is:
+     *   1. [profile foo]  (canonical AWS form)
+     *   2. [foo]          (lenient fallback for hand-written files)
+     *
+     * The default profile is conventionally written as [default], with
+     * [profile default] tolerated as a fallback.
+     *
+     * @param array  $data
+     * @param string $profile
+     *
+     * @return array|null
+     */
+    private static function getProfileSection(array $data, $profile)
+    {
+        if ($profile === self::DEFAULT_PROFILE) {
+            return $data[self::DEFAULT_PROFILE]
+                ?? $data[self::PROFILE_PREFIX . self::DEFAULT_PROFILE]
+                ?? null;
+        }
+
+        return $data[self::PROFILE_PREFIX . $profile]
+            ?? $data[$profile]
+            ?? null;
+    }
+
+    /**
+     * Resolves a value nested in a referenced section (e.g. a profile that
+     * points at a "services" section via `services = my-services`).
+     *
+     * @param array  $data
+     * @param string $profile
+     * @param string $filename
+     * @param string $expectedType
+     * @param array  $options
+     *
+     * @return mixed|null
+     */
+    private static function retrieveValueFromIniSubsection(
+        array $data,
+        $profile,
+        $filename,
+        $expectedType,
+        array $options
+    ) {
+        $profileData = self::getProfileSection($data, $profile);
+        $section = $options['section'];
+
+        // The profile must name a referenced section, and that section must exist.
+        if ($profileData === null || !isset($profileData[$section])) {
+            return null;
+        }
+
+        $referencedSection = "{$section} {$profileData[$section]}";
+        if (!isset($data[$referencedSection])) {
+            return null;
+        }
+
+        $subsections = \Aws\parse_ini_section_with_subsections(
+            $filename,
+            $referencedSection
+        );
+
+        $subsection = $options['subsection'];
+        $subKey = $options['key'];
+        if (!isset($subsections[$subsection][$subKey])) {
+            return null;
+        }
+
+        return self::convertType($subsections[$subsection][$subKey], $expectedType);
+    }
+
+    /**
+     * Gets the environment's HOME directory if available.
+     *
+     * @return string|null
+     */
+    private static function getHomeDir()
+    {
+        // Linux / Unix-like systems.
+        if ($homeDir = getenv('HOME')) {
+            return $homeDir;
+        }
+
+        // Windows hosts.
+        $homeDrive = getenv('HOMEDRIVE');
+        $homePath = getenv('HOMEPATH');
+
+        return ($homeDrive && $homePath) ? $homeDrive . $homePath : null;
+    }
+
+    /**
+     * Gets the config file location from the environment, falling back to the
+     * AWS default location.
+     *
+     * @return string
+     */
+    private static function getDefaultConfigFilename()
+    {
+        return getenv(self::ENV_CONFIG_FILE)
+            ?: self::getHomeDir() . '/.aws/config';
+    }
+
+    /**
+     * Coerces a value to the expected type. The value may be a raw string
+     * (from env()) or already typed by INI_SCANNER_TYPED (from ini()).
+     * Unrecognized values are returned unchanged.
+     *
+     * @param mixed  $value
+     * @param string $type
+     *
+     * @return mixed
+     */
+    private static function convertType(mixed $value, string $type): mixed
+    {
+        // INI_SCANNER_TYPED may already yield a bool/int for keyword or numeric
+        // values; env() always passes a string. Each arm fast-paths the
+        // already-typed case and delegates conversion otherwise. TYPED may also
+        // return int/float/bool for numeric or keyword 'string' values, so the
+        // string arm casts those back to string as it did under NORMAL.
+        return match ($type) {
+            'bool'   => is_bool($value) ? $value : self::toBool($value),
+            'int'    => is_int($value) ? $value : self::toInt($value),
+            'string' => is_string($value) ? $value : (string) $value,
+            default  => $value,
+        };
+    }
+
+    /**
+     * Coerces a non-bool value (typically a string from env()) to bool.
+     * \Aws\boolean_value() returns null when it can't interpret the value.
+     *
+     * @param mixed $value
+     *
+     * @return mixed
+     */
+    private static function toBool(mixed $value): mixed
+    {
+        if ($value === '') {
+            return false;
+        }
+        return \Aws\boolean_value($value) ?? $value;
+    }
+
+    /**
+     * Coerces a non-int value (typically a string from env()) to int. Uses
+     * !== false on filter_var() so a valid "0" is not dropped; if the value
+     * is not a valid int, the original is returned unchanged.
+     *
+     * @param mixed $value
+     *
+     * @return mixed
+     */
+    private static function toInt(mixed $value): mixed
+    {
+        if ($value === '') {
+            return 0;
+        }
+        $int = filter_var($value, FILTER_VALIDATE_INT);
+        return $int !== false ? $int : $value;
+    }
+}

+ 767 - 0
upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/Connect/ConnectClient.php

@@ -0,0 +1,767 @@
+<?php
+namespace Aws\Connect;
+
+use Aws\AwsClient;
+
+/**
+ * This client is used to interact with the **Amazon Connect Service** service.
+ * @method \Aws\Result activateEvaluationForm(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise activateEvaluationFormAsync(array $args = [])
+ * @method \Aws\Result associateAnalyticsDataSet(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise associateAnalyticsDataSetAsync(array $args = [])
+ * @method \Aws\Result associateApprovedOrigin(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise associateApprovedOriginAsync(array $args = [])
+ * @method \Aws\Result associateBot(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise associateBotAsync(array $args = [])
+ * @method \Aws\Result associateContactWithUser(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise associateContactWithUserAsync(array $args = [])
+ * @method \Aws\Result associateDefaultVocabulary(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise associateDefaultVocabularyAsync(array $args = [])
+ * @method \Aws\Result associateEmailAddressAlias(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise associateEmailAddressAliasAsync(array $args = [])
+ * @method \Aws\Result associateFlow(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise associateFlowAsync(array $args = [])
+ * @method \Aws\Result associateHoursOfOperations(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise associateHoursOfOperationsAsync(array $args = [])
+ * @method \Aws\Result associateInstanceStorageConfig(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise associateInstanceStorageConfigAsync(array $args = [])
+ * @method \Aws\Result associateLambdaFunction(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise associateLambdaFunctionAsync(array $args = [])
+ * @method \Aws\Result associateLexBot(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise associateLexBotAsync(array $args = [])
+ * @method \Aws\Result associatePhoneNumberContactFlow(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise associatePhoneNumberContactFlowAsync(array $args = [])
+ * @method \Aws\Result associateQueueEmailAddresses(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise associateQueueEmailAddressesAsync(array $args = [])
+ * @method \Aws\Result associateQueueQuickConnects(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise associateQueueQuickConnectsAsync(array $args = [])
+ * @method \Aws\Result associateRoutingProfileQueues(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise associateRoutingProfileQueuesAsync(array $args = [])
+ * @method \Aws\Result associateSecurityKey(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise associateSecurityKeyAsync(array $args = [])
+ * @method \Aws\Result associateSecurityProfiles(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise associateSecurityProfilesAsync(array $args = [])
+ * @method \Aws\Result associateTrafficDistributionGroupUser(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise associateTrafficDistributionGroupUserAsync(array $args = [])
+ * @method \Aws\Result associateUserProficiencies(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise associateUserProficienciesAsync(array $args = [])
+ * @method \Aws\Result associateWorkspace(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise associateWorkspaceAsync(array $args = [])
+ * @method \Aws\Result batchAssociateAnalyticsDataSet(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise batchAssociateAnalyticsDataSetAsync(array $args = [])
+ * @method \Aws\Result batchCreateDataTableValue(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise batchCreateDataTableValueAsync(array $args = [])
+ * @method \Aws\Result batchDeleteDataTableValue(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise batchDeleteDataTableValueAsync(array $args = [])
+ * @method \Aws\Result batchDescribeDataTableValue(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise batchDescribeDataTableValueAsync(array $args = [])
+ * @method \Aws\Result batchDisassociateAnalyticsDataSet(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise batchDisassociateAnalyticsDataSetAsync(array $args = [])
+ * @method \Aws\Result batchGetAttachedFileMetadata(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise batchGetAttachedFileMetadataAsync(array $args = [])
+ * @method \Aws\Result batchGetFlowAssociation(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise batchGetFlowAssociationAsync(array $args = [])
+ * @method \Aws\Result batchPutContact(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise batchPutContactAsync(array $args = [])
+ * @method \Aws\Result batchUpdateDataTableValue(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise batchUpdateDataTableValueAsync(array $args = [])
+ * @method \Aws\Result claimPhoneNumber(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise claimPhoneNumberAsync(array $args = [])
+ * @method \Aws\Result completeAttachedFileUpload(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise completeAttachedFileUploadAsync(array $args = [])
+ * @method \Aws\Result createAgentStatus(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createAgentStatusAsync(array $args = [])
+ * @method \Aws\Result createAttachedFile(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createAttachedFileAsync(array $args = [])
+ * @method \Aws\Result createAuthCode(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createAuthCodeAsync(array $args = [])
+ * @method \Aws\Result createContact(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createContactAsync(array $args = [])
+ * @method \Aws\Result createContactFlow(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createContactFlowAsync(array $args = [])
+ * @method \Aws\Result createContactFlowModule(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createContactFlowModuleAsync(array $args = [])
+ * @method \Aws\Result createContactFlowModuleAlias(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createContactFlowModuleAliasAsync(array $args = [])
+ * @method \Aws\Result createContactFlowModuleVersion(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createContactFlowModuleVersionAsync(array $args = [])
+ * @method \Aws\Result createContactFlowVersion(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createContactFlowVersionAsync(array $args = [])
+ * @method \Aws\Result createDataTable(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createDataTableAsync(array $args = [])
+ * @method \Aws\Result createDataTableAttribute(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createDataTableAttributeAsync(array $args = [])
+ * @method \Aws\Result createEmailAddress(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createEmailAddressAsync(array $args = [])
+ * @method \Aws\Result createEvaluationForm(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createEvaluationFormAsync(array $args = [])
+ * @method \Aws\Result createHoursOfOperation(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createHoursOfOperationAsync(array $args = [])
+ * @method \Aws\Result createHoursOfOperationOverride(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createHoursOfOperationOverrideAsync(array $args = [])
+ * @method \Aws\Result createInstance(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createInstanceAsync(array $args = [])
+ * @method \Aws\Result createIntegrationAssociation(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createIntegrationAssociationAsync(array $args = [])
+ * @method \Aws\Result createNotification(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createNotificationAsync(array $args = [])
+ * @method \Aws\Result createParticipant(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createParticipantAsync(array $args = [])
+ * @method \Aws\Result createPersistentContactAssociation(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createPersistentContactAssociationAsync(array $args = [])
+ * @method \Aws\Result createPredefinedAttribute(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createPredefinedAttributeAsync(array $args = [])
+ * @method \Aws\Result createPrompt(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createPromptAsync(array $args = [])
+ * @method \Aws\Result createPushNotificationRegistration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createPushNotificationRegistrationAsync(array $args = [])
+ * @method \Aws\Result createQueue(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createQueueAsync(array $args = [])
+ * @method \Aws\Result createQuickConnect(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createQuickConnectAsync(array $args = [])
+ * @method \Aws\Result createRoutingProfile(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createRoutingProfileAsync(array $args = [])
+ * @method \Aws\Result createRule(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createRuleAsync(array $args = [])
+ * @method \Aws\Result createSecurityProfile(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createSecurityProfileAsync(array $args = [])
+ * @method \Aws\Result createTaskTemplate(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createTaskTemplateAsync(array $args = [])
+ * @method \Aws\Result createTestCase(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createTestCaseAsync(array $args = [])
+ * @method \Aws\Result createTrafficDistributionGroup(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createTrafficDistributionGroupAsync(array $args = [])
+ * @method \Aws\Result createUseCase(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createUseCaseAsync(array $args = [])
+ * @method \Aws\Result createUser(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createUserAsync(array $args = [])
+ * @method \Aws\Result createUserHierarchyGroup(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createUserHierarchyGroupAsync(array $args = [])
+ * @method \Aws\Result createView(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createViewAsync(array $args = [])
+ * @method \Aws\Result createViewVersion(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createViewVersionAsync(array $args = [])
+ * @method \Aws\Result createVocabulary(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createVocabularyAsync(array $args = [])
+ * @method \Aws\Result createWorkspace(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createWorkspaceAsync(array $args = [])
+ * @method \Aws\Result createWorkspacePage(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createWorkspacePageAsync(array $args = [])
+ * @method \Aws\Result deactivateEvaluationForm(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deactivateEvaluationFormAsync(array $args = [])
+ * @method \Aws\Result deleteAttachedFile(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteAttachedFileAsync(array $args = [])
+ * @method \Aws\Result deleteContactData(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteContactDataAsync(array $args = [])
+ * @method \Aws\Result deleteContactEvaluation(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteContactEvaluationAsync(array $args = [])
+ * @method \Aws\Result deleteContactFlow(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteContactFlowAsync(array $args = [])
+ * @method \Aws\Result deleteContactFlowModule(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteContactFlowModuleAsync(array $args = [])
+ * @method \Aws\Result deleteContactFlowModuleAlias(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteContactFlowModuleAliasAsync(array $args = [])
+ * @method \Aws\Result deleteContactFlowModuleVersion(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteContactFlowModuleVersionAsync(array $args = [])
+ * @method \Aws\Result deleteContactFlowVersion(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteContactFlowVersionAsync(array $args = [])
+ * @method \Aws\Result deleteDataTable(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteDataTableAsync(array $args = [])
+ * @method \Aws\Result deleteDataTableAttribute(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteDataTableAttributeAsync(array $args = [])
+ * @method \Aws\Result deleteEmailAddress(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteEmailAddressAsync(array $args = [])
+ * @method \Aws\Result deleteEvaluationForm(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteEvaluationFormAsync(array $args = [])
+ * @method \Aws\Result deleteHoursOfOperation(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteHoursOfOperationAsync(array $args = [])
+ * @method \Aws\Result deleteHoursOfOperationOverride(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteHoursOfOperationOverrideAsync(array $args = [])
+ * @method \Aws\Result deleteInstance(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteInstanceAsync(array $args = [])
+ * @method \Aws\Result deleteIntegrationAssociation(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteIntegrationAssociationAsync(array $args = [])
+ * @method \Aws\Result deleteNotification(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteNotificationAsync(array $args = [])
+ * @method \Aws\Result deletePredefinedAttribute(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deletePredefinedAttributeAsync(array $args = [])
+ * @method \Aws\Result deletePrompt(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deletePromptAsync(array $args = [])
+ * @method \Aws\Result deletePushNotificationRegistration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deletePushNotificationRegistrationAsync(array $args = [])
+ * @method \Aws\Result deleteQueue(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteQueueAsync(array $args = [])
+ * @method \Aws\Result deleteQuickConnect(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteQuickConnectAsync(array $args = [])
+ * @method \Aws\Result deleteRoutingProfile(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteRoutingProfileAsync(array $args = [])
+ * @method \Aws\Result deleteRule(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteRuleAsync(array $args = [])
+ * @method \Aws\Result deleteSecurityProfile(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteSecurityProfileAsync(array $args = [])
+ * @method \Aws\Result deleteSession(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteSessionAsync(array $args = [])
+ * @method \Aws\Result deleteTaskTemplate(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteTaskTemplateAsync(array $args = [])
+ * @method \Aws\Result deleteTestCase(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteTestCaseAsync(array $args = [])
+ * @method \Aws\Result deleteTrafficDistributionGroup(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteTrafficDistributionGroupAsync(array $args = [])
+ * @method \Aws\Result deleteUseCase(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteUseCaseAsync(array $args = [])
+ * @method \Aws\Result deleteUser(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteUserAsync(array $args = [])
+ * @method \Aws\Result deleteUserHierarchyGroup(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteUserHierarchyGroupAsync(array $args = [])
+ * @method \Aws\Result deleteView(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteViewAsync(array $args = [])
+ * @method \Aws\Result deleteViewVersion(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteViewVersionAsync(array $args = [])
+ * @method \Aws\Result deleteVocabulary(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteVocabularyAsync(array $args = [])
+ * @method \Aws\Result deleteWorkspace(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteWorkspaceAsync(array $args = [])
+ * @method \Aws\Result deleteWorkspaceMedia(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteWorkspaceMediaAsync(array $args = [])
+ * @method \Aws\Result deleteWorkspacePage(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteWorkspacePageAsync(array $args = [])
+ * @method \Aws\Result describeAgentStatus(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeAgentStatusAsync(array $args = [])
+ * @method \Aws\Result describeAttachedFilesConfiguration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeAttachedFilesConfigurationAsync(array $args = [])
+ * @method \Aws\Result describeAuthenticationProfile(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeAuthenticationProfileAsync(array $args = [])
+ * @method \Aws\Result describeContact(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeContactAsync(array $args = [])
+ * @method \Aws\Result describeContactEvaluation(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeContactEvaluationAsync(array $args = [])
+ * @method \Aws\Result describeContactFlow(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeContactFlowAsync(array $args = [])
+ * @method \Aws\Result describeContactFlowModule(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeContactFlowModuleAsync(array $args = [])
+ * @method \Aws\Result describeContactFlowModuleAlias(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeContactFlowModuleAliasAsync(array $args = [])
+ * @method \Aws\Result describeDataTable(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeDataTableAsync(array $args = [])
+ * @method \Aws\Result describeDataTableAttribute(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeDataTableAttributeAsync(array $args = [])
+ * @method \Aws\Result describeEmailAddress(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeEmailAddressAsync(array $args = [])
+ * @method \Aws\Result describeEvaluationForm(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeEvaluationFormAsync(array $args = [])
+ * @method \Aws\Result describeHoursOfOperation(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeHoursOfOperationAsync(array $args = [])
+ * @method \Aws\Result describeHoursOfOperationOverride(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeHoursOfOperationOverrideAsync(array $args = [])
+ * @method \Aws\Result describeInstance(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeInstanceAsync(array $args = [])
+ * @method \Aws\Result describeInstanceAttribute(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeInstanceAttributeAsync(array $args = [])
+ * @method \Aws\Result describeInstanceStorageConfig(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeInstanceStorageConfigAsync(array $args = [])
+ * @method \Aws\Result describeNotification(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeNotificationAsync(array $args = [])
+ * @method \Aws\Result describePhoneNumber(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describePhoneNumberAsync(array $args = [])
+ * @method \Aws\Result describePredefinedAttribute(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describePredefinedAttributeAsync(array $args = [])
+ * @method \Aws\Result describePrompt(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describePromptAsync(array $args = [])
+ * @method \Aws\Result describeQueue(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeQueueAsync(array $args = [])
+ * @method \Aws\Result describeQuickConnect(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeQuickConnectAsync(array $args = [])
+ * @method \Aws\Result describeRoutingProfile(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeRoutingProfileAsync(array $args = [])
+ * @method \Aws\Result describeRule(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeRuleAsync(array $args = [])
+ * @method \Aws\Result describeSecurityProfile(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeSecurityProfileAsync(array $args = [])
+ * @method \Aws\Result describeTestCase(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeTestCaseAsync(array $args = [])
+ * @method \Aws\Result describeTrafficDistributionGroup(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeTrafficDistributionGroupAsync(array $args = [])
+ * @method \Aws\Result describeUser(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeUserAsync(array $args = [])
+ * @method \Aws\Result describeUserHierarchyGroup(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeUserHierarchyGroupAsync(array $args = [])
+ * @method \Aws\Result describeUserHierarchyStructure(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeUserHierarchyStructureAsync(array $args = [])
+ * @method \Aws\Result describeView(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeViewAsync(array $args = [])
+ * @method \Aws\Result describeVocabulary(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeVocabularyAsync(array $args = [])
+ * @method \Aws\Result describeWorkspace(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeWorkspaceAsync(array $args = [])
+ * @method \Aws\Result disassociateAnalyticsDataSet(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise disassociateAnalyticsDataSetAsync(array $args = [])
+ * @method \Aws\Result disassociateApprovedOrigin(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise disassociateApprovedOriginAsync(array $args = [])
+ * @method \Aws\Result disassociateBot(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise disassociateBotAsync(array $args = [])
+ * @method \Aws\Result disassociateEmailAddressAlias(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise disassociateEmailAddressAliasAsync(array $args = [])
+ * @method \Aws\Result disassociateFlow(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise disassociateFlowAsync(array $args = [])
+ * @method \Aws\Result disassociateHoursOfOperations(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise disassociateHoursOfOperationsAsync(array $args = [])
+ * @method \Aws\Result disassociateInstanceStorageConfig(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise disassociateInstanceStorageConfigAsync(array $args = [])
+ * @method \Aws\Result disassociateLambdaFunction(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise disassociateLambdaFunctionAsync(array $args = [])
+ * @method \Aws\Result disassociateLexBot(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise disassociateLexBotAsync(array $args = [])
+ * @method \Aws\Result disassociatePhoneNumberContactFlow(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise disassociatePhoneNumberContactFlowAsync(array $args = [])
+ * @method \Aws\Result disassociateQueueEmailAddresses(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise disassociateQueueEmailAddressesAsync(array $args = [])
+ * @method \Aws\Result disassociateQueueQuickConnects(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise disassociateQueueQuickConnectsAsync(array $args = [])
+ * @method \Aws\Result disassociateRoutingProfileQueues(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise disassociateRoutingProfileQueuesAsync(array $args = [])
+ * @method \Aws\Result disassociateSecurityKey(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise disassociateSecurityKeyAsync(array $args = [])
+ * @method \Aws\Result disassociateSecurityProfiles(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise disassociateSecurityProfilesAsync(array $args = [])
+ * @method \Aws\Result disassociateTrafficDistributionGroupUser(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise disassociateTrafficDistributionGroupUserAsync(array $args = [])
+ * @method \Aws\Result disassociateUserProficiencies(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise disassociateUserProficienciesAsync(array $args = [])
+ * @method \Aws\Result disassociateWorkspace(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise disassociateWorkspaceAsync(array $args = [])
+ * @method \Aws\Result dismissUserContact(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise dismissUserContactAsync(array $args = [])
+ * @method \Aws\Result evaluateDataTableValues(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise evaluateDataTableValuesAsync(array $args = [])
+ * @method \Aws\Result getAttachedFile(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getAttachedFileAsync(array $args = [])
+ * @method \Aws\Result getContactAttributes(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getContactAttributesAsync(array $args = [])
+ * @method \Aws\Result getContactMetrics(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getContactMetricsAsync(array $args = [])
+ * @method \Aws\Result getCurrentMetricData(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getCurrentMetricDataAsync(array $args = [])
+ * @method \Aws\Result getCurrentUserData(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getCurrentUserDataAsync(array $args = [])
+ * @method \Aws\Result getEffectiveHoursOfOperations(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getEffectiveHoursOfOperationsAsync(array $args = [])
+ * @method \Aws\Result getEvaluationFormValidation(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getEvaluationFormValidationAsync(array $args = [])
+ * @method \Aws\Result getFederationToken(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getFederationTokenAsync(array $args = [])
+ * @method \Aws\Result getFlowAssociation(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getFlowAssociationAsync(array $args = [])
+ * @method \Aws\Result getMetricData(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getMetricDataAsync(array $args = [])
+ * @method \Aws\Result getMetricDataV2(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getMetricDataV2Async(array $args = [])
+ * @method \Aws\Result getPromptFile(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getPromptFileAsync(array $args = [])
+ * @method \Aws\Result getTaskTemplate(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getTaskTemplateAsync(array $args = [])
+ * @method \Aws\Result getTestCaseExecutionSummary(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getTestCaseExecutionSummaryAsync(array $args = [])
+ * @method \Aws\Result getTrafficDistribution(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getTrafficDistributionAsync(array $args = [])
+ * @method \Aws\Result importPhoneNumber(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise importPhoneNumberAsync(array $args = [])
+ * @method \Aws\Result importWorkspaceMedia(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise importWorkspaceMediaAsync(array $args = [])
+ * @method \Aws\Result listAgentStatuses(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listAgentStatusesAsync(array $args = [])
+ * @method \Aws\Result listAnalyticsDataAssociations(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listAnalyticsDataAssociationsAsync(array $args = [])
+ * @method \Aws\Result listAnalyticsDataLakeDataSets(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listAnalyticsDataLakeDataSetsAsync(array $args = [])
+ * @method \Aws\Result listApprovedOrigins(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listApprovedOriginsAsync(array $args = [])
+ * @method \Aws\Result listAssociatedContacts(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listAssociatedContactsAsync(array $args = [])
+ * @method \Aws\Result listAttachedFilesConfigurations(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listAttachedFilesConfigurationsAsync(array $args = [])
+ * @method \Aws\Result listAuthenticationProfiles(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listAuthenticationProfilesAsync(array $args = [])
+ * @method \Aws\Result listBots(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listBotsAsync(array $args = [])
+ * @method \Aws\Result listChildHoursOfOperations(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listChildHoursOfOperationsAsync(array $args = [])
+ * @method \Aws\Result listContactEvaluations(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listContactEvaluationsAsync(array $args = [])
+ * @method \Aws\Result listContactFlowModuleAliases(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listContactFlowModuleAliasesAsync(array $args = [])
+ * @method \Aws\Result listContactFlowModuleVersions(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listContactFlowModuleVersionsAsync(array $args = [])
+ * @method \Aws\Result listContactFlowModules(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listContactFlowModulesAsync(array $args = [])
+ * @method \Aws\Result listContactFlowVersions(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listContactFlowVersionsAsync(array $args = [])
+ * @method \Aws\Result listContactFlows(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listContactFlowsAsync(array $args = [])
+ * @method \Aws\Result listContactReferences(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listContactReferencesAsync(array $args = [])
+ * @method \Aws\Result listDataTableAttributes(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listDataTableAttributesAsync(array $args = [])
+ * @method \Aws\Result listDataTablePrimaryValues(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listDataTablePrimaryValuesAsync(array $args = [])
+ * @method \Aws\Result listDataTableValues(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listDataTableValuesAsync(array $args = [])
+ * @method \Aws\Result listDataTables(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listDataTablesAsync(array $args = [])
+ * @method \Aws\Result listDefaultVocabularies(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listDefaultVocabulariesAsync(array $args = [])
+ * @method \Aws\Result listEntitySecurityProfiles(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listEntitySecurityProfilesAsync(array $args = [])
+ * @method \Aws\Result listEvaluationFormVersions(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listEvaluationFormVersionsAsync(array $args = [])
+ * @method \Aws\Result listEvaluationForms(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listEvaluationFormsAsync(array $args = [])
+ * @method \Aws\Result listFlowAssociations(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listFlowAssociationsAsync(array $args = [])
+ * @method \Aws\Result listHoursOfOperationOverrides(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listHoursOfOperationOverridesAsync(array $args = [])
+ * @method \Aws\Result listHoursOfOperations(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listHoursOfOperationsAsync(array $args = [])
+ * @method \Aws\Result listInstanceAttributes(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listInstanceAttributesAsync(array $args = [])
+ * @method \Aws\Result listInstanceStorageConfigs(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listInstanceStorageConfigsAsync(array $args = [])
+ * @method \Aws\Result listInstances(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listInstancesAsync(array $args = [])
+ * @method \Aws\Result listIntegrationAssociations(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listIntegrationAssociationsAsync(array $args = [])
+ * @method \Aws\Result listLambdaFunctions(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listLambdaFunctionsAsync(array $args = [])
+ * @method \Aws\Result listLexBots(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listLexBotsAsync(array $args = [])
+ * @method \Aws\Result listNotifications(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listNotificationsAsync(array $args = [])
+ * @method \Aws\Result listPhoneNumbers(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listPhoneNumbersAsync(array $args = [])
+ * @method \Aws\Result listPhoneNumbersV2(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listPhoneNumbersV2Async(array $args = [])
+ * @method \Aws\Result listPredefinedAttributes(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listPredefinedAttributesAsync(array $args = [])
+ * @method \Aws\Result listPrompts(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listPromptsAsync(array $args = [])
+ * @method \Aws\Result listQueueEmailAddresses(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listQueueEmailAddressesAsync(array $args = [])
+ * @method \Aws\Result listQueueQuickConnects(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listQueueQuickConnectsAsync(array $args = [])
+ * @method \Aws\Result listQueues(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listQueuesAsync(array $args = [])
+ * @method \Aws\Result listQuickConnects(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listQuickConnectsAsync(array $args = [])
+ * @method \Aws\Result listRealtimeContactAnalysisSegmentsV2(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listRealtimeContactAnalysisSegmentsV2Async(array $args = [])
+ * @method \Aws\Result listRoutingProfileManualAssignmentQueues(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listRoutingProfileManualAssignmentQueuesAsync(array $args = [])
+ * @method \Aws\Result listRoutingProfileQueues(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listRoutingProfileQueuesAsync(array $args = [])
+ * @method \Aws\Result listRoutingProfiles(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listRoutingProfilesAsync(array $args = [])
+ * @method \Aws\Result listRules(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listRulesAsync(array $args = [])
+ * @method \Aws\Result listSecurityKeys(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listSecurityKeysAsync(array $args = [])
+ * @method \Aws\Result listSecurityProfileApplications(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listSecurityProfileApplicationsAsync(array $args = [])
+ * @method \Aws\Result listSecurityProfileFlowModules(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listSecurityProfileFlowModulesAsync(array $args = [])
+ * @method \Aws\Result listSecurityProfilePermissions(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listSecurityProfilePermissionsAsync(array $args = [])
+ * @method \Aws\Result listSecurityProfiles(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listSecurityProfilesAsync(array $args = [])
+ * @method \Aws\Result listTagsForResource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listTagsForResourceAsync(array $args = [])
+ * @method \Aws\Result listTaskTemplates(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listTaskTemplatesAsync(array $args = [])
+ * @method \Aws\Result listTestCaseExecutionRecords(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listTestCaseExecutionRecordsAsync(array $args = [])
+ * @method \Aws\Result listTestCaseExecutions(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listTestCaseExecutionsAsync(array $args = [])
+ * @method \Aws\Result listTestCases(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listTestCasesAsync(array $args = [])
+ * @method \Aws\Result listTrafficDistributionGroupUsers(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listTrafficDistributionGroupUsersAsync(array $args = [])
+ * @method \Aws\Result listTrafficDistributionGroups(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listTrafficDistributionGroupsAsync(array $args = [])
+ * @method \Aws\Result listUseCases(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listUseCasesAsync(array $args = [])
+ * @method \Aws\Result listUserHierarchyGroups(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listUserHierarchyGroupsAsync(array $args = [])
+ * @method \Aws\Result listUserNotifications(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listUserNotificationsAsync(array $args = [])
+ * @method \Aws\Result listUserProficiencies(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listUserProficienciesAsync(array $args = [])
+ * @method \Aws\Result listUsers(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listUsersAsync(array $args = [])
+ * @method \Aws\Result listViewVersions(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listViewVersionsAsync(array $args = [])
+ * @method \Aws\Result listViews(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listViewsAsync(array $args = [])
+ * @method \Aws\Result listWorkspaceMedia(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listWorkspaceMediaAsync(array $args = [])
+ * @method \Aws\Result listWorkspacePages(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listWorkspacePagesAsync(array $args = [])
+ * @method \Aws\Result listWorkspaces(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listWorkspacesAsync(array $args = [])
+ * @method \Aws\Result monitorContact(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise monitorContactAsync(array $args = [])
+ * @method \Aws\Result pauseContact(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise pauseContactAsync(array $args = [])
+ * @method \Aws\Result putUserStatus(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise putUserStatusAsync(array $args = [])
+ * @method \Aws\Result releasePhoneNumber(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise releasePhoneNumberAsync(array $args = [])
+ * @method \Aws\Result replicateInstance(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise replicateInstanceAsync(array $args = [])
+ * @method \Aws\Result resumeContact(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise resumeContactAsync(array $args = [])
+ * @method \Aws\Result resumeContactRecording(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise resumeContactRecordingAsync(array $args = [])
+ * @method \Aws\Result searchAgentStatuses(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise searchAgentStatusesAsync(array $args = [])
+ * @method \Aws\Result searchAvailablePhoneNumbers(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise searchAvailablePhoneNumbersAsync(array $args = [])
+ * @method \Aws\Result searchContactEvaluations(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise searchContactEvaluationsAsync(array $args = [])
+ * @method \Aws\Result searchContactFlowModules(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise searchContactFlowModulesAsync(array $args = [])
+ * @method \Aws\Result searchContactFlows(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise searchContactFlowsAsync(array $args = [])
+ * @method \Aws\Result searchContacts(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise searchContactsAsync(array $args = [])
+ * @method \Aws\Result searchDataTables(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise searchDataTablesAsync(array $args = [])
+ * @method \Aws\Result searchEmailAddresses(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise searchEmailAddressesAsync(array $args = [])
+ * @method \Aws\Result searchEvaluationForms(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise searchEvaluationFormsAsync(array $args = [])
+ * @method \Aws\Result searchHoursOfOperationOverrides(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise searchHoursOfOperationOverridesAsync(array $args = [])
+ * @method \Aws\Result searchHoursOfOperations(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise searchHoursOfOperationsAsync(array $args = [])
+ * @method \Aws\Result searchNotifications(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise searchNotificationsAsync(array $args = [])
+ * @method \Aws\Result searchPredefinedAttributes(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise searchPredefinedAttributesAsync(array $args = [])
+ * @method \Aws\Result searchPrompts(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise searchPromptsAsync(array $args = [])
+ * @method \Aws\Result searchQueues(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise searchQueuesAsync(array $args = [])
+ * @method \Aws\Result searchQuickConnects(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise searchQuickConnectsAsync(array $args = [])
+ * @method \Aws\Result searchResourceTags(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise searchResourceTagsAsync(array $args = [])
+ * @method \Aws\Result searchRoutingProfiles(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise searchRoutingProfilesAsync(array $args = [])
+ * @method \Aws\Result searchRules(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise searchRulesAsync(array $args = [])
+ * @method \Aws\Result searchSecurityProfiles(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise searchSecurityProfilesAsync(array $args = [])
+ * @method \Aws\Result searchTestCases(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise searchTestCasesAsync(array $args = [])
+ * @method \Aws\Result searchUserHierarchyGroups(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise searchUserHierarchyGroupsAsync(array $args = [])
+ * @method \Aws\Result searchUsers(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise searchUsersAsync(array $args = [])
+ * @method \Aws\Result searchViews(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise searchViewsAsync(array $args = [])
+ * @method \Aws\Result searchVocabularies(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise searchVocabulariesAsync(array $args = [])
+ * @method \Aws\Result searchWorkspaceAssociations(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise searchWorkspaceAssociationsAsync(array $args = [])
+ * @method \Aws\Result searchWorkspaces(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise searchWorkspacesAsync(array $args = [])
+ * @method \Aws\Result sendChatIntegrationEvent(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise sendChatIntegrationEventAsync(array $args = [])
+ * @method \Aws\Result sendOutboundEmail(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise sendOutboundEmailAsync(array $args = [])
+ * @method \Aws\Result sendOutboundWebNotification(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise sendOutboundWebNotificationAsync(array $args = [])
+ * @method \Aws\Result startAttachedFileUpload(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise startAttachedFileUploadAsync(array $args = [])
+ * @method \Aws\Result startChatContact(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise startChatContactAsync(array $args = [])
+ * @method \Aws\Result startContactConversationalAnalyticsJob(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise startContactConversationalAnalyticsJobAsync(array $args = [])
+ * @method \Aws\Result startContactEvaluation(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise startContactEvaluationAsync(array $args = [])
+ * @method \Aws\Result startContactMediaProcessing(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise startContactMediaProcessingAsync(array $args = [])
+ * @method \Aws\Result startContactRecording(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise startContactRecordingAsync(array $args = [])
+ * @method \Aws\Result startContactStreaming(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise startContactStreamingAsync(array $args = [])
+ * @method \Aws\Result startEmailContact(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise startEmailContactAsync(array $args = [])
+ * @method \Aws\Result startEvaluationFormValidation(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise startEvaluationFormValidationAsync(array $args = [])
+ * @method \Aws\Result startOutboundChatContact(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise startOutboundChatContactAsync(array $args = [])
+ * @method \Aws\Result startOutboundEmailContact(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise startOutboundEmailContactAsync(array $args = [])
+ * @method \Aws\Result startOutboundVoiceContact(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise startOutboundVoiceContactAsync(array $args = [])
+ * @method \Aws\Result startScreenSharing(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise startScreenSharingAsync(array $args = [])
+ * @method \Aws\Result startTaskContact(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise startTaskContactAsync(array $args = [])
+ * @method \Aws\Result startTestCaseExecution(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise startTestCaseExecutionAsync(array $args = [])
+ * @method \Aws\Result startWebRTCContact(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise startWebRTCContactAsync(array $args = [])
+ * @method \Aws\Result stopContact(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise stopContactAsync(array $args = [])
+ * @method \Aws\Result stopContactMediaProcessing(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise stopContactMediaProcessingAsync(array $args = [])
+ * @method \Aws\Result stopContactRecording(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise stopContactRecordingAsync(array $args = [])
+ * @method \Aws\Result stopContactStreaming(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise stopContactStreamingAsync(array $args = [])
+ * @method \Aws\Result stopTestCaseExecution(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise stopTestCaseExecutionAsync(array $args = [])
+ * @method \Aws\Result submitContactEvaluation(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise submitContactEvaluationAsync(array $args = [])
+ * @method \Aws\Result suspendContactRecording(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise suspendContactRecordingAsync(array $args = [])
+ * @method \Aws\Result tagContact(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise tagContactAsync(array $args = [])
+ * @method \Aws\Result tagResource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise tagResourceAsync(array $args = [])
+ * @method \Aws\Result transferContact(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise transferContactAsync(array $args = [])
+ * @method \Aws\Result untagContact(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise untagContactAsync(array $args = [])
+ * @method \Aws\Result untagResource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise untagResourceAsync(array $args = [])
+ * @method \Aws\Result updateAgentStatus(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateAgentStatusAsync(array $args = [])
+ * @method \Aws\Result updateAttachedFilesConfiguration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateAttachedFilesConfigurationAsync(array $args = [])
+ * @method \Aws\Result updateAuthenticationProfile(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateAuthenticationProfileAsync(array $args = [])
+ * @method \Aws\Result updateContact(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateContactAsync(array $args = [])
+ * @method \Aws\Result updateContactAttributes(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateContactAttributesAsync(array $args = [])
+ * @method \Aws\Result updateContactEvaluation(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateContactEvaluationAsync(array $args = [])
+ * @method \Aws\Result updateContactFlowContent(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateContactFlowContentAsync(array $args = [])
+ * @method \Aws\Result updateContactFlowMetadata(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateContactFlowMetadataAsync(array $args = [])
+ * @method \Aws\Result updateContactFlowModuleAlias(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateContactFlowModuleAliasAsync(array $args = [])
+ * @method \Aws\Result updateContactFlowModuleContent(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateContactFlowModuleContentAsync(array $args = [])
+ * @method \Aws\Result updateContactFlowModuleMetadata(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateContactFlowModuleMetadataAsync(array $args = [])
+ * @method \Aws\Result updateContactFlowName(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateContactFlowNameAsync(array $args = [])
+ * @method \Aws\Result updateContactRoutingData(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateContactRoutingDataAsync(array $args = [])
+ * @method \Aws\Result updateContactSchedule(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateContactScheduleAsync(array $args = [])
+ * @method \Aws\Result updateDataTableAttribute(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateDataTableAttributeAsync(array $args = [])
+ * @method \Aws\Result updateDataTableMetadata(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateDataTableMetadataAsync(array $args = [])
+ * @method \Aws\Result updateDataTablePrimaryValues(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateDataTablePrimaryValuesAsync(array $args = [])
+ * @method \Aws\Result updateEmailAddressMetadata(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateEmailAddressMetadataAsync(array $args = [])
+ * @method \Aws\Result updateEvaluationForm(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateEvaluationFormAsync(array $args = [])
+ * @method \Aws\Result updateHoursOfOperation(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateHoursOfOperationAsync(array $args = [])
+ * @method \Aws\Result updateHoursOfOperationOverride(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateHoursOfOperationOverrideAsync(array $args = [])
+ * @method \Aws\Result updateInstanceAttribute(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateInstanceAttributeAsync(array $args = [])
+ * @method \Aws\Result updateInstanceStorageConfig(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateInstanceStorageConfigAsync(array $args = [])
+ * @method \Aws\Result updateNotificationContent(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateNotificationContentAsync(array $args = [])
+ * @method \Aws\Result updateParticipantAuthentication(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateParticipantAuthenticationAsync(array $args = [])
+ * @method \Aws\Result updateParticipantRoleConfig(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateParticipantRoleConfigAsync(array $args = [])
+ * @method \Aws\Result updatePhoneNumber(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updatePhoneNumberAsync(array $args = [])
+ * @method \Aws\Result updatePhoneNumberMetadata(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updatePhoneNumberMetadataAsync(array $args = [])
+ * @method \Aws\Result updatePredefinedAttribute(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updatePredefinedAttributeAsync(array $args = [])
+ * @method \Aws\Result updatePrompt(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updatePromptAsync(array $args = [])
+ * @method \Aws\Result updateQueueHoursOfOperation(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateQueueHoursOfOperationAsync(array $args = [])
+ * @method \Aws\Result updateQueueMaxContacts(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateQueueMaxContactsAsync(array $args = [])
+ * @method \Aws\Result updateQueueName(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateQueueNameAsync(array $args = [])
+ * @method \Aws\Result updateQueueOutboundCallerConfig(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateQueueOutboundCallerConfigAsync(array $args = [])
+ * @method \Aws\Result updateQueueOutboundEmailConfig(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateQueueOutboundEmailConfigAsync(array $args = [])
+ * @method \Aws\Result updateQueueStatus(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateQueueStatusAsync(array $args = [])
+ * @method \Aws\Result updateQuickConnectConfig(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateQuickConnectConfigAsync(array $args = [])
+ * @method \Aws\Result updateQuickConnectName(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateQuickConnectNameAsync(array $args = [])
+ * @method \Aws\Result updateRoutingProfileAgentAvailabilityTimer(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateRoutingProfileAgentAvailabilityTimerAsync(array $args = [])
+ * @method \Aws\Result updateRoutingProfileConcurrency(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateRoutingProfileConcurrencyAsync(array $args = [])
+ * @method \Aws\Result updateRoutingProfileDefaultOutboundQueue(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateRoutingProfileDefaultOutboundQueueAsync(array $args = [])
+ * @method \Aws\Result updateRoutingProfileName(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateRoutingProfileNameAsync(array $args = [])
+ * @method \Aws\Result updateRoutingProfileQueues(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateRoutingProfileQueuesAsync(array $args = [])
+ * @method \Aws\Result updateRule(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateRuleAsync(array $args = [])
+ * @method \Aws\Result updateSecurityProfile(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateSecurityProfileAsync(array $args = [])
+ * @method \Aws\Result updateTaskTemplate(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateTaskTemplateAsync(array $args = [])
+ * @method \Aws\Result updateTestCase(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateTestCaseAsync(array $args = [])
+ * @method \Aws\Result updateTrafficDistribution(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateTrafficDistributionAsync(array $args = [])
+ * @method \Aws\Result updateUserConfig(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateUserConfigAsync(array $args = [])
+ * @method \Aws\Result updateUserHierarchy(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateUserHierarchyAsync(array $args = [])
+ * @method \Aws\Result updateUserHierarchyGroupName(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateUserHierarchyGroupNameAsync(array $args = [])
+ * @method \Aws\Result updateUserHierarchyStructure(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateUserHierarchyStructureAsync(array $args = [])
+ * @method \Aws\Result updateUserIdentityInfo(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateUserIdentityInfoAsync(array $args = [])
+ * @method \Aws\Result updateUserNotificationStatus(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateUserNotificationStatusAsync(array $args = [])
+ * @method \Aws\Result updateUserPhoneConfig(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateUserPhoneConfigAsync(array $args = [])
+ * @method \Aws\Result updateUserProficiencies(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateUserProficienciesAsync(array $args = [])
+ * @method \Aws\Result updateUserRoutingProfile(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateUserRoutingProfileAsync(array $args = [])
+ * @method \Aws\Result updateUserSecurityProfiles(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateUserSecurityProfilesAsync(array $args = [])
+ * @method \Aws\Result updateViewContent(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateViewContentAsync(array $args = [])
+ * @method \Aws\Result updateViewMetadata(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateViewMetadataAsync(array $args = [])
+ * @method \Aws\Result updateWorkspaceMetadata(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateWorkspaceMetadataAsync(array $args = [])
+ * @method \Aws\Result updateWorkspacePage(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateWorkspacePageAsync(array $args = [])
+ * @method \Aws\Result updateWorkspaceTheme(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateWorkspaceThemeAsync(array $args = [])
+ * @method \Aws\Result updateWorkspaceVisibility(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateWorkspaceVisibilityAsync(array $args = [])
+ */
+class ConnectClient extends AwsClient {}

+ 468 - 0
upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/Credentials/InstanceProfileProvider.php

@@ -0,0 +1,468 @@
+<?php
+namespace Aws\Credentials;
+
+use Aws\Configuration\ConfigurationResolver;
+use Aws\Exception\CredentialsException;
+use Aws\Exception\InvalidJsonException;
+use Aws\Sdk;
+use GuzzleHttp\Exception\TransferException;
+use GuzzleHttp\Promise;
+use GuzzleHttp\Psr7\Request;
+use GuzzleHttp\Promise\PromiseInterface;
+use Psr\Http\Message\ResponseInterface;
+
+/**
+ * Credential provider that provides credentials from the EC2 metadata service.
+ */
+class InstanceProfileProvider
+{
+    const CRED_PATH = 'meta-data/iam/security-credentials/';
+    const TOKEN_PATH = 'api/token';
+    const ENV_DISABLE = 'AWS_EC2_METADATA_DISABLED';
+    const ENV_TIMEOUT = 'AWS_METADATA_SERVICE_TIMEOUT';
+    const ENV_RETRIES = 'AWS_METADATA_SERVICE_NUM_ATTEMPTS';
+    const CFG_EC2_METADATA_V1_DISABLED = 'ec2_metadata_v1_disabled';
+    const CFG_EC2_METADATA_SERVICE_ENDPOINT = 'ec2_metadata_service_endpoint';
+    const CFG_EC2_METADATA_SERVICE_ENDPOINT_MODE = 'ec2_metadata_service_endpoint_mode';
+    const DEFAULT_TIMEOUT = 1.0;
+    const DEFAULT_RETRIES = 3;
+    const DEFAULT_TOKEN_TTL_SECONDS = 21600;
+    const DEFAULT_AWS_EC2_METADATA_V1_DISABLED = false;
+    const ENDPOINT_MODE_IPv4 = 'IPv4';
+    const ENDPOINT_MODE_IPv6 = 'IPv6';
+    const DEFAULT_METADATA_SERVICE_IPv4_ENDPOINT = 'http://169.254.169.254';
+    const DEFAULT_METADATA_SERVICE_IPv6_ENDPOINT = 'http://[fd00:ec2::254]';
+
+    /** @var string */
+    private $profile;
+
+    /** @var callable */
+    private $client;
+
+    /** @var int */
+    private $retries;
+
+    /** @var int */
+    private $attempts;
+
+    /** @var float|mixed */
+    private $timeout;
+
+    /** @var bool */
+    private $secureMode = true;
+
+    /** @var bool|null */
+    private $ec2MetadataV1Disabled;
+
+    /** @var string */
+    private $endpoint;
+
+    /** @var string */
+    private $endpointMode;
+
+    /** @var array */
+    private $config;
+
+    /**
+     * The constructor accepts the following options:
+     *
+     * - timeout: Connection timeout, in seconds.
+     * - profile: Optional EC2 profile name, if known.
+     * - retries: Optional number of retries to be attempted.
+     * - ec2_metadata_v1_disabled: Optional for disabling the fallback to IMDSv1.
+     * - endpoint: Optional for overriding the default endpoint to be used for fetching credentials.
+     *   The value must contain a valid URI scheme. If the URI scheme is not https, it must
+     *   resolve to a loopback address.
+     * - endpoint_mode: Optional for overriding the default endpoint mode (IPv4|IPv6) to be used for
+     *   resolving the default endpoint.
+     * - use_aws_shared_config_files: Decides whether the shared config file should be considered when
+     *   using the ConfigurationResolver::resolve method.
+     *
+     * @param array $config Configuration options.
+     */
+    public function __construct(array $config = [])
+    {
+        $this->timeout = (float) getenv(self::ENV_TIMEOUT) ?: ($config['timeout'] ?? self::DEFAULT_TIMEOUT);
+        $this->profile = $config['profile'] ?? null;
+        $this->retries = (int) getenv(self::ENV_RETRIES) ?: ($config['retries'] ?? self::DEFAULT_RETRIES);
+        $this->client = $config['client'] ?? \Aws\default_http_handler();
+        $this->ec2MetadataV1Disabled = $config[self::CFG_EC2_METADATA_V1_DISABLED] ?? null;
+        $this->endpoint = $config[self::CFG_EC2_METADATA_SERVICE_ENDPOINT] ?? null;
+        if (!empty($this->endpoint) && !$this->isValidEndpoint($this->endpoint)) {
+            throw new \InvalidArgumentException('The provided URI "' . $this->endpoint . '" is invalid, or contains an unsupported host');
+        }
+
+        $this->endpointMode = $config[self::CFG_EC2_METADATA_SERVICE_ENDPOINT_MODE] ?? null;
+        $this->config = $config;
+    }
+
+    /**
+     * Loads instance profile credentials.
+     *
+     * @return PromiseInterface
+     */
+    public function __invoke($previousCredentials = null)
+    {
+        $this->attempts = 0;
+        return Promise\Coroutine::of(function () use ($previousCredentials) {
+
+            // Retrieve token or switch out of secure mode
+            $token = null;
+            while ($this->secureMode && is_null($token)) {
+                try {
+                    $token = (yield $this->request(
+                        self::TOKEN_PATH,
+                        'PUT',
+                        [
+                            'x-aws-ec2-metadata-token-ttl-seconds' => self::DEFAULT_TOKEN_TTL_SECONDS
+                        ]
+                    ));
+                } catch (TransferException $e) {
+                    if ($this->getExceptionStatusCode($e) === 500
+                        && $previousCredentials instanceof Credentials
+                    ) {
+                        goto generateCredentials;
+                    } elseif ($this->shouldFallbackToIMDSv1()
+                        && (!method_exists($e, 'getResponse')
+                        || empty($e->getResponse())
+                        || !in_array(
+                            $e->getResponse()->getStatusCode(),
+                            [400, 500, 502, 503, 504]
+                        ))
+                    ) {
+                        $this->secureMode = false;
+                    } else {
+                        $this->handleRetryableException(
+                            $e,
+                            [],
+                            $this->createErrorMessage(
+                                'Error retrieving metadata token'
+                            )
+                        );
+                    }
+                }
+                $this->attempts++;
+            }
+
+            // Set token header only for secure mode
+            $headers = [];
+            if ($this->secureMode) {
+                $headers = [
+                    'x-aws-ec2-metadata-token' => $token
+                ];
+            }
+
+            // Retrieve profile
+            while (!$this->profile) {
+                try {
+                    $this->profile = (yield $this->request(
+                        self::CRED_PATH,
+                        'GET',
+                        $headers
+                    ));
+                } catch (TransferException $e) {
+                    // 401 indicates insecure flow not supported, switch to
+                    // attempting secure mode for subsequent calls
+                    if (!empty($this->getExceptionStatusCode($e))
+                        && $this->getExceptionStatusCode($e) === 401
+                    ) {
+                        $this->secureMode = true;
+                    }
+                    $this->handleRetryableException(
+                        $e,
+                        [ 'blacklist' => [401, 403] ],
+                        $this->createErrorMessage($e->getMessage())
+                    );
+                }
+
+                $this->attempts++;
+            }
+
+            // Retrieve credentials
+            $result = null;
+            while ($result == null) {
+                try {
+                    $json = (yield $this->request(
+                        self::CRED_PATH . $this->profile,
+                        'GET',
+                        $headers
+                    ));
+                    $result = $this->decodeResult($json);
+                } catch (InvalidJsonException $e) {
+                    $this->handleRetryableException(
+                        $e,
+                        [ 'blacklist' => [401, 403] ],
+                        $this->createErrorMessage(
+                            'Invalid JSON response, retries exhausted'
+                        )
+                    );
+                } catch (TransferException $e) {
+                    // 401 indicates insecure flow not supported, switch to
+                    // attempting secure mode for subsequent calls
+                    if (($this->getExceptionStatusCode($e) === 500
+                            || strpos($e->getMessage(), "cURL error 28") !== false)
+                        && $previousCredentials instanceof Credentials
+                    ) {
+                        goto generateCredentials;
+                    } elseif (!empty($this->getExceptionStatusCode($e))
+                        && $this->getExceptionStatusCode($e) === 401
+                    ) {
+                        $this->secureMode = true;
+                    }
+                    $this->handleRetryableException(
+                        $e,
+                        [ 'blacklist' => [401, 403] ],
+                        $this->createErrorMessage($e->getMessage())
+                    );
+                }
+                $this->attempts++;
+            }
+            generateCredentials:
+
+            if (!isset($result)) {
+                $credentials = $previousCredentials;
+            } else {
+                $credentials = new Credentials(
+                    $result['AccessKeyId'],
+                    $result['SecretAccessKey'],
+                    $result['Token'],
+                    strtotime($result['Expiration']),
+                    $result['AccountId'] ?? null,
+                    CredentialSources::IMDS
+                );
+            }
+
+            if ($credentials->isExpired()) {
+                $credentials->extendExpiration();
+            }
+
+            yield $credentials;
+        });
+    }
+
+    /**
+     * @param string $url
+     * @param string $method
+     * @param array $headers
+     * @return PromiseInterface Returns a promise that is fulfilled with the
+     *                          body of the response as a string.
+     */
+    private function request($url, $method = 'GET', $headers = [])
+    {
+        $disabled = getenv(self::ENV_DISABLE) ?: false;
+        if (strcasecmp($disabled, 'true') === 0) {
+            throw new CredentialsException(
+                $this->createErrorMessage('EC2 metadata service access disabled')
+            );
+        }
+
+        $fn = $this->client;
+        $request = new Request($method, $this->resolveEndpoint() . $url);
+        $userAgent = 'aws-sdk-php/' . Sdk::VERSION;
+        if (defined('HHVM_VERSION')) {
+            $userAgent .= ' HHVM/' . HHVM_VERSION;
+        }
+        $userAgent .= ' ' . \Aws\default_user_agent();
+        $request = $request->withHeader('User-Agent', $userAgent);
+        foreach ($headers as $key => $value) {
+            $request = $request->withHeader($key, (string) $value);
+        }
+
+        return $fn($request, ['timeout' => $this->timeout])
+            ->then(function (ResponseInterface $response) {
+                return (string) $response->getBody();
+            })->otherwise(function (array $reason) {
+                $reason = $reason['exception'];
+                if ($reason instanceof TransferException) {
+                    throw $reason;
+                }
+                $msg = $reason->getMessage();
+                throw new CredentialsException(
+                    $this->createErrorMessage($msg)
+                );
+            });
+    }
+
+    private function handleRetryableException(
+        \Exception $e,
+        $retryOptions,
+        $message
+    ) {
+        $isRetryable = true;
+        if (!empty($status = $this->getExceptionStatusCode($e))
+            && isset($retryOptions['blacklist'])
+            && in_array($status, $retryOptions['blacklist'])
+        ) {
+            $isRetryable = false;
+        }
+        if ($isRetryable && $this->attempts < $this->retries) {
+            sleep((int) pow(1.2, $this->attempts));
+        } else {
+            throw new CredentialsException($message);
+        }
+    }
+
+    private function getExceptionStatusCode(\Exception $e)
+    {
+        if (method_exists($e, 'getResponse')
+            && !empty($e->getResponse())
+        ) {
+            return $e->getResponse()->getStatusCode();
+        }
+        return null;
+    }
+
+    private function createErrorMessage($previous)
+    {
+        return "Error retrieving credentials from the instance profile "
+            . "metadata service. ({$previous})";
+    }
+
+    private function decodeResult($response)
+    {
+        $result = json_decode($response, true);
+
+        if (json_last_error() > 0) {
+            throw new InvalidJsonException();
+        }
+
+        if ($result['Code'] !== 'Success') {
+            throw new CredentialsException('Unexpected instance profile '
+                .  'response code: ' . $result['Code']);
+        }
+
+        return $result;
+    }
+
+    /**
+     * This functions checks for whether we should fall back to IMDSv1 or not.
+     * If $ec2MetadataV1Disabled is null then we will try to resolve this value from
+     * the following sources:
+     * - From environment: "AWS_EC2_METADATA_V1_DISABLED".
+     * - From config file: aws_ec2_metadata_v1_disabled
+     * - Defaulted to false
+     *
+     * @return bool
+     */
+    private function shouldFallbackToIMDSv1(): bool
+    {
+        $isImdsV1Disabled = \Aws\boolean_value($this->ec2MetadataV1Disabled)
+            ?? \Aws\boolean_value(
+                ConfigurationResolver::resolve(
+                    self::CFG_EC2_METADATA_V1_DISABLED,
+                    self::DEFAULT_AWS_EC2_METADATA_V1_DISABLED,
+                    'bool',
+                    $this->config
+                )
+            )
+            ?? self::DEFAULT_AWS_EC2_METADATA_V1_DISABLED;
+
+        return !$isImdsV1Disabled;
+    }
+
+    /**
+     * Resolves the metadata service endpoint. If the endpoint is not provided
+     * or configured then, the default endpoint, based on the endpoint mode resolved,
+     * will be used.
+     * Example: if endpoint_mode is resolved to be IPv4 and the endpoint is not provided
+     * then, the endpoint to be used will be http://169.254.169.254.
+     *
+     * @return string
+     */
+    private function resolveEndpoint(): string
+    {
+        $endpoint = $this->endpoint;
+        if (is_null($endpoint)) {
+            $endpoint = ConfigurationResolver::resolve(
+                self::CFG_EC2_METADATA_SERVICE_ENDPOINT,
+                $this->getDefaultEndpoint(),
+                'string',
+                $this->config
+            );
+        }
+
+        if (!$this->isValidEndpoint($endpoint)) {
+            throw new CredentialsException('The provided URI "' . $endpoint . '" is invalid, or contains an unsupported host');
+        }
+
+        if (substr($endpoint, strlen($endpoint) - 1) !== '/') {
+            $endpoint = $endpoint . '/';
+        }
+
+        return $endpoint . 'latest/';
+    }
+
+    /**
+     * Resolves the default metadata service endpoint.
+     * If endpoint_mode is resolved as IPv4 then:
+     * - endpoint = http://169.254.169.254
+     * If endpoint_mode is resolved as IPv6 then:
+     * - endpoint = http://[fd00:ec2::254]
+     *
+     * @return string
+     */
+    private function getDefaultEndpoint(): string
+    {
+        $endpointMode = $this->resolveEndpointMode();
+        switch ($endpointMode) {
+            case self::ENDPOINT_MODE_IPv4:
+                return self::DEFAULT_METADATA_SERVICE_IPv4_ENDPOINT;
+            case self::ENDPOINT_MODE_IPv6:
+                return self::DEFAULT_METADATA_SERVICE_IPv6_ENDPOINT;
+        }
+
+        throw new CredentialsException("Invalid endpoint mode '$endpointMode' resolved");
+    }
+
+    /**
+     * Resolves the endpoint mode to be considered when resolving the default
+     * metadata service endpoint.
+     *
+     * @return string
+     */
+    private function resolveEndpointMode(): string
+    {
+        $endpointMode = $this->endpointMode;
+        if (is_null($endpointMode)) {
+            $endpointMode = ConfigurationResolver::resolve(
+                self::CFG_EC2_METADATA_SERVICE_ENDPOINT_MODE,
+                    self::ENDPOINT_MODE_IPv4,
+                'string',
+                $this->config
+            );
+        }
+
+        return $endpointMode;
+    }
+
+    /**
+     * This method checks for whether a provide URI is valid.
+     * @param string $uri this parameter is the uri to do the validation against to.
+     *
+     * @return string|null
+     */
+    private function isValidEndpoint(
+        $uri
+    ): bool
+    {
+        // We make sure first the provided uri is a valid URL
+        $isValidURL = filter_var($uri, FILTER_VALIDATE_URL) !== false;
+        if (!$isValidURL) {
+            return false;
+        }
+
+        // We make sure that if is a no secure host then it must be a loop back address.
+        $parsedUri = parse_url($uri);
+        if ($parsedUri['scheme'] !== 'https') {
+            $host = trim($parsedUri['host'], '[]');
+
+            return CredentialsUtils::isLoopBackAddress(gethostbyname($host))
+                || in_array(
+                    $uri,
+                    [self::DEFAULT_METADATA_SERVICE_IPv4_ENDPOINT, self::DEFAULT_METADATA_SERVICE_IPv6_ENDPOINT]
+                );
+        }
+
+        return true;
+    }
+}

+ 109 - 0
upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/Crypto/AesGcmDecryptingStream.php

@@ -0,0 +1,109 @@
+<?php
+namespace Aws\Crypto;
+
+use Aws\Exception\CryptoException;
+use GuzzleHttp\Psr7;
+use GuzzleHttp\Psr7\StreamDecoratorTrait;
+use Psr\Http\Message\StreamInterface;
+
+/**
+ * @internal Represents a stream of data to be gcm decrypted.
+ */
+class AesGcmDecryptingStream implements AesStreamInterface
+{
+    use StreamDecoratorTrait;
+
+    private $aad;
+
+    private $initializationVector;
+
+    private $key;
+
+    private $keySize;
+
+    private $cipherText;
+
+    private $tag;
+
+    private $tagLength;
+
+    /**
+     * @var StreamInterface
+     */
+    private $stream;
+
+    /**
+     * @param StreamInterface $cipherText
+     * @param string $key
+     * @param string $initializationVector
+     * @param string $tag
+     * @param string $aad
+     * @param int $tagLength
+     * @param int $keySize
+     */
+    public function __construct(
+        StreamInterface $cipherText,
+        $key,
+        $initializationVector,
+        $tag,
+        $aad = '',
+        $tagLength = 128,
+        $keySize = 256
+    ) {
+        $this->cipherText = $cipherText;
+        $this->key = $key;
+        $this->initializationVector = $initializationVector;
+        $this->tag = $tag;
+        $this->aad = $aad;
+        $this->tagLength = $tagLength;
+        $this->keySize = $keySize;
+        // unsetting the property forces the first access to go through
+        // __get().
+        unset($this->stream);
+    }
+
+    public function getOpenSslName()
+    {
+        return "aes-{$this->keySize}-gcm";
+    }
+
+    public function getAesName()
+    {
+        return 'AES/GCM/NoPadding';
+    }
+
+    public function getCurrentIv()
+    {
+        return $this->initializationVector;
+    }
+
+    public function createStream()
+    {
+        if (strlen($this->tag) !== 16) {
+            throw new CryptoException(
+                'Unsupported GCM tag length; only 128-bit tags are supported.'
+            );
+        }
+
+        $result = \openssl_decrypt(
+            (string)$this->cipherText,
+            $this->getOpenSslName(),
+            $this->key,
+            OPENSSL_RAW_DATA,
+            $this->initializationVector,
+            $this->tag,
+            $this->aad
+        );
+        if ($result === false) {
+            throw new CryptoException('The requested object could not be '
+            . 'decrypted due to an invalid authentication tag.');
+        }
+        return Psr7\Utils::streamFor($result);
+
+    }
+
+    public function isWritable(): bool
+    {
+        return false;
+    }
+}

+ 424 - 0
upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/Crypto/DecryptionTraitV2.php

@@ -0,0 +1,424 @@
+<?php
+namespace Aws\Crypto;
+
+use Aws\Exception\CryptoException;
+use GuzzleHttp\Psr7;
+use GuzzleHttp\Psr7\LimitStream;
+use Psr\Http\Message\StreamInterface;
+
+trait DecryptionTraitV2
+{
+    /**
+     * Dependency to reverse lookup the openssl_* cipher name from the AESName
+     * in the MetadataEnvelope.
+     *
+     * @param $aesName
+     *
+     * @return string
+     *
+     * @internal
+     */
+    abstract protected function getCipherFromAesName($aesName);
+
+    /**
+     * Dependency to generate a CipherMethod from a set of inputs for loading
+     * in to an AesDecryptingStream.
+     *
+     * @param string $cipherName Name of the cipher to generate for decrypting.
+     * @param string $iv Base Initialization Vector for the cipher.
+     * @param int $keySize Size of the encryption key, in bits, that will be
+     *                     used.
+     *
+     * @return Cipher\CipherMethod
+     *
+     * @internal
+     */
+    abstract protected function buildCipherMethod($cipherName, $iv, $keySize);
+
+    /**
+     * Builds an AesStreamInterface using cipher options loaded from the
+     * MetadataEnvelope and MaterialsProvider. Can decrypt data from both the
+     * legacy and V2 encryption client workflows.
+     *
+     * @param string $cipherText Plain-text data to be encrypted using the
+     *                           materials, algorithm, and data provided.
+     * @param MaterialsProviderInterfaceV2 $provider A provider to supply and encrypt
+     *                                             materials used in encryption.
+     * @param MetadataEnvelope $envelope A storage envelope for encryption
+     *                                   metadata to be read from.
+     * @param array $options Options used for decryption.
+     *
+     * @return AesStreamInterface
+     *
+     * @throws \InvalidArgumentException Thrown when a value in $cipherOptions
+     *                                   is not valid.
+     *
+     * @internal
+     */
+    public function decrypt(
+        $cipherText,
+        MaterialsProviderInterfaceV2 $provider,
+        MetadataEnvelope $envelope,
+        array $options = []
+    ) 
+    {
+        $commitmentPolicy = $this->getKeyCommitmentPolicy($options);
+        unset($options['@CommitmentPolicy']);
+        if (isset($envelope[MetadataEnvelope::ENCRYPTED_DATA_KEY_V3])) {
+            if ($commitmentPolicy !== "FORBID_ENCRYPT_ALLOW_DECRYPT") {
+                throw new CryptoException(
+                    "The requested item is encrypted"
+                    . " with Key Commitment. The current policy {$commitmentPolicy}"
+                    . " conflicts with the object metadata. Select an appropriate"
+                    . " '@CommitmentPolicy' to decrypt this item."
+                );
+            }
+            $algorithmSuite = AlgorithmSuite::ALG_AES_256_GCM_HKDF_SHA512_COMMIT_KEY;
+            $options['@CipherOptions'] = $options['@CipherOptions'] ?? [];
+            $options['@CipherOptions']['Iv'] = str_repeat("\1", 12);
+            $options['@CipherOptions']['TagLength'] = $algorithmSuite->getCipherTagLengthInBytes();
+            $materialDescription = json_decode(
+                $envelope[MetadataEnvelope::ENCRYPTION_CONTEXT_V3],
+                true
+            );
+
+
+            $cek = $provider->decryptCek(
+                base64_decode($envelope[MetadataEnvelope::ENCRYPTED_DATA_KEY_V3]),
+                $materialDescription,
+                $options
+            );
+
+            $options['@CipherOptions']['KeySize'] = strlen($cek) * 8;
+            $options['@CipherOptions']['Cipher'] = $this->getCipherFromAesName(
+                $this->numericalContenCipherToAesName($envelope)
+            );
+            $this->validateOptionsAndEnvelope($options, $envelope);
+
+            $messageId = base64_decode($envelope[MetadataEnvelope::MESSAGE_ID_V3]);
+            $commitmentKey = base64_decode($envelope[MetadataEnvelope::KEY_COMMITMENT_V3]);
+
+            if (strlen($messageId) !== ($algorithmSuite->getKeyCommitmentSaltLengthBits()) / 8) {
+                throw new CryptoException("Invalid MessageId length found in object envelope.");
+            }
+
+            if (strlen($commitmentKey) !== $algorithmSuite->getCommitmentOutputKeyLengthBytes()) {
+                throw new CryptoException("Invalid Commitment Key length found in object envelope.");
+            }
+
+            $decryptionStream = $this->getCommitingDecryptingStream(
+                $cipherText,
+                $cek,
+                $options['@CipherOptions'],
+                $messageId,
+                $commitmentKey,
+                $algorithmSuite
+            );
+            unset($cek);
+
+            return $decryptionStream;
+        } else {
+            $options['@CipherOptions'] = $options['@CipherOptions'] ?? [];
+            $options['@CipherOptions']['Iv'] = base64_decode(
+                $envelope[MetadataEnvelope::IV_HEADER]
+            );
+
+            $options['@CipherOptions']['TagLength'] =
+                $envelope[MetadataEnvelope::CRYPTO_TAG_LENGTH_HEADER] / 8;
+
+            $cek = $provider->decryptCek(
+                base64_decode(
+                    $envelope[MetadataEnvelope::CONTENT_KEY_V2_HEADER]
+                ),
+                json_decode(
+                    $envelope[MetadataEnvelope::MATERIALS_DESCRIPTION_HEADER],
+                    true
+                ),
+                $options
+            );
+            $options['@CipherOptions']['KeySize'] = strlen($cek) * 8;
+            $options['@CipherOptions']['Cipher'] = $this->getCipherFromAesName(
+                $envelope[MetadataEnvelope::CONTENT_CRYPTO_SCHEME_HEADER]
+            );
+
+            $this->validateOptionsAndEnvelope($options, $envelope);
+
+            $decryptionStream = $this->getDecryptingStream(
+                $cipherText,
+                $cek,
+                $options['@CipherOptions']
+            );
+            unset($cek);
+
+            return $decryptionStream;
+        }
+    }
+
+    private function buildMaterialDescription(
+        MetadataEnvelope $envelope
+    ): array 
+    {
+        switch ($envelope[MetadataEnvelope::ENCRYPTED_DATA_KEY_ALGORITHM_V3]) {
+            case 12:
+                return ['aws:x-amz-cek-alg' => '115'];
+            default:
+                throw new CryptoException(
+                    "Unknown Encrypted Data Key "
+                    . "wrapping algorithm found: "
+                    . "{$envelope[MetadataEnvelope::ENCRYPTED_DATA_KEY_ALGORITHM_V3]}"
+                );
+        }
+    }
+
+    private function numericalContenCipherToAesName(
+        MetadataEnvelope $envelope
+    ): string
+    {
+        switch ($envelope[MetadataEnvelope::CONTENT_CIPHER_V3]) {
+            case 115:
+                return 'AES/GCM/NoPadding';
+            default:
+                throw new CryptoException(
+                    "Unknown Encrypted Data Key "
+                    . "wrapping algorithm found: "
+                    . "{$envelope[MetadataEnvelope::ENCRYPTED_DATA_KEY_ALGORITHM_V3]}"
+                );
+        }
+
+    }
+
+    private function getTagFromCiphertextStream(
+        StreamInterface $cipherText,
+        $tagLength
+    ) 
+    {
+        $cipherTextSize = $cipherText->getSize();
+        if ($cipherTextSize == null || $cipherTextSize <= 0) {
+            throw new \RuntimeException('Cannot decrypt a stream of unknown'
+                . ' size.');
+        }
+        return (string) new LimitStream(
+            $cipherText,
+            $tagLength,
+            $cipherTextSize - $tagLength
+        );
+    }
+
+    private function getStrippedCiphertextStream(
+        StreamInterface $cipherText,
+        $tagLength
+    ) 
+    {
+        $cipherTextSize = $cipherText->getSize();
+        if ($cipherTextSize == null || $cipherTextSize <= 0) {
+            throw new \RuntimeException('Cannot decrypt a stream of unknown'
+                . ' size.');
+        }
+        return new LimitStream(
+            $cipherText,
+            $cipherTextSize - $tagLength,
+            0
+        );
+    }
+
+    private function validateOptionsAndEnvelope($options, $envelope): void
+    {
+        $allowedCiphers = AbstractCryptoClientV2::$supportedCiphers;
+        $allowedKeywraps = AbstractCryptoClientV2::$supportedKeyWraps;
+        if ($options['@SecurityProfile'] == 'V2_AND_LEGACY') {
+            $allowedCiphers = array_unique(array_merge(
+                $allowedCiphers,
+                AbstractCryptoClient::$supportedCiphers
+            ));
+            $allowedKeywraps = array_unique(array_merge(
+                $allowedKeywraps,
+                AbstractCryptoClient::$supportedKeyWraps
+            ));
+        }
+
+        $v1SchemaException = new CryptoException("The requested object is encrypted"
+            . " with V1 encryption schemas that have been disabled by"
+            . " client configuration @SecurityProfile=V2. Retry with"
+            . " V2_AND_LEGACY enabled or reencrypt the object.");
+
+        if (!in_array($options['@CipherOptions']['Cipher'], $allowedCiphers)) {
+            if (in_array($options['@CipherOptions']['Cipher'], AbstractCryptoClient::$supportedCiphers)) {
+                throw $v1SchemaException;
+            }
+            throw new CryptoException("The requested object is encrypted with"
+                . " the cipher '{$options['@CipherOptions']['Cipher']}', which is not"
+                . " supported for decryption with the selected security profile."
+                . " This profile allows decryption with: "
+                . implode(", ", $allowedCiphers));
+        }
+
+        if (isset($envelope[MetadataEnvelope::ENCRYPTED_DATA_KEY_V3])) {
+            if ($envelope[MetadataEnvelope::ENCRYPTED_DATA_KEY_ALGORITHM_V3] !== '12') {
+                throw new CryptoException("The requested object is encrypted with"
+                    . " the keywrap schema '{$envelope[MetadataEnvelope::ENCRYPTED_DATA_KEY_ALGORITHM_V3]}',"
+                    . " which is not supported for decryption with the current security"
+                    . " profile.");
+            }
+        } else {
+            if (!in_array($envelope[MetadataEnvelope::KEY_WRAP_ALGORITHM_HEADER], $allowedKeywraps)) {
+                if (in_array($envelope[MetadataEnvelope::KEY_WRAP_ALGORITHM_HEADER], AbstractCryptoClient::$supportedKeyWraps)) {
+                    throw $v1SchemaException;
+                }
+
+                throw new CryptoException("The requested object is encrypted with"
+                    . " the keywrap schema '{$envelope[MetadataEnvelope::KEY_WRAP_ALGORITHM_HEADER]}',"
+                    . " which is not supported for decryption with the current security"
+                    . " profile.");
+            }
+            $matdesc = json_decode(
+                $envelope[MetadataEnvelope::MATERIALS_DESCRIPTION_HEADER],
+                true
+            );
+            if (isset($matdesc['aws:x-amz-cek-alg'])
+                && ($envelope[MetadataEnvelope::CONTENT_CRYPTO_SCHEME_HEADER]
+                    !== $matdesc['aws:x-amz-cek-alg'])
+            ) {
+                throw new CryptoException("There is a mismatch in specified content"
+                    . " encryption algrithm between the materials description value"
+                    . " and the metadata envelope value: {$matdesc['aws:x-amz-cek-alg']}"
+                    . " vs. {$envelope[MetadataEnvelope::CONTENT_CRYPTO_SCHEME_HEADER]}.");
+            }
+        }
+    }
+
+    /**
+     * Generates a stream that wraps the cipher text with the proper cipher and
+     * uses the content encryption key (CEK) to decrypt the data when read.
+     *
+     * @param string $cipherText Plain-text data to be encrypted using the
+     *                           materials, algorithm, and data provided.
+     * @param string $cek A content encryption key for use by the stream for
+     *                    encrypting the plaintext data.
+     * @param array $cipherOptions Options for use in determining the cipher to
+     *                             be used for encrypting data.
+     *
+     * @return AesStreamInterface
+     *
+     * @internal
+     */
+    protected function getDecryptingStream(
+        $cipherText,
+        $cek,
+        $cipherOptions
+    ) 
+    {
+        $cipherTextStream = Psr7\Utils::streamFor($cipherText);
+        switch ($cipherOptions['Cipher']) {
+            case 'gcm':
+                $cipherOptions['Tag'] = $this->getTagFromCiphertextStream(
+                    $cipherTextStream,
+                    $cipherOptions['TagLength']
+                );
+
+                return new AesGcmDecryptingStream(
+                    $this->getStrippedCiphertextStream(
+                        $cipherTextStream,
+                        $cipherOptions['TagLength']
+                    ),
+                    $cek,
+                    $cipherOptions['Iv'],
+                    $cipherOptions['Tag'],
+                    $cipherOptions['Aad'] = $cipherOptions['Aad'] ?? '',
+                    $cipherOptions['TagLength'] ?: null,
+                    $cipherOptions['KeySize']
+                );
+            default:
+                $cipherMethod = $this->buildCipherMethod(
+                    $cipherOptions['Cipher'],
+                    $cipherOptions['Iv'],
+                    $cipherOptions['KeySize']
+                );
+                return new AesDecryptingStream(
+                    $cipherTextStream,
+                    $cek,
+                    $cipherMethod
+                );
+        }
+    }
+
+    /**
+     * Generates a stream that wraps the cipher text with the proper cipher and
+     * uses the content encryption key (CEK) to derive both a derived content encryption key
+     * and a commitment key to decrypt the data when read.
+     *
+     * @param string $cipherText Plain-text data to be encrypted using the
+     *                           materials, algorithm, and data provided.
+     * @param string $cek A content encryption key for use by the stream for
+     *                    encrypting the plaintext data.
+     * @param array $cipherOptions Options for use in determining the cipher to
+     *                             be used for encrypting data.
+     * @param string $messageId a string value used to calculate both a commitment
+     *                          key and derived content encryption key
+     * @param string $commitmentKey a string value to compare with the calculated commitment
+     *                              key value, if the values don't match an exception is raised.
+     *
+     * @return AesStreamInterface | CryptoException
+     *
+     * @internal
+     */
+    protected function getCommitingDecryptingStream(
+        string $cipherText,
+        string $cek,
+        array $cipherOptions,
+        string $messageId,
+        string $commitmentKey,
+        AlgorithmSuite $algorithmSuite
+    ): AesStreamInterface|CryptoException
+    {
+        $algorithmSuiteIdAsBytes = pack('n', $algorithmSuite->getId());
+        $derivedEncryptionKeyInfo = $algorithmSuiteIdAsBytes . "DERIVEKEY";
+        $commitmentKeyInfo = $algorithmSuiteIdAsBytes . "COMMITKEY";
+        $derivedEncryptionKey = hash_hkdf(
+            $algorithmSuite->getHashingAlgorithm(),
+            $cek,
+            $algorithmSuite->getDerivationOutputKeyLengthBytes(),
+            $derivedEncryptionKeyInfo,
+            $messageId
+        );
+        $calculatedCommitmentKey = hash_hkdf(
+            $algorithmSuite->getHashingAlgorithm(),
+            $cek,
+            $algorithmSuite->getCommitmentOutputKeyLengthBytes(),
+            $commitmentKeyInfo,
+            $messageId
+        );
+
+        if ($commitmentKey != $calculatedCommitmentKey) {
+            throw new CryptoException("Calculated commitment key does "
+                . "not match expected commitment key value ");
+        }
+
+        $cipherTextStream = Psr7\Utils::streamFor($cipherText);
+        switch ($cipherOptions['Cipher']) {
+            case 'gcm':
+                $cipherOptions['Tag'] = $this->getTagFromCiphertextStream(
+                    $cipherTextStream,
+                    $cipherOptions['TagLength']
+                );
+                $cipherOptions['Aad'] = isset($cipherOptions['Aad'])
+                    ? $cipherOptions['Aad'] . $algorithmSuiteIdAsBytes
+                    : $algorithmSuiteIdAsBytes;
+
+                return new AesGcmDecryptingStream(
+                    $this->getStrippedCiphertextStream(
+                        $cipherTextStream,
+                        $cipherOptions['TagLength']
+                    ),
+                    $derivedEncryptionKey,
+                    $cipherOptions['Iv'],
+                    $cipherOptions['Tag'],
+                    $cipherOptions['Aad'],
+                    $cipherOptions['TagLength'] ?: null,
+                    $cipherOptions['KeySize']
+                );
+            default: 
+                throw new CryptoException("Unsupported Cipher used for key commitment messages."
+                    . " Found {$cipherOptions["Cipher"]}. Only 'gcm' is supported.");
+        }
+    }
+}

+ 530 - 0
upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/Crypto/DecryptionTraitV3.php

@@ -0,0 +1,530 @@
+<?php
+
+namespace Aws\Crypto;
+
+use Aws\Crypto\Cipher\CipherMethod;
+use Aws\Exception\CryptoException;
+use GuzzleHttp\Psr7;
+use GuzzleHttp\Psr7\LimitStream;
+use PHPUnit\Framework\Constraint\IsEmpty;
+use Psr\Http\Message\StreamInterface;
+
+trait DecryptionTraitV3
+{
+    /**
+     * Dependency to reverse lookup the openssl_* cipher name from the AESName
+     * in the MetadataEnvelope.
+     *
+     * @param string $aesName
+     *
+     * @return string
+     *
+     * @internal
+     */
+    abstract protected function getCipherFromAesName($aesName);
+
+    /**
+     * Dependency to generate a CipherMethod from a set of inputs for loading
+     * in to an AesDecryptingStream.
+     *
+     * @param string $cipherName Name of the cipher to generate for decrypting.
+     * @param string $iv Base Initialization Vector for the cipher.
+     * @param int $keySize Size of the encryption key, in bits, that will be
+     *                     used.
+     *
+     * @return Cipher\CipherMethod
+     *
+     * @internal
+     */
+    abstract protected function buildCipherMethod(
+        $cipherName,
+        $iv,
+        $keySize
+    );
+
+    /**
+     * Builds an AesStreamInterface using cipher options loaded from the
+     * MetadataEnvelope and MaterialsProvider. Can decrypt data from both the
+     * legacy and V3 encryption client workflows.
+     *
+     * @param string $cipherText Plain-text data to be encrypted using the
+     *                           materials, algorithm, and data provided.
+     * @param MaterialsProviderInterfaceV3 $provider A provider to supply and encrypt
+     *                                             materials used in encryption.
+     * @param MetadataEnvelope $envelope A storage envelope for encryption
+     *                                   metadata to be read from.
+     * @param string $commitmentPolicy Commitment Policy to use for decrypting objects.
+     * @param array $options Options used for decryption.
+     *
+     * @return AesStreamInterface
+     *
+     * @throws \InvalidArgumentException Thrown when a value in $cipherOptions
+     *                                   is not valid.
+     *
+     * @internal
+     */
+    public function decrypt(
+        string $cipherText,
+        MaterialsProviderInterfaceV3 $provider,
+        MetadataEnvelope $envelope,
+        string $commitmentPolicy,
+        array $options = []
+    ): AesStreamInterface 
+    {
+        if (isset($envelope[MetadataEnvelope::ENCRYPTED_DATA_KEY_V3])) {
+            $this->checkEnvelopeForExclusiveMapKeys(
+                $envelope,
+                MetadataEnvelope::getV2Fields(),
+                "Expected V3 only fields but found V2 fields in header metadata."
+            );
+            // PHP only supports one commiting algorithm suite
+            $algorithmSuite = AlgorithmSuite::ALG_AES_256_GCM_HKDF_SHA512_COMMIT_KEY;
+            $options['@CipherOptions'] = $options['@CipherOptions'] ?? [];
+            $options['@CipherOptions']['Iv'] = str_repeat("\1", 12);
+            $options['@CipherOptions']['TagLength'] = $algorithmSuite->getCipherTagLengthInBytes();
+
+            //= ../specification/s3-encryption/data-format/content-metadata.md#v3-only
+            //= type=implication
+            //# - The wrapping algorithm value "12" MUST be translated to kms+context upon retrieval, and vice versa on write.
+            $materialDescription = $this->buildMaterialDescription($envelope);
+
+            $cek = $provider->decryptCek(
+                base64_decode($envelope[MetadataEnvelope::ENCRYPTED_DATA_KEY_V3]),
+                $materialDescription,
+                $options
+            );
+
+            $options['@CipherOptions']['KeySize'] = strlen($cek) * 8;
+            $options['@CipherOptions']['Cipher'] = $this->getCipherFromAesName(
+                $this->numericalContenCipherToAesName($envelope)
+            );
+            $this->validateOptionsAndEnvelope($options, $envelope, $commitmentPolicy);
+
+            $messageId = base64_decode($envelope[MetadataEnvelope::MESSAGE_ID_V3]);
+            $commitmentKey = base64_decode($envelope[MetadataEnvelope::KEY_COMMITMENT_V3]);
+            
+            if (strlen($messageId) !== ($algorithmSuite->getKeyCommitmentSaltLengthBits()) / 8) {
+                throw new CryptoException("Invalid MessageId length found in object envelope.");
+            }
+
+            if (strlen($commitmentKey) !== $algorithmSuite->getCommitmentOutputKeyLengthBytes()) {
+                throw new CryptoException("Invalid Commitment Key length found in object envelope.");
+            }
+
+            $decryptionStream = $this->getCommitingDecryptingStream(
+                $cipherText,
+                $cek,
+                $options['@CipherOptions'],
+                $messageId,
+                $commitmentKey,
+                $algorithmSuite
+            );
+            unset($cek);
+
+            return $decryptionStream;
+        } else {
+            //= ../specification/s3-encryption/key-commitment.md#commitment-policy
+            //# When the commitment policy is REQUIRE_ENCRYPT_REQUIRE_DECRYPT,
+            //# the S3EC MUST NOT allow decryption using algorithm suites which do not support key commitment.
+            if ($commitmentPolicy == "REQUIRE_ENCRYPT_REQUIRE_DECRYPT") {
+                //= ../specification/s3-encryption/client.md#key-commitment
+                //# If the configured Encryption Algorithm is incompatible with
+                //# the key commitment policy, then it MUST throw an exception.
+                throw new CryptoException("Message is encrypted with a "
+                    . "non commiting algorithm but commitment policy is set "
+                    . "to {$commitmentPolicy}. Select a valid commitment "
+                    . "policy to decrypt this object. ");
+            }
+            $this->checkEnvelopeForExclusiveMapKeys(
+                $envelope,
+                MetadataEnvelope::getV3Fields(),
+                "Expected V2 only fields but found V3 fields in header metadata."
+            );
+            $options['@CipherOptions'] = $options['@CipherOptions'] ?? [];
+            $options['@CipherOptions']['Iv'] = base64_decode(
+                $envelope[MetadataEnvelope::IV_HEADER]
+            );
+
+            $options['@CipherOptions']['TagLength'] =
+                $envelope[MetadataEnvelope::CRYPTO_TAG_LENGTH_HEADER] / 8;
+
+            $cek = $provider->decryptCek(
+                base64_decode(
+                    $envelope[MetadataEnvelope::CONTENT_KEY_V2_HEADER]
+                ),
+                json_decode(
+                    $envelope[MetadataEnvelope::MATERIALS_DESCRIPTION_HEADER],
+                    true
+                ),
+                $options
+            );
+            $options['@CipherOptions']['KeySize'] = strlen($cek) * 8;
+            $options['@CipherOptions']['Cipher'] = $this->getCipherFromAesName(
+                $envelope[MetadataEnvelope::CONTENT_CRYPTO_SCHEME_HEADER]
+            );
+
+            //= ../specification/s3-encryption/decryption.md#key-commitment
+            //= type=implication
+            //# The S3EC MUST validate the algorithm suite used for decryption
+            //# against the key commitment policy before attempting to decrypt
+            //# the content ciphertext.
+            $this->validateOptionsAndEnvelope($options, $envelope, $commitmentPolicy);
+
+            $decryptionStream = $this->getNonCommitingDecryptingStream(
+                $cipherText,
+                $cek,
+                $options['@CipherOptions']
+            );
+            unset($cek);
+
+            return $decryptionStream;
+        }
+    }
+
+    private function checkEnvelopeForExclusiveMapKeys(
+        MetadataEnvelope $envelope,
+        array $exclusiveKeys,
+        string $errorMessage
+    ): void
+    {
+        foreach ($exclusiveKeys as $exclusiveKey) {
+            //= ../specification/s3-encryption/data-format/content-metadata.md#determining-s3ec-object-status
+            //# If there are multiple mapkeys which are meant to be exclusive, such as "x-amz-key", "x-amz-key-v2", and "x-amz-3" then the S3EC SHOULD throw an exception.
+            if (isset($envelope[$exclusiveKey])) {
+                throw new CryptoException($errorMessage);
+            }
+        }
+    }
+
+    private function numericalContenCipherToAesName(
+        MetadataEnvelope $envelope
+    ): string
+    {
+        switch ($envelope[MetadataEnvelope::CONTENT_CIPHER_V3]) {
+            case 115:
+                return 'AES/GCM/NoPadding';
+            default:
+                throw new CryptoException(
+                    "Unknown Encrypted Data Key "
+                    . "wrapping algorithm found: "
+                    . "{$envelope[MetadataEnvelope::ENCRYPTED_DATA_KEY_ALGORITHM_V3]}"
+                );
+        }
+
+    }
+
+    private function buildMaterialDescription(
+        MetadataEnvelope $envelope
+    ): array
+    {
+        switch ($envelope[MetadataEnvelope::ENCRYPTED_DATA_KEY_ALGORITHM_V3]) {
+            case 12:
+                return json_decode(
+                    $envelope[MetadataEnvelope::ENCRYPTION_CONTEXT_V3],
+                    true
+                );
+            default:
+                throw new CryptoException(
+                    "Unknown Encrypted Data Key "
+                    . "wrapping algorithm found: "
+                    . "{$envelope[MetadataEnvelope::ENCRYPTED_DATA_KEY_ALGORITHM_V3]}"
+                );
+        }
+    }
+
+    private function getTagFromCiphertextStream(
+        StreamInterface $cipherText,
+        $tagLength
+    ): string
+    {
+        $cipherTextSize = $cipherText->getSize();
+        if ($cipherTextSize == null || $cipherTextSize <= 0) {
+            throw new \RuntimeException('Cannot decrypt a stream of unknown size');
+        }
+
+        return (string) new LimitStream(
+            $cipherText,
+            $tagLength,
+            $cipherTextSize - $tagLength
+        );
+    }
+
+    private function getStrippedCiphertextStream(
+        StreamInterface $cipherText,
+        $tagLength
+    ): LimitStream 
+    {
+        $cipherTextSize = $cipherText->getSize();
+        if ($cipherTextSize == null || $cipherTextSize <= 0) {
+            throw new \RuntimeException('Cannot decrypt a stream of unknown size');
+        }
+
+        return new LimitStream(
+            $cipherText,
+            $cipherTextSize - $tagLength,
+            0
+        );
+    }
+
+    private function validateOptionsAndEnvelope(
+        array $options,
+        MetadataEnvelope $envelope,
+        string $commitmentPolicy
+    ): void 
+    {
+        //= ../specification/s3-encryption/key-commitment.md#commitment-policy
+        //# When the commitment policy is REQUIRE_ENCRYPT_ALLOW_DECRYPT,
+        //# the S3EC MUST allow decryption using algorithm suites which do not support key commitment.
+
+        //= ../specification/s3-encryption/key-commitment.md#commitment-policy
+        //# When the commitment policy is FORBID_ENCRYPT_ALLOW_DECRYPT,
+        //# the S3EC MUST allow decryption using algorithm suites which do not support key commitment.
+
+        $allowedCiphers = AbstractCryptoClientV3::$supportedCiphers;
+        $allowedKeywraps = AbstractCryptoClientV3::$supportedKeyWraps;
+        //= ../specification/s3-encryption/client.md#enable-legacy-wrapping-algorithms
+        //# When enabled, the S3EC MUST be able to decrypt objects encrypted with all
+        //# supported wrapping algorithms (both legacy and fully supported).
+        if ($options['@SecurityProfile'] == 'V3_AND_LEGACY') {
+            $allowedCiphers = array_unique(array_merge(
+                $allowedCiphers,
+                AbstractCryptoClient::$supportedCiphers
+            ));
+            $allowedKeywraps = array_unique(array_merge(
+                $allowedKeywraps,
+                AbstractCryptoClient::$supportedKeyWraps
+            ));
+        }
+
+        $v1SchemaException = new CryptoException("The requested object is encrypted"
+            . " with V1 encryption schemas that have been disabled by"
+            . " client configuration @SecurityProfile=V3. Retry with"
+            . " V3_AND_LEGACY enabled or reencrypt the object.");
+
+        if (!in_array($options['@CipherOptions']['Cipher'], $allowedCiphers)) {
+            //= ../specification/s3-encryption/client.md#enable-legacy-wrapping-algorithms
+            //= type=implication
+            //# When disabled, the S3EC MUST NOT decrypt objects encrypted using legacy wrapping algorithms;
+            //# it MUST throw an exception when attempting to decrypt an object encrypted with a legacy wrapping algorithm.
+            
+            //= ../specification/s3-encryption/decryption.md#legacy-decryption
+            //# The S3EC MUST NOT decrypt objects encrypted using legacy unauthenticated algorithm suites unless specifically configured to do so.
+            if (in_array($options['@CipherOptions']['Cipher'], AbstractCryptoClient::$supportedCiphers)) {
+                //= ../specification/s3-encryption/decryption.md#legacy-decryption
+                //# If the S3EC is not configured to enable legacy unauthenticated content decryption, the client MUST throw an exception when attempting to decrypt an object encrypted with a legacy unauthenticated algorithm suite.
+                throw $v1SchemaException;
+            }
+
+            throw new CryptoException("The requested object is encrypted with"
+                . " the cipher '{$options['@CipherOptions']['Cipher']}', which is not"
+                . " supported for decryption with the selected security profile."
+                . " This profile allows decryption with: "
+                . implode(", ", $allowedCiphers));
+        }
+
+        if (isset($envelope[MetadataEnvelope::ENCRYPTED_DATA_KEY_V3])) {
+            if ($envelope[MetadataEnvelope::ENCRYPTED_DATA_KEY_ALGORITHM_V3] !== '12') {
+                throw new CryptoException("The requested object is encrypted with"
+                    . " the keywrap schema '{$envelope[MetadataEnvelope::ENCRYPTED_DATA_KEY_ALGORITHM_V3]}',"
+                    . " which is not supported for decryption with the current security"
+                    . " profile.");
+            }
+        } else {
+            if (!in_array($envelope[MetadataEnvelope::KEY_WRAP_ALGORITHM_HEADER], $allowedKeywraps)) {
+                if (in_array($envelope[MetadataEnvelope::KEY_WRAP_ALGORITHM_HEADER], AbstractCryptoClient::$supportedKeyWraps)) {
+                    throw $v1SchemaException;
+                }
+
+                throw new CryptoException("The requested object is encrypted with"
+                    . " the keywrap schema '{$envelope[MetadataEnvelope::KEY_WRAP_ALGORITHM_HEADER]}',"
+                    . " which is not supported for decryption with the current security"
+                    . " profile.");
+            }
+            $matdesc = json_decode(
+                $envelope[MetadataEnvelope::MATERIALS_DESCRIPTION_HEADER],
+                true
+            );
+            if (isset($matdesc['aws:x-amz-cek-alg'])
+                && ($envelope[MetadataEnvelope::CONTENT_CRYPTO_SCHEME_HEADER]
+                    !== $matdesc['aws:x-amz-cek-alg'])
+            ) {
+                throw new CryptoException("There is a mismatch in specified content"
+                    . " encryption algrithm between the materials description value"
+                    . " and the metadata envelope value: {$matdesc['aws:x-amz-cek-alg']}"
+                    . " vs. {$envelope[MetadataEnvelope::CONTENT_CRYPTO_SCHEME_HEADER]}.");
+            }
+        }
+        //= ../specification/s3-encryption/data-format/content-metadata.md#determining-s3ec-object-status
+        //= type=implication
+        //# - If the metadata contains "x-amz-3" and "x-amz-d" and "x-amz-i" then the object MUST be considered an S3EC-encrypted object using the V3 format.
+        if (!MetadataEnvelope::isV3Envelope($envelope)
+            && $commitmentPolicy == "REQUIRE_ENCRYPT_REQUIRE_DECRYPT"
+        ) {
+            //= ../specification/s3-encryption/decryption.md#key-commitment
+            //# If the commitment policy requires decryption using a committing algorithm suite
+            //# and the algorithm suite associated with the object does not support key commitment,
+            //# then the S3EC MUST throw an exception.
+            throw new CryptoException("There is a mismatch in specified"
+                . "commitment policy value {$commitmentPolicy} and"
+                . "Metadata Envelope found in object.");
+        }
+
+    }
+
+    /**
+     * Generates a stream that wraps the cipher text with the proper cipher and
+     * uses the content encryption key (CEK) to decrypt the data when read.
+     *
+     * @param string $cipherText Plain-text data to be encrypted using the
+     *                           materials, algorithm, and data provided.
+     * @param string $cek A content encryption key for use by the stream for
+     *                    encrypting the plaintext data.
+     * @param array $cipherOptions Options for use in determining the cipher to
+     *                             be used for encrypting data.
+     *
+     * @return AesStreamInterface
+     *
+     * @internal
+     */
+    protected function getNonCommitingDecryptingStream(
+        string $cipherText,
+        string $cek,
+        array $cipherOptions
+    ): AesStreamInterface
+    {
+        $cipherTextStream = Psr7\Utils::streamFor($cipherText);
+        switch ($cipherOptions['Cipher']) {
+            case 'gcm':
+                $cipherOptions['Tag'] = $this->getTagFromCiphertextStream(
+                    $cipherTextStream,
+                    $cipherOptions['TagLength']
+                );
+
+                return new AesGcmDecryptingStream(
+                    $this->getStrippedCiphertextStream(
+                        $cipherTextStream,
+                        $cipherOptions['TagLength']
+                    ),
+                    $cek,
+                    $cipherOptions['Iv'],
+                    $cipherOptions['Tag'],
+                    $cipherOptions['Aad'] = isset($cipherOptions['Aad'])
+                    ? $cipherOptions['Aad']
+                    : '',
+                    $cipherOptions['TagLength'] ?: null,
+                    $cipherOptions['KeySize']
+                );
+            default:
+                $cipherMethod = $this->buildCipherMethod(
+                    $cipherOptions['Cipher'],
+                    $cipherOptions['Iv'],
+                    $cipherOptions['KeySize']
+                );
+
+                return new AesDecryptingStream(
+                    $cipherTextStream,
+                    $cek,
+                    $cipherMethod
+                );
+        }
+    }
+
+    /**
+     * Generates a stream that wraps the cipher text with the proper cipher and
+     * uses the content encryption key (CEK) to derive both a derived content encryption key
+     * and a commitment key to decrypt the data when read.
+     *
+     * @param string $cipherText Plain-text data to be encrypted using the
+     *                           materials, algorithm, and data provided.
+     * @param string $cek A content encryption key for use by the stream for
+     *                    encrypting the plaintext data.
+     * @param array $cipherOptions Options for use in determining the cipher to
+     *                             be used for encrypting data.
+     * @param string $messageId a string value used to calculate both a commitment
+     *                          key and derived content encryption key
+     * @param string $commitmentKey a string value to compare with the calculated commitment
+     *                              key value, if the values don't match an exception is raised.
+     *
+     * @return AesStreamInterface | CryptoException
+     *
+     * @internal
+     */
+    protected function getCommitingDecryptingStream(
+        string $cipherText,
+        string $cek,
+        array $cipherOptions,
+        string $messageId,
+        string $commitmentKey,
+        AlgorithmSuite $algorithmSuite
+    ): AesStreamInterface|CryptoException
+    {
+        $algorithmSuiteIdAsBytes = pack('n', $algorithmSuite->getId());
+        $derivedEncryptionKeyInfo = $algorithmSuiteIdAsBytes . "DERIVEKEY";
+        $commitmentKeyInfo = $algorithmSuiteIdAsBytes . "COMMITKEY";
+        $calculatedCommitmentKey = hash_hkdf(
+            $algorithmSuite->getHashingAlgorithm(),
+            $cek,
+            $algorithmSuite->getCommitmentOutputKeyLengthBytes(),
+            $commitmentKeyInfo,
+            $messageId
+        );
+        //= ../specification/s3-encryption/decryption.md#decrypting-with-commitment
+        //= type=implication
+        //# When using an algorithm suite which supports key commitment, the client MUST verify that the [derived key commitment](./key-derivation.md#hkdf-operation) contains the same bytes as the stored key commitment retrieved from the stored object's metadata.
+        if (
+            //= ../specification/s3-encryption/decryption.md#decrypting-with-commitment
+            //= type=implication
+            //# When using an algorithm suite which supports key commitment,
+            //# the verification of the derived key commitment value MUST be done in constant time.
+            !hash_equals($commitmentKey, $calculatedCommitmentKey)
+        ) {
+            //= ../specification/s3-encryption/decryption.md#decrypting-with-commitment
+            //= type=implication
+            //# When using an algorithm suite which supports key commitment, the client MUST
+            //# throw an exception when the derived key commitment value
+            //# and stored key commitment value do not match.
+            throw new CryptoException("Calculated commitment key does "
+                . "not match expected commitment key value ");
+        }
+        //= ../specification/s3-encryption/decryption.md#decrypting-with-commitment
+        //= type=implication
+        //# When using an algorithm suite which supports key commitment,
+        //# the client MUST verify the key commitment values match before
+        //# deriving the [derived encryption key](./key-derivation.md#hkdf-operation).
+        $derivedEncryptionKey = hash_hkdf(
+            $algorithmSuite->getHashingAlgorithm(),
+            $cek,
+            $algorithmSuite->getDerivationOutputKeyLengthBytes(),
+            $derivedEncryptionKeyInfo,
+            $messageId
+        );
+
+        $cipherTextStream = Psr7\Utils::streamFor($cipherText);
+        switch ($cipherOptions['Cipher']) {
+            case 'gcm':
+                $cipherOptions['Tag'] = $this->getTagFromCiphertextStream(
+                    $cipherTextStream,
+                    $cipherOptions['TagLength']
+                );
+                $cipherOptions['Aad'] = isset($cipherOptions['Aad'])
+                    ? $cipherOptions['Aad'] . $algorithmSuiteIdAsBytes
+                    : $algorithmSuiteIdAsBytes;
+
+                return new AesGcmDecryptingStream(
+                    $this->getStrippedCiphertextStream(
+                        $cipherTextStream,
+                        $cipherOptions['TagLength']
+                    ),
+                    $derivedEncryptionKey,
+                    $cipherOptions['Iv'],
+                    $cipherOptions['Tag'],
+                    $cipherOptions['Aad'],
+                    $cipherOptions['TagLength'] ?: null,
+                    $cipherOptions['KeySize']
+                );
+            default: 
+                throw new CryptoException("Unsupported Cipher used for key commitment messages."
+                    . " Found {$cipherOptions["Cipher"]}. Only 'gcm' is supported.");
+        }
+    }
+}

+ 193 - 0
upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/Crypto/EncryptionTrait.php

@@ -0,0 +1,193 @@
+<?php
+namespace Aws\Crypto;
+
+use GuzzleHttp\Psr7;
+use GuzzleHttp\Psr7\AppendStream;
+use GuzzleHttp\Psr7\Stream;
+use Psr\Http\Message\StreamInterface;
+
+trait EncryptionTrait
+{
+    private static $allowedOptions = [
+        'Cipher' => true,
+        'KeySize' => true,
+        'Aad' => true,
+    ];
+
+    /**
+     * Dependency to generate a CipherMethod from a set of inputs for loading
+     * in to an AesEncryptingStream.
+     *
+     * @param string $cipherName Name of the cipher to generate for encrypting.
+     * @param string $iv Base Initialization Vector for the cipher.
+     * @param int $keySize Size of the encryption key, in bits, that will be
+     *                     used.
+     *
+     * @return Cipher\CipherMethod
+     *
+     * @internal
+     */
+    abstract protected function buildCipherMethod($cipherName, $iv, $keySize);
+
+    /**
+     * Builds an AesStreamInterface and populates encryption metadata into the
+     * supplied envelope.
+     *
+     * @param Stream $plaintext Plain-text data to be encrypted using the
+     *                          materials, algorithm, and data provided.
+     * @param array $cipherOptions Options for use in determining the cipher to
+     *                             be used for encrypting data.
+     * @param MaterialsProvider $provider A provider to supply and encrypt
+     *                                    materials used in encryption.
+     * @param MetadataEnvelope $envelope A storage envelope for encryption
+     *                                   metadata to be added to.
+     *
+     * @return AesStreamInterface
+     *
+     * @throws \InvalidArgumentException Thrown when a value in $cipherOptions
+     *                                   is not valid.
+     *
+     * @internal
+     */
+    public function encrypt(
+        StreamInterface $plaintext,
+        array $cipherOptions,
+        MaterialsProvider $provider,
+        MetadataEnvelope $envelope
+    ) {
+        $materialsDescription = $provider->getMaterialsDescription();
+
+        $cipherOptions = array_intersect_key(
+            $cipherOptions,
+            self::$allowedOptions
+        );
+
+        if (empty($cipherOptions['Cipher'])) {
+            throw new \InvalidArgumentException('An encryption cipher must be'
+                . ' specified in the "cipher_options".');
+        }
+
+        if (!self::isSupportedCipher($cipherOptions['Cipher'])) {
+            throw new \InvalidArgumentException('The cipher requested is not'
+                . ' supported by the SDK.');
+        }
+
+        if (empty($cipherOptions['KeySize'])) {
+            $cipherOptions['KeySize'] = 256;
+        }
+        if (!is_int($cipherOptions['KeySize'])) {
+            throw new \InvalidArgumentException('The cipher "KeySize" must be'
+                . ' an integer.');
+        }
+
+        if (!MaterialsProvider::isSupportedKeySize(
+            $cipherOptions['KeySize']
+        )) {
+            throw new \InvalidArgumentException('The cipher "KeySize" requested'
+                . ' is not supported by AES (128, 192, or 256).');
+        }
+
+        $cipherOptions['Iv'] = $provider->generateIv(
+            $this->getCipherOpenSslName(
+                $cipherOptions['Cipher'],
+                $cipherOptions['KeySize']
+            )
+        );
+
+        $cek = $provider->generateCek($cipherOptions['KeySize']);
+
+        list($encryptingStream, $aesName) = $this->getEncryptingStream(
+            $plaintext,
+            $cek,
+            $cipherOptions
+        );
+
+        // Populate envelope data
+        $envelope[MetadataEnvelope::CONTENT_KEY_V2_HEADER] =
+            $provider->encryptCek(
+                $cek,
+                $materialsDescription
+            );
+        unset($cek);
+
+        $envelope[MetadataEnvelope::IV_HEADER] =
+            base64_encode($cipherOptions['Iv']);
+        $envelope[MetadataEnvelope::KEY_WRAP_ALGORITHM_HEADER] =
+            $provider->getWrapAlgorithmName();
+        $envelope[MetadataEnvelope::CONTENT_CRYPTO_SCHEME_HEADER] = $aesName;
+        $envelope[MetadataEnvelope::UNENCRYPTED_CONTENT_LENGTH_HEADER] =
+            strlen($plaintext);
+        $envelope[MetadataEnvelope::MATERIALS_DESCRIPTION_HEADER] =
+            json_encode($materialsDescription);
+        if (!empty($cipherOptions['Tag'])) {
+            $envelope[MetadataEnvelope::CRYPTO_TAG_LENGTH_HEADER] =
+                strlen($cipherOptions['Tag']) * 8;
+        }
+
+        return $encryptingStream;
+    }
+
+    /**
+     * Generates a stream that wraps the plaintext with the proper cipher and
+     * uses the content encryption key (CEK) to encrypt the data when read.
+     *
+     * @param Stream $plaintext Plain-text data to be encrypted using the
+     *                          materials, algorithm, and data provided.
+     * @param string $cek A content encryption key for use by the stream for
+     *                    encrypting the plaintext data.
+     * @param array $cipherOptions Options for use in determining the cipher to
+     *                             be used for encrypting data.
+     *
+     * @return array returns an array with two elements as follows: [string, AesStreamInterface]
+     *
+     * @internal
+     */
+    protected function getEncryptingStream(
+        StreamInterface $plaintext,
+        $cek,
+        &$cipherOptions
+    ) {
+        switch ($cipherOptions['Cipher']) {
+            case 'gcm':
+                $cipherOptions['TagLength'] = 16;
+
+                $cipherTextStream = new AesGcmEncryptingStream(
+                    $plaintext,
+                    $cek,
+                    $cipherOptions['Iv'],
+                    $cipherOptions['Aad'] = isset($cipherOptions['Aad'])
+                        ? $cipherOptions['Aad']
+                        : '',
+                    $cipherOptions['TagLength'],
+                    $cipherOptions['KeySize']
+                );
+
+                if (!empty($cipherOptions['Aad'])) {
+                    trigger_error("'Aad' has been supplied for content encryption"
+                        . " with " . $cipherTextStream->getAesName() . ". The"
+                        . " PHP SDK encryption client can decrypt an object"
+                        . " encrypted in this way, but other AWS SDKs may not be"
+                        . " able to.", E_USER_WARNING);
+                }
+
+                $appendStream = new AppendStream([
+                    $cipherTextStream->createStream()
+                ]);
+                $cipherOptions['Tag'] = $cipherTextStream->getTag();
+                $appendStream->addStream(Psr7\Utils::streamFor($cipherOptions['Tag']));
+                return [$appendStream, $cipherTextStream->getAesName()];
+            default:
+                $cipherMethod = $this->buildCipherMethod(
+                    $cipherOptions['Cipher'],
+                    $cipherOptions['Iv'],
+                    $cipherOptions['KeySize']
+                );
+                $cipherTextStream = new AesEncryptingStream(
+                    $plaintext,
+                    $cek,
+                    $cipherMethod
+                );
+                return [$cipherTextStream, $cipherTextStream->getAesName()];
+        }
+    }
+}

+ 192 - 0
upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/Crypto/EncryptionTraitV2.php

@@ -0,0 +1,192 @@
+<?php
+namespace Aws\Crypto;
+
+use GuzzleHttp\Psr7;
+use GuzzleHttp\Psr7\AppendStream;
+use GuzzleHttp\Psr7\Stream;
+use Psr\Http\Message\StreamInterface;
+
+trait EncryptionTraitV2
+{
+    private static $allowedOptions = [
+        'Cipher' => true,
+        'KeySize' => true,
+        'Aad' => true,
+    ];
+
+    private static $encryptClasses = [
+        'gcm' => AesGcmEncryptingStream::class
+    ];
+
+    /**
+     * Dependency to generate a CipherMethod from a set of inputs for loading
+     * in to an AesEncryptingStream.
+     *
+     * @param string $cipherName Name of the cipher to generate for encrypting.
+     * @param string $iv Base Initialization Vector for the cipher.
+     * @param int $keySize Size of the encryption key, in bits, that will be
+     *                     used.
+     *
+     * @return Cipher\CipherMethod
+     *
+     * @internal
+     */
+    abstract protected function buildCipherMethod($cipherName, $iv, $keySize);
+
+    /**
+     * Builds an AesStreamInterface and populates encryption metadata into the
+     * supplied envelope.
+     *
+     * @param Stream $plaintext Plain-text data to be encrypted using the
+     *                          materials, algorithm, and data provided.
+     * @param array $options    Options for use in encryption, including cipher
+     *                          options, and encryption context.
+     * @param MaterialsProviderV2 $provider A provider to supply and encrypt
+     *                                      materials used in encryption.
+     * @param MetadataEnvelope $envelope A storage envelope for encryption
+     *                                   metadata to be added to.
+     *
+     * @return StreamInterface
+     *
+     * @throws \InvalidArgumentException Thrown when a value in $options['@CipherOptions']
+     *                                   is not valid.
+     *s
+     * @internal
+     */
+    public function encrypt(
+        StreamInterface $plaintext,
+        array $options,
+        MaterialsProviderV2 $provider,
+        MetadataEnvelope $envelope
+    ) {
+        $options = array_change_key_case($options);
+        $cipherOptions = array_intersect_key(
+            $options['@cipheroptions'],
+            self::$allowedOptions
+        );
+
+        if (empty($cipherOptions['Cipher'])) {
+            throw new \InvalidArgumentException('An encryption cipher must be'
+                . ' specified in @CipherOptions["Cipher"].');
+        }
+
+        $cipherOptions['Cipher'] = strtolower($cipherOptions['Cipher']);
+
+        if (!self::isSupportedCipher($cipherOptions['Cipher'])) {
+            throw new \InvalidArgumentException('The cipher requested is not'
+                . ' supported by the SDK.');
+        }
+
+        if (empty($cipherOptions['KeySize'])) {
+            $cipherOptions['KeySize'] = 256;
+        }
+        if (!is_int($cipherOptions['KeySize'])) {
+            throw new \InvalidArgumentException('The cipher "KeySize" must be'
+                . ' an integer.');
+        }
+
+        if (!MaterialsProviderV2::isSupportedKeySize($cipherOptions['KeySize'])) {
+            throw new \InvalidArgumentException('The cipher "KeySize" requested'
+                . ' is not supported by AES (128 or 256).');
+        }
+
+        $cipherOptions['Iv'] = $provider->generateIv(
+            $this->getCipherOpenSslName(
+                $cipherOptions['Cipher'],
+                $cipherOptions['KeySize']
+            )
+        );
+
+        $encryptClass = self::$encryptClasses[$cipherOptions['Cipher']];
+        $aesName = $encryptClass::getStaticAesName();
+        $materialsDescription = ['aws:x-amz-cek-alg' => $aesName];
+
+        $keys = $provider->generateCek(
+            $cipherOptions['KeySize'],
+            $materialsDescription,
+            $options
+        );
+
+        // Some providers modify materials description based on options
+        if (isset($keys['UpdatedContext'])) {
+            $materialsDescription = $keys['UpdatedContext'];
+        }
+
+        $encryptingStream = $this->getEncryptingStream(
+            $plaintext,
+            $keys['Plaintext'],
+            $cipherOptions
+        );
+
+        // Populate envelope data
+        $envelope[MetadataEnvelope::CONTENT_KEY_V2_HEADER] = $keys['Ciphertext'];
+        unset($keys);
+
+        $envelope[MetadataEnvelope::IV_HEADER] =
+            base64_encode($cipherOptions['Iv']);
+        $envelope[MetadataEnvelope::KEY_WRAP_ALGORITHM_HEADER] =
+            $provider->getWrapAlgorithmName();
+        $envelope[MetadataEnvelope::CONTENT_CRYPTO_SCHEME_HEADER] = $aesName;
+        $envelope[MetadataEnvelope::UNENCRYPTED_CONTENT_LENGTH_HEADER] =
+            (string) strlen($plaintext);
+        $envelope[MetadataEnvelope::MATERIALS_DESCRIPTION_HEADER] =
+            json_encode($materialsDescription);
+        if (!empty($cipherOptions['Tag'])) {
+            $envelope[MetadataEnvelope::CRYPTO_TAG_LENGTH_HEADER] =
+                (string) (strlen($cipherOptions['Tag']) * 8);
+        }
+
+        return $encryptingStream;
+    }
+
+    /**
+     * Generates a stream that wraps the plaintext with the proper cipher and
+     * uses the content encryption key (CEK) to encrypt the data when read.
+     *
+     * @param Stream $plaintext Plain-text data to be encrypted using the
+     *                          materials, algorithm, and data provided.
+     * @param string $cek A content encryption key for use by the stream for
+     *                    encrypting the plaintext data.
+     * @param array $cipherOptions Options for use in determining the cipher to
+     *                             be used for encrypting data.
+     *
+     * @return array returns an array with two elements as follows: [string, AesStreamInterface]
+     *
+     * @internal
+     */
+    protected function getEncryptingStream(
+        StreamInterface $plaintext,
+        $cek,
+        &$cipherOptions
+    ) {
+        switch ($cipherOptions['Cipher']) {
+            // Only 'gcm' is supported for encryption currently
+            case 'gcm':
+                $cipherOptions['TagLength'] = 16;
+                $encryptClass = self::$encryptClasses['gcm'];
+                $cipherTextStream = new $encryptClass(
+                    $plaintext,
+                    $cek,
+                    $cipherOptions['Iv'],
+                    $cipherOptions['Aad'] = $cipherOptions['Aad'] ?? '',
+                    $cipherOptions['TagLength'],
+                    $cipherOptions['KeySize']
+                );
+
+                if (!empty($cipherOptions['Aad'])) {
+                    trigger_error("'Aad' has been supplied for content encryption"
+                        . " with " . $cipherTextStream->getAesName() . ". The"
+                        . " PHP SDK encryption client can decrypt an object"
+                        . " encrypted in this way, but other AWS SDKs may not be"
+                        . " able to.", E_USER_WARNING);
+                }
+
+                $appendStream = new AppendStream([
+                    $cipherTextStream->createStream()
+                ]);
+                $cipherOptions['Tag'] = $cipherTextStream->getTag();
+                $appendStream->addStream(Psr7\Utils::streamFor($cipherOptions['Tag']));
+                return $appendStream;
+        }
+    }
+}

+ 474 - 0
upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/Crypto/EncryptionTraitV3.php

@@ -0,0 +1,474 @@
+<?php
+namespace Aws\Crypto;
+
+use Aws\Crypto\Cipher\CipherMethod;
+use Aws\Exception\CryptoException;
+use GuzzleHttp\Psr7;
+use GuzzleHttp\Psr7\AppendStream;
+use GuzzleHttp\Psr7\Stream;
+use Psr\Http\Message\StreamInterface;
+
+trait EncryptionTraitV3
+{
+    private static array $allowedOptions = [
+        'Cipher' => true,
+        'KeySize' => true,
+        'Aad' => true,
+    ];
+
+    private static array $encryptClasses = [
+        'gcm' => AesGcmEncryptingStream::class
+    ];
+
+    /**
+     * Dependency to generate a CipherMethod from a set of inputs for loading
+     * in to an AesEncryptingStream.
+     *
+     * @param string $cipherName Name of the cipher to generate for encrypting.
+     * @param string $iv Base Initialization Vector for the cipher.
+     * @param int $keySize Size of the encryption key, in bits, that will be
+     *                     used.
+     *
+     * @return Cipher\CipherMethod
+     *
+     * @internal
+     */
+    abstract protected function buildCipherMethod(
+        $cipherName,
+        $iv,
+        $keySize
+    );
+
+    /**
+     * Builds an AesStreamInterface and populates encryption metadata into the
+     * supplied envelope.
+     *
+     * @param StreamInterface $plaintext Plain-text data to be encrypted using the
+     *                          materials, algorithm, and data provided.
+     * @param AlgorithmSuite $algorithmSuite Algorithm Suite for use in encryption
+     * @param array $options    Options for use in encryption, including cipher
+     *                          options, and encryption context.
+     * @param MaterialsProviderV3 $provider A provider to supply and encrypt
+     *                                      materials used in encryption.
+     * @param MetadataEnvelope $envelope A storage envelope for encryption
+     *                                   metadata to be added to.
+     *
+     * @return AppendStream
+     *
+     * @throws \InvalidArgumentException Thrown when a value in $options['@CipherOptions']
+     *                                   is not valid.
+     *s
+     * @internal
+     */
+    public function encrypt(
+        StreamInterface $plaintext,
+        AlgorithmSuite $algorithmSuite,
+        array $options,
+        MaterialsProviderV3 $provider,
+        MetadataEnvelope $envelope
+    ): AppendStream 
+    {
+        $options = array_change_key_case($options);
+        $cipherOptions = array_intersect_key(
+            $options['@cipheroptions'],
+            self::$allowedOptions
+        );
+        //= ../specification/s3-encryption/encryption.md#content-encryption
+        //= type=implication
+        //# The client MUST validate that the length of the plaintext bytes does not exceed
+        //# the algorithm suite's cipher's maximum content length in bytes.
+        if (strlen($plaintext) > $algorithmSuite->getCipherMaxContentLengthBytes()) {
+            throw new \InvalidArgumentException("The contentLength of the object you are attempting"
+                . " to encrypt exceeds the maximum length allowed for GCM encryption.");
+        }
+        $cipherOptions['Cipher'] = strtolower($cipherOptions['Cipher']);
+
+        if (!self::isSupportedCipher($cipherOptions['Cipher'])) {
+            throw new \InvalidArgumentException('The cipher requested is not'
+                . ' supported by the SDK.');
+        }
+
+        if (empty($cipherOptions['KeySize'])) {
+            $cipherOptions['KeySize'] = 256;
+        }
+
+        if (!is_int($cipherOptions['KeySize'])) {
+            throw new \InvalidArgumentException('The cipher "KeySize" must be'
+                . ' an integer.');
+        }
+
+        if (!MaterialsProviderV3::isSupportedKeySize($cipherOptions['KeySize'])) {
+            throw new \InvalidArgumentException('The cipher "KeySize" requested'
+                . ' is not supported by AES (256).');
+        }
+
+        $encryptClass = self::$encryptClasses[$algorithmSuite->getCipherName()];
+        $aesName = $encryptClass::getStaticAesName();
+        $materialsDescription = $algorithmSuite->isKeyCommitting()
+            ? ['aws:x-amz-cek-alg' => '115']
+            : ['aws:x-amz-cek-alg' => $aesName];
+
+        $keys = $provider->generateCek(
+            $algorithmSuite->getDataKeyLengthBits(),
+            $materialsDescription,
+            $options
+        );
+
+        // Some providers modify materials description based on options
+        if (isset($keys['UpdatedContext'])) {
+            $materialsDescription = $keys['UpdatedContext'];
+        }
+
+        if ($algorithmSuite->isKeyCommitting()) {
+            return $this->encryptCommitingStream(
+                $plaintext,
+                $algorithmSuite,
+                $cipherOptions,
+                $keys,
+                $materialsDescription,
+                $provider,
+                $envelope
+            );
+        } else {
+            return $this->encryptNonCommitingStream(
+                $plaintext,
+                $cipherOptions,
+                $keys,
+                $materialsDescription,
+                $aesName,
+                $provider,
+                $envelope
+            );
+        }
+    }
+
+    private function encryptNonCommitingStream(
+        StreamInterface $plaintext,
+        array &$cipherOptions,
+        array $keys,
+        array $materialsDescription,
+        string $aesName,
+        MaterialsProviderV3 $provider,
+        MetadataEnvelope $envelope
+    ): AppendStream
+    {
+        //= ../specification/s3-encryption/encryption.md#content-encryption
+        //# The generated IV or Message ID MUST be set or returned from the
+        //# encryption process such that it can be included in the content metadata.
+        //= ../specification/s3-encryption/encryption.md#content-encryption
+        //# The client MUST generate an IV or Message ID using the length of the IV or Message ID defined in the algorithm suite.
+        $cipherOptions['Iv'] = $provider->generateIv(
+            $this->getCipherOpenSslName(
+                $cipherOptions['Cipher'],
+                $cipherOptions['KeySize']
+            )
+        );
+        // Some providers modify materials description based on options
+        if (isset($keys['UpdatedContext'])) {
+            $materialsDescription = $keys['UpdatedContext'];
+        }
+
+        $encryptingStream = $this->getNonCommittingEncryptingStream(
+            $plaintext,
+            $keys['Plaintext'],
+            $cipherOptions
+        );
+
+        // Populate envelope data
+        //= ../specification/s3-encryption/data-format/content-metadata.md#determining-s3ec-object-status
+        //# - If the metadata contains "x-amz-iv" and "x-amz-metadata-x-amz-key-v2" then the object MUST be considered as an S3EC-encrypted object using the V2 format.
+        $envelope[MetadataEnvelope::CONTENT_KEY_V2_HEADER] = $keys['Ciphertext'];
+        unset($keys);
+
+        $envelope[MetadataEnvelope::IV_HEADER] =
+            base64_encode($cipherOptions['Iv']);
+        $envelope[MetadataEnvelope::KEY_WRAP_ALGORITHM_HEADER] =
+            $provider->getWrapAlgorithmName();
+        $envelope[MetadataEnvelope::CONTENT_CRYPTO_SCHEME_HEADER] = $aesName;
+        $envelope[MetadataEnvelope::UNENCRYPTED_CONTENT_LENGTH_HEADER] =
+            (string) strlen($plaintext);
+        $envelope[MetadataEnvelope::MATERIALS_DESCRIPTION_HEADER] =
+            json_encode($materialsDescription);
+        if (!empty($cipherOptions['Tag'])) {
+            $envelope[MetadataEnvelope::CRYPTO_TAG_LENGTH_HEADER] =
+                (string) (strlen($cipherOptions['Tag']) * 8);
+        }
+        if (!MetadataEnvelope::isV2Envelope($envelope)) {
+            throw new CryptoException("Error while writing metadata envelope."
+                . " Not all required fields were set.");
+        }
+        
+        return $encryptingStream;
+    }
+
+    private function encryptCommitingStream(
+        StreamInterface $plaintext,
+        AlgorithmSuite $algorithmSuite,
+        array &$options,
+        array $keys,
+        array $materialsDescription,
+        MaterialsProviderV3 $provider,
+        MetadataEnvelope $envelope
+    ): AppendStream
+    {
+        //= ../specification/s3-encryption/encryption.md#content-encryption
+        //# The generated IV or Message ID MUST be set or returned from the
+        //# encryption process such that it can be included in the content metadata.
+        //= ../specification/s3-encryption/key-derivation.md#hkdf-operation
+        //= type=implication
+        //# When encrypting or decrypting with ALG_AES_256_GCM_HKDF_SHA512_COMMIT_KEY,
+        //# the IV used in the AES-GCM content encryption/decryption
+        //# MUST consist entirely of bytes with the value 0x01.
+        //= ../specification/s3-encryption/key-derivation.md#hkdf-operation
+        //= type=implication
+        //# The IV's total length MUST match the IV length defined by the algorithm suite.
+        $options['Iv'] = str_repeat("\1", $algorithmSuite->getIvLengthBytes());
+        $messageId = $provider->generateIv(
+            $this->getCipherOpenSslName(
+                $algorithmSuite->getCipherName(),
+                //= ../specification/s3-encryption/encryption.md#content-encryption
+                //# The client MUST generate an IV or Message ID using the length of
+                //# the IV or Message ID defined in the algorithm suite.
+                $algorithmSuite->getKeyCommitmentSaltLengthBits()
+            )
+        );
+        // Some providers modify materials description based on options
+        if (isset($keys['UpdatedContext'])) {
+            $materialsDescription["aws:x-amz-cek-alg"] = (string) $algorithmSuite->getId();
+        }
+        $commitingEncryptingArray = $this->getCommitingEncryptionStream(
+            $plaintext,
+            $keys['Plaintext'],
+            $options,
+            $messageId,
+            $algorithmSuite
+        );
+        //= ../specification/s3-encryption/encryption.md#alg-aes-256-gcm-hkdf-sha512-commit-key
+        //= type=implication
+        //# The derived key commitment value MUST be set or returned from the encryption process
+        //# such that it can be included in the content metadata.
+        $commitmentKey = $commitingEncryptingArray[0];
+        $encryptionStream = $commitingEncryptingArray[1];
+
+        // Populate envelope data
+        $envelope[MetadataEnvelope::ENCRYPTED_DATA_KEY_V3] = $keys['Ciphertext'];
+        unset($keys);
+
+        $envelope[MetadataEnvelope::CONTENT_CIPHER_V3] = $algorithmSuite->getId();
+        // we are able to always set the encryption context in the envelope because PHP
+        // only supports a KMS Material Provider.
+        $envelope[MetadataEnvelope::ENCRYPTION_CONTEXT_V3] =
+            json_encode($materialsDescription);
+        //= ../specification/s3-encryption/data-format/content-metadata.md#v3-only
+        //# The Encryption Context value MUST be used for wrapping algorithm `kms+context` or `12`.
+        $envelope[MetadataEnvelope::ENCRYPTED_DATA_KEY_ALGORITHM_V3] = '12';
+        $envelope[MetadataEnvelope::KEY_COMMITMENT_V3] = $commitmentKey;
+        $envelope[MetadataEnvelope::MESSAGE_ID_V3] = base64_encode($messageId);
+        if (!MetadataEnvelope::isV3Envelope($envelope)) {
+            throw new CryptoException("Error while writing metadata envelope."
+                . " Not all required fields were set.");
+        }
+
+        return $encryptionStream;
+    }
+
+    /**
+     * Generates a stream that wraps the plaintext with the proper cipher and
+     * uses the content encryption key (CEK) to encrypt the data when read.
+     *
+     * @param StreamInterface $plaintext Plain-text data to be encrypted using the
+     *                          materials, algorithm, and data provided.
+     * @param string $cek A content encryption key for use by the stream for
+     *                    encrypting the plaintext data.
+     * @param array $cipherOptions Options for use in determining the cipher to
+     *                             be used for encrypting data.
+     *
+     * @return AppendStream returns an AppendStream
+     *
+     * @internal
+     */
+    protected function getNonCommittingEncryptingStream(
+        StreamInterface $plaintext,
+        string $cek,
+        array &$cipherOptions
+    ): AppendStream
+    {
+        // Only 'gcm' is supported for encryption currently
+        switch ($cipherOptions['Cipher']) {
+            //= ../specification/s3-encryption/encryption.md#content-encryption
+            //= type=implication
+            //# The S3EC MUST use the encryption algorithm configured during [client](./client.md) initialization.
+            case 'gcm':
+                $cipherOptions['TagLength'] = 16;
+                $encryptClass = self::$encryptClasses['gcm'];
+                //= ../specification/s3-encryption/encryption.md#alg-aes-256-gcm-iv12-tag16-no-kdf
+                //= type=implication
+                //# The client MUST initialize the cipher, or call an AES-GCM encryption API,
+                //# with the plaintext data key, the generated IV, and the tag length defined
+                //# in the Algorithm Suite when encrypting with ALG_AES_256_GCM_IV12_TAG16_NO_KDF.
+                $cipherTextStream = new $encryptClass(
+                    $plaintext,
+                    $cek,
+                    $cipherOptions['Iv'],
+                    $cipherOptions['Aad'] = isset($cipherOptions['Aad'])
+                    ? $cipherOptions['Aad']
+                    : '',
+                    $cipherOptions['TagLength'],
+                    $cipherOptions['KeySize']
+                );
+
+                if (!empty($cipherOptions['Aad'])) {
+                    trigger_error("'Aad' has been supplied for content encryption"
+                        . " with " . $cipherTextStream->getAesName() . ". The"
+                        . " PHP SDK encryption client can decrypt an object"
+                        . " encrypted in this way, but other AWS SDKs may not be"
+                        . " able to.", E_USER_WARNING);
+                }
+
+                $appendStream = new AppendStream([
+                    $cipherTextStream->createStream()
+                ]);
+                //= ../specification/s3-encryption/encryption.md#alg-aes-256-gcm-iv12-tag16-no-kdf
+                //= type=implication
+                //# The client MUST append the GCM auth tag to the ciphertext if the underlying
+                //# crypto provider does not do so automatically.
+                $cipherOptions['Tag'] = $cipherTextStream->getTag();
+                $appendStream->addStream(Psr7\Utils::streamFor($cipherOptions['Tag']));
+
+                return $appendStream;
+            default: 
+                throw new CryptoException("Unsupported Cipher used for key commitment messages."
+                    . " Found {$cipherOptions["Cipher"]}. Only 'gcm' is supported.");
+        }
+    }
+
+    /**
+     * Generates a stream that wraps the plaintext with the proper cipher and
+     * uses the content encryption key (CEK) to encrypt the data when read.
+     *
+     * @param StreamInterface $plaintext Plain-text data to be encrypted using the
+     *                          materials, algorithm, and data provided.
+     * @param string $cek A content encryption key for use by the stream for
+     *                    encrypting the plaintext data.
+     * @param array $cipherOptions Options for use in determining the cipher to
+     *                             be used for encrypting data.
+     * @param string $messageId salt value used for key extraction step in the key
+     *                          derivation process.
+     * @param AlgorithmSuite $algorithmSuite options used for key commitment
+     *
+     * @return array returns an array with two elements as follows: [commitmentKey, AppendStream]
+     *
+     * @internal
+     */
+    protected function getCommitingEncryptionStream(
+        StreamInterface $plaintext,
+        string $dek,
+        array &$cipherOptions,
+        string $messageId,
+        AlgorithmSuite $algorithmSuite
+    ): array
+    {
+        $algorithmSuiteIdAsBytes = pack('n', $algorithmSuite->getId());
+        //= ../specification/s3-encryption/key-derivation.md#hkdf-operation
+        //= type=implication
+        //# - The input info MUST be a concatenation of the algorithm suite ID as bytes followed by the string DERIVEKEY as UTF8 encoded bytes.
+        $derivedEncryptionKeyInfo = $algorithmSuiteIdAsBytes . "DERIVEKEY";
+        //= ../specification/s3-encryption/key-derivation.md#hkdf-operation
+        //= type=implication
+        //# - The input info MUST be a concatenation of the algorithm suite ID as bytes followed by the string COMMITKEY as UTF8 encoded bytes.
+        $commitmentKeyInfo = $algorithmSuiteIdAsBytes . "COMMITKEY";
+        //= ../specification/s3-encryption/key-derivation.md#hkdf-operation
+        //= type=implication
+        //# - The length of the input keying material MUST equal the key derivation
+        //# input length specified by the algorithm suite commit key derivation setting.
+        if (strlen($dek) !== $algorithmSuite->getDerivationInputKeyLengthBytes()) {
+            throw new CryptoException("Input Key Material length exceeds "
+                . "key derivation input length specified by the algorithm suite.");
+        }
+        //= ../specification/s3-encryption/encryption.md#alg-aes-256-gcm-hkdf-sha512-commit-key
+        //= type=implication
+        //# The client MUST use HKDF to derive the key commitment value and
+        //# the derived encrypting key as described in [Key Derivation](key-derivation.md).
+        $cek = hash_hkdf(
+            //= ../specification/s3-encryption/key-derivation.md#hkdf-operation
+            //= type=implication
+            //# - The hash function MUST be specified by the algorithm suite commitment settings.
+            $algorithmSuite->getHashingAlgorithm(),
+            //= ../specification/s3-encryption/key-derivation.md#hkdf-operation
+            //= type=implication
+            //# - The input keying material MUST be the plaintext data key (PDK) generated by the key provider.
+            //= ../specification/s3-encryption/key-derivation.md#hkdf-operation
+            //= type=implication
+            //# - The DEK input pseudorandom key MUST be the output from the extract step.
+            $dek,
+            //= ../specification/s3-encryption/key-derivation.md#hkdf-operation
+            //= type=implication
+            //# - The length of the output keying material MUST equal the encryption key length specified by the algorithm suite encryption settings.
+            $algorithmSuite->getDerivationOutputKeyLengthBytes(),
+            $derivedEncryptionKeyInfo,
+            //= ../specification/s3-encryption/key-derivation.md#hkdf-operation
+            //= type=implication
+            //# - The salt MUST be the Message ID with the length defined in the algorithm suite.
+            $messageId
+        );
+        $commitmentKey = hash_hkdf(
+            $algorithmSuite->getHashingAlgorithm(),
+            //= ../specification/s3-encryption/key-derivation.md#hkdf-operation
+            //= type=implication
+            //# - The CK input pseudorandom key MUST be the output from the extract step.
+            $dek,
+            //= ../specification/s3-encryption/key-derivation.md#hkdf-operation
+            //= type=implication
+            //# - The length of the output keying material MUST equal the commit key length specified by the supported algorithm suites.
+            $algorithmSuite->getCommitmentOutputKeyLengthBytes(),
+            $commitmentKeyInfo,
+            $messageId
+        );
+
+        switch ($cipherOptions['Cipher']) {
+            // Only 'gcm' is supported for encryption currently
+            case 'gcm':
+                $cipherOptions['TagLength'] = $algorithmSuite->getCipherTagLengthInBytes();
+                $encryptClass = self::$encryptClasses[$algorithmSuite->getCipherName()];
+
+                if (!empty($cipherOptions['Aad'])) {
+                    trigger_error("'Aad' has been supplied for content encryption"
+                        . " with " . $encryptClass::getStaticAesName() . ". The"
+                        . " PHP SDK encryption client can decrypt an object"
+                        . " encrypted in this way, but other AWS SDKs may not be"
+                        . " able to.", E_USER_NOTICE);
+                }
+                $cipherOptions['Aad'] = isset($cipherOptions['Aad'])
+                    ? $cipherOptions['Aad'] . $algorithmSuiteIdAsBytes
+                    : $algorithmSuiteIdAsBytes;
+                //= ../specification/s3-encryption/key-derivation.md#hkdf-operation
+                //= type=implication
+                //# The client MUST initialize the cipher, or call an AES-GCM encryption API,
+                //# with the derived encryption key, an IV containing only bytes with the value 0x01,
+                //# and the tag length defined in the Algorithm Suite when encrypting or
+                //# decrypting with ALG_AES_256_GCM_HKDF_SHA512_COMMIT_KEY.
+                $cipherTextStream = new $encryptClass(
+                    $plaintext,
+                    $cek,
+                    $cipherOptions['Iv'],
+                    $cipherOptions['Aad'],
+                    $cipherOptions['TagLength'],
+                    $cipherOptions['KeySize']
+                );
+
+                $appendStream = new AppendStream([
+                    $cipherTextStream->createStream()
+                ]);
+                //= ../specification/s3-encryption/encryption.md#alg-aes-256-gcm-hkdf-sha512-commit-key
+                //= type=implication
+                //# The client MUST append the GCM auth tag to the ciphertext if the underlying
+                //# crypto provider does not do so automatically.
+                $cipherOptions['Tag'] = $cipherTextStream->getTag();
+                $appendStream->addStream(Psr7\Utils::streamFor($cipherOptions['Tag']));
+                
+                return [base64_encode($commitmentKey), $appendStream];
+            default: 
+                throw new CryptoException("Unsupported Cipher used for content encryption");
+        }
+    }
+}

+ 223 - 0
upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/CustomerProfiles/CustomerProfilesClient.php

@@ -0,0 +1,223 @@
+<?php
+namespace Aws\CustomerProfiles;
+
+use Aws\AwsClient;
+
+/**
+ * This client is used to interact with the **Amazon Connect Customer Profiles** service.
+ * @method \Aws\Result addProfileKey(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise addProfileKeyAsync(array $args = [])
+ * @method \Aws\Result batchGetCalculatedAttributeForProfile(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise batchGetCalculatedAttributeForProfileAsync(array $args = [])
+ * @method \Aws\Result batchGetProfile(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise batchGetProfileAsync(array $args = [])
+ * @method \Aws\Result batchPutProfileObject(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise batchPutProfileObjectAsync(array $args = [])
+ * @method \Aws\Result createCalculatedAttributeDefinition(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createCalculatedAttributeDefinitionAsync(array $args = [])
+ * @method \Aws\Result createDomain(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createDomainAsync(array $args = [])
+ * @method \Aws\Result createDomainLayout(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createDomainLayoutAsync(array $args = [])
+ * @method \Aws\Result createEventStream(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createEventStreamAsync(array $args = [])
+ * @method \Aws\Result createEventTrigger(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createEventTriggerAsync(array $args = [])
+ * @method \Aws\Result createIntegrationWorkflow(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createIntegrationWorkflowAsync(array $args = [])
+ * @method \Aws\Result createProfile(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createProfileAsync(array $args = [])
+ * @method \Aws\Result createRecommender(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createRecommenderAsync(array $args = [])
+ * @method \Aws\Result createRecommenderFilter(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createRecommenderFilterAsync(array $args = [])
+ * @method \Aws\Result createRecommenderSchema(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createRecommenderSchemaAsync(array $args = [])
+ * @method \Aws\Result createSegmentDefinition(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createSegmentDefinitionAsync(array $args = [])
+ * @method \Aws\Result createSegmentEstimate(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createSegmentEstimateAsync(array $args = [])
+ * @method \Aws\Result createSegmentSnapshot(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createSegmentSnapshotAsync(array $args = [])
+ * @method \Aws\Result createUploadJob(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createUploadJobAsync(array $args = [])
+ * @method \Aws\Result deleteCalculatedAttributeDefinition(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteCalculatedAttributeDefinitionAsync(array $args = [])
+ * @method \Aws\Result deleteDomain(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteDomainAsync(array $args = [])
+ * @method \Aws\Result deleteDomainLayout(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteDomainLayoutAsync(array $args = [])
+ * @method \Aws\Result deleteDomainObjectType(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteDomainObjectTypeAsync(array $args = [])
+ * @method \Aws\Result deleteEventStream(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteEventStreamAsync(array $args = [])
+ * @method \Aws\Result deleteEventTrigger(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteEventTriggerAsync(array $args = [])
+ * @method \Aws\Result deleteIntegration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteIntegrationAsync(array $args = [])
+ * @method \Aws\Result deleteProfile(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteProfileAsync(array $args = [])
+ * @method \Aws\Result deleteProfileKey(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteProfileKeyAsync(array $args = [])
+ * @method \Aws\Result deleteProfileObject(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteProfileObjectAsync(array $args = [])
+ * @method \Aws\Result deleteProfileObjectType(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteProfileObjectTypeAsync(array $args = [])
+ * @method \Aws\Result deleteRecommender(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteRecommenderAsync(array $args = [])
+ * @method \Aws\Result deleteRecommenderFilter(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteRecommenderFilterAsync(array $args = [])
+ * @method \Aws\Result deleteRecommenderSchema(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteRecommenderSchemaAsync(array $args = [])
+ * @method \Aws\Result deleteSegmentDefinition(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteSegmentDefinitionAsync(array $args = [])
+ * @method \Aws\Result deleteWorkflow(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteWorkflowAsync(array $args = [])
+ * @method \Aws\Result detectProfileObjectType(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise detectProfileObjectTypeAsync(array $args = [])
+ * @method \Aws\Result getAutoMergingPreview(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getAutoMergingPreviewAsync(array $args = [])
+ * @method \Aws\Result getCalculatedAttributeDefinition(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getCalculatedAttributeDefinitionAsync(array $args = [])
+ * @method \Aws\Result getCalculatedAttributeForProfile(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getCalculatedAttributeForProfileAsync(array $args = [])
+ * @method \Aws\Result getDomain(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getDomainAsync(array $args = [])
+ * @method \Aws\Result getDomainLayout(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getDomainLayoutAsync(array $args = [])
+ * @method \Aws\Result getDomainObjectType(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getDomainObjectTypeAsync(array $args = [])
+ * @method \Aws\Result getEventStream(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getEventStreamAsync(array $args = [])
+ * @method \Aws\Result getEventTrigger(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getEventTriggerAsync(array $args = [])
+ * @method \Aws\Result getIdentityResolutionJob(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getIdentityResolutionJobAsync(array $args = [])
+ * @method \Aws\Result getIntegration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getIntegrationAsync(array $args = [])
+ * @method \Aws\Result getMatches(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getMatchesAsync(array $args = [])
+ * @method \Aws\Result getObjectTypeAttributeStatistics(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getObjectTypeAttributeStatisticsAsync(array $args = [])
+ * @method \Aws\Result getProfileHistoryRecord(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getProfileHistoryRecordAsync(array $args = [])
+ * @method \Aws\Result getProfileObjectType(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getProfileObjectTypeAsync(array $args = [])
+ * @method \Aws\Result getProfileObjectTypeTemplate(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getProfileObjectTypeTemplateAsync(array $args = [])
+ * @method \Aws\Result getProfileRecommendations(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getProfileRecommendationsAsync(array $args = [])
+ * @method \Aws\Result getRecommender(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getRecommenderAsync(array $args = [])
+ * @method \Aws\Result getRecommenderFilter(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getRecommenderFilterAsync(array $args = [])
+ * @method \Aws\Result getRecommenderSchema(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getRecommenderSchemaAsync(array $args = [])
+ * @method \Aws\Result getSegmentDefinition(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getSegmentDefinitionAsync(array $args = [])
+ * @method \Aws\Result getSegmentEstimate(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getSegmentEstimateAsync(array $args = [])
+ * @method \Aws\Result getSegmentMembership(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getSegmentMembershipAsync(array $args = [])
+ * @method \Aws\Result getSegmentSnapshot(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getSegmentSnapshotAsync(array $args = [])
+ * @method \Aws\Result getSimilarProfiles(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getSimilarProfilesAsync(array $args = [])
+ * @method \Aws\Result getUploadJob(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getUploadJobAsync(array $args = [])
+ * @method \Aws\Result getUploadJobPath(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getUploadJobPathAsync(array $args = [])
+ * @method \Aws\Result getWorkflow(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getWorkflowAsync(array $args = [])
+ * @method \Aws\Result getWorkflowSteps(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getWorkflowStepsAsync(array $args = [])
+ * @method \Aws\Result listAccountIntegrations(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listAccountIntegrationsAsync(array $args = [])
+ * @method \Aws\Result listCalculatedAttributeDefinitions(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listCalculatedAttributeDefinitionsAsync(array $args = [])
+ * @method \Aws\Result listCalculatedAttributesForProfile(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listCalculatedAttributesForProfileAsync(array $args = [])
+ * @method \Aws\Result listDomainLayouts(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listDomainLayoutsAsync(array $args = [])
+ * @method \Aws\Result listDomainObjectTypes(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listDomainObjectTypesAsync(array $args = [])
+ * @method \Aws\Result listDomains(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listDomainsAsync(array $args = [])
+ * @method \Aws\Result listEventStreams(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listEventStreamsAsync(array $args = [])
+ * @method \Aws\Result listEventTriggers(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listEventTriggersAsync(array $args = [])
+ * @method \Aws\Result listIdentityResolutionJobs(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listIdentityResolutionJobsAsync(array $args = [])
+ * @method \Aws\Result listIntegrations(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listIntegrationsAsync(array $args = [])
+ * @method \Aws\Result listObjectTypeAttributeValues(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listObjectTypeAttributeValuesAsync(array $args = [])
+ * @method \Aws\Result listObjectTypeAttributes(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listObjectTypeAttributesAsync(array $args = [])
+ * @method \Aws\Result listProfileAttributeValues(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listProfileAttributeValuesAsync(array $args = [])
+ * @method \Aws\Result listProfileHistoryRecords(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listProfileHistoryRecordsAsync(array $args = [])
+ * @method \Aws\Result listProfileObjectTypeTemplates(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listProfileObjectTypeTemplatesAsync(array $args = [])
+ * @method \Aws\Result listProfileObjectTypes(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listProfileObjectTypesAsync(array $args = [])
+ * @method \Aws\Result listProfileObjects(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listProfileObjectsAsync(array $args = [])
+ * @method \Aws\Result listRecommenderFilters(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listRecommenderFiltersAsync(array $args = [])
+ * @method \Aws\Result listRecommenderRecipes(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listRecommenderRecipesAsync(array $args = [])
+ * @method \Aws\Result listRecommenderSchemas(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listRecommenderSchemasAsync(array $args = [])
+ * @method \Aws\Result listRecommenders(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listRecommendersAsync(array $args = [])
+ * @method \Aws\Result listRuleBasedMatches(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listRuleBasedMatchesAsync(array $args = [])
+ * @method \Aws\Result listSegmentDefinitions(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listSegmentDefinitionsAsync(array $args = [])
+ * @method \Aws\Result listTagsForResource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listTagsForResourceAsync(array $args = [])
+ * @method \Aws\Result listUploadJobs(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listUploadJobsAsync(array $args = [])
+ * @method \Aws\Result listWorkflows(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listWorkflowsAsync(array $args = [])
+ * @method \Aws\Result mergeProfiles(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise mergeProfilesAsync(array $args = [])
+ * @method \Aws\Result putDomainObjectType(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise putDomainObjectTypeAsync(array $args = [])
+ * @method \Aws\Result putIntegration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise putIntegrationAsync(array $args = [])
+ * @method \Aws\Result putProfileObject(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise putProfileObjectAsync(array $args = [])
+ * @method \Aws\Result putProfileObjectType(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise putProfileObjectTypeAsync(array $args = [])
+ * @method \Aws\Result searchProfiles(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise searchProfilesAsync(array $args = [])
+ * @method \Aws\Result startRecommender(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise startRecommenderAsync(array $args = [])
+ * @method \Aws\Result startUploadJob(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise startUploadJobAsync(array $args = [])
+ * @method \Aws\Result stopRecommender(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise stopRecommenderAsync(array $args = [])
+ * @method \Aws\Result stopUploadJob(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise stopUploadJobAsync(array $args = [])
+ * @method \Aws\Result tagResource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise tagResourceAsync(array $args = [])
+ * @method \Aws\Result untagResource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise untagResourceAsync(array $args = [])
+ * @method \Aws\Result updateCalculatedAttributeDefinition(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateCalculatedAttributeDefinitionAsync(array $args = [])
+ * @method \Aws\Result updateDomain(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateDomainAsync(array $args = [])
+ * @method \Aws\Result updateDomainLayout(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateDomainLayoutAsync(array $args = [])
+ * @method \Aws\Result updateEventTrigger(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateEventTriggerAsync(array $args = [])
+ * @method \Aws\Result updateProfile(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateProfileAsync(array $args = [])
+ * @method \Aws\Result updateRecommender(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateRecommenderAsync(array $args = [])
+ */
+class CustomerProfilesClient extends AwsClient {}

+ 387 - 0
upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/DataZone/DataZoneClient.php

@@ -0,0 +1,387 @@
+<?php
+namespace Aws\DataZone;
+
+use Aws\AwsClient;
+
+/**
+ * This client is used to interact with the **Amazon DataZone** service.
+ * @method \Aws\Result acceptPredictions(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise acceptPredictionsAsync(array $args = [])
+ * @method \Aws\Result acceptSubscriptionRequest(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise acceptSubscriptionRequestAsync(array $args = [])
+ * @method \Aws\Result addEntityOwner(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise addEntityOwnerAsync(array $args = [])
+ * @method \Aws\Result addPolicyGrant(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise addPolicyGrantAsync(array $args = [])
+ * @method \Aws\Result associateEnvironmentRole(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise associateEnvironmentRoleAsync(array $args = [])
+ * @method \Aws\Result associateGovernedTerms(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise associateGovernedTermsAsync(array $args = [])
+ * @method \Aws\Result batchGetAttributesMetadata(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise batchGetAttributesMetadataAsync(array $args = [])
+ * @method \Aws\Result batchPutAttributesMetadata(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise batchPutAttributesMetadataAsync(array $args = [])
+ * @method \Aws\Result cancelMetadataGenerationRun(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise cancelMetadataGenerationRunAsync(array $args = [])
+ * @method \Aws\Result cancelSubscription(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise cancelSubscriptionAsync(array $args = [])
+ * @method \Aws\Result createAccountPool(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createAccountPoolAsync(array $args = [])
+ * @method \Aws\Result createAsset(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createAssetAsync(array $args = [])
+ * @method \Aws\Result createAssetFilter(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createAssetFilterAsync(array $args = [])
+ * @method \Aws\Result createAssetRevision(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createAssetRevisionAsync(array $args = [])
+ * @method \Aws\Result createAssetType(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createAssetTypeAsync(array $args = [])
+ * @method \Aws\Result createConnection(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createConnectionAsync(array $args = [])
+ * @method \Aws\Result createDataProduct(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createDataProductAsync(array $args = [])
+ * @method \Aws\Result createDataProductRevision(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createDataProductRevisionAsync(array $args = [])
+ * @method \Aws\Result createDataSource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createDataSourceAsync(array $args = [])
+ * @method \Aws\Result createDomain(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createDomainAsync(array $args = [])
+ * @method \Aws\Result createDomainUnit(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createDomainUnitAsync(array $args = [])
+ * @method \Aws\Result createEnvironment(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createEnvironmentAsync(array $args = [])
+ * @method \Aws\Result createEnvironmentAction(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createEnvironmentActionAsync(array $args = [])
+ * @method \Aws\Result createEnvironmentBlueprint(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createEnvironmentBlueprintAsync(array $args = [])
+ * @method \Aws\Result createEnvironmentProfile(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createEnvironmentProfileAsync(array $args = [])
+ * @method \Aws\Result createFormType(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createFormTypeAsync(array $args = [])
+ * @method \Aws\Result createGlossary(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createGlossaryAsync(array $args = [])
+ * @method \Aws\Result createGlossaryTerm(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createGlossaryTermAsync(array $args = [])
+ * @method \Aws\Result createGroupProfile(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createGroupProfileAsync(array $args = [])
+ * @method \Aws\Result createListingChangeSet(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createListingChangeSetAsync(array $args = [])
+ * @method \Aws\Result createNotebook(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createNotebookAsync(array $args = [])
+ * @method \Aws\Result createProject(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createProjectAsync(array $args = [])
+ * @method \Aws\Result createProjectMembership(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createProjectMembershipAsync(array $args = [])
+ * @method \Aws\Result createProjectProfile(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createProjectProfileAsync(array $args = [])
+ * @method \Aws\Result createRule(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createRuleAsync(array $args = [])
+ * @method \Aws\Result createSubscriptionGrant(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createSubscriptionGrantAsync(array $args = [])
+ * @method \Aws\Result createSubscriptionRequest(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createSubscriptionRequestAsync(array $args = [])
+ * @method \Aws\Result createSubscriptionTarget(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createSubscriptionTargetAsync(array $args = [])
+ * @method \Aws\Result createUserProfile(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createUserProfileAsync(array $args = [])
+ * @method \Aws\Result deleteAccountPool(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteAccountPoolAsync(array $args = [])
+ * @method \Aws\Result deleteAsset(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteAssetAsync(array $args = [])
+ * @method \Aws\Result deleteAssetFilter(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteAssetFilterAsync(array $args = [])
+ * @method \Aws\Result deleteAssetType(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteAssetTypeAsync(array $args = [])
+ * @method \Aws\Result deleteConnection(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteConnectionAsync(array $args = [])
+ * @method \Aws\Result deleteDataExportConfiguration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteDataExportConfigurationAsync(array $args = [])
+ * @method \Aws\Result deleteDataProduct(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteDataProductAsync(array $args = [])
+ * @method \Aws\Result deleteDataSource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteDataSourceAsync(array $args = [])
+ * @method \Aws\Result deleteDomain(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteDomainAsync(array $args = [])
+ * @method \Aws\Result deleteDomainUnit(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteDomainUnitAsync(array $args = [])
+ * @method \Aws\Result deleteEnvironment(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteEnvironmentAsync(array $args = [])
+ * @method \Aws\Result deleteEnvironmentAction(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteEnvironmentActionAsync(array $args = [])
+ * @method \Aws\Result deleteEnvironmentBlueprint(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteEnvironmentBlueprintAsync(array $args = [])
+ * @method \Aws\Result deleteEnvironmentBlueprintConfiguration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteEnvironmentBlueprintConfigurationAsync(array $args = [])
+ * @method \Aws\Result deleteEnvironmentProfile(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteEnvironmentProfileAsync(array $args = [])
+ * @method \Aws\Result deleteFormType(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteFormTypeAsync(array $args = [])
+ * @method \Aws\Result deleteGlossary(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteGlossaryAsync(array $args = [])
+ * @method \Aws\Result deleteGlossaryTerm(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteGlossaryTermAsync(array $args = [])
+ * @method \Aws\Result deleteLineageEvent(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteLineageEventAsync(array $args = [])
+ * @method \Aws\Result deleteListing(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteListingAsync(array $args = [])
+ * @method \Aws\Result deleteNotebook(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteNotebookAsync(array $args = [])
+ * @method \Aws\Result deleteProject(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteProjectAsync(array $args = [])
+ * @method \Aws\Result deleteProjectMembership(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteProjectMembershipAsync(array $args = [])
+ * @method \Aws\Result deleteProjectProfile(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteProjectProfileAsync(array $args = [])
+ * @method \Aws\Result deleteRule(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteRuleAsync(array $args = [])
+ * @method \Aws\Result deleteSubscriptionGrant(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteSubscriptionGrantAsync(array $args = [])
+ * @method \Aws\Result deleteSubscriptionRequest(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteSubscriptionRequestAsync(array $args = [])
+ * @method \Aws\Result deleteSubscriptionTarget(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteSubscriptionTargetAsync(array $args = [])
+ * @method \Aws\Result deleteTimeSeriesDataPoints(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteTimeSeriesDataPointsAsync(array $args = [])
+ * @method \Aws\Result disassociateEnvironmentRole(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise disassociateEnvironmentRoleAsync(array $args = [])
+ * @method \Aws\Result disassociateGovernedTerms(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise disassociateGovernedTermsAsync(array $args = [])
+ * @method \Aws\Result getAccountPool(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getAccountPoolAsync(array $args = [])
+ * @method \Aws\Result getAsset(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getAssetAsync(array $args = [])
+ * @method \Aws\Result getAssetFilter(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getAssetFilterAsync(array $args = [])
+ * @method \Aws\Result getAssetType(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getAssetTypeAsync(array $args = [])
+ * @method \Aws\Result getConnection(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getConnectionAsync(array $args = [])
+ * @method \Aws\Result getDataExportConfiguration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getDataExportConfigurationAsync(array $args = [])
+ * @method \Aws\Result getDataProduct(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getDataProductAsync(array $args = [])
+ * @method \Aws\Result getDataSource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getDataSourceAsync(array $args = [])
+ * @method \Aws\Result getDataSourceRun(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getDataSourceRunAsync(array $args = [])
+ * @method \Aws\Result getDomain(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getDomainAsync(array $args = [])
+ * @method \Aws\Result getDomainUnit(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getDomainUnitAsync(array $args = [])
+ * @method \Aws\Result getEnvironment(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getEnvironmentAsync(array $args = [])
+ * @method \Aws\Result getEnvironmentAction(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getEnvironmentActionAsync(array $args = [])
+ * @method \Aws\Result getEnvironmentBlueprint(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getEnvironmentBlueprintAsync(array $args = [])
+ * @method \Aws\Result getEnvironmentBlueprintConfiguration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getEnvironmentBlueprintConfigurationAsync(array $args = [])
+ * @method \Aws\Result getEnvironmentCredentials(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getEnvironmentCredentialsAsync(array $args = [])
+ * @method \Aws\Result getEnvironmentProfile(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getEnvironmentProfileAsync(array $args = [])
+ * @method \Aws\Result getFormType(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getFormTypeAsync(array $args = [])
+ * @method \Aws\Result getGlossary(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getGlossaryAsync(array $args = [])
+ * @method \Aws\Result getGlossaryTerm(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getGlossaryTermAsync(array $args = [])
+ * @method \Aws\Result getGroupProfile(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getGroupProfileAsync(array $args = [])
+ * @method \Aws\Result getIamPortalLoginUrl(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getIamPortalLoginUrlAsync(array $args = [])
+ * @method \Aws\Result getJobRun(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getJobRunAsync(array $args = [])
+ * @method \Aws\Result getLineageEvent(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getLineageEventAsync(array $args = [])
+ * @method \Aws\Result getLineageNode(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getLineageNodeAsync(array $args = [])
+ * @method \Aws\Result getListing(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getListingAsync(array $args = [])
+ * @method \Aws\Result getMetadataGenerationRun(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getMetadataGenerationRunAsync(array $args = [])
+ * @method \Aws\Result getNotebook(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getNotebookAsync(array $args = [])
+ * @method \Aws\Result getNotebookExport(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getNotebookExportAsync(array $args = [])
+ * @method \Aws\Result getNotebookRun(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getNotebookRunAsync(array $args = [])
+ * @method \Aws\Result getProject(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getProjectAsync(array $args = [])
+ * @method \Aws\Result getProjectProfile(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getProjectProfileAsync(array $args = [])
+ * @method \Aws\Result getRule(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getRuleAsync(array $args = [])
+ * @method \Aws\Result getSubscription(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getSubscriptionAsync(array $args = [])
+ * @method \Aws\Result getSubscriptionGrant(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getSubscriptionGrantAsync(array $args = [])
+ * @method \Aws\Result getSubscriptionRequestDetails(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getSubscriptionRequestDetailsAsync(array $args = [])
+ * @method \Aws\Result getSubscriptionTarget(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getSubscriptionTargetAsync(array $args = [])
+ * @method \Aws\Result getTimeSeriesDataPoint(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getTimeSeriesDataPointAsync(array $args = [])
+ * @method \Aws\Result getUserProfile(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getUserProfileAsync(array $args = [])
+ * @method \Aws\Result listAccountPools(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listAccountPoolsAsync(array $args = [])
+ * @method \Aws\Result listAccountsInAccountPool(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listAccountsInAccountPoolAsync(array $args = [])
+ * @method \Aws\Result listAssetFilters(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listAssetFiltersAsync(array $args = [])
+ * @method \Aws\Result listAssetRevisions(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listAssetRevisionsAsync(array $args = [])
+ * @method \Aws\Result listConnections(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listConnectionsAsync(array $args = [])
+ * @method \Aws\Result listDataProductRevisions(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listDataProductRevisionsAsync(array $args = [])
+ * @method \Aws\Result listDataSourceRunActivities(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listDataSourceRunActivitiesAsync(array $args = [])
+ * @method \Aws\Result listDataSourceRuns(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listDataSourceRunsAsync(array $args = [])
+ * @method \Aws\Result listDataSources(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listDataSourcesAsync(array $args = [])
+ * @method \Aws\Result listDomainUnitsForParent(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listDomainUnitsForParentAsync(array $args = [])
+ * @method \Aws\Result listDomains(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listDomainsAsync(array $args = [])
+ * @method \Aws\Result listEntityOwners(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listEntityOwnersAsync(array $args = [])
+ * @method \Aws\Result listEnvironmentActions(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listEnvironmentActionsAsync(array $args = [])
+ * @method \Aws\Result listEnvironmentBlueprintConfigurations(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listEnvironmentBlueprintConfigurationsAsync(array $args = [])
+ * @method \Aws\Result listEnvironmentBlueprints(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listEnvironmentBlueprintsAsync(array $args = [])
+ * @method \Aws\Result listEnvironmentProfiles(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listEnvironmentProfilesAsync(array $args = [])
+ * @method \Aws\Result listEnvironments(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listEnvironmentsAsync(array $args = [])
+ * @method \Aws\Result listJobRuns(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listJobRunsAsync(array $args = [])
+ * @method \Aws\Result listLineageEvents(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listLineageEventsAsync(array $args = [])
+ * @method \Aws\Result listLineageNodeHistory(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listLineageNodeHistoryAsync(array $args = [])
+ * @method \Aws\Result listMetadataGenerationRuns(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listMetadataGenerationRunsAsync(array $args = [])
+ * @method \Aws\Result listNotebookRuns(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listNotebookRunsAsync(array $args = [])
+ * @method \Aws\Result listNotebooks(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listNotebooksAsync(array $args = [])
+ * @method \Aws\Result listNotifications(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listNotificationsAsync(array $args = [])
+ * @method \Aws\Result listPolicyGrants(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listPolicyGrantsAsync(array $args = [])
+ * @method \Aws\Result listProjectMemberships(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listProjectMembershipsAsync(array $args = [])
+ * @method \Aws\Result listProjectProfiles(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listProjectProfilesAsync(array $args = [])
+ * @method \Aws\Result listProjects(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listProjectsAsync(array $args = [])
+ * @method \Aws\Result listRules(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listRulesAsync(array $args = [])
+ * @method \Aws\Result listSubscriptionGrants(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listSubscriptionGrantsAsync(array $args = [])
+ * @method \Aws\Result listSubscriptionRequests(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listSubscriptionRequestsAsync(array $args = [])
+ * @method \Aws\Result listSubscriptionTargets(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listSubscriptionTargetsAsync(array $args = [])
+ * @method \Aws\Result listSubscriptions(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listSubscriptionsAsync(array $args = [])
+ * @method \Aws\Result listTagsForResource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listTagsForResourceAsync(array $args = [])
+ * @method \Aws\Result listTimeSeriesDataPoints(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listTimeSeriesDataPointsAsync(array $args = [])
+ * @method \Aws\Result postLineageEvent(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise postLineageEventAsync(array $args = [])
+ * @method \Aws\Result postTimeSeriesDataPoints(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise postTimeSeriesDataPointsAsync(array $args = [])
+ * @method \Aws\Result putDataExportConfiguration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise putDataExportConfigurationAsync(array $args = [])
+ * @method \Aws\Result putEnvironmentBlueprintConfiguration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise putEnvironmentBlueprintConfigurationAsync(array $args = [])
+ * @method \Aws\Result queryGraph(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise queryGraphAsync(array $args = [])
+ * @method \Aws\Result rejectPredictions(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise rejectPredictionsAsync(array $args = [])
+ * @method \Aws\Result rejectSubscriptionRequest(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise rejectSubscriptionRequestAsync(array $args = [])
+ * @method \Aws\Result removeEntityOwner(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise removeEntityOwnerAsync(array $args = [])
+ * @method \Aws\Result removePolicyGrant(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise removePolicyGrantAsync(array $args = [])
+ * @method \Aws\Result revokeSubscription(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise revokeSubscriptionAsync(array $args = [])
+ * @method \Aws\Result search(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise searchAsync(array $args = [])
+ * @method \Aws\Result searchGroupProfiles(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise searchGroupProfilesAsync(array $args = [])
+ * @method \Aws\Result searchListings(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise searchListingsAsync(array $args = [])
+ * @method \Aws\Result searchTypes(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise searchTypesAsync(array $args = [])
+ * @method \Aws\Result searchUserProfiles(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise searchUserProfilesAsync(array $args = [])
+ * @method \Aws\Result startDataSourceRun(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise startDataSourceRunAsync(array $args = [])
+ * @method \Aws\Result startMetadataGenerationRun(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise startMetadataGenerationRunAsync(array $args = [])
+ * @method \Aws\Result startNotebookExport(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise startNotebookExportAsync(array $args = [])
+ * @method \Aws\Result startNotebookImport(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise startNotebookImportAsync(array $args = [])
+ * @method \Aws\Result startNotebookRun(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise startNotebookRunAsync(array $args = [])
+ * @method \Aws\Result stopNotebookRun(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise stopNotebookRunAsync(array $args = [])
+ * @method \Aws\Result tagResource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise tagResourceAsync(array $args = [])
+ * @method \Aws\Result untagResource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise untagResourceAsync(array $args = [])
+ * @method \Aws\Result updateAccountPool(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateAccountPoolAsync(array $args = [])
+ * @method \Aws\Result updateAssetFilter(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateAssetFilterAsync(array $args = [])
+ * @method \Aws\Result updateConnection(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateConnectionAsync(array $args = [])
+ * @method \Aws\Result updateDataSource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateDataSourceAsync(array $args = [])
+ * @method \Aws\Result updateDomain(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateDomainAsync(array $args = [])
+ * @method \Aws\Result updateDomainUnit(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateDomainUnitAsync(array $args = [])
+ * @method \Aws\Result updateEnvironment(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateEnvironmentAsync(array $args = [])
+ * @method \Aws\Result updateEnvironmentAction(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateEnvironmentActionAsync(array $args = [])
+ * @method \Aws\Result updateEnvironmentBlueprint(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateEnvironmentBlueprintAsync(array $args = [])
+ * @method \Aws\Result updateEnvironmentProfile(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateEnvironmentProfileAsync(array $args = [])
+ * @method \Aws\Result updateGlossary(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateGlossaryAsync(array $args = [])
+ * @method \Aws\Result updateGlossaryTerm(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateGlossaryTermAsync(array $args = [])
+ * @method \Aws\Result updateGroupProfile(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateGroupProfileAsync(array $args = [])
+ * @method \Aws\Result updateNotebook(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateNotebookAsync(array $args = [])
+ * @method \Aws\Result updateProject(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateProjectAsync(array $args = [])
+ * @method \Aws\Result updateProjectProfile(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateProjectProfileAsync(array $args = [])
+ * @method \Aws\Result updateRootDomainUnitOwner(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateRootDomainUnitOwnerAsync(array $args = [])
+ * @method \Aws\Result updateRule(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateRuleAsync(array $args = [])
+ * @method \Aws\Result updateSubscriptionGrantStatus(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateSubscriptionGrantStatusAsync(array $args = [])
+ * @method \Aws\Result updateSubscriptionRequest(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateSubscriptionRequestAsync(array $args = [])
+ * @method \Aws\Result updateSubscriptionTarget(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateSubscriptionTargetAsync(array $args = [])
+ * @method \Aws\Result updateUserProfile(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateUserProfileAsync(array $args = [])
+ */
+class DataZoneClient extends AwsClient {}

+ 261 - 0
upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/Deadline/DeadlineClient.php

@@ -0,0 +1,261 @@
+<?php
+namespace Aws\Deadline;
+
+use Aws\AwsClient;
+
+/**
+ * This client is used to interact with the **AWSDeadlineCloud** service.
+ * @method \Aws\Result associateMemberToFarm(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise associateMemberToFarmAsync(array $args = [])
+ * @method \Aws\Result associateMemberToFleet(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise associateMemberToFleetAsync(array $args = [])
+ * @method \Aws\Result associateMemberToJob(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise associateMemberToJobAsync(array $args = [])
+ * @method \Aws\Result associateMemberToQueue(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise associateMemberToQueueAsync(array $args = [])
+ * @method \Aws\Result assumeFleetRoleForRead(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise assumeFleetRoleForReadAsync(array $args = [])
+ * @method \Aws\Result assumeFleetRoleForWorker(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise assumeFleetRoleForWorkerAsync(array $args = [])
+ * @method \Aws\Result assumeQueueRoleForRead(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise assumeQueueRoleForReadAsync(array $args = [])
+ * @method \Aws\Result assumeQueueRoleForUser(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise assumeQueueRoleForUserAsync(array $args = [])
+ * @method \Aws\Result assumeQueueRoleForWorker(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise assumeQueueRoleForWorkerAsync(array $args = [])
+ * @method \Aws\Result batchGetJob(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise batchGetJobAsync(array $args = [])
+ * @method \Aws\Result batchGetJobEntity(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise batchGetJobEntityAsync(array $args = [])
+ * @method \Aws\Result batchGetSession(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise batchGetSessionAsync(array $args = [])
+ * @method \Aws\Result batchGetSessionAction(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise batchGetSessionActionAsync(array $args = [])
+ * @method \Aws\Result batchGetStep(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise batchGetStepAsync(array $args = [])
+ * @method \Aws\Result batchGetTask(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise batchGetTaskAsync(array $args = [])
+ * @method \Aws\Result batchGetWorker(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise batchGetWorkerAsync(array $args = [])
+ * @method \Aws\Result batchUpdateJob(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise batchUpdateJobAsync(array $args = [])
+ * @method \Aws\Result batchUpdateTask(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise batchUpdateTaskAsync(array $args = [])
+ * @method \Aws\Result copyJobTemplate(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise copyJobTemplateAsync(array $args = [])
+ * @method \Aws\Result createBudget(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createBudgetAsync(array $args = [])
+ * @method \Aws\Result createFarm(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createFarmAsync(array $args = [])
+ * @method \Aws\Result createFleet(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createFleetAsync(array $args = [])
+ * @method \Aws\Result createJob(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createJobAsync(array $args = [])
+ * @method \Aws\Result createLicenseEndpoint(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createLicenseEndpointAsync(array $args = [])
+ * @method \Aws\Result createLimit(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createLimitAsync(array $args = [])
+ * @method \Aws\Result createMonitor(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createMonitorAsync(array $args = [])
+ * @method \Aws\Result createQueue(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createQueueAsync(array $args = [])
+ * @method \Aws\Result createQueueEnvironment(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createQueueEnvironmentAsync(array $args = [])
+ * @method \Aws\Result createQueueFleetAssociation(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createQueueFleetAssociationAsync(array $args = [])
+ * @method \Aws\Result createQueueLimitAssociation(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createQueueLimitAssociationAsync(array $args = [])
+ * @method \Aws\Result createStorageProfile(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createStorageProfileAsync(array $args = [])
+ * @method \Aws\Result createWorker(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createWorkerAsync(array $args = [])
+ * @method \Aws\Result deleteBudget(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteBudgetAsync(array $args = [])
+ * @method \Aws\Result deleteFarm(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteFarmAsync(array $args = [])
+ * @method \Aws\Result deleteFleet(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteFleetAsync(array $args = [])
+ * @method \Aws\Result deleteLicenseEndpoint(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteLicenseEndpointAsync(array $args = [])
+ * @method \Aws\Result deleteLimit(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteLimitAsync(array $args = [])
+ * @method \Aws\Result deleteMeteredProduct(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteMeteredProductAsync(array $args = [])
+ * @method \Aws\Result deleteMonitor(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteMonitorAsync(array $args = [])
+ * @method \Aws\Result deleteQueue(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteQueueAsync(array $args = [])
+ * @method \Aws\Result deleteQueueEnvironment(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteQueueEnvironmentAsync(array $args = [])
+ * @method \Aws\Result deleteQueueFleetAssociation(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteQueueFleetAssociationAsync(array $args = [])
+ * @method \Aws\Result deleteQueueLimitAssociation(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteQueueLimitAssociationAsync(array $args = [])
+ * @method \Aws\Result deleteStorageProfile(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteStorageProfileAsync(array $args = [])
+ * @method \Aws\Result deleteVolume(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteVolumeAsync(array $args = [])
+ * @method \Aws\Result deleteWorker(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteWorkerAsync(array $args = [])
+ * @method \Aws\Result disassociateMemberFromFarm(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise disassociateMemberFromFarmAsync(array $args = [])
+ * @method \Aws\Result disassociateMemberFromFleet(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise disassociateMemberFromFleetAsync(array $args = [])
+ * @method \Aws\Result disassociateMemberFromJob(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise disassociateMemberFromJobAsync(array $args = [])
+ * @method \Aws\Result disassociateMemberFromQueue(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise disassociateMemberFromQueueAsync(array $args = [])
+ * @method \Aws\Result getBudget(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getBudgetAsync(array $args = [])
+ * @method \Aws\Result getFarm(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getFarmAsync(array $args = [])
+ * @method \Aws\Result getFleet(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getFleetAsync(array $args = [])
+ * @method \Aws\Result getJob(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getJobAsync(array $args = [])
+ * @method \Aws\Result getLicenseEndpoint(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getLicenseEndpointAsync(array $args = [])
+ * @method \Aws\Result getLimit(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getLimitAsync(array $args = [])
+ * @method \Aws\Result getMonitor(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getMonitorAsync(array $args = [])
+ * @method \Aws\Result getMonitorSettings(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getMonitorSettingsAsync(array $args = [])
+ * @method \Aws\Result getQueue(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getQueueAsync(array $args = [])
+ * @method \Aws\Result getQueueEnvironment(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getQueueEnvironmentAsync(array $args = [])
+ * @method \Aws\Result getQueueFleetAssociation(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getQueueFleetAssociationAsync(array $args = [])
+ * @method \Aws\Result getQueueLimitAssociation(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getQueueLimitAssociationAsync(array $args = [])
+ * @method \Aws\Result getSession(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getSessionAsync(array $args = [])
+ * @method \Aws\Result getSessionAction(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getSessionActionAsync(array $args = [])
+ * @method \Aws\Result getSessionsStatisticsAggregation(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getSessionsStatisticsAggregationAsync(array $args = [])
+ * @method \Aws\Result getStep(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getStepAsync(array $args = [])
+ * @method \Aws\Result getStorageProfile(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getStorageProfileAsync(array $args = [])
+ * @method \Aws\Result getStorageProfileForQueue(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getStorageProfileForQueueAsync(array $args = [])
+ * @method \Aws\Result getTask(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getTaskAsync(array $args = [])
+ * @method \Aws\Result getVolume(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getVolumeAsync(array $args = [])
+ * @method \Aws\Result getWorker(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getWorkerAsync(array $args = [])
+ * @method \Aws\Result listAvailableMeteredProducts(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listAvailableMeteredProductsAsync(array $args = [])
+ * @method \Aws\Result listBudgets(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listBudgetsAsync(array $args = [])
+ * @method \Aws\Result listFarmMembers(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listFarmMembersAsync(array $args = [])
+ * @method \Aws\Result listFarms(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listFarmsAsync(array $args = [])
+ * @method \Aws\Result listFleetMembers(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listFleetMembersAsync(array $args = [])
+ * @method \Aws\Result listFleets(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listFleetsAsync(array $args = [])
+ * @method \Aws\Result listJobMembers(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listJobMembersAsync(array $args = [])
+ * @method \Aws\Result listJobParameterDefinitions(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listJobParameterDefinitionsAsync(array $args = [])
+ * @method \Aws\Result listJobs(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listJobsAsync(array $args = [])
+ * @method \Aws\Result listLicenseEndpoints(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listLicenseEndpointsAsync(array $args = [])
+ * @method \Aws\Result listLimits(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listLimitsAsync(array $args = [])
+ * @method \Aws\Result listMeteredProducts(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listMeteredProductsAsync(array $args = [])
+ * @method \Aws\Result listMonitors(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listMonitorsAsync(array $args = [])
+ * @method \Aws\Result listQueueEnvironments(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listQueueEnvironmentsAsync(array $args = [])
+ * @method \Aws\Result listQueueFleetAssociations(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listQueueFleetAssociationsAsync(array $args = [])
+ * @method \Aws\Result listQueueLimitAssociations(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listQueueLimitAssociationsAsync(array $args = [])
+ * @method \Aws\Result listQueueMembers(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listQueueMembersAsync(array $args = [])
+ * @method \Aws\Result listQueues(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listQueuesAsync(array $args = [])
+ * @method \Aws\Result listSessionActions(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listSessionActionsAsync(array $args = [])
+ * @method \Aws\Result listSessions(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listSessionsAsync(array $args = [])
+ * @method \Aws\Result listSessionsForWorker(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listSessionsForWorkerAsync(array $args = [])
+ * @method \Aws\Result listStepConsumers(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listStepConsumersAsync(array $args = [])
+ * @method \Aws\Result listStepDependencies(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listStepDependenciesAsync(array $args = [])
+ * @method \Aws\Result listSteps(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listStepsAsync(array $args = [])
+ * @method \Aws\Result listStorageProfiles(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listStorageProfilesAsync(array $args = [])
+ * @method \Aws\Result listStorageProfilesForQueue(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listStorageProfilesForQueueAsync(array $args = [])
+ * @method \Aws\Result listTagsForResource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listTagsForResourceAsync(array $args = [])
+ * @method \Aws\Result listTasks(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listTasksAsync(array $args = [])
+ * @method \Aws\Result listVolumes(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listVolumesAsync(array $args = [])
+ * @method \Aws\Result listWorkers(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listWorkersAsync(array $args = [])
+ * @method \Aws\Result putMeteredProduct(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise putMeteredProductAsync(array $args = [])
+ * @method \Aws\Result searchJobs(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise searchJobsAsync(array $args = [])
+ * @method \Aws\Result searchSteps(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise searchStepsAsync(array $args = [])
+ * @method \Aws\Result searchTasks(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise searchTasksAsync(array $args = [])
+ * @method \Aws\Result searchWorkers(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise searchWorkersAsync(array $args = [])
+ * @method \Aws\Result startSessionsStatisticsAggregation(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise startSessionsStatisticsAggregationAsync(array $args = [])
+ * @method \Aws\Result tagResource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise tagResourceAsync(array $args = [])
+ * @method \Aws\Result untagResource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise untagResourceAsync(array $args = [])
+ * @method \Aws\Result updateBudget(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateBudgetAsync(array $args = [])
+ * @method \Aws\Result updateFarm(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateFarmAsync(array $args = [])
+ * @method \Aws\Result updateFleet(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateFleetAsync(array $args = [])
+ * @method \Aws\Result updateJob(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateJobAsync(array $args = [])
+ * @method \Aws\Result updateLimit(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateLimitAsync(array $args = [])
+ * @method \Aws\Result updateMonitor(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateMonitorAsync(array $args = [])
+ * @method \Aws\Result updateMonitorSettings(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateMonitorSettingsAsync(array $args = [])
+ * @method \Aws\Result updateQueue(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateQueueAsync(array $args = [])
+ * @method \Aws\Result updateQueueEnvironment(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateQueueEnvironmentAsync(array $args = [])
+ * @method \Aws\Result updateQueueFleetAssociation(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateQueueFleetAssociationAsync(array $args = [])
+ * @method \Aws\Result updateQueueLimitAssociation(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateQueueLimitAssociationAsync(array $args = [])
+ * @method \Aws\Result updateSession(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateSessionAsync(array $args = [])
+ * @method \Aws\Result updateStep(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateStepAsync(array $args = [])
+ * @method \Aws\Result updateStorageProfile(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateStorageProfileAsync(array $args = [])
+ * @method \Aws\Result updateTask(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateTaskAsync(array $args = [])
+ * @method \Aws\Result updateWorker(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateWorkerAsync(array $args = [])
+ * @method \Aws\Result updateWorkerSchedule(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateWorkerScheduleAsync(array $args = [])
+ */
+class DeadlineClient extends AwsClient {}

+ 133 - 0
upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/DevOpsAgent/DevOpsAgentClient.php

@@ -0,0 +1,133 @@
+<?php
+namespace Aws\DevOpsAgent;
+
+use Aws\AwsClient;
+
+/**
+ * This client is used to interact with the **AWS DevOps Agent Service** service.
+ * @method \Aws\Result associateService(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise associateServiceAsync(array $args = [])
+ * @method \Aws\Result createAgentSpace(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createAgentSpaceAsync(array $args = [])
+ * @method \Aws\Result createAsset(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createAssetAsync(array $args = [])
+ * @method \Aws\Result createAssetFile(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createAssetFileAsync(array $args = [])
+ * @method \Aws\Result createBacklogTask(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createBacklogTaskAsync(array $args = [])
+ * @method \Aws\Result createChat(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createChatAsync(array $args = [])
+ * @method \Aws\Result createPrivateConnection(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createPrivateConnectionAsync(array $args = [])
+ * @method \Aws\Result createTrigger(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createTriggerAsync(array $args = [])
+ * @method \Aws\Result deleteAgentSpace(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteAgentSpaceAsync(array $args = [])
+ * @method \Aws\Result deleteAsset(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteAssetAsync(array $args = [])
+ * @method \Aws\Result deleteAssetFile(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteAssetFileAsync(array $args = [])
+ * @method \Aws\Result deletePrivateConnection(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deletePrivateConnectionAsync(array $args = [])
+ * @method \Aws\Result deleteTrigger(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteTriggerAsync(array $args = [])
+ * @method \Aws\Result deregisterService(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deregisterServiceAsync(array $args = [])
+ * @method \Aws\Result describePrivateConnection(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describePrivateConnectionAsync(array $args = [])
+ * @method \Aws\Result disableOperatorApp(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise disableOperatorAppAsync(array $args = [])
+ * @method \Aws\Result disassociateService(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise disassociateServiceAsync(array $args = [])
+ * @method \Aws\Result enableOperatorApp(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise enableOperatorAppAsync(array $args = [])
+ * @method \Aws\Result getAccountUsage(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getAccountUsageAsync(array $args = [])
+ * @method \Aws\Result getAgentSpace(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getAgentSpaceAsync(array $args = [])
+ * @method \Aws\Result getAsset(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getAssetAsync(array $args = [])
+ * @method \Aws\Result getAssetContent(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getAssetContentAsync(array $args = [])
+ * @method \Aws\Result getAssetFile(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getAssetFileAsync(array $args = [])
+ * @method \Aws\Result getAssociation(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getAssociationAsync(array $args = [])
+ * @method \Aws\Result getBacklogTask(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getBacklogTaskAsync(array $args = [])
+ * @method \Aws\Result getOperatorApp(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getOperatorAppAsync(array $args = [])
+ * @method \Aws\Result getRecommendation(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getRecommendationAsync(array $args = [])
+ * @method \Aws\Result getService(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getServiceAsync(array $args = [])
+ * @method \Aws\Result getTrigger(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getTriggerAsync(array $args = [])
+ * @method \Aws\Result listAgentSpaces(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listAgentSpacesAsync(array $args = [])
+ * @method \Aws\Result listAssetFiles(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listAssetFilesAsync(array $args = [])
+ * @method \Aws\Result listAssetTypes(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listAssetTypesAsync(array $args = [])
+ * @method \Aws\Result listAssetVersions(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listAssetVersionsAsync(array $args = [])
+ * @method \Aws\Result listAssets(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listAssetsAsync(array $args = [])
+ * @method \Aws\Result listAssociations(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listAssociationsAsync(array $args = [])
+ * @method \Aws\Result listBacklogTasks(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listBacklogTasksAsync(array $args = [])
+ * @method \Aws\Result listChats(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listChatsAsync(array $args = [])
+ * @method \Aws\Result listExecutions(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listExecutionsAsync(array $args = [])
+ * @method \Aws\Result listGoals(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listGoalsAsync(array $args = [])
+ * @method \Aws\Result listJournalRecords(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listJournalRecordsAsync(array $args = [])
+ * @method \Aws\Result listPendingMessages(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listPendingMessagesAsync(array $args = [])
+ * @method \Aws\Result listPrivateConnections(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listPrivateConnectionsAsync(array $args = [])
+ * @method \Aws\Result listRecommendations(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listRecommendationsAsync(array $args = [])
+ * @method \Aws\Result listServices(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listServicesAsync(array $args = [])
+ * @method \Aws\Result listTagsForResource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listTagsForResourceAsync(array $args = [])
+ * @method \Aws\Result listTriggers(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listTriggersAsync(array $args = [])
+ * @method \Aws\Result listWebhooks(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listWebhooksAsync(array $args = [])
+ * @method \Aws\Result registerService(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise registerServiceAsync(array $args = [])
+ * @method \Aws\Result sendMessage(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise sendMessageAsync(array $args = [])
+ * @method \Aws\Result tagResource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise tagResourceAsync(array $args = [])
+ * @method \Aws\Result untagResource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise untagResourceAsync(array $args = [])
+ * @method \Aws\Result updateAgentSpace(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateAgentSpaceAsync(array $args = [])
+ * @method \Aws\Result updateAsset(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateAssetAsync(array $args = [])
+ * @method \Aws\Result updateAssetFile(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateAssetFileAsync(array $args = [])
+ * @method \Aws\Result updateAssociation(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateAssociationAsync(array $args = [])
+ * @method \Aws\Result updateBacklogTask(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateBacklogTaskAsync(array $args = [])
+ * @method \Aws\Result updateGoal(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateGoalAsync(array $args = [])
+ * @method \Aws\Result updateOperatorAppIdpConfig(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateOperatorAppIdpConfigAsync(array $args = [])
+ * @method \Aws\Result updatePrivateConnectionCertificate(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updatePrivateConnectionCertificateAsync(array $args = [])
+ * @method \Aws\Result updateRecommendation(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateRecommendationAsync(array $args = [])
+ * @method \Aws\Result updateTrigger(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateTriggerAsync(array $args = [])
+ * @method \Aws\Result validateAwsAssociations(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise validateAwsAssociationsAsync(array $args = [])
+ */
+class DevOpsAgentClient extends AwsClient {}

+ 139 - 0
upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/EKS/EKSClient.php

@@ -0,0 +1,139 @@
+<?php
+namespace Aws\EKS;
+
+use Aws\AwsClient;
+
+/**
+ * This client is used to interact with the **Amazon Elastic Container Service for Kubernetes** service.
+ * @method \Aws\Result associateAccessPolicy(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise associateAccessPolicyAsync(array $args = [])
+ * @method \Aws\Result associateEncryptionConfig(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise associateEncryptionConfigAsync(array $args = [])
+ * @method \Aws\Result associateIdentityProviderConfig(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise associateIdentityProviderConfigAsync(array $args = [])
+ * @method \Aws\Result cancelUpdate(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise cancelUpdateAsync(array $args = [])
+ * @method \Aws\Result createAccessEntry(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createAccessEntryAsync(array $args = [])
+ * @method \Aws\Result createAddon(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createAddonAsync(array $args = [])
+ * @method \Aws\Result createCapability(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createCapabilityAsync(array $args = [])
+ * @method \Aws\Result createCluster(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createClusterAsync(array $args = [])
+ * @method \Aws\Result createEksAnywhereSubscription(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createEksAnywhereSubscriptionAsync(array $args = [])
+ * @method \Aws\Result createFargateProfile(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createFargateProfileAsync(array $args = [])
+ * @method \Aws\Result createNodegroup(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createNodegroupAsync(array $args = [])
+ * @method \Aws\Result createPodIdentityAssociation(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createPodIdentityAssociationAsync(array $args = [])
+ * @method \Aws\Result deleteAccessEntry(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteAccessEntryAsync(array $args = [])
+ * @method \Aws\Result deleteAddon(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteAddonAsync(array $args = [])
+ * @method \Aws\Result deleteCapability(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteCapabilityAsync(array $args = [])
+ * @method \Aws\Result deleteCluster(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteClusterAsync(array $args = [])
+ * @method \Aws\Result deleteEksAnywhereSubscription(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteEksAnywhereSubscriptionAsync(array $args = [])
+ * @method \Aws\Result deleteFargateProfile(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteFargateProfileAsync(array $args = [])
+ * @method \Aws\Result deleteNodegroup(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteNodegroupAsync(array $args = [])
+ * @method \Aws\Result deletePodIdentityAssociation(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deletePodIdentityAssociationAsync(array $args = [])
+ * @method \Aws\Result deregisterCluster(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deregisterClusterAsync(array $args = [])
+ * @method \Aws\Result describeAccessEntry(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeAccessEntryAsync(array $args = [])
+ * @method \Aws\Result describeAddon(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeAddonAsync(array $args = [])
+ * @method \Aws\Result describeAddonConfiguration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeAddonConfigurationAsync(array $args = [])
+ * @method \Aws\Result describeAddonVersions(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeAddonVersionsAsync(array $args = [])
+ * @method \Aws\Result describeCapability(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeCapabilityAsync(array $args = [])
+ * @method \Aws\Result describeCluster(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeClusterAsync(array $args = [])
+ * @method \Aws\Result describeClusterVersions(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeClusterVersionsAsync(array $args = [])
+ * @method \Aws\Result describeEksAnywhereSubscription(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeEksAnywhereSubscriptionAsync(array $args = [])
+ * @method \Aws\Result describeFargateProfile(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeFargateProfileAsync(array $args = [])
+ * @method \Aws\Result describeIdentityProviderConfig(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeIdentityProviderConfigAsync(array $args = [])
+ * @method \Aws\Result describeInsight(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeInsightAsync(array $args = [])
+ * @method \Aws\Result describeInsightsRefresh(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeInsightsRefreshAsync(array $args = [])
+ * @method \Aws\Result describeNodegroup(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeNodegroupAsync(array $args = [])
+ * @method \Aws\Result describePodIdentityAssociation(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describePodIdentityAssociationAsync(array $args = [])
+ * @method \Aws\Result describeUpdate(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeUpdateAsync(array $args = [])
+ * @method \Aws\Result disassociateAccessPolicy(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise disassociateAccessPolicyAsync(array $args = [])
+ * @method \Aws\Result disassociateIdentityProviderConfig(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise disassociateIdentityProviderConfigAsync(array $args = [])
+ * @method \Aws\Result listAccessEntries(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listAccessEntriesAsync(array $args = [])
+ * @method \Aws\Result listAccessPolicies(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listAccessPoliciesAsync(array $args = [])
+ * @method \Aws\Result listAddons(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listAddonsAsync(array $args = [])
+ * @method \Aws\Result listAssociatedAccessPolicies(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listAssociatedAccessPoliciesAsync(array $args = [])
+ * @method \Aws\Result listCapabilities(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listCapabilitiesAsync(array $args = [])
+ * @method \Aws\Result listClusters(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listClustersAsync(array $args = [])
+ * @method \Aws\Result listEksAnywhereSubscriptions(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listEksAnywhereSubscriptionsAsync(array $args = [])
+ * @method \Aws\Result listFargateProfiles(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listFargateProfilesAsync(array $args = [])
+ * @method \Aws\Result listIdentityProviderConfigs(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listIdentityProviderConfigsAsync(array $args = [])
+ * @method \Aws\Result listInsights(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listInsightsAsync(array $args = [])
+ * @method \Aws\Result listNodegroups(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listNodegroupsAsync(array $args = [])
+ * @method \Aws\Result listPodIdentityAssociations(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listPodIdentityAssociationsAsync(array $args = [])
+ * @method \Aws\Result listTagsForResource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listTagsForResourceAsync(array $args = [])
+ * @method \Aws\Result listUpdates(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listUpdatesAsync(array $args = [])
+ * @method \Aws\Result registerCluster(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise registerClusterAsync(array $args = [])
+ * @method \Aws\Result startInsightsRefresh(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise startInsightsRefreshAsync(array $args = [])
+ * @method \Aws\Result tagResource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise tagResourceAsync(array $args = [])
+ * @method \Aws\Result untagResource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise untagResourceAsync(array $args = [])
+ * @method \Aws\Result updateAccessEntry(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateAccessEntryAsync(array $args = [])
+ * @method \Aws\Result updateAddon(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateAddonAsync(array $args = [])
+ * @method \Aws\Result updateCapability(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateCapabilityAsync(array $args = [])
+ * @method \Aws\Result updateClusterConfig(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateClusterConfigAsync(array $args = [])
+ * @method \Aws\Result updateClusterVersion(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateClusterVersionAsync(array $args = [])
+ * @method \Aws\Result updateEksAnywhereSubscription(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateEksAnywhereSubscriptionAsync(array $args = [])
+ * @method \Aws\Result updateNodegroupConfig(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateNodegroupConfigAsync(array $args = [])
+ * @method \Aws\Result updateNodegroupVersion(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateNodegroupVersionAsync(array $args = [])
+ * @method \Aws\Result updatePodIdentityAssociation(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updatePodIdentityAssociationAsync(array $args = [])
+ */
+class EKSClient extends AwsClient {}

+ 1602 - 0
upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/Ec2/Ec2Client.php

@@ -0,0 +1,1602 @@
+<?php
+namespace Aws\Ec2;
+
+use Aws\AwsClient;
+use Aws\Api\Service;
+use Aws\Api\DocModel;
+use Aws\Api\ApiProvider;
+use Aws\PresignUrlMiddleware;
+
+/**
+ * Client used to interact with **Amazon EC2**.
+ *
+ * @method \Aws\Result acceptVpcPeeringConnection(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise acceptVpcPeeringConnectionAsync(array $args = [])
+ * @method \Aws\Result allocateAddress(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise allocateAddressAsync(array $args = [])
+ * @method \Aws\Result allocateHosts(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise allocateHostsAsync(array $args = [])
+ * @method \Aws\Result assignPrivateIpAddresses(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise assignPrivateIpAddressesAsync(array $args = [])
+ * @method \Aws\Result associateAddress(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise associateAddressAsync(array $args = [])
+ * @method \Aws\Result associateDhcpOptions(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise associateDhcpOptionsAsync(array $args = [])
+ * @method \Aws\Result associateRouteTable(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise associateRouteTableAsync(array $args = [])
+ * @method \Aws\Result attachClassicLinkVpc(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise attachClassicLinkVpcAsync(array $args = [])
+ * @method \Aws\Result attachInternetGateway(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise attachInternetGatewayAsync(array $args = [])
+ * @method \Aws\Result attachNetworkInterface(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise attachNetworkInterfaceAsync(array $args = [])
+ * @method \Aws\Result attachVolume(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise attachVolumeAsync(array $args = [])
+ * @method \Aws\Result attachVpnGateway(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise attachVpnGatewayAsync(array $args = [])
+ * @method \Aws\Result authorizeSecurityGroupEgress(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise authorizeSecurityGroupEgressAsync(array $args = [])
+ * @method \Aws\Result authorizeSecurityGroupIngress(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise authorizeSecurityGroupIngressAsync(array $args = [])
+ * @method \Aws\Result bundleInstance(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise bundleInstanceAsync(array $args = [])
+ * @method \Aws\Result cancelBundleTask(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise cancelBundleTaskAsync(array $args = [])
+ * @method \Aws\Result cancelConversionTask(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise cancelConversionTaskAsync(array $args = [])
+ * @method \Aws\Result cancelExportTask(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise cancelExportTaskAsync(array $args = [])
+ * @method \Aws\Result cancelImportTask(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise cancelImportTaskAsync(array $args = [])
+ * @method \Aws\Result cancelReservedInstancesListing(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise cancelReservedInstancesListingAsync(array $args = [])
+ * @method \Aws\Result cancelSpotFleetRequests(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise cancelSpotFleetRequestsAsync(array $args = [])
+ * @method \Aws\Result cancelSpotInstanceRequests(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise cancelSpotInstanceRequestsAsync(array $args = [])
+ * @method \Aws\Result confirmProductInstance(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise confirmProductInstanceAsync(array $args = [])
+ * @method \Aws\Result copyImage(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise copyImageAsync(array $args = [])
+ * @method \Aws\Result copySnapshot(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise copySnapshotAsync(array $args = [])
+ * @method \Aws\Result createCustomerGateway(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createCustomerGatewayAsync(array $args = [])
+ * @method \Aws\Result createDhcpOptions(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createDhcpOptionsAsync(array $args = [])
+ * @method \Aws\Result createFlowLogs(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createFlowLogsAsync(array $args = [])
+ * @method \Aws\Result createImage(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createImageAsync(array $args = [])
+ * @method \Aws\Result createInstanceExportTask(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createInstanceExportTaskAsync(array $args = [])
+ * @method \Aws\Result createInternetGateway(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createInternetGatewayAsync(array $args = [])
+ * @method \Aws\Result createKeyPair(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createKeyPairAsync(array $args = [])
+ * @method \Aws\Result createNatGateway(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createNatGatewayAsync(array $args = [])
+ * @method \Aws\Result createNetworkAcl(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createNetworkAclAsync(array $args = [])
+ * @method \Aws\Result createNetworkAclEntry(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createNetworkAclEntryAsync(array $args = [])
+ * @method \Aws\Result createNetworkInterface(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createNetworkInterfaceAsync(array $args = [])
+ * @method \Aws\Result createPlacementGroup(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createPlacementGroupAsync(array $args = [])
+ * @method \Aws\Result createReservedInstancesListing(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createReservedInstancesListingAsync(array $args = [])
+ * @method \Aws\Result createRoute(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createRouteAsync(array $args = [])
+ * @method \Aws\Result createRouteTable(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createRouteTableAsync(array $args = [])
+ * @method \Aws\Result createSecurityGroup(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createSecurityGroupAsync(array $args = [])
+ * @method \Aws\Result createSnapshot(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createSnapshotAsync(array $args = [])
+ * @method \Aws\Result createSpotDatafeedSubscription(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createSpotDatafeedSubscriptionAsync(array $args = [])
+ * @method \Aws\Result createSubnet(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createSubnetAsync(array $args = [])
+ * @method \Aws\Result createTags(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createTagsAsync(array $args = [])
+ * @method \Aws\Result createVolume(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createVolumeAsync(array $args = [])
+ * @method \Aws\Result createVpc(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createVpcAsync(array $args = [])
+ * @method \Aws\Result createVpcEndpoint(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createVpcEndpointAsync(array $args = [])
+ * @method \Aws\Result createVpcPeeringConnection(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createVpcPeeringConnectionAsync(array $args = [])
+ * @method \Aws\Result createVpnConnection(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createVpnConnectionAsync(array $args = [])
+ * @method \Aws\Result createVpnConnectionRoute(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createVpnConnectionRouteAsync(array $args = [])
+ * @method \Aws\Result createVpnGateway(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createVpnGatewayAsync(array $args = [])
+ * @method \Aws\Result deleteCustomerGateway(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteCustomerGatewayAsync(array $args = [])
+ * @method \Aws\Result deleteDhcpOptions(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteDhcpOptionsAsync(array $args = [])
+ * @method \Aws\Result deleteFlowLogs(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteFlowLogsAsync(array $args = [])
+ * @method \Aws\Result deleteInternetGateway(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteInternetGatewayAsync(array $args = [])
+ * @method \Aws\Result deleteKeyPair(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteKeyPairAsync(array $args = [])
+ * @method \Aws\Result deleteNatGateway(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteNatGatewayAsync(array $args = [])
+ * @method \Aws\Result deleteNetworkAcl(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteNetworkAclAsync(array $args = [])
+ * @method \Aws\Result deleteNetworkAclEntry(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteNetworkAclEntryAsync(array $args = [])
+ * @method \Aws\Result deleteNetworkInterface(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteNetworkInterfaceAsync(array $args = [])
+ * @method \Aws\Result deletePlacementGroup(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deletePlacementGroupAsync(array $args = [])
+ * @method \Aws\Result deleteRoute(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteRouteAsync(array $args = [])
+ * @method \Aws\Result deleteRouteTable(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteRouteTableAsync(array $args = [])
+ * @method \Aws\Result deleteSecurityGroup(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteSecurityGroupAsync(array $args = [])
+ * @method \Aws\Result deleteSnapshot(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteSnapshotAsync(array $args = [])
+ * @method \Aws\Result deleteSpotDatafeedSubscription(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteSpotDatafeedSubscriptionAsync(array $args = [])
+ * @method \Aws\Result deleteSubnet(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteSubnetAsync(array $args = [])
+ * @method \Aws\Result deleteTags(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteTagsAsync(array $args = [])
+ * @method \Aws\Result deleteVolume(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteVolumeAsync(array $args = [])
+ * @method \Aws\Result deleteVpc(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteVpcAsync(array $args = [])
+ * @method \Aws\Result deleteVpcEndpoints(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteVpcEndpointsAsync(array $args = [])
+ * @method \Aws\Result deleteVpcPeeringConnection(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteVpcPeeringConnectionAsync(array $args = [])
+ * @method \Aws\Result deleteVpnConnection(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteVpnConnectionAsync(array $args = [])
+ * @method \Aws\Result deleteVpnConnectionRoute(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteVpnConnectionRouteAsync(array $args = [])
+ * @method \Aws\Result deleteVpnGateway(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteVpnGatewayAsync(array $args = [])
+ * @method \Aws\Result deregisterImage(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deregisterImageAsync(array $args = [])
+ * @method \Aws\Result describeAccountAttributes(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeAccountAttributesAsync(array $args = [])
+ * @method \Aws\Result describeAddresses(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeAddressesAsync(array $args = [])
+ * @method \Aws\Result describeAvailabilityZones(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeAvailabilityZonesAsync(array $args = [])
+ * @method \Aws\Result describeBundleTasks(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeBundleTasksAsync(array $args = [])
+ * @method \Aws\Result describeClassicLinkInstances(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeClassicLinkInstancesAsync(array $args = [])
+ * @method \Aws\Result describeConversionTasks(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeConversionTasksAsync(array $args = [])
+ * @method \Aws\Result describeCustomerGateways(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeCustomerGatewaysAsync(array $args = [])
+ * @method \Aws\Result describeDhcpOptions(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeDhcpOptionsAsync(array $args = [])
+ * @method \Aws\Result describeExportTasks(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeExportTasksAsync(array $args = [])
+ * @method \Aws\Result describeFlowLogs(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeFlowLogsAsync(array $args = [])
+ * @method \Aws\Result describeHosts(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeHostsAsync(array $args = [])
+ * @method \Aws\Result describeIdFormat(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeIdFormatAsync(array $args = [])
+ * @method \Aws\Result describeImageAttribute(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeImageAttributeAsync(array $args = [])
+ * @method \Aws\Result describeImages(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeImagesAsync(array $args = [])
+ * @method \Aws\Result describeImportImageTasks(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeImportImageTasksAsync(array $args = [])
+ * @method \Aws\Result describeImportSnapshotTasks(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeImportSnapshotTasksAsync(array $args = [])
+ * @method \Aws\Result describeInstanceAttribute(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeInstanceAttributeAsync(array $args = [])
+ * @method \Aws\Result describeInstanceStatus(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeInstanceStatusAsync(array $args = [])
+ * @method \Aws\Result describeInstances(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeInstancesAsync(array $args = [])
+ * @method \Aws\Result describeInternetGateways(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeInternetGatewaysAsync(array $args = [])
+ * @method \Aws\Result describeKeyPairs(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeKeyPairsAsync(array $args = [])
+ * @method \Aws\Result describeMovingAddresses(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeMovingAddressesAsync(array $args = [])
+ * @method \Aws\Result describeNatGateways(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeNatGatewaysAsync(array $args = [])
+ * @method \Aws\Result describeNetworkAcls(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeNetworkAclsAsync(array $args = [])
+ * @method \Aws\Result describeNetworkInterfaceAttribute(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeNetworkInterfaceAttributeAsync(array $args = [])
+ * @method \Aws\Result describeNetworkInterfaces(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeNetworkInterfacesAsync(array $args = [])
+ * @method \Aws\Result describePlacementGroups(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describePlacementGroupsAsync(array $args = [])
+ * @method \Aws\Result describePrefixLists(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describePrefixListsAsync(array $args = [])
+ * @method \Aws\Result describeRegions(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeRegionsAsync(array $args = [])
+ * @method \Aws\Result describeReservedInstances(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeReservedInstancesAsync(array $args = [])
+ * @method \Aws\Result describeReservedInstancesListings(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeReservedInstancesListingsAsync(array $args = [])
+ * @method \Aws\Result describeReservedInstancesModifications(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeReservedInstancesModificationsAsync(array $args = [])
+ * @method \Aws\Result describeReservedInstancesOfferings(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeReservedInstancesOfferingsAsync(array $args = [])
+ * @method \Aws\Result describeRouteTables(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeRouteTablesAsync(array $args = [])
+ * @method \Aws\Result describeScheduledInstanceAvailability(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeScheduledInstanceAvailabilityAsync(array $args = [])
+ * @method \Aws\Result describeScheduledInstances(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeScheduledInstancesAsync(array $args = [])
+ * @method \Aws\Result describeSecurityGroupReferences(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeSecurityGroupReferencesAsync(array $args = [])
+ * @method \Aws\Result describeSecurityGroups(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeSecurityGroupsAsync(array $args = [])
+ * @method \Aws\Result describeSnapshotAttribute(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeSnapshotAttributeAsync(array $args = [])
+ * @method \Aws\Result describeSnapshots(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeSnapshotsAsync(array $args = [])
+ * @method \Aws\Result describeSpotDatafeedSubscription(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeSpotDatafeedSubscriptionAsync(array $args = [])
+ * @method \Aws\Result describeSpotFleetInstances(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeSpotFleetInstancesAsync(array $args = [])
+ * @method \Aws\Result describeSpotFleetRequestHistory(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeSpotFleetRequestHistoryAsync(array $args = [])
+ * @method \Aws\Result describeSpotFleetRequests(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeSpotFleetRequestsAsync(array $args = [])
+ * @method \Aws\Result describeSpotInstanceRequests(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeSpotInstanceRequestsAsync(array $args = [])
+ * @method \Aws\Result describeSpotPriceHistory(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeSpotPriceHistoryAsync(array $args = [])
+ * @method \Aws\Result describeStaleSecurityGroups(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeStaleSecurityGroupsAsync(array $args = [])
+ * @method \Aws\Result describeSubnets(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeSubnetsAsync(array $args = [])
+ * @method \Aws\Result describeTags(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeTagsAsync(array $args = [])
+ * @method \Aws\Result describeVolumeAttribute(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeVolumeAttributeAsync(array $args = [])
+ * @method \Aws\Result describeVolumeStatus(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeVolumeStatusAsync(array $args = [])
+ * @method \Aws\Result describeVolumes(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeVolumesAsync(array $args = [])
+ * @method \Aws\Result describeVpcAttribute(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeVpcAttributeAsync(array $args = [])
+ * @method \Aws\Result describeVpcClassicLink(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeVpcClassicLinkAsync(array $args = [])
+ * @method \Aws\Result describeVpcClassicLinkDnsSupport(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeVpcClassicLinkDnsSupportAsync(array $args = [])
+ * @method \Aws\Result describeVpcEndpointServices(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeVpcEndpointServicesAsync(array $args = [])
+ * @method \Aws\Result describeVpcEndpoints(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeVpcEndpointsAsync(array $args = [])
+ * @method \Aws\Result describeVpcPeeringConnections(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeVpcPeeringConnectionsAsync(array $args = [])
+ * @method \Aws\Result describeVpcs(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeVpcsAsync(array $args = [])
+ * @method \Aws\Result describeVpnConnections(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeVpnConnectionsAsync(array $args = [])
+ * @method \Aws\Result describeVpnGateways(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeVpnGatewaysAsync(array $args = [])
+ * @method \Aws\Result detachClassicLinkVpc(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise detachClassicLinkVpcAsync(array $args = [])
+ * @method \Aws\Result detachInternetGateway(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise detachInternetGatewayAsync(array $args = [])
+ * @method \Aws\Result detachNetworkInterface(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise detachNetworkInterfaceAsync(array $args = [])
+ * @method \Aws\Result detachVolume(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise detachVolumeAsync(array $args = [])
+ * @method \Aws\Result detachVpnGateway(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise detachVpnGatewayAsync(array $args = [])
+ * @method \Aws\Result disableVgwRoutePropagation(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise disableVgwRoutePropagationAsync(array $args = [])
+ * @method \Aws\Result disableVpcClassicLink(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise disableVpcClassicLinkAsync(array $args = [])
+ * @method \Aws\Result disableVpcClassicLinkDnsSupport(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise disableVpcClassicLinkDnsSupportAsync(array $args = [])
+ * @method \Aws\Result disassociateAddress(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise disassociateAddressAsync(array $args = [])
+ * @method \Aws\Result disassociateRouteTable(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise disassociateRouteTableAsync(array $args = [])
+ * @method \Aws\Result enableVgwRoutePropagation(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise enableVgwRoutePropagationAsync(array $args = [])
+ * @method \Aws\Result enableVolumeIO(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise enableVolumeIOAsync(array $args = [])
+ * @method \Aws\Result enableVpcClassicLink(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise enableVpcClassicLinkAsync(array $args = [])
+ * @method \Aws\Result enableVpcClassicLinkDnsSupport(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise enableVpcClassicLinkDnsSupportAsync(array $args = [])
+ * @method \Aws\Result getConsoleOutput(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getConsoleOutputAsync(array $args = [])
+ * @method \Aws\Result getConsoleScreenshot(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getConsoleScreenshotAsync(array $args = [])
+ * @method \Aws\Result getPasswordData(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getPasswordDataAsync(array $args = [])
+ * @method \Aws\Result importImage(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise importImageAsync(array $args = [])
+ * @method \Aws\Result importInstance(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise importInstanceAsync(array $args = [])
+ * @method \Aws\Result importKeyPair(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise importKeyPairAsync(array $args = [])
+ * @method \Aws\Result importSnapshot(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise importSnapshotAsync(array $args = [])
+ * @method \Aws\Result importVolume(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise importVolumeAsync(array $args = [])
+ * @method \Aws\Result modifyHosts(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise modifyHostsAsync(array $args = [])
+ * @method \Aws\Result modifyIdFormat(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise modifyIdFormatAsync(array $args = [])
+ * @method \Aws\Result modifyImageAttribute(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise modifyImageAttributeAsync(array $args = [])
+ * @method \Aws\Result modifyInstanceAttribute(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise modifyInstanceAttributeAsync(array $args = [])
+ * @method \Aws\Result modifyInstancePlacement(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise modifyInstancePlacementAsync(array $args = [])
+ * @method \Aws\Result modifyNetworkInterfaceAttribute(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise modifyNetworkInterfaceAttributeAsync(array $args = [])
+ * @method \Aws\Result modifyReservedInstances(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise modifyReservedInstancesAsync(array $args = [])
+ * @method \Aws\Result modifySnapshotAttribute(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise modifySnapshotAttributeAsync(array $args = [])
+ * @method \Aws\Result modifySpotFleetRequest(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise modifySpotFleetRequestAsync(array $args = [])
+ * @method \Aws\Result modifySubnetAttribute(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise modifySubnetAttributeAsync(array $args = [])
+ * @method \Aws\Result modifyVolumeAttribute(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise modifyVolumeAttributeAsync(array $args = [])
+ * @method \Aws\Result modifyVpcAttribute(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise modifyVpcAttributeAsync(array $args = [])
+ * @method \Aws\Result modifyVpcEndpoint(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise modifyVpcEndpointAsync(array $args = [])
+ * @method \Aws\Result modifyVpcPeeringConnectionOptions(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise modifyVpcPeeringConnectionOptionsAsync(array $args = [])
+ * @method \Aws\Result monitorInstances(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise monitorInstancesAsync(array $args = [])
+ * @method \Aws\Result moveAddressToVpc(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise moveAddressToVpcAsync(array $args = [])
+ * @method \Aws\Result purchaseReservedInstancesOffering(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise purchaseReservedInstancesOfferingAsync(array $args = [])
+ * @method \Aws\Result purchaseScheduledInstances(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise purchaseScheduledInstancesAsync(array $args = [])
+ * @method \Aws\Result rebootInstances(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise rebootInstancesAsync(array $args = [])
+ * @method \Aws\Result registerImage(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise registerImageAsync(array $args = [])
+ * @method \Aws\Result rejectVpcPeeringConnection(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise rejectVpcPeeringConnectionAsync(array $args = [])
+ * @method \Aws\Result releaseAddress(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise releaseAddressAsync(array $args = [])
+ * @method \Aws\Result releaseHosts(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise releaseHostsAsync(array $args = [])
+ * @method \Aws\Result replaceNetworkAclAssociation(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise replaceNetworkAclAssociationAsync(array $args = [])
+ * @method \Aws\Result replaceNetworkAclEntry(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise replaceNetworkAclEntryAsync(array $args = [])
+ * @method \Aws\Result replaceRoute(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise replaceRouteAsync(array $args = [])
+ * @method \Aws\Result replaceRouteTableAssociation(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise replaceRouteTableAssociationAsync(array $args = [])
+ * @method \Aws\Result reportInstanceStatus(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise reportInstanceStatusAsync(array $args = [])
+ * @method \Aws\Result requestSpotFleet(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise requestSpotFleetAsync(array $args = [])
+ * @method \Aws\Result requestSpotInstances(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise requestSpotInstancesAsync(array $args = [])
+ * @method \Aws\Result resetImageAttribute(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise resetImageAttributeAsync(array $args = [])
+ * @method \Aws\Result resetInstanceAttribute(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise resetInstanceAttributeAsync(array $args = [])
+ * @method \Aws\Result resetNetworkInterfaceAttribute(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise resetNetworkInterfaceAttributeAsync(array $args = [])
+ * @method \Aws\Result resetSnapshotAttribute(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise resetSnapshotAttributeAsync(array $args = [])
+ * @method \Aws\Result restoreAddressToClassic(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise restoreAddressToClassicAsync(array $args = [])
+ * @method \Aws\Result revokeSecurityGroupEgress(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise revokeSecurityGroupEgressAsync(array $args = [])
+ * @method \Aws\Result revokeSecurityGroupIngress(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise revokeSecurityGroupIngressAsync(array $args = [])
+ * @method \Aws\Result runInstances(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise runInstancesAsync(array $args = [])
+ * @method \Aws\Result runScheduledInstances(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise runScheduledInstancesAsync(array $args = [])
+ * @method \Aws\Result startInstances(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise startInstancesAsync(array $args = [])
+ * @method \Aws\Result stopInstances(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise stopInstancesAsync(array $args = [])
+ * @method \Aws\Result terminateInstances(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise terminateInstancesAsync(array $args = [])
+ * @method \Aws\Result unassignPrivateIpAddresses(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise unassignPrivateIpAddressesAsync(array $args = [])
+ * @method \Aws\Result unmonitorInstances(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise unmonitorInstancesAsync(array $args = [])
+ * @method \Aws\Result describeHostReservationOfferings(array $args = []) (supported in versions 2016-04-01, 2016-09-15, 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise describeHostReservationOfferingsAsync(array $args = []) (supported in versions 2016-04-01, 2016-09-15, 2016-11-15)
+ * @method \Aws\Result describeHostReservations(array $args = []) (supported in versions 2016-04-01, 2016-09-15, 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise describeHostReservationsAsync(array $args = []) (supported in versions 2016-04-01, 2016-09-15, 2016-11-15)
+ * @method \Aws\Result describeIdentityIdFormat(array $args = []) (supported in versions 2016-04-01, 2016-09-15, 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise describeIdentityIdFormatAsync(array $args = []) (supported in versions 2016-04-01, 2016-09-15, 2016-11-15)
+ * @method \Aws\Result getHostReservationPurchasePreview(array $args = []) (supported in versions 2016-04-01, 2016-09-15, 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise getHostReservationPurchasePreviewAsync(array $args = []) (supported in versions 2016-04-01, 2016-09-15, 2016-11-15)
+ * @method \Aws\Result modifyIdentityIdFormat(array $args = []) (supported in versions 2016-04-01, 2016-09-15, 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise modifyIdentityIdFormatAsync(array $args = []) (supported in versions 2016-04-01, 2016-09-15, 2016-11-15)
+ * @method \Aws\Result purchaseHostReservation(array $args = []) (supported in versions 2016-04-01, 2016-09-15, 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise purchaseHostReservationAsync(array $args = []) (supported in versions 2016-04-01, 2016-09-15, 2016-11-15)
+ * @method \Aws\Result acceptReservedInstancesExchangeQuote(array $args = []) (supported in versions 2016-09-15, 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise acceptReservedInstancesExchangeQuoteAsync(array $args = []) (supported in versions 2016-09-15, 2016-11-15)
+ * @method \Aws\Result getReservedInstancesExchangeQuote(array $args = []) (supported in versions 2016-09-15, 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise getReservedInstancesExchangeQuoteAsync(array $args = []) (supported in versions 2016-09-15, 2016-11-15)
+ * @method \Aws\Result acceptAddressTransfer(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise acceptAddressTransferAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result acceptCapacityReservationBillingOwnership(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise acceptCapacityReservationBillingOwnershipAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result acceptTransitGatewayClientVpnAttachment(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise acceptTransitGatewayClientVpnAttachmentAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result acceptTransitGatewayMulticastDomainAssociations(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise acceptTransitGatewayMulticastDomainAssociationsAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result acceptTransitGatewayPeeringAttachment(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise acceptTransitGatewayPeeringAttachmentAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result acceptTransitGatewayVpcAttachment(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise acceptTransitGatewayVpcAttachmentAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result acceptVpcEndpointConnections(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise acceptVpcEndpointConnectionsAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result advertiseByoipCidr(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise advertiseByoipCidrAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result allocateIpamPoolCidr(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise allocateIpamPoolCidrAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result applySecurityGroupsToClientVpnTargetNetwork(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise applySecurityGroupsToClientVpnTargetNetworkAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result assignIpv6Addresses(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise assignIpv6AddressesAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result assignPrivateNatGatewayAddress(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise assignPrivateNatGatewayAddressAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result associateCapacityReservationBillingOwner(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise associateCapacityReservationBillingOwnerAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result associateClientVpnTargetNetwork(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise associateClientVpnTargetNetworkAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result associateEnclaveCertificateIamRole(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise associateEnclaveCertificateIamRoleAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result associateIamInstanceProfile(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise associateIamInstanceProfileAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result associateInstanceEventWindow(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise associateInstanceEventWindowAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result associateIpamByoasn(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise associateIpamByoasnAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result associateIpamResourceDiscovery(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise associateIpamResourceDiscoveryAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result associateNatGatewayAddress(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise associateNatGatewayAddressAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result associateRouteServer(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise associateRouteServerAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result associateSecurityGroupVpc(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise associateSecurityGroupVpcAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result associateSubnetCidrBlock(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise associateSubnetCidrBlockAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result associateTransitGatewayMulticastDomain(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise associateTransitGatewayMulticastDomainAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result associateTransitGatewayPolicyTable(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise associateTransitGatewayPolicyTableAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result associateTransitGatewayRouteTable(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise associateTransitGatewayRouteTableAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result associateTrunkInterface(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise associateTrunkInterfaceAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result associateVpcCidrBlock(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise associateVpcCidrBlockAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result attachImageWatermark(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise attachImageWatermarkAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result attachVerifiedAccessTrustProvider(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise attachVerifiedAccessTrustProviderAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result authorizeClientVpnIngress(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise authorizeClientVpnIngressAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result cancelCapacityReservation(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise cancelCapacityReservationAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result cancelCapacityReservationFleets(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise cancelCapacityReservationFleetsAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result cancelDeclarativePoliciesReport(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise cancelDeclarativePoliciesReportAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result cancelImageLaunchPermission(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise cancelImageLaunchPermissionAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result copyFpgaImage(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise copyFpgaImageAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result copyVolumes(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise copyVolumesAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result createCapacityManagerDataExport(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise createCapacityManagerDataExportAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result createCapacityReservation(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise createCapacityReservationAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result createCapacityReservationBySplitting(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise createCapacityReservationBySplittingAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result createCapacityReservationCancellationQuote(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise createCapacityReservationCancellationQuoteAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result createCapacityReservationFleet(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise createCapacityReservationFleetAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result createCarrierGateway(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise createCarrierGatewayAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result createClientVpnEndpoint(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise createClientVpnEndpointAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result createClientVpnRoute(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise createClientVpnRouteAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result createCoipCidr(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise createCoipCidrAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result createCoipPool(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise createCoipPoolAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result createDefaultSubnet(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise createDefaultSubnetAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result createDefaultVpc(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise createDefaultVpcAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result createDelegateMacVolumeOwnershipTask(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise createDelegateMacVolumeOwnershipTaskAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result createEgressOnlyInternetGateway(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise createEgressOnlyInternetGatewayAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result createFleet(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise createFleetAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result createFpgaImage(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise createFpgaImageAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result createImageUsageReport(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise createImageUsageReportAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result createInstanceConnectEndpoint(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise createInstanceConnectEndpointAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result createInstanceEventWindow(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise createInstanceEventWindowAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result createInterruptibleCapacityReservationAllocation(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise createInterruptibleCapacityReservationAllocationAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result createIpam(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise createIpamAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result createIpamExternalResourceVerificationToken(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise createIpamExternalResourceVerificationTokenAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result createIpamPolicy(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise createIpamPolicyAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result createIpamPool(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise createIpamPoolAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result createIpamPrefixListResolver(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise createIpamPrefixListResolverAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result createIpamPrefixListResolverTarget(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise createIpamPrefixListResolverTargetAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result createIpamResourceDiscovery(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise createIpamResourceDiscoveryAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result createIpamScope(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise createIpamScopeAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result createLaunchTemplate(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise createLaunchTemplateAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result createLaunchTemplateVersion(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise createLaunchTemplateVersionAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result createLocalGatewayRoute(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise createLocalGatewayRouteAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result createLocalGatewayRouteTable(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise createLocalGatewayRouteTableAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result createLocalGatewayRouteTableVirtualInterfaceGroupAssociation(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise createLocalGatewayRouteTableVirtualInterfaceGroupAssociationAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result createLocalGatewayRouteTableVpcAssociation(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise createLocalGatewayRouteTableVpcAssociationAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result createLocalGatewayVirtualInterface(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise createLocalGatewayVirtualInterfaceAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result createLocalGatewayVirtualInterfaceGroup(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise createLocalGatewayVirtualInterfaceGroupAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result createMacSystemIntegrityProtectionModificationTask(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise createMacSystemIntegrityProtectionModificationTaskAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result createManagedPrefixList(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise createManagedPrefixListAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result createNetworkInsightsAccessScope(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise createNetworkInsightsAccessScopeAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result createNetworkInsightsPath(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise createNetworkInsightsPathAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result createNetworkInterfacePermission(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise createNetworkInterfacePermissionAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result createPublicIpv4Pool(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise createPublicIpv4PoolAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result createReplaceRootVolumeTask(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise createReplaceRootVolumeTaskAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result createRestoreImageTask(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise createRestoreImageTaskAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result createRouteServer(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise createRouteServerAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result createRouteServerEndpoint(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise createRouteServerEndpointAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result createRouteServerPeer(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise createRouteServerPeerAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result createSecondaryNetwork(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise createSecondaryNetworkAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result createSecondarySubnet(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise createSecondarySubnetAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result createSnapshots(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise createSnapshotsAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result createStoreImageTask(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise createStoreImageTaskAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result createSubnetCidrReservation(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise createSubnetCidrReservationAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result createTrafficMirrorFilter(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise createTrafficMirrorFilterAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result createTrafficMirrorFilterRule(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise createTrafficMirrorFilterRuleAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result createTrafficMirrorSession(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise createTrafficMirrorSessionAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result createTrafficMirrorTarget(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise createTrafficMirrorTargetAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result createTransitGateway(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise createTransitGatewayAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result createTransitGatewayConnect(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise createTransitGatewayConnectAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result createTransitGatewayConnectPeer(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise createTransitGatewayConnectPeerAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result createTransitGatewayMeteringPolicy(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise createTransitGatewayMeteringPolicyAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result createTransitGatewayMeteringPolicyEntry(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise createTransitGatewayMeteringPolicyEntryAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result createTransitGatewayMulticastDomain(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise createTransitGatewayMulticastDomainAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result createTransitGatewayPeeringAttachment(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise createTransitGatewayPeeringAttachmentAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result createTransitGatewayPolicyTable(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise createTransitGatewayPolicyTableAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result createTransitGatewayPrefixListReference(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise createTransitGatewayPrefixListReferenceAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result createTransitGatewayRoute(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise createTransitGatewayRouteAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result createTransitGatewayRouteTable(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise createTransitGatewayRouteTableAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result createTransitGatewayRouteTableAnnouncement(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise createTransitGatewayRouteTableAnnouncementAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result createTransitGatewayVpcAttachment(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise createTransitGatewayVpcAttachmentAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result createVerifiedAccessEndpoint(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise createVerifiedAccessEndpointAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result createVerifiedAccessGroup(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise createVerifiedAccessGroupAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result createVerifiedAccessInstance(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise createVerifiedAccessInstanceAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result createVerifiedAccessTrustProvider(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise createVerifiedAccessTrustProviderAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result createVpcBlockPublicAccessExclusion(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise createVpcBlockPublicAccessExclusionAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result createVpcEncryptionControl(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise createVpcEncryptionControlAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result createVpcEndpointConnectionNotification(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise createVpcEndpointConnectionNotificationAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result createVpcEndpointServiceConfiguration(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise createVpcEndpointServiceConfigurationAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result createVpnConcentrator(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise createVpnConcentratorAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result deleteCapacityManagerDataExport(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise deleteCapacityManagerDataExportAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result deleteCarrierGateway(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise deleteCarrierGatewayAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result deleteClientVpnEndpoint(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise deleteClientVpnEndpointAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result deleteClientVpnRoute(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise deleteClientVpnRouteAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result deleteCoipCidr(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise deleteCoipCidrAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result deleteCoipPool(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise deleteCoipPoolAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result deleteEgressOnlyInternetGateway(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise deleteEgressOnlyInternetGatewayAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result deleteFleets(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise deleteFleetsAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result deleteFpgaImage(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise deleteFpgaImageAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result deleteImageUsageReport(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise deleteImageUsageReportAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result deleteInstanceConnectEndpoint(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise deleteInstanceConnectEndpointAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result deleteInstanceEventWindow(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise deleteInstanceEventWindowAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result deleteIpam(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise deleteIpamAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result deleteIpamExternalResourceVerificationToken(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise deleteIpamExternalResourceVerificationTokenAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result deleteIpamPolicy(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise deleteIpamPolicyAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result deleteIpamPool(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise deleteIpamPoolAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result deleteIpamPrefixListResolver(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise deleteIpamPrefixListResolverAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result deleteIpamPrefixListResolverTarget(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise deleteIpamPrefixListResolverTargetAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result deleteIpamResourceDiscovery(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise deleteIpamResourceDiscoveryAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result deleteIpamScope(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise deleteIpamScopeAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result deleteLaunchTemplate(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise deleteLaunchTemplateAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result deleteLaunchTemplateVersions(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise deleteLaunchTemplateVersionsAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result deleteLocalGatewayRoute(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise deleteLocalGatewayRouteAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result deleteLocalGatewayRouteTable(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise deleteLocalGatewayRouteTableAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result deleteLocalGatewayRouteTableVirtualInterfaceGroupAssociation(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise deleteLocalGatewayRouteTableVirtualInterfaceGroupAssociationAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result deleteLocalGatewayRouteTableVpcAssociation(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise deleteLocalGatewayRouteTableVpcAssociationAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result deleteLocalGatewayVirtualInterface(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise deleteLocalGatewayVirtualInterfaceAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result deleteLocalGatewayVirtualInterfaceGroup(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise deleteLocalGatewayVirtualInterfaceGroupAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result deleteManagedPrefixList(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise deleteManagedPrefixListAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result deleteNetworkInsightsAccessScope(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise deleteNetworkInsightsAccessScopeAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result deleteNetworkInsightsAccessScopeAnalysis(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise deleteNetworkInsightsAccessScopeAnalysisAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result deleteNetworkInsightsAnalysis(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise deleteNetworkInsightsAnalysisAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result deleteNetworkInsightsPath(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise deleteNetworkInsightsPathAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result deleteNetworkInterfacePermission(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise deleteNetworkInterfacePermissionAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result deletePublicIpv4Pool(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise deletePublicIpv4PoolAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result deleteQueuedReservedInstances(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise deleteQueuedReservedInstancesAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result deleteRouteServer(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise deleteRouteServerAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result deleteRouteServerEndpoint(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise deleteRouteServerEndpointAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result deleteRouteServerPeer(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise deleteRouteServerPeerAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result deleteSecondaryNetwork(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise deleteSecondaryNetworkAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result deleteSecondarySubnet(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise deleteSecondarySubnetAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result deleteSubnetCidrReservation(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise deleteSubnetCidrReservationAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result deleteTrafficMirrorFilter(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise deleteTrafficMirrorFilterAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result deleteTrafficMirrorFilterRule(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise deleteTrafficMirrorFilterRuleAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result deleteTrafficMirrorSession(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise deleteTrafficMirrorSessionAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result deleteTrafficMirrorTarget(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise deleteTrafficMirrorTargetAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result deleteTransitGateway(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise deleteTransitGatewayAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result deleteTransitGatewayClientVpnAttachment(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise deleteTransitGatewayClientVpnAttachmentAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result deleteTransitGatewayConnect(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise deleteTransitGatewayConnectAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result deleteTransitGatewayConnectPeer(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise deleteTransitGatewayConnectPeerAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result deleteTransitGatewayMeteringPolicy(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise deleteTransitGatewayMeteringPolicyAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result deleteTransitGatewayMeteringPolicyEntry(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise deleteTransitGatewayMeteringPolicyEntryAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result deleteTransitGatewayMulticastDomain(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise deleteTransitGatewayMulticastDomainAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result deleteTransitGatewayPeeringAttachment(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise deleteTransitGatewayPeeringAttachmentAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result deleteTransitGatewayPolicyTable(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise deleteTransitGatewayPolicyTableAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result deleteTransitGatewayPrefixListReference(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise deleteTransitGatewayPrefixListReferenceAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result deleteTransitGatewayRoute(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise deleteTransitGatewayRouteAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result deleteTransitGatewayRouteTable(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise deleteTransitGatewayRouteTableAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result deleteTransitGatewayRouteTableAnnouncement(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise deleteTransitGatewayRouteTableAnnouncementAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result deleteTransitGatewayVpcAttachment(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise deleteTransitGatewayVpcAttachmentAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result deleteVerifiedAccessEndpoint(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise deleteVerifiedAccessEndpointAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result deleteVerifiedAccessGroup(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise deleteVerifiedAccessGroupAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result deleteVerifiedAccessInstance(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise deleteVerifiedAccessInstanceAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result deleteVerifiedAccessTrustProvider(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise deleteVerifiedAccessTrustProviderAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result deleteVpcBlockPublicAccessExclusion(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise deleteVpcBlockPublicAccessExclusionAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result deleteVpcEncryptionControl(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise deleteVpcEncryptionControlAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result deleteVpcEndpointConnectionNotifications(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise deleteVpcEndpointConnectionNotificationsAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result deleteVpcEndpointServiceConfigurations(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise deleteVpcEndpointServiceConfigurationsAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result deleteVpnConcentrator(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise deleteVpnConcentratorAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result deprovisionByoipCidr(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise deprovisionByoipCidrAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result deprovisionIpamByoasn(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise deprovisionIpamByoasnAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result deprovisionIpamPoolCidr(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise deprovisionIpamPoolCidrAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result deprovisionPublicIpv4PoolCidr(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise deprovisionPublicIpv4PoolCidrAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result deregisterInstanceEventNotificationAttributes(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise deregisterInstanceEventNotificationAttributesAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result deregisterTransitGatewayMulticastGroupMembers(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise deregisterTransitGatewayMulticastGroupMembersAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result deregisterTransitGatewayMulticastGroupSources(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise deregisterTransitGatewayMulticastGroupSourcesAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result describeAccountVpcEncryptionControl(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise describeAccountVpcEncryptionControlAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result describeAddressTransfers(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise describeAddressTransfersAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result describeAddressesAttribute(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise describeAddressesAttributeAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result describeAggregateIdFormat(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise describeAggregateIdFormatAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result describeAwsNetworkPerformanceMetricSubscriptions(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise describeAwsNetworkPerformanceMetricSubscriptionsAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result describeByoipCidrs(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise describeByoipCidrsAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result describeCapacityBlockExtensionHistory(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise describeCapacityBlockExtensionHistoryAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result describeCapacityBlockExtensionOfferings(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise describeCapacityBlockExtensionOfferingsAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result describeCapacityBlockOfferings(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise describeCapacityBlockOfferingsAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result describeCapacityBlockStatus(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise describeCapacityBlockStatusAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result describeCapacityBlocks(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise describeCapacityBlocksAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result describeCapacityManagerDataExports(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise describeCapacityManagerDataExportsAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result describeCapacityReservationBillingRequests(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise describeCapacityReservationBillingRequestsAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result describeCapacityReservationCancellationQuotes(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise describeCapacityReservationCancellationQuotesAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result describeCapacityReservationFleets(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise describeCapacityReservationFleetsAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result describeCapacityReservationTopology(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise describeCapacityReservationTopologyAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result describeCapacityReservations(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise describeCapacityReservationsAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result describeCarrierGateways(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise describeCarrierGatewaysAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result describeClientVpnAuthorizationRules(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise describeClientVpnAuthorizationRulesAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result describeClientVpnConnections(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise describeClientVpnConnectionsAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result describeClientVpnEndpoints(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise describeClientVpnEndpointsAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result describeClientVpnRoutes(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise describeClientVpnRoutesAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result describeClientVpnTargetNetworks(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise describeClientVpnTargetNetworksAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result describeCoipPools(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise describeCoipPoolsAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result describeDeclarativePoliciesReports(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise describeDeclarativePoliciesReportsAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result describeEgressOnlyInternetGateways(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise describeEgressOnlyInternetGatewaysAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result describeElasticGpus(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise describeElasticGpusAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result describeExportImageTasks(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise describeExportImageTasksAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result describeFastLaunchImages(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise describeFastLaunchImagesAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result describeFastSnapshotRestores(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise describeFastSnapshotRestoresAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result describeFleetHistory(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise describeFleetHistoryAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result describeFleetInstances(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise describeFleetInstancesAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result describeFleets(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise describeFleetsAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result describeFpgaImageAttribute(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise describeFpgaImageAttributeAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result describeFpgaImages(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise describeFpgaImagesAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result describeIamInstanceProfileAssociations(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise describeIamInstanceProfileAssociationsAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result describeImageReferences(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise describeImageReferencesAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result describeImageUsageReportEntries(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise describeImageUsageReportEntriesAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result describeImageUsageReports(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise describeImageUsageReportsAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result describeInstanceConnectEndpoints(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise describeInstanceConnectEndpointsAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result describeInstanceCreditSpecifications(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise describeInstanceCreditSpecificationsAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result describeInstanceEventNotificationAttributes(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise describeInstanceEventNotificationAttributesAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result describeInstanceEventWindows(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise describeInstanceEventWindowsAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result describeInstanceImageMetadata(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise describeInstanceImageMetadataAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result describeInstanceSqlHaHistoryStates(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise describeInstanceSqlHaHistoryStatesAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result describeInstanceSqlHaStates(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise describeInstanceSqlHaStatesAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result describeInstanceTopology(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise describeInstanceTopologyAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result describeInstanceTypeOfferings(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise describeInstanceTypeOfferingsAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result describeInstanceTypes(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise describeInstanceTypesAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result describeIpamByoasn(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise describeIpamByoasnAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result describeIpamExternalResourceVerificationTokens(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise describeIpamExternalResourceVerificationTokensAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result describeIpamPolicies(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise describeIpamPoliciesAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result describeIpamPoolAllocations(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise describeIpamPoolAllocationsAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result describeIpamPools(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise describeIpamPoolsAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result describeIpamPrefixListResolverTargets(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise describeIpamPrefixListResolverTargetsAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result describeIpamPrefixListResolvers(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise describeIpamPrefixListResolversAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result describeIpamResourceDiscoveries(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise describeIpamResourceDiscoveriesAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result describeIpamResourceDiscoveryAssociations(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise describeIpamResourceDiscoveryAssociationsAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result describeIpamScopes(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise describeIpamScopesAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result describeIpams(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise describeIpamsAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result describeIpv6Pools(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise describeIpv6PoolsAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result describeLaunchTemplateVersions(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise describeLaunchTemplateVersionsAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result describeLaunchTemplates(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise describeLaunchTemplatesAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result describeLocalGatewayRouteTableVirtualInterfaceGroupAssociations(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise describeLocalGatewayRouteTableVirtualInterfaceGroupAssociationsAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result describeLocalGatewayRouteTableVpcAssociations(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise describeLocalGatewayRouteTableVpcAssociationsAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result describeLocalGatewayRouteTables(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise describeLocalGatewayRouteTablesAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result describeLocalGatewayVirtualInterfaceGroups(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise describeLocalGatewayVirtualInterfaceGroupsAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result describeLocalGatewayVirtualInterfaces(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise describeLocalGatewayVirtualInterfacesAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result describeLocalGateways(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise describeLocalGatewaysAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result describeLockedSnapshots(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise describeLockedSnapshotsAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result describeMacHosts(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise describeMacHostsAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result describeMacModificationTasks(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise describeMacModificationTasksAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result describeManagedPrefixLists(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise describeManagedPrefixListsAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result describeNetworkInsightsAccessScopeAnalyses(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise describeNetworkInsightsAccessScopeAnalysesAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result describeNetworkInsightsAccessScopes(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise describeNetworkInsightsAccessScopesAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result describeNetworkInsightsAnalyses(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise describeNetworkInsightsAnalysesAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result describeNetworkInsightsPaths(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise describeNetworkInsightsPathsAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result describeNetworkInterfacePermissions(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise describeNetworkInterfacePermissionsAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result describeOutpostLags(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise describeOutpostLagsAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result describePrincipalIdFormat(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise describePrincipalIdFormatAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result describePublicIpv4Pools(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise describePublicIpv4PoolsAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result describeReplaceRootVolumeTasks(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise describeReplaceRootVolumeTasksAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result describeRouteServerEndpoints(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise describeRouteServerEndpointsAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result describeRouteServerPeers(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise describeRouteServerPeersAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result describeRouteServers(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise describeRouteServersAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result describeSecondaryInterfaces(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise describeSecondaryInterfacesAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result describeSecondaryNetworks(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise describeSecondaryNetworksAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result describeSecondarySubnets(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise describeSecondarySubnetsAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result describeSecurityGroupRules(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise describeSecurityGroupRulesAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result describeSecurityGroupVpcAssociations(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise describeSecurityGroupVpcAssociationsAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result describeServiceLinkVirtualInterfaces(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise describeServiceLinkVirtualInterfacesAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result describeSnapshotTierStatus(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise describeSnapshotTierStatusAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result describeStoreImageTasks(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise describeStoreImageTasksAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result describeTrafficMirrorFilterRules(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise describeTrafficMirrorFilterRulesAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result describeTrafficMirrorFilters(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise describeTrafficMirrorFiltersAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result describeTrafficMirrorSessions(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise describeTrafficMirrorSessionsAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result describeTrafficMirrorTargets(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise describeTrafficMirrorTargetsAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result describeTransitGatewayAttachments(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise describeTransitGatewayAttachmentsAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result describeTransitGatewayConnectPeers(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise describeTransitGatewayConnectPeersAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result describeTransitGatewayConnects(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise describeTransitGatewayConnectsAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result describeTransitGatewayMeteringPolicies(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise describeTransitGatewayMeteringPoliciesAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result describeTransitGatewayMulticastDomains(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise describeTransitGatewayMulticastDomainsAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result describeTransitGatewayPeeringAttachments(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise describeTransitGatewayPeeringAttachmentsAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result describeTransitGatewayPolicyTables(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise describeTransitGatewayPolicyTablesAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result describeTransitGatewayRouteTableAnnouncements(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise describeTransitGatewayRouteTableAnnouncementsAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result describeTransitGatewayRouteTables(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise describeTransitGatewayRouteTablesAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result describeTransitGatewayVpcAttachments(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise describeTransitGatewayVpcAttachmentsAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result describeTransitGateways(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise describeTransitGatewaysAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result describeTrunkInterfaceAssociations(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise describeTrunkInterfaceAssociationsAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result describeVerifiedAccessEndpoints(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise describeVerifiedAccessEndpointsAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result describeVerifiedAccessGroups(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise describeVerifiedAccessGroupsAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result describeVerifiedAccessInstanceLoggingConfigurations(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise describeVerifiedAccessInstanceLoggingConfigurationsAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result describeVerifiedAccessInstances(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise describeVerifiedAccessInstancesAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result describeVerifiedAccessTrustProviders(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise describeVerifiedAccessTrustProvidersAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result describeVolumesModifications(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise describeVolumesModificationsAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result describeVpcBlockPublicAccessExclusions(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise describeVpcBlockPublicAccessExclusionsAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result describeVpcBlockPublicAccessOptions(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise describeVpcBlockPublicAccessOptionsAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result describeVpcEncryptionControls(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise describeVpcEncryptionControlsAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result describeVpcEndpointAssociations(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise describeVpcEndpointAssociationsAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result describeVpcEndpointConnectionNotifications(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise describeVpcEndpointConnectionNotificationsAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result describeVpcEndpointConnections(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise describeVpcEndpointConnectionsAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result describeVpcEndpointServiceConfigurations(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise describeVpcEndpointServiceConfigurationsAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result describeVpcEndpointServicePermissions(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise describeVpcEndpointServicePermissionsAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result describeVpnConcentrators(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise describeVpnConcentratorsAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result detachImageWatermark(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise detachImageWatermarkAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result detachVerifiedAccessTrustProvider(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise detachVerifiedAccessTrustProviderAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result disableAddressTransfer(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise disableAddressTransferAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result disableAllowedImagesSettings(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise disableAllowedImagesSettingsAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result disableAwsNetworkPerformanceMetricSubscription(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise disableAwsNetworkPerformanceMetricSubscriptionAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result disableCapacityManager(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise disableCapacityManagerAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result disableEbsEncryptionByDefault(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise disableEbsEncryptionByDefaultAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result disableFastLaunch(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise disableFastLaunchAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result disableFastSnapshotRestores(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise disableFastSnapshotRestoresAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result disableImage(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise disableImageAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result disableImageBlockPublicAccess(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise disableImageBlockPublicAccessAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result disableImageDeprecation(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise disableImageDeprecationAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result disableImageDeregistrationProtection(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise disableImageDeregistrationProtectionAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result disableInstanceSqlHaStandbyDetections(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise disableInstanceSqlHaStandbyDetectionsAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result disableIpamOrganizationAdminAccount(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise disableIpamOrganizationAdminAccountAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result disableIpamPolicy(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise disableIpamPolicyAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result disableRouteServerPropagation(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise disableRouteServerPropagationAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result disableSerialConsoleAccess(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise disableSerialConsoleAccessAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result disableSnapshotBlockPublicAccess(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise disableSnapshotBlockPublicAccessAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result disableTransitGatewayRouteTablePropagation(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise disableTransitGatewayRouteTablePropagationAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result disassociateCapacityReservationBillingOwner(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise disassociateCapacityReservationBillingOwnerAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result disassociateClientVpnTargetNetwork(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise disassociateClientVpnTargetNetworkAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result disassociateEnclaveCertificateIamRole(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise disassociateEnclaveCertificateIamRoleAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result disassociateIamInstanceProfile(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise disassociateIamInstanceProfileAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result disassociateInstanceEventWindow(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise disassociateInstanceEventWindowAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result disassociateIpamByoasn(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise disassociateIpamByoasnAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result disassociateIpamResourceDiscovery(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise disassociateIpamResourceDiscoveryAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result disassociateNatGatewayAddress(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise disassociateNatGatewayAddressAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result disassociateRouteServer(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise disassociateRouteServerAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result disassociateSecurityGroupVpc(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise disassociateSecurityGroupVpcAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result disassociateSubnetCidrBlock(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise disassociateSubnetCidrBlockAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result disassociateTransitGatewayMulticastDomain(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise disassociateTransitGatewayMulticastDomainAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result disassociateTransitGatewayPolicyTable(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise disassociateTransitGatewayPolicyTableAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result disassociateTransitGatewayRouteTable(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise disassociateTransitGatewayRouteTableAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result disassociateTrunkInterface(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise disassociateTrunkInterfaceAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result disassociateVpcCidrBlock(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise disassociateVpcCidrBlockAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result enableAddressTransfer(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise enableAddressTransferAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result enableAllowedImagesSettings(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise enableAllowedImagesSettingsAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result enableAwsNetworkPerformanceMetricSubscription(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise enableAwsNetworkPerformanceMetricSubscriptionAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result enableCapacityManager(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise enableCapacityManagerAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result enableEbsEncryptionByDefault(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise enableEbsEncryptionByDefaultAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result enableFastLaunch(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise enableFastLaunchAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result enableFastSnapshotRestores(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise enableFastSnapshotRestoresAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result enableImage(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise enableImageAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result enableImageBlockPublicAccess(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise enableImageBlockPublicAccessAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result enableImageDeprecation(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise enableImageDeprecationAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result enableImageDeregistrationProtection(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise enableImageDeregistrationProtectionAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result enableInstanceSqlHaStandbyDetections(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise enableInstanceSqlHaStandbyDetectionsAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result enableIpamOrganizationAdminAccount(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise enableIpamOrganizationAdminAccountAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result enableIpamPolicy(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise enableIpamPolicyAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result enableReachabilityAnalyzerOrganizationSharing(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise enableReachabilityAnalyzerOrganizationSharingAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result enableRouteServerPropagation(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise enableRouteServerPropagationAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result enableSerialConsoleAccess(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise enableSerialConsoleAccessAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result enableSnapshotBlockPublicAccess(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise enableSnapshotBlockPublicAccessAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result enableTransitGatewayRouteTablePropagation(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise enableTransitGatewayRouteTablePropagationAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result exportClientVpnClientCertificateRevocationList(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise exportClientVpnClientCertificateRevocationListAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result exportClientVpnClientConfiguration(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise exportClientVpnClientConfigurationAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result exportImage(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise exportImageAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result exportTransitGatewayRoutes(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise exportTransitGatewayRoutesAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result exportVerifiedAccessInstanceClientConfiguration(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise exportVerifiedAccessInstanceClientConfigurationAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result getActiveVpnTunnelStatus(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise getActiveVpnTunnelStatusAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result getAllowedImagesSettings(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise getAllowedImagesSettingsAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result getAssociatedEnclaveCertificateIamRoles(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise getAssociatedEnclaveCertificateIamRolesAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result getAssociatedIpv6PoolCidrs(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise getAssociatedIpv6PoolCidrsAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result getAwsNetworkPerformanceData(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise getAwsNetworkPerformanceDataAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result getCapacityManagerAttributes(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise getCapacityManagerAttributesAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result getCapacityManagerMetricData(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise getCapacityManagerMetricDataAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result getCapacityManagerMetricDimensions(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise getCapacityManagerMetricDimensionsAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result getCapacityManagerMonitoredTagKeys(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise getCapacityManagerMonitoredTagKeysAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result getCapacityReservationUsage(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise getCapacityReservationUsageAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result getCoipPoolUsage(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise getCoipPoolUsageAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result getDeclarativePoliciesReportSummary(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise getDeclarativePoliciesReportSummaryAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result getDefaultCreditSpecification(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise getDefaultCreditSpecificationAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result getEbsDefaultKmsKeyId(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise getEbsDefaultKmsKeyIdAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result getEbsEncryptionByDefault(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise getEbsEncryptionByDefaultAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result getEnabledIpamPolicy(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise getEnabledIpamPolicyAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result getFlowLogsIntegrationTemplate(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise getFlowLogsIntegrationTemplateAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result getGroupsForCapacityReservation(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise getGroupsForCapacityReservationAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result getImageAncestry(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise getImageAncestryAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result getImageBlockPublicAccessState(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise getImageBlockPublicAccessStateAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result getInstanceMetadataDefaults(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise getInstanceMetadataDefaultsAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result getInstanceTpmEkPub(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise getInstanceTpmEkPubAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result getInstanceTypesFromInstanceRequirements(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise getInstanceTypesFromInstanceRequirementsAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result getInstanceUefiData(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise getInstanceUefiDataAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result getIpamAddressHistory(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise getIpamAddressHistoryAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result getIpamDiscoveredAccounts(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise getIpamDiscoveredAccountsAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result getIpamDiscoveredPublicAddresses(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise getIpamDiscoveredPublicAddressesAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result getIpamDiscoveredResourceCidrs(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise getIpamDiscoveredResourceCidrsAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result getIpamPolicyAllocationRules(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise getIpamPolicyAllocationRulesAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result getIpamPolicyOrganizationTargets(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise getIpamPolicyOrganizationTargetsAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result getIpamPoolAllocations(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise getIpamPoolAllocationsAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result getIpamPoolCidrs(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise getIpamPoolCidrsAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result getIpamPrefixListResolverRules(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise getIpamPrefixListResolverRulesAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result getIpamPrefixListResolverVersionEntries(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise getIpamPrefixListResolverVersionEntriesAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result getIpamPrefixListResolverVersions(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise getIpamPrefixListResolverVersionsAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result getIpamResourceCidrs(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise getIpamResourceCidrsAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result getLaunchTemplateData(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise getLaunchTemplateDataAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result getManagedPrefixListAssociations(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise getManagedPrefixListAssociationsAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result getManagedPrefixListEntries(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise getManagedPrefixListEntriesAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result getManagedResourceVisibility(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise getManagedResourceVisibilityAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result getNetworkInsightsAccessScopeAnalysisFindings(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise getNetworkInsightsAccessScopeAnalysisFindingsAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result getNetworkInsightsAccessScopeContent(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise getNetworkInsightsAccessScopeContentAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result getRouteServerAssociations(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise getRouteServerAssociationsAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result getRouteServerPropagations(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise getRouteServerPropagationsAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result getRouteServerRoutingDatabase(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise getRouteServerRoutingDatabaseAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result getSecurityGroupsForVpc(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise getSecurityGroupsForVpcAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result getSerialConsoleAccessStatus(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise getSerialConsoleAccessStatusAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result getSnapshotBlockPublicAccessState(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise getSnapshotBlockPublicAccessStateAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result getSpotPlacementScores(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise getSpotPlacementScoresAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result getSubnetCidrReservations(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise getSubnetCidrReservationsAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result getTransitGatewayAttachmentPropagations(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise getTransitGatewayAttachmentPropagationsAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result getTransitGatewayMeteringPolicyEntries(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise getTransitGatewayMeteringPolicyEntriesAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result getTransitGatewayMulticastDomainAssociations(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise getTransitGatewayMulticastDomainAssociationsAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result getTransitGatewayPolicyTableAssociations(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise getTransitGatewayPolicyTableAssociationsAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result getTransitGatewayPolicyTableEntries(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise getTransitGatewayPolicyTableEntriesAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result getTransitGatewayPrefixListReferences(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise getTransitGatewayPrefixListReferencesAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result getTransitGatewayRouteTableAssociations(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise getTransitGatewayRouteTableAssociationsAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result getTransitGatewayRouteTablePropagations(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise getTransitGatewayRouteTablePropagationsAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result getVerifiedAccessEndpointPolicy(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise getVerifiedAccessEndpointPolicyAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result getVerifiedAccessEndpointTargets(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise getVerifiedAccessEndpointTargetsAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result getVerifiedAccessGroupPolicy(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise getVerifiedAccessGroupPolicyAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result getVpcResourcesBlockingEncryptionEnforcement(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise getVpcResourcesBlockingEncryptionEnforcementAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result getVpnConnectionDeviceSampleConfiguration(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise getVpnConnectionDeviceSampleConfigurationAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result getVpnConnectionDeviceTypes(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise getVpnConnectionDeviceTypesAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result getVpnTunnelReplacementStatus(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise getVpnTunnelReplacementStatusAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result importClientVpnClientCertificateRevocationList(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise importClientVpnClientCertificateRevocationListAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result listImagesInRecycleBin(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise listImagesInRecycleBinAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result listSnapshotsInRecycleBin(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise listSnapshotsInRecycleBinAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result listVolumesInRecycleBin(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise listVolumesInRecycleBinAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result lockSnapshot(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise lockSnapshotAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result modifyAccountVpcEncryptionControl(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise modifyAccountVpcEncryptionControlAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result modifyAddressAttribute(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise modifyAddressAttributeAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result modifyAvailabilityZoneGroup(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise modifyAvailabilityZoneGroupAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result modifyCapacityReservation(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise modifyCapacityReservationAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result modifyCapacityReservationFleet(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise modifyCapacityReservationFleetAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result modifyClientVpnEndpoint(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise modifyClientVpnEndpointAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result modifyDefaultCreditSpecification(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise modifyDefaultCreditSpecificationAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result modifyEbsDefaultKmsKeyId(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise modifyEbsDefaultKmsKeyIdAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result modifyFleet(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise modifyFleetAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result modifyFpgaImageAttribute(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise modifyFpgaImageAttributeAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result modifyInstanceCapacityReservationAttributes(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise modifyInstanceCapacityReservationAttributesAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result modifyInstanceConnectEndpoint(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise modifyInstanceConnectEndpointAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result modifyInstanceCpuOptions(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise modifyInstanceCpuOptionsAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result modifyInstanceCreditSpecification(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise modifyInstanceCreditSpecificationAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result modifyInstanceEventStartTime(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise modifyInstanceEventStartTimeAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result modifyInstanceEventWindow(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise modifyInstanceEventWindowAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result modifyInstanceMaintenanceOptions(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise modifyInstanceMaintenanceOptionsAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result modifyInstanceMetadataDefaults(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise modifyInstanceMetadataDefaultsAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result modifyInstanceMetadataOptions(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise modifyInstanceMetadataOptionsAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result modifyInstanceNetworkPerformanceOptions(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise modifyInstanceNetworkPerformanceOptionsAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result modifyIpam(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise modifyIpamAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result modifyIpamPolicyAllocationRules(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise modifyIpamPolicyAllocationRulesAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result modifyIpamPool(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise modifyIpamPoolAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result modifyIpamPoolAllocation(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise modifyIpamPoolAllocationAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result modifyIpamPrefixListResolver(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise modifyIpamPrefixListResolverAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result modifyIpamPrefixListResolverTarget(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise modifyIpamPrefixListResolverTargetAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result modifyIpamResourceCidr(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise modifyIpamResourceCidrAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result modifyIpamResourceDiscovery(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise modifyIpamResourceDiscoveryAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result modifyIpamScope(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise modifyIpamScopeAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result modifyLaunchTemplate(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise modifyLaunchTemplateAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result modifyLocalGatewayRoute(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise modifyLocalGatewayRouteAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result modifyManagedPrefixList(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise modifyManagedPrefixListAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result modifyManagedResourceVisibility(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise modifyManagedResourceVisibilityAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result modifyPrivateDnsNameOptions(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise modifyPrivateDnsNameOptionsAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result modifyPublicIpDnsNameOptions(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise modifyPublicIpDnsNameOptionsAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result modifyRouteServer(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise modifyRouteServerAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result modifySecurityGroupRules(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise modifySecurityGroupRulesAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result modifySnapshotTier(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise modifySnapshotTierAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result modifyTrafficMirrorFilterNetworkServices(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise modifyTrafficMirrorFilterNetworkServicesAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result modifyTrafficMirrorFilterRule(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise modifyTrafficMirrorFilterRuleAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result modifyTrafficMirrorSession(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise modifyTrafficMirrorSessionAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result modifyTransitGateway(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise modifyTransitGatewayAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result modifyTransitGatewayMeteringPolicy(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise modifyTransitGatewayMeteringPolicyAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result modifyTransitGatewayPrefixListReference(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise modifyTransitGatewayPrefixListReferenceAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result modifyTransitGatewayVpcAttachment(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise modifyTransitGatewayVpcAttachmentAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result modifyVerifiedAccessEndpoint(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise modifyVerifiedAccessEndpointAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result modifyVerifiedAccessEndpointPolicy(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise modifyVerifiedAccessEndpointPolicyAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result modifyVerifiedAccessGroup(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise modifyVerifiedAccessGroupAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result modifyVerifiedAccessGroupPolicy(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise modifyVerifiedAccessGroupPolicyAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result modifyVerifiedAccessInstance(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise modifyVerifiedAccessInstanceAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result modifyVerifiedAccessInstanceLoggingConfiguration(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise modifyVerifiedAccessInstanceLoggingConfigurationAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result modifyVerifiedAccessTrustProvider(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise modifyVerifiedAccessTrustProviderAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result modifyVolume(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise modifyVolumeAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result modifyVpcBlockPublicAccessExclusion(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise modifyVpcBlockPublicAccessExclusionAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result modifyVpcBlockPublicAccessOptions(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise modifyVpcBlockPublicAccessOptionsAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result modifyVpcEncryptionControl(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise modifyVpcEncryptionControlAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result modifyVpcEndpointConnectionNotification(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise modifyVpcEndpointConnectionNotificationAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result modifyVpcEndpointPayerResponsibility(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise modifyVpcEndpointPayerResponsibilityAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result modifyVpcEndpointServiceConfiguration(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise modifyVpcEndpointServiceConfigurationAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result modifyVpcEndpointServicePayerResponsibility(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise modifyVpcEndpointServicePayerResponsibilityAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result modifyVpcEndpointServicePermissions(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise modifyVpcEndpointServicePermissionsAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result modifyVpcTenancy(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise modifyVpcTenancyAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result modifyVpnConnection(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise modifyVpnConnectionAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result modifyVpnConnectionOptions(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise modifyVpnConnectionOptionsAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result modifyVpnTunnelCertificate(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise modifyVpnTunnelCertificateAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result modifyVpnTunnelOptions(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise modifyVpnTunnelOptionsAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result moveByoipCidrToIpam(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise moveByoipCidrToIpamAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result moveCapacityReservationInstances(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise moveCapacityReservationInstancesAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result provisionByoipCidr(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise provisionByoipCidrAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result provisionIpamByoasn(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise provisionIpamByoasnAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result provisionIpamPoolCidr(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise provisionIpamPoolCidrAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result provisionPublicIpv4PoolCidr(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise provisionPublicIpv4PoolCidrAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result purchaseCapacityBlock(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise purchaseCapacityBlockAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result purchaseCapacityBlockExtension(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise purchaseCapacityBlockExtensionAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result registerInstanceEventNotificationAttributes(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise registerInstanceEventNotificationAttributesAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result registerTransitGatewayMulticastGroupMembers(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise registerTransitGatewayMulticastGroupMembersAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result registerTransitGatewayMulticastGroupSources(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise registerTransitGatewayMulticastGroupSourcesAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result rejectCapacityReservationBillingOwnership(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise rejectCapacityReservationBillingOwnershipAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result rejectTransitGatewayClientVpnAttachment(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise rejectTransitGatewayClientVpnAttachmentAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result rejectTransitGatewayMulticastDomainAssociations(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise rejectTransitGatewayMulticastDomainAssociationsAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result rejectTransitGatewayPeeringAttachment(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise rejectTransitGatewayPeeringAttachmentAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result rejectTransitGatewayVpcAttachment(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise rejectTransitGatewayVpcAttachmentAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result rejectVpcEndpointConnections(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise rejectVpcEndpointConnectionsAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result releaseIpamPoolAllocation(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise releaseIpamPoolAllocationAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result replaceIamInstanceProfileAssociation(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise replaceIamInstanceProfileAssociationAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result replaceImageCriteriaInAllowedImagesSettings(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise replaceImageCriteriaInAllowedImagesSettingsAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result replaceTransitGatewayRoute(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise replaceTransitGatewayRouteAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result replaceVpnTunnel(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise replaceVpnTunnelAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result resetAddressAttribute(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise resetAddressAttributeAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result resetEbsDefaultKmsKeyId(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise resetEbsDefaultKmsKeyIdAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result resetFpgaImageAttribute(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise resetFpgaImageAttributeAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result restoreImageFromRecycleBin(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise restoreImageFromRecycleBinAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result restoreManagedPrefixListVersion(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise restoreManagedPrefixListVersionAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result restoreSnapshotFromRecycleBin(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise restoreSnapshotFromRecycleBinAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result restoreSnapshotTier(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise restoreSnapshotTierAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result restoreVolumeFromRecycleBin(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise restoreVolumeFromRecycleBinAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result revokeClientVpnIngress(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise revokeClientVpnIngressAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result searchLocalGatewayRoutes(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise searchLocalGatewayRoutesAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result searchTransitGatewayMulticastGroups(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise searchTransitGatewayMulticastGroupsAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result searchTransitGatewayRoutes(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise searchTransitGatewayRoutesAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result sendDiagnosticInterrupt(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise sendDiagnosticInterruptAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result startDeclarativePoliciesReport(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise startDeclarativePoliciesReportAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result startNetworkInsightsAccessScopeAnalysis(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise startNetworkInsightsAccessScopeAnalysisAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result startNetworkInsightsAnalysis(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise startNetworkInsightsAnalysisAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result startVpcEndpointServicePrivateDnsVerification(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise startVpcEndpointServicePrivateDnsVerificationAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result terminateClientVpnConnections(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise terminateClientVpnConnectionsAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result unassignIpv6Addresses(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise unassignIpv6AddressesAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result unassignPrivateNatGatewayAddress(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise unassignPrivateNatGatewayAddressAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result unlockSnapshot(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise unlockSnapshotAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result updateCapacityManagerMonitoredTagKeys(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise updateCapacityManagerMonitoredTagKeysAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result updateCapacityManagerOrganizationsAccess(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise updateCapacityManagerOrganizationsAccessAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result updateInterruptibleCapacityReservationAllocation(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise updateInterruptibleCapacityReservationAllocationAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result updateSecurityGroupRuleDescriptionsEgress(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise updateSecurityGroupRuleDescriptionsEgressAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result updateSecurityGroupRuleDescriptionsIngress(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise updateSecurityGroupRuleDescriptionsIngressAsync(array $args = []) (supported in versions 2016-11-15)
+ * @method \Aws\Result withdrawByoipCidr(array $args = []) (supported in versions 2016-11-15)
+ * @method \GuzzleHttp\Promise\Promise withdrawByoipCidrAsync(array $args = []) (supported in versions 2016-11-15)
+ */
+class Ec2Client extends AwsClient
+{
+    public function __construct(array $args)
+    {
+        $args['with_resolved'] = function (array $args) {
+            $this->getHandlerList()->appendInit(
+                PresignUrlMiddleware::wrap(
+                    $this,
+                    $args['endpoint_provider'],
+                    [
+                        'operations' => [
+                            'CopySnapshot',
+                        ],
+                        'service' => 'ec2',
+                        'presign_param' => 'PresignedUrl',
+                    ]
+                ),
+                'ec2.copy_snapshot'
+            );
+        };
+
+        parent::__construct($args);
+    }
+
+    /**
+     * @internal
+     * @codeCoverageIgnore
+     */
+    public static function applyDocFilters(array $api, array $docs)
+    {
+        // Several copy snapshot parameters are optional.
+        $docs['shapes']['String']['refs']['CopySnapshotRequest$PresignedUrl']
+            = '<div class="alert alert-info">The SDK will compute this value '
+            . 'for you on your behalf.</div>';
+        $docs['shapes']['String']['refs']['CopySnapshotRequest$DestinationRegion']
+            = '<div class="alert alert-info">The SDK will populate this '
+            . 'parameter on your behalf using the configured region value of '
+            . 'the client.</div>';
+
+        return [
+            new Service($api, ApiProvider::defaultProvider()),
+            new DocModel($docs)
+        ];
+    }
+}

+ 140 - 0
upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/Emr/EmrClient.php

@@ -0,0 +1,140 @@
+<?php
+namespace Aws\Emr;
+
+use Aws\AwsClient;
+
+/**
+ * This client is used to interact with the **Amazon Elastic MapReduce (Amazon EMR)** service.
+ *
+ * @method \Aws\Result addInstanceFleet(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise addInstanceFleetAsync(array $args = [])
+ * @method \Aws\Result addInstanceGroups(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise addInstanceGroupsAsync(array $args = [])
+ * @method \Aws\Result addJobFlowSteps(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise addJobFlowStepsAsync(array $args = [])
+ * @method \Aws\Result addTags(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise addTagsAsync(array $args = [])
+ * @method \Aws\Result cancelSteps(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise cancelStepsAsync(array $args = [])
+ * @method \Aws\Result createPersistentAppUI(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createPersistentAppUIAsync(array $args = [])
+ * @method \Aws\Result createSecurityConfiguration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createSecurityConfigurationAsync(array $args = [])
+ * @method \Aws\Result createStudio(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createStudioAsync(array $args = [])
+ * @method \Aws\Result createStudioSessionMapping(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createStudioSessionMappingAsync(array $args = [])
+ * @method \Aws\Result deleteSecurityConfiguration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteSecurityConfigurationAsync(array $args = [])
+ * @method \Aws\Result deleteStudio(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteStudioAsync(array $args = [])
+ * @method \Aws\Result deleteStudioSessionMapping(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteStudioSessionMappingAsync(array $args = [])
+ * @method \Aws\Result describeCluster(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeClusterAsync(array $args = [])
+ * @method \Aws\Result describeJobFlows(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeJobFlowsAsync(array $args = [])
+ * @method \Aws\Result describeNotebookExecution(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeNotebookExecutionAsync(array $args = [])
+ * @method \Aws\Result describePersistentAppUI(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describePersistentAppUIAsync(array $args = [])
+ * @method \Aws\Result describeReleaseLabel(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeReleaseLabelAsync(array $args = [])
+ * @method \Aws\Result describeSecurityConfiguration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeSecurityConfigurationAsync(array $args = [])
+ * @method \Aws\Result describeStep(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeStepAsync(array $args = [])
+ * @method \Aws\Result describeStudio(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeStudioAsync(array $args = [])
+ * @method \Aws\Result getAutoTerminationPolicy(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getAutoTerminationPolicyAsync(array $args = [])
+ * @method \Aws\Result getBlockPublicAccessConfiguration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getBlockPublicAccessConfigurationAsync(array $args = [])
+ * @method \Aws\Result getClusterSessionCredentials(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getClusterSessionCredentialsAsync(array $args = [])
+ * @method \Aws\Result getManagedScalingPolicy(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getManagedScalingPolicyAsync(array $args = [])
+ * @method \Aws\Result getOnClusterAppUIPresignedURL(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getOnClusterAppUIPresignedURLAsync(array $args = [])
+ * @method \Aws\Result getPersistentAppUIPresignedURL(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getPersistentAppUIPresignedURLAsync(array $args = [])
+ * @method \Aws\Result getSession(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getSessionAsync(array $args = [])
+ * @method \Aws\Result getSessionEndpoint(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getSessionEndpointAsync(array $args = [])
+ * @method \Aws\Result getStudioSessionMapping(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getStudioSessionMappingAsync(array $args = [])
+ * @method \Aws\Result listBootstrapActions(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listBootstrapActionsAsync(array $args = [])
+ * @method \Aws\Result listClusters(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listClustersAsync(array $args = [])
+ * @method \Aws\Result listInstanceFleets(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listInstanceFleetsAsync(array $args = [])
+ * @method \Aws\Result listInstanceGroups(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listInstanceGroupsAsync(array $args = [])
+ * @method \Aws\Result listInstances(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listInstancesAsync(array $args = [])
+ * @method \Aws\Result listNotebookExecutions(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listNotebookExecutionsAsync(array $args = [])
+ * @method \Aws\Result listReleaseLabels(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listReleaseLabelsAsync(array $args = [])
+ * @method \Aws\Result listSecurityConfigurations(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listSecurityConfigurationsAsync(array $args = [])
+ * @method \Aws\Result listSessions(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listSessionsAsync(array $args = [])
+ * @method \Aws\Result listSteps(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listStepsAsync(array $args = [])
+ * @method \Aws\Result listStudioSessionMappings(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listStudioSessionMappingsAsync(array $args = [])
+ * @method \Aws\Result listStudios(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listStudiosAsync(array $args = [])
+ * @method \Aws\Result listSupportedInstanceTypes(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listSupportedInstanceTypesAsync(array $args = [])
+ * @method \Aws\Result modifyCluster(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise modifyClusterAsync(array $args = [])
+ * @method \Aws\Result modifyInstanceFleet(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise modifyInstanceFleetAsync(array $args = [])
+ * @method \Aws\Result modifyInstanceGroups(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise modifyInstanceGroupsAsync(array $args = [])
+ * @method \Aws\Result putAutoScalingPolicy(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise putAutoScalingPolicyAsync(array $args = [])
+ * @method \Aws\Result putAutoTerminationPolicy(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise putAutoTerminationPolicyAsync(array $args = [])
+ * @method \Aws\Result putBlockPublicAccessConfiguration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise putBlockPublicAccessConfigurationAsync(array $args = [])
+ * @method \Aws\Result putManagedScalingPolicy(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise putManagedScalingPolicyAsync(array $args = [])
+ * @method \Aws\Result removeAutoScalingPolicy(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise removeAutoScalingPolicyAsync(array $args = [])
+ * @method \Aws\Result removeAutoTerminationPolicy(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise removeAutoTerminationPolicyAsync(array $args = [])
+ * @method \Aws\Result removeManagedScalingPolicy(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise removeManagedScalingPolicyAsync(array $args = [])
+ * @method \Aws\Result removeTags(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise removeTagsAsync(array $args = [])
+ * @method \Aws\Result runJobFlow(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise runJobFlowAsync(array $args = [])
+ * @method \Aws\Result setKeepJobFlowAliveWhenNoSteps(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise setKeepJobFlowAliveWhenNoStepsAsync(array $args = [])
+ * @method \Aws\Result setTerminationProtection(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise setTerminationProtectionAsync(array $args = [])
+ * @method \Aws\Result setUnhealthyNodeReplacement(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise setUnhealthyNodeReplacementAsync(array $args = [])
+ * @method \Aws\Result setVisibleToAllUsers(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise setVisibleToAllUsersAsync(array $args = [])
+ * @method \Aws\Result startNotebookExecution(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise startNotebookExecutionAsync(array $args = [])
+ * @method \Aws\Result startSession(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise startSessionAsync(array $args = [])
+ * @method \Aws\Result stopNotebookExecution(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise stopNotebookExecutionAsync(array $args = [])
+ * @method \Aws\Result terminateJobFlows(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise terminateJobFlowsAsync(array $args = [])
+ * @method \Aws\Result terminateSession(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise terminateSessionAsync(array $args = [])
+ * @method \Aws\Result updateStudio(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateStudioAsync(array $args = [])
+ * @method \Aws\Result updateStudioSessionMapping(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateStudioSessionMappingAsync(array $args = [])
+ */
+class EmrClient extends AwsClient {}

+ 59 - 0
upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/GameLiftStreams/GameLiftStreamsClient.php

@@ -0,0 +1,59 @@
+<?php
+namespace Aws\GameLiftStreams;
+
+use Aws\AwsClient;
+
+/**
+ * This client is used to interact with the **Amazon GameLift Streams** service.
+ * @method \Aws\Result addStreamGroupLocations(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise addStreamGroupLocationsAsync(array $args = [])
+ * @method \Aws\Result associateApplications(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise associateApplicationsAsync(array $args = [])
+ * @method \Aws\Result createApplication(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createApplicationAsync(array $args = [])
+ * @method \Aws\Result createStreamGroup(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createStreamGroupAsync(array $args = [])
+ * @method \Aws\Result createStreamSessionAdminShell(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createStreamSessionAdminShellAsync(array $args = [])
+ * @method \Aws\Result createStreamSessionConnection(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createStreamSessionConnectionAsync(array $args = [])
+ * @method \Aws\Result deleteApplication(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteApplicationAsync(array $args = [])
+ * @method \Aws\Result deleteStreamGroup(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteStreamGroupAsync(array $args = [])
+ * @method \Aws\Result disassociateApplications(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise disassociateApplicationsAsync(array $args = [])
+ * @method \Aws\Result exportStreamSessionFiles(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise exportStreamSessionFilesAsync(array $args = [])
+ * @method \Aws\Result getApplication(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getApplicationAsync(array $args = [])
+ * @method \Aws\Result getStreamGroup(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getStreamGroupAsync(array $args = [])
+ * @method \Aws\Result getStreamSession(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getStreamSessionAsync(array $args = [])
+ * @method \Aws\Result listApplications(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listApplicationsAsync(array $args = [])
+ * @method \Aws\Result listStreamGroups(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listStreamGroupsAsync(array $args = [])
+ * @method \Aws\Result listStreamSessions(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listStreamSessionsAsync(array $args = [])
+ * @method \Aws\Result listStreamSessionsByAccount(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listStreamSessionsByAccountAsync(array $args = [])
+ * @method \Aws\Result listTagsForResource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listTagsForResourceAsync(array $args = [])
+ * @method \Aws\Result removeStreamGroupLocations(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise removeStreamGroupLocationsAsync(array $args = [])
+ * @method \Aws\Result startStreamSession(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise startStreamSessionAsync(array $args = [])
+ * @method \Aws\Result tagResource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise tagResourceAsync(array $args = [])
+ * @method \Aws\Result terminateStreamSession(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise terminateStreamSessionAsync(array $args = [])
+ * @method \Aws\Result untagResource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise untagResourceAsync(array $args = [])
+ * @method \Aws\Result updateApplication(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateApplicationAsync(array $args = [])
+ * @method \Aws\Result updateStreamGroup(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateStreamGroupAsync(array $args = [])
+ */
+class GameLiftStreamsClient extends AwsClient {}

+ 601 - 0
upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/Glue/GlueClient.php

@@ -0,0 +1,601 @@
+<?php
+namespace Aws\Glue;
+
+use Aws\AwsClient;
+
+/**
+ * This client is used to interact with the **AWS Glue** service.
+ * @method \Aws\Result associateGlossaryTerms(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise associateGlossaryTermsAsync(array $args = [])
+ * @method \Aws\Result batchCreatePartition(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise batchCreatePartitionAsync(array $args = [])
+ * @method \Aws\Result batchDeleteConnection(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise batchDeleteConnectionAsync(array $args = [])
+ * @method \Aws\Result batchDeletePartition(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise batchDeletePartitionAsync(array $args = [])
+ * @method \Aws\Result batchDeleteTable(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise batchDeleteTableAsync(array $args = [])
+ * @method \Aws\Result batchDeleteTableVersion(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise batchDeleteTableVersionAsync(array $args = [])
+ * @method \Aws\Result batchGetBlueprints(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise batchGetBlueprintsAsync(array $args = [])
+ * @method \Aws\Result batchGetCrawlers(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise batchGetCrawlersAsync(array $args = [])
+ * @method \Aws\Result batchGetCustomEntityTypes(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise batchGetCustomEntityTypesAsync(array $args = [])
+ * @method \Aws\Result batchGetDataQualityResult(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise batchGetDataQualityResultAsync(array $args = [])
+ * @method \Aws\Result batchGetDevEndpoints(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise batchGetDevEndpointsAsync(array $args = [])
+ * @method \Aws\Result batchGetIterableForms(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise batchGetIterableFormsAsync(array $args = [])
+ * @method \Aws\Result batchGetJobs(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise batchGetJobsAsync(array $args = [])
+ * @method \Aws\Result batchGetPartition(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise batchGetPartitionAsync(array $args = [])
+ * @method \Aws\Result batchGetTableOptimizer(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise batchGetTableOptimizerAsync(array $args = [])
+ * @method \Aws\Result batchGetTriggers(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise batchGetTriggersAsync(array $args = [])
+ * @method \Aws\Result batchGetWorkflows(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise batchGetWorkflowsAsync(array $args = [])
+ * @method \Aws\Result batchPutDataQualityStatisticAnnotation(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise batchPutDataQualityStatisticAnnotationAsync(array $args = [])
+ * @method \Aws\Result batchStopJobRun(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise batchStopJobRunAsync(array $args = [])
+ * @method \Aws\Result batchUpdatePartition(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise batchUpdatePartitionAsync(array $args = [])
+ * @method \Aws\Result cancelDataQualityRuleRecommendationRun(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise cancelDataQualityRuleRecommendationRunAsync(array $args = [])
+ * @method \Aws\Result cancelDataQualityRulesetEvaluationRun(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise cancelDataQualityRulesetEvaluationRunAsync(array $args = [])
+ * @method \Aws\Result cancelMLTaskRun(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise cancelMLTaskRunAsync(array $args = [])
+ * @method \Aws\Result cancelStatement(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise cancelStatementAsync(array $args = [])
+ * @method \Aws\Result checkSchemaVersionValidity(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise checkSchemaVersionValidityAsync(array $args = [])
+ * @method \Aws\Result createBlueprint(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createBlueprintAsync(array $args = [])
+ * @method \Aws\Result createCatalog(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createCatalogAsync(array $args = [])
+ * @method \Aws\Result createClassifier(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createClassifierAsync(array $args = [])
+ * @method \Aws\Result createColumnStatisticsTaskSettings(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createColumnStatisticsTaskSettingsAsync(array $args = [])
+ * @method \Aws\Result createConnection(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createConnectionAsync(array $args = [])
+ * @method \Aws\Result createCrawler(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createCrawlerAsync(array $args = [])
+ * @method \Aws\Result createCustomEntityType(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createCustomEntityTypeAsync(array $args = [])
+ * @method \Aws\Result createDataQualityRuleset(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createDataQualityRulesetAsync(array $args = [])
+ * @method \Aws\Result createDatabase(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createDatabaseAsync(array $args = [])
+ * @method \Aws\Result createDevEndpoint(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createDevEndpointAsync(array $args = [])
+ * @method \Aws\Result createGlossary(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createGlossaryAsync(array $args = [])
+ * @method \Aws\Result createGlossaryTerm(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createGlossaryTermAsync(array $args = [])
+ * @method \Aws\Result createGlueIdentityCenterConfiguration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createGlueIdentityCenterConfigurationAsync(array $args = [])
+ * @method \Aws\Result createIntegration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createIntegrationAsync(array $args = [])
+ * @method \Aws\Result createIntegrationResourceProperty(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createIntegrationResourcePropertyAsync(array $args = [])
+ * @method \Aws\Result createIntegrationTableProperties(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createIntegrationTablePropertiesAsync(array $args = [])
+ * @method \Aws\Result createJob(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createJobAsync(array $args = [])
+ * @method \Aws\Result createMLTransform(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createMLTransformAsync(array $args = [])
+ * @method \Aws\Result createPartition(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createPartitionAsync(array $args = [])
+ * @method \Aws\Result createPartitionIndex(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createPartitionIndexAsync(array $args = [])
+ * @method \Aws\Result createRegistry(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createRegistryAsync(array $args = [])
+ * @method \Aws\Result createSchema(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createSchemaAsync(array $args = [])
+ * @method \Aws\Result createScript(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createScriptAsync(array $args = [])
+ * @method \Aws\Result createSecurityConfiguration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createSecurityConfigurationAsync(array $args = [])
+ * @method \Aws\Result createSession(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createSessionAsync(array $args = [])
+ * @method \Aws\Result createTable(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createTableAsync(array $args = [])
+ * @method \Aws\Result createTableOptimizer(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createTableOptimizerAsync(array $args = [])
+ * @method \Aws\Result createTrigger(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createTriggerAsync(array $args = [])
+ * @method \Aws\Result createUsageProfile(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createUsageProfileAsync(array $args = [])
+ * @method \Aws\Result createUserDefinedFunction(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createUserDefinedFunctionAsync(array $args = [])
+ * @method \Aws\Result createWorkflow(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createWorkflowAsync(array $args = [])
+ * @method \Aws\Result deleteAsset(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteAssetAsync(array $args = [])
+ * @method \Aws\Result deleteAssetType(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteAssetTypeAsync(array $args = [])
+ * @method \Aws\Result deleteAttachment(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteAttachmentAsync(array $args = [])
+ * @method \Aws\Result deleteBlueprint(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteBlueprintAsync(array $args = [])
+ * @method \Aws\Result deleteCatalog(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteCatalogAsync(array $args = [])
+ * @method \Aws\Result deleteClassifier(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteClassifierAsync(array $args = [])
+ * @method \Aws\Result deleteColumnStatisticsForPartition(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteColumnStatisticsForPartitionAsync(array $args = [])
+ * @method \Aws\Result deleteColumnStatisticsForTable(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteColumnStatisticsForTableAsync(array $args = [])
+ * @method \Aws\Result deleteColumnStatisticsTaskSettings(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteColumnStatisticsTaskSettingsAsync(array $args = [])
+ * @method \Aws\Result deleteConnection(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteConnectionAsync(array $args = [])
+ * @method \Aws\Result deleteConnectionType(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteConnectionTypeAsync(array $args = [])
+ * @method \Aws\Result deleteCrawler(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteCrawlerAsync(array $args = [])
+ * @method \Aws\Result deleteCustomEntityType(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteCustomEntityTypeAsync(array $args = [])
+ * @method \Aws\Result deleteDataQualityRuleset(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteDataQualityRulesetAsync(array $args = [])
+ * @method \Aws\Result deleteDatabase(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteDatabaseAsync(array $args = [])
+ * @method \Aws\Result deleteDevEndpoint(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteDevEndpointAsync(array $args = [])
+ * @method \Aws\Result deleteFormType(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteFormTypeAsync(array $args = [])
+ * @method \Aws\Result deleteGlossary(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteGlossaryAsync(array $args = [])
+ * @method \Aws\Result deleteGlossaryTerm(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteGlossaryTermAsync(array $args = [])
+ * @method \Aws\Result deleteGlueIdentityCenterConfiguration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteGlueIdentityCenterConfigurationAsync(array $args = [])
+ * @method \Aws\Result deleteIntegration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteIntegrationAsync(array $args = [])
+ * @method \Aws\Result deleteIntegrationResourceProperty(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteIntegrationResourcePropertyAsync(array $args = [])
+ * @method \Aws\Result deleteIntegrationTableProperties(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteIntegrationTablePropertiesAsync(array $args = [])
+ * @method \Aws\Result deleteJob(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteJobAsync(array $args = [])
+ * @method \Aws\Result deleteMLTransform(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteMLTransformAsync(array $args = [])
+ * @method \Aws\Result deletePartition(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deletePartitionAsync(array $args = [])
+ * @method \Aws\Result deletePartitionIndex(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deletePartitionIndexAsync(array $args = [])
+ * @method \Aws\Result deleteRegistry(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteRegistryAsync(array $args = [])
+ * @method \Aws\Result deleteResourcePolicy(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteResourcePolicyAsync(array $args = [])
+ * @method \Aws\Result deleteSchema(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteSchemaAsync(array $args = [])
+ * @method \Aws\Result deleteSchemaVersions(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteSchemaVersionsAsync(array $args = [])
+ * @method \Aws\Result deleteSecurityConfiguration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteSecurityConfigurationAsync(array $args = [])
+ * @method \Aws\Result deleteSession(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteSessionAsync(array $args = [])
+ * @method \Aws\Result deleteTable(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteTableAsync(array $args = [])
+ * @method \Aws\Result deleteTableOptimizer(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteTableOptimizerAsync(array $args = [])
+ * @method \Aws\Result deleteTableVersion(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteTableVersionAsync(array $args = [])
+ * @method \Aws\Result deleteTrigger(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteTriggerAsync(array $args = [])
+ * @method \Aws\Result deleteUsageProfile(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteUsageProfileAsync(array $args = [])
+ * @method \Aws\Result deleteUserDefinedFunction(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteUserDefinedFunctionAsync(array $args = [])
+ * @method \Aws\Result deleteWorkflow(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteWorkflowAsync(array $args = [])
+ * @method \Aws\Result describeConnectionType(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeConnectionTypeAsync(array $args = [])
+ * @method \Aws\Result describeEntity(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeEntityAsync(array $args = [])
+ * @method \Aws\Result describeInboundIntegrations(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeInboundIntegrationsAsync(array $args = [])
+ * @method \Aws\Result describeIntegrations(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeIntegrationsAsync(array $args = [])
+ * @method \Aws\Result disassociateGlossaryTerms(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise disassociateGlossaryTermsAsync(array $args = [])
+ * @method \Aws\Result getAsset(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getAssetAsync(array $args = [])
+ * @method \Aws\Result getAssetType(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getAssetTypeAsync(array $args = [])
+ * @method \Aws\Result getBlueprint(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getBlueprintAsync(array $args = [])
+ * @method \Aws\Result getBlueprintRun(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getBlueprintRunAsync(array $args = [])
+ * @method \Aws\Result getBlueprintRuns(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getBlueprintRunsAsync(array $args = [])
+ * @method \Aws\Result getCatalog(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getCatalogAsync(array $args = [])
+ * @method \Aws\Result getCatalogImportStatus(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getCatalogImportStatusAsync(array $args = [])
+ * @method \Aws\Result getCatalogs(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getCatalogsAsync(array $args = [])
+ * @method \Aws\Result getClassifier(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getClassifierAsync(array $args = [])
+ * @method \Aws\Result getClassifiers(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getClassifiersAsync(array $args = [])
+ * @method \Aws\Result getColumnStatisticsForPartition(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getColumnStatisticsForPartitionAsync(array $args = [])
+ * @method \Aws\Result getColumnStatisticsForTable(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getColumnStatisticsForTableAsync(array $args = [])
+ * @method \Aws\Result getColumnStatisticsTaskRun(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getColumnStatisticsTaskRunAsync(array $args = [])
+ * @method \Aws\Result getColumnStatisticsTaskRuns(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getColumnStatisticsTaskRunsAsync(array $args = [])
+ * @method \Aws\Result getColumnStatisticsTaskSettings(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getColumnStatisticsTaskSettingsAsync(array $args = [])
+ * @method \Aws\Result getConnection(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getConnectionAsync(array $args = [])
+ * @method \Aws\Result getConnections(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getConnectionsAsync(array $args = [])
+ * @method \Aws\Result getCrawler(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getCrawlerAsync(array $args = [])
+ * @method \Aws\Result getCrawlerMetrics(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getCrawlerMetricsAsync(array $args = [])
+ * @method \Aws\Result getCrawlers(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getCrawlersAsync(array $args = [])
+ * @method \Aws\Result getCustomEntityType(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getCustomEntityTypeAsync(array $args = [])
+ * @method \Aws\Result getDashboardUrl(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getDashboardUrlAsync(array $args = [])
+ * @method \Aws\Result getDataCatalogEncryptionSettings(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getDataCatalogEncryptionSettingsAsync(array $args = [])
+ * @method \Aws\Result getDataQualityModel(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getDataQualityModelAsync(array $args = [])
+ * @method \Aws\Result getDataQualityModelResult(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getDataQualityModelResultAsync(array $args = [])
+ * @method \Aws\Result getDataQualityResult(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getDataQualityResultAsync(array $args = [])
+ * @method \Aws\Result getDataQualityRuleRecommendationRun(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getDataQualityRuleRecommendationRunAsync(array $args = [])
+ * @method \Aws\Result getDataQualityRuleset(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getDataQualityRulesetAsync(array $args = [])
+ * @method \Aws\Result getDataQualityRulesetEvaluationRun(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getDataQualityRulesetEvaluationRunAsync(array $args = [])
+ * @method \Aws\Result getDatabase(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getDatabaseAsync(array $args = [])
+ * @method \Aws\Result getDatabases(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getDatabasesAsync(array $args = [])
+ * @method \Aws\Result getDataflowGraph(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getDataflowGraphAsync(array $args = [])
+ * @method \Aws\Result getDevEndpoint(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getDevEndpointAsync(array $args = [])
+ * @method \Aws\Result getDevEndpoints(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getDevEndpointsAsync(array $args = [])
+ * @method \Aws\Result getEntityRecords(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getEntityRecordsAsync(array $args = [])
+ * @method \Aws\Result getFormType(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getFormTypeAsync(array $args = [])
+ * @method \Aws\Result getGlossary(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getGlossaryAsync(array $args = [])
+ * @method \Aws\Result getGlossaryTerm(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getGlossaryTermAsync(array $args = [])
+ * @method \Aws\Result getGlueIdentityCenterConfiguration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getGlueIdentityCenterConfigurationAsync(array $args = [])
+ * @method \Aws\Result getIntegrationResourceProperty(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getIntegrationResourcePropertyAsync(array $args = [])
+ * @method \Aws\Result getIntegrationTableProperties(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getIntegrationTablePropertiesAsync(array $args = [])
+ * @method \Aws\Result getJob(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getJobAsync(array $args = [])
+ * @method \Aws\Result getJobBookmark(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getJobBookmarkAsync(array $args = [])
+ * @method \Aws\Result getJobRun(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getJobRunAsync(array $args = [])
+ * @method \Aws\Result getJobRuns(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getJobRunsAsync(array $args = [])
+ * @method \Aws\Result getJobs(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getJobsAsync(array $args = [])
+ * @method \Aws\Result getMLTaskRun(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getMLTaskRunAsync(array $args = [])
+ * @method \Aws\Result getMLTaskRuns(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getMLTaskRunsAsync(array $args = [])
+ * @method \Aws\Result getMLTransform(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getMLTransformAsync(array $args = [])
+ * @method \Aws\Result getMLTransforms(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getMLTransformsAsync(array $args = [])
+ * @method \Aws\Result getMapping(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getMappingAsync(array $args = [])
+ * @method \Aws\Result getMaterializedViewRefreshTaskRun(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getMaterializedViewRefreshTaskRunAsync(array $args = [])
+ * @method \Aws\Result getPartition(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getPartitionAsync(array $args = [])
+ * @method \Aws\Result getPartitionIndexes(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getPartitionIndexesAsync(array $args = [])
+ * @method \Aws\Result getPartitions(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getPartitionsAsync(array $args = [])
+ * @method \Aws\Result getPlan(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getPlanAsync(array $args = [])
+ * @method \Aws\Result getRegistry(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getRegistryAsync(array $args = [])
+ * @method \Aws\Result getResourcePolicies(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getResourcePoliciesAsync(array $args = [])
+ * @method \Aws\Result getResourcePolicy(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getResourcePolicyAsync(array $args = [])
+ * @method \Aws\Result getSchema(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getSchemaAsync(array $args = [])
+ * @method \Aws\Result getSchemaByDefinition(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getSchemaByDefinitionAsync(array $args = [])
+ * @method \Aws\Result getSchemaVersion(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getSchemaVersionAsync(array $args = [])
+ * @method \Aws\Result getSchemaVersionsDiff(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getSchemaVersionsDiffAsync(array $args = [])
+ * @method \Aws\Result getSecurityConfiguration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getSecurityConfigurationAsync(array $args = [])
+ * @method \Aws\Result getSecurityConfigurations(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getSecurityConfigurationsAsync(array $args = [])
+ * @method \Aws\Result getSession(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getSessionAsync(array $args = [])
+ * @method \Aws\Result getSessionEndpoint(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getSessionEndpointAsync(array $args = [])
+ * @method \Aws\Result getStatement(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getStatementAsync(array $args = [])
+ * @method \Aws\Result getTable(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getTableAsync(array $args = [])
+ * @method \Aws\Result getTableOptimizer(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getTableOptimizerAsync(array $args = [])
+ * @method \Aws\Result getTableVersion(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getTableVersionAsync(array $args = [])
+ * @method \Aws\Result getTableVersions(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getTableVersionsAsync(array $args = [])
+ * @method \Aws\Result getTables(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getTablesAsync(array $args = [])
+ * @method \Aws\Result getTags(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getTagsAsync(array $args = [])
+ * @method \Aws\Result getTrigger(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getTriggerAsync(array $args = [])
+ * @method \Aws\Result getTriggers(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getTriggersAsync(array $args = [])
+ * @method \Aws\Result getUnfilteredPartitionMetadata(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getUnfilteredPartitionMetadataAsync(array $args = [])
+ * @method \Aws\Result getUnfilteredPartitionsMetadata(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getUnfilteredPartitionsMetadataAsync(array $args = [])
+ * @method \Aws\Result getUnfilteredTableMetadata(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getUnfilteredTableMetadataAsync(array $args = [])
+ * @method \Aws\Result getUsageProfile(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getUsageProfileAsync(array $args = [])
+ * @method \Aws\Result getUserDefinedFunction(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getUserDefinedFunctionAsync(array $args = [])
+ * @method \Aws\Result getUserDefinedFunctions(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getUserDefinedFunctionsAsync(array $args = [])
+ * @method \Aws\Result getWorkflow(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getWorkflowAsync(array $args = [])
+ * @method \Aws\Result getWorkflowRun(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getWorkflowRunAsync(array $args = [])
+ * @method \Aws\Result getWorkflowRunProperties(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getWorkflowRunPropertiesAsync(array $args = [])
+ * @method \Aws\Result getWorkflowRuns(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getWorkflowRunsAsync(array $args = [])
+ * @method \Aws\Result importCatalogToGlue(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise importCatalogToGlueAsync(array $args = [])
+ * @method \Aws\Result listAssetTypes(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listAssetTypesAsync(array $args = [])
+ * @method \Aws\Result listBlueprints(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listBlueprintsAsync(array $args = [])
+ * @method \Aws\Result listColumnStatisticsTaskRuns(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listColumnStatisticsTaskRunsAsync(array $args = [])
+ * @method \Aws\Result listConnectionTypes(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listConnectionTypesAsync(array $args = [])
+ * @method \Aws\Result listCrawlers(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listCrawlersAsync(array $args = [])
+ * @method \Aws\Result listCrawls(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listCrawlsAsync(array $args = [])
+ * @method \Aws\Result listCustomEntityTypes(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listCustomEntityTypesAsync(array $args = [])
+ * @method \Aws\Result listDataQualityResults(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listDataQualityResultsAsync(array $args = [])
+ * @method \Aws\Result listDataQualityRuleRecommendationRuns(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listDataQualityRuleRecommendationRunsAsync(array $args = [])
+ * @method \Aws\Result listDataQualityRulesetEvaluationRuns(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listDataQualityRulesetEvaluationRunsAsync(array $args = [])
+ * @method \Aws\Result listDataQualityRulesets(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listDataQualityRulesetsAsync(array $args = [])
+ * @method \Aws\Result listDataQualityStatisticAnnotations(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listDataQualityStatisticAnnotationsAsync(array $args = [])
+ * @method \Aws\Result listDataQualityStatistics(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listDataQualityStatisticsAsync(array $args = [])
+ * @method \Aws\Result listDevEndpoints(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listDevEndpointsAsync(array $args = [])
+ * @method \Aws\Result listEntities(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listEntitiesAsync(array $args = [])
+ * @method \Aws\Result listFormTypes(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listFormTypesAsync(array $args = [])
+ * @method \Aws\Result listGlossaries(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listGlossariesAsync(array $args = [])
+ * @method \Aws\Result listGlossaryTerms(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listGlossaryTermsAsync(array $args = [])
+ * @method \Aws\Result listIntegrationResourceProperties(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listIntegrationResourcePropertiesAsync(array $args = [])
+ * @method \Aws\Result listIterableForms(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listIterableFormsAsync(array $args = [])
+ * @method \Aws\Result listJobs(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listJobsAsync(array $args = [])
+ * @method \Aws\Result listMLTransforms(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listMLTransformsAsync(array $args = [])
+ * @method \Aws\Result listMaterializedViewRefreshTaskRuns(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listMaterializedViewRefreshTaskRunsAsync(array $args = [])
+ * @method \Aws\Result listRegistries(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listRegistriesAsync(array $args = [])
+ * @method \Aws\Result listSchemaVersions(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listSchemaVersionsAsync(array $args = [])
+ * @method \Aws\Result listSchemas(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listSchemasAsync(array $args = [])
+ * @method \Aws\Result listSessions(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listSessionsAsync(array $args = [])
+ * @method \Aws\Result listStatements(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listStatementsAsync(array $args = [])
+ * @method \Aws\Result listTableOptimizerRuns(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listTableOptimizerRunsAsync(array $args = [])
+ * @method \Aws\Result listTriggers(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listTriggersAsync(array $args = [])
+ * @method \Aws\Result listUsageProfiles(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listUsageProfilesAsync(array $args = [])
+ * @method \Aws\Result listWorkflows(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listWorkflowsAsync(array $args = [])
+ * @method \Aws\Result modifyIntegration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise modifyIntegrationAsync(array $args = [])
+ * @method \Aws\Result putAsset(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise putAssetAsync(array $args = [])
+ * @method \Aws\Result putAssetType(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise putAssetTypeAsync(array $args = [])
+ * @method \Aws\Result putAttachment(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise putAttachmentAsync(array $args = [])
+ * @method \Aws\Result putDataCatalogEncryptionSettings(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise putDataCatalogEncryptionSettingsAsync(array $args = [])
+ * @method \Aws\Result putDataQualityProfileAnnotation(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise putDataQualityProfileAnnotationAsync(array $args = [])
+ * @method \Aws\Result putFormType(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise putFormTypeAsync(array $args = [])
+ * @method \Aws\Result putResourcePolicy(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise putResourcePolicyAsync(array $args = [])
+ * @method \Aws\Result putSchemaVersionMetadata(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise putSchemaVersionMetadataAsync(array $args = [])
+ * @method \Aws\Result putWorkflowRunProperties(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise putWorkflowRunPropertiesAsync(array $args = [])
+ * @method \Aws\Result querySchemaVersionMetadata(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise querySchemaVersionMetadataAsync(array $args = [])
+ * @method \Aws\Result registerConnectionType(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise registerConnectionTypeAsync(array $args = [])
+ * @method \Aws\Result registerSchemaVersion(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise registerSchemaVersionAsync(array $args = [])
+ * @method \Aws\Result removeSchemaVersionMetadata(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise removeSchemaVersionMetadataAsync(array $args = [])
+ * @method \Aws\Result resetJobBookmark(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise resetJobBookmarkAsync(array $args = [])
+ * @method \Aws\Result resumeWorkflowRun(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise resumeWorkflowRunAsync(array $args = [])
+ * @method \Aws\Result runStatement(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise runStatementAsync(array $args = [])
+ * @method \Aws\Result searchAssets(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise searchAssetsAsync(array $args = [])
+ * @method \Aws\Result searchTables(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise searchTablesAsync(array $args = [])
+ * @method \Aws\Result startBlueprintRun(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise startBlueprintRunAsync(array $args = [])
+ * @method \Aws\Result startColumnStatisticsTaskRun(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise startColumnStatisticsTaskRunAsync(array $args = [])
+ * @method \Aws\Result startColumnStatisticsTaskRunSchedule(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise startColumnStatisticsTaskRunScheduleAsync(array $args = [])
+ * @method \Aws\Result startCrawler(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise startCrawlerAsync(array $args = [])
+ * @method \Aws\Result startCrawlerSchedule(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise startCrawlerScheduleAsync(array $args = [])
+ * @method \Aws\Result startDataQualityRuleRecommendationRun(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise startDataQualityRuleRecommendationRunAsync(array $args = [])
+ * @method \Aws\Result startDataQualityRulesetEvaluationRun(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise startDataQualityRulesetEvaluationRunAsync(array $args = [])
+ * @method \Aws\Result startExportLabelsTaskRun(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise startExportLabelsTaskRunAsync(array $args = [])
+ * @method \Aws\Result startImportLabelsTaskRun(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise startImportLabelsTaskRunAsync(array $args = [])
+ * @method \Aws\Result startJobRun(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise startJobRunAsync(array $args = [])
+ * @method \Aws\Result startMLEvaluationTaskRun(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise startMLEvaluationTaskRunAsync(array $args = [])
+ * @method \Aws\Result startMLLabelingSetGenerationTaskRun(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise startMLLabelingSetGenerationTaskRunAsync(array $args = [])
+ * @method \Aws\Result startMaterializedViewRefreshTaskRun(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise startMaterializedViewRefreshTaskRunAsync(array $args = [])
+ * @method \Aws\Result startTrigger(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise startTriggerAsync(array $args = [])
+ * @method \Aws\Result startWorkflowRun(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise startWorkflowRunAsync(array $args = [])
+ * @method \Aws\Result stopColumnStatisticsTaskRun(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise stopColumnStatisticsTaskRunAsync(array $args = [])
+ * @method \Aws\Result stopColumnStatisticsTaskRunSchedule(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise stopColumnStatisticsTaskRunScheduleAsync(array $args = [])
+ * @method \Aws\Result stopCrawler(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise stopCrawlerAsync(array $args = [])
+ * @method \Aws\Result stopCrawlerSchedule(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise stopCrawlerScheduleAsync(array $args = [])
+ * @method \Aws\Result stopMaterializedViewRefreshTaskRun(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise stopMaterializedViewRefreshTaskRunAsync(array $args = [])
+ * @method \Aws\Result stopSession(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise stopSessionAsync(array $args = [])
+ * @method \Aws\Result stopTrigger(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise stopTriggerAsync(array $args = [])
+ * @method \Aws\Result stopWorkflowRun(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise stopWorkflowRunAsync(array $args = [])
+ * @method \Aws\Result tagResource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise tagResourceAsync(array $args = [])
+ * @method \Aws\Result testConnection(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise testConnectionAsync(array $args = [])
+ * @method \Aws\Result untagResource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise untagResourceAsync(array $args = [])
+ * @method \Aws\Result updateAsset(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateAssetAsync(array $args = [])
+ * @method \Aws\Result updateBlueprint(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateBlueprintAsync(array $args = [])
+ * @method \Aws\Result updateCatalog(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateCatalogAsync(array $args = [])
+ * @method \Aws\Result updateClassifier(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateClassifierAsync(array $args = [])
+ * @method \Aws\Result updateColumnStatisticsForPartition(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateColumnStatisticsForPartitionAsync(array $args = [])
+ * @method \Aws\Result updateColumnStatisticsForTable(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateColumnStatisticsForTableAsync(array $args = [])
+ * @method \Aws\Result updateColumnStatisticsTaskSettings(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateColumnStatisticsTaskSettingsAsync(array $args = [])
+ * @method \Aws\Result updateConnection(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateConnectionAsync(array $args = [])
+ * @method \Aws\Result updateCrawler(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateCrawlerAsync(array $args = [])
+ * @method \Aws\Result updateCrawlerSchedule(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateCrawlerScheduleAsync(array $args = [])
+ * @method \Aws\Result updateDataQualityRuleset(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateDataQualityRulesetAsync(array $args = [])
+ * @method \Aws\Result updateDatabase(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateDatabaseAsync(array $args = [])
+ * @method \Aws\Result updateDevEndpoint(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateDevEndpointAsync(array $args = [])
+ * @method \Aws\Result updateGlossary(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateGlossaryAsync(array $args = [])
+ * @method \Aws\Result updateGlossaryTerm(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateGlossaryTermAsync(array $args = [])
+ * @method \Aws\Result updateGlueIdentityCenterConfiguration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateGlueIdentityCenterConfigurationAsync(array $args = [])
+ * @method \Aws\Result updateIntegrationResourceProperty(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateIntegrationResourcePropertyAsync(array $args = [])
+ * @method \Aws\Result updateIntegrationTableProperties(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateIntegrationTablePropertiesAsync(array $args = [])
+ * @method \Aws\Result updateJob(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateJobAsync(array $args = [])
+ * @method \Aws\Result updateJobFromSourceControl(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateJobFromSourceControlAsync(array $args = [])
+ * @method \Aws\Result updateMLTransform(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateMLTransformAsync(array $args = [])
+ * @method \Aws\Result updatePartition(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updatePartitionAsync(array $args = [])
+ * @method \Aws\Result updateRegistry(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateRegistryAsync(array $args = [])
+ * @method \Aws\Result updateSchema(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateSchemaAsync(array $args = [])
+ * @method \Aws\Result updateSourceControlFromJob(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateSourceControlFromJobAsync(array $args = [])
+ * @method \Aws\Result updateTable(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateTableAsync(array $args = [])
+ * @method \Aws\Result updateTableOptimizer(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateTableOptimizerAsync(array $args = [])
+ * @method \Aws\Result updateTrigger(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateTriggerAsync(array $args = [])
+ * @method \Aws\Result updateUsageProfile(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateUsageProfileAsync(array $args = [])
+ * @method \Aws\Result updateUserDefinedFunction(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateUserDefinedFunctionAsync(array $args = [])
+ * @method \Aws\Result updateWorkflow(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateWorkflowAsync(array $args = [])
+ */
+class GlueClient extends AwsClient {}

+ 189 - 0
upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/GuardDuty/GuardDutyClient.php

@@ -0,0 +1,189 @@
+<?php
+namespace Aws\GuardDuty;
+
+use Aws\AwsClient;
+
+/**
+ * This client is used to interact with the **Amazon GuardDuty** service.
+ * @method \Aws\Result acceptAdministratorInvitation(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise acceptAdministratorInvitationAsync(array $args = [])
+ * @method \Aws\Result acceptInvitation(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise acceptInvitationAsync(array $args = [])
+ * @method \Aws\Result archiveFindings(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise archiveFindingsAsync(array $args = [])
+ * @method \Aws\Result createDetector(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createDetectorAsync(array $args = [])
+ * @method \Aws\Result createFilter(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createFilterAsync(array $args = [])
+ * @method \Aws\Result createIPSet(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createIPSetAsync(array $args = [])
+ * @method \Aws\Result createInvestigation(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createInvestigationAsync(array $args = [])
+ * @method \Aws\Result createMalwareProtectionPlan(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createMalwareProtectionPlanAsync(array $args = [])
+ * @method \Aws\Result createMembers(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createMembersAsync(array $args = [])
+ * @method \Aws\Result createPublishingDestination(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createPublishingDestinationAsync(array $args = [])
+ * @method \Aws\Result createSampleFindings(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createSampleFindingsAsync(array $args = [])
+ * @method \Aws\Result createThreatEntitySet(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createThreatEntitySetAsync(array $args = [])
+ * @method \Aws\Result createThreatIntelSet(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createThreatIntelSetAsync(array $args = [])
+ * @method \Aws\Result createTrustedEntitySet(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createTrustedEntitySetAsync(array $args = [])
+ * @method \Aws\Result declineInvitations(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise declineInvitationsAsync(array $args = [])
+ * @method \Aws\Result deleteDetector(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteDetectorAsync(array $args = [])
+ * @method \Aws\Result deleteFilter(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteFilterAsync(array $args = [])
+ * @method \Aws\Result deleteIPSet(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteIPSetAsync(array $args = [])
+ * @method \Aws\Result deleteInvitations(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteInvitationsAsync(array $args = [])
+ * @method \Aws\Result deleteMalwareProtectionPlan(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteMalwareProtectionPlanAsync(array $args = [])
+ * @method \Aws\Result deleteMembers(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteMembersAsync(array $args = [])
+ * @method \Aws\Result deletePublishingDestination(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deletePublishingDestinationAsync(array $args = [])
+ * @method \Aws\Result deleteThreatEntitySet(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteThreatEntitySetAsync(array $args = [])
+ * @method \Aws\Result deleteThreatIntelSet(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteThreatIntelSetAsync(array $args = [])
+ * @method \Aws\Result deleteTrustedEntitySet(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteTrustedEntitySetAsync(array $args = [])
+ * @method \Aws\Result describeMalwareScans(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeMalwareScansAsync(array $args = [])
+ * @method \Aws\Result describeOrganizationConfiguration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeOrganizationConfigurationAsync(array $args = [])
+ * @method \Aws\Result describePublishingDestination(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describePublishingDestinationAsync(array $args = [])
+ * @method \Aws\Result disableOrganizationAdminAccount(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise disableOrganizationAdminAccountAsync(array $args = [])
+ * @method \Aws\Result disassociateFromAdministratorAccount(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise disassociateFromAdministratorAccountAsync(array $args = [])
+ * @method \Aws\Result disassociateFromMasterAccount(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise disassociateFromMasterAccountAsync(array $args = [])
+ * @method \Aws\Result disassociateMembers(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise disassociateMembersAsync(array $args = [])
+ * @method \Aws\Result enableOrganizationAdminAccount(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise enableOrganizationAdminAccountAsync(array $args = [])
+ * @method \Aws\Result getAdministratorAccount(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getAdministratorAccountAsync(array $args = [])
+ * @method \Aws\Result getCoverageStatistics(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getCoverageStatisticsAsync(array $args = [])
+ * @method \Aws\Result getDetector(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getDetectorAsync(array $args = [])
+ * @method \Aws\Result getFilter(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getFilterAsync(array $args = [])
+ * @method \Aws\Result getFindings(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getFindingsAsync(array $args = [])
+ * @method \Aws\Result getFindingsStatistics(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getFindingsStatisticsAsync(array $args = [])
+ * @method \Aws\Result getIPSet(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getIPSetAsync(array $args = [])
+ * @method \Aws\Result getInvestigation(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getInvestigationAsync(array $args = [])
+ * @method \Aws\Result getInvitationsCount(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getInvitationsCountAsync(array $args = [])
+ * @method \Aws\Result getMalwareProtectionPlan(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getMalwareProtectionPlanAsync(array $args = [])
+ * @method \Aws\Result getMalwareScan(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getMalwareScanAsync(array $args = [])
+ * @method \Aws\Result getMalwareScanSettings(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getMalwareScanSettingsAsync(array $args = [])
+ * @method \Aws\Result getMasterAccount(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getMasterAccountAsync(array $args = [])
+ * @method \Aws\Result getMemberDetectors(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getMemberDetectorsAsync(array $args = [])
+ * @method \Aws\Result getMembers(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getMembersAsync(array $args = [])
+ * @method \Aws\Result getOrganizationStatistics(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getOrganizationStatisticsAsync(array $args = [])
+ * @method \Aws\Result getRemainingFreeTrialDays(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getRemainingFreeTrialDaysAsync(array $args = [])
+ * @method \Aws\Result getThreatEntitySet(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getThreatEntitySetAsync(array $args = [])
+ * @method \Aws\Result getThreatIntelSet(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getThreatIntelSetAsync(array $args = [])
+ * @method \Aws\Result getTrustedEntitySet(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getTrustedEntitySetAsync(array $args = [])
+ * @method \Aws\Result getUsageStatistics(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getUsageStatisticsAsync(array $args = [])
+ * @method \Aws\Result inviteMembers(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise inviteMembersAsync(array $args = [])
+ * @method \Aws\Result listCoverage(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listCoverageAsync(array $args = [])
+ * @method \Aws\Result listDetectors(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listDetectorsAsync(array $args = [])
+ * @method \Aws\Result listFilters(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listFiltersAsync(array $args = [])
+ * @method \Aws\Result listFindings(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listFindingsAsync(array $args = [])
+ * @method \Aws\Result listIPSets(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listIPSetsAsync(array $args = [])
+ * @method \Aws\Result listInvestigations(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listInvestigationsAsync(array $args = [])
+ * @method \Aws\Result listInvitations(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listInvitationsAsync(array $args = [])
+ * @method \Aws\Result listMalwareProtectionPlans(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listMalwareProtectionPlansAsync(array $args = [])
+ * @method \Aws\Result listMalwareScans(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listMalwareScansAsync(array $args = [])
+ * @method \Aws\Result listMembers(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listMembersAsync(array $args = [])
+ * @method \Aws\Result listOrganizationAdminAccounts(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listOrganizationAdminAccountsAsync(array $args = [])
+ * @method \Aws\Result listPublishingDestinations(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listPublishingDestinationsAsync(array $args = [])
+ * @method \Aws\Result listTagsForResource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listTagsForResourceAsync(array $args = [])
+ * @method \Aws\Result listThreatEntitySets(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listThreatEntitySetsAsync(array $args = [])
+ * @method \Aws\Result listThreatIntelSets(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listThreatIntelSetsAsync(array $args = [])
+ * @method \Aws\Result listTrustedEntitySets(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listTrustedEntitySetsAsync(array $args = [])
+ * @method \Aws\Result sendObjectMalwareScan(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise sendObjectMalwareScanAsync(array $args = [])
+ * @method \Aws\Result startMalwareScan(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise startMalwareScanAsync(array $args = [])
+ * @method \Aws\Result startMonitoringMembers(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise startMonitoringMembersAsync(array $args = [])
+ * @method \Aws\Result stopMonitoringMembers(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise stopMonitoringMembersAsync(array $args = [])
+ * @method \Aws\Result tagResource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise tagResourceAsync(array $args = [])
+ * @method \Aws\Result unarchiveFindings(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise unarchiveFindingsAsync(array $args = [])
+ * @method \Aws\Result untagResource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise untagResourceAsync(array $args = [])
+ * @method \Aws\Result updateDetector(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateDetectorAsync(array $args = [])
+ * @method \Aws\Result updateFilter(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateFilterAsync(array $args = [])
+ * @method \Aws\Result updateFindingsFeedback(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateFindingsFeedbackAsync(array $args = [])
+ * @method \Aws\Result updateIPSet(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateIPSetAsync(array $args = [])
+ * @method \Aws\Result updateMalwareProtectionPlan(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateMalwareProtectionPlanAsync(array $args = [])
+ * @method \Aws\Result updateMalwareScanSettings(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateMalwareScanSettingsAsync(array $args = [])
+ * @method \Aws\Result updateMemberDetectors(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateMemberDetectorsAsync(array $args = [])
+ * @method \Aws\Result updateOrganizationConfiguration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateOrganizationConfigurationAsync(array $args = [])
+ * @method \Aws\Result updatePublishingDestination(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updatePublishingDestinationAsync(array $args = [])
+ * @method \Aws\Result updateThreatEntitySet(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateThreatEntitySetAsync(array $args = [])
+ * @method \Aws\Result updateThreatIntelSet(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateThreatIntelSetAsync(array $args = [])
+ * @method \Aws\Result updateTrustedEntitySet(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateTrustedEntitySetAsync(array $args = [])
+ */
+class GuardDutyClient extends AwsClient {}

+ 59 - 0
upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/HealthLake/HealthLakeClient.php

@@ -0,0 +1,59 @@
+<?php
+namespace Aws\HealthLake;
+
+use Aws\AwsClient;
+
+/**
+ * This client is used to interact with the **Amazon HealthLake** service.
+ * @method \Aws\Result createDataTransformationProfile(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createDataTransformationProfileAsync(array $args = [])
+ * @method \Aws\Result createFHIRDatastore(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createFHIRDatastoreAsync(array $args = [])
+ * @method \Aws\Result deleteDataTransformationProfile(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteDataTransformationProfileAsync(array $args = [])
+ * @method \Aws\Result deleteFHIRDatastore(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteFHIRDatastoreAsync(array $args = [])
+ * @method \Aws\Result describeDataTransformationJob(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeDataTransformationJobAsync(array $args = [])
+ * @method \Aws\Result describeFHIRDatastore(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeFHIRDatastoreAsync(array $args = [])
+ * @method \Aws\Result describeFHIRExportJob(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeFHIRExportJobAsync(array $args = [])
+ * @method \Aws\Result describeFHIRImportJob(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeFHIRImportJobAsync(array $args = [])
+ * @method \Aws\Result getDataTransformationProfile(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getDataTransformationProfileAsync(array $args = [])
+ * @method \Aws\Result listDataTransformationJobs(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listDataTransformationJobsAsync(array $args = [])
+ * @method \Aws\Result listDataTransformationProfileVersions(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listDataTransformationProfileVersionsAsync(array $args = [])
+ * @method \Aws\Result listDataTransformationProfiles(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listDataTransformationProfilesAsync(array $args = [])
+ * @method \Aws\Result listFHIRDatastores(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listFHIRDatastoresAsync(array $args = [])
+ * @method \Aws\Result listFHIRExportJobs(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listFHIRExportJobsAsync(array $args = [])
+ * @method \Aws\Result listFHIRImportJobs(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listFHIRImportJobsAsync(array $args = [])
+ * @method \Aws\Result listTagsForResource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listTagsForResourceAsync(array $args = [])
+ * @method \Aws\Result publishDataTransformationProfile(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise publishDataTransformationProfileAsync(array $args = [])
+ * @method \Aws\Result startDataTransformationJob(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise startDataTransformationJobAsync(array $args = [])
+ * @method \Aws\Result startFHIRExportJob(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise startFHIRExportJobAsync(array $args = [])
+ * @method \Aws\Result startFHIRImportJob(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise startFHIRImportJobAsync(array $args = [])
+ * @method \Aws\Result tagResource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise tagResourceAsync(array $args = [])
+ * @method \Aws\Result untagResource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise untagResourceAsync(array $args = [])
+ * @method \Aws\Result updateDataTransformationProfile(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateDataTransformationProfileAsync(array $args = [])
+ * @method \Aws\Result updateFHIRDatastore(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateFHIRDatastoreAsync(array $args = [])
+ * @method \Aws\Result updateProfileWithAgent(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateProfileWithAgentAsync(array $args = [])
+ */
+class HealthLakeClient extends AwsClient {}

+ 91 - 0
upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/IVS/IVSClient.php

@@ -0,0 +1,91 @@
+<?php
+namespace Aws\IVS;
+
+use Aws\AwsClient;
+
+/**
+ * This client is used to interact with the **Amazon Interactive Video Service** service.
+ * @method \Aws\Result batchGetChannel(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise batchGetChannelAsync(array $args = [])
+ * @method \Aws\Result batchGetStreamKey(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise batchGetStreamKeyAsync(array $args = [])
+ * @method \Aws\Result batchStartViewerSessionRevocation(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise batchStartViewerSessionRevocationAsync(array $args = [])
+ * @method \Aws\Result createAdConfiguration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createAdConfigurationAsync(array $args = [])
+ * @method \Aws\Result createChannel(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createChannelAsync(array $args = [])
+ * @method \Aws\Result createPlaybackRestrictionPolicy(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createPlaybackRestrictionPolicyAsync(array $args = [])
+ * @method \Aws\Result createRecordingConfiguration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createRecordingConfigurationAsync(array $args = [])
+ * @method \Aws\Result createStreamKey(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createStreamKeyAsync(array $args = [])
+ * @method \Aws\Result deleteAdConfiguration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteAdConfigurationAsync(array $args = [])
+ * @method \Aws\Result deleteChannel(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteChannelAsync(array $args = [])
+ * @method \Aws\Result deletePlaybackKeyPair(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deletePlaybackKeyPairAsync(array $args = [])
+ * @method \Aws\Result deletePlaybackRestrictionPolicy(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deletePlaybackRestrictionPolicyAsync(array $args = [])
+ * @method \Aws\Result deleteRecordingConfiguration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteRecordingConfigurationAsync(array $args = [])
+ * @method \Aws\Result deleteStreamKey(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteStreamKeyAsync(array $args = [])
+ * @method \Aws\Result getAdConfiguration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getAdConfigurationAsync(array $args = [])
+ * @method \Aws\Result getChannel(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getChannelAsync(array $args = [])
+ * @method \Aws\Result getPlaybackKeyPair(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getPlaybackKeyPairAsync(array $args = [])
+ * @method \Aws\Result getPlaybackRestrictionPolicy(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getPlaybackRestrictionPolicyAsync(array $args = [])
+ * @method \Aws\Result getRecordingConfiguration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getRecordingConfigurationAsync(array $args = [])
+ * @method \Aws\Result getStream(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getStreamAsync(array $args = [])
+ * @method \Aws\Result getStreamKey(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getStreamKeyAsync(array $args = [])
+ * @method \Aws\Result getStreamSession(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getStreamSessionAsync(array $args = [])
+ * @method \Aws\Result importPlaybackKeyPair(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise importPlaybackKeyPairAsync(array $args = [])
+ * @method \Aws\Result insertAdBreak(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise insertAdBreakAsync(array $args = [])
+ * @method \Aws\Result listAdConfigurations(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listAdConfigurationsAsync(array $args = [])
+ * @method \Aws\Result listChannels(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listChannelsAsync(array $args = [])
+ * @method \Aws\Result listPlaybackKeyPairs(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listPlaybackKeyPairsAsync(array $args = [])
+ * @method \Aws\Result listPlaybackRestrictionPolicies(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listPlaybackRestrictionPoliciesAsync(array $args = [])
+ * @method \Aws\Result listRecordingConfigurations(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listRecordingConfigurationsAsync(array $args = [])
+ * @method \Aws\Result listStreamKeys(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listStreamKeysAsync(array $args = [])
+ * @method \Aws\Result listStreamSessions(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listStreamSessionsAsync(array $args = [])
+ * @method \Aws\Result listStreams(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listStreamsAsync(array $args = [])
+ * @method \Aws\Result listTagsForResource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listTagsForResourceAsync(array $args = [])
+ * @method \Aws\Result putMetadata(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise putMetadataAsync(array $args = [])
+ * @method \Aws\Result startViewerSessionRevocation(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise startViewerSessionRevocationAsync(array $args = [])
+ * @method \Aws\Result stopStream(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise stopStreamAsync(array $args = [])
+ * @method \Aws\Result tagResource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise tagResourceAsync(array $args = [])
+ * @method \Aws\Result untagResource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise untagResourceAsync(array $args = [])
+ * @method \Aws\Result updateAdConfiguration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateAdConfigurationAsync(array $args = [])
+ * @method \Aws\Result updateChannel(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateChannelAsync(array $args = [])
+ * @method \Aws\Result updatePlaybackRestrictionPolicy(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updatePlaybackRestrictionPolicyAsync(array $args = [])
+ */
+class IVSClient extends AwsClient {}

+ 171 - 0
upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/Inspector2/Inspector2Client.php

@@ -0,0 +1,171 @@
+<?php
+namespace Aws\Inspector2;
+
+use Aws\AwsClient;
+
+/**
+ * This client is used to interact with the **Inspector2** service.
+ * @method \Aws\Result associateMember(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise associateMemberAsync(array $args = [])
+ * @method \Aws\Result batchAssociateCodeSecurityScanConfiguration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise batchAssociateCodeSecurityScanConfigurationAsync(array $args = [])
+ * @method \Aws\Result batchDisassociateCodeSecurityScanConfiguration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise batchDisassociateCodeSecurityScanConfigurationAsync(array $args = [])
+ * @method \Aws\Result batchGetAccountStatus(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise batchGetAccountStatusAsync(array $args = [])
+ * @method \Aws\Result batchGetCodeSnippet(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise batchGetCodeSnippetAsync(array $args = [])
+ * @method \Aws\Result batchGetFindingDetails(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise batchGetFindingDetailsAsync(array $args = [])
+ * @method \Aws\Result batchGetFreeTrialInfo(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise batchGetFreeTrialInfoAsync(array $args = [])
+ * @method \Aws\Result batchGetMemberEc2DeepInspectionStatus(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise batchGetMemberEc2DeepInspectionStatusAsync(array $args = [])
+ * @method \Aws\Result batchUpdateMemberEc2DeepInspectionStatus(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise batchUpdateMemberEc2DeepInspectionStatusAsync(array $args = [])
+ * @method \Aws\Result cancelFindingsReport(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise cancelFindingsReportAsync(array $args = [])
+ * @method \Aws\Result cancelSbomExport(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise cancelSbomExportAsync(array $args = [])
+ * @method \Aws\Result createCisScanConfiguration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createCisScanConfigurationAsync(array $args = [])
+ * @method \Aws\Result createCodeSecurityIntegration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createCodeSecurityIntegrationAsync(array $args = [])
+ * @method \Aws\Result createCodeSecurityScanConfiguration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createCodeSecurityScanConfigurationAsync(array $args = [])
+ * @method \Aws\Result createConnector(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createConnectorAsync(array $args = [])
+ * @method \Aws\Result createFilter(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createFilterAsync(array $args = [])
+ * @method \Aws\Result createFindingsReport(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createFindingsReportAsync(array $args = [])
+ * @method \Aws\Result createSbomExport(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createSbomExportAsync(array $args = [])
+ * @method \Aws\Result deleteCisScanConfiguration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteCisScanConfigurationAsync(array $args = [])
+ * @method \Aws\Result deleteCodeSecurityIntegration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteCodeSecurityIntegrationAsync(array $args = [])
+ * @method \Aws\Result deleteCodeSecurityScanConfiguration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteCodeSecurityScanConfigurationAsync(array $args = [])
+ * @method \Aws\Result deleteConnector(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteConnectorAsync(array $args = [])
+ * @method \Aws\Result deleteFilter(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteFilterAsync(array $args = [])
+ * @method \Aws\Result describeOrganizationConfiguration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeOrganizationConfigurationAsync(array $args = [])
+ * @method \Aws\Result disable(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise disableAsync(array $args = [])
+ * @method \Aws\Result disableDelegatedAdminAccount(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise disableDelegatedAdminAccountAsync(array $args = [])
+ * @method \Aws\Result disassociateMember(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise disassociateMemberAsync(array $args = [])
+ * @method \Aws\Result enable(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise enableAsync(array $args = [])
+ * @method \Aws\Result enableDelegatedAdminAccount(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise enableDelegatedAdminAccountAsync(array $args = [])
+ * @method \Aws\Result getCisScanReport(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getCisScanReportAsync(array $args = [])
+ * @method \Aws\Result getCisScanResultDetails(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getCisScanResultDetailsAsync(array $args = [])
+ * @method \Aws\Result getClustersForImage(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getClustersForImageAsync(array $args = [])
+ * @method \Aws\Result getCodeSecurityIntegration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getCodeSecurityIntegrationAsync(array $args = [])
+ * @method \Aws\Result getCodeSecurityScan(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getCodeSecurityScanAsync(array $args = [])
+ * @method \Aws\Result getCodeSecurityScanConfiguration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getCodeSecurityScanConfigurationAsync(array $args = [])
+ * @method \Aws\Result getConfiguration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getConfigurationAsync(array $args = [])
+ * @method \Aws\Result getDelegatedAdminAccount(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getDelegatedAdminAccountAsync(array $args = [])
+ * @method \Aws\Result getEc2DeepInspectionConfiguration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getEc2DeepInspectionConfigurationAsync(array $args = [])
+ * @method \Aws\Result getEncryptionKey(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getEncryptionKeyAsync(array $args = [])
+ * @method \Aws\Result getFindingsReportStatus(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getFindingsReportStatusAsync(array $args = [])
+ * @method \Aws\Result getMember(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getMemberAsync(array $args = [])
+ * @method \Aws\Result getSbomExport(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getSbomExportAsync(array $args = [])
+ * @method \Aws\Result listAccountPermissions(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listAccountPermissionsAsync(array $args = [])
+ * @method \Aws\Result listCisScanConfigurations(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listCisScanConfigurationsAsync(array $args = [])
+ * @method \Aws\Result listCisScanResultsAggregatedByChecks(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listCisScanResultsAggregatedByChecksAsync(array $args = [])
+ * @method \Aws\Result listCisScanResultsAggregatedByTargetResource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listCisScanResultsAggregatedByTargetResourceAsync(array $args = [])
+ * @method \Aws\Result listCisScans(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listCisScansAsync(array $args = [])
+ * @method \Aws\Result listCodeSecurityIntegrations(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listCodeSecurityIntegrationsAsync(array $args = [])
+ * @method \Aws\Result listCodeSecurityScanConfigurationAssociations(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listCodeSecurityScanConfigurationAssociationsAsync(array $args = [])
+ * @method \Aws\Result listCodeSecurityScanConfigurations(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listCodeSecurityScanConfigurationsAsync(array $args = [])
+ * @method \Aws\Result listConnectorScanConfigurations(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listConnectorScanConfigurationsAsync(array $args = [])
+ * @method \Aws\Result listConnectors(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listConnectorsAsync(array $args = [])
+ * @method \Aws\Result listCoverage(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listCoverageAsync(array $args = [])
+ * @method \Aws\Result listCoverageStatistics(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listCoverageStatisticsAsync(array $args = [])
+ * @method \Aws\Result listDelegatedAdminAccounts(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listDelegatedAdminAccountsAsync(array $args = [])
+ * @method \Aws\Result listFilters(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listFiltersAsync(array $args = [])
+ * @method \Aws\Result listFindingAggregations(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listFindingAggregationsAsync(array $args = [])
+ * @method \Aws\Result listFindings(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listFindingsAsync(array $args = [])
+ * @method \Aws\Result listMembers(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listMembersAsync(array $args = [])
+ * @method \Aws\Result listTagsForResource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listTagsForResourceAsync(array $args = [])
+ * @method \Aws\Result listUsageTotals(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listUsageTotalsAsync(array $args = [])
+ * @method \Aws\Result resetEncryptionKey(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise resetEncryptionKeyAsync(array $args = [])
+ * @method \Aws\Result searchVulnerabilities(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise searchVulnerabilitiesAsync(array $args = [])
+ * @method \Aws\Result sendCisSessionHealth(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise sendCisSessionHealthAsync(array $args = [])
+ * @method \Aws\Result sendCisSessionTelemetry(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise sendCisSessionTelemetryAsync(array $args = [])
+ * @method \Aws\Result startCisSession(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise startCisSessionAsync(array $args = [])
+ * @method \Aws\Result startCodeSecurityScan(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise startCodeSecurityScanAsync(array $args = [])
+ * @method \Aws\Result stopCisSession(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise stopCisSessionAsync(array $args = [])
+ * @method \Aws\Result tagResource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise tagResourceAsync(array $args = [])
+ * @method \Aws\Result untagResource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise untagResourceAsync(array $args = [])
+ * @method \Aws\Result updateCisScanConfiguration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateCisScanConfigurationAsync(array $args = [])
+ * @method \Aws\Result updateCodeSecurityIntegration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateCodeSecurityIntegrationAsync(array $args = [])
+ * @method \Aws\Result updateCodeSecurityScanConfiguration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateCodeSecurityScanConfigurationAsync(array $args = [])
+ * @method \Aws\Result updateConfiguration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateConfigurationAsync(array $args = [])
+ * @method \Aws\Result updateConnector(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateConnectorAsync(array $args = [])
+ * @method \Aws\Result updateConnectorScanConfiguration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateConnectorScanConfigurationAsync(array $args = [])
+ * @method \Aws\Result updateEc2DeepInspectionConfiguration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateEc2DeepInspectionConfigurationAsync(array $args = [])
+ * @method \Aws\Result updateEncryptionKey(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateEncryptionKeyAsync(array $args = [])
+ * @method \Aws\Result updateFilter(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateFilterAsync(array $args = [])
+ * @method \Aws\Result updateOrgEc2DeepInspectionConfiguration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateOrgEc2DeepInspectionConfigurationAsync(array $args = [])
+ * @method \Aws\Result updateOrganizationConfiguration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateOrganizationConfigurationAsync(array $args = [])
+ */
+class Inspector2Client extends AwsClient {}

+ 32 - 0
upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/IotDataPlane/IotDataPlaneClient.php

@@ -0,0 +1,32 @@
+<?php
+namespace Aws\IotDataPlane;
+
+use Aws\AwsClient;
+
+/**
+ * This client is used to interact with the **AWS IoT Data Plane** service.
+ *
+ * @method \Aws\Result deleteConnection(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteConnectionAsync(array $args = [])
+ * @method \Aws\Result deleteThingShadow(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteThingShadowAsync(array $args = [])
+ * @method \Aws\Result getConnection(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getConnectionAsync(array $args = [])
+ * @method \Aws\Result getRetainedMessage(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getRetainedMessageAsync(array $args = [])
+ * @method \Aws\Result getThingShadow(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getThingShadowAsync(array $args = [])
+ * @method \Aws\Result listNamedShadowsForThing(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listNamedShadowsForThingAsync(array $args = [])
+ * @method \Aws\Result listRetainedMessages(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listRetainedMessagesAsync(array $args = [])
+ * @method \Aws\Result listSubscriptions(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listSubscriptionsAsync(array $args = [])
+ * @method \Aws\Result publish(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise publishAsync(array $args = [])
+ * @method \Aws\Result sendDirectMessage(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise sendDirectMessageAsync(array $args = [])
+ * @method \Aws\Result updateThingShadow(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateThingShadowAsync(array $args = [])
+ */
+class IotDataPlaneClient extends AwsClient {}

+ 9 - 0
upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/LambdaCore/Exception/LambdaCoreException.php

@@ -0,0 +1,9 @@
+<?php
+namespace Aws\LambdaCore\Exception;
+
+use Aws\Exception\AwsException;
+
+/**
+ * Represents an error interacting with the **AWS Lambda Core** service.
+ */
+class LambdaCoreException extends AwsException {}

+ 19 - 0
upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/LambdaCore/LambdaCoreClient.php

@@ -0,0 +1,19 @@
+<?php
+namespace Aws\LambdaCore;
+
+use Aws\AwsClient;
+
+/**
+ * This client is used to interact with the **AWS Lambda Core** service.
+ * @method \Aws\Result createNetworkConnector(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createNetworkConnectorAsync(array $args = [])
+ * @method \Aws\Result deleteNetworkConnector(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteNetworkConnectorAsync(array $args = [])
+ * @method \Aws\Result getNetworkConnector(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getNetworkConnectorAsync(array $args = [])
+ * @method \Aws\Result listNetworkConnectors(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listNetworkConnectorsAsync(array $args = [])
+ * @method \Aws\Result updateNetworkConnector(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateNetworkConnectorAsync(array $args = [])
+ */
+class LambdaCoreClient extends AwsClient {}

+ 9 - 0
upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/LambdaMicrovms/Exception/LambdaMicrovmsException.php

@@ -0,0 +1,9 @@
+<?php
+namespace Aws\LambdaMicrovms\Exception;
+
+use Aws\Exception\AwsException;
+
+/**
+ * Represents an error interacting with the **Lambda MicroVMs** service.
+ */
+class LambdaMicrovmsException extends AwsException {}

+ 57 - 0
upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/LambdaMicrovms/LambdaMicrovmsClient.php

@@ -0,0 +1,57 @@
+<?php
+namespace Aws\LambdaMicrovms;
+
+use Aws\AwsClient;
+
+/**
+ * This client is used to interact with the **Lambda MicroVMs** service.
+ * @method \Aws\Result createMicrovmAuthToken(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createMicrovmAuthTokenAsync(array $args = [])
+ * @method \Aws\Result createMicrovmImage(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createMicrovmImageAsync(array $args = [])
+ * @method \Aws\Result createMicrovmShellAuthToken(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createMicrovmShellAuthTokenAsync(array $args = [])
+ * @method \Aws\Result deleteMicrovmImage(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteMicrovmImageAsync(array $args = [])
+ * @method \Aws\Result deleteMicrovmImageVersion(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteMicrovmImageVersionAsync(array $args = [])
+ * @method \Aws\Result getMicrovm(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getMicrovmAsync(array $args = [])
+ * @method \Aws\Result getMicrovmImage(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getMicrovmImageAsync(array $args = [])
+ * @method \Aws\Result getMicrovmImageBuild(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getMicrovmImageBuildAsync(array $args = [])
+ * @method \Aws\Result getMicrovmImageVersion(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getMicrovmImageVersionAsync(array $args = [])
+ * @method \Aws\Result listManagedMicrovmImageVersions(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listManagedMicrovmImageVersionsAsync(array $args = [])
+ * @method \Aws\Result listManagedMicrovmImages(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listManagedMicrovmImagesAsync(array $args = [])
+ * @method \Aws\Result listMicrovmImageBuilds(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listMicrovmImageBuildsAsync(array $args = [])
+ * @method \Aws\Result listMicrovmImageVersions(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listMicrovmImageVersionsAsync(array $args = [])
+ * @method \Aws\Result listMicrovmImages(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listMicrovmImagesAsync(array $args = [])
+ * @method \Aws\Result listMicrovms(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listMicrovmsAsync(array $args = [])
+ * @method \Aws\Result listTags(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listTagsAsync(array $args = [])
+ * @method \Aws\Result resumeMicrovm(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise resumeMicrovmAsync(array $args = [])
+ * @method \Aws\Result runMicrovm(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise runMicrovmAsync(array $args = [])
+ * @method \Aws\Result suspendMicrovm(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise suspendMicrovmAsync(array $args = [])
+ * @method \Aws\Result tagResource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise tagResourceAsync(array $args = [])
+ * @method \Aws\Result terminateMicrovm(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise terminateMicrovmAsync(array $args = [])
+ * @method \Aws\Result untagResource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise untagResourceAsync(array $args = [])
+ * @method \Aws\Result updateMicrovmImage(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateMicrovmImageAsync(array $args = [])
+ * @method \Aws\Result updateMicrovmImageVersion(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateMicrovmImageVersionAsync(array $args = [])
+ */
+class LambdaMicrovmsClient extends AwsClient {}

+ 59 - 0
upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/MQ/MQClient.php

@@ -0,0 +1,59 @@
+<?php
+namespace Aws\MQ;
+
+use Aws\AwsClient;
+
+/**
+ * This client is used to interact with the **AmazonMQ** service.
+ * @method \Aws\Result createBroker(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createBrokerAsync(array $args = [])
+ * @method \Aws\Result createConfiguration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createConfigurationAsync(array $args = [])
+ * @method \Aws\Result createTags(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createTagsAsync(array $args = [])
+ * @method \Aws\Result createUser(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createUserAsync(array $args = [])
+ * @method \Aws\Result deleteBroker(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteBrokerAsync(array $args = [])
+ * @method \Aws\Result deleteConfiguration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteConfigurationAsync(array $args = [])
+ * @method \Aws\Result deleteTags(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteTagsAsync(array $args = [])
+ * @method \Aws\Result deleteUser(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteUserAsync(array $args = [])
+ * @method \Aws\Result describeBroker(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeBrokerAsync(array $args = [])
+ * @method \Aws\Result describeBrokerEngineTypes(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeBrokerEngineTypesAsync(array $args = [])
+ * @method \Aws\Result describeBrokerInstanceOptions(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeBrokerInstanceOptionsAsync(array $args = [])
+ * @method \Aws\Result describeConfiguration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeConfigurationAsync(array $args = [])
+ * @method \Aws\Result describeConfigurationRevision(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeConfigurationRevisionAsync(array $args = [])
+ * @method \Aws\Result describeSharedResources(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeSharedResourcesAsync(array $args = [])
+ * @method \Aws\Result describeUser(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeUserAsync(array $args = [])
+ * @method \Aws\Result listBrokers(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listBrokersAsync(array $args = [])
+ * @method \Aws\Result listConfigurationRevisions(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listConfigurationRevisionsAsync(array $args = [])
+ * @method \Aws\Result listConfigurations(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listConfigurationsAsync(array $args = [])
+ * @method \Aws\Result listTags(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listTagsAsync(array $args = [])
+ * @method \Aws\Result listUsers(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listUsersAsync(array $args = [])
+ * @method \Aws\Result promote(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise promoteAsync(array $args = [])
+ * @method \Aws\Result rebootBroker(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise rebootBrokerAsync(array $args = [])
+ * @method \Aws\Result updateBroker(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateBrokerAsync(array $args = [])
+ * @method \Aws\Result updateConfiguration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateConfigurationAsync(array $args = [])
+ * @method \Aws\Result updateUser(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateUserAsync(array $args = [])
+ */
+class MQClient extends AwsClient {}

+ 473 - 0
upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/Middleware.php

@@ -0,0 +1,473 @@
+<?php
+namespace Aws;
+
+use Aws\Api\Service;
+use Aws\Api\Validator;
+use Aws\Credentials\CredentialsInterface;
+use Aws\EndpointV2\EndpointProviderV2;
+use Aws\Exception\AwsException;
+use Aws\Signature\DpopSignature;
+use Aws\Signature\S3ExpressSignature;
+use Aws\Token\TokenAuthorization;
+use Aws\Token\TokenInterface;
+use GuzzleHttp\Promise;
+use GuzzleHttp\Psr7;
+use GuzzleHttp\Psr7\LazyOpenStream;
+use Psr\Http\Message\RequestInterface;
+
+final class Middleware
+{
+    /**
+     * Middleware used to allow a command parameter (e.g., "SourceFile") to
+     * be used to specify the source of data for an upload operation.
+     *
+     * @param Service $api
+     * @param string  $bodyParameter
+     * @param string  $sourceParameter
+     *
+     * @return callable
+     */
+    public static function sourceFile(
+        Service $api,
+        $bodyParameter = 'Body',
+        $sourceParameter = 'SourceFile'
+    ) {
+        return function (callable $handler) use (
+            $api,
+            $bodyParameter,
+            $sourceParameter
+        ) {
+            return function (
+                CommandInterface $command,
+                ?RequestInterface $request = null)
+            use (
+                $handler,
+                $api,
+                $bodyParameter,
+                $sourceParameter
+            ) {
+                $operation = $api->getOperation($command->getName());
+                $source = $command[$sourceParameter];
+
+                if ($source !== null
+                    && $operation->getInput()->hasMember($bodyParameter)
+                ) {
+                    $lazyOpenStream = new LazyOpenStream($source, 'r');
+                    $command[$bodyParameter] = $lazyOpenStream;
+                    unset($command[$sourceParameter]);
+
+                    $next = $handler($command, $request);
+                    // To avoid failures in some tests cases
+                    if ($next !== null && method_exists($next, 'then')) {
+                        return $next->then(
+                            function ($result) use ($lazyOpenStream) {
+                                // To make sure the resource is closed.
+                                $lazyOpenStream->close();
+
+                                return $result;
+                            }
+                        )->otherwise(function (\Throwable $e) use ($lazyOpenStream) {
+                            $lazyOpenStream->close();
+
+                            throw $e;
+                        });
+                    }
+
+                    return $next;
+                }
+
+                return $handler($command, $request);
+            };
+        };
+    }
+
+    /**
+     * Adds a middleware that uses client-side validation.
+     *
+     * @param Service $api API being accessed.
+     *
+     * @return callable
+     */
+    public static function validation(Service $api, ?Validator $validator = null)
+    {
+        $validator = $validator ?: new Validator();
+        if ($api->isModifiedModel()) {
+            $api = new Service(
+                $api->getDefinition(),
+                $api->getProvider()
+            );
+        }
+        return function (callable $handler) use ($api, $validator) {
+            return function (
+                CommandInterface $command,
+                ?RequestInterface $request = null
+            ) use ($api, $validator, $handler) {
+                $operation = $api->getOperation($command->getName());
+                $validator->validate(
+                    $command->getName(),
+                    $operation->getInput(),
+                    $command->toArray()
+                );
+                return $handler($command, $request);
+            };
+        };
+    }
+
+    /**
+     * Builds an HTTP request for a command.
+     *
+     * @param callable $serializer Function used to serialize a request for a
+     *                             command.
+     * @param EndpointProviderV2 | null $endpointProvider
+     * @param array $providerArgs
+     * @return callable
+     */
+    public static function requestBuilder($serializer)
+    {
+        return function (callable $handler) use ($serializer) {
+            return function (CommandInterface $command, $endpoint = null) use ($serializer, $handler) {
+                return $handler($command, $serializer($command, $endpoint));
+            };
+        };
+    }
+
+    /**
+     * Creates a middleware that signs requests for a command.
+     *
+     * @param callable $credProvider      Credentials provider function that
+     *                                    returns a promise that is resolved
+     *                                    with a CredentialsInterface object.
+     * @param callable $signatureFunction Function that accepts a Command
+     *                                    object and returns a
+     *                                    SignatureInterface.
+     *
+     * @return callable
+     */
+    public static function signer(
+        callable $credProvider,
+        callable $signatureFunction,
+        $tokenProvider = null,
+        $config = []
+    ) {
+        return function (callable $handler) use ($signatureFunction, $credProvider, $tokenProvider, $config) {
+            return function (
+                CommandInterface $command,
+                RequestInterface $request
+            ) use ($handler, $signatureFunction, $credProvider, $tokenProvider, $config) {
+                $signer = $signatureFunction($command);
+
+                // Token authorization path
+                if ($signer instanceof TokenAuthorization) {
+                    return $tokenProvider()->then(function (TokenInterface $token) use ($handler, $command, $signer, $request) {
+                        $command->getMetricsBuilder()->identifyMetricByValueAndAppend('token', $token);
+                        return $handler($command, $signer->authorizeRequest($request, $token));
+                    });
+                }
+
+                // DPoP path
+                if ($signer instanceof DpopSignature) {
+                    if (empty($key = $command['dpopKey'])
+                        || !($key instanceof \OpenSSLAsymmetricKey)
+                    ) {
+                        throw new \RuntimeException(
+                            'A valid DPoP key must be present for DPoP signatures'
+                        );
+                    }
+
+                    return $handler($command, $signer->signRequest($request, $key));
+                }
+
+                // Credential signing path
+                $credentialPromise = ($signer instanceof S3ExpressSignature)
+                    ? $config['s3_express_identity_provider']($command)
+                    : $credProvider();
+
+                return $credentialPromise->then(function (CredentialsInterface $creds) use ($handler,
+                    $command,
+                    $signer,
+                    $request
+                ) {
+                    $command->getMetricsBuilder()->identifyMetricByValueAndAppend('credentials', $creds);
+                    return $handler($command, $signer->signRequest($request, $creds));
+                });
+            };
+        };
+    }
+
+    /**
+     * Creates a middleware that invokes a callback at a given step.
+     *
+     * The tap callback accepts a CommandInterface and RequestInterface as
+     * arguments but is not expected to return a new value or proxy to
+     * downstream middleware. It's simply a way to "tap" into the handler chain
+     * to debug or get an intermediate value.
+     *
+     * @param callable $fn Tap function
+     *
+     * @return callable
+     */
+    public static function tap(callable $fn)
+    {
+        return function (callable $handler) use ($fn) {
+            return function (
+                CommandInterface $command,
+                ?RequestInterface $request = null
+            ) use ($handler, $fn) {
+                $fn($command, $request);
+                return $handler($command, $request);
+            };
+        };
+    }
+
+    /**
+     * Middleware wrapper function that retries requests based on the boolean
+     * result of invoking the provided "decider" function.
+     *
+     * If no delay function is provided, a simple implementation of exponential
+     * backoff will be utilized.
+     *
+     * @param callable $decider Function that accepts the number of retries,
+     *                          a request, [result], and [exception] and
+     *                          returns true if the command is to be retried.
+     * @param callable $delay   Function that accepts the number of retries and
+     *                          returns the number of milliseconds to delay.
+     * @param bool $stats       Whether to collect statistics on retries and the
+     *                          associated delay.
+     *
+     * @return callable
+     */
+    public static function retry(
+        ?callable $decider = null,
+        ?callable $delay = null,
+        $stats = false
+    ) {
+        $decider = $decider ?: RetryMiddleware::createDefaultDecider();
+        $delay = $delay ?: [RetryMiddleware::class, 'exponentialDelay'];
+
+        return function (callable $handler) use ($decider, $delay, $stats) {
+            return new RetryMiddleware($decider, $delay, $handler, $stats);
+        };
+    }
+    /**
+     * Middleware wrapper function that adds an invocation id header to
+     * requests, which is only applied after the build step.
+     *
+     * This is a uniquely generated UUID to identify initial and subsequent
+     * retries as part of a complete request lifecycle.
+     *
+     * @return callable
+     */
+    public static function invocationId()
+    {
+        return function (callable $handler) {
+            return function (
+                CommandInterface $command,
+                RequestInterface $request
+            ) use ($handler){
+                return $handler($command, $request->withHeader(
+                    'aws-sdk-invocation-id',
+                    md5(uniqid(gethostname(), true))
+                ));
+            };
+        };
+    }
+    /**
+     * Middleware wrapper function that adds a Content-Type header to requests.
+     * This is only done when the Content-Type has not already been set, and the
+     * request body's URI is available. It then checks the file extension of the
+     * URI to determine the mime-type.
+     *
+     * @param array $operations Operations that Content-Type should be added to.
+     *
+     * @return callable
+     */
+    public static function contentType(array $operations)
+    {
+        return function (callable $handler) use ($operations) {
+            return function (
+                CommandInterface $command,
+                ?RequestInterface $request = null
+            ) use ($handler, $operations) {
+                if (!$request->hasHeader('Content-Type')
+                    && in_array($command->getName(), $operations, true)
+                    && ($uri = $request->getBody()->getMetadata('uri'))
+                ) {
+                    $request = $request->withHeader(
+                        'Content-Type',
+                        Psr7\MimeType::fromFilename($uri) ?: 'application/octet-stream'
+                    );
+                }
+
+                return $handler($command, $request);
+            };
+        };
+    }
+    /**
+     * Middleware wrapper function that adds a trace id header to requests
+     * from clients instantiated in supported Lambda runtime environments.
+     *
+     * The purpose for this header is to track and stop Lambda functions
+     * from being recursively invoked due to misconfigured resources.
+     *
+     * @return callable
+     */
+    public static function recursionDetection()
+    {
+        return function (callable $handler) {
+            return function (
+                CommandInterface $command,
+                RequestInterface $request
+            ) use ($handler){
+                $isLambda = getenv('AWS_LAMBDA_FUNCTION_NAME');
+                $traceId = str_replace('\e', '\x1b', getenv('_X_AMZN_TRACE_ID'));
+
+                if ($isLambda && $traceId) {
+                    if (!$request->hasHeader('X-Amzn-Trace-Id')) {
+                        $ignoreChars = ['=', ';', ':', '+', '&', '[', ']', '{', '}', '"', '\'', ','];
+                        $traceIdEncoded = rawurlencode(stripcslashes($traceId));
+
+                        foreach($ignoreChars as $char) {
+                            $encodedChar = rawurlencode($char);
+                            $traceIdEncoded = str_replace($encodedChar, $char,  $traceIdEncoded);
+                        }
+
+                        return $handler($command, $request->withHeader(
+                            'X-Amzn-Trace-Id',
+                            $traceIdEncoded
+                        ));
+                    }
+                }
+                return $handler($command, $request);
+            };
+        };
+    }
+    /**
+     * Tracks command and request history using a history container.
+     *
+     * This is useful for testing.
+     *
+     * @param History $history History container to store entries.
+     *
+     * @return callable
+     */
+    public static function history(History $history)
+    {
+        return function (callable $handler) use ($history) {
+            return function (
+                CommandInterface $command,
+                ?RequestInterface $request = null
+            ) use ($handler, $history) {
+                $ticket = $history->start($command, $request);
+                return $handler($command, $request)
+                    ->then(
+                        function ($result) use ($history, $ticket) {
+                            $history->finish($ticket, $result);
+                            return $result;
+                        },
+                        function ($reason) use ($history, $ticket) {
+                            $history->finish($ticket, $reason);
+                            return Promise\Create::rejectionFor($reason);
+                        }
+                    );
+            };
+        };
+    }
+
+    /**
+     * Creates a middleware that applies a map function to requests as they
+     * pass through the middleware.
+     *
+     * @param callable $f Map function that accepts a RequestInterface and
+     *                    returns a RequestInterface.
+     *
+     * @return callable
+     */
+    public static function mapRequest(callable $f)
+    {
+        return static function (callable $handler) use ($f) {
+            return static function (
+                CommandInterface $command,
+                ?RequestInterface $request = null
+            ) use ($handler, $f) {
+                return $handler($command, $f($request));
+            };
+        };
+    }
+
+    /**
+     * Creates a middleware that applies a map function to commands as they
+     * pass through the middleware.
+     *
+     * @param callable $f Map function that accepts a command and returns a
+     *                    command.
+     *
+     * @return callable
+     */
+    public static function mapCommand(callable $f)
+    {
+        return function (callable $handler) use ($f) {
+            return function (
+                CommandInterface $command,
+                ?RequestInterface $request = null
+            ) use ($handler, $f) {
+                return $handler($f($command), $request);
+            };
+        };
+    }
+
+    /**
+     * Creates a middleware that applies a map function to results.
+     *
+     * @param callable $f Map function that accepts an Aws\ResultInterface and
+     *                    returns an Aws\ResultInterface.
+     *
+     * @return callable
+     */
+    public static function mapResult(callable $f)
+    {
+        return function (callable $handler) use ($f) {
+            return function (
+                CommandInterface $command,
+                ?RequestInterface $request = null
+            ) use ($handler, $f) {
+                return $handler($command, $request)->then($f);
+            };
+        };
+    }
+
+    public static function timer()
+    {
+        return function (callable $handler) {
+            return function (
+                CommandInterface $command,
+                ?RequestInterface $request = null
+            ) use ($handler) {
+                $start = microtime(true);
+                return $handler($command, $request)
+                    ->then(
+                        function (ResultInterface $res) use ($start) {
+                            if (!isset($res['@metadata'])) {
+                                $res['@metadata'] = [];
+                            }
+                            if (!isset($res['@metadata']['transferStats'])) {
+                                $res['@metadata']['transferStats'] = [];
+                            }
+
+                            $res['@metadata']['transferStats']['total_time']
+                                = microtime(true) - $start;
+
+                            return $res;
+                        },
+                        function ($err) use ($start) {
+                            if ($err instanceof AwsException) {
+                                $err->setTransferInfo([
+                                    'total_time' => microtime(true) - $start,
+                                ] + $err->getTransferInfo());
+                            }
+                            return Promise\Create::rejectionFor($err);
+                        }
+                    );
+            };
+        };
+    }
+}

+ 157 - 0
upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/Multipart/AbstractUploader.php

@@ -0,0 +1,157 @@
+<?php
+namespace Aws\Multipart;
+
+use Aws\AwsClientInterface as Client;
+use Aws\Exception\AwsException;
+use GuzzleHttp\Psr7;
+use InvalidArgumentException as IAE;
+use Psr\Http\Message\StreamInterface as Stream;
+
+abstract class AbstractUploader extends AbstractUploadManager
+{
+    /** @var Stream Source of the data to be uploaded. */
+    protected $source;
+
+    /** @var bool Configuration used to indicate if upload progress will be displayed. */
+    protected $displayProgress;
+
+    /**
+     * @param Client $client
+     * @param mixed  $source
+     * @param array  $config
+     */
+    public function __construct(Client $client, $source, array $config = [])
+    {
+        $this->source = $this->determineSource($source);
+        parent::__construct($client, $config);
+    }
+
+    /**
+     * Create a stream for a part that starts at the current position and
+     * has a length of the upload part size (or less with the final part).
+     *
+     * @param Stream $stream
+     *
+     * @return Psr7\LimitStream
+     */
+    protected function limitPartStream(Stream $stream)
+    {
+        // Limit what is read from the stream to the part size.
+        return new Psr7\LimitStream(
+            $stream,
+            $this->state->getPartSize(),
+            $this->source->tell()
+        );
+    }
+
+    protected function getUploadCommands(callable $resultHandler)
+    {
+        // Determine if the source can be seeked.
+        $seekable = $this->source->isSeekable()
+            && $this->source->getMetadata('wrapper_type') === 'plainfile';
+
+        for ($partNumber = 1; $this->isEof($seekable); $partNumber++) {
+            // If we haven't already uploaded this part, yield a new part.
+            if (!$this->state->hasPartBeenUploaded($partNumber)) {
+                $partStartPos = $this->source->tell();
+                if (!($data = $this->createPart($seekable, $partNumber))) {
+                    break;
+                }
+                $command = $this->client->getCommand(
+                    $this->info['command']['upload'],
+                    $data + $this->state->getId()
+                );
+                $command->getHandlerList()->appendSign($resultHandler, 'mup');
+                $numberOfParts = $this->getNumberOfParts($this->state->getPartSize());
+                if (isset($numberOfParts) && $partNumber > $numberOfParts) {
+                    throw new $this->config['exception_class'](
+                        $this->state,
+                        new AwsException(
+                            "Maximum part number for this job exceeded, file has likely been corrupted." .
+                            "  Please restart this upload.",
+                            $command
+                        )
+                    );
+                }
+
+                yield $command;
+                if ($this->source->tell() > $partStartPos) {
+                    continue;
+                }
+            }
+
+            // Advance the source's offset if not already advanced.
+            if ($seekable) {
+                $this->source->seek(min(
+                    $this->source->tell() + $this->state->getPartSize(),
+                    $this->source->getSize()
+                ));
+            } else {
+                $this->source->read($this->state->getPartSize());
+            }
+        }
+    }
+
+    /**
+     * Generates the parameters for an upload part by analyzing a range of the
+     * source starting from the current offset up to the part size.
+     *
+     * @param bool $seekable
+     * @param int  $number
+     *
+     * @return array|null
+     */
+    abstract protected function createPart($seekable, $number);
+
+    /**
+     * Checks if the source is at EOF.
+     *
+     * @param bool $seekable
+     *
+     * @return bool
+     */
+    private function isEof($seekable)
+    {
+        return $seekable
+            ? $this->source->tell() < $this->source->getSize()
+            : !$this->source->eof();
+    }
+
+    /**
+     * Turns the provided source into a stream and stores it.
+     *
+     * If a string is provided, it is assumed to be a filename, otherwise, it
+     * passes the value directly to `Psr7\Utils::streamFor()`.
+     *
+     * @param mixed $source
+     *
+     * @return Stream
+     */
+    private function determineSource($source)
+    {
+        // Use the contents of a file as the data source.
+        if (is_string($source)) {
+            $source = Psr7\Utils::tryFopen($source, 'r');
+            $stream = Psr7\Utils::streamFor($source);
+        } elseif (is_resource($source)) {
+            // User-owned resource — don't fclose on destruct.
+            $stream = \Aws\detach_on_close_stream(Psr7\Utils::streamFor($source));
+        } else {
+            $stream = Psr7\Utils::streamFor($source);
+        }
+
+        if (!$stream->isReadable()) {
+            throw new IAE('Source stream must be readable.');
+        }
+
+        return $stream;
+    }
+
+    protected function getNumberOfParts($partSize)
+    {
+        if ($sourceSize = $this->source->getSize()) {
+            return ceil($sourceSize/$partSize);
+        }
+        return null;
+    }
+}

+ 237 - 0
upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/Multipart/UploadState.php

@@ -0,0 +1,237 @@
+<?php
+namespace Aws\Multipart;
+
+/**
+ * Representation of the multipart upload.
+ *
+ * This object keeps track of the state of the upload, including the status and
+ * which parts have been uploaded.
+ */
+class UploadState
+{
+    const CREATED = 0;
+    const INITIATED = 1;
+    const COMPLETED = 2;
+    const PROGRESS_THRESHOLD_SIZE = 8;
+
+    private $progressBar = [
+        "Transfer initiated...\n|                    | 0.0%\n",
+        "|==                  | 12.5%\n",
+        "|=====               | 25.0%\n",
+        "|=======             | 37.5%\n",
+        "|==========          | 50.0%\n",
+        "|============        | 62.5%\n",
+        "|===============     | 75.0%\n",
+        "|=================   | 87.5%\n",
+        "|====================| 100.0%\nTransfer complete!\n"
+    ];
+
+    /** @var array Params used to identity the upload. */
+    private $id;
+
+    /** @var int Part size being used by the upload. */
+    private $partSize;
+
+    /** @var array Parts that have been uploaded. */
+    private $uploadedParts = [];
+
+    /** @var int Identifies the status the upload. */
+    private $status = self::CREATED;
+
+    /** @var array Thresholds for progress of the upload. */
+    private $progressThresholds = [];
+
+    /** @var boolean Determines status for tracking the upload */
+    private $displayProgress = false;
+
+    /**
+     * @var array Subset of upload-manager config retained for resume flows.
+     *
+     * Carries the original caller's directives (`metadata_directive`,
+     * `tags_directive`, `annotations_directive`) so a later
+     * `getStateFromService(...) → new MultipartCopy(['state' => $s])` can
+     * replay Phase 3 correctly without the caller having to re-specify.
+     */
+    private array $config = [];
+
+    /**
+     * @param array $id Params used to identity the upload.
+     */
+    public function __construct(array $id, array $config = [])
+    {
+        $this->id = $id;
+        $this->config = $config;
+
+        if (isset($config['display_progress'])
+            && is_bool($config['display_progress'])
+        ) {
+            $this->displayProgress = $config['display_progress'];
+        }
+    }
+
+    /**
+     * @return array The config array the state was constructed with.
+     */
+    public function getConfig(): array
+    {
+        return $this->config;
+    }
+
+    /**
+     * Get the upload's ID, which is a tuple of parameters that can uniquely
+     * identify the upload.
+     *
+     * @return array
+     */
+    public function getId()
+    {
+        return $this->id;
+    }
+
+    /**
+     * Sets the "upload_id", or 3rd part of the upload's ID. This typically
+     * only needs to be done after initiating an upload.
+     *
+     * @param string $key   The param key of the upload_id.
+     * @param string $value The param value of the upload_id.
+     */
+    public function setUploadId($key, $value)
+    {
+        $this->id[$key] = $value;
+    }
+
+    /**
+     * Get the part size.
+     *
+     * @return int
+     */
+    public function getPartSize()
+    {
+        return $this->partSize;
+    }
+
+    /**
+     * Set the part size.
+     *
+     * @param $partSize int Size of upload parts.
+     */
+    public function setPartSize($partSize)
+    {
+        $this->partSize = $partSize;
+    }
+
+    /**
+     * Sets the 1/8th thresholds array. $totalSize is only sent if
+     * 'track_upload' is true.
+     *
+     * @param $totalSize numeric Size of object to upload.
+     *
+     * @return array
+     */
+    public function setProgressThresholds($totalSize): array
+    {
+        if(!is_numeric($totalSize)) {
+            throw new \InvalidArgumentException(
+                'The total size of the upload must be a number.'
+            );
+        }
+
+        $this->progressThresholds[0] = 0;
+        for ($i = 1; $i <= self::PROGRESS_THRESHOLD_SIZE; $i++) {
+            $this->progressThresholds[] = round(
+                $totalSize * ($i / self::PROGRESS_THRESHOLD_SIZE)
+            );
+        }
+
+        return $this->progressThresholds;
+    }
+
+    /**
+     * Prints progress of upload.
+     *
+     * @param $totalUploaded numeric Size of upload so far.
+     */
+    public function getDisplayProgress($totalUploaded): void
+    {
+        if (!is_numeric($totalUploaded)) {
+            throw new \InvalidArgumentException(
+                'The size of the bytes being uploaded must be a number.'
+            );
+        }
+
+        if ($this->displayProgress) {
+            while (!empty($this->progressBar)
+                && $totalUploaded >= $this->progressThresholds[0]
+            ) {
+                echo array_shift($this->progressBar);
+                array_shift($this->progressThresholds);
+            }
+        }
+    }
+
+    /**
+     * Marks a part as being uploaded.
+     *
+     * @param int   $partNumber The part number.
+     * @param array $partData   Data from the upload operation that needs to be
+     *                          recalled during the complete operation.
+     */
+    public function markPartAsUploaded($partNumber, array $partData = [])
+    {
+        $this->uploadedParts[$partNumber] = $partData;
+    }
+
+    /**
+     * Returns whether a part has been uploaded.
+     *
+     * @param int $partNumber The part number.
+     *
+     * @return bool
+     */
+    public function hasPartBeenUploaded($partNumber)
+    {
+        return isset($this->uploadedParts[$partNumber]);
+    }
+
+    /**
+     * Returns a sorted list of all the uploaded parts.
+     *
+     * @return array
+     */
+    public function getUploadedParts()
+    {
+        ksort($this->uploadedParts);
+        return $this->uploadedParts;
+    }
+
+    /**
+     * Set the status of the upload.
+     *
+     * @param int $status Status is an integer code defined by the constants
+     *                    CREATED, INITIATED, and COMPLETED on this class.
+     */
+    public function setStatus($status)
+    {
+        $this->status = $status;
+    }
+
+    /**
+     * Determines whether the upload state is in the INITIATED status.
+     *
+     * @return bool
+     */
+    public function isInitiated()
+    {
+        return $this->status === self::INITIATED;
+    }
+
+    /**
+     * Determines whether the upload state is in the COMPLETED status.
+     *
+     * @return bool
+     */
+    public function isCompleted()
+    {
+        return $this->status === self::COMPLETED;
+    }
+}

+ 177 - 0
upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/NetworkFirewall/NetworkFirewallClient.php

@@ -0,0 +1,177 @@
+<?php
+namespace Aws\NetworkFirewall;
+
+use Aws\AwsClient;
+
+/**
+ * This client is used to interact with the **AWS Network Firewall** service.
+ * @method \Aws\Result acceptNetworkFirewallTransitGatewayAttachment(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise acceptNetworkFirewallTransitGatewayAttachmentAsync(array $args = [])
+ * @method \Aws\Result associateAvailabilityZones(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise associateAvailabilityZonesAsync(array $args = [])
+ * @method \Aws\Result associateFirewallPolicy(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise associateFirewallPolicyAsync(array $args = [])
+ * @method \Aws\Result associateSubnets(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise associateSubnetsAsync(array $args = [])
+ * @method \Aws\Result attachRuleGroupsToProxyConfiguration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise attachRuleGroupsToProxyConfigurationAsync(array $args = [])
+ * @method \Aws\Result createContainerAssociation(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createContainerAssociationAsync(array $args = [])
+ * @method \Aws\Result createFirewall(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createFirewallAsync(array $args = [])
+ * @method \Aws\Result createFirewallPolicy(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createFirewallPolicyAsync(array $args = [])
+ * @method \Aws\Result createProxy(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createProxyAsync(array $args = [])
+ * @method \Aws\Result createProxyConfiguration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createProxyConfigurationAsync(array $args = [])
+ * @method \Aws\Result createProxyRuleGroup(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createProxyRuleGroupAsync(array $args = [])
+ * @method \Aws\Result createProxyRules(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createProxyRulesAsync(array $args = [])
+ * @method \Aws\Result createRuleGroup(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createRuleGroupAsync(array $args = [])
+ * @method \Aws\Result createTLSInspectionConfiguration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createTLSInspectionConfigurationAsync(array $args = [])
+ * @method \Aws\Result createVpcEndpointAssociation(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createVpcEndpointAssociationAsync(array $args = [])
+ * @method \Aws\Result deleteContainerAssociation(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteContainerAssociationAsync(array $args = [])
+ * @method \Aws\Result deleteFirewall(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteFirewallAsync(array $args = [])
+ * @method \Aws\Result deleteFirewallPolicy(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteFirewallPolicyAsync(array $args = [])
+ * @method \Aws\Result deleteNetworkFirewallTransitGatewayAttachment(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteNetworkFirewallTransitGatewayAttachmentAsync(array $args = [])
+ * @method \Aws\Result deleteProxy(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteProxyAsync(array $args = [])
+ * @method \Aws\Result deleteProxyConfiguration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteProxyConfigurationAsync(array $args = [])
+ * @method \Aws\Result deleteProxyRuleGroup(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteProxyRuleGroupAsync(array $args = [])
+ * @method \Aws\Result deleteProxyRules(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteProxyRulesAsync(array $args = [])
+ * @method \Aws\Result deleteResourcePolicy(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteResourcePolicyAsync(array $args = [])
+ * @method \Aws\Result deleteRuleGroup(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteRuleGroupAsync(array $args = [])
+ * @method \Aws\Result deleteTLSInspectionConfiguration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteTLSInspectionConfigurationAsync(array $args = [])
+ * @method \Aws\Result deleteVpcEndpointAssociation(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteVpcEndpointAssociationAsync(array $args = [])
+ * @method \Aws\Result describeContainerAssociation(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeContainerAssociationAsync(array $args = [])
+ * @method \Aws\Result describeFirewall(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeFirewallAsync(array $args = [])
+ * @method \Aws\Result describeFirewallMetadata(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeFirewallMetadataAsync(array $args = [])
+ * @method \Aws\Result describeFirewallPolicy(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeFirewallPolicyAsync(array $args = [])
+ * @method \Aws\Result describeFlowOperation(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeFlowOperationAsync(array $args = [])
+ * @method \Aws\Result describeLoggingConfiguration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeLoggingConfigurationAsync(array $args = [])
+ * @method \Aws\Result describeProxy(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeProxyAsync(array $args = [])
+ * @method \Aws\Result describeProxyConfiguration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeProxyConfigurationAsync(array $args = [])
+ * @method \Aws\Result describeProxyRule(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeProxyRuleAsync(array $args = [])
+ * @method \Aws\Result describeProxyRuleGroup(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeProxyRuleGroupAsync(array $args = [])
+ * @method \Aws\Result describeResourcePolicy(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeResourcePolicyAsync(array $args = [])
+ * @method \Aws\Result describeRuleGroup(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeRuleGroupAsync(array $args = [])
+ * @method \Aws\Result describeRuleGroupMetadata(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeRuleGroupMetadataAsync(array $args = [])
+ * @method \Aws\Result describeRuleGroupSummary(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeRuleGroupSummaryAsync(array $args = [])
+ * @method \Aws\Result describeTLSInspectionConfiguration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeTLSInspectionConfigurationAsync(array $args = [])
+ * @method \Aws\Result describeVpcEndpointAssociation(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeVpcEndpointAssociationAsync(array $args = [])
+ * @method \Aws\Result detachRuleGroupsFromProxyConfiguration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise detachRuleGroupsFromProxyConfigurationAsync(array $args = [])
+ * @method \Aws\Result disassociateAvailabilityZones(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise disassociateAvailabilityZonesAsync(array $args = [])
+ * @method \Aws\Result disassociateSubnets(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise disassociateSubnetsAsync(array $args = [])
+ * @method \Aws\Result getAnalysisReportResults(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getAnalysisReportResultsAsync(array $args = [])
+ * @method \Aws\Result listAnalysisReports(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listAnalysisReportsAsync(array $args = [])
+ * @method \Aws\Result listContainerAssociations(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listContainerAssociationsAsync(array $args = [])
+ * @method \Aws\Result listFirewallPolicies(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listFirewallPoliciesAsync(array $args = [])
+ * @method \Aws\Result listFirewalls(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listFirewallsAsync(array $args = [])
+ * @method \Aws\Result listFlowOperationResults(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listFlowOperationResultsAsync(array $args = [])
+ * @method \Aws\Result listFlowOperations(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listFlowOperationsAsync(array $args = [])
+ * @method \Aws\Result listProxies(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listProxiesAsync(array $args = [])
+ * @method \Aws\Result listProxyConfigurations(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listProxyConfigurationsAsync(array $args = [])
+ * @method \Aws\Result listProxyRuleGroups(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listProxyRuleGroupsAsync(array $args = [])
+ * @method \Aws\Result listRuleGroups(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listRuleGroupsAsync(array $args = [])
+ * @method \Aws\Result listTLSInspectionConfigurations(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listTLSInspectionConfigurationsAsync(array $args = [])
+ * @method \Aws\Result listTagsForResource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listTagsForResourceAsync(array $args = [])
+ * @method \Aws\Result listVpcEndpointAssociations(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listVpcEndpointAssociationsAsync(array $args = [])
+ * @method \Aws\Result putResourcePolicy(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise putResourcePolicyAsync(array $args = [])
+ * @method \Aws\Result rejectNetworkFirewallTransitGatewayAttachment(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise rejectNetworkFirewallTransitGatewayAttachmentAsync(array $args = [])
+ * @method \Aws\Result startAnalysisReport(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise startAnalysisReportAsync(array $args = [])
+ * @method \Aws\Result startFlowCapture(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise startFlowCaptureAsync(array $args = [])
+ * @method \Aws\Result startFlowFlush(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise startFlowFlushAsync(array $args = [])
+ * @method \Aws\Result tagResource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise tagResourceAsync(array $args = [])
+ * @method \Aws\Result untagResource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise untagResourceAsync(array $args = [])
+ * @method \Aws\Result updateAvailabilityZoneChangeProtection(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateAvailabilityZoneChangeProtectionAsync(array $args = [])
+ * @method \Aws\Result updateContainerAssociation(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateContainerAssociationAsync(array $args = [])
+ * @method \Aws\Result updateFirewallAnalysisSettings(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateFirewallAnalysisSettingsAsync(array $args = [])
+ * @method \Aws\Result updateFirewallDeleteProtection(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateFirewallDeleteProtectionAsync(array $args = [])
+ * @method \Aws\Result updateFirewallDescription(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateFirewallDescriptionAsync(array $args = [])
+ * @method \Aws\Result updateFirewallEncryptionConfiguration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateFirewallEncryptionConfigurationAsync(array $args = [])
+ * @method \Aws\Result updateFirewallPolicy(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateFirewallPolicyAsync(array $args = [])
+ * @method \Aws\Result updateFirewallPolicyChangeProtection(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateFirewallPolicyChangeProtectionAsync(array $args = [])
+ * @method \Aws\Result updateLoggingConfiguration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateLoggingConfigurationAsync(array $args = [])
+ * @method \Aws\Result updateProxy(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateProxyAsync(array $args = [])
+ * @method \Aws\Result updateProxyConfiguration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateProxyConfigurationAsync(array $args = [])
+ * @method \Aws\Result updateProxyRule(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateProxyRuleAsync(array $args = [])
+ * @method \Aws\Result updateProxyRuleGroupPriorities(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateProxyRuleGroupPrioritiesAsync(array $args = [])
+ * @method \Aws\Result updateProxyRulePriorities(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateProxyRulePrioritiesAsync(array $args = [])
+ * @method \Aws\Result updateRuleGroup(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateRuleGroupAsync(array $args = [])
+ * @method \Aws\Result updateSubnetChangeProtection(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateSubnetChangeProtectionAsync(array $args = [])
+ * @method \Aws\Result updateTLSInspectionConfiguration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateTLSInspectionConfigurationAsync(array $args = [])
+ */
+class NetworkFirewallClient extends AwsClient {}

+ 141 - 0
upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/Odb/OdbClient.php

@@ -0,0 +1,141 @@
+<?php
+namespace Aws\Odb;
+
+use Aws\AwsClient;
+
+/**
+ * This client is used to interact with the **odb** service.
+ * @method \Aws\Result acceptMarketplaceRegistration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise acceptMarketplaceRegistrationAsync(array $args = [])
+ * @method \Aws\Result associateIamRoleToResource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise associateIamRoleToResourceAsync(array $args = [])
+ * @method \Aws\Result createAutonomousDatabase(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createAutonomousDatabaseAsync(array $args = [])
+ * @method \Aws\Result createAutonomousDatabaseBackup(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createAutonomousDatabaseBackupAsync(array $args = [])
+ * @method \Aws\Result createAutonomousDatabaseWallet(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createAutonomousDatabaseWalletAsync(array $args = [])
+ * @method \Aws\Result createCloudAutonomousVmCluster(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createCloudAutonomousVmClusterAsync(array $args = [])
+ * @method \Aws\Result createCloudExadataInfrastructure(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createCloudExadataInfrastructureAsync(array $args = [])
+ * @method \Aws\Result createCloudVmCluster(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createCloudVmClusterAsync(array $args = [])
+ * @method \Aws\Result createOdbNetwork(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createOdbNetworkAsync(array $args = [])
+ * @method \Aws\Result createOdbPeeringConnection(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createOdbPeeringConnectionAsync(array $args = [])
+ * @method \Aws\Result deleteAutonomousDatabase(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteAutonomousDatabaseAsync(array $args = [])
+ * @method \Aws\Result deleteAutonomousDatabaseBackup(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteAutonomousDatabaseBackupAsync(array $args = [])
+ * @method \Aws\Result deleteCloudAutonomousVmCluster(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteCloudAutonomousVmClusterAsync(array $args = [])
+ * @method \Aws\Result deleteCloudExadataInfrastructure(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteCloudExadataInfrastructureAsync(array $args = [])
+ * @method \Aws\Result deleteCloudVmCluster(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteCloudVmClusterAsync(array $args = [])
+ * @method \Aws\Result deleteOdbNetwork(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteOdbNetworkAsync(array $args = [])
+ * @method \Aws\Result deleteOdbPeeringConnection(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteOdbPeeringConnectionAsync(array $args = [])
+ * @method \Aws\Result disassociateIamRoleFromResource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise disassociateIamRoleFromResourceAsync(array $args = [])
+ * @method \Aws\Result failoverAutonomousDatabase(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise failoverAutonomousDatabaseAsync(array $args = [])
+ * @method \Aws\Result getAutonomousDatabase(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getAutonomousDatabaseAsync(array $args = [])
+ * @method \Aws\Result getAutonomousDatabaseBackup(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getAutonomousDatabaseBackupAsync(array $args = [])
+ * @method \Aws\Result getAutonomousDatabaseWalletDetails(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getAutonomousDatabaseWalletDetailsAsync(array $args = [])
+ * @method \Aws\Result getCloudAutonomousVmCluster(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getCloudAutonomousVmClusterAsync(array $args = [])
+ * @method \Aws\Result getCloudExadataInfrastructure(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getCloudExadataInfrastructureAsync(array $args = [])
+ * @method \Aws\Result getCloudExadataInfrastructureUnallocatedResources(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getCloudExadataInfrastructureUnallocatedResourcesAsync(array $args = [])
+ * @method \Aws\Result getCloudVmCluster(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getCloudVmClusterAsync(array $args = [])
+ * @method \Aws\Result getDbNode(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getDbNodeAsync(array $args = [])
+ * @method \Aws\Result getDbServer(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getDbServerAsync(array $args = [])
+ * @method \Aws\Result getOciOnboardingStatus(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getOciOnboardingStatusAsync(array $args = [])
+ * @method \Aws\Result getOdbNetwork(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getOdbNetworkAsync(array $args = [])
+ * @method \Aws\Result getOdbPeeringConnection(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getOdbPeeringConnectionAsync(array $args = [])
+ * @method \Aws\Result initializeService(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise initializeServiceAsync(array $args = [])
+ * @method \Aws\Result listAutonomousDatabaseBackups(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listAutonomousDatabaseBackupsAsync(array $args = [])
+ * @method \Aws\Result listAutonomousDatabaseCharacterSets(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listAutonomousDatabaseCharacterSetsAsync(array $args = [])
+ * @method \Aws\Result listAutonomousDatabaseClones(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listAutonomousDatabaseClonesAsync(array $args = [])
+ * @method \Aws\Result listAutonomousDatabasePeers(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listAutonomousDatabasePeersAsync(array $args = [])
+ * @method \Aws\Result listAutonomousDatabaseVersions(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listAutonomousDatabaseVersionsAsync(array $args = [])
+ * @method \Aws\Result listAutonomousDatabases(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listAutonomousDatabasesAsync(array $args = [])
+ * @method \Aws\Result listAutonomousVirtualMachines(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listAutonomousVirtualMachinesAsync(array $args = [])
+ * @method \Aws\Result listCloudAutonomousVmClusters(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listCloudAutonomousVmClustersAsync(array $args = [])
+ * @method \Aws\Result listCloudExadataInfrastructures(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listCloudExadataInfrastructuresAsync(array $args = [])
+ * @method \Aws\Result listCloudVmClusters(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listCloudVmClustersAsync(array $args = [])
+ * @method \Aws\Result listDbNodes(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listDbNodesAsync(array $args = [])
+ * @method \Aws\Result listDbServers(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listDbServersAsync(array $args = [])
+ * @method \Aws\Result listDbSystemShapes(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listDbSystemShapesAsync(array $args = [])
+ * @method \Aws\Result listGiVersions(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listGiVersionsAsync(array $args = [])
+ * @method \Aws\Result listOdbNetworks(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listOdbNetworksAsync(array $args = [])
+ * @method \Aws\Result listOdbPeeringConnections(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listOdbPeeringConnectionsAsync(array $args = [])
+ * @method \Aws\Result listSystemVersions(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listSystemVersionsAsync(array $args = [])
+ * @method \Aws\Result listTagsForResource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listTagsForResourceAsync(array $args = [])
+ * @method \Aws\Result rebootAutonomousDatabase(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise rebootAutonomousDatabaseAsync(array $args = [])
+ * @method \Aws\Result rebootDbNode(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise rebootDbNodeAsync(array $args = [])
+ * @method \Aws\Result restoreAutonomousDatabase(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise restoreAutonomousDatabaseAsync(array $args = [])
+ * @method \Aws\Result shrinkAutonomousDatabase(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise shrinkAutonomousDatabaseAsync(array $args = [])
+ * @method \Aws\Result startAutonomousDatabase(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise startAutonomousDatabaseAsync(array $args = [])
+ * @method \Aws\Result startDbNode(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise startDbNodeAsync(array $args = [])
+ * @method \Aws\Result stopAutonomousDatabase(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise stopAutonomousDatabaseAsync(array $args = [])
+ * @method \Aws\Result stopDbNode(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise stopDbNodeAsync(array $args = [])
+ * @method \Aws\Result switchoverAutonomousDatabase(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise switchoverAutonomousDatabaseAsync(array $args = [])
+ * @method \Aws\Result tagResource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise tagResourceAsync(array $args = [])
+ * @method \Aws\Result untagResource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise untagResourceAsync(array $args = [])
+ * @method \Aws\Result updateAutonomousDatabase(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateAutonomousDatabaseAsync(array $args = [])
+ * @method \Aws\Result updateAutonomousDatabaseBackup(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateAutonomousDatabaseBackupAsync(array $args = [])
+ * @method \Aws\Result updateCloudExadataInfrastructure(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateCloudExadataInfrastructureAsync(array $args = [])
+ * @method \Aws\Result updateOdbNetwork(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateOdbNetworkAsync(array $args = [])
+ * @method \Aws\Result updateOdbPeeringConnection(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateOdbPeeringConnectionAsync(array $args = [])
+ */
+class OdbClient extends AwsClient {}

+ 201 - 0
upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/OpenSearchService/OpenSearchServiceClient.php

@@ -0,0 +1,201 @@
+<?php
+namespace Aws\OpenSearchService;
+
+use Aws\AwsClient;
+
+/**
+ * This client is used to interact with the **Amazon OpenSearch Service** service.
+ * @method \Aws\Result acceptInboundConnection(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise acceptInboundConnectionAsync(array $args = [])
+ * @method \Aws\Result addDataSource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise addDataSourceAsync(array $args = [])
+ * @method \Aws\Result addDirectQueryDataSource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise addDirectQueryDataSourceAsync(array $args = [])
+ * @method \Aws\Result addTags(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise addTagsAsync(array $args = [])
+ * @method \Aws\Result associatePackage(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise associatePackageAsync(array $args = [])
+ * @method \Aws\Result associatePackages(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise associatePackagesAsync(array $args = [])
+ * @method \Aws\Result attachDataSource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise attachDataSourceAsync(array $args = [])
+ * @method \Aws\Result authorizeVpcEndpointAccess(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise authorizeVpcEndpointAccessAsync(array $args = [])
+ * @method \Aws\Result cancelDomainConfigChange(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise cancelDomainConfigChangeAsync(array $args = [])
+ * @method \Aws\Result cancelServiceSoftwareUpdate(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise cancelServiceSoftwareUpdateAsync(array $args = [])
+ * @method \Aws\Result createApplication(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createApplicationAsync(array $args = [])
+ * @method \Aws\Result createDomain(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createDomainAsync(array $args = [])
+ * @method \Aws\Result createIndex(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createIndexAsync(array $args = [])
+ * @method \Aws\Result createOutboundConnection(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createOutboundConnectionAsync(array $args = [])
+ * @method \Aws\Result createPackage(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createPackageAsync(array $args = [])
+ * @method \Aws\Result createVpcEndpoint(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createVpcEndpointAsync(array $args = [])
+ * @method \Aws\Result deleteApplication(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteApplicationAsync(array $args = [])
+ * @method \Aws\Result deleteDataSource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteDataSourceAsync(array $args = [])
+ * @method \Aws\Result deleteDirectQueryDataSource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteDirectQueryDataSourceAsync(array $args = [])
+ * @method \Aws\Result deleteDomain(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteDomainAsync(array $args = [])
+ * @method \Aws\Result deleteInboundConnection(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteInboundConnectionAsync(array $args = [])
+ * @method \Aws\Result deleteIndex(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteIndexAsync(array $args = [])
+ * @method \Aws\Result deleteOutboundConnection(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteOutboundConnectionAsync(array $args = [])
+ * @method \Aws\Result deletePackage(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deletePackageAsync(array $args = [])
+ * @method \Aws\Result deleteVpcEndpoint(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteVpcEndpointAsync(array $args = [])
+ * @method \Aws\Result deregisterCapability(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deregisterCapabilityAsync(array $args = [])
+ * @method \Aws\Result describeDataSourceAttachment(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeDataSourceAttachmentAsync(array $args = [])
+ * @method \Aws\Result describeDomain(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeDomainAsync(array $args = [])
+ * @method \Aws\Result describeDomainAutoTunes(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeDomainAutoTunesAsync(array $args = [])
+ * @method \Aws\Result describeDomainChangeProgress(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeDomainChangeProgressAsync(array $args = [])
+ * @method \Aws\Result describeDomainConfig(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeDomainConfigAsync(array $args = [])
+ * @method \Aws\Result describeDomainHealth(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeDomainHealthAsync(array $args = [])
+ * @method \Aws\Result describeDomainNodes(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeDomainNodesAsync(array $args = [])
+ * @method \Aws\Result describeDomains(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeDomainsAsync(array $args = [])
+ * @method \Aws\Result describeDryRunProgress(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeDryRunProgressAsync(array $args = [])
+ * @method \Aws\Result describeInboundConnections(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeInboundConnectionsAsync(array $args = [])
+ * @method \Aws\Result describeInsightDetails(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeInsightDetailsAsync(array $args = [])
+ * @method \Aws\Result describeInstanceTypeLimits(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeInstanceTypeLimitsAsync(array $args = [])
+ * @method \Aws\Result describeOutboundConnections(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeOutboundConnectionsAsync(array $args = [])
+ * @method \Aws\Result describePackages(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describePackagesAsync(array $args = [])
+ * @method \Aws\Result describeReservedInstanceOfferings(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeReservedInstanceOfferingsAsync(array $args = [])
+ * @method \Aws\Result describeReservedInstances(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeReservedInstancesAsync(array $args = [])
+ * @method \Aws\Result describeVpcEndpoints(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeVpcEndpointsAsync(array $args = [])
+ * @method \Aws\Result detachDataSource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise detachDataSourceAsync(array $args = [])
+ * @method \Aws\Result dissociatePackage(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise dissociatePackageAsync(array $args = [])
+ * @method \Aws\Result dissociatePackages(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise dissociatePackagesAsync(array $args = [])
+ * @method \Aws\Result getApplication(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getApplicationAsync(array $args = [])
+ * @method \Aws\Result getCapability(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getCapabilityAsync(array $args = [])
+ * @method \Aws\Result getCompatibleVersions(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getCompatibleVersionsAsync(array $args = [])
+ * @method \Aws\Result getDataSource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getDataSourceAsync(array $args = [])
+ * @method \Aws\Result getDefaultApplicationSetting(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getDefaultApplicationSettingAsync(array $args = [])
+ * @method \Aws\Result getDirectQueryDataSource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getDirectQueryDataSourceAsync(array $args = [])
+ * @method \Aws\Result getDomainMaintenanceStatus(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getDomainMaintenanceStatusAsync(array $args = [])
+ * @method \Aws\Result getIndex(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getIndexAsync(array $args = [])
+ * @method \Aws\Result getMigration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getMigrationAsync(array $args = [])
+ * @method \Aws\Result getPackageVersionHistory(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getPackageVersionHistoryAsync(array $args = [])
+ * @method \Aws\Result getUpgradeHistory(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getUpgradeHistoryAsync(array $args = [])
+ * @method \Aws\Result getUpgradeStatus(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getUpgradeStatusAsync(array $args = [])
+ * @method \Aws\Result insightFeedback(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise insightFeedbackAsync(array $args = [])
+ * @method \Aws\Result listApplications(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listApplicationsAsync(array $args = [])
+ * @method \Aws\Result listDataSourceAttachments(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listDataSourceAttachmentsAsync(array $args = [])
+ * @method \Aws\Result listDataSources(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listDataSourcesAsync(array $args = [])
+ * @method \Aws\Result listDirectQueryDataSources(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listDirectQueryDataSourcesAsync(array $args = [])
+ * @method \Aws\Result listDomainMaintenances(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listDomainMaintenancesAsync(array $args = [])
+ * @method \Aws\Result listDomainNames(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listDomainNamesAsync(array $args = [])
+ * @method \Aws\Result listDomainsForPackage(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listDomainsForPackageAsync(array $args = [])
+ * @method \Aws\Result listInsights(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listInsightsAsync(array $args = [])
+ * @method \Aws\Result listInstanceTypeDetails(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listInstanceTypeDetailsAsync(array $args = [])
+ * @method \Aws\Result listMigrations(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listMigrationsAsync(array $args = [])
+ * @method \Aws\Result listPackagesForDomain(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listPackagesForDomainAsync(array $args = [])
+ * @method \Aws\Result listScheduledActions(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listScheduledActionsAsync(array $args = [])
+ * @method \Aws\Result listTags(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listTagsAsync(array $args = [])
+ * @method \Aws\Result listVersions(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listVersionsAsync(array $args = [])
+ * @method \Aws\Result listVpcEndpointAccess(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listVpcEndpointAccessAsync(array $args = [])
+ * @method \Aws\Result listVpcEndpoints(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listVpcEndpointsAsync(array $args = [])
+ * @method \Aws\Result listVpcEndpointsForDomain(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listVpcEndpointsForDomainAsync(array $args = [])
+ * @method \Aws\Result purchaseReservedInstanceOffering(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise purchaseReservedInstanceOfferingAsync(array $args = [])
+ * @method \Aws\Result putDefaultApplicationSetting(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise putDefaultApplicationSettingAsync(array $args = [])
+ * @method \Aws\Result registerCapability(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise registerCapabilityAsync(array $args = [])
+ * @method \Aws\Result rejectInboundConnection(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise rejectInboundConnectionAsync(array $args = [])
+ * @method \Aws\Result removeTags(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise removeTagsAsync(array $args = [])
+ * @method \Aws\Result revokeVpcEndpointAccess(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise revokeVpcEndpointAccessAsync(array $args = [])
+ * @method \Aws\Result rollbackServiceSoftwareUpdate(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise rollbackServiceSoftwareUpdateAsync(array $args = [])
+ * @method \Aws\Result startDomainMaintenance(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise startDomainMaintenanceAsync(array $args = [])
+ * @method \Aws\Result startMigration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise startMigrationAsync(array $args = [])
+ * @method \Aws\Result startServiceSoftwareUpdate(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise startServiceSoftwareUpdateAsync(array $args = [])
+ * @method \Aws\Result updateApplication(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateApplicationAsync(array $args = [])
+ * @method \Aws\Result updateDataSource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateDataSourceAsync(array $args = [])
+ * @method \Aws\Result updateDirectQueryDataSource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateDirectQueryDataSourceAsync(array $args = [])
+ * @method \Aws\Result updateDomainConfig(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateDomainConfigAsync(array $args = [])
+ * @method \Aws\Result updateIndex(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateIndexAsync(array $args = [])
+ * @method \Aws\Result updatePackage(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updatePackageAsync(array $args = [])
+ * @method \Aws\Result updatePackageScope(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updatePackageScopeAsync(array $args = [])
+ * @method \Aws\Result updateScheduledAction(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateScheduledActionAsync(array $args = [])
+ * @method \Aws\Result updateVpcEndpoint(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateVpcEndpointAsync(array $args = [])
+ * @method \Aws\Result upgradeDomain(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise upgradeDomainAsync(array $args = [])
+ */
+class OpenSearchServiceClient extends AwsClient {}

+ 95 - 0
upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/Outposts/OutpostsClient.php

@@ -0,0 +1,95 @@
+<?php
+namespace Aws\Outposts;
+
+use Aws\AwsClient;
+
+/**
+ * This client is used to interact with the **AWS Outposts** service.
+ * @method \Aws\Result cancelCapacityTask(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise cancelCapacityTaskAsync(array $args = [])
+ * @method \Aws\Result cancelOrder(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise cancelOrderAsync(array $args = [])
+ * @method \Aws\Result createOrder(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createOrderAsync(array $args = [])
+ * @method \Aws\Result createOutpost(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createOutpostAsync(array $args = [])
+ * @method \Aws\Result createQuote(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createQuoteAsync(array $args = [])
+ * @method \Aws\Result createRenewal(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createRenewalAsync(array $args = [])
+ * @method \Aws\Result createSite(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createSiteAsync(array $args = [])
+ * @method \Aws\Result deleteOutpost(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteOutpostAsync(array $args = [])
+ * @method \Aws\Result deleteQuote(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteQuoteAsync(array $args = [])
+ * @method \Aws\Result deleteSite(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteSiteAsync(array $args = [])
+ * @method \Aws\Result getCapacityTask(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getCapacityTaskAsync(array $args = [])
+ * @method \Aws\Result getCatalogItem(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getCatalogItemAsync(array $args = [])
+ * @method \Aws\Result getConnection(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getConnectionAsync(array $args = [])
+ * @method \Aws\Result getOrder(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getOrderAsync(array $args = [])
+ * @method \Aws\Result getOutpost(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getOutpostAsync(array $args = [])
+ * @method \Aws\Result getOutpostBillingInformation(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getOutpostBillingInformationAsync(array $args = [])
+ * @method \Aws\Result getOutpostInstanceTypes(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getOutpostInstanceTypesAsync(array $args = [])
+ * @method \Aws\Result getOutpostSupportedInstanceTypes(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getOutpostSupportedInstanceTypesAsync(array $args = [])
+ * @method \Aws\Result getQuote(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getQuoteAsync(array $args = [])
+ * @method \Aws\Result getRenewalPricing(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getRenewalPricingAsync(array $args = [])
+ * @method \Aws\Result getSite(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getSiteAsync(array $args = [])
+ * @method \Aws\Result getSiteAddress(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getSiteAddressAsync(array $args = [])
+ * @method \Aws\Result listAssetInstances(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listAssetInstancesAsync(array $args = [])
+ * @method \Aws\Result listAssets(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listAssetsAsync(array $args = [])
+ * @method \Aws\Result listBlockingInstancesForCapacityTask(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listBlockingInstancesForCapacityTaskAsync(array $args = [])
+ * @method \Aws\Result listCapacityTasks(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listCapacityTasksAsync(array $args = [])
+ * @method \Aws\Result listCatalogItems(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listCatalogItemsAsync(array $args = [])
+ * @method \Aws\Result listOrderableInstanceTypes(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listOrderableInstanceTypesAsync(array $args = [])
+ * @method \Aws\Result listOrders(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listOrdersAsync(array $args = [])
+ * @method \Aws\Result listOutposts(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listOutpostsAsync(array $args = [])
+ * @method \Aws\Result listQuotes(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listQuotesAsync(array $args = [])
+ * @method \Aws\Result listSites(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listSitesAsync(array $args = [])
+ * @method \Aws\Result listTagsForResource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listTagsForResourceAsync(array $args = [])
+ * @method \Aws\Result startCapacityTask(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise startCapacityTaskAsync(array $args = [])
+ * @method \Aws\Result startConnection(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise startConnectionAsync(array $args = [])
+ * @method \Aws\Result startOutpostDecommission(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise startOutpostDecommissionAsync(array $args = [])
+ * @method \Aws\Result tagResource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise tagResourceAsync(array $args = [])
+ * @method \Aws\Result untagResource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise untagResourceAsync(array $args = [])
+ * @method \Aws\Result updateOutpost(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateOutpostAsync(array $args = [])
+ * @method \Aws\Result updateQuote(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateQuoteAsync(array $args = [])
+ * @method \Aws\Result updateSite(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateSiteAsync(array $args = [])
+ * @method \Aws\Result updateSiteAddress(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateSiteAddressAsync(array $args = [])
+ * @method \Aws\Result updateSiteRackPhysicalProperties(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateSiteRackPhysicalPropertiesAsync(array $args = [])
+ */
+class OutpostsClient extends AwsClient {}

+ 9 - 0
upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/PartnerCentralRevenueMeasurement/Exception/PartnerCentralRevenueMeasurementException.php

@@ -0,0 +1,9 @@
+<?php
+namespace Aws\PartnerCentralRevenueMeasurement\Exception;
+
+use Aws\Exception\AwsException;
+
+/**
+ * Represents an error interacting with the **Partner Central Revenue Measurement API** service.
+ */
+class PartnerCentralRevenueMeasurementException extends AwsException {}

+ 45 - 0
upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/PartnerCentralRevenueMeasurement/PartnerCentralRevenueMeasurementClient.php

@@ -0,0 +1,45 @@
+<?php
+namespace Aws\PartnerCentralRevenueMeasurement;
+
+use Aws\AwsClient;
+
+/**
+ * This client is used to interact with the **Partner Central Revenue Measurement API** service.
+ * @method \Aws\Result createMarketplaceRevenueShare(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createMarketplaceRevenueShareAsync(array $args = [])
+ * @method \Aws\Result createMarketplaceRevenueShareAllocation(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createMarketplaceRevenueShareAllocationAsync(array $args = [])
+ * @method \Aws\Result createRevenueAttribution(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createRevenueAttributionAsync(array $args = [])
+ * @method \Aws\Result getMarketplaceRevenueShare(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getMarketplaceRevenueShareAsync(array $args = [])
+ * @method \Aws\Result getMarketplaceRevenueShareAllocation(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getMarketplaceRevenueShareAllocationAsync(array $args = [])
+ * @method \Aws\Result getRevenueAttribution(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getRevenueAttributionAsync(array $args = [])
+ * @method \Aws\Result getRevenueAttributionAllocation(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getRevenueAttributionAllocationAsync(array $args = [])
+ * @method \Aws\Result getRevenueAttributionAllocationsTask(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getRevenueAttributionAllocationsTaskAsync(array $args = [])
+ * @method \Aws\Result listMarketplaceRevenueShareAllocations(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listMarketplaceRevenueShareAllocationsAsync(array $args = [])
+ * @method \Aws\Result listMarketplaceRevenueShares(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listMarketplaceRevenueSharesAsync(array $args = [])
+ * @method \Aws\Result listRevenueAttributionAllocations(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listRevenueAttributionAllocationsAsync(array $args = [])
+ * @method \Aws\Result listRevenueAttributions(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listRevenueAttributionsAsync(array $args = [])
+ * @method \Aws\Result listTagsForResource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listTagsForResourceAsync(array $args = [])
+ * @method \Aws\Result startRevenueAttributionAllocationsTask(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise startRevenueAttributionAllocationsTaskAsync(array $args = [])
+ * @method \Aws\Result tagResource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise tagResourceAsync(array $args = [])
+ * @method \Aws\Result untagResource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise untagResourceAsync(array $args = [])
+ * @method \Aws\Result updateMarketplaceRevenueShareAllocation(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateMarketplaceRevenueShareAllocationAsync(array $args = [])
+ * @method \Aws\Result updateRevenueAttribution(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateRevenueAttributionAsync(array $args = [])
+ */
+class PartnerCentralRevenueMeasurementClient extends AwsClient {}

+ 99 - 0
upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/PartnerCentralSelling/PartnerCentralSellingClient.php

@@ -0,0 +1,99 @@
+<?php
+namespace Aws\PartnerCentralSelling;
+
+use Aws\AwsClient;
+
+/**
+ * This client is used to interact with the **Partner Central Selling API** service.
+ * @method \Aws\Result acceptEngagementInvitation(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise acceptEngagementInvitationAsync(array $args = [])
+ * @method \Aws\Result assignOpportunity(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise assignOpportunityAsync(array $args = [])
+ * @method \Aws\Result associateOpportunity(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise associateOpportunityAsync(array $args = [])
+ * @method \Aws\Result createEngagement(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createEngagementAsync(array $args = [])
+ * @method \Aws\Result createEngagementContext(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createEngagementContextAsync(array $args = [])
+ * @method \Aws\Result createEngagementInvitation(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createEngagementInvitationAsync(array $args = [])
+ * @method \Aws\Result createOpportunity(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createOpportunityAsync(array $args = [])
+ * @method \Aws\Result createResourceSnapshot(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createResourceSnapshotAsync(array $args = [])
+ * @method \Aws\Result createResourceSnapshotJob(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createResourceSnapshotJobAsync(array $args = [])
+ * @method \Aws\Result deleteResourceSnapshotJob(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteResourceSnapshotJobAsync(array $args = [])
+ * @method \Aws\Result disassociateOpportunity(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise disassociateOpportunityAsync(array $args = [])
+ * @method \Aws\Result getAwsOpportunitySummary(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getAwsOpportunitySummaryAsync(array $args = [])
+ * @method \Aws\Result getEngagement(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getEngagementAsync(array $args = [])
+ * @method \Aws\Result getEngagementInvitation(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getEngagementInvitationAsync(array $args = [])
+ * @method \Aws\Result getOpportunity(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getOpportunityAsync(array $args = [])
+ * @method \Aws\Result getProspectingFromEngagementTask(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getProspectingFromEngagementTaskAsync(array $args = [])
+ * @method \Aws\Result getResourceSnapshot(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getResourceSnapshotAsync(array $args = [])
+ * @method \Aws\Result getResourceSnapshotJob(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getResourceSnapshotJobAsync(array $args = [])
+ * @method \Aws\Result getSellingSystemSettings(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getSellingSystemSettingsAsync(array $args = [])
+ * @method \Aws\Result listEngagementByAcceptingInvitationTasks(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listEngagementByAcceptingInvitationTasksAsync(array $args = [])
+ * @method \Aws\Result listEngagementFromOpportunityTasks(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listEngagementFromOpportunityTasksAsync(array $args = [])
+ * @method \Aws\Result listEngagementInvitations(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listEngagementInvitationsAsync(array $args = [])
+ * @method \Aws\Result listEngagementMembers(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listEngagementMembersAsync(array $args = [])
+ * @method \Aws\Result listEngagementResourceAssociations(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listEngagementResourceAssociationsAsync(array $args = [])
+ * @method \Aws\Result listEngagements(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listEngagementsAsync(array $args = [])
+ * @method \Aws\Result listOpportunities(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listOpportunitiesAsync(array $args = [])
+ * @method \Aws\Result listOpportunityFromEngagementTasks(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listOpportunityFromEngagementTasksAsync(array $args = [])
+ * @method \Aws\Result listProspectingFromEngagementTasks(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listProspectingFromEngagementTasksAsync(array $args = [])
+ * @method \Aws\Result listResourceSnapshotJobs(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listResourceSnapshotJobsAsync(array $args = [])
+ * @method \Aws\Result listResourceSnapshots(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listResourceSnapshotsAsync(array $args = [])
+ * @method \Aws\Result listSolutions(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listSolutionsAsync(array $args = [])
+ * @method \Aws\Result listTagsForResource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listTagsForResourceAsync(array $args = [])
+ * @method \Aws\Result putSellingSystemSettings(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise putSellingSystemSettingsAsync(array $args = [])
+ * @method \Aws\Result rejectEngagementInvitation(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise rejectEngagementInvitationAsync(array $args = [])
+ * @method \Aws\Result startEngagementByAcceptingInvitationTask(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise startEngagementByAcceptingInvitationTaskAsync(array $args = [])
+ * @method \Aws\Result startEngagementFromOpportunityTask(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise startEngagementFromOpportunityTaskAsync(array $args = [])
+ * @method \Aws\Result startOpportunityFromEngagementTask(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise startOpportunityFromEngagementTaskAsync(array $args = [])
+ * @method \Aws\Result startProspectingFromEngagementTask(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise startProspectingFromEngagementTaskAsync(array $args = [])
+ * @method \Aws\Result startResourceSnapshotJob(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise startResourceSnapshotJobAsync(array $args = [])
+ * @method \Aws\Result stopResourceSnapshotJob(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise stopResourceSnapshotJobAsync(array $args = [])
+ * @method \Aws\Result submitOpportunity(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise submitOpportunityAsync(array $args = [])
+ * @method \Aws\Result tagResource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise tagResourceAsync(array $args = [])
+ * @method \Aws\Result untagResource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise untagResourceAsync(array $args = [])
+ * @method \Aws\Result updateEngagementContext(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateEngagementContextAsync(array $args = [])
+ * @method \Aws\Result updateOpportunity(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateOpportunityAsync(array $args = [])
+ */
+class PartnerCentralSellingClient extends AwsClient {}

+ 227 - 0
upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/PinpointSMSVoiceV2/PinpointSMSVoiceV2Client.php

@@ -0,0 +1,227 @@
+<?php
+namespace Aws\PinpointSMSVoiceV2;
+
+use Aws\AwsClient;
+
+/**
+ * This client is used to interact with the **Amazon Pinpoint SMS Voice V2** service.
+ * @method \Aws\Result associateOriginationIdentity(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise associateOriginationIdentityAsync(array $args = [])
+ * @method \Aws\Result associateProtectConfiguration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise associateProtectConfigurationAsync(array $args = [])
+ * @method \Aws\Result carrierLookup(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise carrierLookupAsync(array $args = [])
+ * @method \Aws\Result createConfigurationSet(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createConfigurationSetAsync(array $args = [])
+ * @method \Aws\Result createEventDestination(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createEventDestinationAsync(array $args = [])
+ * @method \Aws\Result createNotifyConfiguration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createNotifyConfigurationAsync(array $args = [])
+ * @method \Aws\Result createOptOutList(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createOptOutListAsync(array $args = [])
+ * @method \Aws\Result createPool(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createPoolAsync(array $args = [])
+ * @method \Aws\Result createProtectConfiguration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createProtectConfigurationAsync(array $args = [])
+ * @method \Aws\Result createRcsAgent(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createRcsAgentAsync(array $args = [])
+ * @method \Aws\Result createRegistration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createRegistrationAsync(array $args = [])
+ * @method \Aws\Result createRegistrationAssociation(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createRegistrationAssociationAsync(array $args = [])
+ * @method \Aws\Result createRegistrationAttachment(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createRegistrationAttachmentAsync(array $args = [])
+ * @method \Aws\Result createRegistrationVersion(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createRegistrationVersionAsync(array $args = [])
+ * @method \Aws\Result createVerifiedDestinationNumber(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createVerifiedDestinationNumberAsync(array $args = [])
+ * @method \Aws\Result deleteAccountDefaultProtectConfiguration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteAccountDefaultProtectConfigurationAsync(array $args = [])
+ * @method \Aws\Result deleteConfigurationSet(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteConfigurationSetAsync(array $args = [])
+ * @method \Aws\Result deleteDefaultMessageType(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteDefaultMessageTypeAsync(array $args = [])
+ * @method \Aws\Result deleteDefaultSenderId(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteDefaultSenderIdAsync(array $args = [])
+ * @method \Aws\Result deleteEventDestination(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteEventDestinationAsync(array $args = [])
+ * @method \Aws\Result deleteKeyword(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteKeywordAsync(array $args = [])
+ * @method \Aws\Result deleteMediaMessageSpendLimitOverride(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteMediaMessageSpendLimitOverrideAsync(array $args = [])
+ * @method \Aws\Result deleteNotifyConfiguration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteNotifyConfigurationAsync(array $args = [])
+ * @method \Aws\Result deleteNotifyMessageSpendLimitOverride(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteNotifyMessageSpendLimitOverrideAsync(array $args = [])
+ * @method \Aws\Result deleteOptOutList(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteOptOutListAsync(array $args = [])
+ * @method \Aws\Result deleteOptedOutNumber(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteOptedOutNumberAsync(array $args = [])
+ * @method \Aws\Result deletePool(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deletePoolAsync(array $args = [])
+ * @method \Aws\Result deleteProtectConfiguration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteProtectConfigurationAsync(array $args = [])
+ * @method \Aws\Result deleteProtectConfigurationRuleSetNumberOverride(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteProtectConfigurationRuleSetNumberOverrideAsync(array $args = [])
+ * @method \Aws\Result deleteRcsAgent(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteRcsAgentAsync(array $args = [])
+ * @method \Aws\Result deleteRcsMessageSpendLimitOverride(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteRcsMessageSpendLimitOverrideAsync(array $args = [])
+ * @method \Aws\Result deleteRegistration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteRegistrationAsync(array $args = [])
+ * @method \Aws\Result deleteRegistrationAttachment(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteRegistrationAttachmentAsync(array $args = [])
+ * @method \Aws\Result deleteRegistrationFieldValue(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteRegistrationFieldValueAsync(array $args = [])
+ * @method \Aws\Result deleteResourcePolicy(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteResourcePolicyAsync(array $args = [])
+ * @method \Aws\Result deleteTextMessageSpendLimitOverride(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteTextMessageSpendLimitOverrideAsync(array $args = [])
+ * @method \Aws\Result deleteVerifiedDestinationNumber(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteVerifiedDestinationNumberAsync(array $args = [])
+ * @method \Aws\Result deleteVoiceMessageSpendLimitOverride(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteVoiceMessageSpendLimitOverrideAsync(array $args = [])
+ * @method \Aws\Result describeAccountAttributes(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeAccountAttributesAsync(array $args = [])
+ * @method \Aws\Result describeAccountLimits(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeAccountLimitsAsync(array $args = [])
+ * @method \Aws\Result describeConfigurationSets(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeConfigurationSetsAsync(array $args = [])
+ * @method \Aws\Result describeKeywords(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeKeywordsAsync(array $args = [])
+ * @method \Aws\Result describeNotifyConfigurations(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeNotifyConfigurationsAsync(array $args = [])
+ * @method \Aws\Result describeNotifyTemplates(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeNotifyTemplatesAsync(array $args = [])
+ * @method \Aws\Result describeOptOutLists(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeOptOutListsAsync(array $args = [])
+ * @method \Aws\Result describeOptedOutNumbers(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeOptedOutNumbersAsync(array $args = [])
+ * @method \Aws\Result describePhoneNumbers(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describePhoneNumbersAsync(array $args = [])
+ * @method \Aws\Result describePools(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describePoolsAsync(array $args = [])
+ * @method \Aws\Result describeProtectConfigurations(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeProtectConfigurationsAsync(array $args = [])
+ * @method \Aws\Result describeRcsAgentCountryLaunchStatus(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeRcsAgentCountryLaunchStatusAsync(array $args = [])
+ * @method \Aws\Result describeRcsAgents(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeRcsAgentsAsync(array $args = [])
+ * @method \Aws\Result describeRegistrationAttachments(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeRegistrationAttachmentsAsync(array $args = [])
+ * @method \Aws\Result describeRegistrationFieldDefinitions(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeRegistrationFieldDefinitionsAsync(array $args = [])
+ * @method \Aws\Result describeRegistrationFieldValues(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeRegistrationFieldValuesAsync(array $args = [])
+ * @method \Aws\Result describeRegistrationSectionDefinitions(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeRegistrationSectionDefinitionsAsync(array $args = [])
+ * @method \Aws\Result describeRegistrationTypeDefinitions(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeRegistrationTypeDefinitionsAsync(array $args = [])
+ * @method \Aws\Result describeRegistrationVersions(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeRegistrationVersionsAsync(array $args = [])
+ * @method \Aws\Result describeRegistrations(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeRegistrationsAsync(array $args = [])
+ * @method \Aws\Result describeSenderIds(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeSenderIdsAsync(array $args = [])
+ * @method \Aws\Result describeSpendLimits(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeSpendLimitsAsync(array $args = [])
+ * @method \Aws\Result describeVerifiedDestinationNumbers(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeVerifiedDestinationNumbersAsync(array $args = [])
+ * @method \Aws\Result disassociateOriginationIdentity(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise disassociateOriginationIdentityAsync(array $args = [])
+ * @method \Aws\Result disassociateProtectConfiguration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise disassociateProtectConfigurationAsync(array $args = [])
+ * @method \Aws\Result discardRegistrationVersion(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise discardRegistrationVersionAsync(array $args = [])
+ * @method \Aws\Result getProtectConfigurationCountryRuleSet(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getProtectConfigurationCountryRuleSetAsync(array $args = [])
+ * @method \Aws\Result getResourcePolicy(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getResourcePolicyAsync(array $args = [])
+ * @method \Aws\Result listNotifyCountries(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listNotifyCountriesAsync(array $args = [])
+ * @method \Aws\Result listPoolOriginationIdentities(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listPoolOriginationIdentitiesAsync(array $args = [])
+ * @method \Aws\Result listProtectConfigurationRuleSetNumberOverrides(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listProtectConfigurationRuleSetNumberOverridesAsync(array $args = [])
+ * @method \Aws\Result listRegistrationAssociations(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listRegistrationAssociationsAsync(array $args = [])
+ * @method \Aws\Result listTagsForResource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listTagsForResourceAsync(array $args = [])
+ * @method \Aws\Result putKeyword(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise putKeywordAsync(array $args = [])
+ * @method \Aws\Result putMessageFeedback(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise putMessageFeedbackAsync(array $args = [])
+ * @method \Aws\Result putOptedOutNumber(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise putOptedOutNumberAsync(array $args = [])
+ * @method \Aws\Result putProtectConfigurationRuleSetNumberOverride(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise putProtectConfigurationRuleSetNumberOverrideAsync(array $args = [])
+ * @method \Aws\Result putRegistrationFieldValue(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise putRegistrationFieldValueAsync(array $args = [])
+ * @method \Aws\Result putResourcePolicy(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise putResourcePolicyAsync(array $args = [])
+ * @method \Aws\Result releasePhoneNumber(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise releasePhoneNumberAsync(array $args = [])
+ * @method \Aws\Result releaseSenderId(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise releaseSenderIdAsync(array $args = [])
+ * @method \Aws\Result requestPhoneNumber(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise requestPhoneNumberAsync(array $args = [])
+ * @method \Aws\Result requestSenderId(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise requestSenderIdAsync(array $args = [])
+ * @method \Aws\Result sendDestinationNumberVerificationCode(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise sendDestinationNumberVerificationCodeAsync(array $args = [])
+ * @method \Aws\Result sendMediaMessage(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise sendMediaMessageAsync(array $args = [])
+ * @method \Aws\Result sendNotifyTextMessage(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise sendNotifyTextMessageAsync(array $args = [])
+ * @method \Aws\Result sendNotifyVoiceMessage(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise sendNotifyVoiceMessageAsync(array $args = [])
+ * @method \Aws\Result sendRcsMessage(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise sendRcsMessageAsync(array $args = [])
+ * @method \Aws\Result sendTextMessage(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise sendTextMessageAsync(array $args = [])
+ * @method \Aws\Result sendVoiceMessage(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise sendVoiceMessageAsync(array $args = [])
+ * @method \Aws\Result setAccountDefaultProtectConfiguration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise setAccountDefaultProtectConfigurationAsync(array $args = [])
+ * @method \Aws\Result setDefaultMessageFeedbackEnabled(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise setDefaultMessageFeedbackEnabledAsync(array $args = [])
+ * @method \Aws\Result setDefaultMessageType(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise setDefaultMessageTypeAsync(array $args = [])
+ * @method \Aws\Result setDefaultSenderId(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise setDefaultSenderIdAsync(array $args = [])
+ * @method \Aws\Result setMediaMessageSpendLimitOverride(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise setMediaMessageSpendLimitOverrideAsync(array $args = [])
+ * @method \Aws\Result setNotifyMessageSpendLimitOverride(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise setNotifyMessageSpendLimitOverrideAsync(array $args = [])
+ * @method \Aws\Result setRcsMessageSpendLimitOverride(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise setRcsMessageSpendLimitOverrideAsync(array $args = [])
+ * @method \Aws\Result setTextMessageSpendLimitOverride(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise setTextMessageSpendLimitOverrideAsync(array $args = [])
+ * @method \Aws\Result setVoiceMessageSpendLimitOverride(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise setVoiceMessageSpendLimitOverrideAsync(array $args = [])
+ * @method \Aws\Result submitRegistrationVersion(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise submitRegistrationVersionAsync(array $args = [])
+ * @method \Aws\Result tagResource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise tagResourceAsync(array $args = [])
+ * @method \Aws\Result untagResource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise untagResourceAsync(array $args = [])
+ * @method \Aws\Result updateEventDestination(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateEventDestinationAsync(array $args = [])
+ * @method \Aws\Result updateNotifyConfiguration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateNotifyConfigurationAsync(array $args = [])
+ * @method \Aws\Result updatePhoneNumber(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updatePhoneNumberAsync(array $args = [])
+ * @method \Aws\Result updatePool(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updatePoolAsync(array $args = [])
+ * @method \Aws\Result updateProtectConfiguration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateProtectConfigurationAsync(array $args = [])
+ * @method \Aws\Result updateProtectConfigurationCountryRuleSet(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateProtectConfigurationCountryRuleSetAsync(array $args = [])
+ * @method \Aws\Result updateRcsAgent(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateRcsAgentAsync(array $args = [])
+ * @method \Aws\Result updateSenderId(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateSenderIdAsync(array $args = [])
+ * @method \Aws\Result verifyDestinationNumber(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise verifyDestinationNumberAsync(array $args = [])
+ */
+class PinpointSMSVoiceV2Client extends AwsClient {}

+ 547 - 0
upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/QuickSight/QuickSightClient.php

@@ -0,0 +1,547 @@
+<?php
+namespace Aws\QuickSight;
+
+use Aws\AwsClient;
+
+/**
+ * This client is used to interact with the **Amazon QuickSight** service.
+ * @method \Aws\Result batchCreateTopicReviewedAnswer(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise batchCreateTopicReviewedAnswerAsync(array $args = [])
+ * @method \Aws\Result batchDeleteKnowledgeBase(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise batchDeleteKnowledgeBaseAsync(array $args = [])
+ * @method \Aws\Result batchDeleteTopicReviewedAnswer(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise batchDeleteTopicReviewedAnswerAsync(array $args = [])
+ * @method \Aws\Result cancelIngestion(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise cancelIngestionAsync(array $args = [])
+ * @method \Aws\Result createAccountCustomization(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createAccountCustomizationAsync(array $args = [])
+ * @method \Aws\Result createAccountSubscription(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createAccountSubscriptionAsync(array $args = [])
+ * @method \Aws\Result createActionConnector(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createActionConnectorAsync(array $args = [])
+ * @method \Aws\Result createAgent(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createAgentAsync(array $args = [])
+ * @method \Aws\Result createAnalysis(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createAnalysisAsync(array $args = [])
+ * @method \Aws\Result createBrand(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createBrandAsync(array $args = [])
+ * @method \Aws\Result createCustomPermissions(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createCustomPermissionsAsync(array $args = [])
+ * @method \Aws\Result createDashboard(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createDashboardAsync(array $args = [])
+ * @method \Aws\Result createDataSet(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createDataSetAsync(array $args = [])
+ * @method \Aws\Result createDataSource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createDataSourceAsync(array $args = [])
+ * @method \Aws\Result createFlow(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createFlowAsync(array $args = [])
+ * @method \Aws\Result createFolder(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createFolderAsync(array $args = [])
+ * @method \Aws\Result createFolderMembership(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createFolderMembershipAsync(array $args = [])
+ * @method \Aws\Result createGroup(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createGroupAsync(array $args = [])
+ * @method \Aws\Result createGroupMembership(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createGroupMembershipAsync(array $args = [])
+ * @method \Aws\Result createIAMPolicyAssignment(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createIAMPolicyAssignmentAsync(array $args = [])
+ * @method \Aws\Result createIngestion(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createIngestionAsync(array $args = [])
+ * @method \Aws\Result createKnowledgeBase(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createKnowledgeBaseAsync(array $args = [])
+ * @method \Aws\Result createNamespace(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createNamespaceAsync(array $args = [])
+ * @method \Aws\Result createOAuthClientApplication(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createOAuthClientApplicationAsync(array $args = [])
+ * @method \Aws\Result createRefreshSchedule(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createRefreshScheduleAsync(array $args = [])
+ * @method \Aws\Result createRoleMembership(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createRoleMembershipAsync(array $args = [])
+ * @method \Aws\Result createSpace(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createSpaceAsync(array $args = [])
+ * @method \Aws\Result createTemplate(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createTemplateAsync(array $args = [])
+ * @method \Aws\Result createTemplateAlias(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createTemplateAliasAsync(array $args = [])
+ * @method \Aws\Result createTheme(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createThemeAsync(array $args = [])
+ * @method \Aws\Result createThemeAlias(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createThemeAliasAsync(array $args = [])
+ * @method \Aws\Result createTopic(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createTopicAsync(array $args = [])
+ * @method \Aws\Result createTopicRefreshSchedule(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createTopicRefreshScheduleAsync(array $args = [])
+ * @method \Aws\Result createVPCConnection(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createVPCConnectionAsync(array $args = [])
+ * @method \Aws\Result deleteAccountCustomPermission(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteAccountCustomPermissionAsync(array $args = [])
+ * @method \Aws\Result deleteAccountCustomization(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteAccountCustomizationAsync(array $args = [])
+ * @method \Aws\Result deleteAccountSubscription(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteAccountSubscriptionAsync(array $args = [])
+ * @method \Aws\Result deleteActionConnector(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteActionConnectorAsync(array $args = [])
+ * @method \Aws\Result deleteAgent(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteAgentAsync(array $args = [])
+ * @method \Aws\Result deleteAnalysis(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteAnalysisAsync(array $args = [])
+ * @method \Aws\Result deleteBrand(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteBrandAsync(array $args = [])
+ * @method \Aws\Result deleteBrandAssignment(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteBrandAssignmentAsync(array $args = [])
+ * @method \Aws\Result deleteCustomPermissions(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteCustomPermissionsAsync(array $args = [])
+ * @method \Aws\Result deleteDashboard(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteDashboardAsync(array $args = [])
+ * @method \Aws\Result deleteDataSet(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteDataSetAsync(array $args = [])
+ * @method \Aws\Result deleteDataSetRefreshProperties(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteDataSetRefreshPropertiesAsync(array $args = [])
+ * @method \Aws\Result deleteDataSource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteDataSourceAsync(array $args = [])
+ * @method \Aws\Result deleteDefaultQBusinessApplication(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteDefaultQBusinessApplicationAsync(array $args = [])
+ * @method \Aws\Result deleteFlow(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteFlowAsync(array $args = [])
+ * @method \Aws\Result deleteFolder(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteFolderAsync(array $args = [])
+ * @method \Aws\Result deleteFolderMembership(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteFolderMembershipAsync(array $args = [])
+ * @method \Aws\Result deleteGroup(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteGroupAsync(array $args = [])
+ * @method \Aws\Result deleteGroupMembership(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteGroupMembershipAsync(array $args = [])
+ * @method \Aws\Result deleteIAMPolicyAssignment(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteIAMPolicyAssignmentAsync(array $args = [])
+ * @method \Aws\Result deleteIdentityPropagationConfig(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteIdentityPropagationConfigAsync(array $args = [])
+ * @method \Aws\Result deleteKnowledgeBase(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteKnowledgeBaseAsync(array $args = [])
+ * @method \Aws\Result deleteNamespace(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteNamespaceAsync(array $args = [])
+ * @method \Aws\Result deleteOAuthClientApplication(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteOAuthClientApplicationAsync(array $args = [])
+ * @method \Aws\Result deleteRefreshSchedule(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteRefreshScheduleAsync(array $args = [])
+ * @method \Aws\Result deleteRoleCustomPermission(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteRoleCustomPermissionAsync(array $args = [])
+ * @method \Aws\Result deleteRoleMembership(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteRoleMembershipAsync(array $args = [])
+ * @method \Aws\Result deleteSpace(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteSpaceAsync(array $args = [])
+ * @method \Aws\Result deleteTemplate(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteTemplateAsync(array $args = [])
+ * @method \Aws\Result deleteTemplateAlias(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteTemplateAliasAsync(array $args = [])
+ * @method \Aws\Result deleteTheme(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteThemeAsync(array $args = [])
+ * @method \Aws\Result deleteThemeAlias(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteThemeAliasAsync(array $args = [])
+ * @method \Aws\Result deleteTopic(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteTopicAsync(array $args = [])
+ * @method \Aws\Result deleteTopicRefreshSchedule(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteTopicRefreshScheduleAsync(array $args = [])
+ * @method \Aws\Result deleteUser(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteUserAsync(array $args = [])
+ * @method \Aws\Result deleteUserByPrincipalId(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteUserByPrincipalIdAsync(array $args = [])
+ * @method \Aws\Result deleteUserCustomPermission(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteUserCustomPermissionAsync(array $args = [])
+ * @method \Aws\Result deleteVPCConnection(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteVPCConnectionAsync(array $args = [])
+ * @method \Aws\Result describeAccountCustomPermission(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeAccountCustomPermissionAsync(array $args = [])
+ * @method \Aws\Result describeAccountCustomization(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeAccountCustomizationAsync(array $args = [])
+ * @method \Aws\Result describeAccountSettings(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeAccountSettingsAsync(array $args = [])
+ * @method \Aws\Result describeAccountSubscription(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeAccountSubscriptionAsync(array $args = [])
+ * @method \Aws\Result describeActionConnector(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeActionConnectorAsync(array $args = [])
+ * @method \Aws\Result describeActionConnectorPermissions(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeActionConnectorPermissionsAsync(array $args = [])
+ * @method \Aws\Result describeAgent(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeAgentAsync(array $args = [])
+ * @method \Aws\Result describeAgentPermissions(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeAgentPermissionsAsync(array $args = [])
+ * @method \Aws\Result describeAnalysis(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeAnalysisAsync(array $args = [])
+ * @method \Aws\Result describeAnalysisDefinition(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeAnalysisDefinitionAsync(array $args = [])
+ * @method \Aws\Result describeAnalysisPermissions(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeAnalysisPermissionsAsync(array $args = [])
+ * @method \Aws\Result describeAssetBundleExportJob(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeAssetBundleExportJobAsync(array $args = [])
+ * @method \Aws\Result describeAssetBundleImportJob(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeAssetBundleImportJobAsync(array $args = [])
+ * @method \Aws\Result describeAutomationJob(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeAutomationJobAsync(array $args = [])
+ * @method \Aws\Result describeBrand(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeBrandAsync(array $args = [])
+ * @method \Aws\Result describeBrandAssignment(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeBrandAssignmentAsync(array $args = [])
+ * @method \Aws\Result describeBrandPublishedVersion(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeBrandPublishedVersionAsync(array $args = [])
+ * @method \Aws\Result describeCustomPermissions(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeCustomPermissionsAsync(array $args = [])
+ * @method \Aws\Result describeDashboard(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeDashboardAsync(array $args = [])
+ * @method \Aws\Result describeDashboardDefinition(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeDashboardDefinitionAsync(array $args = [])
+ * @method \Aws\Result describeDashboardPermissions(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeDashboardPermissionsAsync(array $args = [])
+ * @method \Aws\Result describeDashboardSnapshotJob(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeDashboardSnapshotJobAsync(array $args = [])
+ * @method \Aws\Result describeDashboardSnapshotJobResult(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeDashboardSnapshotJobResultAsync(array $args = [])
+ * @method \Aws\Result describeDashboardsQAConfiguration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeDashboardsQAConfigurationAsync(array $args = [])
+ * @method \Aws\Result describeDataSet(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeDataSetAsync(array $args = [])
+ * @method \Aws\Result describeDataSetPermissions(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeDataSetPermissionsAsync(array $args = [])
+ * @method \Aws\Result describeDataSetRefreshProperties(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeDataSetRefreshPropertiesAsync(array $args = [])
+ * @method \Aws\Result describeDataSource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeDataSourceAsync(array $args = [])
+ * @method \Aws\Result describeDataSourcePermissions(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeDataSourcePermissionsAsync(array $args = [])
+ * @method \Aws\Result describeDefaultQBusinessApplication(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeDefaultQBusinessApplicationAsync(array $args = [])
+ * @method \Aws\Result describeFlow(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeFlowAsync(array $args = [])
+ * @method \Aws\Result describeFolder(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeFolderAsync(array $args = [])
+ * @method \Aws\Result describeFolderPermissions(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeFolderPermissionsAsync(array $args = [])
+ * @method \Aws\Result describeFolderResolvedPermissions(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeFolderResolvedPermissionsAsync(array $args = [])
+ * @method \Aws\Result describeGroup(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeGroupAsync(array $args = [])
+ * @method \Aws\Result describeGroupMembership(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeGroupMembershipAsync(array $args = [])
+ * @method \Aws\Result describeIAMPolicyAssignment(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeIAMPolicyAssignmentAsync(array $args = [])
+ * @method \Aws\Result describeIngestion(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeIngestionAsync(array $args = [])
+ * @method \Aws\Result describeIpRestriction(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeIpRestrictionAsync(array $args = [])
+ * @method \Aws\Result describeKeyRegistration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeKeyRegistrationAsync(array $args = [])
+ * @method \Aws\Result describeKnowledgeBase(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeKnowledgeBaseAsync(array $args = [])
+ * @method \Aws\Result describeKnowledgeBasePermissions(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeKnowledgeBasePermissionsAsync(array $args = [])
+ * @method \Aws\Result describeNamespace(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeNamespaceAsync(array $args = [])
+ * @method \Aws\Result describeOAuthClientApplication(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeOAuthClientApplicationAsync(array $args = [])
+ * @method \Aws\Result describeQPersonalizationConfiguration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeQPersonalizationConfigurationAsync(array $args = [])
+ * @method \Aws\Result describeQuickSightQSearchConfiguration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeQuickSightQSearchConfigurationAsync(array $args = [])
+ * @method \Aws\Result describeRefreshSchedule(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeRefreshScheduleAsync(array $args = [])
+ * @method \Aws\Result describeRoleCustomPermission(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeRoleCustomPermissionAsync(array $args = [])
+ * @method \Aws\Result describeSelfUpgradeConfiguration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeSelfUpgradeConfigurationAsync(array $args = [])
+ * @method \Aws\Result describeSpace(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeSpaceAsync(array $args = [])
+ * @method \Aws\Result describeSpacePermissions(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeSpacePermissionsAsync(array $args = [])
+ * @method \Aws\Result describeTemplate(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeTemplateAsync(array $args = [])
+ * @method \Aws\Result describeTemplateAlias(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeTemplateAliasAsync(array $args = [])
+ * @method \Aws\Result describeTemplateDefinition(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeTemplateDefinitionAsync(array $args = [])
+ * @method \Aws\Result describeTemplatePermissions(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeTemplatePermissionsAsync(array $args = [])
+ * @method \Aws\Result describeTheme(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeThemeAsync(array $args = [])
+ * @method \Aws\Result describeThemeAlias(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeThemeAliasAsync(array $args = [])
+ * @method \Aws\Result describeThemePermissions(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeThemePermissionsAsync(array $args = [])
+ * @method \Aws\Result describeTopic(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeTopicAsync(array $args = [])
+ * @method \Aws\Result describeTopicPermissions(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeTopicPermissionsAsync(array $args = [])
+ * @method \Aws\Result describeTopicRefresh(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeTopicRefreshAsync(array $args = [])
+ * @method \Aws\Result describeTopicRefreshSchedule(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeTopicRefreshScheduleAsync(array $args = [])
+ * @method \Aws\Result describeUser(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeUserAsync(array $args = [])
+ * @method \Aws\Result describeVPCConnection(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise describeVPCConnectionAsync(array $args = [])
+ * @method \Aws\Result generateEmbedUrlForAnonymousUser(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise generateEmbedUrlForAnonymousUserAsync(array $args = [])
+ * @method \Aws\Result generateEmbedUrlForRegisteredUser(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise generateEmbedUrlForRegisteredUserAsync(array $args = [])
+ * @method \Aws\Result generateEmbedUrlForRegisteredUserWithIdentity(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise generateEmbedUrlForRegisteredUserWithIdentityAsync(array $args = [])
+ * @method \Aws\Result getDashboardEmbedUrl(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getDashboardEmbedUrlAsync(array $args = [])
+ * @method \Aws\Result getFlowMetadata(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getFlowMetadataAsync(array $args = [])
+ * @method \Aws\Result getFlowPermissions(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getFlowPermissionsAsync(array $args = [])
+ * @method \Aws\Result getIdentityContext(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getIdentityContextAsync(array $args = [])
+ * @method \Aws\Result getSessionEmbedUrl(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getSessionEmbedUrlAsync(array $args = [])
+ * @method \Aws\Result listActionConnectors(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listActionConnectorsAsync(array $args = [])
+ * @method \Aws\Result listAgents(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listAgentsAsync(array $args = [])
+ * @method \Aws\Result listAnalyses(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listAnalysesAsync(array $args = [])
+ * @method \Aws\Result listAssetBundleExportJobs(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listAssetBundleExportJobsAsync(array $args = [])
+ * @method \Aws\Result listAssetBundleImportJobs(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listAssetBundleImportJobsAsync(array $args = [])
+ * @method \Aws\Result listBrands(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listBrandsAsync(array $args = [])
+ * @method \Aws\Result listCustomPermissions(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listCustomPermissionsAsync(array $args = [])
+ * @method \Aws\Result listDashboardVersions(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listDashboardVersionsAsync(array $args = [])
+ * @method \Aws\Result listDashboards(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listDashboardsAsync(array $args = [])
+ * @method \Aws\Result listDataSets(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listDataSetsAsync(array $args = [])
+ * @method \Aws\Result listDataSources(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listDataSourcesAsync(array $args = [])
+ * @method \Aws\Result listFlows(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listFlowsAsync(array $args = [])
+ * @method \Aws\Result listFolderMembers(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listFolderMembersAsync(array $args = [])
+ * @method \Aws\Result listFolders(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listFoldersAsync(array $args = [])
+ * @method \Aws\Result listFoldersForResource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listFoldersForResourceAsync(array $args = [])
+ * @method \Aws\Result listGroupMemberships(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listGroupMembershipsAsync(array $args = [])
+ * @method \Aws\Result listGroups(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listGroupsAsync(array $args = [])
+ * @method \Aws\Result listIAMPolicyAssignments(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listIAMPolicyAssignmentsAsync(array $args = [])
+ * @method \Aws\Result listIAMPolicyAssignmentsForUser(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listIAMPolicyAssignmentsForUserAsync(array $args = [])
+ * @method \Aws\Result listIdentityPropagationConfigs(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listIdentityPropagationConfigsAsync(array $args = [])
+ * @method \Aws\Result listIngestions(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listIngestionsAsync(array $args = [])
+ * @method \Aws\Result listKnowledgeBases(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listKnowledgeBasesAsync(array $args = [])
+ * @method \Aws\Result listNamespaces(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listNamespacesAsync(array $args = [])
+ * @method \Aws\Result listOAuthClientApplications(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listOAuthClientApplicationsAsync(array $args = [])
+ * @method \Aws\Result listRefreshSchedules(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listRefreshSchedulesAsync(array $args = [])
+ * @method \Aws\Result listRoleMemberships(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listRoleMembershipsAsync(array $args = [])
+ * @method \Aws\Result listSelfUpgrades(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listSelfUpgradesAsync(array $args = [])
+ * @method \Aws\Result listSpaceResources(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listSpaceResourcesAsync(array $args = [])
+ * @method \Aws\Result listSpaces(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listSpacesAsync(array $args = [])
+ * @method \Aws\Result listTagsForResource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listTagsForResourceAsync(array $args = [])
+ * @method \Aws\Result listTemplateAliases(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listTemplateAliasesAsync(array $args = [])
+ * @method \Aws\Result listTemplateVersions(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listTemplateVersionsAsync(array $args = [])
+ * @method \Aws\Result listTemplates(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listTemplatesAsync(array $args = [])
+ * @method \Aws\Result listThemeAliases(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listThemeAliasesAsync(array $args = [])
+ * @method \Aws\Result listThemeVersions(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listThemeVersionsAsync(array $args = [])
+ * @method \Aws\Result listThemes(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listThemesAsync(array $args = [])
+ * @method \Aws\Result listTopicRefreshSchedules(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listTopicRefreshSchedulesAsync(array $args = [])
+ * @method \Aws\Result listTopicReviewedAnswers(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listTopicReviewedAnswersAsync(array $args = [])
+ * @method \Aws\Result listTopics(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listTopicsAsync(array $args = [])
+ * @method \Aws\Result listUserGroups(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listUserGroupsAsync(array $args = [])
+ * @method \Aws\Result listUsers(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listUsersAsync(array $args = [])
+ * @method \Aws\Result listUsersIndexCapacity(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listUsersIndexCapacityAsync(array $args = [])
+ * @method \Aws\Result listVPCConnections(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listVPCConnectionsAsync(array $args = [])
+ * @method \Aws\Result predictQAResults(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise predictQAResultsAsync(array $args = [])
+ * @method \Aws\Result putDataSetRefreshProperties(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise putDataSetRefreshPropertiesAsync(array $args = [])
+ * @method \Aws\Result registerUser(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise registerUserAsync(array $args = [])
+ * @method \Aws\Result restoreAnalysis(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise restoreAnalysisAsync(array $args = [])
+ * @method \Aws\Result searchActionConnectors(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise searchActionConnectorsAsync(array $args = [])
+ * @method \Aws\Result searchAgents(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise searchAgentsAsync(array $args = [])
+ * @method \Aws\Result searchAnalyses(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise searchAnalysesAsync(array $args = [])
+ * @method \Aws\Result searchDashboards(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise searchDashboardsAsync(array $args = [])
+ * @method \Aws\Result searchDataSets(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise searchDataSetsAsync(array $args = [])
+ * @method \Aws\Result searchDataSources(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise searchDataSourcesAsync(array $args = [])
+ * @method \Aws\Result searchFlows(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise searchFlowsAsync(array $args = [])
+ * @method \Aws\Result searchFolders(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise searchFoldersAsync(array $args = [])
+ * @method \Aws\Result searchGroups(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise searchGroupsAsync(array $args = [])
+ * @method \Aws\Result searchKnowledgeBases(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise searchKnowledgeBasesAsync(array $args = [])
+ * @method \Aws\Result searchSpaces(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise searchSpacesAsync(array $args = [])
+ * @method \Aws\Result searchTopics(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise searchTopicsAsync(array $args = [])
+ * @method \Aws\Result startAssetBundleExportJob(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise startAssetBundleExportJobAsync(array $args = [])
+ * @method \Aws\Result startAssetBundleImportJob(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise startAssetBundleImportJobAsync(array $args = [])
+ * @method \Aws\Result startAutomationJob(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise startAutomationJobAsync(array $args = [])
+ * @method \Aws\Result startDashboardSnapshotJob(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise startDashboardSnapshotJobAsync(array $args = [])
+ * @method \Aws\Result startDashboardSnapshotJobSchedule(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise startDashboardSnapshotJobScheduleAsync(array $args = [])
+ * @method \Aws\Result tagResource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise tagResourceAsync(array $args = [])
+ * @method \Aws\Result untagResource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise untagResourceAsync(array $args = [])
+ * @method \Aws\Result updateAccountCustomPermission(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateAccountCustomPermissionAsync(array $args = [])
+ * @method \Aws\Result updateAccountCustomization(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateAccountCustomizationAsync(array $args = [])
+ * @method \Aws\Result updateAccountSettings(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateAccountSettingsAsync(array $args = [])
+ * @method \Aws\Result updateActionConnector(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateActionConnectorAsync(array $args = [])
+ * @method \Aws\Result updateActionConnectorPermissions(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateActionConnectorPermissionsAsync(array $args = [])
+ * @method \Aws\Result updateAgent(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateAgentAsync(array $args = [])
+ * @method \Aws\Result updateAgentPermissions(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateAgentPermissionsAsync(array $args = [])
+ * @method \Aws\Result updateAnalysis(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateAnalysisAsync(array $args = [])
+ * @method \Aws\Result updateAnalysisPermissions(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateAnalysisPermissionsAsync(array $args = [])
+ * @method \Aws\Result updateApplicationWithTokenExchangeGrant(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateApplicationWithTokenExchangeGrantAsync(array $args = [])
+ * @method \Aws\Result updateBrand(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateBrandAsync(array $args = [])
+ * @method \Aws\Result updateBrandAssignment(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateBrandAssignmentAsync(array $args = [])
+ * @method \Aws\Result updateBrandPublishedVersion(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateBrandPublishedVersionAsync(array $args = [])
+ * @method \Aws\Result updateCustomPermissions(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateCustomPermissionsAsync(array $args = [])
+ * @method \Aws\Result updateDashboard(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateDashboardAsync(array $args = [])
+ * @method \Aws\Result updateDashboardLinks(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateDashboardLinksAsync(array $args = [])
+ * @method \Aws\Result updateDashboardPermissions(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateDashboardPermissionsAsync(array $args = [])
+ * @method \Aws\Result updateDashboardPublishedVersion(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateDashboardPublishedVersionAsync(array $args = [])
+ * @method \Aws\Result updateDashboardsQAConfiguration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateDashboardsQAConfigurationAsync(array $args = [])
+ * @method \Aws\Result updateDataSet(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateDataSetAsync(array $args = [])
+ * @method \Aws\Result updateDataSetPermissions(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateDataSetPermissionsAsync(array $args = [])
+ * @method \Aws\Result updateDataSource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateDataSourceAsync(array $args = [])
+ * @method \Aws\Result updateDataSourcePermissions(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateDataSourcePermissionsAsync(array $args = [])
+ * @method \Aws\Result updateDefaultQBusinessApplication(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateDefaultQBusinessApplicationAsync(array $args = [])
+ * @method \Aws\Result updateFlow(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateFlowAsync(array $args = [])
+ * @method \Aws\Result updateFlowPermissions(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateFlowPermissionsAsync(array $args = [])
+ * @method \Aws\Result updateFolder(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateFolderAsync(array $args = [])
+ * @method \Aws\Result updateFolderPermissions(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateFolderPermissionsAsync(array $args = [])
+ * @method \Aws\Result updateGroup(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateGroupAsync(array $args = [])
+ * @method \Aws\Result updateIAMPolicyAssignment(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateIAMPolicyAssignmentAsync(array $args = [])
+ * @method \Aws\Result updateIdentityPropagationConfig(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateIdentityPropagationConfigAsync(array $args = [])
+ * @method \Aws\Result updateIpRestriction(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateIpRestrictionAsync(array $args = [])
+ * @method \Aws\Result updateKeyRegistration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateKeyRegistrationAsync(array $args = [])
+ * @method \Aws\Result updateKnowledgeBase(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateKnowledgeBaseAsync(array $args = [])
+ * @method \Aws\Result updateKnowledgeBasePermissions(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateKnowledgeBasePermissionsAsync(array $args = [])
+ * @method \Aws\Result updateOAuthClientApplication(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateOAuthClientApplicationAsync(array $args = [])
+ * @method \Aws\Result updatePublicSharingSettings(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updatePublicSharingSettingsAsync(array $args = [])
+ * @method \Aws\Result updateQPersonalizationConfiguration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateQPersonalizationConfigurationAsync(array $args = [])
+ * @method \Aws\Result updateQuickSightQSearchConfiguration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateQuickSightQSearchConfigurationAsync(array $args = [])
+ * @method \Aws\Result updateRefreshSchedule(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateRefreshScheduleAsync(array $args = [])
+ * @method \Aws\Result updateRoleCustomPermission(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateRoleCustomPermissionAsync(array $args = [])
+ * @method \Aws\Result updateSPICECapacityConfiguration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateSPICECapacityConfigurationAsync(array $args = [])
+ * @method \Aws\Result updateSelfUpgrade(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateSelfUpgradeAsync(array $args = [])
+ * @method \Aws\Result updateSelfUpgradeConfiguration(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateSelfUpgradeConfigurationAsync(array $args = [])
+ * @method \Aws\Result updateSpace(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateSpaceAsync(array $args = [])
+ * @method \Aws\Result updateSpacePermissions(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateSpacePermissionsAsync(array $args = [])
+ * @method \Aws\Result updateSpaceResources(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateSpaceResourcesAsync(array $args = [])
+ * @method \Aws\Result updateTemplate(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateTemplateAsync(array $args = [])
+ * @method \Aws\Result updateTemplateAlias(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateTemplateAliasAsync(array $args = [])
+ * @method \Aws\Result updateTemplatePermissions(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateTemplatePermissionsAsync(array $args = [])
+ * @method \Aws\Result updateTheme(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateThemeAsync(array $args = [])
+ * @method \Aws\Result updateThemeAlias(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateThemeAliasAsync(array $args = [])
+ * @method \Aws\Result updateThemePermissions(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateThemePermissionsAsync(array $args = [])
+ * @method \Aws\Result updateTopic(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateTopicAsync(array $args = [])
+ * @method \Aws\Result updateTopicPermissions(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateTopicPermissionsAsync(array $args = [])
+ * @method \Aws\Result updateTopicRefreshSchedule(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateTopicRefreshScheduleAsync(array $args = [])
+ * @method \Aws\Result updateUser(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateUserAsync(array $args = [])
+ * @method \Aws\Result updateUserCustomPermission(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateUserCustomPermissionAsync(array $args = [])
+ * @method \Aws\Result updateVPCConnection(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateVPCConnectionAsync(array $args = [])
+ */
+class QuickSightClient extends AwsClient {}

+ 9 - 0
upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/Resiliencehubv2/Exception/Resiliencehubv2Exception.php

@@ -0,0 +1,9 @@
+<?php
+namespace Aws\Resiliencehubv2\Exception;
+
+use Aws\Exception\AwsException;
+
+/**
+ * Represents an error interacting with the **AWS Resilience Hub V2** service.
+ */
+class Resiliencehubv2Exception extends AwsException {}

+ 111 - 0
upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/Resiliencehubv2/Resiliencehubv2Client.php

@@ -0,0 +1,111 @@
+<?php
+namespace Aws\Resiliencehubv2;
+
+use Aws\AwsClient;
+
+/**
+ * This client is used to interact with the **AWS Resilience Hub V2** service.
+ * @method \Aws\Result createAssertion(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createAssertionAsync(array $args = [])
+ * @method \Aws\Result createInputSource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createInputSourceAsync(array $args = [])
+ * @method \Aws\Result createPolicy(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createPolicyAsync(array $args = [])
+ * @method \Aws\Result createReport(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createReportAsync(array $args = [])
+ * @method \Aws\Result createService(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createServiceAsync(array $args = [])
+ * @method \Aws\Result createServiceFunction(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createServiceFunctionAsync(array $args = [])
+ * @method \Aws\Result createServiceFunctionResources(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createServiceFunctionResourcesAsync(array $args = [])
+ * @method \Aws\Result createSystem(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createSystemAsync(array $args = [])
+ * @method \Aws\Result createUserJourney(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createUserJourneyAsync(array $args = [])
+ * @method \Aws\Result deleteAssertion(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteAssertionAsync(array $args = [])
+ * @method \Aws\Result deleteInputSource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteInputSourceAsync(array $args = [])
+ * @method \Aws\Result deletePolicy(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deletePolicyAsync(array $args = [])
+ * @method \Aws\Result deleteService(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteServiceAsync(array $args = [])
+ * @method \Aws\Result deleteServiceFunction(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteServiceFunctionAsync(array $args = [])
+ * @method \Aws\Result deleteServiceFunctionResources(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteServiceFunctionResourcesAsync(array $args = [])
+ * @method \Aws\Result deleteSystem(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteSystemAsync(array $args = [])
+ * @method \Aws\Result deleteUserJourney(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteUserJourneyAsync(array $args = [])
+ * @method \Aws\Result getFailureModeFinding(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getFailureModeFindingAsync(array $args = [])
+ * @method \Aws\Result getPolicy(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getPolicyAsync(array $args = [])
+ * @method \Aws\Result getService(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getServiceAsync(array $args = [])
+ * @method \Aws\Result getSystem(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getSystemAsync(array $args = [])
+ * @method \Aws\Result getUserJourney(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getUserJourneyAsync(array $args = [])
+ * @method \Aws\Result importApp(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise importAppAsync(array $args = [])
+ * @method \Aws\Result importPolicy(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise importPolicyAsync(array $args = [])
+ * @method \Aws\Result listAssertions(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listAssertionsAsync(array $args = [])
+ * @method \Aws\Result listDependencies(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listDependenciesAsync(array $args = [])
+ * @method \Aws\Result listFailureModeAssessments(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listFailureModeAssessmentsAsync(array $args = [])
+ * @method \Aws\Result listFailureModeFindings(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listFailureModeFindingsAsync(array $args = [])
+ * @method \Aws\Result listInputSources(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listInputSourcesAsync(array $args = [])
+ * @method \Aws\Result listPolicies(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listPoliciesAsync(array $args = [])
+ * @method \Aws\Result listReports(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listReportsAsync(array $args = [])
+ * @method \Aws\Result listResources(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listResourcesAsync(array $args = [])
+ * @method \Aws\Result listServiceEvents(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listServiceEventsAsync(array $args = [])
+ * @method \Aws\Result listServiceFunctions(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listServiceFunctionsAsync(array $args = [])
+ * @method \Aws\Result listServiceTopologyEdges(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listServiceTopologyEdgesAsync(array $args = [])
+ * @method \Aws\Result listServices(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listServicesAsync(array $args = [])
+ * @method \Aws\Result listSystemEvents(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listSystemEventsAsync(array $args = [])
+ * @method \Aws\Result listSystems(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listSystemsAsync(array $args = [])
+ * @method \Aws\Result listTagsForResource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listTagsForResourceAsync(array $args = [])
+ * @method \Aws\Result listUserJourneys(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listUserJourneysAsync(array $args = [])
+ * @method \Aws\Result startFailureModeAssessment(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise startFailureModeAssessmentAsync(array $args = [])
+ * @method \Aws\Result tagResource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise tagResourceAsync(array $args = [])
+ * @method \Aws\Result untagResource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise untagResourceAsync(array $args = [])
+ * @method \Aws\Result updateAssertion(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateAssertionAsync(array $args = [])
+ * @method \Aws\Result updateDependency(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateDependencyAsync(array $args = [])
+ * @method \Aws\Result updateFailureModeFinding(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateFailureModeFindingAsync(array $args = [])
+ * @method \Aws\Result updatePolicy(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updatePolicyAsync(array $args = [])
+ * @method \Aws\Result updateService(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateServiceAsync(array $args = [])
+ * @method \Aws\Result updateServiceFunction(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateServiceFunctionAsync(array $args = [])
+ * @method \Aws\Result updateSystem(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateSystemAsync(array $args = [])
+ * @method \Aws\Result updateUserJourney(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateUserJourneyAsync(array $args = [])
+ */
+class Resiliencehubv2Client extends AwsClient {}

+ 464 - 0
upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/Retry/V3/RetryMiddleware.php

@@ -0,0 +1,464 @@
+<?php
+namespace Aws\Retry\V3;
+
+use Aws\CommandInterface;
+use Aws\Exception\AwsException;
+use Aws\MonitoringEventsInterface;
+use Aws\ResultInterface;
+use Aws\Retry\ConfigurationInterface;
+use Aws\Retry\RateLimiter;
+use Aws\Retry\RetryHelperTrait;
+use GuzzleHttp\Exception\RequestException;
+use GuzzleHttp\Promise;
+use GuzzleHttp\Promise\PromiseInterface;
+use Psr\Http\Message\RequestInterface;
+
+/**
+ * Retry middleware for the AWS_NEW_RETRIES_2026 opt-in path. Implements
+ * the spec-defined behavior for 'standard' and 'adaptive' modes:
+ * throttling-aware quota, retry-after header support, max-attempts
+ * before quota in the decision order, supplemental customer deciders,
+ * and long-polling sleep on quota exhaustion.
+ *
+ * @internal
+ */
+class RetryMiddleware
+{
+    use RetryHelperTrait;
+
+    private const THROTTLING_BASE_DELAY_MS = 1_000;
+    private const DEFAULT_BASE_DELAY_MS = 50;
+    private const DEFAULT_MAX_BACKOFF_MS = 20_000;
+    private const RETRY_AFTER_HEADER = 'x-amz-retry-after';
+
+    private static array $standardThrottlingErrors = [
+        'Throttling'                                => true,
+        'ThrottlingException'                       => true,
+        'ThrottledException'                        => true,
+        'RequestThrottledException'                 => true,
+        'TooManyRequestsException'                  => true,
+        'ProvisionedThroughputExceededException'    => true,
+        'TransactionInProgressException'            => true,
+        'RequestLimitExceeded'                      => true,
+        'BandwidthLimitExceeded'                    => true,
+        'LimitExceededException'                    => true,
+        'RequestThrottled'                          => true,
+        'SlowDown'                                  => true,
+        'PriorRequestNotComplete'                   => true,
+        'EC2ThrottledException'                     => true,
+    ];
+
+    private static array $standardTransientErrors = [
+        'RequestTimeout'            => true,
+        'RequestTimeoutException'   => true,
+    ];
+
+    private static array $standardTransientStatusCodes = [
+        500 => true,
+        502 => true,
+        503 => true,
+        504 => true,
+    ];
+
+    private float $baseDelayMs;
+    private bool $collectStats;
+    private ?\Closure $customDecider;
+    private ?\Closure $delayer;
+    private ?float $exponentialBase;
+    private int $maxAttempts;
+    private int $maxBackoffMs;
+    private string $mode;
+    private \Closure $nextHandler;
+    private array $options;
+    private QuotaManager $quotaManager;
+    private ?RateLimiter $rateLimiter = null;
+    private array $retryCurlErrors;
+    private ?string $service;
+
+    public static function wrap(ConfigurationInterface $config, array $options): \Closure
+    {
+        return function (callable $handler) use ($config, $options) {
+            return new static($config, $handler, $options);
+        };
+    }
+
+    /**
+     * Returns a closure that decides retryability for a given result based
+     * on the standard error codes, status codes, and curl errors. Quota and
+     * max-attempts decisions are handled by the middleware itself, not by
+     * this closure.
+     */
+    public static function createDefaultDecider(array $options = []): \Closure
+    {
+        $retryCurlErrors = [];
+        if (extension_loaded('curl')) {
+            $retryCurlErrors[CURLE_RECV_ERROR] = true;
+        }
+
+        return function (
+            int $attempts,
+            CommandInterface $command,
+            mixed $result
+        ) use ($options, $retryCurlErrors): bool {
+            return self::isRetryable($result, $retryCurlErrors, $options);
+        };
+    }
+
+    public function __construct(
+        ConfigurationInterface $config,
+        callable $handler,
+        array $options = []
+    ) {
+        $this->options = $options;
+        $this->maxAttempts = $config->getMaxAttempts();
+        $this->mode = $config->getMode();
+        $this->nextHandler = $handler(...);
+        $this->service = $options['service'] ?? null;
+        $this->quotaManager = $options['quota_manager'] ?? new QuotaManager();
+        $this->maxBackoffMs = $options['max_backoff'] ?? self::DEFAULT_MAX_BACKOFF_MS;
+        $this->baseDelayMs = $options['base_delay'] ?? self::DEFAULT_BASE_DELAY_MS;
+        $this->exponentialBase = $options['exponential_base'] ?? null;
+        $this->collectStats = (bool) ($options['collect_stats'] ?? false);
+
+        $this->customDecider = isset($options['decider'])
+            ? ($options['decider'])(...)
+            : null;
+
+        $this->delayer = isset($options['delayer'])
+            ? ($options['delayer'])(...)
+            : null;
+
+        $this->retryCurlErrors = [];
+        if (extension_loaded('curl')) {
+            $this->retryCurlErrors[CURLE_RECV_ERROR] = true;
+        }
+        if (!empty($options['curl_errors']) && is_array($options['curl_errors'])) {
+            foreach ($options['curl_errors'] as $code) {
+                $this->retryCurlErrors[$code] = true;
+            }
+        }
+
+        if ($this->mode === 'adaptive') {
+            $this->rateLimiter = $options['rate_limiter'] ?? new RateLimiter();
+        }
+    }
+
+    public function __invoke(CommandInterface $cmd, RequestInterface $req): PromiseInterface
+    {
+        $handler = $this->nextHandler;
+
+        $attempts = 1;
+        $monitoringEvents = [];
+        $requestStats = [];
+        $capacityUsed = null;
+
+        $req = $this->addRetryHeader($req, 0, 0);
+
+        $callback = function ($value) use (
+            $handler,
+            $cmd,
+            $req,
+            &$attempts,
+            &$requestStats,
+            &$monitoringEvents,
+            &$callback,
+            &$capacityUsed
+        ) {
+            if ($this->mode === 'adaptive') {
+                $this->rateLimiter->updateSendingRate($this->isThrottlingError($value));
+            }
+
+            $this->updateHttpStats($value, $requestStats);
+
+            if ($value instanceof MonitoringEventsInterface) {
+                $reversedEvents = array_reverse($monitoringEvents);
+                $monitoringEvents = array_merge($monitoringEvents, $value->getMonitoringEvents());
+                foreach ($reversedEvents as $event) {
+                    $value->prependMonitoringEvent($event);
+                }
+            }
+
+            $isError = $value instanceof \Throwable;
+
+            $isSuccess = false;
+            if (!$isError && $value instanceof ResultInterface) {
+                $statusCode = isset($value['@metadata']['statusCode'])
+                    ? (int) $value['@metadata']['statusCode']
+                    : null;
+                if (!empty($statusCode) && $statusCode >= 200 && $statusCode < 300) {
+                    $isSuccess = true;
+                }
+            }
+
+            if ($isSuccess) {
+                $this->quotaManager->releaseQuota($capacityUsed);
+                $callback = null;
+                return $this->bindStatsToReturn($value, $requestStats);
+            }
+
+            $isRetryable = self::isRetryable(
+                $value,
+                $this->retryCurlErrors,
+                $this->options
+            );
+
+            // Custom decider supplements default retryability
+            if (!$isRetryable && $this->customDecider !== null) {
+                $isRetryable = ($this->customDecider)($attempts, $cmd, $value);
+            }
+
+            if (!$isRetryable) {
+                if ($isError) {
+                    $callback = null;
+                    return Promise\Create::rejectionFor(
+                        $this->bindStatsToReturn($value, $requestStats)
+                    );
+                }
+                $callback = null;
+                return $this->bindStatsToReturn($value, $requestStats);
+            }
+
+            // Max attempts is checked before retry quota.
+            $maxAttempts = ($cmd['@retries'] !== null)
+                ? $cmd['@retries'] + 1
+                : $this->maxAttempts;
+
+            if ($attempts >= $maxAttempts) {
+                if ($value instanceof AwsException) {
+                    $value->setMaxRetriesExceeded();
+                }
+                if ($isError) {
+                    $callback = null;
+                    return Promise\Create::rejectionFor(
+                        $this->bindStatsToReturn($value, $requestStats)
+                    );
+                }
+                $callback = null;
+                return $this->bindStatsToReturn($value, $requestStats);
+            }
+
+            $isThrottling = $this->isThrottlingError($value);
+            $attemptIndex = $attempts - 1;
+            $delayByMs = $this->computeRetryDelay(
+                $attemptIndex,
+                $isThrottling,
+                $value
+            );
+
+            $acquired = $this->quotaManager->acquireRetryQuota($isThrottling);
+            if ($acquired === false) {
+                // Long-polling: sleep and surface the error rather than retry.
+                if (LongPolling::isLongPolling($this->service, $cmd->getName())) {
+                    $cmd['@http']['delay'] = $delayByMs;
+                    usleep((int) ($delayByMs * 1000));
+                }
+
+                if ($isError) {
+                    $callback = null;
+                    return Promise\Create::rejectionFor(
+                        $this->bindStatsToReturn($value, $requestStats)
+                    );
+                }
+                $callback = null;
+                return $this->bindStatsToReturn($value, $requestStats);
+            }
+            $capacityUsed = $acquired;
+
+            if ($this->delayer !== null) {
+                $delayByMs = ($this->delayer)($attempts);
+            }
+
+            $attempts++;
+            $cmd['@http']['delay'] = $delayByMs;
+
+            if ($this->collectStats) {
+                $this->updateStats($attempts - 1, $delayByMs, $requestStats);
+            }
+
+            $req = $this->addRetryHeader($req, $attempts - 1, $delayByMs);
+
+            if ($this->mode === 'adaptive') {
+                $this->rateLimiter->getSendToken();
+            }
+
+            return $handler($cmd, $req)->then($callback, $callback);
+        };
+
+        if ($this->mode === 'adaptive') {
+            $this->rateLimiter->getSendToken();
+        }
+
+        return $handler($cmd, $req)->then($callback, $callback);
+    }
+
+    public function exponentialDelayWithJitter(int $attempts): int
+    {
+        return $this->computeRetryDelay($attempts - 1, false, null);
+    }
+
+    private function computeRetryDelay(int $attemptIndex, bool $isThrottling, mixed $value): int
+    {
+        $baseMs = $isThrottling
+            ? self::THROTTLING_BASE_DELAY_MS
+            : $this->baseDelayMs;
+
+        if ($this->exponentialBase !== null) {
+            $jitter = $this->exponentialBase;
+        } else {
+            $max = mt_getrandmax();
+            try {
+                $jitter = random_int(0, $max) / $max;
+            } catch (\Exception $_) {
+                $jitter = mt_rand(0, $max) / $max;
+            }
+        }
+
+        $delayMs = $jitter * min(
+            $baseMs * pow(2, $attemptIndex),
+            $this->maxBackoffMs
+        );
+
+        $retryAfterHeader = null;
+        if ($value instanceof AwsException) {
+            $response = $value->getResponse();
+            $retryAfterHeader = $response?->getHeaderLine(
+                self::RETRY_AFTER_HEADER
+            ) ?? null;
+        } elseif ($value instanceof ResultInterface) {
+            $retryAfterHeader = $value['@metadata']['headers'][
+                self::RETRY_AFTER_HEADER
+            ] ?? null;
+        }
+
+        if (ctype_digit((string) $retryAfterHeader)) {
+            $retryAfterMs = (int) $retryAfterHeader;
+            $retryAfterMs = max($retryAfterMs, $delayMs);
+            $retryAfterMs = min($retryAfterMs, 5000 + $delayMs);
+            $delayMs = $retryAfterMs;
+        }
+
+        return (int) $delayMs;
+    }
+
+    private static function isRetryable(
+        mixed $result,
+        array $retryCurlErrors,
+        array $options = []
+    ): bool
+    {
+        $errorCodes = self::$standardThrottlingErrors + self::$standardTransientErrors;
+        if (!empty($options['transient_error_codes'])
+            && is_array($options['transient_error_codes'])
+        ) {
+            foreach ($options['transient_error_codes'] as $code) {
+                $errorCodes[$code] = true;
+            }
+        }
+        if (!empty($options['throttling_error_codes'])
+            && is_array($options['throttling_error_codes'])
+        ) {
+            foreach ($options['throttling_error_codes'] as $code) {
+                $errorCodes[$code] = true;
+            }
+        }
+
+        $statusCodes = self::$standardTransientStatusCodes;
+        if (!empty($options['status_codes'])
+            && is_array($options['status_codes'])
+        ) {
+            foreach ($options['status_codes'] as $code) {
+                $statusCodes[$code] = true;
+            }
+        }
+
+        if (!empty($options['curl_errors'])
+            && is_array($options['curl_errors'])
+        ) {
+            foreach ($options['curl_errors'] as $code) {
+                $retryCurlErrors[$code] = true;
+            }
+        }
+
+        $isError = $result instanceof \Throwable;
+
+        if (!$isError) {
+            if (!isset($result['@metadata']['statusCode'])) {
+                return false;
+            }
+            return isset($statusCodes[$result['@metadata']['statusCode']]);
+        }
+
+        if (!($result instanceof AwsException)) {
+            return false;
+        }
+
+        if ($result->isConnectionError()) {
+            return true;
+        }
+
+        $awsCode = $result->getAwsErrorCode();
+        if ($awsCode !== null && isset($errorCodes[$awsCode])) {
+            return true;
+        }
+
+        $status = $result->getStatusCode();
+        if ($status !== null && isset($statusCodes[$status])) {
+            return true;
+        }
+
+        if (count($retryCurlErrors)
+            && ($previous = $result->getPrevious())
+            && $previous instanceof RequestException
+        ) {
+            if (method_exists($previous, 'getHandlerContext')) {
+                $context = $previous->getHandlerContext();
+                return !empty($context['errno'])
+                    && isset($retryCurlErrors[$context['errno']]);
+            }
+
+            $message = $previous->getMessage();
+            foreach (array_keys($retryCurlErrors) as $curlError) {
+                if (str_starts_with($message, 'cURL error ' . $curlError . ':')) {
+                    return true;
+                }
+            }
+        }
+
+        if (!empty($errorShape = $result->getAwsErrorShape())) {
+            $definition = $errorShape->toArray();
+            if (!empty($definition['retryable'])) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    private function isThrottlingError(mixed $result): bool
+    {
+        if ($result instanceof AwsException) {
+            $throttlingErrors = self::$standardThrottlingErrors;
+            if (!empty($this->options['throttling_error_codes'])
+                && is_array($this->options['throttling_error_codes'])
+            ) {
+                foreach ($this->options['throttling_error_codes'] as $code) {
+                    $throttlingErrors[$code] = true;
+                }
+            }
+            if (!empty($result->getAwsErrorCode())
+                && !empty($throttlingErrors[$result->getAwsErrorCode()])
+            ) {
+                return true;
+            }
+
+            if (!empty($errorShape = $result->getAwsErrorShape())) {
+                $definition = $errorShape->toArray();
+                if (!empty($definition['retryable']['throttling'])) {
+                    return true;
+                }
+            }
+        }
+
+        return false;
+    }
+}

+ 281 - 0
upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/RetryMiddleware.php

@@ -0,0 +1,281 @@
+<?php
+namespace Aws;
+
+use Aws\Exception\AwsException;
+use Aws\Retry\RetryHelperTrait;
+use GuzzleHttp\Exception\RequestException;
+use Psr\Http\Message\RequestInterface;
+use GuzzleHttp\Promise\PromiseInterface;
+use GuzzleHttp\Promise;
+
+/**
+ * Middleware that retries failures. V1 implemention that supports 'legacy' mode.
+ *
+ * @internal
+ */
+class RetryMiddleware
+{
+    use RetryHelperTrait;
+
+    private static $retryStatusCodes = [
+        500 => true,
+        502 => true,
+        503 => true,
+        504 => true
+    ];
+
+    private static $retryCodes = [
+        // Throttling error
+        'RequestLimitExceeded'                   => true,
+        'Throttling'                             => true,
+        'ThrottlingException'                    => true,
+        'ThrottledException'                     => true,
+        'ProvisionedThroughputExceededException' => true,
+        'RequestThrottled'                       => true,
+        'BandwidthLimitExceeded'                 => true,
+        'RequestThrottledException'              => true,
+        'TooManyRequestsException'               => true,
+        'IDPCommunicationError'                  => true,
+        'EC2ThrottledException'                  => true,
+    ];
+
+    private $decider;
+    private $delay;
+    private $nextHandler;
+    private $collectStats;
+
+    public function __construct(
+        callable $decider,
+        callable $delay,
+        callable $nextHandler,
+        $collectStats = false
+    ) {
+        $this->decider = $decider;
+        $this->delay = $delay;
+        $this->nextHandler = $nextHandler;
+        $this->collectStats = (bool) $collectStats;
+    }
+
+    /**
+     * Creates a default AWS retry decider function.
+     *
+     * The optional $extraConfig parameter is an associative array
+     * that specifies additional retry conditions on top of the ones specified
+     * by default by the Aws\RetryMiddleware class, with the following keys:
+     *
+     * - errorCodes: (string[]) An indexed array of AWS exception codes to retry.
+     *   Optional.
+     * - statusCodes: (int[]) An indexed array of HTTP status codes to retry.
+     *   Optional.
+     * - curlErrors: (int[]) An indexed array of Curl error codes to retry. Note
+     *   these should be valid Curl constants. Optional.
+     *
+     * @param int $maxRetries
+     * @param array $extraConfig
+     * @return callable
+     */
+    public static function createDefaultDecider(
+        $maxRetries = 3,
+        $extraConfig = []
+    ) {
+        $retryCurlErrors = [];
+        if (extension_loaded('curl')) {
+            $retryCurlErrors[CURLE_RECV_ERROR] = true;
+        }
+
+        return function (
+            $retries,
+            CommandInterface $command,
+            RequestInterface $request,
+            ?ResultInterface $result = null,
+            $error = null
+        ) use ($maxRetries, $retryCurlErrors, $extraConfig) {
+            // Allow command-level options to override this value
+            $maxRetries = null !== $command['@retries'] ?
+                $command['@retries']
+                : $maxRetries;
+
+            $isRetryable = self::isRetryable(
+                $result,
+                $error,
+                $retryCurlErrors,
+                $extraConfig
+            );
+
+            if ($retries >= $maxRetries) {
+                if (!empty($error)
+                    && $error instanceof AwsException
+                    && $isRetryable
+                ) {
+                    $error->setMaxRetriesExceeded();
+                }
+                return false;
+            }
+
+            return $isRetryable;
+        };
+    }
+
+    private static function isRetryable(
+        $result,
+        $error,
+        $retryCurlErrors,
+        $extraConfig = []
+    ) {
+        $errorCodes = self::$retryCodes;
+        if (!empty($extraConfig['error_codes'])
+            && is_array($extraConfig['error_codes'])
+        ) {
+            foreach($extraConfig['error_codes'] as $code) {
+                $errorCodes[$code] = true;
+            }
+        }
+
+        $statusCodes = self::$retryStatusCodes;
+        if (!empty($extraConfig['status_codes'])
+            && is_array($extraConfig['status_codes'])
+        ) {
+            foreach($extraConfig['status_codes'] as $code) {
+                $statusCodes[$code] = true;
+            }
+        }
+
+        if (!empty($extraConfig['curl_errors'])
+            && is_array($extraConfig['curl_errors'])
+        ) {
+            foreach($extraConfig['curl_errors'] as $code) {
+                $retryCurlErrors[$code] = true;
+            }
+        }
+
+        if (!$error) {
+            if (!isset($result['@metadata']['statusCode'])) {
+                return false;
+            }
+            return isset($statusCodes[$result['@metadata']['statusCode']]);
+        }
+
+        if (!($error instanceof AwsException)) {
+            return false;
+        }
+
+        if ($error->isConnectionError()) {
+            return true;
+        }
+
+        $awsCode = $error->getAwsErrorCode();
+        if (!is_null($awsCode) && isset($errorCodes[$awsCode])) {
+            return true;
+        }
+
+        $status = $error->getStatusCode();
+        if (!is_null($status) && isset($statusCodes[$status])) {
+            return true;
+        }
+
+        if (count($retryCurlErrors)
+            && ($previous = $error->getPrevious())
+            && $previous instanceof RequestException
+        ) {
+            if (method_exists($previous, 'getHandlerContext')) {
+                $context = $previous->getHandlerContext();
+                return !empty($context['errno'])
+                    && isset($retryCurlErrors[$context['errno']]);
+            }
+
+            $message = $previous->getMessage();
+            foreach (array_keys($retryCurlErrors) as $curlError) {
+                if (strpos($message, 'cURL error ' . $curlError . ':') === 0) {
+                    return true;
+                }
+            }
+        }
+
+        return false;
+    }
+
+    /**
+     * Delay function that calculates an exponential delay.
+     *
+     * Exponential backoff with jitter, 100ms base, 20 sec ceiling
+     *
+     * @param $retries - The number of retries that have already been attempted
+     *
+     * @return int
+     *
+     * @link https://aws.amazon.com/blogs/architecture/exponential-backoff-and-jitter/
+     */
+    public static function exponentialDelay($retries)
+    {
+        return mt_rand(0, (int) min(20000, (int) pow(2, $retries) * 100));
+    }
+
+    /**
+     * @param CommandInterface $command
+     * @param RequestInterface $request
+     *
+     * @return PromiseInterface
+     */
+    public function __invoke(
+        CommandInterface $command,
+        ?RequestInterface $request = null
+    ) {
+        $retries = 0;
+        $requestStats = [];
+        $monitoringEvents = [];
+        $handler = $this->nextHandler;
+        $decider = $this->decider;
+        $delay = $this->delay;
+
+        $request = $this->addRetryHeader($request, 0, 0);
+
+        $g = function ($value) use (
+            $handler,
+            $decider,
+            $delay,
+            $command,
+            $request,
+            &$retries,
+            &$requestStats,
+            &$monitoringEvents,
+            &$g
+        ) {
+            $this->updateHttpStats($value, $requestStats);
+
+            if ($value instanceof MonitoringEventsInterface) {
+                $reversedEvents = array_reverse($monitoringEvents);
+                $monitoringEvents = array_merge($monitoringEvents, $value->getMonitoringEvents());
+                foreach ($reversedEvents as $event) {
+                    $value->prependMonitoringEvent($event);
+                }
+            }
+            if ($value instanceof \Exception || $value instanceof \Throwable) {
+                if (!$decider($retries, $command, $request, null, $value)) {
+                    $g = null;
+                    return Promise\Create::rejectionFor(
+                        $this->bindStatsToReturn($value, $requestStats)
+                    );
+                }
+            } elseif ($value instanceof ResultInterface
+                && !$decider($retries, $command, $request, $value, null)
+            ) {
+                $g = null;
+                return $this->bindStatsToReturn($value, $requestStats);
+            }
+
+            // Delay fn is called with 0, 1, ... so increment after the call.
+            $delayBy = $delay($retries++);
+            $command['@http']['delay'] = $delayBy;
+            if ($this->collectStats) {
+                $this->updateStats($retries, $delayBy, $requestStats);
+            }
+
+            // Update retry header with retry count and delayBy
+            $request = $this->addRetryHeader($request, $retries, $delayBy);
+
+            return $handler($command, $request)->then($g, $g);
+        };
+
+        return $handler($command, $request)->then($g, $g);
+    }
+}

+ 389 - 0
upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/RetryMiddlewareV2.php

@@ -0,0 +1,389 @@
+<?php
+namespace Aws;
+
+use Aws\Exception\AwsException;
+use Aws\Retry\ConfigurationInterface;
+use Aws\Retry\QuotaManager;
+use Aws\Retry\RateLimiter;
+use Aws\Retry\RetryHelperTrait;
+use Exception;
+use GuzzleHttp\Exception\RequestException;
+use GuzzleHttp\Promise;
+use Psr\Http\Message\RequestInterface;
+
+/**
+ * Middleware that retries failures. V2 implementation that supports 'standard'
+ * and 'adaptive' modes.
+ *
+ * @internal
+ */
+class RetryMiddlewareV2
+{
+    use RetryHelperTrait;
+
+    private static $standardThrottlingErrors = [
+        'Throttling'                                => true,
+        'ThrottlingException'                       => true,
+        'ThrottledException'                        => true,
+        'RequestThrottledException'                 => true,
+        'TooManyRequestsException'                  => true,
+        'ProvisionedThroughputExceededException'    => true,
+        'TransactionInProgressException'            => true,
+        'RequestLimitExceeded'                      => true,
+        'BandwidthLimitExceeded'                    => true,
+        'LimitExceededException'                    => true,
+        'RequestThrottled'                          => true,
+        'SlowDown'                                  => true,
+        'PriorRequestNotComplete'                   => true,
+        'EC2ThrottledException'                     => true,
+    ];
+
+    private static $standardTransientErrors = [
+        'RequestTimeout'            => true,
+        'RequestTimeoutException'   => true,
+    ];
+
+    private static $standardTransientStatusCodes = [
+        500 => true,
+        502 => true,
+        503 => true,
+        504 => true,
+    ];
+
+    private $collectStats;
+    private $decider;
+    private $delayer;
+    private $maxAttempts;
+    private $maxBackoff;
+    private $mode;
+    private $nextHandler;
+    private $options;
+    private $quotaManager;
+    private $rateLimiter;
+
+    public static function wrap($config, $options)
+    {
+        return function (callable $handler) use (
+            $config,
+            $options
+        ) {
+            return new static(
+                $config,
+                $handler,
+                $options
+            );
+        };
+    }
+
+    public static function createDefaultDecider(
+        QuotaManager $quotaManager,
+        $maxAttempts = 3,
+        $options = []
+    ) {
+        $retryCurlErrors = [];
+        if (extension_loaded('curl')) {
+            $retryCurlErrors[CURLE_RECV_ERROR] = true;
+        }
+
+        return function(
+            $attempts,
+            CommandInterface $command,
+            $result
+        ) use ($options, $quotaManager, $retryCurlErrors, $maxAttempts) {
+
+            // Release retry tokens back to quota on a successful result
+            $quotaManager->releaseToQuota($result);
+
+            // Allow command-level option to override this value
+            // # of attempts = # of retries + 1
+            $maxAttempts = (null !== $command['@retries'])
+                ? $command['@retries'] + 1
+                : $maxAttempts;
+
+            $isRetryable = self::isRetryable(
+                $result,
+                $retryCurlErrors,
+                $options
+            );
+
+            if ($isRetryable) {
+
+                // Retrieve retry tokens and check if quota has been exceeded
+                if (!$quotaManager->hasRetryQuota($result)) {
+                    return false;
+                }
+
+                if ($attempts >= $maxAttempts) {
+                    if (!empty($result) && $result instanceof AwsException) {
+                        $result->setMaxRetriesExceeded();
+                    }
+                    return false;
+                }
+            }
+
+            return $isRetryable;
+        };
+    }
+
+    public function __construct(
+        ConfigurationInterface $config,
+        callable $handler,
+        $options = []
+    ) {
+        $this->options = $options;
+        $this->maxAttempts = $config->getMaxAttempts();
+        $this->mode = $config->getMode();
+        $this->nextHandler = $handler;
+        $this->quotaManager = new QuotaManager();
+
+        $this->maxBackoff = isset($options['max_backoff'])
+            ? $options['max_backoff']
+            : 20000;
+
+        $this->collectStats = isset($options['collect_stats'])
+            ? (bool) $options['collect_stats']
+            : false;
+
+        $this->decider = isset($options['decider'])
+            ? $options['decider']
+            : self::createDefaultDecider(
+                $this->quotaManager,
+                $this->maxAttempts,
+                $options
+            );
+
+        $this->delayer = isset($options['delayer'])
+            ? $options['delayer']
+            : function ($attempts) {
+                return $this->exponentialDelayWithJitter($attempts);
+            };
+
+        if ($this->mode === 'adaptive') {
+            $this->rateLimiter = isset($options['rate_limiter'])
+                ? $options['rate_limiter']
+                : new RateLimiter();
+        }
+    }
+
+    public function __invoke(CommandInterface $cmd, RequestInterface $req)
+    {
+        $decider = $this->decider;
+        $delayer = $this->delayer;
+        $handler = $this->nextHandler;
+
+        $attempts = 1;
+        $monitoringEvents = [];
+        $requestStats = [];
+
+        $req = $this->addRetryHeader($req, 0, 0);
+
+        $callback = function ($value) use (
+            $handler,
+            $cmd,
+            $req,
+            $decider,
+            $delayer,
+            &$attempts,
+            &$requestStats,
+            &$monitoringEvents,
+            &$callback
+        ) {
+            if ($this->mode === 'adaptive') {
+                $this->rateLimiter->updateSendingRate($this->isThrottlingError($value));
+            }
+
+            $this->updateHttpStats($value, $requestStats);
+
+            if ($value instanceof MonitoringEventsInterface) {
+                $reversedEvents = array_reverse($monitoringEvents);
+                $monitoringEvents = array_merge($monitoringEvents, $value->getMonitoringEvents());
+                foreach ($reversedEvents as $event) {
+                    $value->prependMonitoringEvent($event);
+                }
+            }
+            if ($value instanceof Exception || $value instanceof \Throwable) {
+                if (!$decider($attempts, $cmd, $value)) {
+                    $callback = null;
+                    return Promise\Create::rejectionFor(
+                        $this->bindStatsToReturn($value, $requestStats)
+                    );
+                }
+            } elseif ($value instanceof ResultInterface
+                && !$decider($attempts, $cmd, $value)
+            ) {
+                $callback = null;
+                return $this->bindStatsToReturn($value, $requestStats);
+            }
+
+            $delayBy = $delayer($attempts++);
+            $cmd['@http']['delay'] = $delayBy;
+            if ($this->collectStats) {
+                $this->updateStats($attempts - 1, $delayBy, $requestStats);
+            }
+
+            // Update retry header with retry count and delayBy
+            $req = $this->addRetryHeader($req, $attempts - 1, $delayBy);
+
+            // Get token from rate limiter, which will sleep if necessary
+            if ($this->mode === 'adaptive') {
+                $this->rateLimiter->getSendToken();
+            }
+
+            return $handler($cmd, $req)->then($callback, $callback);
+        };
+
+        // Get token from rate limiter, which will sleep if necessary
+        if ($this->mode === 'adaptive') {
+            $this->rateLimiter->getSendToken();
+        }
+
+        return $handler($cmd, $req)->then($callback, $callback);
+    }
+
+    /**
+     * Amount of milliseconds to delay as a function of attempt number
+     *
+     * @param $attempts
+     * @return mixed
+     */
+    public function exponentialDelayWithJitter($attempts)
+    {
+        $max = mt_getrandmax();
+        try {
+            $rand = random_int(0, $max) / $max;
+        } catch (Exception $_) {
+            // fallback to prevent failing
+            $rand = mt_rand(0, $max) / $max;
+        }
+
+        return min(1000 * $rand * pow(2, $attempts) , $this->maxBackoff);
+    }
+
+    private static function isRetryable(
+        $result,
+        $retryCurlErrors,
+        $options = []
+    ) {
+        $errorCodes = self::$standardThrottlingErrors + self::$standardTransientErrors;
+        if (!empty($options['transient_error_codes'])
+            && is_array($options['transient_error_codes'])
+        ) {
+            foreach($options['transient_error_codes'] as $code) {
+                $errorCodes[$code] = true;
+            }
+        }
+        if (!empty($options['throttling_error_codes'])
+            && is_array($options['throttling_error_codes'])
+        ) {
+            foreach($options['throttling_error_codes'] as $code) {
+                $errorCodes[$code] = true;
+            }
+        }
+
+        $statusCodes = self::$standardTransientStatusCodes;
+        if (!empty($options['status_codes'])
+            && is_array($options['status_codes'])
+        ) {
+            foreach($options['status_codes'] as $code) {
+                $statusCodes[$code] = true;
+            }
+        }
+
+        if (!empty($options['curl_errors'])
+            && is_array($options['curl_errors'])
+        ) {
+            foreach($options['curl_errors'] as $code) {
+                $retryCurlErrors[$code] = true;
+            }
+        }
+
+        if ($result instanceof Exception || $result instanceof \Throwable) {
+            $isError = true;
+        } else {
+            $isError = false;
+        }
+
+        if (!$isError) {
+            if (!isset($result['@metadata']['statusCode'])) {
+                return false;
+            }
+            return isset($statusCodes[$result['@metadata']['statusCode']]);
+        }
+
+        if (!($result instanceof AwsException)) {
+            return false;
+        }
+
+        if ($result->isConnectionError()) {
+            return true;
+        }
+
+        $awsCode = $result->getAwsErrorCode();
+        if (!is_null($awsCode) && isset($errorCodes[$awsCode])) {
+            return true;
+        }
+
+        $status = $result->getStatusCode();
+        if (!is_null($status) && isset($statusCodes[$status])) {
+            return true;
+        }
+
+        if (count($retryCurlErrors)
+            && ($previous = $result->getPrevious())
+            && $previous instanceof RequestException
+        ) {
+            if (method_exists($previous, 'getHandlerContext')) {
+                $context = $previous->getHandlerContext();
+                return !empty($context['errno'])
+                    && isset($retryCurlErrors[$context['errno']]);
+            }
+
+            $message = $previous->getMessage();
+            foreach (array_keys($retryCurlErrors) as $curlError) {
+                if (strpos($message, 'cURL error ' . $curlError . ':') === 0) {
+                    return true;
+                }
+            }
+        }
+
+        // Check error shape for the retryable trait
+        if (!empty($errorShape = $result->getAwsErrorShape())) {
+            $definition = $errorShape->toArray();
+            if (!empty($definition['retryable'])) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    private function isThrottlingError($result)
+    {
+        if ($result instanceof AwsException) {
+            // Check pre-defined throttling errors
+            $throttlingErrors = self::$standardThrottlingErrors;
+            if (!empty($this->options['throttling_error_codes'])
+                && is_array($this->options['throttling_error_codes'])
+            ) {
+                foreach($this->options['throttling_error_codes'] as $code) {
+                    $throttlingErrors[$code] = true;
+                }
+            }
+            if (!empty($result->getAwsErrorCode())
+                && !empty($throttlingErrors[$result->getAwsErrorCode()])
+            ) {
+                return true;
+            }
+
+            // Check error shape for the throttling trait
+            if (!empty($errorShape = $result->getAwsErrorShape())) {
+                $definition = $errorShape->toArray();
+                if (!empty($definition['retryable']['throttling'])) {
+                    return true;
+                }
+            }
+        }
+
+        return false;
+    }
+}

+ 105 - 0
upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/Route53GlobalResolver/Route53GlobalResolverClient.php

@@ -0,0 +1,105 @@
+<?php
+namespace Aws\Route53GlobalResolver;
+
+use Aws\AwsClient;
+
+/**
+ * This client is used to interact with the **Amazon Route 53 Global Resolver** service.
+ * @method \Aws\Result associateHostedZone(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise associateHostedZoneAsync(array $args = [])
+ * @method \Aws\Result batchCreateFirewallRule(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise batchCreateFirewallRuleAsync(array $args = [])
+ * @method \Aws\Result batchDeleteFirewallRule(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise batchDeleteFirewallRuleAsync(array $args = [])
+ * @method \Aws\Result batchUpdateFirewallRule(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise batchUpdateFirewallRuleAsync(array $args = [])
+ * @method \Aws\Result createAccessSource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createAccessSourceAsync(array $args = [])
+ * @method \Aws\Result createAccessToken(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createAccessTokenAsync(array $args = [])
+ * @method \Aws\Result createDNSView(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createDNSViewAsync(array $args = [])
+ * @method \Aws\Result createFirewallDomainList(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createFirewallDomainListAsync(array $args = [])
+ * @method \Aws\Result createFirewallRule(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createFirewallRuleAsync(array $args = [])
+ * @method \Aws\Result createGlobalResolver(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createGlobalResolverAsync(array $args = [])
+ * @method \Aws\Result deleteAccessSource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteAccessSourceAsync(array $args = [])
+ * @method \Aws\Result deleteAccessToken(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteAccessTokenAsync(array $args = [])
+ * @method \Aws\Result deleteDNSView(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteDNSViewAsync(array $args = [])
+ * @method \Aws\Result deleteFirewallDomainList(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteFirewallDomainListAsync(array $args = [])
+ * @method \Aws\Result deleteFirewallRule(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteFirewallRuleAsync(array $args = [])
+ * @method \Aws\Result deleteGlobalResolver(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteGlobalResolverAsync(array $args = [])
+ * @method \Aws\Result disableDNSView(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise disableDNSViewAsync(array $args = [])
+ * @method \Aws\Result disassociateHostedZone(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise disassociateHostedZoneAsync(array $args = [])
+ * @method \Aws\Result enableDNSView(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise enableDNSViewAsync(array $args = [])
+ * @method \Aws\Result getAccessSource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getAccessSourceAsync(array $args = [])
+ * @method \Aws\Result getAccessToken(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getAccessTokenAsync(array $args = [])
+ * @method \Aws\Result getDNSView(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getDNSViewAsync(array $args = [])
+ * @method \Aws\Result getFirewallDomainList(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getFirewallDomainListAsync(array $args = [])
+ * @method \Aws\Result getFirewallRule(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getFirewallRuleAsync(array $args = [])
+ * @method \Aws\Result getGlobalResolver(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getGlobalResolverAsync(array $args = [])
+ * @method \Aws\Result getHostedZoneAssociation(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getHostedZoneAssociationAsync(array $args = [])
+ * @method \Aws\Result getManagedFirewallDomainList(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getManagedFirewallDomainListAsync(array $args = [])
+ * @method \Aws\Result importFirewallDomains(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise importFirewallDomainsAsync(array $args = [])
+ * @method \Aws\Result listAccessSources(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listAccessSourcesAsync(array $args = [])
+ * @method \Aws\Result listAccessTokens(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listAccessTokensAsync(array $args = [])
+ * @method \Aws\Result listDNSViews(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listDNSViewsAsync(array $args = [])
+ * @method \Aws\Result listFirewallDomainLists(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listFirewallDomainListsAsync(array $args = [])
+ * @method \Aws\Result listFirewallDomains(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listFirewallDomainsAsync(array $args = [])
+ * @method \Aws\Result listFirewallRules(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listFirewallRulesAsync(array $args = [])
+ * @method \Aws\Result listGlobalResolvers(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listGlobalResolversAsync(array $args = [])
+ * @method \Aws\Result listHostedZoneAssociations(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listHostedZoneAssociationsAsync(array $args = [])
+ * @method \Aws\Result listManagedFirewallDomainLists(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listManagedFirewallDomainListsAsync(array $args = [])
+ * @method \Aws\Result listSharedDNSViews(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listSharedDNSViewsAsync(array $args = [])
+ * @method \Aws\Result listTagsForResource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listTagsForResourceAsync(array $args = [])
+ * @method \Aws\Result tagResource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise tagResourceAsync(array $args = [])
+ * @method \Aws\Result untagResource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise untagResourceAsync(array $args = [])
+ * @method \Aws\Result updateAccessSource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateAccessSourceAsync(array $args = [])
+ * @method \Aws\Result updateAccessToken(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateAccessTokenAsync(array $args = [])
+ * @method \Aws\Result updateDNSView(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateDNSViewAsync(array $args = [])
+ * @method \Aws\Result updateFirewallDomains(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateFirewallDomainsAsync(array $args = [])
+ * @method \Aws\Result updateFirewallRule(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateFirewallRuleAsync(array $args = [])
+ * @method \Aws\Result updateGlobalResolver(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateGlobalResolverAsync(array $args = [])
+ * @method \Aws\Result updateHostedZoneAssociation(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateHostedZoneAssociationAsync(array $args = [])
+ */
+class Route53GlobalResolverClient extends AwsClient {}

+ 153 - 0
upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/Route53Resolver/Route53ResolverClient.php

@@ -0,0 +1,153 @@
+<?php
+namespace Aws\Route53Resolver;
+
+use Aws\AwsClient;
+
+/**
+ * This client is used to interact with the **Amazon Route 53 Resolver** service.
+ * @method \Aws\Result associateFirewallRuleGroup(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise associateFirewallRuleGroupAsync(array $args = [])
+ * @method \Aws\Result associateResolverEndpointIpAddress(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise associateResolverEndpointIpAddressAsync(array $args = [])
+ * @method \Aws\Result associateResolverQueryLogConfig(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise associateResolverQueryLogConfigAsync(array $args = [])
+ * @method \Aws\Result associateResolverRule(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise associateResolverRuleAsync(array $args = [])
+ * @method \Aws\Result batchCreateFirewallRule(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise batchCreateFirewallRuleAsync(array $args = [])
+ * @method \Aws\Result batchDeleteFirewallRule(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise batchDeleteFirewallRuleAsync(array $args = [])
+ * @method \Aws\Result batchUpdateFirewallRule(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise batchUpdateFirewallRuleAsync(array $args = [])
+ * @method \Aws\Result createFirewallDomainList(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createFirewallDomainListAsync(array $args = [])
+ * @method \Aws\Result createFirewallRule(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createFirewallRuleAsync(array $args = [])
+ * @method \Aws\Result createFirewallRuleGroup(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createFirewallRuleGroupAsync(array $args = [])
+ * @method \Aws\Result createOutpostResolver(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createOutpostResolverAsync(array $args = [])
+ * @method \Aws\Result createResolverEndpoint(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createResolverEndpointAsync(array $args = [])
+ * @method \Aws\Result createResolverQueryLogConfig(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createResolverQueryLogConfigAsync(array $args = [])
+ * @method \Aws\Result createResolverRule(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise createResolverRuleAsync(array $args = [])
+ * @method \Aws\Result deleteFirewallDomainList(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteFirewallDomainListAsync(array $args = [])
+ * @method \Aws\Result deleteFirewallRule(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteFirewallRuleAsync(array $args = [])
+ * @method \Aws\Result deleteFirewallRuleGroup(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteFirewallRuleGroupAsync(array $args = [])
+ * @method \Aws\Result deleteOutpostResolver(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteOutpostResolverAsync(array $args = [])
+ * @method \Aws\Result deleteResolverEndpoint(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteResolverEndpointAsync(array $args = [])
+ * @method \Aws\Result deleteResolverQueryLogConfig(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteResolverQueryLogConfigAsync(array $args = [])
+ * @method \Aws\Result deleteResolverRule(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise deleteResolverRuleAsync(array $args = [])
+ * @method \Aws\Result disassociateFirewallRuleGroup(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise disassociateFirewallRuleGroupAsync(array $args = [])
+ * @method \Aws\Result disassociateResolverEndpointIpAddress(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise disassociateResolverEndpointIpAddressAsync(array $args = [])
+ * @method \Aws\Result disassociateResolverQueryLogConfig(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise disassociateResolverQueryLogConfigAsync(array $args = [])
+ * @method \Aws\Result disassociateResolverRule(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise disassociateResolverRuleAsync(array $args = [])
+ * @method \Aws\Result getFirewallConfig(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getFirewallConfigAsync(array $args = [])
+ * @method \Aws\Result getFirewallDomainList(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getFirewallDomainListAsync(array $args = [])
+ * @method \Aws\Result getFirewallRuleGroup(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getFirewallRuleGroupAsync(array $args = [])
+ * @method \Aws\Result getFirewallRuleGroupAssociation(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getFirewallRuleGroupAssociationAsync(array $args = [])
+ * @method \Aws\Result getFirewallRuleGroupPolicy(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getFirewallRuleGroupPolicyAsync(array $args = [])
+ * @method \Aws\Result getOutpostResolver(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getOutpostResolverAsync(array $args = [])
+ * @method \Aws\Result getResolverConfig(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getResolverConfigAsync(array $args = [])
+ * @method \Aws\Result getResolverDnssecConfig(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getResolverDnssecConfigAsync(array $args = [])
+ * @method \Aws\Result getResolverEndpoint(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getResolverEndpointAsync(array $args = [])
+ * @method \Aws\Result getResolverQueryLogConfig(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getResolverQueryLogConfigAsync(array $args = [])
+ * @method \Aws\Result getResolverQueryLogConfigAssociation(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getResolverQueryLogConfigAssociationAsync(array $args = [])
+ * @method \Aws\Result getResolverQueryLogConfigPolicy(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getResolverQueryLogConfigPolicyAsync(array $args = [])
+ * @method \Aws\Result getResolverRule(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getResolverRuleAsync(array $args = [])
+ * @method \Aws\Result getResolverRuleAssociation(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getResolverRuleAssociationAsync(array $args = [])
+ * @method \Aws\Result getResolverRulePolicy(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise getResolverRulePolicyAsync(array $args = [])
+ * @method \Aws\Result importFirewallDomains(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise importFirewallDomainsAsync(array $args = [])
+ * @method \Aws\Result listFirewallConfigs(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listFirewallConfigsAsync(array $args = [])
+ * @method \Aws\Result listFirewallDomainLists(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listFirewallDomainListsAsync(array $args = [])
+ * @method \Aws\Result listFirewallDomains(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listFirewallDomainsAsync(array $args = [])
+ * @method \Aws\Result listFirewallRuleGroupAssociations(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listFirewallRuleGroupAssociationsAsync(array $args = [])
+ * @method \Aws\Result listFirewallRuleGroups(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listFirewallRuleGroupsAsync(array $args = [])
+ * @method \Aws\Result listFirewallRuleTypes(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listFirewallRuleTypesAsync(array $args = [])
+ * @method \Aws\Result listFirewallRules(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listFirewallRulesAsync(array $args = [])
+ * @method \Aws\Result listOutpostResolvers(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listOutpostResolversAsync(array $args = [])
+ * @method \Aws\Result listResolverConfigs(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listResolverConfigsAsync(array $args = [])
+ * @method \Aws\Result listResolverDnssecConfigs(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listResolverDnssecConfigsAsync(array $args = [])
+ * @method \Aws\Result listResolverEndpointIpAddresses(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listResolverEndpointIpAddressesAsync(array $args = [])
+ * @method \Aws\Result listResolverEndpoints(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listResolverEndpointsAsync(array $args = [])
+ * @method \Aws\Result listResolverQueryLogConfigAssociations(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listResolverQueryLogConfigAssociationsAsync(array $args = [])
+ * @method \Aws\Result listResolverQueryLogConfigs(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listResolverQueryLogConfigsAsync(array $args = [])
+ * @method \Aws\Result listResolverRuleAssociations(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listResolverRuleAssociationsAsync(array $args = [])
+ * @method \Aws\Result listResolverRules(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listResolverRulesAsync(array $args = [])
+ * @method \Aws\Result listTagsForResource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise listTagsForResourceAsync(array $args = [])
+ * @method \Aws\Result putFirewallRuleGroupPolicy(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise putFirewallRuleGroupPolicyAsync(array $args = [])
+ * @method \Aws\Result putResolverQueryLogConfigPolicy(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise putResolverQueryLogConfigPolicyAsync(array $args = [])
+ * @method \Aws\Result putResolverRulePolicy(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise putResolverRulePolicyAsync(array $args = [])
+ * @method \Aws\Result tagResource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise tagResourceAsync(array $args = [])
+ * @method \Aws\Result untagResource(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise untagResourceAsync(array $args = [])
+ * @method \Aws\Result updateFirewallConfig(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateFirewallConfigAsync(array $args = [])
+ * @method \Aws\Result updateFirewallDomains(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateFirewallDomainsAsync(array $args = [])
+ * @method \Aws\Result updateFirewallRule(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateFirewallRuleAsync(array $args = [])
+ * @method \Aws\Result updateFirewallRuleGroupAssociation(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateFirewallRuleGroupAssociationAsync(array $args = [])
+ * @method \Aws\Result updateOutpostResolver(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateOutpostResolverAsync(array $args = [])
+ * @method \Aws\Result updateResolverConfig(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateResolverConfigAsync(array $args = [])
+ * @method \Aws\Result updateResolverDnssecConfig(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateResolverDnssecConfigAsync(array $args = [])
+ * @method \Aws\Result updateResolverEndpoint(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateResolverEndpointAsync(array $args = [])
+ * @method \Aws\Result updateResolverRule(array $args = [])
+ * @method \GuzzleHttp\Promise\Promise updateResolverRuleAsync(array $args = [])
+ */
+class Route53ResolverClient extends AwsClient {}

+ 359 - 0
upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/S3/Crypto/S3EncryptionClient.php

@@ -0,0 +1,359 @@
+<?php
+namespace Aws\S3\Crypto;
+
+use Aws\Crypto\DecryptionTrait;
+use Aws\HashingStream;
+use Aws\MetricsBuilder;
+use Aws\PhpHash;
+use Aws\Crypto\AbstractCryptoClient;
+use Aws\Crypto\EncryptionTrait;
+use Aws\Crypto\MetadataEnvelope;
+use Aws\Crypto\MaterialsProvider;
+use Aws\Crypto\Cipher\CipherBuilderTrait;
+use Aws\S3\S3Client;
+use GuzzleHttp\Promise;
+use GuzzleHttp\Promise\PromiseInterface;
+use GuzzleHttp\Psr7;
+
+/**
+ * Provides a wrapper for an S3Client that supplies functionality to encrypt
+ * data on putObject[Async] calls and decrypt data on getObject[Async] calls.
+ *
+ * Legacy implementation using older encryption workflow.
+ *
+ * AWS strongly recommends the upgrade to the S3EncryptionClientV2 (over the
+ * S3EncryptionClient), as it offers updated data security best practices to our
+ * customers who upgrade. S3EncryptionClientV2 contains breaking changes, so this
+ * will require planning by engineering teams to migrate. New workflows should
+ * just start with S3EncryptionClientV2.
+ *
+ * @deprecated
+ */
+class S3EncryptionClient extends AbstractCryptoClient
+{
+    use CipherBuilderTrait;
+    use CryptoParamsTrait;
+    use DecryptionTrait;
+    use EncryptionTrait;
+    use UserAgentTrait;
+
+    const CRYPTO_VERSION = '1n';
+
+    private $client;
+    private $instructionFileSuffix;
+
+    /**
+     * @param S3Client $client The S3Client to be used for true uploading and
+     *                         retrieving objects from S3 when using the
+     *                         encryption client.
+     * @param string|null $instructionFileSuffix Suffix for a client wide
+     *                                           default when using instruction
+     *                                           files for metadata storage.
+     */
+    public function __construct(
+        S3Client $client,
+        $instructionFileSuffix = null
+    ) {
+        trigger_error(
+            'S3EncryptionClient is deprecated and will be removed in a future ' .
+            'release due to security vulnerabilities. Please migrate to ' .
+            'S3EncryptionClientV3 as soon as possible.' . "\n" .
+            'See https://docs.aws.amazon.com/sdk-for-php/v3/developer-guide/' .
+            'security.html for upgrade guidance.',
+            E_USER_DEPRECATED
+        );
+        $this->client = $client;
+        $this->instructionFileSuffix = $instructionFileSuffix;
+        MetricsBuilder::appendMetricsCaptureMiddleware(
+            $this->client->getHandlerList(),
+            MetricsBuilder::S3_CRYPTO_V1N
+        );
+    }
+
+    private static function getDefaultStrategy()
+    {
+        return new HeadersMetadataStrategy();
+    }
+
+    /**
+     * Encrypts the data in the 'Body' field of $args and promises to upload it
+     * to the specified location on S3.
+     *
+     * @param array $args Arguments for encrypting an object and uploading it
+     *                    to S3 via PutObject.
+     *
+     * The required configuration arguments are as follows:
+     *
+     * - @MaterialsProvider: (MaterialsProvider) Provides Cek, Iv, and Cek
+     *   encrypting/decrypting for encryption metadata.
+     * - @CipherOptions: (array) Cipher options for encrypting data. Only the
+     *   Cipher option is required. Accepts the following:
+     *       - Cipher: (string) cbc|gcm
+     *            See also: AbstractCryptoClient::$supportedCiphers. Note that
+     *            cbc is deprecated and gcm should be used when possible.
+     *       - KeySize: (int) 128|192|256
+     *            See also: MaterialsProvider::$supportedKeySizes
+     *       - Aad: (string) Additional authentication data. This option is
+     *            passed directly to OpenSSL when using gcm. It is ignored when
+     *            using cbc. Note if you pass in Aad for gcm encryption, the
+     *            PHP SDK will be able to decrypt the resulting object, but other
+     *            AWS SDKs may not be able to do so.
+     *
+     * The optional configuration arguments are as follows:
+     *
+     * - @MetadataStrategy: (MetadataStrategy|string|null) Strategy for storing
+     *   MetadataEnvelope information. Defaults to using a
+     *   HeadersMetadataStrategy. Can either be a class implementing
+     *   MetadataStrategy, a class name of a predefined strategy, or empty/null
+     *   to default.
+     * - @InstructionFileSuffix: (string|null) Suffix used when writing to an
+     *   instruction file if using an InstructionFileMetadataHandler.
+     *
+     * @return PromiseInterface
+     *
+     * @throws \InvalidArgumentException Thrown when arguments above are not
+     *                                   passed or are passed incorrectly.
+     */
+    public function putObjectAsync(array $args)
+    {
+        $provider = $this->getMaterialsProvider($args);
+        unset($args['@MaterialsProvider']);
+
+        $instructionFileSuffix = $this->getInstructionFileSuffix($args);
+        unset($args['@InstructionFileSuffix']);
+
+        $strategy = $this->getMetadataStrategy($args, $instructionFileSuffix);
+        unset($args['@MetadataStrategy']);
+
+        $envelope = new MetadataEnvelope();
+
+        $bodyStream = Psr7\Utils::streamFor($args['Body']);
+        // User-owned resource which should be detached instead of closed
+        // during garbage-collection
+        if (is_resource($args['Body'])) {
+            $bodyStream = \Aws\detach_on_close_stream($bodyStream);
+        }
+
+        return Promise\Create::promiseFor($this->encrypt(
+            $bodyStream,
+            $args['@CipherOptions'] ?: [],
+            $provider,
+            $envelope
+        ))->then(
+            function ($encryptedBodyStream) use ($args) {
+                $hash = new PhpHash('sha256');
+                $hashingEncryptedBodyStream = new HashingStream(
+                    $encryptedBodyStream,
+                    $hash,
+                    self::getContentShaDecorator($args)
+                );
+                return [$hashingEncryptedBodyStream, $args];
+            }
+        )->then(
+            function ($putObjectContents) use ($strategy, $envelope) {
+                list($bodyStream, $args) = $putObjectContents;
+                if ($strategy === null) {
+                    $strategy = self::getDefaultStrategy();
+                }
+
+                $updatedArgs = $strategy->save($envelope, $args);
+                $updatedArgs['Body'] = $bodyStream;
+                return $updatedArgs;
+            }
+        )->then(
+            function ($args) {
+                unset($args['@CipherOptions']);
+                return $this->client->putObjectAsync($args);
+            }
+        );
+    }
+
+    private static function getContentShaDecorator(&$args)
+    {
+        return function ($hash) use (&$args) {
+            $args['ContentSHA256'] = bin2hex($hash);
+        };
+    }
+
+    /**
+     * Encrypts the data in the 'Body' field of $args and uploads it to the
+     * specified location on S3.
+     *
+     * @param array $args Arguments for encrypting an object and uploading it
+     *                    to S3 via PutObject.
+     *
+     * The required configuration arguments are as follows:
+     *
+     * - @MaterialsProvider: (MaterialsProvider) Provides Cek, Iv, and Cek
+     *   encrypting/decrypting for encryption metadata.
+     * - @CipherOptions: (array) Cipher options for encrypting data. A Cipher
+     *   is required. Accepts the following options:
+     *       - Cipher: (string) cbc|gcm
+     *            See also: AbstractCryptoClient::$supportedCiphers. Note that
+     *            cbc is deprecated and gcm should be used when possible.
+     *       - KeySize: (int) 128|192|256
+     *            See also: MaterialsProvider::$supportedKeySizes
+     *       - Aad: (string) Additional authentication data. This option is
+     *            passed directly to OpenSSL when using gcm. It is ignored when
+     *            using cbc. Note if you pass in Aad for gcm encryption, the
+     *            PHP SDK will be able to decrypt the resulting object, but other
+     *            AWS SDKs may not be able to do so.
+     *
+     * The optional configuration arguments are as follows:
+     *
+     * - @MetadataStrategy: (MetadataStrategy|string|null) Strategy for storing
+     *   MetadataEnvelope information. Defaults to using a
+     *   HeadersMetadataStrategy. Can either be a class implementing
+     *   MetadataStrategy, a class name of a predefined strategy, or empty/null
+     *   to default.
+     * - @InstructionFileSuffix: (string|null) Suffix used when writing to an
+     *   instruction file if an using an InstructionFileMetadataHandler was
+     *   determined.
+     *
+     * @return \Aws\Result PutObject call result with the details of uploading
+     *                     the encrypted file.
+     *
+     * @throws \InvalidArgumentException Thrown when arguments above are not
+     *                                   passed or are passed incorrectly.
+     */
+    public function putObject(array $args)
+    {
+        return $this->putObjectAsync($args)->wait();
+    }
+
+    /**
+     * Promises to retrieve an object from S3 and decrypt the data in the
+     * 'Body' field.
+     *
+     * @param array $args Arguments for retrieving an object from S3 via
+     *                    GetObject and decrypting it.
+     *
+     * The required configuration argument is as follows:
+     *
+     * - @MaterialsProvider: (MaterialsProvider) Provides Cek, Iv, and Cek
+     *   encrypting/decrypting for decryption metadata. May have data loaded
+     *   from the MetadataEnvelope upon decryption.
+     *
+     * The optional configuration arguments are as follows:
+     *
+     * - SaveAs: (string) The path to a file on disk to save the decrypted
+     *   object data. This will be handled by file_put_contents instead of the
+     *   Guzzle sink.
+     *
+     * - @MetadataStrategy: (MetadataStrategy|string|null) Strategy for reading
+     *   MetadataEnvelope information. Defaults to determining based on object
+     *   response headers. Can either be a class implementing MetadataStrategy,
+     *   a class name of a predefined strategy, or empty/null to default.
+     * - @InstructionFileSuffix: (string) Suffix used when looking for an
+     *   instruction file if an InstructionFileMetadataHandler is being used.
+     * - @CipherOptions: (array) Cipher options for decrypting data. A Cipher
+     *   is required. Accepts the following options:
+     *       - Aad: (string) Additional authentication data. This option is
+     *            passed directly to OpenSSL when using gcm. It is ignored when
+     *            using cbc.
+     *
+     * @return PromiseInterface
+     *
+     * @throws \InvalidArgumentException Thrown when required arguments are not
+     *                                   passed or are passed incorrectly.
+     */
+    public function getObjectAsync(array $args)
+    {
+        $provider = $this->getMaterialsProvider($args);
+        unset($args['@MaterialsProvider']);
+
+        $instructionFileSuffix = $this->getInstructionFileSuffix($args);
+        unset($args['@InstructionFileSuffix']);
+
+        $strategy = $this->getMetadataStrategy($args, $instructionFileSuffix);
+        unset($args['@MetadataStrategy']);
+
+        $saveAs = null;
+        if (!empty($args['SaveAs'])) {
+            $saveAs = $args['SaveAs'];
+        }
+
+        $promise = $this->client->getObjectAsync($args)
+            ->then(
+                function ($result) use (
+                    $provider,
+                    $instructionFileSuffix,
+                    $strategy,
+                    $args
+                ) {
+                    if ($strategy === null) {
+                        $strategy = $this->determineGetObjectStrategy(
+                            $result,
+                            $instructionFileSuffix
+                        );
+                    }
+
+                    $envelope = $strategy->load($args + [
+                        'Metadata' => $result['Metadata']
+                    ]);
+
+                    $provider = $provider->fromDecryptionEnvelope($envelope);
+
+                    $result['Body'] = $this->decrypt(
+                        $result['Body'],
+                        $provider,
+                        $envelope,
+                        isset($args['@CipherOptions'])
+                            ? $args['@CipherOptions']
+                            : []
+                    );
+                    return $result;
+                }
+            )->then(
+                function ($result) use ($saveAs) {
+                    if (!empty($saveAs)) {
+                        file_put_contents(
+                            $saveAs,
+                            (string)$result['Body'],
+                            LOCK_EX
+                        );
+                    }
+                    return $result;
+                }
+            );
+
+        return $promise;
+    }
+
+    /**
+     * Retrieves an object from S3 and decrypts the data in the 'Body' field.
+     *
+     * @param array $args Arguments for retrieving an object from S3 via
+     *                    GetObject and decrypting it.
+     *
+     * The required configuration argument is as follows:
+     *
+     * - @MaterialsProvider: (MaterialsProvider) Provides Cek, Iv, and Cek
+     *   encrypting/decrypting for decryption metadata. May have data loaded
+     *   from the MetadataEnvelope upon decryption.
+     *
+     * The optional configuration arguments are as follows:
+     *
+     * - SaveAs: (string) The path to a file on disk to save the decrypted
+     *   object data. This will be handled by file_put_contents instead of the
+     *   Guzzle sink.
+     * - @InstructionFileSuffix: (string|null) Suffix used when looking for an
+     *   instruction file if an InstructionFileMetadataHandler was detected.
+     * - @CipherOptions: (array) Cipher options for encrypting data. A Cipher
+     *   is required. Accepts the following options:
+     *       - Aad: (string) Additional authentication data. This option is
+     *            passed directly to OpenSSL when using gcm. It is ignored when
+     *            using cbc.
+     *
+     * @return \Aws\Result GetObject call result with the 'Body' field
+     *                     wrapped in a decryption stream with its metadata
+     *                     information.
+     *
+     * @throws \InvalidArgumentException Thrown when arguments above are not
+     *                                   passed or are passed incorrectly.
+     */
+    public function getObject(array $args)
+    {
+        return $this->getObjectAsync($args)->wait();
+    }
+}

+ 475 - 0
upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/S3/Crypto/S3EncryptionClientV2.php

@@ -0,0 +1,475 @@
+<?php
+namespace Aws\S3\Crypto;
+
+use Aws\Crypto\DecryptionTraitV2;
+use Aws\Exception\CryptoException;
+use Aws\HashingStream;
+use Aws\MetricsBuilder;
+use Aws\PhpHash;
+use Aws\Crypto\AbstractCryptoClientV2;
+use Aws\Crypto\EncryptionTraitV2;
+use Aws\Crypto\MetadataEnvelope;
+use Aws\Crypto\MaterialsProvider;
+use Aws\Crypto\Cipher\CipherBuilderTrait;
+use Aws\S3\S3Client;
+use GuzzleHttp\Promise;
+use GuzzleHttp\Promise\PromiseInterface;
+use GuzzleHttp\Psr7;
+
+/**
+ * Provides a wrapper for an S3Client that supplies functionality to encrypt
+ * data on putObject[Async] calls and decrypt data on getObject[Async] calls.
+ *
+ * AWS strongly recommends the upgrade to the S3EncryptionClientV3 (over the
+ * S3EncryptionClientV2), as it offers updated data security best practices to our
+ * customers who upgrade. S3EncryptionClientV3 contains breaking changes, so this
+ * will require planning by engineering teams to migrate. New workflows should
+ * just start with S3EncryptionClientV3.
+ *
+ * Note that for PHP versions of < 7.1, this class uses an AES-GCM polyfill
+ * for encryption since there is no native PHP support. The performance for large
+ * inputs will be a lot slower than for PHP 7.1+, so upgrading older PHP version
+ * environments may be necessary to use this effectively.
+ *
+ * Example write path:
+ *
+ * <code>
+ * use Aws\Crypto\KmsMaterialsProviderV2;
+ * use Aws\S3\Crypto\S3EncryptionClientV2;
+ * use Aws\S3\S3Client;
+ *
+ * $encryptionClient = new S3EncryptionClientV2(
+ *     new S3Client([
+ *         'region' => 'us-west-2',
+ *         'version' => 'latest'
+ *     ])
+ * );
+ * $materialsProvider = new KmsMaterialsProviderV2(
+ *     new KmsClient([
+ *         'profile' => 'default',
+ *         'region' => 'us-east-1',
+ *         'version' => 'latest',
+ *     ],
+ *    'your-kms-key-id'
+ * );
+ *
+ * $encryptionClient->putObject([
+ *     '@MaterialsProvider' => $materialsProvider,
+ *     '@CipherOptions' => [
+ *         'Cipher' => 'gcm',
+ *         'KeySize' => 256,
+ *     ],
+ *     '@KmsEncryptionContext' => ['foo' => 'bar'],
+ *     'Bucket' => 'your-bucket',
+ *     'Key' => 'your-key',
+ *     'Body' => 'your-encrypted-data',
+ * ]);
+ * </code>
+ *
+ * Example read call (using objects from previous example):
+ *
+ * <code>
+ * $encryptionClient->getObject([
+ *     '@MaterialsProvider' => $materialsProvider,
+ *     '@CipherOptions' => [
+ *         'Cipher' => 'gcm',
+ *         'KeySize' => 256,
+ *     ],
+ *     '@CommitmentPolicy' => 'FORBID_ENCRYPT_ALLOW_DECRYPT',
+ *     'Bucket' => 'your-bucket',
+ *     'Key' => 'your-key',
+ * ]);
+ * </code>
+ */
+class S3EncryptionClientV2 extends AbstractCryptoClientV2
+{
+    use CipherBuilderTrait;
+    use CryptoParamsTraitV2;
+    use DecryptionTraitV2;
+    use EncryptionTraitV2;
+    use UserAgentTrait;
+
+    const CRYPTO_VERSION = '2.1';
+
+    private $client;
+    private $instructionFileSuffix;
+    private $legacyWarningCount;
+
+    /**
+     * @param S3Client $client The S3Client to be used for true uploading and
+     *                         retrieving objects from S3 when using the
+     *                         encryption client.
+     * @param string|null $instructionFileSuffix Suffix for a client wide
+     *                                           default when using instruction
+     *                                           files for metadata storage.
+     */
+    public function __construct(
+        S3Client $client,
+        $instructionFileSuffix = null
+    ) {
+        trigger_error(
+            'S3EncryptionClientV2 will be deprecated soon and will be removed in a future ' .
+            'release due to security vulnerabilities (CVE-2024-56473). Please ' .
+            'migrate to S3EncryptionClientV3 as soon as possible.' . "\n" .
+            'See https://docs.aws.amazon.com/sdk-for-php/v3/developer-guide/' .
+            'security.html for upgrade guidance.',
+            E_USER_DEPRECATED
+        );
+        $this->client = $client;
+        $this->instructionFileSuffix = $instructionFileSuffix;
+        $this->legacyWarningCount = 0;
+        MetricsBuilder::appendMetricsCaptureMiddleware(
+            $this->client->getHandlerList(),
+            MetricsBuilder::S3_CRYPTO_V2
+        );
+    }
+
+    private static function getDefaultStrategy()
+    {
+        return new HeadersMetadataStrategy();
+    }
+
+    /**
+     * Encrypts the data in the 'Body' field of $args and promises to upload it
+     * to the specified location on S3.
+     *
+     * Note that for PHP versions of < 7.1, this operation uses an AES-GCM
+     * polyfill for encryption since there is no native PHP support. The
+     * performance for large inputs will be a lot slower than for PHP 7.1+, so
+     * upgrading older PHP version environments may be necessary to use this
+     * effectively.
+     *
+     * @param array $args Arguments for encrypting an object and uploading it
+     *                    to S3 via PutObject.
+     *
+     * The required configuration arguments are as follows:
+     *
+     * - @MaterialsProvider: (MaterialsProviderV2) Provides Cek, Iv, and Cek
+     *   encrypting/decrypting for encryption metadata.
+     * - @CipherOptions: (array) Cipher options for encrypting data. Only the
+     *   Cipher option is required. Accepts the following:
+     *       - Cipher: (string) gcm
+     *            See also: AbstractCryptoClientV2::$supportedCiphers
+     *       - KeySize: (int) 128|256
+     *            See also: MaterialsProvider::$supportedKeySizes
+     *       - Aad: (string) Additional authentication data. This option is
+     *            passed directly to OpenSSL when using gcm. Note if you pass in
+     *            Aad, the PHP SDK will be able to decrypt the resulting object,
+     *            but other AWS SDKs may not be able to do so.
+     * - @KmsEncryptionContext: (array) Only required if using
+     *   KmsMaterialsProviderV2. An associative array of key-value
+     *   pairs to be added to the encryption context for KMS key encryption. An
+     *   empty array may be passed if no additional context is desired.
+     *
+     * The optional configuration arguments are as follows:
+     *
+     * - @MetadataStrategy: (MetadataStrategy|string|null) Strategy for storing
+     *   MetadataEnvelope information. Defaults to using a
+     *   HeadersMetadataStrategy. Can either be a class implementing
+     *   MetadataStrategy, a class name of a predefined strategy, or empty/null
+     *   to default.
+     * - @InstructionFileSuffix: (string|null) Suffix used when writing to an
+     *   instruction file if using an InstructionFileMetadataHandler.
+     *
+     * @return PromiseInterface
+     *
+     * @throws \InvalidArgumentException Thrown when arguments above are not
+     *                                   passed or are passed incorrectly.
+     */
+    public function putObjectAsync(array $args)
+    {
+        $provider = $this->getMaterialsProvider($args);
+        unset($args['@MaterialsProvider']);
+
+        $instructionFileSuffix = $this->getInstructionFileSuffix($args);
+        unset($args['@InstructionFileSuffix']);
+
+        $strategy = $this->getMetadataStrategy($args, $instructionFileSuffix);
+        unset($args['@MetadataStrategy']);
+
+        $envelope = new MetadataEnvelope();
+
+        $bodyStream = Psr7\Utils::streamFor($args['Body']);
+        // User-owned resource which should be detached instead of closed
+        // during garbage-collection
+        if (is_resource($args['Body'])) {
+            $bodyStream = \Aws\detach_on_close_stream($bodyStream);
+        }
+
+        return Promise\Create::promiseFor($this->encrypt(
+            $bodyStream,
+            $args,
+            $provider,
+            $envelope
+        ))->then(
+            function ($encryptedBodyStream) use ($args) {
+                $hash = new PhpHash('sha256');
+                $hashingEncryptedBodyStream = new HashingStream(
+                    $encryptedBodyStream,
+                    $hash,
+                    self::getContentShaDecorator($args)
+                );
+                return [$hashingEncryptedBodyStream, $args];
+            }
+        )->then(
+            function ($putObjectContents) use ($strategy, $envelope) {
+                list($bodyStream, $args) = $putObjectContents;
+                if ($strategy === null) {
+                    $strategy = self::getDefaultStrategy();
+                }
+
+                $updatedArgs = $strategy->save($envelope, $args);
+                $updatedArgs['Body'] = $bodyStream;
+                return $updatedArgs;
+            }
+        )->then(
+            function ($args) {
+                unset($args['@CipherOptions']);
+                return $this->client->putObjectAsync($args);
+            }
+        );
+    }
+
+    private static function getContentShaDecorator(&$args)
+    {
+        return function ($hash) use (&$args) {
+            $args['ContentSHA256'] = bin2hex($hash);
+        };
+    }
+
+    /**
+     * Encrypts the data in the 'Body' field of $args and uploads it to the
+     * specified location on S3.
+     *
+     * Note that for PHP versions of < 7.1, this operation uses an AES-GCM
+     * polyfill for encryption since there is no native PHP support. The
+     * performance for large inputs will be a lot slower than for PHP 7.1+, so
+     * upgrading older PHP version environments may be necessary to use this
+     * effectively.
+     *
+     * @param array $args Arguments for encrypting an object and uploading it
+     *                    to S3 via PutObject.
+     *
+     * The required configuration arguments are as follows:
+     *
+     * - @MaterialsProvider: (MaterialsProvider) Provides Cek, Iv, and Cek
+     *   encrypting/decrypting for encryption metadata.
+     * - @CipherOptions: (array) Cipher options for encrypting data. A Cipher
+     *   is required. Accepts the following options:
+     *       - Cipher: (string) gcm
+     *            See also: AbstractCryptoClientV2::$supportedCiphers
+     *       - KeySize: (int) 128|256
+     *            See also: MaterialsProvider::$supportedKeySizes
+     *       - Aad: (string) Additional authentication data. This option is
+     *            passed directly to OpenSSL when using gcm. Note if you pass in
+     *            Aad, the PHP SDK will be able to decrypt the resulting object,
+     *            but other AWS SDKs may not be able to do so.
+     * - @KmsEncryptionContext: (array) Only required if using
+     *   KmsMaterialsProviderV2. An associative array of key-value
+     *   pairs to be added to the encryption context for KMS key encryption. An
+     *   empty array may be passed if no additional context is desired.
+     *
+     * The optional configuration arguments are as follows:
+     *
+     * - @MetadataStrategy: (MetadataStrategy|string|null) Strategy for storing
+     *   MetadataEnvelope information. Defaults to using a
+     *   HeadersMetadataStrategy. Can either be a class implementing
+     *   MetadataStrategy, a class name of a predefined strategy, or empty/null
+     *   to default.
+     * - @InstructionFileSuffix: (string|null) Suffix used when writing to an
+     *   instruction file if an using an InstructionFileMetadataHandler was
+     *   determined.
+     *
+     * @return \Aws\Result PutObject call result with the details of uploading
+     *                     the encrypted file.
+     *
+     * @throws \InvalidArgumentException Thrown when arguments above are not
+     *                                   passed or are passed incorrectly.
+     */
+    public function putObject(array $args)
+    {
+        return $this->putObjectAsync($args)->wait();
+    }
+
+    /**
+     * Promises to retrieve an object from S3 and decrypt the data in the
+     * 'Body' field.
+     *
+     * @param array $args Arguments for retrieving an object from S3 via
+     *                    GetObject and decrypting it.
+     *
+     * The required configuration argument is as follows:
+     *
+     * - @MaterialsProvider: (MaterialsProviderInterface) Provides Cek, Iv, and Cek
+     *   encrypting/decrypting for decryption metadata. May have data loaded
+     *   from the MetadataEnvelope upon decryption.
+     * - @SecurityProfile: (string) Must be set to 'V2' or 'V2_AND_LEGACY'.
+     *      - 'V2' indicates that only objects encrypted with S3EncryptionClientV2
+     *        content encryption and key wrap schemas are able to be decrypted.
+     *      - 'V2_AND_LEGACY' indicates that objects encrypted with both
+     *        S3EncryptionClientV2 and older legacy encryption clients are able
+     *        to be decrypted.
+     * - @CommitmentPolicy: (string) Must be set to 'FORBID_ENCRYPT_ALLOW_DECRYPT'.
+     *      - 'FORBID_ENCRYPT_ALLOW_DECRYPT' indicates that the client is configured
+     *         to read messages encrypted with key commitment or without key commitment.
+     * 
+     * The optional configuration arguments are as follows:
+     *
+     * - SaveAs: (string) The path to a file on disk to save the decrypted
+     *   object data. This will be handled by file_put_contents instead of the
+     *   Guzzle sink.
+     *
+     * - @MetadataStrategy: (MetadataStrategy|string|null) Strategy for reading
+     *   MetadataEnvelope information. Defaults to determining based on object
+     *   response headers. Can either be a class implementing MetadataStrategy,
+     *   a class name of a predefined strategy, or empty/null to default.
+     * - @InstructionFileSuffix: (string) Suffix used when looking for an
+     *   instruction file if an InstructionFileMetadataHandler is being used.
+     * - @CipherOptions: (array) Cipher options for decrypting data. A Cipher
+     *   is required. Accepts the following options:
+     *       - Aad: (string) Additional authentication data. This option is
+     *            passed directly to OpenSSL when using gcm. It is ignored when
+     *            using cbc.
+     * - @KmsAllowDecryptWithAnyCmk: (bool) This allows decryption with
+     *   KMS materials for any KMS key ID, instead of needing the KMS key ID to
+     *   be specified and provided to the decrypt operation. Ignored for non-KMS
+     *   materials providers. Defaults to false.
+     *
+     * @return PromiseInterface
+     *
+     * @throws \InvalidArgumentException Thrown when required arguments are not
+     *                                   passed or are passed incorrectly.
+     */
+    public function getObjectAsync(array $args)
+    {
+        $provider = $this->getMaterialsProvider($args);
+        unset($args['@MaterialsProvider']);
+
+        $keyCommitmentPolicy = $this->getKeyCommitmentPolicy($args);
+
+        $instructionFileSuffix = $this->getInstructionFileSuffix($args);
+        unset($args['@InstructionFileSuffix']);
+
+        $strategy = $this->getMetadataStrategy($args, $instructionFileSuffix);
+        unset($args['@MetadataStrategy']);
+
+        if (!isset($args['@SecurityProfile'])
+            || !in_array($args['@SecurityProfile'], self::$supportedSecurityProfiles)
+        ) {
+            throw new CryptoException("@SecurityProfile is required and must be"
+                . " set to 'V2' or 'V2_AND_LEGACY'");
+        }
+
+        // Only throw this legacy warning once per client
+        if (in_array($args['@SecurityProfile'], self::$legacySecurityProfiles)
+            && $this->legacyWarningCount < 1
+        ) {
+            $this->legacyWarningCount++;
+            trigger_error(
+                "This S3 Encryption Client operation is configured to"
+                . " read encrypted data with legacy encryption modes. If you"
+                . " don't have objects encrypted with these legacy modes,"
+                . " you should disable support for them to enhance security. ",
+                E_USER_WARNING
+            );
+        }
+
+        $saveAs = null;
+        if (!empty($args['SaveAs'])) {
+            $saveAs = $args['SaveAs'];
+        }
+
+        $promise = $this->client->getObjectAsync($args)
+            ->then(
+                function ($result) use (
+                    $provider,
+                    $instructionFileSuffix,
+                    $strategy,
+                    $args
+                ) {
+                    if ($strategy === null) {
+                        $strategy = $this->determineGetObjectStrategy(
+                            $result,
+                            $instructionFileSuffix
+                        );
+                    }
+
+                    $envelope = $strategy->load($args + [
+                        'Metadata' => $result['Metadata']
+                    ]);
+
+                    $result['Body'] = $this->decrypt(
+                        $result['Body'],
+                        $provider,
+                        $envelope,
+                        $args
+                    );
+                    return $result;
+                }
+            )->then(
+                function ($result) use ($saveAs) {
+                    if (!empty($saveAs)) {
+                        file_put_contents(
+                            $saveAs,
+                            (string)$result['Body'],
+                            LOCK_EX
+                        );
+                    }
+                    return $result;
+                }
+            );
+
+        return $promise;
+    }
+
+    /**
+     * Retrieves an object from S3 and decrypts the data in the 'Body' field.
+     *
+     * @param array $args Arguments for retrieving an object from S3 via
+     *                    GetObject and decrypting it.
+     *
+     * The required configuration argument is as follows:
+     *
+     * - @MaterialsProvider: (MaterialsProviderInterface) Provides Cek, Iv, and Cek
+     *   encrypting/decrypting for decryption metadata. May have data loaded
+     *   from the MetadataEnvelope upon decryption.
+     * - @SecurityProfile: (string) Must be set to 'V2' or 'V2_AND_LEGACY'.
+     *      - 'V2' indicates that only objects encrypted with S3EncryptionClientV2
+     *        content encryption and key wrap schemas are able to be decrypted.
+     *      - 'V2_AND_LEGACY' indicates that objects encrypted with both
+     *        S3EncryptionClientV2 and older legacy encryption clients are able
+     *        to be decrypted.
+     * - @CommitmentPolicy: (string) Must be set to 'FORBID_ENCRYPT_ALLOW_DECRYPT'.
+     *      - 'FORBID_ENCRYPT_ALLOW_DECRYPT' indicates that the client is 
+     *         configured to read messages encrypted with key commitment 
+     *         or without key commitment.
+     *
+     * The optional configuration arguments are as follows:
+     *
+     * - SaveAs: (string) The path to a file on disk to save the decrypted
+     *   object data. This will be handled by file_put_contents instead of the
+     *   Guzzle sink.
+     * - @InstructionFileSuffix: (string|null) Suffix used when looking for an
+     *   instruction file if an InstructionFileMetadataHandler was detected.
+     * - @CipherOptions: (array) Cipher options for encrypting data. A Cipher
+     *   is required. Accepts the following options:
+     *       - Aad: (string) Additional authentication data. This option is
+     *            passed directly to OpenSSL when using gcm. It is ignored when
+     *            using cbc.
+     * - @KmsAllowDecryptWithAnyCmk: (bool) This allows decryption with
+     *   KMS materials for any KMS key ID, instead of needing the KMS key ID to
+     *   be specified and provided to the decrypt operation. Ignored for non-KMS
+     *   materials providers. Defaults to false.
+     *
+     * @return \Aws\Result GetObject call result with the 'Body' field
+     *                     wrapped in a decryption stream with its metadata
+     *                     information.
+     *
+     * @throws \InvalidArgumentException Thrown when arguments above are not
+     *                                   passed or are passed incorrectly.
+     */
+    public function getObject(array $args)
+    {
+        return $this->getObjectAsync($args)->wait();
+    }
+}

+ 588 - 0
upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/S3/Crypto/S3EncryptionClientV3.php

@@ -0,0 +1,588 @@
+<?php
+namespace Aws\S3\Crypto;
+
+use Aws\Crypto\DecryptionTraitV3;
+use Aws\Exception\CryptoException;
+use Aws\HashingStream;
+use Aws\MetricsBuilder;
+use Aws\PhpHash;
+use Aws\Result;
+use Aws\Crypto\AbstractCryptoClientV3;
+use Aws\Crypto\EncryptionTraitV3;
+use Aws\Crypto\MetadataEnvelope;
+use Aws\Crypto\AlgorithmSuite;
+use Aws\Crypto\Cipher\CipherBuilderTrait;
+use Aws\S3\S3Client;
+use GuzzleHttp\Promise;
+use GuzzleHttp\Promise\PromiseInterface;
+use GuzzleHttp\Psr7;
+
+/**
+ * Provides a wrapper for an S3Client that supplies functionality to encrypt
+ * data on putObject[Async] calls and decrypt data on getObject[Async] calls.
+ *
+ * AWS strongly recommends the upgrade to the S3EncryptionClientV3 (over the
+ * S3EncryptionClientV2 or S3EncryptionClient), as it offers updated 
+ * data security best practices to our customers who upgrade.
+ * S3EncryptionClientV3 contains breaking changes, so this
+ * will require planning by engineering teams to migrate. New workflows should
+ * just start with S3EncryptionClientV3.
+ *
+ *
+ * Example write path:
+ *
+ * <code>
+ * use Aws\Crypto\KmsMaterialsProviderV3;
+ * use Aws\S3\Crypto\S3EncryptionClientV3;
+ * use Aws\S3\S3Client;
+ *
+ * $encryptionClient = new S3EncryptionClientV3(
+ *     new S3Client([
+ *         'region' => 'us-west-2',
+ *         'version' => 'latest'
+ *     ])
+ * );
+ * $materialsProvider = new KmsMaterialsProviderV3(
+ *     new KmsClient([
+ *         'profile' => 'default',
+ *         'region' => 'us-east-1',
+ *         'version' => 'latest',
+ *     ],
+ *    'your-kms-key-id'
+ * );
+ *
+ * $encryptionClient->putObject([
+ *     '@MaterialsProvider' => $materialsProvider,
+ *     '@CipherOptions' => [
+ *         'Cipher' => 'gcm',
+ *         'KeySize' => 256,
+ *     ],
+ *     '@CommitmentPolicy' => 'REQUIRE_ENCRYPT_REQUIRE_DECRYPT',
+ *     '@KmsEncryptionContext' => ['foo' => 'bar'],
+ *     'Bucket' => 'your-bucket',
+ *     'Key' => 'your-key',
+ *     'Body' => 'your-encrypted-data',
+ * ]);
+ * </code>
+ *
+ * Example read call (using objects from previous example):
+ *
+ * <code>
+ * $encryptionClient->getObject([
+ *     '@MaterialsProvider' => $materialsProvider,
+ *     '@CipherOptions' => [
+ *         'Cipher' => 'gcm',
+ *         'KeySize' => 256,
+ *     ],
+ *     '@CommitmentPolicy' => 'REQUIRE_ENCRYPT_REQUIRE_DECRYPT',
+ *     'Bucket' => 'your-bucket',
+ *     'Key' => 'your-key',
+ * ]);
+ * </code>
+ */
+class S3EncryptionClientV3 extends AbstractCryptoClientV3
+{
+    use CipherBuilderTrait;
+    use CryptoParamsTraitV3;
+    use DecryptionTraitV3;
+    use EncryptionTraitV3;
+    use UserAgentTrait;
+
+    const CRYPTO_VERSION = '3.0';
+
+    private S3Client $client;
+    private ?string $instructionFileSuffix;
+    private int $legacyWarningCount;
+
+    /**
+     * @param S3Client $client The S3Client to be used for true uploading and
+     *                         retrieving objects from S3 when using the
+     *                         encryption client.
+     * @param string|null $instructionFileSuffix Suffix for a client wide
+     *                                           default when using instruction
+     *                                           files for metadata storage.
+     */
+    public function __construct(
+        //= ../specification/s3-encryption/client.md#wrapped-s3-client-s
+        //= type=implication
+        //# The S3EC MUST support the option to provide an SDK S3 client instance during its initialization.
+        S3Client $client,
+        //= ../specification/s3-encryption/client.md#aws-sdk-compatibility
+        //= type=implication
+        //# The S3EC MUST provide a different set of configuration options than the conventional S3 client.
+
+        //= ../specification/s3-encryption/client.md#instruction-file-configuration
+        //= type=implication
+        //# In this case, the Instruction File Configuration SHOULD be optional,
+        //# such that its default configuration is used when none is provided.
+        ?string $instructionFileSuffix = null
+    ) {
+        //= ../specification/s3-encryption/client.md#aws-sdk-compatibility
+        //= type=implication
+        //# The S3EC MUST adhere to the same interface for API operations as the conventional AWS SDK S3 client.
+        $this->appendUserAgent($client, 'feat/s3-encrypt-php/' . self::CRYPTO_VERSION);
+        //= ../specification/s3-encryption/client.md#wrapped-s3-client-s
+        //# The S3EC MUST NOT support use of S3EC as the provided S3 client during its initialization;
+        //# it MUST throw an exception in this case.
+        if ($client instanceof S3EncryptionClientV3) {
+            throw new CryptoException("Client configuration error."
+                . " An S3 Encryption Client is not a valid S3 client for an S3 Encryption Client.");   
+        }
+        $this->client = $client;
+        //= ../specification/s3-encryption/client.md#instruction-file-configuration
+        //= type=implication
+        //# The S3EC MAY support the option to provide Instruction File Configuration during its initialization.
+
+        //= ../specification/s3-encryption/client.md#instruction-file-configuration
+        //= type=implication
+        //# If the S3EC in a given language supports Instruction Files,
+        //# then it MUST accept Instruction File Configuration during its initialization.
+        $this->instructionFileSuffix = $instructionFileSuffix;
+        $this->legacyWarningCount = 0;
+        MetricsBuilder::appendMetricsCaptureMiddleware(
+            $this->client->getHandlerList(),
+            MetricsBuilder::S3_CRYPTO_V3
+        );
+
+        if (!extension_loaded('openssl')) {
+            throw new CryptoException("Unable to load `openssl` extension.");
+        }
+    }
+
+    //= ../specification/s3-encryption/data-format/metadata-strategy.md#instruction-file
+    //# Instruction File writes MUST NOT be enabled by default.
+    private static function getDefaultStrategy(): HeadersMetadataStrategy
+    {
+        return new HeadersMetadataStrategy();
+    }
+
+    /**
+     * Encrypts the data in the 'Body' field of $args and promises to upload it
+     * to the specified location on S3.
+     *
+     * @param array $args Arguments for encrypting an object and uploading it
+     *                    to S3 via PutObject.
+     *
+     * The required configuration arguments are as follows:
+     *
+     * - @MaterialsProvider: (MaterialsProviderV3) Provides Cek, Iv, and Cek
+     *   encrypting/decrypting for encryption metadata.
+     * - @CommitmentPolicy: (string) Must be set to 'FORBID_ENCRYPT_ALLOW_DECRYPT',
+     *         'REQUIRE_ENCRYPT_ALLOW_DECRYPT', or 'REQUIRE_ENCRYPT_REQUIRE_DECRYPT'.
+     *      - 'FORBID_ENCRYPT_ALLOW_DECRYPT' indicates that the client is configured
+     *         to write messages without key commitment and read messages encrypted 
+     *         with key commitment or without key commitment.
+     *      - 'REQUIRE_ENCRYPT_ALLOW_DECRYPT' indicates that the client is configured
+     *         to write messages with key commitment and read messages encrypted 
+     *         with key commitment or without key commitment.
+     *      - 'REQUIRE_ENCRYPT_REQUIRE_DECRYPT' indicates that the client is configured
+     *         to write messages with key commitment and read messages encrypted 
+     *         with key commitment.
+     * - @CipherOptions: (array) Cipher options for encrypting data. Only the
+     *   Cipher option is required. Accepts the following:
+     *       - Cipher: (string) gcm
+     *            See also: AbstractCryptoClientV3::$supportedCiphers
+     *       - KeySize: (int) 256
+     *            See also: MaterialsProvider::$supportedKeySizes
+     *       - Aad: (string) Additional authentication data. This option is
+     *            passed directly to OpenSSL when using gcm. Note if you pass in
+     *            Aad, the PHP SDK will be able to decrypt the resulting object,
+     *            but other AWS SDKs may not be able to do so.
+     * - @KmsEncryptionContext: (array) Only required if using
+     *   KmsMaterialsProviderV3. An associative array of key-value
+     *   pairs to be added to the encryption context for KMS key encryption. An
+     *   empty array may be passed if no additional context is desired.
+     *
+     * The optional configuration arguments are as follows:
+     *
+     * - @MetadataStrategy: (MetadataStrategy|string|null) Strategy for storing
+     *   MetadataEnvelope information. Defaults to using a
+     *   HeadersMetadataStrategy. Can either be a class implementing
+     *   MetadataStrategy, a class name of a predefined strategy, or empty/null
+     *   to default.
+     * - @InstructionFileSuffix: (string|null) Suffix used when writing to an
+     *   instruction file if using an InstructionFileMetadataHandler.
+     *
+     * @return PromiseInterface
+     *
+     * @throws \InvalidArgumentException Thrown when arguments above are not
+     *                                   passed or are passed incorrectly.
+     */
+    public function putObjectAsync(array $args): PromiseInterface
+    {
+        //= ../specification/s3-encryption/client.md#cryptographic-materials
+        //= type=implication
+        //# The S3EC MUST accept either one CMM or one Keyring instance upon initialization.
+        $provider = $this->getMaterialsProvider($args);
+        unset($args['@MaterialsProvider']);
+
+        //= ../specification/s3-encryption/client.md#key-commitment
+        //= type=implication
+        //# The S3EC MUST support configuration of the [Key Commitment policy](./key-commitment.md) during its initialization.
+        $keyCommitmentPolicy = $this->getKeyCommitmentPolicy($args);
+        unset($args['@CommitmentPolicy']);
+
+        //= ../specification/s3-encryption/data-format/metadata-strategy.md#instruction-file
+        //# Instruction File writes MUST be optionally configured during client creation or on each PutObject request.
+        $instructionFileSuffix = $this->getInstructionFileSuffix($args);
+        unset($args['@InstructionFileSuffix']);
+
+        $strategy = $this->getMetadataStrategy($args, $instructionFileSuffix);
+        unset($args['@MetadataStrategy']);
+
+        //= ../specification/s3-encryption/client.md#encryption-algorithm
+        //= type=implication
+        //# The S3EC MUST support configuration of the encryption algorithm (or algorithm suite) during its initialization.
+        $options = array_change_key_case($args);
+        $cipherOptions = array_intersect_key(
+            $options['@cipheroptions'],
+            self::$allowedOptions
+        );
+        if (empty($cipherOptions['Cipher'])) {
+            throw new \InvalidArgumentException('An encryption cipher must be'
+                . ' specified in @CipherOptions["Cipher"].');
+        }
+
+        $algorithmSuite = AlgorithmSuite::validateCommitmentPolicyOnEncrypt(
+            $cipherOptions,
+            $keyCommitmentPolicy
+        );
+
+        $envelope = new MetadataEnvelope();
+
+        $bodyStream = Psr7\Utils::streamFor($args['Body']);
+        // User-owned resource which should be detached instead of closed
+        // during garbage-collection
+        if (is_resource($args['Body'])) {
+            $bodyStream = \Aws\detach_on_close_stream($bodyStream);
+        }
+
+        return Promise\Create::promiseFor(
+            //= ../specification/s3-encryption/client.md#required-api-operations
+            //= type=implication
+            //# - PutObject MUST encrypt its input data before it is uploaded to S3.
+            $this->encrypt(
+                $bodyStream,
+                $algorithmSuite,
+                $options,
+                $provider,
+                $envelope
+            )
+        )->then(
+                function ($encryptedBodyStream) use ($args) {
+                    $hash = new PhpHash('sha256');
+                    $hashingEncryptedBodyStream = new HashingStream(
+                        $encryptedBodyStream,
+                        $hash,
+                        self::getContentShaDecorator($args)
+                    );
+                    
+                    return [$hashingEncryptedBodyStream, $args];
+                }
+            )->then(
+                function ($putObjectContents) use ($strategy, $envelope) {
+                    list($bodyStream, $args) = $putObjectContents;
+                    if ($strategy === null) {
+                        $strategy = self::getDefaultStrategy();
+                    }
+                    //= ../specification/s3-encryption/data-format/metadata-strategy.md#object-metadata
+                    //# By default, the S3EC MUST store content metadata in the S3 Object Metadata.
+                    $updatedArgs = $strategy->save($envelope, $args);
+                    $updatedArgs['Body'] = $bodyStream;
+                    
+                    return $updatedArgs;
+                }
+            )->then(
+                function ($args) {
+                    unset($args['@CipherOptions']);
+                    
+                    return $this->client->putObjectAsync($args);
+                }
+            );
+    }
+
+    private static function getContentShaDecorator(&$args): \Closure
+    {
+        return function ($hash) use (&$args) {
+            $args['ContentSHA256'] = bin2hex($hash);
+        };
+    }
+
+    /**
+     * Encrypts the data in the 'Body' field of $args and uploads it to the
+     * specified location on S3.
+     *
+     * @param array $args Arguments for encrypting an object and uploading it
+     *                    to S3 via PutObject.
+     *
+     * The required configuration arguments are as follows:
+     *
+     * - @MaterialsProvider: (MaterialsProvider) Provides Cek, Iv, and Cek
+     *   encrypting/decrypting for encryption metadata.
+     * - @CommitmentPolicy: (string) Must be set to 'FORBID_ENCRYPT_ALLOW_DECRYPT',
+     *         'REQUIRE_ENCRYPT_ALLOW_DECRYPT', or 'REQUIRE_ENCRYPT_REQUIRE_DECRYPT'.
+     *      - 'FORBID_ENCRYPT_ALLOW_DECRYPT' indicates that the client is configured
+     *         to write messages without key commitment and read messages encrypted 
+     *         with key commitment or without key commitment.
+     *      - 'REQUIRE_ENCRYPT_ALLOW_DECRYPT' indicates that the client is configured
+     *         to write messages with key commitment and read messages encrypted 
+     *         with key commitment or without key commitment.
+     *      - 'REQUIRE_ENCRYPT_REQUIRE_DECRYPT' indicates that the client is configured
+     *         to write messages with key commitment and read messages encrypted 
+     *         with key commitment.
+     * - @CipherOptions: (array) Cipher options for encrypting data. A Cipher
+     *   is required. Accepts the following options:
+     *       - Cipher: (string) gcm
+     *            See also: AbstractCryptoClientV3::$supportedCiphers
+     *       - KeySize: (int) 128|256
+     *            See also: MaterialsProvider::$supportedKeySizes
+     *       - Aad: (string) Additional authentication data. This option is
+     *            passed directly to OpenSSL when using gcm. Note if you pass in
+     *            Aad, the PHP SDK will be able to decrypt the resulting object,
+     *            but other AWS SDKs may not be able to do so.
+     * - @KmsEncryptionContext: (array) Only required if using
+     *   KmsMaterialsProviderV3. An associative array of key-value
+     *   pairs to be added to the encryption context for KMS key encryption. An
+     *   empty array may be passed if no additional context is desired.
+     *
+     * The optional configuration arguments are as follows:
+     *
+     * - @MetadataStrategy: (MetadataStrategy|string|null) Strategy for storing
+     *   MetadataEnvelope information. Defaults to using a
+     *   HeadersMetadataStrategy. Can either be a class implementing
+     *   MetadataStrategy, a class name of a predefined strategy, or empty/null
+     *   to default.
+     * - @InstructionFileSuffix: (string|null) Suffix used when writing to an
+     *   instruction file if an using an InstructionFileMetadataHandler was
+     *   determined.
+     *
+     * @return \Aws\Result PutObject call result with the details of uploading
+     *                     the encrypted file.
+     *
+     * @throws \InvalidArgumentException Thrown when arguments above are not
+     *                                   passed or are passed incorrectly.
+     */
+    public function putObject(array $args): Result
+    {
+        //= ../specification/s3-encryption/client.md#required-api-operations
+        //= type=implication
+        //# - PutObject MUST be implemented by the S3EC.
+        return $this->putObjectAsync($args)->wait();
+    }
+
+    /**
+     * Promises to retrieve an object from S3 and decrypt the data in the
+     * 'Body' field.
+     *
+     * @param array $args Arguments for retrieving an object from S3 via
+     *                    GetObject and decrypting it.
+     *
+     * The required configuration argument is as follows:
+     *
+     * - @MaterialsProvider: (MaterialsProviderInterface) Provides Cek, Iv, and Cek
+     *   encrypting/decrypting for decryption metadata. May have data loaded
+     *   from the MetadataEnvelope upon decryption.
+     * - @CommitmentPolicy: (string) Must be set to 'FORBID_ENCRYPT_ALLOW_DECRYPT',
+     *         'REQUIRE_ENCRYPT_ALLOW_DECRYPT', or 'REQUIRE_ENCRYPT_REQUIRE_DECRYPT'.
+     *      - 'FORBID_ENCRYPT_ALLOW_DECRYPT' indicates that the client is configured
+     *         to write messages without key commitment and read messages encrypted 
+     *         with key commitment or without key commitment.
+     *      - 'REQUIRE_ENCRYPT_ALLOW_DECRYPT' indicates that the client is configured
+     *         to write messages with key commitment and read messages encrypted 
+     *         with key commitment or without key commitment.
+     *      - 'REQUIRE_ENCRYPT_REQUIRE_DECRYPT' indicates that the client is configured
+     *         to write messages with key commitment and read messages encrypted 
+     *         with key commitment.
+     * - @SecurityProfile: (string) Must be set to 'V3' or 'V3_AND_LEGACY'.
+     *      - 'V3' indicates that only objects encrypted with S3EncryptionClientV3
+     *        content encryption and key wrap schemas are able to be decrypted.
+     *      - 'V3_AND_LEGACY' indicates that objects encrypted with both
+     *        S3EncryptionClientV3 and older legacy encryption clients are able
+     *        to be decrypted.
+     *
+     * The optional configuration arguments are as follows:
+     *
+     * - SaveAs: (string) The path to a file on disk to save the decrypted
+     *   object data. This will be handled by file_put_contents instead of the
+     *   Guzzle sink.
+     *
+     * - @MetadataStrategy: (MetadataStrategy|string|null) Strategy for reading
+     *   MetadataEnvelope information. Defaults to determining based on object
+     *   response headers. Can either be a class implementing MetadataStrategy,
+     *   a class name of a predefined strategy, or empty/null to default.
+     * - @InstructionFileSuffix: (string) Suffix used when looking for an
+     *   instruction file if an InstructionFileMetadataHandler is being used.
+     * - @CipherOptions: (array) Cipher options for decrypting data. A Cipher
+     *   is required. Accepts the following options:
+     *       - Aad: (string) Additional authentication data. This option is
+     *            passed directly to OpenSSL when using gcm. It is ignored when
+     *            using cbc.
+     * - @KmsAllowDecryptWithAnyCmk: (bool) This allows decryption with
+     *   KMS materials for any KMS key ID, instead of needing the KMS key ID to
+     *   be specified and provided to the decrypt operation. Ignored for non-KMS
+     *   materials providers. Defaults to false.
+     *
+     * @return PromiseInterface
+     *
+     * @throws \InvalidArgumentException Thrown when required arguments are not
+     *                                   passed or are passed incorrectly.
+     */
+    public function getObjectAsync(array $args): PromiseInterface
+    {
+        //= ../specification/s3-encryption/client.md#cryptographic-materials
+        //= type=implication
+        //# The S3EC MUST accept either one CMM or one Keyring instance upon initialization.
+        $provider = $this->getMaterialsProvider($args);
+        unset($args['@MaterialsProvider']);
+
+        //= ../specification/s3-encryption/client.md#key-commitment
+        //= type=implication
+        //# The S3EC MUST support configuration of the [Key Commitment policy](./key-commitment.md) during its initialization.
+        $keyCommitmentPolicy = $this->getKeyCommitmentPolicy($args);
+        unset($args['@CommitmentPolicy']);
+
+        $instructionFileSuffix = $this->getInstructionFileSuffix($args);
+        unset($args['@InstructionFileSuffix']);
+
+        $strategy = $this->getMetadataStrategy($args, $instructionFileSuffix);
+        unset($args['@MetadataStrategy']);
+
+        //= ../specification/s3-encryption/client.md#enable-legacy-wrapping-algorithms
+        //= type=implication
+        //# The S3EC MUST support the option to enable or disable legacy wrapping algorithms.
+        if (!isset($args['@SecurityProfile'])
+            || !in_array($args['@SecurityProfile'], self::SUPPORTED_SECURITY_PROFILES)
+        ) {
+            throw new CryptoException("@SecurityProfile is required and must be"
+                . " set to 'V3' or 'V3_AND_LEGACY'");
+        }
+
+        // Only throw this legacy warning once per client
+        if (in_array($args['@SecurityProfile'], self::LEGACY_SECURITY_PROFILES)
+            && $this->legacyWarningCount < 1
+        ) {
+            $this->legacyWarningCount++;
+            trigger_error(
+                "This S3 Encryption Client operation is configured to"
+                . " read encrypted data with legacy encryption modes. If you"
+                . " don't have objects encrypted with these legacy modes,"
+                . " you should disable support for them to enhance security. ",
+                E_USER_WARNING
+            );
+        }
+
+        $saveAs = null;
+        if (!empty($args['SaveAs'])) {
+            $saveAs = $args['SaveAs'];
+        }
+
+        $promise = $this->client->getObjectAsync($args)
+            ->then(
+                function ($result) use (
+                    $provider,
+                    $instructionFileSuffix,
+                    $strategy,
+                    $keyCommitmentPolicy,
+                    $args
+                ) {
+                    if ($strategy === null) {
+                        $strategy = $this->determineGetObjectStrategy(
+                            $result,
+                            $instructionFileSuffix
+                        );
+                    }
+
+                    $envelope = $strategy->load($args + [
+                        'Metadata' => $result['Metadata']
+                    ]);
+                    //= ../specification/s3-encryption/client.md#required-api-operations
+                    //= type=implication
+                    //# - GetObject MUST decrypt data received from the S3 server and return it as plaintext.
+                    $result['Body'] = $this->decrypt(
+                        $result['Body'],
+                        $provider,
+                        $envelope,
+                        $keyCommitmentPolicy,
+                        $args
+                    );
+                    
+                    return $result;
+                }
+            )->then(
+                function ($result) use ($saveAs) {
+                    if (!empty($saveAs)) {
+                        file_put_contents(
+                            $saveAs,
+                            (string)$result['Body'],
+                            LOCK_EX
+                        );
+                    }
+                    
+                    return $result;
+                }
+            );
+
+        return $promise;
+    }
+
+    /**
+     * Retrieves an object from S3 and decrypts the data in the 'Body' field.
+     *
+     * @param array $args Arguments for retrieving an object from S3 via
+     *                    GetObject and decrypting it.
+     *
+     * The required configuration argument is as follows:
+     *
+     * - @MaterialsProvider: (MaterialsProviderInterface) Provides Cek, Iv, and Cek
+     *   encrypting/decrypting for decryption metadata. May have data loaded
+     *   from the MetadataEnvelope upon decryption.
+     * - @CommitmentPolicy: (string) Must be set to 'FORBID_ENCRYPT_ALLOW_DECRYPT',
+     *         'REQUIRE_ENCRYPT_ALLOW_DECRYPT', or 'REQUIRE_ENCRYPT_REQUIRE_DECRYPT'.
+     *      - 'FORBID_ENCRYPT_ALLOW_DECRYPT' indicates that the client is configured
+     *         to write messages without key commitment and read messages encrypted 
+     *         with key commitment or without key commitment.
+     *      - 'REQUIRE_ENCRYPT_ALLOW_DECRYPT' indicates that the client is configured
+     *         to write messages with key commitment and read messages encrypted 
+     *         with key commitment or without key commitment.
+     *      - 'REQUIRE_ENCRYPT_REQUIRE_DECRYPT' indicates that the client is configured
+     *         to write messages with key commitment and read messages encrypted 
+     *         with key commitment.
+     * - @SecurityProfile: (string) Must be set to 'V3' or 'V3_AND_LEGACY'.
+     *      - 'V3' indicates that only objects encrypted with S3EncryptionClientV3
+     *        content encryption and key wrap schemas are able to be decrypted.
+     *      - 'V3_AND_LEGACY' indicates that objects encrypted with both
+     *        S3EncryptionClientV3 and older legacy encryption clients are able
+     *        to be decrypted.
+     *
+     * The optional configuration arguments are as follows:
+     *
+     * - SaveAs: (string) The path to a file on disk to save the decrypted
+     *   object data. This will be handled by file_put_contents instead of the
+     *   Guzzle sink.
+     * - @InstructionFileSuffix: (string|null) Suffix used when looking for an
+     *   instruction file if an InstructionFileMetadataHandler was detected.
+     * - @CipherOptions: (array) Cipher options for encrypting data. A Cipher
+     *   is required. Accepts the following options:
+     *       - Aad: (string) Additional authentication data. This option is
+     *            passed directly to OpenSSL when using gcm. It is ignored when
+     *            using cbc.
+     * - @KmsAllowDecryptWithAnyCmk: (bool) This allows decryption with
+     *   KMS materials for any KMS key ID, instead of needing the KMS key ID to
+     *   be specified and provided to the decrypt operation. Ignored for non-KMS
+     *   materials providers. Defaults to false.
+     *
+     * @return \Aws\Result GetObject call result with the 'Body' field
+     *                     wrapped in a decryption stream with its metadata
+     *                     information.
+     *
+     * @throws \InvalidArgumentException Thrown when arguments above are not
+     *                                   passed or are passed incorrectly.
+     */
+    public function getObject(array $args): Result
+    {
+        //= ../specification/s3-encryption/client.md#required-api-operations
+        //= type=implication
+        //# - GetObject MUST be implemented by the S3EC.
+        return $this->getObjectAsync($args)->wait();
+    }
+}

+ 47 - 0
upgrade/files/15.0.0.B3-15.0.0.RC1/files/plugins/aws/aws-sdk-php/src/S3/Exception/MultipartCopyAnnotationException.php

@@ -0,0 +1,47 @@
+<?php
+namespace Aws\S3\Exception;
+
+use Aws\Exception\MultipartUploadException;
+use Aws\Multipart\UploadState;
+
+/**
+ * Phase 3 PutObjectAnnotation partial failure. Carries per-name
+ * succeeded/failed maps via {@see getSucceededAnnotations()} and
+ * {@see getFailedAnnotations()}.
+ */
+class MultipartCopyAnnotationException extends MultipartUploadException
+{
+    /** @var string[] */
+    private array $succeeded;
+    /** @var array<string,S3Exception> */
+    private array $failed;
+
+    /**
+     * @param UploadState               $state
+     * @param array<string,S3Exception> $failed
+     * @param string[]                  $succeeded
+     */
+    public function __construct(UploadState $state, array $failed, array $succeeded = [])
+    {
+        parent::__construct($state, $failed);
+
+        $this->failed    = $failed;
+        $this->succeeded = $succeeded;
+    }
+
+    /**
+     * @return string[]
+     */
+    public function getSucceededAnnotations(): array
+    {
+        return $this->succeeded;
+    }
+
+    /**
+     * @return array<string,S3Exception>
+     */
+    public function getFailedAnnotations(): array
+    {
+        return $this->failed;
+    }
+}

Unele fișiere nu au fost afișate deoarece prea multe fișiere au fost modificate în acest diff