protected function applyOptions(RequestInterface $request, array $options = [])
 {
     $config = $request->getConfig();
     $emitter = $request->getEmitter();
     foreach ($options as $key => $value) {
         if (isset(self::$configMap[$key])) {
             $config[$key] = $value;
             continue;
         }
         switch ($key) {
             case 'allow_redirects':
                 if ($value === false) {
                     continue;
                 }
                 if ($value === true) {
                     $value = self::$defaultRedirect;
                 } elseif (!is_array($value)) {
                     throw new Iae('allow_redirects must be true, false, or array');
                 } else {
                     // Merge the default settings with the provided settings
                     $value += self::$defaultRedirect;
                 }
                 $config['redirect'] = $value;
                 $emitter->attach($this->redirectPlugin);
                 break;
             case 'decode_content':
                 if ($value === false) {
                     continue;
                 }
                 $config['decode_content'] = true;
                 if ($value !== true) {
                     $request->setHeader('Accept-Encoding', $value);
                 }
                 break;
             case 'headers':
                 if (!is_array($value)) {
                     throw new Iae('header value must be an array');
                 }
                 foreach ($value as $k => $v) {
                     $request->setHeader($k, $v);
                 }
                 break;
             case 'exceptions':
                 if ($value === true) {
                     $emitter->attach($this->errorPlugin);
                 }
                 break;
             case 'body':
                 if (is_array($value)) {
                     $this->addPostData($request, $value);
                 } elseif ($value !== null) {
                     $request->setBody(Stream::factory($value));
                 }
                 break;
             case 'auth':
                 if (!$value) {
                     continue;
                 }
                 if (is_array($value)) {
                     $type = isset($value[2]) ? strtolower($value[2]) : 'basic';
                 } else {
                     $type = strtolower($value);
                 }
                 $config['auth'] = $value;
                 if ($type == 'basic') {
                     $request->setHeader('Authorization', 'Basic ' . base64_encode("{$value['0']}:{$value['1']}"));
                 } elseif ($type == 'digest') {
                     // @todo: Do not rely on curl
                     $config->setPath('curl/' . CURLOPT_HTTPAUTH, CURLAUTH_DIGEST);
                     $config->setPath('curl/' . CURLOPT_USERPWD, "{$value['0']}:{$value['1']}");
                 }
                 break;
             case 'query':
                 if ($value instanceof Query) {
                     $original = $request->getQuery();
                     // Do not overwrite existing query string variables by
                     // overwriting the object with the query string data passed
                     // in the URL
                     $value->overwriteWith($original->toArray());
                     $request->setQuery($value);
                 } elseif (is_array($value)) {
                     // Do not overwrite existing query string variables
                     $query = $request->getQuery();
                     foreach ($value as $k => $v) {
                         if (!isset($query[$k])) {
                             $query[$k] = $v;
                         }
                     }
                 } else {
                     throw new Iae('query must be an array or Query object');
                 }
                 break;
             case 'cookies':
                 if ($value === true) {
                     static $cookie = null;
                     if (!$cookie) {
                         $cookie = new Cookie();
                     }
                     $emitter->attach($cookie);
                 } elseif (is_array($value)) {
                     $emitter->attach(new Cookie(CookieJar::fromArray($value, $request->getHost())));
                 } elseif ($value instanceof CookieJarInterface) {
                     $emitter->attach(new Cookie($value));
                 } elseif ($value !== false) {
                     throw new Iae('cookies must be an array, true, or CookieJarInterface');
                 }
                 break;
             case 'events':
                 if (!is_array($value)) {
                     throw new Iae('events must be an array');
                 }
                 $this->attachListeners($request, $this->prepareListeners($value, ['before', 'complete', 'error', 'progress', 'end']));
                 break;
             case 'subscribers':
                 if (!is_array($value)) {
                     throw new Iae('subscribers must be an array');
                 }
                 foreach ($value as $subscribers) {
                     $emitter->attach($subscribers);
                 }
                 break;
             case 'json':
                 $request->setBody(Stream::factory(json_encode($value)));
                 if (!$request->hasHeader('Content-Type')) {
                     $request->setHeader('Content-Type', 'application/json');
                 }
                 break;
             default:
                 // Check for custom handler functions.
                 if (isset($this->customOptions[$key])) {
                     $fn = $this->customOptions[$key];
                     $fn($request, $value);
                     continue;
                 }
                 throw new Iae("No method can handle the {$key} config key");
         }
     }
 }
 private function addListeners(RequestInterface $request, &$calls)
 {
     $request->getEmitter()->on('before', function (BeforeEvent $e) use(&$calls) {
         $calls[] = 'before';
     }, RequestEvents::EARLY);
     $request->getEmitter()->on('complete', function (CompleteEvent $e) use(&$calls) {
         $calls[] = 'complete';
     }, RequestEvents::EARLY);
     $request->getEmitter()->on('error', function (ErrorEvent $e) use(&$calls) {
         $calls[] = 'error';
     }, RequestEvents::EARLY);
     $request->getEmitter()->on('end', function (EndEvent $e) use(&$calls) {
         $calls[] = 'end';
     }, RequestEvents::EARLY);
 }