/**
  * Performs the building logic using all of the parameters that have been
  * set and falling back to default values. Returns an instantiate service
  * client with credentials prepared and plugins attached.
  *
  * @return MssClientInterface
  * @throws InvalidArgumentException
  */
 public function build($s3_image = null)
 {
     // Resolve configuration
     $config = Collection::fromConfig($this->config, array_merge(self::$commonConfigDefaults, $this->configDefaults), self::$commonConfigRequirements + $this->configRequirements);
     if ($config[Options::VERSION] === 'latest') {
         $config[Options::VERSION] = constant("{$this->clientClass}::LATEST_API_VERSION");
     }
     if (!isset($config['endpoint_provider'])) {
         $config['endpoint_provider'] = RulesEndpointProvider::fromDefaults();
     }
     // Resolve the endpoint, signature, and credentials
     $description = $this->updateConfigFromDescription($config);
     $signature = $this->getSignature($description, $config);
     $credentials = $this->getCredentials($config);
     $this->extractHttpConfig($config);
     // Resolve exception parser
     if (!$this->exceptionParser) {
         $this->exceptionParser = new DefaultXmlExceptionParser();
     }
     // Resolve backoff strategy
     $backoff = $config->get(Options::BACKOFF);
     if ($backoff === null) {
         $backoff = $this->createDefaultBackoff();
         $config->set(Options::BACKOFF, $backoff);
     }
     if ($backoff) {
         $this->addBackoffLogger($backoff, $config);
     }
     /** @var MssClientInterface $client */
     $client = new $this->clientClass($credentials, $signature, $config);
     $client->setDescription($description);
     // Add exception marshaling so that more descriptive exception are thrown
     if ($this->clientNamespace) {
         $exceptionFactory = new NamespaceExceptionFactory($this->exceptionParser, "{$this->clientNamespace}\\Exception", "{$this->clientNamespace}\\Exception\\{$this->serviceName}Exception");
         $client->addSubscriber(new ExceptionListener($exceptionFactory));
     }
     // Add the UserAgentPlugin to append to the User-Agent header of requests
     $client->addSubscriber(new UserAgentListener());
     // Filters used for the cache plugin
     $client->getConfig()->set('params.cache.key_filter', 'header=date,x-amz-date,x-amz-security-token,x-amzn-authorization');
     // Set the iterator resource factory based on the provided iterators config
     $client->setResourceIteratorFactory(new MssResourceIteratorFactory($this->iteratorsConfig, new ResourceIteratorClassFactory($this->clientNamespace . '\\Iterator')));
     // Disable parameter validation if needed
     if ($config->get(Options::VALIDATION) === false) {
         $params = $config->get('command.params') ?: array();
         $params['command.disable_validation'] = true;
         $config->set('command.params', $params);
     }
     $client->s3_image = $s3_image;
     return $client;
 }
 /**
  * Get an endpoint for a specific region from a service description
  * @deprecated This function will no longer be updated to work with new regions.
  */
 public static function getEndpoint(ServiceDescriptionInterface $description, $region, $scheme)
 {
     try {
         $service = $description->getData('endpointPrefix');
         $provider = RulesEndpointProvider::fromDefaults();
         $result = $provider(array('service' => $service, 'region' => $region, 'scheme' => $scheme));
         return $result['endpoint'];
     } catch (\InvalidArgumentException $e) {
         throw new InvalidArgumentException($e->getMessage(), 0, $e);
     }
 }